Files
Merge-DSCConfigurationData/Tests/Extends.Tests.ps1

410 lines
12 KiB
PowerShell

$script:ModuleRoot = Split-Path -Parent $PSScriptRoot
$script:ModuleManifest = Join-Path -Path $script:ModuleRoot -ChildPath 'Merge-DSCConfigurationData.psd1'
Import-Module $script:ModuleManifest -Force
Describe 'Merge-DSCConfigurationData Extends' {
It 'keeps the existing hashtable merge behavior' {
$Template = @{
Parameters = @{
DomainFQDN = @{
Type = 'string'
Required = $true
DefaultValue = 'example.local'
}
}
}
$Deployment = @{
Parameters = @{
DomainFQDN = @{
Value = 'contoso.local'
}
}
}
$Result = Merge-DSCConfigurationData -Template $Template -Deployment $Deployment
$Result.Parameters.DomainFQDN.Type | Should Be 'string'
$Result.Parameters.DomainFQDN.Required | Should Be $true
$Result.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
}
It 'merges a child template with Metadata.Extends' {
$DefaultPath = Join-Path -Path $TestDrive -ChildPath 'Default.psd1'
$ChildPath = Join-Path -Path $TestDrive -ChildPath 'Contoso.psd1'
@'
@{
Metadata = @{
TemplateType = 'Environment'
Name = 'Default'
}
Parameters = @{
DomainFQDN = @{
Type = 'string'
Required = $true
DefaultValue = 'example.local'
}
DomainNetBIOS = @{
Type = 'string'
Required = $true
}
}
Resources = @{
NonNodeData = @{
RequiredModules = @(
@{
Name = 'ActiveDirectoryDsc'
Version = '6.7.1'
}
)
}
}
}
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
@'
@{
Metadata = @{
TemplateType = 'Environment'
Name = 'Contoso'
Extends = './Default.psd1'
}
Parameters = @{
DomainFQDN = @{
Value = 'contoso.local'
}
DomainNetBIOS = @{
Value = 'CONTOSO'
}
}
}
'@ | Set-Content -Path $ChildPath -Encoding UTF8
$Result = Merge-DSCConfigurationData -Path $ChildPath -PassThru
$Result.Files.Count | Should Be 2
[System.IO.Path]::GetFileName($Result.Files[0]) | Should Be 'Default.psd1'
[System.IO.Path]::GetFileName($Result.Files[1]) | Should Be 'Contoso.psd1'
$Result.ConfigurationData.Parameters.DomainFQDN.Type | Should Be 'string'
$Result.ConfigurationData.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
$Result.ConfigurationData.Parameters.DomainNetBIOS.Required | Should Be $true
$Result.ConfigurationData.Parameters.DomainNetBIOS.Value | Should Be 'CONTOSO'
$Result.ConfigurationData.Resources.NonNodeData.RequiredModules[0].Name | Should Be 'ActiveDirectoryDsc'
$Result.ConfigurationData.ContainsKey('Metadata') | Should Be $false
}
It 'detects circular Metadata.Extends references' {
$APath = Join-Path -Path $TestDrive -ChildPath 'A.psd1'
$BPath = Join-Path -Path $TestDrive -ChildPath 'B.psd1'
@'
@{
Metadata = @{
Extends = './B.psd1'
}
}
'@ | Set-Content -Path $APath -Encoding UTF8
@'
@{
Metadata = @{
Extends = './A.psd1'
}
}
'@ | Set-Content -Path $BPath -Encoding UTF8
{ Merge-DSCConfigurationData -Path $APath } | Should Throw
}
It 'exports importable PSD1 files with quoted metadata keys' {
$Path = Join-Path -Path $TestDrive -ChildPath 'Export.psd1'
@{
Metadata = @{
Description = @{
'de-DE' = 'Deutsch'
'en-US' = 'English'
}
}
} | Export-PowerShellDataFile -Path $Path -Force
$Data = Import-PowerShellDataFile -Path $Path
$Data.Metadata.Description['de-DE'] | Should Be 'Deutsch'
$Data.Metadata.Description['en-US'] | Should Be 'English'
}
It 'creates materialized deployment data without exporting by default' {
$DefaultPath = Join-Path -Path $TestDrive -ChildPath 'Default.psd1'
$ChildPath = Join-Path -Path $TestDrive -ChildPath 'Contoso.psd1'
@'
@{
Metadata = @{
TemplateType = 'Environment'
Name = 'Default'
}
Parameters = @{
DomainFQDN = @{
Type = 'string'
Required = $true
}
}
Resources = @{
AllNodes = @(
@{
NodeName = '*'
PSDSCAllowPlainTextPassword = $true
}
)
}
}
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
@'
@{
Metadata = @{
TemplateType = 'Environment'
Name = 'Contoso'
Extends = './Default.psd1'
}
Parameters = @{
DomainFQDN = @{
Value = 'contoso.local'
}
}
}
'@ | Set-Content -Path $ChildPath -Encoding UTF8
$Result = New-DSCConfigurationDataDeployment `
-Name 'Contoso-Test' `
-DeploymentId '123' `
-SourceTemplatePath $ChildPath `
-AllNodes @(
@{
NodeName = 'Node01'
RunCentralAdministration = $true
}
)
$Result.Metadata.TemplateType | Should Be 'Deployment'
$Result.Metadata.Sources.Files.Count | Should Be 2
$Result.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
$Result.Resources.AllNodes[0].NodeName | Should Be 'Node01'
$Result.Resources.AllNodes[0].PSDSCAllowPlainTextPassword | Should Be $true
}
It 'exports materialized deployment data as PSD1' {
$DefaultPath = Join-Path -Path $TestDrive -ChildPath 'Default.psd1'
$ChildPath = Join-Path -Path $TestDrive -ChildPath 'Contoso.psd1'
$DeploymentPath = Join-Path -Path $TestDrive -ChildPath 'Deployments\Deployment_123.psd1'
@'
@{
Metadata = @{
TemplateType = 'Environment'
Name = 'Default'
}
Parameters = @{
DomainFQDN = @{
Type = 'string'
Required = $true
}
}
Variables = @{
}
}
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
@'
@{
Metadata = @{
TemplateType = 'Environment'
Name = 'Contoso'
Extends = './Default.psd1'
}
Parameters = @{
DomainFQDN = @{
Value = 'contoso.local'
}
}
}
'@ | Set-Content -Path $ChildPath -Encoding UTF8
$Result = New-DSCConfigurationDataDeployment `
-Path $DeploymentPath `
-Name 'Contoso-Test' `
-DeploymentId '123' `
-SourceTemplatePath $ChildPath `
-AllNodes @(
@{
NodeName = 'Node01'
RunCentralAdministration = $true
}
) `
-UseRelativePaths `
-Export `
-Format PowerShellDataFile `
-Force `
-PassThru
$DeploymentPath | Should Exist
$Result.ConfigurationData.Metadata.TemplateType | Should Be 'Deployment'
$Result.ConfigurationData.Metadata.Sources.Files.Count | Should Be 2
$Result.ConfigurationData.Metadata.Sources.Files[0].Hash.Length | Should Be 64
$Result.ConfigurationData.Metadata.Sources.Files[0].Algorithm | Should Be 'SHA256'
$Result.ConfigurationData.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
$Result.ConfigurationData.Resources.AllNodes[0].NodeName | Should Be 'Node01'
$Result.ConfigurationData.Resources.AllNodes[0].RunCentralAdministration | Should Be $true
$Imported = Import-PowerShellDataFile -Path $DeploymentPath
$Imported.Metadata.Name | Should Be 'Contoso-Test'
$Imported.Metadata.Sources.Templates.Count | Should Be 1
$Validation = Test-DSCConfigurationDataDeployment -Path $DeploymentPath -PassThru
$Validation.IsValid | Should Be $true
$Validation.IsStale | Should Be $false
}
It 'exports materialized deployment data as JSON' {
$DefaultPath = Join-Path -Path $TestDrive -ChildPath 'Default.psd1'
$DeploymentPath = Join-Path -Path $TestDrive -ChildPath 'Deployment_123.json'
@'
@{
Parameters = @{
DomainFQDN = @{
Type = 'string'
Value = 'contoso.local'
}
}
Variables = @{
}
}
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
New-DSCConfigurationDataDeployment `
-Path $DeploymentPath `
-Name 'Contoso-Test' `
-DeploymentId '123' `
-SourceTemplatePath $DefaultPath `
-Export `
-Format Json `
-Force
$DeploymentPath | Should Exist
$Imported = Get-Content -Path $DeploymentPath -Raw | ConvertFrom-Json
$Imported.Metadata.TemplateType | Should Be 'Deployment'
$Imported.Parameters.DomainFQDN.Value | Should Be 'contoso.local'
}
It 'detects changed deployment source files by hash' {
$DefaultPath = Join-Path -Path $TestDrive -ChildPath 'Default.psd1'
$DeploymentPath = Join-Path -Path $TestDrive -ChildPath 'Deployment_123.psd1'
@'
@{
Parameters = @{
DomainFQDN = @{
Type = 'string'
Value = 'contoso.local'
}
}
Variables = @{
}
}
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
New-DSCConfigurationDataDeployment `
-Path $DeploymentPath `
-Name 'Contoso-Test' `
-DeploymentId '123' `
-SourceTemplatePath $DefaultPath `
-AllNodes @(
@{
NodeName = 'Node01'
}
) `
-Export `
-Force
@'
@{
Parameters = @{
DomainFQDN = @{
Type = 'string'
Value = 'changed.local'
}
}
Variables = @{
}
}
'@ | Set-Content -Path $DefaultPath -Encoding UTF8
$Validation = Test-DSCConfigurationDataDeployment -Path $DeploymentPath -PassThru
$Validation.IsValid | Should Be $true
$Validation.IsStale | Should Be $true
@($Validation.Issues | Where-Object { $_.Code -eq 'SourceChanged' }).Count | Should Be 1
}
It 'prevents overriding a sealed parameter definition' {
$Template = @{
Parameters = @{
DomainNetBIOS = @{
Type = 'string'
Value = 'CONTOSO'
Sealed = $true
}
}
}
$Deployment = @{
Parameters = @{
DomainNetBIOS = @{
Value = 'OTHER'
}
}
}
{ Merge-DSCConfigurationData -Template $Template -Deployment $Deployment } | Should Throw
}
It 'prevents adding values below a sealed resource tree' {
$Template = @{
Resources = @{
NonNodeData = @{
Services = @{
SharePoint = @{
Farm = @{
ManagedAccounts = @{
Sealed = $true
FarmAccount = "[parameters('FarmCredential')]"
}
}
}
}
}
}
}
$Deployment = @{
Resources = @{
NonNodeData = @{
Services = @{
SharePoint = @{
Farm = @{
ManagedAccounts = @{
SearchAccount = "[parameters('SearchCredential')]"
}
}
}
}
}
}
}
{ Merge-DSCConfigurationData -Template $Template -Deployment $Deployment } | Should Throw
}
}