prefab-cloud-ruby 0.20.0 → 0.22.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/.envrc.sample +3 -0
- data/.github/workflows/ruby.yml +5 -1
- data/.gitmodules +3 -0
- data/Gemfile +14 -12
- data/Gemfile.lock +24 -14
- data/README.md +12 -10
- data/Rakefile +13 -14
- data/VERSION +1 -1
- data/lib/prefab/auth_interceptor.rb +2 -1
- data/lib/prefab/cancellable_interceptor.rb +8 -7
- data/lib/prefab/client.rb +52 -27
- data/lib/prefab/config_client.rb +59 -70
- data/lib/prefab/config_loader.rb +7 -114
- data/lib/prefab/config_resolver.rb +27 -57
- data/lib/prefab/config_value_unwrapper.rb +23 -0
- data/lib/prefab/criteria_evaluator.rb +96 -0
- data/lib/prefab/errors/invalid_api_key_error.rb +1 -1
- data/lib/prefab/feature_flag_client.rb +13 -145
- data/lib/prefab/internal_logger.rb +7 -6
- data/lib/prefab/local_config_parser.rb +110 -0
- data/lib/prefab/log_path_collector.rb +98 -0
- data/lib/prefab/logger_client.rb +46 -44
- data/lib/prefab/murmer3.rb +3 -4
- data/lib/prefab/noop_cache.rb +5 -7
- data/lib/prefab/noop_stats.rb +2 -3
- data/lib/prefab/options.rb +32 -11
- data/lib/prefab/ratelimit_client.rb +11 -13
- data/lib/prefab/sse_logger.rb +3 -2
- data/lib/prefab/weighted_value_resolver.rb +42 -0
- data/lib/prefab/yaml_config_parser.rb +32 -0
- data/lib/prefab-cloud-ruby.rb +7 -2
- data/lib/prefab_pb.rb +70 -43
- data/lib/prefab_services_pb.rb +14 -1
- data/prefab-cloud-ruby.gemspec +33 -19
- data/test/.prefab.unit_tests.config.yaml +3 -2
- data/test/integration_test.rb +98 -0
- data/test/integration_test_helpers.rb +37 -0
- data/test/test_client.rb +56 -31
- data/test/test_config_client.rb +21 -20
- data/test/test_config_loader.rb +48 -37
- data/test/test_config_resolver.rb +312 -135
- data/test/test_config_value_unwrapper.rb +83 -0
- data/test/test_criteria_evaluator.rb +533 -0
- data/test/test_feature_flag_client.rb +35 -347
- data/test/test_helper.rb +18 -14
- data/test/test_integration.rb +33 -0
- data/test/test_local_config_parser.rb +78 -0
- data/test/test_log_path_collector.rb +56 -0
- data/test/test_logger.rb +52 -51
- data/test/test_options.rb +32 -0
- data/test/test_weighted_value_resolver.rb +65 -0
- metadata +30 -16
- data/lib/prefab/config_helper.rb +0 -31
- data/run_test_harness_server.sh +0 -8
- data/test/harness_server.rb +0 -64
@@ -1,366 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'test_helper'
|
3
4
|
|
4
5
|
class TestFeatureFlagClient < Minitest::Test
|
6
|
+
DEFAULT = 'default'
|
5
7
|
|
6
|
-
def
|
7
|
-
|
8
|
-
@mock_base_client = MockBaseClient.new
|
9
|
-
@client = Prefab::FeatureFlagClient.new(@mock_base_client)
|
10
|
-
Prefab::FeatureFlagClient.send(:public, :is_on?) #publicize for testing
|
11
|
-
Prefab::FeatureFlagClient.send(:public, :segment_match?) #publicize for testing
|
12
|
-
Prefab::FeatureFlagClient.send(:public, :get_variant) #publicize for testing
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_pct
|
16
|
-
feature = "FlagName"
|
17
|
-
|
18
|
-
variants = [
|
19
|
-
Prefab::FeatureFlagVariant.new(bool: false),
|
20
|
-
Prefab::FeatureFlagVariant.new(bool: true)
|
21
|
-
]
|
22
|
-
flag = Prefab::FeatureFlag.new(
|
23
|
-
active: true,
|
24
|
-
inactive_variant_idx: 1,
|
25
|
-
rules: [
|
26
|
-
Prefab::Rule.new(
|
27
|
-
criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
|
28
|
-
variant_weights: [
|
29
|
-
Prefab::VariantWeight.new(weight: 86,
|
30
|
-
variant_idx: 2), #true
|
31
|
-
Prefab::VariantWeight.new(weight: 14,
|
32
|
-
variant_idx: 1), #false
|
33
|
-
]
|
34
|
-
)
|
35
|
-
]
|
36
|
-
)
|
37
|
-
# weights above chosen to be 86% in variant_idx 2. and 14% in variant_idx 1.
|
38
|
-
# since hashes high is 86.32 > 86 it just falls outside the 86% range and gets false
|
39
|
-
|
40
|
-
# "FlagNamevery high hash" hashes to 88.8602812% through dist
|
41
|
-
assert_equal false,
|
42
|
-
evaluate(feature, "very high hash", [], flag, variants)
|
43
|
-
# "FlagNamehashes low" hashes to 42.7934% through dist
|
44
|
-
assert_equal true,
|
45
|
-
evaluate(feature, "hashes low", [], flag, variants)
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_basic_active_inactive
|
50
|
-
feature = "FlagName"
|
51
|
-
variants = [
|
52
|
-
Prefab::FeatureFlagVariant.new(bool: false),
|
53
|
-
Prefab::FeatureFlagVariant.new(bool: true)
|
54
|
-
]
|
55
|
-
flag = Prefab::FeatureFlag.new(
|
56
|
-
active: true,
|
57
|
-
inactive_variant_idx: 1,
|
58
|
-
rules: default_ff_rule(2)
|
59
|
-
)
|
60
|
-
assert_equal true,
|
61
|
-
evaluate(feature, "hashes high", [], flag, variants)
|
62
|
-
assert_equal true,
|
63
|
-
evaluate(feature, "hashes low", [], flag, variants)
|
8
|
+
def test_feature_is_on
|
9
|
+
ff_client = new_client
|
64
10
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
flag = Prefab::FeatureFlag.new(
|
70
|
-
active: false,
|
71
|
-
inactive_variant_idx: 1,
|
72
|
-
rules: default_ff_rule(2)
|
73
|
-
)
|
74
|
-
assert_equal false,
|
75
|
-
evaluate(feature, "hashes high", [], flag, variants)
|
76
|
-
assert_equal false,
|
77
|
-
evaluate(feature, "hashes low", [], flag, variants)
|
11
|
+
assert_equal false, ff_client.feature_is_on?('something-that-does-not-exist')
|
12
|
+
assert_equal false, ff_client.feature_is_on?('disabled_flag')
|
13
|
+
assert_equal true, ff_client.feature_is_on?('enabled_flag')
|
14
|
+
assert_equal false, ff_client.feature_is_on?('flag_with_a_value')
|
78
15
|
end
|
79
16
|
|
80
|
-
def
|
81
|
-
|
82
|
-
variants = [
|
83
|
-
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
84
|
-
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
85
|
-
Prefab::FeatureFlagVariant.new(string: "default"),
|
86
|
-
]
|
87
|
-
flag = Prefab::FeatureFlag.new(
|
88
|
-
active: true,
|
89
|
-
inactive_variant_idx: 1,
|
90
|
-
rules: [
|
91
|
-
Prefab::Rule.new(
|
92
|
-
variant_weights: [
|
93
|
-
Prefab::VariantWeight.new(weight: 1000,
|
94
|
-
variant_idx: 2)
|
95
|
-
],
|
96
|
-
criteria: Prefab::Criteria.new(
|
97
|
-
operator: "LOOKUP_KEY_IN",
|
98
|
-
values: ["user:1"]
|
99
|
-
)
|
100
|
-
),
|
101
|
-
Prefab::Rule.new(
|
102
|
-
criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
|
103
|
-
variant_weights: [
|
104
|
-
Prefab::VariantWeight.new(weight: 1000,
|
105
|
-
variant_idx: 3)
|
106
|
-
]
|
107
|
-
)
|
108
|
-
|
109
|
-
],
|
110
|
-
)
|
111
|
-
|
112
|
-
assert_equal "rule target",
|
113
|
-
evaluate(feature, "user:1", [], flag, variants)
|
114
|
-
assert_equal "default",
|
115
|
-
evaluate(feature, "user:2", [], flag, variants)
|
17
|
+
def test_feature_is_on_for
|
18
|
+
ff_client = new_client
|
116
19
|
|
20
|
+
assert_equal false, ff_client.feature_is_on_for?('something-that-does-not-exist', 'irrelevant')
|
21
|
+
assert_equal false, ff_client.feature_is_on_for?('in_lookup_key', 'not-included')
|
22
|
+
assert_equal true, ff_client.feature_is_on_for?('in_lookup_key', 'abc123')
|
23
|
+
assert_equal true, ff_client.feature_is_on_for?('in_lookup_key', 'xyz987')
|
117
24
|
end
|
118
25
|
|
119
|
-
def
|
120
|
-
|
121
|
-
variants = [
|
122
|
-
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
123
|
-
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
124
|
-
Prefab::FeatureFlagVariant.new(string: "default"),
|
125
|
-
]
|
126
|
-
flag = Prefab::FeatureFlag.new(
|
127
|
-
active: true,
|
128
|
-
inactive_variant_idx: 1,
|
129
|
-
rules: [
|
130
|
-
Prefab::Rule.new(
|
131
|
-
variant_weights: [
|
132
|
-
Prefab::VariantWeight.new(weight: 1000,
|
133
|
-
variant_idx: 2)
|
134
|
-
],
|
135
|
-
criteria: Prefab::Criteria.new(
|
136
|
-
operator: "PROP_IS_ONE_OF",
|
137
|
-
values: ["a@example.com", "b@example.com"],
|
138
|
-
property: "email"
|
139
|
-
)
|
140
|
-
),
|
141
|
-
Prefab::Rule.new(
|
142
|
-
criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
|
143
|
-
variant_weights: [
|
144
|
-
Prefab::VariantWeight.new(weight: 1000,
|
145
|
-
variant_idx: 3)
|
146
|
-
]
|
147
|
-
)
|
148
|
-
|
149
|
-
],
|
150
|
-
)
|
151
|
-
|
152
|
-
assert_equal "default",
|
153
|
-
evaluate(feature, "user:1", { email: "not@example.com" }, flag, variants)
|
154
|
-
assert_equal "default",
|
155
|
-
evaluate(feature, "user:2", {}, flag, variants)
|
156
|
-
assert_equal "rule target",
|
157
|
-
evaluate(feature, "user:2", { email: "b@example.com" }, flag, variants)
|
158
|
-
assert_equal "rule target",
|
159
|
-
evaluate(feature, "user:2", { "email" => "b@example.com" }, flag, variants)
|
26
|
+
def test_get
|
27
|
+
ff_client = new_client
|
160
28
|
|
161
|
-
|
29
|
+
# No default
|
30
|
+
assert_equal false, ff_client.get('something-that-does-not-exist')
|
31
|
+
assert_equal false, ff_client.get('disabled_flag')
|
32
|
+
assert_equal true, ff_client.get('enabled_flag')
|
33
|
+
assert_equal 'all-features', ff_client.get('flag_with_a_value')
|
162
34
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
values: ["a@example.com", "b@example.com"],
|
169
|
-
property: "email"
|
170
|
-
),
|
171
|
-
Prefab::Criteria.new(
|
172
|
-
operator: "LOOKUP_KEY_IN",
|
173
|
-
values: ["user:2"]
|
174
|
-
)
|
175
|
-
]
|
176
|
-
)
|
177
|
-
assert_equal false, @client.segment_match?(segment, "user:0", {})
|
178
|
-
assert_equal true, @client.segment_match?(segment, "user:2", {})
|
179
|
-
assert_equal false, @client.segment_match?(segment, "user:1", { email: "no@example.com" })
|
180
|
-
assert_equal true, @client.segment_match?(segment, "user:1", { email: "a@example.com" })
|
35
|
+
# with defaults
|
36
|
+
assert_equal DEFAULT, ff_client.get('something-that-does-not-exist', default: DEFAULT)
|
37
|
+
assert_equal false, ff_client.get('disabled_flag', default: DEFAULT)
|
38
|
+
assert_equal true, ff_client.get('enabled_flag', default: DEFAULT)
|
39
|
+
assert_equal 'all-features', ff_client.get('flag_with_a_value', default: DEFAULT)
|
181
40
|
end
|
182
41
|
|
183
|
-
|
184
|
-
segment_key = "prefab-segment-beta-group"
|
185
|
-
@mock_base_client.config_client.mock_this_config(segment_key,
|
186
|
-
Prefab::Segment.new(
|
187
|
-
criterion: [
|
188
|
-
Prefab::Criteria.new(
|
189
|
-
operator: Prefab::Criteria::CriteriaOperator::LOOKUP_KEY_IN,
|
190
|
-
values: ["user:1"]
|
191
|
-
)
|
192
|
-
]
|
193
|
-
)
|
194
|
-
)
|
195
|
-
|
196
|
-
feature = "FlagName"
|
197
|
-
variants = [
|
198
|
-
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
199
|
-
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
200
|
-
Prefab::FeatureFlagVariant.new(string: "default"),
|
201
|
-
]
|
202
|
-
flag = Prefab::FeatureFlag.new(
|
203
|
-
active: true,
|
204
|
-
inactive_variant_idx: 1,
|
205
|
-
rules: [
|
206
|
-
Prefab::Rule.new(
|
207
|
-
variant_weights: [
|
208
|
-
Prefab::VariantWeight.new(weight: 1000,
|
209
|
-
variant_idx: 2)
|
210
|
-
],
|
211
|
-
criteria: Prefab::Criteria.new(
|
212
|
-
operator: "IN_SEG",
|
213
|
-
values: [segment_key]
|
214
|
-
)
|
215
|
-
),
|
216
|
-
Prefab::Rule.new(
|
217
|
-
criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
|
218
|
-
variant_weights: [
|
219
|
-
Prefab::VariantWeight.new(weight: 1000,
|
220
|
-
variant_idx: 3)
|
221
|
-
]
|
222
|
-
)
|
223
|
-
|
224
|
-
],
|
225
|
-
)
|
226
|
-
|
227
|
-
assert_equal "rule target",
|
228
|
-
evaluate(feature, "user:1", [], flag, variants)
|
229
|
-
assert_equal "default",
|
230
|
-
evaluate(feature, "user:2", [], flag, variants)
|
42
|
+
private
|
231
43
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
Prefab::Criteria.new(
|
240
|
-
operator: Prefab::Criteria::CriteriaOperator::LOOKUP_KEY_IN,
|
241
|
-
values: ["user:1", "user:2"]
|
242
|
-
)
|
243
|
-
]
|
244
|
-
)
|
245
|
-
)
|
246
|
-
segment_key_two = "prefab-segment-segment-2"
|
247
|
-
@mock_base_client.config_client.mock_this_config(segment_key_two,
|
248
|
-
Prefab::Segment.new(
|
249
|
-
criterion: [
|
250
|
-
Prefab::Criteria.new(
|
251
|
-
operator: Prefab::Criteria::CriteriaOperator::LOOKUP_KEY_IN,
|
252
|
-
values: ["user:3", "user:4"]
|
253
|
-
)
|
254
|
-
]
|
255
|
-
)
|
256
|
-
)
|
257
|
-
|
258
|
-
feature = "FlagName"
|
259
|
-
variants = [
|
260
|
-
Prefab::FeatureFlagVariant.new(string: "inactive"),
|
261
|
-
Prefab::FeatureFlagVariant.new(string: "rule target"),
|
262
|
-
Prefab::FeatureFlagVariant.new(string: "default"),
|
263
|
-
]
|
264
|
-
flag = Prefab::FeatureFlag.new(
|
265
|
-
active: true,
|
266
|
-
inactive_variant_idx: 1,
|
267
|
-
rules: [
|
268
|
-
Prefab::Rule.new(
|
269
|
-
variant_weights: [
|
270
|
-
Prefab::VariantWeight.new(weight: 1000,
|
271
|
-
variant_idx: 2)
|
272
|
-
],
|
273
|
-
criteria: Prefab::Criteria.new(
|
274
|
-
operator: "IN_SEG",
|
275
|
-
values: [segment_key_one, segment_key_two]
|
276
|
-
)
|
277
|
-
),
|
278
|
-
Prefab::Rule.new(
|
279
|
-
criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
|
280
|
-
variant_weights: [
|
281
|
-
Prefab::VariantWeight.new(weight: 1000,
|
282
|
-
variant_idx: 3)
|
283
|
-
]
|
284
|
-
)
|
285
|
-
|
286
|
-
],
|
287
|
-
)
|
288
|
-
|
289
|
-
assert_equal "rule target",
|
290
|
-
evaluate(feature, "user:1", [], flag, variants)
|
291
|
-
assert_equal "rule target",
|
292
|
-
evaluate(feature, "user:2", [], flag, variants), "matches segment 1"
|
293
|
-
assert_equal "rule target",
|
294
|
-
evaluate(feature, "user:3", [], flag, variants)
|
295
|
-
assert_equal "rule target",
|
296
|
-
evaluate(feature, "user:4", [], flag, variants)
|
297
|
-
assert_equal "default",
|
298
|
-
evaluate(feature, "user:5", [], flag, variants)
|
299
|
-
|
300
|
-
end
|
301
|
-
|
302
|
-
def test_prop_ends_with_one_of
|
303
|
-
feature = "FlagName"
|
304
|
-
|
305
|
-
variants = [
|
306
|
-
Prefab::FeatureFlagVariant.new(bool: false),
|
307
|
-
Prefab::FeatureFlagVariant.new(bool: true)
|
308
|
-
]
|
309
|
-
flag = Prefab::FeatureFlag.new(
|
310
|
-
active: true,
|
311
|
-
inactive_variant_idx: 1,
|
312
|
-
rules: [
|
313
|
-
Prefab::Rule.new(
|
314
|
-
criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::PROP_ENDS_WITH_ONE_OF,
|
315
|
-
property: "email",
|
316
|
-
values: ["@example.com"]),
|
317
|
-
variant_weights: [
|
318
|
-
Prefab::VariantWeight.new(weight: 100, variant_idx: 2)
|
319
|
-
]
|
320
|
-
)
|
321
|
-
]
|
322
|
-
)
|
323
|
-
|
324
|
-
assert_equal false, evaluate(feature, "user:0", {}, flag, variants)
|
325
|
-
assert_equal true, evaluate(feature, "user:0", {email: "test@example.com"}, flag, variants)
|
326
|
-
assert_equal true, evaluate(feature, "user:0", {"email" => "test@example.com"}, flag, variants)
|
327
|
-
end
|
328
|
-
|
329
|
-
def test_prop_does_not_end_with_one_of
|
330
|
-
feature = "FlagName"
|
331
|
-
|
332
|
-
variants = [
|
333
|
-
Prefab::FeatureFlagVariant.new(bool: false),
|
334
|
-
Prefab::FeatureFlagVariant.new(bool: true)
|
335
|
-
]
|
336
|
-
flag = Prefab::FeatureFlag.new(
|
337
|
-
active: true,
|
338
|
-
inactive_variant_idx: 1,
|
339
|
-
rules: [
|
340
|
-
Prefab::Rule.new(
|
341
|
-
criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::PROP_DOES_NOT_END_WITH_ONE_OF,
|
342
|
-
property: "email",
|
343
|
-
values: ["@example.com"]),
|
344
|
-
variant_weights: [
|
345
|
-
Prefab::VariantWeight.new(weight: 100, variant_idx: 2)
|
346
|
-
]
|
347
|
-
),
|
348
|
-
Prefab::Rule.new(
|
349
|
-
criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
|
350
|
-
variant_weights: [
|
351
|
-
Prefab::VariantWeight.new(weight: 100, variant_idx: 1)
|
352
|
-
]
|
353
|
-
)
|
354
|
-
],
|
355
|
-
)
|
356
|
-
|
357
|
-
assert_equal true, evaluate(feature, "user:0", {}, flag, variants)
|
358
|
-
assert_equal false, evaluate(feature, "user:0", {email: "test@example.com"}, flag, variants)
|
359
|
-
assert_equal false, evaluate(feature, "user:0", {"email" => "test@example.com"}, flag, variants)
|
360
|
-
end
|
44
|
+
def new_client(overrides = {})
|
45
|
+
options = Prefab::Options.new(**{
|
46
|
+
prefab_config_override_dir: 'none',
|
47
|
+
prefab_config_classpath_dir: 'test',
|
48
|
+
prefab_envs: ['unit_tests'],
|
49
|
+
prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY
|
50
|
+
}.merge(overrides))
|
361
51
|
|
362
|
-
|
363
|
-
variant = @client.get_variant(feature_name, lookup_key, attributes, flag, variants)
|
364
|
-
@client.value_of_variant(variant)
|
52
|
+
Prefab::Client.new(options).feature_flag_client
|
365
53
|
end
|
366
54
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'minitest/autorun'
|
3
|
-
require
|
4
|
+
require 'minitest/focus'
|
5
|
+
require 'minitest/reporters'
|
6
|
+
Minitest::Reporters.use!
|
7
|
+
|
4
8
|
require 'prefab-cloud-ruby'
|
5
9
|
|
6
10
|
class MockBaseClient
|
7
11
|
STAGING_ENV_ID = 1
|
8
12
|
PRODUCTION_ENV_ID = 2
|
9
13
|
TEST_ENV_ID = 3
|
10
|
-
attr_reader :namespace
|
14
|
+
attr_reader :namespace
|
15
|
+
attr_reader :logger
|
16
|
+
attr_reader :config_client
|
17
|
+
attr_reader :options
|
11
18
|
|
12
19
|
def initialize(options = Prefab::Options.new)
|
13
20
|
@options = options
|
@@ -24,20 +31,19 @@ class MockBaseClient
|
|
24
31
|
@logger
|
25
32
|
end
|
26
33
|
|
27
|
-
def log_internal
|
28
|
-
end
|
34
|
+
def log_internal(level, message); end
|
29
35
|
|
30
|
-
def config_value
|
36
|
+
def config_value(key)
|
31
37
|
@config_values[key]
|
32
38
|
end
|
33
|
-
|
34
39
|
end
|
35
40
|
|
36
41
|
class MockConfigClient
|
37
42
|
def initialize(config_values = {})
|
38
43
|
@config_values = config_values
|
39
44
|
end
|
40
|
-
|
45
|
+
|
46
|
+
def get(key, default = nil)
|
41
47
|
@config_values.fetch(key, default)
|
42
48
|
end
|
43
49
|
|
@@ -45,17 +51,15 @@ class MockConfigClient
|
|
45
51
|
Prefab::Config.new(value: @config_values[key], key: key)
|
46
52
|
end
|
47
53
|
|
48
|
-
def mock_this_config
|
54
|
+
def mock_this_config(key, config_value)
|
49
55
|
@config_values[key] = config_value
|
50
56
|
end
|
51
57
|
end
|
52
58
|
|
53
59
|
class MockConfigLoader
|
54
|
-
def calc_config
|
55
|
-
end
|
60
|
+
def calc_config; end
|
56
61
|
end
|
57
62
|
|
58
|
-
|
59
63
|
private
|
60
64
|
|
61
65
|
def default_ff_rule(variant_idx)
|
@@ -81,9 +85,9 @@ end
|
|
81
85
|
|
82
86
|
def new_client(overrides = {})
|
83
87
|
options = Prefab::Options.new(**{
|
84
|
-
prefab_config_override_dir:
|
85
|
-
prefab_config_classpath_dir:
|
86
|
-
prefab_envs: [
|
88
|
+
prefab_config_override_dir: 'none',
|
89
|
+
prefab_config_classpath_dir: 'test',
|
90
|
+
prefab_envs: ['unit_tests'],
|
87
91
|
prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY
|
88
92
|
}.merge(overrides))
|
89
93
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'integration_test_helpers'
|
5
|
+
require 'integration_test'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
class TestIntegration < Minitest::Test
|
9
|
+
IntegrationTestHelpers.find_integration_tests.map do |test_file|
|
10
|
+
tests = YAML.load(File.read(test_file))['tests']
|
11
|
+
|
12
|
+
tests.each do |test|
|
13
|
+
define_method(:"test_#{test['name']}") do
|
14
|
+
it = IntegrationTest.new(test)
|
15
|
+
|
16
|
+
case it.test_type
|
17
|
+
when :raise
|
18
|
+
err = assert_raises(it.expected[:error]) do
|
19
|
+
it.test_client.send(it.func, *it.input)
|
20
|
+
end
|
21
|
+
assert_match(/#{it.expected[:message]}/, err.message)
|
22
|
+
when :nil
|
23
|
+
assert_nil it.test_client.send(it.func, *it.input)
|
24
|
+
when :feature_flag
|
25
|
+
flag, lookup_key, attributes = *it.input
|
26
|
+
assert_equal it.expected[:value], it.test_client.send(it.func, flag, lookup_key, attributes: attributes)
|
27
|
+
when :simple_equality
|
28
|
+
assert_equal it.expected[:value], it.test_client.send(it.func, *it.input)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestLocalConfigParser < Minitest::Test
|
6
|
+
FILE_NAME = 'example-config.yaml'
|
7
|
+
DEFAULT_MATCH = 'default'
|
8
|
+
|
9
|
+
def test_parse_int_config
|
10
|
+
key = :sample_int
|
11
|
+
parsed = Prefab::LocalConfigParser.parse(key, 123, {}, FILE_NAME)[key]
|
12
|
+
config = parsed[:config]
|
13
|
+
|
14
|
+
assert_equal FILE_NAME, parsed[:source]
|
15
|
+
assert_equal DEFAULT_MATCH, parsed[:match]
|
16
|
+
assert_equal :CONFIG, config.config_type
|
17
|
+
assert_equal key.to_s, config.key
|
18
|
+
assert_equal 1, config.rows.size
|
19
|
+
assert_equal 1, config.rows[0].values.size
|
20
|
+
assert_equal 123, config.rows[0].values[0].value.int
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_flag_with_a_value
|
24
|
+
key = :flag_with_a_value
|
25
|
+
value = stringify_keys({ feature_flag: true, value: 'all-features' })
|
26
|
+
parsed = Prefab::LocalConfigParser.parse(key, value, {}, FILE_NAME)[key]
|
27
|
+
config = parsed[:config]
|
28
|
+
|
29
|
+
assert_equal FILE_NAME, parsed[:source]
|
30
|
+
assert_equal key, parsed[:match]
|
31
|
+
assert_equal :FEATURE_FLAG, config.config_type
|
32
|
+
assert_equal key.to_s, config.key
|
33
|
+
assert_equal 1, config.rows.size
|
34
|
+
assert_equal 1, config.rows[0].values.size
|
35
|
+
|
36
|
+
value_row = config.rows[0].values[0]
|
37
|
+
assert_equal Prefab::WeightedValues, value_row.value.weighted_values.class
|
38
|
+
assert_equal 'all-features', Prefab::ConfigValueUnwrapper.unwrap(value_row.value, key, {})
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_flag_in_lookup_key
|
42
|
+
key = :flag_in_lookup_key
|
43
|
+
value = stringify_keys({ "feature_flag": 'true', value: true,
|
44
|
+
criterion: { operator: 'LOOKUP_KEY_IN', values: %w[abc123 xyz987] } })
|
45
|
+
parsed = Prefab::LocalConfigParser.parse(key, value, {}, FILE_NAME)[key]
|
46
|
+
config = parsed[:config]
|
47
|
+
|
48
|
+
assert_equal FILE_NAME, parsed[:source]
|
49
|
+
assert_equal key, parsed[:match]
|
50
|
+
assert_equal :FEATURE_FLAG, config.config_type
|
51
|
+
assert_equal key.to_s, config.key
|
52
|
+
assert_equal 1, config.rows.size
|
53
|
+
assert_equal 1, config.rows[0].values.size
|
54
|
+
assert_equal 1, config.rows[0].values[0].criteria.size
|
55
|
+
|
56
|
+
value_row = config.rows[0].values[0]
|
57
|
+
assert_equal Prefab::WeightedValues, value_row.value.weighted_values.class
|
58
|
+
assert_equal true, Prefab::ConfigValueUnwrapper.unwrap(value_row.value, key, {})
|
59
|
+
|
60
|
+
assert_equal Prefab::CriteriaEvaluator::LOOKUP_KEY, value_row.criteria[0].property_name
|
61
|
+
assert_equal :LOOKUP_KEY_IN, value_row.criteria[0].operator
|
62
|
+
assert_equal %w[abc123 xyz987], value_row.criteria[0].value_to_match.string_list.values
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def stringify_keys(hash)
|
68
|
+
deep_transform_keys(hash, &:to_s)
|
69
|
+
end
|
70
|
+
|
71
|
+
def deep_transform_keys(hash, &block)
|
72
|
+
result = {}
|
73
|
+
hash.each do |key, value|
|
74
|
+
result[yield(key)] = value.is_a?(Hash) ? deep_transform_keys(value, &block) : value
|
75
|
+
end
|
76
|
+
result
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'timecop'
|
5
|
+
|
6
|
+
class TestLogPathCollector < Minitest::Test
|
7
|
+
def test_sync
|
8
|
+
Timecop.freeze do
|
9
|
+
client = new_client(namespace: 'this.is.a.namespace')
|
10
|
+
|
11
|
+
2.times { client.log.info('here is a message') }
|
12
|
+
3.times { client.log.error('here is a message') }
|
13
|
+
|
14
|
+
requests = []
|
15
|
+
|
16
|
+
client.define_singleton_method(:request) do |*params|
|
17
|
+
requests.push(params)
|
18
|
+
end
|
19
|
+
|
20
|
+
client.log_path_collector.send(:sync)
|
21
|
+
|
22
|
+
# let the flush thread run
|
23
|
+
sleep 0.01 while requests.length == 0
|
24
|
+
|
25
|
+
assert_equal requests, [[
|
26
|
+
Prefab::LoggerReportingService,
|
27
|
+
:send,
|
28
|
+
{
|
29
|
+
req_options: {},
|
30
|
+
params: Prefab::Loggers.new(
|
31
|
+
loggers: [Prefab::Logger.new(logger_name: 'test.test_log_path_collector.test_sync',
|
32
|
+
infos: 2, errors: 3)],
|
33
|
+
start_at: (Time.now.utc.to_f * 1000).to_i,
|
34
|
+
end_at: (Time.now.utc.to_f * 1000).to_i,
|
35
|
+
instance_hash: client.instance_hash,
|
36
|
+
namespace: 'this.is.a.namespace'
|
37
|
+
)
|
38
|
+
}
|
39
|
+
]]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def new_client(overrides = {})
|
46
|
+
options = Prefab::Options.new(**{
|
47
|
+
prefab_config_override_dir: 'none',
|
48
|
+
prefab_config_classpath_dir: 'test',
|
49
|
+
prefab_envs: ['unit_tests'],
|
50
|
+
api_key: '123-development-yourapikey-SDK',
|
51
|
+
collect_sync_interval: 1000 # we'll trigger sync manually in our test
|
52
|
+
}.merge(overrides))
|
53
|
+
|
54
|
+
Prefab::Client.new(options)
|
55
|
+
end
|
56
|
+
end
|