c04a2f25aa
Task 5.1: Delete runner/Install-Runner.ps1 (superseded by Setup-Host.ps1).
Task 5.2: Replace Unicode/Discord emoji in Watch-DiskSpace.ps1, Watch-RunnerHealth.ps1,
Test-E2E-Section3.3.ps1 with plain-text prefixes ([WARNING], [ALERT], [WARN]).
Task 5.3: docs/TEST-PLAN-v1.3-to-HEAD.md: ForEach-Object -Parallel replaced with Start-Job;
-RepositoryUrl replaced with -RepoUrl (3 occurrences); PS7 syntax removed.
Task 5.4: scripts/Get-CIJobSummary.ps1 (new): scans JSONL logs in F:\CI\Logs, prints summary
table per job, -JobId detail view, -Failed filter, -Last N.
Task 3.5: gitea/workflows/self-test.yml (new): workflow_dispatch, smoke-windows + smoke-linux.
scripts/Test-Smoke.ps1 (new): invokes Invoke-CIJob.ps1 with marker-file build,
asserts artifact dir and JSONL success event.
Task 5.6: docs/BEST-PRACTICES.md Section 10 added: SHA256 pinning policy, priority table,
PS 5.1 implementation pattern, update guidance.
240 lines
10 KiB
PowerShell
240 lines
10 KiB
PowerShell
#Requires -Version 5.1
|
|
<#
|
|
.SYNOPSIS
|
|
E2E test for §3.3 In-VM Git Clone feature.
|
|
|
|
.DESCRIPTION
|
|
Runs nsis-plugin-nsinnounp build twice:
|
|
1. Without -UseGitClone (baseline: host-side zip-transfer)
|
|
2. With -UseGitClone (target: guest-side git clone)
|
|
|
|
Measures elapsed time, artifact size, and logs comparison.
|
|
Prerequisite: Template VM must have Git for Windows installed (§6.6).
|
|
|
|
.PARAMETER BaselineJobId
|
|
Job ID for baseline run (host-side clone).
|
|
Default: e2e-baseline-<yyyyMMdd_HHmmss>
|
|
|
|
.PARAMETER GuestCloneJobId
|
|
Job ID for guest-side clone run.
|
|
Default: e2e-guestclone-<yyyyMMdd_HHmmss>
|
|
|
|
.PARAMETER Branch
|
|
Branch to build. Default: main
|
|
|
|
.PARAMETER TemplatePath
|
|
Path to template VMX. Default: env:GITEA_CI_TEMPLATE_PATH or
|
|
F:\CI\Templates\WinBuild2025\WinBuild2025.vmx
|
|
|
|
.PARAMETER GuestRepoUrl
|
|
HTTP(S) URL for guest-side clone. Must be reachable from inside the VM.
|
|
Default: https://gitea.emulab.it/Simone/nsis-plugin-nsinnounp.git
|
|
NOTE: ssh://gitea-ci alias works only on the host (SSH config), not inside the VM.
|
|
|
|
.PARAMETER SkipBaseline
|
|
If set, skip baseline run and only run with -UseGitClone.
|
|
|
|
.PARAMETER SkipGuestClone
|
|
If set, skip guest-clone run and only run baseline.
|
|
|
|
.EXAMPLE
|
|
# Full comparison (both runs):
|
|
.\Test-E2E-Section3.3.ps1
|
|
|
|
# Only test guest-clone mode (assume baseline already exists):
|
|
.\Test-E2E-Section3.3.ps1 -SkipBaseline
|
|
|
|
# Only test baseline:
|
|
.\Test-E2E-Section3.3.ps1 -SkipGuestClone
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[string] $BaselineJobId = "e2e-baseline-$(Get-Date -Format 'yyyyMMdd_HHmmss')",
|
|
[string] $GuestCloneJobId = "e2e-guestclone-$(Get-Date -Format 'yyyyMMdd_HHmmss')",
|
|
[string] $Branch = 'main',
|
|
[string] $TemplatePath = $(
|
|
if ($env:GITEA_CI_TEMPLATE_PATH) { $env:GITEA_CI_TEMPLATE_PATH }
|
|
else { 'F:\CI\Templates\WinBuild2025\WinBuild2025.vmx' }
|
|
),
|
|
# URL for host-side clone (SSH alias works on host)
|
|
[string] $HostRepoUrl = 'ssh://gitea-ci/Simone/nsis-plugin-nsinnounp.git',
|
|
# URL for guest-side clone (must be HTTP reachable from inside VM — SSH alias not available in guest)
|
|
[string] $GuestRepoUrl = 'https://gitea.emulab.it/Simone/nsis-plugin-nsinnounp.git',
|
|
[switch] $SkipBaseline,
|
|
[switch] $SkipGuestClone
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$scriptDir = Split-Path $MyInvocation.MyCommand.Path -Parent
|
|
$orchestrator = Join-Path $scriptDir 'Invoke-CIJob.ps1'
|
|
|
|
# Common parameters (RepoUrl set per-mode below)
|
|
$commonParams = @{
|
|
Branch = $Branch
|
|
TemplatePath = $TemplatePath
|
|
Submodules = $true
|
|
BuildCommand = 'python build_plugin.py --final --dist-dir dist'
|
|
GuestArtifactSource = 'dist'
|
|
GuestCredentialTarget = 'BuildVMGuest'
|
|
}
|
|
|
|
function Format-Elapsed {
|
|
param([TimeSpan] $ts)
|
|
if ($ts.TotalHours -ge 1) {
|
|
return $ts.ToString('hh\:mm\:ss')
|
|
} else {
|
|
return $ts.ToString('mm\:ss\.ff')
|
|
}
|
|
}
|
|
|
|
function Run-Test {
|
|
param(
|
|
[string] $JobId,
|
|
[string] $Mode,
|
|
[switch] $UseGitClone,
|
|
[hashtable] $CommonParams
|
|
)
|
|
|
|
Write-Host ""
|
|
Write-Host "────────────────────────────────────────────────────────" -ForegroundColor Cyan
|
|
Write-Host " $Mode" -ForegroundColor Cyan
|
|
Write-Host "────────────────────────────────────────────────────────" -ForegroundColor Cyan
|
|
Write-Host " JobId : $JobId"
|
|
Write-Host " Branch : $Branch"
|
|
Write-Host " Mode : $(if ($UseGitClone) { 'Guest-side clone (-UseGitClone)' } else { 'Host-side zip-transfer (baseline)' })"
|
|
Write-Host ""
|
|
|
|
$params = $CommonParams.Clone()
|
|
$params['JobId'] = $JobId
|
|
if ($UseGitClone) {
|
|
$params['UseGitClone'] = $true
|
|
$params['RepoUrl'] = $script:GuestRepoUrl # HTTP URL reachable from inside VM
|
|
} else {
|
|
$params['RepoUrl'] = $script:HostRepoUrl # SSH alias — works on host
|
|
}
|
|
|
|
$startTime = Get-Date
|
|
$exitCode = 0
|
|
|
|
try {
|
|
# Pipe to Out-Host so orchestrator output doesn't pollute this function's pipeline
|
|
& $orchestrator @params | Out-Host
|
|
$exitCode = $LASTEXITCODE
|
|
}
|
|
catch {
|
|
Write-Host "[Test] Orchestrator threw: $_" -ForegroundColor Red
|
|
$exitCode = 1
|
|
}
|
|
|
|
$elapsed = (Get-Date) - $startTime
|
|
|
|
if ($exitCode -ne 0) {
|
|
Write-Host "[Test] FAIL — exit code $exitCode after $(Format-Elapsed $elapsed)" -ForegroundColor Red
|
|
return @{ Success = $false; Elapsed = $elapsed; JobId = $JobId; Mode = $Mode }
|
|
}
|
|
|
|
$artifactDir = "F:\CI\Artifacts\$JobId"
|
|
$artifactZip = Join-Path $artifactDir 'artifacts.zip'
|
|
|
|
if (-not (Test-Path $artifactZip)) {
|
|
Write-Host "[Test] FAIL — artifact not found: $artifactZip" -ForegroundColor Red
|
|
return @{ Success = $false; Elapsed = $elapsed; JobId = $JobId; Mode = $Mode }
|
|
}
|
|
|
|
$zipSize = [math]::Round((Get-Item $artifactZip).Length / 1MB, 2)
|
|
Write-Host "[Test] PASS — $(Format-Elapsed $elapsed)" -ForegroundColor Green
|
|
Write-Host " Artifact: $zipSize MB"
|
|
Write-Host " Logs : $artifactDir"
|
|
|
|
return @{ Success = $true; Elapsed = $elapsed; Size = $zipSize; JobId = $JobId; Mode = $Mode }
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
# Test runs
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
|
|
Write-Host ""
|
|
Write-Host "╔════════════════════════════════════════════════════════╗" -ForegroundColor Yellow
|
|
Write-Host "║ §3.3 E2E Test: In-VM Git Clone vs Host-side Zip ║" -ForegroundColor Yellow
|
|
Write-Host "╚════════════════════════════════════════════════════════╝" -ForegroundColor Yellow
|
|
|
|
$baselineResult = $null
|
|
$guestCloneResult = $null
|
|
|
|
if (-not $SkipBaseline) {
|
|
$baselineResult = Run-Test -JobId $BaselineJobId -Mode "BASELINE (host-side zip)" -CommonParams $commonParams
|
|
}
|
|
|
|
if (-not $SkipGuestClone) {
|
|
$guestCloneResult = Run-Test -JobId $GuestCloneJobId -Mode "GUEST CLONE (-UseGitClone)" -UseGitClone -CommonParams $commonParams
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
# Summary
|
|
# ────────────────────────────────────────────────────────────────────────────
|
|
|
|
Write-Host ""
|
|
Write-Host "════════════════════════════════════════════════════════" -ForegroundColor Cyan
|
|
Write-Host " SUMMARY" -ForegroundColor Cyan
|
|
Write-Host "════════════════════════════════════════════════════════" -ForegroundColor Cyan
|
|
|
|
if ($baselineResult -and $guestCloneResult) {
|
|
if ($baselineResult.Success -and $guestCloneResult.Success) {
|
|
$baselineTime = $baselineResult.Elapsed.TotalSeconds
|
|
$guestTime = $guestCloneResult.Elapsed.TotalSeconds
|
|
$diff = $baselineTime - $guestTime
|
|
$pctChange = [math]::Round(($diff / $baselineTime) * 100, 1)
|
|
|
|
Write-Host ""
|
|
Write-Host "Baseline (host-side): $(Format-Elapsed $baselineResult.Elapsed) / $($baselineResult.Size) MB"
|
|
Write-Host "Guest clone (-UseGit): $(Format-Elapsed $guestCloneResult.Elapsed) / $($guestCloneResult.Size) MB"
|
|
Write-Host ""
|
|
Write-Host "Difference: $([math]::Round($diff, 1)) sec ($pctChange%)" -ForegroundColor $(if ($diff -gt 0) { 'Green' } else { 'Red' })
|
|
Write-Host ""
|
|
|
|
if ($diff -gt 0) {
|
|
Write-Host "✓ §3.3 guest-clone is FASTER by $(Format-Elapsed ([TimeSpan]::FromSeconds($diff)))" -ForegroundColor Green
|
|
}
|
|
else {
|
|
Write-Host "[WARN] Host-side is faster by $(Format-Elapsed ([TimeSpan]::FromSeconds(-$diff)))" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
else {
|
|
Write-Host ""
|
|
Write-Host "One or both tests failed. Review logs above." -ForegroundColor Red
|
|
Write-Host ""
|
|
if ($baselineResult.Success) {
|
|
Write-Host " Baseline: ✓ PASS"
|
|
}
|
|
else {
|
|
Write-Host " Baseline: ✗ FAIL"
|
|
}
|
|
if ($guestCloneResult.Success) {
|
|
Write-Host " Guest: ✓ PASS"
|
|
}
|
|
else {
|
|
Write-Host " Guest: ✗ FAIL"
|
|
}
|
|
}
|
|
}
|
|
elseif ($baselineResult) {
|
|
Write-Host ""
|
|
Write-Host "Baseline (host-side): $(if ($baselineResult.Success) { '✓ PASS' } else { '✗ FAIL' })" -ForegroundColor $(if ($baselineResult.Success) { 'Green' } else { 'Red' })
|
|
if ($baselineResult.Success) {
|
|
Write-Host " Time: $(Format-Elapsed $baselineResult.Elapsed)"
|
|
}
|
|
}
|
|
elseif ($guestCloneResult) {
|
|
Write-Host ""
|
|
Write-Host "Guest clone (-UseGit): $(if ($guestCloneResult.Success) { '✓ PASS' } else { '✗ FAIL' })" -ForegroundColor $(if ($guestCloneResult.Success) { 'Green' } else { 'Red' })
|
|
if ($guestCloneResult.Success) {
|
|
Write-Host " Time: $(Format-Elapsed $guestCloneResult.Elapsed)"
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Logs: F:\CI\Logs\$BaselineJobId or $GuestCloneJobId" -ForegroundColor Gray
|
|
Write-Host "════════════════════════════════════════════════════════" -ForegroundColor Cyan
|