diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c91360dc1..8197114807 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Removed + +- BREAKING CHANGE: Removed public command `Test-SqlDscDatabase`. Use + `Test-SqlDscIsDatabase` to check existence. For property checks, use + `Test-SqlDscDatabaseProperty`. See [issue #2201](https://github.com/dsccommunity/SqlServerDsc/issues/2201). + ### Added +- Added public command `Test-SqlDscIsDatabase` to test if a database exists on a + SQL Server Database Engine instance ([issue #2201](https://github.com/dsccommunity/SqlServerDsc/issues/2201)). - Added public command `Get-SqlDscSetupLog` to retrieve SQL Server setup bootstrap logs (Summary.txt) from the most recent setup operation. This command can be used interactively for troubleshooting or within integration tests to help diagnose diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9a668d328f..b4c8d93d3f 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -336,7 +336,7 @@ stages: 'tests/Integration/Commands/ConvertFrom-SqlDscDatabasePermission.Integration.Tests.ps1' 'tests/Integration/Commands/New-SqlDscDatabase.Integration.Tests.ps1' 'tests/Integration/Commands/Set-SqlDscDatabase.Integration.Tests.ps1' - 'tests/Integration/Commands/Test-SqlDscDatabase.Integration.Tests.ps1' + 'tests/Integration/Commands/Test-SqlDscIsDatabase.Integration.Tests.ps1' 'tests/Integration/Commands/Test-SqlDscDatabaseProperty.Integration.Tests.ps1' 'tests/Integration/Commands/Get-SqlDscDatabasePermission.Integration.Tests.ps1' 'tests/Integration/Commands/Set-SqlDscDatabasePermission.Integration.Tests.ps1' diff --git a/source/Public/Test-SqlDscDatabase.ps1 b/source/Public/Test-SqlDscDatabase.ps1 deleted file mode 100644 index 9eb05fb87b..0000000000 --- a/source/Public/Test-SqlDscDatabase.ps1 +++ /dev/null @@ -1,168 +0,0 @@ -<# - .SYNOPSIS - Tests if a database on a SQL Server Database Engine instance is in the desired state. - - .DESCRIPTION - This command tests if a database on a SQL Server Database Engine instance is in the desired state. - - .PARAMETER ServerObject - Specifies current server connection object. - - .PARAMETER Name - Specifies the name of the database to test. - - .PARAMETER Ensure - When set to 'Present', the database must exist. - When set to 'Absent', the database must not exist. - - .PARAMETER Collation - The name of the SQL collation that the database should have. - - .PARAMETER CompatibilityLevel - The version of the SQL compatibility level that the database should have. - - .PARAMETER RecoveryModel - The recovery model that the database should have. - - .PARAMETER OwnerName - Specifies the name of the login that should be the owner of the database. - - .PARAMETER Refresh - Specifies that the **ServerObject**'s databases should be refreshed before - testing the database state. This is helpful when databases could have been - modified outside of the **ServerObject**, for example through T-SQL. But - on instances with a large amount of databases it might be better to make - sure the **ServerObject** is recent enough. - - .EXAMPLE - $serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance' - $serverObject | Test-SqlDscDatabase -Name 'MyDatabase' -Ensure 'Present' - - Tests if the database named **MyDatabase** exists. - - .EXAMPLE - $serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance' - $serverObject | Test-SqlDscDatabase -Name 'MyDatabase' -Ensure 'Present' -RecoveryModel 'Simple' -OwnerName 'sa' - - Tests if the database named **MyDatabase** exists and has the specified recovery model and owner. - - .OUTPUTS - `[System.Boolean]` -#> -function Test-SqlDscDatabase -{ - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the rule does not yet support parsing the code when a parameter type is not available. The ScriptAnalyzer rule UseSyntacticallyCorrectExamples will always error in the editor due to https://github.com/indented-automation/Indented.ScriptAnalyzerRules/issues/8.')] - [OutputType([System.Boolean])] - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] - [Microsoft.SqlServer.Management.Smo.Server] - $ServerObject, - - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Name, - - [Parameter()] - [ValidateSet('Present', 'Absent')] - [ValidateNotNullOrEmpty()] - [System.String] - $Ensure = 'Present', - - [Parameter()] - [ValidateNotNullOrEmpty()] - [System.String] - $Collation, - - [Parameter()] - [ValidateSet('Version80', 'Version90', 'Version100', 'Version110', 'Version120', 'Version130', 'Version140', 'Version150', 'Version160')] - [System.String] - $CompatibilityLevel, - - [Parameter()] - [ValidateSet('Simple', 'Full', 'BulkLogged')] - [System.String] - $RecoveryModel, - - [Parameter()] - [System.String] - $OwnerName, - - [Parameter()] - [System.Management.Automation.SwitchParameter] - $Refresh - ) - - process - { - if ($Refresh.IsPresent) - { - # Refresh the server object's databases collection - $ServerObject.Databases.Refresh() - } - - Write-Verbose -Message ($script:localizedData.Database_Test -f $Name, $ServerObject.InstanceName) - - $isDatabaseInDesiredState = $true - - # Check database exists - $sqlDatabaseObject = $ServerObject.Databases[$Name] - - switch ($Ensure) - { - 'Absent' - { - if ($sqlDatabaseObject) - { - Write-Verbose -Message ($script:localizedData.Database_NotInDesiredStateAbsent -f $Name) - $isDatabaseInDesiredState = $false - } - else - { - Write-Verbose -Message ($script:localizedData.Database_InDesiredStateAbsent -f $Name) - } - } - - 'Present' - { - if (-not $sqlDatabaseObject) - { - Write-Verbose -Message ($script:localizedData.Database_NotInDesiredStatePresent -f $Name) - $isDatabaseInDesiredState = $false - } - else - { - Write-Verbose -Message ($script:localizedData.Database_InDesiredStatePresent -f $Name) - - if ($PSBoundParameters.ContainsKey('Collation') -and $sqlDatabaseObject.Collation -ne $Collation) - { - Write-Verbose -Message ($script:localizedData.Database_CollationWrong -f $Name, $sqlDatabaseObject.Collation, $Collation) - $isDatabaseInDesiredState = $false - } - - if ($PSBoundParameters.ContainsKey('CompatibilityLevel') -and $sqlDatabaseObject.CompatibilityLevel -ne $CompatibilityLevel) - { - Write-Verbose -Message ($script:localizedData.Database_CompatibilityLevelWrong -f $Name, $sqlDatabaseObject.CompatibilityLevel, $CompatibilityLevel) - $isDatabaseInDesiredState = $false - } - - if ($PSBoundParameters.ContainsKey('RecoveryModel') -and $sqlDatabaseObject.RecoveryModel -ne $RecoveryModel) - { - Write-Verbose -Message ($script:localizedData.Database_RecoveryModelWrong -f $Name, $sqlDatabaseObject.RecoveryModel, $RecoveryModel) - $isDatabaseInDesiredState = $false - } - - if ($PSBoundParameters.ContainsKey('OwnerName') -and $sqlDatabaseObject.Owner -ne $OwnerName) - { - Write-Verbose -Message ($script:localizedData.Database_OwnerNameWrong -f $Name, $sqlDatabaseObject.Owner, $OwnerName) - $isDatabaseInDesiredState = $false - } - } - } - } - - return $isDatabaseInDesiredState - } -} diff --git a/source/Public/Test-SqlDscDatabaseProperty.ps1 b/source/Public/Test-SqlDscDatabaseProperty.ps1 index e7a91140ac..ad8f157f45 100644 --- a/source/Public/Test-SqlDscDatabaseProperty.ps1 +++ b/source/Public/Test-SqlDscDatabaseProperty.ps1 @@ -26,6 +26,16 @@ .PARAMETER DatabaseObject Specifies the database object to test properties for (from Get-SqlDscDatabase). + .PARAMETER Refresh + Specifies that the **ServerObject**'s databases should be refreshed before + trying to get the database object. This is helpful when databases could have been + modified outside of the **ServerObject**, for example through T-SQL. But + on instances with a large amount of databases it might be better to make + sure the **ServerObject** is recent enough. + + This parameter is only used when testing properties using **ServerObject** and + **Name** parameters. + .PARAMETER Collation Specifies the default collation for the database. @@ -505,6 +515,10 @@ function Test-SqlDscDatabaseProperty [System.String] $Name, + [Parameter(ParameterSetName = 'ServerObjectSet')] + [System.Management.Automation.SwitchParameter] + $Refresh, + [Parameter(ParameterSetName = 'DatabaseObjectSet', Mandatory = $true, ValueFromPipeline = $true)] [Microsoft.SqlServer.Management.Smo.Database] $DatabaseObject, @@ -1109,7 +1123,7 @@ function Test-SqlDscDatabaseProperty $previousErrorActionPreference = $ErrorActionPreference $ErrorActionPreference = 'Stop' - $sqlDatabaseObject = $ServerObject | Get-SqlDscDatabase -Name $Name -ErrorAction 'Stop' + $sqlDatabaseObject = $ServerObject | Get-SqlDscDatabase -Name $Name -Refresh:$Refresh -ErrorAction 'Stop' $ErrorActionPreference = $previousErrorActionPreference } @@ -1127,7 +1141,7 @@ function Test-SqlDscDatabaseProperty $boundParameters = Remove-CommonParameter -Hashtable $PSBoundParameters # Remove function-specific parameters - foreach ($parameterToRemove in @('ServerObject', 'Name', 'DatabaseObject')) + foreach ($parameterToRemove in @('ServerObject', 'Name', 'DatabaseObject', 'Refresh')) { $boundParameters.Remove($parameterToRemove) } diff --git a/source/Public/Test-SqlDscIsDatabase.ps1 b/source/Public/Test-SqlDscIsDatabase.ps1 new file mode 100644 index 0000000000..2d39b1cfe2 --- /dev/null +++ b/source/Public/Test-SqlDscIsDatabase.ps1 @@ -0,0 +1,81 @@ +<# + .SYNOPSIS + Tests if a database exists on a SQL Server Database Engine instance. + + .DESCRIPTION + This command tests if a database exists on a SQL Server Database Engine instance. + + .PARAMETER ServerObject + Specifies current server connection object. + + .PARAMETER Name + Specifies the name of the database to test for existence. + + .PARAMETER Refresh + Specifies that the **ServerObject**'s databases should be refreshed before + testing the database existence. This is helpful when databases could have been + modified outside of the **ServerObject**, for example through T-SQL. But + on instances with a large amount of databases it might be better to make + sure the **ServerObject** is recent enough. + + .EXAMPLE + $serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance' + $serverObject | Test-SqlDscIsDatabase -Name 'MyDatabase' + + Tests if the database named **MyDatabase** exists on the instance. + + .EXAMPLE + $serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance' + Test-SqlDscIsDatabase -ServerObject $serverObject -Name 'MyDatabase' -Refresh + + Tests if the database named **MyDatabase** exists on the instance, refreshing + the server object's databases collection first. + + .OUTPUTS + `[System.Boolean]` + + Returns `$true` if the target object is a database; otherwise, `$false`. + + .INPUTS + `[Microsoft.SqlServer.Management.Smo.Server]` + + The server object can be provided via the pipeline to **ServerObject**. +#> +function Test-SqlDscIsDatabase +{ + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the rule does not yet support parsing the code when a parameter type is not available. The ScriptAnalyzer rule UseSyntacticallyCorrectExamples will always error in the editor due to https://github.com/indented-automation/Indented.ScriptAnalyzerRules/issues/8.')] + [OutputType([System.Boolean])] + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Microsoft.SqlServer.Management.Smo.Server] + $ServerObject, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Name, + + [Parameter()] + [System.Management.Automation.SwitchParameter] + $Refresh + ) + + process + { + Write-Verbose -Message ($script:localizedData.IsDatabase_Test -f $Name, $ServerObject.InstanceName) + + # Check if database exists using Get-SqlDscDatabase + $sqlDatabaseObject = Get-SqlDscDatabase -ServerObject $ServerObject -Name $Name -Refresh:$Refresh -ErrorAction 'SilentlyContinue' + + if ($sqlDatabaseObject) + { + return $true + } + else + { + return $false + } + } +} diff --git a/source/en-US/SqlServerDsc.strings.psd1 b/source/en-US/SqlServerDsc.strings.psd1 index f934639d13..cbc25a6a2c 100644 --- a/source/en-US/SqlServerDsc.strings.psd1 +++ b/source/en-US/SqlServerDsc.strings.psd1 @@ -387,16 +387,8 @@ ConvertFrom-StringData @' Database_Remove_ShouldProcessCaption = Remove database from instance Remove_SqlDscDatabase_NotFound = Database '{0}' was not found. - ## Test-SqlDscDatabase - Database_Test = Testing the state of database '{0}' on instance '{1}'. - Database_InDesiredStatePresent = Database '{0}' is present and in desired state. - Database_InDesiredStateAbsent = Database '{0}' is absent as expected. - Database_NotInDesiredStatePresent = Expected the database '{0}' to be present, but it was absent. - Database_NotInDesiredStateAbsent = Expected the database '{0}' to be absent, but it was present. - Database_CollationWrong = The database '{0}' exists and has the collation '{1}', but expected it to have the collation '{2}'. - Database_CompatibilityLevelWrong = The database '{0}' exists and has the compatibility level '{1}', but expected it to have the compatibility level '{2}'. - Database_RecoveryModelWrong = The database '{0}' exists and has the recovery model '{1}', but expected it to have the recovery model '{2}'. - Database_OwnerNameWrong = The database '{0}' exists and has the owner '{1}', but expected it to have the owner '{2}'. + ## Test-SqlDscIsDatabase + IsDatabase_Test = Testing if database '{0}' exists on instance '{1}'. (TSID0001) ## Test-SqlDscDatabaseProperty DatabaseProperty_TestingProperties = Testing properties of database '{0}' on instance '{1}'. (TSDDP0001) diff --git a/tests/Integration/Commands/README.md b/tests/Integration/Commands/README.md index 8b32058254..d64ae6980b 100644 --- a/tests/Integration/Commands/README.md +++ b/tests/Integration/Commands/README.md @@ -92,7 +92,8 @@ Get-SqlDscDatabase | 4 | 1 (Install-SqlDscServer), 0 (Prerequisites) | DSCSQLTES ConvertFrom-SqlDscDatabasePermission | 4 | 0 (Prerequisites) | - | - New-SqlDscDatabase | 4 | 1 (Install-SqlDscServer), 0 (Prerequisites) | DSCSQLTEST | SqlDscIntegrationTestDatabase_Persistent database Set-SqlDscDatabase | 4 | 1 (Install-SqlDscServer), 0 (Prerequisites) | DSCSQLTEST | - -Test-SqlDscDatabase | 4 | 1 (Install-SqlDscServer), 0 (Prerequisites) | DSCSQLTEST | - +Test-SqlDscIsDatabase | 4 | 1 (Install-SqlDscServer), 0 (Prerequisites) | DSCSQLTEST | - +Test-SqlDscDatabaseProperty | 4 | 1 (Install-SqlDscServer), 0 (Prerequisites) | DSCSQLTEST | - Get-SqlDscDatabasePermission | 4 | 1 (Install-SqlDscServer), 0 (Prerequisites) | DSCSQLTEST | Test database, Test user ConvertTo-SqlDscDatabasePermission | 4 | 1 (Install-SqlDscServer), 0 (Prerequisites) | DSCSQLTEST | - Set-SqlDscDatabasePermission | 4 | 4 (New-SqlDscLogin), 1 (Install-SqlDscServer), 0 (Prerequisites) | DSCSQLTEST | - diff --git a/tests/Integration/Commands/Test-SqlDscDatabase.Integration.Tests.ps1 b/tests/Integration/Commands/Test-SqlDscDatabase.Integration.Tests.ps1 deleted file mode 100644 index 0f73093962..0000000000 --- a/tests/Integration/Commands/Test-SqlDscDatabase.Integration.Tests.ps1 +++ /dev/null @@ -1,98 +0,0 @@ -[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] -param () - -BeforeDiscovery { - try - { - if (-not (Get-Module -Name 'DscResource.Test')) - { - # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task. - if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) - { - # Redirect all streams to $null, except the error stream (stream 2) - & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null - } - - # If the dependencies have not been resolved, this will throw an error. - Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' - } - } - catch [System.IO.FileNotFoundException] - { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks noop" first.' - } -} - -BeforeAll { - $script:moduleName = 'SqlServerDsc' - - Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' -} - -Describe 'Test-SqlDscDatabase' -Tag @('Integration_SQL2017', 'Integration_SQL2019', 'Integration_SQL2022') { - BeforeAll { - $script:mockInstanceName = 'DSCSQLTEST' - $script:mockComputerName = Get-ComputerName - - $mockSqlAdministratorUserName = 'SqlAdmin' # Using computer name as NetBIOS name throw exception. - $mockSqlAdministratorPassword = ConvertTo-SecureString -String 'P@ssw0rd1' -AsPlainText -Force - - $script:mockSqlAdminCredential = [System.Management.Automation.PSCredential]::new($mockSqlAdministratorUserName, $mockSqlAdministratorPassword) - - $script:serverObject = Connect-SqlDscDatabaseEngine -InstanceName $script:mockInstanceName -Credential $script:mockSqlAdminCredential -ErrorAction 'Stop' - } - - AfterAll { - Disconnect-SqlDscDatabaseEngine -ServerObject $script:serverObject -ErrorAction 'Stop' - } - - Context 'When testing database presence' { - It 'Should return true when system database exists and Ensure is Present' { - $result = Test-SqlDscDatabase -ServerObject $script:serverObject -Name 'master' -Ensure 'Present' -ErrorAction 'Stop' - - $result | Should -BeTrue - } - - It 'Should return false when non-existent database is tested with Ensure Present' { - $result = Test-SqlDscDatabase -ServerObject $script:serverObject -Name 'NonExistentDatabase' -Ensure 'Present' -ErrorAction 'Stop' - - $result | Should -BeFalse - } - - It 'Should return false when system database exists and Ensure is Absent' { - $result = Test-SqlDscDatabase -ServerObject $script:serverObject -Name 'master' -Ensure 'Absent' -ErrorAction 'Stop' - - $result | Should -BeFalse - } - - It 'Should return true when non-existent database is tested with Ensure Absent' { - $result = Test-SqlDscDatabase -ServerObject $script:serverObject -Name 'NonExistentDatabase' -Ensure 'Absent' -ErrorAction 'Stop' - - $result | Should -BeTrue - } - } - - Context 'When testing database properties' { - It 'Should return true when testing master database with correct recovery model' { - # Master database typically has Simple recovery model - $result = Test-SqlDscDatabase -ServerObject $script:serverObject -Name 'master' -Ensure 'Present' -RecoveryModel 'Simple' -ErrorAction 'Stop' - - $result | Should -BeTrue - } - - It 'Should return false when testing master database with incorrect recovery model' { - # Master database typically has Simple recovery model, so Full should return false - $result = Test-SqlDscDatabase -ServerObject $script:serverObject -Name 'master' -Ensure 'Present' -RecoveryModel 'Full' -ErrorAction 'Stop' - - $result | Should -BeFalse - } - } - - Context 'When using the Refresh parameter' { - It 'Should refresh the database collection and test database presence' { - $result = Test-SqlDscDatabase -ServerObject $script:serverObject -Name 'master' -Ensure 'Present' -Refresh -ErrorAction 'Stop' - - $result | Should -BeTrue - } - } -} diff --git a/tests/Integration/Commands/Test-SqlDscDatabaseProperty.Integration.Tests.ps1 b/tests/Integration/Commands/Test-SqlDscDatabaseProperty.Integration.Tests.ps1 index 8a2c176ce2..472da8e3ec 100644 --- a/tests/Integration/Commands/Test-SqlDscDatabaseProperty.Integration.Tests.ps1 +++ b/tests/Integration/Commands/Test-SqlDscDatabaseProperty.Integration.Tests.ps1 @@ -350,11 +350,16 @@ Describe 'Test-SqlDscDatabaseProperty' -Tag @('Integration_SQL2017', 'Integratio $actualRecoveryModel = $testDb.RecoveryModel.ToString() $actualOwner = $testDb.Owner - $result = Test-SqlDscDatabaseProperty -ServerObject $script:serverObject -Name 'SqlDscIntegrationTestDatabase_Persistent' ` - -Collation $actualCollation ` - -RecoveryModel $actualRecoveryModel ` - -Owner $actualOwner ` - -ErrorAction 'Stop' + $testParameters = @{ + ServerObject = $script:serverObject + Name = 'SqlDscIntegrationTestDatabase_Persistent' + Collation = $actualCollation + RecoveryModel = $actualRecoveryModel + Owner = $actualOwner + ErrorAction = 'Stop' + } + + $result = Test-SqlDscDatabaseProperty @testParameters $result | Should -BeTrue } @@ -375,11 +380,16 @@ Describe 'Test-SqlDscDatabaseProperty' -Tag @('Integration_SQL2017', 'Integratio 'Simple' } - $result = Test-SqlDscDatabaseProperty -ServerObject $script:serverObject -Name 'SqlDscIntegrationTestDatabase_Persistent' ` - -Collation $actualCollation ` - -RecoveryModel $wrongRecoveryModel ` - -Owner $actualOwner ` - -ErrorAction 'Stop' + $testParameters = @{ + ServerObject = $script:serverObject + Name = 'SqlDscIntegrationTestDatabase_Persistent' + Collation = $actualCollation + RecoveryModel = $wrongRecoveryModel + Owner = $actualOwner + ErrorAction = 'Stop' + } + + $result = Test-SqlDscDatabaseProperty @testParameters $result | Should -BeFalse } diff --git a/tests/Integration/Commands/Test-SqlDscIsDatabase.Integration.Tests.ps1 b/tests/Integration/Commands/Test-SqlDscIsDatabase.Integration.Tests.ps1 new file mode 100644 index 0000000000..917a4bd7a3 --- /dev/null +++ b/tests/Integration/Commands/Test-SqlDscIsDatabase.Integration.Tests.ps1 @@ -0,0 +1,138 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies have not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks noop" first.' + } +} + +BeforeAll { + $script:moduleName = 'SqlServerDsc' + + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' +} + +Describe 'Test-SqlDscIsDatabase' -Tag @('Integration_SQL2017', 'Integration_SQL2019', 'Integration_SQL2022') { + BeforeAll { + $script:mockInstanceName = 'DSCSQLTEST' + + $mockSqlAdministratorUserName = 'SqlAdmin' + $mockSqlAdministratorPassword = ConvertTo-SecureString -String 'P@ssw0rd1' -AsPlainText -Force + + $script:mockSqlAdminCredential = [System.Management.Automation.PSCredential]::new($mockSqlAdministratorUserName, $mockSqlAdministratorPassword) + + $script:serverObject = Connect-SqlDscDatabaseEngine -InstanceName $script:mockInstanceName -Credential $script:mockSqlAdminCredential -ErrorAction 'Stop' + + # Use existing persistent database for testing + $script:testDatabaseName = 'SqlDscIntegrationTestDatabase_Persistent' + } + + AfterAll { + Disconnect-SqlDscDatabaseEngine -ServerObject $script:serverObject -ErrorAction 'Stop' + } + + Context 'When testing database existence using ServerObject parameter set' { + It 'Should return True when database exists' { + # Test with persistent integration test database + $result = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name $script:testDatabaseName -ErrorAction 'Stop' + + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue + } + + It 'Should return False when database does not exist' { + # Test with non-existent database + $result = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name 'NonExistentDatabase' -ErrorAction 'Stop' + + $result | Should -BeOfType [System.Boolean] + $result | Should -BeFalse + } + + It 'Should accept ServerObject from pipeline' { + # Test using pipeline + $result = $script:serverObject | Test-SqlDscIsDatabase -Name $script:testDatabaseName -ErrorAction 'Stop' + + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue + } + + It 'Should return True for system database master' { + # Test with built-in master database + $result = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name 'master' -ErrorAction 'Stop' + + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue + } + + It 'Should return True for system database msdb' { + # Test with built-in msdb database + $result = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name 'msdb' -ErrorAction 'Stop' + + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue + } + + It 'Should return True for system database model' { + # Test with built-in model database + $result = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name 'model' -ErrorAction 'Stop' + + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue + } + + It 'Should return True for system database tempdb' { + # Test with built-in tempdb database + $result = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name 'tempdb' -ErrorAction 'Stop' + + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue + } + } + + Context 'When testing case sensitivity' { + It 'Should handle case differences correctly' { + # Test with different case - SQL Server database names are case-insensitive by default + $result1 = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name $script:testDatabaseName.ToUpper() -ErrorAction 'Stop' + $result2 = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name $script:testDatabaseName.ToLower() -ErrorAction 'Stop' + + $result1 | Should -BeOfType [System.Boolean] + $result2 | Should -BeOfType [System.Boolean] + $result1 | Should -Be $result2 + } + } + + Context 'When using Refresh parameter' { + It 'Should return correct result when using Refresh switch' { + # Test with Refresh parameter + $result = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name $script:testDatabaseName -Refresh -ErrorAction 'Stop' + + $result | Should -BeOfType [System.Boolean] + $result | Should -BeTrue + } + + It 'Should return False for non-existent database when using Refresh switch' { + # Test with Refresh parameter for non-existent database + $result = Test-SqlDscIsDatabase -ServerObject $script:serverObject -Name 'NonExistentDatabase' -Refresh -ErrorAction 'Stop' + + $result | Should -BeOfType [System.Boolean] + $result | Should -BeFalse + } + } +} diff --git a/tests/Unit/Public/Test-SqlDscDatabase.Tests.ps1 b/tests/Unit/Public/Test-SqlDscDatabase.Tests.ps1 deleted file mode 100644 index 44338697c9..0000000000 --- a/tests/Unit/Public/Test-SqlDscDatabase.Tests.ps1 +++ /dev/null @@ -1,186 +0,0 @@ -[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] -param () - -BeforeDiscovery { - try - { - if (-not (Get-Module -Name 'DscResource.Test')) - { - # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task. - if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) - { - # Redirect all streams to $null, except the error stream (stream 2) - & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null - } - - # If the dependencies have not been resolved, this will throw an error. - Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' - } - } - catch [System.IO.FileNotFoundException] - { - throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks noop" first.' - } -} - -BeforeAll { - $script:dscModuleName = 'SqlServerDsc' - - $env:SqlServerDscCI = $true - - Import-Module -Name $script:dscModuleName -Force -ErrorAction 'Stop' - - # Loading mocked classes - Add-Type -Path (Join-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath '../Stubs') -ChildPath 'SMO.cs') - - $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName - $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscModuleName - $PSDefaultParameterValues['Should:ModuleName'] = $script:dscModuleName -} - -AfterAll { - $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') - $PSDefaultParameterValues.Remove('Mock:ModuleName') - $PSDefaultParameterValues.Remove('Should:ModuleName') - - # Unload the module being tested so that it doesn't impact any other tests. - Get-Module -Name $script:dscModuleName -All | Remove-Module -Force - - Remove-Item -Path 'env:SqlServerDscCI' -} - -Describe 'Test-SqlDscDatabase' -Tag 'Public' { - Context 'When testing database presence' { - BeforeAll { - $mockExistingDatabase = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Database' - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'Name' -Value 'TestDatabase' -Force - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'Collation' -Value 'SQL_Latin1_General_CP1_CI_AS' -Force - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'CompatibilityLevel' -Value 'Version150' -Force - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'RecoveryModel' -Value 'Full' -Force - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'Owner' -Value 'sa' -Force - - $mockServerObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server' - $mockServerObject | Add-Member -MemberType 'NoteProperty' -Name 'InstanceName' -Value 'TestInstance' -Force - $mockServerObject | Add-Member -MemberType 'ScriptProperty' -Name 'Databases' -Value { - return @{ - 'TestDatabase' = $mockExistingDatabase - } | Add-Member -MemberType 'ScriptMethod' -Name 'Refresh' -Value { - # Mock implementation - } -PassThru -Force - } -Force - } - - It 'Should return true when database exists and Ensure is Present' { - - $result = Test-SqlDscDatabase -ServerObject $mockServerObject -Name 'TestDatabase' -Ensure 'Present' - - $result | Should -BeTrue - } - - It 'Should return false when database does not exist and Ensure is Present' { - - $result = Test-SqlDscDatabase -ServerObject $mockServerObject -Name 'NonExistentDatabase' -Ensure 'Present' - - $result | Should -BeFalse - } - - It 'Should return false when database exists and Ensure is Absent' { - - $result = Test-SqlDscDatabase -ServerObject $mockServerObject -Name 'TestDatabase' -Ensure 'Absent' - - $result | Should -BeFalse - } - - It 'Should return true when database does not exist and Ensure is Absent' { - - $result = Test-SqlDscDatabase -ServerObject $mockServerObject -Name 'NonExistentDatabase' -Ensure 'Absent' - - $result | Should -BeTrue - } - } - - Context 'When testing database properties' { - BeforeAll { - $mockExistingDatabase = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Database' - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'Name' -Value 'TestDatabase' -Force - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'Collation' -Value 'SQL_Latin1_General_CP1_CI_AS' -Force - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'CompatibilityLevel' -Value 'Version150' -Force - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'RecoveryModel' -Value 'Full' -Force - $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'Owner' -Value 'sa' -Force - - $mockServerObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server' - $mockServerObject | Add-Member -MemberType 'NoteProperty' -Name 'InstanceName' -Value 'TestInstance' -Force - $mockServerObject | Add-Member -MemberType 'ScriptProperty' -Name 'Databases' -Value { - return @{ - 'TestDatabase' = $mockExistingDatabase - } | Add-Member -MemberType 'ScriptMethod' -Name 'Refresh' -Value { - # Mock implementation - } -PassThru -Force - } -Force - } - - It 'Should return true when all properties match' { - - $result = Test-SqlDscDatabase -ServerObject $mockServerObject -Name 'TestDatabase' -Ensure 'Present' -Collation 'SQL_Latin1_General_CP1_CI_AS' -CompatibilityLevel 'Version150' -RecoveryModel 'Full' -OwnerName 'sa' - - $result | Should -BeTrue - } - - It 'Should return false when collation does not match' { - - $result = Test-SqlDscDatabase -ServerObject $mockServerObject -Name 'TestDatabase' -Ensure 'Present' -Collation 'Different_Collation' - - $result | Should -BeFalse - } - - It 'Should return false when compatibility level does not match' { - - $result = Test-SqlDscDatabase -ServerObject $mockServerObject -Name 'TestDatabase' -Ensure 'Present' -CompatibilityLevel 'Version140' - - $result | Should -BeFalse - } - - It 'Should return false when recovery model does not match' { - - $result = Test-SqlDscDatabase -ServerObject $mockServerObject -Name 'TestDatabase' -Ensure 'Present' -RecoveryModel 'Simple' - - $result | Should -BeFalse - } - - It 'Should return false when owner does not match' { - - $result = Test-SqlDscDatabase -ServerObject $mockServerObject -Name 'TestDatabase' -Ensure 'Present' -OwnerName 'DifferentOwner' - - $result | Should -BeFalse - } - } - - Context 'Parameter validation' { - It 'Should have the correct parameters in parameter set __AllParameterSets' -ForEach @( - @{ - ExpectedParameterSetName = '__AllParameterSets' - ExpectedParameters = '[-ServerObject] [-Name] [[-Ensure] ] [[-Collation] ] [[-CompatibilityLevel] ] [[-RecoveryModel] ] [[-OwnerName] ] [-Refresh] []' - } - ) { - $result = (Get-Command -Name 'Test-SqlDscDatabase').ParameterSets | - Where-Object -FilterScript { $_.Name -eq $ExpectedParameterSetName } | - Select-Object -Property @( - @{ Name = 'ParameterSetName'; Expression = { $_.Name } }, - @{ Name = 'ParameterListAsString'; Expression = { $_.ToString() } } - ) - - $result.ParameterSetName | Should -Be $ExpectedParameterSetName - $result.ParameterListAsString | Should -Be $ExpectedParameters - } - - It 'Should have ServerObject as a mandatory parameter' { - $parameterInfo = (Get-Command -Name 'Test-SqlDscDatabase').Parameters['ServerObject'] - $parameterInfo.Attributes.Mandatory | Should -BeTrue - } - - It 'Should have Name as a mandatory parameter' { - $parameterInfo = (Get-Command -Name 'Test-SqlDscDatabase').Parameters['Name'] - $parameterInfo.Attributes.Mandatory | Should -BeTrue - } - } -} diff --git a/tests/Unit/Public/Test-SqlDscDatabaseProperty.Tests.ps1 b/tests/Unit/Public/Test-SqlDscDatabaseProperty.Tests.ps1 index 2ec25d8f67..ffb0f4f9f6 100644 --- a/tests/Unit/Public/Test-SqlDscDatabaseProperty.Tests.ps1 +++ b/tests/Unit/Public/Test-SqlDscDatabaseProperty.Tests.ps1 @@ -323,6 +323,30 @@ Describe 'Test-SqlDscDatabaseProperty' -Tag 'Public' { $result | Should -BeFalse } + + It 'Should pass Refresh parameter to Get-SqlDscDatabase when specified' { + Mock -CommandName Get-SqlDscDatabase -MockWith { + return $mockExistingDatabase + } + + Test-SqlDscDatabaseProperty -ServerObject $mockServerObject -Name 'TestDatabase' -Refresh + + Should -Invoke -CommandName Get-SqlDscDatabase -ParameterFilter { + $Refresh -eq $true + } -Exactly -Times 1 -Scope It + } + + It 'Should not pass Refresh parameter to Get-SqlDscDatabase when not specified' { + Mock -CommandName Get-SqlDscDatabase -MockWith { + return $mockExistingDatabase + } + + Test-SqlDscDatabaseProperty -ServerObject $mockServerObject -Name 'TestDatabase' + + Should -Invoke -CommandName Get-SqlDscDatabase -ParameterFilter { + -not $PSBoundParameters.ContainsKey('Refresh') + } -Exactly -Times 1 -Scope It + } } Context 'When using DatabaseObjectSet parameter set' { @@ -455,7 +479,7 @@ Describe 'Test-SqlDscDatabaseProperty' -Tag 'Public' { It 'Should have the correct parameters in parameter set ' -ForEach @( @{ ExpectedParameterSetName = 'ServerObjectSet' - ExpectedParameters = '-ServerObject -Name [-AcceleratedRecoveryEnabled ] [-ActiveDirectory ] [-AnsiNullDefault ] [-AnsiNullsEnabled ] [-AnsiPaddingEnabled ] [-AnsiWarningsEnabled ] [-ArithmeticAbortEnabled ] [-AutoClose ] [-AutoCreateIncrementalStatisticsEnabled ] [-AutoCreateStatisticsEnabled ] [-AutoShrink ] [-AutoUpdateStatisticsAsync ] [-AutoUpdateStatisticsEnabled ] [-BrokerEnabled ] [-CaseSensitive ] [-ChangeTrackingAutoCleanUp ] [-ChangeTrackingEnabled ] [-CloseCursorsOnCommitEnabled ] [-ConcatenateNullYieldsNull ] [-DatabaseOwnershipChaining ] [-DataRetentionEnabled ] [-DateCorrelationOptimization ] [-DelayedDurability ] [-EncryptionEnabled ] [-HasDatabaseEncryptionKey ] [-HasFileInCloud ] [-HasMemoryOptimizedObjects ] [-HonorBrokerPriority ] [-IsAccessible ] [-IsDatabaseSnapshot ] [-IsDatabaseSnapshotBase ] [-IsDbAccessAdmin ] [-IsDbBackupOperator ] [-IsDbDataReader ] [-IsDbDataWriter ] [-IsDbDdlAdmin ] [-IsDbDenyDataReader ] [-IsDbDenyDataWriter ] [-IsDbManager ] [-IsDbOwner ] [-IsDbSecurityAdmin ] [-IsFabricDatabase ] [-IsFullTextEnabled ] [-IsLedger ] [-IsLoginManager ] [-IsMailHost ] [-IsManagementDataWarehouse ] [-IsMaxSizeApplicable ] [-IsMirroringEnabled ] [-IsParameterizationForced ] [-IsReadCommittedSnapshotOn ] [-IsSqlDw ] [-IsSqlDwEdition ] [-IsSystemObject ] [-IsVarDecimalStorageFormatEnabled ] [-IsVarDecimalStorageFormatSupported ] [-LegacyCardinalityEstimation ] [-LegacyCardinalityEstimationForSecondary ] [-LocalCursorsDefault ] [-NestedTriggersEnabled ] [-NumericRoundAbortEnabled ] [-ParameterSniffing ] [-ParameterSniffingForSecondary ] [-QueryOptimizerHotfixes ] [-QueryOptimizerHotfixesForSecondary ] [-QuotedIdentifiersEnabled ] [-ReadOnly ] [-RecursiveTriggersEnabled ] [-RemoteDataArchiveEnabled ] [-RemoteDataArchiveUseFederatedServiceAccount ] [-TemporalHistoryRetentionEnabled ] [-TransformNoiseWords ] [-Trustworthy ] [-WarnOnRename ] [-ActiveConnections ] [-ChangeTrackingRetentionPeriod ] [-DefaultFullTextLanguage ] [-DefaultLanguage ] [-ID ] [-MaxDop ] [-MaxDopForSecondary ] [-MirroringRedoQueueMaxSize ] [-MirroringRoleSequence ] [-MirroringSafetySequence ] [-MirroringTimeout ] [-TargetRecoveryTime ] [-TwoDigitYearCutoff ] [-Version ] [-IndexSpaceUsage ] [-MaxSizeInBytes ] [-MemoryAllocatedToMemoryOptimizedObjectsInKB ] [-MemoryUsedByMemoryOptimizedObjectsInKB ] [-MirroringFailoverLogSequenceNumber ] [-PersistentVersionStoreSizeKB ] [-SpaceAvailable ] [-Size ] [-AvailabilityGroupName ] [-AzureServiceObjective ] [-CatalogCollation ] [-Collation ] [-DboLogin ] [-DefaultFileGroup ] [-DefaultFileStreamFileGroup ] [-DefaultFullTextCatalog ] [-DefaultSchema ] [-FilestreamDirectoryName ] [-MirroringPartner ] [-MirroringPartnerInstance ] [-MirroringWitness ] [-Owner ] [-PersistentVersionStoreFileGroup ] [-PrimaryFilePath ] [-RemoteDataArchiveCredential ] [-RemoteDataArchiveEndpoint ] [-RemoteDataArchiveLinkedServer ] [-RemoteDatabaseName ] [-UserName ] [-AzureEdition ] [-CreateDate ] [-LastBackupDate ] [-LastDifferentialBackupDate ] [-LastGoodCheckDbTime ] [-LastLogBackupDate ] [-DatabaseGuid ] [-MirroringID ] [-RecoveryForkGuid ] [-ServiceBrokerGuid ] [-AvailabilityDatabaseSynchronizationState ] [-ChangeTrackingRetentionPeriodUnits ] [-CompatibilityLevel ] [-ContainmentType ] [-DatabaseEngineEdition ] [-DatabaseEngineType ] [-FilestreamNonTransactedAccess ] [-LogReuseWaitStatus ] [-MirroringSafetyLevel ] [-MirroringStatus ] [-MirroringWitnessStatus ] [-PageVerify ] [-RecoveryModel ] [-ReplicationOptions ] [-SnapshotIsolationState ] [-State ] [-Status ] [-UserAccess ] []' + ExpectedParameters = '-ServerObject -Name [-Refresh] [-AcceleratedRecoveryEnabled ] [-ActiveDirectory ] [-AnsiNullDefault ] [-AnsiNullsEnabled ] [-AnsiPaddingEnabled ] [-AnsiWarningsEnabled ] [-ArithmeticAbortEnabled ] [-AutoClose ] [-AutoCreateIncrementalStatisticsEnabled ] [-AutoCreateStatisticsEnabled ] [-AutoShrink ] [-AutoUpdateStatisticsAsync ] [-AutoUpdateStatisticsEnabled ] [-BrokerEnabled ] [-CaseSensitive ] [-ChangeTrackingAutoCleanUp ] [-ChangeTrackingEnabled ] [-CloseCursorsOnCommitEnabled ] [-ConcatenateNullYieldsNull ] [-DatabaseOwnershipChaining ] [-DataRetentionEnabled ] [-DateCorrelationOptimization ] [-DelayedDurability ] [-EncryptionEnabled ] [-HasDatabaseEncryptionKey ] [-HasFileInCloud ] [-HasMemoryOptimizedObjects ] [-HonorBrokerPriority ] [-IsAccessible ] [-IsDatabaseSnapshot ] [-IsDatabaseSnapshotBase ] [-IsDbAccessAdmin ] [-IsDbBackupOperator ] [-IsDbDataReader ] [-IsDbDataWriter ] [-IsDbDdlAdmin ] [-IsDbDenyDataReader ] [-IsDbDenyDataWriter ] [-IsDbManager ] [-IsDbOwner ] [-IsDbSecurityAdmin ] [-IsFabricDatabase ] [-IsFullTextEnabled ] [-IsLedger ] [-IsLoginManager ] [-IsMailHost ] [-IsManagementDataWarehouse ] [-IsMaxSizeApplicable ] [-IsMirroringEnabled ] [-IsParameterizationForced ] [-IsReadCommittedSnapshotOn ] [-IsSqlDw ] [-IsSqlDwEdition ] [-IsSystemObject ] [-IsVarDecimalStorageFormatEnabled ] [-IsVarDecimalStorageFormatSupported ] [-LegacyCardinalityEstimation ] [-LegacyCardinalityEstimationForSecondary ] [-LocalCursorsDefault ] [-NestedTriggersEnabled ] [-NumericRoundAbortEnabled ] [-ParameterSniffing ] [-ParameterSniffingForSecondary ] [-QueryOptimizerHotfixes ] [-QueryOptimizerHotfixesForSecondary ] [-QuotedIdentifiersEnabled ] [-ReadOnly ] [-RecursiveTriggersEnabled ] [-RemoteDataArchiveEnabled ] [-RemoteDataArchiveUseFederatedServiceAccount ] [-TemporalHistoryRetentionEnabled ] [-TransformNoiseWords ] [-Trustworthy ] [-WarnOnRename ] [-ActiveConnections ] [-ChangeTrackingRetentionPeriod ] [-DefaultFullTextLanguage ] [-DefaultLanguage ] [-ID ] [-MaxDop ] [-MaxDopForSecondary ] [-MirroringRedoQueueMaxSize ] [-MirroringRoleSequence ] [-MirroringSafetySequence ] [-MirroringTimeout ] [-TargetRecoveryTime ] [-TwoDigitYearCutoff ] [-Version ] [-IndexSpaceUsage ] [-MaxSizeInBytes ] [-MemoryAllocatedToMemoryOptimizedObjectsInKB ] [-MemoryUsedByMemoryOptimizedObjectsInKB ] [-MirroringFailoverLogSequenceNumber ] [-PersistentVersionStoreSizeKB ] [-SpaceAvailable ] [-Size ] [-AvailabilityGroupName ] [-AzureServiceObjective ] [-CatalogCollation ] [-Collation ] [-DboLogin ] [-DefaultFileGroup ] [-DefaultFileStreamFileGroup ] [-DefaultFullTextCatalog ] [-DefaultSchema ] [-FilestreamDirectoryName ] [-MirroringPartner ] [-MirroringPartnerInstance ] [-MirroringWitness ] [-Owner ] [-PersistentVersionStoreFileGroup ] [-PrimaryFilePath ] [-RemoteDataArchiveCredential ] [-RemoteDataArchiveEndpoint ] [-RemoteDataArchiveLinkedServer ] [-RemoteDatabaseName ] [-UserName ] [-AzureEdition ] [-CreateDate ] [-LastBackupDate ] [-LastDifferentialBackupDate ] [-LastGoodCheckDbTime ] [-LastLogBackupDate ] [-DatabaseGuid ] [-MirroringID ] [-RecoveryForkGuid ] [-ServiceBrokerGuid ] [-AvailabilityDatabaseSynchronizationState ] [-ChangeTrackingRetentionPeriodUnits ] [-CompatibilityLevel ] [-ContainmentType ] [-DatabaseEngineEdition ] [-DatabaseEngineType ] [-FilestreamNonTransactedAccess ] [-LogReuseWaitStatus ] [-MirroringSafetyLevel ] [-MirroringStatus ] [-MirroringWitnessStatus ] [-PageVerify ] [-RecoveryModel ] [-ReplicationOptions ] [-SnapshotIsolationState ] [-State ] [-Status ] [-UserAccess ] []' } @{ ExpectedParameterSetName = 'DatabaseObjectSet' diff --git a/tests/Unit/Public/Test-SqlDscIsDatabase.Tests.ps1 b/tests/Unit/Public/Test-SqlDscIsDatabase.Tests.ps1 new file mode 100644 index 0000000000..5713618bc6 --- /dev/null +++ b/tests/Unit/Public/Test-SqlDscIsDatabase.Tests.ps1 @@ -0,0 +1,157 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies have been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies have not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks noop" first.' + } +} + +BeforeAll { + $script:dscModuleName = 'SqlServerDsc' + + $env:SqlServerDscCI = $true + + Import-Module -Name $script:dscModuleName -Force -ErrorAction 'Stop' + + # Loading mocked classes + Add-Type -Path (Join-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath '../Stubs') -ChildPath 'SMO.cs') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscModuleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscModuleName -All | Remove-Module -Force + + Remove-Item -Path 'env:SqlServerDscCI' +} + +Describe 'Test-SqlDscIsDatabase' -Tag 'Public' { + Context 'When testing if database exists' { + BeforeAll { + $mockExistingDatabase = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Database' + $mockExistingDatabase | Add-Member -MemberType 'NoteProperty' -Name 'Name' -Value 'TestDatabase' -Force + + $mockServerObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server' + $mockServerObject | Add-Member -MemberType 'NoteProperty' -Name 'InstanceName' -Value 'TestInstance' -Force + } + + It 'Should return true when database exists' { + Mock -CommandName Get-SqlDscDatabase -MockWith { + return $mockExistingDatabase + } + + $result = Test-SqlDscIsDatabase -ServerObject $mockServerObject -Name 'TestDatabase' + + $result | Should -BeTrue + + Should -Invoke -CommandName Get-SqlDscDatabase -ParameterFilter { + $ServerObject -eq $mockServerObject -and $Name -eq 'TestDatabase' -and $Refresh -eq $false + } -Exactly -Times 1 -Scope It + } + + It 'Should return false when database does not exist' { + Mock -CommandName Get-SqlDscDatabase -MockWith { + return $null + } + + $result = Test-SqlDscIsDatabase -ServerObject $mockServerObject -Name 'NonExistentDatabase' + + $result | Should -BeFalse + + Should -Invoke -CommandName Get-SqlDscDatabase -ParameterFilter { + $ServerObject -eq $mockServerObject -and $Name -eq 'NonExistentDatabase' -and $Refresh -eq $false + } -Exactly -Times 1 -Scope It + } + + It 'Should call Refresh when Refresh parameter is specified' { + Mock -CommandName Get-SqlDscDatabase -MockWith { + return $mockExistingDatabase + } + + $result = Test-SqlDscIsDatabase -ServerObject $mockServerObject -Name 'TestDatabase' -Refresh + + $result | Should -BeTrue + + Should -Invoke -CommandName Get-SqlDscDatabase -ParameterFilter { + $ServerObject -eq $mockServerObject -and $Name -eq 'TestDatabase' -and $Refresh -eq $true + } -Exactly -Times 1 -Scope It + } + + It 'Should support pipeline input' { + Mock -CommandName Get-SqlDscDatabase -MockWith { + return $mockExistingDatabase + } + + $result = $mockServerObject | Test-SqlDscIsDatabase -Name 'TestDatabase' + + $result | Should -BeTrue + + Should -Invoke -CommandName Get-SqlDscDatabase -ParameterFilter { + $ServerObject -eq $mockServerObject -and $Name -eq 'TestDatabase' -and $Refresh -eq $false + } -Exactly -Times 1 -Scope It + } + } + + Context 'Parameter validation' { + It 'Should have the correct parameters in parameter set __AllParameterSets' -ForEach @( + @{ + ExpectedParameterSetName = '__AllParameterSets' + ExpectedParameters = '[-ServerObject] [-Name] [-Refresh] []' + } + ) { + $result = (Get-Command -Name 'Test-SqlDscIsDatabase').ParameterSets | + Where-Object -FilterScript { $_.Name -eq $ExpectedParameterSetName } | + Select-Object -Property @( + @{ Name = 'ParameterSetName'; Expression = { $_.Name } }, + @{ Name = 'ParameterListAsString'; Expression = { $_.ToString() } } + ) + + $result.ParameterSetName | Should -Be $ExpectedParameterSetName + $result.ParameterListAsString | Should -Be $ExpectedParameters + } + + It 'Should have ServerObject as a mandatory parameter' { + $parameterInfo = (Get-Command -Name 'Test-SqlDscIsDatabase').Parameters['ServerObject'] + $parameterInfo.Attributes.Mandatory | Should -BeTrue + } + + It 'Should have Name as a mandatory parameter' { + $parameterInfo = (Get-Command -Name 'Test-SqlDscIsDatabase').Parameters['Name'] + $parameterInfo.Attributes.Mandatory | Should -BeTrue + } + + It 'Should have Refresh as an optional parameter' { + $parameterInfo = (Get-Command -Name 'Test-SqlDscIsDatabase').Parameters['Refresh'] + $parameterInfo.Attributes.Mandatory | Should -BeFalse + } + + It 'Should have ServerObject accept pipeline input' { + $parameterInfo = (Get-Command -Name 'Test-SqlDscIsDatabase').Parameters['ServerObject'] + $parameterInfo.Attributes.ValueFromPipeline | Should -BeTrue + } + } +}