#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- .PARAMETER GuestCloneJobId Job ID for guest-side clone run. Default: e2e-guestclone- .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