Tests/Unit/MSFT_SqlServerSecureConnection.Tests.ps1
<#
.SYNOPSIS Automated unit test for MSFT_SqlServerSecureConnection DSC resource. .NOTES To run this script locally, please make sure to first run the bootstrap script. Read more at https://github.com/PowerShell/SqlServerDsc/blob/dev/CONTRIBUTING.md#bootstrap-script-assert-testenvironment #> Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') if (Test-SkipContinuousIntegrationTask -Type 'Unit') { return } $script:dscModuleName = 'SqlServerDsc' $script:dscResourceName = 'MSFT_SqlServerSecureConnection' #region HEADER # Unit Test Template Version: 1.2.0 $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) } Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $script:dscModuleName ` -DSCResourceName $script:dscResourceName ` -TestType Unit #endregion HEADER function Invoke-TestSetup { # Importing SQLPS stubs Import-Module -Name (Join-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Stubs') -ChildPath 'SQLPSStub.psm1') -Force -Global } function Invoke-TestCleanup { Restore-TestEnvironment -TestEnvironment $TestEnvironment } # Begin Testing try { Invoke-TestSetup InModuleScope $script:dscResourceName { class MockedAccessControl { [hashtable]$Access = @{ IdentityReference = 'Everyone' FileSystemRights = @{ value__ = '131209' } } [void] AddAccessRule([System.Security.AccessControl.FileSystemAccessRule] $object) { } } class MockedGetItem { [string] $Thumbprint = '12345678' [string] $PSPath = 'PathToItem' [string] $Path = 'PathToItem' [MockedAccessControl]$ACL = [MockedAccessControl]::new() [hashtable]$PrivateKey = @{ CspKeyContainerInfo = @{ UniqueKeyContainerName = 'key' } } [MockedGetItem] GetAccessControl() { return $this } } $mockNamedInstanceName = 'INSTANCE' $mockDefaultInstanceName = 'MSSQLSERVER' $mockThumbprint = '123456789' $mockServiceAccount = 'SqlSvc' Describe 'SqlServerSecureConnection\Get-TargetResource' -Tag 'Get' { BeforeAll { $mockDynamic_SqlBuildVersion = '13.0.4001.0' $defaultParameters = @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Present' } } Context 'When the system is in the desired state and Ensure is Present' { Mock -CommandName Get-EncryptedConnectionSetting -MockWith { return @{ ForceEncryption = $true Certificate = $mockThumbprint } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $true } It 'Should return the the state of present' { $resultGetTargetResource = Get-TargetResource @defaultParameters $resultGetTargetResource.InstanceName | Should -Be $mockNamedInstanceName $resultGetTargetResource.Thumbprint | Should -Be $mockThumbprint $resultGetTargetResource.ServiceAccount | Should -Be $mockServiceAccount $resultGetTargetResource.ForceEncryption | Should -Be $true $resultGetTargetResource.Ensure | Should -Be 'Present' Assert-MockCalled -CommandName Get-EncryptedConnectionSetting -Exactly -Times 1 -Scope It } } Context 'When the system is not in the desired state and Ensure is Present' { Mock -CommandName Get-EncryptedConnectionSetting -MockWith { return @{ ForceEncryption = $false Certificate = '987654321' } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $false } It "Should return the state of absent when certificate thumbprint and certificate permissions don't match." { $resultGetTargetResource = Get-TargetResource @defaultParameters $resultGetTargetResource.InstanceName | Should -Be $mockNamedInstanceName $resultGetTargetResource.Thumbprint | Should -Not -Be $mockThumbprint $resultGetTargetResource.ServiceAccount | Should -Be $mockServiceAccount $resultGetTargetResource.ForceEncryption | Should -Be $false $resultGetTargetResource.Ensure | Should -Be 'Absent' Assert-MockCalled -CommandName Get-EncryptedConnectionSetting -Exactly -Times 1 -Scope It } } Context 'When the system is not in the desired state and Ensure is Present' { Mock -CommandName Get-EncryptedConnectionSetting -MockWith { return @{ ForceEncryption = $true Certificate = '987654321' } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $true } It 'Should return the state of absent when certificate permissions match but encryption settings dont' { $resultGetTargetResource = Get-TargetResource @defaultParameters $resultGetTargetResource.InstanceName | Should -Be $mockNamedInstanceName $resultGetTargetResource.Thumbprint | Should -Not -Be $mockThumbprint $resultGetTargetResource.ServiceAccount | Should -Be $mockServiceAccount $resultGetTargetResource.ForceEncryption | Should -Be $true $resultGetTargetResource.Ensure | Should -Be 'Absent' Assert-MockCalled -CommandName Get-EncryptedConnectionSetting -Exactly -Times 1 -Scope It } } Context 'When the system is not in the desired state and Ensure is Present' { Mock -CommandName Get-EncryptedConnectionSetting -MockWith { return @{ ForceEncryption = $true Certificate = $mockThumbprint } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $false } It 'Should return the state of absent when certificate permissions dont match but encryption settings do' { $resultGetTargetResource = Get-TargetResource @defaultParameters $resultGetTargetResource.InstanceName | Should -Be $mockNamedInstanceName $resultGetTargetResource.Thumbprint | Should -Be $mockThumbprint $resultGetTargetResource.ServiceAccount | Should -Be $mockServiceAccount $resultGetTargetResource.ForceEncryption | Should -Be $true $resultGetTargetResource.Ensure | Should -Be 'Absent' Assert-MockCalled -CommandName Get-EncryptedConnectionSetting -Exactly -Times 1 -Scope It } } $defaultParameters.Ensure = 'Absent' Context 'When the system is in the desired state and Ensure is Absent' { Mock -CommandName Get-EncryptedConnectionSetting -MockWith { return @{ ForceEncryption = $false Certificate = '' } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $true } It 'Should return the the state of absent' { $resultGetTargetResource = Get-TargetResource @defaultParameters $resultGetTargetResource.InstanceName | Should -Be $mockNamedInstanceName $resultGetTargetResource.Thumbprint | Should -BeNullOrEmpty $resultGetTargetResource.ServiceAccount | Should -Be $mockServiceAccount $resultGetTargetResource.ForceEncryption | Should -Be $false $resultGetTargetResource.Ensure | Should -Be 'Absent' Assert-MockCalled -CommandName Get-EncryptedConnectionSetting -Exactly -Times 1 -Scope It } } Context 'When the system is not in the desired state and Ensure is Absent' { Mock -CommandName Get-EncryptedConnectionSetting -MockWith { return @{ ForceEncryption = $true Certificate = $mockThumbprint } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $true } It 'Should return the the state of present' { $resultGetTargetResource = Get-TargetResource @defaultParameters $resultGetTargetResource.InstanceName | Should -Be $mockNamedInstanceName $resultGetTargetResource.Thumbprint | Should -Be $mockThumbprint $resultGetTargetResource.ServiceAccount | Should -Be $mockServiceAccount $resultGetTargetResource.ForceEncryption | Should -Be $true $resultGetTargetResource.Ensure | Should -Be 'Present' Assert-MockCalled -CommandName Get-EncryptedConnectionSetting -Exactly -Times 1 -Scope It } } Context 'When the system is not in the desired state and Ensure is Absent' { Mock -CommandName Get-EncryptedConnectionSetting -MockWith { return @{ ForceEncryption = $false Certificate = $mockThumbprint } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $true } It 'Should return the the state of present when ForceEncryption is False but a thumbprint exist.' { $resultGetTargetResource = Get-TargetResource @defaultParameters $resultGetTargetResource.InstanceName | Should -Be $mockNamedInstanceName $resultGetTargetResource.Thumbprint | Should -Be $mockThumbprint $resultGetTargetResource.ServiceAccount | Should -Be $mockServiceAccount $resultGetTargetResource.ForceEncryption | Should -Be $false $resultGetTargetResource.Ensure | Should -Be 'Present' Assert-MockCalled -CommandName Get-EncryptedConnectionSetting -Exactly -Times 1 -Scope It } } Context 'When the system is not in the desired state and Ensure is Absent' { Mock -CommandName Get-EncryptedConnectionSetting -MockWith { return @{ ForceEncryption = $true Certificate = '' } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $true } It 'Should return the the state of present when Certificate is null but ForceEncryption is True.' { $resultGetTargetResource = Get-TargetResource @defaultParameters $resultGetTargetResource.InstanceName | Should -Be $mockNamedInstanceName $resultGetTargetResource.Thumbprint | Should -BeNullOrEmpty $resultGetTargetResource.ServiceAccount | Should -Be $mockServiceAccount $resultGetTargetResource.ForceEncryption | Should -Be $true $resultGetTargetResource.Ensure | Should -Be 'Present' Assert-MockCalled -CommandName Get-EncryptedConnectionSetting -Exactly -Times 1 -Scope It } } } Describe 'SqlServerSecureConnection\Set-TargetResource' -Tag 'Set' { BeforeAll { $defaultParameters = @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Present' } $defaultAbsentParameters = @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Absent' } Mock -CommandName Set-EncryptedConnectionSetting -Verifiable Mock -CommandName Set-CertificatePermission -Verifiable Mock -CommandName Restart-SqlService -Verifiable } Context 'When the system is not in the desired state' { Context 'When only certificate permissions are set' { Mock -CommandName Get-TargetResource -MockWith { return @{ InstanceName = $mockNamedInstanceName Thumbprint = '987654321' ServiceAccount = $mockServiceAccount ForceEncryption = $false Ensure = 'Present' } } Mock -CommandName Test-CertificatePermission -MockWith { return $true } It 'Should configure only ForceEncryption and Certificate thumbprint' { { Set-TargetResource @defaultParameters } | Should -Not -Throw Assert-MockCalled -CommandName Set-EncryptedConnectionSetting -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Set-CertificatePermission -Exactly -Times 0 -Scope It Assert-MockCalled -CommandName Restart-SqlService -Exactly -Times 1 -Scope It } } Context 'When there is no certificate permissions set' { Mock -CommandName Get-TargetResource -MockWith { return @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Present' } } Mock -CommandName Test-CertificatePermission -MockWith { return $false } It 'Should configure only certificate permissions' { { Set-TargetResource @defaultParameters } | Should -Not -Throw Assert-MockCalled -CommandName Set-EncryptedConnectionSetting -Exactly -Times 0 -Scope It Assert-MockCalled -CommandName Set-CertificatePermission -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Restart-SqlService -Exactly -Times 1 -Scope It } } Context 'When no settings are configured' { Mock -CommandName Get-TargetResource -MockWith { return @{ InstanceName = $mockNamedInstanceName Thumbprint = '987654321' ServiceAccount = $mockServiceAccount ForceEncryption = $false Ensure = 'Present' } } Mock -CommandName Test-CertificatePermission -MockWith { return $false } It 'Should configure Encryption settings and certificate permissions' { { Set-TargetResource @defaultParameters } | Should -Not -Throw Assert-MockCalled -CommandName Set-EncryptedConnectionSetting -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Set-CertificatePermission -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Restart-SqlService -Exactly -Times 1 -Scope It } } Context 'When ensure is absent' { Mock -CommandName Get-TargetResource -MockWith { return @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Absent' } } Mock -CommandName Test-CertificatePermission -MockWith { return $false } It 'Should configure Encryption settings setting certificate to empty string' { { Set-TargetResource @defaultAbsentParameters } | Should -Not -Throw Assert-MockCalled -CommandName Set-EncryptedConnectionSetting -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Set-CertificatePermission -Exactly -Times 0 -Scope It Assert-MockCalled -CommandName Restart-SqlService -Exactly -Times 1 -Scope It } } } } Describe 'SqlServerSecureConnection\Test-TargetResource' -Tag 'Test' { Context 'When the system is not in the desired state' { Context 'When ForceEncryption is not configured properly' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $false Ensure = 'Absent' } } -Verifiable $testParameters = @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Present' } } It 'Should return state as not in desired state' { $resultTestTargetResource = Test-TargetResource @testParameters $resultTestTargetResource | Should -Be $false } } Context 'When Thumbprint is not configured properly' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ InstanceName = $mockNamedInstanceName Thumbprint = '987654321' ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Absent' } } -Verifiable $testParameters = @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Present' } } It 'Should return state as not in desired state' { $resultTestTargetResource = Test-TargetResource @testParameters $resultTestTargetResource | Should -Be $false } } Context 'When certificate permission is not set' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Absent' } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $false } $testParameters = @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Present' } } It 'Should return state as not in desired state' { $resultTestTargetResource = Test-TargetResource @testParameters $resultTestTargetResource | Should -Be $false } } Context 'When Ensure is Absent' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Absent' } } -Verifiable $testParameters = @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Present' } } It 'Should return state as not in desired state' { $resultTestTargetResource = Test-TargetResource @testParameters $resultTestTargetResource | Should -Be $false } } } Context 'When the system is in the desired state' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Present' } } -Verifiable Mock -CommandName Test-CertificatePermission -MockWith { return $true } $testParameters = @{ InstanceName = $mockNamedInstanceName Thumbprint = $mockThumbprint ServiceAccount = $mockServiceAccount ForceEncryption = $true Ensure = 'Present' } } It 'Should return state as in desired state' { $resultTestTargetResource = Test-TargetResource @testParameters $resultTestTargetResource | Should -Be $true } } } Describe 'SqlServerSecureConnection\Get-EncryptedConnectionSetting' -Tag 'Helper' { Mock -CommandName 'Get-ItemProperty' -MockWith { return @{ ForceEncryption = '1' } } -ParameterFilter { $Name -eq 'ForceEncryption' } -Verifiable Mock -CommandName 'Get-ItemProperty' -MockWith { return @{ Certificate = '12345678' } } -ParameterFilter { $Name -eq 'Certificate' } -Verifiable Context 'When calling a method that execute successfully' { BeforeAll { Mock -CommandName 'Get-SqlEncryptionValue' -MockWith { return [MockedGetItem]::new() } -Verifiable } It 'Should return hashtable with ForceEncryption and Certificate' { $result = Get-EncryptedConnectionSetting -InstanceName 'NamedInstance' $result.Certificate | Should -Be '12345678' $result.ForceEncryption | Should -Be 1 $result | Should -BeOfType [Hashtable] Assert-VerifiableMock } } Context 'When calling a method that executes unsuccesfuly' { BeforeAll { Mock -CommandName 'Get-SqlEncryptionValue' -MockWith { return $null } } It 'Should return null' { $result = Get-EncryptedConnectionSetting -InstanceName 'NamedInstance' $result | Should -BeNullOrEmpty Assert-VerifiableMock } } } Describe 'SqlServerSecureConnection\Set-EncryptedConnectionSetting' -Tag 'Helper' { Context 'When calling a method that execute successfully' { BeforeAll { Mock -CommandName 'Get-SqlEncryptionValue' -MockWith { return [MockedGetItem]::new() } Mock -CommandName 'Set-ItemProperty' -Verifiable } It 'Should not throw' { { Set-EncryptedConnectionSetting -InstanceName 'NamedInstance' -Thumbprint '12345678' -ForceEncryption $true } | Should -Not -Throw Assert-VerifiableMock } } Context 'When calling a method that executes unsuccesfuly' { BeforeAll { Mock -CommandName 'Get-SqlEncryptionValue' -MockWith { return $null } -Verifiable Mock -CommandName 'Set-ItemProperty' } It 'Should throw' { { Set-EncryptedConnectionSetting -InstanceName 'NamedInstance' -Thumbprint '12345678' -ForceEncryption $true } | Should -Throw Assert-MockCalled -CommandName 'Set-ItemProperty' -Times 0 Assert-VerifiableMock } } } Describe 'SqlServerSecureConnection\Test-CertificatePermission' -Tag 'Helper' { Context 'When calling a method that execute successfully' { BeforeAll { Mock -CommandName 'Get-CertificateAcl' -MockWith { return [MockedGetItem]::new() } -Verifiable } It 'Should return True' { $result = Test-CertificatePermission -Thumbprint '12345678' -ServiceAccount 'Everyone' $result | Should -be $true Assert-VerifiableMock } } Context 'When calling a method that execute successfully' { BeforeAll { Mock -CommandName 'Get-CertificateAcl' -MockWith { $mockedItem = [MockedGetItem]::new() $mockedItem.ACL = $null return $mockedItem } -Verifiable } It 'Should return False when no permissions were found' { $result = Test-CertificatePermission -Thumbprint '12345678' -ServiceAccount 'Everyone' $result | Should -be $false Assert-VerifiableMock } } Context 'When calling a method that execute successfully' { BeforeAll { Mock -CommandName 'Get-CertificateAcl' -MockWith { $mockedItem = [MockedGetItem]::new() $mockedItem.ACL.FileSystemRights.Value__ = 1 return $mockedItem } -Verifiable } It 'Should return False when the wrong permissions are added' { $result = Test-CertificatePermission -Thumbprint '12345678' -ServiceAccount 'Everyone' $result | Should -be $false Assert-VerifiableMock } } Context 'When calling a method that executes unsuccesfuly' { BeforeAll { Mock -CommandName 'Get-CertificateAcl' -MockWith { return $null } -Verifiable } It 'Should return False' { $result = Test-CertificatePermission -Thumbprint '12345678' -ServiceAccount 'Everyone' $result | Should -be $false Assert-VerifiableMock } } } Describe 'SqlServerSecureConnection\Set-CertificatePermission' -Tag 'Helper' { Context 'When calling a method that execute successfully' { BeforeAll { Mock -CommandName 'Get-CertificateAcl' -MockWith { return [MockedGetItem]::new() } -Verifiable Mock -CommandName 'Set-Acl' -Verifiable } It 'Should not throw' { { Set-CertificatePermission -Thumbprint '12345678' -ServiceAccount 'Everyone' } | Should -Not -Throw Assert-VerifiableMock } } Context 'When calling a method that executes unsuccesfuly' { BeforeAll { Mock -CommandName 'Get-Item' -MockWith { return $null } -Verifiable Mock -CommandName 'Get-ChildItem' -MockWith { return $null } -Verifiable } It 'Should throw' { { Set-CertificatePermission -Thumbprint '12345678' -ServiceAccount 'Everyone' } | Should -Throw Assert-VerifiableMock } } } Describe 'SqlServerSecureConnection\Get-CertificateAcl' -Tag 'Helper' { Context 'When calling a method that execute successfully' { BeforeAll { Mock -CommandName 'Get-ChildItem' -MockWith { return [MockedGetItem]::new() } -Verifiable Mock -CommandName 'Get-Item' -MockWith { return [MockedGetItem]::new() } -Verifiable } It 'Should not throw' { { Get-CertificateAcl -Thumbprint '12345678' } | Should -Not -Throw Assert-VerifiableMock } } } Describe 'SqlServerSecureConnection\Get-SqlEncryptionValue' -Tag 'Helper' { Context 'When calling a method that execute successfully' { BeforeAll { Mock -CommandName 'Get-ItemProperty' -MockWith { return [MockedGetItem]::new() } -Verifiable Mock -CommandName 'Get-Item' -MockWith { return [MockedGetItem]::new() } -Verifiable } It 'Should not throw' { { Get-SqlEncryptionValue -InstanceName $mockNamedInstanceName } | Should -Not -Throw Assert-VerifiableMock } } Context 'When calling a method that execute unsuccessfully' { BeforeAll { Mock -CommandName 'Get-ItemProperty' -MockWith { throw "Error" } -Verifiable Mock -CommandName 'Get-Item' -MockWith { return [MockedGetItem]::new() } -Verifiable } It 'Should throw with expected message' { { Get-SqlEncryptionValue -InstanceName $mockNamedInstanceName } | Should -Throw -ExpectedMessage "SQL instance '$mockNamedInstanceName' not found on SQL Server." Assert-VerifiableMock } } } } } finally { Invoke-TestCleanup } |