flipper 0.7.5 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +12 -0
- data/Gemfile +1 -0
- data/Rakefile +9 -4
- data/docs/Optimization.md +8 -2
- data/lib/flipper/adapters/instrumented.rb +21 -17
- data/lib/flipper/adapters/memoizable.rb +20 -13
- data/lib/flipper/adapters/memory.rb +1 -1
- data/lib/flipper/adapters/operation_logger.rb +49 -12
- data/lib/flipper/adapters/pstore.rb +1 -1
- data/lib/flipper/adapters/read_only.rb +51 -0
- data/lib/flipper/dsl.rb +9 -0
- data/lib/flipper/feature.rb +8 -20
- data/lib/flipper/gate.rb +0 -4
- data/lib/flipper/gate_values.rb +4 -2
- data/lib/flipper/gates/actor.rb +1 -1
- data/lib/flipper/gates/boolean.rb +1 -1
- data/lib/flipper/gates/group.rb +1 -1
- data/lib/flipper/gates/percentage_of_actors.rb +3 -5
- data/lib/flipper/gates/percentage_of_time.rb +2 -3
- data/lib/flipper/instrumentation/log_subscriber.rb +0 -28
- data/lib/flipper/instrumentation/subscriber.rb +0 -22
- data/lib/flipper/middleware/memoizer.rb +2 -3
- data/lib/flipper/spec/shared_adapter_specs.rb +32 -0
- data/lib/flipper/test/shared_adapter_test.rb +249 -0
- data/lib/flipper/typecast.rb +1 -1
- data/lib/flipper/types/group.rb +1 -1
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/adapters/instrumented_spec.rb +6 -0
- data/spec/flipper/adapters/memoizable_spec.rb +6 -0
- data/spec/flipper/adapters/read_only_spec.rb +94 -0
- data/spec/flipper/dsl_spec.rb +14 -2
- data/spec/flipper/feature_spec.rb +11 -0
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +0 -10
- data/spec/flipper/instrumentation/metriks_subscriber_spec.rb +0 -10
- data/spec/flipper/instrumentation/statsd_subscriber_spec.rb +0 -10
- data/spec/flipper/types/group_spec.rb +14 -0
- data/spec/helper.rb +4 -0
- data/spec/integration_spec.rb +11 -0
- data/spec/support/spec_helpers.rb +4 -0
- data/test/adapters/memory_test.rb +10 -0
- data/test/adapters/pstore_test.rb +17 -0
- data/test/helper.rb +0 -2
- data/test/test_helper.rb +6 -0
- metadata +12 -4
- data/lib/flipper/adapters/decorator.rb +0 -11
- data/lib/flipper/decorator.rb +0 -6
data/lib/flipper/dsl.rb
CHANGED
@@ -145,6 +145,15 @@ module Flipper
|
|
145
145
|
feature(name).disable_percentage_of_actors
|
146
146
|
end
|
147
147
|
|
148
|
+
# Public: Remove a feature.
|
149
|
+
#
|
150
|
+
# name - The String or Symbol name of the feature.
|
151
|
+
#
|
152
|
+
# Returns result of remove.
|
153
|
+
def remove(name)
|
154
|
+
feature(name).remove
|
155
|
+
end
|
156
|
+
|
148
157
|
# Public: Access a feature instance by name.
|
149
158
|
#
|
150
159
|
# name - The String or Symbol name of the feature.
|
data/lib/flipper/feature.rb
CHANGED
@@ -9,9 +9,6 @@ module Flipper
|
|
9
9
|
# Private: The name of feature instrumentation events.
|
10
10
|
InstrumentationName = "feature_operation.#{InstrumentationNamespace}"
|
11
11
|
|
12
|
-
# Private: The name of gate instrumentation events.
|
13
|
-
GateInstrumentationName = "gate_operation.#{InstrumentationNamespace}"
|
14
|
-
|
15
12
|
# Public: The name of the feature.
|
16
13
|
attr_reader :name
|
17
14
|
|
@@ -75,6 +72,13 @@ module Flipper
|
|
75
72
|
}
|
76
73
|
end
|
77
74
|
|
75
|
+
# Public: Removes this feature.
|
76
|
+
#
|
77
|
+
# Returns the result of Adapter#remove.
|
78
|
+
def remove
|
79
|
+
instrument(:remove) { adapter.remove(self) }
|
80
|
+
end
|
81
|
+
|
78
82
|
# Public: Check if a feature is enabled for a thing.
|
79
83
|
#
|
80
84
|
# Returns true if enabled, false if not.
|
@@ -85,9 +89,7 @@ module Flipper
|
|
85
89
|
payload[:thing] = gate(:actor).wrap(thing) unless thing.nil?
|
86
90
|
|
87
91
|
open_gate = gates.detect { |gate|
|
88
|
-
|
89
|
-
gate.open?(thing, values[gate.key], feature_name: @name)
|
90
|
-
}
|
92
|
+
gate.open?(thing, values[gate.key], feature_name: @name)
|
91
93
|
}
|
92
94
|
|
93
95
|
if open_gate.nil?
|
@@ -356,19 +358,5 @@ module Flipper
|
|
356
358
|
payload[:result] = yield(payload) if block_given?
|
357
359
|
}
|
358
360
|
end
|
359
|
-
|
360
|
-
# Private: Intrument a gate operation.
|
361
|
-
def instrument_gate(gate, operation, thing)
|
362
|
-
payload = {
|
363
|
-
:feature_name => @name,
|
364
|
-
:gate_name => gate.name,
|
365
|
-
:operation => operation,
|
366
|
-
:thing => thing,
|
367
|
-
}
|
368
|
-
|
369
|
-
@instrumenter.instrument(GateInstrumentationName, payload) { |payload|
|
370
|
-
payload[:result] = yield(payload) if block_given?
|
371
|
-
}
|
372
|
-
end
|
373
361
|
end
|
374
362
|
end
|
data/lib/flipper/gate.rb
CHANGED
data/lib/flipper/gate_values.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
+
require "set"
|
2
|
+
|
1
3
|
module Flipper
|
2
4
|
class GateValues
|
3
5
|
# Private: Array of instance variables that are readable through the []
|
4
6
|
# instance method.
|
5
|
-
LegitIvars = [
|
7
|
+
LegitIvars = Set.new([
|
6
8
|
"boolean",
|
7
9
|
"actors",
|
8
10
|
"groups",
|
9
11
|
"percentage_of_time",
|
10
12
|
"percentage_of_actors",
|
11
|
-
]
|
13
|
+
]).freeze
|
12
14
|
|
13
15
|
attr_reader :boolean
|
14
16
|
attr_reader :actors
|
data/lib/flipper/gates/actor.rb
CHANGED
data/lib/flipper/gates/group.rb
CHANGED
@@ -18,20 +18,18 @@ module Flipper
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def enabled?(value)
|
21
|
-
|
21
|
+
value > 0
|
22
22
|
end
|
23
23
|
|
24
24
|
# Internal: Checks if the gate is open for a thing.
|
25
25
|
#
|
26
26
|
# Returns true if gate open for thing, false if not.
|
27
27
|
def open?(thing, value, options = {})
|
28
|
-
feature_name = options.fetch(:feature_name)
|
29
|
-
percentage = Typecast.to_integer(value)
|
30
|
-
|
31
28
|
if Types::Actor.wrappable?(thing)
|
32
29
|
actor = Types::Actor.wrap(thing)
|
30
|
+
feature_name = options.fetch(:feature_name)
|
33
31
|
key = "#{feature_name}#{actor.value}"
|
34
|
-
Zlib.crc32(key) % 100 <
|
32
|
+
Zlib.crc32(key) % 100 < value
|
35
33
|
else
|
36
34
|
false
|
37
35
|
end
|
@@ -16,15 +16,14 @@ module Flipper
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def enabled?(value)
|
19
|
-
|
19
|
+
value > 0
|
20
20
|
end
|
21
21
|
|
22
22
|
# Internal: Checks if the gate is open for a thing.
|
23
23
|
#
|
24
24
|
# Returns true if gate open for thing, false if not.
|
25
25
|
def open?(thing, value, options = {})
|
26
|
-
|
27
|
-
rand < (percentage / 100.0)
|
26
|
+
rand < (value / 100.0)
|
28
27
|
end
|
29
28
|
|
30
29
|
def protects?(thing)
|
@@ -65,34 +65,6 @@ module Flipper
|
|
65
65
|
debug " #{color(name, CYAN, true)} [ #{details} ]"
|
66
66
|
end
|
67
67
|
|
68
|
-
# Logs a gate operation.
|
69
|
-
#
|
70
|
-
# Example Output
|
71
|
-
#
|
72
|
-
# flipper[:search].enabled?(user)
|
73
|
-
# # Flipper feature(search) gate(boolean) open false (0.1ms) [ thing=... ]
|
74
|
-
# # Flipper feature(search) gate(group) open false (0.1ms) [ thing=... ]
|
75
|
-
# # Flipper feature(search) gate(actor) open false (0.1ms) [ thing=... ]
|
76
|
-
# # Flipper feature(search) gate(percentage_of_actors) open false (0.1ms) [ thing=... ]
|
77
|
-
# # Flipper feature(search) gate(percentage_of_time) open false (0.1ms) [ thing=... ]
|
78
|
-
#
|
79
|
-
# Returns nothing.
|
80
|
-
def gate_operation(event)
|
81
|
-
return unless logger.debug?
|
82
|
-
|
83
|
-
feature_name = event.payload[:feature_name]
|
84
|
-
gate_name = event.payload[:gate_name]
|
85
|
-
operation = event.payload[:operation]
|
86
|
-
result = event.payload[:result]
|
87
|
-
thing = event.payload[:thing]
|
88
|
-
|
89
|
-
description = "Flipper feature(#{feature_name}) gate(#{gate_name}) #{operation} #{result.inspect}"
|
90
|
-
details = "thing=#{thing.inspect}"
|
91
|
-
|
92
|
-
name = '%s (%.1fms)' % [description, event.duration]
|
93
|
-
debug " #{color(name, CYAN, true)} [ #{details} ]"
|
94
|
-
end
|
95
|
-
|
96
68
|
def logger
|
97
69
|
self.class.logger
|
98
70
|
end
|
@@ -71,28 +71,6 @@ module Flipper
|
|
71
71
|
update_timer "flipper.adapter.#{adapter_name}.#{operation}"
|
72
72
|
end
|
73
73
|
|
74
|
-
# Private
|
75
|
-
def update_gate_operation_metrics
|
76
|
-
feature_name = @payload[:feature_name]
|
77
|
-
gate_name = @payload[:gate_name]
|
78
|
-
operation = strip_trailing_question_mark(@payload[:operation])
|
79
|
-
result = @payload[:result]
|
80
|
-
thing = @payload[:thing]
|
81
|
-
|
82
|
-
update_timer "flipper.gate_operation.#{gate_name}.#{operation}"
|
83
|
-
update_timer "flipper.feature.#{feature_name}.gate_operation.#{gate_name}.#{operation}"
|
84
|
-
|
85
|
-
if @payload[:operation] == :open?
|
86
|
-
metric_name = if result
|
87
|
-
"flipper.feature.#{feature_name}.gate.#{gate_name}.open"
|
88
|
-
else
|
89
|
-
"flipper.feature.#{feature_name}.gate.#{gate_name}.closed"
|
90
|
-
end
|
91
|
-
|
92
|
-
update_counter metric_name
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
74
|
# Private
|
97
75
|
def strip_trailing_question_mark(operation)
|
98
76
|
operation.to_s.chomp('?')
|
@@ -3,7 +3,7 @@ require 'rack/body_proxy'
|
|
3
3
|
module Flipper
|
4
4
|
module Middleware
|
5
5
|
class Memoizer
|
6
|
-
# Public: Initializes an instance of the
|
6
|
+
# Public: Initializes an instance of the Memoizer middleware.
|
7
7
|
#
|
8
8
|
# app - The app this middleware is included in.
|
9
9
|
# flipper_or_block - The Flipper::DSL instance or a block that yields a
|
@@ -11,9 +11,8 @@ module Flipper
|
|
11
11
|
#
|
12
12
|
# Examples
|
13
13
|
#
|
14
|
-
# flipper = Flipper.new(...)
|
15
|
-
#
|
16
14
|
# # using with a normal flipper instance
|
15
|
+
# flipper = Flipper.new(...)
|
17
16
|
# use Flipper::Middleware::Memoizer, flipper
|
18
17
|
#
|
19
18
|
# # using with a block that yields a flipper instance
|
@@ -121,6 +121,22 @@ shared_examples_for 'a flipper adapter' do
|
|
121
121
|
expect(result[:percentage_of_actors]).to eq('0')
|
122
122
|
end
|
123
123
|
|
124
|
+
it "can enable percentage of actors gate many times and consistently return values" do
|
125
|
+
(1..100).each do |percentage|
|
126
|
+
expect(subject.enable(feature, actors_gate, flipper.actors(percentage))).to eq(true)
|
127
|
+
result = subject.get(feature)
|
128
|
+
expect(result[:percentage_of_actors]).to eq(percentage.to_s)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it "can disable percentage of actors gate many times and consistently return values" do
|
133
|
+
(1..100).each do |percentage|
|
134
|
+
expect(subject.disable(feature, actors_gate, flipper.actors(percentage))).to eq(true)
|
135
|
+
result = subject.get(feature)
|
136
|
+
expect(result[:percentage_of_actors]).to eq(percentage.to_s)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
124
140
|
it "can enable, disable and get value for percentage of time gate" do
|
125
141
|
expect(subject.enable(feature, time_gate, flipper.time(10))).to eq(true)
|
126
142
|
result = subject.get(feature)
|
@@ -131,6 +147,22 @@ shared_examples_for 'a flipper adapter' do
|
|
131
147
|
expect(result[:percentage_of_time]).to eq('0')
|
132
148
|
end
|
133
149
|
|
150
|
+
it "can enable percentage of time gate many times and consistently return values" do
|
151
|
+
(1..100).each do |percentage|
|
152
|
+
expect(subject.enable(feature, time_gate, flipper.time(percentage))).to eq(true)
|
153
|
+
result = subject.get(feature)
|
154
|
+
expect(result[:percentage_of_time]).to eq(percentage.to_s)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
it "can disable percentage of time gate many times and consistently return values" do
|
159
|
+
(1..100).each do |percentage|
|
160
|
+
expect(subject.disable(feature, time_gate, flipper.time(percentage))).to eq(true)
|
161
|
+
result = subject.get(feature)
|
162
|
+
expect(result[:percentage_of_time]).to eq(percentage.to_s)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
134
166
|
it "converts boolean value to a string" do
|
135
167
|
expect(subject.enable(feature, boolean_gate, flipper.boolean)).to eq(true)
|
136
168
|
result = subject.get(feature)
|
@@ -0,0 +1,249 @@
|
|
1
|
+
module SharedAdapterTests
|
2
|
+
def setup
|
3
|
+
super
|
4
|
+
@flipper = Flipper.new(@adapter)
|
5
|
+
@actor_class = Struct.new(:flipper_id)
|
6
|
+
@feature = @flipper[:stats]
|
7
|
+
@boolean_gate = @feature.gate(:boolean)
|
8
|
+
@group_gate = @feature.gate(:group)
|
9
|
+
@actor_gate = @feature.gate(:actor)
|
10
|
+
@actors_gate = @feature.gate(:percentage_of_actors)
|
11
|
+
@time_gate = @feature.gate(:percentage_of_time)
|
12
|
+
|
13
|
+
Flipper.register(:admins) do |actor|
|
14
|
+
actor.respond_to?(:admin?) && actor.admin?
|
15
|
+
end
|
16
|
+
|
17
|
+
Flipper.register(:early_access) { |actor|
|
18
|
+
actor.respond_to?(:early_access?) && actor.early_access?
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown
|
23
|
+
super
|
24
|
+
Flipper.unregister_groups
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_has_name_that_is_a_symbol
|
28
|
+
refute_empty @adapter.name
|
29
|
+
assert_kind_of Symbol, @adapter.name
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_has_included_the_flipper_adapter_module
|
33
|
+
assert_includes @adapter.class.ancestors, Flipper::Adapter
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_returns_correct_default_values_for_gates_if_none_are_enabled
|
37
|
+
expected = {
|
38
|
+
:boolean => nil,
|
39
|
+
:groups => Set.new,
|
40
|
+
:actors => Set.new,
|
41
|
+
:percentage_of_actors => nil,
|
42
|
+
:percentage_of_time => nil,
|
43
|
+
}
|
44
|
+
assert_equal expected, @adapter.get(@feature)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_can_enable_disable_and_get_value_for_boolean_gate
|
48
|
+
assert_equal true, @adapter.enable(@feature, @boolean_gate, @flipper.boolean)
|
49
|
+
assert_equal 'true', @adapter.get(@feature)[:boolean]
|
50
|
+
assert_equal true, @adapter.disable(@feature, @boolean_gate, @flipper.boolean(false))
|
51
|
+
assert_equal nil, @adapter.get(@feature)[:boolean]
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_fully_disables_all_enabled_things_when_boolean_gate_disabled
|
55
|
+
actor_22 = @actor_class.new('22')
|
56
|
+
assert_equal true, @adapter.enable(@feature, @boolean_gate, @flipper.boolean)
|
57
|
+
assert_equal true, @adapter.enable(@feature, @group_gate, @flipper.group(:admins))
|
58
|
+
assert_equal true, @adapter.enable(@feature, @actor_gate, @flipper.actor(actor_22))
|
59
|
+
assert_equal true, @adapter.enable(@feature, @actors_gate, @flipper.actors(25))
|
60
|
+
assert_equal true, @adapter.enable(@feature, @time_gate, @flipper.time(45))
|
61
|
+
assert_equal true, @adapter.disable(@feature, @boolean_gate, @flipper.boolean(false))
|
62
|
+
expected = {
|
63
|
+
:boolean => nil,
|
64
|
+
:groups => Set.new,
|
65
|
+
:actors => Set.new,
|
66
|
+
:percentage_of_actors => nil,
|
67
|
+
:percentage_of_time => nil,
|
68
|
+
}
|
69
|
+
assert_equal expected, @adapter.get(@feature)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_can_enable_disable_get_value_for_group_gate
|
73
|
+
assert_equal true, @adapter.enable(@feature, @group_gate, @flipper.group(:admins))
|
74
|
+
assert_equal true, @adapter.enable(@feature, @group_gate, @flipper.group(:early_access))
|
75
|
+
|
76
|
+
result = @adapter.get(@feature)
|
77
|
+
assert_equal Set['admins', 'early_access'], result[:groups]
|
78
|
+
|
79
|
+
assert_equal true, @adapter.disable(@feature, @group_gate, @flipper.group(:early_access))
|
80
|
+
result = @adapter.get(@feature)
|
81
|
+
assert_equal Set['admins'], result[:groups]
|
82
|
+
|
83
|
+
assert_equal true, @adapter.disable(@feature, @group_gate, @flipper.group(:admins))
|
84
|
+
result = @adapter.get(@feature)
|
85
|
+
assert_equal Set.new, result[:groups]
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_can_enable_disable_and_get_value_for_an_actor_gate
|
89
|
+
actor_22 = @actor_class.new('22')
|
90
|
+
actor_asdf = @actor_class.new('asdf')
|
91
|
+
|
92
|
+
assert_equal true, @adapter.enable(@feature, @actor_gate, @flipper.actor(actor_22))
|
93
|
+
assert_equal true, @adapter.enable(@feature, @actor_gate, @flipper.actor(actor_asdf))
|
94
|
+
|
95
|
+
result = @adapter.get(@feature)
|
96
|
+
assert_equal Set['22', 'asdf'], result[:actors]
|
97
|
+
|
98
|
+
assert true, @adapter.disable(@feature, @actor_gate, @flipper.actor(actor_22))
|
99
|
+
result = @adapter.get(@feature)
|
100
|
+
assert_equal Set['asdf'], result[:actors]
|
101
|
+
|
102
|
+
assert_equal true, @adapter.disable(@feature, @actor_gate, @flipper.actor(actor_asdf))
|
103
|
+
result = @adapter.get(@feature)
|
104
|
+
assert_equal Set.new, result[:actors]
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_can_enable_disable_get_value_for_percentage_of_actors_gate
|
108
|
+
assert_equal true, @adapter.enable(@feature, @actors_gate, @flipper.actors(15))
|
109
|
+
result = @adapter.get(@feature)
|
110
|
+
assert_equal '15', result[:percentage_of_actors]
|
111
|
+
|
112
|
+
assert_equal true, @adapter.disable(@feature, @actors_gate, @flipper.actors(0))
|
113
|
+
result = @adapter.get(@feature)
|
114
|
+
assert_equal '0', result[:percentage_of_actors]
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_can_enable_percentage_of_actors_gate_many_times_and_consistently_return_values
|
118
|
+
(1..100).each do |percentage|
|
119
|
+
assert_equal true, @adapter.enable(@feature, @actors_gate, @flipper.actors(percentage))
|
120
|
+
result = @adapter.get(@feature)
|
121
|
+
assert_equal percentage.to_s, result[:percentage_of_actors]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_can_disable_percentage_of_actors_gate_many_times_and_consistently_return_values
|
126
|
+
(1..100).each do |percentage|
|
127
|
+
assert_equal true, @adapter.disable(@feature, @actors_gate, @flipper.actors(percentage))
|
128
|
+
result = @adapter.get(@feature)
|
129
|
+
assert_equal percentage.to_s, result[:percentage_of_actors]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def test_can_enable_disable_and_get_value_for_percentage_of_time_gate
|
134
|
+
assert_equal true, @adapter.enable(@feature, @time_gate, @flipper.time(10))
|
135
|
+
result = @adapter.get(@feature)
|
136
|
+
assert_equal '10', result[:percentage_of_time]
|
137
|
+
|
138
|
+
assert_equal true, @adapter.disable(@feature, @time_gate, @flipper.time(0))
|
139
|
+
result = @adapter.get(@feature)
|
140
|
+
assert_equal '0', result[:percentage_of_time]
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_can_enable_percentage_of_time_gate_many_times_and_consistently_return_values
|
144
|
+
(1..100).each do |percentage|
|
145
|
+
assert_equal true, @adapter.enable(@feature, @time_gate, @flipper.time(percentage))
|
146
|
+
result = @adapter.get(@feature)
|
147
|
+
assert_equal percentage.to_s, result[:percentage_of_time]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_can_disable_percentage_of_time_gate_many_times_and_consistently_return_values
|
152
|
+
(1..100).each do |percentage|
|
153
|
+
assert_equal true, @adapter.disable(@feature, @time_gate, @flipper.time(percentage))
|
154
|
+
result = @adapter.get(@feature)
|
155
|
+
assert_equal percentage.to_s, result[:percentage_of_time]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_converts_boolean_value_to_a_string
|
160
|
+
assert_equal true, @adapter.enable(@feature, @boolean_gate, @flipper.boolean)
|
161
|
+
result = @adapter.get(@feature)
|
162
|
+
assert_equal 'true', result[:boolean]
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_converts_the_actor_value_to_a_string
|
166
|
+
assert_equal true, @adapter.enable(@feature, @actor_gate, @flipper.actor(@actor_class.new(22)))
|
167
|
+
result = @adapter.get(@feature)
|
168
|
+
assert_equal Set['22'], result[:actors]
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_converts_group_value_to_a_string
|
172
|
+
assert_equal true, @adapter.enable(@feature, @group_gate, @flipper.group(:admins))
|
173
|
+
result = @adapter.get(@feature)
|
174
|
+
assert_equal Set['admins'], result[:groups]
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_converts_percentage_of_time_integer_value_to_a_string
|
178
|
+
assert_equal true, @adapter.enable(@feature, @time_gate, @flipper.time(10))
|
179
|
+
result = @adapter.get(@feature)
|
180
|
+
assert_equal '10', result[:percentage_of_time]
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_converts_percentage_of_actors_integer_value_to_a_string
|
184
|
+
assert_equal true, @adapter.enable(@feature, @actors_gate, @flipper.actors(10))
|
185
|
+
result = @adapter.get(@feature)
|
186
|
+
assert_equal '10', result[:percentage_of_actors]
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_can_add_remove_and_list_known_features
|
190
|
+
assert_equal Set.new, @adapter.features
|
191
|
+
|
192
|
+
assert_equal true, @adapter.add(@flipper[:stats])
|
193
|
+
assert_equal Set['stats'], @adapter.features
|
194
|
+
|
195
|
+
assert_equal true, @adapter.add(@flipper[:search])
|
196
|
+
assert_equal Set['stats', 'search'], @adapter.features
|
197
|
+
|
198
|
+
assert_equal true, @adapter.remove(@flipper[:stats])
|
199
|
+
assert_equal Set['search'], @adapter.features
|
200
|
+
|
201
|
+
assert_equal true, @adapter.remove(@flipper[:search])
|
202
|
+
assert_equal Set.new, @adapter.features
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_clears_all_the_gate_values_for_the_feature_on_remove
|
206
|
+
actor_22 = @actor_class.new('22')
|
207
|
+
assert_equal true, @adapter.enable(@feature, @boolean_gate, @flipper.boolean)
|
208
|
+
assert_equal true, @adapter.enable(@feature, @group_gate, @flipper.group(:admins))
|
209
|
+
assert_equal true, @adapter.enable(@feature, @actor_gate, @flipper.actor(actor_22))
|
210
|
+
assert_equal true, @adapter.enable(@feature, @actors_gate, @flipper.actors(25))
|
211
|
+
assert_equal true, @adapter.enable(@feature, @time_gate, @flipper.time(45))
|
212
|
+
|
213
|
+
assert_equal true, @adapter.remove(@feature)
|
214
|
+
|
215
|
+
assert_equal @adapter.get(@feature), {
|
216
|
+
:boolean => nil,
|
217
|
+
:groups => Set.new,
|
218
|
+
:actors => Set.new,
|
219
|
+
:percentage_of_actors => nil,
|
220
|
+
:percentage_of_time => nil,
|
221
|
+
}
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_can_clear_all_the_gate_values_for_a_feature
|
225
|
+
actor_22 = @actor_class.new('22')
|
226
|
+
@adapter.add(@feature)
|
227
|
+
assert_includes @adapter.features, @feature.key
|
228
|
+
|
229
|
+
assert_equal true, @adapter.enable(@feature, @boolean_gate, @flipper.boolean)
|
230
|
+
assert_equal true, @adapter.enable(@feature, @group_gate, @flipper.group(:admins))
|
231
|
+
assert_equal true, @adapter.enable(@feature, @actor_gate, @flipper.actor(actor_22))
|
232
|
+
assert_equal true, @adapter.enable(@feature, @actors_gate, @flipper.actors(25))
|
233
|
+
assert_equal true, @adapter.enable(@feature, @time_gate, @flipper.time(45))
|
234
|
+
|
235
|
+
assert_equal true, @adapter.clear(@feature)
|
236
|
+
assert_includes @adapter.features, @feature.key
|
237
|
+
assert_equal @adapter.get(@feature), {
|
238
|
+
:boolean => nil,
|
239
|
+
:groups => Set.new,
|
240
|
+
:actors => Set.new,
|
241
|
+
:percentage_of_actors => nil,
|
242
|
+
:percentage_of_time => nil,
|
243
|
+
}
|
244
|
+
end
|
245
|
+
|
246
|
+
def test_does_not_complain_clearing_a_feature_that_does_not_exist_in_adapter
|
247
|
+
assert_equal true, @adapter.clear(@flipper[:stats])
|
248
|
+
end
|
249
|
+
end
|