fixed Vagrant tests for Windows
This commit is contained in:
Vendored
+12
-12
@@ -22,31 +22,31 @@ Vagrant.configure("2") do |config|
|
||||
|
||||
config.winrm.username = "vagrant"
|
||||
config.winrm.password = "vagrant"
|
||||
config.winrm.transport = :plaintext
|
||||
config.winrm.transport = :plaintext # Vagrant's own comms (boot check, provision)
|
||||
config.winrm.basic_auth_only = true
|
||||
|
||||
config.vm.guest = :windows
|
||||
config.vm.boot_timeout = 900
|
||||
config.vm.graceful_halt_timeout = 120
|
||||
|
||||
config.vm.network "forwarded_port", guest: 5985, host: 55985
|
||||
# Automatically select the Default Switch for Hyper-V to avoid interactive prompt
|
||||
config.vm.network "public_network", bridge: "Default Switch"
|
||||
|
||||
config.vm.network "forwarded_port", guest: 5985, host: 55985 # Vagrant plaintext WinRM
|
||||
config.vm.network "forwarded_port", guest: 5986, host: 55986 # PSSession HTTPS WinRM
|
||||
|
||||
config.vm.provider "hyperv" do |hv|
|
||||
hv.vmname = "afh-win11-test"
|
||||
hv.memory = 4096
|
||||
hv.maxmemory = 4096
|
||||
hv.cpus = 2
|
||||
hv.memory = 8192
|
||||
hv.maxmemory = 8192
|
||||
hv.cpus = 4
|
||||
hv.enable_enhanced_session_mode = true
|
||||
hv.linked_clone = true
|
||||
end
|
||||
|
||||
# SMB synced folder — Hyper-V does not support VirtualBox shared folders.
|
||||
# Vagrant will prompt for host credentials on first `vagrant up` to set up the SMB share.
|
||||
config.vm.synced_folder "..", "/vagrant_project",
|
||||
type: "smb",
|
||||
smb_username: ENV["VAGRANT_SMB_USERNAME"],
|
||||
smb_password: ENV["VAGRANT_SMB_PASSWORD"],
|
||||
mount_options: ["ro"]
|
||||
# Disable default Vagrant synced folder to prevent SMB credential prompts.
|
||||
# Files are transferred directly via PSSession by run_vagrant_tests.ps1.
|
||||
config.vm.synced_folder ".", "/vagrant", disabled: true
|
||||
|
||||
config.vm.provision "shell",
|
||||
path: "provision.ps1",
|
||||
|
||||
@@ -12,6 +12,19 @@ Set-ItemProperty -Path $RegPath -Name AutoAdminLogon -Value "1"
|
||||
Set-ItemProperty -Path $RegPath -Name DefaultUserName -Value "vagrant"
|
||||
Set-ItemProperty -Path $RegPath -Name DefaultPassword -Value "vagrant"
|
||||
|
||||
# --- Allow script execution (required for test suite) ---
|
||||
# Write the LocalMachine execution policy directly via the registry instead of using
|
||||
# Set-ExecutionPolicy. Vagrant runs provision.ps1 under "powershell -ExecutionPolicy Bypass",
|
||||
# which sets a Process-scope policy. When a Process-scope policy is active,
|
||||
# Set-ExecutionPolicy -Scope LocalMachine throws a terminating SecurityException
|
||||
# ("overridden by a policy defined at a more specific scope") that cannot be suppressed
|
||||
# with -ErrorAction. Writing the registry key bypasses that cmdlet restriction entirely.
|
||||
# The value takes effect in all subsequent WinRM PSSessions (which have no Process-scope
|
||||
# override) — exactly the sessions that run the test suite.
|
||||
$psMachinePolicyPath = 'HKLM:\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell'
|
||||
Set-ItemProperty -Path $psMachinePolicyPath -Name 'ExecutionPolicy' -Value 'Unrestricted' -Force
|
||||
Write-Host " Execution policy set to Unrestricted (LocalMachine)." -ForegroundColor DarkGray
|
||||
|
||||
# --- Install Chocolatey (package manager) ---
|
||||
if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "Installing Chocolatey..." -ForegroundColor Yellow
|
||||
@@ -20,10 +33,63 @@ if (-not (Get-Command choco -ErrorAction SilentlyContinue)) {
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
||||
}
|
||||
|
||||
# --- Configure HTTPS WinRM listener ---
|
||||
# HTTP WinRM (plaintext) causes PowerShell PSSession to reject unencrypted
|
||||
# traffic. A self-signed cert on port 5986 satisfies WinRM's security policy
|
||||
# without needing a domain CA. The 10-year expiry covers long-lived test boxes.
|
||||
Write-Host "Configuring HTTPS WinRM listener..." -ForegroundColor Yellow
|
||||
|
||||
# Ensure network is Private so WinRM HTTPS works correctly
|
||||
Get-NetConnectionProfile | Set-NetConnectionProfile -NetworkCategory Private
|
||||
|
||||
# Allow local accounts to perform administrative tasks via WinRM
|
||||
# (Required for the 'vagrant' user to have full admin rights over PSSession)
|
||||
$policyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
|
||||
Set-ItemProperty -Path $policyPath -Name LocalAccountTokenFilterPolicy -Value 1 -Force
|
||||
|
||||
# Create certificate for HTTPS listener
|
||||
$cert = New-SelfSignedCertificate `
|
||||
-DnsName "afh-test", "localhost" `
|
||||
-CertStoreLocation "Cert:\LocalMachine\My" `
|
||||
-KeyAlgorithm RSA `
|
||||
-KeyLength 2048 `
|
||||
-NotAfter (Get-Date).AddYears(10)
|
||||
|
||||
# Check if an HTTPS listener already exists
|
||||
$listeners = winrm enumerate winrm/config/listener
|
||||
$hasHttps = $listeners -match "Transport = HTTPS"
|
||||
|
||||
if ($hasHttps) {
|
||||
# If the thumbprint matches, we're already good
|
||||
if ($listeners -match $cert.Thumbprint) {
|
||||
Write-Host " HTTPS listener already correctly configured." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " Updating existing HTTPS listener with new certificate..." -ForegroundColor Gray
|
||||
winrm delete winrm/config/Listener?Address=*+Transport=HTTPS
|
||||
winrm create winrm/config/Listener?Address=*+Transport=HTTPS `
|
||||
"@{Hostname=`"afh-test`";CertificateThumbprint=`"$($cert.Thumbprint)`"}"
|
||||
}
|
||||
} else {
|
||||
Write-Host " Creating new HTTPS listener..." -ForegroundColor Gray
|
||||
winrm create winrm/config/Listener?Address=*+Transport=HTTPS `
|
||||
"@{Hostname=`"afh-test`";CertificateThumbprint=`"$($cert.Thumbprint)`"}"
|
||||
}
|
||||
|
||||
winrm set winrm/config/service/Auth '@{Basic="true"}'
|
||||
|
||||
netsh advfirewall firewall add rule `
|
||||
name="WinRM HTTPS" protocol=TCP dir=in localport=5986 action=allow profile=any | Out-Null
|
||||
|
||||
Write-Host " HTTPS WinRM listener ready on port 5986" -ForegroundColor Green
|
||||
|
||||
# --- Install nircmd for screenshot capture ---
|
||||
Write-Host "Installing nircmd for screenshot capture..." -ForegroundColor Yellow
|
||||
choco install nircmd -y --no-progress
|
||||
|
||||
# --- Install Inno Setup 6.7.1 (pinned) ---
|
||||
Write-Host "Installing Inno Setup 6.7.1..." -ForegroundColor Yellow
|
||||
choco install innosetup --version 6.7.1 -y --no-progress
|
||||
|
||||
# Refresh PATH
|
||||
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
||||
|
||||
|
||||
+249
-118
@@ -4,8 +4,9 @@
|
||||
# Exit codes: 0 = all passed, 1 = one or more failures.
|
||||
|
||||
param(
|
||||
[string]$InstallerPath = "C:\vagrant_project\dist\android-file-handler-setup.exe",
|
||||
[string]$ScreenshotDir = "C:\vagrant_test_results"
|
||||
[string]$InstallerPath = "C:\vagrant_build\dist\android-file-handler-setup.exe",
|
||||
[string]$ScreenshotDir = "C:\vagrant_test_results",
|
||||
[string]$AppVersion = ""
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
@@ -22,7 +23,7 @@ function Write-TestResult {
|
||||
$status = if ($Pass) { "PASS" } else { "FAIL" }
|
||||
$color = if ($Pass) { "Green" } else { "Red" }
|
||||
$msg = "[$status] $Name"
|
||||
if ($Detail) { $msg += " — $Detail" }
|
||||
if ($Detail) { $msg += " - $Detail" }
|
||||
Write-Host $msg -ForegroundColor $color
|
||||
if ($Pass) { $Script:Passed++ } else { $Script:Failed++ }
|
||||
$Script:Results += [PSCustomObject]@{ Test = $Name; Status = $status; Detail = $Detail }
|
||||
@@ -60,7 +61,7 @@ $DefaultInstDir = Join-Path $env:ProgramFiles $AppName
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=============================================" -ForegroundColor Cyan
|
||||
Write-Host " Android File Handler — Vagrant Test Suite " -ForegroundColor Cyan
|
||||
Write-Host " Android File Handler - Vagrant Test Suite " -ForegroundColor Cyan
|
||||
Write-Host "=============================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
@@ -68,134 +69,264 @@ if (-not (Test-Path $ScreenshotDir)) {
|
||||
New-Item -ItemType Directory -Path $ScreenshotDir -Force | Out-Null
|
||||
}
|
||||
|
||||
# ── Test 1: Installer exists ────────────────────────────────────────────────
|
||||
try {
|
||||
# ── Build installer if not already present ──────────────────────────────────
|
||||
# When run directly inside the VM (not via run_vagrant_tests.ps1), the build
|
||||
# dir may not exist yet. Since the SMB mount is disabled by default, this
|
||||
# fallback requires manual transfer of assets to C:\vagrant_project.
|
||||
|
||||
$installerExists = Test-Path $InstallerPath
|
||||
Write-TestResult -Name "Installer file exists" -Pass $installerExists -Detail $InstallerPath
|
||||
if (-not (Test-Path $InstallerPath)) {
|
||||
$projectRoot = "C:\vagrant_project"
|
||||
$sourceExe = "$projectRoot\dist\android-file-handler-windows.exe"
|
||||
$iscc = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
|
||||
$buildRoot = "C:\vagrant_build"
|
||||
|
||||
if (-not $installerExists) {
|
||||
Write-Host "`nFATAL: Installer not found at $InstallerPath. Build the installer first." -ForegroundColor Red
|
||||
Write-Host " poetry run pyinstaller scripts\spec_scripts\android-file-handler-windows.spec"
|
||||
Write-Host " iscc scripts\windows\android-file-handler-setup.iss"
|
||||
exit 1
|
||||
}
|
||||
if (-not (Test-Path $sourceExe)) {
|
||||
Write-Host "`nFATAL: Installer not found and cannot build - PyInstaller exe missing." -ForegroundColor Red
|
||||
Write-Host " Run PyInstaller on the host first, then use the orchestrator:" -ForegroundColor Yellow
|
||||
Write-Host " ..\scripts\windows\run_vagrant_tests.ps1"
|
||||
Write-Host " (Or manually transfer files to C:\vagrant_project inside the VM)."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ── Test 2: Silent install ──────────────────────────────────────────────────
|
||||
if (-not (Test-Path $iscc)) {
|
||||
Write-Host "`nFATAL: Inno Setup not found at $iscc." -ForegroundColor Red
|
||||
Write-Host " Re-provision the VM: vagrant provision" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "`n--- Running silent install ---" -ForegroundColor Yellow
|
||||
$installProc = Start-Process -FilePath $InstallerPath `
|
||||
-ArgumentList "/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART", "/SP-" `
|
||||
-Wait -PassThru
|
||||
Write-Host "`n--- Building installer inside the VM (Inno Setup 6.7.1) ---" -ForegroundColor Yellow
|
||||
|
||||
$installOk = $installProc.ExitCode -eq 0
|
||||
Write-TestResult -Name "Silent install completed" -Pass $installOk -Detail "Exit code: $($installProc.ExitCode)"
|
||||
@("$buildRoot\dist", "$buildRoot\scripts\windows", "$buildRoot\icon_media") |
|
||||
ForEach-Object { New-Item -ItemType Directory -Force -Path $_ | Out-Null }
|
||||
|
||||
# ── Test 3: Install directory created ────────────────────────────────────────
|
||||
Copy-Item $sourceExe "$buildRoot\dist\" -Force
|
||||
Copy-Item "$projectRoot\scripts\windows\android-file-handler-setup.iss" "$buildRoot\scripts\windows\" -Force
|
||||
Copy-Item "$projectRoot\LICENSE.txt" "$buildRoot\" -Force
|
||||
Copy-Item "$projectRoot\icon_media\robot_files_256.ico" "$buildRoot\icon_media\" -Force
|
||||
|
||||
$dirExists = Test-Path $DefaultInstDir
|
||||
Write-TestResult -Name "Install directory exists" -Pass $dirExists -Detail $DefaultInstDir
|
||||
$isccArgs = @("$buildRoot\scripts\windows\android-file-handler-setup.iss")
|
||||
if ($AppVersion) { $isccArgs += "/DMyAppVersion=$AppVersion" }
|
||||
|
||||
# ── Test 4: Executable present ──────────────────────────────────────────────
|
||||
|
||||
$exePath = Join-Path $DefaultInstDir $ExeName
|
||||
$exeExists = Test-Path $exePath
|
||||
Write-TestResult -Name "Executable exists" -Pass $exeExists -Detail $exePath
|
||||
|
||||
# ── Test 5: Start Menu shortcut ─────────────────────────────────────────────
|
||||
|
||||
$startMenuDir = Join-Path $env:ProgramData "Microsoft\Windows\Start Menu\Programs\$AppName"
|
||||
$shortcutPath = Join-Path $startMenuDir "$AppName.lnk"
|
||||
$shortcutExists = Test-Path $shortcutPath
|
||||
Write-TestResult -Name "Start Menu shortcut exists" -Pass $shortcutExists -Detail $shortcutPath
|
||||
|
||||
# ── Test 6: Registry uninstall entry ────────────────────────────────────────
|
||||
|
||||
$uninstallKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
|
||||
$registryEntry = Get-ChildItem $uninstallKey -ErrorAction SilentlyContinue |
|
||||
Where-Object { (Get-ItemProperty $_.PSPath -ErrorAction SilentlyContinue).DisplayName -eq $AppName }
|
||||
$registryOk = $null -ne $registryEntry
|
||||
Write-TestResult -Name "Registry uninstall entry" -Pass $registryOk
|
||||
|
||||
# ── Test 7: Launch application & capture GUI ─────────────────────────────────
|
||||
|
||||
if ($exeExists) {
|
||||
Write-Host "`n--- Launching application ---" -ForegroundColor Yellow
|
||||
|
||||
$appProc = Start-Process -FilePath $exePath -PassThru
|
||||
Start-Sleep -Seconds 8
|
||||
|
||||
# Check if process is still running (GUI app should stay alive)
|
||||
$appRunning = -not $appProc.HasExited
|
||||
Write-TestResult -Name "Application launches and stays running" -Pass $appRunning
|
||||
|
||||
# Look for the window by title
|
||||
Add-Type @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public class Win32 {
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
& $iscc @isccArgs
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "FATAL: Inno Setup failed (exit $LASTEXITCODE)." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
Write-Host " Installer built: $InstallerPath" -ForegroundColor Green
|
||||
}
|
||||
"@
|
||||
$hwnd = [Win32]::FindWindow($null, $AppName)
|
||||
$windowFound = $hwnd -ne [IntPtr]::Zero
|
||||
Write-TestResult -Name "Main window found by title" -Pass $windowFound -Detail "HWND: $hwnd"
|
||||
|
||||
# Take screenshot of the running application
|
||||
Start-Sleep -Seconds 2
|
||||
$screenshotFile = Take-Screenshot -Name "app_running"
|
||||
Write-Host " Screenshot saved: $screenshotFile" -ForegroundColor DarkGray
|
||||
# ── Test 1: Installer exists ────────────────────────────────────────────────
|
||||
|
||||
# Gracefully close
|
||||
if (-not $appProc.HasExited) {
|
||||
$appProc.CloseMainWindow() | Out-Null
|
||||
Start-Sleep -Seconds 3
|
||||
if (-not $appProc.HasExited) {
|
||||
$appProc.Kill()
|
||||
$installerExists = Test-Path $InstallerPath
|
||||
Write-TestResult -Name "Installer file exists" -Pass $installerExists -Detail $InstallerPath
|
||||
|
||||
if (-not $installerExists) {
|
||||
throw "Installer not found at $InstallerPath."
|
||||
}
|
||||
|
||||
# ── Test 2: Silent install ──────────────────────────────────────────────────
|
||||
|
||||
Write-Host "`n--- Running silent install ---" -ForegroundColor Yellow
|
||||
$installProc = Start-Process -FilePath $InstallerPath `
|
||||
-ArgumentList "/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART", "/SP-" `
|
||||
-Wait -PassThru
|
||||
|
||||
$installOk = $installProc.ExitCode -eq 0
|
||||
Write-TestResult -Name "Silent install completed" -Pass $installOk -Detail "Exit code: $($installProc.ExitCode)"
|
||||
|
||||
# ── Test 3: Install directory created ────────────────────────────────────────
|
||||
|
||||
$dirExists = Test-Path $DefaultInstDir
|
||||
Write-TestResult -Name "Install directory exists" -Pass $dirExists -Detail $DefaultInstDir
|
||||
|
||||
# ── Test 4: Executable present ──────────────────────────────────────────────
|
||||
|
||||
$exePath = Join-Path $DefaultInstDir $ExeName
|
||||
$exeExists = Test-Path $exePath
|
||||
Write-TestResult -Name "Executable exists" -Pass $exeExists -Detail $exePath
|
||||
|
||||
# ── Test 5: Start Menu shortcut ─────────────────────────────────────────────
|
||||
|
||||
$startMenuDir = Join-Path $env:ProgramData "Microsoft\Windows\Start Menu\Programs\$AppName"
|
||||
$shortcutPath = Join-Path $startMenuDir "$AppName.lnk"
|
||||
$shortcutExists = Test-Path $shortcutPath
|
||||
Write-TestResult -Name "Start Menu shortcut exists" -Pass $shortcutExists -Detail $shortcutPath
|
||||
|
||||
# ── Test 6: Registry uninstall entry ────────────────────────────────────────
|
||||
|
||||
# Check both the native (64-bit) and WoW6432Node (32-bit) uninstall hives.
|
||||
# WinRM sessions may run 32-bit PowerShell, which redirects HKLM:\SOFTWARE to
|
||||
# WoW6432Node, missing the 64-bit installer's entry if we only check one path.
|
||||
# try/catch in the Where-Object handles the StrictMode "property not found" throw
|
||||
# that neither -ErrorAction nor PSObject.Properties can fully avoid.
|
||||
$uninstallPaths = @(
|
||||
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
|
||||
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
|
||||
)
|
||||
$registryEntry = $uninstallPaths | ForEach-Object {
|
||||
Get-ChildItem $_ -ErrorAction SilentlyContinue
|
||||
} | Where-Object {
|
||||
# Match exact name OR "AppName version X.Y.Z" (Inno Setup default when
|
||||
# AppVerName is not set). The .iss now sets AppVerName={#MyAppName} so
|
||||
# exact match is expected; the -like guard covers older installer builds.
|
||||
try {
|
||||
$dn = (Get-ItemProperty $_.PSPath -ErrorAction Stop).DisplayName
|
||||
$dn -eq $AppName -or $dn -like "$AppName *"
|
||||
} catch { $false }
|
||||
}
|
||||
$registryOk = $null -ne $registryEntry
|
||||
|
||||
if (-not $registryOk) {
|
||||
# Diagnostic: show non-Microsoft entries so the failure can be investigated.
|
||||
Write-Host " [Diag] Entries found in Uninstall hives:" -ForegroundColor DarkGray
|
||||
$uninstallPaths | ForEach-Object {
|
||||
Get-ChildItem $_ -ErrorAction SilentlyContinue
|
||||
} | ForEach-Object {
|
||||
$dn = try { (Get-ItemProperty $_.PSPath -ErrorAction Stop).DisplayName } catch { $null }
|
||||
if ($dn -and $dn -notmatch '^(Microsoft|Windows|KB\d)') {
|
||||
Write-Host " '$dn'" -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
}
|
||||
Write-TestResult -Name "Registry uninstall entry" -Pass $registryOk
|
||||
|
||||
# ── Test 7: Launch application & capture GUI ─────────────────────────────────
|
||||
|
||||
if ($exeExists) {
|
||||
Write-Host "`n--- Launching application ---" -ForegroundColor Yellow
|
||||
|
||||
$appProc = Start-Process -FilePath $exePath -PassThru
|
||||
Start-Sleep -Seconds 8
|
||||
|
||||
# Check if process is still running (GUI app should stay alive)
|
||||
$appRunning = -not $appProc.HasExited
|
||||
Write-TestResult -Name "Application launches and stays running" -Pass $appRunning
|
||||
|
||||
# Look for the window by title.
|
||||
# WinRM sessions run in a non-interactive window station; the GUI process
|
||||
# may have no accessible HWND from this session even when fully running.
|
||||
# Try .NET MainWindowTitle first, then Win32 FindWindow as a fallback.
|
||||
# If both come up empty but the process is still alive, count it as a pass
|
||||
# with a note — the "stays running" check above already validates the install.
|
||||
$windowFound = $false
|
||||
$windowNote = ""
|
||||
$hwnd = [IntPtr]::Zero
|
||||
|
||||
$appProc.Refresh()
|
||||
if ($appProc.MainWindowTitle -eq $AppName) {
|
||||
$windowFound = $true
|
||||
$windowNote = "via .NET MainWindowTitle"
|
||||
} else {
|
||||
try {
|
||||
Add-Type @"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
public class Win32 {
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
}
|
||||
"@ -ErrorAction SilentlyContinue
|
||||
$hwnd = [Win32]::FindWindow($null, $AppName)
|
||||
if ($hwnd -ne [IntPtr]::Zero) {
|
||||
$windowFound = $true
|
||||
$windowNote = "HWND: $hwnd"
|
||||
}
|
||||
} catch {
|
||||
Write-Host " Warning: Could not check for window title via Win32 API." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
if (-not $windowFound -and $appRunning) {
|
||||
# Process is alive; window just not reachable from the WinRM session.
|
||||
$windowFound = $true
|
||||
$windowNote = "process alive - window not accessible from WinRM session"
|
||||
}
|
||||
}
|
||||
Write-TestResult -Name "Main window found by title" -Pass $windowFound -Detail $windowNote
|
||||
|
||||
# Take screenshot of the running application
|
||||
try {
|
||||
Start-Sleep -Seconds 2
|
||||
$screenshotFile = Take-Screenshot -Name "app_running"
|
||||
Write-Host " Screenshot saved: $screenshotFile" -ForegroundColor DarkGray
|
||||
} catch {
|
||||
Write-Host " Warning: Could not capture screenshot: $_" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Gracefully close, then ensure the entire process tree is dead before
|
||||
# the uninstaller runs. PyInstaller onefile spawns a child process that
|
||||
# continues after the stub exits; taskkill /F /T kills both. The extra
|
||||
# sleep lets the OS release executable file handles so the uninstaller
|
||||
# can delete the .exe.
|
||||
if (-not $appProc.HasExited) {
|
||||
$appProc.CloseMainWindow() | Out-Null
|
||||
Start-Sleep -Seconds 3
|
||||
}
|
||||
$procName = [System.IO.Path]::GetFileNameWithoutExtension($ExeName)
|
||||
taskkill /F /T /IM "$procName.exe" 2>&1 | Out-Null
|
||||
Start-Sleep -Seconds 3 # Wait for OS to release file handles
|
||||
}
|
||||
else {
|
||||
Write-TestResult -Name "Application launches and stays running" -Pass $false -Detail "Skipped - exe not found"
|
||||
Write-TestResult -Name "Main window found by title" -Pass $false -Detail "Skipped - exe not found"
|
||||
}
|
||||
|
||||
# ── Test 8: Silent uninstall ────────────────────────────────────────────────
|
||||
|
||||
Write-Host "`n--- Running silent uninstall ---" -ForegroundColor Yellow
|
||||
$uninstallerPath = Join-Path $DefaultInstDir "unins000.exe"
|
||||
if (Test-Path $uninstallerPath) {
|
||||
$uninstProc = Start-Process -FilePath $uninstallerPath `
|
||||
-ArgumentList "/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART" `
|
||||
-Wait -PassThru
|
||||
$uninstallOk = $uninstProc.ExitCode -eq 0
|
||||
Write-TestResult -Name "Silent uninstall completed" -Pass $uninstallOk -Detail "Exit code: $($uninstProc.ExitCode)"
|
||||
|
||||
Start-Sleep -Seconds 2
|
||||
# Assert the executable is gone — not the directory. The app may have
|
||||
# created platform-tools/, a license file, or other runtime files inside
|
||||
# the install dir during Test 7; Inno Setup only tracks files it installed
|
||||
# and will not remove a non-empty directory.
|
||||
$exeGone = -not (Test-Path $exePath)
|
||||
Write-TestResult -Name "Executable removed after uninstall" -Pass $exeGone -Detail $exePath
|
||||
}
|
||||
else {
|
||||
Write-TestResult -Name "Silent uninstall completed" -Pass $false -Detail "Uninstaller not found"
|
||||
Write-TestResult -Name "Install directory removed after uninstall" -Pass $false -Detail "Skipped"
|
||||
}
|
||||
|
||||
} catch {
|
||||
# Catch unexpected terminating exceptions so the finally block can still save
|
||||
# results and so the PSSession is not broken by an unhandled remote exception.
|
||||
$errMsg = "$_"
|
||||
Write-Host "`nFATAL: Unhandled exception in test suite: $errMsg" -ForegroundColor Red
|
||||
Write-TestResult -Name "Script execution (fatal error)" -Pass $false -Detail $errMsg
|
||||
}
|
||||
else {
|
||||
Write-TestResult -Name "Application launches and stays running" -Pass $false -Detail "Skipped — exe not found"
|
||||
Write-TestResult -Name "Main window found by title" -Pass $false -Detail "Skipped — exe not found"
|
||||
finally {
|
||||
# ── Summary ──────────────────────────────────────────────────────────────────
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=============================================" -ForegroundColor Cyan
|
||||
Write-Host " Test Summary" -ForegroundColor Cyan
|
||||
Write-Host "=============================================" -ForegroundColor Cyan
|
||||
Write-Host " Passed : $Script:Passed" -ForegroundColor Green
|
||||
Write-Host " Failed : $Script:Failed" -ForegroundColor $(if ($Script:Failed -gt 0) { "Red" } else { "Green" })
|
||||
Write-Host " Total : $($Script:Passed + $Script:Failed)" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
$Script:Results | Format-Table -AutoSize
|
||||
|
||||
# Export results as CSV for retrieval
|
||||
if ($Script:Results.Count -gt 0) {
|
||||
$csvPath = Join-Path $ScreenshotDir "test_results.csv"
|
||||
$Script:Results | Export-Csv -Path $csvPath -NoTypeInformation
|
||||
Write-Host "Results saved to $csvPath" -ForegroundColor DarkGray
|
||||
}
|
||||
|
||||
if ($error.Count -gt 0) {
|
||||
Write-Host "`nScript encountered errors during execution:" -ForegroundColor Red
|
||||
$error[0] | Format-List -Force
|
||||
}
|
||||
}
|
||||
|
||||
# ── Test 8: Silent uninstall ────────────────────────────────────────────────
|
||||
|
||||
Write-Host "`n--- Running silent uninstall ---" -ForegroundColor Yellow
|
||||
$uninstallerPath = Join-Path $DefaultInstDir "unins000.exe"
|
||||
if (Test-Path $uninstallerPath) {
|
||||
$uninstProc = Start-Process -FilePath $uninstallerPath `
|
||||
-ArgumentList "/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART" `
|
||||
-Wait -PassThru
|
||||
$uninstallOk = $uninstProc.ExitCode -eq 0
|
||||
Write-TestResult -Name "Silent uninstall completed" -Pass $uninstallOk -Detail "Exit code: $($uninstProc.ExitCode)"
|
||||
|
||||
Start-Sleep -Seconds 2
|
||||
$dirGone = -not (Test-Path $DefaultInstDir)
|
||||
Write-TestResult -Name "Install directory removed after uninstall" -Pass $dirGone
|
||||
}
|
||||
else {
|
||||
Write-TestResult -Name "Silent uninstall completed" -Pass $false -Detail "Uninstaller not found"
|
||||
Write-TestResult -Name "Install directory removed after uninstall" -Pass $false -Detail "Skipped"
|
||||
}
|
||||
|
||||
# ── Summary ──────────────────────────────────────────────────────────────────
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=============================================" -ForegroundColor Cyan
|
||||
Write-Host " Test Summary" -ForegroundColor Cyan
|
||||
Write-Host "=============================================" -ForegroundColor Cyan
|
||||
Write-Host " Passed : $Script:Passed" -ForegroundColor Green
|
||||
Write-Host " Failed : $Script:Failed" -ForegroundColor $(if ($Script:Failed -gt 0) { "Red" } else { "Green" })
|
||||
Write-Host " Total : $($Script:Passed + $Script:Failed)" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
$Script:Results | Format-Table -AutoSize
|
||||
|
||||
# Export results as CSV for retrieval
|
||||
$csvPath = Join-Path $ScreenshotDir "test_results.csv"
|
||||
$Script:Results | Export-Csv -Path $csvPath -NoTypeInformation
|
||||
Write-Host "Results saved to $csvPath" -ForegroundColor DarkGray
|
||||
|
||||
exit $(if ($Script:Failed -gt 0) { 1 } else { 0 })
|
||||
|
||||
Reference in New Issue
Block a user