tests/AzureConnectedMachineDsc.Unit.Tests.ps1
$ModuleManifestName = 'AzureConnectedMachineDsc.psd1' $ModuleManifestPath = "$PSScriptRoot\..\$ModuleManifestName" Import-Module $ModuleManifestPath Describe -Tag 'Unit' 'Module Tests' { Context 'Module Manifest' { It 'passes Test-ModuleManifest' { $ModuleManifestName = 'AzureConnectedMachineDsc.psd1' $ModuleManifestPath = "$PSScriptRoot\..\$ModuleManifestName" Test-ModuleManifest -Path $ModuleManifestPath | Should -Not -BeNullOrEmpty $? | Should -BeTrue } } Context 'Agent Desired State Configuration resource' { It 'exports a DSC resource' { $dsc = Get-DscResource 'AzureConnectedMachineAgentDsc' $dsc | ForEach-Object Name | Should -Be 'AzureConnectedMachineAgentDsc' } It 'has a property named TenantId' { $dsc = Get-DscResource 'AzureConnectedMachineAgentDsc' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'TenantId' } It 'has a property named SubscriptionId' { $dsc = Get-DscResource 'AzureConnectedMachineAgentDsc' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'SubscriptionId' } It 'has a property named ResourceGroup' { $dsc = Get-DscResource 'AzureConnectedMachineAgentDsc' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'ResourceGroup' } It 'has a property named Location' { $dsc = Get-DscResource 'AzureConnectedMachineAgentDsc' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'Location' } It 'has a property named Tags' { $dsc = Get-DscResource 'AzureConnectedMachineAgentDsc' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'Tags' } It 'has a property named Credential' { $dsc = Get-DscResource 'AzureConnectedMachineAgentDsc' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'Credential' } } Context 'Agent Config Desired State Configuration resource' { It 'exports a DSC resource' { $dsc = Get-DscResource 'AzcmagentConfig' $dsc | ForEach-Object Name | Should -Be 'AzcmagentConfig' } It 'has a property named IsSingleInstance' { $dsc = Get-DscResource 'AzcmagentConfig' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'IsSingleInstance' } It 'has a property named incomingconnections_ports' { $dsc = Get-DscResource 'AzcmagentConfig' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'incomingconnections_ports' } It 'has a property named proxy_url' { $dsc = Get-DscResource 'AzcmagentConfig' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'proxy_url' } It 'has a property named extensions_allowlist' { $dsc = Get-DscResource 'AzcmagentConfig' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'extensions_allowlist' } It 'has a property named extensions_blocklist' { $dsc = Get-DscResource 'AzcmagentConfig' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'extensions_blocklist' } It 'has a property named proxy_bypass' { $dsc = Get-DscResource 'AzcmagentConfig' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'proxy_bypass' } It 'has a property named guestconfiguration_enabled' { $dsc = Get-DscResource 'AzcmagentConfig' $dsc.properties | ForEach-Object { $_.Name } | Should -Contain 'guestconfiguration_enabled' } } Context 'function Connect-AzConnectedMachineAgent' { It 'should attempt to connect when the agent is installed but not connected' { InModuleScope AzureConnectedMachineDsc { $connectParams = @{ TenantId = (new-guid).Guid SubscriptionId = (new-guid).Guid ResourceGroup = 'resource_group_name' Location = 'location' Tags = 'property=value' Credential = New-Object System.Management.Automation.PSCredential ('appid', ('secret' | ConvertTo-SecureString -AsPlainText -Force)) } function azcmagent {} Mock -CommandName azcmagent -MockWith { $Global:LASTEXITCODE = 0 } Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable Mock -CommandName 'Test-AzConnectedMachineAgentConnection' -MockWith { $false } -Verifiable { Connect-AzConnectedMachineAgent @connectParams } | Should -Not -Throw Assert-VerifiableMock } } It 'should attempt to disconnect and reconnect when the agent is installed and connected' { InModuleScope AzureConnectedMachineDsc { $connectParams = @{ TenantId = (new-guid).Guid SubscriptionId = (new-guid).Guid ResourceGroup = 'resource_group_name' Location = 'location' Tags = 'property=value' Credential = New-Object System.Management.Automation.PSCredential ('appid', ('secret' | ConvertTo-SecureString -AsPlainText -Force)) } function azcmagent {} Mock -CommandName azcmagent -MockWith { $Global:LASTEXITCODE = 0 } Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable Mock -CommandName 'Test-AzConnectedMachineAgentConnection' -MockWith { $true } -Verifiable Mock -CommandName 'Restart-Service' -Verifiable { Connect-AzConnectedMachineAgent @connectParams } | Should -Not -Throw Assert-VerifiableMock } } It 'should return an error if the agent is not installed' { InModuleScope AzureConnectedMachineDsc { $connectParams = @{ TenantId = (new-guid).Guid SubscriptionId = (new-guid).Guid ResourceGroup = 'resource_group_name' Location = 'location' Tags = 'property=value' Credential = New-Object System.Management.Automation.PSCredential ('appid', ('secret' | ConvertTo-SecureString -AsPlainText -Force)) } function azcmagent {} Mock -CommandName azcmagent -MockWith { $Global:LASTEXITCODE = 0 } Mock -CommandName 'Test-Path' -MockWith { $false } -Verifiable { Connect-AzConnectedMachineAgent @connectParams } | Should -Throw 'The Hybrid agent is not installed.' Assert-VerifiableMock } } } Context 'function Get-AzConnectedMachineAgent' { It 'should return a hashtable' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName 'Test-AzConnectedMachineAgentService' -MockWith { $true } -Verifiable Mock -CommandName 'Invoke-WebRequest' -Verifiable Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable Mock -CommandName 'Get-Content' -Verifiable Get-AzConnectedMachineAgent | Should -BeOfType 'hashtable' Assert-VerifiableMock } } It 'should have a property TenantId' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName 'Test-AzConnectedMachineAgentService' -MockWith { $true } -Verifiable Mock -CommandName 'Invoke-WebRequest' -Verifiable Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable Mock -CommandName 'Get-Content' -Verifiable (Get-AzConnectedMachineAgent).Keys | Should -Contain TenantId } } It 'should have a property SubscriptionId' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName 'Test-AzConnectedMachineAgentService' -MockWith { $true } -Verifiable Mock -CommandName 'Invoke-WebRequest' -Verifiable Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable Mock -CommandName 'Get-Content' -Verifiable (Get-AzConnectedMachineAgent).Keys | Should -Contain SubscriptionId } } It 'should have a property ResourceGroup' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName 'Test-AzConnectedMachineAgentService' -MockWith { $true } -Verifiable Mock -CommandName 'Invoke-WebRequest' -Verifiable Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable Mock -CommandName 'Get-Content' -Verifiable (Get-AzConnectedMachineAgent).Keys | Should -Contain ResourceGroup } } It 'should have a property Location' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName 'Test-AzConnectedMachineAgentService' -MockWith { $true } -Verifiable Mock -CommandName 'Invoke-WebRequest' -Verifiable Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable Mock -CommandName 'Get-Content' -Verifiable (Get-AzConnectedMachineAgent).Keys | Should -Contain Location } } It 'should have a property Tags' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName 'Test-AzConnectedMachineAgentService' -MockWith { $true } -Verifiable Mock -CommandName 'Invoke-WebRequest' -Verifiable Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable Mock -CommandName 'Get-Content' -Verifiable (Get-AzConnectedMachineAgent).Keys | Should -Contain Tags } } It 'should have a property AgentStatus' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName 'Test-AzConnectedMachineAgentService' -MockWith { $true } -Verifiable Mock -CommandName 'Invoke-WebRequest' -Verifiable Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable Mock -CommandName 'Get-Content' -Verifiable (Get-AzConnectedMachineAgent).Keys | Should -Contain AgentStatus } } } Context 'function Test-AzConnectedMachineAgent' { It 'should be false if the node is not connected' { InModuleScope AzureConnectedMachineDsc { $connectParams = @{ TenantId = (new-guid).Guid SubscriptionId = (new-guid).Guid ResourceGroup = 'resource_group_name' Location = 'location' Tags = 'property=value' } Mock -CommandName 'Get-AzConnectedMachineAgent' -Verifiable Test-AzConnectedMachineAgent @connectParams | Should -BeFalse Assert-VerifiableMock } } It 'should be true if the node is connected' { InModuleScope AzureConnectedMachineDsc { $connectParams = @{ TenantId = (new-guid).Guid SubscriptionId = (new-guid).Guid ResourceGroup = 'resource_group_name' Location = 'location' Tags = 'property=value' } $get = $connectParams.clone() $get.Add('AgentStatus', 'Connected') Mock -CommandName 'Get-AzConnectedMachineAgent' -MockWith { $get } Test-AzConnectedMachineAgent @connectParams | Should -BeTrue Assert-VerifiableMock } } } Context 'function Test-AzConnectedMachineAgentConnection' { It 'should correctly return when the node is connected to Azure' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName Get-AzConnectedMachineAgent -MockWith { @{AgentStatus = 'Connected' } } -Verifiable $TestConnection = Test-AzConnectedMachineAgentConnection $TestConnection | Should -BeOfType boolean $TestConnection | Should -BeTrue Assert-VerifiableMock } } It 'should correctly return when the node is not connected to Azure' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName Get-AzConnectedMachineAgent -MockWith { @{AgentStatus = 'NotConnected' } } -Verifiable $TestConnection = Test-AzConnectedMachineAgentConnection $TestConnection | Should -BeOfType boolean $TestConnection | Should -BeFalse Assert-VerifiableMock } } } Context 'function Test-AzConnectedMachineAgentService' { It 'should return false when the agent service is not running' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName Get-Service -MockWith { New-Object -type PSCustomObject -property @{Name = 'HIMDS'; Status = 'Stopped' } } -Verifiable $TestService = Test-AzConnectedMachineAgentService $TestService | Should -BeOfType boolean $TestService | Should -BeFalse Assert-VerifiableMock } } It 'should return true when the agent service is running' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName Get-Service -MockWith { New-Object -type PSCustomObject -property @{Name = 'HIMDS'; Status = 'Running' } } -Verifiable Mock -CommandName Invoke-WebRequest -MockWith { New-Object -type PSCustomObject -property @{StatusCode = '200' } } -Verifiable $TestService = Test-AzConnectedMachineAgentService $TestService | Should -BeOfType boolean $TestService | Should -BeTrue Assert-VerifiableMock } } It 'should return false when HIMDS is not available' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName Get-Service -MockWith { New-Object -type PSCustomObject -property @{Name = 'HIMDS'; Status = 'Running' } } -Verifiable Mock -CommandName Invoke-WebRequest -MockWith { New-Object -type PSCustomObject -property @{StatusCode = '404' } } -Verifiable $TestService = Test-AzConnectedMachineAgentService $TestService | Should -BeOfType boolean $TestService | Should -BeFalse Assert-VerifiableMock } } } Context 'function Get-AzConnectedMachineAgentConfig' { It 'should return a hashtable' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName Get-AzConnectedMachineAgentConfigValues -MockWith { New-Object -type PSCustomObject -property @{incomingconnections_ports = '23'; proxy_url = ''; extensions_allowlist = ''; extensions_blocklist = ''; proxy_bypass = ''; guestconfiguration_enabled = 'true' } } -Verifiable Get-AzConnectedMachineAgentConfig | Should -BeOfType 'hashtable' Assert-VerifiableMock } } It 'should have a property incomingconnections_ports' { InModuleScope AzureConnectedMachineDsc { InModuleScope AzureConnectedMachineDsc { Mock -CommandName Get-AzConnectedMachineAgentConfigValues -MockWith { New-Object -type PSCustomObject -property @{incomingconnections_ports = '23'; proxy_url = ''; extensions_allowlist = ''; extensions_blocklist = ''; proxy_bypass = ''; guestconfiguration_enabled = 'true' } } -Verifiable (Get-AzConnectedMachineAgentConfig).Keys | Should -Contain incomingconnections_ports Assert-VerifiableMock } } } } Context 'function Get-AzConnectedMachineAgentConfigValues' { It 'should return an error if the agent is not installed' { InModuleScope AzureConnectedMachineDsc { function azcmagent {} Mock -CommandName azcmagent -MockWith { $Global:LASTEXITCODE = 0 } Mock -CommandName 'Test-Path' -MockWith { $false } -Verifiable { Get-AzConnectedMachineAgentConfigValues } | Should -Throw 'The Hybrid agent is not installed.' Assert-VerifiableMock } } It 'should return an object' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable function azcmagent {} Mock -CommandName azcmagent -ParameterFilter {"$args" -match 'config list --json'} -MockWith { '{"LocalSettings":[{"Key":"incomingconnections.ports","Value":[]},{"Key":"proxy.url","Value":""},{"Key":"extensions.allowlist","Value":[]},{"Key":"extensions.blocklist","Value":[]},{"Key":"proxy.bypass","Value":[]},{"Key":"guestconfiguration.enabled","Value":"true"}]}';$Global:LASTEXITCODE = 0 } Mock -CommandName azcmagent -ParameterFilter {"$args" -match 'config info --json'} -MockWith { '[{"DisplayName": "incomingconnections.ports","IsRemote": false,"IsLocal": true,"InPreview": true,"Description": {"General": "Comma separated list of ports that the server will be able to listen on.","Example": "22,8080","Default": "Empty, all incoming traffic on all ports blocked","AdditionalInfo": ""}}]';$Global:LASTEXITCODE = 0 } Get-AzConnectedMachineAgentConfigValues | Should -BeOfType 'PSObject' Assert-VerifiableMock } } It 'should have a property DisplayName' { InModuleScope AzureConnectedMachineDsc { Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable function azcmagent {} Mock -CommandName azcmagent -ParameterFilter {"$args" -match 'config list --json'} -MockWith { '{"LocalSettings":[{"Key":"incomingconnections.ports","Value":[]},{"Key":"proxy.url","Value":""},{"Key":"extensions.allowlist","Value":[]},{"Key":"extensions.blocklist","Value":[]},{"Key":"proxy.bypass","Value":[]},{"Key":"guestconfiguration.enabled","Value":"true"}]}';$Global:LASTEXITCODE = 0 } Mock -CommandName azcmagent -ParameterFilter {"$args" -match 'config info --json'} -MockWith { '[{"DisplayName": "incomingconnections.ports","IsRemote": false,"IsLocal": true,"InPreview": true,"Description": {"General": "Comma separated list of ports that the server will be able to listen on.","Example": "22,8080","Default": "Empty, all incoming traffic on all ports blocked","AdditionalInfo": ""}}]';$Global:LASTEXITCODE = 0 } (Get-AzConnectedMachineAgentConfigValues) | Get-Member -MemberType NoteProperty | ForEach-Object {$_.Name} | Should -Contain 'DisplayName' } } } Context 'function Set-AzConnectedMachineAgentConfig' { It 'should not return an error' { InModuleScope AzureConnectedMachineDsc { $params = @{ incomingconnections_ports = '22' guestconfiguration_enabled = $true } Mock -CommandName 'Set-AzConnectedMachineAgentConfigValue' -MockWith { } -Verifiable { Set-AzConnectedMachineAgentConfig @params } | Should -Not -Throw Assert-VerifiableMock } } It 'should not return an error when a comma seperated value is passed' { InModuleScope AzureConnectedMachineDsc { $params = @{ incomingconnections_ports = '22,2222' guestconfiguration_enabled = $true } Mock -CommandName 'Set-AzConnectedMachineAgentConfigValue' -MockWith { } -Verifiable { Set-AzConnectedMachineAgentConfig @params } | Should -Not -Throw Assert-VerifiableMock } } } Context 'function Test-AzConnectedMachineAgentConfig' { It 'should return false when a value does not match' { InModuleScope AzureConnectedMachineDsc { $params = @{ incomingconnections_ports = '22' } Mock -CommandName Get-AzConnectedMachineAgentConfigValues -MockWith { New-Object -type PSCustomObject -property @{DisplayName = 'incomingconnections.ports'; Value = '23'}} -Verifiable $test = Test-AzConnectedMachineAgentConfig @params $test | Should -BeOfType boolean $test | Should -BeFalse Assert-VerifiableMock } } It 'should return true when values match' { InModuleScope AzureConnectedMachineDsc { $params = @{ incomingconnections_ports = '22' } Mock -CommandName Get-AzConnectedMachineAgentConfigValues -MockWith { New-Object -type PSCustomObject -property @{DisplayName = 'incomingconnections.ports'; Value = '22'}} -Verifiable $test = Test-AzConnectedMachineAgentConfig @params $test | Should -BeOfType boolean $test | Should -BeTrue Assert-VerifiableMock } } } Context 'function Set-AzConnectedMachineAgentConfigValue' { It 'should not return an error' { InModuleScope AzureConnectedMachineDsc { $params = @{ property = 'incomingconnections_ports' value = '22' } Mock -CommandName 'New-ConfigValueValidation' -MockWith { $true } -Verifiable Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable function azcmagent {} Mock -CommandName azcmagent -MockWith { $Global:LASTEXITCODE = 0 } { Set-AzConnectedMachineAgentConfigValue @params } | Should -Not -Throw Assert-VerifiableMock } } It 'should not return an error when an array value is passed' { InModuleScope AzureConnectedMachineDsc { $params = @{ property = 'incomingconnections_ports' value = @('22','2222') } Mock -CommandName 'New-ConfigValueValidation' -MockWith { $true } -Verifiable Mock -CommandName 'Test-Path' -MockWith { $true } -Verifiable function azcmagent {} Mock -CommandName azcmagent -MockWith { $Global:LASTEXITCODE = 0 } { Set-AzConnectedMachineAgentConfigValue @params } | Should -Not -Throw Assert-VerifiableMock } } } Context 'function Get-Reasons' { It 'should return a reasons object' { InModuleScope AzureConnectedMachineDsc { $params = @{ expectedState = @{incomingconnections_ports = '22'} actualState = @{incomingconnections_ports = '22'} className = 'test' } $Reasons = Get-Reasons @params $Reasons.Code | Should -Be 'test:test:Configuration' $Reasons.phrase | Should -Not -BeNullOrEmpty } } } } |