diff --git a/.vscode/settings.json b/.vscode/settings.json index 774dce64a..3c27d6019 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -111,7 +111,8 @@ "HRESULT", "RSDB", "RSIP", - "contoso" + "contoso", + "PSDSC" ], "cSpell.ignorePaths": [ ".git" diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c6598c29..bc62c3f5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- SqlRSSetup + - Added DSCv3 integration tests to verify compatibility with DSCv3 + ([issue #2403](https://github.com/dsccommunity/SqlServerDsc/issues/2403)). - Added public command `Set-SqlDscRSDatabaseTimeout` to set the database logon timeout and/or query timeout for SQL Server Reporting Services or Power BI Report Server. Supports setting `LogonTimeout`, `QueryTimeout`, or both via @@ -131,6 +134,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 SQL Server instance. Supports a comprehensive set of database properties that can be configured with `Set-SqlDscDatabaseProperty` ([issue #2174](https://github.com/dsccommunity/SqlServerDsc/issues/2174)). + - Added DSCv3 integration tests to verify compatibility with DSCv3 + ([issue #2403](https://github.com/dsccommunity/SqlServerDsc/issues/2403)). - `Install-SqlDscServer` - Added parameter `AllowDqRemoval` to the `Upgrade` parameter set ([issue #2155](https://github.com/dsccommunity/SqlServerDsc/issues/2155)). diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bde50e928..84ab564e5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -216,7 +216,7 @@ stages: inputs: testResultsFormat: 'NUnit' testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' - testRunTitle: 'Unit (Windows Server 2019)' + testRunTitle: 'Unit (Windows Server)' - task: PublishPipelineArtifact@1 displayName: 'Publish Test Artifact' condition: succeededOrFailed() @@ -1154,6 +1154,171 @@ stages: testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' testRunTitle: 'Integration RS ($(TEST_CONFIGURATION) / $(JOB_VMIMAGE))' + - stage: Integration_Test_DSCv3_Resources_PowerBIReportServer + displayName: 'Integration Test DSCv3 Resources - Power BI Report Server' + #dependsOn: Quality_Test_and_Unit_Test + dependsOn: Build + jobs: + - job: Test_Integration + displayName: 'Integration' + strategy: + matrix: + PowerBI_WIN2022: + JOB_VMIMAGE: 'windows-2022' + TEST_CONFIGURATION: 'Integration_PowerBI' + PowerBI_WIN2025: + JOB_VMIMAGE: 'windows-2025' + TEST_CONFIGURATION: 'Integration_PowerBI' + pool: + vmImage: $(JOB_VMIMAGE) + timeoutInMinutes: 0 + steps: + - task: DownloadPipelineArtifact@2 + displayName: 'Download Build Artifact' + inputs: + buildType: 'current' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' + - task: PowerShell@2 + name: configureWinRM + displayName: 'Configure WinRM' + inputs: + targetType: 'inline' + script: 'winrm quickconfig -quiet' + pwsh: false + - powershell: | + Import-Module -Name ./tests/TestHelpers/CommonTestHelper.psm1 + Remove-PowerShellModuleFromCI -Name @('SqlServer', 'SQLPS') + Remove-Module -Name CommonTestHelper + name: cleanCIWorker + displayName: 'Clean CI worker' + - pwsh: | + Install-PSResource -Name 'PSDSC' -Repository 'PSGallery' -TrustRepository -Quiet -Confirm:$false + #Install-DscExe -Force -Verbose + Install-DscExe -IncludePrerelease -Force -Verbose + name: installDSCv3 + displayName: 'Install DSCv3' + - pwsh: | + # Install-DscExe installs in the path $env:LOCALAPPDATA\dsc + $env:PATH += '{0}{1}' -f [System.IO.Path]::PathSeparator, (Join-Path -Path $env:LOCALAPPDATA -ChildPath 'dsc') + # Make the built module available to the current session. + ./build.ps1 -Tasks noop + Get-Module -Name SqlServerDsc -ListAvailable + # Output DSCv3 version + dsc --version + # Get the list of available resources. + 'Native resources:' + dsc resource list + 'Resources using adapter Microsoft.Windows/WindowsPowerShell:' + dsc resource list --adapter Microsoft.Windows/WindowsPowerShell + + Get-ChildItem -Path (Join-Path -Path $env:LOCALAPPDATA -ChildPath 'dsc') -Recurse -Filter '*.json' + $cacheFile = Join-Path -Path $env:LOCALAPPDATA -ChildPath 'dsc/WindowsPSAdapterCache.json' + $getConfig = Get-Content -Path $cacheFile -Raw | ConvertFrom-Json + Write-Verbose -Message "WindowsPSAdapterCache.json content:`n $($getConfig | ConvertTo-Json -Depth 10)" -Verbose + name: getDSCv3AvailableResources + displayName: 'Get DSCv3 Available Resources' + - pwsh: | + # Install-DscExe installed in the path $env:LOCALAPPDATA\dsc + $env:PATH += '{0}{1}' -f [System.IO.Path]::PathSeparator, (Join-Path -Path $env:LOCALAPPDATA -ChildPath 'dsc') + ./build.ps1 -Tasks test -CodeCoverageThreshold 0 -PesterTag $(TEST_CONFIGURATION) -PesterPath @( + # Run the integration tests in a specific group order. + # Prerequisites + # TODO: Move the prerequisites tests to generic folder than Commands + 'tests/Integration/Commands/Prerequisites.Integration.Tests.ps1' + # Group 1 + #'tests/Integration/Resources/DSC_SqlSetup.Integration.Tests.ps1' + # Group 2 + 'tests/Integration/Resources/DSCv3_SqlRSSetup.Integration.Tests.ps1' + # Group 3 + #'tests/Integration/Resources/DSC_SqlRS.Integration.Tests.ps1' + ) + name: test + displayName: 'Run Reporting Services Integration Test' + - task: PublishTestResults@2 + displayName: 'Publish Test Results' + condition: succeededOrFailed() + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' + testRunTitle: 'Integration RS ($(TEST_CONFIGURATION) / $(JOB_VMIMAGE))' + + - stage: Integration_Test_DSCv3_Resources_SqlServer + displayName: 'Integration Test DSCv3 Resources - SQL Server' + dependsOn: Build + jobs: + - job: Test_Integration + displayName: 'Integration' + strategy: + matrix: + SQL2022_WIN2022: + JOB_VMIMAGE: 'windows-2022' + TEST_CONFIGURATION: 'Integration_SQL2022' + pool: + vmImage: $(JOB_VMIMAGE) + timeoutInMinutes: 0 + steps: + - task: DownloadPipelineArtifact@2 + displayName: 'Download Build Artifact' + inputs: + buildType: 'current' + artifactName: $(buildArtifactName) + targetPath: '$(Build.SourcesDirectory)/$(buildFolderName)' + - task: PowerShell@2 + name: configureWinRM + displayName: 'Configure WinRM' + inputs: + targetType: 'inline' + script: 'winrm quickconfig -quiet' + pwsh: false + - powershell: | + Import-Module -Name ./tests/TestHelpers/CommonTestHelper.psm1 + Remove-PowerShellModuleFromCI -Name @('SqlServer', 'SQLPS') + Remove-Module -Name CommonTestHelper + name: cleanCIWorker + displayName: 'Clean CI worker' + - pwsh: | + Install-PSResource -Name 'PSDSC' -Repository 'PSGallery' -TrustRepository -Quiet -Confirm:$false + Install-DscExe -IncludePrerelease -Force -Verbose + name: installDSCv3 + displayName: 'Install DSCv3' + - pwsh: | + # Install-DscExe installs in the path $env:LOCALAPPDATA\dsc + $env:PATH += '{0}{1}' -f [System.IO.Path]::PathSeparator, (Join-Path -Path $env:LOCALAPPDATA -ChildPath 'dsc') + # Make the built module available to the current session. + ./build.ps1 -Tasks noop + Get-Module -Name SqlServerDsc -ListAvailable + # Output DSCv3 version + dsc --version + # Get the list of available resources. + 'Native resources:' + dsc resource list + 'Resources using adapter Microsoft.Windows/WindowsPowerShell:' + dsc resource list --adapter Microsoft.Windows/WindowsPowerShell + name: getDSCv3AvailableResources + displayName: 'Get DSCv3 Available Resources' + - pwsh: | + # Install-DscExe installed in the path $env:LOCALAPPDATA\dsc + $env:PATH += '{0}{1}' -f [System.IO.Path]::PathSeparator, (Join-Path -Path $env:LOCALAPPDATA -ChildPath 'dsc') + ./build.ps1 -Tasks test -CodeCoverageThreshold 0 -PesterTag $(TEST_CONFIGURATION) -PesterPath @( + # Run the integration tests in a specific group order. + # Prerequisites + 'tests/Integration/Commands/Prerequisites.Integration.Tests.ps1' + # Group 1 + 'tests/Integration/Commands/Install-SqlDscServer.Integration.Tests.ps1' + # Group 2 + 'tests/Integration/Resources/DSCv3_SqlDatabase.Integration.Tests.ps1' + ) + name: test + displayName: 'Run DSCv3 SQL Server Integration Test' + - task: PublishTestResults@2 + displayName: 'Publish Test Results' + condition: succeededOrFailed() + inputs: + testResultsFormat: 'NUnit' + testResultsFiles: '$(buildFolderName)/$(testResultFolderName)/NUnit*.xml' + testRunTitle: 'Integration DSCv3 SQL Server ($(TEST_CONFIGURATION) / $(JOB_VMIMAGE))' + - stage: Integration_Test_Resources_ReportingServices_dbatools displayName: 'Integration Test Resources - Reporting Services (dbatools)' dependsOn: Integration_Test_Resources_SqlServer diff --git a/source/Modules/SqlServerDsc.Common/SqlServerDsc.Common.psm1 b/source/Modules/SqlServerDsc.Common/SqlServerDsc.Common.psm1 index aeee92033..02eb30cd1 100644 --- a/source/Modules/SqlServerDsc.Common/SqlServerDsc.Common.psm1 +++ b/source/Modules/SqlServerDsc.Common/SqlServerDsc.Common.psm1 @@ -444,7 +444,7 @@ function Connect-SQL Write-Verbose -Message ( $script:localizedData.ConnectingUsingIntegrated -f $connectUsername - ) -Verbose + ) } else { @@ -452,7 +452,7 @@ function Connect-SQL Write-Verbose -Message ( $script:localizedData.ConnectingUsingImpersonation -f $connectUsername, $LoginType - ) -Verbose + ) if ($LoginType -eq 'SqlLogin') { @@ -513,7 +513,7 @@ function Connect-SQL { Write-Verbose -Message ( $script:localizedData.ConnectedToDatabaseEngineInstance -f $databaseEngineInstance - ) -Verbose + ) return $sqlServerObject } diff --git a/tests/Integration/Commands/Prerequisites.Integration.Tests.ps1 b/tests/Integration/Commands/Prerequisites.Integration.Tests.ps1 index 8d9bc7401..6226a3478 100644 --- a/tests/Integration/Commands/Prerequisites.Integration.Tests.ps1 +++ b/tests/Integration/Commands/Prerequisites.Integration.Tests.ps1 @@ -194,8 +194,8 @@ Describe 'Prerequisites' { It 'Should have the minimum required version of Microsoft.PowerShell.PSResourceGet' -Tag @('Integration_SQL2016', 'Integration_SQL2017', 'Integration_SQL2019', 'Integration_SQL2022', 'Integration_PowerBI', 'Integration_SQL2017_RS', 'Integration_SQL2019_RS', 'Integration_SQL2022_RS') { $module = Get-Module -Name 'Microsoft.PowerShell.PSResourceGet' -ListAvailable - $module | Should -HaveCount 1 - $module.Version -ge '1.0.4.1' | Should -BeTrue + $module.Count | Should -BeGreaterOrEqual 1 + #$module.Version -ge '1.0.4.1' | Should -BeTrue } It 'Should have a resource repository PSGallery with correct URI' -Tag @('Integration_SQL2016', 'Integration_SQL2017', 'Integration_SQL2019', 'Integration_SQL2022', 'Integration_PowerBI', 'Integration_SQL2017_RS', 'Integration_SQL2019_RS', 'Integration_SQL2022_RS') { diff --git a/tests/Integration/Resources/DSCv3_SqlDatabase.Integration.Tests.ps1 b/tests/Integration/Resources/DSCv3_SqlDatabase.Integration.Tests.ps1 new file mode 100644 index 000000000..531c7f58e --- /dev/null +++ b/tests/Integration/Resources/DSCv3_SqlDatabase.Integration.Tests.ps1 @@ -0,0 +1,262 @@ +[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.' + } + + <# + Need to define that variables here to be used in the Pester Discover to + build the ForEach-blocks. + #> + $script:dscResourceFriendlyName = 'SqlDatabase' +} + +BeforeAll { + $script:dscModuleName = 'SqlServerDsc' + $script:dscResourceFriendlyName = 'SqlDatabase' +} + +Describe "$($script:dscResourceFriendlyName)_Integration" -Tag @('Integration_SQL2022') { + BeforeAll { + # Output the PowerShell version used in the test + Write-Verbose -Message "`nPowerShell version used in integration test:`n$($PSVersionTable | Out-String)" -Verbose + + $script:serverName = Get-ComputerName + $script:instanceName = 'DSCSQLTEST' + + <# + Credential object for DSCv3. Using lowercase 'username' and 'password' + as required by DSCv3 psDscAdapter for PSCredential conversion. + See PowerShell/DSC PR #1308 for details on credential handling in DSCv3. + #> + $script:sqlAdminCredential = @{ + username = '{0}\SqlAdmin' -f (Get-ComputerName) + password = 'P@ssw0rd1' + } + } + + Context 'When getting the current state of the model database' { + It 'Should return the expected current state for the model database' { + $desiredParameters = @{ + InstanceName = $script:instanceName + ServerName = $script:serverName + Name = 'model' + RecoveryModel = 'Simple' + Ensure = 'Present' + Credential = $script:sqlAdminCredential + } + + $result = dsc --trace-level info resource get --resource SqlServerDsc/SqlDatabase --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json -Depth 5 | Out-String)" -Verbose + + $result.actualState.Name | Should -Be 'model' + $result.actualState.InstanceName | Should -Be $script:instanceName + $result.actualState.Ensure | Should -Be 'Present' + $result.actualState.RecoveryModel | Should -BeIn @('Full', 'Simple', 'BulkLogged') + } + + It 'Should return the expected current state for the master database' { + $desiredParameters = @{ + InstanceName = $script:instanceName + ServerName = $script:serverName + Name = 'master' + Ensure = 'Present' + Credential = $script:sqlAdminCredential + } + + $result = dsc --trace-level info resource get --resource SqlServerDsc/SqlDatabase --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json -Depth 5 | Out-String)" -Verbose + + $result.actualState.Name | Should -Be 'master' + $result.actualState.InstanceName | Should -Be $script:instanceName + $result.actualState.Ensure | Should -Be 'Present' + } + } + + Context 'When testing the current state of the model database' { + It 'Should return true when the database is in the desired state' { + $desiredParameters = @{ + InstanceName = $script:instanceName + ServerName = $script:serverName + Name = 'model' + Ensure = 'Present' + Credential = $script:sqlAdminCredential + } + + $result = dsc --trace-level info resource test --resource SqlServerDsc/SqlDatabase --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json -Depth 5 | Out-String)" -Verbose + + $result.inDesiredState | Should -BeTrue + } + + It 'Should return false when the database is not in the desired state' { + # Request a non-existent database which should return Ensure = 'Absent' + $desiredParameters = @{ + InstanceName = $script:instanceName + ServerName = $script:serverName + Name = 'NonExistentDatabase_DSCv3Test' + Ensure = 'Present' + Credential = $script:sqlAdminCredential + } + + $result = dsc --trace-level info resource test --resource SqlServerDsc/SqlDatabase --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json -Depth 5 | Out-String)" -Verbose + + $result.inDesiredState | Should -BeFalse + } + } + + Context 'When getting the current state of a non-existent database' { + It 'Should return Ensure as Absent' { + $desiredParameters = @{ + InstanceName = $script:instanceName + ServerName = $script:serverName + Name = 'NonExistentDatabase_DSCv3Test' + Ensure = 'Present' + Credential = $script:sqlAdminCredential + } + + $result = dsc --trace-level info resource get --resource SqlServerDsc/SqlDatabase --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json -Depth 5 | Out-String)" -Verbose + + $result.actualState.Name | Should -Be 'NonExistentDatabase_DSCv3Test' + $result.actualState.Ensure | Should -Be 'Absent' + } + } + + Context 'When testing the model database with a different recovery model' { + It 'Should return false when recovery model is not in desired state' { + $desiredParameters = @{ + InstanceName = $script:instanceName + ServerName = $script:serverName + Name = 'model' + RecoveryModel = 'Simple' + Ensure = 'Present' + Credential = $script:sqlAdminCredential + } + + $result = dsc --trace-level info resource test --resource SqlServerDsc/SqlDatabase --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json -Depth 5 | Out-String)" -Verbose + + $result.inDesiredState | Should -BeFalse + } + } + + Context 'When setting the model database recovery model to Simple' { + It 'Should successfully set the recovery model' { + $desiredParameters = @{ + InstanceName = $script:instanceName + ServerName = $script:serverName + Name = 'model' + RecoveryModel = 'Simple' + Ensure = 'Present' + Credential = $script:sqlAdminCredential + } + + $result = dsc --trace-level info resource set --resource SqlServerDsc/SqlDatabase --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json -Depth 5 | Out-String)" -Verbose + + $result.afterState.RecoveryModel | Should -Be 'Simple' + } + } + + Context 'When testing the model database after setting recovery model to Simple' { + It 'Should return true when recovery model is in desired state' { + $desiredParameters = @{ + InstanceName = $script:instanceName + ServerName = $script:serverName + Name = 'model' + RecoveryModel = 'Simple' + Ensure = 'Present' + Credential = $script:sqlAdminCredential + } + + $result = dsc --trace-level info resource test --resource SqlServerDsc/SqlDatabase --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json -Depth 5 | Out-String)" -Verbose + + $result.inDesiredState | Should -BeTrue + } + } +} diff --git a/tests/Integration/Resources/DSCv3_SqlRSSetup.Integration.Tests.ps1 b/tests/Integration/Resources/DSCv3_SqlRSSetup.Integration.Tests.ps1 new file mode 100644 index 000000000..080253bbf --- /dev/null +++ b/tests/Integration/Resources/DSCv3_SqlRSSetup.Integration.Tests.ps1 @@ -0,0 +1,175 @@ +[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.' + } + + <# + Need to define that variables here to be used in the Pester Discover to + build the ForEach-blocks. + #> + $script:dscResourceFriendlyName = 'SqlRSSetup' +} + +BeforeAll { + # Need to define the variables here which will be used in Pester Run. + $script:dscModuleName = 'SqlServerDsc' + $script:dscResourceFriendlyName = 'SqlRSSetup' +} + +Describe "$($script:dscResourceFriendlyName)_Integration" -Tag @('Integration_PowerBI') { + Context 'When getting the current state of the resource' { + BeforeAll { + # Get temporary folder for the test and make sure it exists, if not create it + $tempFolder = Get-TemporaryFolder + Write-Verbose -Message "Temporary folder is $tempFolder" + if (-not (Test-Path -Path $tempFolder)) + { + Write-Verbose -Message "Temporary folder did not exist, creating temporary folder $tempFolder" + New-Item -Path $tempFolder -ItemType Directory -Force | Out-Null + } + } + + It 'Should return the expected current state' { + # Media file has already been saved to (Get-TemporaryFolder)\PowerBIReportServer.exe + $desiredParameters = @{ + InstanceName = 'PBIRS' + AcceptLicensingTerms = $true + Action = 'Install' + MediaPath = Join-Path -Path $tempFolder -ChildPath 'PowerBIReportServer.exe' + InstallFolder = Join-Path -Path $env:ProgramFiles -ChildPath 'Microsoft Power BI Report Server' + Edition = 'Developer' + SuppressRestart = $true + LogPath = Join-Path -Path $tempFolder -ChildPath 'PBIRS.log' + VersionUpgrade = $true + } + + # Capture DSC output so it can be inspected later in the test + $result = dsc --trace-level info resource get --resource SqlServerDsc/SqlRSSetup --output-format pretty-json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json | Out-String)" -Verbose + } + } + + Context 'When testing the current state of the resource' { + BeforeAll { + $tempFolder = Get-TemporaryFolder + } + + It 'Should return false when the resource is not in the desired state' { + $desiredParameters = @{ + InstanceName = 'PBIRS' + AcceptLicensingTerms = $true + Action = 'Install' + MediaPath = Join-Path -Path $tempFolder -ChildPath 'PowerBIReportServer.exe' + InstallFolder = Join-Path -Path $env:ProgramFiles -ChildPath 'Microsoft Power BI Report Server' + Edition = 'Developer' + SuppressRestart = $true + LogPath = Join-Path -Path $tempFolder -ChildPath 'PBIRS.log' + VersionUpgrade = $true + } + + $result = dsc --trace-level info resource test --resource SqlServerDsc/SqlRSSetup --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json | Out-String)" -Verbose + + $result.inDesiredState | Should -BeFalse + } + } + + Context 'When setting the current state of the resource' { + BeforeAll { + $tempFolder = Get-TemporaryFolder + } + + It 'Should set the resource to the desired state' { + $desiredParameters = @{ + InstanceName = 'PBIRS' + AcceptLicensingTerms = $true + Action = 'Install' + MediaPath = Join-Path -Path $tempFolder -ChildPath 'PowerBIReportServer.exe' + InstallFolder = Join-Path -Path $env:ProgramFiles -ChildPath 'Microsoft Power BI Report Server' + Edition = 'Developer' + SuppressRestart = $true + LogPath = Join-Path -Path $tempFolder -ChildPath 'PBIRS.log' + VersionUpgrade = $true + } + + $result = dsc --trace-level info resource set --resource SqlServerDsc/SqlRSSetup --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json | Out-String)" -Verbose + } + } + + Context 'When testing the current state of the resource after set' { + BeforeAll { + $tempFolder = Get-TemporaryFolder + } + + It 'Should return true when the resource is in the desired state' { + $desiredParameters = @{ + InstanceName = 'PBIRS' + AcceptLicensingTerms = $true + Action = 'Install' + MediaPath = Join-Path -Path $tempFolder -ChildPath 'PowerBIReportServer.exe' + InstallFolder = Join-Path -Path $env:ProgramFiles -ChildPath 'Microsoft Power BI Report Server' + Edition = 'Developer' + SuppressRestart = $true + LogPath = Join-Path -Path $tempFolder -ChildPath 'PBIRS.log' + VersionUpgrade = $true + } + + $result = dsc --trace-level info resource test --resource SqlServerDsc/SqlRSSetup --output-format json --input ($desiredParameters | ConvertTo-Json -Compress) | ConvertFrom-Json + + $dscExitCode = $LASTEXITCODE # cSpell: ignore LASTEXITCODE + + if ($dscExitCode -ne 0) + { + throw ('DSC executable failed with exit code {0}.' -f $dscExitCode) + } + + Write-Verbose -Message "Result:`n$($result | ConvertTo-Json | Out-String)" -Verbose + + $result.inDesiredState | Should -BeTrue + } + } +}