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.
Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/.ruby-version +1 -0
  3. data/Gemfile +9 -22
  4. data/Gemfile.lock +88 -160
  5. data/LICENSE.txt +1 -1
  6. data/Rakefile +14 -14
  7. data/VERSION +1 -1
  8. data/lib/prefab/auth_interceptor.rb +25 -0
  9. data/lib/prefab/client.rb +34 -139
  10. data/lib/prefab/config_client.rb +23 -275
  11. data/lib/prefab/config_loader.rb +27 -60
  12. data/lib/prefab/config_resolver.rb +40 -53
  13. data/lib/prefab/noop_cache.rb +13 -0
  14. data/lib/prefab/noop_stats.rb +8 -0
  15. data/lib/prefab/prefab_pb.rb +39 -0
  16. data/lib/prefab/prefab_services_pb.rb +37 -0
  17. data/lib/prefab/ratelimit_client.rb +58 -0
  18. data/lib/prefab/ratelimit_pb.rb +125 -0
  19. data/lib/prefab/store.rb +29 -0
  20. data/lib/prefab_client.rb +35 -0
  21. metadata +36 -198
  22. data/.envrc.sample +0 -3
  23. data/.github/workflows/ruby.yml +0 -46
  24. data/.gitmodules +0 -3
  25. data/.rubocop.yml +0 -13
  26. data/.tool-versions +0 -1
  27. data/CHANGELOG.md +0 -169
  28. data/CODEOWNERS +0 -1
  29. data/README.md +0 -94
  30. data/bin/console +0 -21
  31. data/compile_protos.sh +0 -18
  32. data/lib/prefab/config_client_presenter.rb +0 -18
  33. data/lib/prefab/config_value_unwrapper.rb +0 -115
  34. data/lib/prefab/config_value_wrapper.rb +0 -18
  35. data/lib/prefab/context.rb +0 -179
  36. data/lib/prefab/context_shape.rb +0 -20
  37. data/lib/prefab/context_shape_aggregator.rb +0 -65
  38. data/lib/prefab/criteria_evaluator.rb +0 -136
  39. data/lib/prefab/encryption.rb +0 -65
  40. data/lib/prefab/error.rb +0 -6
  41. data/lib/prefab/errors/env_var_parse_error.rb +0 -11
  42. data/lib/prefab/errors/initialization_timeout_error.rb +0 -13
  43. data/lib/prefab/errors/invalid_api_key_error.rb +0 -19
  44. data/lib/prefab/errors/missing_default_error.rb +0 -13
  45. data/lib/prefab/errors/missing_env_var_error.rb +0 -11
  46. data/lib/prefab/errors/uninitialized_error.rb +0 -13
  47. data/lib/prefab/evaluation.rb +0 -52
  48. data/lib/prefab/evaluation_summary_aggregator.rb +0 -87
  49. data/lib/prefab/example_contexts_aggregator.rb +0 -78
  50. data/lib/prefab/exponential_backoff.rb +0 -21
  51. data/lib/prefab/feature_flag_client.rb +0 -42
  52. data/lib/prefab/http_connection.rb +0 -41
  53. data/lib/prefab/internal_logger.rb +0 -16
  54. data/lib/prefab/local_config_parser.rb +0 -151
  55. data/lib/prefab/log_path_aggregator.rb +0 -69
  56. data/lib/prefab/logger_client.rb +0 -264
  57. data/lib/prefab/murmer3.rb +0 -50
  58. data/lib/prefab/options.rb +0 -208
  59. data/lib/prefab/periodic_sync.rb +0 -69
  60. data/lib/prefab/prefab.rb +0 -56
  61. data/lib/prefab/rate_limit_cache.rb +0 -41
  62. data/lib/prefab/resolved_config_presenter.rb +0 -86
  63. data/lib/prefab/time_helpers.rb +0 -7
  64. data/lib/prefab/weighted_value_resolver.rb +0 -42
  65. data/lib/prefab/yaml_config_parser.rb +0 -34
  66. data/lib/prefab-cloud-ruby.rb +0 -57
  67. data/lib/prefab_pb.rb +0 -93
  68. data/prefab-cloud-ruby.gemspec +0 -155
  69. data/test/.prefab.default.config.yaml +0 -2
  70. data/test/.prefab.unit_tests.config.yaml +0 -28
  71. data/test/integration_test.rb +0 -150
  72. data/test/integration_test_helpers.rb +0 -151
  73. data/test/support/common_helpers.rb +0 -180
  74. data/test/support/mock_base_client.rb +0 -42
  75. data/test/support/mock_config_client.rb +0 -19
  76. data/test/support/mock_config_loader.rb +0 -1
  77. data/test/test_client.rb +0 -444
  78. data/test/test_config_client.rb +0 -109
  79. data/test/test_config_loader.rb +0 -117
  80. data/test/test_config_resolver.rb +0 -430
  81. data/test/test_config_value_unwrapper.rb +0 -224
  82. data/test/test_config_value_wrapper.rb +0 -42
  83. data/test/test_context.rb +0 -203
  84. data/test/test_context_shape.rb +0 -50
  85. data/test/test_context_shape_aggregator.rb +0 -147
  86. data/test/test_criteria_evaluator.rb +0 -726
  87. data/test/test_encryption.rb +0 -16
  88. data/test/test_evaluation_summary_aggregator.rb +0 -162
  89. data/test/test_example_contexts_aggregator.rb +0 -238
  90. data/test/test_exponential_backoff.rb +0 -18
  91. data/test/test_feature_flag_client.rb +0 -48
  92. data/test/test_helper.rb +0 -17
  93. data/test/test_integration.rb +0 -58
  94. data/test/test_local_config_parser.rb +0 -147
  95. data/test/test_log_path_aggregator.rb +0 -62
  96. data/test/test_logger.rb +0 -621
  97. data/test/test_logger_initialization.rb +0 -12
  98. data/test/test_options.rb +0 -75
  99. data/test/test_prefab.rb +0 -12
  100. data/test/test_rate_limit_cache.rb +0 -44
  101. 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
@@ -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