diff --git a/CHANGELOG.md b/CHANGELOG.md index 55f5f2763..aeac8227f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - DSC_SqlRS and DSC_SqlWindowsFirewall - Fixed a duplicated word in localized `TestFailedAfterSet` messages. +- SqlServerDsc + - Updated unit test mocks for compatibility with Pester 6 (`6.0.0`): + added forwarding default mocks so cmdlet calls that no longer + fall through to the real command in Pester 6 behave as before, added a + `$null` default mock for `Get-RegistryPropertyValue` and a default + `Get-PrimaryReplicaServerObject` mock, and merged a duplicate `AfterAll` + block. - SqlScript - Fixed logic in `Get-TargetResource` and `Set-TargetResource` to throw an error when the SQL script file is missing, instead of incorrectly reporting success diff --git a/RequiredModules.psd1 b/RequiredModules.psd1 index 69571d44c..9defe1176 100644 --- a/RequiredModules.psd1 +++ b/RequiredModules.psd1 @@ -16,10 +16,7 @@ back to stable. #> Pester = @{ - Version = 'latest' - Parameters = @{ - AllowPrerelease = $true - } + Version = '6.0.0' } Plaster = 'latest' diff --git a/tests/Unit/DSC_SqlAG.Tests.ps1 b/tests/Unit/DSC_SqlAG.Tests.ps1 index c9e9735e7..44944a8e9 100644 --- a/tests/Unit/DSC_SqlAG.Tests.ps1 +++ b/tests/Unit/DSC_SqlAG.Tests.ps1 @@ -506,6 +506,12 @@ Describe 'SqlAG\Set-TargetResource' { Mock -CommandName Connect-SQL -MockWith $mockConnectSqlServer2 -ParameterFilter { $ServerName -eq 'Server2' } + # Pester 6 no longer falls through to the real command when no -ParameterFilter + # matches. When the availability group's primary replica is the connected server, + # the real Get-PrimaryReplicaServerObject returns the passed-in ServerObject, so + # add a default mock that reproduces that for any unmatched call. + Mock -CommandName Get-PrimaryReplicaServerObject -MockWith { $ServerObject } + Mock -CommandName Get-PrimaryReplicaServerObject -MockWith $mockConnectSqlServer1 -ParameterFilter { $AvailabilityGroup.PrimaryReplicaServerName -eq 'Server1' } diff --git a/tests/Unit/DSC_SqlDatabaseObjectPermission.Tests.ps1 b/tests/Unit/DSC_SqlDatabaseObjectPermission.Tests.ps1 index 1e9d39030..6e79fb98b 100644 --- a/tests/Unit/DSC_SqlDatabaseObjectPermission.Tests.ps1 +++ b/tests/Unit/DSC_SqlDatabaseObjectPermission.Tests.ps1 @@ -89,6 +89,14 @@ Describe 'SqlDatabaseObjectPermission\Get-TargetResource' -Tag 'Get' { } Mock -CommandName Connect-SQL -MockWith $mockConnectSQL + + # The Connect-SQL mock body builds a server with `New-Object -TypeName + # Microsoft.SqlServer.Management.Smo.Server`, which the ObjectPermissionSet + # filter in the child contexts does not match. Pester 6 no longer falls through + # to the real command, so add a forwarding default for any unmatched New-Object. + Mock -CommandName New-Object -MockWith { + & (Get-Command -Name 'New-Object' -CommandType Cmdlet) @PesterBoundParameters + } } Context 'When the system is in the desired state' { diff --git a/tests/Unit/DSC_SqlLogin.Tests.ps1 b/tests/Unit/DSC_SqlLogin.Tests.ps1 index 765e5d2a3..9de5a8c31 100644 --- a/tests/Unit/DSC_SqlLogin.Tests.ps1 +++ b/tests/Unit/DSC_SqlLogin.Tests.ps1 @@ -828,6 +828,14 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { } -PassThru -Force } + # The Connect-SQL mock body builds its object with `New-Object -TypeName Object`, + # which the SMO-typed filter below does not match. Pester 6 no longer falls + # through to the real command, so add a forwarding default that runs the real + # cmdlet for any unmatched New-Object call. + Mock -CommandName New-Object -MockWith { + & (Get-Command -Name 'New-Object' -CommandType Cmdlet) @PesterBoundParameters + } + Mock -CommandName New-Object -MockWith $mockLoginObject -ParameterFilter { $TypeName -eq 'Microsoft.SqlServer.Management.Smo.Login' } @@ -855,7 +863,9 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { } Should -Invoke -CommandName Connect-SQL -Exactly -Times 1 -Scope It - Should -Invoke -CommandName New-Object -Exactly -Times 1 -Scope It + Should -Invoke -CommandName New-Object -ParameterFilter { + $TypeName -eq 'Microsoft.SqlServer.Management.Smo.Login' + } -Exactly -Times 1 -Scope It Should -Invoke -CommandName New-SQLServerLogin -ParameterFilter { $Login.Name -eq 'Windows\Login1' } -Exactly -Times 1 -Scope It @@ -1085,6 +1095,14 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { } -PassThru -Force } + # The Connect-SQL mock body and the test's credential setup build objects + # with `New-Object` for types the SMO-typed filter below does not match. + # Pester 6 no longer falls through to the real command, so add a forwarding + # default that runs the real cmdlet for any unmatched New-Object call. + Mock -CommandName New-Object -MockWith { + & (Get-Command -Name 'New-Object' -CommandType Cmdlet) @PesterBoundParameters + } + Mock -CommandName New-Object -MockWith $mockLoginObject -ParameterFilter { $TypeName -eq 'Microsoft.SqlServer.Management.Smo.Login' } @@ -1115,7 +1133,9 @@ Describe 'SqlLogin\Set-TargetResource' -Tag 'Set' { } Should -Invoke -CommandName Connect-SQL -Exactly -Times 1 -Scope It - Should -Invoke -CommandName New-Object -Exactly -Times 1 -Scope It + Should -Invoke -CommandName New-Object -ParameterFilter { + $TypeName -eq 'Microsoft.SqlServer.Management.Smo.Login' + } -Exactly -Times 1 -Scope It Should -Invoke -CommandName New-SQLServerLogin -ParameterFilter { $Login.Name -eq 'SqlLogin1' } -Exactly -Times 1 -Scope It diff --git a/tests/Unit/DSC_SqlSetup.Tests.ps1 b/tests/Unit/DSC_SqlSetup.Tests.ps1 index 0f54eb840..299e5b2bb 100644 --- a/tests/Unit/DSC_SqlSetup.Tests.ps1 +++ b/tests/Unit/DSC_SqlSetup.Tests.ps1 @@ -234,6 +234,12 @@ Describe 'SqlSetup\Get-TargetResource' -Tag 'Get' { Mock -CommandName Get-PSDrive Mock -CommandName Get-FileVersion -MockWith $mockGetSqlMajorVersion + # Default mock so registry lookups for Names other than 'ImagePath' resolve to + # $null, matching the real function's behavior on a build agent without SQL + # installed. Pester 6 no longer calls the original command when no mock filter + # matches, so without this default those lookups would throw. + Mock -CommandName Get-RegistryPropertyValue + Mock -CommandName Get-RegistryPropertyValue -ParameterFilter { $Name -eq 'ImagePath' } -MockWith { diff --git a/tests/Unit/Private/Invoke-ReportServerSetupAction.Tests.ps1 b/tests/Unit/Private/Invoke-ReportServerSetupAction.Tests.ps1 index fd75e386a..86627b2cf 100644 --- a/tests/Unit/Private/Invoke-ReportServerSetupAction.Tests.ps1 +++ b/tests/Unit/Private/Invoke-ReportServerSetupAction.Tests.ps1 @@ -37,6 +37,13 @@ BeforeAll { $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName + # Pester 6 no longer falls through to the real command when no -ParameterFilter + # matches; add a forwarding default so unmatched Test-Path calls run the real + # cmdlet as they did under Pester 5. + Mock -CommandName Test-Path -MockWith { + & (Get-Command -Name 'Test-Path' -CommandType Cmdlet) @PesterBoundParameters + } + # Adding these mocks to handle the ValidateScript blocks Mock -CommandName Test-Path -ParameterFilter { $Path -match 'setup\.exe' diff --git a/tests/Unit/Public/Get-SqlDscConfigurationOption.Tests.ps1 b/tests/Unit/Public/Get-SqlDscConfigurationOption.Tests.ps1 index 890e1b4a8..b014a5f9f 100644 --- a/tests/Unit/Public/Get-SqlDscConfigurationOption.Tests.ps1 +++ b/tests/Unit/Public/Get-SqlDscConfigurationOption.Tests.ps1 @@ -308,6 +308,17 @@ Describe 'Get-SqlDscConfigurationOption' -Tag 'Public' { if (Get-Variable -Name 'TestServerObject' -Scope Global -ErrorAction SilentlyContinue) { Remove-Variable -Name 'TestServerObject' -Scope Global -Force } + + # Clean up global variables created in error handling tests + if (Get-Variable -Name 'BadTestServerObject' -Scope Global -ErrorAction SilentlyContinue) + { + Remove-Variable -Name 'BadTestServerObject' -Scope Global -Force + } + + if (Get-Variable -Name 'InvalidTestServerObject' -Scope Global -ErrorAction SilentlyContinue) + { + Remove-Variable -Name 'InvalidTestServerObject' -Scope Global -Force + } } It 'Should provide Name parameter completions through TabExpansion2' { @@ -408,19 +419,6 @@ Describe 'Get-SqlDscConfigurationOption' -Tag 'Public' { $completions[1].CompletionText | Should -Be "'max degree of parallelism'" } - AfterAll { - # Clean up global variables created in error handling tests - if (Get-Variable -Name 'BadTestServerObject' -Scope Global -ErrorAction SilentlyContinue) - { - Remove-Variable -Name 'BadTestServerObject' -Scope Global -Force - } - - if (Get-Variable -Name 'InvalidTestServerObject' -Scope Global -ErrorAction SilentlyContinue) - { - Remove-Variable -Name 'InvalidTestServerObject' -Scope Global -Force - } - } - It 'Should handle tab completion errors gracefully' { # Create a server object that will cause an error $badServer = [Microsoft.SqlServer.Management.Smo.Server]::CreateTypeInstance() diff --git a/tests/Unit/Public/Save-SqlDscSqlServerMediaFile.Tests.ps1 b/tests/Unit/Public/Save-SqlDscSqlServerMediaFile.Tests.ps1 index 14e004e19..65614a5f3 100644 --- a/tests/Unit/Public/Save-SqlDscSqlServerMediaFile.Tests.ps1 +++ b/tests/Unit/Public/Save-SqlDscSqlServerMediaFile.Tests.ps1 @@ -74,6 +74,13 @@ Describe 'Save-SqlDscSqlServerMediaFile' -Tag 'Public' { } BeforeAll { + # Pester 6 no longer falls through to the real command when a later + # -ParameterFilter mock doesn't match. Restore the Pester 5 behavior for + # Test-Path so unmatched calls run the real cmdlet. + Mock -CommandName Test-Path -MockWith { + & (Get-Command -Name 'Test-Path' -CommandType Cmdlet) @PesterBoundParameters + } + # Mock the Invoke-WebRequest cmdlet to prevent actual downloads during testing Mock -CommandName Invoke-WebRequest diff --git a/tests/Unit/SqlServerDsc.Common/Public/Connect-Sql.Tests.ps1 b/tests/Unit/SqlServerDsc.Common/Public/Connect-Sql.Tests.ps1 index 38d5c5b6a..7befae685 100644 --- a/tests/Unit/SqlServerDsc.Common/Public/Connect-Sql.Tests.ps1 +++ b/tests/Unit/SqlServerDsc.Common/Public/Connect-Sql.Tests.ps1 @@ -181,6 +181,14 @@ Describe 'SqlServerDsc.Common\Connect-SQL' -Tag 'ConnectSql' { $mockWinFqdnCredential = New-Object -TypeName PSCredential -ArgumentList ($mockWinFqdnCredentialUserName, $mockWinFqdnCredentialSecurePassword) Mock -CommandName Import-SqlDscPreferredModule + + # Pester 6 no longer falls through to the real command when no -ParameterFilter + # matches. The New-Object mock bodies above build their backing objects with + # `New-Object -TypeName Object`, so add a forwarding default that runs the real + # cmdlet for any New-Object call not matched by a more specific mock. + Mock -CommandName New-Object -MockWith { + & (Get-Command -Name 'New-Object' -CommandType Cmdlet) @PesterBoundParameters + } } # Skipping on Linux and macOS because they do not support Windows Authentication.