176 lines
7.3 KiB
PowerShell
176 lines
7.3 KiB
PowerShell
# ============================================================
|
|
# Omika - Tests NON invasifs de Install-OmikaServerFiles.ps1 (Phase 5C.2B)
|
|
# ============================================================
|
|
# Valide le correctif WhatIf / SHA256 :
|
|
# A. Get-Sha256Hex sur fichier connu.
|
|
# B. Get-Sha256Hex sous $WhatIfPreference = $true (aucun null).
|
|
# C. Package valide + WhatIf -> SHA256 calcule, exit 0, aucune exception.
|
|
# D. Hash incorrect + WhatIf -> mismatch detecte, arret avant copie (exit 1).
|
|
# E. Aucune mutation filesystem sous -WhatIf (dossiers + copie).
|
|
# F. PackageRoot explicite honore.
|
|
# G. PackageRoot automatique ($PSScriptRoot parent).
|
|
# AUCUN changement systeme : aucune copie reelle, aucun service, aucun admin.
|
|
# ============================================================
|
|
|
|
[CmdletBinding(SupportsShouldProcess = $true)]
|
|
param()
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$repo = 'D:\Avalonia\Omika'
|
|
$scriptPath = Join-Path $repo 'infra\deploy\Install-OmikaServerFiles.ps1'
|
|
$pkgRoot = Join-Path $repo 'artifacts\server-full'
|
|
|
|
$tests = 0
|
|
$fails = 0
|
|
|
|
function Assert([bool]$condition, [string]$label) {
|
|
$script:tests++
|
|
if ($condition) {
|
|
Write-Host ("PASS {0}" -f $label) -ForegroundColor Green
|
|
}
|
|
else {
|
|
$script:fails++
|
|
Write-Host ("FAIL {0}" -f $label) -ForegroundColor Red
|
|
}
|
|
}
|
|
|
|
# Exécute un bloc dans un process Windows PowerShell 5.1 enfant (exit-safe),
|
|
# retourne @{ Output; ExitCode }. On baisse localement $ErrorActionPreference à
|
|
# 'Continue' pendant l'appel natif : ainsi la stderr du natif (ErrorRecord) ne
|
|
# lève pas, et 2>&1 la capture dans la sortie.
|
|
function Invoke-ChildPS51([string]$scriptText) {
|
|
$encoded = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptText))
|
|
$prevEAP = $ErrorActionPreference
|
|
$ErrorActionPreference = 'Continue'
|
|
try {
|
|
$out = @(& powershell.exe -NoProfile -NonInteractive -EncodedCommand $encoded 2>&1)
|
|
$exitCode = $LASTEXITCODE
|
|
}
|
|
finally {
|
|
$ErrorActionPreference = $prevEAP
|
|
}
|
|
$text = ($out | ForEach-Object { $_.ToString() }) -join "`n"
|
|
return @{ Output = $text; ExitCode = $exitCode }
|
|
}
|
|
|
|
Write-Host "=== 1. Syntaxe PowerShell 5.1 (0 erreur) ==="
|
|
$tokens = $null; $errors = $null
|
|
[System.Management.Automation.Language.Parser]::ParseFile($scriptPath, [ref]$tokens, [ref]$errors) | Out-Null
|
|
Assert (($errors -eq $null) -or ($errors.Count -eq 0)) "Syntaxe OK : Install-OmikaServerFiles.ps1"
|
|
|
|
Write-Host ""
|
|
Write-Host "=== 2. Extraction des fonctions (AST) + module temporaire ==="
|
|
$content = Get-Content -LiteralPath $scriptPath -Raw
|
|
$ast = [System.Management.Automation.Language.Parser]::ParseInput($content, [ref]$tokens, [ref]$errors)
|
|
$want = @('Get-Sha256Hex', 'Test-PackageChecksums', 'Deploy-AppFolder')
|
|
$module = New-Object System.Text.StringBuilder
|
|
foreach ($f in $ast.FindAll({ param($n) $n -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $true)) {
|
|
if ($want -contains $f.Name) {
|
|
[void]$module.AppendLine($f.Extent.Text)
|
|
}
|
|
}
|
|
foreach ($name in $want) {
|
|
Assert ($module.ToString() -match ("function\s+" + [regex]::Escape($name) + "\b")) ("Fonction extraite : " + $name)
|
|
}
|
|
|
|
$modulePath = Join-Path $env:TEMP 'omika-isf-functions.ps1'
|
|
[System.IO.File]::WriteAllText($modulePath, $module.ToString(), (New-Object System.Text.UTF8Encoding($true)))
|
|
. $modulePath
|
|
|
|
Write-Host ""
|
|
Write-Host "=== A/B. Get-Sha256Hex (unitaire) ==="
|
|
$knownFile = Join-Path $env:TEMP 'omika-isf-known.txt'
|
|
[System.IO.File]::WriteAllText($knownFile, 'abc', (New-Object System.Text.UTF8Encoding($false)))
|
|
$expectedHash = 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'
|
|
|
|
Assert ((Get-Sha256Hex -Path $knownFile) -eq $expectedHash) "A. Hash connu 'abc' = ba7816bf... correct"
|
|
|
|
$prevWhatIf = $WhatIfPreference
|
|
$WhatIfPreference = $true
|
|
try {
|
|
$hashUnderWhatIf = Get-Sha256Hex -Path $knownFile
|
|
Assert ($hashUnderWhatIf -eq $expectedHash) "B. Sous WhatIfPreference=true : hash correct (aucun null)"
|
|
Assert ($hashUnderWhatIf -match '^[0-9a-f]{64}$') "B. Format hex lowercase 64 caracteres"
|
|
}
|
|
finally {
|
|
$WhatIfPreference = $prevWhatIf
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "=== C. Package valide + WhatIf (Test-PackageChecksums) ==="
|
|
$childC = @"
|
|
`$ErrorActionPreference = 'Stop'
|
|
. '$modulePath'
|
|
`$WhatIfPreference = `$true
|
|
Test-PackageChecksums -packageRoot '$pkgRoot'
|
|
"@
|
|
$resC = Invoke-ChildPS51 $childC
|
|
Assert ($resC.ExitCode -eq 0) "C. Package valide + WhatIf : exit 0"
|
|
Assert ($resC.Output -match 'SHA256 OK') "C. Package valide + WhatIf : SHA256 calcule et OK"
|
|
|
|
Write-Host ""
|
|
Write-Host "=== D. Hash incorrect + WhatIf (mismatch detecte, arret) ==="
|
|
$corruptDir = Join-Path $env:TEMP 'omika-isf-corrupt'
|
|
if (Test-Path -LiteralPath $corruptDir) { Remove-Item -LiteralPath $corruptDir -Recurse -Force }
|
|
New-Item -ItemType Directory -Force -Path $corruptDir | Out-Null
|
|
[System.IO.File]::WriteAllText((Join-Path $corruptDir 'test.txt'), 'hello', (New-Object System.Text.UTF8Encoding($false)))
|
|
[System.IO.File]::WriteAllText((Join-Path $corruptDir 'SHA256SUMS.txt'), '0000000000000000000000000000000000000000000000000000000000000000 test.txt', (New-Object System.Text.UTF8Encoding($false)))
|
|
|
|
$childD = @"
|
|
`$ErrorActionPreference = 'Stop'
|
|
. '$modulePath'
|
|
`$WhatIfPreference = `$true
|
|
Test-PackageChecksums -packageRoot '$corruptDir'
|
|
"@
|
|
$resD = Invoke-ChildPS51 $childD
|
|
Assert ($resD.ExitCode -eq 1) "D. Hash incorrect + WhatIf : exit 1 (arret avant copie)"
|
|
Assert ($resD.Output -match 'Checksum SHA256 KO') "D. Hash incorrect + WhatIf : mismatch detecte"
|
|
|
|
Write-Host ""
|
|
Write-Host "=== E. Aucune mutation filesystem sous -WhatIf ==="
|
|
$tempRoot = Join-Path $env:TEMP ('omika-isf-mut-' + [guid]::NewGuid().ToString('N'))
|
|
|
|
# E1 : boucle de creation d'arborescence (replique de la logique top-level).
|
|
$WhatIfPreference = $true
|
|
$appsRoot = Join-Path $tempRoot 'Apps'
|
|
$folders = @(
|
|
$appsRoot,
|
|
(Join-Path $appsRoot 'OmikaApi'),
|
|
(Join-Path $appsRoot 'OmikaWorker'),
|
|
(Join-Path $tempRoot 'Data\Api\Diagnostics\Jsonl'),
|
|
(Join-Path $tempRoot 'Data\DiagnosticsWorker\Checkpoint'),
|
|
(Join-Path $tempRoot 'Logs\Api'),
|
|
(Join-Path $tempRoot 'Config'),
|
|
(Join-Path $tempRoot 'Backups'),
|
|
(Join-Path $tempRoot 'Deploy')
|
|
)
|
|
foreach ($folder in $folders) {
|
|
if ($PSCmdlet.ShouldProcess($folder, 'Créer le dossier')) {
|
|
New-Item -ItemType Directory -Force -Path $folder | Out-Null
|
|
}
|
|
}
|
|
|
|
# E2 : Deploy-AppFolder (sauvegarde + copie) sous WhatIf.
|
|
Deploy-AppFolder -Name 'OmikaApi' `
|
|
-Source (Join-Path $pkgRoot 'OmikaApi') `
|
|
-Target (Join-Path $appsRoot 'OmikaApi') `
|
|
-BackupRoot (Join-Path $tempRoot 'Backups') `
|
|
-Preserve @('appsettings.json')
|
|
$WhatIfPreference = $prevWhatIf
|
|
|
|
Assert (-not (Test-Path -LiteralPath $tempRoot)) "E. Aucun dossier/fichier cree sous WhatIf (arborescence + copie)"
|
|
|
|
Write-Host ""
|
|
Write-Host "=== F/G. Resolution PackageRoot ==="
|
|
# G : automatique = parent du dossier Deploy (mirroir exact de $PSScriptRoot).
|
|
$autoResolved = Split-Path -Parent (Join-Path $pkgRoot 'Deploy')
|
|
Assert ($autoResolved -eq $pkgRoot) "G. PackageRoot automatique (parent du dossier Deploy) resout vers le package"
|
|
|
|
# F : explicite = honore (le script ne resout que si -not $PackageRoot).
|
|
Assert ($content -match 'if \(-not \$PackageRoot\)') "F. Garde 'if (-not PackageRoot)' presente (explicite honore)"
|
|
|
|
Write-Host ""
|
|
Write-Host ("=== RESULTAT : {0} tests, {1} echec(s) ===" -f $tests, $fails)
|
|
if ($fails -gt 0) { exit 1 } else { exit 0 }
|