test-kitchen 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/.cane +1 -1
- data/.rubocop.yml +3 -0
- data/.travis.yml +20 -9
- data/CHANGELOG.md +219 -108
- data/Gemfile +10 -6
- data/Guardfile +38 -9
- data/README.md +11 -1
- data/Rakefile +21 -37
- data/bin/kitchen +4 -4
- data/features/kitchen_action_commands.feature +161 -0
- data/features/kitchen_console_command.feature +34 -0
- data/features/kitchen_diagnose_command.feature +64 -0
- data/features/kitchen_init_command.feature +29 -17
- data/features/kitchen_list_command.feature +2 -2
- data/features/kitchen_login_command.feature +56 -0
- data/features/{sink_command.feature → kitchen_sink_command.feature} +0 -0
- data/features/kitchen_test_command.feature +88 -0
- data/features/step_definitions/gem_steps.rb +8 -6
- data/features/step_definitions/git_steps.rb +4 -2
- data/features/step_definitions/output_steps.rb +5 -0
- data/features/support/env.rb +12 -9
- data/lib/kitchen.rb +60 -38
- data/lib/kitchen/base64_stream.rb +55 -0
- data/lib/kitchen/busser.rb +124 -58
- data/lib/kitchen/cli.rb +121 -38
- data/lib/kitchen/collection.rb +3 -3
- data/lib/kitchen/color.rb +4 -4
- data/lib/kitchen/command.rb +78 -11
- data/lib/kitchen/command/action.rb +3 -2
- data/lib/kitchen/command/console.rb +12 -5
- data/lib/kitchen/command/diagnose.rb +17 -3
- data/lib/kitchen/command/driver_discover.rb +26 -7
- data/lib/kitchen/command/exec.rb +41 -0
- data/lib/kitchen/command/list.rb +44 -14
- data/lib/kitchen/command/login.rb +2 -1
- data/lib/kitchen/command/sink.rb +2 -1
- data/lib/kitchen/command/test.rb +5 -4
- data/lib/kitchen/config.rb +146 -14
- data/lib/kitchen/configurable.rb +314 -0
- data/lib/kitchen/data_munger.rb +522 -18
- data/lib/kitchen/diagnostic.rb +43 -4
- data/lib/kitchen/driver.rb +4 -4
- data/lib/kitchen/driver/base.rb +80 -115
- data/lib/kitchen/driver/dummy.rb +34 -6
- data/lib/kitchen/driver/proxy.rb +14 -3
- data/lib/kitchen/driver/ssh_base.rb +61 -7
- data/lib/kitchen/errors.rb +109 -9
- data/lib/kitchen/generator/driver_create.rb +39 -5
- data/lib/kitchen/generator/init.rb +130 -45
- data/lib/kitchen/instance.rb +162 -28
- data/lib/kitchen/lazy_hash.rb +79 -7
- data/lib/kitchen/loader/yaml.rb +159 -27
- data/lib/kitchen/logger.rb +267 -21
- data/lib/kitchen/logging.rb +30 -3
- data/lib/kitchen/login_command.rb +11 -2
- data/lib/kitchen/metadata_chopper.rb +2 -2
- data/lib/kitchen/provisioner.rb +4 -4
- data/lib/kitchen/provisioner/base.rb +107 -103
- data/lib/kitchen/provisioner/chef/berkshelf.rb +36 -8
- data/lib/kitchen/provisioner/chef/librarian.rb +40 -11
- data/lib/kitchen/provisioner/chef_base.rb +206 -167
- data/lib/kitchen/provisioner/chef_solo.rb +25 -7
- data/lib/kitchen/provisioner/chef_zero.rb +105 -29
- data/lib/kitchen/provisioner/dummy.rb +1 -1
- data/lib/kitchen/provisioner/shell.rb +21 -6
- data/lib/kitchen/rake_tasks.rb +8 -3
- data/lib/kitchen/shell_out.rb +15 -18
- data/lib/kitchen/ssh.rb +122 -27
- data/lib/kitchen/state_file.rb +24 -7
- data/lib/kitchen/thor_tasks.rb +9 -4
- data/lib/kitchen/util.rb +43 -118
- data/lib/kitchen/version.rb +1 -1
- data/lib/vendor/hash_recursive_merge.rb +10 -2
- data/spec/kitchen/base64_stream_spec.rb +77 -0
- data/spec/kitchen/busser_spec.rb +490 -0
- data/spec/kitchen/collection_spec.rb +10 -10
- data/spec/kitchen/color_spec.rb +2 -2
- data/spec/kitchen/config_spec.rb +234 -62
- data/spec/kitchen/configurable_spec.rb +490 -0
- data/spec/kitchen/data_munger_spec.rb +1070 -862
- data/spec/kitchen/diagnostic_spec.rb +79 -0
- data/spec/kitchen/driver/base_spec.rb +80 -85
- data/spec/kitchen/driver/dummy_spec.rb +43 -14
- data/spec/kitchen/driver/proxy_spec.rb +134 -0
- data/spec/kitchen/driver/ssh_base_spec.rb +644 -0
- data/spec/kitchen/driver_spec.rb +15 -15
- data/spec/kitchen/errors_spec.rb +309 -0
- data/spec/kitchen/instance_spec.rb +143 -46
- data/spec/kitchen/lazy_hash_spec.rb +36 -9
- data/spec/kitchen/loader/yaml_spec.rb +237 -226
- data/spec/kitchen/logger_spec.rb +419 -0
- data/spec/kitchen/logging_spec.rb +59 -0
- data/spec/kitchen/login_command_spec.rb +49 -0
- data/spec/kitchen/metadata_chopper_spec.rb +82 -0
- data/spec/kitchen/platform_spec.rb +4 -4
- data/spec/kitchen/provisioner/base_spec.rb +65 -125
- data/spec/kitchen/provisioner/chef_base_spec.rb +798 -0
- data/spec/kitchen/provisioner/chef_solo_spec.rb +316 -0
- data/spec/kitchen/provisioner/chef_zero_spec.rb +624 -0
- data/spec/kitchen/provisioner/shell_spec.rb +269 -0
- data/spec/kitchen/provisioner_spec.rb +6 -6
- data/spec/kitchen/shell_out_spec.rb +143 -0
- data/spec/kitchen/ssh_spec.rb +683 -0
- data/spec/kitchen/state_file_spec.rb +28 -21
- data/spec/kitchen/suite_spec.rb +7 -7
- data/spec/kitchen/util_spec.rb +68 -10
- data/spec/kitchen_spec.rb +107 -0
- data/spec/spec_helper.rb +18 -13
- data/support/chef-client-zero.rb +10 -9
- data/support/chef_helpers.sh +16 -0
- data/support/download_helpers.sh +109 -0
- data/test-kitchen.gemspec +42 -33
- metadata +107 -33
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2014, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require_relative "../spec_helper"
|
20
|
+
|
21
|
+
require "kitchen/login_command"
|
22
|
+
|
23
|
+
describe Kitchen::LoginCommand do
|
24
|
+
|
25
|
+
let(:argv) { Array.new }
|
26
|
+
let(:opts) { Hash.new }
|
27
|
+
|
28
|
+
let(:cmd) { Kitchen::LoginCommand.new(argv, opts) }
|
29
|
+
|
30
|
+
it "#cmd_array defaults to an empty array" do
|
31
|
+
Kitchen::LoginCommand.new(nil, opts).cmd_array.must_equal []
|
32
|
+
end
|
33
|
+
|
34
|
+
it "#cmd_array returns the command array from the constructor" do
|
35
|
+
argv.concat(["one", "-o", "two"])
|
36
|
+
|
37
|
+
cmd.cmd_array.must_equal ["one", "-o", "two"]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "#options defaults to an empty hash" do
|
41
|
+
Kitchen::LoginCommand.new(argv, nil).options.must_equal {}
|
42
|
+
end
|
43
|
+
|
44
|
+
it "#options returns the options hash from the constructor" do
|
45
|
+
opts[:cake] = "yummy"
|
46
|
+
|
47
|
+
cmd.options.must_equal(:cake => "yummy")
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2014, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require_relative "../spec_helper"
|
20
|
+
|
21
|
+
require "kitchen/metadata_chopper"
|
22
|
+
|
23
|
+
describe Kitchen::MetadataChopper do
|
24
|
+
|
25
|
+
before do
|
26
|
+
FakeFS.activate!
|
27
|
+
FileUtils.mkdir_p("/tmp")
|
28
|
+
end
|
29
|
+
|
30
|
+
after do
|
31
|
+
FakeFS.deactivate!
|
32
|
+
FakeFS::FileSystem.clear
|
33
|
+
end
|
34
|
+
|
35
|
+
let(:described_class) { Kitchen::MetadataChopper }
|
36
|
+
|
37
|
+
describe ".new" do
|
38
|
+
|
39
|
+
it "contains a :name attribute" do
|
40
|
+
stub_metadata!("banzai")
|
41
|
+
|
42
|
+
described_class.new("/tmp/metadata.rb")[:name].must_equal "banzai"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "contains a :version attribute" do
|
46
|
+
stub_metadata!("foobar", "1.2.3")
|
47
|
+
|
48
|
+
described_class.new("/tmp/metadata.rb")[:version].must_equal "1.2.3"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe ".extract" do
|
53
|
+
|
54
|
+
it "returns a tuple" do
|
55
|
+
stub_metadata!("foo", "1.2.3")
|
56
|
+
|
57
|
+
described_class.extract("/tmp/metadata.rb").must_equal ["foo", "1.2.3"]
|
58
|
+
end
|
59
|
+
|
60
|
+
it "returns nils for a name or version that isn't present" do
|
61
|
+
File.open("/tmp/metadata.rb", "wb") do |f|
|
62
|
+
f.write %{maintainer "Michael Bluth"\n}
|
63
|
+
end
|
64
|
+
|
65
|
+
described_class.extract("/tmp/metadata.rb").must_equal [nil, nil]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def stub_metadata!(name = "foobar", version = "5.2.1")
|
70
|
+
File.open("/tmp/metadata.rb", "wb") do |f|
|
71
|
+
f.write <<-METADATA_RB.gsub(/^ {8}/, "")
|
72
|
+
name "#{name}"
|
73
|
+
maintainer "Michael Bluth"
|
74
|
+
maintainer_email "michael@bluth.com"
|
75
|
+
license "Apache 2.0"
|
76
|
+
description "Doing stuff!"
|
77
|
+
long_description "Doing stuff!"
|
78
|
+
version "#{version}"
|
79
|
+
METADATA_RB
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -16,14 +16,14 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
require_relative
|
19
|
+
require_relative "../spec_helper"
|
20
20
|
|
21
|
-
require
|
22
|
-
require
|
21
|
+
require "kitchen/errors"
|
22
|
+
require "kitchen/platform"
|
23
23
|
|
24
24
|
describe Kitchen::Platform do
|
25
25
|
|
26
|
-
let(:opts) do
|
26
|
+
let(:opts) do; { :name => "plata" }; end
|
27
27
|
let(:platform) { Kitchen::Platform.new(opts) }
|
28
28
|
|
29
29
|
it "raises an ArgumentError if name is missing" do
|
@@ -16,79 +16,31 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
require_relative
|
20
|
-
require
|
19
|
+
require_relative "../../spec_helper"
|
20
|
+
require "logger"
|
21
|
+
require "stringio"
|
21
22
|
|
22
|
-
require
|
23
|
-
|
24
|
-
module Kitchen
|
25
|
-
|
26
|
-
module Provisioner
|
27
|
-
|
28
|
-
class StaticDefaults < Base
|
29
|
-
|
30
|
-
default_config :rank, "captain"
|
31
|
-
default_config :tunables, { "foo" => "fa" }
|
32
|
-
default_config :nice, true
|
33
|
-
end
|
34
|
-
|
35
|
-
class SubclassDefaults < StaticDefaults
|
36
|
-
|
37
|
-
default_config :yea, "ya"
|
38
|
-
end
|
39
|
-
|
40
|
-
class ComputedDefaults < Base
|
41
|
-
|
42
|
-
default_config :beans, "kidney"
|
43
|
-
default_config :fetch_command, "curl"
|
44
|
-
default_config :beans_url do |provisioner|
|
45
|
-
"http://gim.me/#{provisioner[:beans]}"
|
46
|
-
end
|
47
|
-
default_config :command do |provisioner|
|
48
|
-
"#{provisioner[:fetch_command]} #{provisioner[:beans_url]}"
|
49
|
-
end
|
50
|
-
default_config :fetch_url do |provisioner|
|
51
|
-
"http://gim.me/beans-for/#{provisioner.instance.name}"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
23
|
+
require "kitchen"
|
56
24
|
|
57
25
|
describe Kitchen::Provisioner::Base do
|
58
26
|
|
27
|
+
let(:logged_output) { StringIO.new }
|
28
|
+
let(:logger) { Logger.new(logged_output) }
|
59
29
|
let(:config) { Hash.new }
|
60
|
-
let(:logger_io) { StringIO.new }
|
61
|
-
let(:instance_logger) { Kitchen::Logger.new(:logdev => logger_io) }
|
62
30
|
|
63
31
|
let(:instance) do
|
64
|
-
stub(:name => "coolbeans", :logger =>
|
32
|
+
stub(:name => "coolbeans", :logger => logger)
|
65
33
|
end
|
66
34
|
|
67
35
|
let(:provisioner) do
|
68
|
-
|
69
|
-
p.instance = instance
|
70
|
-
p
|
36
|
+
Kitchen::Provisioner::Base.new(config).finalize_config!(instance)
|
71
37
|
end
|
72
38
|
|
73
|
-
it "#
|
74
|
-
provisioner.instance.must_equal instance
|
75
|
-
end
|
76
|
-
|
77
|
-
it "#name returns its class name as a string" do
|
39
|
+
it "#name returns the name of the provisioner" do
|
78
40
|
provisioner.name.must_equal "Base"
|
79
41
|
end
|
80
42
|
|
81
|
-
describe "
|
82
|
-
|
83
|
-
before do
|
84
|
-
config[:animals] = %w{cats dogs}
|
85
|
-
config[:coolness] = true
|
86
|
-
end
|
87
|
-
|
88
|
-
it "injects config into the provisioner" do
|
89
|
-
provisioner[:animals].must_equal ["cats", "dogs"]
|
90
|
-
provisioner[:coolness].must_equal true
|
91
|
-
end
|
43
|
+
describe "configuration" do
|
92
44
|
|
93
45
|
it ":root_path defaults to /tmp/kitchen" do
|
94
46
|
provisioner[:root_path].must_equal "/tmp/kitchen"
|
@@ -97,99 +49,87 @@ describe Kitchen::Provisioner::Base do
|
|
97
49
|
it ":sudo defaults to true" do
|
98
50
|
provisioner[:sudo].must_equal true
|
99
51
|
end
|
100
|
-
|
101
|
-
it "#config_keys returns the config keys" do
|
102
|
-
provisioner.config_keys.sort.
|
103
|
-
must_equal [:animals, :coolness, :root_path, :sudo]
|
104
|
-
end
|
105
52
|
end
|
106
53
|
|
107
|
-
describe "
|
54
|
+
describe "#logger" do
|
108
55
|
|
109
|
-
|
56
|
+
before { @klog = Kitchen.logger }
|
57
|
+
after { Kitchen.logger = @klog }
|
110
58
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
p
|
115
|
-
end
|
59
|
+
it "returns the instance's logger" do
|
60
|
+
provisioner.send(:logger).must_equal logger
|
61
|
+
end
|
116
62
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
63
|
+
it "returns the default logger if instance's logger is not set" do
|
64
|
+
provisioner = Kitchen::Provisioner::Base.new(config)
|
65
|
+
Kitchen.logger = "yep"
|
66
|
+
|
67
|
+
provisioner.send(:logger).must_equal Kitchen.logger
|
68
|
+
end
|
69
|
+
end
|
122
70
|
|
123
|
-
|
124
|
-
config[:rank] = "commander"
|
125
|
-
config[:nice] = :maybe
|
71
|
+
[:init_command, :install_command, :prepare_command, :run_command].each do |cmd|
|
126
72
|
|
127
|
-
|
128
|
-
|
129
|
-
provisioner[:nice].must_equal :maybe
|
130
|
-
end
|
73
|
+
it "has a #{cmd} method" do
|
74
|
+
provisioner.public_send(cmd).must_be_nil
|
131
75
|
end
|
76
|
+
end
|
132
77
|
|
133
|
-
|
78
|
+
describe "sandbox" do
|
134
79
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
80
|
+
after do
|
81
|
+
begin
|
82
|
+
provisioner.cleanup_sandbox
|
83
|
+
rescue # rubocop:disable Lint/HandleExceptions
|
139
84
|
end
|
85
|
+
end
|
140
86
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
provisioner[:nice].must_equal true
|
145
|
-
provisioner[:yea].must_equal "ya"
|
146
|
-
end
|
87
|
+
it "raises ClientError if #sandbox_path is called before #create_sandbox" do
|
88
|
+
proc { provisioner.sandbox_path }.must_raise Kitchen::ClientError
|
89
|
+
end
|
147
90
|
|
148
|
-
|
149
|
-
|
150
|
-
config[:nice] = :maybe
|
91
|
+
it "#create_sandbox creates a temporary directory" do
|
92
|
+
provisioner.create_sandbox
|
151
93
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
provisioner[:yea].must_equal "ya"
|
156
|
-
end
|
94
|
+
File.directory?(provisioner.sandbox_path).must_equal true
|
95
|
+
format("%o", File.stat(provisioner.sandbox_path).mode)[1, 4].
|
96
|
+
must_equal "0755"
|
157
97
|
end
|
158
98
|
|
159
|
-
|
99
|
+
it "#create_sandbox logs an info message" do
|
100
|
+
provisioner.create_sandbox
|
160
101
|
|
161
|
-
|
162
|
-
|
163
|
-
p.instance = instance
|
164
|
-
p
|
165
|
-
end
|
102
|
+
logged_output.string.must_match info_line("Preparing files for transfer")
|
103
|
+
end
|
166
104
|
|
167
|
-
|
168
|
-
|
169
|
-
provisioner[:command].must_equal "curl http://gim.me/kidney"
|
170
|
-
end
|
105
|
+
it "#create_sandbox logs a debug message" do
|
106
|
+
provisioner.create_sandbox
|
171
107
|
|
172
|
-
|
173
|
-
|
174
|
-
|
108
|
+
logged_output.string.
|
109
|
+
must_match debug_line_starting_with("Creating local sandbox in ")
|
110
|
+
end
|
175
111
|
|
176
|
-
|
177
|
-
|
112
|
+
it "#cleanup_sandbox deletes the sandbox directory" do
|
113
|
+
provisioner.create_sandbox
|
114
|
+
provisioner.cleanup_sandbox
|
178
115
|
|
179
|
-
|
180
|
-
end
|
116
|
+
File.directory?(provisioner.sandbox_path).must_equal false
|
181
117
|
end
|
182
|
-
end
|
183
118
|
|
184
|
-
|
119
|
+
it "#cleanup_sandbox logs a debug message" do
|
120
|
+
provisioner.create_sandbox
|
121
|
+
provisioner.cleanup_sandbox
|
185
122
|
|
186
|
-
|
187
|
-
|
123
|
+
logged_output.string.
|
124
|
+
must_match debug_line_starting_with("Cleaning up local sandbox in ")
|
188
125
|
end
|
189
126
|
|
190
|
-
|
191
|
-
|
192
|
-
|
127
|
+
def info_line(msg)
|
128
|
+
%r{^I, .* : #{Regexp.escape(msg)}$}
|
129
|
+
end
|
130
|
+
|
131
|
+
def debug_line_starting_with(msg)
|
132
|
+
%r{^D, .* : #{Regexp.escape(msg)}}
|
193
133
|
end
|
194
134
|
end
|
195
135
|
|
@@ -0,0 +1,798 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2014, Fletcher Nichol
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
|
19
|
+
require_relative "../../spec_helper"
|
20
|
+
|
21
|
+
require "kitchen"
|
22
|
+
require "kitchen/provisioner/chef_base"
|
23
|
+
|
24
|
+
describe Kitchen::Provisioner::ChefBase do
|
25
|
+
|
26
|
+
let(:logged_output) { StringIO.new }
|
27
|
+
let(:logger) { Logger.new(logged_output) }
|
28
|
+
|
29
|
+
let(:config) do
|
30
|
+
{ :test_base_path => "/basist", :kitchen_root => "/rooty" }
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:suite) do
|
34
|
+
stub(:name => "fries")
|
35
|
+
end
|
36
|
+
|
37
|
+
let(:instance) do
|
38
|
+
stub(:name => "coolbeans", :logger => logger, :suite => suite)
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:provisioner) do
|
42
|
+
Class.new(Kitchen::Provisioner::ChefBase) {
|
43
|
+
def calculate_path(path, _opts = {})
|
44
|
+
"<calculated>/#{path}"
|
45
|
+
end
|
46
|
+
}.new(config).finalize_config!(instance)
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "configuration" do
|
50
|
+
|
51
|
+
it ":require_chef_omnibus defaults to true" do
|
52
|
+
provisioner[:require_chef_omnibus].must_equal true
|
53
|
+
end
|
54
|
+
|
55
|
+
it ":chef_omnibus_url has a default" do
|
56
|
+
provisioner[:chef_omnibus_url].
|
57
|
+
must_equal "https://www.chef.io/chef/install.sh"
|
58
|
+
end
|
59
|
+
|
60
|
+
it ":chef_omnibus_root has a default" do
|
61
|
+
provisioner[:chef_omnibus_root].must_equal "/opt/chef"
|
62
|
+
end
|
63
|
+
|
64
|
+
it ":chef_omnibus_install_options defaults to nil" do
|
65
|
+
provisioner[:chef_omnibus_install_options].must_equal nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it ":run_list defaults to an empty array" do
|
69
|
+
provisioner[:run_list].must_equal []
|
70
|
+
end
|
71
|
+
|
72
|
+
it ":attributes defaults to an empty hash" do
|
73
|
+
provisioner[:attributes].must_equal Hash.new
|
74
|
+
end
|
75
|
+
|
76
|
+
it ":log_file defaults to nil" do
|
77
|
+
provisioner[:log_file].must_equal nil
|
78
|
+
end
|
79
|
+
|
80
|
+
it ":cookbook_files_glob includes recipes" do
|
81
|
+
provisioner[:cookbook_files_glob].must_match %r{,recipes/}
|
82
|
+
end
|
83
|
+
|
84
|
+
it ":data_path uses calculate_path and is expanded" do
|
85
|
+
provisioner[:data_path].must_equal "/rooty/<calculated>/data"
|
86
|
+
end
|
87
|
+
|
88
|
+
it ":data_bags_path uses calculate_path and is expanded" do
|
89
|
+
provisioner[:data_bags_path].must_equal "/rooty/<calculated>/data_bags"
|
90
|
+
end
|
91
|
+
|
92
|
+
it ":environments_path uses calculate_path and is expanded" do
|
93
|
+
provisioner[:environments_path].
|
94
|
+
must_equal "/rooty/<calculated>/environments"
|
95
|
+
end
|
96
|
+
|
97
|
+
it ":nodes_path uses calculate_path and is expanded" do
|
98
|
+
provisioner[:nodes_path].must_equal "/rooty/<calculated>/nodes"
|
99
|
+
end
|
100
|
+
|
101
|
+
it ":roles_path uses calculate_path and is expanded" do
|
102
|
+
provisioner[:roles_path].must_equal "/rooty/<calculated>/roles"
|
103
|
+
end
|
104
|
+
|
105
|
+
it ":clients_path uses calculate_path and is expanded" do
|
106
|
+
provisioner[:clients_path].must_equal "/rooty/<calculated>/clients"
|
107
|
+
end
|
108
|
+
|
109
|
+
it "...secret_key_path uses calculate_path and is expanded" do
|
110
|
+
provisioner[:encrypted_data_bag_secret_key_path].
|
111
|
+
must_equal "/rooty/<calculated>/encrypted_data_bag_secret_key"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#install_command" do
|
116
|
+
|
117
|
+
it "returns nil if :require_chef_omnibus is falsey" do
|
118
|
+
config[:require_chef_omnibus] = false
|
119
|
+
|
120
|
+
provisioner.install_command.must_equal nil
|
121
|
+
end
|
122
|
+
|
123
|
+
it "uses bourne shell (sh)" do
|
124
|
+
provisioner.install_command.must_match(/\Ash -c '$/)
|
125
|
+
end
|
126
|
+
|
127
|
+
it "ends with a single quote" do
|
128
|
+
provisioner.install_command.must_match(/'\Z/)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "installs chef using :chef_omnibus_url, if necessary" do
|
132
|
+
config[:chef_omnibus_url] = "FROM_HERE"
|
133
|
+
|
134
|
+
provisioner.install_command.must_match regexify(
|
135
|
+
"do_download FROM_HERE /tmp/install.sh")
|
136
|
+
end
|
137
|
+
|
138
|
+
it "will install a specific version of chef, if necessary" do
|
139
|
+
config[:require_chef_omnibus] = "1.2.3"
|
140
|
+
|
141
|
+
provisioner.install_command.must_match regexify(
|
142
|
+
"sudo -E sh /tmp/install.sh -v 1.2.3")
|
143
|
+
provisioner.install_command.must_match regexify(
|
144
|
+
"Installing Chef Omnibus (1.2.3)", :partial_line)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "will install a major/minor version of chef, if necessary" do
|
148
|
+
config[:require_chef_omnibus] = "11.10"
|
149
|
+
|
150
|
+
provisioner.install_command.must_match regexify(
|
151
|
+
"sudo -E sh /tmp/install.sh -v 11.10")
|
152
|
+
provisioner.install_command.must_match regexify(
|
153
|
+
"Installing Chef Omnibus (11.10)", :partial_line)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "will install a major version of chef, if necessary" do
|
157
|
+
config[:require_chef_omnibus] = "12"
|
158
|
+
|
159
|
+
provisioner.install_command.must_match regexify(
|
160
|
+
"sudo -E sh /tmp/install.sh -v 12")
|
161
|
+
provisioner.install_command.must_match regexify(
|
162
|
+
"Installing Chef Omnibus (12)", :partial_line)
|
163
|
+
end
|
164
|
+
|
165
|
+
it "will install a downcaased version string of chef, if necessary" do
|
166
|
+
config[:require_chef_omnibus] = "10.1.0.RC.1"
|
167
|
+
|
168
|
+
provisioner.install_command.must_match regexify(
|
169
|
+
"sudo -E sh /tmp/install.sh -v 10.1.0.rc.1")
|
170
|
+
provisioner.install_command.must_match regexify(
|
171
|
+
"Installing Chef Omnibus (10.1.0.rc.1)", :partial_line)
|
172
|
+
end
|
173
|
+
|
174
|
+
it "will install the latest of chef, if necessary" do
|
175
|
+
config[:require_chef_omnibus] = "latest"
|
176
|
+
|
177
|
+
provisioner.install_command.must_match regexify(
|
178
|
+
"sudo -E sh /tmp/install.sh ")
|
179
|
+
provisioner.install_command.must_match regexify(
|
180
|
+
"Installing Chef Omnibus (always install latest version)",
|
181
|
+
:partial_line
|
182
|
+
)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "will install a of chef, unless it exists" do
|
186
|
+
config[:require_chef_omnibus] = true
|
187
|
+
|
188
|
+
provisioner.install_command.must_match regexify(
|
189
|
+
"sudo -E sh /tmp/install.sh ")
|
190
|
+
provisioner.install_command.must_match regexify(
|
191
|
+
"Installing Chef Omnibus (install only if missing)", :partial_line)
|
192
|
+
end
|
193
|
+
|
194
|
+
it "will pass install options, when given" do
|
195
|
+
config[:chef_omnibus_install_options] = "-P chefdk"
|
196
|
+
|
197
|
+
provisioner.install_command.must_match regexify(
|
198
|
+
"sudo -E sh /tmp/install.sh -P chefdk")
|
199
|
+
provisioner.install_command.must_match regexify(
|
200
|
+
"Installing Chef Omnibus (install only if missing)", :partial_line)
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "#init_command" do
|
206
|
+
|
207
|
+
it "uses bourne shell" do
|
208
|
+
provisioner.init_command.must_match(/\Ash -c '$/)
|
209
|
+
provisioner.init_command.must_match(/'\Z/)
|
210
|
+
end
|
211
|
+
|
212
|
+
it "uses sudo for rm when configured" do
|
213
|
+
config[:sudo] = true
|
214
|
+
|
215
|
+
provisioner.init_command.
|
216
|
+
must_match regexify("sudo -E rm -rf ", :partial_line)
|
217
|
+
end
|
218
|
+
|
219
|
+
it "does not use sudo for rm when configured" do
|
220
|
+
config[:sudo] = false
|
221
|
+
|
222
|
+
provisioner.init_command.
|
223
|
+
must_match regexify("rm -rf ", :partial_line)
|
224
|
+
provisioner.init_command.
|
225
|
+
wont_match regexify("sudo -E rm -rf ", :partial_line)
|
226
|
+
end
|
227
|
+
|
228
|
+
%w[cookbooks data data_bags environments roles clients].each do |dir|
|
229
|
+
it "removes the #{dir} directory" do
|
230
|
+
config[:root_path] = "/route"
|
231
|
+
|
232
|
+
provisioner.init_command.must_match %r{rm -rf\b.*\s+/route/#{dir}\s+}
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
it "creates :root_path directory" do
|
237
|
+
config[:root_path] = "/root/path"
|
238
|
+
|
239
|
+
provisioner.init_command.must_match regexify("mkdir -p /root/path")
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "#create_sandbox" do
|
244
|
+
|
245
|
+
before do
|
246
|
+
@root = Dir.mktmpdir
|
247
|
+
config[:kitchen_root] = @root
|
248
|
+
end
|
249
|
+
|
250
|
+
after do
|
251
|
+
FileUtils.remove_entry(@root)
|
252
|
+
begin
|
253
|
+
provisioner.cleanup_sandbox
|
254
|
+
rescue # rubocop:disable Lint/HandleExceptions
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
let(:provisioner) do
|
259
|
+
Class.new(Kitchen::Provisioner::ChefBase) {
|
260
|
+
default_config :generic_rb, {}
|
261
|
+
|
262
|
+
def create_sandbox
|
263
|
+
super
|
264
|
+
|
265
|
+
data = default_config_rb.merge(config[:generic_rb])
|
266
|
+
File.open(File.join(sandbox_path, "generic.rb"), "wb") do |file|
|
267
|
+
file.write(format_config_file(data))
|
268
|
+
end
|
269
|
+
end
|
270
|
+
}.new(config).finalize_config!(instance)
|
271
|
+
end
|
272
|
+
|
273
|
+
describe "json file" do
|
274
|
+
|
275
|
+
let(:json) { JSON.parse(IO.read(sandbox_path("dna.json"))) }
|
276
|
+
|
277
|
+
it "creates a json file with node attributes" do
|
278
|
+
config[:attributes] = { "one" => { "two" => "three" } }
|
279
|
+
provisioner.create_sandbox
|
280
|
+
|
281
|
+
json["one"].must_equal("two" => "three")
|
282
|
+
end
|
283
|
+
|
284
|
+
it "creates a json file with run_list" do
|
285
|
+
config[:run_list] = %w[alpha bravo charlie]
|
286
|
+
provisioner.create_sandbox
|
287
|
+
|
288
|
+
json["run_list"].must_equal %w[alpha bravo charlie]
|
289
|
+
end
|
290
|
+
|
291
|
+
it "creates a json file with an empty run_list" do
|
292
|
+
config[:run_list] = []
|
293
|
+
provisioner.create_sandbox
|
294
|
+
|
295
|
+
json["run_list"].must_equal []
|
296
|
+
end
|
297
|
+
|
298
|
+
it "logs a message on info" do
|
299
|
+
provisioner.create_sandbox
|
300
|
+
|
301
|
+
logged_output.string.must_match info_line("Preparing dna.json")
|
302
|
+
end
|
303
|
+
|
304
|
+
it "logs a message on debug" do
|
305
|
+
config[:run_list] = ["yo"]
|
306
|
+
provisioner.create_sandbox
|
307
|
+
|
308
|
+
logged_output.string.
|
309
|
+
must_match debug_line(%|Creating dna.json from {:run_list=>["yo"]}|)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
it "creates a cache directory" do
|
314
|
+
provisioner.create_sandbox
|
315
|
+
|
316
|
+
sandbox_path("cache").directory?.must_equal true
|
317
|
+
end
|
318
|
+
|
319
|
+
%w[data data_bags environments nodes roles clients].each do |thing|
|
320
|
+
describe "#{thing} files" do
|
321
|
+
|
322
|
+
before do
|
323
|
+
create_files_under("#{config[:kitchen_root]}/my_#{thing}")
|
324
|
+
config[:"#{thing}_path"] = "#{config[:kitchen_root]}/my_#{thing}"
|
325
|
+
end
|
326
|
+
|
327
|
+
it "skips directory creation if :#{thing}_path is not set" do
|
328
|
+
config[:"#{thing}_path"] = nil
|
329
|
+
provisioner.create_sandbox
|
330
|
+
|
331
|
+
sandbox_path(thing).directory?.must_equal false
|
332
|
+
end
|
333
|
+
|
334
|
+
it "copies tree from :#{thing}_path into sandbox" do
|
335
|
+
provisioner.create_sandbox
|
336
|
+
|
337
|
+
sandbox_path("#{thing}/alpha.txt").file?.must_equal true
|
338
|
+
IO.read(sandbox_path("#{thing}/alpha.txt")).must_equal "stuff"
|
339
|
+
sandbox_path("#{thing}/sub").directory?.must_equal true
|
340
|
+
sandbox_path("#{thing}/sub/bravo.txt").file?.must_equal true
|
341
|
+
IO.read(sandbox_path("#{thing}/sub/bravo.txt")).must_equal "junk"
|
342
|
+
end
|
343
|
+
|
344
|
+
it "logs a message on info" do
|
345
|
+
provisioner.create_sandbox
|
346
|
+
|
347
|
+
logged_output.string.must_match info_line("Preparing #{thing}")
|
348
|
+
end
|
349
|
+
|
350
|
+
it "logs a message on debug" do
|
351
|
+
provisioner.create_sandbox
|
352
|
+
|
353
|
+
logged_output.string.must_match debug_line(
|
354
|
+
"Using #{thing} from #{config[:kitchen_root]}/my_#{thing}")
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
describe "secret files" do
|
360
|
+
|
361
|
+
before do
|
362
|
+
config[:encrypted_data_bag_secret_key_path] =
|
363
|
+
"#{config[:kitchen_root]}/my_secret"
|
364
|
+
File.open("#{config[:kitchen_root]}/my_secret", "wb") do |file|
|
365
|
+
file.write("p@ss")
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
it "skips file if :encrypted_data_bag_secret_key_path is not set" do
|
370
|
+
config[:encrypted_data_bag_secret_key_path] = nil
|
371
|
+
provisioner.create_sandbox
|
372
|
+
|
373
|
+
sandbox_path("encrypted_data_bag_secret").file?.must_equal false
|
374
|
+
end
|
375
|
+
|
376
|
+
it "copies file from :encrypted_data_bag_secret_key_path into sandbox" do
|
377
|
+
provisioner.create_sandbox
|
378
|
+
|
379
|
+
sandbox_path("encrypted_data_bag_secret").file?.must_equal true
|
380
|
+
IO.read(sandbox_path("encrypted_data_bag_secret")).must_equal "p@ss"
|
381
|
+
end
|
382
|
+
|
383
|
+
it "logs a message on info" do
|
384
|
+
provisioner.create_sandbox
|
385
|
+
|
386
|
+
logged_output.string.must_match info_line("Preparing secret")
|
387
|
+
end
|
388
|
+
|
389
|
+
it "logs a message on debug" do
|
390
|
+
provisioner.create_sandbox
|
391
|
+
|
392
|
+
logged_output.string.must_match debug_line(
|
393
|
+
"Using secret from #{config[:kitchen_root]}/my_secret")
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
describe "cookbooks" do
|
398
|
+
|
399
|
+
let(:kitchen_root) { config[:kitchen_root] }
|
400
|
+
|
401
|
+
describe "with a cookbooks/ directory under kitchen_root" do
|
402
|
+
|
403
|
+
it "copies cookbooks/" do
|
404
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
405
|
+
create_cookbook("#{kitchen_root}/cookbooks/jahva")
|
406
|
+
provisioner.create_sandbox
|
407
|
+
|
408
|
+
sandbox_path("cookbooks/epache").directory?.must_equal true
|
409
|
+
sandbox_path("cookbooks/epache/recipes/default.rb").
|
410
|
+
file?.must_equal true
|
411
|
+
sandbox_path("cookbooks/jahva").directory?.must_equal true
|
412
|
+
sandbox_path("cookbooks/jahva/recipes/default.rb").
|
413
|
+
file?.must_equal true
|
414
|
+
end
|
415
|
+
|
416
|
+
it "copies from kitchen_root as cookbook if it contains metadata.rb" do
|
417
|
+
File.open("#{kitchen_root}/metadata.rb", "wb") do |file|
|
418
|
+
file.write("name 'wat'")
|
419
|
+
end
|
420
|
+
create_cookbook("#{kitchen_root}/cookbooks/bk")
|
421
|
+
provisioner.create_sandbox
|
422
|
+
|
423
|
+
sandbox_path("cookbooks/bk").directory?.must_equal true
|
424
|
+
sandbox_path("cookbooks/wat").directory?.must_equal true
|
425
|
+
sandbox_path("cookbooks/wat/metadata.rb").file?.must_equal true
|
426
|
+
end
|
427
|
+
|
428
|
+
it "copies site-cookbooks/ if it exists" do
|
429
|
+
create_cookbook("#{kitchen_root}/cookbooks/upstream")
|
430
|
+
create_cookbook("#{kitchen_root}/site-cookbooks/mine")
|
431
|
+
provisioner.create_sandbox
|
432
|
+
|
433
|
+
sandbox_path("cookbooks/upstream").directory?.must_equal true
|
434
|
+
sandbox_path("cookbooks/mine").directory?.must_equal true
|
435
|
+
sandbox_path("cookbooks/mine/attributes/all.rb").file?.must_equal true
|
436
|
+
end
|
437
|
+
|
438
|
+
it "logs a message on info for cookbooks/ directory" do
|
439
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
440
|
+
provisioner.create_sandbox
|
441
|
+
|
442
|
+
logged_output.string.must_match info_line(
|
443
|
+
"Preparing cookbooks from project directory")
|
444
|
+
end
|
445
|
+
|
446
|
+
it "logs a meesage on debug for cookbooks/ directory" do
|
447
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
448
|
+
provisioner.create_sandbox
|
449
|
+
|
450
|
+
logged_output.string.must_match debug_line(
|
451
|
+
"Using cookbooks from #{kitchen_root}/cookbooks")
|
452
|
+
end
|
453
|
+
|
454
|
+
it "logs a message on info for site-cookbooks/ directory" do
|
455
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
456
|
+
create_cookbook("#{kitchen_root}/site-cookbooks/mine")
|
457
|
+
provisioner.create_sandbox
|
458
|
+
|
459
|
+
logged_output.string.must_match info_line(
|
460
|
+
"Preparing site-cookbooks from project directory")
|
461
|
+
end
|
462
|
+
|
463
|
+
it "logs a meesage on debug for site-cookbooks/ directory" do
|
464
|
+
create_cookbook("#{kitchen_root}/cookbooks/epache")
|
465
|
+
create_cookbook("#{kitchen_root}/site-cookbooks/mine")
|
466
|
+
provisioner.create_sandbox
|
467
|
+
|
468
|
+
logged_output.string.must_match debug_line(
|
469
|
+
"Using cookbooks from #{kitchen_root}/site-cookbooks")
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
describe "with a cookbook as the project" do
|
474
|
+
|
475
|
+
before do
|
476
|
+
File.open("#{kitchen_root}/metadata.rb", "wb") do |file|
|
477
|
+
file.write("name 'wat'")
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
it "copies from kitchen_root as cookbook if it contains metadata.rb" do
|
482
|
+
provisioner.create_sandbox
|
483
|
+
|
484
|
+
sandbox_path("cookbooks/wat").directory?.must_equal true
|
485
|
+
sandbox_path("cookbooks/wat/metadata.rb").file?.must_equal true
|
486
|
+
end
|
487
|
+
|
488
|
+
it "logs a message on info" do
|
489
|
+
provisioner.create_sandbox
|
490
|
+
|
491
|
+
logged_output.string.must_match info_line(
|
492
|
+
"Preparing current project directory as a cookbook")
|
493
|
+
end
|
494
|
+
|
495
|
+
it "logs a meesage on debug" do
|
496
|
+
provisioner.create_sandbox
|
497
|
+
|
498
|
+
logged_output.string.must_match debug_line(
|
499
|
+
"Using metadata.rb from #{kitchen_root}/metadata.rb")
|
500
|
+
end
|
501
|
+
|
502
|
+
it "raises a UserError is name cannot be determined from metadata.rb" do
|
503
|
+
File.open("#{kitchen_root}/metadata.rb", "wb") do |file|
|
504
|
+
file.write("nameeeeee 'wat'")
|
505
|
+
end
|
506
|
+
|
507
|
+
proc { provisioner.create_sandbox }.must_raise Kitchen::UserError
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
describe "with no referenced cookbooks" do
|
512
|
+
|
513
|
+
it "makes a fake cookbook" do
|
514
|
+
name = File.basename(@root)
|
515
|
+
provisioner.create_sandbox
|
516
|
+
|
517
|
+
sandbox_path("cookbooks/#{name}").directory?.must_equal true
|
518
|
+
sandbox_path("cookbooks/#{name}/metadata.rb").file?.must_equal true
|
519
|
+
IO.read(sandbox_path("cookbooks/#{name}/metadata.rb")).
|
520
|
+
must_equal %{name "#{name}"\n}
|
521
|
+
end
|
522
|
+
|
523
|
+
it "logs a warning" do
|
524
|
+
provisioner.create_sandbox
|
525
|
+
|
526
|
+
logged_output.string.must_match regexify(
|
527
|
+
"Berksfile, Cheffile, cookbooks/, or metadata.rb not found",
|
528
|
+
:partial_line
|
529
|
+
)
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
describe "with a Berksfile under kitchen_root" do
|
534
|
+
|
535
|
+
let(:resolver) { stub(:resolve => true) }
|
536
|
+
|
537
|
+
before do
|
538
|
+
File.open("#{kitchen_root}/Berksfile", "wb") do |file|
|
539
|
+
file.write("cookbook 'wat'")
|
540
|
+
end
|
541
|
+
Kitchen::Provisioner::Chef::Berkshelf.stubs(:new).returns(resolver)
|
542
|
+
end
|
543
|
+
|
544
|
+
it "raises a UserError if Berkshelf library can't be loaded" do
|
545
|
+
proc { provisioner }.must_raise Kitchen::UserError
|
546
|
+
end
|
547
|
+
|
548
|
+
it "logs on debug that Berkshelf is loading" do
|
549
|
+
Kitchen::Provisioner::Chef::Berkshelf.stubs(:load!)
|
550
|
+
provisioner
|
551
|
+
|
552
|
+
logged_output.string.must_match debug_line(
|
553
|
+
"Berksfile found at #{kitchen_root}/Berksfile, loading Berkshelf")
|
554
|
+
end
|
555
|
+
|
556
|
+
it "uses Berkshelf" do
|
557
|
+
Kitchen::Provisioner::Chef::Berkshelf.stubs(:load!)
|
558
|
+
resolver.expects(:resolve)
|
559
|
+
|
560
|
+
provisioner.create_sandbox
|
561
|
+
end
|
562
|
+
|
563
|
+
it "uses Kitchen.mutex for resolving" do
|
564
|
+
Kitchen::Provisioner::Chef::Berkshelf.stubs(:load!)
|
565
|
+
Kitchen.mutex.expects(:synchronize)
|
566
|
+
|
567
|
+
provisioner.create_sandbox
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
describe "with a Cheffile under kitchen_root" do
|
572
|
+
|
573
|
+
let(:resolver) { stub(:resolve => true) }
|
574
|
+
|
575
|
+
before do
|
576
|
+
File.open("#{kitchen_root}/Cheffile", "wb") do |file|
|
577
|
+
file.write("cookbook 'wat'")
|
578
|
+
end
|
579
|
+
Kitchen::Provisioner::Chef::Librarian.stubs(:new).returns(resolver)
|
580
|
+
end
|
581
|
+
|
582
|
+
it "raises a UserError if Librarian library can't be loaded" do
|
583
|
+
proc { provisioner }.must_raise Kitchen::UserError
|
584
|
+
end
|
585
|
+
|
586
|
+
it "logs on debug that Berkshelf is loading" do
|
587
|
+
Kitchen::Provisioner::Chef::Librarian.stubs(:load!)
|
588
|
+
provisioner
|
589
|
+
|
590
|
+
logged_output.string.must_match debug_line(
|
591
|
+
"Cheffile found at #{kitchen_root}/Cheffile, loading Librarian-Chef"
|
592
|
+
)
|
593
|
+
end
|
594
|
+
|
595
|
+
it "uses Librarian" do
|
596
|
+
Kitchen::Provisioner::Chef::Librarian.stubs(:load!)
|
597
|
+
resolver.expects(:resolve)
|
598
|
+
|
599
|
+
provisioner.create_sandbox
|
600
|
+
end
|
601
|
+
|
602
|
+
it "uses Kitchen.mutex for resolving" do
|
603
|
+
Kitchen::Provisioner::Chef::Librarian.stubs(:load!)
|
604
|
+
Kitchen.mutex.expects(:synchronize)
|
605
|
+
|
606
|
+
provisioner.create_sandbox
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
describe "filtering cookbooks files" do
|
611
|
+
|
612
|
+
it "retains all useful cookbook files" do
|
613
|
+
create_full_cookbook("#{kitchen_root}/cookbooks/full")
|
614
|
+
provisioner.create_sandbox
|
615
|
+
|
616
|
+
full_cookbook_files.each do |file|
|
617
|
+
sandbox_path("cookbooks/full/#{file}").file?.must_equal true
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
it "strips extra cookbook files" do
|
622
|
+
extras = %w[
|
623
|
+
.gitignore tmp/librarian chefignore .git/info/excludes
|
624
|
+
cookbooks/another/metadata.rb CONTRIBUTING.md metadata.py
|
625
|
+
]
|
626
|
+
|
627
|
+
create_full_cookbook("#{kitchen_root}/cookbooks/full")
|
628
|
+
extras.each do |file|
|
629
|
+
create_file("#{kitchen_root}/cookbooks/full/#{file}")
|
630
|
+
end
|
631
|
+
provisioner.create_sandbox
|
632
|
+
|
633
|
+
extras.each do |file|
|
634
|
+
sandbox_path("cookbooks/full/#{file}").file?.must_equal false
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
it "logs on info" do
|
639
|
+
create_full_cookbook("#{kitchen_root}/cookbooks/full")
|
640
|
+
provisioner.create_sandbox
|
641
|
+
|
642
|
+
logged_output.string.must_match info_line(
|
643
|
+
"Removing non-cookbook files before transfer")
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
describe "Chef config files" do
|
648
|
+
|
649
|
+
let(:file) do
|
650
|
+
IO.read(sandbox_path("generic.rb")).lines.map(&:chomp)
|
651
|
+
end
|
652
|
+
|
653
|
+
it "#create_sanbox creates a generic.rb" do
|
654
|
+
provisioner.create_sandbox
|
655
|
+
|
656
|
+
sandbox_path("generic.rb").file?.must_equal true
|
657
|
+
end
|
658
|
+
|
659
|
+
describe "defaults" do
|
660
|
+
|
661
|
+
before { provisioner.create_sandbox }
|
662
|
+
|
663
|
+
it "sets node_name to the instance name" do
|
664
|
+
file.must_include %{node_name "#{instance.name}"}
|
665
|
+
end
|
666
|
+
|
667
|
+
it "sets checksum_path" do
|
668
|
+
file.must_include %{checksum_path "/tmp/kitchen/checksums"}
|
669
|
+
end
|
670
|
+
|
671
|
+
it "sets file_backup_path" do
|
672
|
+
file.must_include %{file_backup_path "/tmp/kitchen/backup"}
|
673
|
+
end
|
674
|
+
|
675
|
+
it "sets cookbook_path" do
|
676
|
+
file.must_include %{cookbook_path } +
|
677
|
+
%{["/tmp/kitchen/cookbooks", "/tmp/kitchen/site-cookbooks"]}
|
678
|
+
end
|
679
|
+
|
680
|
+
it "sets data_bag_path" do
|
681
|
+
file.must_include %{data_bag_path "/tmp/kitchen/data_bags"}
|
682
|
+
end
|
683
|
+
|
684
|
+
it "sets environment_path" do
|
685
|
+
file.must_include %{environment_path "/tmp/kitchen/environments"}
|
686
|
+
end
|
687
|
+
|
688
|
+
it "sets node_path" do
|
689
|
+
file.must_include %{node_path "/tmp/kitchen/nodes"}
|
690
|
+
end
|
691
|
+
|
692
|
+
it "sets role_path" do
|
693
|
+
file.must_include %{role_path "/tmp/kitchen/roles"}
|
694
|
+
end
|
695
|
+
|
696
|
+
it "sets client_path" do
|
697
|
+
file.must_include %{client_path "/tmp/kitchen/clients"}
|
698
|
+
end
|
699
|
+
|
700
|
+
it "sets user_path" do
|
701
|
+
file.must_include %{user_path "/tmp/kitchen/users"}
|
702
|
+
end
|
703
|
+
|
704
|
+
it "sets validation_key" do
|
705
|
+
file.must_include %{validation_key "/tmp/kitchen/validation.pem"}
|
706
|
+
end
|
707
|
+
|
708
|
+
it "sets client_key" do
|
709
|
+
file.must_include %{client_key "/tmp/kitchen/client.pem"}
|
710
|
+
end
|
711
|
+
|
712
|
+
it "sets chef_server_url" do
|
713
|
+
file.must_include %{chef_server_url "http://127.0.0.1:8889"}
|
714
|
+
end
|
715
|
+
|
716
|
+
it "sets encrypted_data_bag_secret" do
|
717
|
+
file.must_include %{encrypted_data_bag_secret } +
|
718
|
+
%{"/tmp/kitchen/encrypted_data_bag_secret"}
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
722
|
+
it "supports overwriting defaults" do
|
723
|
+
config[:generic_rb] = {
|
724
|
+
:node_name => "eagles",
|
725
|
+
:user_path => "/a/b/c/u",
|
726
|
+
:chef_server_url => "https://whereever.io"
|
727
|
+
}
|
728
|
+
provisioner.create_sandbox
|
729
|
+
|
730
|
+
file.must_include %{node_name "eagles"}
|
731
|
+
file.must_include %{user_path "/a/b/c/u"}
|
732
|
+
file.must_include %{chef_server_url "https://whereever.io"}
|
733
|
+
end
|
734
|
+
|
735
|
+
it " supports adding new configuration" do
|
736
|
+
config[:generic_rb] = {
|
737
|
+
:dark_secret => "golang"
|
738
|
+
}
|
739
|
+
provisioner.create_sandbox
|
740
|
+
|
741
|
+
file.must_include %{dark_secret "golang"}
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
745
|
+
def create_cookbook(path)
|
746
|
+
%w[metadata.rb attributes/all.rb recipes/default.rb].each do |file|
|
747
|
+
create_file(File.join(path, file))
|
748
|
+
end
|
749
|
+
end
|
750
|
+
|
751
|
+
def full_cookbook_files
|
752
|
+
%w[
|
753
|
+
README.org metadata.rb attributes/all.rb definitions/def.rb
|
754
|
+
files/default/config.conf libraries/one.rb libraries/two.rb
|
755
|
+
providers/sweet.rb recipes/default.rb resources/sweet.rb
|
756
|
+
templates/ubuntu/12.04/nginx.conf.erb
|
757
|
+
]
|
758
|
+
end
|
759
|
+
|
760
|
+
def create_full_cookbook(path)
|
761
|
+
full_cookbook_files.each { |file| create_file(File.join(path, file)) }
|
762
|
+
end
|
763
|
+
|
764
|
+
def create_file(path)
|
765
|
+
FileUtils.mkdir_p(File.dirname(path))
|
766
|
+
File.open(path, "wb") { |f| f.write(path) }
|
767
|
+
end
|
768
|
+
end
|
769
|
+
|
770
|
+
def sandbox_path(path)
|
771
|
+
Pathname.new(provisioner.sandbox_path).join(path)
|
772
|
+
end
|
773
|
+
|
774
|
+
def create_files_under(path)
|
775
|
+
FileUtils.mkdir_p(File.join(path, "sub"))
|
776
|
+
File.open(File.join(path, "alpha.txt"), "wb") do |file|
|
777
|
+
file.write("stuff")
|
778
|
+
end
|
779
|
+
File.open(File.join(path, "sub", "bravo.txt"), "wb") do |file|
|
780
|
+
file.write("junk")
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
784
|
+
def info_line(msg)
|
785
|
+
%r{^I, .* : #{Regexp.escape(msg)}$}
|
786
|
+
end
|
787
|
+
|
788
|
+
def debug_line(msg)
|
789
|
+
%r{^D, .* : #{Regexp.escape(msg)}$}
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
793
|
+
def regexify(str, line = :whole_line)
|
794
|
+
r = Regexp.escape(str)
|
795
|
+
r = "^\s*#{r}$" if line == :whole_line
|
796
|
+
Regexp.new(r)
|
797
|
+
end
|
798
|
+
end
|