chef-apply 0.2.8 → 0.2.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,63 @@
1
+
2
+
3
+ module ChefApply
4
+ class TargetHost
5
+ module Linux
6
+ def omnibus_manifest_path
7
+ # TODO - if habitat install on target, this won't work
8
+ # Note that we can't use File::Join, because that will render for the
9
+ # CURRENT platform - not the platform of the target.
10
+ "/opt/chef/version-manifest.json"
11
+ end
12
+
13
+ def mkdir(path)
14
+ run_command!("mkdir -p #{path}")
15
+ end
16
+
17
+ def chown(path, owner)
18
+ owner ||= user()
19
+ run_command!("chown #{owner} '#{path}'")
20
+ nil
21
+ end
22
+
23
+ def make_temp_dir
24
+ # We will cache this so that we only
25
+ @tempdir ||= begin
26
+ res = run_command!("bash -c '#{MKTEMP_COMMAND}'")
27
+ res.stdout.chomp.strip
28
+ end
29
+ end
30
+
31
+ def install_package(target_package_path)
32
+ install_cmd = case File.extname(target_package_path)
33
+ when ".rpm"
34
+ "rpm -Uvh #{target_package_path}"
35
+ when ".deb"
36
+ "dpkg -i #{target_package_path}"
37
+ end
38
+ run_command!(install_cmd)
39
+ nil
40
+ end
41
+
42
+ def del_file(path)
43
+ run_command!("rm -rf #{path}")
44
+ end
45
+
46
+ def del_dir(path)
47
+ del_file(path)
48
+ end
49
+
50
+ def ws_cache_path
51
+ "/var/chef-workstation"
52
+ end
53
+
54
+ # Nothing to escape in a linux-based path
55
+ def normalize_path(path)
56
+ path
57
+ end
58
+
59
+ MKTEMP_COMMAND = "d=$(mktemp -d -p${TMPDIR:-/tmp} chef_XXXXXX); echo $d".freeze
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,62 @@
1
+
2
+ module ChefApply
3
+ class TargetHost
4
+ module Windows
5
+ def omnibus_manifest_path
6
+ # TODO - use a proper method to query the win installation path -
7
+ # currently we're assuming the default, but this can be customized
8
+ # at install time.
9
+ # A working approach is below - but it runs very slowly (~10s) in testing
10
+ # on a virtualbox windows vm:
11
+ # (over winrm) Get-WmiObject Win32_Product | Where {$_.Name -match 'Chef Client'}
12
+ # TODO - if habitat install on target, this won't work
13
+ "c:\\opscode\\chef\\version-manifest.json"
14
+ end
15
+
16
+ def mkdir(path)
17
+ run_command!("New-Item -ItemType Directory -Force -Path #{path}")
18
+ end
19
+
20
+ def chown(path, owner)
21
+ # This implementation left intentionally blank.
22
+ # To date, we have not needed chown functionality on windows;
23
+ # when/if that changes we'll need to implement it here.
24
+ nil
25
+ end
26
+
27
+ def make_temp_dir
28
+ @tmpdir ||= begin
29
+ res = run_command!(MKTEMP_COMMAND)
30
+ res.stdout.chomp.strip
31
+ end
32
+ end
33
+
34
+ def install_package(target_package_path)
35
+ # While powershell does not mind the mixed path separators \ and /,
36
+ # 'cmd.exe' definitely does - so we'll make the path cmd-friendly
37
+ # before running the command
38
+ cmd = "cmd /c msiexec /package #{target_package_path.tr("/", "\\")} /quiet"
39
+ run_command!(cmd)
40
+ nil
41
+ end
42
+
43
+ def del_file(path)
44
+ run_command!("If (Test-Path #{path}) { Remove-Item -Force -Path #{path} }")
45
+ end
46
+
47
+ def del_dir(path)
48
+ run_command!("Remove-Item -Recurse -Force –Path #{path}")
49
+ end
50
+
51
+ def ws_cache_path
52
+ '#{ENV[\'APPDATA\']}/chef-workstation'
53
+ end
54
+
55
+ MKTEMP_COMMAND = "$parent = [System.IO.Path]::GetTempPath();" +
56
+ "[string] $name = [System.Guid]::NewGuid();" +
57
+ "$tmp = New-Item -ItemType Directory -Path " +
58
+ "(Join-Path $parent $name);" +
59
+ "$tmp.FullName".freeze
60
+ end
61
+ end
62
+ end
@@ -16,5 +16,5 @@
16
16
  #
17
17
 
18
18
  module ChefApply
19
- VERSION = "0.2.8".freeze
19
+ VERSION = "0.2.13".freeze
20
20
  end
@@ -40,6 +40,7 @@ ARGUMENTS:
40
40
  you to specify which recipe to use from the cookbook.
41
41
 
42
42
  FLAGS:
43
+ --chef-license ACCEPTANCE Accept the license for this product and any contained products ('accept', 'accept-no-persist', or 'accept-silent')
43
44
  -c, --config PATH Location of config file. Default: $HOME/.chef-workstation/config.toml
44
45
  --cookbook-repo-paths PATH Comma separated list of cookbook repository paths.
45
46
  -h, --help Show help and usage for `chef-run`
@@ -56,34 +56,4 @@ RSpec.describe ChefApply::Action::Base do
56
56
  end
57
57
  end
58
58
 
59
- shared_examples "check path fetching" do
60
- [:chef_client, :cache_path, :read_chef_report, :delete_chef_report, :tempdir, :delete_folder].each do |path|
61
- it "correctly returns path #{path}" do
62
- expect(action.send(path)).to be_a(String)
63
- end
64
- end
65
- end
66
-
67
- describe "when connecting to a windows target" do
68
- include_examples "check path fetching"
69
-
70
- it "correctly returns chef run string" do
71
- expect(action.run_chef("a", "b", "c")).to eq(
72
- "Set-Location -Path a; " \
73
- "chef-client -z --config #{File.join("a", "b")} --recipe-url #{File.join("a", "c")} | Out-Null; " \
74
- "Set-Location C:/; " \
75
- "exit $LASTEXITCODE"
76
- )
77
- end
78
- end
79
-
80
- describe "when connecting to a non-windows target" do
81
- let(:family) { "linux" }
82
- include_examples "check path fetching"
83
-
84
- it "correctly returns chef run string" do
85
- expect(action.run_chef("a", "b", "c")).to eq("bash -c 'cd a; chef-client -z --config a/b --recipe-url a/c'")
86
- end
87
- end
88
-
89
59
  end
@@ -23,30 +23,33 @@ require "chef_apply/temp_cookbook"
23
23
 
24
24
  RSpec.describe ChefApply::Action::ConvergeTarget do
25
25
  let(:archive) { "archive.tgz" }
26
+ let(:cache_path) { "/var/chef-workstation" }
27
+ let(:platform_family) { "windows" }
28
+ let(:base_os) { :windows }
26
29
  let(:target_host) do
27
- p = double("platform", family: "windows")
28
- instance_double(ChefApply::TargetHost, platform: p)
30
+ p = double("platform", family: platform_family)
31
+ double(ChefApply::TargetHost,
32
+ platform: p, base_os: base_os, ws_cache_path: cache_path)
29
33
  end
30
34
  let(:local_policy_path) { "/local/policy/path/archive.tgz" }
31
35
  let(:opts) { { target_host: target_host, local_policy_path: local_policy_path } }
32
- subject(:action) { ChefApply::Action::ConvergeTarget.new(opts) }
36
+ subject { ChefApply::Action::ConvergeTarget.new(opts) }
33
37
 
38
+ before do
39
+ allow(target_host).to receive(:normalize_path) { |arg| arg }
40
+ end
34
41
  describe "#create_remote_policy" do
35
- let(:remote_folder) { "/tmp/foo" }
36
- let(:remote_archive) { File.join(remote_folder, File.basename(archive)) }
37
-
38
- before do
39
- end
42
+ let(:remote_archive) { File.join(cache_path, File.basename(archive)) }
40
43
 
41
44
  it "pushes it to the remote machine" do
42
45
  expect(target_host).to receive(:upload_file).with(local_policy_path, remote_archive)
43
- expect(subject.create_remote_policy(local_policy_path, remote_folder)).to eq(remote_archive)
46
+ expect(subject.create_remote_policy(local_policy_path, cache_path)).to eq(remote_archive)
44
47
  end
45
48
 
46
49
  it "raises an error if the upload fails" do
47
50
  expect(target_host).to receive(:upload_file).with(local_policy_path, remote_archive).and_raise("foo")
48
51
  err = ChefApply::Action::ConvergeTarget::PolicyUploadFailed
49
- expect { subject.create_remote_policy(local_policy_path, remote_folder) }.to raise_error(err)
52
+ expect { subject.create_remote_policy(local_policy_path, cache_path) }.to raise_error(err)
50
53
  end
51
54
  end
52
55
 
@@ -54,46 +57,78 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
54
57
 
55
58
  @closed = false # tempfile close indicator
56
59
  let(:remote_folder) { "/tmp/foo" }
57
- let(:remote_config) { "#{remote_folder}/workstation.rb" }
60
+ let(:remote_config_path) { "#{remote_folder}/workstation.rb" }
58
61
  # TODO - mock this, I think we're leaving things behind in /tmp in test runs.
59
62
  let!(:local_tempfile) { Tempfile.new }
60
63
 
64
+ before do
65
+ allow(Tempfile).to receive(:new).and_return(local_tempfile)
66
+ end
67
+
61
68
  it "pushes it to the remote machine" do
62
- expect(Tempfile).to receive(:new).and_return(local_tempfile)
63
- expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config)
64
- expect(subject.create_remote_config(remote_folder)).to eq(remote_config)
69
+ expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
70
+ expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
65
71
  # ensure the tempfile is deleted locally
66
72
  expect(local_tempfile.closed?).to eq(true)
67
73
  end
68
74
 
69
75
  it "raises an error if the upload fails" do
70
- expect(Tempfile).to receive(:new).and_return(local_tempfile)
71
- expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config).and_raise("foo")
76
+ expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path).and_raise("foo")
72
77
  err = ChefApply::Action::ConvergeTarget::ConfigUploadFailed
73
78
  expect { subject.create_remote_config(remote_folder) }.to raise_error(err)
74
79
  # ensure the tempfile is deleted locally
75
80
  expect(local_tempfile.closed?).to eq(true)
76
81
  end
77
82
 
83
+ describe "when chef_license is configured" do
84
+ before do
85
+ ChefApply::Config.chef.chef_license = "accept-no-persist"
86
+ end
87
+
88
+ after do
89
+ ChefApply::Config.reset
90
+ end
91
+
92
+ it "creates a config file with chef_license set and quoted" do
93
+ expect(Tempfile).to receive(:new).and_return(local_tempfile)
94
+ expect(local_tempfile).to receive(:write).with(<<~EOM
95
+ local_mode true
96
+ color false
97
+ cache_path "#{cache_path}"
98
+ chef_repo_path "#{cache_path}"
99
+ require_relative "reporter"
100
+ reporter = ChefApply::Reporter.new
101
+ report_handlers << reporter
102
+ exception_handlers << reporter
103
+ chef_license "accept-no-persist"
104
+ EOM
105
+ )
106
+ expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
107
+ expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
108
+ expect(local_tempfile.closed?).to eq(true)
109
+ end
110
+ end
111
+
78
112
  describe "when target_level is left default" do
79
113
  before do
80
114
  ChefApply::Config.reset
81
115
  end
116
+ # TODO - this is a windows config, but we don't set windows?
82
117
  it "creates a config file without a specific log_level (leaving default for chef-client)" do
83
118
  expect(Tempfile).to receive(:new).and_return(local_tempfile)
84
119
  expect(local_tempfile).to receive(:write).with(<<~EOM
85
120
  local_mode true
86
121
  color false
87
- cache_path "\#{ENV['APPDATA']}/chef-workstation"
88
- chef_repo_path "\#{ENV['APPDATA']}/chef-workstation"
122
+ cache_path "#{cache_path}"
123
+ chef_repo_path "#{cache_path}"
89
124
  require_relative "reporter"
90
125
  reporter = ChefApply::Reporter.new
91
126
  report_handlers << reporter
92
127
  exception_handlers << reporter
93
128
  EOM
94
129
  )
95
- expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config)
96
- expect(subject.create_remote_config(remote_folder)).to eq(remote_config)
130
+ expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
131
+ expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
97
132
  expect(local_tempfile.closed?).to eq(true)
98
133
  end
99
134
  end
@@ -112,8 +147,8 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
112
147
  expect(local_tempfile).to receive(:write).with(<<~EOM
113
148
  local_mode true
114
149
  color false
115
- cache_path "\#{ENV['APPDATA']}/chef-workstation"
116
- chef_repo_path "\#{ENV['APPDATA']}/chef-workstation"
150
+ cache_path "#{cache_path}"
151
+ chef_repo_path "#{cache_path}"
117
152
  require_relative "reporter"
118
153
  reporter = ChefApply::Reporter.new
119
154
  report_handlers << reporter
@@ -121,8 +156,8 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
121
156
  log_level :info
122
157
  EOM
123
158
  )
124
- expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config)
125
- expect(subject.create_remote_config(remote_folder)).to eq(remote_config)
159
+ expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
160
+ expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
126
161
  expect(local_tempfile.closed?).to eq(true)
127
162
  end
128
163
  end
@@ -142,8 +177,8 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
142
177
  expect(local_tempfile).to receive(:write).with(<<~EOM
143
178
  local_mode true
144
179
  color false
145
- cache_path "\#{ENV['APPDATA']}/chef-workstation"
146
- chef_repo_path "\#{ENV['APPDATA']}/chef-workstation"
180
+ cache_path "#{cache_path}"
181
+ chef_repo_path "#{cache_path}"
147
182
  require_relative "reporter"
148
183
  reporter = ChefApply::Reporter.new
149
184
  report_handlers << reporter
@@ -154,8 +189,8 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
154
189
  data_collector.organization "Chef Workstation"
155
190
  EOM
156
191
  )
157
- expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config)
158
- expect(subject.create_remote_config(remote_folder)).to eq(remote_config)
192
+ expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
193
+ expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
159
194
  # ensure the tempfile is deleted locally
160
195
  expect(local_tempfile.closed?).to eq(true)
161
196
  end
@@ -172,16 +207,16 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
172
207
  expect(local_tempfile).to receive(:write).with(<<~EOM
173
208
  local_mode true
174
209
  color false
175
- cache_path "\#{ENV['APPDATA']}/chef-workstation"
176
- chef_repo_path "\#{ENV['APPDATA']}/chef-workstation"
210
+ cache_path "#{cache_path}"
211
+ chef_repo_path "#{cache_path}"
177
212
  require_relative "reporter"
178
213
  reporter = ChefApply::Reporter.new
179
214
  report_handlers << reporter
180
215
  exception_handlers << reporter
181
216
  EOM
182
217
  )
183
- expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config)
184
- expect(subject.create_remote_config(remote_folder)).to eq(remote_config)
218
+ expect(target_host).to receive(:upload_file).with(local_tempfile.path, remote_config_path)
219
+ expect(subject.create_remote_config(remote_folder)).to eq(remote_config_path)
185
220
  # ensure the tempfile is deleted locally
186
221
  expect(local_tempfile.closed?).to eq(true)
187
222
  end
@@ -232,7 +267,7 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
232
267
  let!(:cert2) { FileUtils.touch(File.join(certs_dir, "2.pem"))[0] }
233
268
 
234
269
  it "uploads the local certs" do
235
- expect(target_host).to receive(:mkdir).with(remote_tcd)
270
+ expect(target_host).to receive(:make_directory).with(remote_tcd)
236
271
  expect(target_host).to receive(:upload_file).with(cert1, File.join(remote_tcd, File.basename(cert1)))
237
272
  expect(target_host).to receive(:upload_file).with(cert2, File.join(remote_tcd, File.basename(cert2)))
238
273
  subject.upload_trusted_certs(remote_folder)
@@ -256,21 +291,24 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
256
291
  let(:remote_handler) { "#{remote_folder}/reporter.rb" }
257
292
  let(:tmpdir) { remote_folder }
258
293
  before do
259
- expect(target_host).to receive(:mktemp).and_return(tmpdir)
294
+ expect(target_host).to receive(:temp_dir).and_return(tmpdir)
295
+ expect(subject).to receive(:create_remote_policy).with(local_policy_path, remote_folder).and_return(remote_archive)
296
+ expect(subject).to receive(:create_remote_config).with(remote_folder).and_return(remote_config)
297
+ expect(subject).to receive(:create_remote_handler).with(remote_folder).and_return(remote_handler)
298
+ expect(subject).to receive(:upload_trusted_certs).with(remote_folder)
260
299
  end
261
300
  let(:result) { double("command result", exit_status: 0, stdout: "") }
262
301
 
263
302
  it "runs the converge and reports back success" do
264
- expect(action).to receive(:create_remote_policy).with(local_policy_path, remote_folder).and_return(remote_archive)
265
- expect(action).to receive(:create_remote_config).with(remote_folder).and_return(remote_config)
266
- expect(action).to receive(:create_remote_handler).with(remote_folder).and_return(remote_handler)
267
- expect(action).to receive(:upload_trusted_certs).with(remote_folder)
268
- expect(target_host).to receive(:run_command).with(/chef-client.+#{archive}/).and_return(result)
269
- expect(target_host).to receive(:run_command!)
270
- .with("#{subject.delete_folder} #{remote_folder}")
271
- .and_return(result)
303
+ # Note we're only ensuring the command looks the same as #run_chef_cmd - we verify that run_chef_cmd
304
+ # is correct in its own test elsewhere in this file
305
+ expect(target_host).to receive(:run_command).with(subject.run_chef_cmd(remote_folder,
306
+ "workstation.rb",
307
+ "archive.tgz")).and_return result
308
+ expect(target_host).to receive(:del_dir).with(remote_folder).and_return result
309
+
272
310
  [:running_chef, :success].each do |n|
273
- expect(action).to receive(:notify).with(n)
311
+ expect(subject).to receive(:notify).with(n)
274
312
  end
275
313
  subject.perform_action
276
314
  end
@@ -279,16 +317,12 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
279
317
  let(:result) { double("command result", exit_status: 35) }
280
318
 
281
319
  it "runs the converge and reports back reboot" do
282
- expect(action).to receive(:create_remote_policy).with(local_policy_path, remote_folder).and_return(remote_archive)
283
- expect(action).to receive(:create_remote_config).with(remote_folder).and_return(remote_config)
284
- expect(action).to receive(:create_remote_handler).with(remote_folder).and_return(remote_handler)
285
- expect(action).to receive(:upload_trusted_certs).with(remote_folder)
286
- expect(target_host).to receive(:run_command).with(/chef-client.+#{archive}/).and_return(result)
287
- expect(target_host).to receive(:run_command!)
288
- .with("#{subject.delete_folder} #{remote_folder}")
289
- .and_return(result)
320
+ expect(target_host).to receive(:run_command).with(subject.run_chef_cmd(remote_folder,
321
+ "workstation.rb",
322
+ "archive.tgz")).and_return result
323
+ expect(target_host).to receive(:del_dir).with(remote_folder).and_return result
290
324
  [:running_chef, :reboot].each do |n|
291
- expect(action).to receive(:notify).with(n)
325
+ expect(subject).to receive(:notify).with(n)
292
326
  end
293
327
  subject.perform_action
294
328
  end
@@ -296,7 +330,7 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
296
330
 
297
331
  context "when command fails" do
298
332
  let(:result) { double("command result", exit_status: 1, stdout: "", stderr: "") }
299
- let(:report_result) { double("report result", exit_status: 0, stdout: '{ "exception": "thing" }') }
333
+ let(:report_result) { '{ "exception": "thing" }' }
300
334
  let(:exception_mapper) { double("mapper") }
301
335
  before do
302
336
  expect(ChefApply::Errors::CCRFailureMapper).to receive(:new)
@@ -304,41 +338,64 @@ RSpec.describe ChefApply::Action::ConvergeTarget do
304
338
  end
305
339
 
306
340
  it "reports back failure and reads the remote report" do
307
- expect(action).to receive(:create_remote_policy).with(local_policy_path, remote_folder).and_return(remote_archive)
308
- expect(action).to receive(:create_remote_config).with(remote_folder).and_return(remote_config)
309
- expect(action).to receive(:create_remote_handler).with(remote_folder).and_return(remote_handler)
310
- expect(action).to receive(:upload_trusted_certs).with(remote_folder)
311
- expect(target_host).to receive(:run_command).with(/chef-client.+#{archive}/).and_return(result)
312
- expect(target_host).to receive(:run_command!)
313
- .with("#{subject.delete_folder} #{remote_folder}")
341
+ expect(target_host).to receive(:run_command).with(subject.run_chef_cmd(remote_folder,
342
+ "workstation.rb",
343
+ "archive.tgz")).and_return result
344
+ expect(target_host).to receive(:del_dir).with(remote_folder).and_return result
314
345
  [:running_chef, :converge_error].each do |n|
315
- expect(action).to receive(:notify).with(n)
346
+ expect(subject).to receive(:notify).with(n)
316
347
  end
317
- expect(target_host).to receive(:run_command).with(subject.read_chef_report).and_return(report_result)
318
- expect(target_host).to receive(:run_command!).with(subject.delete_chef_report)
348
+ expect(target_host).to receive(:fetch_file_contents).with(subject.chef_report_path).and_return(report_result)
349
+ expect(target_host).to receive(:del_file).with(subject.chef_report_path)
319
350
  expect(exception_mapper).to receive(:raise_mapped_exception!)
320
351
  subject.perform_action
321
352
  end
322
353
 
323
354
  context "when remote report cannot be read" do
324
- let(:report_result) { double("report result", exit_status: 1, stdout: "", stderr: "") }
355
+ let(:report_result) { nil }
325
356
  it "reports back failure" do
326
- expect(action).to receive(:create_remote_policy).with(local_policy_path, remote_folder).and_return(remote_archive)
327
- expect(action).to receive(:create_remote_config).with(remote_folder).and_return(remote_config)
328
- expect(action).to receive(:create_remote_handler).with(remote_folder).and_return(remote_handler)
329
- expect(action).to receive(:upload_trusted_certs).with(remote_folder)
330
- expect(target_host).to receive(:run_command).with(/chef-client.+#{archive}/).and_return(result)
331
- expect(target_host).to receive(:run_command!)
332
- .with("#{subject.delete_folder} #{remote_folder}")
357
+ expect(target_host).to receive(:run_command).with(subject.run_chef_cmd(remote_folder,
358
+ "workstation.rb",
359
+ "archive.tgz")).and_return result
360
+ expect(target_host).to receive(:del_dir).with(remote_folder).and_return result
333
361
  [:running_chef, :converge_error].each do |n|
334
- expect(action).to receive(:notify).with(n)
362
+ expect(subject).to receive(:notify).with(n)
335
363
  end
336
- expect(target_host).to receive(:run_command).with(subject.read_chef_report).and_return(report_result)
364
+ expect(target_host).to receive(:fetch_file_contents).with(subject.chef_report_path).and_return(report_result)
337
365
  expect(exception_mapper).to receive(:raise_mapped_exception!)
338
366
  subject.perform_action
339
367
  end
340
368
  end
341
369
  end
370
+
371
+ end
372
+
373
+ context "#run_chef_cmd" do
374
+ describe "when connecting to a windows target" do
375
+ let(:base_os) { :windows }
376
+ # BOOTSTRAP TODO - can't find these examples anywhere - not sure how this was passing
377
+ # include_examples "check path fetching"
378
+
379
+ it "correctly returns chef run string" do
380
+ expect(subject.run_chef_cmd("a", "b", "c")).to eq(
381
+ "Set-Location -Path a; " \
382
+ "chef-client -z --config #{File.join("a", "b")} --recipe-url #{File.join("a", "c")} | Out-Null; " \
383
+ "Set-Location C:/; " \
384
+ "exit $LASTEXITCODE"
385
+ )
386
+ end
387
+ end
388
+
389
+ describe "when connecting to a non-windows target" do
390
+ let(:base_os) { :linux }
391
+ # BOOTSTRAP TODO - can't find these examples anywhere - not sure how this was passing
392
+ # include_examples "check path fetching"
393
+
394
+ it "correctly returns chef run string" do
395
+ expect(subject.run_chef_cmd("a", "b", "c")).to eq("bash -c 'cd a; chef-client -z --config a/b --recipe-url a/c'")
396
+ end
397
+ end
398
+
342
399
  end
343
400
 
344
401
  end