prefab-cloud-ruby 1.6.0.pre2 → 1.6.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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +4 -2
- data/CHANGELOG.md +10 -1
- data/Gemfile +1 -2
- data/Gemfile.lock +69 -82
- data/README.md +36 -6
- data/Rakefile +35 -32
- data/VERSION +1 -1
- data/dev/allocation_stats +60 -0
- data/dev/benchmark +40 -0
- data/lib/prefab/client.rb +5 -8
- data/lib/prefab/config_client.rb +2 -2
- data/lib/prefab/config_resolver.rb +5 -6
- data/lib/prefab/context.rb +90 -37
- data/lib/prefab/evaluation.rb +2 -1
- data/lib/prefab/options.rb +5 -3
- data/lib/prefab-cloud-ruby.rb +0 -1
- data/prefab-cloud-ruby.gemspec +7 -8
- data/test/support/common_helpers.rb +17 -10
- data/test/test_config_resolver.rb +41 -0
- data/test/test_context.rb +40 -44
- data/test/test_example_contexts_aggregator.rb +1 -4
- data/test/test_helper.rb +1 -1
- data/test/test_integration.rb +6 -0
- data/test/test_log_path_aggregator.rb +6 -6
- metadata +8 -21
- /data/{bin → dev}/console +0 -0
data/lib/prefab/context.rb
CHANGED
@@ -8,18 +8,8 @@ module Prefab
|
|
8
8
|
attr_reader :name
|
9
9
|
|
10
10
|
def initialize(name, hash)
|
11
|
-
@hash = {}
|
12
11
|
@name = name.to_s
|
13
|
-
|
14
|
-
merge!(hash)
|
15
|
-
end
|
16
|
-
|
17
|
-
def get(parts)
|
18
|
-
@hash[parts]
|
19
|
-
end
|
20
|
-
|
21
|
-
def merge!(other)
|
22
|
-
@hash = @hash.merge(other.transform_keys(&:to_s))
|
12
|
+
@hash = hash.transform_keys(&:to_s)
|
23
13
|
end
|
24
14
|
|
25
15
|
def to_h
|
@@ -27,13 +17,13 @@ module Prefab
|
|
27
17
|
end
|
28
18
|
|
29
19
|
def key
|
30
|
-
"#{@name}:#{
|
20
|
+
"#{@name}:#{@hash['key']}"
|
31
21
|
end
|
32
22
|
|
33
23
|
def to_proto
|
34
24
|
PrefabProto::Context.new(
|
35
25
|
type: name,
|
36
|
-
values:
|
26
|
+
values: @hash.transform_values do |value|
|
37
27
|
ConfigValueWrapper.wrap(value)
|
38
28
|
end
|
39
29
|
)
|
@@ -44,17 +34,35 @@ module Prefab
|
|
44
34
|
attr_reader :contexts, :seen_at
|
45
35
|
|
46
36
|
class << self
|
37
|
+
def global_context=(context)
|
38
|
+
@global_context = join(hash: context, parent: nil, id: :global_context)
|
39
|
+
end
|
40
|
+
|
41
|
+
def global_context
|
42
|
+
@global_context ||= join(parent: nil, id: :global_context)
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_context=(context)
|
46
|
+
@default_context = join(hash: context, parent: global_context, id: :default_context)
|
47
|
+
|
48
|
+
self.current.update_parent(@default_context)
|
49
|
+
end
|
50
|
+
|
51
|
+
def default_context
|
52
|
+
@default_context ||= join(parent: global_context, id: :default_context)
|
53
|
+
end
|
54
|
+
|
47
55
|
def current=(context)
|
48
|
-
Thread.current[THREAD_KEY] = context
|
56
|
+
Thread.current[THREAD_KEY] = join(hash: context || {}, parent: default_context, id: :block)
|
49
57
|
end
|
50
58
|
|
51
59
|
def current
|
52
|
-
Thread.current[THREAD_KEY] ||=
|
60
|
+
Thread.current[THREAD_KEY] ||= join(parent: default_context, id: :block)
|
53
61
|
end
|
54
62
|
|
55
63
|
def with_context(context)
|
56
64
|
old_context = Thread.current[THREAD_KEY]
|
57
|
-
Thread.current[THREAD_KEY] =
|
65
|
+
Thread.current[THREAD_KEY] = join(parent: default_context, hash: context, id: :block)
|
58
66
|
yield
|
59
67
|
ensure
|
60
68
|
Thread.current[THREAD_KEY] = old_context
|
@@ -62,7 +70,7 @@ module Prefab
|
|
62
70
|
|
63
71
|
def with_merged_context(context)
|
64
72
|
old_context = Thread.current[THREAD_KEY]
|
65
|
-
Thread.current[THREAD_KEY] =
|
73
|
+
Thread.current[THREAD_KEY] = join(parent: current, hash: context, id: :merged)
|
66
74
|
yield
|
67
75
|
ensure
|
68
76
|
Thread.current[THREAD_KEY] = old_context
|
@@ -77,51 +85,92 @@ module Prefab
|
|
77
85
|
end
|
78
86
|
end
|
79
87
|
|
80
|
-
def
|
88
|
+
def self.join(hash: {}, parent: nil, id: :not_provided)
|
89
|
+
context = new(hash)
|
90
|
+
context.update_parent(parent)
|
91
|
+
context.instance_variable_set(:@id, id)
|
92
|
+
context
|
93
|
+
end
|
94
|
+
|
95
|
+
def initialize(hash = {})
|
81
96
|
@contexts = {}
|
97
|
+
@flattened = {}
|
82
98
|
@seen_at = Time.now.utc.to_i
|
99
|
+
warned = false
|
100
|
+
|
101
|
+
if hash.is_a?(Hash)
|
102
|
+
hash.map do |name, values|
|
103
|
+
unless values.is_a?(Hash)
|
104
|
+
warn "[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash."
|
105
|
+
values = { name => values }
|
106
|
+
name = BLANK_CONTEXT_NAME
|
107
|
+
end
|
83
108
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
context.map do |name, values|
|
88
|
-
if values.is_a?(Hash)
|
89
|
-
@contexts[name.to_s] = NamedContext.new(name, values)
|
90
|
-
else
|
91
|
-
warn '[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash.'
|
92
|
-
|
93
|
-
@contexts[BLANK_CONTEXT_NAME] ||= NamedContext.new(BLANK_CONTEXT_NAME, {})
|
94
|
-
@contexts[BLANK_CONTEXT_NAME].merge!({ name => values })
|
109
|
+
@contexts[name.to_s] = NamedContext.new(name, values)
|
110
|
+
values.each do |key, value|
|
111
|
+
@flattened[name.to_s + '.' + key.to_s] = value
|
95
112
|
end
|
96
113
|
end
|
97
114
|
else
|
98
|
-
raise ArgumentError, 'must be a Hash
|
115
|
+
raise ArgumentError, 'must be a Hash'
|
99
116
|
end
|
100
117
|
end
|
101
118
|
|
119
|
+
def update_parent(parent)
|
120
|
+
@parent = parent
|
121
|
+
end
|
122
|
+
|
102
123
|
def blank?
|
103
124
|
contexts.empty?
|
104
125
|
end
|
105
126
|
|
106
127
|
def set(name, hash)
|
107
128
|
@contexts[name.to_s] = NamedContext.new(name, hash)
|
129
|
+
hash.each do |key, value|
|
130
|
+
@flattened[name.to_s + '.' + key.to_s] = value
|
131
|
+
end
|
108
132
|
end
|
109
133
|
|
110
|
-
def get(property_key)
|
111
|
-
|
112
|
-
|
113
|
-
if key.nil?
|
114
|
-
name = BLANK_CONTEXT_NAME
|
115
|
-
key = property_key
|
134
|
+
def get(property_key, scope: nil)
|
135
|
+
if !property_key.include?(".")
|
136
|
+
property_key = BLANK_CONTEXT_NAME + '.' + property_key
|
116
137
|
end
|
117
138
|
|
118
|
-
|
139
|
+
if @flattened.key?(property_key)
|
140
|
+
@flattened[property_key]
|
141
|
+
else
|
142
|
+
scope ||= property_key.split('.').first
|
143
|
+
|
144
|
+
if @contexts[scope]
|
145
|
+
# If the key is in the present scope, parent values should not be used.
|
146
|
+
# We can consider the parent value clobbered by the present scope.
|
147
|
+
nil
|
148
|
+
else
|
149
|
+
@parent&.get(property_key, scope: scope)
|
150
|
+
end
|
151
|
+
end
|
119
152
|
end
|
120
153
|
|
121
154
|
def to_h
|
122
155
|
contexts.transform_values(&:to_h)
|
123
156
|
end
|
124
157
|
|
158
|
+
def to_s
|
159
|
+
"#<Prefab::Context:#{object_id} id=#{@id} #{to_h}>"
|
160
|
+
end
|
161
|
+
|
162
|
+
# Visualize a tree of the context up through its parents
|
163
|
+
#
|
164
|
+
# example:
|
165
|
+
#
|
166
|
+
# | jit: {"user"=>{"name"=>"Frank"}}
|
167
|
+
# |-- block: {"clock"=>{"timezone"=>"PST"}}
|
168
|
+
# |---- default_context: {"prefab-api-key"=>{"user-id"=>123}}
|
169
|
+
# |------ global_context: {"cpu"=>{"count"=>4, "speed"=>"2.4GHz"}, "clock"=>{"timezone"=>"UTC"}}
|
170
|
+
def tree(depth = 0)
|
171
|
+
"|" + ("-" * depth) + " #{id}: #{(" " * (30 - id.to_s.length - depth ))}#{to_h}\n" + (@parent&.tree(depth + 2) || '')
|
172
|
+
end
|
173
|
+
|
125
174
|
def clear
|
126
175
|
@contexts = {}
|
127
176
|
end
|
@@ -175,5 +224,9 @@ module Prefab
|
|
175
224
|
super
|
176
225
|
end
|
177
226
|
end
|
227
|
+
|
228
|
+
def id
|
229
|
+
@id
|
230
|
+
end
|
178
231
|
end
|
179
232
|
end
|
data/lib/prefab/evaluation.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Prefab
|
4
4
|
# Records the result of evaluating a config's criteria and forensics for reporting
|
5
5
|
class Evaluation
|
6
|
-
attr_reader :value
|
6
|
+
attr_reader :value, :context
|
7
7
|
|
8
8
|
def initialize(config:, value:, value_index:, config_row_index:, context:, resolver:)
|
9
9
|
@config = config
|
@@ -32,6 +32,7 @@ module Prefab
|
|
32
32
|
|
33
33
|
def report(evaluation_summary_aggregator)
|
34
34
|
return if @config.config_type == :LOG_LEVEL
|
35
|
+
|
35
36
|
evaluation_summary_aggregator&.record(
|
36
37
|
config_key: @config.key,
|
37
38
|
config_type: @config.config_type,
|
data/lib/prefab/options.rb
CHANGED
@@ -15,7 +15,7 @@ module Prefab
|
|
15
15
|
attr_reader :collect_sync_interval
|
16
16
|
attr_reader :use_local_cache
|
17
17
|
attr_reader :datafile
|
18
|
-
attr_reader :
|
18
|
+
attr_reader :global_context
|
19
19
|
attr_accessor :is_fork
|
20
20
|
|
21
21
|
module ON_INITIALIZATION_FAILURE
|
@@ -59,7 +59,7 @@ module Prefab
|
|
59
59
|
allow_telemetry_in_local_mode: false,
|
60
60
|
x_datafile: ENV['PREFAB_DATAFILE'],
|
61
61
|
x_use_local_cache: false,
|
62
|
-
|
62
|
+
global_context: {}
|
63
63
|
)
|
64
64
|
@api_key = api_key
|
65
65
|
@namespace = namespace
|
@@ -79,8 +79,8 @@ module Prefab
|
|
79
79
|
@collect_max_evaluation_summaries = collect_max_evaluation_summaries
|
80
80
|
@allow_telemetry_in_local_mode = allow_telemetry_in_local_mode
|
81
81
|
@use_local_cache = x_use_local_cache
|
82
|
-
@disable_action_controller_logging = disable_action_controller_logging
|
83
82
|
@is_fork = false
|
83
|
+
@global_context = global_context
|
84
84
|
|
85
85
|
# defaults that may be overridden by context_upload_mode
|
86
86
|
@collect_shapes = false
|
@@ -94,6 +94,8 @@ module Prefab
|
|
94
94
|
when :periodic_example
|
95
95
|
@collect_example_contexts = true
|
96
96
|
@collect_max_example_contexts = context_max_size
|
97
|
+
@collect_shapes = true
|
98
|
+
@collect_max_shapes = context_max_size
|
97
99
|
when :shape_only
|
98
100
|
@collect_shapes = true
|
99
101
|
@collect_max_shapes = context_max_size
|
data/lib/prefab-cloud-ruby.rb
CHANGED
@@ -45,7 +45,6 @@ require 'prefab/context'
|
|
45
45
|
require 'prefab/logger_client'
|
46
46
|
require 'active_support/deprecation'
|
47
47
|
require 'active_support'
|
48
|
-
require 'action_controller/metal/strong_parameters'
|
49
48
|
require 'prefab/client'
|
50
49
|
require 'prefab/config_client_presenter'
|
51
50
|
require 'prefab/config_client'
|
data/prefab-cloud-ruby.gemspec
CHANGED
@@ -2,19 +2,18 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: prefab-cloud-ruby 1.6.
|
5
|
+
# stub: prefab-cloud-ruby 1.6.1 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "prefab-cloud-ruby".freeze
|
9
|
-
s.version = "1.6.
|
9
|
+
s.version = "1.6.1"
|
10
10
|
|
11
|
-
s.required_rubygems_version = Gem::Requirement.new("
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Jeff Dwyer".freeze]
|
14
|
-
s.date = "2024-
|
14
|
+
s.date = "2024-03-28"
|
15
15
|
s.description = "Feature Flags, Live Config, and Dynamic Log Levels as a service".freeze
|
16
16
|
s.email = "jdwyer@prefab.cloud".freeze
|
17
|
-
s.executables = ["console".freeze]
|
18
17
|
s.extra_rdoc_files = [
|
19
18
|
"CHANGELOG.md",
|
20
19
|
"LICENSE.txt",
|
@@ -34,8 +33,10 @@ Gem::Specification.new do |s|
|
|
34
33
|
"README.md",
|
35
34
|
"Rakefile",
|
36
35
|
"VERSION",
|
37
|
-
"bin/console",
|
38
36
|
"compile_protos.sh",
|
37
|
+
"dev/allocation_stats",
|
38
|
+
"dev/benchmark",
|
39
|
+
"dev/console",
|
39
40
|
"lib/prefab-cloud-ruby.rb",
|
40
41
|
"lib/prefab/client.rb",
|
41
42
|
"lib/prefab/config_client.rb",
|
@@ -129,7 +130,6 @@ Gem::Specification.new do |s|
|
|
129
130
|
s.add_runtime_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
130
131
|
s.add_runtime_dependency(%q<uuid>.freeze, [">= 0"])
|
131
132
|
s.add_runtime_dependency(%q<activesupport>.freeze, [">= 4"])
|
132
|
-
s.add_runtime_dependency(%q<actionpack>.freeze, [">= 4"])
|
133
133
|
s.add_runtime_dependency(%q<semantic_logger>.freeze, [">= 0"])
|
134
134
|
s.add_development_dependency(%q<benchmark-ips>.freeze, [">= 0"])
|
135
135
|
s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
|
@@ -144,7 +144,6 @@ Gem::Specification.new do |s|
|
|
144
144
|
s.add_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
145
145
|
s.add_dependency(%q<uuid>.freeze, [">= 0"])
|
146
146
|
s.add_dependency(%q<activesupport>.freeze, [">= 4"])
|
147
|
-
s.add_dependency(%q<actionpack>.freeze, [">= 4"])
|
148
147
|
s.add_dependency(%q<semantic_logger>.freeze, [">= 0"])
|
149
148
|
s.add_dependency(%q<benchmark-ips>.freeze, [">= 0"])
|
150
149
|
s.add_dependency(%q<bundler>.freeze, [">= 0"])
|
@@ -6,12 +6,24 @@ module CommonHelpers
|
|
6
6
|
def setup
|
7
7
|
$oldstderr, $stderr = $stderr, StringIO.new
|
8
8
|
|
9
|
-
$logs
|
10
|
-
SemanticLogger.add_appender(io: $logs)
|
9
|
+
$logs = StringIO.new
|
10
|
+
SemanticLogger.add_appender(io: $logs, filter: Prefab.log_filter)
|
11
|
+
SemanticLogger.sync!
|
11
12
|
Timecop.freeze('2023-08-09 15:18:12 -0400')
|
12
13
|
end
|
13
14
|
|
14
15
|
def teardown
|
16
|
+
if $logs && !$logs.string.empty?
|
17
|
+
log_lines = $logs.string.split("\n").reject do |line|
|
18
|
+
line.match(/Prefab::ConfigClient -- No success loading checkpoints/)
|
19
|
+
end
|
20
|
+
|
21
|
+
if log_lines.size > 0
|
22
|
+
$logs = nil
|
23
|
+
raise "Unexpected logs. Handle logs with assert_logged\n\n#{log_lines}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
15
27
|
if $stderr != $oldstderr && !$stderr.string.empty?
|
16
28
|
# we ignore 2.X because of the number of `instance variable @xyz not initialized` warnings
|
17
29
|
if !RUBY_VERSION.start_with?('2.')
|
@@ -41,7 +53,6 @@ module CommonHelpers
|
|
41
53
|
}.freeze
|
42
54
|
|
43
55
|
def new_client(overrides = {})
|
44
|
-
|
45
56
|
config = overrides.delete(:config)
|
46
57
|
project_env_id = overrides.delete(:project_env_id)
|
47
58
|
|
@@ -140,12 +151,6 @@ module CommonHelpers
|
|
140
151
|
Prefab::Context.new(properties)
|
141
152
|
end
|
142
153
|
|
143
|
-
def assert_only_expected_logs
|
144
|
-
# assert_equal "WARN 2023-08-09 15:18:12 -0400: cloud.prefab.client.configclient No success loading checkpoints\n", $logs.string
|
145
|
-
# mark nil to indicate we handled it
|
146
|
-
$logs = nil
|
147
|
-
end
|
148
|
-
|
149
154
|
def assert_logged(expected)
|
150
155
|
# we do a uniq here because logging can happen in a separate thread so the
|
151
156
|
# number of times a log might happen could be slightly variable.
|
@@ -159,6 +164,8 @@ module CommonHelpers
|
|
159
164
|
|
160
165
|
assert(matched, "expectation: #{expectation}, got: #{actuals}")
|
161
166
|
end
|
167
|
+
# mark nil to indicate we handled it
|
168
|
+
$logs = nil
|
162
169
|
end
|
163
170
|
|
164
171
|
def assert_stderr(expected)
|
@@ -173,7 +180,7 @@ module CommonHelpers
|
|
173
180
|
return
|
174
181
|
end
|
175
182
|
|
176
|
-
assert_equal expected, $stderr.string.split("\n")
|
183
|
+
assert_equal expected.uniq, $stderr.string.split("\n").uniq
|
177
184
|
|
178
185
|
# restore since we've handled it
|
179
186
|
$stderr = $oldstderr
|
@@ -408,6 +408,47 @@ class TestConfigResolver < Minitest::Test
|
|
408
408
|
end
|
409
409
|
end
|
410
410
|
|
411
|
+
def test_context_lookup
|
412
|
+
global_context = { cpu: { count: 4, speed: '2.4GHz' }, clock: { timezone: 'UTC' } }
|
413
|
+
default_context = { 'prefab-api-key' => { 'user-id' => 123 } }
|
414
|
+
local_context = { clock: { timezone: 'PST' }, user: { name: 'Ted', email: 'ted@example.com' } }
|
415
|
+
jit_context = { user: { name: 'Frank' } }
|
416
|
+
|
417
|
+
config = PrefabProto::Config.new( key: 'example', rows: [ PrefabProto::ConfigRow.new( values: [ PrefabProto::ConditionalValue.new( value: PrefabProto::ConfigValue.new(string: 'valueB2')) ]) ])
|
418
|
+
|
419
|
+
client = new_client(global_context: global_context, config: [config])
|
420
|
+
|
421
|
+
# we fake getting the default context from the API
|
422
|
+
Prefab::Context.default_context = default_context
|
423
|
+
|
424
|
+
resolver = client.resolver
|
425
|
+
|
426
|
+
client.with_context(local_context) do
|
427
|
+
context = resolver.get("example", jit_context).context
|
428
|
+
|
429
|
+
# This digs all the way to the global context
|
430
|
+
assert_equal 4, context.get('cpu.count')
|
431
|
+
assert_equal '2.4GHz', context.get('cpu.speed')
|
432
|
+
|
433
|
+
# This digs to the default context
|
434
|
+
assert_equal 123, context.get('prefab-api-key.user-id')
|
435
|
+
|
436
|
+
# This digs to the local context
|
437
|
+
assert_equal 'PST', context.get('clock.timezone')
|
438
|
+
|
439
|
+
# This uses the jit context
|
440
|
+
assert_equal 'Frank', context.get('user.name')
|
441
|
+
|
442
|
+
# This is nil in the jit context because `user` was clobbered
|
443
|
+
assert_nil context.get('user.email')
|
444
|
+
|
445
|
+
context = resolver.get("example").context
|
446
|
+
|
447
|
+
# But without the JIT clobbering, it is still set
|
448
|
+
assert_equal 'ted@example.com', context.get('user.email')
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
411
452
|
private
|
412
453
|
|
413
454
|
def resolver_for_namespace(namespace, loader, project_env_id: TEST_ENV_ID)
|
data/test/test_context.rb
CHANGED
@@ -15,33 +15,17 @@ class TestContext < Minitest::Test
|
|
15
15
|
assert_empty context.contexts
|
16
16
|
end
|
17
17
|
|
18
|
-
def test_initialize_with_named_context
|
19
|
-
named_context = Prefab::Context::NamedContext.new('test', foo: 'bar')
|
20
|
-
context = Prefab::Context.new(named_context)
|
21
|
-
assert_equal 1, context.contexts.size
|
22
|
-
assert_equal named_context, context.contexts['test']
|
23
|
-
end
|
24
|
-
|
25
18
|
def test_initialize_with_hash
|
26
19
|
context = Prefab::Context.new(test: { foo: 'bar' })
|
27
20
|
assert_equal 1, context.contexts.size
|
28
|
-
assert_equal 'bar', context.
|
21
|
+
assert_equal 'bar', context.get("test.foo")
|
29
22
|
end
|
30
23
|
|
31
24
|
def test_initialize_with_multiple_hashes
|
32
25
|
context = Prefab::Context.new(test: { foo: 'bar' }, other: { foo: 'baz' })
|
33
26
|
assert_equal 2, context.contexts.size
|
34
|
-
assert_equal 'bar', context.
|
35
|
-
assert_equal 'baz', context.
|
36
|
-
end
|
37
|
-
|
38
|
-
def test_initialize_with_invalid_hash
|
39
|
-
_, err = capture_io do
|
40
|
-
Prefab::Context.new({ foo: 'bar', baz: 'qux' })
|
41
|
-
end
|
42
|
-
|
43
|
-
assert_match '[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash',
|
44
|
-
err
|
27
|
+
assert_equal 'bar', context.get("test.foo")
|
28
|
+
assert_equal 'baz', context.get("other.foo")
|
45
29
|
end
|
46
30
|
|
47
31
|
def test_initialize_with_invalid_argument
|
@@ -56,33 +40,11 @@ class TestContext < Minitest::Test
|
|
56
40
|
|
57
41
|
def test_current_set
|
58
42
|
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
59
|
-
Prefab::Context.current = context
|
43
|
+
Prefab::Context.current = context.to_h
|
60
44
|
assert_instance_of Prefab::Context, context
|
61
45
|
assert_equal stringify(EXAMPLE_PROPERTIES), context.to_h
|
62
46
|
end
|
63
47
|
|
64
|
-
def test_merge_with_current
|
65
|
-
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
66
|
-
Prefab::Context.current = context
|
67
|
-
assert_equal stringify(EXAMPLE_PROPERTIES), context.to_h
|
68
|
-
|
69
|
-
new_context = Prefab::Context.merge_with_current({ user: { key: 'brand-new', other: 'different' },
|
70
|
-
address: { city: 'New York' } })
|
71
|
-
assert_equal stringify({
|
72
|
-
# Note that the user's `name` from the original
|
73
|
-
# context is not included. This is because we don't _merge_ the new
|
74
|
-
# properties if they collide with an existing context name. We _replace_
|
75
|
-
# them.
|
76
|
-
user: { key: 'brand-new', other: 'different' },
|
77
|
-
team: EXAMPLE_PROPERTIES[:team],
|
78
|
-
address: { city: 'New York' }
|
79
|
-
}),
|
80
|
-
new_context.to_h
|
81
|
-
|
82
|
-
# the original/current context is unchanged
|
83
|
-
assert_equal stringify(EXAMPLE_PROPERTIES), Prefab::Context.current.to_h
|
84
|
-
end
|
85
|
-
|
86
48
|
def test_with_context
|
87
49
|
Prefab::Context.with_context(EXAMPLE_PROPERTIES) do
|
88
50
|
context = Prefab::Context.current
|
@@ -105,9 +67,14 @@ class TestContext < Minitest::Test
|
|
105
67
|
|
106
68
|
def test_with_context_merge_nesting
|
107
69
|
Prefab::Context.with_context(EXAMPLE_PROPERTIES) do
|
108
|
-
Prefab::Context.with_merged_context({ user: { key: '
|
70
|
+
Prefab::Context.with_merged_context({ user: { key: 'hij', other: 'different' } }) do
|
109
71
|
context = Prefab::Context.current
|
110
|
-
|
72
|
+
assert_nil context.get('user.name')
|
73
|
+
assert_equal context.get('user.key'), 'hij'
|
74
|
+
assert_equal context.get('user.other'), 'different'
|
75
|
+
|
76
|
+
assert_equal context.get('team.key'), 'abc'
|
77
|
+
assert_equal context.get('team.plan'), 'pro'
|
111
78
|
end
|
112
79
|
|
113
80
|
context = Prefab::Context.current
|
@@ -187,6 +154,35 @@ class TestContext < Minitest::Test
|
|
187
154
|
), contexts.to_proto(namespace)
|
188
155
|
end
|
189
156
|
|
157
|
+
def test_parent_lookup
|
158
|
+
global_context = { cpu: { count: 4, speed: '2.4GHz' }, clock: { timezone: 'UTC' } }
|
159
|
+
default_context = { 'prefab-api-key' => { 'user-id' => 123 } }
|
160
|
+
local_context = { clock: { timezone: 'PST' }, user: { name: 'Ted', email: 'ted@example.com' } }
|
161
|
+
jit_context = { user: { name: 'Frank' } }
|
162
|
+
|
163
|
+
Prefab::Context.global_context = global_context
|
164
|
+
Prefab::Context.default_context = default_context
|
165
|
+
Prefab::Context.current = local_context
|
166
|
+
|
167
|
+
context = Prefab::Context.join(parent: Prefab::Context.current, hash: jit_context, id: :jit)
|
168
|
+
|
169
|
+
# This digs all the way to the global context
|
170
|
+
assert_equal 4, context.get('cpu.count')
|
171
|
+
assert_equal '2.4GHz', context.get('cpu.speed')
|
172
|
+
|
173
|
+
# This digs to the default context
|
174
|
+
assert_equal 123, context.get('prefab-api-key.user-id')
|
175
|
+
|
176
|
+
# This digs to the local context
|
177
|
+
assert_equal 'PST', context.get('clock.timezone')
|
178
|
+
|
179
|
+
# This uses the jit context
|
180
|
+
assert_equal 'Frank', context.get('user.name')
|
181
|
+
|
182
|
+
# This is nil in the jit context because `user` was clobbered
|
183
|
+
assert_nil context.get('user.email')
|
184
|
+
end
|
185
|
+
|
190
186
|
private
|
191
187
|
|
192
188
|
def stringify(hash)
|
@@ -10,10 +10,7 @@ class TestExampleContextsAggregator < Minitest::Test
|
|
10
10
|
aggregator = Prefab::ExampleContextsAggregator.new(client: MockBaseClient.new, max_contexts: 2,
|
11
11
|
sync_interval: EFFECTIVELY_NEVER)
|
12
12
|
|
13
|
-
context = Prefab::Context.new(
|
14
|
-
user: { key: 'abc' },
|
15
|
-
device: { key: 'def', mobile: true }
|
16
|
-
)
|
13
|
+
context = Prefab::Context.new(user: { key: 'abc' }, device: { key: 'def', mobile: true })
|
17
14
|
|
18
15
|
aggregator.record(context)
|
19
16
|
assert_equal [context], aggregator.data
|
data/test/test_helper.rb
CHANGED
data/test/test_integration.rb
CHANGED
@@ -50,6 +50,12 @@ class TestIntegration < Minitest::Test
|
|
50
50
|
else
|
51
51
|
raise "Unknown test type: #{it.test_type}"
|
52
52
|
end
|
53
|
+
|
54
|
+
if test_case["name"].match(/doesn't raise on init timeout/)
|
55
|
+
assert_logged [
|
56
|
+
"Prefab::ConfigClient -- Couldn't Initialize In 0.01. Key any-key. Returning what we have"
|
57
|
+
]
|
58
|
+
end
|
53
59
|
end
|
54
60
|
end
|
55
61
|
end
|
@@ -8,7 +8,7 @@ class TestLogPathAggregator < Minitest::Test
|
|
8
8
|
SLEEP_TIME = 0.01
|
9
9
|
|
10
10
|
def test_push
|
11
|
-
client = new_client
|
11
|
+
client = new_client(prefab_datasources: Prefab::Options::DATASOURCES::ALL,)
|
12
12
|
aggregator = Prefab::LogPathAggregator.new(client: client, max_paths: 2, sync_interval: 1000)
|
13
13
|
|
14
14
|
aggregator.push('test.test_log_path_aggregator.test_push.1', ::Logger::INFO)
|
@@ -19,16 +19,14 @@ class TestLogPathAggregator < Minitest::Test
|
|
19
19
|
# we've reached the limit, so no more
|
20
20
|
aggregator.push('test.test_log_path_aggregator.test_push.3', ::Logger::INFO)
|
21
21
|
assert_equal 2, aggregator.data.size
|
22
|
-
|
23
|
-
assert_only_expected_logs
|
24
22
|
end
|
25
23
|
|
26
24
|
def test_sync
|
27
25
|
Timecop.freeze do
|
28
26
|
client = new_client(namespace: 'this.is.a.namespace', allow_telemetry_in_local_mode: true)
|
29
27
|
|
30
|
-
2.times { client.log.should_log? 1, "test.test_log_path_aggregator.test_sync"}
|
31
|
-
3.times { client.log.should_log? 3, "test.test_log_path_aggregator.test_sync"}
|
28
|
+
2.times { client.log.should_log? 1, "test.test_log_path_aggregator.test_sync" }
|
29
|
+
3.times { client.log.should_log? 3, "test.test_log_path_aggregator.test_sync" }
|
32
30
|
|
33
31
|
requests = wait_for_post_requests(client) do
|
34
32
|
client.log_path_aggregator.send(:sync)
|
@@ -40,7 +38,9 @@ class TestLogPathAggregator < Minitest::Test
|
|
40
38
|
assert_equal Prefab::TimeHelpers.now_in_ms, sent_logger.start_at
|
41
39
|
assert_equal Prefab::TimeHelpers.now_in_ms, sent_logger.end_at
|
42
40
|
assert_equal client.instance_hash, sent_logger.instance_hash
|
43
|
-
assert_includes sent_logger.loggers,
|
41
|
+
assert_includes sent_logger.loggers,
|
42
|
+
PrefabProto::Logger.new(logger_name: 'test.test_log_path_aggregator.test_sync', infos: 2,
|
43
|
+
errors: 3)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|