flipper 1.2.2 → 1.3.0.pre
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 +2 -1
- data/.github/workflows/examples.yml +1 -1
- data/README.md +1 -0
- data/lib/flipper/adapters/cache_base.rb +143 -0
- data/lib/flipper/adapters/operation_logger.rb +18 -88
- data/lib/flipper/adapters/read_only.rb +6 -39
- data/lib/flipper/adapters/strict.rb +5 -10
- data/lib/flipper/adapters/wrapper.rb +54 -0
- data/lib/flipper/cli.rb +36 -17
- data/lib/flipper/cloud/configuration.rb +2 -3
- data/lib/flipper/cloud/telemetry/instrumenter.rb +4 -8
- data/lib/flipper/cloud/telemetry.rb +10 -2
- 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/typecast.rb +3 -3
- data/lib/flipper/version.rb +1 -1
- data/lib/flipper.rb +1 -0
- data/package-lock.json +41 -0
- data/package.json +10 -0
- data/spec/flipper/adapters/http_spec.rb +11 -2
- data/spec/flipper/cli_spec.rb +21 -46
- data/spec/flipper/cloud/configuration_spec.rb +2 -1
- data/spec/flipper/cloud/telemetry_spec.rb +52 -0
- data/spec/flipper/cloud_spec.rb +4 -2
- data/spec/flipper/engine_spec.rb +4 -1
- data/spec/flipper/middleware/memoizer_spec.rb +7 -4
- data/spec/support/fail_on_output.rb +8 -0
- data/spec/support/spec_helpers.rb +2 -1
- data/test_rails/system/test_help_test.rb +1 -1
- metadata +9 -3
data/lib/flipper/poller.rb
CHANGED
@@ -20,6 +20,8 @@ module Flipper
|
|
20
20
|
instances.each {|_, instance| instance.stop }.clear
|
21
21
|
end
|
22
22
|
|
23
|
+
MINIMUM_POLL_INTERVAL = 10
|
24
|
+
|
23
25
|
def initialize(options = {})
|
24
26
|
@thread = nil
|
25
27
|
@pid = Process.pid
|
@@ -30,9 +32,9 @@ module Flipper
|
|
30
32
|
@last_synced_at = Concurrent::AtomicFixnum.new(0)
|
31
33
|
@adapter = Adapters::Memory.new(nil, threadsafe: true)
|
32
34
|
|
33
|
-
if @interval <
|
34
|
-
warn "Flipper::Cloud poll interval must be greater than or equal to
|
35
|
-
@interval =
|
35
|
+
if @interval < MINIMUM_POLL_INTERVAL
|
36
|
+
warn "Flipper::Cloud poll interval must be greater than or equal to #{MINIMUM_POLL_INTERVAL} but was #{@interval}. Setting @interval to #{MINIMUM_POLL_INTERVAL}."
|
37
|
+
@interval = MINIMUM_POLL_INTERVAL
|
36
38
|
end
|
37
39
|
|
38
40
|
@start_automatically = options.fetch(:start_automatically, true)
|
@@ -64,8 +66,7 @@ module Flipper
|
|
64
66
|
# you can instrument these using poller.flipper
|
65
67
|
end
|
66
68
|
|
67
|
-
|
68
|
-
sleep sleep_interval if sleep_interval.positive?
|
69
|
+
sleep interval
|
69
70
|
end
|
70
71
|
end
|
71
72
|
|
@@ -3,10 +3,8 @@ require "stringio"
|
|
3
3
|
|
4
4
|
module Flipper
|
5
5
|
module Serializers
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def serialize(source)
|
6
|
+
class Gzip
|
7
|
+
def self.serialize(source)
|
10
8
|
return if source.nil?
|
11
9
|
output = StringIO.new
|
12
10
|
gz = Zlib::GzipWriter.new(output)
|
@@ -15,7 +13,7 @@ module Flipper
|
|
15
13
|
output.string
|
16
14
|
end
|
17
15
|
|
18
|
-
def deserialize(source)
|
16
|
+
def self.deserialize(source)
|
19
17
|
return if source.nil?
|
20
18
|
Zlib::GzipReader.wrap(StringIO.new(source), &:read)
|
21
19
|
end
|
@@ -2,15 +2,13 @@ require "json"
|
|
2
2
|
|
3
3
|
module Flipper
|
4
4
|
module Serializers
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def serialize(source)
|
5
|
+
class Json
|
6
|
+
def self.serialize(source)
|
9
7
|
return if source.nil?
|
10
8
|
JSON.generate(source)
|
11
9
|
end
|
12
10
|
|
13
|
-
def deserialize(source)
|
11
|
+
def self.deserialize(source)
|
14
12
|
return if source.nil?
|
15
13
|
JSON.parse(source)
|
16
14
|
end
|
@@ -108,19 +108,19 @@ RSpec.shared_examples_for 'a flipper adapter' do
|
|
108
108
|
actor22 = Flipper::Actor.new('22')
|
109
109
|
actor_asdf = Flipper::Actor.new('asdf')
|
110
110
|
|
111
|
-
expect(
|
112
|
-
expect(
|
111
|
+
expect(feature.enable(actor22)).to be(true)
|
112
|
+
expect(feature.enable(actor_asdf)).to be(true)
|
113
113
|
|
114
|
-
|
115
|
-
expect(
|
114
|
+
expect(feature).to be_enabled(actor22)
|
115
|
+
expect(feature).to be_enabled(actor_asdf)
|
116
116
|
|
117
|
-
expect(
|
118
|
-
|
119
|
-
expect(
|
117
|
+
expect(feature.disable(actor22)).to be(true)
|
118
|
+
expect(feature).not_to be_enabled(actor22)
|
119
|
+
expect(feature).to be_enabled(actor_asdf)
|
120
120
|
|
121
|
-
expect(
|
122
|
-
|
123
|
-
expect(
|
121
|
+
expect(feature.disable(actor_asdf)).to eq(true)
|
122
|
+
expect(feature).not_to be_enabled(actor22)
|
123
|
+
expect(feature).not_to be_enabled(actor_asdf)
|
124
124
|
end
|
125
125
|
|
126
126
|
it 'can enable, disable and get value for percentage of actors gate' do
|
@@ -182,9 +182,10 @@ RSpec.shared_examples_for 'a flipper adapter' do
|
|
182
182
|
end
|
183
183
|
|
184
184
|
it 'converts the actor value to a string' do
|
185
|
-
|
186
|
-
|
187
|
-
|
185
|
+
actor = Flipper::Actor.new(22)
|
186
|
+
expect(feature).not_to be_enabled(actor)
|
187
|
+
feature.enable_actor actor
|
188
|
+
expect(feature).to be_enabled(actor)
|
188
189
|
end
|
189
190
|
|
190
191
|
it 'converts group value to a string' do
|
@@ -295,9 +296,9 @@ RSpec.shared_examples_for 'a flipper adapter' do
|
|
295
296
|
|
296
297
|
it 'can double enable an actor without error' do
|
297
298
|
actor = Flipper::Actor.new('Flipper::Actor;22')
|
298
|
-
expect(
|
299
|
-
expect(
|
300
|
-
expect(
|
299
|
+
expect(feature.enable(actor)).to be(true)
|
300
|
+
expect(feature.enable(actor)).to be(true)
|
301
|
+
expect(feature).to be_enabled(actor)
|
301
302
|
end
|
302
303
|
|
303
304
|
it 'can double enable a group without error' do
|
@@ -104,19 +104,19 @@ module Flipper
|
|
104
104
|
actor22 = Flipper::Actor.new('22')
|
105
105
|
actor_asdf = Flipper::Actor.new('asdf')
|
106
106
|
|
107
|
-
assert_equal true, @
|
108
|
-
assert_equal true, @
|
107
|
+
assert_equal true, @feature.enable(actor22)
|
108
|
+
assert_equal true, @feature.enable(actor_asdf)
|
109
109
|
|
110
|
-
|
111
|
-
|
110
|
+
assert @feature.enabled?(actor22)
|
111
|
+
assert @feature.enabled?(actor_asdf)
|
112
112
|
|
113
|
-
|
114
|
-
|
115
|
-
|
113
|
+
assert_equal true, @feature.disable(actor22)
|
114
|
+
refute @feature.enabled?(actor22)
|
115
|
+
assert @feature.enabled?(actor_asdf)
|
116
116
|
|
117
|
-
assert_equal true, @
|
118
|
-
|
119
|
-
|
117
|
+
assert_equal true, @feature.disable(actor_asdf)
|
118
|
+
refute @feature.enabled?(actor22)
|
119
|
+
refute @feature.enabled?(actor_asdf)
|
120
120
|
end
|
121
121
|
|
122
122
|
def test_can_enable_disable_get_value_for_percentage_of_actors_gate
|
@@ -178,10 +178,10 @@ module Flipper
|
|
178
178
|
end
|
179
179
|
|
180
180
|
def test_converts_the_actor_value_to_a_string
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
181
|
+
actor = Flipper::Actor.new(22)
|
182
|
+
refute @feature.enabled?(actor)
|
183
|
+
@feature.enable_actor actor
|
184
|
+
assert @feature.enabled?(actor)
|
185
185
|
end
|
186
186
|
|
187
187
|
def test_converts_group_value_to_a_string
|
@@ -292,9 +292,9 @@ module Flipper
|
|
292
292
|
|
293
293
|
def test_can_double_enable_an_actor_without_error
|
294
294
|
actor = Flipper::Actor.new('Flipper::Actor;22')
|
295
|
-
assert_equal true, @
|
296
|
-
assert_equal true, @
|
297
|
-
|
295
|
+
assert_equal true, @feature.enable(actor)
|
296
|
+
assert_equal true, @feature.enable(actor)
|
297
|
+
assert @feature.enabled?(actor)
|
298
298
|
end
|
299
299
|
|
300
300
|
def test_can_double_enable_a_group_without_error
|
data/lib/flipper/typecast.rb
CHANGED
@@ -3,8 +3,8 @@ require "flipper/serializers/json"
|
|
3
3
|
require "flipper/serializers/gzip"
|
4
4
|
|
5
5
|
module Flipper
|
6
|
-
|
7
|
-
|
6
|
+
class Typecast
|
7
|
+
TRUTH_MAP = {
|
8
8
|
true => true,
|
9
9
|
1 => true,
|
10
10
|
'true' => true,
|
@@ -15,7 +15,7 @@ module Flipper
|
|
15
15
|
#
|
16
16
|
# Returns true or false.
|
17
17
|
def self.to_boolean(value)
|
18
|
-
!!
|
18
|
+
!!TRUTH_MAP[value]
|
19
19
|
end
|
20
20
|
|
21
21
|
# Internal: Convert value to an integer.
|
data/lib/flipper/version.rb
CHANGED
data/lib/flipper.rb
CHANGED
data/package-lock.json
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
{
|
2
|
+
"name": "flipper",
|
3
|
+
"lockfileVersion": 3,
|
4
|
+
"requires": true,
|
5
|
+
"packages": {
|
6
|
+
"": {
|
7
|
+
"hasInstallScript": true,
|
8
|
+
"dependencies": {
|
9
|
+
"@popperjs/core": "^2.11.8",
|
10
|
+
"bootstrap": "^5.3.3"
|
11
|
+
}
|
12
|
+
},
|
13
|
+
"node_modules/@popperjs/core": {
|
14
|
+
"version": "2.11.8",
|
15
|
+
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
16
|
+
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
17
|
+
"funding": {
|
18
|
+
"type": "opencollective",
|
19
|
+
"url": "https://opencollective.com/popperjs"
|
20
|
+
}
|
21
|
+
},
|
22
|
+
"node_modules/bootstrap": {
|
23
|
+
"version": "5.3.3",
|
24
|
+
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
|
25
|
+
"integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
|
26
|
+
"funding": [
|
27
|
+
{
|
28
|
+
"type": "github",
|
29
|
+
"url": "https://github.com/sponsors/twbs"
|
30
|
+
},
|
31
|
+
{
|
32
|
+
"type": "opencollective",
|
33
|
+
"url": "https://opencollective.com/bootstrap"
|
34
|
+
}
|
35
|
+
],
|
36
|
+
"peerDependencies": {
|
37
|
+
"@popperjs/core": "^2.11.8"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
data/package.json
ADDED
@@ -1,6 +1,15 @@
|
|
1
1
|
require 'flipper/adapters/http'
|
2
2
|
require 'flipper/adapters/pstore'
|
3
|
-
|
3
|
+
|
4
|
+
rack_handler = begin
|
5
|
+
# Rack 3+
|
6
|
+
require 'rackup/handler/webrick'
|
7
|
+
Rackup::Handler::WEBrick
|
8
|
+
rescue LoadError
|
9
|
+
require 'rack/handler/webrick'
|
10
|
+
Rack::Handler::WEBrick
|
11
|
+
end
|
12
|
+
|
4
13
|
|
5
14
|
FLIPPER_SPEC_API_PORT = ENV.fetch('FLIPPER_SPEC_API_PORT', 9001).to_i
|
6
15
|
|
@@ -36,7 +45,7 @@ RSpec.describe Flipper::Adapters::Http do
|
|
36
45
|
],
|
37
46
|
}
|
38
47
|
@server = WEBrick::HTTPServer.new(server_options)
|
39
|
-
@server.mount '/',
|
48
|
+
@server.mount '/', rack_handler, app
|
40
49
|
|
41
50
|
Thread.new { @server.start }
|
42
51
|
Timeout.timeout(1) { :wait until @started }
|
data/spec/flipper/cli_spec.rb
CHANGED
@@ -1,13 +1,33 @@
|
|
1
1
|
require "flipper/cli"
|
2
2
|
|
3
3
|
RSpec.describe Flipper::CLI do
|
4
|
+
let(:stdout) { StringIO.new }
|
5
|
+
let(:stderr) { StringIO.new }
|
6
|
+
let(:cli) { Flipper::CLI.new(stdout: stdout, stderr: stderr) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
# Prentend stdout/stderr a TTY to test colorization
|
10
|
+
allow(stdout).to receive(:tty?).and_return(true)
|
11
|
+
allow(stderr).to receive(:tty?).and_return(true)
|
12
|
+
end
|
13
|
+
|
4
14
|
# Infer the command from the description
|
5
15
|
subject(:argv) do
|
6
16
|
descriptions = self.class.parent_groups.map {|g| g.metadata[:description_args] }.reverse.flatten.drop(1)
|
7
17
|
descriptions.map { |arg| Shellwords.split(arg) }.flatten
|
8
18
|
end
|
9
19
|
|
10
|
-
subject
|
20
|
+
subject do
|
21
|
+
status = 0
|
22
|
+
|
23
|
+
begin
|
24
|
+
cli.run(argv)
|
25
|
+
rescue SystemExit => e
|
26
|
+
status = e.status
|
27
|
+
end
|
28
|
+
|
29
|
+
OpenStruct.new(status: status, stdout: stdout.string, stderr: stderr.string)
|
30
|
+
end
|
11
31
|
|
12
32
|
before do
|
13
33
|
ENV["FLIPPER_REQUIRE"] = "./spec/fixtures/environment"
|
@@ -141,49 +161,4 @@ RSpec.describe Flipper::CLI do
|
|
141
161
|
it { should have_attributes(status: 0, stdout: /enabled.*admins/m) }
|
142
162
|
end
|
143
163
|
end
|
144
|
-
|
145
|
-
context "bundler is not installed" do
|
146
|
-
let(:argv) { "list" }
|
147
|
-
|
148
|
-
around do |example|
|
149
|
-
original_bundler = Bundler
|
150
|
-
begin
|
151
|
-
Object.send(:remove_const, :Bundler)
|
152
|
-
example.run
|
153
|
-
ensure
|
154
|
-
Object.const_set(:Bundler, original_bundler)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
it "should not raise an error" do
|
159
|
-
Flipper.enable(:enabled_feature)
|
160
|
-
Flipper.enable_group(:enabled_groups, :admins)
|
161
|
-
Flipper.add(:disabled_feature)
|
162
|
-
|
163
|
-
expect(subject).to have_attributes(status: 0, stdout: /enabled_feature.*enabled_groups.*disabled_feature/m)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
def run(argv)
|
168
|
-
original_stdout = $stdout
|
169
|
-
original_stderr = $stderr
|
170
|
-
|
171
|
-
$stdout = StringIO.new
|
172
|
-
$stderr = StringIO.new
|
173
|
-
status = 0
|
174
|
-
|
175
|
-
# Prentend this a TTY so we can test colorization
|
176
|
-
allow($stdout).to receive(:tty?).and_return(true)
|
177
|
-
|
178
|
-
begin
|
179
|
-
Flipper::CLI.run(argv)
|
180
|
-
rescue SystemExit => e
|
181
|
-
status = e.status
|
182
|
-
end
|
183
|
-
|
184
|
-
OpenStruct.new(status: status, stdout: $stdout.string, stderr: $stderr.string)
|
185
|
-
ensure
|
186
|
-
$stdout = original_stdout
|
187
|
-
$stderr = original_stderr
|
188
|
-
end
|
189
164
|
end
|
@@ -20,7 +20,8 @@ RSpec.describe Flipper::Cloud::Configuration do
|
|
20
20
|
it "can set instrumenter" do
|
21
21
|
instrumenter = Object.new
|
22
22
|
instance = described_class.new(required_options.merge(instrumenter: instrumenter))
|
23
|
-
expect(instance.instrumenter).to
|
23
|
+
expect(instance.instrumenter).to be_a(Flipper::Cloud::Telemetry::Instrumenter)
|
24
|
+
expect(instance.instrumenter.instrumenter).to be(instrumenter)
|
24
25
|
end
|
25
26
|
|
26
27
|
it "can set read_timeout" do
|
@@ -2,6 +2,12 @@ require 'flipper/cloud/telemetry'
|
|
2
2
|
require 'flipper/cloud/configuration'
|
3
3
|
|
4
4
|
RSpec.describe Flipper::Cloud::Telemetry do
|
5
|
+
before do
|
6
|
+
# Stub polling for features.
|
7
|
+
stub_request(:get, "https://www.flippercloud.io/adapter/features?exclude_gate_names=true").
|
8
|
+
to_return(status: 200, body: "{}")
|
9
|
+
end
|
10
|
+
|
5
11
|
it "phones home and does not update telemetry interval if missing" do
|
6
12
|
stub = stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
7
13
|
to_return(status: 200, body: "{}")
|
@@ -42,6 +48,52 @@ RSpec.describe Flipper::Cloud::Telemetry do
|
|
42
48
|
expect(stub).to have_been_requested
|
43
49
|
end
|
44
50
|
|
51
|
+
it "phones home and requests shutdown if telemetry-shutdown header is true" do
|
52
|
+
stub = stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
53
|
+
to_return(status: 404, body: "{}", headers: {"telemetry-shutdown" => "true"})
|
54
|
+
|
55
|
+
output = StringIO.new
|
56
|
+
cloud_configuration = Flipper::Cloud::Configuration.new(
|
57
|
+
token: "test",
|
58
|
+
logger: Logger.new(output),
|
59
|
+
logging_enabled: true,
|
60
|
+
)
|
61
|
+
|
62
|
+
# Record some telemetry and stop the threads so we submit a response.
|
63
|
+
telemetry = described_class.new(cloud_configuration)
|
64
|
+
telemetry.record(Flipper::Feature::InstrumentationName, {
|
65
|
+
operation: :enabled?,
|
66
|
+
feature_name: :foo,
|
67
|
+
result: true,
|
68
|
+
})
|
69
|
+
telemetry.stop
|
70
|
+
expect(stub).to have_been_requested
|
71
|
+
expect(output.string).to match(/action=telemetry_shutdown message=The server has requested that telemetry be shut down./)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "phones home and does not shutdown if telemetry shutdown header is missing" do
|
75
|
+
stub = stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
76
|
+
to_return(status: 404, body: "{}", headers: {})
|
77
|
+
|
78
|
+
output = StringIO.new
|
79
|
+
cloud_configuration = Flipper::Cloud::Configuration.new(
|
80
|
+
token: "test",
|
81
|
+
logger: Logger.new(output),
|
82
|
+
logging_enabled: true,
|
83
|
+
)
|
84
|
+
|
85
|
+
# Record some telemetry and stop the threads so we submit a response.
|
86
|
+
telemetry = described_class.new(cloud_configuration)
|
87
|
+
telemetry.record(Flipper::Feature::InstrumentationName, {
|
88
|
+
operation: :enabled?,
|
89
|
+
feature_name: :foo,
|
90
|
+
result: true,
|
91
|
+
})
|
92
|
+
telemetry.stop
|
93
|
+
expect(stub).to have_been_requested
|
94
|
+
expect(output.string).not_to match(/action=telemetry_shutdown message=The server has requested that telemetry be shut down./)
|
95
|
+
end
|
96
|
+
|
45
97
|
it "can update telemetry interval from error" do
|
46
98
|
stub = stub_request(:post, "https://www.flippercloud.io/adapter/telemetry").
|
47
99
|
to_return(status: 500, body: "{}", headers: {"telemetry-interval" => "120"})
|
data/spec/flipper/cloud_spec.rb
CHANGED
@@ -36,7 +36,8 @@ RSpec.describe Flipper::Cloud do
|
|
36
36
|
expect(client.uri.host).to eq('www.flippercloud.io')
|
37
37
|
expect(client.uri.path).to eq('/adapter')
|
38
38
|
expect(client.headers["flipper-cloud-token"]).to eq(token)
|
39
|
-
expect(@instance.instrumenter).to
|
39
|
+
expect(@instance.instrumenter).to be_a(Flipper::Cloud::Telemetry::Instrumenter)
|
40
|
+
expect(@instance.instrumenter.instrumenter).to be(Flipper::Instrumenters::Noop)
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
@@ -62,7 +63,8 @@ RSpec.describe Flipper::Cloud do
|
|
62
63
|
it 'can set instrumenter' do
|
63
64
|
instrumenter = Flipper::Instrumenters::Memory.new
|
64
65
|
instance = described_class.new(token: 'asdf', instrumenter: instrumenter)
|
65
|
-
expect(instance.instrumenter).to
|
66
|
+
expect(instance.instrumenter).to be_a(Flipper::Cloud::Telemetry::Instrumenter)
|
67
|
+
expect(instance.instrumenter.instrumenter).to be(instrumenter)
|
66
68
|
end
|
67
69
|
|
68
70
|
it 'allows wrapping adapter with another adapter like the instrumenter' do
|
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
|
|
@@ -234,7 +236,8 @@ RSpec.describe Flipper::Engine do
|
|
234
236
|
application.initialize!
|
235
237
|
|
236
238
|
expect(Flipper.instance).to be_a(Flipper::Cloud::DSL)
|
237
|
-
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)
|
238
241
|
end
|
239
242
|
|
240
243
|
context "with CLOUD_SYNC_SECRET" do
|
@@ -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
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'ice_age'
|
2
2
|
require 'json'
|
3
3
|
require 'rack/test'
|
4
|
+
require 'rack/session'
|
4
5
|
|
5
6
|
module SpecHelpers
|
6
7
|
extend self
|
@@ -12,7 +13,7 @@ module SpecHelpers
|
|
12
13
|
|
13
14
|
def build_app(flipper, options = {})
|
14
15
|
Flipper::UI.app(flipper, options) do |builder|
|
15
|
-
builder.use Rack::Session::Cookie, secret: 'test'
|
16
|
+
builder.use Rack::Session::Cookie, secret: 'test' * 16 # Rack 3+ wants a 64-character secret
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
@@ -29,7 +29,7 @@ end
|
|
29
29
|
|
30
30
|
class TestHelpTest < ActionDispatch::SystemTestCase
|
31
31
|
# Any driver that runs the app in a separate thread will test what we want here.
|
32
|
-
driven_by :cuprite, options: { process_timeout:
|
32
|
+
driven_by :cuprite, options: { process_timeout: 60 }
|
33
33
|
|
34
34
|
setup do
|
35
35
|
# Reconfigure Flipper since other tests change the adapter.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- lib/flipper/actor.rb
|
91
91
|
- lib/flipper/adapter.rb
|
92
92
|
- lib/flipper/adapter_builder.rb
|
93
|
+
- lib/flipper/adapters/cache_base.rb
|
93
94
|
- lib/flipper/adapters/dual_write.rb
|
94
95
|
- lib/flipper/adapters/failover.rb
|
95
96
|
- lib/flipper/adapters/failsafe.rb
|
@@ -109,6 +110,7 @@ files:
|
|
109
110
|
- lib/flipper/adapters/sync/feature_synchronizer.rb
|
110
111
|
- lib/flipper/adapters/sync/interval_synchronizer.rb
|
111
112
|
- lib/flipper/adapters/sync/synchronizer.rb
|
113
|
+
- lib/flipper/adapters/wrapper.rb
|
112
114
|
- lib/flipper/cli.rb
|
113
115
|
- lib/flipper/cloud.rb
|
114
116
|
- lib/flipper/cloud/configuration.rb
|
@@ -193,6 +195,8 @@ files:
|
|
193
195
|
- lib/generators/flipper/templates/update/migrations/01_create_flipper_tables.rb.erb
|
194
196
|
- lib/generators/flipper/templates/update/migrations/02_change_flipper_gates_value_to_text.rb.erb
|
195
197
|
- lib/generators/flipper/update_generator.rb
|
198
|
+
- package-lock.json
|
199
|
+
- package.json
|
196
200
|
- spec/fixtures/environment.rb
|
197
201
|
- spec/fixtures/feature.json
|
198
202
|
- spec/fixtures/flipper_pstore_1679087600.json
|
@@ -287,6 +291,7 @@ files:
|
|
287
291
|
- spec/spec_helper.rb
|
288
292
|
- spec/support/actor_names.yml
|
289
293
|
- spec/support/descriptions.yml
|
294
|
+
- spec/support/fail_on_output.rb
|
290
295
|
- spec/support/fake_backoff_policy.rb
|
291
296
|
- spec/support/fake_udp_socket.rb
|
292
297
|
- spec/support/skippable.rb
|
@@ -306,7 +311,7 @@ metadata:
|
|
306
311
|
homepage_uri: https://www.flippercloud.io
|
307
312
|
source_code_uri: https://github.com/flippercloud/flipper
|
308
313
|
bug_tracker_uri: https://github.com/flippercloud/flipper/issues
|
309
|
-
changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.
|
314
|
+
changelog_uri: https://github.com/flippercloud/flipper/releases/tag/v1.3.0.pre
|
310
315
|
post_install_message:
|
311
316
|
rdoc_options: []
|
312
317
|
require_paths:
|
@@ -421,6 +426,7 @@ test_files:
|
|
421
426
|
- spec/spec_helper.rb
|
422
427
|
- spec/support/actor_names.yml
|
423
428
|
- spec/support/descriptions.yml
|
429
|
+
- spec/support/fail_on_output.rb
|
424
430
|
- spec/support/fake_backoff_policy.rb
|
425
431
|
- spec/support/fake_udp_socket.rb
|
426
432
|
- spec/support/skippable.rb
|