prefab-cloud-ruby 0 → 0.0.1
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/.ruby-version +1 -0
- data/Gemfile +9 -22
- data/Gemfile.lock +88 -160
- data/LICENSE.txt +1 -1
- data/Rakefile +14 -14
- data/VERSION +1 -1
- data/lib/prefab/auth_interceptor.rb +25 -0
- data/lib/prefab/client.rb +34 -139
- data/lib/prefab/config_client.rb +23 -275
- data/lib/prefab/config_loader.rb +27 -60
- data/lib/prefab/config_resolver.rb +40 -53
- data/lib/prefab/noop_cache.rb +13 -0
- data/lib/prefab/noop_stats.rb +8 -0
- data/lib/prefab/prefab_pb.rb +39 -0
- data/lib/prefab/prefab_services_pb.rb +37 -0
- data/lib/prefab/ratelimit_client.rb +58 -0
- data/lib/prefab/ratelimit_pb.rb +125 -0
- data/lib/prefab/store.rb +29 -0
- data/lib/prefab_client.rb +35 -0
- metadata +36 -198
- data/.envrc.sample +0 -3
- data/.github/workflows/ruby.yml +0 -46
- data/.gitmodules +0 -3
- data/.rubocop.yml +0 -13
- data/.tool-versions +0 -1
- data/CHANGELOG.md +0 -169
- data/CODEOWNERS +0 -1
- data/README.md +0 -94
- data/bin/console +0 -21
- data/compile_protos.sh +0 -18
- data/lib/prefab/config_client_presenter.rb +0 -18
- data/lib/prefab/config_value_unwrapper.rb +0 -115
- data/lib/prefab/config_value_wrapper.rb +0 -18
- data/lib/prefab/context.rb +0 -179
- data/lib/prefab/context_shape.rb +0 -20
- data/lib/prefab/context_shape_aggregator.rb +0 -65
- data/lib/prefab/criteria_evaluator.rb +0 -136
- data/lib/prefab/encryption.rb +0 -65
- data/lib/prefab/error.rb +0 -6
- data/lib/prefab/errors/env_var_parse_error.rb +0 -11
- data/lib/prefab/errors/initialization_timeout_error.rb +0 -13
- data/lib/prefab/errors/invalid_api_key_error.rb +0 -19
- data/lib/prefab/errors/missing_default_error.rb +0 -13
- data/lib/prefab/errors/missing_env_var_error.rb +0 -11
- data/lib/prefab/errors/uninitialized_error.rb +0 -13
- data/lib/prefab/evaluation.rb +0 -52
- data/lib/prefab/evaluation_summary_aggregator.rb +0 -87
- data/lib/prefab/example_contexts_aggregator.rb +0 -78
- data/lib/prefab/exponential_backoff.rb +0 -21
- data/lib/prefab/feature_flag_client.rb +0 -42
- data/lib/prefab/http_connection.rb +0 -41
- data/lib/prefab/internal_logger.rb +0 -16
- data/lib/prefab/local_config_parser.rb +0 -151
- data/lib/prefab/log_path_aggregator.rb +0 -69
- data/lib/prefab/logger_client.rb +0 -264
- data/lib/prefab/murmer3.rb +0 -50
- data/lib/prefab/options.rb +0 -208
- data/lib/prefab/periodic_sync.rb +0 -69
- data/lib/prefab/prefab.rb +0 -56
- data/lib/prefab/rate_limit_cache.rb +0 -41
- data/lib/prefab/resolved_config_presenter.rb +0 -86
- data/lib/prefab/time_helpers.rb +0 -7
- data/lib/prefab/weighted_value_resolver.rb +0 -42
- data/lib/prefab/yaml_config_parser.rb +0 -34
- data/lib/prefab-cloud-ruby.rb +0 -57
- data/lib/prefab_pb.rb +0 -93
- data/prefab-cloud-ruby.gemspec +0 -155
- data/test/.prefab.default.config.yaml +0 -2
- data/test/.prefab.unit_tests.config.yaml +0 -28
- data/test/integration_test.rb +0 -150
- data/test/integration_test_helpers.rb +0 -151
- data/test/support/common_helpers.rb +0 -180
- data/test/support/mock_base_client.rb +0 -42
- data/test/support/mock_config_client.rb +0 -19
- data/test/support/mock_config_loader.rb +0 -1
- data/test/test_client.rb +0 -444
- data/test/test_config_client.rb +0 -109
- data/test/test_config_loader.rb +0 -117
- data/test/test_config_resolver.rb +0 -430
- data/test/test_config_value_unwrapper.rb +0 -224
- data/test/test_config_value_wrapper.rb +0 -42
- data/test/test_context.rb +0 -203
- data/test/test_context_shape.rb +0 -50
- data/test/test_context_shape_aggregator.rb +0 -147
- data/test/test_criteria_evaluator.rb +0 -726
- data/test/test_encryption.rb +0 -16
- data/test/test_evaluation_summary_aggregator.rb +0 -162
- data/test/test_example_contexts_aggregator.rb +0 -238
- data/test/test_exponential_backoff.rb +0 -18
- data/test/test_feature_flag_client.rb +0 -48
- data/test/test_helper.rb +0 -17
- data/test/test_integration.rb +0 -58
- data/test/test_local_config_parser.rb +0 -147
- data/test/test_log_path_aggregator.rb +0 -62
- data/test/test_logger.rb +0 -621
- data/test/test_logger_initialization.rb +0 -12
- data/test/test_options.rb +0 -75
- data/test/test_prefab.rb +0 -12
- data/test/test_rate_limit_cache.rb +0 -44
- data/test/test_weighted_value_resolver.rb +0 -71
@@ -1,224 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
class TestConfigValueUnwrapper < Minitest::Test
|
6
|
-
CONFIG = PrefabProto::Config.new(
|
7
|
-
key: 'config_key'
|
8
|
-
)
|
9
|
-
EMPTY_CONTEXT = Prefab::Context.new()
|
10
|
-
DECRYPTION_KEY_NAME = "decryption.key"
|
11
|
-
DECRYPTION_KEY_VALUE = Prefab::Encryption.generate_new_hex_key
|
12
|
-
|
13
|
-
def setup
|
14
|
-
super
|
15
|
-
@mock_resolver = MockResolver.new
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_unwrapping_int
|
19
|
-
config_value = PrefabProto::ConfigValue.new(int: 123)
|
20
|
-
assert_equal 123, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
21
|
-
end
|
22
|
-
|
23
|
-
def test_unwrapping_string
|
24
|
-
config_value = PrefabProto::ConfigValue.new(string: 'abc')
|
25
|
-
assert_equal 'abc', unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
26
|
-
assert_equal 'abc', reportable_value(config_value, CONFIG, EMPTY_CONTEXT)
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_unwrapping_double
|
30
|
-
config_value = PrefabProto::ConfigValue.new(double: 1.23)
|
31
|
-
assert_equal 1.23, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_unwrapping_bool
|
35
|
-
config_value = PrefabProto::ConfigValue.new(bool: true)
|
36
|
-
assert_equal true, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
37
|
-
|
38
|
-
config_value = PrefabProto::ConfigValue.new(bool: false)
|
39
|
-
assert_equal false, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_unwrapping_log_level
|
43
|
-
config_value = PrefabProto::ConfigValue.new(log_level: :INFO)
|
44
|
-
assert_equal :INFO, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_unwrapping_string_list
|
48
|
-
config_value = PrefabProto::ConfigValue.new(string_list: PrefabProto::StringList.new(values: %w[a b c]))
|
49
|
-
assert_equal %w[a b c], unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_unwrapping_weighted_values
|
53
|
-
# single value
|
54
|
-
config_value = PrefabProto::ConfigValue.new(weighted_values: weighted_values([['abc', 1]]))
|
55
|
-
|
56
|
-
assert_equal 'abc', unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
57
|
-
|
58
|
-
# multiple values, evenly distributed
|
59
|
-
config_value = PrefabProto::ConfigValue.new(weighted_values: weighted_values([['abc', 1], ['def', 1], ['ghi', 1]]))
|
60
|
-
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:000'))
|
61
|
-
assert_equal 'ghi', unwrap(config_value, CONFIG, context_with_key('user:456'))
|
62
|
-
assert_equal 'abc', unwrap(config_value, CONFIG, context_with_key('user:789'))
|
63
|
-
assert_equal 'ghi', unwrap(config_value, CONFIG, context_with_key('user:888'))
|
64
|
-
|
65
|
-
# multiple values, unevenly distributed
|
66
|
-
config_value = PrefabProto::ConfigValue.new(weighted_values: weighted_values([['abc', 1], ['def', 99], ['ghi', 1]]))
|
67
|
-
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:123'))
|
68
|
-
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:456'))
|
69
|
-
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:789'))
|
70
|
-
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:012'))
|
71
|
-
assert_equal 'ghi', unwrap(config_value, CONFIG, context_with_key('user:428'))
|
72
|
-
assert_equal 'abc', unwrap(config_value, CONFIG, context_with_key('user:548'))
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_unwrapping_provided_values
|
76
|
-
with_env('ENV_VAR_NAME', 'unit test value')do
|
77
|
-
value = PrefabProto::Provided.new(
|
78
|
-
source: :ENV_VAR,
|
79
|
-
lookup: "ENV_VAR_NAME"
|
80
|
-
)
|
81
|
-
config_value = PrefabProto::ConfigValue.new(provided: value)
|
82
|
-
assert_equal 'unit test value', unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def test_unwrapping_provided_values_of_type_string_list
|
87
|
-
with_env('ENV_VAR_NAME', '["bob","cary"]')do
|
88
|
-
value = PrefabProto::Provided.new(
|
89
|
-
source: :ENV_VAR,
|
90
|
-
lookup: "ENV_VAR_NAME"
|
91
|
-
)
|
92
|
-
config_value = PrefabProto::ConfigValue.new(provided: value)
|
93
|
-
assert_equal ["bob", "cary"], unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def test_unwrapping_provided_values_coerces_to_int
|
98
|
-
with_env('ENV_VAR_NAME', '42')do
|
99
|
-
value = PrefabProto::Provided.new(
|
100
|
-
source: :ENV_VAR,
|
101
|
-
lookup: "ENV_VAR_NAME"
|
102
|
-
)
|
103
|
-
config_value = PrefabProto::ConfigValue.new(provided: value)
|
104
|
-
assert_equal 42, unwrap(config_value, config_of(PrefabProto::Config::ValueType::INT), EMPTY_CONTEXT)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def test_unwrapping_provided_values_when_value_type_mismatch
|
109
|
-
with_env('ENV_VAR_NAME', 'not an int')do
|
110
|
-
value = PrefabProto::Provided.new(
|
111
|
-
source: :ENV_VAR,
|
112
|
-
lookup: "ENV_VAR_NAME"
|
113
|
-
)
|
114
|
-
config_value = PrefabProto::ConfigValue.new(provided: value)
|
115
|
-
|
116
|
-
assert_raises Prefab::Errors::EnvVarParseError do
|
117
|
-
unwrap(config_value, config_of(PrefabProto::Config::ValueType::INT), EMPTY_CONTEXT)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def test_coerce
|
123
|
-
assert_equal "string", Prefab::ConfigValueUnwrapper.coerce_into_type("string", CONFIG, "ENV")
|
124
|
-
assert_equal 42, Prefab::ConfigValueUnwrapper.coerce_into_type("42", CONFIG, "ENV")
|
125
|
-
assert_equal false, Prefab::ConfigValueUnwrapper.coerce_into_type("false", CONFIG, "ENV")
|
126
|
-
assert_equal 42.42, Prefab::ConfigValueUnwrapper.coerce_into_type("42.42", CONFIG, "ENV")
|
127
|
-
assert_equal ["a","b"], Prefab::ConfigValueUnwrapper.coerce_into_type("['a','b']", CONFIG, "ENV")
|
128
|
-
|
129
|
-
assert_equal "string", Prefab::ConfigValueUnwrapper.coerce_into_type("string", config_of(PrefabProto::Config::ValueType::STRING),"ENV")
|
130
|
-
assert_equal "42", Prefab::ConfigValueUnwrapper.coerce_into_type("42", config_of(PrefabProto::Config::ValueType::STRING),"ENV")
|
131
|
-
assert_equal "42.42", Prefab::ConfigValueUnwrapper.coerce_into_type("42.42", config_of(PrefabProto::Config::ValueType::STRING),"ENV")
|
132
|
-
assert_equal 42, Prefab::ConfigValueUnwrapper.coerce_into_type("42", config_of(PrefabProto::Config::ValueType::INT),"ENV")
|
133
|
-
assert_equal false, Prefab::ConfigValueUnwrapper.coerce_into_type("false", config_of(PrefabProto::Config::ValueType::BOOL),"ENV")
|
134
|
-
assert_equal 42.42, Prefab::ConfigValueUnwrapper.coerce_into_type("42.42", config_of(PrefabProto::Config::ValueType::DOUBLE),"ENV")
|
135
|
-
assert_equal ["a","b"], Prefab::ConfigValueUnwrapper.coerce_into_type("['a','b']", config_of(PrefabProto::Config::ValueType::STRING_LIST),"ENV")
|
136
|
-
|
137
|
-
assert_raises Prefab::Errors::EnvVarParseError do
|
138
|
-
Prefab::ConfigValueUnwrapper.coerce_into_type("not an int", config_of(PrefabProto::Config::ValueType::INT), "ENV")
|
139
|
-
end
|
140
|
-
assert_raises Prefab::Errors::EnvVarParseError do
|
141
|
-
Prefab::ConfigValueUnwrapper.coerce_into_type("not bool", config_of(PrefabProto::Config::ValueType::BOOL), "ENV")
|
142
|
-
end
|
143
|
-
assert_raises Prefab::Errors::EnvVarParseError do
|
144
|
-
Prefab::ConfigValueUnwrapper.coerce_into_type("not a double", config_of(PrefabProto::Config::ValueType::DOUBLE), "ENV")
|
145
|
-
end
|
146
|
-
assert_raises Prefab::Errors::EnvVarParseError do
|
147
|
-
Prefab::ConfigValueUnwrapper.coerce_into_type("not a list", config_of(PrefabProto::Config::ValueType::STRING_LIST), "ENV")
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def test_unwrapping_provided_values_with_missing_env_var
|
152
|
-
value = PrefabProto::Provided.new(
|
153
|
-
source: :ENV_VAR,
|
154
|
-
lookup: "NON_EXISTENT_ENV_VAR_NAME"
|
155
|
-
)
|
156
|
-
config_value = PrefabProto::ConfigValue.new(provided: value)
|
157
|
-
assert_raises(Prefab::Errors::MissingEnvVarError) do
|
158
|
-
unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
def test_unwrapping_encrypted_values_decrypts
|
163
|
-
clear_text = "very secret stuff"
|
164
|
-
encrypted = Prefab::Encryption.new(DECRYPTION_KEY_VALUE).encrypt(clear_text)
|
165
|
-
config_value = PrefabProto::ConfigValue.new(string: encrypted, decrypt_with: "decryption.key")
|
166
|
-
assert_equal clear_text, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
167
|
-
assert reportable_value(config_value, CONFIG, EMPTY_CONTEXT).start_with? Prefab::ConfigValueUnwrapper::CONFIDENTIAL_PREFIX
|
168
|
-
end
|
169
|
-
|
170
|
-
def test_confidential
|
171
|
-
config_value = PrefabProto::ConfigValue.new(confidential: true, string: "something confidential")
|
172
|
-
assert reportable_value(config_value, CONFIG, EMPTY_CONTEXT).start_with? Prefab::ConfigValueUnwrapper::CONFIDENTIAL_PREFIX
|
173
|
-
end
|
174
|
-
|
175
|
-
def test_unwrap_confiential_provided
|
176
|
-
with_env('PAAS_PASSWORD', "the password")do
|
177
|
-
value = PrefabProto::Provided.new(
|
178
|
-
source: :ENV_VAR,
|
179
|
-
lookup: "PAAS_PASSWORD"
|
180
|
-
)
|
181
|
-
config_value = PrefabProto::ConfigValue.new(provided: value, confidential: true)
|
182
|
-
assert_equal "the password", unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
183
|
-
assert reportable_value(config_value, CONFIG, EMPTY_CONTEXT).start_with? Prefab::ConfigValueUnwrapper::CONFIDENTIAL_PREFIX
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
private
|
188
|
-
|
189
|
-
def config_of(value_type)
|
190
|
-
PrefabProto::Config.new(
|
191
|
-
key: 'config-key',
|
192
|
-
value_type: value_type
|
193
|
-
)
|
194
|
-
end
|
195
|
-
|
196
|
-
def context_with_key(key)
|
197
|
-
Prefab::Context.new(user: { key: key })
|
198
|
-
end
|
199
|
-
|
200
|
-
def unwrap(config_value, config_key, context)
|
201
|
-
Prefab::ConfigValueUnwrapper.deepest_value(config_value, config_key, context, @mock_resolver).unwrap
|
202
|
-
end
|
203
|
-
|
204
|
-
def reportable_value(config_value, config_key, context)
|
205
|
-
Prefab::ConfigValueUnwrapper.deepest_value(config_value, config_key, context, @mock_resolver).reportable_value
|
206
|
-
end
|
207
|
-
|
208
|
-
class MockResolver
|
209
|
-
def get(key)
|
210
|
-
if DECRYPTION_KEY_NAME == key
|
211
|
-
Prefab::Evaluation.new(config: PrefabProto::Config.new(key: key),
|
212
|
-
value: PrefabProto::ConfigValue.new(string: DECRYPTION_KEY_VALUE),
|
213
|
-
value_index: 0,
|
214
|
-
config_row_index: 0,
|
215
|
-
context: Prefab::Context.new,
|
216
|
-
resolver: self
|
217
|
-
)
|
218
|
-
|
219
|
-
else
|
220
|
-
raise "unexpected key"
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
class TestConfigValueWrapper < Minitest::Test
|
6
|
-
def test_wrap_integer
|
7
|
-
result = Prefab::ConfigValueWrapper.wrap(42)
|
8
|
-
assert_instance_of PrefabProto::ConfigValue, result
|
9
|
-
assert_equal 42, result.int
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_wrap_float
|
13
|
-
result = Prefab::ConfigValueWrapper.wrap(3.14)
|
14
|
-
assert_instance_of PrefabProto::ConfigValue, result
|
15
|
-
assert_equal 3.14, result.double
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_wrap_boolean_true
|
19
|
-
result = Prefab::ConfigValueWrapper.wrap(true)
|
20
|
-
assert_instance_of PrefabProto::ConfigValue, result
|
21
|
-
assert_equal true, result.bool
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_wrap_boolean_false
|
25
|
-
result = Prefab::ConfigValueWrapper.wrap(false)
|
26
|
-
assert_instance_of PrefabProto::ConfigValue, result
|
27
|
-
assert_equal false, result.bool
|
28
|
-
end
|
29
|
-
|
30
|
-
def test_wrap_array
|
31
|
-
result = Prefab::ConfigValueWrapper.wrap(['one', 'two', 'three'])
|
32
|
-
assert_instance_of PrefabProto::ConfigValue, result
|
33
|
-
assert_instance_of PrefabProto::StringList, result.string_list
|
34
|
-
assert_equal ['one', 'two', 'three'], result.string_list.values
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_wrap_string
|
38
|
-
result = Prefab::ConfigValueWrapper.wrap('hello')
|
39
|
-
assert_instance_of PrefabProto::ConfigValue, result
|
40
|
-
assert_equal 'hello', result.string
|
41
|
-
end
|
42
|
-
end
|
data/test/test_context.rb
DELETED
@@ -1,203 +0,0 @@
|
|
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
|
-
super
|
10
|
-
Prefab::Context.current = nil
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_initialize_with_empty_context
|
14
|
-
context = Prefab::Context.new({})
|
15
|
-
assert_empty context.contexts
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_initialize_with_named_context
|
19
|
-
named_context = Prefab::Context::NamedContext.new('test', foo: 'bar')
|
20
|
-
context = Prefab::Context.new(named_context)
|
21
|
-
assert_equal 1, context.contexts.size
|
22
|
-
assert_equal named_context, context.contexts['test']
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_initialize_with_hash
|
26
|
-
context = Prefab::Context.new(test: { foo: 'bar' })
|
27
|
-
assert_equal 1, context.contexts.size
|
28
|
-
assert_equal 'bar', context.contexts['test'].get('foo')
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_initialize_with_multiple_hashes
|
32
|
-
context = Prefab::Context.new(test: { foo: 'bar' }, other: { foo: 'baz' })
|
33
|
-
assert_equal 2, context.contexts.size
|
34
|
-
assert_equal 'bar', context.contexts['test'].get('foo')
|
35
|
-
assert_equal 'baz', context.contexts['other'].get('foo')
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_initialize_with_invalid_hash
|
39
|
-
_, err = capture_io do
|
40
|
-
Prefab::Context.new({ foo: 'bar', baz: 'qux' })
|
41
|
-
end
|
42
|
-
|
43
|
-
assert_match '[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash',
|
44
|
-
err
|
45
|
-
end
|
46
|
-
|
47
|
-
def test_initialize_with_invalid_argument
|
48
|
-
assert_raises(ArgumentError) { Prefab::Context.new([]) }
|
49
|
-
end
|
50
|
-
|
51
|
-
def test_current
|
52
|
-
context = Prefab::Context.current
|
53
|
-
assert_instance_of Prefab::Context, context
|
54
|
-
assert_empty context.to_h
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_current_set
|
58
|
-
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
59
|
-
Prefab::Context.current = context
|
60
|
-
assert_instance_of Prefab::Context, context
|
61
|
-
assert_equal stringify(EXAMPLE_PROPERTIES), context.to_h
|
62
|
-
end
|
63
|
-
|
64
|
-
def test_merge_with_current
|
65
|
-
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
66
|
-
Prefab::Context.current = context
|
67
|
-
assert_equal stringify(EXAMPLE_PROPERTIES), context.to_h
|
68
|
-
|
69
|
-
new_context = Prefab::Context.merge_with_current({ user: { key: 'brand-new', other: 'different' },
|
70
|
-
address: { city: 'New York' } })
|
71
|
-
assert_equal stringify({
|
72
|
-
# Note that the user's `name` from the original
|
73
|
-
# context is not included. This is because we don't _merge_ the new
|
74
|
-
# properties if they collide with an existing context name. We _replace_
|
75
|
-
# them.
|
76
|
-
user: { key: 'brand-new', other: 'different' },
|
77
|
-
team: EXAMPLE_PROPERTIES[:team],
|
78
|
-
address: { city: 'New York' }
|
79
|
-
}),
|
80
|
-
new_context.to_h
|
81
|
-
|
82
|
-
# the original/current context is unchanged
|
83
|
-
assert_equal stringify(EXAMPLE_PROPERTIES), Prefab::Context.current.to_h
|
84
|
-
end
|
85
|
-
|
86
|
-
def test_with_context
|
87
|
-
Prefab::Context.with_context(EXAMPLE_PROPERTIES) do
|
88
|
-
context = Prefab::Context.current
|
89
|
-
assert_equal(stringify(EXAMPLE_PROPERTIES), context.to_h)
|
90
|
-
assert_equal('some-user-key', context.get('user.key'))
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_with_context_nesting
|
95
|
-
Prefab::Context.with_context(EXAMPLE_PROPERTIES) do
|
96
|
-
Prefab::Context.with_context({ user: { key: 'abc', other: 'different' } }) do
|
97
|
-
context = Prefab::Context.current
|
98
|
-
assert_equal({ 'user' => { 'key' => 'abc', 'other' => 'different' } }, context.to_h)
|
99
|
-
end
|
100
|
-
|
101
|
-
context = Prefab::Context.current
|
102
|
-
assert_equal(stringify(EXAMPLE_PROPERTIES), context.to_h)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def test_with_context_merge_nesting
|
107
|
-
Prefab::Context.with_context(EXAMPLE_PROPERTIES) do
|
108
|
-
Prefab::Context.with_merged_context({ user: { key: 'abc', other: 'different' } }) do
|
109
|
-
context = Prefab::Context.current
|
110
|
-
assert_equal({ 'user' => { 'key' => 'abc', 'other' => 'different' }, "team"=>{"key"=>"abc", "plan"=>"pro"} }, context.to_h)
|
111
|
-
end
|
112
|
-
|
113
|
-
context = Prefab::Context.current
|
114
|
-
assert_equal(stringify(EXAMPLE_PROPERTIES), context.to_h)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def test_setting
|
119
|
-
context = Prefab::Context.new({})
|
120
|
-
context.set('user', { key: 'value' })
|
121
|
-
context.set(:other, { key: 'different', something: 'other' })
|
122
|
-
assert_equal(stringify({ user: { key: 'value' }, other: { key: 'different', something: 'other' } }), context.to_h)
|
123
|
-
end
|
124
|
-
|
125
|
-
def test_getting
|
126
|
-
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
127
|
-
assert_equal('some-user-key', context.get('user.key'))
|
128
|
-
assert_equal('pro', context.get('team.plan'))
|
129
|
-
end
|
130
|
-
|
131
|
-
def test_dot_notation_getting
|
132
|
-
context = Prefab::Context.new({ 'user' => { 'key' => 'value' } })
|
133
|
-
assert_equal('value', context.get('user.key'))
|
134
|
-
end
|
135
|
-
|
136
|
-
def test_dot_notation_getting_with_symbols
|
137
|
-
context = Prefab::Context.new({ user: { key: 'value' } })
|
138
|
-
assert_equal('value', context.get('user.key'))
|
139
|
-
end
|
140
|
-
|
141
|
-
def test_clear
|
142
|
-
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
143
|
-
context.clear
|
144
|
-
|
145
|
-
assert_empty context.to_h
|
146
|
-
end
|
147
|
-
|
148
|
-
def test_to_proto
|
149
|
-
namespace = "my.namespace"
|
150
|
-
|
151
|
-
contexts = Prefab::Context.new({
|
152
|
-
user: {
|
153
|
-
id: 1,
|
154
|
-
email: 'user-email'
|
155
|
-
},
|
156
|
-
team: {
|
157
|
-
id: 2,
|
158
|
-
name: 'team-name'
|
159
|
-
}
|
160
|
-
})
|
161
|
-
|
162
|
-
assert_equal PrefabProto::ContextSet.new(
|
163
|
-
contexts: [
|
164
|
-
PrefabProto::Context.new(
|
165
|
-
type: "user",
|
166
|
-
values: {
|
167
|
-
"id" => PrefabProto::ConfigValue.new(int: 1),
|
168
|
-
"email" => PrefabProto::ConfigValue.new(string: "user-email")
|
169
|
-
}
|
170
|
-
),
|
171
|
-
PrefabProto::Context.new(
|
172
|
-
type: "team",
|
173
|
-
values: {
|
174
|
-
"id" => PrefabProto::ConfigValue.new(int: 2),
|
175
|
-
"name" => PrefabProto::ConfigValue.new(string: "team-name")
|
176
|
-
}
|
177
|
-
),
|
178
|
-
|
179
|
-
PrefabProto::Context.new(
|
180
|
-
type: "prefab",
|
181
|
-
values: {
|
182
|
-
'current-time' => PrefabProto::ConfigValue.new(int: Prefab::TimeHelpers.now_in_ms),
|
183
|
-
'namespace' => PrefabProto::ConfigValue.new(string: namespace)
|
184
|
-
}
|
185
|
-
)
|
186
|
-
]
|
187
|
-
), contexts.to_proto(namespace)
|
188
|
-
end
|
189
|
-
|
190
|
-
private
|
191
|
-
|
192
|
-
def stringify(hash)
|
193
|
-
hash.map { |k, v| [k.to_s, stringify_keys(v)] }.to_h
|
194
|
-
end
|
195
|
-
|
196
|
-
def stringify_keys(value)
|
197
|
-
if value.is_a?(Hash)
|
198
|
-
value.transform_keys(&:to_s)
|
199
|
-
else
|
200
|
-
value
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
data/test/test_context_shape.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
|
5
|
-
class TestContextShape < Minitest::Test
|
6
|
-
class Email; end
|
7
|
-
|
8
|
-
def test_field_type_number
|
9
|
-
[
|
10
|
-
[1, 1],
|
11
|
-
[99999999999999999999999999999999999999999999, 1],
|
12
|
-
[-99999999999999999999999999999999999999999999, 1],
|
13
|
-
|
14
|
-
['a', 2],
|
15
|
-
['99999999999999999999999999999999999999999999', 2],
|
16
|
-
|
17
|
-
[1.0, 4],
|
18
|
-
[99999999999999999999999999999999999999999999.0, 4],
|
19
|
-
[-99999999999999999999999999999999999999999999.0, 4],
|
20
|
-
|
21
|
-
[true, 5],
|
22
|
-
[false, 5],
|
23
|
-
|
24
|
-
[[], 10],
|
25
|
-
[[1, 2, 3], 10],
|
26
|
-
[['a', 'b', 'c'], 10],
|
27
|
-
|
28
|
-
[Email.new, 2],
|
29
|
-
].each do |value, expected|
|
30
|
-
actual = Prefab::ContextShape.field_type_number(value)
|
31
|
-
|
32
|
-
refute_nil actual, "Expected a value for input: #{value}"
|
33
|
-
assert_equal expected, actual, "Expected #{expected} for #{value}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# If this test fails, it means that we've added a new type to the ConfigValue
|
38
|
-
def test_mapping_is_exhaustive
|
39
|
-
unsupported = [:bytes, :limit_definition, :log_level, :weighted_values, :int_range, :provided]
|
40
|
-
type_fields = PrefabProto::ConfigValue.descriptor.lookup_oneof("type").entries
|
41
|
-
supported = type_fields.entries.reject do |entry|
|
42
|
-
unsupported.include?(entry.name.to_sym)
|
43
|
-
end.map(&:number)
|
44
|
-
mapped = Prefab::ContextShape::MAPPING.values.uniq
|
45
|
-
|
46
|
-
unless mapped == supported
|
47
|
-
raise "ContextShape MAPPING needs update: #{mapped} != #{supported}"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,147 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'test_helper'
|
4
|
-
require 'timecop'
|
5
|
-
|
6
|
-
class TestContextShapeAggregator < Minitest::Test
|
7
|
-
DOB = Date.new
|
8
|
-
|
9
|
-
CONTEXT_1 = Prefab::Context.new({
|
10
|
-
'user' => {
|
11
|
-
'name' => 'user-name',
|
12
|
-
'email' => 'user.email',
|
13
|
-
'age' => 42.5
|
14
|
-
},
|
15
|
-
'subscription' => {
|
16
|
-
'plan' => 'advanced',
|
17
|
-
'free' => false
|
18
|
-
}
|
19
|
-
}).freeze
|
20
|
-
|
21
|
-
CONTEXT_2 = Prefab::Context.new({
|
22
|
-
'user' => {
|
23
|
-
'name' => 'other-user-name',
|
24
|
-
'dob' => DOB
|
25
|
-
},
|
26
|
-
'device' => {
|
27
|
-
'name' => 'device-name',
|
28
|
-
'os' => 'os-name',
|
29
|
-
'version' => 3
|
30
|
-
}
|
31
|
-
}).freeze
|
32
|
-
|
33
|
-
CONTEXT_3 = Prefab::Context.new({
|
34
|
-
'subscription' => {
|
35
|
-
'plan' => 'pro',
|
36
|
-
'trial' => true
|
37
|
-
}
|
38
|
-
}).freeze
|
39
|
-
|
40
|
-
def test_push
|
41
|
-
aggregator = new_aggregator(max_shapes: 9)
|
42
|
-
|
43
|
-
aggregator.push(CONTEXT_1)
|
44
|
-
aggregator.push(CONTEXT_2)
|
45
|
-
assert_equal 9, aggregator.data.size
|
46
|
-
|
47
|
-
# we've reached the limit so no more
|
48
|
-
aggregator.push(CONTEXT_3)
|
49
|
-
assert_equal 9, aggregator.data.size
|
50
|
-
|
51
|
-
assert_equal [['user', 'name', 2], ['user', 'email', 2], ['user', 'age', 4], ['subscription', 'plan', 2], ['subscription', 'free', 5], ['user', 'dob', 2], ['device', 'name', 2], ['device', 'os', 2], ['device', 'version', 1]],
|
52
|
-
aggregator.data.to_a
|
53
|
-
|
54
|
-
assert_only_expected_logs
|
55
|
-
end
|
56
|
-
|
57
|
-
def test_prepare_data
|
58
|
-
aggregator = new_aggregator
|
59
|
-
|
60
|
-
aggregator.push(CONTEXT_1)
|
61
|
-
aggregator.push(CONTEXT_2)
|
62
|
-
aggregator.push(CONTEXT_3)
|
63
|
-
|
64
|
-
data = aggregator.prepare_data
|
65
|
-
|
66
|
-
assert_equal %w[user subscription device], data.keys
|
67
|
-
|
68
|
-
assert_equal data['user'], {
|
69
|
-
'name' => 2,
|
70
|
-
'email' => 2,
|
71
|
-
'dob' => 2,
|
72
|
-
'age' => 4
|
73
|
-
}
|
74
|
-
|
75
|
-
assert_equal data['subscription'], {
|
76
|
-
'plan' => 2,
|
77
|
-
'trial' => 5,
|
78
|
-
'free' => 5
|
79
|
-
}
|
80
|
-
|
81
|
-
assert_equal data['device'], {
|
82
|
-
'name' => 2,
|
83
|
-
'os' => 2,
|
84
|
-
'version' => 1
|
85
|
-
}
|
86
|
-
|
87
|
-
assert_equal [], aggregator.data.to_a
|
88
|
-
assert_only_expected_logs
|
89
|
-
end
|
90
|
-
|
91
|
-
def test_sync
|
92
|
-
client = new_client
|
93
|
-
|
94
|
-
client.get 'some.key', 'default', CONTEXT_1
|
95
|
-
client.get 'some.key', 'default', CONTEXT_2
|
96
|
-
client.get 'some.key', 'default', CONTEXT_3
|
97
|
-
|
98
|
-
requests = wait_for_post_requests(client) do
|
99
|
-
client.context_shape_aggregator.send(:sync)
|
100
|
-
end
|
101
|
-
|
102
|
-
assert_equal [
|
103
|
-
[
|
104
|
-
'/api/v1/context-shapes',
|
105
|
-
PrefabProto::ContextShapes.new(shapes: [
|
106
|
-
PrefabProto::ContextShape.new(
|
107
|
-
name: 'user', field_types: {
|
108
|
-
'age' => 4, 'dob' => 2, 'email' => 2, 'name' => 2
|
109
|
-
}
|
110
|
-
),
|
111
|
-
PrefabProto::ContextShape.new(
|
112
|
-
name: 'subscription', field_types: {
|
113
|
-
'plan' => 2, 'free' => 5, 'trial' => 5
|
114
|
-
}
|
115
|
-
),
|
116
|
-
PrefabProto::ContextShape.new(
|
117
|
-
name: 'device', field_types: {
|
118
|
-
'version' => 1, 'os' => 2, 'name' => 2
|
119
|
-
}
|
120
|
-
)
|
121
|
-
])
|
122
|
-
]
|
123
|
-
], requests
|
124
|
-
|
125
|
-
|
126
|
-
assert_logged [
|
127
|
-
"WARN 2023-08-09 15:18:12 -0400: cloud.prefab.client.configclient No success loading checkpoints",
|
128
|
-
"WARN 2023-08-09 15:18:12 -0400: cloud.prefab.client.configclient Couldn't Initialize In 0. Key some.key. Returning what we have"
|
129
|
-
]
|
130
|
-
end
|
131
|
-
|
132
|
-
private
|
133
|
-
|
134
|
-
def new_client(overrides = {})
|
135
|
-
super(**{
|
136
|
-
prefab_datasources: Prefab::Options::DATASOURCES::ALL,
|
137
|
-
initialization_timeout_sec: 0,
|
138
|
-
on_init_failure: Prefab::Options::ON_INITIALIZATION_FAILURE::RETURN,
|
139
|
-
api_key: '123-development-yourapikey-SDK',
|
140
|
-
context_upload_mode: :shape_only
|
141
|
-
}.merge(overrides))
|
142
|
-
end
|
143
|
-
|
144
|
-
def new_aggregator(max_shapes: 1000)
|
145
|
-
Prefab::ContextShapeAggregator.new(client: new_client, sync_interval: 1000, max_shapes: max_shapes)
|
146
|
-
end
|
147
|
-
end
|