prefab-cloud-ruby 0.23.7 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -8
- data/VERSION +1 -1
- data/lib/prefab/client.rb +55 -21
- data/lib/prefab/config_client.rb +13 -25
- data/lib/prefab/config_resolver.rb +28 -28
- data/lib/prefab/config_value_unwrapper.rb +8 -5
- data/lib/prefab/context.rb +119 -0
- data/lib/prefab/criteria_evaluator.rb +23 -17
- data/lib/prefab/feature_flag_client.rb +7 -7
- data/lib/prefab/local_config_parser.rb +2 -17
- data/lib/prefab/logger_client.rb +3 -6
- data/lib/prefab/resolved_config_presenter.rb +84 -0
- data/lib/prefab/weighted_value_resolver.rb +4 -4
- data/lib/prefab-cloud-ruby.rb +6 -0
- data/lib/prefab_pb.rb +42 -41
- data/prefab-cloud-ruby.gemspec +6 -4
- data/test/.prefab.unit_tests.config.yaml +3 -2
- data/test/integration_test.rb +4 -8
- data/test/test_client.rb +28 -27
- data/test/test_config_resolver.rb +106 -54
- data/test/test_config_value_unwrapper.rb +15 -15
- data/test/test_context.rb +158 -0
- data/test/test_criteria_evaluator.rb +93 -78
- data/test/test_feature_flag_client.rb +14 -20
- data/test/test_helper.rb +1 -1
- data/test/test_integration.rb +30 -14
- data/test/test_local_config_parser.rb +6 -8
- data/test/test_log_path_collector.rb +4 -7
- data/test/test_logger.rb +12 -12
- metadata +5 -3
- data/lib/prefab_services_pb.rb +0 -80
@@ -9,10 +9,19 @@ class TestConfigResolver < Minitest::Test
|
|
9
9
|
SEGMENT_KEY = 'segment_key'
|
10
10
|
CONFIG_KEY = 'config_key'
|
11
11
|
DEFAULT_VALUE = 'default_value'
|
12
|
+
DESIRED_VALUE = 'desired_value'
|
12
13
|
IN_SEGMENT_VALUE = 'in_segment_value'
|
13
14
|
WRONG_ENV_VALUE = 'wrong_env_value'
|
14
15
|
NOT_IN_SEGMENT_VALUE = 'not_in_segment_value'
|
15
16
|
|
17
|
+
DEFAULT_ROW = Prefab::ConfigRow.new(
|
18
|
+
values: [
|
19
|
+
Prefab::ConditionalValue.new(
|
20
|
+
value: Prefab::ConfigValue.new(string: DEFAULT_VALUE)
|
21
|
+
)
|
22
|
+
]
|
23
|
+
)
|
24
|
+
|
16
25
|
def test_resolution
|
17
26
|
@loader = MockConfigLoader.new
|
18
27
|
|
@@ -20,13 +29,7 @@ class TestConfigResolver < Minitest::Test
|
|
20
29
|
'key' => { config: Prefab::Config.new(
|
21
30
|
key: 'key',
|
22
31
|
rows: [
|
23
|
-
|
24
|
-
values: [
|
25
|
-
Prefab::ConditionalValue.new(
|
26
|
-
value: Prefab::ConfigValue.new(string: 'value_no_env_default')
|
27
|
-
)
|
28
|
-
]
|
29
|
-
),
|
32
|
+
DEFAULT_ROW,
|
30
33
|
Prefab::ConfigRow.new(
|
31
34
|
project_env_id: TEST_ENV_ID,
|
32
35
|
values: [
|
@@ -114,31 +117,49 @@ class TestConfigResolver < Minitest::Test
|
|
114
117
|
|
115
118
|
@loader.stub :calc_config, loaded_values do
|
116
119
|
@resolverA = resolver_for_namespace('', @loader, project_env_id: PRODUCTION_ENV_ID)
|
117
|
-
|
120
|
+
assert_equal_context_and_jit DEFAULT_VALUE, @resolverA, 'key', {}, :string
|
118
121
|
|
119
122
|
## below here in the test env
|
120
123
|
@resolverA = resolver_for_namespace('', @loader)
|
121
|
-
|
124
|
+
assert_equal_context_and_jit 'value_none', @resolverA, 'key', {}, :string
|
122
125
|
|
123
126
|
@resolverA = resolver_for_namespace('projectA', @loader)
|
124
|
-
|
127
|
+
assert_equal_context_and_jit 'valueA', @resolverA, 'key', {}, :string
|
125
128
|
|
126
129
|
@resolverB = resolver_for_namespace('projectB', @loader)
|
127
|
-
|
130
|
+
assert_equal_context_and_jit 'valueB', @resolverB, 'key', {}, :string
|
128
131
|
|
129
132
|
@resolverBX = resolver_for_namespace('projectB.subprojectX', @loader)
|
130
|
-
|
133
|
+
assert_equal_context_and_jit 'projectB.subprojectX', @resolverBX, 'key', {}, :string
|
131
134
|
|
132
135
|
@resolverBX = resolver_for_namespace('projectB.subprojectX', @loader)
|
133
|
-
|
136
|
+
assert_equal_context_and_jit 'valueB2', @resolverBX, 'key2', {}, :string
|
134
137
|
|
135
|
-
@resolverUndefinedSubProject = resolver_for_namespace('projectB.subprojectX.subsubQ',
|
136
|
-
|
138
|
+
@resolverUndefinedSubProject = resolver_for_namespace('projectB.subprojectX.subsubQ',
|
139
|
+
@loader)
|
140
|
+
assert_equal_context_and_jit 'projectB.subprojectX', @resolverUndefinedSubProject, 'key',
|
141
|
+
{}, :string
|
137
142
|
|
138
143
|
@resolverBX = resolver_for_namespace('projectC', @loader)
|
139
|
-
|
144
|
+
assert_equal_context_and_jit 'value_none', @resolverBX, 'key', {}, :string
|
140
145
|
|
141
146
|
assert_nil @resolverBX.get('key_that_doesnt_exist', nil)
|
147
|
+
|
148
|
+
assert_equal @resolverBX.to_s.strip.split("\n").map(&:strip), [
|
149
|
+
'key | value_none | String | Match: | Source:',
|
150
|
+
'key2 | valueB2 | String | Match: | Source:'
|
151
|
+
]
|
152
|
+
|
153
|
+
assert_equal @resolverBX.presenter.to_h, {
|
154
|
+
'key' => Prefab::ResolvedConfigPresenter::ConfigRow.new('key', 'value_none', nil, nil),
|
155
|
+
'key2' => Prefab::ResolvedConfigPresenter::ConfigRow.new('key2', 'valueB2', nil, nil)
|
156
|
+
}
|
157
|
+
|
158
|
+
resolved_lines = []
|
159
|
+
@resolverBX.presenter.each do |key, row|
|
160
|
+
resolved_lines << [key, row.value]
|
161
|
+
end
|
162
|
+
assert_equal resolved_lines, [%w[key value_none], %w[key2 valueB2]]
|
142
163
|
end
|
143
164
|
end
|
144
165
|
|
@@ -155,7 +176,7 @@ class TestConfigResolver < Minitest::Test
|
|
155
176
|
Prefab::Criterion.new(
|
156
177
|
operator: Prefab::Criterion::CriterionOperator::PROP_ENDS_WITH_ONE_OF,
|
157
178
|
value_to_match: string_list(['hotmail.com', 'gmail.com']),
|
158
|
-
property_name: 'email'
|
179
|
+
property_name: 'user.email'
|
159
180
|
)
|
160
181
|
]
|
161
182
|
),
|
@@ -222,8 +243,10 @@ class TestConfigResolver < Minitest::Test
|
|
222
243
|
resolver = Prefab::ConfigResolver.new(MockBaseClient.new(options), loader)
|
223
244
|
resolver.project_env_id = PRODUCTION_ENV_ID
|
224
245
|
|
225
|
-
|
226
|
-
|
246
|
+
assert_equal_context_and_jit DEFAULT_VALUE, resolver, CONFIG_KEY,
|
247
|
+
{ user: { email: 'test@something-else.com' } }, :string
|
248
|
+
assert_equal_context_and_jit IN_SEGMENT_VALUE, resolver, CONFIG_KEY,
|
249
|
+
{ user: { email: 'test@hotmail.com' } }, :string
|
227
250
|
end
|
228
251
|
end
|
229
252
|
|
@@ -240,7 +263,7 @@ class TestConfigResolver < Minitest::Test
|
|
240
263
|
Prefab::Criterion.new(
|
241
264
|
operator: Prefab::Criterion::CriterionOperator::PROP_ENDS_WITH_ONE_OF,
|
242
265
|
value_to_match: string_list(['hotmail.com', 'gmail.com']),
|
243
|
-
property_name: 'email'
|
266
|
+
property_name: 'user.email'
|
244
267
|
)
|
245
268
|
]
|
246
269
|
),
|
@@ -289,77 +312,98 @@ class TestConfigResolver < Minitest::Test
|
|
289
312
|
options = Prefab::Options.new
|
290
313
|
resolver = Prefab::ConfigResolver.new(MockBaseClient.new(options), loader)
|
291
314
|
|
292
|
-
|
293
|
-
|
315
|
+
assert_equal_context_and_jit IN_SEGMENT_VALUE, resolver, CONFIG_KEY, { user: { email: 'test@hotmail.com' } },
|
316
|
+
:string
|
317
|
+
assert_equal_context_and_jit NOT_IN_SEGMENT_VALUE, resolver, CONFIG_KEY, { user: { email: 'test@something-else.com' } },
|
318
|
+
:string
|
294
319
|
end
|
295
320
|
end
|
296
321
|
|
297
|
-
def
|
298
|
-
|
299
|
-
|
300
|
-
key: SEGMENT_KEY,
|
322
|
+
def test_jit_context_merges_with_existing_context
|
323
|
+
config = Prefab::Config.new(
|
324
|
+
key: CONFIG_KEY,
|
301
325
|
rows: [
|
326
|
+
DEFAULT_ROW,
|
302
327
|
Prefab::ConfigRow.new(
|
328
|
+
project_env_id: TEST_ENV_ID,
|
303
329
|
values: [
|
304
330
|
Prefab::ConditionalValue.new(
|
305
|
-
value: Prefab::ConfigValue.new(bool: true),
|
306
331
|
criteria: [
|
307
332
|
Prefab::Criterion.new(
|
308
|
-
operator: Prefab::Criterion::CriterionOperator::
|
309
|
-
value_to_match: string_list([
|
310
|
-
property_name: '
|
333
|
+
operator: Prefab::Criterion::CriterionOperator::PROP_IS_ONE_OF,
|
334
|
+
value_to_match: string_list(%w[pro advanced]),
|
335
|
+
property_name: 'team.plan'
|
336
|
+
),
|
337
|
+
|
338
|
+
Prefab::Criterion.new(
|
339
|
+
operator: Prefab::Criterion::CriterionOperator::PROP_ENDS_WITH_ONE_OF,
|
340
|
+
value_to_match: string_list(%w[@example.com]),
|
341
|
+
property_name: 'user.email'
|
311
342
|
)
|
312
|
-
]
|
313
|
-
|
314
|
-
|
343
|
+
],
|
344
|
+
value: Prefab::ConfigValue.new(string: DESIRED_VALUE)
|
345
|
+
)
|
315
346
|
]
|
316
347
|
)
|
317
348
|
]
|
318
349
|
)
|
319
350
|
|
351
|
+
loader = MockConfigLoader.new
|
352
|
+
|
353
|
+
loader.stub :calc_config, { CONFIG_KEY => { config: config } } do
|
354
|
+
options = Prefab::Options.new
|
355
|
+
resolver = Prefab::ConfigResolver.new(MockBaseClient.new(options), loader)
|
356
|
+
resolver.project_env_id = TEST_ENV_ID
|
357
|
+
|
358
|
+
Prefab::Context.with_context({ user: { email: 'test@example.com' } }) do
|
359
|
+
assert_equal DEFAULT_VALUE, resolver.get(CONFIG_KEY).string
|
360
|
+
assert_equal DEFAULT_VALUE, resolver.get(CONFIG_KEY, { team: { plan: 'freebie' } }).string
|
361
|
+
assert_equal DESIRED_VALUE, resolver.get(CONFIG_KEY, { team: { plan: 'pro' } }).string
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def test_jit_can_clobber_existing_context
|
320
367
|
config = Prefab::Config.new(
|
321
368
|
key: CONFIG_KEY,
|
322
369
|
rows: [
|
370
|
+
DEFAULT_ROW,
|
323
371
|
Prefab::ConfigRow.new(
|
372
|
+
project_env_id: TEST_ENV_ID,
|
324
373
|
values: [
|
325
374
|
Prefab::ConditionalValue.new(
|
326
375
|
criteria: [
|
327
376
|
Prefab::Criterion.new(
|
328
|
-
operator: Prefab::Criterion::CriterionOperator::
|
329
|
-
value_to_match:
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
),
|
334
|
-
Prefab::ConditionalValue.new(
|
335
|
-
criteria: [
|
377
|
+
operator: Prefab::Criterion::CriterionOperator::PROP_IS_ONE_OF,
|
378
|
+
value_to_match: string_list(%w[pro advanced]),
|
379
|
+
property_name: 'team.plan'
|
380
|
+
),
|
381
|
+
|
336
382
|
Prefab::Criterion.new(
|
337
|
-
operator: Prefab::Criterion::CriterionOperator::
|
338
|
-
value_to_match:
|
383
|
+
operator: Prefab::Criterion::CriterionOperator::PROP_ENDS_WITH_ONE_OF,
|
384
|
+
value_to_match: string_list(%w[@example.com]),
|
385
|
+
property_name: 'user.email'
|
339
386
|
)
|
340
387
|
],
|
341
|
-
value: Prefab::ConfigValue.new(string:
|
388
|
+
value: Prefab::ConfigValue.new(string: DESIRED_VALUE)
|
342
389
|
)
|
343
390
|
]
|
344
391
|
)
|
345
392
|
]
|
346
393
|
)
|
347
394
|
|
348
|
-
loaded_values = {
|
349
|
-
SEGMENT_KEY => { config: segment_config },
|
350
|
-
CONFIG_KEY => { config: config }
|
351
|
-
}
|
352
|
-
|
353
395
|
loader = MockConfigLoader.new
|
354
396
|
|
355
|
-
loader.stub :calc_config,
|
397
|
+
loader.stub :calc_config, { CONFIG_KEY => { config: config } } do
|
356
398
|
options = Prefab::Options.new
|
357
399
|
resolver = Prefab::ConfigResolver.new(MockBaseClient.new(options), loader)
|
400
|
+
resolver.project_env_id = TEST_ENV_ID
|
358
401
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
402
|
+
Prefab::Context.with_context({ user: { email: 'test@hotmail.com' }, team: { plan: 'pro' } }) do
|
403
|
+
assert_equal DEFAULT_VALUE, resolver.get(CONFIG_KEY).string
|
404
|
+
assert_equal DESIRED_VALUE, resolver.get(CONFIG_KEY, { user: { email: 'test@example.com' } }).string
|
405
|
+
assert_equal DEFAULT_VALUE, resolver.get(CONFIG_KEY, { team: { plan: 'freebie' } }).string
|
406
|
+
end
|
363
407
|
end
|
364
408
|
end
|
365
409
|
|
@@ -374,4 +418,12 @@ class TestConfigResolver < Minitest::Test
|
|
374
418
|
resolver.update
|
375
419
|
resolver
|
376
420
|
end
|
421
|
+
|
422
|
+
def assert_equal_context_and_jit(expected_value, resolver, key, properties, type)
|
423
|
+
assert_equal expected_value, resolver.get(key, properties).send(type)
|
424
|
+
|
425
|
+
Prefab::Context.with_context(properties) do
|
426
|
+
assert_equal expected_value, resolver.get(key).send(type)
|
427
|
+
end
|
428
|
+
end
|
377
429
|
end
|
@@ -41,34 +41,34 @@ class TestConfigValueUnwrapper < Minitest::Test
|
|
41
41
|
def test_unwrapping_weighted_values
|
42
42
|
# single value
|
43
43
|
config_value = Prefab::ConfigValue.new(weighted_values: weighted_values([['abc', 1]]))
|
44
|
+
|
44
45
|
assert_equal 'abc', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, {})
|
45
46
|
|
46
47
|
# multiple values, evenly distributed
|
47
48
|
config_value = Prefab::ConfigValue.new(weighted_values: weighted_values([['abc', 1], ['def', 1], ['ghi', 1]]))
|
48
|
-
assert_equal '
|
49
|
-
assert_equal 'ghi', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY,
|
50
|
-
assert_equal 'abc', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY,
|
51
|
-
assert_equal '
|
49
|
+
assert_equal 'def', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:000'))
|
50
|
+
assert_equal 'ghi', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:456'))
|
51
|
+
assert_equal 'abc', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:789'))
|
52
|
+
assert_equal 'ghi', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:888'))
|
52
53
|
|
53
54
|
# multiple values, unevenly distributed
|
54
55
|
config_value = Prefab::ConfigValue.new(weighted_values: weighted_values([['abc', 1], ['def', 99], ['ghi', 1]]))
|
55
|
-
assert_equal 'def', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY,
|
56
|
-
assert_equal 'def', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY,
|
57
|
-
assert_equal 'def', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY,
|
58
|
-
assert_equal 'def', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY,
|
59
|
-
|
60
|
-
assert_equal '
|
61
|
-
assert_equal 'abc', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, lookup_properties('user:119'))
|
56
|
+
assert_equal 'def', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:123'))
|
57
|
+
assert_equal 'def', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:456'))
|
58
|
+
assert_equal 'def', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:789'))
|
59
|
+
assert_equal 'def', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:012'))
|
60
|
+
assert_equal 'ghi', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:428'))
|
61
|
+
assert_equal 'abc', Prefab::ConfigValueUnwrapper.unwrap(config_value, CONFIG_KEY, context_with_key('user:548'))
|
62
62
|
end
|
63
63
|
|
64
64
|
private
|
65
65
|
|
66
|
-
def weighted_values(values_and_weights)
|
66
|
+
def weighted_values(values_and_weights, hash_by_property_name: 'user.key')
|
67
67
|
values = values_and_weights.map do |value, weight|
|
68
68
|
weighted_value(value, weight)
|
69
69
|
end
|
70
70
|
|
71
|
-
Prefab::WeightedValues.new(weighted_values: values)
|
71
|
+
Prefab::WeightedValues.new(weighted_values: values, hash_by_property_name: hash_by_property_name)
|
72
72
|
end
|
73
73
|
|
74
74
|
def weighted_value(string, weight)
|
@@ -77,7 +77,7 @@ class TestConfigValueUnwrapper < Minitest::Test
|
|
77
77
|
)
|
78
78
|
end
|
79
79
|
|
80
|
-
def
|
81
|
-
|
80
|
+
def context_with_key(key)
|
81
|
+
Prefab::Context.new(user: { key: key })
|
82
82
|
end
|
83
83
|
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestContext < Minitest::Test
|
6
|
+
EXAMPLE_PROPERTIES = { user: { key: 'some-user-key', name: 'Ted' }, team: { key: 'abc', plan: 'pro' } }.freeze
|
7
|
+
|
8
|
+
def setup
|
9
|
+
Prefab::Context.current = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_initialize_with_empty_context
|
13
|
+
context = Prefab::Context.new({})
|
14
|
+
assert_empty context.contexts
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_initialize_with_named_context
|
18
|
+
named_context = Prefab::Context::NamedContext.new('test', foo: 'bar')
|
19
|
+
context = Prefab::Context.new(named_context)
|
20
|
+
assert_equal 1, context.contexts.size
|
21
|
+
assert_equal named_context, context.contexts['test']
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_initialize_with_hash
|
25
|
+
context = Prefab::Context.new(test: { foo: 'bar' })
|
26
|
+
assert_equal 1, context.contexts.size
|
27
|
+
assert_equal 'bar', context.contexts['test'].get('foo')
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_initialize_with_multiple_hashes
|
31
|
+
context = Prefab::Context.new(test: { foo: 'bar' }, other: { foo: 'baz' })
|
32
|
+
assert_equal 2, context.contexts.size
|
33
|
+
assert_equal 'bar', context.contexts['test'].get('foo')
|
34
|
+
assert_equal 'baz', context.contexts['other'].get('foo')
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_initialize_with_invalid_hash
|
38
|
+
_, err = capture_io do
|
39
|
+
Prefab::Context.new({ foo: 'bar', baz: 'qux' })
|
40
|
+
end
|
41
|
+
|
42
|
+
assert_match '[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash',
|
43
|
+
err
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_initialize_with_invalid_argument
|
47
|
+
assert_raises(ArgumentError) { Prefab::Context.new([]) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_current
|
51
|
+
context = Prefab::Context.current
|
52
|
+
assert_instance_of Prefab::Context, context
|
53
|
+
assert_empty context.to_h
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_current_set
|
57
|
+
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
58
|
+
Prefab::Context.current = context
|
59
|
+
assert_instance_of Prefab::Context, context
|
60
|
+
assert_equal stringify(EXAMPLE_PROPERTIES), context.to_h
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_merge_with_current
|
64
|
+
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
65
|
+
Prefab::Context.current = context
|
66
|
+
assert_equal stringify(EXAMPLE_PROPERTIES), context.to_h
|
67
|
+
|
68
|
+
new_context = Prefab::Context.merge_with_current({ user: { key: 'brand-new', other: 'different' },
|
69
|
+
address: { city: 'New York' } })
|
70
|
+
assert_equal stringify({
|
71
|
+
# Note that the user's `name` from the original
|
72
|
+
# context is not included. This is because we don't _merge_ the new
|
73
|
+
# properties if they collide with an existing context name. We _replace_
|
74
|
+
# them.
|
75
|
+
user: { key: 'brand-new', other: 'different' },
|
76
|
+
team: EXAMPLE_PROPERTIES[:team],
|
77
|
+
address: { city: 'New York' }
|
78
|
+
}),
|
79
|
+
new_context.to_h
|
80
|
+
|
81
|
+
# the original/current context is unchanged
|
82
|
+
assert_equal stringify(EXAMPLE_PROPERTIES), Prefab::Context.current.to_h
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_with_context
|
86
|
+
Prefab::Context.with_context(EXAMPLE_PROPERTIES) do
|
87
|
+
context = Prefab::Context.current
|
88
|
+
assert_equal(stringify(EXAMPLE_PROPERTIES), context.to_h)
|
89
|
+
assert_equal('some-user-key', context['user.key'])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_with_context_nesting
|
94
|
+
Prefab::Context.with_context(EXAMPLE_PROPERTIES) do
|
95
|
+
Prefab::Context.with_context({ user: { key: 'abc', other: 'different' } }) do
|
96
|
+
context = Prefab::Context.current
|
97
|
+
assert_equal({ 'user' => { 'key' => 'abc', 'other' => 'different' } }, context.to_h)
|
98
|
+
end
|
99
|
+
|
100
|
+
context = Prefab::Context.current
|
101
|
+
assert_equal(stringify(EXAMPLE_PROPERTIES), context.to_h)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_setting
|
106
|
+
context = Prefab::Context.new({})
|
107
|
+
context.set('user', { key: 'value' })
|
108
|
+
context[:other] = { key: 'different', something: 'other' }
|
109
|
+
assert_equal(stringify({ user: { key: 'value' }, other: { key: 'different', something: 'other' } }), context.to_h)
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_getting
|
113
|
+
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
114
|
+
assert_equal('some-user-key', context.get('user.key'))
|
115
|
+
assert_equal('some-user-key', context['user.key'])
|
116
|
+
assert_equal('pro', context.get('team.plan'))
|
117
|
+
assert_equal('pro', context['team.plan'])
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_dot_notation_getting
|
121
|
+
context = Prefab::Context.new({ 'user' => { 'key' => 'value' } })
|
122
|
+
assert_equal('value', context.get('user.key'))
|
123
|
+
assert_equal('value', context['user.key'])
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_dot_notation_getting_with_symbols
|
127
|
+
context = Prefab::Context.new({ user: { key: 'value' } })
|
128
|
+
assert_equal('value', context.get('user.key'))
|
129
|
+
assert_equal('value', context['user.key'])
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_merge
|
133
|
+
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
134
|
+
context.merge!(:other, { key: 'different' })
|
135
|
+
assert_equal(stringify(EXAMPLE_PROPERTIES.merge(other: { key: 'different' })), context.to_h)
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_clear
|
139
|
+
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
140
|
+
context.clear
|
141
|
+
|
142
|
+
assert_empty context.to_h
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def stringify(hash)
|
148
|
+
hash.map { |k, v| [k.to_s, stringify_keys(v)] }.to_h
|
149
|
+
end
|
150
|
+
|
151
|
+
def stringify_keys(value)
|
152
|
+
if value.is_a?(Hash)
|
153
|
+
value.transform_keys(&:to_s)
|
154
|
+
else
|
155
|
+
value
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|