Tests/Unit/MSFT_SqlDatabaseUser.Tests.ps1
<#
.SYNOPSIS Automated unit test for MSFT_SqlDatabaseUser 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_SqlDatabaseUser' #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 (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 { Add-Type -Path (Join-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Stubs') -ChildPath 'SMO.cs') } function Invoke-TestCleanup { Restore-TestEnvironment -TestEnvironment $TestEnvironment } # Begin Testing try { Invoke-TestSetup InModuleScope $script:dscResourceName { $mockName = 'DatabaseUser1' $mockServerName = 'localhost' $mockInstanceName = 'MSSQLSERVER' $mockDatabaseName = 'TestDB' $mockLoginName = 'CONTOSO\Login1' $mockAsymmetricKeyName = 'AsymmetricKey1' $mockCertificateName = 'Certificate1' $mockLoginType = 'WindowsUser' $mockUserType = 'Login' $mockAuthenticationType = 'Windows' # Default parameters that are used for the It-blocks. $mockDefaultParameters = @{ Name = $mockName InstanceName = $mockInstanceName ServerName = $mockServerName DatabaseName = $mockDatabaseName Verbose = $true } Describe 'MSFT_SqlDatabaseUser\Get-TargetResource' -Tag 'Get' { Context 'When the system is in the desired state' { BeforeAll { # Scriptblock for mocked object for mocks of Connect-SQL. $mockSqlServerObject = { New-Object -TypeName Object | Add-Member -MemberType ScriptProperty -Name 'Databases' -Value { return @( @{ $mockDatabaseName = New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockDatabaseName -PassThru | Add-Member -MemberType ScriptProperty -Name 'Users' -Value { return @( @{ $mockName = New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockName -PassThru | Add-Member -MemberType NoteProperty -Name 'AsymmetricKey' -Value $mockAsymmetricKeyName -PassThru | Add-Member -MemberType NoteProperty -Name 'Certificate' -Value $mockCertificateName -PassThru | Add-Member -MemberType NoteProperty -Name 'AuthenticationType' -Value $mockAuthenticationType -PassThru | Add-Member -MemberType NoteProperty -Name 'LoginType' -Value $mockLoginType -PassThru | Add-Member -MemberType NoteProperty -Name 'Login' -Value $mockLoginName -PassThru -Force } ) } -PassThru -Force } ) } -PassThru -Force } Mock -CommandName Connect-SQL -MockWith $mockSqlServerObject } AfterEach { Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It } Context 'When the configuration is absent' { BeforeAll { $mockMissingName = 'MissingUser1' $getTargetResourceParameters = $mockDefaultParameters.Clone() $getTargetResourceParameters['Name'] = $mockMissingName } It 'Should return the state as absent' { $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters $getTargetResourceResult.Ensure | Should -Be 'Absent' } It 'Should return the same values as passed as parameters' { $result = Get-TargetResource @getTargetResourceParameters $result.ServerName | Should -Be $getTargetResourceParameters.ServerName $result.InstanceName | Should -Be $getTargetResourceParameters.InstanceName $result.DatabaseName | Should -Be $getTargetResourceParameters.DatabaseName $result.Name | Should -Be $mockMissingName } It 'Should return $null for the rest of the properties' { $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters $getTargetResourceResult.LoginName | Should -BeNullOrEmpty $getTargetResourceResult.AsymmetricKeyName | Should -BeNullOrEmpty $getTargetResourceResult.CertificateName | Should -BeNullOrEmpty $getTargetResourceResult.AuthenticationType | Should -BeNullOrEmpty $getTargetResourceResult.LoginType | Should -BeNullOrEmpty $getTargetResourceResult.UserType | Should -BeNullOrEmpty } } Context 'When the configuration is present' { BeforeAll { $getTargetResourceParameters = $mockDefaultParameters.Clone() } It 'Should return the state as present' { $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters $getTargetResourceResult.Ensure | Should -Be 'Present' } It 'Should return the same values as passed as parameters' { $result = Get-TargetResource @getTargetResourceParameters $result.ServerName | Should -Be $getTargetResourceParameters.ServerName $result.InstanceName | Should -Be $getTargetResourceParameters.InstanceName $result.DatabaseName | Should -Be $getTargetResourceParameters.DatabaseName $result.Name | Should -Be $getTargetResourceParameters.Name } It 'Should return the correct values for the rest of the properties' { $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters $getTargetResourceResult.LoginName | Should -Be $mockLoginName $getTargetResourceResult.AsymmetricKeyName | Should -Be $mockAsymmetricKeyName $getTargetResourceResult.CertificateName | Should -Be $mockCertificateName $getTargetResourceResult.AuthenticationType | Should -Be $mockAuthenticationType $getTargetResourceResult.LoginType | Should -Be 'WindowsUser' $getTargetResourceResult.UserType | Should -Be $mockUserType } } } Context 'When the system is not in the desired state' { Context 'When the database name does not exist' { BeforeAll { Mock -CommandName Connect-SQL -MockWith $mockSqlServerObject $mockMissingName = 'MissingUser1' $mockMissingDatabaseName = 'MissingDatabase1' $getTargetResourceParameters = $mockDefaultParameters.Clone() $getTargetResourceParameters['DatabaseName'] = $mockMissingDatabaseName $getTargetResourceParameters['Name'] = $mockMissingName } It 'Should throw the correct error' { { Get-TargetResource @getTargetResourceParameters } | Should -Throw ($script:localizedData.DatabaseNotFound -f $mockMissingDatabaseName) Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It } } } Assert-VerifiableMock } Describe 'MSFT_SqlDatabaseUser\Test-TargetResource' -Tag 'Test' { Context 'When the system is in the desired state' { Context 'When the configuration is absent' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Absent' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $null AsymmetricKeyName = $null CertificateName = $null UserType = $null AuthenticationType = $null LoginType = $null } } $testTargetResourceParameters = $mockDefaultParameters.Clone() $testTargetResourceParameters['Ensure'] = 'Absent' } It 'Should return the state as $true' { $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters $testTargetResourceResult | Should -Be $true Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It } } Context 'When the configuration is present' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $mockLoginName AsymmetricKeyName = $null CertificateName = $null UserType = $mockUserType AuthenticationType = $mockAuthenticationType LoginType = $mockLoginType } } $testTargetResourceParameters = $mockDefaultParameters.Clone() $testTargetResourceParameters['UserType'] = $mockUserType $testTargetResourceParameters['LoginName'] = $mockLoginName } It 'Should return the state as $true' { $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters $testTargetResourceResult | Should -Be $true Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It } } } Context 'When the system is not in the desired state' { Context 'When the configuration should be absent' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' } } $testTargetResourceParameters = $mockDefaultParameters.Clone() $testTargetResourceParameters['Ensure'] = 'Absent' } It 'Should return the state as $false' { $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters $testTargetResourceResult | Should -Be $false Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It } } Context 'When the configuration should be present' { Context 'When the property LoginName is not in desired state' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' LoginName = 'OtherLogin1' AsymmetricKeyName = $null CertificateName = $null UserType = 'Login' } } $testTargetResourceParameters = $mockDefaultParameters.Clone() $testTargetResourceParameters['LoginName'] = $mockLoginName $testTargetResourceParameters['UserType'] = 'Login' } It 'Should return the state as $false' { $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters $testTargetResourceResult | Should -Be $false Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It } } Context 'When the property AsymmetricKeyName is not in desired state' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' LoginName = $null AsymmetricKeyName = 'OtherAsymmetricKey1' CertificateName = $null UserType = 'AsymmetricKey' } } $testTargetResourceParameters = $mockDefaultParameters.Clone() $testTargetResourceParameters['AsymmetricKeyName'] = $mockAsymmetricKeyName $testTargetResourceParameters['UserType'] = 'AsymmetricKey' } It 'Should return the state as $false' { $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters $testTargetResourceResult | Should -Be $false Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It } } Context 'When the property CertificateName is not in desired state' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' LoginName = $null AsymmetricKeyName = $null CertificateName = 'OtherCertificate1' UserType = 'Certificate' } } $testTargetResourceParameters = $mockDefaultParameters.Clone() $testTargetResourceParameters['CertificateName'] = $mockCertificateName $testTargetResourceParameters['UserType'] = 'Certificate' } It 'Should return the state as $false' { $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters $testTargetResourceResult | Should -Be $false Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It } } Context 'When the property UserType is not in desired state' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' LoginName = $null AsymmetricKeyName = $null CertificateName = 'OtherCertificate1' UserType = 'Certificate' } } $testTargetResourceParameters = $mockDefaultParameters.Clone() $testTargetResourceParameters['LoginName'] = $mockLoginName $testTargetResourceParameters['UserType'] = 'Login' } It 'Should return the state as $false' { $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters $testTargetResourceResult | Should -Be $false Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It } } } } Assert-VerifiableMock } Describe 'MSFT_SqlDatabaseUser\Set-TargetResource' -Tag 'Set' { BeforeAll { Mock -CommandName Invoke-Query Mock -CommandName Assert-SqlLogin Mock -CommandName Assert-DatabaseAsymmetricKey Mock -CommandName Assert-DatabaseCertificate } Context 'When the system is in the desired state' { Context 'When the configuration is absent' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Absent' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $null AsymmetricKeyName = $null CertificateName = $null UserType = $null AuthenticationType = $null LoginType = $null } } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['Ensure'] = 'Absent' } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -Exactly -Times 0 -Scope It } } Context 'When the configuration is present' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $mockLoginName AsymmetricKeyName = $null CertificateName = $null UserType = $mockUserType AuthenticationType = $mockAuthenticationType LoginType = $mockLoginType } } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['UserType'] = $mockUserType $setTargetResourceParameters['LoginName'] = $mockLoginName } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -Exactly -Times 0 -Scope It } } } Context 'When the system is not in the desired state' { Context 'When the configuration should be absent' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $mockLoginName AsymmetricKeyName = $null CertificateName = $null UserType = $mockUserType AuthenticationType = $mockAuthenticationType LoginType = $mockLoginType } } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['Ensure'] = 'Absent' } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('DROP USER [{0}];' -f $mockName) } -Exactly -Times 1 -Scope It } Context 'When trying to drop a database user but Invoke-Query fails' { BeforeAll { Mock -CommandName Invoke-Query -MockWith { throw } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['Ensure'] = 'Absent' } It 'Should throw the correct error' { { Set-TargetResource @setTargetResourceParameters } | Should -Throw ($script:localizedData.FailedDropDatabaseUser -f $mockName, $MockDatabaseName) Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -Exactly -Times 1 -Scope It } } } Context 'When the configuration should be present' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Absent' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $null AsymmetricKeyName = $null CertificateName = $null UserType = $null AuthenticationType = $null LoginType = $null } } } Context 'When creating a database user with a login' { BeforeAll { $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['LoginName'] = $mockLoginName $setTargetResourceParameters['UserType'] = 'Login' } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('CREATE USER [{0}] FOR LOGIN [{1}];' -f $mockName, $mockLoginName) } -Exactly -Times 1 -Scope It } } Context 'When creating a database user without a login' { BeforeAll { $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['UserType'] = 'NoLogin' } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('CREATE USER [{0}] WITHOUT LOGIN;' -f $mockName) } -Exactly -Times 1 -Scope It } } Context 'When creating a database user mapped to a certificate' { BeforeAll { $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['CertificateName'] = $mockCertificateName $setTargetResourceParameters['UserType'] = 'Certificate' } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('CREATE USER [{0}] FOR CERTIFICATE [{1}];' -f $mockName, $mockCertificateName) } -Exactly -Times 1 -Scope It } } Context 'When creating a database user mapped to an asymmetric key' { BeforeAll { $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['AsymmetricKeyName'] = $mockAsymmetricKeyName $setTargetResourceParameters['UserType'] = 'AsymmetricKey' } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('CREATE USER [{0}] FOR ASYMMETRIC KEY [{1}];' -f $mockName, $mockAsymmetricKeyName) } -Exactly -Times 1 -Scope It } } Context 'When trying to create a database user but Invoke-Query fails' { BeforeAll { Mock -CommandName Invoke-Query -MockWith { throw } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['UserType'] = 'NoLogin' } It 'Should throw the correct error' { { Set-TargetResource @setTargetResourceParameters } | Should -Throw ($script:localizedData.FailedCreateDatabaseUser -f $mockName, $MockDatabaseName, 'NoLogin') Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -Exactly -Times 1 -Scope It } } } Context 'When properties are not in desired state' { Context 'When the database user has the wrong login name' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $mockLoginName AsymmetricKeyName = $null CertificateName = $null UserType = $mockUserType AuthenticationType = $mockAuthenticationType LoginType = 'WindowsUser' } } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['LoginName'] = 'OtherLogin1' $setTargetResourceParameters['UserType'] = 'Login' } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('ALTER USER [{0}] WITH NAME = [{1}], LOGIN = [{2}];' -f $mockName, $mockName, 'OtherLogin1') } -Exactly -Times 1 -Scope It } Context 'When trying to alter the login name but Invoke-Query fails' { BeforeAll { Mock -CommandName Invoke-Query -MockWith { throw } } It 'Should throw the correct error' { { Set-TargetResource @setTargetResourceParameters } | Should -Throw ($script:localizedData.FailedUpdateDatabaseUser -f $mockName, $MockDatabaseName, 'Login') Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -Exactly -Times 1 -Scope It } } } Context 'When the database user has the wrong asymmetric key name' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $mockLoginName AsymmetricKeyName = $mockAsymmetricKeyName CertificateName = $null UserType = 'AsymmetricKey' AuthenticationType = $mockAuthenticationType LoginType = 'AsymmetricKey' } } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['AsymmetricKeyName'] = 'OtherAsymmetricKey1' $setTargetResourceParameters['UserType'] = 'AsymmetricKey' $setTargetResourceParameters['Force'] = $true } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('DROP USER [{0}];' -f $mockName) } -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('CREATE USER [{0}] FOR ASYMMETRIC KEY [{1}];' -f $mockName, 'OtherAsymmetricKey1') } -Exactly -Times 1 -Scope It } } Context 'When the database user has the wrong certificate name' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $mockLoginName AsymmetricKeyName = $mockAsymmetricKeyName CertificateName = $null UserType = 'Certificate' AuthenticationType = $mockAuthenticationType LoginType = 'Certificate' } } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['CertificateName'] = 'OtherCertificate1' $setTargetResourceParameters['UserType'] = 'Certificate' $setTargetResourceParameters['Force'] = $true } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('DROP USER [{0}];' -f $mockName) } -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('CREATE USER [{0}] FOR CERTIFICATE [{1}];' -f $mockName, 'OtherCertificate1') } -Exactly -Times 1 -Scope It } } Context 'When the database user has the wrong certificate name' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $mockLoginName AsymmetricKeyName = $mockAsymmetricKeyName CertificateName = $null UserType = 'Certificate' AuthenticationType = $mockAuthenticationType LoginType = 'Certificate' } } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['LoginName'] = 'OtherLogin1' $setTargetResourceParameters['UserType'] = 'Login' $setTargetResourceParameters['Force'] = $true } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('DROP USER [{0}];' -f $mockName) } -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -ParameterFilter { $Query -eq ('CREATE USER [{0}] FOR LOGIN [{1}];' -f $mockName, 'OtherLogin1') } -Exactly -Times 1 -Scope It } } Context 'When the configuration has not opt-in to re-create a database user' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ Ensure = 'Present' Name = $mockName ServerName = $mockServerName InstanceName = $mockInstanceName DatabaseName = $mockDatabaseName LoginName = $mockLoginName AsymmetricKeyName = $mockAsymmetricKeyName CertificateName = $null UserType = 'Certificate' AuthenticationType = $mockAuthenticationType LoginType = 'Certificate' } } $setTargetResourceParameters = $mockDefaultParameters.Clone() $setTargetResourceParameters['LoginName'] = 'OtherLogin1' $setTargetResourceParameters['UserType'] = 'Login' } It 'Should not throw and should call the correct mocks' { { Set-TargetResource @setTargetResourceParameters } | Should -Throw $script:localizedData.ForceNotEnabled Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Invoke-Query -Exactly -Times 0 -Scope It } } } } Assert-VerifiableMock } Describe 'Assert-Parameters' -Tag 'Helper' { BeforeAll { $mockUserType = 'NoLogin' } Context 'When parameter LoginName is provided, but with the wrong user type' { It 'Should throw the correct error' { { Assert-Parameters -LoginName 'AnyValue' -UserType $mockUserType } | Should -Throw ($script:localizedData.LoginNameProvidedWithWrongUserType -f $mockUserType) } } Context 'When parameter CertificateName is provided, but with the wrong user type' { It 'Should throw the correct error' { { Assert-Parameters -CertificateName 'AnyValue' -UserType $mockUserType } | Should -Throw ($script:localizedData.CertificateNameProvidedWithWrongUserType -f $mockUserType) } } Context 'When parameter AsymmetricKeyName is provided, but with the wrong user type' { It 'Should throw the correct error' { { Assert-Parameters -AsymmetricKeyName 'AnyValue' -UserType $mockUserType } | Should -Throw ($script:localizedData.AsymmetricKeyNameProvidedWithWrongUserType -f $mockUserType) } } Context 'When parameter LoginName is not provided when providing the user type ''Login''' { It 'Should throw the correct error' { { Assert-Parameters -UserType 'Login' } | Should -Throw ($script:localizedData.LoginUserTypeWithoutLoginName -f 'Login') } } Context 'When parameter AsymmetricKeyName is not provide when providing the user type ''AsymmetricKey''' { It 'Should throw the correct error' { { Assert-Parameters -UserType 'AsymmetricKey' } | Should -Throw ($script:localizedData.AsymmetricKeyUserTypeWithoutAsymmetricKeyName -f 'AsymmetricKey') } } Context 'When parameter CertificateName is not provide when providing the user type ''Certificate''' { It 'Should throw the correct error' { { Assert-Parameters -UserType 'Certificate' } | Should -Throw ($script:localizedData.CertificateUserTypeWithoutCertificateName -f 'Certificate') } } } Describe 'ConvertTo-UserType' -Tag 'Helper' { Context 'When converting to a user type' { BeforeAll { $testCases = @( @{ AuthenticationType = 'Windows' LoginType = 'WindowsUser' ExpectedResult = 'Login' } @{ AuthenticationType = 'Windows' LoginType = 'WindowsGroup' ExpectedResult = 'Login' } @{ AuthenticationType = 'Instance' LoginType = 'SqlLogin' ExpectedResult = 'Login' } @{ AuthenticationType = 'None' LoginType = 'SqlLogin' ExpectedResult = 'NoLogin' } @{ AuthenticationType = 'None' LoginType = 'AsymmetricKey' ExpectedResult = 'AsymmetricKey' } @{ AuthenticationType = 'None' LoginType = 'Certificate' ExpectedResult = 'Certificate' } ) } It 'Should return the correct value when converting authentication type <AuthenticationType> and login type <LoginType>' -TestCases $testCases { param ( [Parameter()] [System.String] $AuthenticationType, [Parameter()] [System.String] $LoginType, [Parameter()] [System.String] $ExpectedResult ) $convertToUserTypeResult = ConvertTo-UserType -AuthenticationType $AuthenticationType -LoginType $LoginType $convertToUserTypeResult | Should -Be $ExpectedResult } Context 'When calling with an unsupported authentication type' { BeforeAll { $mockUnsupportedValue = 'UnsupportedValue' $mockLoginType = 'SqlLogin' } It 'Should throw the correct error' { { ConvertTo-UserType -AuthenticationType $mockUnsupportedValue -LoginType $mockLoginType } | Should -Throw ($script:localizedData.UnknownAuthenticationType -f $mockUnsupportedValue, $mockLoginType) } } } } Describe 'Assert-SqlLogin' -Tag 'Helper' { BeforeAll { $mockSqlServerObject = { New-Object -TypeName Object | Add-Member -MemberType ScriptProperty -Name 'Logins' -Value { return @( @{ $mockLoginName = New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockLoginName -PassThru -Force } ) } -PassThru -Force } Mock -CommandName Connect-SQL -MockWith $mockSqlServerObject } Context 'When the SQL login exist' { BeforeAll { $assertSqlLoginParameters = $mockDefaultParameters.Clone() $assertSqlLoginParameters['LoginName'] = $mockLoginName } It 'Should not throw any error' { { Assert-SqlLogin @assertSqlLoginParameters } | Should -Not -Throw } } Context 'When the SQL login does not exist' { BeforeAll { $assertSqlLoginParameters = $mockDefaultParameters.Clone() $assertSqlLoginParameters['LoginName'] = 'AnyValue' } It 'Should throw the correct error' { { Assert-SqlLogin @assertSqlLoginParameters } | Should -Throw ($script:localizedData.SqlLoginNotFound -f 'AnyValue') } } } Describe 'Assert-DatabaseCertificate' -Tag 'Helper' { BeforeAll { $mockSqlServerObject = { New-Object -TypeName Object | Add-Member -MemberType ScriptProperty -Name 'Databases' -Value { return @( @{ $mockDatabaseName = New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockDatabaseName -PassThru | Add-Member -MemberType ScriptProperty -Name 'Certificates' -Value { return @( @{ $mockCertificateName = New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockCertificateName -PassThru -Force } ) } -PassThru -Force } ) } -PassThru -Force } Mock -CommandName Connect-SQL -MockWith $mockSqlServerObject } Context 'When the certificate exist in the database' { BeforeAll { $assertDatabaseCertificateParameters = $mockDefaultParameters.Clone() $assertDatabaseCertificateParameters['CertificateName'] = $mockCertificateName } It 'Should not throw any error' { { Assert-DatabaseCertificate @assertDatabaseCertificateParameters } | Should -Not -Throw } } Context 'When the certificate does not exist in the database' { BeforeAll { $assertDatabaseCertificateParameters = $mockDefaultParameters.Clone() $assertDatabaseCertificateParameters['CertificateName'] = 'AnyValue' } It 'Should throw the correct error' { { Assert-DatabaseCertificate @assertDatabaseCertificateParameters } | Should -Throw ($script:localizedData.CertificateNotFound -f 'AnyValue', $mockDatabaseName) } } } Describe 'Assert-DatabaseAsymmetricKey' -Tag 'Helper' { BeforeAll { $mockSqlServerObject = { New-Object -TypeName Object | Add-Member -MemberType ScriptProperty -Name 'Databases' -Value { return @( @{ $mockDatabaseName = New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockDatabaseName -PassThru | Add-Member -MemberType ScriptProperty -Name 'AsymmetricKeys' -Value { return @( @{ $mockAsymmetricKeyName = New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockAsymmetricKeyName -PassThru -Force } ) } -PassThru -Force } ) } -PassThru -Force } Mock -CommandName Connect-SQL -MockWith $mockSqlServerObject } Context 'When the asymmetric key exist in the database' { BeforeAll { $assertDatabaseAsymmetricKeyParameters = $mockDefaultParameters.Clone() $assertDatabaseAsymmetricKeyParameters['AsymmetricKeyName'] = $mockAsymmetricKeyName } It 'Should not throw any error' { { Assert-DatabaseAsymmetricKey @assertDatabaseAsymmetricKeyParameters } | Should -Not -Throw } } Context 'When the asymmetric key does not exist in the database' { BeforeAll { $assertDatabaseAsymmetricKeyParameters = $mockDefaultParameters.Clone() $assertDatabaseAsymmetricKeyParameters['AsymmetricKeyName'] = 'AnyValue' } It 'Should throw the correct error' { { Assert-DatabaseAsymmetricKey @assertDatabaseAsymmetricKeyParameters } | Should -Throw ($script:localizedData.AsymmetryKeyNotFound -f 'AnyValue', $mockDatabaseName) } } } } } finally { Invoke-TestCleanup } |