flipper 1.1.2 → 1.2.2
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 +7 -1
- data/.github/workflows/examples.yml +7 -1
- data/Changelog.md +1 -647
- data/Gemfile +3 -2
- data/README.md +1 -1
- data/Rakefile +2 -2
- data/exe/flipper +5 -0
- data/flipper.gemspec +5 -1
- data/lib/flipper/adapters/http/client.rb +25 -16
- data/lib/flipper/adapters/strict.rb +11 -8
- data/lib/flipper/cli.rb +244 -0
- data/lib/flipper/cloud/configuration.rb +7 -1
- data/lib/flipper/cloud/middleware.rb +5 -5
- data/lib/flipper/cloud/telemetry/submitter.rb +2 -2
- data/lib/flipper/cloud.rb +1 -1
- data/lib/flipper/engine.rb +32 -17
- data/lib/flipper/instrumentation/log_subscriber.rb +12 -3
- data/lib/flipper/metadata.rb +3 -1
- data/lib/flipper/test_help.rb +43 -0
- data/lib/flipper/version.rb +11 -1
- data/lib/generators/flipper/setup_generator.rb +63 -0
- data/spec/fixtures/environment.rb +1 -0
- data/spec/flipper/adapter_builder_spec.rb +1 -2
- data/spec/flipper/adapters/http/client_spec.rb +61 -0
- data/spec/flipper/adapters/http_spec.rb +92 -75
- data/spec/flipper/adapters/strict_spec.rb +11 -9
- data/spec/flipper/cli_spec.rb +189 -0
- data/spec/flipper/cloud/configuration_spec.rb +33 -35
- data/spec/flipper/cloud/dsl_spec.rb +5 -5
- data/spec/flipper/cloud/middleware_spec.rb +8 -8
- data/spec/flipper/cloud/telemetry/backoff_policy_spec.rb +8 -9
- data/spec/flipper/cloud/telemetry/submitter_spec.rb +24 -24
- data/spec/flipper/cloud/telemetry_spec.rb +1 -1
- data/spec/flipper/cloud_spec.rb +6 -7
- data/spec/flipper/engine_spec.rb +109 -57
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +9 -2
- data/spec/flipper_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/support/spec_helpers.rb +10 -4
- data/test_rails/generators/flipper/setup_generator_test.rb +64 -0
- data/test_rails/system/test_help_test.rb +51 -0
- metadata +20 -9
- data/spec/support/climate_control.rb +0 -7
@@ -12,10 +12,9 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "can set token from ENV var" do
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
15
|
+
ENV["FLIPPER_CLOUD_TOKEN"] = "from_env"
|
16
|
+
instance = described_class.new(required_options.reject { |k, v| k == :token })
|
17
|
+
expect(instance.token).to eq("from_env")
|
19
18
|
end
|
20
19
|
|
21
20
|
it "can set instrumenter" do
|
@@ -30,10 +29,9 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
30
29
|
end
|
31
30
|
|
32
31
|
it "can set read_timeout from ENV var" do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
32
|
+
ENV["FLIPPER_CLOUD_READ_TIMEOUT"] = "9"
|
33
|
+
instance = described_class.new(required_options.reject { |k, v| k == :read_timeout })
|
34
|
+
expect(instance.read_timeout).to eq(9)
|
37
35
|
end
|
38
36
|
|
39
37
|
it "can set open_timeout" do
|
@@ -42,10 +40,9 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
42
40
|
end
|
43
41
|
|
44
42
|
it "can set open_timeout from ENV var" do
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
43
|
+
ENV["FLIPPER_CLOUD_OPEN_TIMEOUT"] = "9"
|
44
|
+
instance = described_class.new(required_options.reject { |k, v| k == :open_timeout })
|
45
|
+
expect(instance.open_timeout).to eq(9)
|
49
46
|
end
|
50
47
|
|
51
48
|
it "can set write_timeout" do
|
@@ -54,10 +51,9 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
54
51
|
end
|
55
52
|
|
56
53
|
it "can set write_timeout from ENV var" do
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
54
|
+
ENV["FLIPPER_CLOUD_WRITE_TIMEOUT"] = "9"
|
55
|
+
instance = described_class.new(required_options.reject { |k, v| k == :write_timeout })
|
56
|
+
expect(instance.write_timeout).to eq(9)
|
61
57
|
end
|
62
58
|
|
63
59
|
it "can set sync_interval" do
|
@@ -66,10 +62,9 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
66
62
|
end
|
67
63
|
|
68
64
|
it "can set sync_interval from ENV var" do
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
65
|
+
ENV["FLIPPER_CLOUD_SYNC_INTERVAL"] = "15"
|
66
|
+
instance = described_class.new(required_options.reject { |k, v| k == :sync_interval })
|
67
|
+
expect(instance.sync_interval).to eq(15)
|
73
68
|
end
|
74
69
|
|
75
70
|
it "passes sync_interval into sync adapter" do
|
@@ -86,6 +81,12 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
86
81
|
expect(instance.debug_output).to eq(STDOUT)
|
87
82
|
end
|
88
83
|
|
84
|
+
it "defaults debug_output to STDOUT if FLIPPER_CLOUD_DEBUG_OUTPUT_STDOUT set to true" do
|
85
|
+
ENV["FLIPPER_CLOUD_DEBUG_OUTPUT_STDOUT"] = "true"
|
86
|
+
instance = described_class.new(required_options)
|
87
|
+
expect(instance.debug_output).to eq(STDOUT)
|
88
|
+
end
|
89
|
+
|
89
90
|
it "defaults adapter block" do
|
90
91
|
# The initial sync of http to local invokes this web request.
|
91
92
|
stub_request(:get, /flippercloud\.io/).to_return(status: 200, body: "{}")
|
@@ -121,10 +122,9 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
121
122
|
end
|
122
123
|
|
123
124
|
it "can override URL using ENV var" do
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
end
|
125
|
+
ENV["FLIPPER_CLOUD_URL"] = "https://example.com"
|
126
|
+
instance = described_class.new(required_options.reject { |k, v| k == :url })
|
127
|
+
expect(instance.url).to eq("https://example.com")
|
128
128
|
end
|
129
129
|
|
130
130
|
it "defaults sync_method to :poll" do
|
@@ -143,12 +143,11 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
143
143
|
end
|
144
144
|
|
145
145
|
it "sets sync_method to :webhook if FLIPPER_CLOUD_SYNC_SECRET set" do
|
146
|
-
|
147
|
-
|
146
|
+
ENV["FLIPPER_CLOUD_SYNC_SECRET"] = "abc"
|
147
|
+
instance = described_class.new(required_options)
|
148
148
|
|
149
|
-
|
150
|
-
|
151
|
-
end
|
149
|
+
expect(instance.sync_method).to eq(:webhook)
|
150
|
+
expect(instance.adapter).to be_instance_of(Flipper::Adapters::DualWrite)
|
152
151
|
end
|
153
152
|
|
154
153
|
it "can set sync_secret" do
|
@@ -157,10 +156,9 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
157
156
|
end
|
158
157
|
|
159
158
|
it "can override sync_secret using ENV var" do
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
159
|
+
ENV["FLIPPER_CLOUD_SYNC_SECRET"] = "from_env"
|
160
|
+
instance = described_class.new(required_options.reject { |k, v| k == :sync_secret })
|
161
|
+
expect(instance.sync_secret).to eq("from_env")
|
164
162
|
end
|
165
163
|
|
166
164
|
it "can sync with cloud" do
|
@@ -233,9 +231,9 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
233
231
|
stub = stub_request(:get, "https://www.flippercloud.io/adapter/features?exclude_gate_names=true").
|
234
232
|
with({
|
235
233
|
headers: {
|
236
|
-
'
|
234
|
+
'flipper-cloud-token'=>'asdf',
|
237
235
|
},
|
238
|
-
}).to_return(status: 200, body: body
|
236
|
+
}).to_return(status: 200, body: body)
|
239
237
|
instance = described_class.new(required_options)
|
240
238
|
instance.sync
|
241
239
|
|
@@ -18,7 +18,7 @@ RSpec.describe Flipper::Cloud::DSL do
|
|
18
18
|
stub = stub_request(:get, "https://www.flippercloud.io/adapter/features?exclude_gate_names=true").
|
19
19
|
with({
|
20
20
|
headers: {
|
21
|
-
'
|
21
|
+
'flipper-cloud-token'=>'asdf',
|
22
22
|
},
|
23
23
|
}).to_return(status: 200, body: '{"features": {}}', headers: {})
|
24
24
|
cloud_configuration = Flipper::Cloud::Configuration.new({
|
@@ -65,11 +65,11 @@ RSpec.describe Flipper::Cloud::DSL do
|
|
65
65
|
|
66
66
|
it "sends writes to cloud and local" do
|
67
67
|
add_stub = stub_request(:post, "https://www.flippercloud.io/adapter/features").
|
68
|
-
with({headers: {'
|
69
|
-
to_return(status: 200, body: '{}'
|
68
|
+
with({headers: {'flipper-cloud-token'=>'asdf'}}).
|
69
|
+
to_return(status: 200, body: '{}')
|
70
70
|
enable_stub = stub_request(:post, "https://www.flippercloud.io/adapter/features/foo/boolean").
|
71
|
-
with(headers: {'
|
72
|
-
to_return(status: 200, body: '{}'
|
71
|
+
with(headers: {'flipper-cloud-token'=>'asdf'}).
|
72
|
+
to_return(status: 200, body: '{}')
|
73
73
|
|
74
74
|
subject.enable(:foo)
|
75
75
|
|
@@ -101,8 +101,8 @@ RSpec.describe Flipper::Cloud::Middleware do
|
|
101
101
|
post '/', request_body, env
|
102
102
|
|
103
103
|
expect(last_response.status).to eq(402)
|
104
|
-
expect(last_response.headers["
|
105
|
-
expect(last_response.headers["
|
104
|
+
expect(last_response.headers["flipper-cloud-response-error-class"]).to eq("Flipper::Adapters::Http::Error")
|
105
|
+
expect(last_response.headers["flipper-cloud-response-error-message"]).to include("Failed with status: 402")
|
106
106
|
expect(stub).to have_been_requested
|
107
107
|
end
|
108
108
|
end
|
@@ -124,8 +124,8 @@ RSpec.describe Flipper::Cloud::Middleware do
|
|
124
124
|
post '/', request_body, env
|
125
125
|
|
126
126
|
expect(last_response.status).to eq(500)
|
127
|
-
expect(last_response.headers["
|
128
|
-
expect(last_response.headers["
|
127
|
+
expect(last_response.headers["flipper-cloud-response-error-class"]).to eq("Flipper::Adapters::Http::Error")
|
128
|
+
expect(last_response.headers["flipper-cloud-response-error-message"]).to include("Failed with status: 503")
|
129
129
|
expect(stub).to have_been_requested
|
130
130
|
end
|
131
131
|
end
|
@@ -147,8 +147,8 @@ RSpec.describe Flipper::Cloud::Middleware do
|
|
147
147
|
post '/', request_body, env
|
148
148
|
|
149
149
|
expect(last_response.status).to eq(500)
|
150
|
-
expect(last_response.headers["
|
151
|
-
expect(last_response.headers["
|
150
|
+
expect(last_response.headers["flipper-cloud-response-error-class"]).to eq("Net::OpenTimeout")
|
151
|
+
expect(last_response.headers["flipper-cloud-response-error-message"]).to eq("execution expired")
|
152
152
|
expect(stub).to have_been_requested
|
153
153
|
end
|
154
154
|
end
|
@@ -277,13 +277,13 @@ RSpec.describe Flipper::Cloud::Middleware do
|
|
277
277
|
stub = stub_request(:get, "https://www.flippercloud.io/adapter/features?exclude_gate_names=true").
|
278
278
|
with({
|
279
279
|
headers: {
|
280
|
-
'
|
280
|
+
'flipper-cloud-token' => token,
|
281
281
|
},
|
282
282
|
})
|
283
283
|
if status == :timeout
|
284
284
|
stub.to_timeout
|
285
285
|
else
|
286
|
-
stub.to_return(status: status, body: response_body
|
286
|
+
stub.to_return(status: status, body: response_body)
|
287
287
|
end
|
288
288
|
end
|
289
289
|
end
|
@@ -49,19 +49,18 @@ RSpec.describe Flipper::Cloud::Telemetry::BackoffPolicy do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
it "from env" do
|
52
|
-
|
52
|
+
ENV.update(
|
53
53
|
"FLIPPER_BACKOFF_MIN_TIMEOUT_MS" => "1000",
|
54
54
|
"FLIPPER_BACKOFF_MAX_TIMEOUT_MS" => "2000",
|
55
55
|
"FLIPPER_BACKOFF_MULTIPLIER" => "1.9",
|
56
56
|
"FLIPPER_BACKOFF_RANDOMIZATION_FACTOR" => "0.1",
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
57
|
+
)
|
58
|
+
|
59
|
+
policy = described_class.new
|
60
|
+
expect(policy.min_timeout_ms).to eq(1000)
|
61
|
+
expect(policy.max_timeout_ms).to eq(2000)
|
62
|
+
expect(policy.multiplier).to eq(1.9)
|
63
|
+
expect(policy.randomization_factor).to eq(0.1)
|
65
64
|
end
|
66
65
|
end
|
67
66
|
|
@@ -43,33 +43,33 @@ RSpec.describe Flipper::Cloud::Telemetry::Submitter do
|
|
43
43
|
]
|
44
44
|
}
|
45
45
|
expected_headers = {
|
46
|
-
'
|
47
|
-
'
|
48
|
-
'
|
49
|
-
'
|
50
|
-
'
|
51
|
-
'
|
52
|
-
'
|
53
|
-
'
|
54
|
-
'
|
55
|
-
'
|
56
|
-
'
|
57
|
-
'
|
58
|
-
'
|
46
|
+
'accept' => 'application/json',
|
47
|
+
'client-engine' => defined?(RUBY_ENGINE) ? RUBY_ENGINE : "",
|
48
|
+
'client-hostname' => Socket.gethostname,
|
49
|
+
'client-language' => 'ruby',
|
50
|
+
'client-language-version' => "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})",
|
51
|
+
'client-pid' => Process.pid.to_s,
|
52
|
+
'client-platform' => RUBY_PLATFORM,
|
53
|
+
'client-thread' => Thread.current.object_id.to_s,
|
54
|
+
'content-encoding' => 'gzip',
|
55
|
+
'content-type' => 'application/json',
|
56
|
+
'flipper-cloud-token' => 'asdf',
|
57
|
+
'schema-version' => 'V1',
|
58
|
+
'user-agent' => "Flipper HTTP Adapter v#{Flipper::VERSION}",
|
59
59
|
}
|
60
60
|
stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
61
61
|
with(headers: expected_headers) { |request|
|
62
62
|
gunzipped = Flipper::Typecast.from_gzip(request.body)
|
63
63
|
body = Flipper::Typecast.from_json(gunzipped)
|
64
64
|
body == expected_body
|
65
|
-
}.to_return(status: 200, body: "{}"
|
65
|
+
}.to_return(status: 200, body: "{}")
|
66
66
|
subject.call(enabled_metrics)
|
67
67
|
end
|
68
68
|
|
69
69
|
it "defaults backoff_policy" do
|
70
70
|
stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
71
|
-
to_return(status: 429, body: "{}"
|
72
|
-
to_return(status: 200, body: "{}"
|
71
|
+
to_return(status: 429, body: "{}").
|
72
|
+
to_return(status: 200, body: "{}")
|
73
73
|
instance = described_class.new(cloud_configuration)
|
74
74
|
expect(instance.backoff_policy.min_timeout_ms).to eq(1_000)
|
75
75
|
expect(instance.backoff_policy.max_timeout_ms).to eq(30_000)
|
@@ -77,7 +77,7 @@ RSpec.describe Flipper::Cloud::Telemetry::Submitter do
|
|
77
77
|
|
78
78
|
it "tries 10 times by default" do
|
79
79
|
stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
80
|
-
to_return(status: 500, body: "{}"
|
80
|
+
to_return(status: 500, body: "{}")
|
81
81
|
subject.call(enabled_metrics)
|
82
82
|
expect(subject.backoff_policy.retries).to eq(9) # 9 retries + 1 initial attempt
|
83
83
|
end
|
@@ -111,19 +111,19 @@ RSpec.describe Flipper::Cloud::Telemetry::Submitter do
|
|
111
111
|
|
112
112
|
it "retries on 429" do
|
113
113
|
stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
114
|
-
to_return(status: 429, body: "{}"
|
115
|
-
to_return(status: 429, body: "{}"
|
116
|
-
to_return(status: 200, body: "{}"
|
114
|
+
to_return(status: 429, body: "{}").
|
115
|
+
to_return(status: 429, body: "{}").
|
116
|
+
to_return(status: 200, body: "{}")
|
117
117
|
subject.call(enabled_metrics)
|
118
118
|
expect(subject.backoff_policy.retries).to eq(2)
|
119
119
|
end
|
120
120
|
|
121
121
|
it "retries on 500" do
|
122
122
|
stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
123
|
-
to_return(status: 500, body: "{}"
|
124
|
-
to_return(status: 503, body: "{}"
|
125
|
-
to_return(status: 502, body: "{}"
|
126
|
-
to_return(status: 200, body: "{}"
|
123
|
+
to_return(status: 500, body: "{}").
|
124
|
+
to_return(status: 503, body: "{}").
|
125
|
+
to_return(status: 502, body: "{}").
|
126
|
+
to_return(status: 200, body: "{}")
|
127
127
|
subject.call(enabled_metrics)
|
128
128
|
expect(subject.backoff_policy.retries).to eq(3)
|
129
129
|
end
|
@@ -4,7 +4,7 @@ require 'flipper/cloud/configuration'
|
|
4
4
|
RSpec.describe Flipper::Cloud::Telemetry do
|
5
5
|
it "phones home and does not update telemetry interval if missing" do
|
6
6
|
stub = stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
7
|
-
to_return(status: 200, body: "{}"
|
7
|
+
to_return(status: 200, body: "{}")
|
8
8
|
|
9
9
|
cloud_configuration = Flipper::Cloud::Configuration.new(token: "test")
|
10
10
|
|
data/spec/flipper/cloud_spec.rb
CHANGED
@@ -35,7 +35,7 @@ RSpec.describe Flipper::Cloud do
|
|
35
35
|
expect(client.uri.scheme).to eq('https')
|
36
36
|
expect(client.uri.host).to eq('www.flippercloud.io')
|
37
37
|
expect(client.uri.path).to eq('/adapter')
|
38
|
-
expect(client.headers[
|
38
|
+
expect(client.headers["flipper-cloud-token"]).to eq(token)
|
39
39
|
expect(@instance.instrumenter).to be(Flipper::Instrumenters::Noop)
|
40
40
|
end
|
41
41
|
end
|
@@ -55,9 +55,8 @@ RSpec.describe Flipper::Cloud do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'can initialize with no token explicitly provided' do
|
58
|
-
|
59
|
-
|
60
|
-
end
|
58
|
+
ENV['FLIPPER_CLOUD_TOKEN'] = 'asdf'
|
59
|
+
expect(described_class.new).to be_instance_of(Flipper::Cloud::DSL)
|
61
60
|
end
|
62
61
|
|
63
62
|
it 'can set instrumenter' do
|
@@ -104,7 +103,7 @@ RSpec.describe Flipper::Cloud do
|
|
104
103
|
|
105
104
|
it 'can import' do
|
106
105
|
stub_request(:post, /www\.flippercloud\.io\/adapter\/features.*/).
|
107
|
-
with(headers: {'
|
106
|
+
with(headers: {'flipper-cloud-token'=>'asdf'}).to_return(status: 200, body: "{}", headers: {})
|
108
107
|
|
109
108
|
flipper = Flipper.new(Flipper::Adapters::Memory.new)
|
110
109
|
|
@@ -130,7 +129,7 @@ RSpec.describe Flipper::Cloud do
|
|
130
129
|
|
131
130
|
it 'raises error for failure while importing' do
|
132
131
|
stub_request(:post, /www\.flippercloud\.io\/adapter\/features.*/).
|
133
|
-
with(headers: {'
|
132
|
+
with(headers: {'flipper-cloud-token'=>'asdf'}).to_return(status: 500, body: "{}")
|
134
133
|
|
135
134
|
flipper = Flipper.new(Flipper::Adapters::Memory.new)
|
136
135
|
|
@@ -155,7 +154,7 @@ RSpec.describe Flipper::Cloud do
|
|
155
154
|
|
156
155
|
it 'raises error for timeout while importing' do
|
157
156
|
stub_request(:post, /www\.flippercloud\.io\/adapter\/features.*/).
|
158
|
-
with(headers: {'
|
157
|
+
with(headers: {'flipper-cloud-token'=>'asdf'}).to_timeout
|
159
158
|
|
160
159
|
flipper = Flipper.new(Flipper::Adapters::Memory.new)
|
161
160
|
|
data/spec/flipper/engine_spec.rb
CHANGED
@@ -33,86 +33,102 @@ RSpec.describe Flipper::Engine do
|
|
33
33
|
let(:adapter) { Flipper.adapter.adapter }
|
34
34
|
|
35
35
|
it 'can set strict=true from ENV' do
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
36
|
+
ENV['FLIPPER_STRICT'] = 'true'
|
37
|
+
subject
|
38
|
+
expect(config.strict).to eq(:raise)
|
39
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
41
40
|
end
|
42
41
|
|
43
42
|
it 'can set strict=warn from ENV' do
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
43
|
+
ENV['FLIPPER_STRICT'] = 'warn'
|
44
|
+
subject
|
45
|
+
expect(config.strict).to eq(:warn)
|
46
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
47
|
+
expect(adapter.handler).to be(:warn)
|
50
48
|
end
|
51
49
|
|
52
50
|
it 'can set strict=false from ENV' do
|
53
|
-
|
51
|
+
ENV['FLIPPER_STRICT'] = 'false'
|
52
|
+
subject
|
53
|
+
expect(config.strict).to eq(false)
|
54
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Memory)
|
55
|
+
end
|
56
|
+
|
57
|
+
[true, :raise, :warn].each do |value|
|
58
|
+
it "can set strict=#{value.inspect} in initializer" do
|
59
|
+
initializer { config.strict = value }
|
54
60
|
subject
|
55
|
-
expect(
|
56
|
-
expect(adapter).to
|
61
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
62
|
+
expect(adapter.handler).to be(value)
|
57
63
|
end
|
58
64
|
end
|
59
65
|
|
60
|
-
it "
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
66
|
+
it "can set strict=false in initializer" do
|
67
|
+
initializer { config.strict = false }
|
68
|
+
subject
|
69
|
+
expect(config.strict).to eq(false)
|
70
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Memory)
|
65
71
|
end
|
66
72
|
|
67
|
-
|
73
|
+
it "defaults to strict=:warn in RAILS_ENV=development" do
|
74
|
+
Rails.env = "development"
|
75
|
+
subject
|
76
|
+
expect(config.strict).to eq(:warn)
|
77
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
78
|
+
end
|
79
|
+
|
80
|
+
%w(production test).each do |env|
|
68
81
|
it "defaults to strict=warn in RAILS_ENV=#{env}" do
|
69
82
|
Rails.env = env
|
70
83
|
expect(Rails.env).to eq(env)
|
71
84
|
subject
|
72
|
-
expect(config.strict).to eq(
|
73
|
-
expect(adapter).to be_instance_of(Flipper::Adapters::
|
74
|
-
expect(adapter.handler).to be(Flipper::Adapters::Strict::HANDLERS.fetch(:warn))
|
85
|
+
expect(config.strict).to eq(false)
|
86
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Memory)
|
75
87
|
end
|
76
88
|
end
|
89
|
+
|
90
|
+
it "defaults to strict=warn in RAILS_ENV=development" do
|
91
|
+
Rails.env = "development"
|
92
|
+
expect(Rails.env).to eq("development")
|
93
|
+
subject
|
94
|
+
expect(config.strict).to eq(:warn)
|
95
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
96
|
+
expect(adapter.handler).to be(:warn)
|
97
|
+
end
|
77
98
|
end
|
78
99
|
|
79
100
|
context 'cloudless' do
|
80
101
|
it_behaves_like 'config.strict'
|
81
102
|
|
82
103
|
it 'can set env_key from ENV' do
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
104
|
+
ENV['FLIPPER_ENV_KEY'] = 'flopper'
|
105
|
+
subject
|
106
|
+
expect(config.env_key).to eq('flopper')
|
87
107
|
end
|
88
108
|
|
89
109
|
it 'can set memoize from ENV' do
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
110
|
+
ENV['FLIPPER_MEMOIZE'] = 'false'
|
111
|
+
subject
|
112
|
+
expect(config.memoize).to eq(false)
|
94
113
|
end
|
95
114
|
|
96
115
|
it 'can set preload from ENV' do
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
116
|
+
ENV['FLIPPER_PRELOAD'] = 'false'
|
117
|
+
subject
|
118
|
+
expect(config.preload).to eq(false)
|
101
119
|
end
|
102
120
|
|
103
121
|
it 'can set instrumenter from ENV' do
|
104
122
|
stub_const('My::Cool::Instrumenter', Class.new)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
123
|
+
ENV['FLIPPER_INSTRUMENTER'] = 'My::Cool::Instrumenter'
|
124
|
+
subject
|
125
|
+
expect(config.instrumenter).to eq(My::Cool::Instrumenter)
|
109
126
|
end
|
110
127
|
|
111
128
|
it 'can set log from ENV' do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
129
|
+
ENV['FLIPPER_LOG'] = 'false'
|
130
|
+
subject
|
131
|
+
expect(config.log).to eq(false)
|
116
132
|
end
|
117
133
|
|
118
134
|
it 'sets defaults' do
|
@@ -153,13 +169,51 @@ RSpec.describe Flipper::Engine do
|
|
153
169
|
if: nil
|
154
170
|
})
|
155
171
|
end
|
172
|
+
|
173
|
+
context "test_help" do
|
174
|
+
it "is loaded if RAILS_ENV=test" do
|
175
|
+
Rails.env = "test"
|
176
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
177
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help")
|
178
|
+
subject
|
179
|
+
expect(config.test_help).to eq(true)
|
180
|
+
end
|
181
|
+
|
182
|
+
it "is loaded if FLIPPER_TEST_HELP=true" do
|
183
|
+
ENV["FLIPPER_TEST_HELP"] = "true"
|
184
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
185
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help")
|
186
|
+
subject
|
187
|
+
expect(config.test_help).to eq(true)
|
188
|
+
end
|
189
|
+
|
190
|
+
it "is loaded if config.flipper.test_help = true" do
|
191
|
+
initializer { config.test_help = true }
|
192
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
193
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help")
|
194
|
+
subject
|
195
|
+
end
|
196
|
+
|
197
|
+
it "is not loaded if FLIPPER_TEST_HELP=false" do
|
198
|
+
ENV["FLIPPER_TEST_HELP"] = "false"
|
199
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
200
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help").never
|
201
|
+
subject
|
202
|
+
end
|
203
|
+
|
204
|
+
it "is not loaded if config.flipper.test_help = false" do
|
205
|
+
Rails.env = "true"
|
206
|
+
initializer { config.test_help = false }
|
207
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
208
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help").never
|
209
|
+
subject
|
210
|
+
end
|
211
|
+
end
|
156
212
|
end
|
157
213
|
|
158
214
|
context 'with cloud' do
|
159
|
-
|
160
|
-
|
161
|
-
example.run
|
162
|
-
end
|
215
|
+
before do
|
216
|
+
ENV["FLIPPER_CLOUD_TOKEN"] = "test-token"
|
163
217
|
end
|
164
218
|
|
165
219
|
# App for Rack::Test
|
@@ -167,7 +221,8 @@ RSpec.describe Flipper::Engine do
|
|
167
221
|
|
168
222
|
it_behaves_like 'config.strict' do
|
169
223
|
let(:adapter) do
|
170
|
-
|
224
|
+
memoizable = Flipper.adapter
|
225
|
+
dual_write = memoizable.adapter
|
171
226
|
poll = dual_write.local
|
172
227
|
poll.adapter
|
173
228
|
end
|
@@ -183,10 +238,8 @@ RSpec.describe Flipper::Engine do
|
|
183
238
|
end
|
184
239
|
|
185
240
|
context "with CLOUD_SYNC_SECRET" do
|
186
|
-
|
187
|
-
|
188
|
-
example.run
|
189
|
-
end
|
241
|
+
before do
|
242
|
+
ENV["FLIPPER_CLOUD_SYNC_SECRET"] = "test-secret"
|
190
243
|
end
|
191
244
|
|
192
245
|
let(:request_body) do
|
@@ -210,7 +263,7 @@ RSpec.describe Flipper::Engine do
|
|
210
263
|
application.initialize!
|
211
264
|
|
212
265
|
stub = stub_request(:get, "https://www.flippercloud.io/adapter/features?exclude_gate_names=true").with({
|
213
|
-
headers: { "
|
266
|
+
headers: { "flipper-cloud-token" => ENV["FLIPPER_CLOUD_TOKEN"] },
|
214
267
|
}).to_return(status: 200, body: JSON.generate({ features: {} }), headers: {})
|
215
268
|
|
216
269
|
post "/_flipper", request_body, { "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value }
|
@@ -231,10 +284,9 @@ RSpec.describe Flipper::Engine do
|
|
231
284
|
|
232
285
|
context "without FLIPPER_CLOUD_TOKEN" do
|
233
286
|
it "gracefully skips configuring webhook app" do
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
end
|
287
|
+
ENV["FLIPPER_CLOUD_TOKEN"] = nil
|
288
|
+
application.initialize!
|
289
|
+
expect(Flipper.instance).to be_a(Flipper::DSL)
|
238
290
|
|
239
291
|
post "/_flipper"
|
240
292
|
expect(last_response.status).to eq(404)
|