kumo_config 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.
@@ -0,0 +1,202 @@
1
+ describe KumoConfig::EnvironmentConfig do
2
+ let(:env_name) { 'the_jungle' }
3
+ let(:config_dir_path) { '/var/config' }
4
+ let(:options) do
5
+ {
6
+ env_name: env_name,
7
+ config_path: config_dir_path,
8
+ params_template_file_path: params_template_file_path
9
+ }
10
+ end
11
+ let(:file_loader) { instance_double(KumoConfig::FileLoader) }
12
+ let(:file_loader_cloudformation) { instance_double(KumoConfig::FileLoader) }
13
+ let(:parameters_erb) { ERB.new("") }
14
+ let(:params_template_file_path) { 'junk.txt' }
15
+ let(:environment_config_file_name) { "#{env_name}.yml" }
16
+ let(:kms) { instance_double(KumoKi::KMS) }
17
+ let(:logger) { double(:test_logger, debug: nil) }
18
+ let(:environment_config) { described_class.new(options, logger) }
19
+
20
+ before do
21
+ allow(KumoConfig::FileLoader).to receive(:new).and_return(file_loader)
22
+ allow(KumoKi::KMS).to receive(:new).and_return(kms)
23
+ allow(file_loader).to receive(:load_erb).with(params_template_file_path).and_return(parameters_erb)
24
+ allow(File).to receive(:dirname).and_return('/tmp')
25
+ end
26
+
27
+ context 'backward compatibility' do
28
+ context 'config_path' do
29
+ let(:options) do
30
+ {
31
+ env_name: env_name,
32
+ config_path: config_dir_path
33
+ }
34
+ end
35
+
36
+ it 'will be used without complaint' do
37
+ expect(KumoConfig::FileLoader).to receive(:new).with(config_dir_path: config_dir_path).and_return(nil)
38
+ expect(logger).to receive(:warn).at_most(0).times
39
+ expect(logger).to receive(:fatal).at_most(0).times
40
+ described_class.new(options, logger)
41
+ end
42
+
43
+ it 'complains if config_path is not present'
44
+ end
45
+
46
+ context 'config_dir_path' do
47
+ let(:options) do
48
+ {
49
+ env_name: env_name,
50
+ config_dir_path: config_dir_path
51
+ }
52
+ end
53
+
54
+ it 'will be used if given and raise a deprecation warning' do
55
+ expect(KumoConfig::FileLoader).to receive(:new).with(config_dir_path: config_dir_path).and_return(nil)
56
+ expect(logger).to receive(:warn).with("[DEPRECATION] `:config_dir_path` is deprecated, please pass in `:config_path` instead")
57
+ described_class.new(options, logger)
58
+ end
59
+ end
60
+ end
61
+
62
+ context 'unit tests' do
63
+ describe '#get_binding' do
64
+ subject { environment_config.get_binding }
65
+
66
+ it 'returns a binding' do
67
+ expect(subject).to be_a(Binding)
68
+ end
69
+ end
70
+
71
+ describe "#config" do
72
+ subject { described_class.new(options, logger).config }
73
+
74
+ context 'injected config' do
75
+
76
+ let(:options) do
77
+ {
78
+ env_name: env_name,
79
+ config_path: config_dir_path,
80
+ params_template_file_path: params_template_file_path,
81
+ injected_config: { "injected" => "yes" }
82
+ }
83
+ end
84
+
85
+ let(:common_parameters) { { "stack_name" => "okonomiyaki" } }
86
+ it 'adds injected config to the config hash' do
87
+ expect(file_loader).to receive(:load_hash).with('common.yml').and_return(common_parameters)
88
+ expect(file_loader).to receive(:load_hash).with(environment_config_file_name).and_return({})
89
+ expect(file_loader).to receive(:load_hash).with("development.yml").and_return({})
90
+
91
+ expect(subject).to eq({ "stack_name" => "okonomiyaki", "injected" => "yes" })
92
+ end
93
+ end
94
+
95
+ context 'common config' do
96
+ let(:common_parameters) { { "stack_name" => "okonomiyaki" } }
97
+
98
+ it 'creates a array containing an aws formatted parameter hash' do
99
+ expect(file_loader).to receive(:load_hash).with('common.yml').and_return(common_parameters)
100
+ expect(file_loader).to receive(:load_hash).with(environment_config_file_name).and_return({})
101
+ expect(file_loader).to receive(:load_hash).with("development.yml").and_return({})
102
+
103
+ expect(subject).to eq('stack_name' => 'okonomiyaki')
104
+ end
105
+ end
106
+
107
+ context 'merging common and environment specific configurations' do
108
+ let(:environment_config) { {'image' => 'ami-5678'} }
109
+ let(:development_config) { {'image' => 'ami-9999'} }
110
+
111
+ context 'with environmental overrides' do
112
+ let(:parameter_template) { "image: <%= config['image'] %>" }
113
+ let(:common_config) { {'image' => 'ami-1234'} }
114
+ let(:env_name) { 'development' }
115
+
116
+ it 'replaces the common value with the env value' do
117
+ expect(file_loader).to receive(:load_hash).with('common.yml').and_return(common_config)
118
+ expect(file_loader).to receive(:load_hash).with(environment_config_file_name).and_return(environment_config)
119
+ expect(subject).to eq('image' => 'ami-5678')
120
+ end
121
+ end
122
+
123
+ it 'falls back to a default environment if the requested one does not exist' do
124
+ expect(file_loader).to receive(:load_hash).with('common.yml').and_return({})
125
+ expect(file_loader).to receive(:load_hash).with("#{env_name}.yml").and_return({})
126
+ expect(file_loader).to receive(:load_hash).with("development.yml").and_return(development_config)
127
+
128
+ expect(subject).to eq('image' => 'ami-9999')
129
+ end
130
+ end
131
+ end
132
+
133
+ describe "#plain_text_secrets" do
134
+ subject { described_class.new(options, logger).plain_text_secrets }
135
+
136
+ let(:crypted_password) { 'lookatmyencryptedpasswords' }
137
+ let(:plain_text_password) { 'plain_text_password' }
138
+ let(:secrets) { { 'secret_password' => "[ENC,#{crypted_password}" } }
139
+
140
+ let(:crypted_env_password) { 'cryptedenvpassword' }
141
+ let(:plain_text_env_password) { 'plain_text_env_password' }
142
+ let(:env_secrets) { { 'secret_password' => "[ENC,#{crypted_env_password}"}}
143
+
144
+ before do
145
+ allow(kms).to receive(:decrypt).with(crypted_password).and_return(plain_text_password)
146
+ end
147
+
148
+ it 'decrypts common secrets' do
149
+ allow(file_loader).to receive(:load_hash).with('common_secrets.yml').and_return(secrets)
150
+ allow(file_loader).to receive(:load_hash).with("#{env_name}_secrets.yml").and_return({})
151
+ allow(file_loader).to receive(:load_hash).with("development_secrets.yml").and_return({})
152
+
153
+ expect(subject).to eq('secret_password' => plain_text_password)
154
+ end
155
+
156
+ it 'decrypts environment secrets' do
157
+ allow(file_loader).to receive(:load_hash).with('common_secrets.yml').and_return({})
158
+ allow(file_loader).to receive(:load_hash).with("#{env_name}_secrets.yml").and_return(secrets)
159
+
160
+ expect(subject).to eq('secret_password' => plain_text_password)
161
+ end
162
+
163
+ it 'gives preference to environment secrets' do
164
+ allow(file_loader).to receive(:load_hash).with('common_secrets.yml').and_return(secrets)
165
+ allow(file_loader).to receive(:load_hash).with("#{env_name}_secrets.yml").and_return(env_secrets)
166
+ allow(kms).to receive(:decrypt).with(crypted_env_password).and_return(plain_text_env_password)
167
+
168
+ expect(subject).to eq('secret_password' => plain_text_env_password)
169
+ end
170
+
171
+ it 'falls back to a default environment if the requested one does not exist' do
172
+ allow(file_loader).to receive(:load_hash).with('common_secrets.yml').and_return({})
173
+ allow(file_loader).to receive(:load_hash).with("#{env_name}_secrets.yml").and_return({})
174
+ expect(file_loader).to receive(:load_hash).with("development_secrets.yml").and_return(secrets)
175
+
176
+ expect(subject).to eq('secret_password' => plain_text_password)
177
+ end
178
+ end
179
+
180
+ describe '#development?' do
181
+ %w(production staging).each do |environment|
182
+ it "returns false for #{environment}" do
183
+ expect(
184
+ described_class.new({
185
+ env_name: environment,
186
+ config_path: '',
187
+ params_template_file_path: ''}
188
+ ).development?).to eq false
189
+ end
190
+ end
191
+
192
+ it 'returns true for anything other than production or staging' do
193
+ expect(
194
+ described_class.new({
195
+ env_name: 'fred',
196
+ config_path: '',
197
+ params_template_file_path: ''}
198
+ ).development?).to eq true
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,64 @@
1
+ describe KumoConfig::FileLoader do
2
+ let(:config_dir_path) { '/the/garden/path' }
3
+ let(:options) { { config_dir_path: config_dir_path } }
4
+ let(:file_name) { 'environment.yml' }
5
+ let(:full_file_path) { config_dir_path + '/' + file_name }
6
+
7
+ describe "#load_erb" do
8
+ subject { KumoConfig::FileLoader.new(options).load_erb(file_name) }
9
+
10
+ context "when the requested erb file exits" do
11
+ let(:fake_erb_object) { double() }
12
+ let(:fake_file_handle) { double() }
13
+
14
+ it "loads the file and returns an ERB object" do
15
+ expect(File).to receive(:read).with("#{config_dir_path}/#{file_name}").and_return(fake_file_handle)
16
+ expect(ERB).to receive(:new).with(fake_file_handle).and_return(fake_erb_object)
17
+ expect(subject).to eq(fake_erb_object)
18
+ end
19
+ end
20
+ end
21
+
22
+ describe "#load_hash" do
23
+ subject { KumoConfig::FileLoader.new(options).load_hash(file_name) }
24
+
25
+ context "when the file does not exist" do
26
+ it "returns an empty hash" do
27
+ expect(subject).to eq({})
28
+ end
29
+ end
30
+
31
+ context "when the file does exist" do
32
+ let(:file_contents) { 'key: value' }
33
+
34
+ it "populates a hash" do
35
+ expect(File).to receive(:read).with(full_file_path).and_return(file_contents)
36
+ expect(subject).to eq({ 'key' => 'value' })
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#load_hash when you set optional flag to false" do
42
+ let(:config_dir_path) { '/the/garden/path' }
43
+ let(:options) { { config_dir_path: config_dir_path } }
44
+ let(:file_name) { 'environment.yml' }
45
+ let(:full_file_path) { config_dir_path + '/' + file_name }
46
+
47
+ subject { KumoConfig::FileLoader.new(options).load_hash(file_name, false) }
48
+
49
+ context 'when the file does not exist' do
50
+ it 'raises an error' do
51
+ expect { subject }.to raise_error(Errno::ENOENT)
52
+ end
53
+ end
54
+
55
+ context 'when the file exists' do
56
+ let(:file_contents) { 'key: value' }
57
+
58
+ it 'populates a hash' do
59
+ expect(File).to receive(:read).with(full_file_path).and_return(file_contents)
60
+ expect(subject).to eq({ 'key' => 'value' })
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,28 @@
1
+ ENV['RUBY_ENV'] ||= 'test'
2
+ require File.expand_path("../../lib/kumo_config.rb", __FILE__)
3
+ Dir[File.expand_path("../support/*.rb", __FILE__)].each {|file| require file }
4
+
5
+ RSpec.configure do |config|
6
+ # rspec-expectations config goes here. You can use an alternate
7
+ # assertion/expectation library such as wrong or the stdlib/minitest
8
+ # assertions if you prefer.
9
+ config.expect_with :rspec do |expectations|
10
+ # This option will default to `true` in RSpec 4. It makes the `description`
11
+ # and `failure_message` of custom matchers include text for helper methods
12
+ # defined using `chain`, e.g.:
13
+ # be_bigger_than(2).and_smaller_than(4).description
14
+ # # => "be bigger than 2 and smaller than 4"
15
+ # ...rather than:
16
+ # # => "be bigger than 2"
17
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
18
+ end
19
+
20
+ # rspec-mocks config goes here. You can use an alternate test double
21
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
22
+ config.mock_with :rspec do |mocks|
23
+ # Prevents you from mocking or stubbing a method that does not exist on
24
+ # a real object. This is generally recommended, and will default to
25
+ # `true` in RSpec 4.
26
+ mocks.verify_partial_doubles = true
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kumo_config
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Redbubble
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-09-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kumo_ki
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.4'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.10'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.10'
83
+ description:
84
+ email:
85
+ - delivery-engineering@redbubble.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".buildkite/pipeline.yml"
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - ".rubocop.yml"
94
+ - Gemfile
95
+ - README.md
96
+ - Rakefile
97
+ - VERSION
98
+ - kumo_config.gemspec
99
+ - lib/kumo_config.rb
100
+ - lib/kumo_config/environment_config.rb
101
+ - lib/kumo_config/file_loader.rb
102
+ - script/build.sh
103
+ - script/integration_test.sh
104
+ - script/unit_test.sh
105
+ - spec/integration/.gitkeep
106
+ - spec/integration/config_spec.rb
107
+ - spec/integration/fixtures/.gitkeep
108
+ - spec/integration/fixtures/common.yml
109
+ - spec/integration/fixtures/common_secrets.yml
110
+ - spec/integration/fixtures/development.yml
111
+ - spec/integration/fixtures/development_secrets.yml
112
+ - spec/integration/fixtures/production.yml
113
+ - spec/integration/fixtures/production_secrets.yml
114
+ - spec/lib/environment_config_spec.rb
115
+ - spec/lib/file_loader_spec.rb
116
+ - spec/spec_helper.rb
117
+ homepage: http://redbubble.com
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.2.2
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: A utility for reading Kumo configuration
141
+ test_files:
142
+ - spec/integration/.gitkeep
143
+ - spec/integration/config_spec.rb
144
+ - spec/integration/fixtures/.gitkeep
145
+ - spec/integration/fixtures/common.yml
146
+ - spec/integration/fixtures/common_secrets.yml
147
+ - spec/integration/fixtures/development.yml
148
+ - spec/integration/fixtures/development_secrets.yml
149
+ - spec/integration/fixtures/production.yml
150
+ - spec/integration/fixtures/production_secrets.yml
151
+ - spec/lib/environment_config_spec.rb
152
+ - spec/lib/file_loader_spec.rb
153
+ - spec/spec_helper.rb