Test-Requirement rewrite
parent
e8bbc5267e
commit
7cc7ba3880
74
src/core.ps1
74
src/core.ps1
|
@ -4,45 +4,59 @@ $ErrorActionPreference = "Stop"
|
|||
|
||||
# idempotently applies a requirement
|
||||
function applyRequirement([Requirement]$Requirement) {
|
||||
$result = $false
|
||||
if ($Requirement.Test) {
|
||||
[RequirementEvent]::new($Requirement, "Test", "Start")
|
||||
$result = &$Requirement.Test
|
||||
[RequirementEvent]::new($Requirement, "Test", "Stop", $result)
|
||||
$result = $false
|
||||
if ($Requirement.Test) {
|
||||
[RequirementEvent]::new($Requirement, "Test", "Start")
|
||||
$result = &$Requirement.Test
|
||||
[RequirementEvent]::new($Requirement, "Test", "Stop", $result)
|
||||
}
|
||||
if (-not $result) {
|
||||
if ($Requirement.Set) {
|
||||
[RequirementEvent]::new($Requirement, "Set", "Start")
|
||||
$result = &$Requirement.Set
|
||||
[RequirementEvent]::new($Requirement, "Set", "Stop", $result)
|
||||
}
|
||||
if (-not $result) {
|
||||
if ($Requirement.Set) {
|
||||
[RequirementEvent]::new($Requirement, "Set", "Start")
|
||||
$result = &$Requirement.Set
|
||||
[RequirementEvent]::new($Requirement, "Set", "Stop", $result)
|
||||
}
|
||||
if ($Requirement.Test -and $Requirement.Set) {
|
||||
[RequirementEvent]::new($Requirement, "Validate", "Start")
|
||||
$result = &$Requirement.Test
|
||||
[RequirementEvent]::new($Requirement, "Validate", "Stop", $result)
|
||||
if (-not $result) {
|
||||
Write-Error "Failed to apply Requirement '$($Requirement.Name)'"
|
||||
}
|
||||
}
|
||||
if ($Requirement.Test -and $Requirement.Set) {
|
||||
[RequirementEvent]::new($Requirement, "Validate", "Start")
|
||||
$result = &$Requirement.Test
|
||||
[RequirementEvent]::new($Requirement, "Validate", "Stop", $result)
|
||||
if (-not $result) {
|
||||
Write-Error "Failed to apply Requirement '$($Requirement.Name)'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# applies an array of requirements
|
||||
function applyRequirements([Requirement[]]$Requirements) {
|
||||
$Requirements | % { applyRequirement $_ }
|
||||
$Requirements | % { applyRequirement $_ }
|
||||
}
|
||||
|
||||
# run the Test method of a requirement
|
||||
function testRequirement([Requirement]$Requirement) {
|
||||
if ($Requirement.Test) {
|
||||
[RequirementEvent]::new($Requirement, "Test", "Start")
|
||||
$result = &$Requirement.Test
|
||||
[RequirementEvent]::new($Requirement, "Test", "Stop", $result)
|
||||
}
|
||||
}
|
||||
|
||||
# tests an array of requirements
|
||||
function testRequirements([Requirement[]]$Requirements) {
|
||||
$Requirements | % { testRequirement $_ }
|
||||
}
|
||||
|
||||
# sorts an array of Requirements in topological order
|
||||
function sortRequirements([Requirement[]]$Requirements) {
|
||||
$stages = @()
|
||||
while ($Requirements) {
|
||||
$nextStages = $Requirements `
|
||||
| ? { -not ($_.DependsOn | ? { $_ -notin $stages.Name }) }
|
||||
if (-not $nextStages) {
|
||||
throw "Could not resolve the dependencies for Requirements with names: $($Requirements.Name -join ', ')"
|
||||
}
|
||||
$Requirements = $Requirements | ? { $_.Name -notin $nextStages.Name }
|
||||
$stages += $nextStages
|
||||
$stages = @()
|
||||
while ($Requirements) {
|
||||
$nextStages = $Requirements `
|
||||
| ? { -not ($_.DependsOn | ? { $_ -notin $stages.Name }) }
|
||||
if (-not $nextStages) {
|
||||
throw "Could not resolve the dependencies for Requirements with names: $($Requirements.Name -join ', ')"
|
||||
}
|
||||
$stages
|
||||
$Requirements = $Requirements | ? { $_.Name -notin $nextStages.Name }
|
||||
$stages += $nextStages
|
||||
}
|
||||
$stages
|
||||
}
|
||||
|
|
|
@ -12,68 +12,68 @@ $ErrorActionPreference = "Stop"
|
|||
Dsc parameter set is unsupported due to cross-platform limitations
|
||||
#>
|
||||
function New-Requirement {
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
|
||||
[OutputType([Requirement])]
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
# The unique identifier for the Requirement
|
||||
[Parameter(ParameterSetName = "Script")]
|
||||
[Parameter(ParameterSetName = "Dsc")]
|
||||
[string] $Name,
|
||||
# A description of the Requirement
|
||||
[Parameter(Mandatory, ParameterSetName = "Script")]
|
||||
[Parameter(Mandatory, ParameterSetName = "Dsc")]
|
||||
[string] $Describe,
|
||||
# The Test condition that determines if the Requirement is in its desired state
|
||||
[Parameter(ParameterSetName = "Script")]
|
||||
[scriptblock] $Test,
|
||||
# The Set condition that Sets the Requirement to its desired state
|
||||
[Parameter(ParameterSetName = "Script")]
|
||||
[scriptblock] $Set,
|
||||
# The list of Requirement Names that must be in desired state prior to this Requirement
|
||||
[Parameter(ParameterSetName = "Script")]
|
||||
[Parameter(ParameterSetName = "Dsc")]
|
||||
[ValidateNotNull()]
|
||||
[string[]] $DependsOn = @(),
|
||||
# The name of the DSC resource associated with the Requirement
|
||||
[Parameter(Mandatory, ParameterSetName = "Dsc")]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$ResourceName,
|
||||
# The module containing the DSC resource
|
||||
[Parameter(Mandatory, ParameterSetName = "Dsc")]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$ModuleName,
|
||||
# The properties passed through to the DSC resource
|
||||
[Parameter(Mandatory, ParameterSetName = "Dsc")]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[hashtable]$Property
|
||||
)
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
|
||||
[OutputType([Requirement])]
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
# The unique identifier for the Requirement
|
||||
[Parameter(ParameterSetName = "Script")]
|
||||
[Parameter(ParameterSetName = "Dsc")]
|
||||
[string] $Name,
|
||||
# A description of the Requirement
|
||||
[Parameter(Mandatory, ParameterSetName = "Script")]
|
||||
[Parameter(Mandatory, ParameterSetName = "Dsc")]
|
||||
[string] $Describe,
|
||||
# The Test condition that determines if the Requirement is in its desired state
|
||||
[Parameter(ParameterSetName = "Script")]
|
||||
[scriptblock] $Test,
|
||||
# The Set condition that Sets the Requirement to its desired state
|
||||
[Parameter(ParameterSetName = "Script")]
|
||||
[scriptblock] $Set,
|
||||
# The list of Requirement Names that must be in desired state prior to this Requirement
|
||||
[Parameter(ParameterSetName = "Script")]
|
||||
[Parameter(ParameterSetName = "Dsc")]
|
||||
[ValidateNotNull()]
|
||||
[string[]] $DependsOn = @(),
|
||||
# The name of the DSC resource associated with the Requirement
|
||||
[Parameter(Mandatory, ParameterSetName = "Dsc")]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$ResourceName,
|
||||
# The module containing the DSC resource
|
||||
[Parameter(Mandatory, ParameterSetName = "Dsc")]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$ModuleName,
|
||||
# The properties passed through to the DSC resource
|
||||
[Parameter(Mandatory, ParameterSetName = "Dsc")]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[hashtable]$Property
|
||||
)
|
||||
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"Script" {
|
||||
[Requirement]@{
|
||||
Name = $Name
|
||||
Describe = $Describe
|
||||
Test = $Test
|
||||
Set = $Set
|
||||
DependsOn = $DependsOn
|
||||
}
|
||||
}
|
||||
"Dsc" {
|
||||
$dscParams = @{
|
||||
Name = $ResourceName
|
||||
ModuleName = $ModuleName
|
||||
Property = $Property
|
||||
}
|
||||
[Requirement]@{
|
||||
Name = $Name
|
||||
Describe = $Describe
|
||||
Test = { Invoke-DscResource -Method "Test" @dscParams }.GetNewClosure()
|
||||
Set = { Invoke-DscResource -Method "Set" @dscParams }.GetNewClosure()
|
||||
DependsOn = $DependsOn
|
||||
}
|
||||
}
|
||||
switch ($PSCmdlet.ParameterSetName) {
|
||||
"Script" {
|
||||
[Requirement]@{
|
||||
Name = $Name
|
||||
Describe = $Describe
|
||||
Test = $Test
|
||||
Set = $Set
|
||||
DependsOn = $DependsOn
|
||||
}
|
||||
}
|
||||
"Dsc" {
|
||||
$dscParams = @{
|
||||
Name = $ResourceName
|
||||
ModuleName = $ModuleName
|
||||
Property = $Property
|
||||
}
|
||||
[Requirement]@{
|
||||
Name = $Name
|
||||
Describe = $Describe
|
||||
Test = { Invoke-DscResource -Method "Test" @dscParams }.GetNewClosure()
|
||||
Set = { Invoke-DscResource -Method "Set" @dscParams }.GetNewClosure()
|
||||
DependsOn = $DependsOn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
|
@ -83,15 +83,15 @@ function New-Requirement {
|
|||
The RequirementEvents logged from each stage of the Requirement lifecycle
|
||||
#>
|
||||
function Invoke-Requirement {
|
||||
[CmdletBinding()]
|
||||
[OutputType([RequirementEvent])]
|
||||
Param(
|
||||
# The Requirements to put in their desired state
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[Requirement[]] $Requirement
|
||||
)
|
||||
[CmdletBinding()]
|
||||
[OutputType([RequirementEvent])]
|
||||
Param(
|
||||
# The Requirements to put in their desired state
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[Requirement[]] $Requirement
|
||||
)
|
||||
|
||||
applyRequirements (sortRequirements $input)
|
||||
applyRequirements (sortRequirements $input)
|
||||
}
|
||||
|
||||
<#
|
||||
|
@ -99,15 +99,15 @@ function Invoke-Requirement {
|
|||
Tests whether a requirement is in its desired state
|
||||
#>
|
||||
function Test-Requirement {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
# The Requirement to test its desired state
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Requirement] $Requirement
|
||||
)
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
# The Requirement to test its desired state
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Requirement[]] $Requirement
|
||||
)
|
||||
|
||||
&$Requirement.Test
|
||||
testRequirements (sortRequirements $input)
|
||||
}
|
||||
|
||||
<#
|
||||
|
@ -115,15 +115,15 @@ function Test-Requirement {
|
|||
Sets the requirement to its desired state
|
||||
#>
|
||||
function Set-Requirement {
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
Param(
|
||||
# The Requirement that sets if its in its desired state
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Requirement] $Requirement
|
||||
)
|
||||
[CmdletBinding(SupportsShouldProcess)]
|
||||
Param(
|
||||
# The Requirement that sets if its in its desired state
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[Requirement] $Requirement
|
||||
)
|
||||
|
||||
if ($PSCmdlet.ShouldProcess($Requirement, "Set")) {
|
||||
&$Requirement.Set
|
||||
}
|
||||
if ($PSCmdlet.ShouldProcess($Requirement, "Set")) {
|
||||
&$Requirement.Set
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
12:04:37 [MyName] BEGIN SET MyDescribe
|
||||
12:04:37 [MyName] END SET
|
||||
10:27:29 [MyName] BEGIN SET MyDescribe
|
||||
10:27:29 [MyName] END SET
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
12:04:37 [MyName] BEGIN TEST MyDescribe
|
||||
12:04:37 [MyName] END TEST => True
|
||||
10:27:29 [MyName] BEGIN TEST MyDescribe
|
||||
10:27:29 [MyName] END TEST => True
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
12:04:37 [MyName] BEGIN TEST MyDescribe
|
||||
12:04:37 [MyName] END TEST => False
|
||||
12:04:37 [MyName] BEGIN SET MyDescribe
|
||||
12:04:37 [MyName] END SET
|
||||
12:04:37 [MyName] BEGIN TEST MyDescribe
|
||||
12:04:37 [MyName] END TEST => True
|
||||
10:27:29 [MyName] BEGIN TEST MyDescribe
|
||||
10:27:29 [MyName] END TEST => False
|
||||
10:27:29 [MyName] BEGIN SET MyDescribe
|
||||
10:27:29 [MyName] END SET
|
||||
10:27:29 [MyName] BEGIN TEST MyDescribe
|
||||
10:27:29 [MyName] END TEST => True
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
12:04:37 [ ] MyDescribe
|
||||
10:27:29 [ ] MyDescribe
|
||||
|
||||
12:04:37 [ √ ] MyDescribe
|
||||
10:27:29 [ √ ] MyDescribe
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
12:04:37 [ ] MyDescribe
|
||||
10:27:29 [ ] MyDescribe
|
||||
|
||||
12:04:37 [ √ ] MyDescribe
|
||||
10:27:29 [ √ ] MyDescribe
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
12:04:37 [ ] MyDescribe
|
||||
10:27:29 [ ] MyDescribe
|
||||
|
||||
12:04:37 [ √ ] MyDescribe
|
||||
10:27:29 [ √ ] MyDescribe
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
Date Method State Result Requirement
|
||||
---- ------ ----- ------ -----------
|
||||
9/21/19 12:04:37 AM Set Start MyName
|
||||
9/21/19 12:04:37 AM Set Stop True MyName
|
||||
9/21/19 10:27:29 AM Set Start MyName
|
||||
9/21/19 10:27:29 AM Set Stop True MyName
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
Date Method State Result Requirement
|
||||
---- ------ ----- ------ -----------
|
||||
9/21/19 12:04:37 AM Test Start MyName
|
||||
9/21/19 12:04:37 AM Test Stop True MyName
|
||||
9/21/19 10:27:29 AM Test Start MyName
|
||||
9/21/19 10:27:29 AM Test Stop True MyName
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
Date Method State Result Requirement
|
||||
---- ------ ----- ------ -----------
|
||||
9/21/19 12:04:37 AM Test Start MyName
|
||||
9/21/19 12:04:37 AM Test Stop False MyName
|
||||
9/21/19 12:04:37 AM Set Start MyName
|
||||
9/21/19 12:04:37 AM Set Stop True MyName
|
||||
9/21/19 12:04:37 AM Validate Start MyName
|
||||
9/21/19 12:04:37 AM Validate Stop True MyName
|
||||
9/21/19 10:27:29 AM Test Start MyName
|
||||
9/21/19 10:27:29 AM Test Stop False MyName
|
||||
9/21/19 10:27:29 AM Set Start MyName
|
||||
9/21/19 10:27:29 AM Set Stop True MyName
|
||||
9/21/19 10:27:29 AM Validate Start MyName
|
||||
9/21/19 10:27:29 AM Validate Stop True MyName
|
||||
|
||||
|
|
|
@ -7,103 +7,99 @@ $SourceRoot = "$RepoRoot/src"
|
|||
|
||||
$PlatformLacksDscSupport = $PSVersionTable.PSEdition -eq "Core"
|
||||
if (-not $PlatformLacksDscSupport) {
|
||||
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$isAdmin = $identity.groups -match "S-1-5-32-544"
|
||||
if (-not $isAdmin) {
|
||||
throw @"
|
||||
$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$isAdmin = $identity.groups -match "S-1-5-32-544"
|
||||
if (-not $isAdmin) {
|
||||
throw @"
|
||||
You are running PowerShell 5 and are therefore testing DSC resources.
|
||||
You must be running as admin to test DSC resources.
|
||||
"@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "New-Requirement" {
|
||||
Context "'Script' parameter set" {
|
||||
$requirement = @{
|
||||
Describe = "My Requirement"
|
||||
Test = { 1 }
|
||||
Set = { 2 }
|
||||
}
|
||||
It "Should not throw" {
|
||||
{ New-Requirement @requirement } | Should -Not -Throw
|
||||
}
|
||||
It "Should not be empty" {
|
||||
New-Requirement @requirement | Should -BeTrue
|
||||
}
|
||||
Context "'Script' parameter set" {
|
||||
$requirement = @{
|
||||
Describe = "My Requirement"
|
||||
Test = { 1 }
|
||||
Set = { 2 }
|
||||
}
|
||||
Context "'Dsc' parameter set" {
|
||||
It "Should not be empty" -Skip:$PlatformLacksDscSupport {
|
||||
$requirement = @{
|
||||
Describe = "My Dsc Requirement"
|
||||
ResourceName = "File"
|
||||
ModuleName = "PSDesiredStateConfiguration"
|
||||
Property = @{
|
||||
Contents = ""
|
||||
DestinationFile = ""
|
||||
}
|
||||
}
|
||||
New-Requirement @requirement | Should -BeTrue
|
||||
}
|
||||
It "Should not throw" {
|
||||
{ New-Requirement @requirement } | Should -Not -Throw
|
||||
}
|
||||
It "Should not be empty" {
|
||||
New-Requirement @requirement | Should -BeTrue
|
||||
}
|
||||
}
|
||||
Context "'Dsc' parameter set" {
|
||||
It "Should not be empty" -Skip:$PlatformLacksDscSupport {
|
||||
$requirement = @{
|
||||
Describe = "My Dsc Requirement"
|
||||
ResourceName = "File"
|
||||
ModuleName = "PSDesiredStateConfiguration"
|
||||
Property = @{
|
||||
Contents = ""
|
||||
DestinationFile = ""
|
||||
}
|
||||
}
|
||||
New-Requirement @requirement | Should -BeTrue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Invoke-Requirement" {
|
||||
Context "Normal Requirement" {
|
||||
It "Should not error" {
|
||||
$requirement = @{
|
||||
Test = { 1 }
|
||||
}
|
||||
{ Invoke-Requirement $requirement } | Should -Not -Throw
|
||||
}
|
||||
Context "Normal Requirement" {
|
||||
It "Should not error" {
|
||||
$requirement = @{
|
||||
Test = { 1 }
|
||||
}
|
||||
{ Invoke-Requirement $requirement } | Should -Not -Throw
|
||||
}
|
||||
Context "DSC Requirement" {
|
||||
It "Should apply the DSC resource" -Skip:$PlatformLacksDscSupport {
|
||||
$tempFilePath = "$env:TEMP\_dsctest_$(New-Guid).txt"
|
||||
$content = "Hello world"
|
||||
$params = @{
|
||||
Name = "[file]MyFile"
|
||||
Describe = "My Dsc Requirement"
|
||||
ResourceName = "File"
|
||||
ModuleName = "PSDesiredStateConfiguration"
|
||||
Property = @{
|
||||
Contents = $content
|
||||
DestinationPath = $tempFilePath
|
||||
Force = $true
|
||||
}
|
||||
}
|
||||
New-Requirement @params | Invoke-Requirement
|
||||
Get-Content $tempFilePath | Should -Be $content
|
||||
Remove-Item $tempFilePath
|
||||
}
|
||||
Context "DSC Requirement" {
|
||||
It "Should apply the DSC resource" -Skip:$PlatformLacksDscSupport {
|
||||
$tempFilePath = "$env:TEMP\_dsctest_$(New-Guid).txt"
|
||||
$content = "Hello world"
|
||||
$params = @{
|
||||
Name = "[file]MyFile"
|
||||
Describe = "My Dsc Requirement"
|
||||
ResourceName = "File"
|
||||
ModuleName = "PSDesiredStateConfiguration"
|
||||
Property = @{
|
||||
Contents = $content
|
||||
DestinationPath = $tempFilePath
|
||||
Force = $true
|
||||
}
|
||||
}
|
||||
New-Requirement @params | Invoke-Requirement
|
||||
Get-Content $tempFilePath | Should -Be $content
|
||||
Remove-Item $tempFilePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Test-Requirement" {
|
||||
It "Should not error" {
|
||||
$requirement = @{
|
||||
Test = { $true }
|
||||
}
|
||||
{ Test-Requirement $requirement } | Should -Not -Throw
|
||||
}
|
||||
It "Should pass through falsey values" {
|
||||
$requirement = @{
|
||||
Test = { $false }
|
||||
}
|
||||
Test-Requirement $requirement | Should -BeFalse
|
||||
}
|
||||
It "Should pass through truthy values" {
|
||||
$requirement = @{
|
||||
Test = { $true }
|
||||
}
|
||||
Test-Requirement $requirement | Should -BeTrue
|
||||
It "Should not error" {
|
||||
$requirement = @{
|
||||
Test = { $true }
|
||||
}
|
||||
{ Test-Requirement $requirement } | Should -Not -Throw
|
||||
}
|
||||
It "Should only emit 'Test' events" {
|
||||
$requirements = @(
|
||||
@{ Test = { $true } },
|
||||
@{ Set = { $true } }
|
||||
)
|
||||
$events = $requirements | Test-Requirement
|
||||
$events | % { $_.Method | Should -Be "Test" }
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Set-Requirement" {
|
||||
It "Should not error" {
|
||||
$requirement = @{
|
||||
Set = { $false }
|
||||
}
|
||||
{ Invoke-Requirement $requirement } | Should -Not -Throw
|
||||
It "Should not error" {
|
||||
$requirement = @{
|
||||
Set = { $false }
|
||||
}
|
||||
{ Invoke-Requirement $requirement } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue