flipper 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Guardfile +3 -8
- data/README.md +26 -38
- data/examples/percentage_of_actors.rb +17 -12
- data/examples/percentage_of_random.rb +3 -7
- data/lib/flipper.rb +8 -1
- data/lib/flipper/adapter.rb +2 -208
- data/lib/flipper/adapters/decorator.rb +9 -0
- data/lib/flipper/adapters/instrumented.rb +92 -0
- data/lib/flipper/adapters/memoizable.rb +88 -0
- data/lib/flipper/adapters/memory.rb +89 -7
- data/lib/flipper/adapters/operation_logger.rb +31 -45
- data/lib/flipper/decorator.rb +6 -0
- data/lib/flipper/dsl.rb +29 -2
- data/lib/flipper/feature.rb +83 -49
- data/lib/flipper/gate.rb +24 -41
- data/lib/flipper/gates/actor.rb +24 -24
- data/lib/flipper/gates/boolean.rb +28 -15
- data/lib/flipper/gates/group.rb +25 -34
- data/lib/flipper/gates/percentage_of_actors.rb +21 -13
- data/lib/flipper/gates/percentage_of_random.rb +20 -12
- data/lib/flipper/instrumentation/log_subscriber.rb +14 -22
- data/lib/flipper/middleware/memoizer.rb +23 -0
- data/lib/flipper/spec/shared_adapter_specs.rb +141 -92
- data/lib/flipper/types/boolean.rb +5 -1
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/adapters/instrumented_spec.rb +92 -0
- data/spec/flipper/adapters/memoizable_spec.rb +184 -0
- data/spec/flipper/adapters/memory_spec.rb +1 -11
- data/spec/flipper/adapters/operation_logger_spec.rb +93 -0
- data/spec/flipper/dsl_spec.rb +18 -43
- data/spec/flipper/feature_spec.rb +25 -9
- data/spec/flipper/gate_spec.rb +8 -20
- data/spec/flipper/gates/actor_spec.rb +6 -14
- data/spec/flipper/gates/boolean_spec.rb +80 -13
- data/spec/flipper/gates/group_spec.rb +8 -18
- data/spec/flipper/gates/percentage_of_actors_spec.rb +12 -28
- data/spec/flipper/gates/percentage_of_random_spec.rb +6 -14
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +15 -8
- data/spec/flipper/instrumentation/metriks_subscriber_spec.rb +3 -6
- data/spec/flipper/middleware/{local_cache_spec.rb → memoizer_spec.rb} +25 -55
- data/spec/flipper/types/boolean_spec.rb +13 -3
- data/spec/flipper_spec.rb +7 -0
- data/spec/helper.rb +21 -3
- data/spec/integration_spec.rb +115 -116
- metadata +17 -27
- data/lib/flipper/adapters/memoized.rb +0 -55
- data/lib/flipper/key.rb +0 -38
- data/lib/flipper/middleware/local_cache.rb +0 -36
- data/lib/flipper/toggle.rb +0 -54
- data/lib/flipper/toggles/boolean.rb +0 -54
- data/lib/flipper/toggles/set.rb +0 -25
- data/lib/flipper/toggles/value.rb +0 -25
- data/spec/flipper/adapter_spec.rb +0 -463
- data/spec/flipper/adapters/memoized_spec.rb +0 -93
- data/spec/flipper/key_spec.rb +0 -23
- data/spec/flipper/toggle_spec.rb +0 -22
- data/spec/flipper/toggles/boolean_spec.rb +0 -40
- data/spec/flipper/toggles/set_spec.rb +0 -35
- data/spec/flipper/toggles/value_spec.rb +0 -55
@@ -38,16 +38,13 @@ describe Flipper::Instrumentation::MetriksSubscriber do
|
|
38
38
|
|
39
39
|
it "updates adapter metrics when calls happen" do
|
40
40
|
flipper[:stats].enable(user)
|
41
|
-
|
42
|
-
Metriks.timer("flipper.adapter.memory.set_add").count.should be(2)
|
41
|
+
Metriks.timer("flipper.adapter.memory.enable").count.should be(1)
|
43
42
|
|
44
43
|
flipper[:stats].enabled?(user)
|
45
|
-
Metriks.timer("flipper.adapter.memory.
|
46
|
-
# one for actors and one for groups
|
47
|
-
Metriks.timer("flipper.adapter.memory.set_members").count.should be(2)
|
44
|
+
Metriks.timer("flipper.adapter.memory.get").count.should be(1)
|
48
45
|
|
49
46
|
flipper[:stats].disable(user)
|
50
|
-
Metriks.timer("flipper.adapter.memory.
|
47
|
+
Metriks.timer("flipper.adapter.memory.disable").count.should be(1)
|
51
48
|
end
|
52
49
|
|
53
50
|
it "updates gate metrics when calls happen" do
|
@@ -1,18 +1,12 @@
|
|
1
1
|
require 'helper'
|
2
2
|
require 'rack/test'
|
3
|
-
require 'flipper/middleware/
|
3
|
+
require 'flipper/middleware/memoizer'
|
4
4
|
require 'flipper/adapters/operation_logger'
|
5
5
|
require 'flipper/adapters/memory'
|
6
6
|
|
7
|
-
describe Flipper::Middleware::
|
7
|
+
describe Flipper::Middleware::Memoizer do
|
8
8
|
include Rack::Test::Methods
|
9
9
|
|
10
|
-
class Enum < Struct.new(:iter)
|
11
|
-
def each(&block)
|
12
|
-
iter.call(&block)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
10
|
let(:source) { {} }
|
17
11
|
let(:memory_adapter) { Flipper::Adapters::Memory.new(source) }
|
18
12
|
let(:adapter) { Flipper::Adapters::OperationLogger.new(memory_adapter) }
|
@@ -36,8 +30,8 @@ describe Flipper::Middleware::LocalCache do
|
|
36
30
|
end.to_app
|
37
31
|
}
|
38
32
|
|
39
|
-
|
40
|
-
adapter.
|
33
|
+
after do
|
34
|
+
flipper.adapter.memoize = nil
|
41
35
|
end
|
42
36
|
|
43
37
|
it "delegates" do
|
@@ -51,50 +45,42 @@ describe Flipper::Middleware::LocalCache do
|
|
51
45
|
called.should be_true
|
52
46
|
end
|
53
47
|
|
54
|
-
it "enables memoization during delegation" do
|
55
|
-
app = lambda { |env|
|
56
|
-
flipper.adapter.using_local_cache?.should be_true
|
57
|
-
[200, {}, nil]
|
58
|
-
}
|
59
|
-
middleware = described_class.new app, flipper
|
60
|
-
middleware.call({})
|
61
|
-
end
|
62
|
-
|
63
|
-
it "enables local cache for body each" do
|
64
|
-
app = lambda { |env|
|
65
|
-
[200, {}, Enum.new(lambda { |&block|
|
66
|
-
flipper.adapter.using_local_cache?.should be_true
|
67
|
-
block.call "hello"
|
68
|
-
})]
|
69
|
-
}
|
70
|
-
middleware = described_class.new app, flipper
|
71
|
-
body = middleware.call({}).last
|
72
|
-
body.each { |x| x.should eql('hello') }
|
73
|
-
end
|
74
|
-
|
75
48
|
it "disables local cache after body close" do
|
76
49
|
app = lambda { |env| [200, {}, []] }
|
77
50
|
middleware = described_class.new app, flipper
|
78
51
|
body = middleware.call({}).last
|
79
52
|
|
80
|
-
flipper.adapter.
|
53
|
+
flipper.adapter.memoizing?.should be_true
|
81
54
|
body.close
|
82
|
-
flipper.adapter.
|
55
|
+
flipper.adapter.memoizing?.should be_false
|
83
56
|
end
|
84
57
|
|
85
58
|
it "clears local cache after body close" do
|
86
59
|
app = lambda { |env| [200, {}, []] }
|
87
60
|
middleware = described_class.new app, flipper
|
88
61
|
body = middleware.call({}).last
|
89
|
-
flipper.adapter.local_cache['hello'] = 'world'
|
90
62
|
|
91
|
-
flipper.adapter.
|
63
|
+
flipper.adapter.cache['hello'] = 'world'
|
92
64
|
body.close
|
93
|
-
flipper.adapter.
|
65
|
+
flipper.adapter.cache.should be_empty
|
66
|
+
end
|
67
|
+
|
68
|
+
it "clears the local cache with a successful request" do
|
69
|
+
flipper.adapter.cache['hello'] = 'world'
|
70
|
+
get '/'
|
71
|
+
flipper.adapter.cache.should be_empty
|
94
72
|
end
|
95
73
|
|
96
|
-
it "
|
74
|
+
it "clears the local cache even when the request raises an error" do
|
75
|
+
flipper.adapter.cache['hello'] = 'world'
|
76
|
+
get '/fail' rescue nil
|
77
|
+
flipper.adapter.cache.should be_empty
|
78
|
+
end
|
79
|
+
|
80
|
+
it "caches getting a feature for duration of request" do
|
97
81
|
flipper[:stats].enable
|
82
|
+
|
83
|
+
# clear the log of operations
|
98
84
|
adapter.reset
|
99
85
|
|
100
86
|
app = lambda { |env|
|
@@ -104,28 +90,12 @@ describe Flipper::Middleware::LocalCache do
|
|
104
90
|
flipper[:stats].enabled?
|
105
91
|
flipper[:stats].enabled?
|
106
92
|
flipper[:stats].enabled?
|
107
|
-
|
108
93
|
[200, {}, []]
|
109
94
|
}
|
95
|
+
|
110
96
|
middleware = described_class.new app, flipper
|
111
97
|
middleware.call({})
|
112
98
|
|
113
|
-
adapter.
|
114
|
-
Flipper::Adapters::OperationLogger::Read.new("stats/boolean"),
|
115
|
-
])
|
116
|
-
end
|
117
|
-
|
118
|
-
context "with a successful request" do
|
119
|
-
it "clears the local cache" do
|
120
|
-
flipper.adapter.local_cache.should_receive(:clear).twice
|
121
|
-
get '/'
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
context "when the request raises an error" do
|
126
|
-
it "clears the local cache" do
|
127
|
-
flipper.adapter.local_cache.should_receive(:clear).once
|
128
|
-
get '/fail' rescue nil
|
129
|
-
end
|
99
|
+
adapter.count(:get).should be(1)
|
130
100
|
end
|
131
101
|
end
|
@@ -2,8 +2,18 @@ require 'helper'
|
|
2
2
|
require 'flipper/types/boolean'
|
3
3
|
|
4
4
|
describe Flipper::Types::Boolean do
|
5
|
-
it "
|
6
|
-
|
7
|
-
|
5
|
+
it "defaults value to true" do
|
6
|
+
boolean = Flipper::Types::Boolean.new
|
7
|
+
boolean.value.should be(true)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "allows overriding default value" do
|
11
|
+
boolean = Flipper::Types::Boolean.new(false)
|
12
|
+
boolean.value.should be(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns true for nil value" do
|
16
|
+
boolean = Flipper::Types::Boolean.new(nil)
|
17
|
+
boolean.value.should be(true)
|
8
18
|
end
|
9
19
|
end
|
data/spec/flipper_spec.rb
CHANGED
@@ -46,6 +46,13 @@ describe Flipper do
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
describe ".unregister_groups" do
|
50
|
+
it "clear group registry" do
|
51
|
+
Flipper.groups.should_receive(:clear)
|
52
|
+
Flipper.unregister_groups
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
49
56
|
describe ".group" do
|
50
57
|
context "for registered group" do
|
51
58
|
before do
|
data/spec/helper.rb
CHANGED
@@ -24,7 +24,7 @@ RSpec.configure do |config|
|
|
24
24
|
config.run_all_when_everything_filtered = true
|
25
25
|
|
26
26
|
config.before(:each) do
|
27
|
-
Flipper.
|
27
|
+
Flipper.unregister_groups
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -67,7 +67,7 @@ shared_examples_for 'a DSL feature' do
|
|
67
67
|
end
|
68
68
|
|
69
69
|
it "sets adapter" do
|
70
|
-
feature.adapter.should eq(dsl.adapter)
|
70
|
+
feature.adapter.name.should eq(dsl.adapter.name)
|
71
71
|
end
|
72
72
|
|
73
73
|
it "sets instrumenter" do
|
@@ -75,6 +75,24 @@ shared_examples_for 'a DSL feature' do
|
|
75
75
|
end
|
76
76
|
|
77
77
|
it "memoizes the feature" do
|
78
|
-
dsl.
|
78
|
+
dsl.send(method_name, :stats).should equal(feature)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "raises argument error if not string or symbol" do
|
82
|
+
expect {
|
83
|
+
dsl.send(method_name, Object.new)
|
84
|
+
}.to raise_error(ArgumentError, /must be a String or Symbol/)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
shared_examples_for "a DSL boolean method" do
|
89
|
+
it "returns boolean with value set" do
|
90
|
+
result = subject.send(method_name, true)
|
91
|
+
result.should be_instance_of(Flipper::Types::Boolean)
|
92
|
+
result.value.should be(true)
|
93
|
+
|
94
|
+
result = subject.send(method_name, false)
|
95
|
+
result.should be_instance_of(Flipper::Types::Boolean)
|
96
|
+
result.value.should be(false)
|
79
97
|
end
|
80
98
|
end
|
data/spec/integration_spec.rb
CHANGED
@@ -2,16 +2,17 @@ require 'helper'
|
|
2
2
|
require 'flipper/feature'
|
3
3
|
require 'flipper/adapters/memory'
|
4
4
|
|
5
|
-
describe Flipper
|
6
|
-
subject { described_class.new(:search, adapter) }
|
7
|
-
|
8
|
-
let(:actor_class) { Struct.new(:flipper_id) }
|
9
|
-
|
5
|
+
describe Flipper do
|
10
6
|
let(:source) { {} }
|
11
7
|
let(:adapter) { Flipper::Adapters::Memory.new(source) }
|
12
8
|
|
13
|
-
let(:
|
14
|
-
let(:
|
9
|
+
let(:flipper) { Flipper.new(adapter) }
|
10
|
+
let(:feature) { flipper[:search] }
|
11
|
+
|
12
|
+
let(:actor_class) { Struct.new(:flipper_id) }
|
13
|
+
|
14
|
+
let(:admin_group) { flipper.group(:admins) }
|
15
|
+
let(:dev_group) { flipper.group(:devs) }
|
15
16
|
|
16
17
|
let(:admin_thing) { double 'Non Flipper Thing', :flipper_id => 1, :admin? => true, :dev? => false }
|
17
18
|
let(:dev_thing) { double 'Non Flipper Thing', :flipper_id => 10, :admin? => false, :dev? => true }
|
@@ -19,22 +20,18 @@ describe Flipper::Feature do
|
|
19
20
|
let(:pitt) { actor_class.new(1) }
|
20
21
|
let(:clooney) { actor_class.new(10) }
|
21
22
|
|
22
|
-
let(:five_percent_of_actors) {
|
23
|
-
let(:five_percent_of_random) {
|
23
|
+
let(:five_percent_of_actors) { flipper.actors(5) }
|
24
|
+
let(:five_percent_of_random) { flipper.random(5) }
|
24
25
|
|
25
26
|
before do
|
26
27
|
Flipper.register(:admins) { |thing| thing.admin? }
|
27
28
|
Flipper.register(:devs) { |thing| thing.dev? }
|
28
29
|
end
|
29
30
|
|
30
|
-
after do
|
31
|
-
Flipper.groups = nil
|
32
|
-
end
|
33
|
-
|
34
31
|
describe "#enable" do
|
35
32
|
context "with no arguments" do
|
36
33
|
before do
|
37
|
-
@result =
|
34
|
+
@result = feature.enable
|
38
35
|
end
|
39
36
|
|
40
37
|
it "returns true" do
|
@@ -42,17 +39,17 @@ describe Flipper::Feature do
|
|
42
39
|
end
|
43
40
|
|
44
41
|
it "enables feature for all" do
|
45
|
-
|
42
|
+
feature.enabled?.should be_true
|
46
43
|
end
|
47
44
|
|
48
45
|
it "adds feature to set of features" do
|
49
|
-
|
46
|
+
flipper.features.map(&:name).should include(:search)
|
50
47
|
end
|
51
48
|
end
|
52
49
|
|
53
50
|
context "with a group" do
|
54
51
|
before do
|
55
|
-
@result =
|
52
|
+
@result = feature.enable(admin_group)
|
56
53
|
end
|
57
54
|
|
58
55
|
it "returns true" do
|
@@ -60,33 +57,33 @@ describe Flipper::Feature do
|
|
60
57
|
end
|
61
58
|
|
62
59
|
it "enables feature for non flipper thing in group" do
|
63
|
-
|
60
|
+
feature.enabled?(admin_thing).should be_true
|
64
61
|
end
|
65
62
|
|
66
63
|
it "does not enable feature for non flipper thing in other group" do
|
67
|
-
|
64
|
+
feature.enabled?(dev_thing).should be_false
|
68
65
|
end
|
69
66
|
|
70
67
|
it "enables feature for flipper actor in group" do
|
71
|
-
|
68
|
+
feature.enabled?(flipper.actor(admin_thing)).should be_true
|
72
69
|
end
|
73
70
|
|
74
71
|
it "does not enable for flipper actor not in group" do
|
75
|
-
|
72
|
+
feature.enabled?(flipper.actor(dev_thing)).should be_false
|
76
73
|
end
|
77
74
|
|
78
75
|
it "does not enable feature for all" do
|
79
|
-
|
76
|
+
feature.enabled?.should be_false
|
80
77
|
end
|
81
78
|
|
82
79
|
it "adds feature to set of features" do
|
83
|
-
|
80
|
+
flipper.features.map(&:name).should include(:search)
|
84
81
|
end
|
85
82
|
end
|
86
83
|
|
87
84
|
context "with an actor" do
|
88
85
|
before do
|
89
|
-
@result =
|
86
|
+
@result = feature.enable(pitt)
|
90
87
|
end
|
91
88
|
|
92
89
|
it "returns true" do
|
@@ -94,21 +91,21 @@ describe Flipper::Feature do
|
|
94
91
|
end
|
95
92
|
|
96
93
|
it "enables feature for actor" do
|
97
|
-
|
94
|
+
feature.enabled?(pitt).should be_true
|
98
95
|
end
|
99
96
|
|
100
97
|
it "does not enable feature for other actors" do
|
101
|
-
|
98
|
+
feature.enabled?(clooney).should be_false
|
102
99
|
end
|
103
100
|
|
104
101
|
it "adds feature to set of features" do
|
105
|
-
|
102
|
+
flipper.features.map(&:name).should include(:search)
|
106
103
|
end
|
107
104
|
end
|
108
105
|
|
109
106
|
context "with a percentage of actors" do
|
110
107
|
before do
|
111
|
-
@result =
|
108
|
+
@result = feature.enable(five_percent_of_actors)
|
112
109
|
end
|
113
110
|
|
114
111
|
it "returns true" do
|
@@ -118,22 +115,21 @@ describe Flipper::Feature do
|
|
118
115
|
it "enables feature for actor within percentage" do
|
119
116
|
enabled = (1..100).select { |i|
|
120
117
|
thing = actor_class.new(i)
|
121
|
-
|
118
|
+
feature.enabled?(thing)
|
122
119
|
}.size
|
123
120
|
|
124
121
|
enabled.should be_within(2).of(5)
|
125
122
|
end
|
126
123
|
|
127
124
|
it "adds feature to set of features" do
|
128
|
-
|
125
|
+
flipper.features.map(&:name).should include(:search)
|
129
126
|
end
|
130
127
|
end
|
131
128
|
|
132
129
|
context "with a percentage of random" do
|
133
130
|
before do
|
134
|
-
@gate =
|
135
|
-
|
136
|
-
@result = subject.enable(five_percent_of_random)
|
131
|
+
@gate = feature.gate(:percentage_of_random)
|
132
|
+
@result = feature.enable(five_percent_of_random)
|
137
133
|
end
|
138
134
|
|
139
135
|
it "returns true" do
|
@@ -142,16 +138,16 @@ describe Flipper::Feature do
|
|
142
138
|
|
143
139
|
it "enables feature for time within percentage" do
|
144
140
|
@gate.stub(:rand => 0.04)
|
145
|
-
|
141
|
+
feature.enabled?.should be_true
|
146
142
|
end
|
147
143
|
|
148
144
|
it "does not enable feature for time not within percentage" do
|
149
145
|
@gate.stub(:rand => 0.10)
|
150
|
-
|
146
|
+
feature.enabled?.should be_false
|
151
147
|
end
|
152
148
|
|
153
149
|
it "adds feature to set of features" do
|
154
|
-
|
150
|
+
flipper.features.map(&:name).should include(:search)
|
155
151
|
end
|
156
152
|
end
|
157
153
|
|
@@ -159,7 +155,7 @@ describe Flipper::Feature do
|
|
159
155
|
it "raises error" do
|
160
156
|
thing = Object.new
|
161
157
|
expect {
|
162
|
-
|
158
|
+
feature.enable(thing)
|
163
159
|
}.to raise_error(Flipper::GateNotFound, "Could not find gate for #{thing.inspect}")
|
164
160
|
end
|
165
161
|
end
|
@@ -169,14 +165,14 @@ describe Flipper::Feature do
|
|
169
165
|
context "with no arguments" do
|
170
166
|
before do
|
171
167
|
# ensures that random gate is stubbed with result that would be true for pitt
|
172
|
-
@gate =
|
168
|
+
@gate = feature.gate(:percentage_of_random)
|
173
169
|
@gate.stub(:rand => 0.04)
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
@result =
|
170
|
+
|
171
|
+
feature.enable admin_group
|
172
|
+
feature.enable pitt
|
173
|
+
feature.enable five_percent_of_actors
|
174
|
+
feature.enable five_percent_of_random
|
175
|
+
@result = feature.disable
|
180
176
|
end
|
181
177
|
|
182
178
|
it "returns true" do
|
@@ -184,40 +180,40 @@ describe Flipper::Feature do
|
|
184
180
|
end
|
185
181
|
|
186
182
|
it "disables feature" do
|
187
|
-
|
183
|
+
feature.enabled?.should be_false
|
188
184
|
end
|
189
185
|
|
190
186
|
it "disables for individual actor" do
|
191
|
-
|
187
|
+
feature.enabled?(pitt).should be_false
|
192
188
|
end
|
193
189
|
|
194
190
|
it "disables actor in group" do
|
195
|
-
|
191
|
+
feature.enabled?(admin_thing).should be_false
|
196
192
|
end
|
197
193
|
|
198
194
|
it "disables actor in percentage of actors" do
|
199
195
|
enabled = (1..100).select { |i|
|
200
196
|
thing = actor_class.new(i)
|
201
|
-
|
197
|
+
feature.enabled?(thing)
|
202
198
|
}.size
|
203
199
|
|
204
200
|
enabled.should be(0)
|
205
201
|
end
|
206
202
|
|
207
203
|
it "disables percentage of random" do
|
208
|
-
|
204
|
+
feature.enabled?(pitt).should be_false
|
209
205
|
end
|
210
206
|
|
211
207
|
it "adds feature to set of features" do
|
212
|
-
|
208
|
+
flipper.features.map(&:name).should include(:search)
|
213
209
|
end
|
214
210
|
end
|
215
211
|
|
216
212
|
context "with a group" do
|
217
213
|
before do
|
218
|
-
|
219
|
-
|
220
|
-
@result =
|
214
|
+
feature.enable dev_group
|
215
|
+
feature.enable admin_group
|
216
|
+
@result = feature.disable(admin_group)
|
221
217
|
end
|
222
218
|
|
223
219
|
it "returns true" do
|
@@ -225,31 +221,31 @@ describe Flipper::Feature do
|
|
225
221
|
end
|
226
222
|
|
227
223
|
it "disables the feature for non flipper thing in the group" do
|
228
|
-
|
224
|
+
feature.enabled?(admin_thing).should be_false
|
229
225
|
end
|
230
226
|
|
231
227
|
it "does not disable feature for non flipper thing in other groups" do
|
232
|
-
|
228
|
+
feature.enabled?(dev_thing).should be_true
|
233
229
|
end
|
234
230
|
|
235
231
|
it "disables feature for flipper actor in group" do
|
236
|
-
|
232
|
+
feature.enabled?(flipper.actor(admin_thing)).should be_false
|
237
233
|
end
|
238
234
|
|
239
235
|
it "does not disable feature for flipper actor in other groups" do
|
240
|
-
|
236
|
+
feature.enabled?(flipper.actor(dev_thing)).should be_true
|
241
237
|
end
|
242
238
|
|
243
239
|
it "adds feature to set of features" do
|
244
|
-
|
240
|
+
flipper.features.map(&:name).should include(:search)
|
245
241
|
end
|
246
242
|
end
|
247
243
|
|
248
244
|
context "with an actor" do
|
249
245
|
before do
|
250
|
-
|
251
|
-
|
252
|
-
@result =
|
246
|
+
feature.enable pitt
|
247
|
+
feature.enable clooney
|
248
|
+
@result = feature.disable(pitt)
|
253
249
|
end
|
254
250
|
|
255
251
|
it "returns true" do
|
@@ -257,21 +253,21 @@ describe Flipper::Feature do
|
|
257
253
|
end
|
258
254
|
|
259
255
|
it "disables feature for actor" do
|
260
|
-
|
256
|
+
feature.enabled?(pitt).should be_false
|
261
257
|
end
|
262
258
|
|
263
259
|
it "does not disable feature for other actors" do
|
264
|
-
|
260
|
+
feature.enabled?(clooney).should be_true
|
265
261
|
end
|
266
262
|
|
267
263
|
it "adds feature to set of features" do
|
268
|
-
|
264
|
+
flipper.features.map(&:name).should include(:search)
|
269
265
|
end
|
270
266
|
end
|
271
267
|
|
272
268
|
context "with a percentage of actors" do
|
273
269
|
before do
|
274
|
-
@result =
|
270
|
+
@result = feature.disable(flipper.actors(0))
|
275
271
|
end
|
276
272
|
|
277
273
|
it "returns true" do
|
@@ -281,22 +277,21 @@ describe Flipper::Feature do
|
|
281
277
|
it "disables feature" do
|
282
278
|
enabled = (1..100).select { |i|
|
283
279
|
thing = actor_class.new(i)
|
284
|
-
|
280
|
+
feature.enabled?(thing)
|
285
281
|
}.size
|
286
282
|
|
287
283
|
enabled.should be(0)
|
288
284
|
end
|
289
285
|
|
290
286
|
it "adds feature to set of features" do
|
291
|
-
|
287
|
+
flipper.features.map(&:name).should include(:search)
|
292
288
|
end
|
293
289
|
end
|
294
290
|
|
295
291
|
context "with a percentage of time" do
|
296
292
|
before do
|
297
|
-
@gate =
|
298
|
-
|
299
|
-
@result = subject.disable(five_percent_of_random)
|
293
|
+
@gate = feature.gate(:percentage_of_random)
|
294
|
+
@result = feature.disable(flipper.random(0))
|
300
295
|
end
|
301
296
|
|
302
297
|
it "returns true" do
|
@@ -305,16 +300,16 @@ describe Flipper::Feature do
|
|
305
300
|
|
306
301
|
it "disables feature for time within percentage" do
|
307
302
|
@gate.stub(:rand => 0.04)
|
308
|
-
|
303
|
+
feature.enabled?.should be_false
|
309
304
|
end
|
310
305
|
|
311
306
|
it "disables feature for time not within percentage" do
|
312
307
|
@gate.stub(:rand => 0.10)
|
313
|
-
|
308
|
+
feature.enabled?.should be_false
|
314
309
|
end
|
315
310
|
|
316
311
|
it "adds feature to set of features" do
|
317
|
-
|
312
|
+
flipper.features.map(&:name).should include(:search)
|
318
313
|
end
|
319
314
|
end
|
320
315
|
|
@@ -322,7 +317,7 @@ describe Flipper::Feature do
|
|
322
317
|
it "raises error" do
|
323
318
|
thing = Object.new
|
324
319
|
expect {
|
325
|
-
|
320
|
+
feature.disable(thing)
|
326
321
|
}.to raise_error(Flipper::GateNotFound, "Could not find gate for #{thing.inspect}")
|
327
322
|
end
|
328
323
|
end
|
@@ -331,132 +326,136 @@ describe Flipper::Feature do
|
|
331
326
|
describe "#enabled?" do
|
332
327
|
context "with no arguments" do
|
333
328
|
it "defaults to false" do
|
334
|
-
|
329
|
+
feature.enabled?.should be_false
|
335
330
|
end
|
336
331
|
end
|
337
332
|
|
338
333
|
context "with no arguments, but boolean enabled" do
|
339
334
|
before do
|
340
|
-
|
335
|
+
feature.enable
|
341
336
|
end
|
342
337
|
|
343
338
|
it "returns true" do
|
344
|
-
|
339
|
+
feature.enabled?.should be_true
|
345
340
|
end
|
346
341
|
end
|
347
342
|
|
348
343
|
context "for actor in enabled group" do
|
349
344
|
before do
|
350
|
-
|
345
|
+
feature.enable admin_group
|
351
346
|
end
|
352
347
|
|
353
348
|
it "returns true" do
|
354
|
-
|
349
|
+
feature.enabled?(flipper.actor(admin_thing)).should be_true
|
350
|
+
feature.enabled?(admin_thing).should be_true
|
355
351
|
end
|
356
352
|
end
|
357
353
|
|
358
354
|
context "for actor in disabled group" do
|
359
355
|
it "returns false" do
|
360
|
-
|
356
|
+
feature.enabled?(flipper.actor(dev_thing)).should be_false
|
357
|
+
feature.enabled?(dev_thing).should be_false
|
361
358
|
end
|
362
359
|
end
|
363
360
|
|
364
361
|
context "for enabled actor" do
|
365
362
|
before do
|
366
|
-
|
363
|
+
feature.enable pitt
|
367
364
|
end
|
368
365
|
|
369
366
|
it "returns true" do
|
370
|
-
|
367
|
+
feature.enabled?(pitt).should be_true
|
371
368
|
end
|
372
369
|
end
|
373
370
|
|
374
371
|
context "for not enabled actor" do
|
375
372
|
it "returns false" do
|
376
|
-
|
373
|
+
feature.enabled?(clooney).should be_false
|
377
374
|
end
|
378
375
|
|
379
376
|
it "returns true if boolean enabled" do
|
380
|
-
|
381
|
-
|
377
|
+
feature.enable
|
378
|
+
feature.enabled?(clooney).should be_true
|
382
379
|
end
|
383
380
|
end
|
384
381
|
|
385
382
|
context "during enabled percentage of time" do
|
386
383
|
before do
|
387
|
-
|
384
|
+
# ensure percentage of random returns enabled percentage
|
385
|
+
@gate = feature.gate(:percentage_of_random)
|
388
386
|
@gate.stub(:rand => 0.04)
|
389
|
-
|
390
|
-
|
387
|
+
|
388
|
+
feature.enable five_percent_of_random
|
391
389
|
end
|
392
390
|
|
393
391
|
it "returns true" do
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
392
|
+
feature.enabled?.should be_true
|
393
|
+
feature.enabled?(nil).should be_true
|
394
|
+
feature.enabled?(pitt).should be_true
|
395
|
+
feature.enabled?(admin_thing).should be_true
|
398
396
|
end
|
399
397
|
end
|
400
398
|
|
401
399
|
context "during not enabled percentage of time" do
|
402
400
|
before do
|
403
|
-
|
401
|
+
# ensure percentage of random returns not enabled percentage
|
402
|
+
@gate = feature.gate(:percentage_of_random)
|
404
403
|
@gate.stub(:rand => 0.10)
|
405
|
-
|
406
|
-
|
404
|
+
|
405
|
+
feature.enable five_percent_of_random
|
407
406
|
end
|
408
407
|
|
409
408
|
it "returns false" do
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
409
|
+
feature.enabled?.should be_false
|
410
|
+
feature.enabled?(nil).should be_false
|
411
|
+
feature.enabled?(pitt).should be_false
|
412
|
+
feature.enabled?(admin_thing).should be_false
|
414
413
|
end
|
415
414
|
|
416
415
|
it "returns true if boolean enabled" do
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
416
|
+
feature.enable
|
417
|
+
feature.enabled?.should be_true
|
418
|
+
feature.enabled?(nil).should be_true
|
419
|
+
feature.enabled?(pitt).should be_true
|
420
|
+
feature.enabled?(admin_thing).should be_true
|
422
421
|
end
|
423
422
|
end
|
424
423
|
|
425
424
|
context "for a non flipper thing" do
|
426
425
|
before do
|
427
|
-
|
426
|
+
feature.enable admin_group
|
428
427
|
end
|
429
428
|
|
430
429
|
it "returns true if in enabled group" do
|
431
|
-
|
430
|
+
feature.enabled?(admin_thing).should be_true
|
432
431
|
end
|
433
432
|
|
434
433
|
it "returns false if not in enabled group" do
|
435
|
-
|
434
|
+
feature.enabled?(dev_thing).should be_false
|
436
435
|
end
|
437
436
|
|
438
437
|
it "returns true if boolean enabled" do
|
439
|
-
|
440
|
-
|
441
|
-
|
438
|
+
feature.enable
|
439
|
+
feature.enabled?(admin_thing).should be_true
|
440
|
+
feature.enabled?(dev_thing).should be_true
|
442
441
|
end
|
443
442
|
end
|
444
443
|
end
|
445
444
|
|
446
445
|
context "enabling multiple groups, disabling everything, then enabling one group" do
|
447
446
|
before do
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
447
|
+
feature.enable(admin_group)
|
448
|
+
feature.enable(dev_group)
|
449
|
+
feature.disable
|
450
|
+
feature.enable(admin_group)
|
452
451
|
end
|
453
452
|
|
454
453
|
it "enables feature for object in enabled group" do
|
455
|
-
|
454
|
+
feature.enabled?(admin_thing).should be_true
|
456
455
|
end
|
457
456
|
|
458
457
|
it "does not enable feature for object in not enabled group" do
|
459
|
-
|
458
|
+
feature.enabled?(dev_thing).should be_false
|
460
459
|
end
|
461
460
|
end
|
462
461
|
end
|