flipper 0.22.0 → 0.28.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/.codeclimate.yml +1 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/ci.yml +26 -20
- data/.github/workflows/examples.yml +62 -0
- data/.rspec +1 -0
- data/.tool-versions +1 -0
- data/Changelog.md +152 -3
- data/Dockerfile +1 -1
- data/Gemfile +9 -6
- data/README.md +15 -67
- data/Rakefile +4 -2
- data/benchmark/enabled_ips.rb +10 -0
- data/benchmark/enabled_multiple_actors_ips.rb +20 -0
- data/benchmark/enabled_profile.rb +20 -0
- data/benchmark/instrumentation_ips.rb +21 -0
- data/benchmark/typecast_ips.rb +19 -0
- data/docker-compose.yml +37 -34
- data/docs/README.md +1 -0
- data/docs/images/banner.jpg +0 -0
- data/examples/api/basic.ru +3 -4
- data/examples/api/custom_memoized.ru +3 -4
- data/examples/api/memoized.ru +3 -4
- data/examples/dsl.rb +3 -3
- data/examples/enabled_for_actor.rb +4 -2
- data/examples/instrumentation.rb +1 -0
- data/examples/instrumentation_last_accessed_at.rb +38 -0
- data/flipper.gemspec +2 -2
- data/lib/flipper/actor.rb +4 -0
- data/lib/flipper/adapter.rb +23 -7
- data/lib/flipper/adapters/dual_write.rb +10 -16
- data/lib/flipper/adapters/failover.rb +83 -0
- data/lib/flipper/adapters/failsafe.rb +76 -0
- data/lib/flipper/adapters/http/client.rb +18 -12
- data/lib/flipper/adapters/http/error.rb +19 -1
- data/lib/flipper/adapters/http.rb +14 -4
- data/lib/flipper/adapters/instrumented.rb +25 -2
- data/lib/flipper/adapters/memoizable.rb +27 -18
- data/lib/flipper/adapters/memory.rb +56 -39
- data/lib/flipper/adapters/operation_logger.rb +16 -3
- data/lib/flipper/adapters/poll/poller.rb +2 -0
- data/lib/flipper/adapters/poll.rb +39 -0
- data/lib/flipper/adapters/pstore.rb +2 -5
- data/lib/flipper/adapters/sync/interval_synchronizer.rb +1 -6
- data/lib/flipper/adapters/sync/synchronizer.rb +2 -1
- data/lib/flipper/adapters/sync.rb +9 -15
- data/lib/flipper/dsl.rb +9 -11
- data/lib/flipper/errors.rb +3 -20
- data/lib/flipper/export.rb +26 -0
- data/lib/flipper/exporter.rb +17 -0
- data/lib/flipper/exporters/json/export.rb +32 -0
- data/lib/flipper/exporters/json/v1.rb +33 -0
- data/lib/flipper/feature.rb +32 -26
- data/lib/flipper/feature_check_context.rb +10 -6
- data/lib/flipper/gate.rb +12 -11
- data/lib/flipper/gate_values.rb +0 -16
- data/lib/flipper/gates/actor.rb +10 -17
- data/lib/flipper/gates/boolean.rb +1 -1
- data/lib/flipper/gates/group.rb +5 -7
- data/lib/flipper/gates/percentage_of_actors.rb +10 -13
- data/lib/flipper/gates/percentage_of_time.rb +1 -2
- data/lib/flipper/identifier.rb +2 -2
- data/lib/flipper/instrumentation/log_subscriber.rb +7 -3
- data/lib/flipper/instrumentation/subscriber.rb +8 -1
- data/lib/flipper/instrumenters/memory.rb +6 -2
- data/lib/flipper/metadata.rb +1 -1
- data/lib/flipper/middleware/memoizer.rb +2 -12
- data/lib/flipper/poller.rb +117 -0
- data/lib/flipper/railtie.rb +23 -22
- data/lib/flipper/spec/shared_adapter_specs.rb +23 -0
- data/lib/flipper/test/shared_adapter_test.rb +24 -0
- data/lib/flipper/typecast.rb +28 -15
- data/lib/flipper/types/actor.rb +19 -13
- data/lib/flipper/types/group.rb +12 -5
- data/lib/flipper/version.rb +1 -1
- data/lib/flipper.rb +6 -4
- data/spec/fixtures/flipper_pstore_1679087600.json +46 -0
- data/spec/flipper/actor_spec.rb +10 -2
- data/spec/flipper/adapter_spec.rb +29 -4
- data/spec/flipper/adapters/dual_write_spec.rb +0 -2
- data/spec/flipper/adapters/failover_spec.rb +129 -0
- data/spec/flipper/adapters/failsafe_spec.rb +58 -0
- data/spec/flipper/adapters/http_spec.rb +64 -6
- data/spec/flipper/adapters/instrumented_spec.rb +28 -12
- data/spec/flipper/adapters/memoizable_spec.rb +30 -12
- data/spec/flipper/adapters/memory_spec.rb +3 -4
- data/spec/flipper/adapters/operation_logger_spec.rb +29 -12
- data/spec/flipper/adapters/pstore_spec.rb +0 -2
- data/spec/flipper/adapters/read_only_spec.rb +0 -1
- data/spec/flipper/adapters/sync/feature_synchronizer_spec.rb +0 -1
- data/spec/flipper/adapters/sync/interval_synchronizer_spec.rb +4 -5
- data/spec/flipper/adapters/sync/synchronizer_spec.rb +0 -1
- data/spec/flipper/adapters/sync_spec.rb +0 -2
- data/spec/flipper/configuration_spec.rb +0 -1
- data/spec/flipper/dsl_spec.rb +38 -12
- data/spec/flipper/export_spec.rb +13 -0
- data/spec/flipper/exporter_spec.rb +16 -0
- data/spec/flipper/exporters/json/export_spec.rb +60 -0
- data/spec/flipper/exporters/json/v1_spec.rb +33 -0
- data/spec/flipper/feature_check_context_spec.rb +17 -19
- data/spec/flipper/feature_spec.rb +76 -33
- data/spec/flipper/gate_spec.rb +0 -2
- data/spec/flipper/gate_values_spec.rb +2 -34
- data/spec/flipper/gates/actor_spec.rb +0 -2
- data/spec/flipper/gates/boolean_spec.rb +1 -3
- data/spec/flipper/gates/group_spec.rb +2 -5
- data/spec/flipper/gates/percentage_of_actors_spec.rb +61 -7
- data/spec/flipper/gates/percentage_of_time_spec.rb +2 -4
- data/spec/flipper/identifier_spec.rb +0 -1
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +15 -6
- data/spec/flipper/instrumentation/statsd_subscriber_spec.rb +10 -1
- data/spec/flipper/instrumenters/memory_spec.rb +18 -1
- data/spec/flipper/instrumenters/noop_spec.rb +14 -8
- data/spec/flipper/middleware/memoizer_spec.rb +0 -23
- data/spec/flipper/middleware/setup_env_spec.rb +0 -2
- data/spec/flipper/poller_spec.rb +47 -0
- data/spec/flipper/railtie_spec.rb +73 -33
- data/spec/flipper/registry_spec.rb +0 -1
- data/spec/flipper/typecast_spec.rb +82 -4
- data/spec/flipper/types/actor_spec.rb +45 -46
- data/spec/flipper/types/boolean_spec.rb +0 -1
- data/spec/flipper/types/group_spec.rb +2 -3
- data/spec/flipper/types/percentage_of_actors_spec.rb +0 -1
- data/spec/flipper/types/percentage_of_time_spec.rb +0 -1
- data/spec/flipper/types/percentage_spec.rb +0 -1
- data/spec/flipper_integration_spec.rb +62 -51
- data/spec/flipper_spec.rb +7 -2
- data/spec/{helper.rb → spec_helper.rb} +4 -2
- data/spec/support/skippable.rb +18 -0
- data/spec/support/spec_helpers.rb +2 -6
- metadata +63 -19
- data/docs/Adapters.md +0 -124
- data/docs/Caveats.md +0 -4
- data/docs/Gates.md +0 -167
- data/docs/Instrumentation.md +0 -27
- data/docs/Optimization.md +0 -137
- data/docs/api/README.md +0 -884
- data/docs/http/README.md +0 -36
- data/docs/read-only/README.md +0 -24
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require "flipper/poller"
|
|
2
|
+
|
|
3
|
+
RSpec.describe Flipper::Poller do
|
|
4
|
+
let(:remote_adapter) { Flipper::Adapters::Memory.new }
|
|
5
|
+
let(:remote) { Flipper.new(remote_adapter) }
|
|
6
|
+
let(:local) { Flipper.new(subject.adapter) }
|
|
7
|
+
|
|
8
|
+
subject do
|
|
9
|
+
described_class.new(
|
|
10
|
+
remote_adapter: remote_adapter,
|
|
11
|
+
start_automatically: false,
|
|
12
|
+
interval: Float::INFINITY
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
before do
|
|
17
|
+
allow(subject).to receive(:loop).and_yield # Make loop just call once
|
|
18
|
+
allow(subject).to receive(:sleep) # Disable sleep
|
|
19
|
+
allow(Thread).to receive(:new).and_yield # Disable separate thread
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "#adapter" do
|
|
23
|
+
it "always returns same memory adapter instance" do
|
|
24
|
+
expect(subject.adapter).to be_a(Flipper::Adapters::Memory)
|
|
25
|
+
expect(subject.adapter.object_id).to eq(subject.adapter.object_id)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "#sync" do
|
|
30
|
+
it "syncs remote adapter to local adapter" do
|
|
31
|
+
remote.enable :polling
|
|
32
|
+
|
|
33
|
+
expect(local.enabled?(:polling)).to be(false)
|
|
34
|
+
subject.sync
|
|
35
|
+
expect(local.enabled?(:polling)).to be(true)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe "#start" do
|
|
40
|
+
it "starts the poller thread" do
|
|
41
|
+
expect(Thread).to receive(:new).and_yield
|
|
42
|
+
expect(subject).to receive(:loop).and_yield
|
|
43
|
+
expect(subject).to receive(:sync)
|
|
44
|
+
subject.start
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -1,63 +1,96 @@
|
|
|
1
|
-
require 'helper'
|
|
2
1
|
require 'rails'
|
|
3
2
|
require 'flipper/railtie'
|
|
4
3
|
|
|
5
4
|
RSpec.describe Flipper::Railtie do
|
|
6
5
|
let(:application) do
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
)
|
|
11
|
-
app.config.eager_load = false
|
|
12
|
-
app.config.logger = ActiveSupport::Logger.new($stdout)
|
|
13
|
-
app.run_load_hooks!
|
|
6
|
+
Class.new(Rails::Application).create(railties: [Flipper::Railtie]) do
|
|
7
|
+
config.eager_load = false
|
|
8
|
+
end
|
|
14
9
|
end
|
|
15
10
|
|
|
16
11
|
before do
|
|
17
|
-
|
|
12
|
+
ActiveSupport::Dependencies.autoload_paths = ActiveSupport::Dependencies.autoload_paths.dup
|
|
13
|
+
ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_once_paths.dup
|
|
18
14
|
end
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
end
|
|
16
|
+
let(:config) { application.config.flipper }
|
|
17
|
+
|
|
18
|
+
subject { application.initialize! }
|
|
24
19
|
|
|
25
20
|
describe 'initializers' do
|
|
26
|
-
it '
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
it 'can set env_key from ENV' do
|
|
22
|
+
ENV['FLIPPER_ENV_KEY'] = 'flopper'
|
|
23
|
+
|
|
24
|
+
subject
|
|
25
|
+
expect(config.env_key).to eq('flopper')
|
|
30
26
|
end
|
|
31
27
|
|
|
32
|
-
it
|
|
28
|
+
it 'can set memoize from ENV' do
|
|
29
|
+
ENV['FLIPPER_MEMOIZE'] = 'false'
|
|
30
|
+
|
|
33
31
|
subject
|
|
32
|
+
expect(config.memoize).to eq(false)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'can set preload from ENV' do
|
|
36
|
+
ENV['FLIPPER_PRELOAD'] = 'false'
|
|
37
|
+
|
|
38
|
+
subject
|
|
39
|
+
expect(config.preload).to eq(false)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'can set instrumenter from ENV' do
|
|
43
|
+
stub_const('My::Cool::Instrumenter', Class.new)
|
|
44
|
+
ENV['FLIPPER_INSTRUMENTER'] = 'My::Cool::Instrumenter'
|
|
45
|
+
|
|
46
|
+
subject
|
|
47
|
+
expect(config.instrumenter).to eq(My::Cool::Instrumenter)
|
|
48
|
+
end
|
|
34
49
|
|
|
50
|
+
it 'can set log from ENV' do
|
|
51
|
+
ENV['FLIPPER_LOG'] = 'false'
|
|
52
|
+
|
|
53
|
+
subject
|
|
54
|
+
expect(config.log).to eq(false)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'sets defaults' do
|
|
58
|
+
subject # initialize
|
|
59
|
+
expect(config.env_key).to eq("flipper")
|
|
60
|
+
expect(config.memoize).to be(true)
|
|
61
|
+
expect(config.preload).to be(true)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "configures instrumentor on default instance" do
|
|
65
|
+
subject # initialize
|
|
35
66
|
expect(Flipper.instance.instrumenter).to eq(ActiveSupport::Notifications)
|
|
36
67
|
end
|
|
37
68
|
|
|
38
69
|
it 'uses Memoizer middleware if config.memoize = true' do
|
|
39
|
-
|
|
70
|
+
initializer { config.memoize = true }
|
|
71
|
+
expect(subject.middleware).to include(Flipper::Middleware::Memoizer)
|
|
40
72
|
end
|
|
41
73
|
|
|
42
74
|
it 'does not use Memoizer middleware if config.memoize = false' do
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
expect(subject.middleware.last).not_to eq(Flipper::Middleware::Memoizer)
|
|
75
|
+
initializer { config.memoize = false }
|
|
76
|
+
expect(subject.middleware).not_to include(Flipper::Middleware::Memoizer)
|
|
47
77
|
end
|
|
48
78
|
|
|
49
79
|
it 'passes config to memoizer' do
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
expect(Flipper::Middleware::Memoizer).to receive(:new).with(application.routes,
|
|
57
|
-
env_key: 'my_flipper', preload: [:stats, :search], if: nil
|
|
58
|
-
)
|
|
80
|
+
initializer do
|
|
81
|
+
config.update(
|
|
82
|
+
env_key: 'my_flipper',
|
|
83
|
+
preload: [:stats, :search]
|
|
84
|
+
)
|
|
85
|
+
end
|
|
59
86
|
|
|
60
|
-
subject
|
|
87
|
+
expect(subject.middleware).to include(Flipper::Middleware::Memoizer)
|
|
88
|
+
middleware = subject.middleware.detect { |m| m.klass == Flipper::Middleware::Memoizer }
|
|
89
|
+
expect(middleware.args[0]).to eq({
|
|
90
|
+
env_key: config.env_key,
|
|
91
|
+
preload: config.preload,
|
|
92
|
+
if: nil
|
|
93
|
+
})
|
|
61
94
|
end
|
|
62
95
|
|
|
63
96
|
it "defines #flipper_id on AR::Base" do
|
|
@@ -66,4 +99,11 @@ RSpec.describe Flipper::Railtie do
|
|
|
66
99
|
expect(ActiveRecord::Base.ancestors).to include(Flipper::Identifier)
|
|
67
100
|
end
|
|
68
101
|
end
|
|
102
|
+
|
|
103
|
+
# Add app initializer in the same order as config/initializers/*
|
|
104
|
+
def initializer(&block)
|
|
105
|
+
application.initializer 'spec', before: :load_config_initializers do
|
|
106
|
+
block.call
|
|
107
|
+
end
|
|
108
|
+
end
|
|
69
109
|
end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require 'helper'
|
|
2
1
|
require 'flipper/typecast'
|
|
3
2
|
|
|
4
3
|
RSpec.describe Flipper::Typecast do
|
|
@@ -57,7 +56,7 @@ RSpec.describe Flipper::Typecast do
|
|
|
57
56
|
nil => 0,
|
|
58
57
|
'' => 0,
|
|
59
58
|
0 => 0,
|
|
60
|
-
0.0 => 0
|
|
59
|
+
0.0 => 0,
|
|
61
60
|
1 => 1,
|
|
62
61
|
1.1 => 1.1,
|
|
63
62
|
'0.01' => 0.01,
|
|
@@ -101,13 +100,13 @@ RSpec.describe Flipper::Typecast do
|
|
|
101
100
|
it 'raises argument error for bad integer percentage' do
|
|
102
101
|
expect do
|
|
103
102
|
described_class.to_percentage(['asdf'])
|
|
104
|
-
end.to raise_error(ArgumentError, %(["asdf"] cannot be converted to
|
|
103
|
+
end.to raise_error(ArgumentError, %(["asdf"] cannot be converted to a percentage))
|
|
105
104
|
end
|
|
106
105
|
|
|
107
106
|
it 'raises argument error for bad float percentage' do
|
|
108
107
|
expect do
|
|
109
108
|
described_class.to_percentage(['asdf.0'])
|
|
110
|
-
end.to raise_error(ArgumentError, %(["asdf.0"] cannot be converted to a
|
|
109
|
+
end.to raise_error(ArgumentError, %(["asdf.0"] cannot be converted to a percentage))
|
|
111
110
|
end
|
|
112
111
|
|
|
113
112
|
it 'raises argument error for set value that cannot be converted to a set' do
|
|
@@ -115,4 +114,83 @@ RSpec.describe Flipper::Typecast do
|
|
|
115
114
|
described_class.to_set('asdf')
|
|
116
115
|
end.to raise_error(ArgumentError, %("asdf" cannot be converted to a set))
|
|
117
116
|
end
|
|
117
|
+
|
|
118
|
+
describe "#features_hash" do
|
|
119
|
+
it "returns new hash" do
|
|
120
|
+
hash = {
|
|
121
|
+
"search" => {
|
|
122
|
+
boolean: nil,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
result = described_class.features_hash(hash)
|
|
126
|
+
expect(result).not_to be(hash)
|
|
127
|
+
expect(result["search"]).not_to be(hash["search"])
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "converts gate value arrays to sets" do
|
|
131
|
+
hash = {
|
|
132
|
+
"search" => {
|
|
133
|
+
boolean: nil,
|
|
134
|
+
groups: ['a', 'b'],
|
|
135
|
+
actors: ['User;1'],
|
|
136
|
+
percentage_of_actors: nil,
|
|
137
|
+
percentage_of_time: nil,
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
result = described_class.features_hash(hash)
|
|
141
|
+
expect(result).to eq({
|
|
142
|
+
"search" => {
|
|
143
|
+
boolean: nil,
|
|
144
|
+
groups: Set['a', 'b'],
|
|
145
|
+
actors: Set['User;1'],
|
|
146
|
+
percentage_of_actors: nil,
|
|
147
|
+
percentage_of_time: nil,
|
|
148
|
+
},
|
|
149
|
+
})
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "converts gate value boolean and integers to strings" do
|
|
153
|
+
hash = {
|
|
154
|
+
"search" => {
|
|
155
|
+
boolean: true,
|
|
156
|
+
groups: Set.new,
|
|
157
|
+
actors: Set.new,
|
|
158
|
+
percentage_of_actors: 10,
|
|
159
|
+
percentage_of_time: 15,
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
result = described_class.features_hash(hash)
|
|
163
|
+
expect(result).to eq({
|
|
164
|
+
"search" => {
|
|
165
|
+
boolean: "true",
|
|
166
|
+
groups: Set.new,
|
|
167
|
+
actors: Set.new,
|
|
168
|
+
percentage_of_actors: "10",
|
|
169
|
+
percentage_of_time: "15",
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "converts string gate keys to symbols" do
|
|
175
|
+
hash = {
|
|
176
|
+
"search" => {
|
|
177
|
+
"boolean" => nil,
|
|
178
|
+
"groups" => Set.new,
|
|
179
|
+
"actors" => Set.new,
|
|
180
|
+
"percentage_of_actors" => nil,
|
|
181
|
+
"percentage_of_time" => nil,
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
result = described_class.features_hash(hash)
|
|
185
|
+
expect(result).to eq({
|
|
186
|
+
"search" => {
|
|
187
|
+
boolean: nil,
|
|
188
|
+
groups: Set.new,
|
|
189
|
+
actors: Set.new,
|
|
190
|
+
percentage_of_actors: nil,
|
|
191
|
+
percentage_of_time: nil,
|
|
192
|
+
},
|
|
193
|
+
})
|
|
194
|
+
end
|
|
195
|
+
end
|
|
118
196
|
end
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
require 'helper'
|
|
2
1
|
require 'flipper/types/actor'
|
|
3
2
|
|
|
4
3
|
RSpec.describe Flipper::Types::Actor do
|
|
5
4
|
subject do
|
|
6
|
-
|
|
7
|
-
described_class.new(
|
|
5
|
+
actor = actor_class.new('2')
|
|
6
|
+
described_class.new(actor)
|
|
8
7
|
end
|
|
9
8
|
|
|
10
|
-
let(:
|
|
9
|
+
let(:actor_class) do
|
|
11
10
|
Class.new do
|
|
12
11
|
attr_reader :flipper_id
|
|
13
12
|
|
|
@@ -23,14 +22,14 @@ RSpec.describe Flipper::Types::Actor do
|
|
|
23
22
|
|
|
24
23
|
describe '.wrappable?' do
|
|
25
24
|
it 'returns true if actor' do
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
expect(described_class.wrappable?(
|
|
25
|
+
actor = actor_class.new('1')
|
|
26
|
+
actor_type_instance = described_class.new(actor)
|
|
27
|
+
expect(described_class.wrappable?(actor_type_instance)).to eq(true)
|
|
29
28
|
end
|
|
30
29
|
|
|
31
30
|
it 'returns true if responds to flipper_id' do
|
|
32
|
-
|
|
33
|
-
expect(described_class.wrappable?(
|
|
31
|
+
actor = actor_class.new(10)
|
|
32
|
+
expect(described_class.wrappable?(actor)).to eq(true)
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
it 'returns false if nil' do
|
|
@@ -39,27 +38,27 @@ RSpec.describe Flipper::Types::Actor do
|
|
|
39
38
|
end
|
|
40
39
|
|
|
41
40
|
describe '.wrap' do
|
|
42
|
-
context 'for actor' do
|
|
43
|
-
it 'returns actor' do
|
|
44
|
-
|
|
45
|
-
expect(
|
|
46
|
-
expect(
|
|
41
|
+
context 'for actor type instance' do
|
|
42
|
+
it 'returns actor type instance' do
|
|
43
|
+
actor_type_instance = described_class.wrap(subject)
|
|
44
|
+
expect(actor_type_instance).to be_instance_of(described_class)
|
|
45
|
+
expect(actor_type_instance).to be(subject)
|
|
47
46
|
end
|
|
48
47
|
end
|
|
49
48
|
|
|
50
|
-
context 'for other
|
|
51
|
-
it 'returns actor' do
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
expect(
|
|
49
|
+
context 'for other object' do
|
|
50
|
+
it 'returns actor type instance' do
|
|
51
|
+
actor = actor_class.new('1')
|
|
52
|
+
actor_type_instance = described_class.wrap(actor)
|
|
53
|
+
expect(actor_type_instance).to be_instance_of(described_class)
|
|
55
54
|
end
|
|
56
55
|
end
|
|
57
56
|
end
|
|
58
57
|
|
|
59
|
-
it 'initializes with
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
expect(
|
|
58
|
+
it 'initializes with object that responds to flipper_id' do
|
|
59
|
+
actor = actor_class.new('1')
|
|
60
|
+
actor_type_instance = described_class.new(actor)
|
|
61
|
+
expect(actor_type_instance.value).to eq('1')
|
|
63
62
|
end
|
|
64
63
|
|
|
65
64
|
it 'raises error when initialized with nil' do
|
|
@@ -69,48 +68,48 @@ RSpec.describe Flipper::Types::Actor do
|
|
|
69
68
|
end
|
|
70
69
|
|
|
71
70
|
it 'raises error when initalized with non-wrappable object' do
|
|
72
|
-
|
|
71
|
+
unwrappable_object = Struct.new(:id).new(1)
|
|
73
72
|
expect do
|
|
74
|
-
described_class.new(
|
|
73
|
+
described_class.new(unwrappable_object)
|
|
75
74
|
end.to raise_error(ArgumentError,
|
|
76
|
-
"#{
|
|
75
|
+
"#{unwrappable_object.inspect} must respond to flipper_id, but does not")
|
|
77
76
|
end
|
|
78
77
|
|
|
79
78
|
it 'converts id to string' do
|
|
80
|
-
|
|
81
|
-
actor = described_class.new(
|
|
79
|
+
actor = actor_class.new(2)
|
|
80
|
+
actor = described_class.new(actor)
|
|
82
81
|
expect(actor.value).to eq('2')
|
|
83
82
|
end
|
|
84
83
|
|
|
85
|
-
it 'proxies everything to
|
|
86
|
-
|
|
87
|
-
actor = described_class.new(
|
|
84
|
+
it 'proxies everything to actor' do
|
|
85
|
+
actor = actor_class.new(10)
|
|
86
|
+
actor = described_class.new(actor)
|
|
88
87
|
expect(actor.admin?).to eq(true)
|
|
89
88
|
end
|
|
90
89
|
|
|
91
|
-
it 'exposes
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
expect(actor
|
|
90
|
+
it 'exposes actor' do
|
|
91
|
+
actor = actor_class.new(10)
|
|
92
|
+
actor_type_instance = described_class.new(actor)
|
|
93
|
+
expect(actor_type_instance.actor).to be(actor)
|
|
95
94
|
end
|
|
96
95
|
|
|
97
96
|
describe '#respond_to?' do
|
|
98
97
|
it 'returns true if responds to method' do
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
expect(
|
|
98
|
+
actor = actor_class.new('1')
|
|
99
|
+
actor_type_instance = described_class.new(actor)
|
|
100
|
+
expect(actor_type_instance.respond_to?(:value)).to eq(true)
|
|
102
101
|
end
|
|
103
102
|
|
|
104
|
-
it 'returns true if
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
expect(
|
|
103
|
+
it 'returns true if actor responds to method' do
|
|
104
|
+
actor = actor_class.new(10)
|
|
105
|
+
actor_type_instance = described_class.new(actor)
|
|
106
|
+
expect(actor_type_instance.respond_to?(:admin?)).to eq(true)
|
|
108
107
|
end
|
|
109
108
|
|
|
110
|
-
it 'returns false if does not respond to method and
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
expect(
|
|
109
|
+
it 'returns false if does not respond to method and actor does not respond to method' do
|
|
110
|
+
actor = actor_class.new(10)
|
|
111
|
+
actor_type_instance = described_class.new(actor)
|
|
112
|
+
expect(actor_type_instance.respond_to?(:frankenstein)).to eq(false)
|
|
114
113
|
end
|
|
115
114
|
end
|
|
116
115
|
end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require 'helper'
|
|
2
1
|
require 'flipper/types/group'
|
|
3
2
|
|
|
4
3
|
RSpec.describe Flipper::Types::Group do
|
|
@@ -91,7 +90,7 @@ RSpec.describe Flipper::Types::Group do
|
|
|
91
90
|
context = Flipper::FeatureCheckContext.new(
|
|
92
91
|
feature_name: :my_feature,
|
|
93
92
|
values: Flipper::GateValues.new({}),
|
|
94
|
-
|
|
93
|
+
actors: [Flipper::Types::Actor.new(Flipper::Actor.new('1'))]
|
|
95
94
|
)
|
|
96
95
|
group = Flipper.register(:group_with_context) { |actor| actor }
|
|
97
96
|
yielded_actor = group.match?(admin_actor, context)
|
|
@@ -102,7 +101,7 @@ RSpec.describe Flipper::Types::Group do
|
|
|
102
101
|
context = Flipper::FeatureCheckContext.new(
|
|
103
102
|
feature_name: :my_feature,
|
|
104
103
|
values: Flipper::GateValues.new({}),
|
|
105
|
-
|
|
104
|
+
actors: [Flipper::Types::Actor.new(Flipper::Actor.new('1'))]
|
|
106
105
|
)
|
|
107
106
|
group = Flipper.register(:group_with_context) { |actor, context| [actor, context] }
|
|
108
107
|
yielded_actor, yielded_context = group.match?(admin_actor, context)
|