test-kitchen 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +1 -1
  3. data/.rubocop.yml +3 -0
  4. data/.travis.yml +20 -9
  5. data/CHANGELOG.md +219 -108
  6. data/Gemfile +10 -6
  7. data/Guardfile +38 -9
  8. data/README.md +11 -1
  9. data/Rakefile +21 -37
  10. data/bin/kitchen +4 -4
  11. data/features/kitchen_action_commands.feature +161 -0
  12. data/features/kitchen_console_command.feature +34 -0
  13. data/features/kitchen_diagnose_command.feature +64 -0
  14. data/features/kitchen_init_command.feature +29 -17
  15. data/features/kitchen_list_command.feature +2 -2
  16. data/features/kitchen_login_command.feature +56 -0
  17. data/features/{sink_command.feature → kitchen_sink_command.feature} +0 -0
  18. data/features/kitchen_test_command.feature +88 -0
  19. data/features/step_definitions/gem_steps.rb +8 -6
  20. data/features/step_definitions/git_steps.rb +4 -2
  21. data/features/step_definitions/output_steps.rb +5 -0
  22. data/features/support/env.rb +12 -9
  23. data/lib/kitchen.rb +60 -38
  24. data/lib/kitchen/base64_stream.rb +55 -0
  25. data/lib/kitchen/busser.rb +124 -58
  26. data/lib/kitchen/cli.rb +121 -38
  27. data/lib/kitchen/collection.rb +3 -3
  28. data/lib/kitchen/color.rb +4 -4
  29. data/lib/kitchen/command.rb +78 -11
  30. data/lib/kitchen/command/action.rb +3 -2
  31. data/lib/kitchen/command/console.rb +12 -5
  32. data/lib/kitchen/command/diagnose.rb +17 -3
  33. data/lib/kitchen/command/driver_discover.rb +26 -7
  34. data/lib/kitchen/command/exec.rb +41 -0
  35. data/lib/kitchen/command/list.rb +44 -14
  36. data/lib/kitchen/command/login.rb +2 -1
  37. data/lib/kitchen/command/sink.rb +2 -1
  38. data/lib/kitchen/command/test.rb +5 -4
  39. data/lib/kitchen/config.rb +146 -14
  40. data/lib/kitchen/configurable.rb +314 -0
  41. data/lib/kitchen/data_munger.rb +522 -18
  42. data/lib/kitchen/diagnostic.rb +43 -4
  43. data/lib/kitchen/driver.rb +4 -4
  44. data/lib/kitchen/driver/base.rb +80 -115
  45. data/lib/kitchen/driver/dummy.rb +34 -6
  46. data/lib/kitchen/driver/proxy.rb +14 -3
  47. data/lib/kitchen/driver/ssh_base.rb +61 -7
  48. data/lib/kitchen/errors.rb +109 -9
  49. data/lib/kitchen/generator/driver_create.rb +39 -5
  50. data/lib/kitchen/generator/init.rb +130 -45
  51. data/lib/kitchen/instance.rb +162 -28
  52. data/lib/kitchen/lazy_hash.rb +79 -7
  53. data/lib/kitchen/loader/yaml.rb +159 -27
  54. data/lib/kitchen/logger.rb +267 -21
  55. data/lib/kitchen/logging.rb +30 -3
  56. data/lib/kitchen/login_command.rb +11 -2
  57. data/lib/kitchen/metadata_chopper.rb +2 -2
  58. data/lib/kitchen/provisioner.rb +4 -4
  59. data/lib/kitchen/provisioner/base.rb +107 -103
  60. data/lib/kitchen/provisioner/chef/berkshelf.rb +36 -8
  61. data/lib/kitchen/provisioner/chef/librarian.rb +40 -11
  62. data/lib/kitchen/provisioner/chef_base.rb +206 -167
  63. data/lib/kitchen/provisioner/chef_solo.rb +25 -7
  64. data/lib/kitchen/provisioner/chef_zero.rb +105 -29
  65. data/lib/kitchen/provisioner/dummy.rb +1 -1
  66. data/lib/kitchen/provisioner/shell.rb +21 -6
  67. data/lib/kitchen/rake_tasks.rb +8 -3
  68. data/lib/kitchen/shell_out.rb +15 -18
  69. data/lib/kitchen/ssh.rb +122 -27
  70. data/lib/kitchen/state_file.rb +24 -7
  71. data/lib/kitchen/thor_tasks.rb +9 -4
  72. data/lib/kitchen/util.rb +43 -118
  73. data/lib/kitchen/version.rb +1 -1
  74. data/lib/vendor/hash_recursive_merge.rb +10 -2
  75. data/spec/kitchen/base64_stream_spec.rb +77 -0
  76. data/spec/kitchen/busser_spec.rb +490 -0
  77. data/spec/kitchen/collection_spec.rb +10 -10
  78. data/spec/kitchen/color_spec.rb +2 -2
  79. data/spec/kitchen/config_spec.rb +234 -62
  80. data/spec/kitchen/configurable_spec.rb +490 -0
  81. data/spec/kitchen/data_munger_spec.rb +1070 -862
  82. data/spec/kitchen/diagnostic_spec.rb +79 -0
  83. data/spec/kitchen/driver/base_spec.rb +80 -85
  84. data/spec/kitchen/driver/dummy_spec.rb +43 -14
  85. data/spec/kitchen/driver/proxy_spec.rb +134 -0
  86. data/spec/kitchen/driver/ssh_base_spec.rb +644 -0
  87. data/spec/kitchen/driver_spec.rb +15 -15
  88. data/spec/kitchen/errors_spec.rb +309 -0
  89. data/spec/kitchen/instance_spec.rb +143 -46
  90. data/spec/kitchen/lazy_hash_spec.rb +36 -9
  91. data/spec/kitchen/loader/yaml_spec.rb +237 -226
  92. data/spec/kitchen/logger_spec.rb +419 -0
  93. data/spec/kitchen/logging_spec.rb +59 -0
  94. data/spec/kitchen/login_command_spec.rb +49 -0
  95. data/spec/kitchen/metadata_chopper_spec.rb +82 -0
  96. data/spec/kitchen/platform_spec.rb +4 -4
  97. data/spec/kitchen/provisioner/base_spec.rb +65 -125
  98. data/spec/kitchen/provisioner/chef_base_spec.rb +798 -0
  99. data/spec/kitchen/provisioner/chef_solo_spec.rb +316 -0
  100. data/spec/kitchen/provisioner/chef_zero_spec.rb +624 -0
  101. data/spec/kitchen/provisioner/shell_spec.rb +269 -0
  102. data/spec/kitchen/provisioner_spec.rb +6 -6
  103. data/spec/kitchen/shell_out_spec.rb +143 -0
  104. data/spec/kitchen/ssh_spec.rb +683 -0
  105. data/spec/kitchen/state_file_spec.rb +28 -21
  106. data/spec/kitchen/suite_spec.rb +7 -7
  107. data/spec/kitchen/util_spec.rb +68 -10
  108. data/spec/kitchen_spec.rb +107 -0
  109. data/spec/spec_helper.rb +18 -13
  110. data/support/chef-client-zero.rb +10 -9
  111. data/support/chef_helpers.sh +16 -0
  112. data/support/download_helpers.sh +109 -0
  113. data/test-kitchen.gemspec +42 -33
  114. 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 '../spec_helper'
19
+ require_relative "../spec_helper"
20
20
 
21
- require 'kitchen/errors'
22
- require 'kitchen/platform'
21
+ require "kitchen/errors"
22
+ require "kitchen/platform"
23
23
 
24
24
  describe Kitchen::Platform do
25
25
 
26
- let(:opts) do ; { :name => 'plata' } ; end
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 '../../spec_helper'
20
- require 'stringio'
19
+ require_relative "../../spec_helper"
20
+ require "logger"
21
+ require "stringio"
21
22
 
22
- require 'kitchen'
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 => instance_logger)
32
+ stub(:name => "coolbeans", :logger => logger)
65
33
  end
66
34
 
67
35
  let(:provisioner) do
68
- p = Kitchen::Provisioner::Base.new(config)
69
- p.instance = instance
70
- p
36
+ Kitchen::Provisioner::Base.new(config).finalize_config!(instance)
71
37
  end
72
38
 
73
- it "#instance returns its instance" do
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 "user config" do
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 ".default_config" do
54
+ describe "#logger" do
108
55
 
109
- describe "static default config" do
56
+ before { @klog = Kitchen.logger }
57
+ after { Kitchen.logger = @klog }
110
58
 
111
- let(:provisioner) do
112
- p = Kitchen::Provisioner::StaticDefaults.new(config)
113
- p.instance = instance
114
- p
115
- end
59
+ it "returns the instance's logger" do
60
+ provisioner.send(:logger).must_equal logger
61
+ end
116
62
 
117
- it "uses default config" do
118
- provisioner[:rank].must_equal "captain"
119
- provisioner[:tunables]["foo"].must_equal "fa"
120
- provisioner[:nice].must_equal true
121
- end
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
- it "uses user config over default config" do
124
- config[:rank] = "commander"
125
- config[:nice] = :maybe
71
+ [:init_command, :install_command, :prepare_command, :run_command].each do |cmd|
126
72
 
127
- provisioner[:rank].must_equal "commander"
128
- provisioner[:tunables]["foo"].must_equal "fa"
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
- describe "inherited static default config" do
78
+ describe "sandbox" do
134
79
 
135
- let(:provisioner) do
136
- p = Kitchen::Provisioner::SubclassDefaults.new(config)
137
- p.instance = instance
138
- p
80
+ after do
81
+ begin
82
+ provisioner.cleanup_sandbox
83
+ rescue # rubocop:disable Lint/HandleExceptions
139
84
  end
85
+ end
140
86
 
141
- it "contains defaults from superclass" do
142
- provisioner[:rank].must_equal "captain"
143
- provisioner[:tunables]["foo"].must_equal "fa"
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
- it "uses user config over default config" do
149
- config[:rank] = "commander"
150
- config[:nice] = :maybe
91
+ it "#create_sandbox creates a temporary directory" do
92
+ provisioner.create_sandbox
151
93
 
152
- provisioner[:rank].must_equal "commander"
153
- provisioner[:tunables]["foo"].must_equal "fa"
154
- provisioner[:nice].must_equal :maybe
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
- describe "computed default config" do
99
+ it "#create_sandbox logs an info message" do
100
+ provisioner.create_sandbox
160
101
 
161
- let(:provisioner) do
162
- p = Kitchen::Provisioner::ComputedDefaults.new(config)
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
- it "uses computed config" do
168
- provisioner[:beans_url].must_equal "http://gim.me/kidney"
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
- it "has access to instance object" do
173
- provisioner[:fetch_url].must_equal "http://gim.me/beans-for/coolbeans"
174
- end
108
+ logged_output.string.
109
+ must_match debug_line_starting_with("Creating local sandbox in ")
110
+ end
175
111
 
176
- it "uses user config over default config" do
177
- config[:command] = "echo listentome"
112
+ it "#cleanup_sandbox deletes the sandbox directory" do
113
+ provisioner.create_sandbox
114
+ provisioner.cleanup_sandbox
178
115
 
179
- provisioner[:command].must_equal "echo listentome"
180
- end
116
+ File.directory?(provisioner.sandbox_path).must_equal false
181
117
  end
182
- end
183
118
 
184
- describe "#logger" do
119
+ it "#cleanup_sandbox logs a debug message" do
120
+ provisioner.create_sandbox
121
+ provisioner.cleanup_sandbox
185
122
 
186
- it "if instance is set, use its logger" do
187
- provisioner.send(:logger).must_equal instance_logger
123
+ logged_output.string.
124
+ must_match debug_line_starting_with("Cleaning up local sandbox in ")
188
125
  end
189
126
 
190
- it "if instance is not set, use Kitchen.logger" do
191
- provisioner.instance = nil
192
- provisioner.send(:logger).must_equal Kitchen.logger
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