quonfig 0.0.9 → 0.0.11
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/CHANGELOG.md +43 -0
- data/README.md +4 -4
- data/lib/quonfig/evaluation_details.rb +60 -0
- data/lib/quonfig/options.rb +37 -16
- data/lib/quonfig/sse_config_client.rb +1 -1
- data/lib/quonfig/version.rb +5 -0
- data/lib/quonfig.rb +2 -1
- data/quonfig.gemspec +30 -163
- metadata +29 -182
- data/.claude/rules/constitution.md +0 -81
- data/.claude/rules/git-safety.md +0 -11
- data/.claude/rules/issue-tracking.md +0 -13
- data/.claude/rules/testing-workflow.md +0 -28
- data/.envrc.sample +0 -3
- data/.github/CODEOWNERS +0 -2
- data/.github/pull_request_template.md +0 -8
- data/.github/workflows/release.yml +0 -49
- data/.github/workflows/ruby.yml +0 -60
- data/.github/workflows/test.yaml +0 -40
- data/.rubocop.yml +0 -13
- data/.tool-versions +0 -1
- data/CLAUDE.md +0 -29
- data/CODEOWNERS +0 -1
- data/Gemfile +0 -26
- data/Gemfile.lock +0 -177
- data/Rakefile +0 -64
- data/VERSION +0 -1
- data/dev/allocation_stats +0 -60
- data/dev/benchmark +0 -40
- data/dev/console +0 -12
- data/dev/script_setup.rb +0 -18
- data/test/fixtures/datafile.json +0 -87
- data/test/integration/test_context_precedence.rb +0 -112
- data/test/integration/test_datadir_environment.rb +0 -54
- data/test/integration/test_dev_overrides.rb +0 -40
- data/test/integration/test_enabled.rb +0 -478
- data/test/integration/test_enabled_with_contexts.rb +0 -64
- data/test/integration/test_get.rb +0 -136
- data/test/integration/test_get_feature_flag.rb +0 -28
- data/test/integration/test_get_or_raise.rb +0 -60
- data/test/integration/test_get_weighted_values.rb +0 -34
- data/test/integration/test_helpers.rb +0 -667
- data/test/integration/test_helpers_test.rb +0 -73
- data/test/integration/test_post.rb +0 -44
- data/test/integration/test_telemetry.rb +0 -170
- data/test/support/common_helpers.rb +0 -106
- data/test/support/mock_base_client.rb +0 -27
- data/test/support/mock_config_loader.rb +0 -1
- data/test/test_bound_client.rb +0 -109
- data/test/test_caching_http_connection.rb +0 -218
- data/test/test_client.rb +0 -255
- data/test/test_client_network_mode.rb +0 -136
- data/test/test_client_telemetry.rb +0 -175
- data/test/test_config_loader.rb +0 -70
- data/test/test_context.rb +0 -139
- data/test/test_context_shape.rb +0 -37
- data/test/test_context_shape_aggregator.rb +0 -126
- data/test/test_datadir.rb +0 -203
- data/test/test_dev_context.rb +0 -163
- data/test/test_duration.rb +0 -37
- data/test/test_encryption.rb +0 -16
- data/test/test_evaluation_summaries_aggregator.rb +0 -180
- data/test/test_evaluator.rb +0 -285
- data/test/test_example_contexts_aggregator.rb +0 -119
- data/test/test_exponential_backoff.rb +0 -44
- data/test/test_fixed_size_hash.rb +0 -119
- data/test/test_helper.rb +0 -17
- data/test/test_http_connection.rb +0 -79
- data/test/test_internal_logger.rb +0 -34
- data/test/test_options.rb +0 -167
- data/test/test_rate_limit_cache.rb +0 -44
- data/test/test_reason.rb +0 -79
- data/test/test_rename.rb +0 -65
- data/test/test_resolver.rb +0 -291
- data/test/test_semantic_logger_filter.rb +0 -144
- data/test/test_semver.rb +0 -108
- data/test/test_should_log.rb +0 -186
- data/test/test_sse_config_client.rb +0 -297
- data/test/test_stdlib_formatter.rb +0 -195
- data/test/test_telemetry_reporter.rb +0 -209
- data/test/test_typed_getters.rb +0 -131
- data/test/test_types.rb +0 -141
- data/test/test_weighted_value_resolver.rb +0 -84
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'test_helper'
|
|
4
|
-
require 'semantic_logger'
|
|
5
|
-
|
|
6
|
-
# Verifies the SemanticLoggerFilter: ONE Quonfig config gates many loggers.
|
|
7
|
-
# The filter injects the native SemanticLogger logger name under the
|
|
8
|
-
# `quonfig-sdk-logging` context (keyed at `.key`) so customer rules can target
|
|
9
|
-
# `PROP_STARTS_WITH_ONE_OF MyApp::` etc.
|
|
10
|
-
#
|
|
11
|
-
# Breaking change in 0.0.5: context key was renamed from `quonfig.logger-name`
|
|
12
|
-
# (dotted snake_case, flat) to `quonfig-sdk-logging.key` (nested, verbatim
|
|
13
|
-
# class name). Normalization was removed — logger names are passed through
|
|
14
|
-
# as-is.
|
|
15
|
-
class TestSemanticLoggerFilter < Minitest::Test
|
|
16
|
-
CONFIG_KEY = 'log-levels.my-app'
|
|
17
|
-
|
|
18
|
-
# FakeClient lets us assert the exact key + context the filter passes to
|
|
19
|
-
# the SDK without standing up a full datadir.
|
|
20
|
-
class FakeClient
|
|
21
|
-
attr_reader :calls
|
|
22
|
-
|
|
23
|
-
def initialize(level)
|
|
24
|
-
@level = level
|
|
25
|
-
@calls = []
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def get(key, default = nil, context = nil)
|
|
29
|
-
@calls << { key: key, default: default, context: context }
|
|
30
|
-
@level.nil? ? default : @level
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def make_log(name, level)
|
|
35
|
-
SemanticLogger::Log.new(name, level).tap { |log| log.level = level }
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def filter_for(level)
|
|
39
|
-
client = FakeClient.new(level)
|
|
40
|
-
[Quonfig::SemanticLoggerFilter.new(client, config_key: CONFIG_KEY), client]
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def test_calls_single_config_key_with_logger_name_in_context
|
|
44
|
-
filter, client = filter_for(:info)
|
|
45
|
-
filter.call(make_log('MyApp::Foo::Bar', :warn))
|
|
46
|
-
|
|
47
|
-
assert_equal 1, client.calls.size
|
|
48
|
-
assert_equal CONFIG_KEY, client.calls.first[:key]
|
|
49
|
-
ctx = client.calls.first[:context]
|
|
50
|
-
assert_equal({ 'quonfig-sdk-logging' => { 'key' => 'MyApp::Foo::Bar' } }, ctx)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def test_passes_through_when_level_meets_configured_minimum
|
|
54
|
-
filter, _ = filter_for(:info)
|
|
55
|
-
|
|
56
|
-
assert_equal true, filter.call(make_log('Anything', :info))
|
|
57
|
-
assert_equal true, filter.call(make_log('Anything', :warn))
|
|
58
|
-
assert_equal true, filter.call(make_log('Anything', :error))
|
|
59
|
-
assert_equal true, filter.call(make_log('Anything', :fatal))
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def test_suppresses_below_configured_minimum
|
|
63
|
-
filter, _ = filter_for(:warn)
|
|
64
|
-
|
|
65
|
-
assert_equal false, filter.call(make_log('Anything', :trace))
|
|
66
|
-
assert_equal false, filter.call(make_log('Anything', :debug))
|
|
67
|
-
assert_equal false, filter.call(make_log('Anything', :info))
|
|
68
|
-
assert_equal true, filter.call(make_log('Anything', :warn))
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def test_missing_key_falls_through_to_semantic_logger_default
|
|
72
|
-
filter, _ = filter_for(nil) # FakeClient returns the default (nil) when configured level is nil
|
|
73
|
-
|
|
74
|
-
assert_equal true, filter.call(make_log('Anything', :trace))
|
|
75
|
-
assert_equal true, filter.call(make_log('Anything', :debug))
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def test_logger_name_passed_through_verbatim
|
|
79
|
-
# Normalization is gone. Native Ruby class names are preserved as-is,
|
|
80
|
-
# which matches how sdk-node and sdk-go pass the logger path.
|
|
81
|
-
filter, client = filter_for(:debug)
|
|
82
|
-
|
|
83
|
-
[
|
|
84
|
-
'MyApp::Foo::Bar',
|
|
85
|
-
'HTMLParser',
|
|
86
|
-
'foo',
|
|
87
|
-
'A::B::CDPath',
|
|
88
|
-
'MyApp::Services::Auth'
|
|
89
|
-
].each do |raw|
|
|
90
|
-
client.calls.clear
|
|
91
|
-
filter.call(make_log(raw, :info))
|
|
92
|
-
assert_equal raw, client.calls.first[:context]['quonfig-sdk-logging']['key'],
|
|
93
|
-
"logger name should be passed through verbatim: #{raw.inspect}"
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def test_no_dotted_path_traversal_or_get_log_level
|
|
98
|
-
# Verifies the legacy hierarchical walk is gone — the filter must NOT
|
|
99
|
-
# synthesize keys like "log-levels.my_app" or call any `get_log_level`.
|
|
100
|
-
refute Quonfig::SemanticLoggerFilter.instance_methods.include?(:get_log_level)
|
|
101
|
-
|
|
102
|
-
filter, client = filter_for(:info)
|
|
103
|
-
filter.call(make_log('MyApp::Foo::Bar', :info))
|
|
104
|
-
|
|
105
|
-
keys = client.calls.map { |c| c[:key] }
|
|
106
|
-
assert_equal [CONFIG_KEY], keys.uniq,
|
|
107
|
-
'Filter should call exactly the configured key, never derived per-logger keys'
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def test_normalize_method_is_gone
|
|
111
|
-
# The old normalize() method converted "MyApp::Foo" → "my_app.foo".
|
|
112
|
-
# It is intentionally removed so callers see native Ruby class names in
|
|
113
|
-
# context telemetry and rule matching.
|
|
114
|
-
refute Quonfig::SemanticLoggerFilter.instance_methods.include?(:normalize),
|
|
115
|
-
'normalize() should be removed — logger names are passed through as-is'
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def test_context_key_constant_is_new_shape
|
|
119
|
-
# Sanity check that the context key constant exposes the new shape.
|
|
120
|
-
assert_equal 'quonfig-sdk-logging', Quonfig::SemanticLoggerFilter::LOGGER_CONTEXT_NAME
|
|
121
|
-
assert_equal 'key', Quonfig::SemanticLoggerFilter::LOGGER_CONTEXT_KEY_PROP
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def test_all_six_levels_mapped_correctly
|
|
125
|
-
expected = { trace: 0, debug: 1, info: 2, warn: 3, error: 4, fatal: 5 }
|
|
126
|
-
assert_equal expected, Quonfig::SemanticLoggerFilter::LEVELS
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def test_string_level_from_config
|
|
130
|
-
filter, _ = filter_for('warn')
|
|
131
|
-
|
|
132
|
-
assert_equal false, filter.call(make_log('Anything', :info))
|
|
133
|
-
assert_equal true, filter.call(make_log('Anything', :warn))
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def test_raises_loaderror_when_semantic_logger_missing
|
|
137
|
-
Quonfig::SemanticLoggerFilter.stub(:semantic_logger_loaded?, false) do
|
|
138
|
-
err = assert_raises(LoadError) do
|
|
139
|
-
Quonfig::SemanticLoggerFilter.new(FakeClient.new(:info), config_key: CONFIG_KEY)
|
|
140
|
-
end
|
|
141
|
-
assert_match(/semantic_logger/i, err.message)
|
|
142
|
-
end
|
|
143
|
-
end
|
|
144
|
-
end
|
data/test/test_semver.rb
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
class TestSemanticVersion < Minitest::Test
|
|
3
|
-
def test_parse_valid_version
|
|
4
|
-
version = SemanticVersion.parse('1.2.3')
|
|
5
|
-
assert_equal 1, version.major
|
|
6
|
-
assert_equal 2, version.minor
|
|
7
|
-
assert_equal 3, version.patch
|
|
8
|
-
assert_nil version.prerelease
|
|
9
|
-
assert_nil version.build_metadata
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def test_parse_version_with_prerelease
|
|
13
|
-
version = SemanticVersion.parse('1.2.3-alpha.1')
|
|
14
|
-
assert_equal 1, version.major
|
|
15
|
-
assert_equal 2, version.minor
|
|
16
|
-
assert_equal 3, version.patch
|
|
17
|
-
assert_equal 'alpha.1', version.prerelease
|
|
18
|
-
assert_nil version.build_metadata
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def test_parse_version_with_build_metadata
|
|
22
|
-
version = SemanticVersion.parse('1.2.3+build.123')
|
|
23
|
-
assert_equal 1, version.major
|
|
24
|
-
assert_equal 2, version.minor
|
|
25
|
-
assert_equal 3, version.patch
|
|
26
|
-
assert_nil version.prerelease
|
|
27
|
-
assert_equal 'build.123', version.build_metadata
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def test_parse_full_version
|
|
31
|
-
version = SemanticVersion.parse('1.2.3-alpha.1+build.123')
|
|
32
|
-
assert_equal 1, version.major
|
|
33
|
-
assert_equal 2, version.minor
|
|
34
|
-
assert_equal 3, version.patch
|
|
35
|
-
assert_equal 'alpha.1', version.prerelease
|
|
36
|
-
assert_equal 'build.123', version.build_metadata
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def test_parse_invalid_version
|
|
40
|
-
assert_raises(ArgumentError) { SemanticVersion.parse('invalid') }
|
|
41
|
-
assert_raises(ArgumentError) { SemanticVersion.parse('1.2') }
|
|
42
|
-
assert_raises(ArgumentError) { SemanticVersion.parse('1.2.3.4') }
|
|
43
|
-
assert_raises(ArgumentError) { SemanticVersion.parse('') }
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def test_parse_quietly
|
|
47
|
-
assert_nil SemanticVersion.parse_quietly('invalid')
|
|
48
|
-
refute_nil SemanticVersion.parse_quietly('1.2.3')
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def test_to_string
|
|
52
|
-
assert_equal '1.2.3', SemanticVersion.parse('1.2.3').to_s
|
|
53
|
-
assert_equal '1.2.3-alpha.1', SemanticVersion.parse('1.2.3-alpha.1').to_s
|
|
54
|
-
assert_equal '1.2.3+build.123', SemanticVersion.parse('1.2.3+build.123').to_s
|
|
55
|
-
assert_equal '1.2.3-alpha.1+build.123', SemanticVersion.parse('1.2.3-alpha.1+build.123').to_s
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def test_equality
|
|
59
|
-
v1 = SemanticVersion.parse('1.2.3')
|
|
60
|
-
v2 = SemanticVersion.parse('1.2.3')
|
|
61
|
-
v3 = SemanticVersion.parse('1.2.4')
|
|
62
|
-
v4 = SemanticVersion.parse('1.2.3-alpha')
|
|
63
|
-
v5 = SemanticVersion.parse('1.2.3+build.123')
|
|
64
|
-
|
|
65
|
-
assert_equal v1, v2
|
|
66
|
-
refute_equal v1, v3
|
|
67
|
-
refute_equal v1, v4
|
|
68
|
-
assert_equal v1, v5 # build metadata is ignored in equality
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def test_comparison
|
|
72
|
-
versions = [
|
|
73
|
-
'1.0.0-alpha',
|
|
74
|
-
'1.0.0-alpha.1',
|
|
75
|
-
'1.0.0-beta.2',
|
|
76
|
-
'1.0.0-beta.11',
|
|
77
|
-
'1.0.0-rc.1',
|
|
78
|
-
'1.0.0',
|
|
79
|
-
'2.0.0',
|
|
80
|
-
'2.1.0',
|
|
81
|
-
'2.1.1'
|
|
82
|
-
].map { |v| SemanticVersion.parse(v) }
|
|
83
|
-
|
|
84
|
-
# Test that each version is less than the next version
|
|
85
|
-
(versions.length - 1).times do |i|
|
|
86
|
-
assert versions[i] < versions[i + 1], "Expected #{versions[i]} < #{versions[i + 1]}"
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def test_prerelease_comparison
|
|
91
|
-
# Test specific prerelease comparison cases
|
|
92
|
-
cases = [
|
|
93
|
-
['1.0.0-alpha', '1.0.0-alpha.1', -1],
|
|
94
|
-
['1.0.0-alpha.1', '1.0.0-alpha.beta', -1],
|
|
95
|
-
['1.0.0-alpha.beta', '1.0.0-beta', -1],
|
|
96
|
-
['1.0.0-beta', '1.0.0-beta.2', -1],
|
|
97
|
-
['1.0.0-beta.2', '1.0.0-beta.11', -1],
|
|
98
|
-
['1.0.0-beta.11', '1.0.0-rc.1', -1],
|
|
99
|
-
['1.0.0-rc.1', '1.0.0', -1]
|
|
100
|
-
]
|
|
101
|
-
|
|
102
|
-
cases.each do |v1_str, v2_str, expected|
|
|
103
|
-
v1 = SemanticVersion.parse(v1_str)
|
|
104
|
-
v2 = SemanticVersion.parse(v2_str)
|
|
105
|
-
assert_equal expected, (v1 <=> v2), "Expected #{v1} <=> #{v2} to be #{expected}"
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
data/test/test_should_log.rb
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'test_helper'
|
|
4
|
-
|
|
5
|
-
# Verifies the client-level should_log?(logger_path:, desired_level:, contexts:)
|
|
6
|
-
# API — a Reforge-style convenience built on top of the primitive get() that
|
|
7
|
-
# uses the client's `logger_key` option as the config key and injects the
|
|
8
|
-
# logger path under `quonfig-sdk-logging.key`. Parallels sdk-node's
|
|
9
|
-
# shouldLog({loggerPath}) and sdk-go's ShouldLogPath.
|
|
10
|
-
class TestShouldLog < Minitest::Test
|
|
11
|
-
LOG_LEVEL_KEY = 'log-level.my-app'
|
|
12
|
-
|
|
13
|
-
# Minimal config fixture mirroring what ConfigStore expects: a string
|
|
14
|
-
# config whose rule returns the configured log level.
|
|
15
|
-
def make_log_level_config(key:, level:)
|
|
16
|
-
{
|
|
17
|
-
'id' => '1',
|
|
18
|
-
'key' => key,
|
|
19
|
-
'type' => 'config',
|
|
20
|
-
'valueType' => 'string',
|
|
21
|
-
'sendToClientSdk' => false,
|
|
22
|
-
'default' => {
|
|
23
|
-
'rules' => [
|
|
24
|
-
{ 'criteria' => [{ 'operator' => 'ALWAYS_TRUE' }],
|
|
25
|
-
'value' => { 'type' => 'string', 'value' => level } }
|
|
26
|
-
]
|
|
27
|
-
},
|
|
28
|
-
'environment' => nil
|
|
29
|
-
}
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def store_with(*configs)
|
|
33
|
-
store = Quonfig::ConfigStore.new
|
|
34
|
-
configs.each { |c| store.set(c['key'], c) }
|
|
35
|
-
store
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def client_with(store, **options)
|
|
39
|
-
Quonfig::Client.new(Quonfig::Options.new(**options), store: store)
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# ---- logger_key option surface ---------------------------------------
|
|
43
|
-
|
|
44
|
-
def test_logger_key_option_defaults_to_nil
|
|
45
|
-
assert_nil Quonfig::Options.new.logger_key
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def test_logger_key_option_accepts_value
|
|
49
|
-
opts = Quonfig::Options.new(logger_key: LOG_LEVEL_KEY)
|
|
50
|
-
assert_equal LOG_LEVEL_KEY, opts.logger_key
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def test_client_exposes_logger_key_from_options
|
|
54
|
-
client = client_with(Quonfig::ConfigStore.new, logger_key: LOG_LEVEL_KEY)
|
|
55
|
-
assert_equal LOG_LEVEL_KEY, client.logger_key
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# ---- should_log? requires logger_key ---------------------------------
|
|
59
|
-
|
|
60
|
-
def test_should_log_raises_without_logger_key
|
|
61
|
-
client = client_with(Quonfig::ConfigStore.new)
|
|
62
|
-
err = assert_raises(Quonfig::Error) do
|
|
63
|
-
client.should_log?(logger_path: 'MyApp::Foo', desired_level: :info)
|
|
64
|
-
end
|
|
65
|
-
assert_match(/logger_key/, err.message)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# ---- should_log? gating ----------------------------------------------
|
|
69
|
-
|
|
70
|
-
def test_should_log_true_when_desired_at_or_above_configured
|
|
71
|
-
store = store_with(make_log_level_config(key: LOG_LEVEL_KEY, level: 'info'))
|
|
72
|
-
client = client_with(store, logger_key: LOG_LEVEL_KEY)
|
|
73
|
-
|
|
74
|
-
assert_equal true, client.should_log?(logger_path: 'MyApp::Foo', desired_level: :info)
|
|
75
|
-
assert_equal true, client.should_log?(logger_path: 'MyApp::Foo', desired_level: :warn)
|
|
76
|
-
assert_equal true, client.should_log?(logger_path: 'MyApp::Foo', desired_level: :error)
|
|
77
|
-
assert_equal true, client.should_log?(logger_path: 'MyApp::Foo', desired_level: :fatal)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def test_should_log_false_when_desired_below_configured
|
|
81
|
-
store = store_with(make_log_level_config(key: LOG_LEVEL_KEY, level: 'warn'))
|
|
82
|
-
client = client_with(store, logger_key: LOG_LEVEL_KEY)
|
|
83
|
-
|
|
84
|
-
assert_equal false, client.should_log?(logger_path: 'MyApp::Foo', desired_level: :trace)
|
|
85
|
-
assert_equal false, client.should_log?(logger_path: 'MyApp::Foo', desired_level: :debug)
|
|
86
|
-
assert_equal false, client.should_log?(logger_path: 'MyApp::Foo', desired_level: :info)
|
|
87
|
-
assert_equal true, client.should_log?(logger_path: 'MyApp::Foo', desired_level: :warn)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def test_should_log_accepts_string_desired_level
|
|
91
|
-
store = store_with(make_log_level_config(key: LOG_LEVEL_KEY, level: 'warn'))
|
|
92
|
-
client = client_with(store, logger_key: LOG_LEVEL_KEY)
|
|
93
|
-
|
|
94
|
-
assert_equal true, client.should_log?(logger_path: 'MyApp::Foo', desired_level: 'warn')
|
|
95
|
-
assert_equal false, client.should_log?(logger_path: 'MyApp::Foo', desired_level: 'info')
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def test_should_log_returns_true_when_no_config_found
|
|
99
|
-
# Missing config key → log everything (match go/node).
|
|
100
|
-
client = client_with(Quonfig::ConfigStore.new, logger_key: LOG_LEVEL_KEY)
|
|
101
|
-
assert_equal true, client.should_log?(logger_path: 'MyApp::Foo', desired_level: :trace)
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# ---- context injection -----------------------------------------------
|
|
105
|
-
|
|
106
|
-
# Capture what context reaches get() by injecting a spy client that wraps
|
|
107
|
-
# a real store-backed client.
|
|
108
|
-
class ContextCapturingClient
|
|
109
|
-
attr_reader :captured_contexts
|
|
110
|
-
|
|
111
|
-
def initialize(delegate)
|
|
112
|
-
@delegate = delegate
|
|
113
|
-
@captured_contexts = []
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def logger_key
|
|
117
|
-
@delegate.logger_key
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def get(key, default = Quonfig::NO_DEFAULT_PROVIDED, jit_context = Quonfig::NO_DEFAULT_PROVIDED)
|
|
121
|
-
@captured_contexts << jit_context
|
|
122
|
-
@delegate.get(key, default, jit_context)
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def test_should_log_injects_logger_path_under_quonfig_sdk_logging_key
|
|
127
|
-
store = store_with(make_log_level_config(key: LOG_LEVEL_KEY, level: 'trace'))
|
|
128
|
-
client = client_with(store, logger_key: LOG_LEVEL_KEY)
|
|
129
|
-
|
|
130
|
-
# Reach into the context that get() sees. We do this by asserting on the
|
|
131
|
-
# resolver via a fake — simplest path: call should_log? with a sentinel
|
|
132
|
-
# path and verify the evaluator would see it. We assert via the public
|
|
133
|
-
# contract: context reaches get(), so we patch get() temporarily.
|
|
134
|
-
captured = []
|
|
135
|
-
client.define_singleton_method(:get) do |key, default = nil, jit_context = nil|
|
|
136
|
-
captured << { key: key, jit_context: jit_context }
|
|
137
|
-
'trace'
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
client.should_log?(logger_path: 'MyApp::Services::Auth', desired_level: :info)
|
|
141
|
-
|
|
142
|
-
assert_equal 1, captured.size
|
|
143
|
-
assert_equal LOG_LEVEL_KEY, captured.first[:key]
|
|
144
|
-
ctx = captured.first[:jit_context]
|
|
145
|
-
assert_equal({ 'quonfig-sdk-logging' => { 'key' => 'MyApp::Services::Auth' } }, ctx)
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def test_should_log_merges_caller_contexts_with_logger_context
|
|
149
|
-
store = store_with(make_log_level_config(key: LOG_LEVEL_KEY, level: 'trace'))
|
|
150
|
-
client = client_with(store, logger_key: LOG_LEVEL_KEY)
|
|
151
|
-
|
|
152
|
-
captured = []
|
|
153
|
-
client.define_singleton_method(:get) do |key, default = nil, jit_context = nil|
|
|
154
|
-
captured << jit_context
|
|
155
|
-
'trace'
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
client.should_log?(
|
|
159
|
-
logger_path: 'MyApp::Foo',
|
|
160
|
-
desired_level: :info,
|
|
161
|
-
contexts: { 'user' => { 'id' => 'u1' } }
|
|
162
|
-
)
|
|
163
|
-
|
|
164
|
-
assert_equal(
|
|
165
|
-
{
|
|
166
|
-
'user' => { 'id' => 'u1' },
|
|
167
|
-
'quonfig-sdk-logging' => { 'key' => 'MyApp::Foo' }
|
|
168
|
-
},
|
|
169
|
-
captured.first
|
|
170
|
-
)
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
def test_should_log_logger_path_verbatim_no_normalization
|
|
174
|
-
store = store_with(make_log_level_config(key: LOG_LEVEL_KEY, level: 'trace'))
|
|
175
|
-
client = client_with(store, logger_key: LOG_LEVEL_KEY)
|
|
176
|
-
|
|
177
|
-
captured = []
|
|
178
|
-
client.define_singleton_method(:get) do |key, default = nil, jit_context = nil|
|
|
179
|
-
captured << jit_context
|
|
180
|
-
'trace'
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
client.should_log?(logger_path: 'HTMLParser', desired_level: :info)
|
|
184
|
-
assert_equal 'HTMLParser', captured.first['quonfig-sdk-logging']['key']
|
|
185
|
-
end
|
|
186
|
-
end
|