prefab-cloud-ruby 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|