winrm-fs 0.4.3 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +6 -2
- data/Gemfile +2 -0
- data/README.md +5 -12
- data/VERSION +1 -1
- data/Vagrantfile +1 -1
- data/appveyor.yml +2 -2
- data/changelog.md +2 -0
- data/lib/winrm-fs/core/file_transporter.rb +80 -93
- data/lib/winrm-fs/file_manager.rb +13 -13
- data/lib/winrm-fs/scripts/check_files.ps1.erb +17 -28
- data/lib/winrm-fs/scripts/checksum.ps1.erb +1 -1
- data/lib/winrm-fs/scripts/extract_files.ps1.erb +52 -0
- data/spec/config-example.yml +3 -5
- data/spec/integration/file_manager_spec.rb +10 -4
- data/spec/spec_helper.rb +5 -6
- data/winrm-fs.gemspec +1 -1
- metadata +7 -9
- data/lib/winrm-fs/scripts/decode_files.ps1.erb +0 -58
- data/spec/unit/file_transporter_spec.rb +0 -839
@@ -1,20 +1,11 @@
|
|
1
|
-
$
|
2
|
-
$hash_file = "<%= hash_file %>"
|
1
|
+
$hash_file = <%= hash_file %>
|
3
2
|
|
4
|
-
Function Cleanup($
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
$in = (Get-Item $src).OpenRead()
|
9
|
-
$b64 = New-Object -TypeName System.Security.Cryptography.FromBase64Transform
|
10
|
-
$m = [System.Security.Cryptography.CryptoStreamMode]::Read
|
11
|
-
$d = New-Object -TypeName System.Security.Cryptography.CryptoStream $in,$b64,$m
|
12
|
-
Copy-Stream $d ($out = [System.IO.File]::OpenWrite($dst))
|
13
|
-
} Finally { Cleanup $in; Cleanup $out; Cleanup $d }
|
3
|
+
Function Cleanup($disposable) {
|
4
|
+
if (($disposable -ne $null) -and ($disposable.GetType().GetMethod("Dispose") -ne $null)) {
|
5
|
+
$disposable.Dispose()
|
6
|
+
}
|
14
7
|
}
|
15
8
|
|
16
|
-
Function Copy-Stream($src, $dst) { $b = New-Object Byte[] 4096; while (($i = $src.Read($b, 0, $b.Length)) -ne 0) { $dst.Write($b, 0, $i) } }
|
17
|
-
|
18
9
|
Function Check-Files($h) {
|
19
10
|
return $h.GetEnumerator() | ForEach-Object {
|
20
11
|
$dst = Unresolve-Path $_.Value.target
|
@@ -36,25 +27,23 @@ Function Check-Files($h) {
|
|
36
27
|
|
37
28
|
Function Get-MD5Sum($src) {
|
38
29
|
Try {
|
39
|
-
$c =
|
30
|
+
$c = [System.Security.Cryptography.MD5]::Create()
|
40
31
|
$bytes = $c.ComputeHash(($in = (Get-Item $src).OpenRead()))
|
41
32
|
return ([System.BitConverter]::ToString($bytes)).Replace("-", "").ToLower()
|
42
|
-
}
|
33
|
+
}
|
34
|
+
Finally {
|
35
|
+
Cleanup $c
|
36
|
+
Cleanup $in
|
37
|
+
}
|
43
38
|
}
|
44
39
|
|
45
|
-
Function
|
46
|
-
$
|
47
|
-
|
48
|
-
$expr = Get-Content $decoded | Out-String
|
49
|
-
Remove-Item $in,$decoded -Force
|
50
|
-
try {
|
51
|
-
return Invoke-Expression "$expr"
|
40
|
+
Function Unresolve-Path($path) {
|
41
|
+
if ($path -eq $null) {
|
42
|
+
return $null
|
52
43
|
}
|
53
|
-
|
54
|
-
|
44
|
+
else {
|
45
|
+
return $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($path)
|
55
46
|
}
|
56
47
|
}
|
57
48
|
|
58
|
-
|
59
|
-
|
60
|
-
Check-Files (Invoke-Input $hash_file) | ConvertTo-Csv -NoTypeInformation
|
49
|
+
Check-Files $hash_file | ConvertTo-Csv -NoTypeInformation
|
@@ -2,7 +2,7 @@ $p = $ExecutionContext.SessionState.Path
|
|
2
2
|
$path = $p.GetUnresolvedProviderPathFromPSPath("<%= path %>")
|
3
3
|
|
4
4
|
if (Test-Path $path -PathType Leaf) {
|
5
|
-
$cryptoProv =
|
5
|
+
$cryptoProv = [System.Security.Cryptography.MD5]::Create()
|
6
6
|
$file = [System.IO.File]::Open($path,
|
7
7
|
[System.IO.Filemode]::Open, [System.IO.FileAccess]::Read)
|
8
8
|
$md5 = ([System.BitConverter]::ToString($cryptoProv.ComputeHash($file)))
|
@@ -0,0 +1,52 @@
|
|
1
|
+
trap {
|
2
|
+
$e = $_.Exception
|
3
|
+
$e.InvocationInfo.ScriptName
|
4
|
+
do {
|
5
|
+
$e.Message
|
6
|
+
$e = $e.InnerException
|
7
|
+
} while ($e)
|
8
|
+
break
|
9
|
+
}
|
10
|
+
|
11
|
+
function folder($path){
|
12
|
+
$path | ? {-not (test-path $_)} | % {$null = mkdir $_}
|
13
|
+
}
|
14
|
+
|
15
|
+
Function Decode-Files($hash) {
|
16
|
+
foreach ($key in $hash.keys) {
|
17
|
+
$value = $hash[$key]
|
18
|
+
$tzip, $dst = $Value["tmpzip"], $Value["dst"]
|
19
|
+
if ($tzip) {Unzip-File $tzip $dst}
|
20
|
+
New-Object psobject -Property @{dst=$dst;src_md5=$key;tmpzip=$tzip}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
Function Unzip-File($src, $dst) {
|
25
|
+
$unpack = $src -replace '\.zip'
|
26
|
+
$dst_parent = Split-Path -Path $dst -Parent
|
27
|
+
if(!(Test-Path $dst_parent)) { $dst = $dst_parent }
|
28
|
+
folder $unpack, $dst
|
29
|
+
try {
|
30
|
+
try{
|
31
|
+
[IO.Compression.ZipFile]::ExtractToDirectory($src, $unpack)
|
32
|
+
}
|
33
|
+
catch {
|
34
|
+
Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop
|
35
|
+
[IO.Compression.ZipFile]::ExtractToDirectory($src, $unpack)
|
36
|
+
}
|
37
|
+
}
|
38
|
+
catch {
|
39
|
+
Try {
|
40
|
+
$s = New-Object -ComObject Shell.Application
|
41
|
+
($s.NameSpace($unpack)).CopyHere(($s.NameSpace($src)).Items(), 0x610)
|
42
|
+
}
|
43
|
+
Finally {
|
44
|
+
[void][Runtime.Interopservices.Marshal]::ReleaseComObject($s)
|
45
|
+
}
|
46
|
+
}
|
47
|
+
dir $unpack | cp -dest "$dst/" -force -recurse
|
48
|
+
rm $unpack -recurse -force
|
49
|
+
}
|
50
|
+
|
51
|
+
$hash_file = <%= hash_file %>
|
52
|
+
Decode-Files $hash_file | ConvertTo-Csv -NoTypeInformation
|
data/spec/config-example.yml
CHANGED
@@ -5,7 +5,7 @@ describe WinRM::FS::FileManager do
|
|
5
5
|
let(:dest_dir) { File.join(subject.temp_dir, "winrm_#{rand(2**16)}") }
|
6
6
|
let(:temp_upload_dir) { '$env:TEMP/winrm-upload' }
|
7
7
|
let(:spec_dir) { File.expand_path(File.dirname(File.dirname(__FILE__))) }
|
8
|
-
let(:this_file) { __FILE__ }
|
8
|
+
let(:this_file) { Pathname.new(__FILE__) }
|
9
9
|
let(:service) { winrm_connection }
|
10
10
|
|
11
11
|
subject { WinRM::FS::FileManager.new(service) }
|
@@ -40,7 +40,7 @@ describe WinRM::FS::FileManager do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
context 'upload file' do
|
43
|
-
let(:dest_file) { File.join(dest_dir, File.basename(this_file)) }
|
43
|
+
let(:dest_file) { Pathname.new(File.join(dest_dir, File.basename(this_file))) }
|
44
44
|
|
45
45
|
before(:each) do
|
46
46
|
expect(subject.delete(dest_dir)).to be true
|
@@ -57,6 +57,12 @@ describe WinRM::FS::FileManager do
|
|
57
57
|
subject.delete('c:/winrmtest.rb')
|
58
58
|
end
|
59
59
|
|
60
|
+
it 'should upload just filename' do
|
61
|
+
subject.upload(this_file, 'winrmtest.rb')
|
62
|
+
expect(subject).to have_created('winrmtest.rb').with_content(this_file)
|
63
|
+
subject.delete('winrmtest.rb')
|
64
|
+
end
|
65
|
+
|
60
66
|
it 'should upload using relative file path' do
|
61
67
|
subject.upload('./spec/integration/file_manager_spec.rb', dest_file)
|
62
68
|
expect(subject).to have_created(dest_file).with_content(this_file)
|
@@ -108,8 +114,8 @@ describe WinRM::FS::FileManager do
|
|
108
114
|
|bytes_copied, total_bytes, local_path, remote_path|
|
109
115
|
expect(total_bytes).to be > 0
|
110
116
|
total_bytes_copied = bytes_copied
|
111
|
-
expect(local_path).to eq(this_file)
|
112
|
-
expect(remote_path).to eq(dest_file)
|
117
|
+
expect(local_path).to eq(this_file.to_s)
|
118
|
+
expect(remote_path).to eq(dest_file.to_s)
|
113
119
|
block_called = true
|
114
120
|
end
|
115
121
|
expect(total_bytes_copied).to eq(total)
|
data/spec/spec_helper.rb
CHANGED
@@ -9,15 +9,14 @@ require_relative 'matchers'
|
|
9
9
|
module ConnectionHelper
|
10
10
|
# rubocop:disable AbcSize
|
11
11
|
def winrm_connection
|
12
|
-
WinRM::
|
13
|
-
config[:endpoint], config[:auth_type].to_sym, config[:options])
|
12
|
+
WinRM::Connection.new(config)
|
14
13
|
end
|
15
14
|
# rubocop:enable AbcSize
|
16
15
|
|
17
16
|
def config
|
18
17
|
@config ||= begin
|
19
18
|
cfg = symbolize_keys(YAML.load(File.read(winrm_config_path)))
|
20
|
-
cfg
|
19
|
+
cfg.merge!(basic_auth_only: true) unless cfg[:transport].eql? :kerberos
|
21
20
|
merge_environment!(cfg)
|
22
21
|
cfg
|
23
22
|
end
|
@@ -25,18 +24,18 @@ module ConnectionHelper
|
|
25
24
|
|
26
25
|
def merge_environment!(config)
|
27
26
|
merge_config_option_from_environment(config, 'user')
|
28
|
-
merge_config_option_from_environment(config, '
|
27
|
+
merge_config_option_from_environment(config, 'password')
|
29
28
|
merge_config_option_from_environment(config, 'no_ssl_peer_verification')
|
30
29
|
if ENV['use_ssl_peer_fingerprint']
|
31
30
|
config[:options][:ssl_peer_fingerprint] = ENV['winrm_cert']
|
32
31
|
end
|
33
32
|
config[:endpoint] = ENV['winrm_endpoint'] if ENV['winrm_endpoint']
|
34
|
-
config[:
|
33
|
+
config[:transport] = ENV['winrm_transport'] if ENV['winrm_transport']
|
35
34
|
end
|
36
35
|
|
37
36
|
def merge_config_option_from_environment(config, key)
|
38
37
|
env_key = 'winrm_' + key
|
39
|
-
config[
|
38
|
+
config[key.to_sym] = ENV[env_key] if ENV[env_key]
|
40
39
|
end
|
41
40
|
|
42
41
|
def winrm_config_path
|
data/winrm-fs.gemspec
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_runtime_dependency 'erubis', '~> 2.7'
|
30
30
|
s.add_runtime_dependency 'logging', ['>= 1.6.1', '< 3.0']
|
31
31
|
s.add_runtime_dependency 'rubyzip', '~> 1.1'
|
32
|
-
s.add_runtime_dependency 'winrm', '~>
|
32
|
+
s.add_runtime_dependency 'winrm', '~> 2.0'
|
33
33
|
s.add_development_dependency 'pry'
|
34
34
|
s.add_development_dependency 'rspec', '~> 3.0.0'
|
35
35
|
s.add_development_dependency 'rake', '~> 10.3.2'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: winrm-fs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shawn Neal
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-08-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: erubis
|
@@ -65,14 +65,14 @@ dependencies:
|
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '2.0'
|
69
69
|
type: :runtime
|
70
70
|
prerelease: false
|
71
71
|
version_requirements: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '2.0'
|
76
76
|
- !ruby/object:Gem::Dependency
|
77
77
|
name: pry
|
78
78
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,8 +129,7 @@ dependencies:
|
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
131
|
version: 0.28.0
|
132
|
-
description:
|
133
|
-
Ruby library for file system operations via Windows Remote Management
|
132
|
+
description: " Ruby library for file system operations via Windows Remote Management\n"
|
134
133
|
email:
|
135
134
|
- sneal@sneal.net
|
136
135
|
- matt@mattwrock.com
|
@@ -162,17 +161,16 @@ files:
|
|
162
161
|
- lib/winrm-fs/scripts/check_files.ps1.erb
|
163
162
|
- lib/winrm-fs/scripts/checksum.ps1.erb
|
164
163
|
- lib/winrm-fs/scripts/create_dir.ps1.erb
|
165
|
-
- lib/winrm-fs/scripts/decode_files.ps1.erb
|
166
164
|
- lib/winrm-fs/scripts/delete.ps1.erb
|
167
165
|
- lib/winrm-fs/scripts/download.ps1.erb
|
168
166
|
- lib/winrm-fs/scripts/exists.ps1.erb
|
167
|
+
- lib/winrm-fs/scripts/extract_files.ps1.erb
|
169
168
|
- lib/winrm-fs/scripts/scripts.rb
|
170
169
|
- spec/config-example.yml
|
171
170
|
- spec/integration/file_manager_spec.rb
|
172
171
|
- spec/integration/tmp_zip_spec.rb
|
173
172
|
- spec/matchers.rb
|
174
173
|
- spec/spec_helper.rb
|
175
|
-
- spec/unit/file_transporter_spec.rb
|
176
174
|
- spec/unit/tmp_zip_spec.rb
|
177
175
|
- winrm-fs.gemspec
|
178
176
|
homepage: http://github.com/WinRb/winrm-fs
|
@@ -198,7 +196,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
198
196
|
version: '0'
|
199
197
|
requirements: []
|
200
198
|
rubyforge_project:
|
201
|
-
rubygems_version: 2.6.
|
199
|
+
rubygems_version: 2.6.6
|
202
200
|
signing_key:
|
203
201
|
specification_version: 4
|
204
202
|
summary: WinRM File System
|
@@ -1,58 +0,0 @@
|
|
1
|
-
trap {$e = $_.Exception; $e.InvocationInfo.ScriptName; do {$e.Message; $e = $e.InnerException} while ($e); break;}
|
2
|
-
function Decode-Base64File($src, $dst) {folder (split-path $dst);sc -force -Encoding Byte -Path $dst -Value ([Convert]::FromBase64String([IO.File]::ReadAllLines($src)))}
|
3
|
-
function Copy-Stream($src, $dst) {$b = New-Object Byte[] 4096; while (($i = $src.Read($b, 0, $b.Length)) -ne 0) { $dst.Write($b, 0, $i) } }
|
4
|
-
function Resolve-ProviderPath{ $input | % {if ($_){(Resolve-Path $_).ProviderPath} else{$null}} }
|
5
|
-
function Get-FrameworkVersion { "Full", "Client" | % {([version](gp "HKLM:\Software\Microsoft\NET Framework Setup\NDP\v4\$_").Version)} | select -first 1}
|
6
|
-
function Test-NETStack($Version){ Get-FrameworkVersion -ge $Version }
|
7
|
-
function Test-IOCompression {($PSVersionTable.PSVersion.Major -ge 3) -and (Test-NETStack '4.5')}
|
8
|
-
function folder($path){ $path | ? {-not (test-path $_)} | % {$null = mkdir $_}}
|
9
|
-
function disposable($o){($o -is [IDisposable]) -and (($o | gm | %{$_.name}) -contains 'Dispose')}
|
10
|
-
function use($obj, [scriptblock]$sb){try {& $sb} catch [exception]{throw $_} finally {if (disposable $obj) {$obj.Dispose()}} }
|
11
|
-
set-alias RPP -Value Resolve-ProviderPath
|
12
|
-
|
13
|
-
Function Decode-Files($hash) {
|
14
|
-
foreach ($key in $hash.keys) {
|
15
|
-
$value = $hash[$key]
|
16
|
-
$tmp, $tzip, $dst = $Key, $Value["tmpzip"], $Value["dst"]
|
17
|
-
if(!$tmp.StartsWith("clean")) {
|
18
|
-
$sMd5 = (gi $tmp).BaseName.Replace("b64-", "")
|
19
|
-
$decoded = if ($tzip -ne $null) { $tzip } else { $dst }
|
20
|
-
Decode-Base64File $tmp $decoded
|
21
|
-
rm $tmp -Force
|
22
|
-
$dMd5 = Get-MD5Sum $decoded
|
23
|
-
$verifies = $sMd5 -like $dMd5
|
24
|
-
}
|
25
|
-
if ($tzip) {Unzip-File $tzip $dst}
|
26
|
-
New-Object psobject -Property @{dst=$dst;verifies=$verifies;src_md5=$sMd5;dst_md5=$dMd5;tmpfile=$tmp;tmpzip=$tzip}
|
27
|
-
}
|
28
|
-
}
|
29
|
-
|
30
|
-
Function Get-MD5Sum($src) {
|
31
|
-
if ($src -and (test-path $src)) {
|
32
|
-
use ($c = New-Object -TypeName Security.Cryptography.MD5CryptoServiceProvider) {
|
33
|
-
use ($in = (gi $src).OpenRead()) {([BitConverter]::ToString($c.ComputeHash($in))).Replace("-", "").ToLower()}}
|
34
|
-
}
|
35
|
-
}
|
36
|
-
|
37
|
-
Function Invoke-Input($in) {
|
38
|
-
$in = $in | rpp
|
39
|
-
$d = "$($in).ps1"
|
40
|
-
Decode-Base64File $in $d
|
41
|
-
$expr = gc $d | Out-String
|
42
|
-
rm $in,$d -Force
|
43
|
-
iex "$expr"
|
44
|
-
}
|
45
|
-
|
46
|
-
Function Unzip-File($src, $dst) {
|
47
|
-
$unpack = $src -replace '\.zip'
|
48
|
-
$dst_parent = Split-Path -Path $dst -Parent
|
49
|
-
if(!(Test-Path $dst_parent)) { $dst = $dst_parent }
|
50
|
-
folder $unpack, $dst
|
51
|
-
if (Test-IOCompression) {Add-Type -AN System.IO.Compression.FileSystem; [IO.Compression.ZipFile]::ExtractToDirectory($src, $unpack)}
|
52
|
-
else {Try {$s = New-Object -ComObject Shell.Application; ($s.NameSpace($unpack)).CopyHere(($s.NameSpace($src)).Items(), 0x610)} Finally {[void][Runtime.Interopservices.Marshal]::ReleaseComObject($s)}}
|
53
|
-
dir $unpack | cp -dest "$dst/" -force -recurse
|
54
|
-
rm $unpack -recurse -force
|
55
|
-
}
|
56
|
-
|
57
|
-
$hash_file = "<%= hash_file %>"
|
58
|
-
Decode-Files (Invoke-Input $hash_file) | ConvertTo-Csv -NoTypeInformation
|
@@ -1,839 +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 'base64'
|
20
|
-
require 'csv'
|
21
|
-
require 'stringio'
|
22
|
-
require 'logger'
|
23
|
-
require 'winrm'
|
24
|
-
|
25
|
-
require 'winrm-fs/core/file_transporter'
|
26
|
-
|
27
|
-
describe WinRM::FS::Core::FileTransporter do
|
28
|
-
CheckEntry = Struct.new(
|
29
|
-
:chk_exists, :src_md5, :dst_md5, :chk_dirty, :verifies)
|
30
|
-
DecodeEntry = Struct.new(
|
31
|
-
:dst, :verifies, :src_md5, :dst_md5, :tmpfile, :tmpzip)
|
32
|
-
|
33
|
-
let(:logged_output) { StringIO.new }
|
34
|
-
let(:logger) { Logger.new(logged_output) }
|
35
|
-
|
36
|
-
let(:randomness) { %w(alpha beta charlie delta).each }
|
37
|
-
let(:id_generator) { -> { randomness.next } }
|
38
|
-
let(:winrm_service) { double('winrm_service', logger: logger) }
|
39
|
-
let(:service) { double('command_executor', service: winrm_service) }
|
40
|
-
let(:transporter) do
|
41
|
-
WinRM::FS::Core::FileTransporter.new(
|
42
|
-
service,
|
43
|
-
id_generator: id_generator
|
44
|
-
)
|
45
|
-
end
|
46
|
-
|
47
|
-
before { @tempfiles = [] }
|
48
|
-
|
49
|
-
after { @tempfiles.each(&:unlink) }
|
50
|
-
|
51
|
-
describe 'when uploading a single file' do
|
52
|
-
let(:content) { '.' * 12_003 }
|
53
|
-
let(:local) { create_tempfile('input.txt', content) }
|
54
|
-
let(:remote) { 'C:\\dest' }
|
55
|
-
let(:dst) { "#{remote}/#{File.basename(local)}" }
|
56
|
-
let(:src_md5) { md5sum(local) }
|
57
|
-
let(:size) { File.size(local) }
|
58
|
-
let(:cmd_tmpfile) { "%TEMP%\\b64-#{src_md5}.txt" }
|
59
|
-
let(:ps_tmpfile) { "$env:TEMP\\b64-#{src_md5}.txt" }
|
60
|
-
|
61
|
-
let(:upload) { transporter.upload(local, remote) }
|
62
|
-
|
63
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
64
|
-
def self.common_specs_for_all_single_file_types
|
65
|
-
it 'truncates a zero-byte hash_file for check_files' do
|
66
|
-
expect(service).to receive(:run_cmd).with(
|
67
|
-
regexify(%(echo|set /p=>"%TEMP%\\hash-alpha.txt")))
|
68
|
-
.and_return(cmd_output)
|
69
|
-
|
70
|
-
upload
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'uploads the hash_file in chunks for check_files' do
|
74
|
-
hash = outdent!(<<-HASH.chomp)
|
75
|
-
@{
|
76
|
-
"#{src_md5}" = @{
|
77
|
-
"target" = "#{remote}";
|
78
|
-
"src_basename" = "#{File.basename(local)}";
|
79
|
-
"dst" = "#{remote}"
|
80
|
-
}
|
81
|
-
}
|
82
|
-
HASH
|
83
|
-
|
84
|
-
expect(service).to receive(:run_cmd)
|
85
|
-
.with(%(echo #{base64(hash)} >> "%TEMP%\\hash-alpha.txt"))
|
86
|
-
.and_return(cmd_output).once
|
87
|
-
|
88
|
-
upload
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'sets hash_file and runs the check_files powershell script' do
|
92
|
-
expect(service).to receive(:run_powershell_script).with(
|
93
|
-
regexify(%($hash_file = "$env:TEMP\\hash-alpha.txt")) &&
|
94
|
-
regexify(
|
95
|
-
'Check-Files (Invoke-Input $hash_file) | ' \
|
96
|
-
'ConvertTo-Csv -NoTypeInformation')
|
97
|
-
).and_return(check_output)
|
98
|
-
|
99
|
-
upload
|
100
|
-
end
|
101
|
-
end
|
102
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
103
|
-
|
104
|
-
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
105
|
-
def self.common_specs_for_all_single_dirty_file_types
|
106
|
-
it 'truncates a zero-byte tempfile' do
|
107
|
-
expect(service).to receive(:run_cmd).with(
|
108
|
-
regexify(%(echo|set /p=>"#{cmd_tmpfile}"))
|
109
|
-
).and_return(cmd_output)
|
110
|
-
|
111
|
-
upload
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'ploads the file in 8k chunks' do
|
115
|
-
expect(service).to receive(:run_cmd)
|
116
|
-
.with(%(echo #{base64('.' * 6000)} >> "#{cmd_tmpfile}"))
|
117
|
-
.and_return(cmd_output).twice
|
118
|
-
expect(service).to receive(:run_cmd)
|
119
|
-
.with(%(echo #{base64('.' * 3)} >> "#{cmd_tmpfile}"))
|
120
|
-
.and_return(cmd_output).once
|
121
|
-
|
122
|
-
upload
|
123
|
-
end
|
124
|
-
|
125
|
-
describe 'with a small file' do
|
126
|
-
let(:content) { 'hello, world' }
|
127
|
-
|
128
|
-
it 'uploads the file in base64 encoding' do
|
129
|
-
expect(service).to receive(:run_cmd)
|
130
|
-
.with(%(echo #{base64(content)} >> "#{cmd_tmpfile}"))
|
131
|
-
.and_return(cmd_output)
|
132
|
-
|
133
|
-
upload
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'truncates a zero-byte hash_file for decode_files' do
|
138
|
-
expect(service).to receive(:run_cmd).with(
|
139
|
-
regexify(%(echo|set /p=>"%TEMP%\\hash-beta.txt"))
|
140
|
-
).and_return(cmd_output)
|
141
|
-
|
142
|
-
upload
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'uploads the hash_file in chunks for decode_files' do
|
146
|
-
hash = outdent!(<<-HASH.chomp)
|
147
|
-
@{
|
148
|
-
"#{ps_tmpfile}" = @{
|
149
|
-
"dst" = "#{remote}"
|
150
|
-
}
|
151
|
-
}
|
152
|
-
HASH
|
153
|
-
|
154
|
-
expect(service).to receive(:run_cmd)
|
155
|
-
.with(%(echo #{base64(hash)} >> "%TEMP%\\hash-beta.txt"))
|
156
|
-
.and_return(cmd_output).once
|
157
|
-
|
158
|
-
upload
|
159
|
-
end
|
160
|
-
|
161
|
-
it 'sets hash_file and runs the decode_files powershell script' do
|
162
|
-
expect(service).to receive(:run_powershell_script).with(
|
163
|
-
regexify(%($hash_file = "$env:TEMP\\hash-beta.txt")) &&
|
164
|
-
regexify(
|
165
|
-
'Decode-Files (Invoke-Input $hash_file) | ' \
|
166
|
-
'ConvertTo-Csv -NoTypeInformation')
|
167
|
-
).and_return(check_output)
|
168
|
-
|
169
|
-
upload
|
170
|
-
end
|
171
|
-
end
|
172
|
-
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
173
|
-
|
174
|
-
describe 'for a new file' do
|
175
|
-
# let(:check_output) do
|
176
|
-
def check_output
|
177
|
-
create_check_output([
|
178
|
-
CheckEntry.new('False', src_md5, nil, 'True', 'False')
|
179
|
-
])
|
180
|
-
end
|
181
|
-
|
182
|
-
let(:cmd_output) do
|
183
|
-
o = ::WinRM::Output.new
|
184
|
-
o[:exitcode] = 0
|
185
|
-
o
|
186
|
-
end
|
187
|
-
|
188
|
-
# let(:decode_output) do
|
189
|
-
def decode_output
|
190
|
-
create_decode_output([
|
191
|
-
DecodeEntry.new(dst, 'True', src_md5, src_md5, ps_tmpfile, nil)
|
192
|
-
])
|
193
|
-
end
|
194
|
-
|
195
|
-
before do
|
196
|
-
allow(service).to receive(:run_cmd)
|
197
|
-
.and_return(cmd_output)
|
198
|
-
|
199
|
-
allow(service).to receive(:run_powershell_script)
|
200
|
-
.with(/^Check-Files .+ \| ConvertTo-Csv/)
|
201
|
-
.and_return(check_output)
|
202
|
-
|
203
|
-
allow(service).to receive(:run_powershell_script)
|
204
|
-
.with(/^Decode-Files .+ \| ConvertTo-Csv/)
|
205
|
-
.and_return(decode_output)
|
206
|
-
end
|
207
|
-
|
208
|
-
common_specs_for_all_single_file_types
|
209
|
-
|
210
|
-
common_specs_for_all_single_dirty_file_types
|
211
|
-
|
212
|
-
it 'returns a report hash' do
|
213
|
-
expect(upload[1]).to eq(
|
214
|
-
src_md5 => {
|
215
|
-
'src' => local,
|
216
|
-
'dst' => dst,
|
217
|
-
'tmpfile' => ps_tmpfile,
|
218
|
-
'tmpzip' => nil,
|
219
|
-
'src_md5' => src_md5,
|
220
|
-
'dst_md5' => src_md5,
|
221
|
-
'chk_exists' => 'False',
|
222
|
-
'chk_dirty' => 'True',
|
223
|
-
'verifies' => 'True',
|
224
|
-
'size' => size,
|
225
|
-
'xfered' => size / 3 * 4,
|
226
|
-
'chunks' => (size / 6000.to_f).ceil
|
227
|
-
}
|
228
|
-
)
|
229
|
-
end
|
230
|
-
|
231
|
-
describe 'when a failed check command is returned' do
|
232
|
-
def check_output
|
233
|
-
o = ::WinRM::Output.new
|
234
|
-
o[:exitcode] = 10
|
235
|
-
o[:data].concat([{ stderr: 'Oh noes\n' }])
|
236
|
-
o
|
237
|
-
end
|
238
|
-
|
239
|
-
it 'raises a FileTransporterFailed error' do
|
240
|
-
expect { upload }.to raise_error(
|
241
|
-
WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
describe 'when a failed decode command is returned' do
|
246
|
-
def decode_output
|
247
|
-
o = ::WinRM::Output.new
|
248
|
-
o[:exitcode] = 10
|
249
|
-
o[:data].concat([{ stderr: 'Oh noes\n' }])
|
250
|
-
o
|
251
|
-
end
|
252
|
-
|
253
|
-
it 'raises a FileTransporterFailed error' do
|
254
|
-
expect { upload }.to raise_error(
|
255
|
-
WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
describe 'for an out of date (dirty) file' do
|
261
|
-
let(:check_output) do
|
262
|
-
create_check_output([
|
263
|
-
CheckEntry.new('True', src_md5, 'aabbcc', 'True', 'False')
|
264
|
-
])
|
265
|
-
end
|
266
|
-
|
267
|
-
let(:cmd_output) do
|
268
|
-
o = ::WinRM::Output.new
|
269
|
-
o[:exitcode] = 0
|
270
|
-
o
|
271
|
-
end
|
272
|
-
|
273
|
-
let(:decode_output) do
|
274
|
-
create_decode_output([
|
275
|
-
DecodeEntry.new(dst, 'True', src_md5, src_md5, ps_tmpfile, nil)
|
276
|
-
])
|
277
|
-
end
|
278
|
-
|
279
|
-
before do
|
280
|
-
allow(service).to receive(:run_cmd)
|
281
|
-
.and_return(cmd_output)
|
282
|
-
|
283
|
-
allow(service).to receive(:run_powershell_script)
|
284
|
-
.with(/^Check-Files .+ \| ConvertTo-Csv/)
|
285
|
-
.and_return(check_output)
|
286
|
-
|
287
|
-
allow(service).to receive(:run_powershell_script)
|
288
|
-
.with(/^Decode-Files .+ \| ConvertTo-Csv/)
|
289
|
-
.and_return(decode_output)
|
290
|
-
end
|
291
|
-
|
292
|
-
common_specs_for_all_single_file_types
|
293
|
-
|
294
|
-
common_specs_for_all_single_dirty_file_types
|
295
|
-
|
296
|
-
it 'returns a report hash' do
|
297
|
-
expect(upload[1]).to eq(
|
298
|
-
src_md5 => {
|
299
|
-
'src' => local,
|
300
|
-
'dst' => dst,
|
301
|
-
'tmpfile' => ps_tmpfile,
|
302
|
-
'tmpzip' => nil,
|
303
|
-
'src_md5' => src_md5,
|
304
|
-
'dst_md5' => src_md5,
|
305
|
-
'chk_exists' => 'True',
|
306
|
-
'chk_dirty' => 'True',
|
307
|
-
'verifies' => 'True',
|
308
|
-
'size' => size,
|
309
|
-
'xfered' => size / 3 * 4,
|
310
|
-
'chunks' => (size / 6000.to_f).ceil
|
311
|
-
}
|
312
|
-
)
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
describe 'for an up to date (clean) file' do
|
317
|
-
let(:check_output) do
|
318
|
-
create_check_output([
|
319
|
-
CheckEntry.new('True', src_md5, src_md5, 'False', 'True')
|
320
|
-
])
|
321
|
-
end
|
322
|
-
|
323
|
-
let(:cmd_output) do
|
324
|
-
o = ::WinRM::Output.new
|
325
|
-
o[:exitcode] = 0
|
326
|
-
o
|
327
|
-
end
|
328
|
-
|
329
|
-
before do
|
330
|
-
allow(service).to receive(:run_cmd)
|
331
|
-
.and_return(cmd_output)
|
332
|
-
|
333
|
-
allow(service).to receive(:run_powershell_script)
|
334
|
-
.with(/^Check-Files .+ \| ConvertTo-Csv/)
|
335
|
-
.and_return(check_output)
|
336
|
-
end
|
337
|
-
|
338
|
-
common_specs_for_all_single_file_types
|
339
|
-
|
340
|
-
it 'uploads nothing' do
|
341
|
-
expect(service).not_to receive(:run_cmd).with(/#{remote}/)
|
342
|
-
|
343
|
-
upload
|
344
|
-
end
|
345
|
-
|
346
|
-
it 'skips the decode_files powershell script' do
|
347
|
-
expect(service).not_to receive(:run_powershell_script).with(regexify(
|
348
|
-
'Decode-Files $files | ConvertTo-Csv -NoTypeInformation')
|
349
|
-
)
|
350
|
-
|
351
|
-
upload
|
352
|
-
end
|
353
|
-
|
354
|
-
it 'returns a report hash' do
|
355
|
-
expect(upload[1]).to eq(
|
356
|
-
src_md5 => {
|
357
|
-
'src' => local,
|
358
|
-
'dst' => remote,
|
359
|
-
'size' => size,
|
360
|
-
'src_md5' => src_md5,
|
361
|
-
'dst_md5' => src_md5,
|
362
|
-
'chk_exists' => 'True',
|
363
|
-
'chk_dirty' => 'False',
|
364
|
-
'verifies' => 'True'
|
365
|
-
}
|
366
|
-
)
|
367
|
-
end
|
368
|
-
end
|
369
|
-
end
|
370
|
-
|
371
|
-
describe 'when uploading a single directory' do
|
372
|
-
let(:content) { "I'm a fake zip file" }
|
373
|
-
let(:local) { Dir.mktmpdir('input') }
|
374
|
-
let(:remote) { 'C:\\dest' }
|
375
|
-
let(:src_zip) { create_tempfile('fake.zip', content) }
|
376
|
-
let(:dst) { remote }
|
377
|
-
let(:src_md5) { md5sum(src_zip) }
|
378
|
-
let(:size) { File.size(src_zip) }
|
379
|
-
let(:cmd_tmpfile) { "%TEMP%\\b64-#{src_md5}.txt" }
|
380
|
-
let(:ps_tmpfile) { "$env:TEMP\\b64-#{src_md5}.txt" }
|
381
|
-
let(:ps_tmpzip) { "$env:TEMP\\winrm-upload\\tmpzip-#{src_md5}.zip" }
|
382
|
-
|
383
|
-
let(:tmp_zip) { double('tmp_zip') }
|
384
|
-
|
385
|
-
let(:cmd_output) do
|
386
|
-
o = ::WinRM::Output.new
|
387
|
-
o[:exitcode] = 0
|
388
|
-
o
|
389
|
-
end
|
390
|
-
|
391
|
-
let(:check_output) do
|
392
|
-
create_check_output([
|
393
|
-
CheckEntry.new('False', src_md5, nil, 'True', 'False')
|
394
|
-
])
|
395
|
-
end
|
396
|
-
|
397
|
-
let(:decode_output) do
|
398
|
-
create_decode_output([
|
399
|
-
DecodeEntry.new(dst, 'True', src_md5, src_md5, ps_tmpfile, ps_tmpzip)
|
400
|
-
])
|
401
|
-
end
|
402
|
-
|
403
|
-
before do
|
404
|
-
allow(tmp_zip).to receive(:path).and_return(Pathname(src_zip))
|
405
|
-
allow(tmp_zip).to receive(:unlink)
|
406
|
-
allow(WinRM::FS::Core::TmpZip).to receive(:new).with("#{local}/", logger)
|
407
|
-
.and_return(tmp_zip)
|
408
|
-
|
409
|
-
allow(service).to receive(:run_cmd)
|
410
|
-
.and_return(cmd_output)
|
411
|
-
|
412
|
-
allow(service).to receive(:run_powershell_script)
|
413
|
-
.with(/^Check-Files .+ \| ConvertTo-Csv/)
|
414
|
-
.and_return(check_output)
|
415
|
-
|
416
|
-
allow(service).to receive(:run_powershell_script)
|
417
|
-
.with(/^Decode-Files .+ \| ConvertTo-Csv/)
|
418
|
-
.and_return(decode_output)
|
419
|
-
end
|
420
|
-
|
421
|
-
after do
|
422
|
-
FileUtils.rm_rf(local)
|
423
|
-
end
|
424
|
-
|
425
|
-
let(:upload) { transporter.upload("#{local}/", remote) }
|
426
|
-
|
427
|
-
it 'truncates a zero-byte hash_file for check_files' do
|
428
|
-
expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"%TEMP%\\hash-alpha.txt"))
|
429
|
-
).and_return(cmd_output)
|
430
|
-
|
431
|
-
upload
|
432
|
-
end
|
433
|
-
|
434
|
-
it 'uploads the hash_file in chunks for check_files' do
|
435
|
-
hash = outdent!(<<-HASH.chomp)
|
436
|
-
@{
|
437
|
-
"#{src_md5}" = @{
|
438
|
-
"target" = "#{ps_tmpzip}";
|
439
|
-
"src_basename" = "#{File.basename(local)}";
|
440
|
-
"dst" = "#{dst}\\#{File.basename(local)}"
|
441
|
-
}
|
442
|
-
}
|
443
|
-
HASH
|
444
|
-
|
445
|
-
expect(service).to receive(:run_cmd)
|
446
|
-
.with(%(echo #{base64(hash)} >> "%TEMP%\\hash-alpha.txt"))
|
447
|
-
.and_return(cmd_output).once
|
448
|
-
|
449
|
-
upload
|
450
|
-
end
|
451
|
-
|
452
|
-
it 'sets hash_file and runs the check_files powershell script' do
|
453
|
-
expect(service).to receive(:run_powershell_script).with(
|
454
|
-
regexify(%($hash_file = "$env:TEMP\\hash-alpha.txt")) &&
|
455
|
-
regexify(
|
456
|
-
'Check-Files (Invoke-Input $hash_file) | ' \
|
457
|
-
'ConvertTo-Csv -NoTypeInformation')
|
458
|
-
).and_return(check_output)
|
459
|
-
|
460
|
-
upload
|
461
|
-
end
|
462
|
-
|
463
|
-
it 'truncates a zero-byte tempfile' do
|
464
|
-
expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"#{cmd_tmpfile}"))
|
465
|
-
).and_return(cmd_output)
|
466
|
-
|
467
|
-
upload
|
468
|
-
end
|
469
|
-
|
470
|
-
it 'uploads the zip file in base64 encoding' do
|
471
|
-
expect(service).to receive(:run_cmd)
|
472
|
-
.with(%(echo #{base64(content)} >> "#{cmd_tmpfile}"))
|
473
|
-
.and_return(cmd_output)
|
474
|
-
|
475
|
-
upload
|
476
|
-
end
|
477
|
-
|
478
|
-
it 'truncates a zero-byte hash_file for decode_files' do
|
479
|
-
expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"%TEMP%\\hash-beta.txt"))
|
480
|
-
).and_return(cmd_output)
|
481
|
-
|
482
|
-
upload
|
483
|
-
end
|
484
|
-
|
485
|
-
it 'uploads the hash_file in chunks for decode_files' do
|
486
|
-
hash = outdent!(<<-HASH.chomp)
|
487
|
-
@{
|
488
|
-
"#{ps_tmpfile}" = @{
|
489
|
-
"dst" = "#{dst}\\#{File.basename(local)}";
|
490
|
-
"tmpzip" = "#{ps_tmpzip}"
|
491
|
-
}
|
492
|
-
}
|
493
|
-
HASH
|
494
|
-
|
495
|
-
expect(service).to receive(:run_cmd)
|
496
|
-
.with(%(echo #{base64(hash)} >> "%TEMP%\\hash-beta.txt"))
|
497
|
-
.and_return(cmd_output).once
|
498
|
-
|
499
|
-
upload
|
500
|
-
end
|
501
|
-
|
502
|
-
it 'sets hash_file and runs the decode_files powershell script' do
|
503
|
-
expect(service).to receive(:run_powershell_script).with(
|
504
|
-
regexify(%($hash_file = "$env:TEMP\\hash-beta.txt")) &&
|
505
|
-
regexify(
|
506
|
-
'Decode-Files (Invoke-Input $hash_file) | ' \
|
507
|
-
'ConvertTo-Csv -NoTypeInformation')
|
508
|
-
).and_return(check_output)
|
509
|
-
|
510
|
-
upload
|
511
|
-
end
|
512
|
-
|
513
|
-
it 'returns a report hash' do
|
514
|
-
expect(upload[1]).to eq(
|
515
|
-
src_md5 => {
|
516
|
-
'src' => "#{local}/",
|
517
|
-
'src_zip' => src_zip,
|
518
|
-
'dst' => dst,
|
519
|
-
'tmpfile' => ps_tmpfile,
|
520
|
-
'tmpzip' => ps_tmpzip,
|
521
|
-
'src_md5' => src_md5,
|
522
|
-
'dst_md5' => src_md5,
|
523
|
-
'chk_exists' => 'False',
|
524
|
-
'chk_dirty' => 'True',
|
525
|
-
'verifies' => 'True',
|
526
|
-
'size' => size,
|
527
|
-
'xfered' => size / 3 * 4,
|
528
|
-
'chunks' => (size / 6000.to_f).ceil
|
529
|
-
}
|
530
|
-
)
|
531
|
-
end
|
532
|
-
|
533
|
-
it 'cleans up the zip file' do
|
534
|
-
expect(tmp_zip).to receive(:unlink)
|
535
|
-
|
536
|
-
upload
|
537
|
-
end
|
538
|
-
|
539
|
-
describe 'when a failed check command is returned' do
|
540
|
-
def check_output
|
541
|
-
o = ::WinRM::Output.new
|
542
|
-
o[:exitcode] = 10
|
543
|
-
o[:data].concat([{ stderr: 'Oh noes\n' }])
|
544
|
-
o
|
545
|
-
end
|
546
|
-
|
547
|
-
it 'raises a FileTransporterFailed error' do
|
548
|
-
expect { upload }.to raise_error(
|
549
|
-
WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
|
550
|
-
end
|
551
|
-
end
|
552
|
-
|
553
|
-
describe 'when a failed decode command is returned' do
|
554
|
-
def decode_output
|
555
|
-
o = ::WinRM::Output.new
|
556
|
-
o[:exitcode] = 10
|
557
|
-
o[:data].concat([{ stderr: 'Oh noes\n' }])
|
558
|
-
o
|
559
|
-
end
|
560
|
-
|
561
|
-
it 'raises a FileTransporterFailed error' do
|
562
|
-
expect { upload }.to raise_error(
|
563
|
-
WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
|
564
|
-
end
|
565
|
-
end
|
566
|
-
end
|
567
|
-
|
568
|
-
describe 'when uploading multiple files' do
|
569
|
-
let(:remote) { 'C:\\Program Files' }
|
570
|
-
|
571
|
-
1.upto(3).each do |i|
|
572
|
-
let(:"local#{i}") { create_tempfile("input#{i}.txt", "input#{i}") }
|
573
|
-
let(:"src#{i}_md5") { md5sum(send("local#{i}")) }
|
574
|
-
let(:"dst#{i}") { "#{remote}" }
|
575
|
-
let(:"size#{i}") { File.size(send("local#{i}")) }
|
576
|
-
let(:"cmd#{i}_tmpfile") { "%TEMP%\\b64-#{send("src#{i}_md5")}.txt" }
|
577
|
-
let(:"ps#{i}_tmpfile") { "$env:TEMP\\b64-#{send("src#{i}_md5")}.txt" }
|
578
|
-
end
|
579
|
-
|
580
|
-
let(:check_output) do
|
581
|
-
create_check_output([
|
582
|
-
# new
|
583
|
-
CheckEntry.new('False', src1_md5, nil, 'True', 'False'),
|
584
|
-
# out-of-date
|
585
|
-
CheckEntry.new('True', src2_md5, 'aabbcc', 'True', 'False'),
|
586
|
-
# current
|
587
|
-
CheckEntry.new('True', src3_md5, src3_md5, 'False', 'True')
|
588
|
-
])
|
589
|
-
end
|
590
|
-
|
591
|
-
let(:cmd_output) do
|
592
|
-
o = ::WinRM::Output.new
|
593
|
-
o[:exitcode] = 0
|
594
|
-
o
|
595
|
-
end
|
596
|
-
|
597
|
-
let(:decode_output) do
|
598
|
-
create_decode_output([
|
599
|
-
DecodeEntry.new(dst1, 'True', src1_md5, src1_md5, ps1_tmpfile, nil),
|
600
|
-
DecodeEntry.new(dst2, 'True', src2_md5, src2_md5, ps2_tmpfile, nil)
|
601
|
-
])
|
602
|
-
end
|
603
|
-
|
604
|
-
let(:upload) { transporter.upload([local1, local2, local3], remote) }
|
605
|
-
|
606
|
-
before do
|
607
|
-
allow(service).to receive(:run_cmd)
|
608
|
-
.and_return(cmd_output)
|
609
|
-
|
610
|
-
allow(service).to receive(:run_powershell_script)
|
611
|
-
.with(/^Check-Files .+ \| ConvertTo-Csv/)
|
612
|
-
.and_return(check_output)
|
613
|
-
|
614
|
-
allow(service).to receive(:run_powershell_script)
|
615
|
-
.with(/^Decode-Files .+ \| ConvertTo-Csv/)
|
616
|
-
.and_return(decode_output)
|
617
|
-
end
|
618
|
-
|
619
|
-
it 'truncates a zero-byte hash_file for check_files' do
|
620
|
-
expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"%TEMP%\\hash-alpha.txt"))
|
621
|
-
).and_return(cmd_output)
|
622
|
-
|
623
|
-
upload
|
624
|
-
end
|
625
|
-
|
626
|
-
it 'uploads the hash_file in chunks for check_files' do
|
627
|
-
hash = outdent!(<<-HASH.chomp)
|
628
|
-
@{
|
629
|
-
"#{src1_md5}" = @{
|
630
|
-
"target" = "#{dst1}";
|
631
|
-
"src_basename" = "#{File.basename(local1)}";
|
632
|
-
"dst" = "#{dst1}"
|
633
|
-
};
|
634
|
-
"#{src2_md5}" = @{
|
635
|
-
"target" = "#{dst2}";
|
636
|
-
"src_basename" = "#{File.basename(local2)}";
|
637
|
-
"dst" = "#{dst2}"
|
638
|
-
};
|
639
|
-
"#{src3_md5}" = @{
|
640
|
-
"target" = "#{dst3}";
|
641
|
-
"src_basename" = "#{File.basename(local3)}";
|
642
|
-
"dst" = "#{dst3}"
|
643
|
-
}
|
644
|
-
}
|
645
|
-
HASH
|
646
|
-
|
647
|
-
expect(service).to receive(:run_cmd)
|
648
|
-
.with(%(echo #{base64(hash)} >> "%TEMP%\\hash-alpha.txt"))
|
649
|
-
.and_return(cmd_output).once
|
650
|
-
|
651
|
-
upload
|
652
|
-
end
|
653
|
-
|
654
|
-
it 'sets hash_file and runs the check_files powershell script' do
|
655
|
-
expect(service).to receive(:run_powershell_script).with(
|
656
|
-
regexify(%($hash_file = "$env:TEMP\\hash-alpha.txt")) &&
|
657
|
-
regexify(
|
658
|
-
'Check-Files (Invoke-Input $hash_file) | ' \
|
659
|
-
'ConvertTo-Csv -NoTypeInformation')
|
660
|
-
).and_return(check_output)
|
661
|
-
|
662
|
-
upload
|
663
|
-
end
|
664
|
-
|
665
|
-
it 'only uploads dirty files' do
|
666
|
-
expect(service).to receive(:run_cmd)
|
667
|
-
.with(%(echo #{base64(IO.read(local1))} >> "#{cmd1_tmpfile}"))
|
668
|
-
expect(service).to receive(:run_cmd)
|
669
|
-
.with(%(echo #{base64(IO.read(local2))} >> "#{cmd2_tmpfile}"))
|
670
|
-
expect(service).not_to receive(:run_cmd)
|
671
|
-
.with(%(echo #{base64(IO.read(local3))} >> "#{cmd3_tmpfile}"))
|
672
|
-
|
673
|
-
upload
|
674
|
-
end
|
675
|
-
|
676
|
-
it 'truncates a zero-byte hash_file for decode_files' do
|
677
|
-
expect(service).to receive(:run_cmd).with(regexify(%(echo|set /p=>"%TEMP%\\hash-beta.txt"))
|
678
|
-
).and_return(cmd_output)
|
679
|
-
|
680
|
-
upload
|
681
|
-
end
|
682
|
-
|
683
|
-
it 'uploads the hash_file in chunks for decode_files' do
|
684
|
-
hash = outdent!(<<-HASH.chomp)
|
685
|
-
@{
|
686
|
-
"#{ps1_tmpfile}" = @{
|
687
|
-
"dst" = "#{dst1}"
|
688
|
-
};
|
689
|
-
"#{ps2_tmpfile}" = @{
|
690
|
-
"dst" = "#{dst2}"
|
691
|
-
}
|
692
|
-
}
|
693
|
-
HASH
|
694
|
-
|
695
|
-
expect(service).to receive(:run_cmd)
|
696
|
-
.with(%(echo #{base64(hash)} >> "%TEMP%\\hash-beta.txt"))
|
697
|
-
.and_return(cmd_output).once
|
698
|
-
|
699
|
-
upload
|
700
|
-
end
|
701
|
-
|
702
|
-
it 'sets hash_file and runs the decode_files powershell script' do
|
703
|
-
expect(service).to receive(:run_powershell_script).with(
|
704
|
-
regexify(%($hash_file = '$env:TEMP\\hash-beta.txt')) &&
|
705
|
-
regexify(
|
706
|
-
'Decode-Files (Invoke-Input $hash_file) | ' \
|
707
|
-
'ConvertTo-Csv -NoTypeInformation')
|
708
|
-
).and_return(check_output)
|
709
|
-
|
710
|
-
upload
|
711
|
-
end
|
712
|
-
|
713
|
-
it 'returns a report hash' do
|
714
|
-
report = upload[1]
|
715
|
-
|
716
|
-
expect(report.fetch(src1_md5)).to eq(
|
717
|
-
'src' => local1,
|
718
|
-
'dst' => dst1,
|
719
|
-
'tmpfile' => ps1_tmpfile,
|
720
|
-
'tmpzip' => nil,
|
721
|
-
'src_md5' => src1_md5,
|
722
|
-
'dst_md5' => src1_md5,
|
723
|
-
'chk_exists' => 'False',
|
724
|
-
'chk_dirty' => 'True',
|
725
|
-
'verifies' => 'True',
|
726
|
-
'size' => size1,
|
727
|
-
'xfered' => size1 / 3 * 4,
|
728
|
-
'chunks' => (size1 / 6000.to_f).ceil
|
729
|
-
)
|
730
|
-
expect(report.fetch(src2_md5)).to eq(
|
731
|
-
'src' => local2,
|
732
|
-
'dst' => dst2,
|
733
|
-
'tmpfile' => ps2_tmpfile,
|
734
|
-
'tmpzip' => nil,
|
735
|
-
'src_md5' => src2_md5,
|
736
|
-
'dst_md5' => src2_md5,
|
737
|
-
'chk_exists' => 'True',
|
738
|
-
'chk_dirty' => 'True',
|
739
|
-
'verifies' => 'True',
|
740
|
-
'size' => size2,
|
741
|
-
'xfered' => size2 / 3 * 4,
|
742
|
-
'chunks' => (size2 / 6000.to_f).ceil
|
743
|
-
)
|
744
|
-
expect(report.fetch(src3_md5)).to eq(
|
745
|
-
'src' => local3,
|
746
|
-
'dst' => dst3,
|
747
|
-
'src_md5' => src3_md5,
|
748
|
-
'dst_md5' => src3_md5,
|
749
|
-
'chk_exists' => 'True',
|
750
|
-
'chk_dirty' => 'False',
|
751
|
-
'verifies' => 'True',
|
752
|
-
'size' => size3
|
753
|
-
)
|
754
|
-
end
|
755
|
-
|
756
|
-
describe 'when a failed check command is returned' do
|
757
|
-
def check_output
|
758
|
-
o = ::WinRM::Output.new
|
759
|
-
o[:exitcode] = 10
|
760
|
-
o[:data].concat([{ stderr: "Oh noes\n" }])
|
761
|
-
o
|
762
|
-
end
|
763
|
-
|
764
|
-
it 'raises a FileTransporterFailed error' do
|
765
|
-
expect { upload }.to raise_error(
|
766
|
-
WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
|
767
|
-
end
|
768
|
-
end
|
769
|
-
|
770
|
-
describe 'when a failed decode command is returned' do
|
771
|
-
def decode_output
|
772
|
-
o = ::WinRM::Output.new
|
773
|
-
o[:exitcode] = 10
|
774
|
-
o[:data].concat([{ stderr: "Oh noes\n" }])
|
775
|
-
o
|
776
|
-
end
|
777
|
-
|
778
|
-
it 'raises a FileTransporterFailed error' do
|
779
|
-
expect { upload }.to raise_error(
|
780
|
-
WinRM::FS::Core::FileTransporterFailed, /Upload failed \(exitcode: 10\)/)
|
781
|
-
end
|
782
|
-
end
|
783
|
-
end
|
784
|
-
|
785
|
-
it 'raises an exception when local file or directory is not found' do
|
786
|
-
expect { transporter.upload('/a/b/c/nope', 'C:\\nopeland') }.to raise_error Errno::ENOENT
|
787
|
-
end
|
788
|
-
|
789
|
-
def base64(string)
|
790
|
-
Base64.strict_encode64(string)
|
791
|
-
end
|
792
|
-
|
793
|
-
def create_check_output(entries)
|
794
|
-
csv = CSV.generate(force_quotes: true) do |rows|
|
795
|
-
rows << CheckEntry.new.members.map(&:to_s)
|
796
|
-
entries.each { |entry| rows << entry.to_a }
|
797
|
-
end
|
798
|
-
|
799
|
-
o = ::WinRM::Output.new
|
800
|
-
o[:exitcode] = 0
|
801
|
-
o[:data].concat(csv.lines.map { |line| { stdout: line } })
|
802
|
-
o
|
803
|
-
end
|
804
|
-
|
805
|
-
def create_decode_output(entries)
|
806
|
-
csv = CSV.generate(force_quotes: true) do |rows|
|
807
|
-
rows << DecodeEntry.new.members.map(&:to_s)
|
808
|
-
entries.each { |entry| rows << entry.to_a }
|
809
|
-
end
|
810
|
-
|
811
|
-
o = ::WinRM::Output.new
|
812
|
-
o[:exitcode] = 0
|
813
|
-
o[:data].concat(csv.lines.map { |line| { stdout: line } })
|
814
|
-
o
|
815
|
-
end
|
816
|
-
|
817
|
-
def create_tempfile(name, content)
|
818
|
-
pre, _, ext = name.rpartition('.')
|
819
|
-
file = Tempfile.open(["#{pre}-", ".#{ext}"])
|
820
|
-
@tempfiles << file
|
821
|
-
file.write(content)
|
822
|
-
file.close
|
823
|
-
file.path
|
824
|
-
end
|
825
|
-
|
826
|
-
def md5sum(local)
|
827
|
-
Digest::MD5.file(local).hexdigest
|
828
|
-
end
|
829
|
-
|
830
|
-
def outdent!(string)
|
831
|
-
string.gsub!(/^ {#{string.index(/[^ ]/)}}/, '')
|
832
|
-
end
|
833
|
-
|
834
|
-
def regexify(str, line = :whole_line)
|
835
|
-
r = Regexp.escape(str)
|
836
|
-
r = "^#{r}$" if line == :whole_line
|
837
|
-
Regexp.new(r)
|
838
|
-
end
|
839
|
-
end
|