prefab-cloud-ruby 0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,109 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class TestConfigClient < Minitest::Test
6
- def setup
7
- super
8
- options = Prefab::Options.new(
9
- prefab_config_override_dir: 'none',
10
- prefab_config_classpath_dir: 'test',
11
- prefab_envs: 'unit_tests',
12
- prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY,
13
- x_use_local_cache: true,
14
- )
15
-
16
- @config_client = Prefab::ConfigClient.new(MockBaseClient.new(options), 10)
17
- end
18
-
19
- def test_load
20
- assert_equal 'test sample value', @config_client.get('sample')
21
- assert_equal 123, @config_client.get('sample_int')
22
- assert_equal 12.12, @config_client.get('sample_double')
23
- assert_equal true, @config_client.get('sample_bool')
24
- assert_equal :ERROR, @config_client.get('log-level.app')
25
- end
26
-
27
- def test_initialization_timeout_error
28
- options = Prefab::Options.new(
29
- api_key: '123-ENV-KEY-SDK',
30
- initialization_timeout_sec: 0.01,
31
- logdev: StringIO.new
32
- )
33
-
34
- err = assert_raises(Prefab::Errors::InitializationTimeoutError) do
35
- Prefab::Client.new(options).config_client.get('anything')
36
- end
37
-
38
- assert_match(/couldn't initialize in 0.01 second timeout/, err.message)
39
- end
40
-
41
- def test_prefab_envs_is_forgiving
42
- assert_equal ['my_env'], Prefab::Options.new(
43
- prefab_envs: 'my_env'
44
- ).prefab_envs
45
-
46
- assert_equal %w[my_env a_second_env], Prefab::Options.new(
47
- prefab_envs: %w[my_env a_second_env]
48
- ).prefab_envs
49
- end
50
-
51
- def test_prefab_envs_env_var
52
- ENV['PREFAB_ENVS'] = 'one,two'
53
- assert_equal %w[one two], Prefab::Options.new.prefab_envs
54
- end
55
-
56
- def test_invalid_api_key_error
57
- options = Prefab::Options.new(
58
- api_key: ''
59
- )
60
-
61
- err = assert_raises(Prefab::Errors::InvalidApiKeyError) do
62
- Prefab::Client.new(options).config_client.get('anything')
63
- end
64
-
65
- assert_match(/No API key/, err.message)
66
-
67
- options = Prefab::Options.new(
68
- api_key: 'invalid'
69
- )
70
-
71
- err = assert_raises(Prefab::Errors::InvalidApiKeyError) do
72
- Prefab::Client.new(options).config_client.get('anything')
73
- end
74
-
75
- assert_match(/format is invalid/, err.message)
76
- end
77
-
78
- def test_caching
79
- @config_client.send(:cache_configs,
80
- PrefabProto::Configs.new(configs:
81
- [PrefabProto::Config.new(key: 'test', id: 1,
82
- rows: [PrefabProto::ConfigRow.new(
83
- values: [
84
- PrefabProto::ConditionalValue.new(
85
- value: PrefabProto::ConfigValue.new(string: "test value")
86
- )
87
- ]
88
- )])],
89
- config_service_pointer: PrefabProto::ConfigServicePointer.new(project_id: 3, project_env_id: 5)))
90
- @config_client.send(:load_cache)
91
- assert_equal "test value", @config_client.get("test")
92
- end
93
-
94
- def test_cache_path_respects_xdg
95
- options = Prefab::Options.new(
96
- prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY,
97
- x_use_local_cache: true,
98
- api_key: "123-ENV-KEY-SDK",)
99
-
100
- config_client = Prefab::ConfigClient.new(MockBaseClient.new(options), 10)
101
- assert_equal "#{Dir.home}/.cache/prefab.cache.123.json", config_client.send(:cache_path)
102
-
103
- with_env('XDG_CACHE_HOME', '/tmp') do
104
- config_client = Prefab::ConfigClient.new(MockBaseClient.new(options), 10)
105
- assert_equal "/tmp/prefab.cache.123.json", config_client.send(:cache_path)
106
- end
107
- end
108
-
109
- end
@@ -1,117 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class TestConfigLoader < Minitest::Test
6
- def setup
7
- super
8
- options = Prefab::Options.new(
9
- prefab_config_override_dir: 'none',
10
- prefab_config_classpath_dir: 'test',
11
- prefab_envs: 'unit_tests'
12
- )
13
- @loader = Prefab::ConfigLoader.new(MockBaseClient.new(options))
14
- end
15
-
16
- def test_load
17
- should_be :int, 123, 'sample_int'
18
- should_be :string, 'test sample value', 'sample'
19
- should_be :bool, true, 'sample_bool'
20
- should_be :double, 12.12, 'sample_double'
21
- end
22
-
23
- def test_nested
24
- should_be :string, 'nested value', 'nested.values.string'
25
- should_be :string, 'top level', 'nested.values'
26
- should_be :log_level, :ERROR, 'log-level.app'
27
- should_be :log_level, :WARN, 'log-level.app.controller.hello'
28
- should_be :log_level, :INFO, 'log-level.app.controller.hello.index'
29
- end
30
-
31
- def test_invalid_log_level
32
- should_be :log_level, :NOT_SET_LOG_LEVEL, 'log-level.invalid'
33
- end
34
-
35
- def test_load_without_unit_test_env
36
- options = Prefab::Options.new(
37
- prefab_config_override_dir: 'none',
38
- prefab_config_classpath_dir: 'test'
39
- # no prefab_envs
40
- )
41
- @loader = Prefab::ConfigLoader.new(MockBaseClient.new(options))
42
- should_be :string, 'default sample value', 'sample'
43
- should_be :bool, true, 'sample_bool'
44
- end
45
-
46
- def test_highwater
47
- assert_equal 0, @loader.highwater_mark
48
- @loader.set(PrefabProto::Config.new(id: 1, key: 'sample_int', rows: [config_row(PrefabProto::ConfigValue.new(int: 456))]),
49
- 'test')
50
- assert_equal 1, @loader.highwater_mark
51
-
52
- @loader.set(PrefabProto::Config.new(id: 5, key: 'sample_int', rows: [config_row(PrefabProto::ConfigValue.new(int: 456))]),
53
- 'test')
54
- assert_equal 5, @loader.highwater_mark
55
- @loader.set(PrefabProto::Config.new(id: 2, key: 'sample_int', rows: [config_row(PrefabProto::ConfigValue.new(int: 456))]),
56
- 'test')
57
- assert_equal 5, @loader.highwater_mark
58
- end
59
-
60
- def test_keeps_most_recent
61
- assert_equal 0, @loader.highwater_mark
62
- @loader.set(PrefabProto::Config.new(id: 1, key: 'sample_int', rows: [config_row(PrefabProto::ConfigValue.new(int: 1))]),
63
- 'test')
64
- assert_equal 1, @loader.highwater_mark
65
- should_be :int, 1, 'sample_int'
66
-
67
- @loader.set(PrefabProto::Config.new(id: 4, key: 'sample_int', rows: [config_row(PrefabProto::ConfigValue.new(int: 4))]),
68
- 'test')
69
- assert_equal 4, @loader.highwater_mark
70
- should_be :int, 4, 'sample_int'
71
-
72
- @loader.set(PrefabProto::Config.new(id: 2, key: 'sample_int', rows: [config_row(PrefabProto::ConfigValue.new(int: 2))]),
73
- 'test')
74
- assert_equal 4, @loader.highwater_mark
75
- should_be :int, 4, 'sample_int'
76
- end
77
-
78
- def test_api_precedence
79
- should_be :int, 123, 'sample_int'
80
-
81
- @loader.set(PrefabProto::Config.new(key: 'sample_int', rows: [config_row(PrefabProto::ConfigValue.new(int: 456))]), 'test')
82
- should_be :int, 456, 'sample_int'
83
- end
84
-
85
- def test_api_deltas
86
- val = PrefabProto::ConfigValue.new(int: 456)
87
- config = PrefabProto::Config.new(key: 'sample_int', rows: [config_row(val)])
88
- @loader.set(config, 'test')
89
-
90
- configs = PrefabProto::Configs.new
91
- configs.configs << config
92
- assert_equal configs, @loader.get_api_deltas
93
- end
94
-
95
- def test_loading_tombstones_removes_entries
96
- val = PrefabProto::ConfigValue.new(int: 456)
97
- config = PrefabProto::Config.new(key: 'sample_int', rows: [config_row(val)], id: 2)
98
- @loader.set(config, 'test')
99
-
100
- config = PrefabProto::Config.new(key: 'sample_int', rows: [], id: 3)
101
- @loader.set(config, 'test')
102
-
103
- configs = PrefabProto::Configs.new
104
- assert_equal configs, @loader.get_api_deltas
105
- end
106
-
107
- private
108
-
109
- def should_be(type, value, key)
110
- assert_equal type, @loader.calc_config[key][:config].rows[0].values[0].value.type
111
- assert_equal value, @loader.calc_config[key][:config].rows[0].values[0].value.send(type)
112
- end
113
-
114
- def config_row(value)
115
- PrefabProto::ConfigRow.new(values: [PrefabProto::ConditionalValue.new(value: value)])
116
- end
117
- end
@@ -1,430 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class TestConfigResolver < Minitest::Test
6
- STAGING_ENV_ID = 1
7
- PRODUCTION_ENV_ID = 2
8
- TEST_ENV_ID = 3
9
- SEGMENT_KEY = 'segment_key'
10
- CONFIG_KEY = 'config_key'
11
- DEFAULT_VALUE = 'default_value'
12
- DESIRED_VALUE = 'desired_value'
13
- IN_SEGMENT_VALUE = 'in_segment_value'
14
- WRONG_ENV_VALUE = 'wrong_env_value'
15
- NOT_IN_SEGMENT_VALUE = 'not_in_segment_value'
16
-
17
- DEFAULT_ROW = PrefabProto::ConfigRow.new(
18
- values: [
19
- PrefabProto::ConditionalValue.new(
20
- value: PrefabProto::ConfigValue.new(string: DEFAULT_VALUE)
21
- )
22
- ]
23
- )
24
-
25
- class MockConfigLoader
26
- def calc_config; end
27
- end
28
-
29
- def test_resolution
30
- @loader = MockConfigLoader.new
31
-
32
- loaded_values = {
33
- 'key' => { config: PrefabProto::Config.new(
34
- key: 'key',
35
- rows: [
36
- DEFAULT_ROW,
37
- PrefabProto::ConfigRow.new(
38
- project_env_id: TEST_ENV_ID,
39
- values: [
40
- PrefabProto::ConditionalValue.new(
41
- criteria: [
42
- PrefabProto::Criterion.new(
43
- operator: PrefabProto::Criterion::CriterionOperator::HIERARCHICAL_MATCH,
44
- value_to_match: PrefabProto::ConfigValue.new(string: 'projectB.subprojectX'),
45
- property_name: Prefab::CriteriaEvaluator::NAMESPACE_KEY
46
- )
47
- ],
48
- value: PrefabProto::ConfigValue.new(string: 'projectB.subprojectX')
49
- ),
50
- PrefabProto::ConditionalValue.new(
51
- criteria: [
52
- PrefabProto::Criterion.new(
53
- operator: PrefabProto::Criterion::CriterionOperator::HIERARCHICAL_MATCH,
54
- value_to_match: PrefabProto::ConfigValue.new(string: 'projectB.subprojectY'),
55
- property_name: Prefab::CriteriaEvaluator::NAMESPACE_KEY
56
- )
57
- ],
58
- value: PrefabProto::ConfigValue.new(string: 'projectB.subprojectY')
59
- ),
60
- PrefabProto::ConditionalValue.new(
61
- criteria: [
62
- PrefabProto::Criterion.new(
63
- operator: PrefabProto::Criterion::CriterionOperator::HIERARCHICAL_MATCH,
64
- value_to_match: PrefabProto::ConfigValue.new(string: 'projectA'),
65
- property_name: Prefab::CriteriaEvaluator::NAMESPACE_KEY
66
- )
67
- ],
68
- value: PrefabProto::ConfigValue.new(string: 'valueA')
69
- ),
70
- PrefabProto::ConditionalValue.new(
71
- criteria: [
72
- PrefabProto::Criterion.new(
73
- operator: PrefabProto::Criterion::CriterionOperator::HIERARCHICAL_MATCH,
74
- value_to_match: PrefabProto::ConfigValue.new(string: 'projectB'),
75
- property_name: Prefab::CriteriaEvaluator::NAMESPACE_KEY
76
- )
77
- ],
78
- value: PrefabProto::ConfigValue.new(string: 'valueB')
79
- ),
80
- PrefabProto::ConditionalValue.new(
81
- criteria: [
82
- PrefabProto::Criterion.new(
83
- operator: PrefabProto::Criterion::CriterionOperator::HIERARCHICAL_MATCH,
84
- value_to_match: PrefabProto::ConfigValue.new(string: 'projectB.subprojectX'),
85
- property_name: Prefab::CriteriaEvaluator::NAMESPACE_KEY
86
- )
87
- ],
88
- value: PrefabProto::ConfigValue.new(string: 'projectB.subprojectX')
89
- ),
90
- PrefabProto::ConditionalValue.new(
91
- criteria: [
92
- PrefabProto::Criterion.new(
93
- operator: PrefabProto::Criterion::CriterionOperator::HIERARCHICAL_MATCH,
94
- value_to_match: PrefabProto::ConfigValue.new(string: 'projectB.subprojectY'),
95
- property_name: Prefab::CriteriaEvaluator::NAMESPACE_KEY
96
- )
97
- ],
98
- value: PrefabProto::ConfigValue.new(string: 'projectB.subprojectY')
99
- ),
100
- PrefabProto::ConditionalValue.new(
101
- value: PrefabProto::ConfigValue.new(string: 'value_none')
102
- )
103
- ]
104
- )
105
-
106
- ]
107
- ) },
108
- 'key2' => { config: PrefabProto::Config.new(
109
- key: 'key2',
110
- rows: [
111
- PrefabProto::ConfigRow.new(
112
- values: [
113
- PrefabProto::ConditionalValue.new(
114
- value: PrefabProto::ConfigValue.new(string: 'valueB2')
115
- )
116
- ]
117
- )
118
- ]
119
- ) }
120
- }
121
-
122
- @loader.stub :calc_config, loaded_values do
123
- @resolverA = resolver_for_namespace('', @loader, project_env_id: PRODUCTION_ENV_ID)
124
- assert_equal_context_and_jit DEFAULT_VALUE, @resolverA, 'key', {}
125
-
126
- ## below here in the test env
127
- @resolverA = resolver_for_namespace('', @loader)
128
- assert_equal_context_and_jit 'value_none', @resolverA, 'key', {}
129
-
130
- @resolverA = resolver_for_namespace('projectA', @loader)
131
- assert_equal_context_and_jit 'valueA', @resolverA, 'key', {}
132
-
133
- @resolverB = resolver_for_namespace('projectB', @loader)
134
- assert_equal_context_and_jit 'valueB', @resolverB, 'key', {}
135
-
136
- @resolverBX = resolver_for_namespace('projectB.subprojectX', @loader)
137
- assert_equal_context_and_jit 'projectB.subprojectX', @resolverBX, 'key', {}
138
-
139
- @resolverBX = resolver_for_namespace('projectB.subprojectX', @loader)
140
- assert_equal_context_and_jit 'valueB2', @resolverBX, 'key2', {}
141
-
142
- @resolverUndefinedSubProject = resolver_for_namespace('projectB.subprojectX.subsubQ',
143
- @loader)
144
- assert_equal_context_and_jit 'projectB.subprojectX', @resolverUndefinedSubProject, 'key', {}
145
-
146
- @resolverBX = resolver_for_namespace('projectC', @loader)
147
- assert_equal_context_and_jit 'value_none', @resolverBX, 'key', {}
148
-
149
- assert_nil @resolverBX.get('key_that_doesnt_exist', nil)
150
-
151
- assert_equal @resolverBX.to_s.strip.split("\n").map(&:strip), [
152
- 'key | value_none | String | Match: | Source:',
153
- 'key2 | valueB2 | String | Match: | Source:'
154
- ]
155
-
156
- assert_equal @resolverBX.presenter.to_h, {
157
- 'key' => Prefab::ResolvedConfigPresenter::ConfigRow.new('key', 'value_none', nil, nil),
158
- 'key2' => Prefab::ResolvedConfigPresenter::ConfigRow.new('key2', 'valueB2', nil, nil)
159
- }
160
-
161
- resolved_lines = []
162
- @resolverBX.presenter.each do |key, row|
163
- resolved_lines << [key, row.value]
164
- end
165
- assert_equal resolved_lines, [%w[key value_none], %w[key2 valueB2]]
166
- end
167
- end
168
-
169
- def test_resolving_in_segment
170
- segment_config = PrefabProto::Config.new(
171
- config_type: PrefabProto::ConfigType::SEGMENT,
172
- key: SEGMENT_KEY,
173
- rows: [
174
- PrefabProto::ConfigRow.new(
175
- values: [
176
- PrefabProto::ConditionalValue.new(
177
- value: PrefabProto::ConfigValue.new(bool: true),
178
- criteria: [
179
- PrefabProto::Criterion.new(
180
- operator: PrefabProto::Criterion::CriterionOperator::PROP_ENDS_WITH_ONE_OF,
181
- value_to_match: string_list(['hotmail.com', 'gmail.com']),
182
- property_name: 'user.email'
183
- )
184
- ]
185
- ),
186
- PrefabProto::ConditionalValue.new(value: PrefabProto::ConfigValue.new(bool: false))
187
- ]
188
- )
189
- ]
190
- )
191
-
192
- config = PrefabProto::Config.new(
193
- key: CONFIG_KEY,
194
- rows: [
195
- # wrong env
196
- PrefabProto::ConfigRow.new(
197
- project_env_id: TEST_ENV_ID,
198
- values: [
199
- PrefabProto::ConditionalValue.new(
200
- criteria: [
201
- PrefabProto::Criterion.new(
202
- operator: PrefabProto::Criterion::CriterionOperator::IN_SEG,
203
- value_to_match: PrefabProto::ConfigValue.new(string: SEGMENT_KEY)
204
- )
205
- ],
206
- value: PrefabProto::ConfigValue.new(string: WRONG_ENV_VALUE)
207
- ),
208
- PrefabProto::ConditionalValue.new(
209
- criteria: [],
210
- value: PrefabProto::ConfigValue.new(string: DEFAULT_VALUE)
211
- )
212
- ]
213
- ),
214
-
215
- # correct env
216
- PrefabProto::ConfigRow.new(
217
- project_env_id: PRODUCTION_ENV_ID,
218
- values: [
219
- PrefabProto::ConditionalValue.new(
220
- criteria: [
221
- PrefabProto::Criterion.new(
222
- operator: PrefabProto::Criterion::CriterionOperator::IN_SEG,
223
- value_to_match: PrefabProto::ConfigValue.new(string: SEGMENT_KEY)
224
- )
225
- ],
226
- value: PrefabProto::ConfigValue.new(string: IN_SEGMENT_VALUE)
227
- ),
228
- PrefabProto::ConditionalValue.new(
229
- criteria: [],
230
- value: PrefabProto::ConfigValue.new(string: DEFAULT_VALUE)
231
- )
232
- ]
233
- )
234
- ]
235
- )
236
-
237
- loaded_values = {
238
- SEGMENT_KEY => { config: segment_config },
239
- CONFIG_KEY => { config: config }
240
- }
241
-
242
- loader = MockConfigLoader.new
243
-
244
- loader.stub :calc_config, loaded_values do
245
- options = Prefab::Options.new
246
- resolver = Prefab::ConfigResolver.new(MockBaseClient.new(options), loader)
247
- resolver.project_env_id = PRODUCTION_ENV_ID
248
-
249
- assert_equal_context_and_jit DEFAULT_VALUE, resolver, CONFIG_KEY,
250
- { user: { email: 'test@something-else.com' } }
251
- assert_equal_context_and_jit IN_SEGMENT_VALUE, resolver, CONFIG_KEY,
252
- { user: { email: 'test@hotmail.com' } }
253
- end
254
- end
255
-
256
- def test_resolving_not_in_segment
257
- segment_config = PrefabProto::Config.new(
258
- config_type: PrefabProto::ConfigType::SEGMENT,
259
- key: SEGMENT_KEY,
260
- rows: [
261
- PrefabProto::ConfigRow.new(
262
- values: [
263
- PrefabProto::ConditionalValue.new(
264
- value: PrefabProto::ConfigValue.new(bool: true),
265
- criteria: [
266
- PrefabProto::Criterion.new(
267
- operator: PrefabProto::Criterion::CriterionOperator::PROP_ENDS_WITH_ONE_OF,
268
- value_to_match: string_list(['hotmail.com', 'gmail.com']),
269
- property_name: 'user.email'
270
- )
271
- ]
272
- ),
273
- PrefabProto::ConditionalValue.new(value: PrefabProto::ConfigValue.new(bool: false))
274
- ]
275
- )
276
- ]
277
- )
278
-
279
- config = PrefabProto::Config.new(
280
- key: CONFIG_KEY,
281
- rows: [
282
- PrefabProto::ConfigRow.new(
283
- values: [
284
- PrefabProto::ConditionalValue.new(
285
- criteria: [
286
- PrefabProto::Criterion.new(
287
- operator: PrefabProto::Criterion::CriterionOperator::IN_SEG,
288
- value_to_match: PrefabProto::ConfigValue.new(string: SEGMENT_KEY)
289
- )
290
- ],
291
- value: PrefabProto::ConfigValue.new(string: IN_SEGMENT_VALUE)
292
- ),
293
- PrefabProto::ConditionalValue.new(
294
- criteria: [
295
- PrefabProto::Criterion.new(
296
- operator: PrefabProto::Criterion::CriterionOperator::NOT_IN_SEG,
297
- value_to_match: PrefabProto::ConfigValue.new(string: SEGMENT_KEY)
298
- )
299
- ],
300
- value: PrefabProto::ConfigValue.new(string: NOT_IN_SEGMENT_VALUE)
301
- )
302
- ]
303
- )
304
- ]
305
- )
306
-
307
- loaded_values = {
308
- SEGMENT_KEY => { config: segment_config },
309
- CONFIG_KEY => { config: config }
310
- }
311
-
312
- loader = MockConfigLoader.new
313
-
314
- loader.stub :calc_config, loaded_values do
315
- options = Prefab::Options.new
316
- resolver = Prefab::ConfigResolver.new(MockBaseClient.new(options), loader)
317
-
318
- assert_equal_context_and_jit IN_SEGMENT_VALUE, resolver, CONFIG_KEY, { user: { email: 'test@hotmail.com' } }
319
- assert_equal_context_and_jit NOT_IN_SEGMENT_VALUE, resolver, CONFIG_KEY, { user: { email: 'test@something-else.com' } }
320
- end
321
- end
322
-
323
- def test_jit_context_merges_with_existing_context
324
- config = PrefabProto::Config.new(
325
- key: CONFIG_KEY,
326
- rows: [
327
- DEFAULT_ROW,
328
- PrefabProto::ConfigRow.new(
329
- project_env_id: TEST_ENV_ID,
330
- values: [
331
- PrefabProto::ConditionalValue.new(
332
- criteria: [
333
- PrefabProto::Criterion.new(
334
- operator: PrefabProto::Criterion::CriterionOperator::PROP_IS_ONE_OF,
335
- value_to_match: string_list(%w[pro advanced]),
336
- property_name: 'team.plan'
337
- ),
338
-
339
- PrefabProto::Criterion.new(
340
- operator: PrefabProto::Criterion::CriterionOperator::PROP_ENDS_WITH_ONE_OF,
341
- value_to_match: string_list(%w[@example.com]),
342
- property_name: 'user.email'
343
- )
344
- ],
345
- value: PrefabProto::ConfigValue.new(string: DESIRED_VALUE)
346
- )
347
- ]
348
- )
349
- ]
350
- )
351
-
352
- loader = MockConfigLoader.new
353
-
354
- loader.stub :calc_config, { CONFIG_KEY => { config: config } } do
355
- options = Prefab::Options.new
356
- resolver = Prefab::ConfigResolver.new(MockBaseClient.new(options), loader)
357
- resolver.project_env_id = TEST_ENV_ID
358
-
359
- Prefab::Context.with_context({ user: { email: 'test@example.com' } }) do
360
- assert_equal DEFAULT_VALUE, resolver.get(CONFIG_KEY).unwrapped_value
361
- assert_equal DEFAULT_VALUE, resolver.get(CONFIG_KEY, { team: { plan: 'freebie' } }).unwrapped_value
362
- assert_equal DESIRED_VALUE, resolver.get(CONFIG_KEY, { team: { plan: 'pro' } }).unwrapped_value
363
- end
364
- end
365
- end
366
-
367
- def test_jit_can_clobber_existing_context
368
- config = PrefabProto::Config.new(
369
- key: CONFIG_KEY,
370
- rows: [
371
- DEFAULT_ROW,
372
- PrefabProto::ConfigRow.new(
373
- project_env_id: TEST_ENV_ID,
374
- values: [
375
- PrefabProto::ConditionalValue.new(
376
- criteria: [
377
- PrefabProto::Criterion.new(
378
- operator: PrefabProto::Criterion::CriterionOperator::PROP_IS_ONE_OF,
379
- value_to_match: string_list(%w[pro advanced]),
380
- property_name: 'team.plan'
381
- ),
382
-
383
- PrefabProto::Criterion.new(
384
- operator: PrefabProto::Criterion::CriterionOperator::PROP_ENDS_WITH_ONE_OF,
385
- value_to_match: string_list(%w[@example.com]),
386
- property_name: 'user.email'
387
- )
388
- ],
389
- value: PrefabProto::ConfigValue.new(string: DESIRED_VALUE)
390
- )
391
- ]
392
- )
393
- ]
394
- )
395
-
396
- loader = MockConfigLoader.new
397
-
398
- loader.stub :calc_config, { CONFIG_KEY => { config: config } } do
399
- options = Prefab::Options.new
400
- resolver = Prefab::ConfigResolver.new(MockBaseClient.new(options), loader)
401
- resolver.project_env_id = TEST_ENV_ID
402
-
403
- Prefab::Context.with_context({ user: { email: 'test@hotmail.com' }, team: { plan: 'pro' } }) do
404
- assert_equal DEFAULT_VALUE, resolver.get(CONFIG_KEY).unwrapped_value
405
- assert_equal DESIRED_VALUE, resolver.get(CONFIG_KEY, { user: { email: 'test@example.com' } }).unwrapped_value
406
- assert_equal DEFAULT_VALUE, resolver.get(CONFIG_KEY, { team: { plan: 'freebie' } }).unwrapped_value
407
- end
408
- end
409
- end
410
-
411
- private
412
-
413
- def resolver_for_namespace(namespace, loader, project_env_id: TEST_ENV_ID)
414
- options = Prefab::Options.new(
415
- namespace: namespace
416
- )
417
- resolver = Prefab::ConfigResolver.new(MockBaseClient.new(options), loader)
418
- resolver.project_env_id = project_env_id
419
- resolver.update
420
- resolver
421
- end
422
-
423
- def assert_equal_context_and_jit(expected_value, resolver, key, properties)
424
- assert_equal expected_value, resolver.get(key, properties).unwrapped_value
425
-
426
- Prefab::Context.with_context(properties) do
427
- assert_equal expected_value, resolver.get(key).unwrapped_value
428
- end
429
- end
430
- end