flipper 0.7.5 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|