GraphRunbook.Tests.ps1
$here = Split-Path -Parent $MyInvocation.MyCommand.Path $sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.ps1$' Get-Module -Name $sut -All | Remove-Module -Force -ErrorAction Ignore Import-Module -Name "$here\$sut.psm1" -Force -ErrorAction Stop InModuleScope $sut { function WithRunbookFile( [Orchestrator.GraphRunbook.Model.GraphRunbook]$Runbook, [scriptblock]$Action) { $SerializedRunbook = [Orchestrator.GraphRunbook.Model.Serialization.RunbookSerializer]::Serialize($Runbook) $File = New-TemporaryFile try { $SerializedRunbook | Out-File $File.FullName $Action.Invoke($File) } finally { Remove-Item $File -ErrorAction SilentlyContinue } } Describe "Show-GraphRunbookActivityTraces" { $TestJobId = New-Guid $TestResourceGroup = 'TestResourceGroupName' $TestAutomationAccount = 'TestAccountName' $TestJobOutputRecords = @( @{ Value = @{ Message = 'GraphTrace:{Activity:"Activity1",Event:"ActivityStart",Time:"2016-11-23 23:04"}' } }, @{ Value = @{ Message = 'GraphTrace:{Activity:"Activity1",Event:"ActivityInput",Time:"2016-11-23 23:05",Values:{Data:{Input1:"A",Input2:"B"}}}' } }, @{ Value = @{ Message = 'GraphTrace:{Activity:"Activity1",Event:"ActivityOutput",Time:"2016-11-23 23:05"}' } }, @{ Value = @{ Message = 'GraphTrace:{Activity:"Activity1",Event:"ActivityEnd",Time:"2016-11-23 23:06",DurationSeconds:1.2}' } }, @{ Value = @{ Message = 'GraphTrace:{Activity:"Activity2",Event:"ActivityStart",Time:"2016-11-23 23:09"}' } }, @{ Value = @{ Message = 'GraphTrace:{Activity:"Activity2",Event:"ActivityOutput",Time:"2016-11-23 23:12",Values:{Data:[2,7,1]}}' } }, @{ Value = @{ Message = 'GraphTrace:{Activity:"Activity2",Event:"ActivityEnd",Time:"2016-11-23 23:13",DurationSeconds:7}' } } ) function VerifyShowObjectInput($InputObject) { $InputObject | Should not be $null $InputObject | Measure-Object | % Count | Should be 1 $InputObject.'Job ID' | Should be $TestJobId $ActivityExecutionInstances = $InputObject.'Activity execution instances' $ActivityExecutionInstances | Measure-Object | % Count | Should be 2 $ActivityExecutionInstances[0].Activity | Should be 'Activity1' $ActivityExecutionInstances[0].Start | Should be (Get-Date '2016-11-23 23:04') $ActivityExecutionInstances[0].End | Should be (Get-Date '2016-11-23 23:06') $ActivityExecutionInstances[0].Duration | Should be ([System.TimeSpan]::FromSeconds(1.2)) $ActivityExecutionInstances[0].Input | Should not be $null $ActivityExecutionInstances[0].Input.Input1 | Should be "A" $ActivityExecutionInstances[0].Input.Input2 | Should be "B" $ActivityExecutionInstances[0].Output | Should be $null $ActivityExecutionInstances[1].Activity | Should be 'Activity2' $ActivityExecutionInstances[1].Start | Should be (Get-Date '2016-11-23 23:09') $ActivityExecutionInstances[1].End | Should be (Get-Date '2016-11-23 23:13') $ActivityExecutionInstances[1].Duration | Should be ([System.TimeSpan]::FromSeconds(7)) $ActivityExecutionInstances[1].Input | Should be $null $ActivityExecutionInstances[1].Output | Measure-Object | % Count | Should be 3 $ActivityExecutionInstances[1].Output[0] | Should be 2 $ActivityExecutionInstances[1].Output[1] | Should be 7 $ActivityExecutionInstances[1].Output[2] | Should be 1 } Context "When Graph Runbook activity traces exist and job ID is known" { Mock Get-AzureRmAutomationJobOutput -Verifiable ` -ParameterFilter { ($ResourceGroupName -eq $TestResourceGroup) -and ($AutomationAccountName -eq $TestAutomationAccount) -and ($JobId -eq $TestJobId) -and ($Stream -eq 'Verbose') } ` -MockWith { 0..($TestJobOutputRecords.Length - 1) } function Get-AzureRmAutomationJobOutputRecord { [CmdletBinding()] param ([Parameter(ValueFromPipeline = $true)] $Id) process { $TestJobOutputRecords[$Id] } } Mock Show-Object -Verifiable ` -MockWith { VerifyShowObjectInput -InputObject $InputObject } Show-GraphRunbookActivityTraces ` -ResourceGroupName $TestResourceGroup ` -AutomationAccountName $TestAutomationAccount ` -JobId $TestJobId It "Shows Graph Runbook activity traces" { Assert-VerifiableMocks } } Context "When Graph Runbook activity traces exist and runbook name is known" { $TestRunbookName = 'TestRunbookName' Mock Get-AzureRmAutomationJob -Verifiable ` -ParameterFilter { ($ResourceGroupName -eq $TestResourceGroup) -and ($AutomationAccountName -eq $TestAutomationAccount) -and ($RunbookName -eq $TestRunbookName) } ` -MockWith { $LatestJobStartTime = Get-Date New-Object PSObject -Property @{ StartTime = $LatestJobStartTime - [System.TimeSpan]::FromSeconds(1); JobId = New-Guid } New-Object PSObject -Property @{ StartTime = $LatestJobStartTime; JobId = $TestJobId } New-Object PSObject -Property @{ StartTime = $LatestJobStartTime - [System.TimeSpan]::FromSeconds(2); JobId = New-Guid } } Mock Get-AzureRmAutomationJobOutput -Verifiable ` -ParameterFilter { ($ResourceGroupName -eq $TestResourceGroup) -and ($AutomationAccountName -eq $TestAutomationAccount) -and ($Stream -eq 'Verbose') } ` -MockWith { $JobId | Should be $TestJobId > $null 0..($TestJobOutputRecords.Length - 1) } function Get-AzureRmAutomationJobOutputRecord { [CmdletBinding()] param ([Parameter(ValueFromPipeline = $true)] $Id) process { $TestJobOutputRecords[$Id] } } Mock Show-Object -Verifiable ` -MockWith { VerifyShowObjectInput -InputObject $InputObject } Show-GraphRunbookActivityTraces ` -ResourceGroupName $TestResourceGroup ` -AutomationAccountName $TestAutomationAccount ` -RunbookName $TestRunbookName It "Shows Graph Runbook activity traces" { Assert-VerifiableMocks } } Context "When no Graph Runbook activity traces" { Mock Get-AzureRmAutomationJobOutput -Verifiable ` -ParameterFilter { ($ResourceGroupName -eq $TestResourceGroup) -and ($AutomationAccountName -eq $TestAutomationAccount) -and ($JobId -eq $TestJobId) -and ($Stream -eq 'Verbose') } ` -MockWith { 1 } function Get-AzureRmAutomationJobOutputRecord { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] $Id) @{ Value = @{ Message = 'Regular verbose message' } } } Mock Write-Error -Verifiable ` -MockWith { $Message | Should be ('No activity traces found. Make sure activity tracing and ' + 'logging Verbose stream are enabled in the runbook configuration.') } Show-GraphRunbookActivityTraces ` -ResourceGroupName $TestResourceGroup ` -AutomationAccountName $TestAutomationAccount ` -JobId $TestJobId It "Shows 'no activity traces' message" { Assert-VerifiableMocks } } Context "When no Verbose output" { Mock Get-AzureRmAutomationJobOutput -Verifiable ` -ParameterFilter { ($ResourceGroupName -eq $TestResourceGroup) -and ($AutomationAccountName -eq $TestAutomationAccount) -and ($JobId -eq $TestJobId) -and ($Stream -eq 'Verbose') } Mock Get-AzureRmAutomationJobOutputRecord Mock Write-Error -Verifiable ` -MockWith { $Message | Should be ('No activity traces found. Make sure activity tracing and ' + 'logging Verbose stream are enabled in the runbook configuration.') } Show-GraphRunbookActivityTraces ` -ResourceGroupName $TestResourceGroup ` -AutomationAccountName $TestAutomationAccount ` -JobId $TestJobId It "Shows 'no activity traces' message" { Assert-VerifiableMocks Assert-MockCalled Get-AzureRmAutomationJobOutputRecord -Times 0 } } } Describe "Convert-GraphRunbookToPowerShellData" { Add-GraphRunbookModelAssembly Context "When GraphRunbook is empty" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be @" @{ } "@ } } Context "When GraphRunbook has parameters" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $ParameterA = New-Object Orchestrator.GraphRunbook.Model.Parameter -ArgumentList 'ParamA' $ParameterA.Optional = $false $ParameterA.Description = 'Parameter description' $Runbook.AddParameter($ParameterA) $ParameterB = New-Object Orchestrator.GraphRunbook.Model.Parameter -ArgumentList 'ParamB' $ParameterB.Optional = $true $ParameterB.DefaultValue = 'Default value' $Runbook.AddParameter($ParameterB) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be @" @{ Parameters = @( @{ Name = 'ParamA' Description = 'Parameter description' Mandatory = `$true } @{ Name = 'ParamB' DefaultValue = 'Default value' } ) } "@ } } Context "When GraphRunbook contains Code activity" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $Activity = New-Object Orchestrator.GraphRunbook.Model.WorkflowScriptActivity -ArgumentList 'Activity name' $Activity.Description = 'Activity description' $Activity.Begin = "'Begin code block'" $Activity.Process = "'Process code block'" $Activity.End = "'End code block'" $Activity.CheckpointAfter = $true $Activity.ExceptionsToErrors = $true $Activity.LoopExitCondition = '$RetryData.NumberOfAttempts -gt 5' $Activity.PositionX = 12 $Activity.PositionY = 456 $Runbook.AddActivity($Activity) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be @" @{ Activities = @( @{ Name = 'Activity name' Description = 'Activity description' Type = 'Code' Begin = { 'Begin code block' } Process = { 'Process code block' } End = { 'End code block' } CheckpointAfter = `$true ExceptionsToErrors = `$true Retry = @{ ExitCondition = { `$RetryData.NumberOfAttempts -gt 5 } } Position = 12, 456 } ) } "@ } } Context "When GraphRunbook contains Command activity" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $CommandActivityType = New-Object Orchestrator.GraphRunbook.Model.CommandActivityType $CommandActivityType.ModuleName = 'MyModule' $CommandActivityType.CommandName = 'Do-Something' $Activity = New-Object Orchestrator.GraphRunbook.Model.CommandActivity -ArgumentList 'Activity name', $CommandActivityType $Activity.Parameters = New-Object Orchestrator.GraphRunbook.Model.ActivityParameters $Activity.Parameters.Add("Parameter1", (New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList 'Value 1')) $Activity.Parameters.Add("Parameter2", (New-Object Orchestrator.GraphRunbook.Model.ActivityOutputValueDescriptor -ArgumentList 'Activity A')) $Activity.Parameters.Add("Parameter3", (New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList @($null))) $Activity.CustomParameters = '-CustomParam CustomValue' $Activity.Description = 'Activity description' $Activity.CheckpointAfter = $true $Activity.ExceptionsToErrors = $true $Activity.LoopExitCondition = '$RetryData.NumberOfAttempts -gt 5' $LoopDelayTimeSpan = New-Object System.TimeSpan -ArgumentList 8765 $Activity.LoopDelay = New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList $LoopDelayTimeSpan $Activity.PositionX = 12 $Activity.PositionY = 456 $Runbook.AddActivity($Activity) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be @" @{ Activities = @( @{ Name = 'Activity name' Description = 'Activity description' Type = 'Command' ModuleName = 'MyModule' CommandName = 'Do-Something' Parameters = @{ Parameter1 = 'Value 1' Parameter2 = @{ SourceType = 'ActivityOutput' Activity = 'Activity A' } Parameter3 = `$null } CustomParameters = '-CustomParam CustomValue' CheckpointAfter = `$true ExceptionsToErrors = `$true Retry = @{ ExitCondition = { `$RetryData.NumberOfAttempts -gt 5 } Delay = 8765 } Position = 12, 456 } ) } "@ } } Context "When GraphRunbook contains minimal Command activity" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $CommandActivityType = New-Object Orchestrator.GraphRunbook.Model.CommandActivityType $CommandActivityType.CommandName = 'Do-Something' $Activity = New-Object Orchestrator.GraphRunbook.Model.CommandActivity -ArgumentList 'Activity name', $CommandActivityType $Runbook.AddActivity($Activity) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be @" @{ Activities = @( @{ Name = 'Activity name' Type = 'Command' CommandName = 'Do-Something' } ) } "@ } } Context "When GraphRunbook contains InvokeRunbook activity" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $InvokeRunbookActivityType = New-Object Orchestrator.GraphRunbook.Model.InvokeRunbookActivityType $InvokeRunbookActivityType.CommandName = 'Do-Something' $Activity = New-Object Orchestrator.GraphRunbook.Model.InvokeRunbookActivity -ArgumentList 'Activity name', $InvokeRunbookActivityType $Activity.Parameters = New-Object Orchestrator.GraphRunbook.Model.ActivityParameters $Activity.Parameters.Add("Parameter1", (New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList 'Value 1')) $Activity.Parameters.Add("Parameter2", (New-Object Orchestrator.GraphRunbook.Model.ActivityOutputValueDescriptor -ArgumentList 'Activity A')) $Activity.Parameters.Add("Parameter3", (New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList @($null))) $Activity.CustomParameters = '-CustomParam CustomValue' $Activity.Description = 'Activity description' $Activity.CheckpointAfter = $true $Activity.ExceptionsToErrors = $true $Activity.LoopExitCondition = '$RetryData.NumberOfAttempts -gt 5' $Activity.PositionX = 12 $Activity.PositionY = 456 $Runbook.AddActivity($Activity) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be @" @{ Activities = @( @{ Name = 'Activity name' Description = 'Activity description' Type = 'InvokeRunbook' CommandName = 'Do-Something' Parameters = @{ Parameter1 = 'Value 1' Parameter2 = @{ SourceType = 'ActivityOutput' Activity = 'Activity A' } Parameter3 = `$null } CustomParameters = '-CustomParam CustomValue' CheckpointAfter = `$true ExceptionsToErrors = `$true Retry = @{ ExitCondition = { `$RetryData.NumberOfAttempts -gt 5 } } Position = 12, 456 } ) } "@ } } Context "When GraphRunbook contains Junction activity" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $Activity = New-Object Orchestrator.GraphRunbook.Model.JunctionActivity -ArgumentList 'Activity name' $Activity.Description = 'Activity description' $Activity.CheckpointAfter = $true $Activity.PositionX = 12 $Activity.PositionY = 456 $Runbook.AddActivity($Activity) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be @" @{ Activities = @( @{ Name = 'Activity name' Description = 'Activity description' Type = 'Junction' CheckpointAfter = `$true Position = 12, 456 } ) } "@ } } function CreateRunbookWithCommandActivityWithParameter($ValueDescriptor) { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $CommandActivityType = New-Object Orchestrator.GraphRunbook.Model.CommandActivityType $CommandActivityType.CommandName = 'Do-Something' $Activity = New-Object Orchestrator.GraphRunbook.Model.CommandActivity -ArgumentList 'Activity name', $CommandActivityType $Activity.Parameters = New-Object Orchestrator.GraphRunbook.Model.ActivityParameters $Activity.Parameters.Add('ParameterName', $ValueDescriptor) [void]$Runbook.AddActivity($Activity) $Runbook } function CreateExpectedRunbookTextWithCommandActivityWithParameter($ParameterText) { @" @{ Activities = @( @{ Name = 'Activity name' Type = 'Command' CommandName = 'Do-Something' Parameters = @{ ParameterName = $ParameterText } } ) } "@ } Context "When GraphRunbook contains Command activity with ConstantValueDescriptor" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList 'Parameter value') It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter "'Parameter value'") } } Context "When GraphRunbook contains Command activity with NullConstantValueDescriptor" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.NullConstantValueDescriptor) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter "`$null") } } Context "When GraphRunbook contains Command activity with EmptyStringConstantValueDescriptor" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.EmptyStringConstantValueDescriptor) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter "''") } } Context "When GraphRunbook contains Command activity with ActivityOutputValueDescriptor (activity name only)" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.ActivityOutputValueDescriptor -ArgumentList 'Source activity') It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter @" @{ SourceType = 'ActivityOutput' Activity = 'Source activity' } "@) } } Context "When GraphRunbook contains Command activity with ActivityOutputValueDescriptor (activity name and field path)" { $FieldPath = New-Object 'System.Collections.Generic.List`1[string]' $FieldPath.Add('Field1') $FieldPath.Add('Field2') $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.ActivityOutputValueDescriptor -ArgumentList 'Source activity', $FieldPath) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter @" @{ SourceType = 'ActivityOutput' Activity = 'Source activity' FieldPath = @( 'Field1' 'Field2' ) } "@) } } Context "When GraphRunbook contains Command activity with PowerShellExpressionValueDescriptor" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.PowerShellExpressionValueDescriptor -ArgumentList '"PowerShell expression"') It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter @" { "PowerShell expression" } "@) } } Context "When GraphRunbook contains Command activity with RunbookParameterValueDescriptor" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.RunbookParameterValueDescriptor -ArgumentList 'RunbookParameterName') It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter @" @{ SourceType = 'RunbookParameter' Name = 'RunbookParameterName' } "@) } } Context "When GraphRunbook contains Command activity with AutomationCertificateValueDescriptor" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.AutomationCertificateValueDescriptor -ArgumentList 'AssetName') It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter @" @{ SourceType = 'AutomationCertificate' Name = 'AssetName' } "@) } } Context "When GraphRunbook contains Command activity with AutomationCredentialValueDescriptor" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.AutomationCredentialValueDescriptor -ArgumentList 'AssetName') It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter @" @{ SourceType = 'AutomationCredential' Name = 'AssetName' } "@) } } Context "When GraphRunbook contains Command activity with AutomationConnectionValueDescriptor" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.AutomationConnectionValueDescriptor -ArgumentList 'AssetName') It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter @" @{ SourceType = 'AutomationConnection' Name = 'AssetName' } "@) } } Context "When GraphRunbook contains Command activity with AutomationVariableValueDescriptor" { $Runbook = CreateRunbookWithCommandActivityWithParameter ` -ValueDescriptor (New-Object Orchestrator.GraphRunbook.Model.AutomationVariableValueDescriptor -ArgumentList 'AssetName') It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookTextWithCommandActivityWithParameter @" @{ SourceType = 'AutomationVariable' Name = 'AssetName' } "@) } } function CreateRunbookWithLink($LinkType) { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $ActivityA = New-Object Orchestrator.GraphRunbook.Model.WorkflowScriptActivity -ArgumentList 'Activity A' [void]$Runbook.AddActivity($ActivityA) $ActivityB = New-Object Orchestrator.GraphRunbook.Model.WorkflowScriptActivity -ArgumentList 'Activity B' [void]$Runbook.AddActivity($ActivityB) $LinkAtoB = New-Object Orchestrator.GraphRunbook.Model.Link -ArgumentList $ActivityA, $ActivityB, $LinkType [void]$Runbook.AddLink($LinkAtoB) $Runbook $LinkAtoB } function CreateExpectedRunbookWithLinkText($LinkText) { @" @{ Activities = @( @{ Name = 'Activity A' Type = 'Code' } @{ Name = 'Activity B' Type = 'Code' } ) Links = @( $LinkText ) } "@ } Context "When GraphRunbook contains regular sequence link" { $Runbook, $Link = CreateRunbookWithLink -LinkType Sequence $Link.Condition = '$ActivityOutput[''A''].Count -gt 0' $Link.LinkStreamType = 'Output' It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookWithLinkText @" @{ From = 'Activity A' To = 'Activity B' Type = 'Sequence' Condition = { `$ActivityOutput['A'].Count -gt 0 } } "@) } } Context "When GraphRunbook contains error pipeline link" { $Runbook, $Link = CreateRunbookWithLink -LinkType Pipeline $Link.Condition = '$ActivityOutput[''A''].Count -gt 0' $Link.LinkStreamType = 'Error' It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookWithLinkText @" @{ From = 'Activity A' To = 'Activity B' Stream = 'Error' Type = 'Pipeline' Condition = { `$ActivityOutput['A'].Count -gt 0 } } "@) } } Context "When GraphRunbook contains link with description" { $Runbook, $Link = CreateRunbookWithLink -LinkType Pipeline $Link.Description = 'My link description' It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookWithLinkText @" @{ From = 'Activity A' To = 'Activity B' Description = 'My link description' Type = 'Pipeline' } "@) } } Context "When GraphRunbook contains link with empty description" { $Runbook, $Link = CreateRunbookWithLink -LinkType Pipeline $Link.Description = '' It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be (CreateExpectedRunbookWithLinkText @" @{ From = 'Activity A' To = 'Activity B' Type = 'Pipeline' } "@) } } Context "When GraphRunbook contains activities, links, output types, and comments" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $ParameterA = New-Object Orchestrator.GraphRunbook.Model.Parameter -ArgumentList 'ParamA' $Runbook.AddParameter($ParameterA) $ParameterB = New-Object Orchestrator.GraphRunbook.Model.Parameter -ArgumentList 'ParamB' $Runbook.AddParameter($ParameterB) $Comment1 = New-Object Orchestrator.GraphRunbook.Model.Comment -ArgumentList 'First comment' $Comment1.Text = 'First comment text' $Runbook.AddComment($Comment1) $Comment2 = New-Object Orchestrator.GraphRunbook.Model.Comment -ArgumentList 'Second comment' $Comment2.Text = 'Second comment text' $Runbook.AddComment($Comment2) $Runbook.AddOutputType('First output type'); $Runbook.AddOutputType('Second output type'); $ActivityA = New-Object Orchestrator.GraphRunbook.Model.WorkflowScriptActivity -ArgumentList 'Activity A' $ActivityA.Process = "'Hello'" $Runbook.AddActivity($ActivityA) $CommandActivityType = New-Object Orchestrator.GraphRunbook.Model.CommandActivityType $CommandActivityType.CommandName = 'Get-Date' $ActivityB = New-Object Orchestrator.GraphRunbook.Model.CommandActivity -ArgumentList 'Activity B', $CommandActivityType $ActivityB.Parameters = New-Object Orchestrator.GraphRunbook.Model.ActivityParameters $ActivityB.Parameters.Add("Parameter1", (New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList 'Value 1')) $ActivityB.Parameters.Add("Parameter2", (New-Object Orchestrator.GraphRunbook.Model.ActivityOutputValueDescriptor -ArgumentList 'Activity A')) $ActivityB.Parameters.Add("Parameter3", (New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList @($null))) $Runbook.AddActivity($ActivityB) $LinkAtoB = New-Object Orchestrator.GraphRunbook.Model.Link -ArgumentList $ActivityA, $ActivityB, Pipeline $Runbook.AddLink($LinkAtoB) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -Runbook $Runbook $Text | Should be @" @{ Parameters = @( @{ Name = 'ParamA' } @{ Name = 'ParamB' } ) Comments = @( @{ Name = 'First comment' Text = 'First comment text' } @{ Name = 'Second comment' Text = 'Second comment text' } ) OutputTypes = @( 'First output type' 'Second output type' ) Activities = @( @{ Name = 'Activity A' Type = 'Code' Process = { 'Hello' } } @{ Name = 'Activity B' Type = 'Command' CommandName = 'Get-Date' Parameters = @{ Parameter1 = 'Value 1' Parameter2 = @{ SourceType = 'ActivityOutput' Activity = 'Activity A' } Parameter3 = `$null } } ) Links = @( @{ From = 'Activity A' To = 'Activity B' Type = 'Pipeline' } ) } "@ } } Context "When .graphrunbook file name is provided" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $Activity = New-Object Orchestrator.GraphRunbook.Model.WorkflowScriptActivity -ArgumentList 'Activity' $Runbook.AddActivity($Activity) WithRunbookFile -Runbook $Runbook -Action { param($File) It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData -RunbookFileName $File.FullName $Text | Should be @" @{ Activities = @( @{ Name = 'Activity' Type = 'Code' } ) } "@ } } } Context "When runbook name is provided" { $TestResourceGroup = 'TestResourceGroupName' $TestAutomationAccount = 'TestAccountName' $TestRunbookName = 'TestRunbookName' Mock Export-AzureRMAutomationRunbook -Verifiable ` -MockWith { $ResourceGroupName | Should be $TestResourceGroup > $null $AutomationAccountName | Should be $AutomationAccountName > $null $Name | Should be $TestRunbookName > $null $Slot | Should be 'Published' > $null $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $Activity = New-Object Orchestrator.GraphRunbook.Model.WorkflowScriptActivity -ArgumentList 'Activity' [void]$Runbook.AddActivity($Activity) $SerializedRunbook = [Orchestrator.GraphRunbook.Model.Serialization.RunbookSerializer]::Serialize($Runbook) $OutputFileName = Join-Path $OutputFolder "$Name.graphrunbook" $SerializedRunbook | Out-File $OutputFileName Get-Item -Path $OutputFileName } It "Converts GraphRunbook to text" { $Text = Convert-GraphRunbookToPowerShellData ` -RunbookName $TestRunbookName ` -ResourceGroupName $TestResourceGroup ` -AutomationAccount $TestAutomationAccount $Text | Should be @" @{ Activities = @( @{ Name = 'Activity' Type = 'Code' } ) } "@ Assert-VerifiableMocks } } } Describe "Get-GraphRunbookDependency" { function New-CommandActivity($ModuleName, $CommandName = 'Do-Something', $ValueDescriptors) { $CommandActivityType = New-Object Orchestrator.GraphRunbook.Model.CommandActivityType $CommandActivityType.ModuleName = $ModuleName $CommandActivityType.CommandName = $CommandName $Activity = New-Object Orchestrator.GraphRunbook.Model.CommandActivity -ArgumentList New-Guid, $CommandActivityType $Activity.Parameters = New-Object Orchestrator.GraphRunbook.Model.ActivityParameters foreach ($ValueDescriptor in $ValueDescriptors) { [void]$Activity.Parameters.Add((New-Guid).ToString(), $ValueDescriptor) } $Activity } function New-AssetAccessCommandActivity($ModuleName, $CommandName, $AssetName) { $CommandActivityType = New-Object Orchestrator.GraphRunbook.Model.CommandActivityType $CommandActivityType.CommandName = $CommandName $Activity = New-Object Orchestrator.GraphRunbook.Model.CommandActivity -ArgumentList New-Guid, $CommandActivityType $Activity.Parameters = New-Object Orchestrator.GraphRunbook.Model.ActivityParameters $ValueDescriptor = New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList $AssetName [void]$Activity.Parameters.Add('Name', $ValueDescriptor) $Activity } function New-GetAutomationCertificateActivity($CertificateName) { New-AssetAccessCommandActivity -CommandName 'Get-AutomationCertificate' -AssetName $CertificateName } function New-GetAutomationConnectionActivity($ConnectionName) { New-AssetAccessCommandActivity -CommandName 'Get-AutomationConnection' -AssetName $ConnectionName } function New-GetAutomationCredentialActivity($CredentialName) { New-AssetAccessCommandActivity -CommandName 'Get-AutomationPSCredential' -AssetName $CredentialName } function New-GetAutomationVariableActivity($VariableName) { New-AssetAccessCommandActivity -CommandName 'Get-AutomationVariable' -AssetName $VariableName } function New-SetAutomationVariableActivity($VariableName) { New-AssetAccessCommandActivity -CommandName 'Set-AutomationVariable' -AssetName $VariableName } function New-InvokeRunbookActivity($RunbookName, $ValueDescriptors) { $InvokeRunbookCommandActivityType = New-Object Orchestrator.GraphRunbook.Model.InvokeRunbookActivityType $InvokeRunbookCommandActivityType.CommandName = $RunbookName $Activity = New-Object Orchestrator.GraphRunbook.Model.InvokeRunbookActivity -ArgumentList New-Guid, $InvokeRunbookCommandActivityType $Activity.Parameters = New-Object Orchestrator.GraphRunbook.Model.ActivityParameters foreach ($ValueDescriptor in $ValueDescriptors) { [void]$Activity.Parameters.Add((New-Guid).ToString(), $ValueDescriptor) } $Activity } Context "When modules are requested" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $Runbook.AddActivity((New-CommandActivity -ModuleName 'ModuleA')) $Runbook.AddActivity((New-CommandActivity -ModuleName 'ModuleB')) $Runbook.AddActivity((New-CommandActivity -ModuleName 'ModuleA')) $Runbook.AddActivity((New-CommandActivity -ModuleName '')) $Runbook.AddActivity((New-CommandActivity -ModuleName 'modulea')) $Runbook.AddActivity((New-CommandActivity -ModuleName 'MODULEB')) It "Outputs required modules" { $RequiredModules = Get-GraphRunbookDependency -Runbook $Runbook -DependencyType Module $RequiredModules | Measure-Object | ForEach-Object Count | Should be 2 ($RequiredModules[0].Name -ieq 'ModuleA') | Should be $true $RequiredModules[0].Type | Should be 'Module' ($RequiredModules[1].Name -ieq 'ModuleB') | Should be $true $RequiredModules[1].Type | Should be 'Module' } } Context "When Automation Assets are requested" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $Runbook.AddActivity((New-CommandActivity -ValueDescriptors ` (New-Object Orchestrator.GraphRunbook.Model.AutomationVariableValueDescriptor -ArgumentList 'Variable1'), (New-Object Orchestrator.GraphRunbook.Model.AutomationCredentialValueDescriptor -ArgumentList 'Credential1'), (New-Object Orchestrator.GraphRunbook.Model.AutomationVariableValueDescriptor -ArgumentList 'VARIABLE1'), (New-Object Orchestrator.GraphRunbook.Model.AutomationConnectionValueDescriptor -ArgumentList 'Connection3'), (New-Object Orchestrator.GraphRunbook.Model.AutomationVariableValueDescriptor -ArgumentList 'Variable2'), (New-Object Orchestrator.GraphRunbook.Model.AutomationCertificateValueDescriptor -ArgumentList 'Certificate2'))) $Runbook.AddActivity((New-CommandActivity -ValueDescriptors @())) $Runbook.AddActivity((New-CommandActivity -ValueDescriptors ` (New-Object Orchestrator.GraphRunbook.Model.AutomationConnectionValueDescriptor -ArgumentList 'Connection2'), (New-Object Orchestrator.GraphRunbook.Model.AutomationVariableValueDescriptor -ArgumentList 'variable1'), (New-Object Orchestrator.GraphRunbook.Model.AutomationCertificateValueDescriptor -ArgumentList 'certificate1'), (New-Object Orchestrator.GraphRunbook.Model.AutomationConnectionValueDescriptor -ArgumentList 'Connection1'))) $Runbook.AddActivity((New-GetAutomationCertificateActivity -CertificateName 'Certificate3')) $Runbook.AddActivity((New-GetAutomationConnectionActivity -ConnectionName 'Connection4')) $Runbook.AddActivity((New-GetAutomationCredentialActivity -CredentialName 'Credential2')) $Runbook.AddActivity((New-GetAutomationVariableActivity -VariableName 'Variable3')) $Runbook.AddActivity((New-SetAutomationVariableActivity -VariableName 'variable4')) It "Outputs required Automation Assets" { $RequiredAssets = Get-GraphRunbookDependency -Runbook $Runbook -DependencyType AutomationAsset $RequiredAssets | Measure-Object | ForEach-Object Count | Should be 13 $RequiredVariables = $RequiredAssets | Where-Object { $_.Type -eq 'AutomationVariable' } $RequiredVariables | Measure-Object | ForEach-Object Count | Should be 4 ($RequiredVariables[0].Name -ieq 'Variable1') | Should be $true $RequiredVariables[1].Name | Should be 'Variable2' $RequiredVariables[2].Name | Should be 'Variable3' $RequiredVariables[3].Name | Should be 'variable4' $RequiredCertificates = $RequiredAssets | Where-Object { $_.Type -eq 'AutomationCertificate' } $RequiredCertificates | Measure-Object | ForEach-Object Count | Should be 3 $RequiredCertificates[0].Name | Should be 'certificate1' $RequiredCertificates[1].Name | Should be 'Certificate2' $RequiredCertificates[2].Name | Should be 'Certificate3' $RequiredConnections = $RequiredAssets | Where-Object { $_.Type -eq 'AutomationConnection' } $RequiredConnections | Measure-Object | ForEach-Object Count | Should be 4 $RequiredConnections[0].Name | Should be 'Connection1' $RequiredConnections[1].Name | Should be 'Connection2' $RequiredConnections[2].Name | Should be 'Connection3' $RequiredConnections[3].Name | Should be 'Connection4' $RequiredCredentials = $RequiredAssets | Where-Object { $_.Type -eq 'AutomationCredential' } $RequiredCredentials | Measure-Object | ForEach-Object Count | Should be 2 $RequiredCredentials[0].Name | Should be 'Credential1' $RequiredCredentials[1].Name | Should be 'Credential2' } } Context "When runbooks are requested" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $Runbook.AddActivity((New-InvokeRunbookActivity -RunbookName 'RunbookA')) $Runbook.AddActivity((New-InvokeRunbookActivity -RunbookName 'RunbookB')) $Runbook.AddActivity((New-InvokeRunbookActivity -RunbookName 'runbooka')) $CommandActivityType = New-Object Orchestrator.GraphRunbook.Model.CommandActivityType $CommandActivityType.CommandName = 'Start-AzureRmAutomationRunbook' $Activity = New-Object Orchestrator.GraphRunbook.Model.CommandActivity -ArgumentList New-Guid, $CommandActivityType $Activity.Parameters = New-Object Orchestrator.GraphRunbook.Model.ActivityParameters $ValueDescriptor = New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList 'RunbookC' $Activity.Parameters.Add('Name', $ValueDescriptor) $Runbook.AddActivity($Activity) $CommandActivityType = New-Object Orchestrator.GraphRunbook.Model.CommandActivityType $CommandActivityType.CommandName = 'Start-AzureAutomationRunbook' $Activity = New-Object Orchestrator.GraphRunbook.Model.CommandActivity -ArgumentList New-Guid, $CommandActivityType $Activity.Parameters = New-Object Orchestrator.GraphRunbook.Model.ActivityParameters $ValueDescriptor = New-Object Orchestrator.GraphRunbook.Model.ConstantValueDescriptor -ArgumentList 'RunbookD' $Activity.Parameters.Add('Name', $ValueDescriptor) $Runbook.AddActivity($Activity) It "Outputs required runbooks" { $RequiredRunbooks = Get-GraphRunbookDependency -Runbook $Runbook -DependencyType Runbook $RequiredRunbooks | Measure-Object | ForEach-Object Count | Should be 4 ($RequiredRunbooks[0].Name -ieq 'RunbookA') | Should be $true $RequiredRunbooks[0].Type | Should be 'Runbook' $RequiredRunbooks[1].Name | Should be 'RunbookB' $RequiredRunbooks[1].Type | Should be 'Runbook' $RequiredRunbooks[2].Name | Should be 'RunbookC' $RequiredRunbooks[2].Type | Should be 'Runbook' $RequiredRunbooks[3].Name | Should be 'RunbookD' $RequiredRunbooks[3].Type | Should be 'Runbook' } } Context "When all dependencies are requested" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $Runbook.AddActivity((New-CommandActivity -ModuleName 'ModuleA')) $Runbook.AddActivity((New-CommandActivity -ValueDescriptors ` (New-Object Orchestrator.GraphRunbook.Model.AutomationVariableValueDescriptor -ArgumentList 'Variable1'), (New-Object Orchestrator.GraphRunbook.Model.AutomationCredentialValueDescriptor -ArgumentList 'Credential1'))) $Runbook.AddActivity((New-InvokeRunbookActivity -RunbookName 'RunbookA')) $Runbook.AddActivity((New-Object Orchestrator.GraphRunbook.Model.WorkflowScriptActivity -ArgumentList 'Activity')) It "Outputs all dependencies" { $AllDependencies = Get-GraphRunbookDependency -Runbook $Runbook -DependencyType All $AllDependencies | Measure-Object | ForEach-Object Count | Should be 4 $RequiredModules = $AllDependencies | Where-Object { $_.Type -eq 'Module' } $RequiredModules | Measure-Object | ForEach-Object Count | Should be 1 $RequiredModules.Name | Should be 'ModuleA' $RequiredVariables = $AllDependencies | Where-Object { $_.Type -eq 'AutomationVariable' } $RequiredVariables | Measure-Object | ForEach-Object Count | Should be 1 $RequiredVariables.Name | Should be 'Variable1' $RequiredCredentials = $AllDependencies | Where-Object { $_.Type -eq 'AutomationCredential' } $RequiredCredentials | Measure-Object | ForEach-Object Count | Should be 1 $RequiredCredentials.Name | Should be 'Credential1' $RequiredRunbooks = $AllDependencies | Where-Object { $_.Type -eq 'Runbook' } $RequiredRunbooks | Measure-Object | ForEach-Object Count | Should be 1 $RequiredRunbooks.Name | Should be 'RunbookA' } } Context "When .graphrunbook file name is provided" { $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook $Runbook.AddActivity((New-CommandActivity -ModuleName 'ModuleA')) $Runbook.AddActivity((New-CommandActivity -ValueDescriptors ` (New-Object Orchestrator.GraphRunbook.Model.AutomationVariableValueDescriptor -ArgumentList 'Variable1'), (New-Object Orchestrator.GraphRunbook.Model.AutomationCredentialValueDescriptor -ArgumentList 'Credential1'))) WithRunbookFile -Runbook $Runbook -Action { param($File) It "Outputs all dependencies" { $AllDependencies = Get-GraphRunbookDependency -RunbookFileName $File.FullName -DependencyType All $AllDependencies | Measure-Object | ForEach-Object Count | Should be 3 $RequiredModules = $AllDependencies | Where-Object { $_.Type -eq 'Module' } $RequiredModules | Measure-Object | ForEach-Object Count | Should be 1 $RequiredModules.Name | Should be 'ModuleA' $RequiredVariables = $AllDependencies | Where-Object { $_.Type -eq 'AutomationVariable' } $RequiredVariables | Measure-Object | ForEach-Object Count | Should be 1 $RequiredVariables.Name | Should be 'Variable1' $RequiredCredentials = $AllDependencies | Where-Object { $_.Type -eq 'AutomationCredential' } $RequiredCredentials | Measure-Object | ForEach-Object Count | Should be 1 $RequiredCredentials.Name | Should be 'Credential1' } } } Context "When runbook name is provided" { $TestResourceGroup = 'TestResourceGroupName' $TestAutomationAccount = 'TestAccountName' $TestRunbookName = 'TestRunbookName' Mock Export-AzureRMAutomationRunbook -Verifiable ` -MockWith { $ResourceGroupName | Should be $TestResourceGroup > $null $AutomationAccountName | Should be $AutomationAccountName > $null $Name | Should be $TestRunbookName > $null $Slot | Should be 'Published' > $null $Runbook = New-Object Orchestrator.GraphRunbook.Model.GraphRunbook [void]$Runbook.AddActivity((New-CommandActivity -ModuleName 'ModuleA')) [void]$Runbook.AddActivity((New-CommandActivity -ValueDescriptors ` (New-Object Orchestrator.GraphRunbook.Model.AutomationVariableValueDescriptor -ArgumentList 'Variable1'), (New-Object Orchestrator.GraphRunbook.Model.AutomationCredentialValueDescriptor -ArgumentList 'Credential1'))) $SerializedRunbook = [Orchestrator.GraphRunbook.Model.Serialization.RunbookSerializer]::Serialize($Runbook) $OutputFileName = Join-Path $OutputFolder "$Name.graphrunbook" $SerializedRunbook | Out-File $OutputFileName Get-Item -Path $OutputFileName } It "Outputs all dependencies" { $AllDependencies = Get-GraphRunbookDependency ` -RunbookName $TestRunbookName ` -ResourceGroupName $TestResourceGroup ` -AutomationAccount $TestAutomationAccount ` -DependencyType All $AllDependencies | Measure-Object | ForEach-Object Count | Should be 3 $RequiredModules = $AllDependencies | Where-Object { $_.Type -eq 'Module' } $RequiredModules | Measure-Object | ForEach-Object Count | Should be 1 $RequiredModules.Name | Should be 'ModuleA' $RequiredVariables = $AllDependencies | Where-Object { $_.Type -eq 'AutomationVariable' } $RequiredVariables | Measure-Object | ForEach-Object Count | Should be 1 $RequiredVariables.Name | Should be 'Variable1' $RequiredCredentials = $AllDependencies | Where-Object { $_.Type -eq 'AutomationCredential' } $RequiredCredentials | Measure-Object | ForEach-Object Count | Should be 1 $RequiredCredentials.Name | Should be 'Credential1' Assert-VerifiableMocks } } } } |