flipper 0.26.0 → 1.1.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/FUNDING.yml +1 -0
- data/.github/workflows/ci.yml +19 -13
- data/.github/workflows/examples.yml +32 -15
- data/Changelog.md +294 -154
- data/Gemfile +15 -10
- data/README.md +13 -11
- 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/docs/images/flipper_cloud.png +0 -0
- data/examples/api/basic.ru +3 -4
- data/examples/api/custom_memoized.ru +3 -4
- data/examples/api/memoized.ru +3 -4
- 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/threaded.rb +33 -0
- data/examples/dsl.rb +1 -15
- data/examples/enabled_for_actor.rb +4 -2
- data/examples/expressions.rb +213 -0
- data/examples/mirroring.rb +59 -0
- data/examples/strict.rb +18 -0
- data/flipper-cloud.gemspec +19 -0
- data/flipper.gemspec +3 -5
- data/lib/flipper/actor.rb +6 -3
- data/lib/flipper/adapter.rb +33 -7
- data/lib/flipper/adapter_builder.rb +44 -0
- data/lib/flipper/adapters/dual_write.rb +1 -3
- data/lib/flipper/adapters/failover.rb +0 -4
- data/lib/flipper/adapters/failsafe.rb +0 -4
- data/lib/flipper/adapters/http/client.rb +26 -7
- data/lib/flipper/adapters/http/error.rb +1 -1
- data/lib/flipper/adapters/http.rb +29 -16
- data/lib/flipper/adapters/instrumented.rb +25 -6
- data/lib/flipper/adapters/memoizable.rb +33 -21
- data/lib/flipper/adapters/memory.rb +81 -46
- data/lib/flipper/adapters/operation_logger.rb +16 -7
- data/lib/flipper/adapters/poll/poller.rb +2 -125
- data/lib/flipper/adapters/poll.rb +5 -3
- data/lib/flipper/adapters/pstore.rb +17 -11
- data/lib/flipper/adapters/read_only.rb +4 -4
- data/lib/flipper/adapters/strict.rb +47 -0
- data/lib/flipper/adapters/sync/feature_synchronizer.rb +10 -1
- data/lib/flipper/adapters/sync.rb +0 -4
- data/lib/flipper/cloud/configuration.rb +258 -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/routes.rb +14 -0
- data/lib/flipper/cloud/telemetry/backoff_policy.rb +93 -0
- data/lib/flipper/cloud/telemetry/instrumenter.rb +26 -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 +98 -0
- data/lib/flipper/cloud/telemetry.rb +183 -0
- data/lib/flipper/cloud.rb +53 -0
- data/lib/flipper/configuration.rb +25 -4
- data/lib/flipper/dsl.rb +46 -45
- data/lib/flipper/engine.rb +88 -0
- data/lib/flipper/errors.rb +3 -3
- data/lib/flipper/export.rb +26 -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 +11 -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/duration.rb +28 -0
- data/lib/flipper/expressions/equal.rb +9 -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 +9 -0
- data/lib/flipper/feature.rb +87 -26
- 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 +2 -2
- data/lib/flipper/instrumentation/log_subscriber.rb +24 -5
- data/lib/flipper/instrumentation/statsd_subscriber.rb +2 -4
- data/lib/flipper/instrumentation/subscriber.rb +8 -1
- data/lib/flipper/metadata.rb +5 -1
- data/lib/flipper/middleware/memoizer.rb +30 -14
- data/lib/flipper/poller.rb +117 -0
- data/lib/flipper/serializers/gzip.rb +24 -0
- data/lib/flipper/serializers/json.rb +19 -0
- data/lib/flipper/spec/shared_adapter_specs.rb +95 -54
- data/lib/flipper/test/shared_adapter_test.rb +91 -48
- data/lib/flipper/typecast.rb +56 -15
- data/lib/flipper/types/actor.rb +13 -13
- data/lib/flipper/types/group.rb +4 -4
- data/lib/flipper/types/percentage.rb +1 -1
- data/lib/flipper/version.rb +1 -1
- data/lib/flipper.rb +47 -10
- data/spec/fixtures/flipper_pstore_1679087600.json +46 -0
- data/spec/flipper/adapter_builder_spec.rb +73 -0
- data/spec/flipper/adapter_spec.rb +30 -2
- data/spec/flipper/adapters/dual_write_spec.rb +2 -2
- data/spec/flipper/adapters/http_spec.rb +64 -8
- data/spec/flipper/adapters/instrumented_spec.rb +29 -11
- data/spec/flipper/adapters/memoizable_spec.rb +51 -31
- data/spec/flipper/adapters/memory_spec.rb +14 -3
- data/spec/flipper/adapters/operation_logger_spec.rb +31 -12
- data/spec/flipper/adapters/read_only_spec.rb +32 -17
- data/spec/flipper/adapters/strict_spec.rb +62 -0
- data/spec/flipper/adapters/sync/feature_synchronizer_spec.rb +27 -0
- data/spec/flipper/cloud/configuration_spec.rb +252 -0
- data/spec/flipper/cloud/dsl_spec.rb +82 -0
- data/spec/flipper/cloud/message_verifier_spec.rb +104 -0
- data/spec/flipper/cloud/middleware_spec.rb +289 -0
- data/spec/flipper/cloud/telemetry/backoff_policy_spec.rb +108 -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 +156 -0
- data/spec/flipper/cloud_spec.rb +180 -0
- data/spec/flipper/configuration_spec.rb +17 -0
- data/spec/flipper/dsl_spec.rb +54 -73
- data/spec/flipper/engine_spec.rb +291 -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/duration_spec.rb +43 -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 +13 -0
- data/spec/flipper/feature_check_context_spec.rb +17 -17
- data/spec/flipper/feature_spec.rb +436 -33
- data/spec/flipper/gate_values_spec.rb +2 -33
- data/spec/flipper/gates/boolean_spec.rb +1 -1
- data/spec/flipper/gates/expression_spec.rb +108 -0
- data/spec/flipper/gates/group_spec.rb +2 -3
- data/spec/flipper/gates/percentage_of_actors_spec.rb +61 -5
- data/spec/flipper/gates/percentage_of_time_spec.rb +2 -2
- data/spec/flipper/identifier_spec.rb +4 -5
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +15 -5
- data/spec/flipper/instrumentation/statsd_subscriber_spec.rb +25 -1
- data/spec/flipper/middleware/memoizer_spec.rb +67 -0
- data/spec/flipper/poller_spec.rb +47 -0
- 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 -6
- data/spec/flipper/types/actor_spec.rb +63 -46
- data/spec/flipper/types/group_spec.rb +2 -2
- data/spec/flipper_integration_spec.rb +168 -58
- data/spec/flipper_spec.rb +92 -28
- data/spec/spec_helper.rb +6 -13
- data/spec/support/actor_names.yml +1 -0
- data/spec/support/climate_control.rb +7 -0
- data/spec/support/fake_backoff_policy.rb +15 -0
- data/spec/support/skippable.rb +18 -0
- data/spec/support/spec_helpers.rb +11 -3
- metadata +166 -13
- data/.github/workflows/release.yml +0 -44
- data/.tool-versions +0 -1
- data/lib/flipper/railtie.rb +0 -47
- data/spec/flipper/railtie_spec.rb +0 -109
@@ -0,0 +1,188 @@
|
|
1
|
+
require 'flipper/expression'
|
2
|
+
|
3
|
+
RSpec.describe Flipper::Expression do
|
4
|
+
describe "#build" do
|
5
|
+
it "can build Equal" do
|
6
|
+
expression = described_class.build({
|
7
|
+
"Equal" => [
|
8
|
+
"basic",
|
9
|
+
"basic",
|
10
|
+
]
|
11
|
+
})
|
12
|
+
|
13
|
+
expect(expression).to be_instance_of(Flipper::Expression)
|
14
|
+
expect(expression.function).to be(Flipper::Expressions::Equal)
|
15
|
+
expect(expression.args).to eq([
|
16
|
+
Flipper.constant("basic"),
|
17
|
+
Flipper.constant("basic"),
|
18
|
+
])
|
19
|
+
end
|
20
|
+
|
21
|
+
it "can build GreaterThanOrEqualTo" do
|
22
|
+
expression = described_class.build({
|
23
|
+
"GreaterThanOrEqualTo" => [
|
24
|
+
2,
|
25
|
+
1,
|
26
|
+
]
|
27
|
+
})
|
28
|
+
|
29
|
+
expect(expression).to be_instance_of(Flipper::Expression)
|
30
|
+
expect(expression.function).to be(Flipper::Expressions::GreaterThanOrEqualTo)
|
31
|
+
expect(expression.args).to eq([
|
32
|
+
Flipper.constant(2),
|
33
|
+
Flipper.constant(1),
|
34
|
+
])
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can build GreaterThan" do
|
38
|
+
expression = described_class.build({
|
39
|
+
"GreaterThan" => [
|
40
|
+
2,
|
41
|
+
1,
|
42
|
+
]
|
43
|
+
})
|
44
|
+
|
45
|
+
expect(expression).to be_instance_of(Flipper::Expression)
|
46
|
+
expect(expression.function).to be(Flipper::Expressions::GreaterThan)
|
47
|
+
expect(expression.args).to eq([
|
48
|
+
Flipper.constant(2),
|
49
|
+
Flipper.constant(1),
|
50
|
+
])
|
51
|
+
end
|
52
|
+
|
53
|
+
it "can build LessThanOrEqualTo" do
|
54
|
+
expression = described_class.build({
|
55
|
+
"LessThanOrEqualTo" => [
|
56
|
+
2,
|
57
|
+
1,
|
58
|
+
]
|
59
|
+
})
|
60
|
+
|
61
|
+
expect(expression).to be_instance_of(Flipper::Expression)
|
62
|
+
expect(expression.function).to be(Flipper::Expressions::LessThanOrEqualTo)
|
63
|
+
expect(expression.args).to eq([
|
64
|
+
Flipper.constant(2),
|
65
|
+
Flipper.constant(1),
|
66
|
+
])
|
67
|
+
end
|
68
|
+
|
69
|
+
it "can build LessThan" do
|
70
|
+
expression = described_class.build({
|
71
|
+
"LessThan" => [2, 1]
|
72
|
+
})
|
73
|
+
|
74
|
+
expect(expression).to be_instance_of(Flipper::Expression)
|
75
|
+
expect(expression.function).to be(Flipper::Expressions::LessThan)
|
76
|
+
expect(expression.args).to eq([
|
77
|
+
Flipper.constant(2),
|
78
|
+
Flipper.constant(1),
|
79
|
+
])
|
80
|
+
end
|
81
|
+
|
82
|
+
it "can build NotEqual" do
|
83
|
+
expression = described_class.build({
|
84
|
+
"NotEqual" => [
|
85
|
+
"basic",
|
86
|
+
"plus",
|
87
|
+
]
|
88
|
+
})
|
89
|
+
|
90
|
+
expect(expression).to be_instance_of(Flipper::Expression)
|
91
|
+
expect(expression.function).to be(Flipper::Expressions::NotEqual)
|
92
|
+
expect(expression.args).to eq([
|
93
|
+
Flipper.constant("basic"),
|
94
|
+
Flipper.constant("plus"),
|
95
|
+
])
|
96
|
+
end
|
97
|
+
|
98
|
+
it "can build Number" do
|
99
|
+
expression = described_class.build(1)
|
100
|
+
|
101
|
+
expect(expression).to be_instance_of(Flipper::Expression::Constant)
|
102
|
+
expect(expression.value).to eq(1)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "can build Percentage" do
|
106
|
+
expression = described_class.build({
|
107
|
+
"Percentage" => [1]
|
108
|
+
})
|
109
|
+
|
110
|
+
expect(expression).to be_instance_of(Flipper::Expression)
|
111
|
+
expect(expression.function).to be(Flipper::Expressions::Percentage)
|
112
|
+
expect(expression.args).to eq([Flipper.constant(1)])
|
113
|
+
end
|
114
|
+
|
115
|
+
it "can build PercentageOfActors" do
|
116
|
+
expression = described_class.build({
|
117
|
+
"PercentageOfActors" => [
|
118
|
+
"User;1",
|
119
|
+
40,
|
120
|
+
]
|
121
|
+
})
|
122
|
+
|
123
|
+
expect(expression).to be_instance_of(Flipper::Expression)
|
124
|
+
expect(expression.function).to be(Flipper::Expressions::PercentageOfActors)
|
125
|
+
expect(expression.args).to eq([
|
126
|
+
Flipper.constant("User;1"),
|
127
|
+
Flipper.constant(40),
|
128
|
+
])
|
129
|
+
end
|
130
|
+
|
131
|
+
it "can build String" do
|
132
|
+
expression = described_class.build("basic")
|
133
|
+
|
134
|
+
expect(expression).to be_instance_of(Flipper::Expression::Constant)
|
135
|
+
expect(expression.value).to eq("basic")
|
136
|
+
end
|
137
|
+
|
138
|
+
it "can build Property" do
|
139
|
+
expression = described_class.build({
|
140
|
+
"Property" => ["flipper_id"]
|
141
|
+
})
|
142
|
+
|
143
|
+
expect(expression).to be_instance_of(Flipper::Expression)
|
144
|
+
expect(expression.function).to be(Flipper::Expressions::Property)
|
145
|
+
expect(expression.args).to eq([Flipper.constant("flipper_id")])
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "#eql?" do
|
150
|
+
it "returns true for same class and args" do
|
151
|
+
expression = described_class.build("foo")
|
152
|
+
other = described_class.build("foo")
|
153
|
+
expect(expression.eql?(other)).to be(true)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "returns false for different class" do
|
157
|
+
expression = described_class.build("foo")
|
158
|
+
other = Object.new
|
159
|
+
expect(expression.eql?(other)).to be(false)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "returns false for different args" do
|
163
|
+
expression = described_class.build("foo")
|
164
|
+
other = described_class.build("bar")
|
165
|
+
expect(expression.eql?(other)).to be(false)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe "#==" do
|
170
|
+
it "returns true for same class and args" do
|
171
|
+
expression = described_class.build("foo")
|
172
|
+
other = described_class.build("foo")
|
173
|
+
expect(expression == other).to be(true)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "returns false for different class" do
|
177
|
+
expression = described_class.build("foo")
|
178
|
+
other = Object.new
|
179
|
+
expect(expression == other).to be(false)
|
180
|
+
end
|
181
|
+
|
182
|
+
it "returns false for different args" do
|
183
|
+
expression = described_class.build("foo")
|
184
|
+
other = described_class.build("bar")
|
185
|
+
expect(expression == other).to be(false)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::All do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns true if all args evaluate as true" do
|
4
|
+
expect(described_class.call(true, true)).to be(true)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns false if any args evaluate as false" do
|
8
|
+
expect(described_class.call(false, true)).to be(false)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns true with empty args" do
|
12
|
+
expect(described_class.call).to be(true)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::Any do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns true if any args evaluate as true" do
|
4
|
+
expect(described_class.call(true, false)).to be(true)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns false if all args evaluate as false" do
|
8
|
+
expect(described_class.call(false, false)).to be(false)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns false with empty args" do
|
12
|
+
expect(described_class.call).to be(false)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::Boolean do
|
2
|
+
describe "#call" do
|
3
|
+
[true, 'true', 1, '1'].each do |value|
|
4
|
+
it "returns a true for #{value.inspect}" do
|
5
|
+
expect(described_class.call(value)).to be(true)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
[false, 'false', 0, '0', nil].each do |value|
|
10
|
+
it "returns a true for #{value.inspect}" do
|
11
|
+
expect(described_class.call(value)).to be(false)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::Duration do
|
2
|
+
describe "#call" do
|
3
|
+
it "raises error with invalid value" do
|
4
|
+
expect { described_class.call(false, 'minute') }.to raise_error(ArgumentError)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "raises error with invalid unit" do
|
8
|
+
expect { described_class.call(4, 'score') }.to raise_error(ArgumentError)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'defaults unit to seconds' do
|
12
|
+
expect(described_class.call(10)).to eq(10)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "evaluates seconds" do
|
16
|
+
expect(described_class.call(10, 'seconds')).to eq(10)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "evaluates minutes" do
|
20
|
+
expect(described_class.call(2, 'minutes')).to eq(120)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "evaluates hours" do
|
24
|
+
expect(described_class.call(2, 'hours')).to eq(7200)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "evaluates days" do
|
28
|
+
expect(described_class.call(2, 'days')).to eq(172_800)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "evaluates weeks" do
|
32
|
+
expect(described_class.call(2, 'weeks')).to eq(1_209_600)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "evaluates months" do
|
36
|
+
expect(described_class.call(2, 'months')).to eq(5_259_492)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "evaluates years" do
|
40
|
+
expect(described_class.call(2, 'years')).to eq(63_113_904)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::Equal do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns true when equal" do
|
4
|
+
expect(described_class.call("basic", "basic")).to be(true)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns false when not equal" do
|
8
|
+
expect(described_class.call("basic", "plus")).to be(false)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns false when value evaluates to nil" do
|
12
|
+
expect(described_class.call(nil, 1)).to be(false)
|
13
|
+
expect(described_class.call(1, nil)).to be(false)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "raises ArgumentError with no arguments" do
|
17
|
+
expect { described_class.call }.to raise_error(ArgumentError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "raises ArgumentError with one argument" do
|
21
|
+
expect { described_class.call(10) }.to raise_error(ArgumentError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::GreaterThanOrEqualTo do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns true when equal" do
|
4
|
+
expect(described_class.call(2, 2)).to be(true)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns true when greater" do
|
8
|
+
expect(described_class.call(2, 1)).to be(true)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns false when less" do
|
12
|
+
expect(described_class.call(1, 2)).to be(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns false when value evaluates to nil" do
|
16
|
+
expect(described_class.call(nil, 1)).to be(false)
|
17
|
+
expect(described_class.call(1, nil)).to be(false)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "raises ArgumentError with no arguments" do
|
21
|
+
expect { described_class.call }.to raise_error(ArgumentError)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "raises ArgumentError with one argument" do
|
25
|
+
expect { described_class.call(10) }.to raise_error(ArgumentError)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::GreaterThan do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns false when equal" do
|
4
|
+
expect(described_class.call(2, 2)).to be(false)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns true when greater" do
|
8
|
+
expect(described_class.call(2, 1)).to be(true)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns false when less" do
|
12
|
+
expect(described_class.call(1, 2)).to be(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns false when value evaluates to nil" do
|
16
|
+
expect(described_class.call(nil, 1)).to be(false)
|
17
|
+
expect(described_class.call(1, nil)).to be(false)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "raises ArgumentError with no arguments" do
|
21
|
+
expect { described_class.call }.to raise_error(ArgumentError)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "raises ArgumentError with one argument" do
|
25
|
+
expect { described_class.call(10) }.to raise_error(ArgumentError)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::LessThanOrEqualTo do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns true when equal" do
|
4
|
+
expect(described_class.call(2, 2)).to be(true)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns true when less" do
|
8
|
+
expect(described_class.call(1, 2)).to be(true)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns false when greater" do
|
12
|
+
expect(described_class.call(2, 1)).to be(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns false when value evaluates to nil" do
|
16
|
+
expect(described_class.call(nil, 1)).to be(false)
|
17
|
+
expect(described_class.call(1, nil)).to be(false)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "raises ArgumentError with no arguments" do
|
21
|
+
expect { described_class.call }.to raise_error(ArgumentError)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "raises ArgumentError with one argument" do
|
25
|
+
expect { described_class.call(10) }.to raise_error(ArgumentError)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::LessThan do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns false when equal" do
|
4
|
+
expect(described_class.call(2, 2)).to be(false)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns true when less" do
|
8
|
+
expect(described_class.call(1, 2)).to be(true)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns true when less with args that need evaluation" do
|
12
|
+
expect(described_class.call(1, 2)).to be(true)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns false when greater" do
|
16
|
+
expect(described_class.call(2, 1)).to be(false)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns false when value evaluates to nil" do
|
20
|
+
expect(described_class.call(nil, 1)).to be(false)
|
21
|
+
expect(described_class.call(1, nil)).to be(false)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "raises ArgumentError with no arguments" do
|
25
|
+
expect { described_class.call }.to raise_error(ArgumentError)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "raises ArgumentError with one argument" do
|
29
|
+
expect { described_class.call(10) }.to raise_error(ArgumentError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::NotEqual do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns true when not equal" do
|
4
|
+
expect(described_class.call("basic", "plus")).to be(true)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns false when equal" do
|
8
|
+
expect(described_class.call("basic", "basic")).to be(false)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "raises ArgumentError for more arguments" do
|
12
|
+
expect { described_class.call(20, 10, 20).evaluate }.to raise_error(ArgumentError)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::Now do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns current time" do
|
4
|
+
expect(described_class.call).to be_within(2).of(Time.now.utc)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "defaults to UTC" do
|
8
|
+
expect(described_class.call.zone).to eq("UTC")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::Number do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns Integer for Integer" do
|
4
|
+
expect(described_class.call(10)).to be(10)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns Float for Float" do
|
8
|
+
expect(described_class.call(10.1)).to be(10.1)
|
9
|
+
expect(described_class.call(10.0)).to be(10.0)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns Integer for String" do
|
13
|
+
expect(described_class.call('10')).to be(10)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "returns Float for String" do
|
17
|
+
expect(described_class.call('10.0')).to be(10.0)
|
18
|
+
expect(described_class.call('10.1')).to be(10.1)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::PercentageOfActors do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns true when string in percentage enabled" do
|
4
|
+
expect(described_class.call("User;1", 42)).to be(true)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns true when string in fractional percentage enabled" do
|
8
|
+
expect(described_class.call("User;1", 41.687)).to be(true)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns false when string in percentage enabled" do
|
12
|
+
expect(described_class.call("User;1", 0)).to be(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "changes value based on feature_name so not all actors get all features first" do
|
16
|
+
expect(described_class.call("User;1", 70, context: {feature_name: "a"})).to be(true)
|
17
|
+
expect(described_class.call("User;1", 70, context: {feature_name: "b"})).to be(false)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::Percentage do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns numeric" do
|
4
|
+
expect(described_class.call(10)).to be(10.0)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "returns 0 if less than 0" do
|
8
|
+
expect(described_class.call(-1)).to be(0)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns 100 if greater than 100" do
|
12
|
+
expect(described_class.call(101)).to be(100)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::Property do
|
2
|
+
describe "#call" do
|
3
|
+
it "returns value for property key" do
|
4
|
+
context = { properties: { "flipper_id" => "User;1" } }
|
5
|
+
expect(described_class.call("flipper_id", context: context)).to eq("User;1")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "returns nil if key not found in properties" do
|
9
|
+
context = { properties: { } }
|
10
|
+
expect(described_class.call("flipper_id", context: context)).to be(nil)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
RSpec.describe Flipper::Expressions::Time do
|
2
|
+
let(:time) { Time.now.round }
|
3
|
+
|
4
|
+
describe "#call" do
|
5
|
+
it "returns time for #to_s format" do
|
6
|
+
expect(described_class.call(time.to_s)).to eq(time)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns time for #iso8601 format" do
|
10
|
+
expect(described_class.call(time.iso8601)).to eq(time)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,65 +1,65 @@
|
|
1
1
|
RSpec.describe Flipper::FeatureCheckContext do
|
2
2
|
let(:feature_name) { :new_profiles }
|
3
3
|
let(:values) { Flipper::GateValues.new({}) }
|
4
|
-
let(:
|
4
|
+
let(:actor) { Flipper::Actor.new('5') }
|
5
5
|
let(:options) do
|
6
6
|
{
|
7
7
|
feature_name: feature_name,
|
8
8
|
values: values,
|
9
|
-
|
9
|
+
actors: [actor],
|
10
10
|
}
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'initializes just fine' do
|
14
|
-
instance = described_class.new(options)
|
14
|
+
instance = described_class.new(**options)
|
15
15
|
expect(instance.feature_name).to eq(feature_name)
|
16
16
|
expect(instance.values).to eq(values)
|
17
|
-
expect(instance.
|
17
|
+
expect(instance.actors).to eq([actor])
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'requires feature_name' do
|
21
21
|
options.delete(:feature_name)
|
22
22
|
expect do
|
23
|
-
described_class.new(options)
|
24
|
-
end.to raise_error(
|
23
|
+
described_class.new(**options)
|
24
|
+
end.to raise_error(ArgumentError)
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'requires values' do
|
28
28
|
options.delete(:values)
|
29
29
|
expect do
|
30
|
-
described_class.new(options)
|
31
|
-
end.to raise_error(
|
30
|
+
described_class.new(**options)
|
31
|
+
end.to raise_error(ArgumentError)
|
32
32
|
end
|
33
33
|
|
34
|
-
it 'requires
|
35
|
-
options.delete(:
|
34
|
+
it 'requires actors' do
|
35
|
+
options.delete(:actors)
|
36
36
|
expect do
|
37
|
-
described_class.new(options)
|
38
|
-
end.to raise_error(
|
37
|
+
described_class.new(**options)
|
38
|
+
end.to raise_error(ArgumentError)
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'knows actors_value' do
|
42
42
|
args = options.merge(values: Flipper::GateValues.new(actors: Set['User;1']))
|
43
|
-
expect(described_class.new(args).actors_value).to eq(Set['User;1'])
|
43
|
+
expect(described_class.new(**args).actors_value).to eq(Set['User;1'])
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'knows groups_value' do
|
47
47
|
args = options.merge(values: Flipper::GateValues.new(groups: Set['admins']))
|
48
|
-
expect(described_class.new(args).groups_value).to eq(Set['admins'])
|
48
|
+
expect(described_class.new(**args).groups_value).to eq(Set['admins'])
|
49
49
|
end
|
50
50
|
|
51
51
|
it 'knows boolean_value' do
|
52
|
-
instance = described_class.new(options.merge(values: Flipper::GateValues.new(boolean: true)))
|
52
|
+
instance = described_class.new(**options.merge(values: Flipper::GateValues.new(boolean: true)))
|
53
53
|
expect(instance.boolean_value).to eq(true)
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'knows percentage_of_actors_value' do
|
57
57
|
args = options.merge(values: Flipper::GateValues.new(percentage_of_actors: 14))
|
58
|
-
expect(described_class.new(args).percentage_of_actors_value).to eq(14)
|
58
|
+
expect(described_class.new(**args).percentage_of_actors_value).to eq(14)
|
59
59
|
end
|
60
60
|
|
61
61
|
it 'knows percentage_of_time_value' do
|
62
62
|
args = options.merge(values: Flipper::GateValues.new(percentage_of_time: 41))
|
63
|
-
expect(described_class.new(args).percentage_of_time_value).to eq(41)
|
63
|
+
expect(described_class.new(**args).percentage_of_time_value).to eq(41)
|
64
64
|
end
|
65
65
|
end
|