flipper 0.10.2 → 0.11.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +42 -0
- data/.rubocop_todo.yml +188 -0
- data/Changelog.md +10 -0
- data/Gemfile +6 -3
- data/README.md +4 -3
- data/Rakefile +13 -13
- data/docs/Adapters.md +2 -1
- data/docs/DockerCompose.md +6 -3
- data/docs/Gates.md +25 -3
- data/docs/Optimization.md +27 -5
- data/docs/api/README.md +73 -32
- data/docs/http/README.md +34 -0
- data/docs/read-only/README.md +22 -0
- data/examples/percentage_of_actors_group.rb +49 -0
- data/flipper.gemspec +15 -15
- data/lib/flipper.rb +2 -5
- data/lib/flipper/adapter.rb +10 -0
- data/lib/flipper/adapters/http.rb +147 -0
- data/lib/flipper/adapters/http/client.rb +83 -0
- data/lib/flipper/adapters/http/error.rb +14 -0
- data/lib/flipper/adapters/instrumented.rb +36 -36
- data/lib/flipper/adapters/memoizable.rb +2 -6
- data/lib/flipper/adapters/memory.rb +10 -9
- data/lib/flipper/adapters/operation_logger.rb +1 -1
- data/lib/flipper/adapters/pstore.rb +12 -11
- data/lib/flipper/adapters/read_only.rb +6 -6
- data/lib/flipper/dsl.rb +1 -3
- data/lib/flipper/feature.rb +11 -16
- data/lib/flipper/gate.rb +3 -3
- data/lib/flipper/gate_values.rb +6 -6
- data/lib/flipper/gates/group.rb +2 -2
- data/lib/flipper/gates/percentage_of_actors.rb +2 -2
- data/lib/flipper/instrumentation/log_subscriber.rb +2 -4
- data/lib/flipper/instrumentation/metriks.rb +1 -1
- data/lib/flipper/instrumentation/statsd.rb +1 -1
- data/lib/flipper/instrumentation/statsd_subscriber.rb +1 -3
- data/lib/flipper/instrumentation/subscriber.rb +11 -10
- data/lib/flipper/instrumenters/memory.rb +1 -5
- data/lib/flipper/instrumenters/noop.rb +1 -1
- data/lib/flipper/middleware/memoizer.rb +11 -27
- data/lib/flipper/middleware/setup_env.rb +44 -0
- data/lib/flipper/registry.rb +8 -10
- data/lib/flipper/spec/shared_adapter_specs.rb +45 -67
- data/lib/flipper/test/shared_adapter_test.rb +25 -31
- data/lib/flipper/typecast.rb +2 -2
- data/lib/flipper/types/actor.rb +2 -4
- data/lib/flipper/types/group.rb +1 -1
- data/lib/flipper/types/percentage.rb +2 -1
- data/lib/flipper/version.rb +1 -1
- data/spec/fixtures/feature.json +31 -0
- data/spec/flipper/adapters/http_spec.rb +148 -0
- data/spec/flipper/adapters/instrumented_spec.rb +20 -20
- data/spec/flipper/adapters/memoizable_spec.rb +59 -59
- data/spec/flipper/adapters/operation_logger_spec.rb +16 -16
- data/spec/flipper/adapters/pstore_spec.rb +6 -6
- data/spec/flipper/adapters/read_only_spec.rb +28 -34
- data/spec/flipper/dsl_spec.rb +73 -84
- data/spec/flipper/feature_check_context_spec.rb +27 -27
- data/spec/flipper/feature_spec.rb +186 -196
- data/spec/flipper/gate_spec.rb +11 -11
- data/spec/flipper/gate_values_spec.rb +46 -45
- data/spec/flipper/gates/actor_spec.rb +2 -2
- data/spec/flipper/gates/boolean_spec.rb +24 -23
- data/spec/flipper/gates/group_spec.rb +19 -19
- data/spec/flipper/gates/percentage_of_actors_spec.rb +10 -10
- data/spec/flipper/gates/percentage_of_time_spec.rb +2 -2
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +20 -20
- data/spec/flipper/instrumentation/metriks_subscriber_spec.rb +20 -20
- data/spec/flipper/instrumentation/statsd_subscriber_spec.rb +11 -11
- data/spec/flipper/instrumenters/memory_spec.rb +5 -5
- data/spec/flipper/instrumenters/noop_spec.rb +6 -6
- data/spec/flipper/middleware/memoizer_spec.rb +83 -100
- data/spec/flipper/middleware/setup_env_spec.rb +76 -0
- data/spec/flipper/registry_spec.rb +35 -39
- data/spec/flipper/typecast_spec.rb +18 -18
- data/spec/flipper/types/actor_spec.rb +30 -29
- data/spec/flipper/types/boolean_spec.rb +8 -8
- data/spec/flipper/types/group_spec.rb +28 -28
- data/spec/flipper/types/percentage_spec.rb +14 -14
- data/spec/flipper_spec.rb +61 -54
- data/spec/helper.rb +26 -21
- data/spec/integration_spec.rb +121 -113
- data/spec/support/fake_udp_socket.rb +1 -1
- data/spec/support/spec_helpers.rb +32 -4
- data/test/adapters/pstore_test.rb +3 -3
- data/test/test_helper.rb +1 -1
- metadata +20 -5
@@ -5,22 +5,22 @@ require 'flipper/adapters/memory'
|
|
5
5
|
require 'flipper/instrumentation/log_subscriber'
|
6
6
|
|
7
7
|
RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
8
|
-
let(:adapter)
|
8
|
+
let(:adapter) do
|
9
9
|
memory = Flipper::Adapters::Memory.new
|
10
|
-
Flipper::Adapters::Instrumented.new(memory, :
|
11
|
-
|
12
|
-
let(:flipper)
|
13
|
-
Flipper.new(adapter, :
|
14
|
-
|
10
|
+
Flipper::Adapters::Instrumented.new(memory, instrumenter: ActiveSupport::Notifications)
|
11
|
+
end
|
12
|
+
let(:flipper) do
|
13
|
+
Flipper.new(adapter, instrumenter: ActiveSupport::Notifications)
|
14
|
+
end
|
15
15
|
|
16
16
|
before do
|
17
|
-
Flipper.register(:admins)
|
17
|
+
Flipper.register(:admins) do |thing|
|
18
18
|
thing.respond_to?(:admin?) && thing.admin?
|
19
|
-
|
19
|
+
end
|
20
20
|
|
21
21
|
@io = StringIO.new
|
22
22
|
logger = Logger.new(@io)
|
23
|
-
logger.formatter = proc { |
|
23
|
+
logger.formatter = proc { |_severity, _datetime, _progname, msg| "#{msg}\n" }
|
24
24
|
described_class.logger = logger
|
25
25
|
end
|
26
26
|
|
@@ -30,25 +30,25 @@ RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
30
30
|
|
31
31
|
let(:log) { @io.string }
|
32
32
|
|
33
|
-
context
|
33
|
+
context 'feature enabled checks' do
|
34
34
|
before do
|
35
35
|
clear_logs
|
36
36
|
flipper[:search].enabled?
|
37
37
|
end
|
38
38
|
|
39
|
-
it
|
39
|
+
it 'logs feature calls with result after operation' do
|
40
40
|
feature_line = find_line('Flipper feature(search) enabled? false')
|
41
41
|
expect(feature_line).to include('[ thing=nil ]')
|
42
42
|
end
|
43
43
|
|
44
|
-
it
|
44
|
+
it 'logs adapter calls' do
|
45
45
|
adapter_line = find_line('Flipper feature(search) adapter(memory) get')
|
46
46
|
expect(adapter_line).to include('[ result={')
|
47
47
|
expect(adapter_line).to include('} ]')
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
context
|
51
|
+
context 'feature enabled checks with a thing' do
|
52
52
|
let(:user) { Flipper::Types::Actor.new(Struct.new(:flipper_id).new('1')) }
|
53
53
|
|
54
54
|
before do
|
@@ -56,13 +56,13 @@ RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
56
56
|
flipper[:search].enabled?(user)
|
57
57
|
end
|
58
58
|
|
59
|
-
it
|
59
|
+
it 'logs thing for feature' do
|
60
60
|
feature_line = find_line('Flipper feature(search) enabled?')
|
61
61
|
expect(feature_line).to include(user.inspect)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
65
|
-
context
|
65
|
+
context 'changing feature enabled state' do
|
66
66
|
let(:user) { Flipper::Types::Actor.new(Struct.new(:flipper_id).new('1')) }
|
67
67
|
|
68
68
|
before do
|
@@ -70,24 +70,24 @@ RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
70
70
|
flipper[:search].enable(user)
|
71
71
|
end
|
72
72
|
|
73
|
-
it
|
73
|
+
it 'logs feature calls with result in brackets' do
|
74
74
|
feature_line = find_line('Flipper feature(search) enable true')
|
75
75
|
expect(feature_line).to include("[ thing=#{user.inspect} gate_name=actor ]")
|
76
76
|
end
|
77
77
|
|
78
|
-
it
|
78
|
+
it 'logs adapter value' do
|
79
79
|
adapter_line = find_line('Flipper feature(search) adapter(memory) enable')
|
80
|
-
expect(adapter_line).to include(
|
80
|
+
expect(adapter_line).to include('[ result=')
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
context
|
84
|
+
context 'getting all the features from the adapter' do
|
85
85
|
before do
|
86
86
|
clear_logs
|
87
87
|
flipper.features
|
88
88
|
end
|
89
89
|
|
90
|
-
it
|
90
|
+
it 'logs adapter calls' do
|
91
91
|
adapter_line = find_line('Flipper adapter(memory) features')
|
92
92
|
expect(adapter_line).to include('[ result=')
|
93
93
|
end
|
@@ -3,13 +3,13 @@ require 'flipper/adapters/memory'
|
|
3
3
|
require 'flipper/instrumentation/metriks'
|
4
4
|
|
5
5
|
RSpec.describe Flipper::Instrumentation::MetriksSubscriber do
|
6
|
-
let(:adapter)
|
6
|
+
let(:adapter) do
|
7
7
|
memory = Flipper::Adapters::Memory.new
|
8
|
-
Flipper::Adapters::Instrumented.new(memory, :
|
9
|
-
|
10
|
-
let(:flipper)
|
11
|
-
Flipper.new(adapter, :
|
12
|
-
|
8
|
+
Flipper::Adapters::Instrumented.new(memory, instrumenter: ActiveSupport::Notifications)
|
9
|
+
end
|
10
|
+
let(:flipper) do
|
11
|
+
Flipper.new(adapter, instrumenter: ActiveSupport::Notifications)
|
12
|
+
end
|
13
13
|
|
14
14
|
let(:user) { user = Struct.new(:flipper_id).new('1') }
|
15
15
|
|
@@ -17,36 +17,36 @@ RSpec.describe Flipper::Instrumentation::MetriksSubscriber do
|
|
17
17
|
Metriks::Registry.default.clear
|
18
18
|
end
|
19
19
|
|
20
|
-
context
|
21
|
-
it
|
20
|
+
context 'for enabled feature' do
|
21
|
+
it 'updates feature metrics when calls happen' do
|
22
22
|
flipper[:stats].enable(user)
|
23
|
-
expect(Metriks.timer(
|
23
|
+
expect(Metriks.timer('flipper.feature_operation.enable').count).to be(1)
|
24
24
|
|
25
25
|
flipper[:stats].enabled?(user)
|
26
|
-
expect(Metriks.timer(
|
27
|
-
expect(Metriks.meter(
|
26
|
+
expect(Metriks.timer('flipper.feature_operation.enabled').count).to be(1)
|
27
|
+
expect(Metriks.meter('flipper.feature.stats.enabled').count).to be(1)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
context
|
32
|
-
it
|
31
|
+
context 'for disabled feature' do
|
32
|
+
it 'updates feature metrics when calls happen' do
|
33
33
|
flipper[:stats].disable(user)
|
34
|
-
expect(Metriks.timer(
|
34
|
+
expect(Metriks.timer('flipper.feature_operation.disable').count).to be(1)
|
35
35
|
|
36
36
|
flipper[:stats].enabled?(user)
|
37
|
-
expect(Metriks.timer(
|
38
|
-
expect(Metriks.meter(
|
37
|
+
expect(Metriks.timer('flipper.feature_operation.enabled').count).to be(1)
|
38
|
+
expect(Metriks.meter('flipper.feature.stats.disabled').count).to be(1)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
it
|
42
|
+
it 'updates adapter metrics when calls happen' do
|
43
43
|
flipper[:stats].enable(user)
|
44
|
-
expect(Metriks.timer(
|
44
|
+
expect(Metriks.timer('flipper.adapter.memory.enable').count).to be(1)
|
45
45
|
|
46
46
|
flipper[:stats].enabled?(user)
|
47
|
-
expect(Metriks.timer(
|
47
|
+
expect(Metriks.timer('flipper.adapter.memory.get').count).to be(1)
|
48
48
|
|
49
49
|
flipper[:stats].disable(user)
|
50
|
-
expect(Metriks.timer(
|
50
|
+
expect(Metriks.timer('flipper.adapter.memory.disable').count).to be(1)
|
51
51
|
end
|
52
52
|
end
|
@@ -7,13 +7,13 @@ require 'statsd'
|
|
7
7
|
RSpec.describe Flipper::Instrumentation::StatsdSubscriber do
|
8
8
|
let(:statsd_client) { Statsd.new }
|
9
9
|
let(:socket) { FakeUDPSocket.new }
|
10
|
-
let(:adapter)
|
10
|
+
let(:adapter) do
|
11
11
|
memory = Flipper::Adapters::Memory.new
|
12
|
-
Flipper::Adapters::Instrumented.new(memory, :
|
13
|
-
|
14
|
-
let(:flipper)
|
15
|
-
Flipper.new(adapter, :
|
16
|
-
|
12
|
+
Flipper::Adapters::Instrumented.new(memory, instrumenter: ActiveSupport::Notifications)
|
13
|
+
end
|
14
|
+
let(:flipper) do
|
15
|
+
Flipper.new(adapter, instrumenter: ActiveSupport::Notifications)
|
16
|
+
end
|
17
17
|
|
18
18
|
let(:user) { user = Struct.new(:flipper_id).new('1') }
|
19
19
|
|
@@ -38,8 +38,8 @@ RSpec.describe Flipper::Instrumentation::StatsdSubscriber do
|
|
38
38
|
expect(result).not_to be_nil
|
39
39
|
end
|
40
40
|
|
41
|
-
context
|
42
|
-
it
|
41
|
+
context 'for enabled feature' do
|
42
|
+
it 'updates feature metrics when calls happen' do
|
43
43
|
flipper[:stats].enable(user)
|
44
44
|
assert_timer 'flipper.feature_operation.enable'
|
45
45
|
|
@@ -49,8 +49,8 @@ RSpec.describe Flipper::Instrumentation::StatsdSubscriber do
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
context
|
53
|
-
it
|
52
|
+
context 'for disabled feature' do
|
53
|
+
it 'updates feature metrics when calls happen' do
|
54
54
|
flipper[:stats].disable(user)
|
55
55
|
assert_timer 'flipper.feature_operation.disable'
|
56
56
|
|
@@ -60,7 +60,7 @@ RSpec.describe Flipper::Instrumentation::StatsdSubscriber do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
it
|
63
|
+
it 'updates adapter metrics when calls happen' do
|
64
64
|
flipper[:stats].enable(user)
|
65
65
|
assert_timer 'flipper.adapter.memory.enable'
|
66
66
|
|
@@ -2,18 +2,18 @@ require 'helper'
|
|
2
2
|
require 'flipper/instrumenters/memory'
|
3
3
|
|
4
4
|
RSpec.describe Flipper::Instrumenters::Memory do
|
5
|
-
describe
|
6
|
-
it
|
5
|
+
describe '#initialize' do
|
6
|
+
it 'sets events to empty array' do
|
7
7
|
instrumenter = described_class.new
|
8
8
|
expect(instrumenter.events).to eq([])
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
describe
|
13
|
-
it
|
12
|
+
describe '#instrument' do
|
13
|
+
it 'adds to events' do
|
14
14
|
instrumenter = described_class.new
|
15
15
|
name = 'user.signup'
|
16
|
-
payload = {:
|
16
|
+
payload = { email: 'john@doe.com' }
|
17
17
|
block_result = :yielded
|
18
18
|
|
19
19
|
result = instrumenter.instrument(name, payload) { block_result }
|
@@ -2,19 +2,19 @@ require 'helper'
|
|
2
2
|
require 'flipper/instrumenters/noop'
|
3
3
|
|
4
4
|
RSpec.describe Flipper::Instrumenters::Noop do
|
5
|
-
describe
|
6
|
-
context
|
7
|
-
it
|
5
|
+
describe '.instrument' do
|
6
|
+
context 'with name' do
|
7
|
+
it 'yields block' do
|
8
8
|
yielded = false
|
9
9
|
described_class.instrument(:foo) { yielded = true }
|
10
10
|
expect(yielded).to eq(true)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
context
|
15
|
-
it
|
14
|
+
context 'with name and payload' do
|
15
|
+
it 'yields block' do
|
16
16
|
yielded = false
|
17
|
-
described_class.instrument(:foo,
|
17
|
+
described_class.instrument(:foo, pay: :load) { yielded = true }
|
18
18
|
expect(yielded).to eq(true)
|
19
19
|
end
|
20
20
|
end
|
@@ -8,66 +8,71 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
8
8
|
include Rack::Test::Methods
|
9
9
|
|
10
10
|
let(:memory_adapter) { Flipper::Adapters::Memory.new }
|
11
|
-
let(:adapter)
|
11
|
+
let(:adapter) do
|
12
12
|
Flipper::Adapters::OperationLogger.new(memory_adapter)
|
13
|
-
|
14
|
-
let(:flipper)
|
13
|
+
end
|
14
|
+
let(:flipper) { Flipper.new(adapter) }
|
15
|
+
let(:env) { { 'flipper' => flipper } }
|
15
16
|
|
16
17
|
after do
|
17
18
|
flipper.adapter.memoize = nil
|
18
19
|
end
|
19
20
|
|
20
|
-
RSpec.shared_examples_for
|
21
|
-
it
|
21
|
+
RSpec.shared_examples_for 'flipper middleware' do
|
22
|
+
it 'delegates' do
|
22
23
|
called = false
|
23
|
-
app = lambda
|
24
|
+
app = lambda do |_env|
|
24
25
|
called = true
|
25
26
|
[200, {}, nil]
|
26
|
-
|
27
|
-
middleware = described_class.new
|
28
|
-
middleware.call(
|
27
|
+
end
|
28
|
+
middleware = described_class.new(app)
|
29
|
+
middleware.call(env)
|
29
30
|
expect(called).to eq(true)
|
30
31
|
end
|
31
32
|
|
32
|
-
it
|
33
|
-
app =
|
34
|
-
middleware = described_class.new
|
35
|
-
body = middleware.call(
|
33
|
+
it 'disables local cache after body close' do
|
34
|
+
app = ->(_env) { [200, {}, []] }
|
35
|
+
middleware = described_class.new(app)
|
36
|
+
body = middleware.call(env).last
|
36
37
|
|
37
38
|
expect(flipper.adapter.memoizing?).to eq(true)
|
38
39
|
body.close
|
39
40
|
expect(flipper.adapter.memoizing?).to eq(false)
|
40
41
|
end
|
41
42
|
|
42
|
-
it
|
43
|
-
app =
|
44
|
-
middleware = described_class.new
|
45
|
-
body = middleware.call(
|
43
|
+
it 'clears local cache after body close' do
|
44
|
+
app = ->(_env) { [200, {}, []] }
|
45
|
+
middleware = described_class.new(app)
|
46
|
+
body = middleware.call(env).last
|
46
47
|
|
47
48
|
flipper.adapter.cache['hello'] = 'world'
|
48
49
|
body.close
|
49
50
|
expect(flipper.adapter.cache).to be_empty
|
50
51
|
end
|
51
52
|
|
52
|
-
it
|
53
|
+
it 'clears the local cache with a successful request' do
|
53
54
|
flipper.adapter.cache['hello'] = 'world'
|
54
|
-
get '/'
|
55
|
+
get '/', {}, 'flipper' => flipper
|
55
56
|
expect(flipper.adapter.cache).to be_empty
|
56
57
|
end
|
57
58
|
|
58
|
-
it
|
59
|
+
it 'clears the local cache even when the request raises an error' do
|
59
60
|
flipper.adapter.cache['hello'] = 'world'
|
60
|
-
|
61
|
+
begin
|
62
|
+
get '/fail', {}, 'flipper' => flipper
|
63
|
+
rescue
|
64
|
+
nil
|
65
|
+
end
|
61
66
|
expect(flipper.adapter.cache).to be_empty
|
62
67
|
end
|
63
68
|
|
64
|
-
it
|
69
|
+
it 'caches getting a feature for duration of request' do
|
65
70
|
flipper[:stats].enable
|
66
71
|
|
67
72
|
# clear the log of operations
|
68
73
|
adapter.reset
|
69
74
|
|
70
|
-
app = lambda
|
75
|
+
app = lambda do |_env|
|
71
76
|
flipper[:stats].enabled?
|
72
77
|
flipper[:stats].enabled?
|
73
78
|
flipper[:stats].enabled?
|
@@ -75,188 +80,166 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
75
80
|
flipper[:stats].enabled?
|
76
81
|
flipper[:stats].enabled?
|
77
82
|
[200, {}, []]
|
78
|
-
|
83
|
+
end
|
79
84
|
|
80
|
-
middleware = described_class.new
|
81
|
-
middleware.call(
|
85
|
+
middleware = described_class.new(app)
|
86
|
+
middleware.call(env)
|
82
87
|
|
83
88
|
expect(adapter.count(:get)).to be(1)
|
84
89
|
end
|
85
90
|
end
|
86
91
|
|
87
|
-
context
|
88
|
-
let(:app)
|
92
|
+
context 'with preload_all' do
|
93
|
+
let(:app) do
|
89
94
|
# ensure scoped for builder block, annoying...
|
90
95
|
instance = flipper
|
91
96
|
middleware = described_class
|
92
97
|
|
93
98
|
Rack::Builder.new do
|
94
|
-
use middleware,
|
99
|
+
use middleware, preload_all: true
|
95
100
|
|
96
|
-
map
|
97
|
-
run
|
101
|
+
map '/' do
|
102
|
+
run ->(_env) { [200, {}, []] }
|
98
103
|
end
|
99
104
|
|
100
|
-
map
|
101
|
-
run
|
105
|
+
map '/fail' do
|
106
|
+
run ->(_env) { raise 'FAIL!' }
|
102
107
|
end
|
103
108
|
end.to_app
|
104
|
-
|
105
|
-
|
106
|
-
include_examples "flipper middleware"
|
107
|
-
end
|
108
|
-
|
109
|
-
context "with preload_all" do
|
110
|
-
let(:app) {
|
111
|
-
# ensure scoped for builder block, annoying...
|
112
|
-
instance = flipper
|
113
|
-
middleware = described_class
|
114
|
-
|
115
|
-
Rack::Builder.new do
|
116
|
-
use middleware, instance, preload_all: true
|
117
|
-
|
118
|
-
map "/" do
|
119
|
-
run lambda {|env| [200, {}, []] }
|
120
|
-
end
|
121
|
-
|
122
|
-
map "/fail" do
|
123
|
-
run lambda {|env| raise "FAIL!" }
|
124
|
-
end
|
125
|
-
end.to_app
|
126
|
-
}
|
109
|
+
end
|
127
110
|
|
128
|
-
include_examples
|
111
|
+
include_examples 'flipper middleware'
|
129
112
|
|
130
|
-
it
|
113
|
+
it 'eagerly caches known features for duration of request' do
|
131
114
|
flipper[:stats].enable
|
132
115
|
flipper[:shiny].enable
|
133
116
|
|
134
117
|
# clear the log of operations
|
135
118
|
adapter.reset
|
136
119
|
|
137
|
-
app = lambda
|
120
|
+
app = lambda do |_env|
|
138
121
|
flipper[:stats].enabled?
|
139
122
|
flipper[:stats].enabled?
|
140
123
|
flipper[:shiny].enabled?
|
141
124
|
flipper[:shiny].enabled?
|
142
125
|
[200, {}, []]
|
143
|
-
|
126
|
+
end
|
144
127
|
|
145
|
-
middleware = described_class.new
|
146
|
-
middleware.call(
|
128
|
+
middleware = described_class.new(app, preload_all: true)
|
129
|
+
middleware.call(env)
|
147
130
|
|
148
131
|
expect(adapter.count(:features)).to be(1)
|
149
132
|
expect(adapter.count(:get_multi)).to be(1)
|
150
133
|
expect(adapter.last(:get_multi).args).to eq([[flipper[:stats], flipper[:shiny]]])
|
151
134
|
end
|
152
135
|
|
153
|
-
it
|
136
|
+
it 'caches unknown features for duration of request' do
|
154
137
|
# clear the log of operations
|
155
138
|
adapter.reset
|
156
139
|
|
157
|
-
app = lambda
|
140
|
+
app = lambda do |_env|
|
158
141
|
flipper[:other].enabled?
|
159
142
|
flipper[:other].enabled?
|
160
143
|
[200, {}, []]
|
161
|
-
|
144
|
+
end
|
162
145
|
|
163
|
-
middleware = described_class.new
|
164
|
-
middleware.call(
|
146
|
+
middleware = described_class.new(app, preload_all: true)
|
147
|
+
middleware.call(env)
|
165
148
|
|
166
149
|
expect(adapter.count(:get)).to be(1)
|
167
150
|
expect(adapter.last(:get).args).to eq([flipper[:other]])
|
168
151
|
end
|
169
152
|
end
|
170
153
|
|
171
|
-
context
|
172
|
-
let(:app)
|
154
|
+
context 'with preload specific' do
|
155
|
+
let(:app) do
|
173
156
|
# ensure scoped for builder block, annoying...
|
174
157
|
instance = flipper
|
175
158
|
middleware = described_class
|
176
159
|
|
177
160
|
Rack::Builder.new do
|
178
|
-
use middleware,
|
161
|
+
use middleware, preload: %i(stats)
|
179
162
|
|
180
|
-
map
|
181
|
-
run
|
163
|
+
map '/' do
|
164
|
+
run ->(_env) { [200, {}, []] }
|
182
165
|
end
|
183
166
|
|
184
|
-
map
|
185
|
-
run
|
167
|
+
map '/fail' do
|
168
|
+
run ->(_env) { raise 'FAIL!' }
|
186
169
|
end
|
187
170
|
end.to_app
|
188
|
-
|
171
|
+
end
|
189
172
|
|
190
|
-
include_examples
|
173
|
+
include_examples 'flipper middleware'
|
191
174
|
|
192
|
-
it
|
175
|
+
it 'eagerly caches specified features for duration of request' do
|
193
176
|
# clear the log of operations
|
194
177
|
adapter.reset
|
195
178
|
|
196
|
-
app = lambda
|
179
|
+
app = lambda do |_env|
|
197
180
|
flipper[:stats].enabled?
|
198
181
|
flipper[:stats].enabled?
|
199
182
|
flipper[:shiny].enabled?
|
200
183
|
flipper[:shiny].enabled?
|
201
184
|
[200, {}, []]
|
202
|
-
|
185
|
+
end
|
203
186
|
|
204
|
-
middleware = described_class.new app,
|
205
|
-
middleware.call(
|
187
|
+
middleware = described_class.new app, preload: %i(stats)
|
188
|
+
middleware.call(env)
|
206
189
|
|
207
190
|
expect(adapter.count(:get_multi)).to be(1)
|
208
191
|
expect(adapter.last(:get_multi).args).to eq([[flipper[:stats]]])
|
209
192
|
end
|
210
193
|
|
211
|
-
it
|
194
|
+
it 'caches unknown features for duration of request' do
|
212
195
|
# clear the log of operations
|
213
196
|
adapter.reset
|
214
197
|
|
215
|
-
app = lambda
|
198
|
+
app = lambda do |_env|
|
216
199
|
flipper[:other].enabled?
|
217
200
|
flipper[:other].enabled?
|
218
201
|
[200, {}, []]
|
219
|
-
|
202
|
+
end
|
220
203
|
|
221
|
-
middleware = described_class.new app,
|
222
|
-
middleware.call(
|
204
|
+
middleware = described_class.new app, preload: %i(stats)
|
205
|
+
middleware.call(env)
|
223
206
|
|
224
207
|
expect(adapter.count(:get)).to be(1)
|
225
208
|
expect(adapter.last(:get).args).to eq([flipper[:other]])
|
226
209
|
end
|
227
210
|
end
|
228
211
|
|
229
|
-
context
|
230
|
-
it
|
212
|
+
context 'when an app raises an exception' do
|
213
|
+
it 'resets memoize' do
|
231
214
|
begin
|
232
|
-
app =
|
233
|
-
middleware = described_class.new
|
234
|
-
middleware.call(
|
215
|
+
app = ->(_env) { raise }
|
216
|
+
middleware = described_class.new(app)
|
217
|
+
middleware.call(env)
|
235
218
|
rescue RuntimeError
|
236
219
|
expect(flipper.adapter.memoizing?).to be(false)
|
237
220
|
end
|
238
221
|
end
|
239
222
|
end
|
240
223
|
|
241
|
-
context
|
242
|
-
let(:app)
|
224
|
+
context 'with flipper setup in env' do
|
225
|
+
let(:app) do
|
243
226
|
# ensure scoped for builder block, annoying...
|
244
227
|
instance = flipper
|
245
228
|
middleware = described_class
|
246
229
|
|
247
230
|
Rack::Builder.new do
|
248
|
-
use middleware
|
231
|
+
use middleware
|
249
232
|
|
250
|
-
map
|
251
|
-
run
|
233
|
+
map '/' do
|
234
|
+
run ->(_env) { [200, {}, []] }
|
252
235
|
end
|
253
236
|
|
254
|
-
map
|
255
|
-
run
|
237
|
+
map '/fail' do
|
238
|
+
run ->(_env) { raise 'FAIL!' }
|
256
239
|
end
|
257
240
|
end.to_app
|
258
|
-
|
241
|
+
end
|
259
242
|
|
260
|
-
include_examples
|
243
|
+
include_examples 'flipper middleware'
|
261
244
|
end
|
262
245
|
end
|