prefab-cloud-ruby 0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.ruby-version +1 -0
- data/Gemfile +9 -22
- data/Gemfile.lock +88 -160
- data/LICENSE.txt +1 -1
- data/Rakefile +14 -14
- data/VERSION +1 -1
- data/lib/prefab/auth_interceptor.rb +25 -0
- data/lib/prefab/client.rb +34 -139
- data/lib/prefab/config_client.rb +23 -275
- data/lib/prefab/config_loader.rb +27 -60
- data/lib/prefab/config_resolver.rb +40 -53
- data/lib/prefab/noop_cache.rb +13 -0
- data/lib/prefab/noop_stats.rb +8 -0
- data/lib/prefab/prefab_pb.rb +39 -0
- data/lib/prefab/prefab_services_pb.rb +37 -0
- data/lib/prefab/ratelimit_client.rb +58 -0
- data/lib/prefab/ratelimit_pb.rb +125 -0
- data/lib/prefab/store.rb +29 -0
- data/lib/prefab_client.rb +35 -0
- metadata +36 -198
- data/.envrc.sample +0 -3
- data/.github/workflows/ruby.yml +0 -46
- data/.gitmodules +0 -3
- data/.rubocop.yml +0 -13
- data/.tool-versions +0 -1
- data/CHANGELOG.md +0 -169
- data/CODEOWNERS +0 -1
- data/README.md +0 -94
- data/bin/console +0 -21
- data/compile_protos.sh +0 -18
- data/lib/prefab/config_client_presenter.rb +0 -18
- data/lib/prefab/config_value_unwrapper.rb +0 -115
- data/lib/prefab/config_value_wrapper.rb +0 -18
- data/lib/prefab/context.rb +0 -179
- data/lib/prefab/context_shape.rb +0 -20
- data/lib/prefab/context_shape_aggregator.rb +0 -65
- data/lib/prefab/criteria_evaluator.rb +0 -136
- data/lib/prefab/encryption.rb +0 -65
- data/lib/prefab/error.rb +0 -6
- data/lib/prefab/errors/env_var_parse_error.rb +0 -11
- data/lib/prefab/errors/initialization_timeout_error.rb +0 -13
- data/lib/prefab/errors/invalid_api_key_error.rb +0 -19
- data/lib/prefab/errors/missing_default_error.rb +0 -13
- data/lib/prefab/errors/missing_env_var_error.rb +0 -11
- data/lib/prefab/errors/uninitialized_error.rb +0 -13
- data/lib/prefab/evaluation.rb +0 -52
- data/lib/prefab/evaluation_summary_aggregator.rb +0 -87
- data/lib/prefab/example_contexts_aggregator.rb +0 -78
- data/lib/prefab/exponential_backoff.rb +0 -21
- data/lib/prefab/feature_flag_client.rb +0 -42
- data/lib/prefab/http_connection.rb +0 -41
- data/lib/prefab/internal_logger.rb +0 -16
- data/lib/prefab/local_config_parser.rb +0 -151
- data/lib/prefab/log_path_aggregator.rb +0 -69
- data/lib/prefab/logger_client.rb +0 -264
- data/lib/prefab/murmer3.rb +0 -50
- data/lib/prefab/options.rb +0 -208
- data/lib/prefab/periodic_sync.rb +0 -69
- data/lib/prefab/prefab.rb +0 -56
- data/lib/prefab/rate_limit_cache.rb +0 -41
- data/lib/prefab/resolved_config_presenter.rb +0 -86
- data/lib/prefab/time_helpers.rb +0 -7
- data/lib/prefab/weighted_value_resolver.rb +0 -42
- data/lib/prefab/yaml_config_parser.rb +0 -34
- data/lib/prefab-cloud-ruby.rb +0 -57
- data/lib/prefab_pb.rb +0 -93
- data/prefab-cloud-ruby.gemspec +0 -155
- data/test/.prefab.default.config.yaml +0 -2
- data/test/.prefab.unit_tests.config.yaml +0 -28
- data/test/integration_test.rb +0 -150
- data/test/integration_test_helpers.rb +0 -151
- data/test/support/common_helpers.rb +0 -180
- data/test/support/mock_base_client.rb +0 -42
- data/test/support/mock_config_client.rb +0 -19
- data/test/support/mock_config_loader.rb +0 -1
- data/test/test_client.rb +0 -444
- data/test/test_config_client.rb +0 -109
- data/test/test_config_loader.rb +0 -117
- data/test/test_config_resolver.rb +0 -430
- data/test/test_config_value_unwrapper.rb +0 -224
- data/test/test_config_value_wrapper.rb +0 -42
- data/test/test_context.rb +0 -203
- data/test/test_context_shape.rb +0 -50
- data/test/test_context_shape_aggregator.rb +0 -147
- data/test/test_criteria_evaluator.rb +0 -726
- data/test/test_encryption.rb +0 -16
- data/test/test_evaluation_summary_aggregator.rb +0 -162
- data/test/test_example_contexts_aggregator.rb +0 -238
- data/test/test_exponential_backoff.rb +0 -18
- data/test/test_feature_flag_client.rb +0 -48
- data/test/test_helper.rb +0 -17
- data/test/test_integration.rb +0 -58
- data/test/test_local_config_parser.rb +0 -147
- data/test/test_log_path_aggregator.rb +0 -62
- data/test/test_logger.rb +0 -621
- data/test/test_logger_initialization.rb +0 -12
- data/test/test_options.rb +0 -75
- data/test/test_prefab.rb +0 -12
- data/test/test_rate_limit_cache.rb +0 -44
- 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
|