A 404 result coming from an Invoke-WebRequest is usually a bad thing. This time, however, the 404 is a result I actually hoped to see. I am creating a custom Azure Devops extension that talks with the API of VMWare VRealize 8. The extension allows users to create a new resources such as a VM within VRA through an Azure Devops Pipeline. The API that I am querying generates a 200 statuscode if the resource with a curtain name exists. If this resource does not exists, a 404 is thrown. I wrote a function that checks 3 things.
- Is the statuscode 200? Throw an error.
- Is the statuscode 404? The test passed and we do not really have to do anything.
- The statuscode is neither 200 or 404? It seems like something else is up, so throw an error with some bonus information.
Function Get-vraDeploymentName {
Param ($Uri, $Name, $Headers)
$RequestURL = "$Uri/deployment/api/deployments/names/$Name"
#Get the statuscode.
$Result = try {
(Invoke-WebRequest -Uri $RequestURL -Method GET -Headers $Headers)
}
catch [System.Net.WebException] {
$_.Exception.Response
}
$statusCodeInt = [int]$Result.StatusCode
#200 is bad. 404 is good. Everything else is very bad
If ($statusCodeInt -eq 200) {
Throw "A resource with the name `'$Name`' already exists."
}
ElseIf ($statusCodeInt -eq 404) {
Write-Host "The name `'$Name`' is available for creating the new resource."
}
Else {
throw "Module = Get-vraDeploymentName: $($_.Exception.Message)"
}
}
How do we test such functionality with Pester? You can mock the Invoke-WebRequest with some JSON output, but this will prevent Pester from testing the try/catch loop. I decided to mock the object ‘System.Net.HttpWebResponse’.
Mock Invoke-WebRequest {
$status = [System.Net.WebExceptionStatus]::ConnectionClosed
$response = New-MockObject -type 'System.Net.HttpWebResponse'
$response | Add-Member -MemberType noteProperty -Name 'StatusCode' -Value 404 -force
$exception = New-Object System.Net.WebException "Fout" , $null, $status, $response
Throw $exception
}
So what is actually happening here?
When running Invoke-WebRequest, PowerShell uses the System.Net assemblies to establish the connection with the API. The result of this action is faked with Mock-Object. Powershell believes that the connection actually failed and it returns the results we need for the test.
Here is the full set of Pester tests I wrote for this particular function.
Describe "Get-vraDeploymentName" {
It "Resource exist" {
Mock Invoke-WebRequest { @{ StatusCode = 200 } }
{ Get-vraDeploymentName -Name 'test' -Uri 'http://fakeurl' } | Should -Throw "A resource with the name `'test`' already exists."
}
It "Resource not exist" {
Mock Invoke-WebRequest {
$status = [System.Net.WebExceptionStatus]::ConnectionClosed
$response = New-MockObject -type 'System.Net.HttpWebResponse'
$response | Add-Member -MemberType noteProperty -Name 'StatusCode' -Value 404 -force
$exception = New-Object System.Net.WebException "Fout" , $null, $status, $response
Throw $exception
}
Mock Write-Host {}
Get-vraDeploymentName -Name 'test' -Uri 'http://fakeurl'
Assert-MockCalled Write-Host -Exactly 1 -ParameterFilter { $Object -eq "The name `'test`' is available for creating the new resource." }
}
It "Failed" {
Mock Invoke-WebRequest { }
{ Get-vraDeploymentName -Name 'test' -Uri 'http://fakeurl' } | Should -Throw "Module = Get-vraDeploymentName: "
}
}