Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SqlServerDsc: Initial integration tests for commands #2028

Merged
merged 41 commits into from
May 11, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
d27bbcc
More integ test and commands
johlju May 9, 2024
f5ff618
Fix changelog
johlju May 9, 2024
bb2308b
Fix Save-SqlDscSqlServerMedia
johlju May 9, 2024
d6e38c3
Remove unnecessary code
johlju May 9, 2024
3dd2803
Update tests
johlju May 9, 2024
6114dfb
Fix tests
johlju May 9, 2024
c8be949
Update integ tests
johlju May 9, 2024
29759cb
Fix parameter
johlju May 9, 2024
1f565a1
Fix integ tests
johlju May 9, 2024
f2fe9a8
Fix integ test
johlju May 9, 2024
3b7344b
Fix integ test
johlju May 9, 2024
f6e722d
Fix integ test
johlju May 9, 2024
ae720d5
Fix integ test
johlju May 9, 2024
6498e98
Fix account name
johlju May 9, 2024
6036f58
Fix integ test
johlju May 9, 2024
912cdf7
Fix formatting
johlju May 9, 2024
3de6a47
Fix integ test
johlju May 9, 2024
548dcf4
Fix `Invoke-SetupAction`
johlju May 10, 2024
4ce2ecf
Fix ErrorAction for all calls to Invoke-SetupAction
johlju May 10, 2024
34e08ff
Fix README.md
johlju May 10, 2024
7155f24
Fix integ test
johlju May 10, 2024
93f9866
Fix integ test
johlju May 10, 2024
a39ef4e
Fix integ test
johlju May 10, 2024
069a447
Fix integ test + unit test + localization
johlju May 10, 2024
740f7ab
Fix command name to be singular noun
johlju May 10, 2024
227a694
Fix integ test
johlju May 10, 2024
b14c9a0
Fix integ test
johlju May 10, 2024
7e96de8
Fix remoting
johlju May 11, 2024
33fbc1a
Fix missing brace
johlju May 11, 2024
915572f
Fix missed computer name
johlju May 11, 2024
b51de3d
Fix WInRM
johlju May 11, 2024
932f4bf
Fix integ test
johlju May 11, 2024
916c87d
Fix integ test
johlju May 11, 2024
5e63487
Fix integ test
johlju May 11, 2024
e7e6429
Fix integ test
johlju May 11, 2024
80dabbc
Revert test
johlju May 11, 2024
020f3c4
Fix integ test
johlju May 11, 2024
e431fa4
Fix integ test
johlju May 11, 2024
b1dbddd
Improve Save-SqlDscSqlServerMediaFile
johlju May 11, 2024
bef25b9
Fix unit test
johlju May 11, 2024
5385af0
Fix unit tests
johlju May 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- SqlServerDsc
- Added build tasks to generate Wiki documentation for public commands.
- Initial integration tests for commands.
- SqlDatabaseMail
- Added the parameter `UseDefaultCredentials` to control use of the DatabaseEngine
service account for SMTP server authentication.
Expand Down
3 changes: 2 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -244,9 +244,10 @@ stages:
- powershell: |
./build.ps1 -Tasks test -CodeCoverageThreshold 0 -PesterTag $(TEST_CONFIGURATION) -PesterPath @(
# Run the integration tests in a specific group order.
# Group 0
'tests/Integration/Commands/Prerequisites.Integration.Tests.ps1'
# Group 1
'tests/Integration/Commands/Install-SqlDscServer.Integration.Tests.ps1'
# Group 2
#'tests/Integration/Commands/Install-SqlDscReportingServices.Integration.Tests.ps1'
)
name: test
Expand Down
4 changes: 2 additions & 2 deletions source/Modules/SqlServerDsc.Common/SqlServerDsc.Common.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -569,9 +569,9 @@ function Connect-SQL
$sqlConnectionContext.Connect()

<#
The addition of the ConnetTimeout property to the ConnectionContext will force the
The addition of the ConnectTimeout property to the ConnectionContext will force the
Connect() method to block until successful. THe SMO object's Status property may not
report 'Online' immediately eventhough the Connect() was successful. The loop is to
report 'Online' immediately even though the Connect() was successful. The loop is to
ensure the SMO's Status property was been updated.
#>
$sleepInSeconds = 2
Expand Down
219 changes: 219 additions & 0 deletions source/Public/Save-SqlDscSqlServerMedia.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
<#
.SYNOPSIS
Downloads SQL Server media from a provided URL and saves the downloaded
media file to the specified file path

.DESCRIPTION
The Save-SqlDscSqlServerMedia function downloads SQL Server media from a
provided URL and saves the downloaded media file to the specified file path.

If the URL ends with ".exe", it is treated as an executable that downloads
an ISO. If it doesn't, it is treated as a direct link to an ISO.

The function also prints the SHA1 hash of the downloaded file.

.PARAMETER MediaUrl
The URL of the SQL Server media to download.

.PARAMETER DestinationPath
The file path where the downloaded media file should be saved.

.PARAMETER FileName
The file name of the downloaded media file. Defaults to media.iso if not
provided.

.PARAMETER Language
The language parameter specifies the language of the downloaded iso. This
parameter is only used when the provided URL is an executable file. Defaults
to 'en-US' if not provided.

.PARAMETER Quiet
Disables verbose progress output during the download process.

.PARAMETER Force
Forces the download of the media file even if the file already exists at the
specified destination path.

.EXAMPLE
Save-SqlDscSqlServerMedia -MediaUrl 'https://download.microsoft.com/download/c/c/9/cc9c6797-383c-4b24-8920-dc057c1de9d3/SQL2022-SSEI-Dev.exe' -DestinationPath 'C:\path\to\destination'

This downloads the SQL Server 2022 media and saves it to the specified destination path.

.EXAMPLE
Save-SqlDscSqlServerMedia -MediaUrl 'https://download.microsoft.com/download/d/a/2/da259851-b941-459d-989c-54a18a5d44dd/SQL2019-SSEI-Dev.exe' -DestinationPath 'C:\path\to\destination'

This downloads the SQL Server 2019 media and saves it to the specified destination path.

.EXAMPLE
Save-SqlDscSqlServerMedia -MediaUrl 'https://download.microsoft.com/download/E/F/2/EF23C21D-7860-4F05-88CE-39AA114B014B/SQLServer2017-x64-ENU.iso' -DestinationPath 'C:\path\to\destination'

This downloads the SQL Server 2017 media and saves it to the specified destination path.

.EXAMPLE
Save-SqlDscSqlServerMedia -MediaUrl 'https://download.microsoft.com/download/9/0/7/907AD35F-9F9C-43A5-9789-52470555DB90/ENU/SQLServer2016SP1-FullSlipstream-x64-ENU.iso' -DestinationPath 'C:\path\to\destination'

This downloads the SQL Server 2016 media and saves it to the specified destination path.
#>
function Save-SqlDscSqlServerMedia
{
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
[OutputType([System.IO.FileInfo])]
param
(
[Parameter(Mandatory = $true)]
[System.String]
$MediaUrl,

[Parameter(Mandatory = $true)]
[System.IO.FileInfo]
[ValidateScript({Test-Path $_ -PathType 'Container'})]
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
$DestinationPath,

[Parameter()]
[System.String]
$FileName = 'media.iso',

[Parameter()]
# Supported by SQL Server version 2019 and 2022.
[ValidateSet('zh-CN', 'zh-TW', 'en-US', 'fr-FR', 'de-DE', 'it-IT', 'ja-JP', 'ko-KR', 'pt-BR', 'ru-RU', 'es-ES')]
[System.String]
$Language = 'en-US',

[Parameter()]
[System.Management.Automation.SwitchParameter]
$Quiet,

[Parameter()]
[System.Management.Automation.SwitchParameter]
$Force
)

if ((Get-Item -Path "$DestinationPath/*.iso" -Force).Count -gt 0)
{
$auditAlreadyPresentMessage = $script:localizedData.SqlServerMedia_Save_InvalidDestinationFolder

$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
$auditAlreadyPresentMessage,
'SSDSSM0001', # cspell: disable-line
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$DestinationPath
)
)
}

$destinationFilePath = Join-Path -Path $DestinationPath -ChildPath $FileName

if ((Test-Path -Path $destinationFilePath) -and (-not $Force))
{
$verboseDescriptionMessage = $script:localizedData.SqlServerMedia_Save_ShouldProcessVerboseDescription -f $destinationFilePath
$verboseWarningMessage = $script:localizedData.qlServerMedia_Save_ShouldProcessVerboseWarning -f $destinationFilePath
$captionMessage = $script:localizedData.qlServerMedia_Save_ShouldProcessCaption

if (-not ($PSCmdlet.ShouldProcess($verboseDescriptionMessage, $verboseWarningMessage, $captionMessage)))
{
return
}

Remove-Item -Path $destinationFilePath -Force
}

Write-Verbose -Message "Downloading SQL Server media to '$destinationFilePath'"

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$isExecutable = $false

if ($MediaUrl -match '\.exe$')
{
Write-Verbose -Message 'Provided URL is an executable file. Downloading the executable file.'

$isExecutable = $true

# Change the file extension of the destination file path to .exe
$destinationExecutableFilePath = [System.IO.Path]::ChangeExtension($destinationFilePath, 'exe')

$downloadedFilePath = $destinationExecutableFilePath
}
else
{
Write-Verbose -Message 'Provided URL is a direct link to an ISO file. Downloading the ISO file.'

$downloadedFilePath = $destinationFilePath
}

if ($Quiet.IsPresent)
{
<#
By switching to 'SilentlyContinue' it removes the progress bar of
Invoke-WebRequest and should also theoretically increase the download
speed.
#>
$previousProgressPreference = $ProgressPreference
$ProgressPreference = 'SilentlyContinue'
}

# Download the URL content.
Invoke-WebRequest -Uri $MediaUrl -OutFile $downloadedFilePath | Out-Null

if ($Quiet.IsPresent)
{
# Revert the progress preference back to the previous value.
$ProgressPreference = $previousProgressPreference
}

if ($isExecutable)
{
Write-Verbose -Message 'Provided URL was an executable file. Using executable to download the media file.'

$executableArguments = @(
'/Quiet'
)

if ($VerbosePreference -eq 'SilentlyContinue')
{
$executableArguments += @(
'/HideProgressBar'
)
}
else
{
$executableArguments += @(
'/Verbose'
)
}

$executableArguments += @(
'/Action=Download',
"/Language=$Language",
'/MediaType=ISO',
"/MediaPath=$destinationPath"
)

$startProcessArgumentList = $executableArguments -join ' '

# Download ISO media using the downloaded executable.
Start-Process -FilePath $destinationExecutableFilePath -ArgumentList $startProcessArgumentList -Wait

Write-Verbose -Message 'Removing the downloaded executable file.'

# Remove the downloaded executable.
Remove-Item -Path $destinationExecutableFilePath -Force

# Get all the iso files in the destination path and if there are more than one throw an error.
$isoFile = Get-Item -Path "$DestinationPath/*.iso" -Force

if ($isoFile.Count -gt 1)
{
# TODO: Fix to Write-Error
throw 'More than one iso file found in the destination path. Cannot determine which was downloaded.'
Fixed Show fixed Hide fixed
}

Write-Verbose -Message 'Renaming the downloaded iso file from ''{0}'' to ''{1}''' -f $isoFile.Name, $FileName

# Rename the iso file in the destination path.
Rename-Item -Path $isoFile.FullName -NewName $FileName -Force
}

return (Get-Item -Path $destinationFilePath)
}
9 changes: 8 additions & 1 deletion source/en-US/SqlServerDsc.strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ ConvertFrom-StringData @'
## Get-SqlDscPreferredModule
PreferredModule_ModuleVersionFound = Preferred module '{0}' with version '{1}' found.
PreferredModule_ModuleNotFound = No preferred PowerShell module was found.
PreferredModule_ModuleVersionNotFound = No preferred Powershell module with version '{0}' was found.
PreferredModule_ModuleVersionNotFound = No preferred Powershell module with version '{0}' was found.

## Import-SqlDscPreferredModule
PreferredModule_ImportedModule = Imported PowerShell module '{0}' with version '{1}' from path '{2}'.
Expand Down Expand Up @@ -182,4 +182,11 @@ PreferredModule_ModuleVersionNotFound = No preferred Powershell module with vers

## Get-SqlDscConfigurationOption
ConfigurationOption_Get_Missing = There is no configuration option with the name '{0}'.

## Save-SqlDscSqlServerMedia
SqlServerMedia_Save_ShouldProcessVerboseDescription = The existing destination file '{0}' already exists and will be replaced.
SqlServerMedia_Save_ShouldProcessVerboseWarning = Are you sure you want to replace existing file '{0}'?
# This string shall not end with full stop (.) since it is used as a title of ShouldProcess messages.
SqlServerMedia_Save_ShouldProcessCaption = Replace existing file
SqlServerMedia_Save_InvalidDestinationFolder = One or more files with the .iso extension was found in the destination path. Please choose another destination folder.
'@
92 changes: 92 additions & 0 deletions tests/Integration/Commands/Prerequisites.Integration.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
[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 has 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' 2>&1 4>&1 5>&1 6>&1 > $null
}

# If the dependencies has 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 build" first.'
}
}

Describe 'Prerequisites' -Tag @('Integration_SQL2016', 'Integration_SQL2017', 'Integration_SQL2019', 'Integration_SQL2022') {
Context 'Create required local Windows users' {
BeforeAll {
$password = ConvertTo-SecureString -String 'P@ssw0rd1' -AsPlainText -Force
}

It 'Creates SqlInstall user' {
$user = New-LocalUser -Name 'SqlInstall' -Password $password -FullName 'SQL Install User' -Description 'User for SQL installation.'

$user.Name | Should -Be 'SqlInstall'
(Get-LocalUser -Name 'SqlInstall').Name | Should -Be 'SqlInstall'
}

It 'Creates SqlAdmin user' {
$user = New-LocalUser -Name 'SqlAdmin' -Password $password -FullName 'SQL Admin User' -Description 'User for SQL administration.'

$user.Name | Should -Be 'SqlAdmin'
(Get-LocalUser -Name 'SqlAdmin').Name | Should -Be 'SqlAdmin'
}
}

Context 'Create required local Windows service accounts' {
BeforeAll {
$password = ConvertTo-SecureString -String 'yig-C^Equ3' -AsPlainText -Force
}

It 'Creates svc-SqlPrimary user' {
$user = New-LocalUser -Name 'svc-SqlPrimary' -Password $password2 -FullName 'svc-SqlPrimary' -Description 'Runs the SQL Server service.'

$user.Name | Should -Be 'svc-SqlPrimary'
(Get-LocalUser -Name 'svc-SqlPrimary').Name | Should -Be 'svc-SqlPrimary'
}

It 'Creates svc-SqlAgentPri user' {
$user = New-LocalUser -Name 'svc-SqlAgentPri' -Password $password2 -FullName 'svc-SqlAgentPri' -Description 'Runs the SQL Server Agent service.'

$user.Name | Should -Be 'svc-SqlAgentPri'
(Get-LocalUser -Name 'svc-SqlAgentPri').Name | Should -Be 'svc-SqlAgentPri'
}

It 'Creates svc-SqlSecondary user' {
$user = New-LocalUser -Name 'svc-SqlSecondary' -Password $password2 -FullName 'svc-SqlSecondary' -Description 'Runs the SQL Server service on the second node.'

$user.Name | Should -Be 'svc-SqlSecondary'
(Get-LocalUser -Name 'svc-SqlSecondary').Name | Should -Be 'svc-SqlSecondary'
}

It 'Creates svc-SqlAgentSec user' {
$user = New-LocalUser -Name 'svc-SqlAgentSec' -Password $password2 -FullName 'svc-SqlAgentSec' -Description 'Runs the SQL Server Agent service on the second node.'

$user.Name | Should -Be 'svc-SqlAgentSec'
(Get-LocalUser -Name 'svc-SqlAgentSec').Name | Should -Be 'svc-SqlAgentSec'
}
}

Context 'Add local Windows users to local groups' {
It 'Adds SqlInstall to local administrator group' {
# Add user to local administrator group
Add-LocalGroupMember -Group 'Administrators' -Member 'SqlInstall'

# Verify if user is part of local administrator group
$adminGroup = Get-LocalGroup -Name 'Administrators'
$adminGroupMembers = Get-LocalGroupMember -Group $adminGroup
$adminGroupMembers.Name | Should -Contain 'SqlInstall'
}
}
}
12 changes: 6 additions & 6 deletions tests/Integration/Commands/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ The following local users are created and can be used by integration tests.
<!-- markdownlint-disable MD013 -->
User | Password | Permission | Description
--- | --- | --- | ---
.\SqlInstall | P@ssw0rd1 | Local Windows administrator. Administrator of Database Engine instance DSCSQLTEST\*. | Runs Setup for the default instance.
.\SqlAdmin | P@ssw0rd1 | Administrator of all SQL Server instances. |
.\svc-SqlPrimary | yig-C^Equ3 | Local user. | Runs the SQL Server Agent service.
.\svc-SqlAgentPri | yig-C^Equ3 | Local user. | Runs the SQL Server Agent service.
.\svc-SqlSecondary | yig-C^Equ3 | Local user. | Used by other tests, but created here.
.\svc-SqlAgentSec | yig-C^Equ3 | Local user. | Used by other tests.
.\SqlInstall | P@ssw0rd1 | Local Windows administrator and sysadmin | Runs Setup for all instances.
.\SqlAdmin | P@ssw0rd1 | Local Windows user and sysadmin | Administrator of all SQL Server instances.
.\svc-SqlPrimary | yig-C^Equ3 | Local Windows user. | Runs the SQL Server service.
.\svc-SqlAgentPri | yig-C^Equ3 | Local Windows user. | Runs the SQL Server Agent service.
.\svc-SqlSecondary | yig-C^Equ3 | Local Windows user. | Runs the SQL Server service in multi node scenarios.
.\svc-SqlAgentSec | yig-C^Equ3 | Local Windows user. | Runs the SQL Server Agent service in multi node scenarios.

Login | Password | Permission | Description
--- | --- | --- | ---
Expand Down
Loading