flipper 0.17.1 → 0.21.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/.github/workflows/ci.yml +57 -0
- data/Changelog.md +114 -1
- data/Dockerfile +1 -1
- data/Gemfile +3 -6
- data/README.md +103 -47
- data/Rakefile +1 -4
- data/docs/Adapters.md +9 -9
- data/docs/Caveats.md +2 -2
- data/docs/DockerCompose.md +0 -1
- data/docs/Gates.md +74 -74
- data/docs/Optimization.md +70 -47
- data/docs/http/README.md +12 -11
- data/docs/images/banner.jpg +0 -0
- data/docs/read-only/README.md +8 -5
- data/examples/basic.rb +1 -12
- data/examples/configuring_default.rb +2 -5
- data/examples/dsl.rb +13 -24
- data/examples/enabled_for_actor.rb +8 -15
- data/examples/group.rb +3 -6
- data/examples/group_dynamic_lookup.rb +5 -19
- data/examples/group_with_members.rb +4 -14
- data/examples/importing.rb +1 -1
- data/examples/individual_actor.rb +2 -5
- data/examples/instrumentation.rb +1 -2
- data/examples/memoizing.rb +35 -0
- data/examples/percentage_of_actors.rb +6 -16
- data/examples/percentage_of_actors_enabled_check.rb +7 -10
- data/examples/percentage_of_actors_group.rb +5 -18
- data/examples/percentage_of_time.rb +3 -6
- data/flipper.gemspec +3 -4
- data/lib/flipper.rb +7 -3
- data/lib/flipper/adapters/dual_write.rb +67 -0
- data/lib/flipper/adapters/http.rb +32 -28
- data/lib/flipper/adapters/memory.rb +23 -94
- data/lib/flipper/adapters/operation_logger.rb +5 -0
- data/lib/flipper/adapters/pstore.rb +8 -1
- data/lib/flipper/adapters/sync.rb +7 -7
- data/lib/flipper/adapters/sync/interval_synchronizer.rb +1 -1
- data/lib/flipper/adapters/sync/synchronizer.rb +1 -0
- data/lib/flipper/configuration.rb +33 -7
- data/lib/flipper/dsl.rb +8 -0
- data/lib/flipper/errors.rb +2 -3
- data/lib/flipper/feature.rb +2 -2
- data/lib/flipper/identifier.rb +17 -0
- data/lib/flipper/middleware/memoizer.rb +30 -15
- data/lib/flipper/middleware/setup_env.rb +13 -3
- data/lib/flipper/railtie.rb +38 -0
- data/lib/flipper/spec/shared_adapter_specs.rb +15 -0
- data/lib/flipper/test/shared_adapter_test.rb +16 -1
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/adapter_spec.rb +2 -2
- data/spec/flipper/adapters/dual_write_spec.rb +71 -0
- data/spec/flipper/adapters/http_spec.rb +74 -8
- data/spec/flipper/adapters/memory_spec.rb +21 -1
- data/spec/flipper/adapters/operation_logger_spec.rb +9 -0
- data/spec/flipper/adapters/sync_spec.rb +4 -4
- data/spec/flipper/configuration_spec.rb +20 -2
- data/spec/flipper/feature_spec.rb +5 -5
- data/spec/flipper/identifier_spec.rb +14 -0
- data/spec/flipper/middleware/memoizer_spec.rb +95 -35
- data/spec/flipper/middleware/setup_env_spec.rb +23 -3
- data/spec/flipper/railtie_spec.rb +69 -0
- data/spec/{integration_spec.rb → flipper_integration_spec.rb} +0 -0
- data/spec/flipper_spec.rb +26 -0
- data/spec/helper.rb +3 -3
- data/spec/support/descriptions.yml +1 -0
- data/spec/support/spec_helpers.rb +25 -0
- data/test/test_helper.rb +2 -1
- metadata +19 -10
- data/.rubocop.yml +0 -52
- data/.rubocop_todo.yml +0 -562
- data/examples/example_setup.rb +0 -8
@@ -76,9 +76,9 @@ RSpec.describe Flipper::Adapters::Http do
|
|
76
76
|
.to_return(status: 503, body: "", headers: {})
|
77
77
|
|
78
78
|
adapter = described_class.new(url: 'http://app.com/flipper')
|
79
|
-
expect
|
79
|
+
expect {
|
80
80
|
adapter.get(flipper[:feature_panel])
|
81
|
-
|
81
|
+
}.to raise_error(Flipper::Adapters::Http::Error)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
@@ -88,9 +88,9 @@ RSpec.describe Flipper::Adapters::Http do
|
|
88
88
|
.to_return(status: 503, body: "", headers: {})
|
89
89
|
|
90
90
|
adapter = described_class.new(url: 'http://app.com/flipper')
|
91
|
-
expect
|
91
|
+
expect {
|
92
92
|
adapter.get_multi([flipper[:feature_panel]])
|
93
|
-
|
93
|
+
}.to raise_error(Flipper::Adapters::Http::Error)
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -100,9 +100,9 @@ RSpec.describe Flipper::Adapters::Http do
|
|
100
100
|
.to_return(status: 503, body: "", headers: {})
|
101
101
|
|
102
102
|
adapter = described_class.new(url: 'http://app.com/flipper')
|
103
|
-
expect
|
103
|
+
expect {
|
104
104
|
adapter.get_all
|
105
|
-
|
105
|
+
}.to raise_error(Flipper::Adapters::Http::Error)
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
@@ -112,9 +112,75 @@ RSpec.describe Flipper::Adapters::Http do
|
|
112
112
|
.to_return(status: 503, body: "", headers: {})
|
113
113
|
|
114
114
|
adapter = described_class.new(url: 'http://app.com/flipper')
|
115
|
-
expect
|
115
|
+
expect {
|
116
116
|
adapter.features
|
117
|
-
|
117
|
+
}.to raise_error(Flipper::Adapters::Http::Error)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "#add" do
|
122
|
+
it "raises error when not successful" do
|
123
|
+
stub_request(:post, /app.com/)
|
124
|
+
.to_return(status: 503, body: "{}", headers: {})
|
125
|
+
|
126
|
+
adapter = described_class.new(url: 'http://app.com/flipper')
|
127
|
+
expect {
|
128
|
+
adapter.add(Flipper::Feature.new(:search, adapter))
|
129
|
+
}.to raise_error(Flipper::Adapters::Http::Error)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "#remove" do
|
134
|
+
it "raises error when not successful" do
|
135
|
+
stub_request(:delete, /app.com/)
|
136
|
+
.to_return(status: 503, body: "{}", headers: {})
|
137
|
+
|
138
|
+
adapter = described_class.new(url: 'http://app.com/flipper')
|
139
|
+
expect {
|
140
|
+
adapter.remove(Flipper::Feature.new(:search, adapter))
|
141
|
+
}.to raise_error(Flipper::Adapters::Http::Error)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "#clear" do
|
146
|
+
it "raises error when not successful" do
|
147
|
+
stub_request(:delete, /app.com/)
|
148
|
+
.to_return(status: 503, body: "{}", headers: {})
|
149
|
+
|
150
|
+
adapter = described_class.new(url: 'http://app.com/flipper')
|
151
|
+
expect {
|
152
|
+
adapter.clear(Flipper::Feature.new(:search, adapter))
|
153
|
+
}.to raise_error(Flipper::Adapters::Http::Error)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "#enable" do
|
158
|
+
it "raises error when not successful" do
|
159
|
+
stub_request(:post, /app.com/)
|
160
|
+
.to_return(status: 503, body: "{}", headers: {})
|
161
|
+
|
162
|
+
adapter = described_class.new(url: 'http://app.com/flipper')
|
163
|
+
feature = Flipper::Feature.new(:search, adapter)
|
164
|
+
gate = feature.gate(:boolean)
|
165
|
+
thing = gate.wrap(true)
|
166
|
+
expect {
|
167
|
+
adapter.enable(feature, gate, thing)
|
168
|
+
}.to raise_error(Flipper::Adapters::Http::Error)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe "#disable" do
|
173
|
+
it "raises error when not successful" do
|
174
|
+
stub_request(:delete, /app.com/)
|
175
|
+
.to_return(status: 503, body: "{}", headers: {})
|
176
|
+
|
177
|
+
adapter = described_class.new(url: 'http://app.com/flipper')
|
178
|
+
feature = Flipper::Feature.new(:search, adapter)
|
179
|
+
gate = feature.gate(:boolean)
|
180
|
+
thing = gate.wrap(false)
|
181
|
+
expect {
|
182
|
+
adapter.disable(feature, gate, thing)
|
183
|
+
}.to raise_error(Flipper::Adapters::Http::Error)
|
118
184
|
end
|
119
185
|
end
|
120
186
|
|
@@ -2,7 +2,27 @@ require 'helper'
|
|
2
2
|
require 'flipper/spec/shared_adapter_specs'
|
3
3
|
|
4
4
|
RSpec.describe Flipper::Adapters::Memory do
|
5
|
-
|
5
|
+
let(:source) { {} }
|
6
|
+
subject { described_class.new(source) }
|
6
7
|
|
7
8
|
it_should_behave_like 'a flipper adapter'
|
9
|
+
|
10
|
+
it "can initialize from big hash" do
|
11
|
+
flipper = Flipper.new(subject)
|
12
|
+
flipper.enable :subscriptions
|
13
|
+
flipper.disable :search
|
14
|
+
flipper.enable_percentage_of_actors :pro_deal, 20
|
15
|
+
flipper.enable_percentage_of_time :logging, 30
|
16
|
+
flipper.enable_actor :following, Flipper::Actor.new('1')
|
17
|
+
flipper.enable_actor :following, Flipper::Actor.new('3')
|
18
|
+
flipper.enable_group :following, Flipper::Types::Group.new(:staff)
|
19
|
+
|
20
|
+
expect(source).to eq({
|
21
|
+
"subscriptions" => subject.default_config.merge(boolean: "true"),
|
22
|
+
"search" => subject.default_config,
|
23
|
+
"logging" => subject.default_config.merge(:percentage_of_time => "30"),
|
24
|
+
"pro_deal" => subject.default_config.merge(:percentage_of_actors => "20"),
|
25
|
+
"following" => subject.default_config.merge(actors: Set["1", "3"], groups: Set["staff"]),
|
26
|
+
})
|
27
|
+
end
|
8
28
|
end
|
@@ -11,6 +11,15 @@ RSpec.describe Flipper::Adapters::OperationLogger do
|
|
11
11
|
|
12
12
|
it_should_behave_like 'a flipper adapter'
|
13
13
|
|
14
|
+
it 'shows itself when inspect' do
|
15
|
+
subject.features
|
16
|
+
output = subject.inspect
|
17
|
+
expect(output).to match(/OperationLogger/)
|
18
|
+
expect(output).to match(/operation_logger/)
|
19
|
+
expect(output).to match(/@type=:features/)
|
20
|
+
expect(output).to match(/@adapter=#<Flipper::Adapters::Memory/)
|
21
|
+
end
|
22
|
+
|
14
23
|
it 'forwards missing methods to underlying adapter' do
|
15
24
|
adapter = Class.new do
|
16
25
|
def foo
|
@@ -175,22 +175,22 @@ RSpec.describe Flipper::Adapters::Sync do
|
|
175
175
|
end
|
176
176
|
|
177
177
|
it 'synchronizes for #features' do
|
178
|
-
expect(subject).to receive(:
|
178
|
+
expect(subject).to receive(:synchronize)
|
179
179
|
subject.features
|
180
180
|
end
|
181
181
|
|
182
182
|
it 'synchronizes for #get' do
|
183
|
-
expect(subject).to receive(:
|
183
|
+
expect(subject).to receive(:synchronize)
|
184
184
|
subject.get sync[:search]
|
185
185
|
end
|
186
186
|
|
187
187
|
it 'synchronizes for #get_multi' do
|
188
|
-
expect(subject).to receive(:
|
188
|
+
expect(subject).to receive(:synchronize)
|
189
189
|
subject.get_multi [sync[:search]]
|
190
190
|
end
|
191
191
|
|
192
192
|
it 'synchronizes for #get_all' do
|
193
|
-
expect(subject).to receive(:
|
193
|
+
expect(subject).to receive(:synchronize)
|
194
194
|
subject.get_all
|
195
195
|
end
|
196
196
|
|
@@ -2,13 +2,31 @@ require 'helper'
|
|
2
2
|
require 'flipper/configuration'
|
3
3
|
|
4
4
|
RSpec.describe Flipper::Configuration do
|
5
|
+
describe '#adapter' do
|
6
|
+
it 'returns instance using Memory adapter' do
|
7
|
+
expect(subject.adapter).to be_a(Flipper::Adapters::Memory)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'can be set' do
|
11
|
+
instance = Flipper::Adapters::Memory.new
|
12
|
+
expect(subject.adapter).not_to be(instance)
|
13
|
+
subject.adapter { instance }
|
14
|
+
expect(subject.adapter).to be(instance)
|
15
|
+
# All adapters are wrapped in Memoizable
|
16
|
+
expect(subject.default.adapter.adapter).to be(instance)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
5
20
|
describe '#default' do
|
6
|
-
it '
|
7
|
-
expect
|
21
|
+
it 'returns instance using Memory adapter' do
|
22
|
+
expect(subject.default).to be_a(Flipper::DSL)
|
23
|
+
# All adapters are wrapped in Memoizable
|
24
|
+
expect(subject.default.adapter.adapter).to be_a(Flipper::Adapters::Memory)
|
8
25
|
end
|
9
26
|
|
10
27
|
it 'can be set default' do
|
11
28
|
instance = Flipper.new(Flipper::Adapters::Memory.new)
|
29
|
+
expect(subject.default).not_to be(instance)
|
12
30
|
subject.default { instance }
|
13
31
|
expect(subject.default).to be(instance)
|
14
32
|
end
|
@@ -359,19 +359,19 @@ RSpec.describe Flipper::Feature do
|
|
359
359
|
end
|
360
360
|
|
361
361
|
it 'returns :on' do
|
362
|
-
expect(subject.state).to be(:
|
362
|
+
expect(subject.state).to be(:conditional)
|
363
363
|
end
|
364
364
|
|
365
|
-
it 'returns
|
366
|
-
expect(subject.on?).to be(
|
365
|
+
it 'returns false for on?' do
|
366
|
+
expect(subject.on?).to be(false)
|
367
367
|
end
|
368
368
|
|
369
369
|
it 'returns false for off?' do
|
370
370
|
expect(subject.off?).to be(false)
|
371
371
|
end
|
372
372
|
|
373
|
-
it 'returns
|
374
|
-
expect(subject.conditional?).to be(
|
373
|
+
it 'returns true for conditional?' do
|
374
|
+
expect(subject.conditional?).to be(true)
|
375
375
|
end
|
376
376
|
end
|
377
377
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'flipper/identifier'
|
3
|
+
|
4
|
+
RSpec.describe Flipper::Identifier do
|
5
|
+
describe '#flipper_id' do
|
6
|
+
class User < Struct.new(:id)
|
7
|
+
include Flipper::Identifier
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'uses class name and id' do
|
11
|
+
expect(User.new(5).flipper_id).to eq('User;5')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -15,10 +15,6 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
15
15
|
let(:flipper) { Flipper.new(adapter) }
|
16
16
|
let(:env) { { 'flipper' => flipper } }
|
17
17
|
|
18
|
-
after do
|
19
|
-
flipper.memoize = nil
|
20
|
-
end
|
21
|
-
|
22
18
|
it 'raises if initialized with app and flipper instance' do
|
23
19
|
expect do
|
24
20
|
described_class.new(app, flipper)
|
@@ -103,14 +99,14 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
103
99
|
end
|
104
100
|
end
|
105
101
|
|
106
|
-
context 'with
|
102
|
+
context 'with preload: true' do
|
107
103
|
let(:app) do
|
108
104
|
# ensure scoped for builder block, annoying...
|
109
105
|
instance = flipper
|
110
106
|
middleware = described_class
|
111
107
|
|
112
108
|
Rack::Builder.new do
|
113
|
-
use middleware,
|
109
|
+
use middleware, preload: true
|
114
110
|
|
115
111
|
map '/' do
|
116
112
|
run ->(_env) { [200, {}, []] }
|
@@ -139,7 +135,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
139
135
|
[200, {}, []]
|
140
136
|
end
|
141
137
|
|
142
|
-
middleware = described_class.new(app,
|
138
|
+
middleware = described_class.new(app, preload: true)
|
143
139
|
middleware.call(env)
|
144
140
|
|
145
141
|
expect(adapter.operations.size).to be(1)
|
@@ -156,7 +152,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
156
152
|
[200, {}, []]
|
157
153
|
end
|
158
154
|
|
159
|
-
middleware = described_class.new(app,
|
155
|
+
middleware = described_class.new(app, preload: true)
|
160
156
|
middleware.call(env)
|
161
157
|
|
162
158
|
expect(adapter.count(:get)).to be(1)
|
@@ -222,6 +218,44 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
222
218
|
end
|
223
219
|
end
|
224
220
|
|
221
|
+
context 'with multiple instances' do
|
222
|
+
let(:app) do
|
223
|
+
# ensure scoped for builder block, annoying...
|
224
|
+
instance = flipper
|
225
|
+
middleware = described_class
|
226
|
+
|
227
|
+
Rack::Builder.new do
|
228
|
+
use middleware, preload: %i(stats)
|
229
|
+
# Second instance should be a noop
|
230
|
+
use middleware, preload: true
|
231
|
+
|
232
|
+
map '/' do
|
233
|
+
run ->(_env) { [200, {}, []] }
|
234
|
+
end
|
235
|
+
|
236
|
+
map '/fail' do
|
237
|
+
run ->(_env) { raise 'FAIL!' }
|
238
|
+
end
|
239
|
+
end.to_app
|
240
|
+
end
|
241
|
+
|
242
|
+
def get(uri, params = {}, env = {}, &block)
|
243
|
+
silence { super(uri, params, env, &block) }
|
244
|
+
end
|
245
|
+
|
246
|
+
include_examples 'flipper middleware'
|
247
|
+
|
248
|
+
it 'does not call preload in second instance' do
|
249
|
+
expect(flipper).not_to receive(:preload_all)
|
250
|
+
|
251
|
+
output = get '/', {}, 'flipper' => flipper
|
252
|
+
|
253
|
+
expect(output).to match(/Flipper::Middleware::Memoizer appears to be running twice/)
|
254
|
+
expect(adapter.count(:get_multi)).to be(1)
|
255
|
+
expect(adapter.last(:get_multi).args).to eq([[flipper[:stats]]])
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
225
259
|
context 'when an app raises an exception' do
|
226
260
|
it 'resets memoize' do
|
227
261
|
begin
|
@@ -259,10 +293,9 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
259
293
|
context 'with Flipper setup in env' do
|
260
294
|
it 'caches getting a feature for duration of request' do
|
261
295
|
Flipper.configure do |config|
|
262
|
-
config.
|
296
|
+
config.adapter do
|
263
297
|
memory = Flipper::Adapters::Memory.new
|
264
|
-
|
265
|
-
Flipper.new(logged_adapter)
|
298
|
+
Flipper::Adapters::OperationLogger.new(memory)
|
266
299
|
end
|
267
300
|
end
|
268
301
|
Flipper.enable(:stats)
|
@@ -308,14 +341,16 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
308
341
|
end
|
309
342
|
end
|
310
343
|
|
311
|
-
context 'with
|
344
|
+
context 'with preload:true' do
|
345
|
+
let(:options) { {preload: true} }
|
346
|
+
|
312
347
|
let(:app) do
|
313
348
|
# ensure scoped for builder block, annoying...
|
314
349
|
middleware = described_class
|
350
|
+
opts = options
|
315
351
|
|
316
352
|
Rack::Builder.new do
|
317
|
-
use middleware,
|
318
|
-
unless: ->(request) { request.path.start_with?("/assets") }
|
353
|
+
use middleware, opts
|
319
354
|
|
320
355
|
map '/' do
|
321
356
|
run ->(_env) { [200, {}, []] }
|
@@ -327,22 +362,57 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
327
362
|
end.to_app
|
328
363
|
end
|
329
364
|
|
330
|
-
|
331
|
-
|
332
|
-
|
365
|
+
|
366
|
+
context 'and unless option' do
|
367
|
+
before do
|
368
|
+
options[:unless] = ->(request) { request.path.start_with?("/assets") }
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'does NOT preload if request matches unless block' do
|
372
|
+
expect(flipper).to receive(:preload_all).never
|
373
|
+
get '/assets/foo.png', {}, 'flipper' => flipper
|
374
|
+
end
|
375
|
+
|
376
|
+
it 'does preload if request does NOT match unless block' do
|
377
|
+
expect(flipper).to receive(:preload_all).once
|
378
|
+
get '/some/other/path', {}, 'flipper' => flipper
|
379
|
+
end
|
333
380
|
end
|
334
381
|
|
335
|
-
|
336
|
-
|
337
|
-
|
382
|
+
context 'and if option' do
|
383
|
+
before do
|
384
|
+
options[:if] = ->(request) { !request.path.start_with?("/assets") }
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'does NOT preload if request does not match if block' do
|
388
|
+
expect(flipper).to receive(:preload_all).never
|
389
|
+
get '/assets/foo.png', {}, 'flipper' => flipper
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'does preload if request matches if block' do
|
393
|
+
expect(flipper).to receive(:preload_all).once
|
394
|
+
get '/some/other/path', {}, 'flipper' => flipper
|
395
|
+
end
|
338
396
|
end
|
339
397
|
end
|
340
398
|
|
341
|
-
context 'with
|
399
|
+
context 'with preload:true and caching adapter' do
|
400
|
+
let(:app) do
|
401
|
+
app = lambda do |_env|
|
402
|
+
flipper[:stats].enabled?
|
403
|
+
flipper[:stats].enabled?
|
404
|
+
flipper[:shiny].enabled?
|
405
|
+
flipper[:shiny].enabled?
|
406
|
+
[200, {}, []]
|
407
|
+
end
|
408
|
+
|
409
|
+
described_class.new(app, preload: true)
|
410
|
+
end
|
411
|
+
|
342
412
|
it 'eagerly caches known features for duration of request' do
|
343
413
|
memory = Flipper::Adapters::Memory.new
|
344
414
|
logged_memory = Flipper::Adapters::OperationLogger.new(memory)
|
345
|
-
cache = ActiveSupport::Cache::
|
415
|
+
cache = ActiveSupport::Cache::MemoryStore.new
|
346
416
|
cache.clear
|
347
417
|
cached = Flipper::Adapters::ActiveSupportCacheStore.new(logged_memory, cache, expires_in: 10)
|
348
418
|
logged_cached = Flipper::Adapters::OperationLogger.new(cached)
|
@@ -355,25 +425,15 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
355
425
|
logged_memory.reset
|
356
426
|
logged_cached.reset
|
357
427
|
|
358
|
-
|
359
|
-
flipper[:stats].enabled?
|
360
|
-
flipper[:stats].enabled?
|
361
|
-
flipper[:shiny].enabled?
|
362
|
-
flipper[:shiny].enabled?
|
363
|
-
[200, {}, []]
|
364
|
-
end
|
365
|
-
|
366
|
-
middleware = described_class.new(app, preload_all: true)
|
367
|
-
|
368
|
-
middleware.call('flipper' => flipper)
|
428
|
+
get '/', {}, 'flipper' => flipper
|
369
429
|
expect(logged_cached.count(:get_all)).to be(1)
|
370
430
|
expect(logged_memory.count(:get_all)).to be(1)
|
371
431
|
|
372
|
-
|
432
|
+
get '/', {}, 'flipper' => flipper
|
373
433
|
expect(logged_cached.count(:get_all)).to be(2)
|
374
434
|
expect(logged_memory.count(:get_all)).to be(1)
|
375
435
|
|
376
|
-
|
436
|
+
get '/', {}, 'flipper' => flipper
|
377
437
|
expect(logged_cached.count(:get_all)).to be(3)
|
378
438
|
expect(logged_memory.count(:get_all)).to be(1)
|
379
439
|
end
|