1 #!powershell
2
3 #AnsibleRequires -CSharpUtil Ansible.Basic
4 #Requires -Module Ansible.ModuleUtils.WebRequest
5
6 $spec = @{
7 options = @{
8 httpbin_host = @{ type = 'str'; required = $true }
9 }
10 }
11
12 $module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
13
14 $httpbin_host = $module.Params.httpbin_host
15
Assert-Equals()16 Function Assert-Equals {
17 param(
18 [Parameter(Mandatory=$true, ValueFromPipeline=$true)][AllowNull()]$Actual,
19 [Parameter(Mandatory=$true, Position=0)][AllowNull()]$Expected
20 )
21
22 $matched = $false
23 if ($Actual -is [System.Collections.ArrayList] -or $Actual -is [Array] -or $Actual -is [System.Collections.IList]) {
24 $Actual.Count | Assert-Equals -Expected $Expected.Count
25 for ($i = 0; $i -lt $Actual.Count; $i++) {
26 $actualValue = $Actual[$i]
27 $expectedValue = $Expected[$i]
28 Assert-Equals -Actual $actualValue -Expected $expectedValue
29 }
30 $matched = $true
31 } else {
32 $matched = $Actual -ceq $Expected
33 }
34
35 if (-not $matched) {
36 if ($Actual -is [PSObject]) {
37 $Actual = $Actual.ToString()
38 }
39
40 $call_stack = (Get-PSCallStack)[1]
41 $module.Result.test = $test
42 $module.Result.actual = $Actual
43 $module.Result.expected = $Expected
44 $module.Result.line = $call_stack.ScriptLineNumber
45 $module.Result.method = $call_stack.Position.Text
46
47 $module.FailJson("AssertionError: actual != expected")
48 }
49 }
50
Convert-StreamToString()51 Function Convert-StreamToString {
52 [CmdletBinding()]
53 param (
54 [Parameter(Mandatory=$true)]
55 [System.IO.Stream]
56 $Stream
57 )
58
59 $ms = New-Object -TypeName System.IO.MemoryStream
60 try {
61 $Stream.CopyTo($ms)
62 [System.Text.Encoding]::UTF8.GetString($ms.ToArray())
63 } finally {
64 $ms.Dispose()
65 }
66 }
67
68 $tests = [Ordered]@{
69 'GET request over http' = {
70 $r = Get-AnsibleWebRequest -Uri "http://$httpbin_host/get"
71
72 $r.Method | Assert-Equals -Expected 'GET'
73 $r.Timeout | Assert-Equals -Expected 30000
74 $r.UseDefaultCredentials | Assert-Equals -Expected $false
75 $r.Credentials | Assert-Equals -Expected $null
76 $r.ClientCertificates.Count | Assert-Equals -Expected 0
77 $r.Proxy.Credentials | Assert-Equals -Expected $null
78 $r.UserAgent | Assert-Equals -Expected 'ansible-httpget'
79
80 $actual = Invoke-WithWebRequest -Module $module -Request $r -Script {
81 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
82
83 $Response.StatusCode | Assert-Equals -Expected 200
84 Convert-StreamToString -Stream $Stream
85 } | ConvertFrom-Json
86
87 $actual.headers.'User-Agent' | Assert-Equals -Expected 'ansible-httpget'
88 $actual.headers.'Host' | Assert-Equals -Expected $httpbin_host
89
90 $module.Result.msg | Assert-Equals -Expected 'OK'
91 $module.Result.status_code | Assert-Equals -Expected 200
92 $module.Result.ContainsKey('elapsed') | Assert-Equals -Expected $true
93 }
94
95 'GET request over https' = {
96 # url is an alias for the -Uri parameter.
97 $r = Get-AnsibleWebRequest -url "https://$httpbin_host/get"
98
99 $r.Method | Assert-Equals -Expected 'GET'
100 $r.Timeout | Assert-Equals -Expected 30000
101 $r.UseDefaultCredentials | Assert-Equals -Expected $false
102 $r.Credentials | Assert-Equals -Expected $null
103 $r.ClientCertificates.Count | Assert-Equals -Expected 0
104 $r.Proxy.Credentials | Assert-Equals -Expected $null
105 $r.UserAgent | Assert-Equals -Expected 'ansible-httpget'
106
107 $actual = Invoke-WithWebRequest -Module $module -Request $r -Script {
108 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
109
110 $Response.StatusCode | Assert-Equals -Expected 200
111 Convert-StreamToString -Stream $Stream
112 } | ConvertFrom-Json
113
114 $actual.headers.'User-Agent' | Assert-Equals -Expected 'ansible-httpget'
115 $actual.headers.'Host' | Assert-Equals -Expected $httpbin_host
116 }
117
118 'POST request' = {
119 $getParams = @{
120 Headers = @{
121 'Content-Type' = 'application/json'
122 }
123 Method = 'POST'
124 Uri = "https://$httpbin_host/post"
125 }
126 $r = Get-AnsibleWebRequest @getParams
127
128 $r.Method | Assert-Equals -Expected 'POST'
129 $r.Timeout | Assert-Equals -Expected 30000
130 $r.UseDefaultCredentials | Assert-Equals -Expected $false
131 $r.Credentials | Assert-Equals -Expected $null
132 $r.ClientCertificates.Count | Assert-Equals -Expected 0
133 $r.Proxy.Credentials | Assert-Equals -Expected $null
134 $r.ContentType | Assert-Equals -Expected 'application/json'
135 $r.UserAgent | Assert-Equals -Expected 'ansible-httpget'
136
137 $body = New-Object -TypeName System.IO.MemoryStream -ArgumentList @(,
138 ([System.Text.Encoding]::UTF8.GetBytes('{"foo":"bar"}'))
139 )
140 $actual = Invoke-WithWebRequest -Module $module -Request $r -Body $body -Script {
141 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
142
143 $Response.StatusCode | Assert-Equals -Expected 200
144 Convert-StreamToString -Stream $Stream
145 } | ConvertFrom-Json
146
147 $actual.headers.'User-Agent' | Assert-Equals -Expected 'ansible-httpget'
148 $actual.headers.'Host' | Assert-Equals -Expected $httpbin_host
149 $actual.data | Assert-Equals -Expected '{"foo":"bar"}'
150 }
151
152 'Safe redirection of GET' = {
153 $r = Get-AnsibleWebRequest -Uri "http://$httpbin_host/redirect/2"
154
155 Invoke-WithWebRequest -Module $module -Request $r -Script {
156 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
157
158 $Response.ResponseUri | Assert-Equals -Expected "http://$httpbin_host/get"
159 $Response.StatusCode | Assert-Equals -Expected 200
160 }
161 }
162
163 'Safe redirection of HEAD' = {
164 $r = Get-AnsibleWebRequest -Uri "http://$httpbin_host/redirect/2" -Method HEAD
165
166 Invoke-WithWebRequest -Module $module -Request $r -Script {
167 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
168
169 $Response.ResponseUri | Assert-Equals -Expected "http://$httpbin_host/get"
170 $Response.StatusCode | Assert-Equals -Expected 200
171 }
172 }
173
174 'Safe redirection of PUT' = {
175 $params = @{
176 Method = 'PUT'
177 Uri = "http://$httpbin_host/redirect-to?url=https://$httpbin_host/put"
178 }
179 $r = Get-AnsibleWebRequest @params
180
181 Invoke-WithWebRequest -Module $module -Request $r -Script {
182 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
183
184 $Response.ResponseUri | Assert-Equals -Expected $r.RequestUri
185 $Response.StatusCode | Assert-Equals -Expected 302
186 }
187 }
188
189 'None redirection of GET' = {
190 $params = @{
191 FollowRedirects = 'None'
192 Uri = "http://$httpbin_host/redirect/2"
193 }
194 $r = Get-AnsibleWebRequest @params
195
196 Invoke-WithWebRequest -Module $module -Request $r -Script {
197 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
198
199 $Response.ResponseUri | Assert-Equals -Expected $r.RequestUri
200 $Response.StatusCode | Assert-Equals -Expected 302
201 }
202 }
203
204 'None redirection of HEAD' = {
205 $params = @{
206 follow_redirects = 'None'
207 method = 'HEAD'
208 Uri = "http://$httpbin_host/redirect/2"
209 }
210 $r = Get-AnsibleWebRequest @params
211
212 Invoke-WithWebRequest -Module $module -Request $r -Script {
213 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
214
215 $Response.ResponseUri | Assert-Equals -Expected $r.RequestUri
216 $Response.StatusCode | Assert-Equals -Expected 302
217 }
218 }
219
220 'None redirection of PUT' = {
221 $params = @{
222 FollowRedirects = 'None'
223 Method = 'PUT'
224 Uri = "http://$httpbin_host/redirect-to?url=https://$httpbin_host/put"
225 }
226 $r = Get-AnsibleWebRequest @params
227
228 Invoke-WithWebRequest -Module $module -Request $r -Script {
229 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
230
231 $Response.ResponseUri | Assert-Equals -Expected $r.RequestUri
232 $Response.StatusCode | Assert-Equals -Expected 302
233 }
234 }
235
236 'All redirection of GET' = {
237 $params = @{
238 FollowRedirects = 'All'
239 Uri = "http://$httpbin_host/redirect/2"
240 }
241 $r = Get-AnsibleWebRequest @params
242
243 Invoke-WithWebRequest -Module $module -Request $r -Script {
244 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
245
246 $Response.ResponseUri | Assert-Equals -Expected "http://$httpbin_host/get"
247 $Response.StatusCode | Assert-Equals -Expected 200
248 }
249 }
250
251 'All redirection of HEAD' = {
252 $params = @{
253 follow_redirects = 'All'
254 method = 'HEAD'
255 Uri = "http://$httpbin_host/redirect/2"
256 }
257 $r = Get-AnsibleWebRequest @params
258
259 Invoke-WithWebRequest -Module $module -Request $r -Script {
260 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
261
262 $Response.ResponseUri | Assert-Equals -Expected "http://$httpbin_host/get"
263 $Response.StatusCode | Assert-Equals -Expected 200
264 }
265 }
266
267 'All redirection of PUT' = {
268 $params = @{
269 FollowRedirects = 'All'
270 Method = 'PUT'
271 Uri = "http://$httpbin_host/redirect-to?url=https://$httpbin_host/put"
272 }
273 $r = Get-AnsibleWebRequest @params
274
275 Invoke-WithWebRequest -Module $module -Request $r -Script {
276 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
277
278 $Response.ResponseUri | Assert-Equals -Expected "https://$httpbin_host/put"
279 $Response.StatusCode | Assert-Equals -Expected 200
280 }
281 }
282
283 'Exceeds maximum redirection - ignored' = {
284 $params = @{
285 MaximumRedirection = 4
286 Uri = "https://$httpbin_host/redirect/5"
287 }
288 $r = Get-AnsibleWebRequest @params
289
290 Invoke-WithWebRequest -Module $module -Request $r -IgnoreBadResponse -Script {
291 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
292
293 $Response.ResponseUri | Assert-Equals -Expected "https://$httpbin_host/relative-redirect/1"
294 $Response.StatusCode | Assert-Equals -Expected 302
295 }
296 }
297
298 'Exceeds maximum redirection - exception' = {
299 $params = @{
300 MaximumRedirection = 1
301 Uri = "https://$httpbin_host/redirect/2"
302 }
303 $r = Get-AnsibleWebRequest @params
304
305 $failed = $false
306 try {
307 $null = Invoke-WithWebRequest -Module $module -Request $r -Script {}
308 } catch {
309 $_.Exception.GetType().Name | Assert-Equals -Expected 'WebException'
310 $_.Exception.Message | Assert-Equals -Expected 'Too many automatic redirections were attempted.'
311 $failed = $true
312 }
313 $failed | Assert-Equals -Expected $true
314 }
315
316 'Basic auth as Credential' = {
317 $params = @{
318 Url = "http://$httpbin_host/basic-auth/username/password"
319 UrlUsername = 'username'
320 UrlPassword = 'password'
321 }
322 $r = Get-AnsibleWebRequest @params
323
324 Invoke-WithWebRequest -Module $module -Request $r -IgnoreBadResponse -Script {
325 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
326
327 $Response.StatusCode | Assert-Equals -Expected 200
328 }
329 }
330
331 'Basic auth as Header' = {
332 $params = @{
333 Url = "http://$httpbin_host/basic-auth/username/password"
334 url_username = 'username'
335 url_password = 'password'
336 ForceBasicAuth = $true
337 }
338 $r = Get-AnsibleWebRequest @params
339
340 Invoke-WithWebRequest -Module $module -Request $r -IgnoreBadResponse -Script {
341 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
342
343 $Response.StatusCode | Assert-Equals -Expected 200
344 }
345 }
346
347 'Send request with headers' = {
348 $params = @{
349 Headers = @{
350 'Content-Length' = 0
351 testingheader = 'testing_header'
352 TestHeader = 'test-header'
353 'User-Agent' = 'test-agent'
354 }
355 Url = "https://$httpbin_host/get"
356 }
357 $r = Get-AnsibleWebRequest @params
358
359 $actual = Invoke-WithWebRequest -Module $module -Request $r -Script {
360 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
361
362 $Response.StatusCode | Assert-Equals -Expected 200
363 Convert-StreamToString -Stream $Stream
364 } | ConvertFrom-Json
365
366 $actual.headers.'Testheader' | Assert-Equals -Expected 'test-header'
367 $actual.headers.'testingheader' | Assert-Equals -Expected 'testing_header'
368 $actual.Headers.'User-Agent' | Assert-Equals -Expected 'test-agent'
369 }
370
371 'Request with timeout' = {
372 $params = @{
373 Uri = "https://$httpbin_host/delay/5"
374 Timeout = 1
375 }
376 $r = Get-AnsibleWebRequest @params
377
378 $failed = $false
379 try {
380 $null = Invoke-WithWebRequest -Module $module -Request $r -Script {}
381 } catch {
382 $failed = $true
383 $_.Exception.GetType().Name | Assert-Equals -Expected WebException
384 $_.Exception.Message | Assert-Equals -Expected 'The operation has timed out'
385 }
386 $failed | Assert-Equals -Expected $true
387 }
388
389 'Request with file URI' = {
390 $filePath = Join-Path $module.Tmpdir -ChildPath 'test.txt'
391 Set-Content -LiteralPath $filePath -Value 'test'
392
393 $r = Get-AnsibleWebRequest -Uri $filePath
394
395 $actual = Invoke-WithWebRequest -Module $module -Request $r -Script {
396 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
397
398 $Response.ContentLength | Assert-Equals -Expected 6
399 Convert-StreamToString -Stream $Stream
400 }
401 $actual | Assert-Equals -Expected "test`r`n"
402 $module.Result.msg | Assert-Equals -Expected "OK"
403 $module.Result.status_code | Assert-Equals -Expected 200
404 }
405
406 'Web request based on module options' = {
407 Set-Variable complex_args -Scope Global -Value @{
408 url = "https://$httpbin_host/redirect/2"
409 method = 'GET'
410 follow_redirects = 'safe'
411 headers = @{
412 'User-Agent' = 'other-agent'
413 }
414 http_agent = 'actual-agent'
415 maximum_redirection = 2
416 timeout = 10
417 validate_certs = $false
418 }
419 $spec = @{
420 options = @{
421 url = @{ type = 'str'; required = $true }
422 test = @{ type = 'str'; choices = 'abc', 'def'}
423 }
424 mutually_exclusive = @(,@('url', 'test'))
425 }
426
427 $testModule = [Ansible.Basic.AnsibleModule]::Create(@(), $spec, @(Get-AnsibleWebRequestSpec))
428 $r = Get-AnsibleWebRequest -Url $testModule.Params.url -Module $testModule
429
430 $actual = Invoke-WithWebRequest -Module $testModule -Request $r -Script {
431 Param ([System.Net.WebResponse]$Response, [System.IO.Stream]$Stream)
432
433 $Response.ResponseUri | Assert-Equals -Expected "https://$httpbin_host/get"
434 Convert-StreamToString -Stream $Stream
435 } | ConvertFrom-Json
436 $actual.headers.'User-Agent' | Assert-Equals -Expected 'actual-agent'
437 }
438
439 'Web request with default proxy' = {
440 $params = @{
441 Uri = "https://$httpbin_host/get"
442 }
443 $r = Get-AnsibleWebRequest @params
444
445 $null -ne $r.Proxy | Assert-Equals -Expected $true
446 }
447
448 'Web request with no proxy' = {
449 $params = @{
450 Uri = "https://$httpbin_host/get"
451 UseProxy = $false
452 }
453 $r = Get-AnsibleWebRequest @params
454
455 $null -eq $r.Proxy | Assert-Equals -Expected $true
456 }
457 }
458
459 # setup and teardown should favour native tools to create and delete the service and not the util we are testing.
460 foreach ($testImpl in $tests.GetEnumerator()) {
461 Set-Variable -Name complex_args -Scope Global -Value @{}
462 $test = $testImpl.Key
463 &$testImpl.Value
464 }
465
466 $module.Result.data = "success"
467 $module.ExitJson()
468