prefab-cloud-ruby 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +21 -0
- data/LICENSE.txt +1 -1
- data/VERSION +1 -1
- data/lib/prefab/client.rb +4 -0
- data/lib/prefab/config_client.rb +20 -1
- data/lib/prefab/config_loader.rb +2 -0
- data/lib/prefab/config_value_unwrapper.rb +93 -15
- data/lib/prefab/config_value_wrapper.rb +6 -6
- data/lib/prefab/criteria_evaluator.rb +4 -3
- data/lib/prefab/encryption.rb +65 -0
- data/lib/prefab/errors/env_var_parse_error.rb +11 -0
- data/lib/prefab/evaluation.rb +8 -4
- data/lib/prefab/internal_logger.rb +6 -23
- data/lib/prefab/local_config_parser.rb +58 -2
- data/lib/prefab/log_subscribers/action_controller_subscriber.rb +54 -0
- data/lib/prefab/logger_client.rb +0 -7
- data/lib/prefab/options.rb +11 -1
- data/lib/prefab/resolved_config_presenter.rb +2 -2
- data/lib/prefab/sse_logger.rb +4 -20
- data/lib/prefab/static_logger.rb +29 -0
- data/lib/prefab-cloud-ruby.rb +6 -0
- data/prefab-cloud-ruby.gemspec +11 -3
- data/test/test_action_controller.rb +52 -0
- data/test/test_config_value_unwrapper.rb +167 -20
- data/test/test_context_shape.rb +0 -1
- data/test/test_encryption.rb +16 -0
- data/test/test_local_config_parser.rb +73 -2
- data/test/test_logger.rb +5 -5
- metadata +22 -2
@@ -0,0 +1,54 @@
|
|
1
|
+
# Modified from https://github.com/reidmorrison/rails_semantic_logger/blob/master/lib/rails_semantic_logger/action_controller/log_subscriber.rb
|
2
|
+
#
|
3
|
+
# Copyright 2012, 2013, 2014, 2015 Reid Morrison
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
#
|
17
|
+
module Prefab
|
18
|
+
module LogSubscribers
|
19
|
+
class ActionControllerSubscriber < ActiveSupport::LogSubscriber
|
20
|
+
|
21
|
+
INTERNAL_PARAMS = %w[controller action format _method only_path].freeze
|
22
|
+
|
23
|
+
LOG = Prefab::StaticLogger.new("rails.controller.request")
|
24
|
+
|
25
|
+
# With great debt to https://github.com/reidmorrison/rails_semantic_logger/blob/master/lib/rails_semantic_logger/action_controller/log_subscriber.rb
|
26
|
+
def process_action(event)
|
27
|
+
payload = event.payload.dup
|
28
|
+
payload.delete(:headers)
|
29
|
+
payload.delete(:request)
|
30
|
+
payload.delete(:response)
|
31
|
+
params = payload[:params]
|
32
|
+
|
33
|
+
if params.kind_of?(Hash) || params.kind_of?(::ActionController::Parameters)
|
34
|
+
payload[:params] = params.to_unsafe_h unless params.is_a?(Hash)
|
35
|
+
payload[:params] = params.except(*INTERNAL_PARAMS)
|
36
|
+
|
37
|
+
if payload[:params].empty?
|
38
|
+
payload.delete(:params)
|
39
|
+
elsif params["file"]
|
40
|
+
# When logging to JSON the entire tempfile is logged, so convert it to a string.
|
41
|
+
payload[:params]["file"] = params["file"].inspect
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Rounds off the runtimes. For example, :view_runtime, :mongo_runtime, etc.
|
46
|
+
payload.keys.each do |key|
|
47
|
+
payload[key] = payload[key].to_f.round(2) if key.to_s =~ /(.*)_runtime/
|
48
|
+
end
|
49
|
+
|
50
|
+
LOG.info "#{payload[:status]} #{payload[:controller]}##{payload[:action]}", **payload
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/prefab/logger_client.rb
CHANGED
@@ -5,7 +5,6 @@ module Prefab
|
|
5
5
|
SEP = '.'
|
6
6
|
BASE_KEY = 'log-level'
|
7
7
|
UNKNOWN_PATH = 'unknown.'
|
8
|
-
INTERNAL_PREFIX = 'cloud.prefab.client'
|
9
8
|
|
10
9
|
LOG_LEVEL_LOOKUPS = {
|
11
10
|
PrefabProto::LogLevel::NOT_SET_LOG_LEVEL => ::Logger::DEBUG,
|
@@ -65,12 +64,6 @@ module Prefab
|
|
65
64
|
def log_internal(severity, message, path, log_context={}, &block)
|
66
65
|
return if @recurse_check[local_log_id]
|
67
66
|
@recurse_check[local_log_id] = true
|
68
|
-
|
69
|
-
path = if path
|
70
|
-
"#{INTERNAL_PREFIX}.#{path}"
|
71
|
-
else
|
72
|
-
INTERNAL_PREFIX
|
73
|
-
end
|
74
67
|
begin
|
75
68
|
log(message, path, nil, severity, log_context, &block)
|
76
69
|
ensure
|
data/lib/prefab/options.rb
CHANGED
@@ -17,6 +17,8 @@ module Prefab
|
|
17
17
|
attr_reader :prefab_envs
|
18
18
|
attr_reader :collect_sync_interval
|
19
19
|
attr_reader :use_local_cache
|
20
|
+
attr_reader :datafile
|
21
|
+
attr_reader :disable_action_controller_logging
|
20
22
|
attr_accessor :is_fork
|
21
23
|
|
22
24
|
DEFAULT_LOG_FORMATTER = proc { |data|
|
@@ -82,7 +84,9 @@ module Prefab
|
|
82
84
|
collect_evaluation_summaries: true,
|
83
85
|
collect_max_evaluation_summaries: DEFAULT_MAX_EVAL_SUMMARIES,
|
84
86
|
allow_telemetry_in_local_mode: false,
|
85
|
-
|
87
|
+
x_datafile: ENV['PREFAB_DATAFILE'],
|
88
|
+
x_use_local_cache: false,
|
89
|
+
disable_action_controller_logging: false
|
86
90
|
)
|
87
91
|
@api_key = api_key
|
88
92
|
@logdev = logdev
|
@@ -94,6 +98,7 @@ module Prefab
|
|
94
98
|
@initialization_timeout_sec = initialization_timeout_sec
|
95
99
|
@on_init_failure = on_init_failure
|
96
100
|
@prefab_datasources = prefab_datasources
|
101
|
+
@datafile = x_datafile
|
97
102
|
@prefab_config_classpath_dir = prefab_config_classpath_dir
|
98
103
|
@prefab_config_override_dir = prefab_config_override_dir
|
99
104
|
@prefab_envs = Array(prefab_envs)
|
@@ -104,6 +109,7 @@ module Prefab
|
|
104
109
|
@collect_max_evaluation_summaries = collect_max_evaluation_summaries
|
105
110
|
@allow_telemetry_in_local_mode = allow_telemetry_in_local_mode
|
106
111
|
@use_local_cache = x_use_local_cache
|
112
|
+
@disable_action_controller_logging = disable_action_controller_logging
|
107
113
|
@is_fork = false
|
108
114
|
|
109
115
|
# defaults that may be overridden by context_upload_mode
|
@@ -134,6 +140,10 @@ module Prefab
|
|
134
140
|
@prefab_datasources == DATASOURCES::LOCAL_ONLY
|
135
141
|
end
|
136
142
|
|
143
|
+
def datafile?
|
144
|
+
!@datafile.nil?
|
145
|
+
end
|
146
|
+
|
137
147
|
def collect_max_paths
|
138
148
|
return 0 unless telemetry_allowed?(@collect_logger_counts)
|
139
149
|
|
@@ -44,7 +44,7 @@ module Prefab
|
|
44
44
|
if v.nil?
|
45
45
|
hash[k] = ConfigRow.new(k, nil, nil, nil)
|
46
46
|
else
|
47
|
-
value = @resolver.evaluate(v[:config])&.
|
47
|
+
value = @resolver.evaluate(v[:config])&.reportable_value
|
48
48
|
hash[k] = ConfigRow.new(k, value, v[:match], v[:source])
|
49
49
|
end
|
50
50
|
end
|
@@ -65,7 +65,7 @@ module Prefab
|
|
65
65
|
if v.nil?
|
66
66
|
elements << 'tombstone'
|
67
67
|
else
|
68
|
-
value = @resolver.evaluate(v[:config])&.
|
68
|
+
value = @resolver.evaluate(v[:config])&.reportable_value
|
69
69
|
elements << value.to_s.slice(0..34).ljust(35)
|
70
70
|
elements << value.class.to_s.slice(0..6).ljust(7)
|
71
71
|
elements << "Match: #{v[:match]}".slice(0..29).ljust(30)
|
data/lib/prefab/sse_logger.rb
CHANGED
@@ -1,30 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Prefab
|
4
|
-
class SseLogger <
|
4
|
+
class SseLogger < InternalLogger
|
5
5
|
def initialize()
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
def debug(progname = nil, &block)
|
10
|
-
Prefab::LoggerClient.instance.log_internal ::Logger::DEBUG, progname, @path, &block
|
11
|
-
end
|
12
|
-
|
13
|
-
def info(progname = nil, &block)
|
14
|
-
Prefab::LoggerClient.instance.log_internal ::Logger::INFO, progname, @path, &block
|
6
|
+
super("sse")
|
15
7
|
end
|
16
8
|
|
17
9
|
# The SSE::Client warns on a perfectly normal stream disconnect, recast to info
|
18
|
-
def warn(
|
19
|
-
Prefab::LoggerClient.instance.log_internal ::Logger::INFO,
|
20
|
-
end
|
21
|
-
|
22
|
-
def error(progname = nil, &block)
|
23
|
-
Prefab::LoggerClient.instance.log_internal ::Logger::ERROR, progname, @path, &block
|
24
|
-
end
|
25
|
-
|
26
|
-
def fatal(progname = nil, &block)
|
27
|
-
Prefab::LoggerClient.instance.log_internal ::Logger::FATAL, progname, @path, &block
|
10
|
+
def warn(msg = nil,**log_context, &block)
|
11
|
+
Prefab::LoggerClient.instance.log_internal ::Logger::INFO, msg, @path, log_context, &block
|
28
12
|
end
|
29
13
|
end
|
30
14
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Prefab
|
4
|
+
class StaticLogger < ::Logger
|
5
|
+
def initialize(path)
|
6
|
+
@path = path
|
7
|
+
end
|
8
|
+
|
9
|
+
def debug(msg = nil, **log_context, &block)
|
10
|
+
Prefab::LoggerClient.instance.log_internal ::Logger::DEBUG, msg, @path, log_context, &block
|
11
|
+
end
|
12
|
+
|
13
|
+
def info(msg = nil, **log_context, &block)
|
14
|
+
Prefab::LoggerClient.instance.log_internal ::Logger::INFO, msg, @path, log_context, &block
|
15
|
+
end
|
16
|
+
|
17
|
+
def warn(msg = nil, **log_context, &block)
|
18
|
+
Prefab::LoggerClient.instance.log_internal ::Logger::WARN, msg, @path, log_context, &block
|
19
|
+
end
|
20
|
+
|
21
|
+
def error(msg = nil, **log_context, &block)
|
22
|
+
Prefab::LoggerClient.instance.log_internal ::Logger::ERROR, msg, @path, log_context, &block
|
23
|
+
end
|
24
|
+
|
25
|
+
def fatal(msg = nil, **log_context, &block)
|
26
|
+
Prefab::LoggerClient.instance.log_internal ::Logger::FATAL, msg, @path, log_context, &block
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/prefab-cloud-ruby.rb
CHANGED
@@ -14,11 +14,14 @@ require 'prefab_pb'
|
|
14
14
|
require 'prefab/time_helpers'
|
15
15
|
require 'prefab/error'
|
16
16
|
require 'prefab/evaluation'
|
17
|
+
require 'prefab/encryption'
|
17
18
|
require 'prefab/exponential_backoff'
|
18
19
|
require 'prefab/errors/initialization_timeout_error'
|
19
20
|
require 'prefab/errors/invalid_api_key_error'
|
20
21
|
require 'prefab/errors/missing_default_error'
|
22
|
+
require 'prefab/errors/env_var_parse_error'
|
21
23
|
require 'prefab/options'
|
24
|
+
require 'prefab/static_logger'
|
22
25
|
require 'prefab/internal_logger'
|
23
26
|
require 'prefab/rate_limit_cache'
|
24
27
|
require 'prefab/context_shape_aggregator'
|
@@ -39,6 +42,9 @@ require 'prefab/config_resolver'
|
|
39
42
|
require 'prefab/http_connection'
|
40
43
|
require 'prefab/context'
|
41
44
|
require 'prefab/logger_client'
|
45
|
+
require 'active_support/deprecation'
|
46
|
+
require 'active_support'
|
47
|
+
require 'prefab/log_subscribers/action_controller_subscriber'
|
42
48
|
require 'prefab/client'
|
43
49
|
require 'prefab/config_client_presenter'
|
44
50
|
require 'prefab/config_client'
|
data/prefab-cloud-ruby.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
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.
|
5
|
+
# stub: prefab-cloud-ruby 1.3.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "prefab-cloud-ruby".freeze
|
9
|
-
s.version = "1.
|
9
|
+
s.version = "1.3.0"
|
10
10
|
|
11
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 = "2023-11-
|
14
|
+
s.date = "2023-11-13"
|
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
17
|
s.executables = ["console".freeze]
|
@@ -48,7 +48,9 @@ Gem::Specification.new do |s|
|
|
48
48
|
"lib/prefab/context_shape.rb",
|
49
49
|
"lib/prefab/context_shape_aggregator.rb",
|
50
50
|
"lib/prefab/criteria_evaluator.rb",
|
51
|
+
"lib/prefab/encryption.rb",
|
51
52
|
"lib/prefab/error.rb",
|
53
|
+
"lib/prefab/errors/env_var_parse_error.rb",
|
52
54
|
"lib/prefab/errors/initialization_timeout_error.rb",
|
53
55
|
"lib/prefab/errors/invalid_api_key_error.rb",
|
54
56
|
"lib/prefab/errors/missing_default_error.rb",
|
@@ -61,6 +63,7 @@ Gem::Specification.new do |s|
|
|
61
63
|
"lib/prefab/internal_logger.rb",
|
62
64
|
"lib/prefab/local_config_parser.rb",
|
63
65
|
"lib/prefab/log_path_aggregator.rb",
|
66
|
+
"lib/prefab/log_subscribers/action_controller_subscriber.rb",
|
64
67
|
"lib/prefab/logger_client.rb",
|
65
68
|
"lib/prefab/murmer3.rb",
|
66
69
|
"lib/prefab/options.rb",
|
@@ -69,6 +72,7 @@ Gem::Specification.new do |s|
|
|
69
72
|
"lib/prefab/rate_limit_cache.rb",
|
70
73
|
"lib/prefab/resolved_config_presenter.rb",
|
71
74
|
"lib/prefab/sse_logger.rb",
|
75
|
+
"lib/prefab/static_logger.rb",
|
72
76
|
"lib/prefab/time_helpers.rb",
|
73
77
|
"lib/prefab/weighted_value_resolver.rb",
|
74
78
|
"lib/prefab/yaml_config_parser.rb",
|
@@ -82,6 +86,7 @@ Gem::Specification.new do |s|
|
|
82
86
|
"test/support/mock_base_client.rb",
|
83
87
|
"test/support/mock_config_client.rb",
|
84
88
|
"test/support/mock_config_loader.rb",
|
89
|
+
"test/test_action_controller.rb",
|
85
90
|
"test/test_client.rb",
|
86
91
|
"test/test_config_client.rb",
|
87
92
|
"test/test_config_loader.rb",
|
@@ -92,6 +97,7 @@ Gem::Specification.new do |s|
|
|
92
97
|
"test/test_context_shape.rb",
|
93
98
|
"test/test_context_shape_aggregator.rb",
|
94
99
|
"test/test_criteria_evaluator.rb",
|
100
|
+
"test/test_encryption.rb",
|
95
101
|
"test/test_evaluation_summary_aggregator.rb",
|
96
102
|
"test/test_example_contexts_aggregator.rb",
|
97
103
|
"test/test_exponential_backoff.rb",
|
@@ -123,6 +129,7 @@ Gem::Specification.new do |s|
|
|
123
129
|
s.add_runtime_dependency(%q<google-protobuf>.freeze, [">= 0"])
|
124
130
|
s.add_runtime_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
125
131
|
s.add_runtime_dependency(%q<uuid>.freeze, [">= 0"])
|
132
|
+
s.add_runtime_dependency(%q<activesupport>.freeze, [">= 4"])
|
126
133
|
s.add_development_dependency(%q<benchmark-ips>.freeze, [">= 0"])
|
127
134
|
s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
|
128
135
|
s.add_development_dependency(%q<juwelier>.freeze, ["~> 2.4.9"])
|
@@ -135,6 +142,7 @@ Gem::Specification.new do |s|
|
|
135
142
|
s.add_dependency(%q<google-protobuf>.freeze, [">= 0"])
|
136
143
|
s.add_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
137
144
|
s.add_dependency(%q<uuid>.freeze, [">= 0"])
|
145
|
+
s.add_dependency(%q<activesupport>.freeze, [">= 4"])
|
138
146
|
s.add_dependency(%q<benchmark-ips>.freeze, [">= 0"])
|
139
147
|
s.add_dependency(%q<bundler>.freeze, [">= 0"])
|
140
148
|
s.add_dependency(%q<juwelier>.freeze, ["~> 2.4.9"])
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestActionController < Minitest::Test
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
new_client(config: log_level_config("log-level.rails.controller", "INFO"))
|
9
|
+
@subscriber = Prefab::LogSubscribers::ActionControllerSubscriber.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_load
|
13
|
+
@subscriber.process_action(event)
|
14
|
+
assert_logged ['INFO 2023-08-09 15:18:12 -0400: rails.controller.request 200 MyController#index action=index controller=MyController db_runtime=0.05 format=application/html method=GET params={"p1"=>"v1"} path=/my?p1=v1 status=200 view_runtime=0.02']
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def event
|
19
|
+
ActiveSupport::Notifications::Event.new(
|
20
|
+
'process_action.action_controller',
|
21
|
+
Time.now,
|
22
|
+
Time.now,
|
23
|
+
99,
|
24
|
+
status: 200,
|
25
|
+
controller: 'MyController',
|
26
|
+
action: 'index',
|
27
|
+
format: 'application/html',
|
28
|
+
method: 'GET',
|
29
|
+
path: '/my?p1=v1',
|
30
|
+
params: { 'p1' => 'v1' },
|
31
|
+
db_runtime: 0.051123,
|
32
|
+
view_runtime: 0.024555
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def log_level_config(path, level)
|
37
|
+
PrefabProto::Config.new(
|
38
|
+
id: 123,
|
39
|
+
key: path,
|
40
|
+
config_type: PrefabProto::ConfigType::LOG_LEVEL,
|
41
|
+
rows: [
|
42
|
+
PrefabProto::ConfigRow.new(
|
43
|
+
values: [
|
44
|
+
PrefabProto::ConditionalValue.new(
|
45
|
+
value: PrefabProto::ConfigValue.new(log_level: level)
|
46
|
+
)
|
47
|
+
]
|
48
|
+
)
|
49
|
+
]
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
@@ -3,72 +3,219 @@
|
|
3
3
|
require 'test_helper'
|
4
4
|
|
5
5
|
class TestConfigValueUnwrapper < Minitest::Test
|
6
|
-
|
6
|
+
CONFIG = PrefabProto::Config.new(
|
7
|
+
key: 'config_key'
|
8
|
+
)
|
7
9
|
EMPTY_CONTEXT = Prefab::Context.new()
|
10
|
+
DECRYPTION_KEY_NAME = "decryption.key"
|
11
|
+
DECRYPTION_KEY_VALUE = Prefab::Encryption.generate_new_hex_key
|
12
|
+
|
13
|
+
def setup
|
14
|
+
super
|
15
|
+
@mock_resolver = MockResolver.new
|
16
|
+
end
|
8
17
|
|
9
18
|
def test_unwrapping_int
|
10
19
|
config_value = PrefabProto::ConfigValue.new(int: 123)
|
11
|
-
assert_equal 123, unwrap(config_value,
|
20
|
+
assert_equal 123, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
12
21
|
end
|
13
22
|
|
14
23
|
def test_unwrapping_string
|
15
24
|
config_value = PrefabProto::ConfigValue.new(string: 'abc')
|
16
|
-
assert_equal 'abc', unwrap(config_value,
|
25
|
+
assert_equal 'abc', unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
26
|
+
assert_equal 'abc', reportable_value(config_value, CONFIG, EMPTY_CONTEXT)
|
17
27
|
end
|
18
28
|
|
19
29
|
def test_unwrapping_double
|
20
30
|
config_value = PrefabProto::ConfigValue.new(double: 1.23)
|
21
|
-
assert_equal 1.23, unwrap(config_value,
|
31
|
+
assert_equal 1.23, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
22
32
|
end
|
23
33
|
|
24
34
|
def test_unwrapping_bool
|
25
35
|
config_value = PrefabProto::ConfigValue.new(bool: true)
|
26
|
-
assert_equal true, unwrap(config_value,
|
36
|
+
assert_equal true, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
27
37
|
|
28
38
|
config_value = PrefabProto::ConfigValue.new(bool: false)
|
29
|
-
assert_equal false, unwrap(config_value,
|
39
|
+
assert_equal false, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
30
40
|
end
|
31
41
|
|
32
42
|
def test_unwrapping_log_level
|
33
43
|
config_value = PrefabProto::ConfigValue.new(log_level: :INFO)
|
34
|
-
assert_equal :INFO, unwrap(config_value,
|
44
|
+
assert_equal :INFO, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
35
45
|
end
|
36
46
|
|
37
47
|
def test_unwrapping_string_list
|
38
48
|
config_value = PrefabProto::ConfigValue.new(string_list: PrefabProto::StringList.new(values: %w[a b c]))
|
39
|
-
assert_equal %w[a b c], unwrap(config_value,
|
49
|
+
assert_equal %w[a b c], unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
40
50
|
end
|
41
51
|
|
42
52
|
def test_unwrapping_weighted_values
|
43
53
|
# single value
|
44
54
|
config_value = PrefabProto::ConfigValue.new(weighted_values: weighted_values([['abc', 1]]))
|
45
55
|
|
46
|
-
assert_equal 'abc', unwrap(config_value,
|
56
|
+
assert_equal 'abc', unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
47
57
|
|
48
58
|
# multiple values, evenly distributed
|
49
59
|
config_value = PrefabProto::ConfigValue.new(weighted_values: weighted_values([['abc', 1], ['def', 1], ['ghi', 1]]))
|
50
|
-
assert_equal 'def', unwrap(config_value,
|
51
|
-
assert_equal 'ghi', unwrap(config_value,
|
52
|
-
assert_equal 'abc', unwrap(config_value,
|
53
|
-
assert_equal 'ghi', unwrap(config_value,
|
60
|
+
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:000'))
|
61
|
+
assert_equal 'ghi', unwrap(config_value, CONFIG, context_with_key('user:456'))
|
62
|
+
assert_equal 'abc', unwrap(config_value, CONFIG, context_with_key('user:789'))
|
63
|
+
assert_equal 'ghi', unwrap(config_value, CONFIG, context_with_key('user:888'))
|
54
64
|
|
55
65
|
# multiple values, unevenly distributed
|
56
66
|
config_value = PrefabProto::ConfigValue.new(weighted_values: weighted_values([['abc', 1], ['def', 99], ['ghi', 1]]))
|
57
|
-
assert_equal 'def', unwrap(config_value,
|
58
|
-
assert_equal 'def', unwrap(config_value,
|
59
|
-
assert_equal 'def', unwrap(config_value,
|
60
|
-
assert_equal 'def', unwrap(config_value,
|
61
|
-
assert_equal 'ghi', unwrap(config_value,
|
62
|
-
assert_equal 'abc', unwrap(config_value,
|
67
|
+
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:123'))
|
68
|
+
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:456'))
|
69
|
+
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:789'))
|
70
|
+
assert_equal 'def', unwrap(config_value, CONFIG, context_with_key('user:012'))
|
71
|
+
assert_equal 'ghi', unwrap(config_value, CONFIG, context_with_key('user:428'))
|
72
|
+
assert_equal 'abc', unwrap(config_value, CONFIG, context_with_key('user:548'))
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_unwrapping_provided_values
|
76
|
+
with_env('ENV_VAR_NAME', 'unit test value')do
|
77
|
+
value = PrefabProto::Provided.new(
|
78
|
+
source: :ENV_VAR,
|
79
|
+
lookup: "ENV_VAR_NAME"
|
80
|
+
)
|
81
|
+
config_value = PrefabProto::ConfigValue.new(provided: value)
|
82
|
+
assert_equal 'unit test value', unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_unwrapping_provided_values_of_type_string_list
|
87
|
+
with_env('ENV_VAR_NAME', '["bob","cary"]')do
|
88
|
+
value = PrefabProto::Provided.new(
|
89
|
+
source: :ENV_VAR,
|
90
|
+
lookup: "ENV_VAR_NAME"
|
91
|
+
)
|
92
|
+
config_value = PrefabProto::ConfigValue.new(provided: value)
|
93
|
+
assert_equal ["bob", "cary"], unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_unwrapping_provided_values_coerces_to_int
|
98
|
+
with_env('ENV_VAR_NAME', '42')do
|
99
|
+
value = PrefabProto::Provided.new(
|
100
|
+
source: :ENV_VAR,
|
101
|
+
lookup: "ENV_VAR_NAME"
|
102
|
+
)
|
103
|
+
config_value = PrefabProto::ConfigValue.new(provided: value)
|
104
|
+
assert_equal 42, unwrap(config_value, config_of(PrefabProto::Config::ValueType::INT), EMPTY_CONTEXT)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_unwrapping_provided_values_when_value_type_mismatch
|
109
|
+
with_env('ENV_VAR_NAME', 'not an int')do
|
110
|
+
value = PrefabProto::Provided.new(
|
111
|
+
source: :ENV_VAR,
|
112
|
+
lookup: "ENV_VAR_NAME"
|
113
|
+
)
|
114
|
+
config_value = PrefabProto::ConfigValue.new(provided: value)
|
115
|
+
|
116
|
+
assert_raises Prefab::Errors::EnvVarParseError do
|
117
|
+
unwrap(config_value, config_of(PrefabProto::Config::ValueType::INT), EMPTY_CONTEXT)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_coerce
|
123
|
+
assert_equal "string", Prefab::ConfigValueUnwrapper.coerce_into_type("string", CONFIG, "ENV")
|
124
|
+
assert_equal 42, Prefab::ConfigValueUnwrapper.coerce_into_type("42", CONFIG, "ENV")
|
125
|
+
assert_equal false, Prefab::ConfigValueUnwrapper.coerce_into_type("false", CONFIG, "ENV")
|
126
|
+
assert_equal 42.42, Prefab::ConfigValueUnwrapper.coerce_into_type("42.42", CONFIG, "ENV")
|
127
|
+
assert_equal ["a","b"], Prefab::ConfigValueUnwrapper.coerce_into_type("['a','b']", CONFIG, "ENV")
|
128
|
+
|
129
|
+
assert_equal "string", Prefab::ConfigValueUnwrapper.coerce_into_type("string", config_of(PrefabProto::Config::ValueType::STRING),"ENV")
|
130
|
+
assert_equal "42", Prefab::ConfigValueUnwrapper.coerce_into_type("42", config_of(PrefabProto::Config::ValueType::STRING),"ENV")
|
131
|
+
assert_equal "42.42", Prefab::ConfigValueUnwrapper.coerce_into_type("42.42", config_of(PrefabProto::Config::ValueType::STRING),"ENV")
|
132
|
+
assert_equal 42, Prefab::ConfigValueUnwrapper.coerce_into_type("42", config_of(PrefabProto::Config::ValueType::INT),"ENV")
|
133
|
+
assert_equal false, Prefab::ConfigValueUnwrapper.coerce_into_type("false", config_of(PrefabProto::Config::ValueType::BOOL),"ENV")
|
134
|
+
assert_equal 42.42, Prefab::ConfigValueUnwrapper.coerce_into_type("42.42", config_of(PrefabProto::Config::ValueType::DOUBLE),"ENV")
|
135
|
+
assert_equal ["a","b"], Prefab::ConfigValueUnwrapper.coerce_into_type("['a','b']", config_of(PrefabProto::Config::ValueType::STRING_LIST),"ENV")
|
136
|
+
|
137
|
+
assert_raises Prefab::Errors::EnvVarParseError do
|
138
|
+
Prefab::ConfigValueUnwrapper.coerce_into_type("not an int", config_of(PrefabProto::Config::ValueType::INT), "ENV")
|
139
|
+
end
|
140
|
+
assert_raises Prefab::Errors::EnvVarParseError do
|
141
|
+
Prefab::ConfigValueUnwrapper.coerce_into_type("not bool", config_of(PrefabProto::Config::ValueType::BOOL), "ENV")
|
142
|
+
end
|
143
|
+
assert_raises Prefab::Errors::EnvVarParseError do
|
144
|
+
Prefab::ConfigValueUnwrapper.coerce_into_type("not a double", config_of(PrefabProto::Config::ValueType::DOUBLE), "ENV")
|
145
|
+
end
|
146
|
+
assert_raises Prefab::Errors::EnvVarParseError do
|
147
|
+
Prefab::ConfigValueUnwrapper.coerce_into_type("not a list", config_of(PrefabProto::Config::ValueType::STRING_LIST), "ENV")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_unwrapping_provided_values_with_missing_env_var
|
152
|
+
value = PrefabProto::Provided.new(
|
153
|
+
source: :ENV_VAR,
|
154
|
+
lookup: "NON_EXISTENT_ENV_VAR_NAME"
|
155
|
+
)
|
156
|
+
config_value = PrefabProto::ConfigValue.new(provided: value)
|
157
|
+
assert_equal '', unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_unwrapping_encrypted_values_decrypts
|
161
|
+
clear_text = "very secret stuff"
|
162
|
+
encrypted = Prefab::Encryption.new(DECRYPTION_KEY_VALUE).encrypt(clear_text)
|
163
|
+
config_value = PrefabProto::ConfigValue.new(string: encrypted, decrypt_with: "decryption.key")
|
164
|
+
assert_equal clear_text, unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_confidential
|
168
|
+
config_value = PrefabProto::ConfigValue.new(confidential: true, string: "something confidential")
|
169
|
+
assert reportable_value(config_value, CONFIG, EMPTY_CONTEXT).start_with? Prefab::ConfigValueUnwrapper::CONFIDENTIAL_PREFIX
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_unwrap_confiential_provided
|
173
|
+
with_env('PAAS_PASSWORD', "the password")do
|
174
|
+
value = PrefabProto::Provided.new(
|
175
|
+
source: :ENV_VAR,
|
176
|
+
lookup: "PAAS_PASSWORD"
|
177
|
+
)
|
178
|
+
config_value = PrefabProto::ConfigValue.new(provided: value, confidential: true)
|
179
|
+
assert_equal "the password", unwrap(config_value, CONFIG, EMPTY_CONTEXT)
|
180
|
+
assert reportable_value(config_value, CONFIG, EMPTY_CONTEXT).start_with? Prefab::ConfigValueUnwrapper::CONFIDENTIAL_PREFIX
|
181
|
+
end
|
63
182
|
end
|
64
183
|
|
65
184
|
private
|
66
185
|
|
186
|
+
def config_of(value_type)
|
187
|
+
PrefabProto::Config.new(
|
188
|
+
key: 'config-key',
|
189
|
+
value_type: value_type
|
190
|
+
)
|
191
|
+
end
|
192
|
+
|
67
193
|
def context_with_key(key)
|
68
194
|
Prefab::Context.new(user: { key: key })
|
69
195
|
end
|
70
196
|
|
71
197
|
def unwrap(config_value, config_key, context)
|
72
|
-
Prefab::ConfigValueUnwrapper.deepest_value(config_value, config_key, context).unwrap
|
198
|
+
Prefab::ConfigValueUnwrapper.deepest_value(config_value, config_key, context, @mock_resolver).unwrap
|
199
|
+
end
|
200
|
+
|
201
|
+
def reportable_value(config_value, config_key, context)
|
202
|
+
Prefab::ConfigValueUnwrapper.deepest_value(config_value, config_key, context, @mock_resolver).reportable_value
|
203
|
+
end
|
204
|
+
|
205
|
+
class MockResolver
|
206
|
+
def get(key)
|
207
|
+
if DECRYPTION_KEY_NAME == key
|
208
|
+
Prefab::Evaluation.new(config: PrefabProto::Config.new(key: key),
|
209
|
+
value: PrefabProto::ConfigValue.new(string: DECRYPTION_KEY_VALUE),
|
210
|
+
value_index: 0,
|
211
|
+
config_row_index: 0,
|
212
|
+
context: Prefab::Context.new,
|
213
|
+
resolver: self
|
214
|
+
)
|
215
|
+
|
216
|
+
else
|
217
|
+
raise "unexpected key"
|
218
|
+
end
|
219
|
+
end
|
73
220
|
end
|
74
221
|
end
|
data/test/test_context_shape.rb
CHANGED
@@ -36,7 +36,6 @@ class TestContextShape < Minitest::Test
|
|
36
36
|
|
37
37
|
# If this test fails, it means that we've added a new type to the ConfigValue
|
38
38
|
def test_mapping_is_exhaustive
|
39
|
-
#this removes provided for now
|
40
39
|
unsupported = [:bytes, :limit_definition, :log_level, :weighted_values, :int_range, :provided]
|
41
40
|
type_fields = PrefabProto::ConfigValue.descriptor.lookup_oneof("type").entries
|
42
41
|
supported = type_fields.entries.reject do |entry|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestEncryption < Minitest::Test
|
6
|
+
def test_encryption
|
7
|
+
secret = Prefab::Encryption.generate_new_hex_key
|
8
|
+
|
9
|
+
enc = Prefab::Encryption.new(secret)
|
10
|
+
|
11
|
+
clear_text = "hello world"
|
12
|
+
encrypted = enc.encrypt(clear_text)
|
13
|
+
decrypted = enc.decrypt(encrypted)
|
14
|
+
assert_equal clear_text, decrypted
|
15
|
+
end
|
16
|
+
end
|