diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e90d531bd..943fcdf60e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ For older change log history see the [historic changelog](HISTORIC_CHANGELOG.md) - SqlSetup - A read only property `IsClustered` was added that can be used to determine if the instance is clustered. +- SqlServerReplication + - Add integration tests ([issue #755](https://github.com/dsccommunity/SqlServerDsc/issues/755) - SqlServerDsc.Common - The helper function `Restart-SqlService` was improved to handle Failover Clusters better. Now the SQL Server service will only be taken offline diff --git a/source/Examples/Resources/SqlServerReplication/1-ConfigureInstanceAsDistributor.ps1 b/source/Examples/Resources/SqlServerReplication/1-ConfigureInstanceAsDistributor.ps1 index 37f1840e2c..05f483bd59 100644 --- a/source/Examples/Resources/SqlServerReplication/1-ConfigureInstanceAsDistributor.ps1 +++ b/source/Examples/Resources/SqlServerReplication/1-ConfigureInstanceAsDistributor.ps1 @@ -21,6 +21,7 @@ Configuration Example InstanceName = 'MSSQLSERVER' AdminLinkCredentials = $SqlAdministratorCredential DistributorMode = 'Local' + DistributionDBName = 'Database1' WorkingDirectory = 'C:\Temp' PsDscRunAsCredential = $SqlAdministratorCredential diff --git a/tests/Integration/DSC_SqlServerReplication.Integration.Tests.ps1 b/tests/Integration/DSC_SqlServerReplication.Integration.Tests.ps1 new file mode 100644 index 0000000000..e1d21f3fcb --- /dev/null +++ b/tests/Integration/DSC_SqlServerReplication.Integration.Tests.ps1 @@ -0,0 +1,245 @@ +Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') + +if (-not (Test-BuildCategory -Type 'Integration' -Category @('Integration_SQL2016','Integration_SQL2017'))) +{ + return +} + +$script:dscModuleName = 'SqlServerDsc' +$script:dscResourceFriendlyName = 'SqlServerProtocolTcpIp' +$script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" + +try +{ + Import-Module -Name DscResource.Test -Force -ErrorAction 'Stop' +} +catch [System.IO.FileNotFoundException] +{ + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -Tasks build" first.' +} + +$script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Integration' + +try +{ + $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" + . $configFile + + Describe "$($script:dscResourceName)_Integration" { + BeforeAll { + $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" + } + + $configurationName = "$($script:dscResourceName)_AddDistributor_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.InstanceName | Should -Be $ConfigurationData.AllNodes.InstanceName + $resourceCurrentState.DistributorMode | Should -Be 'Local' + $resourceCurrentState.DistributionDBName | Should -Be 'Database1' + $resourceCurrentState.RemoteDistributor | Should -BeNullOrEmpty + $resourceCurrentState.WorkingDirectory | Should -Be 'C:\Temp' + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_RemoveDistributor_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.InstanceName | Should -Be $ConfigurationData.AllNodes.InstanceName + $resourceCurrentState.DistributorMode | Should -Be 'Local' + $resourceCurrentState.DistributionDBName | Should -BeNullOrEmpty + $resourceCurrentState.RemoteDistributor | Should -BeNullOrEmpty + $resourceCurrentState.WorkingDirectory | Should -BeNullOrEmpty + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_AddPublisher_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.InstanceName | Should -Be $ConfigurationData.AllNodes.InstanceName + $resourceCurrentState.DistributorMode | Should -Be 'Remote' + $resourceCurrentState.DistributionDBName | Should -BeNullOrEmpty + $resourceCurrentState.RemoteDistributor | Should -Be 'distsqlsrv.company.local' + $resourceCurrentState.WorkingDirectory | Should -Be 'C:\Temp' + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_RemovePublisher_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.Ensure | Should -Be 'Present' + $resourceCurrentState.InstanceName | Should -Be $ConfigurationData.AllNodes.InstanceName + $resourceCurrentState.DistributorMode | Should -Be 'Remote' + $resourceCurrentState.DistributionDBName | Should -BeNullOrEmpty + $resourceCurrentState.RemoteDistributor | Should -BeNullOrEmpty + $resourceCurrentState.WorkingDirectory | Should -BeNullOrEmpty + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + } +} +finally +{ + Restore-TestEnvironment -TestEnvironment $script:testEnvironment +} diff --git a/tests/Integration/DSC_SqlServerReplication.config.ps1 b/tests/Integration/DSC_SqlServerReplication.config.ps1 new file mode 100644 index 0000000000..2d4c4e2f88 --- /dev/null +++ b/tests/Integration/DSC_SqlServerReplication.config.ps1 @@ -0,0 +1,138 @@ +#region HEADER +# Integration Test Config Template Version: 1.2.0 +#endregion + +$configFile = [System.IO.Path]::ChangeExtension($MyInvocation.MyCommand.Path, 'json') +if (Test-Path -Path $configFile) +{ + <# + Allows reading the configuration data from a JSON file, + for real testing scenarios outside of the CI. + #> + $ConfigurationData = Get-Content -Path $configFile | ConvertFrom-Json +} +else +{ + $ConfigurationData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + + UserName = "$env:COMPUTERNAME\SqlInstall" + Password = 'P@ssw0rd1' + + InstanceName = 'DSCSQLTEST' + + CertificateFile = $env:DscPublicCertificatePath + } + ) + } +} + +<# + .SYNOPSIS + Adds the instance as a distributor. +#> +Configuration DSC_SqlServerReplication_AddDistributor_Config +{ + Import-DscResource -ModuleName 'SqlServerDsc' + + node $AllNodes.NodeName + { + SqlServerReplication 'Integration_Test' + { + Ensure = 'Present' + InstanceName = $Node.InstanceName + DistributorMode = 'Local' + DistributionDBName = 'Database1' + WorkingDirectory = 'C:\Temp' + + AdminLinkCredentials = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + + PsDscRunAsCredential = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + } + } +} + +<# + .SYNOPSIS + Removes the instance as a distributor. +#> +Configuration DSC_SqlServerReplication_RemoveDistributor_Config +{ + Import-DscResource -ModuleName 'SqlServerDsc' + + node $AllNodes.NodeName + { + SqlServerReplication 'Integration_Test' + { + Ensure = 'Absent' + InstanceName = $Node.InstanceName + DistributorMode = 'Local' + + AdminLinkCredentials = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + + PsDscRunAsCredential = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + } + } +} + +<# + .SYNOPSIS + Adds the instance as a publisher. +#> +Configuration DSC_SqlServerReplication_AddPublisher_Config +{ + Import-DscResource -ModuleName 'SqlServerDsc' + + node $AllNodes.NodeName + { + SqlServerReplication 'Integration_Test' + { + Ensure = 'Present' + InstanceName = $Node.InstanceName + DistributorMode = 'Remote' + RemoteDistributor = 'distsqlsrv.company.local' + WorkingDirectory = 'C:\Temp' + + AdminLinkCredentials = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + + PsDscRunAsCredential = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + } + } +} + +<# + .SYNOPSIS + Removes the instance as a publisher. +#> +Configuration DSC_SqlServerReplication_RemovePublisher_Config +{ + Import-DscResource -ModuleName 'SqlServerDsc' + + node $AllNodes.NodeName + { + SqlServerReplication 'Integration_Test' + { + Ensure = 'Absent' + InstanceName = $Node.InstanceName + DistributorMode = 'Remote' + + PsDscRunAsCredential = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force)) + } + } +} diff --git a/tests/Integration/README.md b/tests/Integration/README.md index d21cd5cbf0..407fd4f8e6 100644 --- a/tests/Integration/README.md +++ b/tests/Integration/README.md @@ -144,7 +144,7 @@ The integration test will leave a database for other integration tests to use. Database | Collation ---- | --- | --- +--- | --- Database1 | Finnish_Swedish_CI_AS ## SqlDatabaseDefaultLocation @@ -331,6 +331,14 @@ Name | Algorithm | Password --- | --- | --- AsymmetricKey1 | RSA_2048 | P@ssw0rd1 +## SqlServerReplication + +**Run order:** 3 + +**Depends on:** SqlDatabase + +The integration test will bot leave anything on any instance. + ## SqlScript **Run order:** 4