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,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