kumo_config 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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