indentation
parent
28e05d161f
commit
9b011d38ca
|
@ -1,3 +1,5 @@
|
|||
{
|
||||
"powershell.scriptAnalysis.settingsPath": "./PSScriptAnalyzerSettings.psd1"
|
||||
"powershell.scriptAnalysis.settingsPath": "./PSScriptAnalyzerSettings.psd1",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.tabSize": 4
|
||||
}
|
72
src/core.ps1
72
src/core.ps1
|
@ -4,59 +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)
|
||||
}
|
||||
if (-not $result) {
|
||||
if ($Requirement.Set) {
|
||||
[RequirementEvent]::new($Requirement, "Set", "Start")
|
||||
$result = &$Requirement.Set
|
||||
[RequirementEvent]::new($Requirement, "Set", "Stop", $result)
|
||||
$result = $false
|
||||
if ($Requirement.Test) {
|
||||
[RequirementEvent]::new($Requirement, "Test", "Start")
|
||||
$result = &$Requirement.Test
|
||||
[RequirementEvent]::new($Requirement, "Test", "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 (-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)'"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 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)
|
||||
}
|
||||
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 $_ }
|
||||
$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 ', ')"
|
||||
$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
|
||||
}
|
||||
$Requirements = $Requirements | ? { $_.Name -notin $nextStages.Name }
|
||||
$stages += $nextStages
|
||||
}
|
||||
$stages
|
||||
$stages
|
||||
}
|
||||
|
|
|
@ -8,83 +8,83 @@ $ErrorActionPreference = "Stop"
|
|||
."$PSScriptRoot\types.ps1"
|
||||
|
||||
function writePending($timestamp, $description) {
|
||||
$symbol = " "
|
||||
$color = "Yellow"
|
||||
$message = "$timestamp [ $symbol ] $description"
|
||||
Write-Host $message -ForegroundColor $color -NoNewline
|
||||
$symbol = " "
|
||||
$color = "Yellow"
|
||||
$message = "$timestamp [ $symbol ] $description"
|
||||
Write-Host $message -ForegroundColor $color -NoNewline
|
||||
}
|
||||
|
||||
function writeSuccess($timestamp, $description, $clearString) {
|
||||
$symbol = [char]8730
|
||||
$color = "Green"
|
||||
$message = "$timestamp [ $symbol ] $description"
|
||||
Write-Host "`r$clearString" -NoNewline
|
||||
Write-Host "`r$message" -ForegroundColor $color
|
||||
$symbol = [char]8730
|
||||
$color = "Green"
|
||||
$message = "$timestamp [ $symbol ] $description"
|
||||
Write-Host "`r$clearString" -NoNewline
|
||||
Write-Host "`r$message" -ForegroundColor $color
|
||||
}
|
||||
|
||||
function writeFail($timestamp, $description, $clearString) {
|
||||
$symbol = "X"
|
||||
$color = "Red"
|
||||
$message = "$timestamp [ $symbol ] $description"
|
||||
Write-Host "`r$clearString" -NoNewline
|
||||
Write-Host "`n$message`n" -ForegroundColor $color
|
||||
exit -1
|
||||
$symbol = "X"
|
||||
$color = "Red"
|
||||
$message = "$timestamp [ $symbol ] $description"
|
||||
Write-Host "`r$clearString" -NoNewline
|
||||
Write-Host "`n$message`n" -ForegroundColor $color
|
||||
exit -1
|
||||
}
|
||||
|
||||
$fsm = @{
|
||||
"Test Test Start $false" = {
|
||||
writePending @args
|
||||
@{
|
||||
"Test Test Stop $true" = {
|
||||
writeSuccess @args
|
||||
$fsm
|
||||
}
|
||||
"Test Test Stop $false" = {
|
||||
writeFail @args
|
||||
}
|
||||
}
|
||||
}
|
||||
"Set Set Start *" = {
|
||||
writePending @args
|
||||
@{
|
||||
"Set Set Stop *" = {
|
||||
writeSuccess @args
|
||||
$fsm
|
||||
}
|
||||
}
|
||||
}
|
||||
"TestSet Test Start $false" = {
|
||||
writePending @args
|
||||
@{
|
||||
"TestSet Test Stop $true" = {
|
||||
writeSuccess @args
|
||||
$fsm
|
||||
}
|
||||
"TestSet Test Stop $false" = {
|
||||
"Test Test Start $false" = {
|
||||
writePending @args
|
||||
@{
|
||||
"TestSet Set Start *" = {
|
||||
@{
|
||||
"TestSet Set Stop *" = {
|
||||
@{
|
||||
"TestSet Validate Start $false" = {
|
||||
@{
|
||||
"TestSet Validate Stop $true" = {
|
||||
writeSuccess @args
|
||||
$fsm
|
||||
}
|
||||
"TestSet Validate Stop $false" = {
|
||||
writeFail @args
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"Test Test Stop $true" = {
|
||||
writeSuccess @args
|
||||
$fsm
|
||||
}
|
||||
"Test Test Stop $false" = {
|
||||
writeFail @args
|
||||
}
|
||||
}
|
||||
}
|
||||
"Set Set Start *" = {
|
||||
writePending @args
|
||||
@{
|
||||
"Set Set Stop *" = {
|
||||
writeSuccess @args
|
||||
$fsm
|
||||
}
|
||||
}
|
||||
}
|
||||
"TestSet Test Start $false" = {
|
||||
writePending @args
|
||||
@{
|
||||
"TestSet Test Stop $true" = {
|
||||
writeSuccess @args
|
||||
$fsm
|
||||
}
|
||||
"TestSet Test Stop $false" = {
|
||||
@{
|
||||
"TestSet Set Start *" = {
|
||||
@{
|
||||
"TestSet Set Stop *" = {
|
||||
@{
|
||||
"TestSet Validate Start $false" = {
|
||||
@{
|
||||
"TestSet Validate Stop $true" = {
|
||||
writeSuccess @args
|
||||
$fsm
|
||||
}
|
||||
"TestSet Validate Stop $false" = {
|
||||
writeFail @args
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
|
@ -94,46 +94,46 @@ $fsm = @{
|
|||
Uses Write-Host
|
||||
#>
|
||||
function Format-Checklist {
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
# Logged Requirement lifecycle events
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[Alias("Event")]
|
||||
[RequirementEvent[]]$RequirementEvent
|
||||
)
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
# Logged Requirement lifecycle events
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[Alias("Event")]
|
||||
[RequirementEvent[]]$RequirementEvent
|
||||
)
|
||||
|
||||
begin {
|
||||
$previousRequirement = $null
|
||||
$nextFsm = $fsm
|
||||
}
|
||||
begin {
|
||||
$previousRequirement = $null
|
||||
$nextFsm = $fsm
|
||||
}
|
||||
|
||||
process {
|
||||
$requirement = $_.Requirement
|
||||
process {
|
||||
$requirement = $_.Requirement
|
||||
|
||||
# build state vector
|
||||
$requirementType = ("Test", "Set" | ? { $requirement.$_ }) -join ""
|
||||
$method = $_.Method
|
||||
$lifecycleState = $_.State
|
||||
$successResult = if ($method -eq "Set") { "*" } else { [bool]$_.Result }
|
||||
$stateVector = "$requirementType $method $lifecycleState $successResult"
|
||||
# build state vector
|
||||
$requirementType = ("Test", "Set" | ? { $requirement.$_ }) -join ""
|
||||
$method = $_.Method
|
||||
$lifecycleState = $_.State
|
||||
$successResult = if ($method -eq "Set") { "*" } else { [bool]$_.Result }
|
||||
$stateVector = "$requirementType $method $lifecycleState $successResult"
|
||||
|
||||
# build transition arguments
|
||||
$timestamp = Get-Date -Date $_.Date -Format "hh:mm:ss"
|
||||
$description = $requirement.Describe
|
||||
$clearString = ' ' * "??:??:?? [ ? ] $($previousRequirement.Describe)".Length
|
||||
$transitionArgs = @($timestamp, $description, $clearString)
|
||||
# build transition arguments
|
||||
$timestamp = Get-Date -Date $_.Date -Format "hh:mm:ss"
|
||||
$description = $requirement.Describe
|
||||
$clearString = ' ' * "??:??:?? [ ? ] $($previousRequirement.Describe)".Length
|
||||
$transitionArgs = @($timestamp, $description, $clearString)
|
||||
|
||||
# transition FSM
|
||||
if (-not $nextFsm[$stateVector]) {
|
||||
throw @"
|
||||
# transition FSM
|
||||
if (-not $nextFsm[$stateVector]) {
|
||||
throw @"
|
||||
Format-Checklist has reached an unexpected state '$stateVector'.
|
||||
If you are piping the output of Invoke-Requirement directly to this
|
||||
cmdlet, then this is probably a bug in Format-Checklist.
|
||||
"@
|
||||
}
|
||||
$nextFsm = &$nextFsm[$stateVector] @transitionArgs
|
||||
$previousRequirement = $requirement
|
||||
}
|
||||
$nextFsm = &$nextFsm[$stateVector] @transitionArgs
|
||||
$previousRequirement = $requirement
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
|
@ -143,79 +143,79 @@ cmdlet, then this is probably a bug in Format-Checklist.
|
|||
Uses Write-Host
|
||||
#>
|
||||
function Format-CallStack {
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "")]
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
# Logged Requirement lifecycle events
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[Alias("Event")]
|
||||
[RequirementEvent[]]$RequirementEvent
|
||||
)
|
||||
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "")]
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
# Logged Requirement lifecycle events
|
||||
[Parameter(Mandatory, ValueFromPipeline)]
|
||||
[Alias("Event")]
|
||||
[RequirementEvent[]]$RequirementEvent
|
||||
)
|
||||
|
||||
begin {
|
||||
$context = [Stack[string]]::new()
|
||||
}
|
||||
|
||||
process {
|
||||
$timestamp = Get-Date -Date $_.Date -Format 'hh:mm:ss'
|
||||
$name = $_.Requirement.Name
|
||||
$description = $_.Requirement.Describe
|
||||
$method, $state, $result = $_.Method, $_.State, $_.Result
|
||||
switch ($method) {
|
||||
"Test" {
|
||||
switch ($state) {
|
||||
"Start" {
|
||||
$context.Push($name)
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] BEGIN TEST $description"
|
||||
}
|
||||
"Stop" {
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] END TEST => $result"
|
||||
$context.Pop() | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
"Set" {
|
||||
switch ($state) {
|
||||
"Start" {
|
||||
$context.Push($name)
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] BEGIN SET $description"
|
||||
}
|
||||
"Stop" {
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] END SET"
|
||||
$context.Pop() | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
"Validate" {
|
||||
switch ($state) {
|
||||
"Start" {
|
||||
$context.Push($name)
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] BEGIN TEST $description"
|
||||
}
|
||||
"Stop" {
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] END TEST => $result"
|
||||
$context.Pop() | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
begin {
|
||||
$context = [Stack[string]]::new()
|
||||
}
|
||||
|
||||
process {
|
||||
$timestamp = Get-Date -Date $_.Date -Format 'hh:mm:ss'
|
||||
$name = $_.Requirement.Name
|
||||
$description = $_.Requirement.Describe
|
||||
$method, $state, $result = $_.Method, $_.State, $_.Result
|
||||
switch ($method) {
|
||||
"Test" {
|
||||
switch ($state) {
|
||||
"Start" {
|
||||
$context.Push($name)
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] BEGIN TEST $description"
|
||||
}
|
||||
"Stop" {
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] END TEST => $result"
|
||||
$context.Pop() | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
"Set" {
|
||||
switch ($state) {
|
||||
"Start" {
|
||||
$context.Push($name)
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] BEGIN SET $description"
|
||||
}
|
||||
"Stop" {
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] END SET"
|
||||
$context.Pop() | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
"Validate" {
|
||||
switch ($state) {
|
||||
"Start" {
|
||||
$context.Push($name)
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] BEGIN TEST $description"
|
||||
}
|
||||
"Stop" {
|
||||
$callstack = $context.ToArray()
|
||||
[array]::Reverse($callstack)
|
||||
$serialized = $callstack -join ">"
|
||||
Write-Host "$timestamp [$serialized] END TEST => $result"
|
||||
$context.Pop() | Out-Null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
"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
|
||||
)
|
||||
|
||||
testRequirements (sortRequirements $input)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,36 +13,36 @@ $OutRoot = "$PSScriptRoot/integration"
|
|||
."$RepoRoot/src/interface.ps1"
|
||||
|
||||
@{
|
||||
Describe = "Integration test output root '$OutRoot' exists"
|
||||
Test = { Test-Path $OutRoot -PathType Container }
|
||||
Set = { New-Item -ItemType Directory -Path $OutRoot }
|
||||
Describe = "Integration test output root '$OutRoot' exists"
|
||||
Test = { Test-Path $OutRoot -PathType Container }
|
||||
Set = { New-Item -ItemType Directory -Path $OutRoot }
|
||||
} | Invoke-Requirement | Out-Null
|
||||
|
||||
$context = @{count = 0}
|
||||
$context = @{ count = 0 }
|
||||
|
||||
$Requirements = @{
|
||||
Test = @{
|
||||
Name = "MyName"
|
||||
Describe = "MyDescribe"
|
||||
Test = { $true }
|
||||
}
|
||||
Set = @{
|
||||
Name = "MyName"
|
||||
Describe = "MyDescribe"
|
||||
Set = { $true }
|
||||
}
|
||||
TestSet = @{
|
||||
Name = "MyName"
|
||||
Describe = "MyDescribe"
|
||||
Test = { $context.count++ % 2 -eq 1 }
|
||||
Set = { $true }
|
||||
}
|
||||
Test = @{
|
||||
Name = "MyName"
|
||||
Describe = "MyDescribe"
|
||||
Test = { $true }
|
||||
}
|
||||
Set = @{
|
||||
Name = "MyName"
|
||||
Describe = "MyDescribe"
|
||||
Set = { $true }
|
||||
}
|
||||
TestSet = @{
|
||||
Name = "MyName"
|
||||
Describe = "MyDescribe"
|
||||
Test = { $context.count++ % 2 -eq 1 }
|
||||
Set = { $true }
|
||||
}
|
||||
}
|
||||
|
||||
$Requirements.Keys `
|
||||
| % {
|
||||
$events = $Requirements[$_] | Invoke-Requirement
|
||||
$events | Format-CallStack *> "$OutRoot/Format-CallStack.$_.txt"
|
||||
$events | Format-Checklist *> "$OutRoot/Format-Checklist.$_.txt"
|
||||
$events | Format-Table *> "$OutRoot/Format-Table.$_.txt"
|
||||
$events = $Requirements[$_] | Invoke-Requirement
|
||||
$events | Format-CallStack *> "$OutRoot/Format-CallStack.$_.txt"
|
||||
$events | Format-Checklist *> "$OutRoot/Format-Checklist.$_.txt"
|
||||
$events | Format-Table *> "$OutRoot/Format-Table.$_.txt"
|
||||
}
|
||||
|
|
|
@ -6,50 +6,50 @@ $SourceRoot = "$RepoRoot/src"
|
|||
."$SourceRoot\formatters.ps1"
|
||||
|
||||
function invoke($Requirement) {
|
||||
[RequirementEvent]::new($Requirement, "Test", "Start")
|
||||
[RequirementEvent]::new($Requirement, "Test", "Stop", $false)
|
||||
[RequirementEvent]::new($Requirement, "Set", "Start")
|
||||
[RequirementEvent]::new($Requirement, "Set", "Stop", $true)
|
||||
[RequirementEvent]::new($Requirement, "Validate", "Start")
|
||||
[RequirementEvent]::new($Requirement, "Validate", "Stop", $true)
|
||||
[RequirementEvent]::new($Requirement, "Test", "Start")
|
||||
[RequirementEvent]::new($Requirement, "Test", "Stop", $false)
|
||||
[RequirementEvent]::new($Requirement, "Set", "Start")
|
||||
[RequirementEvent]::new($Requirement, "Set", "Stop", $true)
|
||||
[RequirementEvent]::new($Requirement, "Validate", "Start")
|
||||
[RequirementEvent]::new($Requirement, "Validate", "Stop", $true)
|
||||
}
|
||||
|
||||
Describe "formatters" {
|
||||
Mock Get-Date { return "00:00:00" }
|
||||
$script:InDesiredState = 0
|
||||
$requirement = @{
|
||||
Name = "simple-requirement"
|
||||
Describe = "Simple Requirement"
|
||||
Test = { $script:InDesiredState++ }
|
||||
Set = { }
|
||||
}
|
||||
$events = invoke $requirement
|
||||
$tempContainer = $PSScriptRoot
|
||||
Context "Format-Table" {
|
||||
$output = $events | Format-Table | Out-String
|
||||
It "Should print a non-empty string" {
|
||||
$output.Trim().Length | Should -BeGreaterThan 10
|
||||
Mock Get-Date { return "00:00:00" }
|
||||
$script:InDesiredState = 0
|
||||
$requirement = @{
|
||||
Name = "simple-requirement"
|
||||
Describe = "Simple Requirement"
|
||||
Test = { $script:InDesiredState++ }
|
||||
Set = { }
|
||||
}
|
||||
}
|
||||
Context "Format-Checklist" {
|
||||
$path = "$tempContainer\$(New-Guid).txt"
|
||||
($events | Format-Checklist) *> $path
|
||||
$output = Get-Content $path -Raw
|
||||
Remove-Item $path
|
||||
It "Should format each line as a checklist" {
|
||||
$output | Should -Match "^\d\d:\d\d:\d\d \[ . \] Simple Requirement"
|
||||
$events = invoke $requirement
|
||||
$tempContainer = $PSScriptRoot
|
||||
Context "Format-Table" {
|
||||
$output = $events | Format-Table | Out-String
|
||||
It "Should print a non-empty string" {
|
||||
$output.Trim().Length | Should -BeGreaterThan 10
|
||||
}
|
||||
}
|
||||
}
|
||||
Context "Format-Callstack" {
|
||||
$path = "$tempContainer\$(New-Guid).txt"
|
||||
($events | Format-CallStack) *> $path
|
||||
$output = Get-Content $path
|
||||
Remove-Item $path
|
||||
It "Should format each line as a callstack" {
|
||||
$output | % { $_ | Should -Match "^\d\d:\d\d:\d\d \[.+\] .+" }
|
||||
Context "Format-Checklist" {
|
||||
$path = "$tempContainer\$(New-Guid).txt"
|
||||
($events | Format-Checklist) *> $path
|
||||
$output = Get-Content $path -Raw
|
||||
Remove-Item $path
|
||||
It "Should format each line as a checklist" {
|
||||
$output | Should -Match "^\d\d:\d\d:\d\d \[ . \] Simple Requirement"
|
||||
}
|
||||
}
|
||||
It "Should print 6 lines" {
|
||||
$output.Count | Should -Be 6
|
||||
Context "Format-Callstack" {
|
||||
$path = "$tempContainer\$(New-Guid).txt"
|
||||
($events | Format-CallStack) *> $path
|
||||
$output = Get-Content $path
|
||||
Remove-Item $path
|
||||
It "Should format each line as a callstack" {
|
||||
$output | % { $_ | Should -Match "^\d\d:\d\d:\d\d \[.+\] .+" }
|
||||
}
|
||||
It "Should print 6 lines" {
|
||||
$output.Count | Should -Be 6
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
10:27:29 [MyName] BEGIN SET MyDescribe
|
||||
10:27:29 [MyName] END SET
|
||||
02:17:08 [MyName] BEGIN SET MyDescribe
|
||||
02:17:08 [MyName] END SET
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
10:27:29 [MyName] BEGIN TEST MyDescribe
|
||||
10:27:29 [MyName] END TEST => True
|
||||
02:17:08 [MyName] BEGIN TEST MyDescribe
|
||||
02:17:08 [MyName] END TEST => True
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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
|
||||
02:17:08 [MyName] BEGIN TEST MyDescribe
|
||||
02:17:08 [MyName] END TEST => False
|
||||
02:17:08 [MyName] BEGIN SET MyDescribe
|
||||
02:17:08 [MyName] END SET
|
||||
02:17:08 [MyName] BEGIN TEST MyDescribe
|
||||
02:17:08 [MyName] END TEST => True
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
10:27:29 [ ] MyDescribe
|
||||
02:17:08 [ ] MyDescribe
|
||||
|
||||
10:27:29 [ √ ] MyDescribe
|
||||
02:17:08 [ √ ] MyDescribe
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
10:27:29 [ ] MyDescribe
|
||||
02:17:08 [ ] MyDescribe
|
||||
|
||||
10:27:29 [ √ ] MyDescribe
|
||||
02:17:08 [ √ ] MyDescribe
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
10:27:29 [ ] MyDescribe
|
||||
02:17:08 [ ] MyDescribe
|
||||
|
||||
10:27:29 [ √ ] MyDescribe
|
||||
02:17:08 [ √ ] MyDescribe
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
Date Method State Result Requirement
|
||||
---- ------ ----- ------ -----------
|
||||
9/21/19 10:27:29 AM Set Start MyName
|
||||
9/21/19 10:27:29 AM Set Stop True MyName
|
||||
Date Method State Result Requirement
|
||||
---- ------ ----- ------ -----------
|
||||
9/22/19 2:17:08 PM Set Start MyName
|
||||
9/22/19 2:17:08 PM Set Stop True MyName
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
Date Method State Result Requirement
|
||||
---- ------ ----- ------ -----------
|
||||
9/21/19 10:27:29 AM Test Start MyName
|
||||
9/21/19 10:27:29 AM Test Stop True MyName
|
||||
Date Method State Result Requirement
|
||||
---- ------ ----- ------ -----------
|
||||
9/22/19 2:17:08 PM Test Start MyName
|
||||
9/22/19 2:17:08 PM Test Stop True MyName
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
Date Method State Result Requirement
|
||||
---- ------ ----- ------ -----------
|
||||
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
|
||||
Date Method State Result Requirement
|
||||
---- ------ ----- ------ -----------
|
||||
9/22/19 2:17:08 PM Test Start MyName
|
||||
9/22/19 2:17:08 PM Test Stop False MyName
|
||||
9/22/19 2:17:08 PM Set Start MyName
|
||||
9/22/19 2:17:08 PM Set Stop True MyName
|
||||
9/22/19 2:17:08 PM Validate Start MyName
|
||||
9/22/19 2:17:08 PM Validate Stop True MyName
|
||||
|
||||
|
|
|
@ -7,99 +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 "'Dsc' parameter set" {
|
||||
It "Should not be empty" -Skip:$PlatformLacksDscSupport {
|
||||
$requirement = @{
|
||||
Describe = "My Dsc Requirement"
|
||||
ResourceName = "File"
|
||||
ModuleName = "PSDesiredStateConfiguration"
|
||||
Property = @{
|
||||
Contents = ""
|
||||
DestinationFile = ""
|
||||
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 "'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
|
||||
}
|
||||
}
|
||||
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 "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
|
||||
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
|
||||
}
|
||||
}
|
||||
New-Requirement @params | Invoke-Requirement
|
||||
Get-Content $tempFilePath | Should -Be $content
|
||||
Remove-Item $tempFilePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Test-Requirement" {
|
||||
It "Should not error" {
|
||||
$requirement = @{
|
||||
Test = { $true }
|
||||
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" }
|
||||
}
|
||||
{ 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 }
|
||||
It "Should not error" {
|
||||
$requirement = @{
|
||||
Set = { $false }
|
||||
}
|
||||
{ Invoke-Requirement $requirement } | Should -Not -Throw
|
||||
}
|
||||
{ Invoke-Requirement $requirement } | Should -Not -Throw
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue