test-kitchen 1.4.0.beta.2 → 1.4.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -0
  3. data/features/kitchen_diagnose_command.feature +32 -0
  4. data/lib/kitchen/cli.rb +3 -0
  5. data/lib/kitchen/command/diagnose.rb +6 -1
  6. data/lib/kitchen/configurable.rb +48 -1
  7. data/lib/kitchen/diagnostic.rb +29 -0
  8. data/lib/kitchen/driver/base.rb +25 -0
  9. data/lib/kitchen/driver/dummy.rb +4 -0
  10. data/lib/kitchen/driver/proxy.rb +3 -0
  11. data/lib/kitchen/instance.rb +17 -0
  12. data/lib/kitchen/provisioner/base.rb +30 -1
  13. data/lib/kitchen/provisioner/chef_base.rb +7 -3
  14. data/lib/kitchen/provisioner/chef_solo.rb +4 -0
  15. data/lib/kitchen/provisioner/chef_zero.rb +5 -1
  16. data/lib/kitchen/provisioner/dummy.rb +4 -0
  17. data/lib/kitchen/provisioner/shell.rb +5 -0
  18. data/lib/kitchen/shell_out.rb +6 -2
  19. data/lib/kitchen/transport/base.rb +25 -0
  20. data/lib/kitchen/transport/dummy.rb +4 -0
  21. data/lib/kitchen/transport/ssh.rb +22 -1
  22. data/lib/kitchen/transport/winrm.rb +61 -90
  23. data/lib/kitchen/verifier/base.rb +30 -1
  24. data/lib/kitchen/verifier/busser.rb +4 -0
  25. data/lib/kitchen/verifier/dummy.rb +4 -0
  26. data/lib/kitchen/version.rb +1 -1
  27. data/spec/kitchen/configurable_spec.rb +35 -0
  28. data/spec/kitchen/diagnostic_spec.rb +53 -3
  29. data/spec/kitchen/driver/dummy_spec.rb +8 -0
  30. data/spec/kitchen/driver/proxy_spec.rb +4 -0
  31. data/spec/kitchen/driver/ssh_base_spec.rb +4 -0
  32. data/spec/kitchen/instance_spec.rb +75 -0
  33. data/spec/kitchen/provisioner/base_spec.rb +32 -6
  34. data/spec/kitchen/provisioner/chef_base_spec.rb +3 -2
  35. data/spec/kitchen/provisioner/chef_solo_spec.rb +10 -2
  36. data/spec/kitchen/provisioner/chef_zero_spec.rb +24 -2
  37. data/spec/kitchen/provisioner/dummy_spec.rb +8 -0
  38. data/spec/kitchen/provisioner/shell_spec.rb +10 -0
  39. data/spec/kitchen/shell_out_spec.rb +7 -0
  40. data/spec/kitchen/transport/ssh_spec.rb +90 -1
  41. data/spec/kitchen/transport/winrm_spec.rb +91 -11
  42. data/spec/kitchen/verifier/base_spec.rb +32 -6
  43. data/spec/kitchen/verifier/busser_spec.rb +8 -0
  44. data/spec/kitchen/verifier/dummy_spec.rb +8 -0
  45. data/support/chef_base_install_command.sh +183 -100
  46. data/test-kitchen.gemspec +1 -2
  47. metadata +11 -48
  48. data/lib/kitchen/transport/winrm/command_executor.rb +0 -188
  49. data/lib/kitchen/transport/winrm/file_transporter.rb +0 -454
  50. data/lib/kitchen/transport/winrm/logging.rb +0 -50
  51. data/lib/kitchen/transport/winrm/template.rb +0 -74
  52. data/lib/kitchen/transport/winrm/tmp_zip.rb +0 -187
  53. data/spec/kitchen/transport/winrm/command_executor_spec.rb +0 -400
  54. data/spec/kitchen/transport/winrm/file_transporter_spec.rb +0 -876
  55. data/spec/kitchen/transport/winrm/logging_spec.rb +0 -92
  56. data/spec/kitchen/transport/winrm/template_spec.rb +0 -51
  57. data/spec/kitchen/transport/winrm/tmp_zip_spec.rb +0 -132
  58. data/support/check_files.ps1.erb +0 -48
  59. data/support/decode_files.ps1.erb +0 -62
@@ -1,876 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher (<fnichol@nichol.ca>)
4
- #
5
- # Copyright (C) 2015, 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 "base64"
22
- require "csv"
23
- require "stringio"
24
- require "logger"
25
- require "winrm"
26
-
27
- require "kitchen"
28
- require "kitchen/transport/winrm/file_transporter"
29
-
30
- describe Kitchen::Transport::Winrm::FileTransporter do
31
-
32
- CheckEntry = Struct.new(
33
- :chk_exists, :src_md5, :dst_md5, :chk_dirty, :verifies)
34
- DecodeEntry = Struct.new(
35
- :dst, :verifies, :src_md5, :dst_md5, :tmpfile, :tmpzip)
36
-
37
- let(:logged_output) { StringIO.new }
38
- let(:logger) { Logger.new(logged_output) }
39
-
40
- let(:randomness) { %W[alpha beta charlie delta].each }
41
- let(:id_generator) { -> { randomness.next } }
42
-
43
- let(:service) do
44
- s = mock("winrm_service")
45
- s.responds_like_instance_of(WinRM::WinRMWebService)
46
- s
47
- end
48
-
49
- let(:transporter) do
50
- Kitchen::Transport::Winrm::FileTransporter.new(
51
- service,
52
- logger,
53
- :id_generator => id_generator
54
- )
55
- end
56
-
57
- before { @tempfiles = [] }
58
-
59
- after { @tempfiles.each(&:unlink) }
60
-
61
- describe "when uploading a single file" do
62
-
63
- let(:content) { "." * 12003 }
64
- let(:local) { create_tempfile("input.txt", content) }
65
- let(:remote) { "C:\\dest" }
66
- let(:dst) { "#{remote}\\#{File.basename(local)}" }
67
- let(:src_md5) { md5sum(local) }
68
- let(:size) { File.size(local) }
69
- let(:cmd_tmpfile) { "%TEMP%\\b64-#{src_md5}.txt" }
70
- let(:ps_tmpfile) { "$env:TEMP\\b64-#{src_md5}.txt" }
71
-
72
- let(:upload) { transporter.upload(local, remote) }
73
-
74
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
75
- def self.common_specs_for_all_single_file_types
76
- it "truncates a zero-byte hash_file for check_files" do
77
- service.expects(:run_cmd).with { |cmd, *_|
78
- cmd =~ regexify(%{echo|set /p=>"%TEMP%\\hash-alpha.txt"})
79
- }.returns(cmd_output)
80
-
81
- upload
82
- end
83
-
84
- it "uploads the hash_file in chunks for check_files" do
85
- hash = Kitchen::Util.outdent!(<<-HASH.chomp)
86
- @{
87
- "#{dst}" = "#{src_md5}"
88
- }
89
- HASH
90
-
91
- service.expects(:run_cmd).
92
- with(%{echo #{base64(hash)} >> "%TEMP%\\hash-alpha.txt"}).
93
- returns(cmd_output).times(1)
94
-
95
- upload
96
- end
97
-
98
- it "sets hash_file and runs the check_files powershell script" do
99
- service.expects(:run_powershell_script).with { |script|
100
- script =~ regexify(%{$hash_file = "$env:TEMP\\hash-alpha.txt"}) &&
101
- script =~ regexify(
102
- "Check-Files (Invoke-Input $hash_file) | " \
103
- "ConvertTo-Csv -NoTypeInformation")
104
- }.returns(check_output)
105
-
106
- upload
107
- end
108
- end
109
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
110
-
111
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
112
- def self.common_specs_for_all_single_dirty_file_types
113
- it "truncates a zero-byte tempfile" do
114
- service.expects(:run_cmd).with { |cmd, *_|
115
- cmd =~ regexify(%{echo|set /p=>"#{cmd_tmpfile}"})
116
- }.returns(cmd_output)
117
-
118
- upload
119
- end
120
-
121
- it "uploads the file in 8k chunks" do
122
- service.expects(:run_cmd).
123
- with(%{echo #{base64("." * 6000)} >> "#{cmd_tmpfile}"}).
124
- returns(cmd_output).times(2)
125
- service.expects(:run_cmd).
126
- with(%{echo #{base64("." * 3)} >> "#{cmd_tmpfile}"}).
127
- returns(cmd_output).times(1)
128
-
129
- upload
130
- end
131
-
132
- describe "with a small file" do
133
-
134
- let(:content) { "hello, world" }
135
-
136
- it "uploads the file in base64 encoding" do
137
- service.expects(:run_cmd).
138
- with(%{echo #{base64(content)} >> "#{cmd_tmpfile}"}).
139
- returns(cmd_output)
140
-
141
- upload
142
- end
143
- end
144
-
145
- it "truncates a zero-byte hash_file for decode_files" do
146
- service.expects(:run_cmd).with { |cmd, *_|
147
- cmd =~ regexify(%{echo|set /p=>"%TEMP%\\hash-beta.txt"})
148
- }.returns(cmd_output)
149
-
150
- upload
151
- end
152
-
153
- it "uploads the hash_file in chunks for decode_files" do
154
- hash = Kitchen::Util.outdent!(<<-HASH.chomp)
155
- @{
156
- "#{ps_tmpfile}" = @{
157
- "dst" = "#{dst}"
158
- }
159
- }
160
- HASH
161
-
162
- service.expects(:run_cmd).
163
- with(%{echo #{base64(hash)} >> "%TEMP%\\hash-beta.txt"}).
164
- returns(cmd_output).times(1)
165
-
166
- upload
167
- end
168
-
169
- it "sets hash_file and runs the decode_files powershell script" do
170
- service.expects(:run_powershell_script).with { |script|
171
- script =~ regexify(%{$hash_file = "$env:TEMP\\hash-beta.txt"}) &&
172
- script =~ regexify(
173
- "Decode-Files (Invoke-Input $hash_file) | " \
174
- "ConvertTo-Csv -NoTypeInformation")
175
- }.returns(check_output)
176
-
177
- upload
178
- end
179
- end
180
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
181
-
182
- describe "for a new file" do
183
-
184
- # let(:check_output) do
185
- def check_output
186
- create_check_output([
187
- CheckEntry.new("False", src_md5, nil, "True", "False")
188
- ])
189
- end
190
-
191
- let(:cmd_output) do
192
- o = WinRM::Output.new
193
- o[:exitcode] = 0
194
- o
195
- end
196
-
197
- # let(:decode_output) do
198
- def decode_output
199
- create_decode_output([
200
- DecodeEntry.new(dst, "True", src_md5, src_md5, ps_tmpfile, nil)
201
- ])
202
- end
203
-
204
- before do
205
- service.stubs(:run_cmd).
206
- returns(cmd_output)
207
-
208
- service.stubs(:run_powershell_script).
209
- with { |script| script =~ /^Check-Files .+ \| ConvertTo-Csv/ }.
210
- returns(check_output)
211
-
212
- service.stubs(:run_powershell_script).
213
- with { |script| script =~ /^Decode-Files .+ \| ConvertTo-Csv/ }.
214
- returns(decode_output)
215
- end
216
-
217
- common_specs_for_all_single_file_types
218
-
219
- common_specs_for_all_single_dirty_file_types
220
-
221
- it "returns a report hash" do
222
- upload.must_equal(
223
- src_md5 => {
224
- "src" => local,
225
- "dst" => dst,
226
- "tmpfile" => ps_tmpfile,
227
- "tmpzip" => nil,
228
- "src_md5" => src_md5,
229
- "dst_md5" => src_md5,
230
- "chk_exists" => "False",
231
- "chk_dirty" => "True",
232
- "verifies" => "True",
233
- "size" => size,
234
- "xfered" => size / 3 * 4,
235
- "chunks" => (size / 6000.to_f).ceil
236
- }
237
- )
238
- end
239
-
240
- describe "when a failed check command is returned" do
241
-
242
- def check_output
243
- o = WinRM::Output.new
244
- o[:exitcode] = 10
245
- o[:data].concat([{ :stderr => "Oh noes\n" }])
246
- o
247
- end
248
-
249
- it "raises a FileTransporterFailed error" do
250
- err = proc {
251
- upload
252
- }.must_raise Kitchen::Transport::Winrm::FileTransporterFailed
253
- err.message.must_match regexify(
254
- "Upload failed (exitcode: 10)", :partial_line)
255
- end
256
- end
257
-
258
- describe "when a failed decode command is returned" do
259
-
260
- def decode_output
261
- o = WinRM::Output.new
262
- o[:exitcode] = 10
263
- o[:data].concat([{ :stderr => "Oh noes\n" }])
264
- o
265
- end
266
-
267
- it "raises a FileTransporterFailed error" do
268
- err = proc {
269
- upload
270
- }.must_raise Kitchen::Transport::Winrm::FileTransporterFailed
271
- err.message.must_match regexify(
272
- "Upload failed (exitcode: 10)", :partial_line)
273
- end
274
- end
275
- end
276
-
277
- describe "for an out of date (dirty) file" do
278
-
279
- let(:check_output) do
280
- create_check_output([
281
- CheckEntry.new("True", src_md5, "aabbcc", "True", "False")
282
- ])
283
- end
284
-
285
- let(:cmd_output) do
286
- o = WinRM::Output.new
287
- o[:exitcode] = 0
288
- o
289
- end
290
-
291
- let(:decode_output) do
292
- create_decode_output([
293
- DecodeEntry.new(dst, "True", src_md5, src_md5, ps_tmpfile, nil)
294
- ])
295
- end
296
-
297
- before do
298
- service.stubs(:run_cmd).
299
- returns(cmd_output)
300
-
301
- service.stubs(:run_powershell_script).
302
- with { |script| script =~ /^Check-Files .+ \| ConvertTo-Csv/ }.
303
- returns(check_output)
304
-
305
- service.stubs(:run_powershell_script).
306
- with { |script| script =~ /^Decode-Files .+ \| ConvertTo-Csv/ }.
307
- returns(decode_output)
308
- end
309
-
310
- common_specs_for_all_single_file_types
311
-
312
- common_specs_for_all_single_dirty_file_types
313
-
314
- it "returns a report hash" do
315
- upload.must_equal(
316
- src_md5 => {
317
- "src" => local,
318
- "dst" => dst,
319
- "tmpfile" => ps_tmpfile,
320
- "tmpzip" => nil,
321
- "src_md5" => src_md5,
322
- "dst_md5" => src_md5,
323
- "chk_exists" => "True",
324
- "chk_dirty" => "True",
325
- "verifies" => "True",
326
- "size" => size,
327
- "xfered" => size / 3 * 4,
328
- "chunks" => (size / 6000.to_f).ceil
329
- }
330
- )
331
- end
332
- end
333
-
334
- describe "for an up to date (clean) file" do
335
-
336
- let(:check_output) do
337
- create_check_output([
338
- CheckEntry.new("True", src_md5, src_md5, "False", "True")
339
- ])
340
- end
341
-
342
- let(:cmd_output) do
343
- o = WinRM::Output.new
344
- o[:exitcode] = 0
345
- o
346
- end
347
-
348
- before do
349
- service.stubs(:run_cmd).
350
- returns(cmd_output)
351
-
352
- service.stubs(:run_powershell_script).
353
- with { |script| script =~ /^Check-Files .+ \| ConvertTo-Csv/ }.
354
- returns(check_output)
355
- end
356
-
357
- common_specs_for_all_single_file_types
358
-
359
- it "uploads nothing" do
360
- service.expects(:run_cmd).never
361
-
362
- upload
363
- end
364
-
365
- it "skips the decode_files powershell script" do
366
- service.expects(:run_powershell_script).with { |script|
367
- script =~ regexify(
368
- "Decode-Files $files | ConvertTo-Csv -NoTypeInformation")
369
- }.never
370
-
371
- upload
372
- end
373
-
374
- it "returns a report hash" do
375
- upload.must_equal(
376
- src_md5 => {
377
- "src" => local,
378
- "dst" => dst,
379
- "size" => size,
380
- "src_md5" => src_md5,
381
- "dst_md5" => src_md5,
382
- "chk_exists" => "True",
383
- "chk_dirty" => "False",
384
- "verifies" => "True"
385
- }
386
- )
387
- end
388
- end
389
- end
390
-
391
- describe "when uploading a single directory" do
392
-
393
- let(:content) { "I'm a fake zip file" }
394
- let(:local) { Dir.mktmpdir("input") }
395
- let(:remote) { "C:\\dest" }
396
- let(:src_zip) { create_tempfile("fake.zip", content) }
397
- let(:dst) { remote }
398
- let(:src_md5) { md5sum(src_zip) }
399
- let(:size) { File.size(src_zip) }
400
- let(:cmd_tmpfile) { "%TEMP%\\b64-#{src_md5}.txt" }
401
- let(:ps_tmpfile) { "$env:TEMP\\b64-#{src_md5}.txt" }
402
- let(:ps_tmpzip) { "$env:TEMP\\tmpzip-#{src_md5}.zip" }
403
-
404
- let(:tmp_zip) do
405
- s = mock("tmp_zip")
406
- s.responds_like_instance_of(Kitchen::Transport::Winrm::TmpZip)
407
- s.stubs(:path).returns(Pathname(src_zip))
408
- s.stubs(:unlink)
409
- s
410
- end
411
-
412
- let(:cmd_output) do
413
- o = WinRM::Output.new
414
- o[:exitcode] = 0
415
- o
416
- end
417
-
418
- let(:check_output) do
419
- create_check_output([
420
- CheckEntry.new("False", src_md5, nil, "True", "False")
421
- ])
422
- end
423
-
424
- let(:decode_output) do
425
- create_decode_output([
426
- DecodeEntry.new(dst, "True", src_md5, src_md5, ps_tmpfile, ps_tmpzip)
427
- ])
428
- end
429
-
430
- before do
431
- Kitchen::Transport::Winrm::TmpZip.stubs(:new).with("#{local}/", logger).
432
- returns(tmp_zip)
433
-
434
- service.stubs(:run_cmd).
435
- returns(cmd_output)
436
-
437
- # service.stubs(:run_cmd).with { |cmd, *_|
438
- # if match = %r{^echo (\w+) >> "%TEMP%\\hash-alpha.txt"$}.match(cmd)
439
- # hash = Base64.strict_decode64(match[1])
440
- # zip_info[:tmpzip] = %r{"(\$env:TEMP\\tmpzip-\w+\.zip)"}.match(hash)[1]
441
- # zip_info[:src_md5] = %r{tmpzip-(\w+)\.zip$}.match(zip_info[:tmpzip])[1]
442
- # end
443
- # }.returns(cmd_output)
444
-
445
- service.stubs(:run_powershell_script).
446
- with { |script| script =~ /^Check-Files .+ \| ConvertTo-Csv/ }.
447
- returns(check_output)
448
-
449
- service.stubs(:run_powershell_script).
450
- with { |script| script =~ /^Decode-Files .+ \| ConvertTo-Csv/ }.
451
- returns(decode_output)
452
- end
453
-
454
- after do
455
- FileUtils.rm_rf(local)
456
- end
457
-
458
- let(:upload) { transporter.upload("#{local}/", remote) }
459
-
460
- it "truncates a zero-byte hash_file for check_files" do
461
- service.expects(:run_cmd).with { |cmd, *_|
462
- cmd =~ regexify(%{echo|set /p=>"%TEMP%\\hash-alpha.txt"})
463
- }.returns(cmd_output)
464
-
465
- upload
466
- end
467
-
468
- it "uploads the hash_file in chunks for check_files" do
469
- hash = Kitchen::Util.outdent!(<<-HASH.chomp)
470
- @{
471
- "#{ps_tmpzip}" = "#{src_md5}"
472
- }
473
- HASH
474
-
475
- service.expects(:run_cmd).
476
- with(%{echo #{base64(hash)} >> "%TEMP%\\hash-alpha.txt"}).
477
- returns(cmd_output).times(1)
478
-
479
- upload
480
- end
481
-
482
- it "sets hash_file and runs the check_files powershell script" do
483
- service.expects(:run_powershell_script).with { |script|
484
- script =~ regexify(%{$hash_file = "$env:TEMP\\hash-alpha.txt"}) &&
485
- script =~ regexify(
486
- "Check-Files (Invoke-Input $hash_file) | " \
487
- "ConvertTo-Csv -NoTypeInformation")
488
- }.returns(check_output)
489
-
490
- upload
491
- end
492
-
493
- it "truncates a zero-byte tempfile" do
494
- service.expects(:run_cmd).with { |cmd, *_|
495
- cmd =~ regexify(%{echo|set /p=>"#{cmd_tmpfile}"})
496
- }.returns(cmd_output)
497
-
498
- upload
499
- end
500
-
501
- it "uploads the zip file in base64 encoding" do
502
- service.expects(:run_cmd).
503
- with(%{echo #{base64(content)} >> "#{cmd_tmpfile}"}).
504
- returns(cmd_output)
505
-
506
- upload
507
- end
508
-
509
- it "truncates a zero-byte hash_file for decode_files" do
510
- service.expects(:run_cmd).with { |cmd, *_|
511
- cmd =~ regexify(%{echo|set /p=>"%TEMP%\\hash-beta.txt"})
512
- }.returns(cmd_output)
513
-
514
- upload
515
- end
516
-
517
- it "uploads the hash_file in chunks for decode_files" do
518
- hash = Kitchen::Util.outdent!(<<-HASH.chomp)
519
- @{
520
- "#{ps_tmpfile}" = @{
521
- "dst" = "#{dst}"
522
- "tmpzip" = "#{ps_tmpzip}"
523
- }
524
- }
525
- HASH
526
-
527
- service.expects(:run_cmd).
528
- with(%{echo #{base64(hash)} >> "%TEMP%\\hash-beta.txt"}).
529
- returns(cmd_output).times(1)
530
-
531
- upload
532
- end
533
-
534
- it "sets hash_file and runs the decode_files powershell script" do
535
- service.expects(:run_powershell_script).with { |script|
536
- script =~ regexify(%{$hash_file = "$env:TEMP\\hash-beta.txt"}) &&
537
- script =~ regexify(
538
- "Decode-Files (Invoke-Input $hash_file) | " \
539
- "ConvertTo-Csv -NoTypeInformation")
540
- }.returns(check_output)
541
-
542
- upload
543
- end
544
-
545
- it "returns a report hash" do
546
- upload.must_equal(
547
- src_md5 => {
548
- "src" => "#{local}/",
549
- "src_zip" => src_zip,
550
- "dst" => dst,
551
- "tmpfile" => ps_tmpfile,
552
- "tmpzip" => ps_tmpzip,
553
- "src_md5" => src_md5,
554
- "dst_md5" => src_md5,
555
- "chk_exists" => "False",
556
- "chk_dirty" => "True",
557
- "verifies" => "True",
558
- "size" => size,
559
- "xfered" => size / 3 * 4,
560
- "chunks" => (size / 6000.to_f).ceil
561
- }
562
- )
563
- end
564
-
565
- it "cleans up the zip file" do
566
- tmp_zip.expects(:unlink)
567
-
568
- upload
569
- end
570
-
571
- describe "when a failed check command is returned" do
572
-
573
- def check_output
574
- o = WinRM::Output.new
575
- o[:exitcode] = 10
576
- o[:data].concat([{ :stderr => "Oh noes\n" }])
577
- o
578
- end
579
-
580
- it "raises a FileTransporterFailed error" do
581
- err = proc {
582
- upload
583
- }.must_raise Kitchen::Transport::Winrm::FileTransporterFailed
584
- err.message.must_match regexify(
585
- "Upload failed (exitcode: 10)", :partial_line)
586
- end
587
- end
588
-
589
- describe "when a failed decode command is returned" do
590
-
591
- def decode_output
592
- o = WinRM::Output.new
593
- o[:exitcode] = 10
594
- o[:data].concat([{ :stderr => "Oh noes\n" }])
595
- o
596
- end
597
-
598
- it "raises a FileTransporterFailed error" do
599
- err = proc {
600
- upload
601
- }.must_raise Kitchen::Transport::Winrm::FileTransporterFailed
602
- err.message.must_match regexify(
603
- "Upload failed (exitcode: 10)", :partial_line)
604
- end
605
- end
606
- end
607
-
608
- describe "when uploading multiple files" do
609
-
610
- let(:remote) { "C:\\Program Files" }
611
-
612
- 1.upto(3).each do |i|
613
- let(:"local#{i}") { create_tempfile("input#{i}.txt", "input#{i}") }
614
- let(:"src#{i}_md5") { md5sum(send("local#{i}")) }
615
- let(:"dst#{i}") { "#{remote}\\#{File.basename(send("local#{i}"))}" }
616
- let(:"size#{i}") { File.size(send("local#{i}")) }
617
- let(:"cmd#{i}_tmpfile") { "%TEMP%\\b64-#{send("src#{i}_md5")}.txt" }
618
- let(:"ps#{i}_tmpfile") { "$env:TEMP\\b64-#{send("src#{i}_md5")}.txt" }
619
- end
620
-
621
- let(:check_output) do
622
- create_check_output([
623
- # new
624
- CheckEntry.new("False", src1_md5, nil, "True", "False"),
625
- # out-of-date
626
- CheckEntry.new("True", src2_md5, "aabbcc", "True", "False"),
627
- # current
628
- CheckEntry.new("True", src3_md5, src3_md5, "False", "True")
629
- ])
630
- end
631
-
632
- let(:cmd_output) do
633
- o = WinRM::Output.new
634
- o[:exitcode] = 0
635
- o
636
- end
637
-
638
- let(:decode_output) do
639
- create_decode_output([
640
- DecodeEntry.new(dst1, "True", src1_md5, src1_md5, ps1_tmpfile, nil),
641
- DecodeEntry.new(dst2, "True", src2_md5, src2_md5, ps2_tmpfile, nil)
642
- ])
643
- end
644
-
645
- let(:upload) { transporter.upload([local1, local2, local3], remote) }
646
-
647
- before do
648
- service.stubs(:run_cmd).
649
- returns(cmd_output)
650
-
651
- service.stubs(:run_powershell_script).
652
- with { |script| script =~ /^Check-Files .+ \| ConvertTo-Csv/ }.
653
- returns(check_output)
654
-
655
- service.stubs(:run_powershell_script).
656
- with { |script| script =~ /^Decode-Files .+ \| ConvertTo-Csv/ }.
657
- returns(decode_output)
658
- end
659
-
660
- it "truncates a zero-byte hash_file for check_files" do
661
- service.expects(:run_cmd).with { |cmd, *_|
662
- cmd =~ regexify(%{echo|set /p=>"%TEMP%\\hash-alpha.txt"})
663
- }.returns(cmd_output)
664
-
665
- upload
666
- end
667
-
668
- it "uploads the hash_file in chunks for check_files" do
669
- hash = Kitchen::Util.outdent!(<<-HASH.chomp)
670
- @{
671
- "#{dst1}" = "#{src1_md5}"
672
- "#{dst2}" = "#{src2_md5}"
673
- "#{dst3}" = "#{src3_md5}"
674
- }
675
- HASH
676
-
677
- service.expects(:run_cmd).
678
- with(%{echo #{base64(hash)} >> "%TEMP%\\hash-alpha.txt"}).
679
- returns(cmd_output).times(1)
680
-
681
- upload
682
- end
683
-
684
- it "sets hash_file and runs the check_files powershell script" do
685
- service.expects(:run_powershell_script).with { |script|
686
- script =~ regexify(%{$hash_file = "$env:TEMP\\hash-alpha.txt"}) &&
687
- script =~ regexify(
688
- "Check-Files (Invoke-Input $hash_file) | " \
689
- "ConvertTo-Csv -NoTypeInformation")
690
- }.returns(check_output)
691
-
692
- upload
693
- end
694
-
695
- it "only uploads dirty files" do
696
- service.expects(:run_cmd).
697
- with(%{echo #{base64(IO.read(local1))} >> "#{cmd1_tmpfile}"})
698
- service.expects(:run_cmd).
699
- with(%{echo #{base64(IO.read(local2))} >> "#{cmd2_tmpfile}"})
700
- service.expects(:run_cmd).
701
- with(%{echo #{base64(IO.read(local3))} >> "#{cmd3_tmpfile}"}).
702
- never
703
-
704
- upload
705
- end
706
-
707
- it "truncates a zero-byte hash_file for decode_files" do
708
- service.expects(:run_cmd).with { |cmd, *_|
709
- cmd =~ regexify(%{echo|set /p=>"%TEMP%\\hash-beta.txt"})
710
- }.returns(cmd_output)
711
-
712
- upload
713
- end
714
-
715
- it "uploads the hash_file in chunks for decode_files" do
716
- hash = Kitchen::Util.outdent!(<<-HASH.chomp)
717
- @{
718
- "#{ps1_tmpfile}" = @{
719
- "dst" = "#{dst1}"
720
- }
721
- "#{ps2_tmpfile}" = @{
722
- "dst" = "#{dst2}"
723
- }
724
- }
725
- HASH
726
-
727
- service.expects(:run_cmd).
728
- with(%{echo #{base64(hash)} >> "%TEMP%\\hash-beta.txt"}).
729
- returns(cmd_output).times(1)
730
-
731
- upload
732
- end
733
-
734
- it "sets hash_file and runs the decode_files powershell script" do
735
- service.expects(:run_powershell_script).with { |script|
736
- script =~ regexify(%{$hash_file = "$env:TEMP\\hash-beta.txt"}) &&
737
- script =~ regexify(
738
- "Decode-Files (Invoke-Input $hash_file) | " \
739
- "ConvertTo-Csv -NoTypeInformation")
740
- }.returns(check_output)
741
-
742
- upload
743
- end
744
-
745
- it "returns a report hash" do
746
- report = upload
747
-
748
- report.fetch(src1_md5).must_equal(
749
- "src" => local1,
750
- "dst" => dst1,
751
- "tmpfile" => ps1_tmpfile,
752
- "tmpzip" => nil,
753
- "src_md5" => src1_md5,
754
- "dst_md5" => src1_md5,
755
- "chk_exists" => "False",
756
- "chk_dirty" => "True",
757
- "verifies" => "True",
758
- "size" => size1,
759
- "xfered" => size1 / 3 * 4,
760
- "chunks" => (size1 / 6000.to_f).ceil
761
- )
762
- report.fetch(src2_md5).must_equal(
763
- "src" => local2,
764
- "dst" => dst2,
765
- "tmpfile" => ps2_tmpfile,
766
- "tmpzip" => nil,
767
- "src_md5" => src2_md5,
768
- "dst_md5" => src2_md5,
769
- "chk_exists" => "True",
770
- "chk_dirty" => "True",
771
- "verifies" => "True",
772
- "size" => size2,
773
- "xfered" => size2 / 3 * 4,
774
- "chunks" => (size2 / 6000.to_f).ceil
775
- )
776
- report.fetch(src3_md5).must_equal(
777
- "src" => local3,
778
- "dst" => dst3,
779
- "src_md5" => src3_md5,
780
- "dst_md5" => src3_md5,
781
- "chk_exists" => "True",
782
- "chk_dirty" => "False",
783
- "verifies" => "True",
784
- "size" => size3
785
- )
786
- end
787
-
788
- describe "when a failed check command is returned" do
789
-
790
- def check_output
791
- o = WinRM::Output.new
792
- o[:exitcode] = 10
793
- o[:data].concat([{ :stderr => "Oh noes\n" }])
794
- o
795
- end
796
-
797
- it "raises a FileTransporterFailed error" do
798
- err = proc {
799
- upload
800
- }.must_raise Kitchen::Transport::Winrm::FileTransporterFailed
801
- err.message.must_match regexify(
802
- "Upload failed (exitcode: 10)", :partial_line)
803
- end
804
- end
805
-
806
- describe "when a failed decode command is returned" do
807
-
808
- def decode_output
809
- o = WinRM::Output.new
810
- o[:exitcode] = 10
811
- o[:data].concat([{ :stderr => "Oh noes\n" }])
812
- o
813
- end
814
-
815
- it "raises a FileTransporterFailed error" do
816
- err = proc {
817
- upload
818
- }.must_raise Kitchen::Transport::Winrm::FileTransporterFailed
819
- err.message.must_match regexify(
820
- "Upload failed (exitcode: 10)", :partial_line)
821
- end
822
- end
823
- end
824
-
825
- it "raises an exception when local file or directory is not found" do
826
- proc { transporter.upload("/a/b/c/nope", "C:\\nopeland") }.
827
- must_raise Errno::ENOENT
828
- end
829
-
830
- def base64(string)
831
- Base64.strict_encode64(string)
832
- end
833
-
834
- def create_check_output(entries)
835
- csv = CSV.generate(:force_quotes => true) do |rows|
836
- rows << CheckEntry.new.members.map(&:to_s)
837
- entries.each { |entry| rows << entry.to_a }
838
- end
839
-
840
- o = WinRM::Output.new
841
- o[:exitcode] = 0
842
- o[:data].concat(csv.lines.map { |line| { :stdout => line } })
843
- o
844
- end
845
-
846
- def create_decode_output(entries)
847
- csv = CSV.generate(:force_quotes => true) do |rows|
848
- rows << DecodeEntry.new.members.map(&:to_s)
849
- entries.each { |entry| rows << entry.to_a }
850
- end
851
-
852
- o = WinRM::Output.new
853
- o[:exitcode] = 0
854
- o[:data].concat(csv.lines.map { |line| { :stdout => line } })
855
- o
856
- end
857
-
858
- def create_tempfile(name, content)
859
- pre, _, ext = name.rpartition(".")
860
- file = Tempfile.open(["#{pre}-", ".#{ext}"])
861
- @tempfiles << file
862
- file.write(content)
863
- file.close
864
- file.path
865
- end
866
-
867
- def md5sum(local)
868
- Digest::MD5.file(local).hexdigest
869
- end
870
-
871
- def regexify(str, line = :whole_line)
872
- r = Regexp.escape(str)
873
- r = "^#{r}$" if line == :whole_line
874
- Regexp.new(r)
875
- end
876
- end