test/qbuild-process.tests.ps1
|
BeforeAll { Get-Module ConfigMap -ErrorAction SilentlyContinue | Remove-Module Import-Module $PSScriptRoot\..\configmap.psm1 -Force } Describe 'qbuild _settings.process=qrun forwarding' { BeforeEach { $script:workDir = Join-Path $TestDrive ("qbuild-process-" + [guid]::NewGuid().ToString('n')) New-Item -ItemType Directory -Path $script:workDir -Force | Out-Null Push-Location $script:workDir # Contract is path-only handoff; write the map to a file for all invokes. $script:mapFile = Join-Path $script:workDir '.build.map.ps1' @' [ordered]@{ build = { param( [ValidateSet('Debug', 'Release')] [string]$Configuration = 'Debug' ) "built:$Configuration" | Set-Content 'build.txt' } bootstrap = [ordered]@{ _settings = @{ process = 'qrun' } description = 'test process' prepare = { New-Item -ItemType Directory -Path 'marker-a' -Force | Out-Null 'a' | Set-Content (Join-Path 'marker-a' 'done.txt') } restore = { param( [ValidateSet('dev', 'prod')] [string]$Environment = 'dev' ) if (!(Test-Path 'marker-a/done.txt')) { throw 'prepare missing' } "restored:$Environment" | Set-Content 'marker-b.txt' } verify = { 'c' | Set-Content 'marker-c.txt' } } } '@ | Set-Content -LiteralPath $script:mapFile -Encoding utf8 } AfterEach { Pop-Location } It 'still runs default qbuild entries' { qbuild -map $script:mapFile build -Configuration Release Get-Content 'build.txt' -Raw | Should -Match 'built:Release' } It 'forwards full process run and persists success state' { qbuild -map $script:mapFile bootstrap Test-Path 'marker-a/done.txt' | Should -BeTrue Test-Path 'marker-b.txt' | Should -BeTrue Test-Path 'marker-c.txt' | Should -BeTrue $stateFiles = @(Get-ChildItem -Path (Join-Path $script:workDir '.configmap' 'process') -Recurse -Filter '*.state.json') $stateFiles.Count | Should -Be 1 $state = Get-Content $stateFiles[0].FullName -Raw | ConvertFrom-Json $state.steps.prepare.status | Should -Be 'Succeeded' $state.steps.restore.status | Should -Be 'Succeeded' $state.steps.verify.status | Should -Be 'Succeeded' } It 'does not delegate a process entry when an in-memory map has no source file' { $map = @{ bootstrap = @{ _settings = @{ process = 'qrun' } prepare = { 'prepared' | Set-Content 'in-memory-process.txt' } } } { qbuild -map $map bootstrap } | Should -Throw '*the map has no _sourceFile*' Test-Path 'in-memory-process.txt' | Should -BeFalse } It 'skips already succeeded steps on re-run' { qbuild -map $script:mapFile bootstrap Remove-Item 'marker-b.txt', 'marker-c.txt' -Force qbuild -map $script:mapFile bootstrap Test-Path 'marker-b.txt' | Should -BeFalse Test-Path 'marker-c.txt' | Should -BeFalse Test-Path 'marker-a/done.txt' | Should -BeTrue } It 'reruns succeeded steps when -Force is specified' { qbuild -map $script:mapFile bootstrap Remove-Item 'marker-b.txt' -Force qbuild -map $script:mapFile bootstrap -Force Test-Path 'marker-b.txt' | Should -BeTrue Test-Path 'marker-c.txt' | Should -BeTrue } It 'runs a single step via process.step path' { qbuild -map $script:mapFile bootstrap.prepare Test-Path 'marker-a/done.txt' | Should -BeTrue Test-Path 'marker-b.txt' | Should -BeFalse qbuild -map $script:mapFile bootstrap.restore Test-Path 'marker-b.txt' | Should -BeTrue Test-Path 'marker-c.txt' | Should -BeFalse } It 'runs from a step onward with -Follow' { qbuild -map $script:mapFile bootstrap.prepare qbuild -map $script:mapFile bootstrap.restore -Follow Test-Path 'marker-b.txt' | Should -BeTrue Test-Path 'marker-c.txt' | Should -BeTrue } It 'rejects -Follow without a step path' { { qbuild -map $script:mapFile bootstrap -Follow } | Should -Throw '*-Follow requires a step path*' } It 'blocks starting mid-process when prior steps are incomplete' { { qbuild -map $script:mapFile bootstrap.restore } | Should -Throw '*prior steps are incomplete*' Test-Path 'marker-b.txt' | Should -BeFalse } It 'allows skipping incomplete prior steps with -Force' { $indepFile = Join-Path $script:workDir 'indep.build.map.ps1' @' [ordered]@{ setup = [ordered]@{ _settings = @{ process = 'qrun' } a = { 'a' | Set-Content 'a.txt' } b = { 'b' | Set-Content 'b.txt' } c = { 'c' | Set-Content 'c.txt' } } } '@ | Set-Content -LiteralPath $indepFile -Encoding utf8 qbuild -map $indepFile setup.b -Force Test-Path 'b.txt' | Should -BeTrue Test-Path 'a.txt' | Should -BeFalse } It 'completes step paths under an _settings.process=qrun entry' { $map = Import-ConfigMap -Map $script:mapFile $completions = @(Get-EntryCompletion -map $map -language build -wordToComplete 'bootstrap.') $completions | Should -Contain 'bootstrap.prepare' $completions | Should -Contain 'bootstrap.restore' $completions | Should -Contain 'bootstrap.verify' } It 'routes entry completion through process !complete -word' { InModuleScope ConfigMap { param($MapFile) $words = @(Get-ConfigMapProcessCompleteWord -ProcessName 'qrun' -MapPath $MapFile -Word 'bootstrap.') $words | Should -Contain 'bootstrap.prepare' $words | Should -Contain 'bootstrap.restore' $words | Should -Contain 'bootstrap.verify' $names = @(Get-ConfigMapProcessNamesInMap -Map (Import-ConfigMap -Map $MapFile)) $names | Should -Contain 'qrun' } -Parameters @{ MapFile = $script:mapFile } } It 'delegates run with explicit -entry' { InModuleScope ConfigMap { param($MapFile) $splat = ConvertTo-ConfigMapProcessSplat -MapPath $MapFile -Entry 'bootstrap.prepare' $splat.entry | Should -Be 'bootstrap.prepare' $splat.Keys | Should -Not -Contain 'command' } -Parameters @{ MapFile = $script:mapFile } qbuild -map $script:mapFile bootstrap.prepare Test-Path 'marker-a/done.txt' | Should -BeTrue } It 'forwards process step parameters end-to-end' { qbuild -map $script:mapFile bootstrap.prepare qbuild -map $script:mapFile bootstrap.restore -Environment prod Get-Content 'marker-b.txt' -Raw | Should -Match 'restored:prod' } It 'lists _settings.process=qrun entries with status output' { qbuild -map $script:mapFile bootstrap.prepare Mock Write-Host -ModuleName ConfigMap qbuild -map $script:mapFile list Should -Invoke Write-Host -ModuleName ConfigMap -ParameterFilter { "$Object" -match 'bootstrap' } Should -Invoke Write-Host -ModuleName ConfigMap -ParameterFilter { "$Object" -match 'prepare' } } It 'smoke-loads the process-mixed sample map' { $sampleDir = Join-Path $PSScriptRoot '..' 'samples' 'process-mixed' $sampleFile = Join-Path $sampleDir '.build.map.ps1' $localMap = Join-Path $script:workDir '.build.map.ps1' Copy-Item -LiteralPath $sampleFile -Destination $localMap $sampleMap = Import-ConfigMap -Map $localMap $sampleMap.Keys | Should -Contain 'build' $sampleMap.Keys | Should -Contain 'bootstrap' $sampleMap.bootstrap._settings.process | Should -Be 'qrun' qbuild -map $localMap clean qbuild -map $localMap bootstrap.prepare Test-Path (Join-Path $script:workDir 'workspace' 'prepare.txt') | Should -BeTrue } } |