flipper 1.1.2 → 1.3.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 +9 -2
- data/.github/workflows/examples.yml +8 -2
- data/Changelog.md +1 -647
- data/Gemfile +3 -2
- data/README.md +3 -1
- data/Rakefile +2 -2
- data/docs/images/banner.jpg +0 -0
- data/exe/flipper +5 -0
- data/flipper.gemspec +5 -1
- data/lib/flipper/adapters/actor_limit.rb +28 -0
- data/lib/flipper/adapters/cache_base.rb +143 -0
- data/lib/flipper/adapters/http/client.rb +25 -16
- data/lib/flipper/adapters/operation_logger.rb +18 -88
- data/lib/flipper/adapters/read_only.rb +6 -39
- data/lib/flipper/adapters/strict.rb +16 -18
- data/lib/flipper/adapters/wrapper.rb +54 -0
- data/lib/flipper/cli.rb +263 -0
- data/lib/flipper/cloud/configuration.rb +9 -4
- data/lib/flipper/cloud/middleware.rb +5 -5
- data/lib/flipper/cloud/telemetry/instrumenter.rb +4 -8
- data/lib/flipper/cloud/telemetry/submitter.rb +2 -2
- data/lib/flipper/cloud/telemetry.rb +10 -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/poller.rb +6 -5
- data/lib/flipper/serializers/gzip.rb +3 -5
- data/lib/flipper/serializers/json.rb +3 -5
- data/lib/flipper/spec/shared_adapter_specs.rb +17 -16
- data/lib/flipper/test/shared_adapter_test.rb +17 -17
- data/lib/flipper/test_help.rb +43 -0
- data/lib/flipper/typecast.rb +3 -3
- data/lib/flipper/version.rb +11 -1
- data/lib/flipper.rb +3 -1
- data/lib/generators/flipper/setup_generator.rb +63 -0
- data/package-lock.json +41 -0
- data/package.json +10 -0
- data/spec/fixtures/environment.rb +1 -0
- data/spec/flipper/adapter_builder_spec.rb +1 -2
- data/spec/flipper/adapters/actor_limit_spec.rb +20 -0
- data/spec/flipper/adapters/http/client_spec.rb +61 -0
- data/spec/flipper/adapters/http_spec.rb +102 -76
- data/spec/flipper/adapters/strict_spec.rb +11 -9
- data/spec/flipper/cli_spec.rb +164 -0
- data/spec/flipper/cloud/configuration_spec.rb +35 -36
- 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 +53 -1
- data/spec/flipper/cloud_spec.rb +10 -9
- data/spec/flipper/engine_spec.rb +140 -58
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +9 -2
- data/spec/flipper/middleware/memoizer_spec.rb +7 -4
- data/spec/flipper_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/support/fail_on_output.rb +8 -0
- data/spec/support/spec_helpers.rb +12 -5
- data/test/adapters/actor_limit_test.rb +20 -0
- data/test_rails/generators/flipper/setup_generator_test.rb +64 -0
- data/test_rails/system/test_help_test.rb +51 -0
- metadata +31 -9
- data/spec/support/climate_control.rb +0 -7
data/spec/flipper/engine_spec.rb
CHANGED
@@ -4,8 +4,10 @@ require 'flipper/engine'
|
|
4
4
|
RSpec.describe Flipper::Engine do
|
5
5
|
let(:application) do
|
6
6
|
Class.new(Rails::Application) do
|
7
|
+
config.load_defaults Rails::VERSION::STRING.to_f
|
7
8
|
config.eager_load = false
|
8
9
|
config.logger = ActiveSupport::Logger.new($stdout)
|
10
|
+
config.active_support.remove_deprecated_time_with_zone_name = false
|
9
11
|
end.instance
|
10
12
|
end
|
11
13
|
|
@@ -33,86 +35,102 @@ RSpec.describe Flipper::Engine do
|
|
33
35
|
let(:adapter) { Flipper.adapter.adapter }
|
34
36
|
|
35
37
|
it 'can set strict=true from ENV' do
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
38
|
+
ENV['FLIPPER_STRICT'] = 'true'
|
39
|
+
subject
|
40
|
+
expect(config.strict).to eq(:raise)
|
41
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
41
42
|
end
|
42
43
|
|
43
44
|
it 'can set strict=warn from ENV' do
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
45
|
+
ENV['FLIPPER_STRICT'] = 'warn'
|
46
|
+
subject
|
47
|
+
expect(config.strict).to eq(:warn)
|
48
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
49
|
+
expect(adapter.handler).to be(:warn)
|
50
50
|
end
|
51
51
|
|
52
52
|
it 'can set strict=false from ENV' do
|
53
|
-
|
53
|
+
ENV['FLIPPER_STRICT'] = 'false'
|
54
|
+
subject
|
55
|
+
expect(config.strict).to eq(false)
|
56
|
+
expect(adapter).not_to be_instance_of(Flipper::Adapters::Strict)
|
57
|
+
end
|
58
|
+
|
59
|
+
[true, :raise, :warn].each do |value|
|
60
|
+
it "can set strict=#{value.inspect} in initializer" do
|
61
|
+
initializer { config.strict = value }
|
54
62
|
subject
|
55
|
-
expect(
|
56
|
-
expect(adapter).to
|
63
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
64
|
+
expect(adapter.handler).to be(value)
|
57
65
|
end
|
58
66
|
end
|
59
67
|
|
60
|
-
it "
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
68
|
+
it "can set strict=false in initializer" do
|
69
|
+
initializer { config.strict = false }
|
70
|
+
subject
|
71
|
+
expect(config.strict).to eq(false)
|
72
|
+
expect(adapter).not_to be_instance_of(Flipper::Adapters::Strict)
|
65
73
|
end
|
66
74
|
|
67
|
-
|
75
|
+
it "defaults to strict=:warn in RAILS_ENV=development" do
|
76
|
+
Rails.env = "development"
|
77
|
+
subject
|
78
|
+
expect(config.strict).to eq(:warn)
|
79
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
80
|
+
end
|
81
|
+
|
82
|
+
%w(production test).each do |env|
|
68
83
|
it "defaults to strict=warn in RAILS_ENV=#{env}" do
|
69
84
|
Rails.env = env
|
70
85
|
expect(Rails.env).to eq(env)
|
71
86
|
subject
|
72
|
-
expect(config.strict).to eq(
|
73
|
-
expect(adapter).
|
74
|
-
expect(adapter.handler).to be(Flipper::Adapters::Strict::HANDLERS.fetch(:warn))
|
87
|
+
expect(config.strict).to eq(false)
|
88
|
+
expect(adapter).not_to be_instance_of(Flipper::Adapters::Strict)
|
75
89
|
end
|
76
90
|
end
|
91
|
+
|
92
|
+
it "defaults to strict=warn in RAILS_ENV=development" do
|
93
|
+
Rails.env = "development"
|
94
|
+
expect(Rails.env).to eq("development")
|
95
|
+
subject
|
96
|
+
expect(config.strict).to eq(:warn)
|
97
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::Strict)
|
98
|
+
expect(adapter.handler).to be(:warn)
|
99
|
+
end
|
77
100
|
end
|
78
101
|
|
79
102
|
context 'cloudless' do
|
80
103
|
it_behaves_like 'config.strict'
|
81
104
|
|
82
105
|
it 'can set env_key from ENV' do
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
106
|
+
ENV['FLIPPER_ENV_KEY'] = 'flopper'
|
107
|
+
subject
|
108
|
+
expect(config.env_key).to eq('flopper')
|
87
109
|
end
|
88
110
|
|
89
111
|
it 'can set memoize from ENV' do
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
112
|
+
ENV['FLIPPER_MEMOIZE'] = 'false'
|
113
|
+
subject
|
114
|
+
expect(config.memoize).to eq(false)
|
94
115
|
end
|
95
116
|
|
96
117
|
it 'can set preload from ENV' do
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
end
|
118
|
+
ENV['FLIPPER_PRELOAD'] = 'false'
|
119
|
+
subject
|
120
|
+
expect(config.preload).to eq(false)
|
101
121
|
end
|
102
122
|
|
103
123
|
it 'can set instrumenter from ENV' do
|
104
124
|
stub_const('My::Cool::Instrumenter', Class.new)
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
125
|
+
ENV['FLIPPER_INSTRUMENTER'] = 'My::Cool::Instrumenter'
|
126
|
+
subject
|
127
|
+
expect(config.instrumenter).to eq(My::Cool::Instrumenter)
|
109
128
|
end
|
110
129
|
|
111
130
|
it 'can set log from ENV' do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
131
|
+
ENV['FLIPPER_LOG'] = 'false'
|
132
|
+
subject
|
133
|
+
expect(config.log).to eq(false)
|
116
134
|
end
|
117
135
|
|
118
136
|
it 'sets defaults' do
|
@@ -153,13 +171,51 @@ RSpec.describe Flipper::Engine do
|
|
153
171
|
if: nil
|
154
172
|
})
|
155
173
|
end
|
174
|
+
|
175
|
+
context "test_help" do
|
176
|
+
it "is loaded if RAILS_ENV=test" do
|
177
|
+
Rails.env = "test"
|
178
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
179
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help")
|
180
|
+
subject
|
181
|
+
expect(config.test_help).to eq(true)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "is loaded if FLIPPER_TEST_HELP=true" do
|
185
|
+
ENV["FLIPPER_TEST_HELP"] = "true"
|
186
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
187
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help")
|
188
|
+
subject
|
189
|
+
expect(config.test_help).to eq(true)
|
190
|
+
end
|
191
|
+
|
192
|
+
it "is loaded if config.flipper.test_help = true" do
|
193
|
+
initializer { config.test_help = true }
|
194
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
195
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help")
|
196
|
+
subject
|
197
|
+
end
|
198
|
+
|
199
|
+
it "is not loaded if FLIPPER_TEST_HELP=false" do
|
200
|
+
ENV["FLIPPER_TEST_HELP"] = "false"
|
201
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
202
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help").never
|
203
|
+
subject
|
204
|
+
end
|
205
|
+
|
206
|
+
it "is not loaded if config.flipper.test_help = false" do
|
207
|
+
Rails.env = "true"
|
208
|
+
initializer { config.test_help = false }
|
209
|
+
allow(Flipper::Engine.instance).to receive(:require).and_call_original
|
210
|
+
expect(Flipper::Engine.instance).to receive(:require).with("flipper/test_help").never
|
211
|
+
subject
|
212
|
+
end
|
213
|
+
end
|
156
214
|
end
|
157
215
|
|
158
216
|
context 'with cloud' do
|
159
|
-
|
160
|
-
|
161
|
-
example.run
|
162
|
-
end
|
217
|
+
before do
|
218
|
+
ENV["FLIPPER_CLOUD_TOKEN"] = "test-token"
|
163
219
|
end
|
164
220
|
|
165
221
|
# App for Rack::Test
|
@@ -167,7 +223,8 @@ RSpec.describe Flipper::Engine do
|
|
167
223
|
|
168
224
|
it_behaves_like 'config.strict' do
|
169
225
|
let(:adapter) do
|
170
|
-
|
226
|
+
memoizable = Flipper.adapter
|
227
|
+
dual_write = memoizable.adapter
|
171
228
|
poll = dual_write.local
|
172
229
|
poll.adapter
|
173
230
|
end
|
@@ -179,14 +236,13 @@ RSpec.describe Flipper::Engine do
|
|
179
236
|
application.initialize!
|
180
237
|
|
181
238
|
expect(Flipper.instance).to be_a(Flipper::Cloud::DSL)
|
182
|
-
expect(Flipper.instance.instrumenter).to
|
239
|
+
expect(Flipper.instance.instrumenter).to be_a(Flipper::Cloud::Telemetry::Instrumenter)
|
240
|
+
expect(Flipper.instance.instrumenter.instrumenter).to be(ActiveSupport::Notifications)
|
183
241
|
end
|
184
242
|
|
185
243
|
context "with CLOUD_SYNC_SECRET" do
|
186
|
-
|
187
|
-
|
188
|
-
example.run
|
189
|
-
end
|
244
|
+
before do
|
245
|
+
ENV["FLIPPER_CLOUD_SYNC_SECRET"] = "test-secret"
|
190
246
|
end
|
191
247
|
|
192
248
|
let(:request_body) do
|
@@ -210,7 +266,7 @@ RSpec.describe Flipper::Engine do
|
|
210
266
|
application.initialize!
|
211
267
|
|
212
268
|
stub = stub_request(:get, "https://www.flippercloud.io/adapter/features?exclude_gate_names=true").with({
|
213
|
-
headers: { "
|
269
|
+
headers: { "flipper-cloud-token" => ENV["FLIPPER_CLOUD_TOKEN"] },
|
214
270
|
}).to_return(status: 200, body: JSON.generate({ features: {} }), headers: {})
|
215
271
|
|
216
272
|
post "/_flipper", request_body, { "HTTP_FLIPPER_CLOUD_SIGNATURE" => signature_header_value }
|
@@ -231,10 +287,9 @@ RSpec.describe Flipper::Engine do
|
|
231
287
|
|
232
288
|
context "without FLIPPER_CLOUD_TOKEN" do
|
233
289
|
it "gracefully skips configuring webhook app" do
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
end
|
290
|
+
ENV["FLIPPER_CLOUD_TOKEN"] = nil
|
291
|
+
application.initialize!
|
292
|
+
expect(Flipper.instance).to be_a(Flipper::DSL)
|
238
293
|
|
239
294
|
post "/_flipper"
|
240
295
|
expect(last_response.status).to eq(404)
|
@@ -282,6 +337,33 @@ RSpec.describe Flipper::Engine do
|
|
282
337
|
expect(ActiveRecord::Base.ancestors).to include(Flipper::Model::ActiveRecord)
|
283
338
|
end
|
284
339
|
|
340
|
+
describe "config.actor_limit" do
|
341
|
+
let(:adapter) do
|
342
|
+
application.initialize!
|
343
|
+
Flipper.adapter.adapter.adapter
|
344
|
+
end
|
345
|
+
|
346
|
+
it "defaults to 100" do
|
347
|
+
expect(adapter).to be_instance_of(Flipper::Adapters::ActorLimit)
|
348
|
+
expect(adapter.limit).to eq(100)
|
349
|
+
end
|
350
|
+
|
351
|
+
it "can be set from FLIPPER_ACTOR_LIMIT env" do
|
352
|
+
ENV["FLIPPER_ACTOR_LIMIT"] = "500"
|
353
|
+
expect(adapter.limit).to eq(500)
|
354
|
+
end
|
355
|
+
|
356
|
+
it "can be set from an initializer" do
|
357
|
+
initializer { config.actor_limit = 99 }
|
358
|
+
expect(adapter.limit).to eq(99)
|
359
|
+
end
|
360
|
+
|
361
|
+
it "can be disabled from an initializer" do
|
362
|
+
initializer { config.actor_limit = false }
|
363
|
+
expect(adapter).not_to be_instance_of(Flipper::Adapters::ActorLimit)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
285
367
|
# Add app initializer in the same order as config/initializers/*
|
286
368
|
def initializer(&block)
|
287
369
|
application.initializer 'spec', before: :load_config_initializers do
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'logger'
|
2
|
-
require 'flipper/adapters/instrumented'
|
3
2
|
require 'flipper/instrumentation/log_subscriber'
|
3
|
+
require 'flipper/adapters/instrumented'
|
4
4
|
|
5
5
|
begin
|
6
6
|
require 'active_support/isolated_execution_state'
|
@@ -8,6 +8,9 @@ rescue LoadError
|
|
8
8
|
# ActiveSupport::IsolatedExecutionState is only available in Rails 5.2+
|
9
9
|
end
|
10
10
|
|
11
|
+
# Don't log in other tests, we'll manually re-attach when this one starts
|
12
|
+
Flipper::Instrumentation::LogSubscriber.detach
|
13
|
+
|
11
14
|
RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
12
15
|
let(:adapter) do
|
13
16
|
memory = Flipper::Adapters::Memory.new
|
@@ -32,8 +35,12 @@ RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
32
35
|
described_class.logger = nil
|
33
36
|
end
|
34
37
|
|
38
|
+
before(:all) do
|
39
|
+
described_class.attach
|
40
|
+
end
|
41
|
+
|
35
42
|
after(:all) do
|
36
|
-
|
43
|
+
described_class.detach
|
37
44
|
end
|
38
45
|
|
39
46
|
let(:log) { @io.string }
|
@@ -458,7 +458,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
458
458
|
logged_memory = Flipper::Adapters::OperationLogger.new(memory)
|
459
459
|
cache = ActiveSupport::Cache::MemoryStore.new
|
460
460
|
cache.clear
|
461
|
-
cached = Flipper::Adapters::ActiveSupportCacheStore.new(logged_memory, cache
|
461
|
+
cached = Flipper::Adapters::ActiveSupportCacheStore.new(logged_memory, cache)
|
462
462
|
logged_cached = Flipper::Adapters::OperationLogger.new(cached)
|
463
463
|
memo = {}
|
464
464
|
flipper = Flipper.new(logged_cached)
|
@@ -471,15 +471,18 @@ RSpec.describe Flipper::Middleware::Memoizer do
|
|
471
471
|
|
472
472
|
get '/', {}, 'flipper' => flipper
|
473
473
|
expect(logged_cached.count(:get_all)).to be(1)
|
474
|
-
expect(logged_memory.count(:
|
474
|
+
expect(logged_memory.count(:features)).to be(1)
|
475
|
+
expect(logged_memory.count(:get_multi)).to be(1)
|
475
476
|
|
476
477
|
get '/', {}, 'flipper' => flipper
|
477
478
|
expect(logged_cached.count(:get_all)).to be(2)
|
478
|
-
expect(logged_memory.count(:
|
479
|
+
expect(logged_memory.count(:features)).to be(1)
|
480
|
+
expect(logged_memory.count(:get_multi)).to be(1)
|
479
481
|
|
480
482
|
get '/', {}, 'flipper' => flipper
|
481
483
|
expect(logged_cached.count(:get_all)).to be(3)
|
482
|
-
expect(logged_memory.count(:
|
484
|
+
expect(logged_memory.count(:features)).to be(1)
|
485
|
+
expect(logged_memory.count(:get_multi)).to be(1)
|
483
486
|
end
|
484
487
|
end
|
485
488
|
end
|
data/spec/flipper_spec.rb
CHANGED
@@ -241,7 +241,7 @@ RSpec.describe Flipper do
|
|
241
241
|
stub = stub_request(:get, "https://www.flippercloud.io/adapter/features?exclude_gate_names=true").
|
242
242
|
with({
|
243
243
|
headers: {
|
244
|
-
'
|
244
|
+
'flipper-cloud-token'=>'asdf',
|
245
245
|
},
|
246
246
|
}).to_return(status: 200, body: '{"features": {}}', headers: {})
|
247
247
|
cloud_configuration = Flipper::Cloud::Configuration.new({
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'ice_age'
|
2
2
|
require 'json'
|
3
3
|
require 'rack/test'
|
4
|
+
require 'rack/session'
|
4
5
|
|
5
6
|
module SpecHelpers
|
7
|
+
extend self
|
8
|
+
|
6
9
|
def self.included(base)
|
7
10
|
base.let(:flipper) { build_flipper }
|
8
11
|
base.let(:app) { build_app(flipper) }
|
@@ -10,7 +13,7 @@ module SpecHelpers
|
|
10
13
|
|
11
14
|
def build_app(flipper, options = {})
|
12
15
|
Flipper::UI.app(flipper, options) do |builder|
|
13
|
-
builder.use Rack::Session::Cookie, secret: 'test'
|
16
|
+
builder.use Rack::Session::Cookie, secret: 'test' * 16 # Rack 3+ wants a 64-character secret
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
@@ -27,7 +30,11 @@ module SpecHelpers
|
|
27
30
|
end
|
28
31
|
|
29
32
|
def json_response
|
30
|
-
|
33
|
+
body = last_response.body
|
34
|
+
if last_response["content-encoding"] == 'gzip'
|
35
|
+
body = Flipper::Typecast.from_gzip(body)
|
36
|
+
end
|
37
|
+
JSON.parse(body)
|
31
38
|
end
|
32
39
|
|
33
40
|
def api_error_code_reference_url
|
@@ -76,11 +83,11 @@ module SpecHelpers
|
|
76
83
|
|
77
84
|
yield
|
78
85
|
|
79
|
-
$stderr = original_stderr
|
80
|
-
$stdout = original_stdout
|
81
|
-
|
82
86
|
# Return output
|
83
87
|
output.string
|
88
|
+
ensure
|
89
|
+
$stderr = original_stderr
|
90
|
+
$stdout = original_stdout
|
84
91
|
end
|
85
92
|
end
|
86
93
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require "flipper/test/shared_adapter_test"
|
3
|
+
require "flipper/adapters/actor_limit"
|
4
|
+
|
5
|
+
class Flipper::Adapters::ActorLimitTest < MiniTest::Test
|
6
|
+
prepend Flipper::Test::SharedAdapterTests
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@memory = Flipper::Adapters::Memory.new
|
10
|
+
@adapter = Flipper::Adapters::ActorLimit.new(@memory, 5)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_enable_fails_when_limit_exceeded
|
14
|
+
5.times { |i| @feature.enable Flipper::Actor.new("User;#{i}") }
|
15
|
+
|
16
|
+
assert_raises Flipper::Adapters::ActorLimit::LimitExceeded do
|
17
|
+
@feature.enable Flipper::Actor.new("User;6")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "helper"
|
2
|
+
require "generators/flipper/setup_generator"
|
3
|
+
|
4
|
+
class SetupGeneratorTest < Rails::Generators::TestCase
|
5
|
+
tests Flipper::Generators::SetupGenerator
|
6
|
+
ROOT = File.expand_path("../../../tmp/generators", __dir__)
|
7
|
+
destination ROOT
|
8
|
+
setup :prepare_destination
|
9
|
+
|
10
|
+
test "invokes flipper:active_record generator if ActiveRecord adapter defined" do
|
11
|
+
begin
|
12
|
+
load 'flipper/adapters/active_record.rb'
|
13
|
+
run_generator
|
14
|
+
assert_migration "db/migrate/create_flipper_tables.rb"
|
15
|
+
ensure
|
16
|
+
Flipper::Adapters.send(:remove_const, :ActiveRecord)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
test "does not invoke flipper:active_record generator if ActiveRecord adapter not defined" do
|
21
|
+
# Ensure adapter not defined
|
22
|
+
Flipper::Adapters.send(:remove_const, :ActiveRecord) rescue nil
|
23
|
+
|
24
|
+
run_generator
|
25
|
+
assert_no_migration "db/migrate/create_flipper_tables.rb"
|
26
|
+
end
|
27
|
+
|
28
|
+
%w(.env.development .env.local .env).each do |file|
|
29
|
+
test "configures Flipper Cloud token in #{file} if it exists" do
|
30
|
+
File.write("#{ROOT}/#{file}", "")
|
31
|
+
run_generator %w(--token abc123)
|
32
|
+
assert_file file, /^FLIPPER_CLOUD_TOKEN=abc123$/m
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
test "configures Flipper Cloud token in .env.development before .env" do
|
37
|
+
File.write("#{ROOT}/.env.development", "")
|
38
|
+
File.write("#{ROOT}/.env", "")
|
39
|
+
|
40
|
+
run_generator %w(--token abc123)
|
41
|
+
assert_file ".env.development", /^FLIPPER_CLOUD_TOKEN=abc123$/m
|
42
|
+
assert_file ".env", ""
|
43
|
+
end
|
44
|
+
|
45
|
+
test "does not write to .env if no token provided" do
|
46
|
+
File.write("#{ROOT}/.env", "")
|
47
|
+
run_generator
|
48
|
+
assert_file ".env", ""
|
49
|
+
end
|
50
|
+
|
51
|
+
test "configures Flipper Cloud token in config/credentials.yml.enc if credentials.yml.enc exist" do
|
52
|
+
Dir.chdir(ROOT) do
|
53
|
+
FileUtils.mkdir_p("config")
|
54
|
+
ENV["RAILS_MASTER_KEY"] = "a" * 32
|
55
|
+
Rails.application = Class.new(Rails::Application)
|
56
|
+
Rails.application.credentials.write("")
|
57
|
+
|
58
|
+
run_generator %w(--token abc123)
|
59
|
+
assert_file "config/credentials.yml.enc"
|
60
|
+
expected_config = { flipper: { cloud_token: "abc123" } }
|
61
|
+
assert_equal expected_config, Rails.application.credentials.config
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative "../helper"
|
2
|
+
|
3
|
+
# Not worth trying to test on old Rails versions
|
4
|
+
return unless Rails::VERSION::MAJOR >= 7
|
5
|
+
|
6
|
+
require "capybara/cuprite"
|
7
|
+
require "flipper"
|
8
|
+
require "flipper/test_help"
|
9
|
+
|
10
|
+
require 'action_dispatch/system_testing/server'
|
11
|
+
ActionDispatch::SystemTesting::Server.silence_puma = true
|
12
|
+
|
13
|
+
class TestApp < Rails::Application
|
14
|
+
config.load_defaults "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
|
15
|
+
config.eager_load = false
|
16
|
+
config.logger = ActiveSupport::Logger.new(StringIO.new)
|
17
|
+
routes.append do
|
18
|
+
root to: "features#index"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
TestApp.initialize!
|
23
|
+
|
24
|
+
class FeaturesController < ActionController::Base
|
25
|
+
def index
|
26
|
+
render json: Flipper.enabled?(:test) ? "Enabled" : "Disabled"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class TestHelpTest < ActionDispatch::SystemTestCase
|
31
|
+
# Any driver that runs the app in a separate thread will test what we want here.
|
32
|
+
driven_by :cuprite, options: { process_timeout: 60 }
|
33
|
+
|
34
|
+
setup do
|
35
|
+
# Reconfigure Flipper since other tests change the adapter.
|
36
|
+
flipper_configure
|
37
|
+
|
38
|
+
# Ensure this test uses this app instance
|
39
|
+
Rails.application = TestApp.instance
|
40
|
+
end
|
41
|
+
|
42
|
+
test "configures a shared adapter between tests and app" do
|
43
|
+
Flipper.disable(:test)
|
44
|
+
visit "/"
|
45
|
+
assert_selector "*", text: "Disabled"
|
46
|
+
|
47
|
+
Flipper.enable(:test)
|
48
|
+
visit "/"
|
49
|
+
assert_selector "*", text: "Enabled"
|
50
|
+
end
|
51
|
+
end
|