1 #!powershell
2
3 #AnsibleRequires -CSharpUtil Ansible.Basic
4 #AnsibleRequires -CSharpUtil Ansible.Process
5
6 $module = [Ansible.Basic.AnsibleModule]::Create($args, @{})
7
Assert-Equalsnull8 Function Assert-Equals {
9 param(
10 [Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
11 [Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
12 )
13
14 $matched = $false
15 if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array]) {
16 $Actual.Count | Assert-Equals -Expected $Expected.Count
17 for ($i = 0; $i -lt $Actual.Count; $i++) {
18 $actual_value = $Actual[$i]
19 $expected_value = $Expected[$i]
20 Assert-Equals -Actual $actual_value -Expected $expected_value
21 }
22 $matched = $true
23 } else {
24 $matched = $Actual -ceq $Expected
25 }
26
27 if (-not $matched) {
28 if ($Actual -is [PSObject]) {
29 $Actual = $Actual.ToString()
30 }
31
32 $call_stack = (Get-PSCallStack)[1]
33 $module.Result.test = $test
34 $module.Result.actual = $Actual
35 $module.Result.expected = $Expected
36 $module.Result.line = $call_stack.ScriptLineNumber
37 $module.Result.method = $call_stack.Position.Text
38 $module.FailJson("AssertionError: actual != expected")
39 }
40 }
41
42 $tests = @{
43 "ParseCommandLine empty string" = {
44 $expected = @((Get-Process -Id $pid).Path)
45 $actual = [Ansible.Process.ProcessUtil]::ParseCommandLine("")
46 Assert-Equals -Actual $actual -Expected $expected
47 }
48
49 "ParseCommandLine single argument" = {
50 $expected = @("powershell.exe")
51 $actual = [Ansible.Process.ProcessUtil]::ParseCommandLine("powershell.exe")
52 Assert-Equals -Actual $actual -Expected $expected
53 }
54
55 "ParseCommandLine multiple arguments" = {
56 $expected = @("powershell.exe", "-File", "C:\temp\script.ps1")
57 $actual = [Ansible.Process.ProcessUtil]::ParseCommandLine("powershell.exe -File C:\temp\script.ps1")
58 Assert-Equals -Actual $actual -Expected $expected
59 }
60
61 "ParseCommandLine comples arguments" = {
62 $expected = @('abc', 'd', 'ef gh', 'i\j', 'k"l', 'm\n op', 'ADDLOCAL=qr, s', 'tuv\', 'w''x', 'yz')
63 $actual = [Ansible.Process.ProcessUtil]::ParseCommandLine('abc d "ef gh" i\j k\"l m\\"n op" ADDLOCAL="qr, s" tuv\ w''x yz')
64 Assert-Equals -Actual $actual -Expected $expected
65 }
66
67 "SearchPath normal" = {
68 $expected = "$($env:SystemRoot)\System32\WindowsPowerShell\v1.0\powershell.exe"
69 $actual = [Ansible.Process.ProcessUtil]::SearchPath("powershell.exe")
70 $actual | Assert-Equals -Expected $expected
71 }
72
73 "SearchPath missing" = {
74 $failed = $false
75 try {
76 [Ansible.Process.ProcessUtil]::SearchPath("fake.exe")
77 } catch {
78 $failed = $true
79 $_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "System.IO.FileNotFoundException"
80 $expected = 'Exception calling "SearchPath" with "1" argument(s): "Could not find file ''fake.exe''."'
81 $_.Exception.Message | Assert-Equals -Expected $expected
82 }
83 $failed | Assert-Equals -Expected $true
84 }
85
86 "CreateProcess basic" = {
87 $actual = [Ansible.Process.ProcessUtil]::CreateProcess("whoami.exe")
88 $actual.GetType().FullName | Assert-Equals -Expected "Ansible.Process.Result"
89 $actual.StandardOut | Assert-Equals -Expected "$(&whoami.exe)`r`n"
90 $actual.StandardError | Assert-Equals -Expected ""
91 $actual.ExitCode | Assert-Equals -Expected 0
92 }
93
94 "CreateProcess stderr" = {
95 $actual = [Ansible.Process.ProcessUtil]::CreateProcess("powershell.exe [System.Console]::Error.WriteLine('hi')")
96 $actual.StandardOut | Assert-Equals -Expected ""
97 $actual.StandardError | Assert-Equals -Expected "hi`r`n"
98 $actual.ExitCode | Assert-Equals -Expected 0
99 }
100
101 "CreateProcess exit code" = {
102 $actual = [Ansible.Process.ProcessUtil]::CreateProcess("powershell.exe exit 10")
103 $actual.StandardOut | Assert-Equals -Expected ""
104 $actual.StandardError | Assert-Equals -Expected ""
105 $actual.ExitCode | Assert-Equals -Expected 10
106 }
107
108 "CreateProcess bad executable" = {
109 $failed = $false
110 try {
111 [Ansible.Process.ProcessUtil]::CreateProcess("fake.exe")
112 } catch {
113 $failed = $true
114 $_.Exception.InnerException.GetType().FullName | Assert-Equals -Expected "Ansible.Process.Win32Exception"
115 $expected = 'Exception calling "CreateProcess" with "1" argument(s): "CreateProcessW() failed '
116 $expected += '(The system cannot find the file specified, Win32ErrorCode 2)"'
117 $_.Exception.Message | Assert-Equals -Expected $expected
118 }
119 $failed | Assert-Equals -Expected $true
120 }
121
122 "CreateProcess with unicode" = {
123 $actual = [Ansible.Process.ProcessUtil]::CreateProcess("cmd.exe /c echo café")
124 $actual.StandardOut | Assert-Equals -Expected " café`r`n"
125 $actual.StandardError | Assert-Equals -Expected ""
126 $actual.ExitCode | Assert-Equals -Expected 0
127
128 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, "cmd.exe /c echo café", $null, $null)
129 $actual.StandardOut | Assert-Equals -Expected " café`r`n"
130 $actual.StandardError | Assert-Equals -Expected ""
131 $actual.ExitCode | Assert-Equals -Expected 0
132 }
133
134 "CreateProcess without working dir" = {
135 $expected = $pwd.Path + "`r`n"
136 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe $pwd.Path', $null, $null)
137 $actual.StandardOut | Assert-Equals -Expected $expected
138 $actual.StandardError | Assert-Equals -Expected ""
139 $actual.ExitCode | Assert-Equals -Expected 0
140 }
141
142 "CreateProcess with working dir" = {
143 $expected = "C:\Windows`r`n"
144 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe $pwd.Path', "C:\Windows", $null)
145 $actual.StandardOut | Assert-Equals -Expected $expected
146 $actual.StandardError | Assert-Equals -Expected ""
147 $actual.ExitCode | Assert-Equals -Expected 0
148 }
149
150 "CreateProcess without environment" = {
151 $expected = "$($env:USERNAME)`r`n"
152 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe $env:TEST; $env:USERNAME', $null, $null)
153 $actual.StandardOut | Assert-Equals -Expected $expected
154 $actual.StandardError | Assert-Equals -Expected ""
155 $actual.ExitCode | Assert-Equals -Expected 0
156 }
157
158 "CreateProcess with environment" = {
159 $env_vars = @{
160 TEST = "tesTing"
161 TEST2 = "Testing 2"
162 }
163 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'cmd.exe /c set', $null, $env_vars)
164 ("TEST=tesTing" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
165 ("TEST2=Testing 2" -cin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
166 ("USERNAME=$($env:USERNAME)" -cnotin $actual.StandardOut.Split("`r`n")) | Assert-Equals -Expected $true
167 $actual.StandardError | Assert-Equals -Expected ""
168 $actual.ExitCode | Assert-Equals -Expected 0
169 }
170
171 "CreateProcess with string stdin" = {
172 $expected = "input value`r`n`r`n"
173 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe [System.Console]::In.ReadToEnd()',
174 $null, $null, "input value")
175 $actual.StandardOut | Assert-Equals -Expected $expected
176 $actual.StandardError | Assert-Equals -Expected ""
177 $actual.ExitCode | Assert-Equals -Expected 0
178 }
179
180 "CreateProcess with string stdin and newline" = {
181 $expected = "input value`r`n`r`n"
182 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe [System.Console]::In.ReadToEnd()',
183 $null, $null, "input value`r`n")
184 $actual.StandardOut | Assert-Equals -Expected $expected
185 $actual.StandardError | Assert-Equals -Expected ""
186 $actual.ExitCode | Assert-Equals -Expected 0
187 }
188
189 "CreateProcess with byte stdin" = {
190 $expected = "input value`r`n"
191 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe [System.Console]::In.ReadToEnd()',
192 $null, $null, [System.Text.Encoding]::UTF8.GetBytes("input value"))
193 $actual.StandardOut | Assert-Equals -Expected $expected
194 $actual.StandardError | Assert-Equals -Expected ""
195 $actual.ExitCode | Assert-Equals -Expected 0
196 }
197
198 "CreateProcess with byte stdin and newline" = {
199 $expected = "input value`r`n`r`n"
200 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, 'powershell.exe [System.Console]::In.ReadToEnd()',
201 $null, $null, [System.Text.Encoding]::UTF8.GetBytes("input value`r`n"))
202 $actual.StandardOut | Assert-Equals -Expected $expected
203 $actual.StandardError | Assert-Equals -Expected ""
204 $actual.ExitCode | Assert-Equals -Expected 0
205 }
206
207 "CreateProcess with lpApplicationName" = {
208 $expected = "abc`r`n"
209 $full_path = "$($env:SystemRoot)\System32\WindowsPowerShell\v1.0\powershell.exe"
210 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($full_path, "Write-Output 'abc'", $null, $null)
211 $actual.StandardOut | Assert-Equals -Expected $expected
212 $actual.StandardError | Assert-Equals -Expected ""
213 $actual.ExitCode | Assert-Equals -Expected 0
214
215 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($full_path, "powershell.exe Write-Output 'abc'", $null, $null)
216 $actual.StandardOut | Assert-Equals -Expected $expected
217 $actual.StandardError | Assert-Equals -Expected ""
218 $actual.ExitCode | Assert-Equals -Expected 0
219 }
220
221 "CreateProcess with unicode and us-ascii encoding" = {
222 $poop = [System.Char]::ConvertFromUtf32(0xE05A) # Coverage breaks due to script parsing encoding issues with unicode chars, just use the code point instead
223 $actual = [Ansible.Process.ProcessUtil]::CreateProcess($null, "cmd.exe /c echo $poop café", $null, $null, '', 'us-ascii')
224 $actual.StandardOut | Assert-Equals -Expected "??? caf??`r`n"
225 $actual.StandardError | Assert-Equals -Expected ""
226 $actual.ExitCode | Assert-Equals -Expected 0
227 }
228 }
229
230 foreach ($test_impl in $tests.GetEnumerator()) {
231 $test = $test_impl.Key
232 &$test_impl.Value
233 }
234
235 $module.Result.data = "success"
236 $module.ExitJson()
237