prefab-cloud-ruby 0.24.5 → 1.0.0

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/VERSION +1 -1
  4. data/compile_protos.sh +7 -0
  5. data/lib/prefab/client.rb +20 -46
  6. data/lib/prefab/config_client.rb +9 -12
  7. data/lib/prefab/config_resolver.rb +2 -1
  8. data/lib/prefab/config_value_unwrapper.rb +20 -9
  9. data/lib/prefab/context.rb +43 -7
  10. data/lib/prefab/context_shape_aggregator.rb +1 -1
  11. data/lib/prefab/criteria_evaluator.rb +24 -16
  12. data/lib/prefab/evaluation.rb +48 -0
  13. data/lib/prefab/evaluation_summary_aggregator.rb +85 -0
  14. data/lib/prefab/example_contexts_aggregator.rb +76 -0
  15. data/lib/prefab/exponential_backoff.rb +5 -0
  16. data/lib/prefab/feature_flag_client.rb +0 -2
  17. data/lib/prefab/log_path_aggregator.rb +1 -1
  18. data/lib/prefab/logger_client.rb +12 -13
  19. data/lib/prefab/options.rb +52 -43
  20. data/lib/prefab/periodic_sync.rb +30 -13
  21. data/lib/prefab/rate_limit_cache.rb +41 -0
  22. data/lib/prefab/resolved_config_presenter.rb +2 -4
  23. data/lib/prefab/weighted_value_resolver.rb +1 -1
  24. data/lib/prefab-cloud-ruby.rb +5 -5
  25. data/lib/prefab_pb.rb +11 -1
  26. data/prefab-cloud-ruby.gemspec +14 -9
  27. data/test/integration_test.rb +1 -3
  28. data/test/integration_test_helpers.rb +0 -1
  29. data/test/support/common_helpers.rb +174 -0
  30. data/test/support/mock_base_client.rb +44 -0
  31. data/test/support/mock_config_client.rb +19 -0
  32. data/test/support/mock_config_loader.rb +1 -0
  33. data/test/test_client.rb +354 -40
  34. data/test/test_config_client.rb +1 -0
  35. data/test/test_config_loader.rb +1 -0
  36. data/test/test_config_resolver.rb +25 -24
  37. data/test/test_config_value_unwrapper.rb +22 -32
  38. data/test/test_context.rb +1 -0
  39. data/test/test_context_shape_aggregator.rb +11 -1
  40. data/test/test_criteria_evaluator.rb +180 -133
  41. data/test/test_evaluation_summary_aggregator.rb +162 -0
  42. data/test/test_example_contexts_aggregator.rb +238 -0
  43. data/test/test_helper.rb +5 -131
  44. data/test/test_integration.rb +6 -4
  45. data/test/test_local_config_parser.rb +2 -2
  46. data/test/test_log_path_aggregator.rb +9 -1
  47. data/test/test_logger.rb +6 -5
  48. data/test/test_options.rb +33 -2
  49. data/test/test_rate_limit_cache.rb +44 -0
  50. data/test/test_weighted_value_resolver.rb +13 -7
  51. metadata +13 -8
  52. data/lib/prefab/evaluated_configs_aggregator.rb +0 -60
  53. data/lib/prefab/evaluated_keys_aggregator.rb +0 -41
  54. data/lib/prefab/noop_cache.rb +0 -15
  55. data/lib/prefab/noop_stats.rb +0 -8
  56. data/test/test_evaluated_configs_aggregator.rb +0 -254
  57. data/test/test_evaluated_keys_aggregator.rb +0 -54
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'timecop'
5
+
6
+ class TestEvaluationSummaryAggregator < Minitest::Test
7
+ EFFECTIVELY_NEVER = 99_999 # we sync manually
8
+
9
+ EXAMPLE_VALUE_1 = PrefabProto::ConfigValue.new(bool: true)
10
+ EXAMPLE_VALUE_2 = PrefabProto::ConfigValue.new(bool: false)
11
+
12
+ EXAMPLE_COUNTER = {
13
+ config_id: 1,
14
+ selected_index: 2,
15
+ config_row_index: 3,
16
+ conditional_value_index: 4,
17
+ weighted_value_index: 5,
18
+ seleced_value: EXAMPLE_VALUE_1
19
+ }.freeze
20
+
21
+ def test_increments_counts
22
+ aggregator = Prefab::EvaluationSummaryAggregator.new(client: MockBaseClient.new, max_keys: 10,
23
+ sync_interval: EFFECTIVELY_NEVER)
24
+
25
+ aggregator.record(config_key: 'foo', config_type: 'bar', counter: EXAMPLE_COUNTER)
26
+
27
+ assert_equal 1, aggregator.data[%w[foo bar]][EXAMPLE_COUNTER]
28
+
29
+ 2.times { aggregator.record(config_key: 'foo', config_type: 'bar', counter: EXAMPLE_COUNTER) }
30
+ assert_equal 3, aggregator.data[%w[foo bar]][EXAMPLE_COUNTER]
31
+
32
+ another_counter = EXAMPLE_COUNTER.merge(selected_index: EXAMPLE_COUNTER[:selected_index] + 1)
33
+
34
+ aggregator.record(config_key: 'foo', config_type: 'bar', counter: another_counter)
35
+ assert_equal 3, aggregator.data[%w[foo bar]][EXAMPLE_COUNTER]
36
+ assert_equal 1, aggregator.data[%w[foo bar]][another_counter]
37
+ end
38
+
39
+ def test_prepare_data
40
+ aggregator = Prefab::EvaluationSummaryAggregator.new(client: MockBaseClient.new, max_keys: 10,
41
+ sync_interval: EFFECTIVELY_NEVER)
42
+
43
+ expected = {
44
+ ['config-1', :CONFIG] => {
45
+ { config_id: 1, selected_index: 2, config_row_index: 3, conditional_value_index: 4,
46
+ weighted_value_index: 5, selected_value: EXAMPLE_VALUE_1 } => 3,
47
+ { config_id: 1, selected_index: 3, config_row_index: 7, conditional_value_index: 8,
48
+ weighted_value_index: 10, selected_value: EXAMPLE_VALUE_2 } => 1
49
+ },
50
+ ['config-2', :FEATURE_FLAG] => {
51
+ { config_id: 2, selected_index: 3, config_row_index: 5, conditional_value_index: 7,
52
+ weighted_value_index: 6, selected_value: EXAMPLE_VALUE_1 } => 9
53
+ }
54
+ }
55
+
56
+ add_example_data(aggregator)
57
+ assert_equal expected, aggregator.prepare_data
58
+ assert aggregator.data.empty?
59
+ end
60
+
61
+ def test_sync
62
+ awhile_ago = Time.now - 60
63
+ now = Time.now
64
+
65
+ client = MockBaseClient.new
66
+
67
+ aggregator = nil
68
+
69
+ Timecop.freeze(awhile_ago) do
70
+ # start the aggregator in the past
71
+ aggregator = Prefab::EvaluationSummaryAggregator.new(client: client, max_keys: 10,
72
+ sync_interval: EFFECTIVELY_NEVER)
73
+ end
74
+
75
+ add_example_data(aggregator)
76
+
77
+ expected_post = PrefabProto::TelemetryEvents.new(
78
+ instance_hash: client.instance_hash,
79
+ events: [
80
+ PrefabProto::TelemetryEvent.new(
81
+ summaries:
82
+
83
+ PrefabProto::ConfigEvaluationSummaries.new(
84
+ start: awhile_ago.to_i * 1000,
85
+ end: now.to_i * 1000,
86
+ summaries: [
87
+ PrefabProto::ConfigEvaluationSummary.new(
88
+ key: 'config-1',
89
+ type: :CONFIG,
90
+ counters: [
91
+ PrefabProto::ConfigEvaluationCounter.new(
92
+ config_id: 1,
93
+ selected_index: 2,
94
+ config_row_index: 3,
95
+ conditional_value_index: 4,
96
+ weighted_value_index: 5,
97
+ selected_value: EXAMPLE_VALUE_1,
98
+ count: 3
99
+ ),
100
+ PrefabProto::ConfigEvaluationCounter.new(
101
+ config_id: 1,
102
+ selected_index: 3,
103
+ config_row_index: 7,
104
+ conditional_value_index: 8,
105
+ weighted_value_index: 10,
106
+ selected_value: EXAMPLE_VALUE_2,
107
+ count: 1
108
+ )
109
+ ]
110
+ ),
111
+ PrefabProto::ConfigEvaluationSummary.new(
112
+ key: 'config-2',
113
+ type: :FEATURE_FLAG,
114
+ counters: [
115
+ PrefabProto::ConfigEvaluationCounter.new(
116
+ config_id: 2,
117
+ selected_index: 3,
118
+ config_row_index: 5,
119
+ conditional_value_index: 7,
120
+ weighted_value_index: 6,
121
+ selected_value: EXAMPLE_VALUE_1,
122
+ count: 9
123
+ )
124
+ ]
125
+ )
126
+ ]
127
+ )
128
+ )
129
+ ]
130
+ )
131
+
132
+ requests = wait_for_post_requests(client) do
133
+ Timecop.freeze(now) do
134
+ aggregator.sync
135
+ end
136
+ end
137
+
138
+ assert_equal [[
139
+ '/api/v1/telemetry',
140
+ expected_post
141
+ ]], requests
142
+ end
143
+
144
+ private
145
+
146
+ def add_example_data(aggregator)
147
+ data = {
148
+ ['config-1', :CONFIG] => {
149
+ { config_id: 1, selected_index: 2, config_row_index: 3, conditional_value_index: 4,
150
+ weighted_value_index: 5, selected_value: EXAMPLE_VALUE_1 } => 3,
151
+ { config_id: 1, selected_index: 3, config_row_index: 7, conditional_value_index: 8,
152
+ weighted_value_index: 10, selected_value: EXAMPLE_VALUE_2 } => 1
153
+ },
154
+ ['config-2', :FEATURE_FLAG] => {
155
+ { config_id: 2, selected_index: 3, config_row_index: 5, conditional_value_index: 7,
156
+ weighted_value_index: 6, selected_value: EXAMPLE_VALUE_1 } => 9
157
+ }
158
+ }
159
+
160
+ aggregator.instance_variable_set('@data', data)
161
+ end
162
+ end
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+ require 'timecop'
5
+
6
+ class TestExampleContextsAggregator < Minitest::Test
7
+ EFFECTIVELY_NEVER = 99_999 # we sync manually
8
+
9
+ def test_record
10
+ aggregator = Prefab::ExampleContextsAggregator.new(client: MockBaseClient.new, max_contexts: 2,
11
+ sync_interval: EFFECTIVELY_NEVER)
12
+
13
+ context = Prefab::Context.new(
14
+ user: { key: 'abc' },
15
+ device: { key: 'def', mobile: true }
16
+ )
17
+
18
+ aggregator.record(context)
19
+ assert_equal [context], aggregator.data
20
+
21
+ # This doesn't get updated because we already have a context for this user/device
22
+ aggregator.record(context)
23
+ assert_equal [context], aggregator.data
24
+
25
+ new_context = Prefab::Context.new(
26
+ user: { key: 'ghi', admin: true },
27
+ team: { key: '999' }
28
+ )
29
+
30
+ aggregator.record(new_context)
31
+ assert_equal [context, new_context], aggregator.data
32
+
33
+ # this doesn't get recorded because we're at max_contexts
34
+ aggregator.record(Prefab::Context.new(user: { key: 'new' }))
35
+ assert_equal [context, new_context], aggregator.data
36
+ end
37
+
38
+ def test_prepare_data
39
+ aggregator = Prefab::ExampleContextsAggregator.new(client: MockBaseClient.new, max_contexts: 10,
40
+ sync_interval: EFFECTIVELY_NEVER)
41
+
42
+ context = Prefab::Context.new(
43
+ user: { key: 'abc' },
44
+ device: { key: 'def', mobile: true }
45
+ )
46
+
47
+ aggregator.record(context)
48
+
49
+ assert_equal [context], aggregator.prepare_data
50
+ assert aggregator.data.empty?
51
+ end
52
+
53
+ def test_record_with_expiry
54
+ aggregator = Prefab::ExampleContextsAggregator.new(client: MockBaseClient.new, max_contexts: 10,
55
+ sync_interval: EFFECTIVELY_NEVER)
56
+
57
+ context = Prefab::Context.new(
58
+ user: { key: 'abc' },
59
+ device: { key: 'def', mobile: true }
60
+ )
61
+
62
+ aggregator.record(context)
63
+
64
+ assert_equal [context], aggregator.data
65
+
66
+ Timecop.travel(Time.now + (60 * 60) - 1) do
67
+ aggregator.record(context)
68
+
69
+ # This doesn't get updated because we already have a context for this user/device in the timeframe
70
+ assert_equal [context], aggregator.data
71
+ end
72
+
73
+ Timecop.travel(Time.now + ((60 * 60) + 1)) do
74
+ # this is new because we've passed the expiry
75
+ aggregator.record(context)
76
+
77
+ assert_equal [context, context], aggregator.data
78
+ end
79
+ end
80
+
81
+ def test_sync
82
+ now = Time.now
83
+
84
+ client = MockBaseClient.new
85
+
86
+ aggregator = Prefab::ExampleContextsAggregator.new(client: client, max_contexts: 10,
87
+ sync_interval: EFFECTIVELY_NEVER)
88
+
89
+ context = Prefab::Context.new(
90
+ user: { key: 'abc' },
91
+ device: { key: 'def', mobile: true }
92
+ )
93
+ aggregator.record(context)
94
+
95
+ # This is the same as above so we shouldn't get anything new
96
+ aggregator.record(context)
97
+
98
+ aggregator.record(
99
+ Prefab::Context.new(
100
+ user: { key: 'ghi' },
101
+ device: { key: 'jkl', mobile: false }
102
+ )
103
+ )
104
+
105
+ aggregator.record(Prefab::Context.new(user: { key: 'kev', name: 'kevin', age: 48.5 }))
106
+
107
+ assert_equal 3, aggregator.cache.data.size
108
+
109
+ expected_post = PrefabProto::TelemetryEvents.new(
110
+ instance_hash: client.instance_hash,
111
+ events: [
112
+ PrefabProto::TelemetryEvent.new(
113
+ example_contexts: PrefabProto::ExampleContexts.new(
114
+ examples: [
115
+ PrefabProto::ExampleContext.new(
116
+ timestamp: now.utc.to_i * 1000,
117
+ contextSet: PrefabProto::ContextSet.new(
118
+ contexts: [
119
+ PrefabProto::Context.new(
120
+ type: 'user',
121
+ values: {
122
+ 'key' => PrefabProto::ConfigValue.new(string: 'abc')
123
+ }
124
+ ),
125
+ PrefabProto::Context.new(
126
+ type: 'device',
127
+ values: {
128
+ 'key' => PrefabProto::ConfigValue.new(string: 'def'),
129
+ 'mobile' => PrefabProto::ConfigValue.new(bool: true)
130
+ }
131
+ )
132
+ ]
133
+ )
134
+ ),
135
+
136
+ PrefabProto::ExampleContext.new(
137
+ timestamp: now.utc.to_i * 1000,
138
+ contextSet: PrefabProto::ContextSet.new(
139
+ contexts: [
140
+ PrefabProto::Context.new(
141
+ type: 'user',
142
+ values: {
143
+ 'key' => PrefabProto::ConfigValue.new(string: 'ghi')
144
+ }
145
+ ),
146
+ PrefabProto::Context.new(
147
+ type: 'device',
148
+ values: {
149
+ 'key' => PrefabProto::ConfigValue.new(string: 'jkl'),
150
+ 'mobile' => PrefabProto::ConfigValue.new(bool: false)
151
+ }
152
+ )
153
+ ]
154
+ )
155
+ ),
156
+
157
+ PrefabProto::ExampleContext.new(
158
+ timestamp: now.utc.to_i * 1000,
159
+ contextSet: PrefabProto::ContextSet.new(
160
+ contexts: [
161
+ PrefabProto::Context.new(
162
+ type: 'user',
163
+ values: {
164
+ 'key' => PrefabProto::ConfigValue.new(string: 'kev'),
165
+ 'name' => PrefabProto::ConfigValue.new(string: 'kevin'),
166
+ 'age' => PrefabProto::ConfigValue.new(double: 48.5)
167
+ }
168
+ )
169
+ ]
170
+ )
171
+ )
172
+ ]
173
+ )
174
+ )
175
+ ]
176
+ )
177
+
178
+ requests = wait_for_post_requests(client) do
179
+ Timecop.freeze(now + (60 * 60) - 1) do
180
+ aggregator.sync
181
+ end
182
+ end
183
+
184
+ assert_equal [[
185
+ '/api/v1/telemetry',
186
+ expected_post
187
+ ]], requests
188
+
189
+ # this hasn't changed because not enough time has passed
190
+ assert_equal 3, aggregator.cache.data.size
191
+
192
+ # a sync past the expiry should clear the cache
193
+ Timecop.freeze(now + (60 * 60) + 1) do
194
+ # we need a new piece of data for the sync to happen
195
+ aggregator.record(Prefab::Context.new(user: { key: 'bozo', name: 'Bozo', age: 99 }))
196
+
197
+ requests = wait_for_post_requests(client) do
198
+ aggregator.sync
199
+ end
200
+ end
201
+
202
+ expected_post = PrefabProto::TelemetryEvents.new(
203
+ instance_hash: client.instance_hash,
204
+ events: [
205
+ PrefabProto::TelemetryEvent.new(
206
+ example_contexts: PrefabProto::ExampleContexts.new(
207
+ examples: [
208
+ PrefabProto::ExampleContext.new(
209
+ timestamp: (now.utc.to_i + (60 * 60) + 1) * 1000,
210
+ contextSet: PrefabProto::ContextSet.new(
211
+ contexts: [
212
+ PrefabProto::Context.new(
213
+ type: 'user',
214
+ values: {
215
+ 'key' => PrefabProto::ConfigValue.new(string: 'bozo'),
216
+ 'name' => PrefabProto::ConfigValue.new(string: 'Bozo'),
217
+ 'age' => PrefabProto::ConfigValue.new(int: 99)
218
+ }
219
+ )
220
+ ]
221
+ )
222
+ )
223
+ ]
224
+ )
225
+ )
226
+ ]
227
+ )
228
+
229
+ assert_equal [[
230
+ '/api/v1/telemetry',
231
+ expected_post
232
+ ]], requests
233
+
234
+ # The last sync should have cleared the cache of everything except the latest context
235
+ assert_equal 1, aggregator.cache.data.size
236
+ assert_equal ['user:bozo'], aggregator.cache.data.keys
237
+ end
238
+ end
data/test/test_helper.rb CHANGED
@@ -7,137 +7,11 @@ Minitest::Reporters.use!
7
7
 
8
8
  require 'prefab-cloud-ruby'
9
9
 
10
- class MockBaseClient
11
- STAGING_ENV_ID = 1
12
- PRODUCTION_ENV_ID = 2
13
- TEST_ENV_ID = 3
14
- attr_reader :namespace
15
- attr_reader :logger
16
- attr_reader :config_client
17
- attr_reader :options
18
-
19
- def initialize(options = Prefab::Options.new)
20
- @options = options
21
- @namespace = namespace
22
- @logger = Prefab::LoggerClient.new($stdout)
23
- @config_client = MockConfigClient.new
24
- end
25
-
26
- def project_id
27
- 1
28
- end
29
-
30
- def log
31
- @logger
32
- end
33
-
34
- def log_internal(level, message); end
35
-
36
- def context_shape_aggregator; end
37
-
38
- def evaluated_keys_aggregator; end
39
-
40
- def evaluated_configs_aggregator; end
41
-
42
- def config_value(key)
43
- @config_values[key]
44
- end
45
- end
46
-
47
- class MockConfigClient
48
- def initialize(config_values = {})
49
- @config_values = config_values
50
- end
51
-
52
- def get(key, default = nil)
53
- @config_values.fetch(key, default)
54
- end
55
-
56
- def get_config(key)
57
- PrefabProto::Config.new(value: @config_values[key], key: key)
58
- end
59
-
60
- def mock_this_config(key, config_value)
61
- @config_values[key] = config_value
62
- end
63
- end
64
-
65
- class MockConfigLoader
66
- def calc_config; end
67
- end
68
-
69
- private
70
-
71
- def default_ff_rule(variant_idx)
72
- [
73
- Prefab::Rule.new(
74
- criteria: Prefab::Criteria.new(operator: Prefab::Criteria::CriteriaOperator::ALWAYS_TRUE),
75
- variant_weights: [
76
- Prefab::VariantWeight.new(weight: 1000,
77
- variant_idx: variant_idx)
78
- ]
79
- )
80
- ]
81
- end
82
-
83
- def with_env(key, value, &block)
84
- old_value = ENV[key]
85
-
86
- ENV[key] = value
87
- block.call
88
- ensure
89
- ENV[key] = old_value
90
- end
91
-
92
- def new_client(overrides = {})
93
- options = Prefab::Options.new(**{
94
- prefab_config_override_dir: 'none',
95
- prefab_config_classpath_dir: 'test',
96
- prefab_envs: ['unit_tests'],
97
- prefab_datasources: Prefab::Options::DATASOURCES::LOCAL_ONLY
98
- }.merge(overrides))
99
-
100
- Prefab::Client.new(options)
101
- end
102
-
103
- def string_list(values)
104
- PrefabProto::ConfigValue.new(string_list: PrefabProto::StringList.new(values: values))
105
- end
106
-
107
- def inject_config(client, config)
108
- resolver = client.config_client.instance_variable_get('@config_resolver')
109
- store = resolver.instance_variable_get('@local_store')
110
-
111
- store[config.key] = { config: config }
10
+ Dir.glob(File.join(File.dirname(__FILE__), 'support', '**', '*.rb')).each do |file|
11
+ require file
112
12
  end
113
13
 
114
- def inject_project_env_id(client, project_env_id)
115
- resolver = client.config_client.instance_variable_get('@config_resolver')
116
- resolver.project_env_id = project_env_id
117
- end
118
-
119
- def wait_for_post_requests(client)
120
- max_wait = 2
121
- sleep_time = 0.01
122
-
123
- requests = []
124
-
125
- client.define_singleton_method(:post) do |*params|
126
- requests.push(params)
127
-
128
- OpenStruct.new(status: 200)
129
- end
130
-
131
- yield
132
-
133
- # let the flush thread run
134
- wait_time = 0
135
- while requests.empty?
136
- wait_time += sleep_time
137
- sleep sleep_time
138
-
139
- raise "Waited #{max_wait} seconds for the flush thread to run, but it never did" if wait_time > max_wait
140
- end
141
-
142
- requests
14
+ MiniTest::Test.class_eval do
15
+ include CommonHelpers
16
+ extend CommonHelpers
143
17
  end
@@ -25,11 +25,13 @@ class TestIntegration < Minitest::Test
25
25
  assert_match(/#{it.expected[:message]}/, err.message)
26
26
  when :nil
27
27
  assert_nil it.test_client.send(it.func, *it.input)
28
- when :feature_flag
29
- flag, context = *it.input
30
- assert_equal it.expected[:value], it.test_client.send(it.func, flag, context)
31
28
  when :simple_equality
32
- assert_equal it.expected[:value], it.test_client.send(it.func, *it.input)
29
+ if it.func == :enabled?
30
+ flag, _default, context = *it.input
31
+ assert_equal it.expected[:value], it.test_client.send(it.func, flag, context)
32
+ else
33
+ assert_equal it.expected[:value], it.test_client.send(it.func, *it.input)
34
+ end
33
35
  when :log_level
34
36
  assert_equal it.expected[:value].to_sym, it.test_client.send(it.func, *it.input)
35
37
  else
@@ -34,7 +34,7 @@ class TestLocalConfigParser < Minitest::Test
34
34
  assert_equal 1, config.rows[0].values.size
35
35
 
36
36
  value_row = config.rows[0].values[0]
37
- assert_equal 'all-features', Prefab::ConfigValueUnwrapper.unwrap(value_row.value, key, {})
37
+ assert_equal 'all-features', Prefab::ConfigValueUnwrapper.deepest_value(value_row.value, key, {}).unwrap
38
38
  end
39
39
 
40
40
  def test_flag_in_user_key
@@ -53,7 +53,7 @@ class TestLocalConfigParser < Minitest::Test
53
53
  assert_equal 1, config.rows[0].values[0].criteria.size
54
54
 
55
55
  value_row = config.rows[0].values[0]
56
- assert_equal true, Prefab::ConfigValueUnwrapper.unwrap(value_row.value, key, {})
56
+ assert_equal true, Prefab::ConfigValueUnwrapper.deepest_value(value_row.value, key, {}).unwrap
57
57
 
58
58
  assert_equal 'user.key', value_row.criteria[0].property_name
59
59
  assert_equal :PROP_IS_ONE_OF, value_row.criteria[0].operator
@@ -8,7 +8,8 @@ class TestLogPathAggregator < Minitest::Test
8
8
  SLEEP_TIME = 0.01
9
9
 
10
10
  def test_push
11
- aggregator = Prefab::LogPathAggregator.new(client: new_client, max_paths: 2, sync_interval: 1000)
11
+ client = new_client
12
+ aggregator = Prefab::LogPathAggregator.new(client: client, max_paths: 2, sync_interval: 1000)
12
13
 
13
14
  aggregator.push('test.test_log_path_aggregator.test_push.1', ::Logger::INFO)
14
15
  aggregator.push('test.test_log_path_aggregator.test_push.2', ::Logger::DEBUG)
@@ -18,6 +19,8 @@ class TestLogPathAggregator < Minitest::Test
18
19
  # we've reached the limit, so no more
19
20
  aggregator.push('test.test_log_path_aggregator.test_push.3', ::Logger::INFO)
20
21
  assert_equal 2, aggregator.data.size
22
+
23
+ assert_only_expected_logs
21
24
  end
22
25
 
23
26
  def test_sync
@@ -42,6 +45,11 @@ class TestLogPathAggregator < Minitest::Test
42
45
  namespace: 'this.is.a.namespace'
43
46
  )
44
47
  ]], requests
48
+
49
+ assert_logged [
50
+ 'WARN 2023-08-09 15:18:12 -0400: cloud.prefab.client No success loading checkpoints',
51
+ 'ERROR 2023-08-09 15:18:12 -0400: test.test_log_path_aggregator.test_sync here is a message'
52
+ ]
45
53
  end
46
54
  end
47
55
 
data/test/test_logger.rb CHANGED
@@ -19,6 +19,7 @@ class TestLogger < Minitest::Test
19
19
  )
20
20
 
21
21
  def setup
22
+ super
22
23
  Prefab::LoggerClient.send(:public, :get_path)
23
24
  Prefab::LoggerClient.send(:public, :get_loc_path)
24
25
  Prefab::LoggerClient.send(:public, :level_of)
@@ -65,20 +66,20 @@ class TestLogger < Minitest::Test
65
66
  assert_equal ::Logger::INFO,
66
67
  @logger.level_of('app.models.user'), 'PREFAB_LOG_CLIENT_BOOTSTRAP_LOG_LEVEL is info'
67
68
 
68
- @logger.set_config_client(MockConfigClient.new({}))
69
+ @logger.config_client = MockConfigClient.new({})
69
70
  assert_equal ::Logger::WARN,
70
71
  @logger.level_of('app.models.user'), 'default is warn'
71
72
 
72
- @logger.set_config_client(MockConfigClient.new('log-level.app' => :INFO))
73
+ @logger.config_client = MockConfigClient.new('log-level.app' => :INFO)
73
74
  assert_equal ::Logger::INFO,
74
75
  @logger.level_of('app.models.user')
75
76
 
76
- @logger.set_config_client(MockConfigClient.new('log-level.app' => :DEBUG))
77
+ @logger.config_client = MockConfigClient.new('log-level.app' => :DEBUG)
77
78
  assert_equal ::Logger::DEBUG,
78
79
  @logger.level_of('app.models.user')
79
80
 
80
- @logger.set_config_client(MockConfigClient.new('log-level.app' => :DEBUG,
81
- 'log-level.app.models' => :ERROR))
81
+ @logger.config_client = MockConfigClient.new('log-level.app' => :DEBUG,
82
+ 'log-level.app.models' => :ERROR)
82
83
  assert_equal ::Logger::ERROR,
83
84
  @logger.level_of('app.models.user'), 'test leveling'
84
85
  end
data/test/test_options.rb CHANGED
@@ -36,9 +36,40 @@ class TestOptions < Minitest::Test
36
36
  assert_equal 0, options.collect_max_paths
37
37
  end
38
38
 
39
- def test_collect_max_paths_with_collect_logs_false
39
+ def test_collect_max_paths_with_collect_logger_counts_false
40
40
  options = Prefab::Options.new(collect_max_paths: 100,
41
- collect_logs: false)
41
+ collect_logger_counts: false)
42
42
  assert_equal 0, options.collect_max_paths
43
43
  end
44
+
45
+ def test_collect_max_evaluation_summaries
46
+ assert_equal 100_000, Prefab::Options.new.collect_max_evaluation_summaries
47
+ assert_equal 0, Prefab::Options.new(collect_evaluation_summaries: false).collect_max_evaluation_summaries
48
+ assert_equal 3,
49
+ Prefab::Options.new(collect_max_evaluation_summaries: 3).collect_max_evaluation_summaries
50
+ end
51
+
52
+ def test_context_upload_mode_periodic
53
+ options = Prefab::Options.new(context_upload_mode: :periodic_example, context_max_size: 100)
54
+ assert_equal 100, options.collect_max_example_contexts
55
+
56
+ options = Prefab::Options.new(context_upload_mode: :none)
57
+ assert_equal 0, options.collect_max_example_contexts
58
+ end
59
+
60
+ def test_context_upload_mode_shape_only
61
+ options = Prefab::Options.new(context_upload_mode: :shape_only, context_max_size: 100)
62
+ assert_equal 100, options.collect_max_shapes
63
+
64
+ options = Prefab::Options.new(context_upload_mode: :none)
65
+ assert_equal 0, options.collect_max_shapes
66
+ end
67
+
68
+ def test_context_upload_mode_none
69
+ options = Prefab::Options.new(context_upload_mode: :none)
70
+ assert_equal 0, options.collect_max_example_contexts
71
+
72
+ options = Prefab::Options.new(context_upload_mode: :none)
73
+ assert_equal 0, options.collect_max_shapes
74
+ end
44
75
  end