From a1df180af8a86c6baf0b7eab1c5eeaab8f4fc3ea Mon Sep 17 00:00:00 2001 From: Troy Lindsay Date: Sun, 1 Jul 2018 11:29:56 -0500 Subject: [PATCH] Add New-ArmorCompleteVM public cmdlet [new] * #109 * #122 * #126 * Also includes a bug fix for ArmorVM ScheduledEvents property tests --- .spelling | 10 + Armor/Armor.psd1 | 3 +- Armor/Etc/ApiData.json | 25 + Armor/Lib/ArmorTypes.ps1 | 65 ++ Armor/Private/Format-ArmorApiRequestBody.ps1 | 3 +- Armor/Public/New-ArmorCompleteVM.ps1 | 223 ++++++ build/etc/VMs_1.json | 2 +- build/etc/VmOrders_1.json | 33 + build/psakefile.ps1 | 1 + tests/lib/ArmorCompleteVmOrder.Tests.ps1 | 133 ++++ tests/lib/ArmorCompleteVmOrderVm.Tests.ps1 | 385 ++++++++++ tests/lib/ArmorVM.Tests.ps1 | 4 +- tests/public/New-ArmorCompleteVM.Tests.ps1 | 727 +++++++++++++++++++ 13 files changed, 1609 insertions(+), 5 deletions(-) create mode 100644 Armor/Public/New-ArmorCompleteVM.ps1 create mode 100644 build/etc/VmOrders_1.json create mode 100644 tests/lib/ArmorCompleteVmOrder.Tests.ps1 create mode 100644 tests/lib/ArmorCompleteVmOrderVm.Tests.ps1 create mode 100644 tests/public/New-ArmorCompleteVM.Tests.ps1 diff --git a/.spelling b/.spelling index 7a97204f..aded85e4 100644 --- a/.spelling +++ b/.spelling @@ -26,6 +26,7 @@ Armor.psm1 ArmorAccount ArmorAccountAddress ArmorCompleteDatacenter +ArmorCompleteVmOrder ArmorCompleteWorkload ArmorCompleteWorkloadTier ArmorPowerShell @@ -54,6 +55,7 @@ eg e.g. ErrorAction ErrorVariable +ExistingWorkloadAndTier Expand-ArmorApiResult FirstName ForceOff @@ -93,11 +95,14 @@ Me_GetMeAsync MkDocs mkdocs.org NewName +NewWorkloadAndTier New-ArmorApiToken New-ArmorApiUri New-ArmorApiUriQuery +New-ArmorCompleteVM OneDrive open-vm-tools +Orders_PostVmOrderAsync OutBuffer OutVariable pasteable @@ -128,6 +133,7 @@ styleguides Styleguides Submit-ArmorApiRequest SuccessCode +System.Guid System.Management.Automation.PSObject System.String System.UInt16 @@ -138,6 +144,8 @@ TenantOAuth_AuthorizeAsync TenantOAuth_ReissueAsync TenantOAuth_TokenAsync TEST-VM +TierID +TierName Tier_AddTier Tier_DeleteTier Tier_Get @@ -153,6 +161,7 @@ Uri Users_GetUser Users_GetUsers Verb-ArmorNoun +VirtualDisks VMs VMware Vm_DeleteVm @@ -169,6 +178,7 @@ whitespace white_check_mark Wildcard WorkloadID +WorkloadName www.apache.org xml #endregion diff --git a/Armor/Armor.psd1 b/Armor/Armor.psd1 index 30159635..d8d681b0 100644 --- a/Armor/Armor.psd1 +++ b/Armor/Armor.psd1 @@ -79,7 +79,7 @@ FunctionsToExport = 'Connect-Armor', 'Disconnect-Armor', 'Get-ArmorAccount', 'Get-ArmorAccountAddress', 'Get-ArmorAccountContext', 'Get-ArmorCompleteDatacenter', 'Get-ArmorCompleteWorkload', 'Get-ArmorCompleteWorkloadTier', 'Get-ArmorIdentity', 'Get-ArmorUser', - 'Get-ArmorVM', 'Invoke-ArmorWebRequest', + 'Get-ArmorVM', 'Invoke-ArmorWebRequest', 'New-ArmorCompleteVM', 'New-ArmorCompleteWorkloadTier', 'Remove-ArmorCompleteVM', 'Remove-ArmorCompleteWorkload', 'Remove-ArmorCompleteWorkloadTier', 'Rename-ArmorCompleteVM', 'Rename-ArmorCompleteWorkload', @@ -120,6 +120,7 @@ FileList = 'Armor.psd1', 'Armor.psm1', 'en-US\Armor-help.xml', 'Etc\Aliases.json 'Public\Get-ArmorCompleteWorkloadTier.ps1', 'Public\Get-ArmorIdentity.ps1', 'Public\Get-ArmorUser.ps1', 'Public\Get-ArmorVM.ps1', 'Public\Invoke-ArmorWebRequest.ps1', + 'Public\New-ArmorCompleteVM.ps1', 'Public\New-ArmorCompleteWorkloadTier.ps1', 'Public\Remove-ArmorCompleteVM.ps1', 'Public\Remove-ArmorCompleteWorkload.ps1', diff --git a/Armor/Etc/ApiData.json b/Armor/Etc/ApiData.json index 9d1901f7..f629e71a 100644 --- a/Armor/Etc/ApiData.json +++ b/Armor/Etc/ApiData.json @@ -185,6 +185,31 @@ "SuccessCode": "200" } }, + "New-ArmorCompleteVM": { + "v1.0": { + "Description": "Order {0} new VM{1}", + "Endpoints": [ + "/orders/vms" + ], + "Method": "Post", + "Body": { + "name": "Name", + "location": "Armor Complete datacenter location code", + "appId": "Workload ID", + "appName": "New Workload Name", + "tierId": "Workload Tier ID", + "tierName": "New Workload Tier Name", + "storage": "Virtual disks", + "secret": "Password", + "sku": "Fixed instance VM geometry", + "quantity": "Quantity to order" + }, + "Query": {}, + "Location": "VMs", + "Filter": {}, + "SuccessCode": "200" + } + }, "New-ArmorCompleteWorkloadTier": { "v1.0": { "Description": "Create workload tier", diff --git a/Armor/Lib/ArmorTypes.ps1 b/Armor/Lib/ArmorTypes.ps1 index af768ab0..4213fabb 100644 --- a/Armor/Lib/ArmorTypes.ps1 +++ b/Armor/Lib/ArmorTypes.ps1 @@ -167,6 +167,50 @@ class ArmorCompleteDatacenter { } +class ArmorCompleteVmOrderVm { + [UInt16] $AccountID + + [UInt16] $AppID + + [AllowEmptyString()] + [String] $AppName + + [AllowEmptyString()] + [String] $Name + + [AllowEmptyString()] + [String] $Location + + [UInt16] $Quantity + + Hidden [String] $Secret + + [AllowEmptyString()] + [String] $SKU + + [AllowEmptyCollection()] + [PSCustomObject[]] $Software + + [AllowEmptyCollection()] + [PSCustomObject[]] $Storage + + [UInt16] $TemplateID + + [UInt16] $TierID + + [AllowEmptyString()] + [String] $TierName + + [Guid] $TrackingID + + [AllowEmptyString()] + [String] $Zone + + #Constructors + ArmorCompleteVmOrderVm () {} +} + + class ArmorDepartment { [ValidateRange( 1, 65535 )] [UInt16] $ID @@ -871,6 +915,27 @@ class ArmorVM { } +class ArmorCompleteVmOrder { + [ValidateRange( 1, 65535 )] + [UInt16] $ID + + [ValidateRange( 1, 65535 )] + [UInt16] $AccountID + + [ValidateNotNullOrEmpty()] + [String] $Status + + [ValidateNotNull()] + [DateTime] $DateCreated + + [ValidateCount( 1, 65535 )] + [ArmorCompleteVmOrderVm[]] $VMs + + #Constructors + ArmorCompleteVmOrder () {} +} + + class ArmorCompleteWorkloadTier { [ValidateRange( 1, 65535 )] [UInt16] $ID diff --git a/Armor/Private/Format-ArmorApiRequestBody.ps1 b/Armor/Private/Format-ArmorApiRequestBody.ps1 index 28d08d3d..29639b64 100644 --- a/Armor/Private/Format-ArmorApiRequestBody.ps1 +++ b/Armor/Private/Format-ArmorApiRequestBody.ps1 @@ -140,7 +140,8 @@ function Format-ArmorApiRequestBody { # Store the results in a JSON string $return = ConvertTo-Json -InputObject $body -ErrorAction 'Stop' - Write-Verbose -Message "Body = ${return}" + $filteredReturn = $return -replace '"secret": ".+"', '"secret": "[redacted]"' + Write-Verbose -Message "Body = $filteredReturn" $return } diff --git a/Armor/Public/New-ArmorCompleteVM.ps1 b/Armor/Public/New-ArmorCompleteVM.ps1 new file mode 100644 index 00000000..f0a389a2 --- /dev/null +++ b/Armor/Public/New-ArmorCompleteVM.ps1 @@ -0,0 +1,223 @@ +function New-ArmorCompleteVM { + <# + .SYNOPSIS + Creates new Armor Complete VMs. + + .DESCRIPTION + Orders and provisions new Armor Complete virtual machines of the specified SKU. + + .INPUTS + System.String + + .INPUTS + System.Management.Automation.PSObject + + .NOTES + - Troy Lindsay + - Twitter: @troylindsay42 + - GitHub: tlindsay42 + + .EXAMPLE + New-ArmorCompleteVM -Name 'web' -Location 'DFW01' -WorkloadName 'portal' -TierName 'presentation' -Secret $mySecurePassword -SKU 'A1-121' -Quantity 3 + + .EXAMPLE + New-ArmorCompleteVM -Name 'app' -Location 'DFW01' -WorkloadID 1 -TierID 1 -Secret $mySecurePassword -SKU 'A1-131' -Quantity 2 + + .LINK + https://tlindsay42.github.io/ArmorPowerShell/public/New-ArmorCompleteVM/ + + .LINK + https://github.com/tlindsay42/ArmorPowerShell/blob/master/Armor/Public/New-ArmorCompleteVM.ps1 + + .LINK + https://docs.armor.com/display/KBSS/Create+New+Virtual+Machine + + .LINK + https://developer.armor.com/#!/Infrastructure/Orders_PostVmOrderAsync + + .COMPONENT + Armor Complete + + .FUNCTIONALITY + Armor Complete infrastructure management + #> + + [CmdletBinding( + SupportsShouldProcess = $true, + ConfirmImpact = 'High', + DefaultParameterSetName = 'ExistingWorkloadAndTier' + )] + [OutputType( [ArmorCompleteVmOrder[]] )] + [OutputType( [ArmorCompleteVmOrder] )] + param ( + # Specifies the name for the new virtual machine. + [Parameter( + Mandatory = $true, + Position = 0, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true + )] + [ValidateNotNullOrEmpty()] + [String] + $Name, + + # Specifies the location code for the Armor Complete datacenter. + [Parameter( + Mandatory = $true, + Position = 1, + ValueFromPipelineByPropertyName = $true + )] + [ValidateSet( 'AMS01', 'DFW01', 'LHR01', 'PHX01', 'SIN01' )] + [String] + $Location, + + # Specifies the ID of the existing Armor Complete workload. + [Parameter( + ParameterSetName = 'ExistingWorkloadAndTier', + Mandatory = $true, + Position = 2, + ValueFromPipelineByPropertyName = $true + )] + [ValidateRange( 1, 65535 )] + [ValidateScript( { Get-ArmorCompleteWorkload -ID $_ -ErrorAction 'Stop' } )] + [Alias( 'AppID' )] + [UInt16] + $WorkloadID, + + # Specifies the name for a new Armor Complete workload. + [Parameter( + ParameterSetName = 'NewWorkloadAndTier', + Mandatory = $true, + Position = 2, + ValueFromPipelineByPropertyName = $true + )] + [ValidateNotNullOrEmpty()] + [Alias( 'AppName' )] + [String] + $WorkloadName, + + # Specifies the ID of the existing workload tier. + [Parameter( + ParameterSetName = 'ExistingWorkloadAndTier', + Mandatory = $true, + Position = 3, + ValueFromPipelineByPropertyName = $true + )] + [ValidateRange( 1, 65535 )] + [UInt16] + $TierID, + + # Specifies the names of the workload tiers. + [Parameter( + ParameterSetName = 'NewWorkloadAndTier', + Mandatory = $true, + Position = 3, + ValueFromPipelineByPropertyName = $true + )] + [ValidateNotNullOrEmpty()] + [String] + $TierName, + + # Specifies the virtual disks that should be added to the new VM. + [Parameter( + Position = 4, + ValueFromPipelineByPropertyName = $true + )] + [AllowEmptyCollection()] + [ValidateCount( 0, 60 )] + [Alias( 'Storage' )] + [ArmorDisk[]] + $VirtualDisks = @(), + + # Specifies the password for the new VM. + [Parameter( + Mandatory = $true, + Position = 5, + ValueFromPipelineByPropertyName = $true + )] + [ValidateLength( 16, 128 )] + [String] + $Secret, + + <# + Specifies the stock keeping unit (SKU) product identification code that + includes the CPU & memory specifications. + #> + [Parameter( + Mandatory = $true, + Position = 6, + ValueFromPipelineByPropertyName = $true + )] + [ValidateNotNullOrEmpty()] + [String] + $SKU, + + # Specifies the quantity of VMs to order of this specification. + [Parameter( + Position = 7, + ValueFromPipelineByPropertyName = $true + )] + [ValidateRange( 1, 20 )] + [UInt16] + $Quantity = 1, + + # Specifies the API version for this request. + [Parameter( Position = 8 )] + [ValidateSet( 'v1.0', 'internal' )] + [String] + $ApiVersion = $Global:ArmorSession.ApiVersion + ) + + begin { + $function = $MyInvocation.MyCommand.Name + + Write-Verbose -Message "Beginning: '${function}' with ParameterSetName '$( $PSCmdlet.ParameterSetName )' and Parameters: $( $PSBoundParameters | Out-String )" + + Test-ArmorSession + } + + process { + [ArmorCompleteVmOrder[]] $return = $null + + if ( $PSCmdlet.ParameterSetName -eq 'ExistingWorkloadAndTier' ) { + # The GET /apps/{id}/tiers/{id} endpoint does not return objects that contain no VMs. ( #122 ) + if ( ( Get-ArmorCompleteWorkload -ID $WorkloadID ).Tiers.Where( { $_.ID -eq $TierID } ).Count -ne 1 ) { + Write-Error -Message "Cannot validate argument on parameter 'TierID': '${TierID}'" -ErrorAction 'Stop' + } + } + + $resources = Get-ArmorApiData -FunctionName $function -ApiVersion $ApiVersion + + $uri = New-ArmorApiUri -Endpoints $resources.Endpoints + + $plural = if ( $Quantity -gt 1 ) { 's' } + $description = $resources.description -f $Quantity, $plural + + if ( $PSCmdlet.ShouldProcess( $SKU, $description ) ) { + $keys = ( $resources.Body | Get-Member -MemberType 'NoteProperty' ).Name + $parameters = ( Get-Command -Name $function ).Parameters.Values + $body = Format-ArmorApiRequestBody -Keys $keys -Parameters $parameters + + $splat = @{ + Uri = $uri + Method = $resources.Method + Body = $body + SuccessCode = $resources.SuccessCode + } + $results = Submit-ArmorApiRequest @splat + + $filters = $resources.Filter | + Get-Member -MemberType 'NoteProperty' + $results = Select-ArmorApiResult -Results $results -Filter $filters + + $return = $results + } + + # Pass the return value to the pipeline + $return + } + + end { + Write-Verbose -Message "Ending: '${function}'." + } +} diff --git a/build/etc/VMs_1.json b/build/etc/VMs_1.json index 4b9c1d83..7aaa6444 100644 --- a/build/etc/VMs_1.json +++ b/build/etc/VMs_1.json @@ -53,4 +53,4 @@ "vmBackupInProgress": false, "profileName": null, "multiVmVapp": false -} \ No newline at end of file +} diff --git a/build/etc/VmOrders_1.json b/build/etc/VmOrders_1.json new file mode 100644 index 00000000..19fad898 --- /dev/null +++ b/build/etc/VmOrders_1.json @@ -0,0 +1,33 @@ +{ + "id": 1, + "accountId": 1, + "status": "submitted", + "dateCreated": "2015-01-07T02:21:00.00000Z", + "vms": [{ + "trackingId": "00000000-0000-0000-0000-000000000000", + "name": "VM1", + "location": "DFW01", + "zone": "DFW01T01-VC01", + "appId": 1, + "appName": "WL1", + "tierId": 1, + "tierName": "TR1", + "storage": [{ + "size": 30, + "sku": "SAN-001", + "quantity": 1, + "accountId": 1 + }], + "software": [{ + "sku": "CentOS 6", + "parameters": [], + "type": "os", + "quantity": 1, + "accountId": 1 + }], + "secret": null, + "sku": "A1-101", + "quantity": 1, + "accountId": 1 + }] +} diff --git a/build/psakefile.ps1 b/build/psakefile.ps1 index 00f2f16d..f5c6ceb6 100644 --- a/build/psakefile.ps1 +++ b/build/psakefile.ps1 @@ -189,6 +189,7 @@ Properties { Tiers1VMs1 = Get-TestResponseBody -FileName 'Tiers_1-VMs_1.json' Token1 = Get-TestResponseBody -FileName 'Token_1.json' Users1 = Get-TestResponseBody -FileName 'Users_1.json' + VmOrders1 = Get-TestResponseBody -FileName 'VmOrders_1.json' VMs1 = Get-TestResponseBody -FileName 'VMs_1.json' VMs2 = Get-TestResponseBody -FileName 'VMs_2.json' Workloads1Tiers1VMs1 = Get-TestResponseBody -FileName 'Workloads_1-Tiers_1-VMs_1.json' diff --git a/tests/lib/ArmorCompleteVmOrder.Tests.ps1 b/tests/lib/ArmorCompleteVmOrder.Tests.ps1 new file mode 100644 index 00000000..eb19aeaa --- /dev/null +++ b/tests/lib/ArmorCompleteVmOrder.Tests.ps1 @@ -0,0 +1,133 @@ +$systemUnderTest = ( Split-Path -Leaf $MyInvocation.MyCommand.Path ) -replace '\.Tests\.', '.' +$filePath = Join-Path -Path $CI_MODULE_LIB_PATH -ChildPath 'ArmorTypes.ps1' + +. $filePath + +$class = $systemUnderTest.Split( '.' )[0] +$describe = $Global:FORM_CLASS -f $class +Describe -Name $describe -Tag 'Class', $class -Fixture { + #region init + #endregion + + Context -Name $Global:CONSTRUCTORS -Fixture { + It -Name $Global:FORM_DEFAULT_CONTRUCTORS -Test { + { [ArmorCompleteVmOrder]::New() } | + Should -Not -Throw + } + } + + [ArmorCompleteVmOrder] $temp = [ArmorCompleteVmOrder]::New() + + $property = 'ID' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = 0 } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [UInt16] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = 1 }, + @{ Value = 65535 } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [UInt16] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.UInt16] ) + } + } + + $property = 'AccountID' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = 0 } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [UInt16] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = 1 }, + @{ Value = 65535 } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [UInt16] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.UInt16] ) + } + } + + $property = 'DateCreated' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = '' } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = '2018-06-30 15:43:39' } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [DateTime] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.DateTime] ) + } + } + + $property = 'VMs' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ + Value = @() + } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [PSCustomObject[]] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = [ArmorCompleteVmOrderVm]::New() }, + @{ Value = [ArmorCompleteVmOrderVm]::New(), [ArmorCompleteVmOrderVm]::New() } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [PSCustomObject[]] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [ArmorCompleteVmOrderVm] ) + } + } +} diff --git a/tests/lib/ArmorCompleteVmOrderVm.Tests.ps1 b/tests/lib/ArmorCompleteVmOrderVm.Tests.ps1 new file mode 100644 index 00000000..8c0dbc72 --- /dev/null +++ b/tests/lib/ArmorCompleteVmOrderVm.Tests.ps1 @@ -0,0 +1,385 @@ +$systemUnderTest = ( Split-Path -Leaf $MyInvocation.MyCommand.Path ) -replace '\.Tests\.', '.' +$filePath = Join-Path -Path $CI_MODULE_LIB_PATH -ChildPath 'ArmorTypes.ps1' + +. $filePath + +$class = $systemUnderTest.Split( '.' )[0] +$describe = $Global:FORM_CLASS -f $class +Describe -Name $describe -Tag 'Class', $class -Fixture { + #region init + #endregion + + Context -Name $Global:CONSTRUCTORS -Fixture { + It -Name $Global:FORM_DEFAULT_CONTRUCTORS -Test { + { [ArmorCompleteVmOrderVm]::New() } | + Should -Not -Throw + } + } + + [ArmorCompleteVmOrderVm] $temp = [ArmorCompleteVmOrderVm]::New() + + $property = 'AccountID' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = -1 } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [Int16] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = 0 }, + @{ Value = 65535 } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [UInt16] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.UInt16] ) + } + } + + $property = 'AppID' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = -1 } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [Int16] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = 0 }, + @{ Value = 65535 } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [UInt16] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.UInt16] ) + } + } + + $property = 'AppName' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = '' }, + @{ Value = 'LAMP stack' } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.String] ) + } + } + + $property = 'Name' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = '' }, + @{ Value = 'app1' } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.String] ) + } + } + + $property = 'Location' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = '' }, + @{ Value = 'AMS01' }, + @{ Value = 'DFW01' }, + @{ Value = 'LHR01' }, + @{ Value = 'PHX01' }, + @{ Value = 'SIN01' } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.String] ) + } + } + + $property = 'Quantity' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = -1 } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [Int16] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = 0 }, + @{ Value = 65535 } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [UInt16] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.UInt16] ) + } + } + + $property = 'Secret' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = '' }, + @{ Value = '$MySecretPassword' } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.String] ) + } + } + + $property = 'SKU' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = '' }, + @{ Value = 'A1-101' } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.String] ) + } + } + + $property = 'Software' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = @() }, + @{ + Value = [PSCustomObject] @{ + SKU = 'CentOS 6' + Parameters = @() + Type = 'OS' + Quantity = 0 + AccountID = 0 + } + } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [PSCustomObject] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [PSCustomObject] ) + } + } + + $property = 'Storage' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = @() }, + @{ + Value = [PSCustomObject] @{ + Size = 30 + SKU = 'SAN-001' + Quantity = 0 + AccountID = 0 + } + } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [PSCustomObject] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [PSCustomObject] ) + } + } + + $property = 'TemplateID' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = -1 } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [Int16] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = 0 }, + @{ Value = 65535 } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [UInt16] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.UInt16] ) + } + } + + $property = 'TierID' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = -1 } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [Int16] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = 0 }, + @{ Value = 65535 } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [UInt16] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.UInt16] ) + } + } + + $property = 'TierName' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = '' }, + @{ Value = 'presentation' }, + @{ Value = 'business logic' }, + @{ Value = 'persistence' } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.String] ) + } + } + + $property = 'TrackingID' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = 'bad_uuid' } + ) + It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Throw + } + + $testCases = @( + @{ Value = '00000000-0000-0000-0000-000000000000' }, + @{ Value = '8df29bc9-f299-4dad-b4b2-8f7451e14310' }, + @{ Value = 'bae27b78-c701-42f5-98bc-2f18128222cd' } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.Guid] ) + } + } + + $property = 'Zone' + $context = $Global:FORM_PROPERTY -f $property + Context -Name $context -Fixture { + $testCases = @( + @{ Value = '' }, + @{ Value = 'AMS01-CD01' }, + @{ Value = 'DFW01-CD01' }, + @{ Value = 'LHR01-CD01' }, + @{ Value = 'PHX01-CD01' }, + @{ Value = 'SIN01-CD01' } + ) + It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { + param ( [String] $Value ) + { $temp.$property = $Value } | + Should -Not -Throw + } + + It -Name $Global:FORM_PROPERTY_TYPE -Test { + $temp.$property | + Should -BeOfType ( [System.String] ) + } + } +} diff --git a/tests/lib/ArmorVM.Tests.ps1 b/tests/lib/ArmorVM.Tests.ps1 index cea42651..7a6d24f2 100644 --- a/tests/lib/ArmorVM.Tests.ps1 +++ b/tests/lib/ArmorVM.Tests.ps1 @@ -1168,7 +1168,7 @@ Describe -Name $describe -Tag 'Class', $class -Fixture { $context = $Global:FORM_PROPERTY -f $property Context -Name $context -Fixture { $testCases = @( - Value = [PSCustomObject] @{ ScheduledEvent = 1 } + @{ Value = [PSCustomObject] @{ ScheduledEvent = 1 } } ) It -Name $Global:FORM_PROPERTY_FAIL -TestCases $testCases -Test { param ( [PSCustomObject] $Value ) @@ -1182,7 +1182,7 @@ Describe -Name $describe -Tag 'Class', $class -Fixture { @{ Value = [ArmorScheduledEvent]::New() } ) It -Name $Global:FORM_PROPERTY_PASS -TestCases $testCases -Test { - param ( [ArmorScheduledEvent] $Value ) + param ( [PSCustomObject[]] $Value ) { $temp.$property = $Value } | Should -Not -Throw } diff --git a/tests/public/New-ArmorCompleteVM.Tests.ps1 b/tests/public/New-ArmorCompleteVM.Tests.ps1 new file mode 100644 index 00000000..b8c04727 --- /dev/null +++ b/tests/public/New-ArmorCompleteVM.Tests.ps1 @@ -0,0 +1,727 @@ +Import-Module -Name $CI_MODULE_MANIFEST_PATH -Force + +$systemUnderTest = ( Split-Path -Leaf $MyInvocation.MyCommand.Path ) -replace '\.Tests\.', '.' + +$function = $systemUnderTest.Split( '.' )[0] +$describe = $Global:FORM_FUNCTION_PUBLIC -f $function +Describe -Name $describe -Tag 'Function', 'Public', $function -Fixture { + #region init + $help = Get-Help -Name $function -Full + + $Global:ArmorSession = [ArmorSession]::New( 'api.armor.com', 443, 'v1.0' ) + #endregion + + $splat = @{ + ExpectedFunctionName = $function + FoundFunctionName = $help.Name + } + Test-AdvancedFunctionName @splat + + Test-AdvancedFunctionHelpMain -Help $help + + Test-AdvancedFunctionHelpInput -Help $help + + $splat = @{ + ExpectedOutputTypeNames = 'ArmorCompleteVmOrder', 'ArmorCompleteVmOrder[]' + Help = $help + } + Test-AdvancedFunctionHelpOutput @splat + + $splat = @{ + ExpectedParameterNames = 'Name', 'Location', 'WorkloadID', 'WorkloadName', 'TierID', 'TierName', + 'VirtualDisks', 'Secret', 'SKU', 'Quantity', 'ApiVersion', 'WhatIf', 'Confirm' + Help = $help + } + Test-AdvancedFunctionHelpParameter @splat + + $splat = @{ + ExpectedNotes = $Global:FORM_FUNCTION_HELP_NOTES + Help = $help + } + Test-AdvancedFunctionHelpNote @splat + + Context -Name $Global:EXECUTION -Fixture { + InModuleScope -ModuleName $Global:CI_MODULE_NAME -ScriptBlock { + #region init + $invalidName = '' + $validName = 'app1' + $invalidLocation = '' + $validLocation = 'DFW01' + $invalidWorkloadID = 0 + $validWorkloadID = 1 + $invalidWorkloadName = '' + $validWorkloadName = 'WISP stack' + $invalidTierID = 0 + $validTierID = 1 + $invalidTierName = '' + $validTierName = 'business logic' + $invalidSecret = 'weak password' + $validSecret = 'only password length is tested client-side' + $invalidSKU = '' + $validSKU = 'A1-101' + $invalidQuantity = 0 + $validQuantity = 1 + $invalidApiVersion = 'v0.0' + $validApiVersion = 'v1.0' + #endregion + + $testCases = @( + @{ + Name = $invalidName + Location = $validLocation + WorkloadID = $validWorkloadID + TierID = $validTierID + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = $invalidLocation + WorkloadID = $validWorkloadID + TierID = $validTierID + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = 'AMS01' + WorkloadID = $invalidWorkloadID + TierID = $validTierID + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = 'LHR01' + WorkloadID = $validWorkloadID + TierID = $invalidTierID + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = 'PHX01' + WorkloadID = $validWorkloadID + TierID = $validTierID + Secret = $invalidSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = 'SIN01' + WorkloadID = $validWorkloadID + TierID = $validTierID + Secret = $validSecret + SKU = $invalidSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = $validLocation + WorkloadID = $validWorkloadID + TierID = $validTierID + Secret = $validSecret + SKU = $validSKU + Quantity = $invalidQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = $validLocation + WorkloadID = $validWorkloadID + TierID = $validTierID + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $invalidApiVersion + } + ) + $testName = ( + 'should fail when set to: Name: , Location: , WorkloadID: , ' + + 'TierID: , Secret: , SKU: , Quantity: , ApiVersion: (named)' + ) + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [UInt16] $WorkloadID, + [UInt16] $TierID, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { + $splat = @{ + Name = $Name + Location = $Location + WorkloadID = $WorkloadID + TierID = $TierID + Secret = $Secret + SKU = $SKU + Quantity = $Quantity + ApiVersion = $ApiVersion + } + New-ArmorCompleteVM @splat + } | + Should -Throw + } + + $testName = $testName -replace '\(named\)', '(positional)' + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [UInt16] $WorkloadID, + [UInt16] $TierID, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { New-ArmorCompleteVM $Name $Location $WorkloadID $TierID $Secret $SKU $Quantity $ApiVersion } | + Should -Throw + } + + $testName = $testName -replace '\(positional\)', '(pipeline by value)' + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [UInt16] $WorkloadID, + [UInt16] $TierID, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { + $splat = @{ + Location = $Location + WorkloadID = $WorkloadID + TierID = $TierID + Secret = $Secret + SKU = $SKU + Quantity = $Quantity + ApiVersion = $ApiVersion + } + $Name | + New-ArmorCompleteVM @splat + } | + Should -Throw + } + + $testCases = @( + @{ + Name = $invalidName + Location = $validLocation + WorkloadName = $validWorkloadName + TierName = $validTierName + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = $invalidLocation + WorkloadName = $validWorkloadName + TierName = $validTierName + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = 'AMS01' + WorkloadName = $invalidWorkloadName + TierName = $validTierName + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = 'LHR01' + WorkloadName = $validWorkloadName + TierName = $invalidTierName + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = 'PHX01' + WorkloadName = $validWorkloadName + TierName = $validTierName + Secret = $invalidSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = 'SIN01' + WorkloadName = $validWorkloadName + TierName = $validTierName + Secret = $validSecret + SKU = $invalidSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = $validLocation + WorkloadName = $validWorkloadName + TierName = $validTierName + Secret = $validSecret + SKU = $validSKU + Quantity = $invalidQuantity + ApiVersion = $validApiVersion + }, + @{ + Name = $validName + Location = $validLocation + WorkloadName = $validWorkloadName + TierName = $validTierName + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $invalidApiVersion + } + ) + $testName = ( + 'should fail when set to: Name: , Location: , WorkloadName: , ' + + 'TierName: , Secret: , SKU: , Quantity: , ApiVersion: (named)' + ) + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [String] $WorkloadName, + [String] $TierName, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { + $splat = @{ + Name = $Name + Location = $Location + WorkloadName = $WorkloadName + TierName = $TierName + Secret = $Secret + SKU = $SKU + Quantity = $Quantity + ApiVersion = $ApiVersion + } + New-ArmorCompleteVM @splat + } | + Should -Throw + } + + $testName = $testName -replace '\(named\)', '(positional)' + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [String] $WorkloadName, + [String] $TierName, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { New-ArmorCompleteVM $Name $Location $WorkloadName $TierName $Secret $SKU $Quantity $ApiVersion } | + Should -Throw + } + + $testName = $testName -replace '\(positional\)', '(pipeline by value)' + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [String] $WorkloadName, + [String] $TierName, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { + $splat = @{ + Location = $Location + WorkloadName = $WorkloadName + TierName = $TierName + Secret = $Secret + SKU = $SKU + Quantity = $Quantity + ApiVersion = $ApiVersion + } + $Name | + New-ArmorCompleteVM @splat + } | + Should -Throw + } + } + + + InModuleScope -ModuleName $Global:CI_MODULE_NAME -ScriptBlock { + #region init + $validName = 'VM1' + $validLocation = 'DFW01' + $validWorkloadID = 1 + $validWorkloadName = 'WL1' + $validTierID = 1 + $validTierName = 'TR1' + $validSecret = '$MySecretPassword1' + $validSKU = 'A1-101' + $validQuantity = 5 + $validApiVersion = 'v1.0' + + $workload = [ArmorCompleteWorkload] ( $Global:JSON_RESPONSE_BODY.Workloads1Tiers1VMs1 | ConvertFrom-Json ) + #endregion + + Mock -CommandName Get-ArmorCompleteWorkload -Verifiable -MockWith { $workload } + # Mock -CommandName Get-ArmorCompleteWorkloadTier -Verifiable -MockWith { $true } + Mock -CommandName Test-ArmorSession -Verifiable -MockWith {} + Mock -CommandName Invoke-WebRequest -Verifiable -MockWith { + @{ + StatusCode = 400 + StatusDescription = 'Bad request' + Content = '{"error":true,"message":"Invalid request"}' + } + } + + $testCases = @( + @{ + Name = $validName + Location = $validLocation + WorkloadID = $validWorkloadID + TierID = $validTierID + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + } + ) + $testName = ( + 'should fail when set to: Name: , Location: , WorkloadID: , ' + + 'TierID: , Secret: , SKU: , Quantity: , ApiVersion: ' + + "and HTTP response code is: '400'" + ) + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [UInt16] $WorkloadID, + [UInt16] $TierID, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { + $splat = @{ + Name = $Name + Location = $Location + WorkloadID = $WorkloadID + TierID = $TierID + Secret = $Secret + SKU = $SKU + Quantity = $Quantity + ApiVersion = $ApiVersion + Confirm = $false + } + New-ArmorCompleteVM @splat + } | + Should -Throw + } + Assert-VerifiableMock + #region Upstream issue #122 + # Assert-MockCalled -CommandName Get-ArmorCompleteWorkload -Times 1 + # Assert-MockCalled -CommandName Get-ArmorCompleteWorkloadTier -Times 1 + Assert-MockCalled -CommandName Get-ArmorCompleteWorkload -Times 2 + #endregion + Assert-MockCalled -CommandName Test-ArmorSession -Times $testCases.Count + Assert-MockCalled -CommandName Invoke-WebRequest -Times $testCases.Count + + $testCases[0].TierID = 2 + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [UInt16] $WorkloadID, + [UInt16] $TierID, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { + $splat = @{ + Name = $Name + Location = $Location + WorkloadID = $WorkloadID + TierID = $TierID + Secret = $Secret + SKU = $SKU + Quantity = $Quantity + ApiVersion = $ApiVersion + Confirm = $false + } + New-ArmorCompleteVM @splat + } | + Should -Throw + } + Assert-VerifiableMock + #region Upstream issue #122 + # Assert-MockCalled -CommandName Get-ArmorCompleteWorkload -Times 1 + # Assert-MockCalled -CommandName Get-ArmorCompleteWorkloadTier -Times 1 + Assert-MockCalled -CommandName Get-ArmorCompleteWorkload -Times 2 + #endregion + Assert-MockCalled -CommandName Test-ArmorSession -Times $testCases.Count + + Mock -CommandName Invoke-WebRequest -Verifiable -MockWith { + @{ + StatusCode = 200 + StatusDescription = 'OK' + Content = $Global:JSON_RESPONSE_BODY.VmOrders1 + } + } + + $testCases[0].TierID = $validTierID + $testName = ( + 'should not fail when set to: Name: , Location: , WorkloadID: , ' + + 'TierID: , Secret: , SKU: , Quantity: , ApiVersion: ' + + "and HTTP response code is: '200'" + ) + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [UInt16] $WorkloadID, + [UInt16] $TierID, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { + $splat = @{ + Name = $Name + Location = $Location + WorkloadID = $WorkloadID + TierID = $TierID + Secret = $Secret + SKU = $SKU + Quantity = $Quantity + ApiVersion = $ApiVersion + Confirm = $false + } + New-ArmorCompleteVM @splat + } | + Should -Not -Throw + } + Assert-VerifiableMock + #region Upstream issue #122 + # Assert-MockCalled -CommandName Get-ArmorCompleteWorkload -Times 1 + # Assert-MockCalled -CommandName Get-ArmorCompleteWorkloadTier -Times 1 + Assert-MockCalled -CommandName Get-ArmorCompleteWorkload -Times 2 + #endregion + Assert-MockCalled -CommandName Test-ArmorSession -Times $testCases.Count + Assert-MockCalled -CommandName Invoke-WebRequest -Times $testCases.Count + + Mock -CommandName Invoke-WebRequest -Verifiable -MockWith { + @{ + StatusCode = 400 + StatusDescription = 'Bad request' + Content = '{"error":true,"message":"Invalid request"}' + } + } + + $testCases = @( + @{ + Name = $validName + Location = $validLocation + WorkloadName = $validWorkloadName + TierName = $validTierName + Secret = $validSecret + SKU = $validSKU + Quantity = $validQuantity + ApiVersion = $validApiVersion + } + ) + $testName = ( + 'should fail when set to: Name: , Location: , WorkloadName: , ' + + 'TierName: , Secret: , SKU: , Quantity: , ApiVersion: ' + + "and HTTP response code is: '400'" + ) + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [String] $WorkloadName, + [String] $TierName, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { + $splat = @{ + Name = $Name + Location = $Location + WorkloadName = $WorkloadName + TierName = $TierName + Secret = $Secret + SKU = $SKU + Quantity = $Quantity + ApiVersion = $ApiVersion + Confirm = $false + } + New-ArmorCompleteVM @splat + } | + Should -Throw + } + Assert-VerifiableMock + Assert-MockCalled -CommandName Test-ArmorSession -Times $testCases.Count + Assert-MockCalled -CommandName Invoke-WebRequest -Times $testCases.Count + + Mock -CommandName Invoke-WebRequest -Verifiable -MockWith { + @{ + StatusCode = 200 + StatusDescription = 'OK' + Content = $Global:JSON_RESPONSE_BODY.VmOrders1 + } + } + + $testName = ( + 'should not fail when set to: Name: , Location: , WorkloadName: , ' + + 'TierName: , Secret: , SKU: , Quantity: , ApiVersion: ' + + "and HTTP response code is: '200'" + ) + It -Name $testName -TestCases $testCases -Test { + param ( + [String] $Name, + [String] $Location, + [String] $WorkloadName, + [String] $TierName, + [String] $Secret, + [String] $SKU, + [UInt16] $Quantity, + [String] $ApiVersion + ) + { + $splat = @{ + Name = $Name + Location = $Location + WorkloadName = $WorkloadName + TierName = $TierName + Secret = $Secret + SKU = $SKU + Quantity = $Quantity + ApiVersion = $ApiVersion + Confirm = $false + } + New-ArmorCompleteVM @splat + } | + Should -Not -Throw + } + Assert-VerifiableMock + Assert-MockCalled -CommandName Test-ArmorSession -Times $testCases.Count + Assert-MockCalled -CommandName Invoke-WebRequest -Times $testCases.Count + } + } + + Context -Name $Global:RETURN_TYPE_CONTEXT -Fixture { + InModuleScope -ModuleName $Global:CI_MODULE_NAME -ScriptBlock { + #region init + $splatID = @{ + Name = 'VM1' + Location = 'DFW01' + WorkloadID = 1 + TierID = 1 + Secret = '$MySecretPassword1' + SKU = 'A1-101' + Quantity = 1 + ApiVersion = 'v1.0' + Confirm = $false + ErrorAction = 'Stop' + } + $splatName = @{ + Name = 'VM1' + Location = 'DFW01' + WorkloadName = 'WL1' + TierName = 'TR1' + Secret = '$MySecretPassword1' + SKU = 'A1-101' + Quantity = 1 + ApiVersion = 'v1.0' + Confirm = $false + ErrorAction = 'Stop' + } + + $workload = [ArmorCompleteWorkload] ( $Global:JSON_RESPONSE_BODY.Workloads1Tiers1VMs1 | ConvertFrom-Json ) + #endregion + + Mock -CommandName Get-ArmorCompleteWorkload -Verifiable -MockWith { $workload } + # Mock -CommandName Get-ArmorCompleteWorkloadTier -Verifiable -MockWith { $true } + Mock -CommandName Test-ArmorSession -Verifiable -MockWith {} + Mock -CommandName Invoke-WebRequest -Verifiable -MockWith { + @{ + StatusCode = 200 + StatusDescription = 'OK' + Content = $Global:JSON_RESPONSE_BODY.VmOrders1 + } + } + + $testCases = @( + @{ + FoundReturnType = ( New-ArmorCompleteVM @splatID ).GetType().FullName + ExpectedReturnType = 'ArmorCompleteVmOrder' + }, + @{ + FoundReturnType = ( New-ArmorCompleteVM @splatName ).GetType().FullName + ExpectedReturnType = 'ArmorCompleteVmOrder' + } + ) + $testName = $Global:FORM_RETURN_TYPE + It -Name $testName -TestCases $testCases -Test { + param ( [String] $FoundReturnType, [String] $ExpectedReturnType ) + $FoundReturnType | + Should -Be $ExpectedReturnType + } + Assert-VerifiableMock + #region Upstream issue #122 + # Assert-MockCalled -CommandName Get-ArmorCompleteWorkload -Times 1 + # Assert-MockCalled -CommandName Get-ArmorCompleteWorkloadTier -Times 1 + Assert-MockCalled -CommandName Get-ArmorCompleteWorkload -Times 2 + #endregion + Assert-MockCalled -CommandName Test-ArmorSession -Times $testCases.Count + Assert-MockCalled -CommandName Invoke-WebRequest -Times $testCases.Count + + $testName = "has an 'OutputType' entry for " + It -Name $testName -TestCases $testCases -Test { + param ( [String] $FoundReturnType, [String] $ExpectedReturnType ) + $FoundReturnType | + Should -BeIn ( Get-Help -Name 'New-ArmorCompleteVM' -Full ).ReturnValues.ReturnValue.Type.Name + } + } + } +}