flipper 1.3.0 → 1.3.6

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +19 -5
  3. data/.github/workflows/examples.yml +19 -5
  4. data/CLAUDE.md +74 -0
  5. data/Gemfile +7 -3
  6. data/README.md +1 -1
  7. data/examples/cloud/backoff_policy.rb +1 -1
  8. data/lib/flipper/adapter_builder.rb +1 -1
  9. data/lib/flipper/adapters/http/error.rb +1 -1
  10. data/lib/flipper/adapters/http.rb +2 -2
  11. data/lib/flipper/adapters/poll.rb +15 -0
  12. data/lib/flipper/cloud/configuration.rb +5 -2
  13. data/lib/flipper/cloud/telemetry/backoff_policy.rb +6 -3
  14. data/lib/flipper/cloud/telemetry/submitter.rb +3 -1
  15. data/lib/flipper/cloud/telemetry.rb +2 -2
  16. data/lib/flipper/export.rb +0 -2
  17. data/lib/flipper/expressions/all.rb +0 -2
  18. data/lib/flipper/feature.rb +8 -1
  19. data/lib/flipper/gate.rb +1 -1
  20. data/lib/flipper/instrumentation/log_subscriber.rb +1 -2
  21. data/lib/flipper/instrumentation/statsd.rb +4 -2
  22. data/lib/flipper/instrumentation/subscriber.rb +0 -4
  23. data/lib/flipper/metadata.rb +1 -0
  24. data/lib/flipper/poller.rb +2 -2
  25. data/lib/flipper/version.rb +1 -1
  26. data/lib/generators/flipper/setup_generator.rb +5 -0
  27. data/lib/generators/flipper/templates/initializer.rb +45 -0
  28. data/spec/flipper/adapters/http_spec.rb +1 -0
  29. data/spec/flipper/adapters/poll_spec.rb +41 -0
  30. data/spec/flipper/adapters/strict_spec.rb +2 -2
  31. data/spec/flipper/cli_spec.rb +4 -2
  32. data/spec/flipper/cloud/dsl_spec.rb +1 -1
  33. data/spec/flipper/cloud/telemetry/backoff_policy_spec.rb +3 -3
  34. data/spec/flipper/cloud/telemetry/submitter_spec.rb +4 -4
  35. data/spec/flipper/cloud/telemetry_spec.rb +6 -6
  36. data/spec/flipper/cloud_spec.rb +9 -4
  37. data/spec/flipper/dsl_spec.rb +0 -3
  38. data/spec/flipper/engine_spec.rb +8 -7
  39. data/spec/flipper/feature_spec.rb +22 -11
  40. data/spec/flipper/instrumentation/log_subscriber_spec.rb +1 -0
  41. data/spec/flipper/instrumentation/statsd_subscriber_spec.rb +1 -1
  42. data/spec/flipper/middleware/memoizer_spec.rb +5 -6
  43. data/spec/flipper/model/active_record_spec.rb +11 -0
  44. data/spec/flipper_spec.rb +1 -1
  45. data/spec/spec_helper.rb +11 -5
  46. data/spec/support/fail_on_output.rb +1 -1
  47. data/spec/support/spec_helpers.rb +13 -2
  48. data/test_rails/generators/flipper/setup_generator_test.rb +5 -0
  49. data/test_rails/generators/flipper/update_generator_test.rb +1 -1
  50. data/test_rails/helper.rb +3 -0
  51. data/test_rails/system/test_help_test.rb +1 -0
  52. metadata +9 -8
@@ -29,13 +29,13 @@ RSpec.describe Flipper::Adapters::Strict do
29
29
 
30
30
  context "#get" do
31
31
  it "raises an error for unknown feature" do
32
- expect(silence { subject.get(feature) }).to match(/Could not find feature "unknown"/)
32
+ expect(capture_output { subject.get(feature) }).to match(/Could not find feature "unknown"/)
33
33
  end
34
34
  end
35
35
 
36
36
  context "#get_multi" do
37
37
  it "raises an error for unknown feature" do
38
- expect(silence { subject.get_multi([feature]) }).to match(/Could not find feature "unknown"/)
38
+ expect(capture_output { subject.get_multi([feature]) }).to match(/Could not find feature "unknown"/)
39
39
  end
40
40
  end
41
41
  end
@@ -5,6 +5,8 @@ RSpec.describe Flipper::CLI do
5
5
  let(:stderr) { StringIO.new }
6
6
  let(:cli) { Flipper::CLI.new(stdout: stdout, stderr: stderr) }
7
7
 
8
+ Result = Struct.new(:status, :stdout, :stderr, keyword_init: true)
9
+
8
10
  before do
9
11
  # Prentend stdout/stderr a TTY to test colorization
10
12
  allow(stdout).to receive(:tty?).and_return(true)
@@ -12,7 +14,7 @@ RSpec.describe Flipper::CLI do
12
14
  end
13
15
 
14
16
  # Infer the command from the description
15
- subject(:argv) do
17
+ let(:argv) do
16
18
  descriptions = self.class.parent_groups.map {|g| g.metadata[:description_args] }.reverse.flatten.drop(1)
17
19
  descriptions.map { |arg| Shellwords.split(arg) }.flatten
18
20
  end
@@ -26,7 +28,7 @@ RSpec.describe Flipper::CLI do
26
28
  status = e.status
27
29
  end
28
30
 
29
- OpenStruct.new(status: status, stdout: stdout.string, stderr: stderr.string)
31
+ Result.new(status: status, stdout: stdout.string, stderr: stderr.string)
30
32
  end
31
33
 
32
34
  before do
@@ -45,7 +45,7 @@ RSpec.describe Flipper::Cloud::DSL do
45
45
  end
46
46
 
47
47
  let(:cloud_configuration) do
48
- cloud_configuration = Flipper::Cloud::Configuration.new({
48
+ Flipper::Cloud::Configuration.new({
49
49
  token: "asdf",
50
50
  sync_secret: "tasty",
51
51
  local_adapter: local_adapter
@@ -4,8 +4,8 @@ RSpec.describe Flipper::Cloud::Telemetry::BackoffPolicy do
4
4
  context "#initialize" do
5
5
  it "with no options" do
6
6
  policy = described_class.new
7
- expect(policy.min_timeout_ms).to eq(1_000)
8
- expect(policy.max_timeout_ms).to eq(30_000)
7
+ expect(policy.min_timeout_ms).to eq(30_000)
8
+ expect(policy.max_timeout_ms).to eq(120_000)
9
9
  expect(policy.multiplier).to eq(1.5)
10
10
  expect(policy.randomization_factor).to eq(0.5)
11
11
  end
@@ -87,7 +87,7 @@ RSpec.describe Flipper::Cloud::Telemetry::BackoffPolicy do
87
87
  randomization_factor: 0.5,
88
88
  })
89
89
  10.times { policy.next_interval }
90
- expect(policy.next_interval).to eq(10_000)
90
+ expect(policy.next_interval).to be_within(10_000*0.1).of(10_000)
91
91
  end
92
92
  end
93
93
 
@@ -71,15 +71,15 @@ RSpec.describe Flipper::Cloud::Telemetry::Submitter do
71
71
  to_return(status: 429, body: "{}").
72
72
  to_return(status: 200, body: "{}")
73
73
  instance = described_class.new(cloud_configuration)
74
- expect(instance.backoff_policy.min_timeout_ms).to eq(1_000)
75
- expect(instance.backoff_policy.max_timeout_ms).to eq(30_000)
74
+ expect(instance.backoff_policy.min_timeout_ms).to eq(30_000)
75
+ expect(instance.backoff_policy.max_timeout_ms).to eq(120_000)
76
76
  end
77
77
 
78
78
  it "tries 10 times by default" do
79
79
  stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
80
80
  to_return(status: 500, body: "{}")
81
81
  subject.call(enabled_metrics)
82
- expect(subject.backoff_policy.retries).to eq(9) # 9 retries + 1 initial attempt
82
+ expect(subject.backoff_policy.retries).to eq(4) # 4 retries + 1 initial attempt
83
83
  end
84
84
 
85
85
  [
@@ -105,7 +105,7 @@ RSpec.describe Flipper::Cloud::Telemetry::Submitter do
105
105
  stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
106
106
  to_raise(error_class)
107
107
  subject.call(enabled_metrics)
108
- expect(subject.backoff_policy.retries).to eq(9)
108
+ expect(subject.backoff_policy.retries).to eq(4)
109
109
  end
110
110
  end
111
111
 
@@ -25,7 +25,7 @@ RSpec.describe Flipper::Cloud::Telemetry do
25
25
 
26
26
  expect(telemetry.interval).to eq(60)
27
27
  expect(telemetry.timer.execution_interval).to eq(60)
28
- expect(stub).to have_been_requested
28
+ expect(stub).to have_been_requested.at_least_once
29
29
  end
30
30
 
31
31
  it "phones home and updates telemetry interval if present" do
@@ -45,7 +45,7 @@ RSpec.describe Flipper::Cloud::Telemetry do
45
45
 
46
46
  expect(telemetry.interval).to eq(120)
47
47
  expect(telemetry.timer.execution_interval).to eq(120)
48
- expect(stub).to have_been_requested
48
+ expect(stub).to have_been_requested.at_least_once
49
49
  end
50
50
 
51
51
  it "phones home and requests shutdown if telemetry-shutdown header is true" do
@@ -67,7 +67,7 @@ RSpec.describe Flipper::Cloud::Telemetry do
67
67
  result: true,
68
68
  })
69
69
  telemetry.stop
70
- expect(stub).to have_been_requested
70
+ expect(stub).to have_been_requested.at_least_once
71
71
  expect(output.string).to match(/action=telemetry_shutdown message=The server has requested that telemetry be shut down./)
72
72
  end
73
73
 
@@ -90,7 +90,7 @@ RSpec.describe Flipper::Cloud::Telemetry do
90
90
  result: true,
91
91
  })
92
92
  telemetry.stop
93
- expect(stub).to have_been_requested
93
+ expect(stub).to have_been_requested.at_least_once
94
94
  expect(output.string).not_to match(/action=telemetry_shutdown message=The server has requested that telemetry be shut down./)
95
95
  end
96
96
 
@@ -122,7 +122,7 @@ RSpec.describe Flipper::Cloud::Telemetry do
122
122
  # Check the conig interval and the timer interval.
123
123
  expect(telemetry.interval).to eq(120)
124
124
  expect(telemetry.timer.execution_interval).to eq(120)
125
- expect(stub).to have_been_requested.times(10)
125
+ expect(stub).to have_been_requested.times(5)
126
126
  end
127
127
 
128
128
  it "doesn't try to update telemetry interval from error if not response error" do
@@ -152,7 +152,7 @@ RSpec.describe Flipper::Cloud::Telemetry do
152
152
 
153
153
  expect(telemetry.interval).to eq(60)
154
154
  expect(telemetry.timer.execution_interval).to eq(60)
155
- expect(stub).to have_been_requested.times(10)
155
+ expect(stub).to have_been_requested.times(5)
156
156
  end
157
157
 
158
158
  describe '#record' do
@@ -43,6 +43,7 @@ RSpec.describe Flipper::Cloud do
43
43
 
44
44
  context 'initialize with token and options' do
45
45
  it 'sets correct url' do
46
+ stub_request(:any, %r{fakeflipper.com}).to_return(status: 200)
46
47
  instance = described_class.new(token: 'asdf', url: 'https://www.fakeflipper.com/sadpanda')
47
48
  # pardon the nesting...
48
49
  memoized = instance.adapter
@@ -78,27 +79,31 @@ RSpec.describe Flipper::Cloud do
78
79
  end
79
80
 
80
81
  it 'can set debug_output' do
82
+ instance = Flipper::Adapters::Http::Client.new(token: 'asdf', url: 'https://www.flippercloud.io/adapter')
81
83
  expect(Flipper::Adapters::Http::Client).to receive(:new)
82
- .with(hash_including(debug_output: STDOUT)).at_least(:once)
84
+ .with(hash_including(debug_output: STDOUT)).at_least(:once).and_return(instance)
83
85
  described_class.new(token: 'asdf', debug_output: STDOUT)
84
86
  end
85
87
 
86
88
  it 'can set read_timeout' do
89
+ instance = Flipper::Adapters::Http::Client.new(token: 'asdf', url: 'https://www.flippercloud.io/adapter')
87
90
  expect(Flipper::Adapters::Http::Client).to receive(:new)
88
- .with(hash_including(read_timeout: 1)).at_least(:once)
91
+ .with(hash_including(read_timeout: 1)).at_least(:once).and_return(instance)
89
92
  described_class.new(token: 'asdf', read_timeout: 1)
90
93
  end
91
94
 
92
95
  it 'can set open_timeout' do
96
+ instance = Flipper::Adapters::Http::Client.new(token: 'asdf', url: 'https://www.flippercloud.io/adapter')
93
97
  expect(Flipper::Adapters::Http::Client).to receive(:new)
94
- .with(hash_including(open_timeout: 1)).at_least(:once)
98
+ .with(hash_including(open_timeout: 1)).at_least(:once).and_return(instance)
95
99
  described_class.new(token: 'asdf', open_timeout: 1)
96
100
  end
97
101
 
98
102
  if RUBY_VERSION >= '2.6.0'
99
103
  it 'can set write_timeout' do
104
+ instance = Flipper::Adapters::Http::Client.new(token: 'asdf', url: 'https://www.flippercloud.io/adapter')
100
105
  expect(Flipper::Adapters::Http::Client).to receive(:new)
101
- .with(hash_including(open_timeout: 1)).at_least(:once)
106
+ .with(hash_including(open_timeout: 1)).at_least(:once).and_return(instance)
102
107
  described_class.new(token: 'asdf', open_timeout: 1)
103
108
  end
104
109
  end
@@ -225,9 +225,6 @@ RSpec.describe Flipper::DSL do
225
225
 
226
226
  describe '#enable_group/disable_group' do
227
227
  it 'enables and disables the feature for group' do
228
- actor = Flipper::Actor.new(5)
229
- group = Flipper.register(:fives) { |actor| actor.flipper_id == 5 }
230
-
231
228
  expect(subject[:stats].groups_value).to be_empty
232
229
  subject.enable_group(:stats, :fives)
233
230
  expect(subject[:stats].groups_value).to eq(Set['fives'])
@@ -12,6 +12,7 @@ RSpec.describe Flipper::Engine do
12
12
  end
13
13
 
14
14
  before do
15
+ stub_request(:get, /flippercloud\.io/).to_return(status: 200, body: "{}")
15
16
  Rails.application = nil
16
17
  ActiveSupport::Dependencies.autoload_paths = ActiveSupport::Dependencies.autoload_paths.dup
17
18
  ActiveSupport::Dependencies.autoload_once_paths = ActiveSupport::Dependencies.autoload_once_paths.dup
@@ -29,7 +30,7 @@ RSpec.describe Flipper::Engine do
29
30
 
30
31
  let(:config) { application.config.flipper }
31
32
 
32
- subject { application.initialize! }
33
+ subject { SpecHelpers.silence { application.initialize! } }
33
34
 
34
35
  shared_examples 'config.strict' do
35
36
  let(:adapter) { Flipper.adapter.adapter }
@@ -233,7 +234,7 @@ RSpec.describe Flipper::Engine do
233
234
  it "initializes cloud configuration" do
234
235
  stub_request(:get, /flippercloud\.io/).to_return(status: 200, body: "{}")
235
236
 
236
- application.initialize!
237
+ silence { application.initialize! }
237
238
 
238
239
  expect(Flipper.instance).to be_a(Flipper::Cloud::DSL)
239
240
  expect(Flipper.instance.instrumenter).to be_a(Flipper::Cloud::Telemetry::Instrumenter)
@@ -263,7 +264,7 @@ RSpec.describe Flipper::Engine do
263
264
  }
264
265
 
265
266
  it "configures webhook app" do
266
- application.initialize!
267
+ silence { application.initialize! }
267
268
 
268
269
  stub = stub_request(:get, "https://www.flippercloud.io/adapter/features?exclude_gate_names=true").with({
269
270
  headers: { "flipper-cloud-token" => ENV["FLIPPER_CLOUD_TOKEN"] },
@@ -278,7 +279,7 @@ RSpec.describe Flipper::Engine do
278
279
 
279
280
  context "without CLOUD_SYNC_SECRET" do
280
281
  it "does not configure webhook app" do
281
- application.initialize!
282
+ silence { application.initialize! }
282
283
 
283
284
  post "/_flipper"
284
285
  expect(last_response.status).to eq(404)
@@ -288,7 +289,7 @@ RSpec.describe Flipper::Engine do
288
289
  context "without FLIPPER_CLOUD_TOKEN" do
289
290
  it "gracefully skips configuring webhook app" do
290
291
  ENV["FLIPPER_CLOUD_TOKEN"] = nil
291
- application.initialize!
292
+ silence { application.initialize! }
292
293
  expect(Flipper.instance).to be_a(Flipper::DSL)
293
294
 
294
295
  post "/_flipper"
@@ -324,7 +325,7 @@ RSpec.describe Flipper::Engine do
324
325
  end
325
326
 
326
327
  it "enables cloud" do
327
- application.initialize!
328
+ silence { application.initialize! }
328
329
  expect(ENV["FLIPPER_CLOUD_TOKEN"]).to eq("credentials-token")
329
330
  expect(ENV["FLIPPER_CLOUD_SYNC_SECRET"]).to eq("credentials-secret")
330
331
  expect(Flipper.instance).to be_a(Flipper::Cloud::DSL)
@@ -339,7 +340,7 @@ RSpec.describe Flipper::Engine do
339
340
 
340
341
  describe "config.actor_limit" do
341
342
  let(:adapter) do
342
- application.initialize!
343
+ silence { application.initialize! }
343
344
  Flipper.adapter.adapter.adapter
344
345
  end
345
346
 
@@ -76,6 +76,26 @@ RSpec.describe Flipper::Feature do
76
76
  expect(subject.enabled?(actors)).to be(false)
77
77
  end
78
78
  end
79
+
80
+ context "for an object that implements .nil? == true" do
81
+ let(:actor) { Flipper::Actor.new("User;1") }
82
+
83
+ before do
84
+ def actor.nil?
85
+ true
86
+ end
87
+ end
88
+
89
+ it 'returns true if feature is enabled' do
90
+ subject.enable
91
+ expect(subject.enabled?(actor)).to be(true)
92
+ end
93
+
94
+ it 'returns false if feature is disabled' do
95
+ subject.disable
96
+ expect(subject.enabled?(actor)).to be(false)
97
+ end
98
+ end
79
99
  end
80
100
 
81
101
  describe '#to_s' do
@@ -195,7 +215,7 @@ RSpec.describe Flipper::Feature do
195
215
 
196
216
  it 'is recorded for enable' do
197
217
  actor = Flipper::Types::Actor.new(Flipper::Actor.new('1'))
198
- gate = subject.gate_for(actor)
218
+ subject.gate_for(actor)
199
219
 
200
220
  subject.enable(actor)
201
221
 
@@ -210,7 +230,7 @@ RSpec.describe Flipper::Feature do
210
230
 
211
231
  it 'always instruments flipper type instance for enable' do
212
232
  actor = Flipper::Actor.new('1')
213
- gate = subject.gate_for(actor)
233
+ subject.gate_for(actor)
214
234
 
215
235
  subject.enable(actor)
216
236
 
@@ -221,7 +241,6 @@ RSpec.describe Flipper::Feature do
221
241
 
222
242
  it 'is recorded for disable' do
223
243
  thing = Flipper::Types::Boolean.new
224
- gate = subject.gate_for(thing)
225
244
 
226
245
  subject.disable(thing)
227
246
 
@@ -266,7 +285,6 @@ RSpec.describe Flipper::Feature do
266
285
 
267
286
  it 'always instruments flipper type instance for disable' do
268
287
  actor = Flipper::Actor.new('1')
269
- gate = subject.gate_for(actor)
270
288
 
271
289
  subject.disable(actor)
272
290
 
@@ -709,7 +727,6 @@ RSpec.describe Flipper::Feature do
709
727
  context "with expression instance" do
710
728
  it "updates gate values to equal expression or clears expression" do
711
729
  expression = Flipper.property(:plan).eq("basic")
712
- other_expression = Flipper.property(:age).gte(21)
713
730
  expect(subject.gate_values.expression).to be(nil)
714
731
  subject.enable_expression(expression)
715
732
  expect(subject.gate_values.expression).to eq(expression.value)
@@ -721,7 +738,6 @@ RSpec.describe Flipper::Feature do
721
738
  context "with Hash" do
722
739
  it "updates gate values to equal expression or clears expression" do
723
740
  expression = Flipper.property(:plan).eq("basic")
724
- other_expression = Flipper.property(:age).gte(21)
725
741
  expect(subject.gate_values.expression).to be(nil)
726
742
  subject.enable_expression(expression.value)
727
743
  expect(subject.gate_values.expression).to eq(expression.value)
@@ -1078,8 +1094,6 @@ RSpec.describe Flipper::Feature do
1078
1094
  describe '#enable_group/disable_group' do
1079
1095
  context 'with symbol group name' do
1080
1096
  it 'updates the gate values to include the group' do
1081
- actor = Flipper::Actor.new(5)
1082
- group = Flipper.register(:five_only) { |actor| actor.flipper_id == 5 }
1083
1097
  expect(subject.gate_values.groups).to be_empty
1084
1098
  subject.enable_group(:five_only)
1085
1099
  expect(subject.gate_values.groups).to eq(Set['five_only'])
@@ -1090,8 +1104,6 @@ RSpec.describe Flipper::Feature do
1090
1104
 
1091
1105
  context 'with string group name' do
1092
1106
  it 'updates the gate values to include the group' do
1093
- actor = Flipper::Actor.new(5)
1094
- group = Flipper.register(:five_only) { |actor| actor.flipper_id == 5 }
1095
1107
  expect(subject.gate_values.groups).to be_empty
1096
1108
  subject.enable_group('five_only')
1097
1109
  expect(subject.gate_values.groups).to eq(Set['five_only'])
@@ -1102,7 +1114,6 @@ RSpec.describe Flipper::Feature do
1102
1114
 
1103
1115
  context 'with group instance' do
1104
1116
  it 'updates the gate values for the group' do
1105
- actor = Flipper::Actor.new(5)
1106
1117
  group = Flipper.register(:five_only) { |actor| actor.flipper_id == 5 }
1107
1118
  expect(subject.gate_values.groups).to be_empty
1108
1119
  subject.enable_group(group)
@@ -1,4 +1,5 @@
1
1
  require 'logger'
2
+ require 'active_support/core_ext/object/blank'
2
3
  require 'flipper/instrumentation/log_subscriber'
3
4
  require 'flipper/adapters/instrumented'
4
5
 
@@ -18,7 +18,7 @@ RSpec.describe Flipper::Instrumentation::StatsdSubscriber do
18
18
  Flipper.new(adapter, instrumenter: ActiveSupport::Notifications)
19
19
  end
20
20
 
21
- let(:user) { user = Flipper::Actor.new('1') }
21
+ let(:user) { Flipper::Actor.new('1') }
22
22
 
23
23
  before do
24
24
  described_class.client = statsd_client
@@ -80,7 +80,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
80
80
  context 'with preload: true' do
81
81
  let(:app) do
82
82
  # ensure scoped for builder block, annoying...
83
- instance = flipper
83
+ flipper
84
84
  middleware = described_class
85
85
 
86
86
  Rack::Builder.new do
@@ -141,7 +141,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
141
141
  context 'with preload specific' do
142
142
  let(:app) do
143
143
  # ensure scoped for builder block, annoying...
144
- instance = flipper
144
+ flipper
145
145
  middleware = described_class
146
146
 
147
147
  Rack::Builder.new do
@@ -266,7 +266,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
266
266
  context 'with multiple instances' do
267
267
  let(:app) do
268
268
  # ensure scoped for builder block, annoying...
269
- instance = flipper
269
+ flipper
270
270
  middleware = described_class
271
271
 
272
272
  Rack::Builder.new do
@@ -285,7 +285,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
285
285
  end
286
286
 
287
287
  def get(uri, params = {}, env = {}, &block)
288
- silence { super(uri, params, env, &block) }
288
+ capture_output { super(uri, params, env, &block) }
289
289
  end
290
290
 
291
291
  include_examples 'flipper middleware'
@@ -316,7 +316,7 @@ RSpec.describe Flipper::Middleware::Memoizer do
316
316
  context 'with flipper setup in env' do
317
317
  let(:app) do
318
318
  # ensure scoped for builder block, annoying...
319
- instance = flipper
319
+ flipper
320
320
  middleware = described_class
321
321
 
322
322
  Rack::Builder.new do
@@ -460,7 +460,6 @@ RSpec.describe Flipper::Middleware::Memoizer do
460
460
  cache.clear
461
461
  cached = Flipper::Adapters::ActiveSupportCacheStore.new(logged_memory, cache)
462
462
  logged_cached = Flipper::Adapters::OperationLogger.new(cached)
463
- memo = {}
464
463
  flipper = Flipper.new(logged_cached)
465
464
  flipper[:stats].enable
466
465
  flipper[:shiny].enable
@@ -30,9 +30,20 @@ RSpec.describe Flipper::Model::ActiveRecord do
30
30
  include Flipper::Model::ActiveRecord
31
31
  end
32
32
 
33
+ class DelegatedUser < DelegateClass(User)
34
+ end
35
+
33
36
  class Admin < User
34
37
  end
35
38
 
39
+ it "doesn't warn for to_ary" do
40
+ # looks like we should remove this but you are wrong, we have specs that
41
+ # fail if there are warnings and if this regresses it will print a warning
42
+ # so it is in fact testing something
43
+ user = User.create!(name: "Test")
44
+ Flipper.enabled?(:something, DelegatedUser.new(user))
45
+ end
46
+
36
47
  describe "flipper_id" do
37
48
  it "returns class name and id" do
38
49
  expect(User.new(id: 1).flipper_id).to eq("User;1")
data/spec/flipper_spec.rb CHANGED
@@ -313,7 +313,7 @@ RSpec.describe Flipper do
313
313
 
314
314
  describe '.group_exists' do
315
315
  it 'returns true if the group is already created' do
316
- group = described_class.register('admins', &:admin?)
316
+ described_class.register('admins', &:admin?)
317
317
  expect(described_class.group_exists?(:admins)).to eq(true)
318
318
  end
319
319
 
data/spec/spec_helper.rb CHANGED
@@ -2,12 +2,14 @@ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
2
2
 
3
3
  require 'pp'
4
4
  require 'pathname'
5
- FlipperRoot = Pathname(__FILE__).dirname.join('..').expand_path
6
-
7
- require 'rubygems'
8
- require 'bundler'
5
+ require 'bundler/setup'
9
6
 
10
- Bundler.setup(:default)
7
+ require 'warning'
8
+ Warning.ignore(/lib\/statsd/)
9
+ Warning.ignore(/lib\/debug\//)
10
+ Warning.ignore(/lib\/ice_age\//)
11
+ Warning.ignore(/lib\/moneta\//)
12
+ Warning.ignore(/lib\/mongo\//)
11
13
 
12
14
  require 'debug'
13
15
  require 'statsd'
@@ -20,6 +22,7 @@ require 'flipper/spec/shared_adapter_specs'
20
22
  require 'flipper/ui'
21
23
  require 'flipper/test_help'
22
24
 
25
+ FlipperRoot = Pathname(__FILE__).dirname.join('..').expand_path
23
26
  Dir[FlipperRoot.join('spec/support/**/*.rb')].sort.each { |f| require f }
24
27
 
25
28
  # Disable telemetry logging in specs.
@@ -27,6 +30,9 @@ ENV["FLIPPER_CLOUD_LOGGING_ENABLED"] = "false"
27
30
 
28
31
  RSpec.configure do |config|
29
32
  config.before(:example) do
33
+ # default stub for telemetry
34
+ stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
35
+ to_return(status: 200, body: "", headers: {})
30
36
  Flipper::Cloud::Telemetry.reset if defined?(Flipper::Cloud::Telemetry) && Flipper::Cloud::Telemetry.respond_to?(:reset)
31
37
  Flipper::Poller.reset if defined?(Flipper::Poller)
32
38
  Flipper.unregister_groups
@@ -1,7 +1,7 @@
1
1
  if ENV["CI"] || ENV["FAIL_ON_OUTPUT"]
2
2
  RSpec.configure do |config|
3
3
  config.around do |example|
4
- output = silence { example.run }
4
+ output = capture_output { example.run }
5
5
  fail "Use `silence { }` to avoid printing to STDOUT/STDERR\n#{output}" unless output.empty?
6
6
  end
7
7
  end
@@ -79,11 +79,22 @@ module SpecHelpers
79
79
  original_stdout = $stdout
80
80
 
81
81
  # Redirect stderr and stdout
82
- output = $stderr = $stdout = StringIO.new
82
+ $stderr = $stdout = StringIO.new
83
+
84
+ yield
85
+ ensure
86
+ $stderr = original_stderr
87
+ $stdout = original_stdout
88
+ end
89
+
90
+ def capture_output
91
+ original_stderr = $stderr
92
+ original_stdout = $stdout
93
+
94
+ output = $stdout = $stderr = StringIO.new
83
95
 
84
96
  yield
85
97
 
86
- # Return output
87
98
  output.string
88
99
  ensure
89
100
  $stderr = original_stderr
@@ -17,6 +17,11 @@ class SetupGeneratorTest < Rails::Generators::TestCase
17
17
  end
18
18
  end
19
19
 
20
+ test "generates an initializer" do
21
+ run_generator
22
+ assert_file 'config/initializers/flipper.rb', /Flipper\.configure/
23
+ end
24
+
20
25
  test "does not invoke flipper:active_record generator if ActiveRecord adapter not defined" do
21
26
  # Ensure adapter not defined
22
27
  Flipper::Adapters.send(:remove_const, :ActiveRecord) rescue nil
@@ -65,7 +65,7 @@ class UpdateGeneratorTest < Rails::Generators::TestCase
65
65
 
66
66
  assert_migration "db/migrate/create_flipper_tables.rb" do |migration|
67
67
  assert_method :up, migration do |up|
68
- assert_match /text :value/, up
68
+ assert_match(/text :value/, up)
69
69
  end
70
70
  end
71
71
 
data/test_rails/helper.rb CHANGED
@@ -4,6 +4,9 @@ require 'minitest/autorun'
4
4
  require 'rails'
5
5
  require 'rails/test_help'
6
6
 
7
+ require 'warning'
8
+ Warning.ignore(/lib\/capybara\//)
9
+
7
10
  begin
8
11
  ActiveSupport::TestCase.test_order = :random
9
12
  rescue NoMethodError
@@ -6,6 +6,7 @@ return unless Rails::VERSION::MAJOR >= 7
6
6
  require "capybara/cuprite"
7
7
  require "flipper"
8
8
  require "flipper/test_help"
9
+ require "action_controller/railtie"
9
10
 
10
11
  require 'action_dispatch/system_testing/server'
11
12
  ActionDispatch::SystemTesting::Server.silence_puma = true