flipper 0.16.0 → 1.4.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 +5 -5
- data/.codeclimate.yml +1 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/ci.yml +110 -0
- data/.github/workflows/examples.yml +105 -0
- data/.github/workflows/release.yml +54 -0
- data/.rspec +1 -0
- data/CLAUDE.md +87 -0
- data/Changelog.md +2 -215
- data/Dockerfile +1 -1
- data/Gemfile +28 -20
- data/README.md +72 -62
- data/Rakefile +13 -3
- data/benchmark/enabled_ips.rb +10 -0
- data/benchmark/enabled_multiple_actors_ips.rb +20 -0
- data/benchmark/enabled_profile.rb +20 -0
- data/benchmark/instrumentation_ips.rb +21 -0
- data/benchmark/typecast_ips.rb +27 -0
- data/docker-compose.yml +37 -34
- data/docs/DockerCompose.md +0 -1
- data/docs/README.md +1 -0
- data/docs/images/banner.jpg +0 -0
- data/docs/images/flipper_cloud.png +0 -0
- data/examples/api/basic.ru +18 -0
- data/examples/api/custom_memoized.ru +36 -0
- data/examples/api/memoized.ru +42 -0
- data/examples/basic.rb +1 -12
- data/examples/cloud/app.ru +12 -0
- data/examples/cloud/backoff_policy.rb +13 -0
- data/examples/cloud/basic.rb +22 -0
- data/examples/cloud/cloud_setup.rb +20 -0
- data/examples/cloud/forked.rb +36 -0
- data/examples/cloud/import.rb +17 -0
- data/examples/cloud/poll_interval/README.md +111 -0
- data/examples/cloud/poll_interval/client.rb +108 -0
- data/examples/cloud/poll_interval/server.rb +98 -0
- data/examples/cloud/threaded.rb +33 -0
- data/examples/configuring_default.rb +2 -5
- data/examples/dsl.rb +10 -35
- data/examples/enabled_for_actor.rb +10 -15
- data/examples/expressions.rb +237 -0
- data/examples/group.rb +3 -6
- data/examples/group_dynamic_lookup.rb +5 -19
- data/examples/group_with_members.rb +4 -14
- data/examples/importing.rb +1 -1
- data/examples/individual_actor.rb +2 -5
- data/examples/instrumentation.rb +2 -2
- data/examples/instrumentation_last_accessed_at.rb +38 -0
- data/examples/memoizing.rb +35 -0
- data/examples/mirroring.rb +59 -0
- data/examples/percentage_of_actors.rb +6 -16
- data/examples/percentage_of_actors_enabled_check.rb +7 -10
- data/examples/percentage_of_actors_group.rb +5 -18
- data/examples/percentage_of_time.rb +3 -6
- data/examples/strict.rb +18 -0
- data/exe/flipper +5 -0
- data/flipper-cloud.gemspec +19 -0
- data/flipper.gemspec +10 -7
- data/lib/flipper/actor.rb +10 -3
- data/lib/flipper/adapter.rb +50 -8
- data/lib/flipper/adapter_builder.rb +44 -0
- data/lib/flipper/adapters/actor_limit.rb +54 -0
- data/lib/flipper/adapters/cache_base.rb +161 -0
- data/lib/flipper/adapters/dual_write.rb +63 -0
- data/lib/flipper/adapters/failover.rb +85 -0
- data/lib/flipper/adapters/failsafe.rb +72 -0
- data/lib/flipper/adapters/http/client.rb +64 -7
- data/lib/flipper/adapters/http/error.rb +19 -1
- data/lib/flipper/adapters/http.rb +97 -43
- data/lib/flipper/adapters/instrumented.rb +47 -26
- data/lib/flipper/adapters/memoizable.rb +44 -40
- data/lib/flipper/adapters/memory.rb +75 -111
- data/lib/flipper/adapters/operation_logger.rb +22 -78
- data/lib/flipper/adapters/poll/poller.rb +2 -0
- data/lib/flipper/adapters/poll.rb +52 -0
- data/lib/flipper/adapters/pstore.rb +27 -17
- data/lib/flipper/adapters/read_only.rb +8 -41
- data/lib/flipper/adapters/strict.rb +45 -0
- data/lib/flipper/adapters/sync/feature_synchronizer.rb +14 -1
- data/lib/flipper/adapters/sync/interval_synchronizer.rb +2 -7
- data/lib/flipper/adapters/sync/synchronizer.rb +13 -6
- data/lib/flipper/adapters/sync.rb +23 -29
- data/lib/flipper/adapters/wrapper.rb +54 -0
- data/lib/flipper/cli.rb +314 -0
- data/lib/flipper/cloud/configuration.rb +271 -0
- data/lib/flipper/cloud/dsl.rb +27 -0
- data/lib/flipper/cloud/message_verifier.rb +95 -0
- data/lib/flipper/cloud/middleware.rb +63 -0
- data/lib/flipper/cloud/migrate.rb +71 -0
- data/lib/flipper/cloud/routes.rb +14 -0
- data/lib/flipper/cloud/telemetry/backoff_policy.rb +96 -0
- data/lib/flipper/cloud/telemetry/instrumenter.rb +22 -0
- data/lib/flipper/cloud/telemetry/metric.rb +39 -0
- data/lib/flipper/cloud/telemetry/metric_storage.rb +30 -0
- data/lib/flipper/cloud/telemetry/submitter.rb +100 -0
- data/lib/flipper/cloud/telemetry.rb +191 -0
- data/lib/flipper/cloud.rb +54 -0
- data/lib/flipper/configuration.rb +54 -7
- data/lib/flipper/dsl.rb +58 -47
- data/lib/flipper/engine.rb +102 -0
- data/lib/flipper/errors.rb +3 -21
- data/lib/flipper/export.rb +24 -0
- data/lib/flipper/exporter.rb +17 -0
- data/lib/flipper/exporters/json/export.rb +32 -0
- data/lib/flipper/exporters/json/v1.rb +33 -0
- data/lib/flipper/expression/builder.rb +73 -0
- data/lib/flipper/expression/constant.rb +25 -0
- data/lib/flipper/expression.rb +71 -0
- data/lib/flipper/expressions/all.rb +9 -0
- data/lib/flipper/expressions/any.rb +9 -0
- data/lib/flipper/expressions/boolean.rb +9 -0
- data/lib/flipper/expressions/comparable.rb +13 -0
- data/lib/flipper/expressions/equal.rb +9 -0
- data/lib/flipper/expressions/feature_enabled.rb +34 -0
- data/lib/flipper/expressions/greater_than.rb +9 -0
- data/lib/flipper/expressions/greater_than_or_equal_to.rb +9 -0
- data/lib/flipper/expressions/less_than.rb +9 -0
- data/lib/flipper/expressions/less_than_or_equal_to.rb +9 -0
- data/lib/flipper/expressions/not_equal.rb +9 -0
- data/lib/flipper/expressions/now.rb +9 -0
- data/lib/flipper/expressions/number.rb +9 -0
- data/lib/flipper/expressions/percentage.rb +9 -0
- data/lib/flipper/expressions/percentage_of_actors.rb +12 -0
- data/lib/flipper/expressions/property.rb +9 -0
- data/lib/flipper/expressions/random.rb +9 -0
- data/lib/flipper/expressions/string.rb +9 -0
- data/lib/flipper/expressions/time.rb +16 -0
- data/lib/flipper/feature.rb +95 -28
- data/lib/flipper/feature_check_context.rb +10 -6
- data/lib/flipper/gate.rb +13 -11
- data/lib/flipper/gate_values.rb +5 -18
- data/lib/flipper/gates/actor.rb +10 -17
- data/lib/flipper/gates/boolean.rb +1 -1
- data/lib/flipper/gates/expression.rb +75 -0
- data/lib/flipper/gates/group.rb +5 -7
- data/lib/flipper/gates/percentage_of_actors.rb +10 -13
- data/lib/flipper/gates/percentage_of_time.rb +1 -2
- data/lib/flipper/identifier.rb +17 -0
- data/lib/flipper/instrumentation/log_subscriber.rb +35 -8
- data/lib/flipper/instrumentation/statsd.rb +4 -2
- data/lib/flipper/instrumentation/statsd_subscriber.rb +2 -4
- data/lib/flipper/instrumentation/subscriber.rb +8 -5
- data/lib/flipper/instrumenters/memory.rb +6 -2
- data/lib/flipper/metadata.rb +8 -1
- data/lib/flipper/middleware/memoizer.rb +46 -27
- data/lib/flipper/middleware/setup_env.rb +13 -3
- data/lib/flipper/model/active_record.rb +23 -0
- data/lib/flipper/poller.rb +157 -0
- data/lib/flipper/serializers/gzip.rb +22 -0
- data/lib/flipper/serializers/json.rb +17 -0
- data/lib/flipper/spec/shared_adapter_specs.rb +122 -56
- data/lib/flipper/test/shared_adapter_test.rb +120 -52
- data/lib/flipper/test_help.rb +43 -0
- data/lib/flipper/typecast.rb +59 -18
- data/lib/flipper/types/actor.rb +19 -13
- data/lib/flipper/types/group.rb +12 -5
- data/lib/flipper/types/percentage.rb +1 -1
- data/lib/flipper/version.rb +11 -1
- data/lib/flipper.rb +71 -12
- data/lib/generators/flipper/setup_generator.rb +68 -0
- data/lib/generators/flipper/templates/initializer.rb +45 -0
- data/lib/generators/flipper/templates/update/migrations/01_create_flipper_tables.rb.erb +22 -0
- data/lib/generators/flipper/templates/update/migrations/02_change_flipper_gates_value_to_text.rb.erb +18 -0
- data/lib/generators/flipper/update_generator.rb +35 -0
- data/package-lock.json +41 -0
- data/package.json +10 -0
- data/spec/fixtures/environment.rb +1 -0
- data/spec/fixtures/flipper_pstore_1679087600.json +46 -0
- data/spec/flipper/actor_spec.rb +10 -2
- data/spec/flipper/adapter_builder_spec.rb +72 -0
- data/spec/flipper/adapter_spec.rb +52 -6
- data/spec/flipper/adapters/actor_limit_spec.rb +75 -0
- data/spec/flipper/adapters/dual_write_spec.rb +82 -0
- data/spec/flipper/adapters/failover_spec.rb +141 -0
- data/spec/flipper/adapters/failsafe_spec.rb +58 -0
- data/spec/flipper/adapters/http/client_spec.rb +61 -0
- data/spec/flipper/adapters/http_spec.rb +402 -65
- data/spec/flipper/adapters/instrumented_spec.rb +31 -13
- data/spec/flipper/adapters/memoizable_spec.rb +51 -33
- data/spec/flipper/adapters/memory_spec.rb +33 -5
- data/spec/flipper/adapters/operation_logger_spec.rb +38 -12
- data/spec/flipper/adapters/poll_spec.rb +41 -0
- data/spec/flipper/adapters/pstore_spec.rb +0 -2
- data/spec/flipper/adapters/read_only_spec.rb +32 -18
- data/spec/flipper/adapters/strict_spec.rb +64 -0
- data/spec/flipper/adapters/sync/feature_synchronizer_spec.rb +39 -1
- data/spec/flipper/adapters/sync/interval_synchronizer_spec.rb +4 -5
- data/spec/flipper/adapters/sync/synchronizer_spec.rb +87 -1
- data/spec/flipper/adapters/sync_spec.rb +17 -6
- data/spec/flipper/cli_spec.rb +217 -0
- data/spec/flipper/cloud/configuration_spec.rb +257 -0
- data/spec/flipper/cloud/dsl_spec.rb +90 -0
- data/spec/flipper/cloud/message_verifier_spec.rb +104 -0
- data/spec/flipper/cloud/middleware_spec.rb +307 -0
- data/spec/flipper/cloud/migrate_spec.rb +160 -0
- data/spec/flipper/cloud/telemetry/backoff_policy_spec.rb +107 -0
- data/spec/flipper/cloud/telemetry/metric_spec.rb +87 -0
- data/spec/flipper/cloud/telemetry/metric_storage_spec.rb +58 -0
- data/spec/flipper/cloud/telemetry/submitter_spec.rb +145 -0
- data/spec/flipper/cloud/telemetry_spec.rb +208 -0
- data/spec/flipper/cloud_spec.rb +186 -0
- data/spec/flipper/configuration_spec.rb +37 -3
- data/spec/flipper/dsl_spec.rb +67 -80
- data/spec/flipper/engine_spec.rb +374 -0
- data/spec/flipper/export_spec.rb +13 -0
- data/spec/flipper/exporter_spec.rb +16 -0
- data/spec/flipper/exporters/json/export_spec.rb +60 -0
- data/spec/flipper/exporters/json/v1_spec.rb +33 -0
- data/spec/flipper/expression/builder_spec.rb +248 -0
- data/spec/flipper/expression_spec.rb +188 -0
- data/spec/flipper/expressions/all_spec.rb +15 -0
- data/spec/flipper/expressions/any_spec.rb +15 -0
- data/spec/flipper/expressions/boolean_spec.rb +15 -0
- data/spec/flipper/expressions/equal_spec.rb +24 -0
- data/spec/flipper/expressions/greater_than_or_equal_to_spec.rb +28 -0
- data/spec/flipper/expressions/greater_than_spec.rb +28 -0
- data/spec/flipper/expressions/less_than_or_equal_to_spec.rb +28 -0
- data/spec/flipper/expressions/less_than_spec.rb +32 -0
- data/spec/flipper/expressions/not_equal_spec.rb +15 -0
- data/spec/flipper/expressions/now_spec.rb +11 -0
- data/spec/flipper/expressions/number_spec.rb +21 -0
- data/spec/flipper/expressions/percentage_of_actors_spec.rb +20 -0
- data/spec/flipper/expressions/percentage_spec.rb +15 -0
- data/spec/flipper/expressions/property_spec.rb +13 -0
- data/spec/flipper/expressions/random_spec.rb +9 -0
- data/spec/flipper/expressions/string_spec.rb +11 -0
- data/spec/flipper/expressions/time_spec.rb +29 -0
- data/spec/flipper/feature_check_context_spec.rb +18 -20
- data/spec/flipper/feature_spec.rb +461 -48
- data/spec/flipper/gate_spec.rb +0 -2
- data/spec/flipper/gate_values_spec.rb +2 -34
- data/spec/flipper/gates/actor_spec.rb +0 -2
- data/spec/flipper/gates/boolean_spec.rb +1 -3
- data/spec/flipper/gates/expression_spec.rb +190 -0
- data/spec/flipper/gates/group_spec.rb +2 -5
- data/spec/flipper/gates/percentage_of_actors_spec.rb +61 -7
- data/spec/flipper/gates/percentage_of_time_spec.rb +2 -4
- data/spec/flipper/identifier_spec.rb +12 -0
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +24 -7
- data/spec/flipper/instrumentation/statsd_subscriber_spec.rb +26 -3
- data/spec/flipper/instrumenters/memory_spec.rb +18 -1
- data/spec/flipper/instrumenters/noop_spec.rb +14 -8
- data/spec/flipper/middleware/memoizer_spec.rb +199 -62
- data/spec/flipper/middleware/setup_env_spec.rb +23 -5
- data/spec/flipper/model/active_record_spec.rb +72 -0
- data/spec/flipper/poller_spec.rb +390 -0
- data/spec/flipper/registry_spec.rb +0 -1
- data/spec/flipper/serializers/gzip_spec.rb +13 -0
- data/spec/flipper/serializers/json_spec.rb +13 -0
- data/spec/flipper/typecast_spec.rb +121 -7
- data/spec/flipper/types/actor_spec.rb +63 -47
- data/spec/flipper/types/boolean_spec.rb +0 -1
- data/spec/flipper/types/group_spec.rb +24 -3
- data/spec/flipper/types/percentage_of_actors_spec.rb +0 -1
- data/spec/flipper/types/percentage_of_time_spec.rb +0 -1
- data/spec/flipper/types/percentage_spec.rb +0 -1
- data/spec/{integration_spec.rb → flipper_integration_spec.rb} +301 -59
- data/spec/flipper_spec.rb +123 -29
- data/spec/{helper.rb → spec_helper.rb} +23 -21
- data/spec/support/actor_names.yml +1 -0
- data/spec/support/descriptions.yml +1 -0
- data/spec/support/fail_on_output.rb +8 -0
- data/spec/support/fake_backoff_policy.rb +15 -0
- data/spec/support/skippable.rb +18 -0
- data/spec/support/spec_helpers.rb +53 -6
- data/test/adapters/actor_limit_test.rb +20 -0
- data/test/test_helper.rb +2 -1
- data/test_rails/generators/flipper/setup_generator_test.rb +69 -0
- data/test_rails/generators/flipper/update_generator_test.rb +96 -0
- data/test_rails/helper.rb +31 -0
- data/test_rails/system/test_help_test.rb +52 -0
- metadata +200 -82
- data/.rubocop.yml +0 -54
- data/.rubocop_todo.yml +0 -199
- data/docs/Adapters.md +0 -124
- data/docs/Caveats.md +0 -4
- data/docs/Gates.md +0 -167
- data/docs/Instrumentation.md +0 -27
- data/docs/Optimization.md +0 -114
- data/docs/api/README.md +0 -849
- data/docs/http/README.md +0 -35
- data/docs/read-only/README.md +0 -21
- data/examples/example_setup.rb +0 -8
- data/test/helper.rb +0 -11
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require 'helper'
|
|
2
1
|
require 'flipper/gate_values'
|
|
3
2
|
|
|
4
3
|
RSpec.describe Flipper::GateValues do
|
|
@@ -81,13 +80,13 @@ RSpec.describe Flipper::GateValues do
|
|
|
81
80
|
it 'raises argument error for percentage of time value that cannot be converted to an integer' do
|
|
82
81
|
expect do
|
|
83
82
|
described_class.new(percentage_of_time: ['asdf'])
|
|
84
|
-
end.to raise_error(ArgumentError, %(["asdf"] cannot be converted to
|
|
83
|
+
end.to raise_error(ArgumentError, %(["asdf"] cannot be converted to a number))
|
|
85
84
|
end
|
|
86
85
|
|
|
87
86
|
it 'raises argument error for percentage of actors value that cannot be converted to an int' do
|
|
88
87
|
expect do
|
|
89
88
|
described_class.new(percentage_of_actors: ['asdf'])
|
|
90
|
-
end.to raise_error(ArgumentError, %(["asdf"] cannot be converted to
|
|
89
|
+
end.to raise_error(ArgumentError, %(["asdf"] cannot be converted to a number))
|
|
91
90
|
end
|
|
92
91
|
|
|
93
92
|
it 'raises argument error for actors value that cannot be converted to a set' do
|
|
@@ -101,35 +100,4 @@ RSpec.describe Flipper::GateValues do
|
|
|
101
100
|
described_class.new(groups: 'asdf')
|
|
102
101
|
end.to raise_error(ArgumentError, %("asdf" cannot be converted to a set))
|
|
103
102
|
end
|
|
104
|
-
|
|
105
|
-
describe '#[]' do
|
|
106
|
-
it 'can read the boolean value' do
|
|
107
|
-
expect(described_class.new(boolean: true)[:boolean]).to be(true)
|
|
108
|
-
expect(described_class.new(boolean: true)['boolean']).to be(true)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
it 'can read the actors value' do
|
|
112
|
-
expect(described_class.new(actors: Set[1, 2])[:actors]).to eq(Set[1, 2])
|
|
113
|
-
expect(described_class.new(actors: Set[1, 2])['actors']).to eq(Set[1, 2])
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
it 'can read the groups value' do
|
|
117
|
-
expect(described_class.new(groups: Set[:admins])[:groups]).to eq(Set[:admins])
|
|
118
|
-
expect(described_class.new(groups: Set[:admins])['groups']).to eq(Set[:admins])
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
it 'can read the percentage of time value' do
|
|
122
|
-
expect(described_class.new(percentage_of_time: 15)[:percentage_of_time]).to eq(15)
|
|
123
|
-
expect(described_class.new(percentage_of_time: 15)['percentage_of_time']).to eq(15)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
it 'can read the percentage of actors value' do
|
|
127
|
-
expect(described_class.new(percentage_of_actors: 15)[:percentage_of_actors]).to eq(15)
|
|
128
|
-
expect(described_class.new(percentage_of_actors: 15)['percentage_of_actors']).to eq(15)
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
it 'returns nil for value that is not present' do
|
|
132
|
-
expect(described_class.new({})['not legit']).to be(nil)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
103
|
end
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'helper'
|
|
2
|
-
|
|
3
1
|
RSpec.describe Flipper::Gates::Boolean do
|
|
4
2
|
let(:feature_name) { :search }
|
|
5
3
|
|
|
@@ -11,7 +9,7 @@ RSpec.describe Flipper::Gates::Boolean do
|
|
|
11
9
|
Flipper::FeatureCheckContext.new(
|
|
12
10
|
feature_name: feature_name,
|
|
13
11
|
values: Flipper::GateValues.new(boolean: bool),
|
|
14
|
-
|
|
12
|
+
actors: [Flipper::Types::Actor.new(Flipper::Actor.new('1'))]
|
|
15
13
|
)
|
|
16
14
|
end
|
|
17
15
|
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
RSpec.describe Flipper::Gates::Expression do
|
|
2
|
+
let(:feature_name) { :search }
|
|
3
|
+
|
|
4
|
+
subject do
|
|
5
|
+
described_class.new
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def context(expression, properties: {})
|
|
9
|
+
Flipper::FeatureCheckContext.new(
|
|
10
|
+
feature_name: feature_name,
|
|
11
|
+
values: Flipper::GateValues.new(expression: expression),
|
|
12
|
+
actors: [Flipper::Types::Actor.new(Flipper::Actor.new(1, properties))]
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '#enabled?' do
|
|
17
|
+
context 'for nil value' do
|
|
18
|
+
it 'returns false' do
|
|
19
|
+
expect(subject.enabled?(nil)).to eq(false)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context 'for empty value' do
|
|
24
|
+
it 'returns false' do
|
|
25
|
+
expect(subject.enabled?({})).to eq(false)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context "for not empty value" do
|
|
30
|
+
it 'returns true' do
|
|
31
|
+
expect(subject.enabled?({"Boolean" => [true]})).to eq(true)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '#open?' do
|
|
37
|
+
context 'for expression that evaluates to true' do
|
|
38
|
+
it 'returns true' do
|
|
39
|
+
expression = Flipper.boolean(true).eq(true)
|
|
40
|
+
expect(subject.open?(context(expression.value))).to be(true)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'for expression that evaluates to false' do
|
|
45
|
+
it 'returns false' do
|
|
46
|
+
expression = Flipper.boolean(true).eq(false)
|
|
47
|
+
expect(subject.open?(context(expression.value))).to be(false)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'for properties that have string keys' do
|
|
52
|
+
it 'returns true when expression evalutes to true' do
|
|
53
|
+
expression = Flipper.property(:type).eq("User")
|
|
54
|
+
context = context(expression.value, properties: {"type" => "User"})
|
|
55
|
+
expect(subject.open?(context)).to be(true)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'returns false when expression evaluates to false' do
|
|
59
|
+
expression = Flipper.property(:type).eq("User")
|
|
60
|
+
context = context(expression.value, properties: {"type" => "Org"})
|
|
61
|
+
expect(subject.open?(context)).to be(false)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context 'for actor in context' do
|
|
66
|
+
it 'passes actor to expression context' do
|
|
67
|
+
actor = Flipper::Actor.new("User;1", {type: "User"})
|
|
68
|
+
wrapped_actor = Flipper::Types::Actor.new(actor)
|
|
69
|
+
expression = Flipper.property(:flipper_id).eq("User;1")
|
|
70
|
+
ctx = Flipper::FeatureCheckContext.new(
|
|
71
|
+
feature_name: feature_name,
|
|
72
|
+
values: Flipper::GateValues.new(expression: expression.value),
|
|
73
|
+
actors: [wrapped_actor]
|
|
74
|
+
)
|
|
75
|
+
expect(subject.open?(ctx)).to be(true)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'passes nil actor when no actors provided' do
|
|
79
|
+
expression = Flipper.boolean(true).eq(true)
|
|
80
|
+
ctx = Flipper::FeatureCheckContext.new(
|
|
81
|
+
feature_name: feature_name,
|
|
82
|
+
values: Flipper::GateValues.new(expression: expression.value),
|
|
83
|
+
actors: nil
|
|
84
|
+
)
|
|
85
|
+
expect(subject.open?(ctx)).to be(true)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
context 'for properties that have symbol keys' do
|
|
90
|
+
it 'returns true when expression evalutes to true' do
|
|
91
|
+
expression = Flipper.property(:type).eq("User")
|
|
92
|
+
context = context(expression.value, properties: {type: "User"})
|
|
93
|
+
expect(subject.open?(context)).to be(true)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it 'returns false when expression evaluates to false' do
|
|
97
|
+
expression = Flipper.property(:type).eq("User")
|
|
98
|
+
context = context(expression.value, properties: {type: "Org"})
|
|
99
|
+
expect(subject.open?(context)).to be(false)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context 'for time-based expressions' do
|
|
104
|
+
it 'enables when now is past a scheduled epoch' do
|
|
105
|
+
past_epoch = Time.now.to_i - 86_400
|
|
106
|
+
expression = Flipper.now.gte(Flipper.time(past_epoch))
|
|
107
|
+
expect(subject.open?(context(expression.value))).to be(true)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it 'does not enable when now is before a future epoch' do
|
|
111
|
+
future_epoch = Time.now.to_i + 86_400
|
|
112
|
+
expression = Flipper.now.gte(Flipper.time(future_epoch))
|
|
113
|
+
expect(subject.open?(context(expression.value))).to be(false)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'enables when now is past a scheduled datetime' do
|
|
117
|
+
past_time = (Time.now.utc - 86_400).iso8601
|
|
118
|
+
expression = Flipper.now.gte(Flipper.time(past_time))
|
|
119
|
+
expect(subject.open?(context(expression.value))).to be(true)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'does not enable when now is before a future datetime' do
|
|
123
|
+
future_time = (Time.now.utc + 86_400).iso8601
|
|
124
|
+
expression = Flipper.now.gte(Flipper.time(future_time))
|
|
125
|
+
expect(subject.open?(context(expression.value))).to be(false)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'enables expiring features with lt' do
|
|
129
|
+
future_time = (Time.now.utc + 86_400).iso8601
|
|
130
|
+
expression = Flipper.now.lt(Flipper.time(future_time))
|
|
131
|
+
expect(subject.open?(context(expression.value))).to be(true)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'disables expired features with lt' do
|
|
135
|
+
past_time = (Time.now.utc - 86_400).iso8601
|
|
136
|
+
expression = Flipper.now.lt(Flipper.time(past_time))
|
|
137
|
+
expect(subject.open?(context(expression.value))).to be(false)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it 'enables within a time window using all' do
|
|
141
|
+
start_time = (Time.now.utc - 86_400).iso8601
|
|
142
|
+
end_time = (Time.now.utc + 86_400).iso8601
|
|
143
|
+
expression = Flipper.all(
|
|
144
|
+
Flipper.now.gte(Flipper.time(start_time)),
|
|
145
|
+
Flipper.now.lt(Flipper.time(end_time))
|
|
146
|
+
)
|
|
147
|
+
expect(subject.open?(context(expression.value))).to be(true)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it 'does not enable outside a time window' do
|
|
151
|
+
start_time = (Time.now.utc + 86_400).iso8601
|
|
152
|
+
end_time = (Time.now.utc + 172_800).iso8601
|
|
153
|
+
expression = Flipper.all(
|
|
154
|
+
Flipper.now.gte(Flipper.time(start_time)),
|
|
155
|
+
Flipper.now.lt(Flipper.time(end_time))
|
|
156
|
+
)
|
|
157
|
+
expect(subject.open?(context(expression.value))).to be(false)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
describe '#protects?' do
|
|
163
|
+
it 'returns true for Flipper::Expression' do
|
|
164
|
+
expression = Flipper.number(20).eq(20)
|
|
165
|
+
expect(subject.protects?(expression)).to be(true)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it 'returns true for Hash' do
|
|
169
|
+
expression = Flipper.number(20).eq(20)
|
|
170
|
+
expect(subject.protects?(expression.value)).to be(true)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it 'returns false for other things' do
|
|
174
|
+
expect(subject.protects?(false)).to be(false)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
describe '#wrap' do
|
|
179
|
+
it 'returns self for Flipper::Expression' do
|
|
180
|
+
expression = Flipper.number(20).eq(20)
|
|
181
|
+
expect(subject.wrap(expression)).to be(expression)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it 'returns Flipper::Expression for Hash' do
|
|
185
|
+
expression = Flipper.number(20).eq(20)
|
|
186
|
+
expect(subject.wrap(expression.value)).to be_instance_of(Flipper::Expression)
|
|
187
|
+
expect(subject.wrap(expression.value)).to eq(expression)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'helper'
|
|
2
|
-
|
|
3
1
|
RSpec.describe Flipper::Gates::Group do
|
|
4
2
|
let(:feature_name) { :search }
|
|
5
3
|
|
|
@@ -11,18 +9,17 @@ RSpec.describe Flipper::Gates::Group do
|
|
|
11
9
|
Flipper::FeatureCheckContext.new(
|
|
12
10
|
feature_name: feature_name,
|
|
13
11
|
values: Flipper::GateValues.new(groups: set),
|
|
14
|
-
|
|
12
|
+
actors: [Flipper::Types::Actor.new(Flipper::Actor.new('5'))]
|
|
15
13
|
)
|
|
16
14
|
end
|
|
17
15
|
|
|
18
16
|
describe '#open?' do
|
|
19
17
|
context 'with a group in adapter, but not registered' do
|
|
20
18
|
before do
|
|
21
|
-
Flipper.register(:staff) { |
|
|
19
|
+
Flipper.register(:staff) { |actor| true }
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
it 'ignores group' do
|
|
25
|
-
thing = Flipper::Actor.new('5')
|
|
26
23
|
expect(subject.open?(context(Set[:newbs, :staff]))).to be(true)
|
|
27
24
|
end
|
|
28
25
|
end
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'helper'
|
|
2
|
-
|
|
3
1
|
RSpec.describe Flipper::Gates::PercentageOfActors do
|
|
4
2
|
let(:feature_name) { :search }
|
|
5
3
|
|
|
@@ -7,11 +5,11 @@ RSpec.describe Flipper::Gates::PercentageOfActors do
|
|
|
7
5
|
described_class.new
|
|
8
6
|
end
|
|
9
7
|
|
|
10
|
-
def context(percentage_of_actors_value, feature = feature_name,
|
|
8
|
+
def context(percentage_of_actors_value, feature = feature_name, actors = nil)
|
|
11
9
|
Flipper::FeatureCheckContext.new(
|
|
12
10
|
feature_name: feature,
|
|
13
11
|
values: Flipper::GateValues.new(percentage_of_actors: percentage_of_actors_value),
|
|
14
|
-
|
|
12
|
+
actors: Array(actors) || [Flipper::Types::Actor.new(Flipper::Actor.new('1'))]
|
|
15
13
|
)
|
|
16
14
|
end
|
|
17
15
|
|
|
@@ -22,7 +20,7 @@ RSpec.describe Flipper::Gates::PercentageOfActors do
|
|
|
22
20
|
let(:number_of_actors) { 10_000 }
|
|
23
21
|
|
|
24
22
|
let(:actors) do
|
|
25
|
-
(1..number_of_actors).map { |n| Flipper::Actor.new(n) }
|
|
23
|
+
(1..number_of_actors).map { |n| Flipper::Types::Actor.new(Flipper::Actor.new(n.to_s)) }
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
let(:feature_one_enabled_actors) do
|
|
@@ -50,13 +48,69 @@ RSpec.describe Flipper::Gates::PercentageOfActors do
|
|
|
50
48
|
end
|
|
51
49
|
end
|
|
52
50
|
|
|
51
|
+
context "with an array of actors" do
|
|
52
|
+
let(:percentage) { 0.05 }
|
|
53
|
+
let(:percentage_as_integer) { percentage * 100 }
|
|
54
|
+
let(:number_of_actors) { 3_000 }
|
|
55
|
+
|
|
56
|
+
let(:user_actors) do
|
|
57
|
+
(1..number_of_actors).map { |n| Flipper::Types::Actor.new(Flipper::Actor.new("User;#{n}")) }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
let(:team_actors) do
|
|
61
|
+
(1..number_of_actors).map { |n| Flipper::Types::Actor.new(Flipper::Actor.new("Team;#{n}")) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
let(:org_actors) do
|
|
65
|
+
(1..number_of_actors).map { |n| Flipper::Types::Actor.new(Flipper::Actor.new("Org;#{n}")) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
let(:actors) { user_actors + team_actors + org_actors }
|
|
69
|
+
|
|
70
|
+
let(:feature_one_enabled_actors) do
|
|
71
|
+
actors.each_slice(3).select do |group|
|
|
72
|
+
context = context(percentage_as_integer, :name_one, group)
|
|
73
|
+
subject.open?(context)
|
|
74
|
+
end.flatten
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
let(:feature_two_enabled_actors) do
|
|
78
|
+
actors.each_slice(3).select do |group|
|
|
79
|
+
context = context(percentage_as_integer, :name_two, group)
|
|
80
|
+
subject.open?(context)
|
|
81
|
+
end.flatten
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'does not enable both features for same set of actors' do
|
|
85
|
+
expect(feature_one_enabled_actors).not_to eq(feature_two_enabled_actors)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'enables feature for accurate number of actors for each feature' do
|
|
89
|
+
margin_of_error = 0.02 * actors.size # 2 percent margin of error
|
|
90
|
+
expected_enabled_size = actors.size * percentage
|
|
91
|
+
|
|
92
|
+
[
|
|
93
|
+
feature_one_enabled_actors.size,
|
|
94
|
+
feature_two_enabled_actors.size,
|
|
95
|
+
].each do |size|
|
|
96
|
+
expect(size).to be_within(margin_of_error).of(expected_enabled_size)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "is consistent regardless of order of actors" do
|
|
101
|
+
actors = user_actors.first(10)
|
|
102
|
+
results = 100.times.map { |n| subject.open?(context(75, :some_feature, actors.shuffle)) }
|
|
103
|
+
expect(results.uniq).to eq([true])
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
53
107
|
context 'for fractional percentage' do
|
|
54
108
|
let(:decimal) { 0.001 }
|
|
55
109
|
let(:percentage) { decimal * 100 }
|
|
56
110
|
let(:number_of_actors) { 10_000 }
|
|
57
111
|
|
|
58
112
|
let(:actors) do
|
|
59
|
-
(1..number_of_actors).map { |n| Flipper::Actor.new(n) }
|
|
113
|
+
(1..number_of_actors).map { |n| Flipper::Types::Actor.new(Flipper::Actor.new(n.to_s)) }
|
|
60
114
|
end
|
|
61
115
|
|
|
62
116
|
subject { described_class.new }
|
|
@@ -66,7 +120,7 @@ RSpec.describe Flipper::Gates::PercentageOfActors do
|
|
|
66
120
|
expected_open_count = number_of_actors * decimal
|
|
67
121
|
|
|
68
122
|
open_count = actors.select do |actor|
|
|
69
|
-
context = context(percentage, :feature, actor)
|
|
123
|
+
context = context(percentage, :feature, [actor])
|
|
70
124
|
subject.open?(context)
|
|
71
125
|
end.size
|
|
72
126
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'helper'
|
|
2
|
-
|
|
3
1
|
RSpec.describe Flipper::Gates::PercentageOfTime do
|
|
4
2
|
let(:feature_name) { :search }
|
|
5
3
|
|
|
@@ -7,11 +5,11 @@ RSpec.describe Flipper::Gates::PercentageOfTime do
|
|
|
7
5
|
described_class.new
|
|
8
6
|
end
|
|
9
7
|
|
|
10
|
-
def context(percentage_of_time_value, feature = feature_name,
|
|
8
|
+
def context(percentage_of_time_value, feature = feature_name, actors = nil)
|
|
11
9
|
Flipper::FeatureCheckContext.new(
|
|
12
10
|
feature_name: feature,
|
|
13
11
|
values: Flipper::GateValues.new(percentage_of_time: percentage_of_time_value),
|
|
14
|
-
|
|
12
|
+
actors: Array(actors) || [Flipper::Types::Actor.new(Flipper::Actor.new('1'))]
|
|
15
13
|
)
|
|
16
14
|
end
|
|
17
15
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'flipper/identifier'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Flipper::Identifier do
|
|
4
|
+
describe '#flipper_id' do
|
|
5
|
+
it 'uses class name and id' do
|
|
6
|
+
class BlahBlah < Struct.new(:id)
|
|
7
|
+
include Flipper::Identifier
|
|
8
|
+
end
|
|
9
|
+
expect(BlahBlah.new(5).flipper_id).to eq('BlahBlah;5')
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
require 'logger'
|
|
2
|
-
require '
|
|
3
|
-
require 'flipper/adapters/instrumented'
|
|
2
|
+
require 'active_support/core_ext/object/blank'
|
|
4
3
|
require 'flipper/instrumentation/log_subscriber'
|
|
4
|
+
require 'flipper/adapters/instrumented'
|
|
5
|
+
|
|
6
|
+
begin
|
|
7
|
+
require 'active_support/isolated_execution_state'
|
|
8
|
+
rescue LoadError
|
|
9
|
+
# ActiveSupport::IsolatedExecutionState is only available in Rails 5.2+
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Don't log in other tests, we'll manually re-attach when this one starts
|
|
13
|
+
Flipper::Instrumentation::LogSubscriber.detach
|
|
5
14
|
|
|
6
15
|
RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
7
16
|
let(:adapter) do
|
|
@@ -13,8 +22,8 @@ RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
|
13
22
|
end
|
|
14
23
|
|
|
15
24
|
before do
|
|
16
|
-
Flipper.register(:admins) do |
|
|
17
|
-
|
|
25
|
+
Flipper.register(:admins) do |actor|
|
|
26
|
+
actor.respond_to?(:admin?) && actor.admin?
|
|
18
27
|
end
|
|
19
28
|
|
|
20
29
|
@io = StringIO.new
|
|
@@ -27,6 +36,14 @@ RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
|
27
36
|
described_class.logger = nil
|
|
28
37
|
end
|
|
29
38
|
|
|
39
|
+
before(:all) do
|
|
40
|
+
described_class.attach
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
after(:all) do
|
|
44
|
+
described_class.detach
|
|
45
|
+
end
|
|
46
|
+
|
|
30
47
|
let(:log) { @io.string }
|
|
31
48
|
|
|
32
49
|
context 'feature enabled checks' do
|
|
@@ -37,7 +54,7 @@ RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
|
37
54
|
|
|
38
55
|
it 'logs feature calls with result after operation' do
|
|
39
56
|
feature_line = find_line('Flipper feature(search) enabled? false')
|
|
40
|
-
expect(feature_line).to include('[
|
|
57
|
+
expect(feature_line).to include('[ actors=nil ]')
|
|
41
58
|
end
|
|
42
59
|
|
|
43
60
|
it 'logs adapter calls' do
|
|
@@ -47,7 +64,7 @@ RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
|
47
64
|
end
|
|
48
65
|
end
|
|
49
66
|
|
|
50
|
-
context 'feature enabled checks with
|
|
67
|
+
context 'feature enabled checks with an actor' do
|
|
51
68
|
let(:user) { Flipper::Types::Actor.new(Flipper::Actor.new('1')) }
|
|
52
69
|
|
|
53
70
|
before do
|
|
@@ -55,7 +72,7 @@ RSpec.describe Flipper::Instrumentation::LogSubscriber do
|
|
|
55
72
|
flipper[:search].enabled?(user)
|
|
56
73
|
end
|
|
57
74
|
|
|
58
|
-
it 'logs
|
|
75
|
+
it 'logs actors for feature' do
|
|
59
76
|
feature_line = find_line('Flipper feature(search) enabled?')
|
|
60
77
|
expect(feature_line).to include(user.inspect)
|
|
61
78
|
end
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
require 'helper'
|
|
2
1
|
require 'flipper/adapters/instrumented'
|
|
3
2
|
require 'flipper/instrumentation/statsd'
|
|
4
|
-
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'active_support/isolated_execution_state'
|
|
6
|
+
rescue LoadError
|
|
7
|
+
# ActiveSupport::IsolatedExecutionState is only available in Rails 5.2+
|
|
8
|
+
end
|
|
5
9
|
|
|
6
10
|
RSpec.describe Flipper::Instrumentation::StatsdSubscriber do
|
|
7
11
|
let(:statsd_client) { Statsd.new }
|
|
@@ -14,7 +18,7 @@ RSpec.describe Flipper::Instrumentation::StatsdSubscriber do
|
|
|
14
18
|
Flipper.new(adapter, instrumenter: ActiveSupport::Notifications)
|
|
15
19
|
end
|
|
16
20
|
|
|
17
|
-
let(:user) {
|
|
21
|
+
let(:user) { Flipper::Actor.new('1') }
|
|
18
22
|
|
|
19
23
|
before do
|
|
20
24
|
described_class.client = statsd_client
|
|
@@ -26,6 +30,10 @@ RSpec.describe Flipper::Instrumentation::StatsdSubscriber do
|
|
|
26
30
|
Thread.current[:statsd_socket] = nil
|
|
27
31
|
end
|
|
28
32
|
|
|
33
|
+
after(:all) do
|
|
34
|
+
ActiveSupport::Notifications.unsubscribe("flipper")
|
|
35
|
+
end
|
|
36
|
+
|
|
29
37
|
def assert_timer(metric)
|
|
30
38
|
regex = /#{Regexp.escape metric}\:\d+\|ms/
|
|
31
39
|
result = socket.buffer.detect { |op| op.first =~ regex }
|
|
@@ -69,4 +77,19 @@ RSpec.describe Flipper::Instrumentation::StatsdSubscriber do
|
|
|
69
77
|
flipper[:stats].disable(user)
|
|
70
78
|
assert_timer 'flipper.adapter.memory.disable'
|
|
71
79
|
end
|
|
80
|
+
|
|
81
|
+
context 'when client is nil' do
|
|
82
|
+
before do
|
|
83
|
+
described_class.client = nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'does not raise error' do
|
|
87
|
+
expect { flipper[:stats].enable(user) }.not_to raise_error
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it 'does not update metrics' do
|
|
91
|
+
flipper[:stats].enable(user)
|
|
92
|
+
expect(socket.buffer).to be_empty
|
|
93
|
+
end
|
|
94
|
+
end
|
|
72
95
|
end
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
require 'helper'
|
|
2
1
|
require 'flipper/instrumenters/memory'
|
|
3
2
|
|
|
4
3
|
RSpec.describe Flipper::Instrumenters::Memory do
|
|
@@ -22,5 +21,23 @@ RSpec.describe Flipper::Instrumenters::Memory do
|
|
|
22
21
|
event = described_class::Event.new(name, payload, block_result)
|
|
23
22
|
expect(instrumenter.events).to eq([event])
|
|
24
23
|
end
|
|
24
|
+
|
|
25
|
+
context 'when an error is raised' do
|
|
26
|
+
subject do
|
|
27
|
+
instrumenter.instrument(:name) { raise IOError }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
let(:instrumenter) { described_class.new }
|
|
31
|
+
|
|
32
|
+
it 'captures and propagates the error' do
|
|
33
|
+
expect { subject }.to raise_error(IOError)
|
|
34
|
+
|
|
35
|
+
expect(instrumenter.events.count).to be 1
|
|
36
|
+
|
|
37
|
+
payload = instrumenter.events[0].payload
|
|
38
|
+
expect(payload.keys).to include(:exception, :exception_object)
|
|
39
|
+
expect(payload[:exception_object]).to be_a IOError
|
|
40
|
+
end
|
|
41
|
+
end
|
|
25
42
|
end
|
|
26
43
|
end
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
require 'helper'
|
|
2
|
-
|
|
3
1
|
RSpec.describe Flipper::Instrumenters::Noop do
|
|
4
2
|
describe '.instrument' do
|
|
5
3
|
context 'with name' do
|
|
6
4
|
it 'yields block' do
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
expect { |block|
|
|
6
|
+
described_class.instrument(:foo, &block)
|
|
7
|
+
}.to yield_control
|
|
10
8
|
end
|
|
11
9
|
end
|
|
12
10
|
|
|
13
11
|
context 'with name and payload' do
|
|
12
|
+
let(:payload) { { pay: :load } }
|
|
13
|
+
|
|
14
14
|
it 'yields block' do
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
expect { |block|
|
|
16
|
+
described_class.instrument(:foo, payload, &block)
|
|
17
|
+
}.to yield_control
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'yields the payload' do
|
|
21
|
+
described_class.instrument(:foo, payload) do |block_payload|
|
|
22
|
+
expect(block_payload).to eq payload
|
|
23
|
+
end
|
|
18
24
|
end
|
|
19
25
|
end
|
|
20
26
|
end
|