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,180 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CommonHelpers
4
- require 'timecop'
5
-
6
- def setup
7
- $oldstderr, $stderr = $stderr, StringIO.new
8
-
9
- $logs = nil
10
- Timecop.freeze('2023-08-09 15:18:12 -0400')
11
- end
12
-
13
- def teardown
14
- if $logs && !$logs.string.empty?
15
- raise "Unexpected logs. Handle logs with assert_only_expected_logs or assert_logged\n\n#{$logs.string}"
16
- end
17
-
18
- if $stderr != $oldstderr && !$stderr.string.empty?
19
- # we ignore 2.X because of the number of `instance variable @xyz not initialized` warnings
20
- if !RUBY_VERSION.start_with?('2.')
21
- raise "Unexpected stderr. Handle stderr with assert_stderr\n\n#{$stderr.string}"
22
- end
23
- end
24
-
25
- $stderr = $oldstderr
26
-
27
- Timecop.return
28
- end
29
-
30
- def with_env(key, value, &block)
31
- old_value = ENV.fetch(key, nil)
32
-
33
- ENV[key] = value
34
- block.call
35
- ensure
36
- ENV[key] = old_value
37
- end
38
-
39
- DEFAULT_NEW_CLIENT_OPTIONS = {
40
- prefab_config_override_dir: 'none',
41
- prefab_config_classpath_dir: 'test',
42
- prefab_envs: ['unit_tests'],
43
- prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY
44
- }.freeze
45
-
46
- def new_client(overrides = {})
47
-
48
- config = overrides.delete(:config)
49
- project_env_id = overrides.delete(:project_env_id)
50
-
51
- Prefab::Client.new(prefab_options(overrides)).tap do |client|
52
- inject_config(client, config) if config
53
-
54
- client.resolver.project_env_id = project_env_id if project_env_id
55
- end
56
- end
57
-
58
- def prefab_options(overrides = {})
59
- $logs ||= StringIO.new
60
- Prefab::Options.new(
61
- **DEFAULT_NEW_CLIENT_OPTIONS.merge(
62
- overrides.merge(logdev: $logs)
63
- )
64
- )
65
- end
66
-
67
- def string_list(values)
68
- PrefabProto::ConfigValue.new(string_list: PrefabProto::StringList.new(values: values))
69
- end
70
-
71
- def inject_config(client, config)
72
- resolver = client.config_client.instance_variable_get('@config_resolver')
73
- store = resolver.instance_variable_get('@local_store')
74
-
75
- Array(config).each do |c|
76
- store[c.key] = { config: c }
77
- end
78
- end
79
-
80
- def inject_project_env_id(client, project_env_id)
81
- resolver = client.config_client.instance_variable_get('@config_resolver')
82
- resolver.project_env_id = project_env_id
83
- end
84
-
85
- FakeResponse = Struct.new(:status, :body)
86
-
87
- def wait_for(condition, max_wait: 2, sleep_time: 0.01)
88
- wait_time = 0
89
- while !condition.call
90
- wait_time += sleep_time
91
- sleep sleep_time
92
-
93
- raise "Waited #{max_wait} seconds for the condition to be true, but it never was" if wait_time > max_wait
94
- end
95
- end
96
-
97
- def wait_for_post_requests(client, max_wait: 2, sleep_time: 0.01)
98
- # we use ivars to avoid re-mocking the post method on subsequent calls
99
- client.instance_variable_set("@_requests", [])
100
-
101
- if !client.instance_variable_get("@_already_faked_post")
102
- client.define_singleton_method(:post) do |*params|
103
- @_requests.push(params)
104
-
105
- FakeResponse.new(200, '')
106
- end
107
- end
108
-
109
- client.instance_variable_set("@_already_faked_post", true)
110
-
111
- yield
112
-
113
- # let the flush thread run
114
- wait_for -> { client.instance_variable_get("@_requests").size > 0 }, max_wait: max_wait, sleep_time: sleep_time
115
-
116
- client.instance_variable_get("@_requests")
117
- end
118
-
119
- def assert_summary(client, data)
120
- raise 'Evaluation summary aggregator not enabled' unless client.evaluation_summary_aggregator
121
-
122
- assert_equal data, client.evaluation_summary_aggregator.data
123
- end
124
-
125
- def assert_example_contexts(client, data)
126
- raise 'Example contexts aggregator not enabled' unless client.example_contexts_aggregator
127
-
128
- assert_equal data, client.example_contexts_aggregator.data
129
- end
130
-
131
- def weighted_values(values_and_weights, hash_by_property_name: 'user.key')
132
- values = values_and_weights.map do |value, weight|
133
- weighted_value(value, weight)
134
- end
135
-
136
- PrefabProto::WeightedValues.new(weighted_values: values, hash_by_property_name: hash_by_property_name)
137
- end
138
-
139
- def weighted_value(string, weight)
140
- PrefabProto::WeightedValue.new(
141
- value: PrefabProto::ConfigValue.new(string: string), weight: weight
142
- )
143
- end
144
-
145
- def context(properties)
146
- Prefab::Context.new(properties)
147
- end
148
-
149
- def assert_only_expected_logs
150
- assert_equal "WARN 2023-08-09 15:18:12 -0400: cloud.prefab.client.configclient No success loading checkpoints\n", $logs.string
151
- # mark nil to indicate we handled it
152
- $logs = nil
153
- end
154
-
155
- def assert_logged(expected)
156
- # we do a uniq here because logging can happen in a separate thread so the
157
- # number of times a log might happen could be slightly variable.
158
- assert_equal expected, $logs.string.split("\n").uniq
159
- # mark nil to indicate we handled it
160
- $logs = nil
161
- end
162
-
163
- def assert_stderr(expected)
164
- assert ($stderr.string.split("\n").uniq & expected).size > 0
165
-
166
- # Ruby 2.X has a lot of warnings about instance variables not being
167
- # initialized so we don't try to assert on stderr for those versions.
168
- # Instead we just stop after asserting that our expected errors are
169
- # included in the output.
170
- if RUBY_VERSION.start_with?('2.')
171
- puts $stderr.string
172
- return
173
- end
174
-
175
- assert_equal expected, $stderr.string.split("\n")
176
-
177
- # restore since we've handled it
178
- $stderr = $oldstderr
179
- end
180
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class MockBaseClient
4
- STAGING_ENV_ID = 1
5
- PRODUCTION_ENV_ID = 2
6
- TEST_ENV_ID = 3
7
- attr_reader :namespace, :logger, :config_client, :options, :posts
8
-
9
- def initialize(options = Prefab::Options.new)
10
- @options = options
11
- @namespace = namespace
12
- @config_client = MockConfigClient.new
13
- Prefab::LoggerClient.new(options.logdev)
14
- @posts = []
15
- end
16
-
17
- def instance_hash
18
- 'mock-base-client-instance-hash'
19
- end
20
-
21
- def project_id
22
- 1
23
- end
24
-
25
- def post(_, _)
26
- raise 'Use wait_for_post_requests'
27
- end
28
-
29
- def log
30
- @logger
31
- end
32
-
33
- def context_shape_aggregator; end
34
-
35
- def evaluation_summary_aggregator; end
36
-
37
- def example_contexts_aggregator; end
38
-
39
- def config_value(key)
40
- @config_values[key]
41
- end
42
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class MockConfigClient
4
- def initialize(config_values = {})
5
- @config_values = config_values
6
- end
7
-
8
- def get(key, default = nil)
9
- @config_values.fetch(key, default)
10
- end
11
-
12
- def get_config(key)
13
- PrefabProto::Config.new(value: @config_values[key], key: key)
14
- end
15
-
16
- def mock_this_config(key, config_value)
17
- @config_values[key] = config_value
18
- end
19
- end
@@ -1 +0,0 @@
1
- # frozen_string_literal: true
data/test/test_client.rb DELETED
@@ -1,444 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
-
5
- class TestClient < Minitest::Test
6
- LOCAL_ONLY = Prefab::Options::DATASOURCES::LOCAL_ONLY
7
-
8
- PROJECT_ENV_ID = 1
9
- KEY = 'the-key'
10
- DEFAULT_VALUE = 'default_value'
11
- DESIRED_VALUE = 'desired_value'
12
-
13
- IRRELEVANT = 'this should never show up'
14
-
15
- DEFAULT_VALUE_CONFIG = PrefabProto::ConfigValue.new(string: DEFAULT_VALUE)
16
- DESIRED_VALUE_CONFIG = PrefabProto::ConfigValue.new(string: DESIRED_VALUE)
17
-
18
- TRUE_CONFIG = PrefabProto::ConfigValue.new(bool: true)
19
- FALSE_CONFIG = PrefabProto::ConfigValue.new(bool: false)
20
-
21
- DEFAULT_ROW = PrefabProto::ConfigRow.new(
22
- values: [
23
- PrefabProto::ConditionalValue.new(value: DEFAULT_VALUE_CONFIG)
24
- ]
25
- )
26
-
27
- def test_get
28
- _, err = capture_io do
29
- client = new_client
30
- assert_equal 'default', client.get('does.not.exist', 'default')
31
- assert_equal 'test sample value', client.get('sample')
32
- assert_equal 123, client.get('sample_int')
33
- end
34
- assert_equal '', err
35
- end
36
-
37
- def test_get_with_default
38
- client = new_client
39
- # A `false` value is not replaced with the default
40
- assert_equal false, client.get('false_value', 'red')
41
-
42
- # A falsy value is not replaced with the default
43
- assert_equal 0, client.get('zero_value', 'red')
44
-
45
- # A missing value returns the default
46
- assert_equal 'buckets', client.get('missing_value', 'buckets')
47
- end
48
-
49
- def test_get_with_missing_default
50
- client = new_client
51
- # it raises by default
52
- err = assert_raises(Prefab::Errors::MissingDefaultError) do
53
- assert_nil client.get('missing_value')
54
- end
55
-
56
- assert_match(/No value found for key/, err.message)
57
- assert_match(/on_no_default/, err.message)
58
-
59
- # you can opt-in to return `nil` instead
60
- client = new_client(on_no_default: Prefab::Options::ON_NO_DEFAULT::RETURN_NIL)
61
- assert_nil client.get('missing_value')
62
- end
63
-
64
- def test_enabled
65
- client = new_client
66
- assert_equal false, client.enabled?('does_not_exist')
67
- assert_equal true, client.enabled?('enabled_flag')
68
- assert_equal false, client.enabled?('disabled_flag')
69
- assert_equal false, client.enabled?('flag_with_a_value')
70
- end
71
-
72
- def test_ff_enabled_with_user_key_match
73
- client = new_client
74
-
75
- ctx = { user: { key: 'jimmy' } }
76
- assert_equal false, client.enabled?('user_key_match', ctx)
77
- assert_equal false, Prefab::Context.with_context(ctx) { client.enabled?('user_key_match') }
78
-
79
- ctx = { user: { key: 'abc123' } }
80
- assert_equal true, client.enabled?('user_key_match', ctx)
81
- assert_equal true, Prefab::Context.with_context(ctx) { client.enabled?('user_key_match') }
82
-
83
- ctx = { user: { key: 'xyz987' } }
84
- assert_equal true, client.enabled?('user_key_match', ctx)
85
- assert_equal true, Prefab::Context.with_context(ctx) { client.enabled?('user_key_match') }
86
- end
87
-
88
- # NOTE: these are all `false` because we're doing a enabled? on a FF with string variants
89
- # see test_ff_get_with_context for the raw value tests
90
- def test_ff_enabled_with_context
91
- client = new_client
92
-
93
- ctx = { user: { domain: 'gmail.com' } }
94
- assert_equal false, client.enabled?('just_my_domain', ctx)
95
- assert_equal false, Prefab::Context.with_context(ctx) { client.enabled?('just_my_domain') }
96
-
97
- ctx = { user: { domain: 'prefab.cloud' } }
98
- assert_equal false, client.enabled?('just_my_domain', ctx)
99
- assert_equal false, Prefab::Context.with_context(ctx) { client.enabled?('just_my_domain') }
100
-
101
- ctx = { user: { domain: 'example.com' } }
102
- assert_equal false, client.enabled?('just_my_domain', ctx)
103
- assert_equal false, Prefab::Context.with_context(ctx) { client.enabled?('just_my_domain') }
104
- end
105
-
106
- def test_ff_get_with_context
107
- client = new_client
108
-
109
- ctx = { user: { domain: 'gmail.com' } }
110
- assert_equal 'DEFAULT', client.get('just_my_domain', 'DEFAULT', ctx)
111
- assert_equal 'DEFAULT', Prefab::Context.with_context(ctx) { client.get('just_my_domain', 'DEFAULT') }
112
-
113
- ctx = { user: { domain: 'prefab.cloud' } }
114
- assert_equal 'new-version', client.get('just_my_domain', 'DEFAULT', ctx)
115
- assert_equal 'new-version', Prefab::Context.with_context(ctx) { client.get('just_my_domain', 'DEFAULT') }
116
-
117
- ctx = { user: { domain: 'example.com' } }
118
- assert_equal 'new-version', client.get('just_my_domain', 'DEFAULT', ctx)
119
- assert_equal 'new-version', Prefab::Context.with_context(ctx) { client.get('just_my_domain', 'DEFAULT') }
120
- end
121
-
122
- def test_deprecated_no_dot_notation_ff_enabled_with_jit_context
123
- client = new_client
124
- # with no lookup key
125
- assert_equal false, client.enabled?('deprecated_no_dot_notation', { domain: 'gmail.com' })
126
- assert_equal true, client.enabled?('deprecated_no_dot_notation', { domain: 'prefab.cloud' })
127
- assert_equal true, client.enabled?('deprecated_no_dot_notation', { domain: 'example.com' })
128
-
129
- assert_stderr [
130
- "[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash.",
131
- "[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash.",
132
- "[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash."
133
- ]
134
- end
135
-
136
- def test_getting_feature_flag_value
137
- client = new_client
138
- assert_equal false, client.enabled?('flag_with_a_value')
139
- assert_equal 'all-features', client.get('flag_with_a_value')
140
- end
141
-
142
- def test_initialization_with_an_options_object
143
- options_hash = {
144
- namespace: 'test-namespace',
145
- prefab_datasources: LOCAL_ONLY
146
- }
147
-
148
- options = Prefab::Options.new(options_hash)
149
-
150
- client = Prefab::Client.new(options)
151
-
152
- assert_equal client.namespace, 'test-namespace'
153
- end
154
-
155
- def test_initialization_with_a_hash
156
- options_hash = {
157
- namespace: 'test-namespace',
158
- prefab_datasources: LOCAL_ONLY
159
- }
160
-
161
- client = Prefab::Client.new(options_hash)
162
-
163
- assert_equal client.namespace, 'test-namespace'
164
- end
165
-
166
- def test_evaluation_summary_aggregator
167
- fake_api_key = '123-development-yourapikey-SDK'
168
-
169
- # it is nil by default
170
- assert_nil new_client(api_key: fake_api_key).evaluation_summary_aggregator
171
-
172
- # it is nil when local_only even if collect_max_evaluation_summaries is true
173
- assert_nil new_client(prefab_datasources: LOCAL_ONLY,
174
- collect_evaluation_summaries: true, ).evaluation_summary_aggregator
175
-
176
- # it is nil when collect_max_evaluation_summaries is false
177
- assert_nil new_client(api_key: fake_api_key,
178
- prefab_datasources: :all,
179
- collect_evaluation_summaries: false).evaluation_summary_aggregator
180
-
181
- # it is not nil when collect_max_evaluation_summaries is true and the datasource is not local_only
182
- assert_equal Prefab::EvaluationSummaryAggregator,
183
- new_client(api_key: fake_api_key,
184
- prefab_datasources: :all,
185
- collect_evaluation_summaries: true).evaluation_summary_aggregator.class
186
-
187
- assert_logged [
188
- "WARN 2023-08-09 15:18:12 -0400: cloud.prefab.client.configclient No success loading checkpoints"
189
- ]
190
- end
191
-
192
- def test_get_with_basic_value
193
- config = basic_value_config
194
- client = new_client(config: config, project_env_id: PROJECT_ENV_ID, collect_evaluation_summaries: true,
195
- context_upload_mode: :periodic_example, allow_telemetry_in_local_mode: true)
196
-
197
- assert_equal DESIRED_VALUE, client.get(config.key, IRRELEVANT, 'user' => { 'key' => 99 })
198
-
199
- assert_summary client, {
200
- [KEY, :CONFIG] => {
201
- {
202
- config_id: config.id,
203
- config_row_index: 1,
204
- selected_value: DESIRED_VALUE_CONFIG,
205
- conditional_value_index: 0,
206
- weighted_value_index: nil,
207
- selected_index: nil
208
- } => 1
209
- }
210
- }
211
-
212
- assert_example_contexts client, [Prefab::Context.new({ user: { 'key' => 99 } })]
213
- end
214
-
215
- def test_get_with_basic_value_with_context
216
- config = basic_value_config
217
- client = new_client(config: config, project_env_id: PROJECT_ENV_ID, collect_evaluation_summaries: true,
218
- context_upload_mode: :periodic_example, allow_telemetry_in_local_mode: true)
219
-
220
- client.with_context('user' => { 'key' => 99 }) do
221
- assert_equal DESIRED_VALUE, client.get(config.key)
222
- end
223
-
224
- assert_summary client, {
225
- [KEY, :CONFIG] => {
226
- {
227
- config_id: config.id,
228
- config_row_index: 1,
229
- selected_value: DESIRED_VALUE_CONFIG,
230
- conditional_value_index: 0,
231
- weighted_value_index: nil,
232
- selected_index: nil
233
- } => 1
234
- }
235
- }
236
-
237
- assert_example_contexts client, [Prefab::Context.new({ user: { 'key' => 99 } })]
238
- end
239
-
240
- def test_get_with_weighted_values
241
- config = PrefabProto::Config.new(
242
- id: 123,
243
- key: KEY,
244
- config_type: PrefabProto::ConfigType::CONFIG,
245
- rows: [
246
- DEFAULT_ROW,
247
- PrefabProto::ConfigRow.new(
248
- project_env_id: PROJECT_ENV_ID,
249
- values: [
250
- PrefabProto::ConditionalValue.new(
251
- criteria: [PrefabProto::Criterion.new(operator: PrefabProto::Criterion::CriterionOperator::ALWAYS_TRUE)],
252
- value: PrefabProto::ConfigValue.new(weighted_values: weighted_values([['abc', 98], ['def', 1],
253
- ['ghi', 1]]))
254
- )
255
- ]
256
- )
257
- ]
258
- )
259
-
260
- client = new_client(config: config, project_env_id: PROJECT_ENV_ID, collect_evaluation_summaries: true,
261
- context_upload_mode: :periodic_example, allow_telemetry_in_local_mode: true)
262
-
263
- 2.times do
264
- assert_equal 'abc', client.get(config.key, IRRELEVANT, 'user' => { 'key' => '1' })
265
- end
266
-
267
- 3.times do
268
- assert_equal 'def', client.get(config.key, IRRELEVANT, 'user' => { 'key' => '12' })
269
- end
270
-
271
- assert_equal 'ghi',
272
- client.get(config.key, IRRELEVANT, 'user' => { 'key' => '4', admin: true })
273
-
274
- assert_summary client, {
275
- [KEY, :CONFIG] => {
276
- {
277
- config_id: config.id,
278
- config_row_index: 1,
279
- selected_value: PrefabProto::ConfigValue.new(string: 'abc'),
280
- conditional_value_index: 0,
281
- weighted_value_index: 0,
282
- selected_index: nil
283
- } => 2,
284
-
285
- {
286
- config_id: config.id,
287
- config_row_index: 1,
288
- selected_value: PrefabProto::ConfigValue.new(string: 'def'),
289
- conditional_value_index: 0,
290
- weighted_value_index: 1,
291
- selected_index: nil
292
- } => 3,
293
-
294
- {
295
- config_id: config.id,
296
- config_row_index: 1,
297
- selected_value: PrefabProto::ConfigValue.new(string: 'ghi'),
298
- conditional_value_index: 0,
299
- weighted_value_index: 2,
300
- selected_index: nil
301
- } => 1
302
- }
303
- }
304
-
305
- assert_example_contexts client, [
306
- Prefab::Context.new(user: { 'key' => '1' }),
307
- Prefab::Context.new(user: { 'key' => '12' }),
308
- Prefab::Context.new(user: { 'key' => '4', admin: true })
309
- ]
310
- end
311
-
312
- def test_in_seg
313
- segment_key = 'segment_key'
314
-
315
- segment_config = PrefabProto::Config.new(
316
- config_type: PrefabProto::ConfigType::SEGMENT,
317
- key: segment_key,
318
- rows: [
319
- PrefabProto::ConfigRow.new(
320
- values: [
321
- PrefabProto::ConditionalValue.new(
322
- value: TRUE_CONFIG,
323
- criteria: [
324
- PrefabProto::Criterion.new(
325
- operator: PrefabProto::Criterion::CriterionOperator::PROP_ENDS_WITH_ONE_OF,
326
- value_to_match: string_list(['hotmail.com', 'gmail.com']),
327
- property_name: 'user.email'
328
- )
329
- ]
330
- ),
331
- PrefabProto::ConditionalValue.new(value: FALSE_CONFIG)
332
- ]
333
- )
334
- ]
335
- )
336
-
337
- config = PrefabProto::Config.new(
338
- key: KEY,
339
- rows: [
340
- DEFAULT_ROW,
341
-
342
- PrefabProto::ConfigRow.new(
343
- project_env_id: PROJECT_ENV_ID,
344
- values: [
345
- PrefabProto::ConditionalValue.new(
346
- criteria: [
347
- PrefabProto::Criterion.new(
348
- operator: PrefabProto::Criterion::CriterionOperator::IN_SEG,
349
- value_to_match: PrefabProto::ConfigValue.new(string: segment_key)
350
- )
351
- ],
352
- value: DESIRED_VALUE_CONFIG
353
- )
354
- ]
355
- )
356
- ]
357
- )
358
-
359
- client = new_client(config: [config, segment_config], project_env_id: PROJECT_ENV_ID,
360
- collect_evaluation_summaries: true, context_upload_mode: :periodic_example, allow_telemetry_in_local_mode: true)
361
-
362
- assert_equal DEFAULT_VALUE, client.get(config.key)
363
- assert_equal DEFAULT_VALUE,
364
- client.get(config.key, IRRELEVANT, user: { key: 'abc', email: 'example@prefab.cloud' })
365
- assert_equal DESIRED_VALUE, client.get(config.key, IRRELEVANT, user: { key: 'def', email: 'example@hotmail.com' })
366
-
367
- assert_summary client, {
368
- [segment_key, :SEGMENT] => {
369
- { config_id: 0, config_row_index: 0, conditional_value_index: 1, selected_value: FALSE_CONFIG,
370
- weighted_value_index: nil, selected_index: nil } => 2,
371
- { config_id: 0, config_row_index: 0, conditional_value_index: 0, selected_value: TRUE_CONFIG,
372
- weighted_value_index: nil, selected_index: nil } => 1
373
- },
374
- [KEY, :NOT_SET_CONFIG_TYPE] => {
375
- { config_id: 0, config_row_index: 0, conditional_value_index: 0, selected_value: DEFAULT_VALUE_CONFIG,
376
- weighted_value_index: nil, selected_index: nil } => 2,
377
- { config_id: 0, config_row_index: 1, conditional_value_index: 0, selected_value: DESIRED_VALUE_CONFIG,
378
- weighted_value_index: nil, selected_index: nil } => 1
379
- }
380
- }
381
-
382
- assert_example_contexts client, [
383
- Prefab::Context.new(user: { key: 'abc', email: 'example@prefab.cloud' }),
384
- Prefab::Context.new(user: { key: 'def', email: 'example@hotmail.com' })
385
- ]
386
- end
387
-
388
- def test_get_log_level
389
- config = PrefabProto::Config.new(
390
- id: 999,
391
- key: 'log-level',
392
- config_type: PrefabProto::ConfigType::LOG_LEVEL,
393
- rows: [
394
- PrefabProto::ConfigRow.new(
395
- values: [
396
- PrefabProto::ConditionalValue.new(
397
- criteria: [PrefabProto::Criterion.new(operator: PrefabProto::Criterion::CriterionOperator::ALWAYS_TRUE)],
398
- value: PrefabProto::ConfigValue.new(log_level: PrefabProto::LogLevel::INFO)
399
- )
400
- ]
401
- )
402
- ]
403
- )
404
-
405
- client = new_client(config: config, project_env_id: PROJECT_ENV_ID,
406
- collect_evaluation_summaries: true, allow_telemetry_in_local_mode: true)
407
-
408
- assert_equal :INFO, client.get(config.key, IRRELEVANT)
409
-
410
- # nothing is summarized for log levels
411
- assert_summary client, {}
412
- end
413
-
414
- def test_fork_includes_logger_context_keys
415
- client = new_client
416
- client.log.add_context_keys "user.name"
417
-
418
- forked = client.fork
419
-
420
- assert forked.log.context_keys.to_a == %w(user.name)
421
- end
422
-
423
- private
424
-
425
- def basic_value_config
426
- PrefabProto::Config.new(
427
- id: 123,
428
- key: KEY,
429
- config_type: PrefabProto::ConfigType::CONFIG,
430
- rows: [
431
- DEFAULT_ROW,
432
- PrefabProto::ConfigRow.new(
433
- project_env_id: PROJECT_ENV_ID,
434
- values: [
435
- PrefabProto::ConditionalValue.new(
436
- criteria: [PrefabProto::Criterion.new(operator: PrefabProto::Criterion::CriterionOperator::ALWAYS_TRUE)],
437
- value: DESIRED_VALUE_CONFIG
438
- )
439
- ]
440
- )
441
- ]
442
- )
443
- end
444
- end