test: add manual harnesses for employee photo preprocessing

Add PowerShell harnesses to exercise EmployeePhotoFaceProcessor against
real HRMS portal photos without touching a device: run_photo_processor
processes given employee ids and writes source/processed JPEGs, and
run_photo_soak repeatedly processes real and synthetic images in one
process to check stability and memory. Both target 32-bit PowerShell to
match the service's x86 build.
main
SYED MUSTUFA AHMED NAQVI 2026-08-15 15:58:56 +05:00
parent 3ce91f4d76
commit e202923a69
2 changed files with 104 additions and 0 deletions

View File

@ -0,0 +1,49 @@
# Manual harness: runs EmployeePhotoFaceProcessor against real HRMS portal photos.
# Run with 32-bit PowerShell (the service targets x86):
# C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -File Tests\run_photo_processor.ps1 142554 144154
param([string[]]$EmployeeIds = @('142554'))
$ErrorActionPreference = 'Stop'
$dir = Join-Path $PSScriptRoot '..\bin\Debug\net48' | Resolve-Path
$outDir = Join-Path $env:TEMP 'hik_photo_test'
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
[System.AppDomain]::CurrentDomain.add_AssemblyResolve({
param($sender, $e)
$name = ($e.Name -split ',')[0]
$path = Join-Path $dir "$name.dll"
if (Test-Path $path) { return [System.Reflection.Assembly]::LoadFrom($path) }
return $null
})
$asm = [System.Reflection.Assembly]::LoadFrom((Join-Path $dir 'HikvisionAttendanceService.exe'))
$type = $asm.GetType('HikvisionAttendanceService.EmployeePhotoFaceProcessor')
$method = $type.GetMethod('Process', [System.Reflection.BindingFlags]'Static,Public,NonPublic')
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
$client = New-Object System.Net.WebClient
foreach ($id in $EmployeeIds) {
$url = "https://portal.utopiaindustries.pk/uind/employee-photo/$id.jpeg"
try { $bytes = $client.DownloadData($url) }
catch { Write-Host "$id download failed: $($_.Exception.Message)"; continue }
$result = $method.Invoke($null, @(, $bytes))
$srcPath = Join-Path $outDir "$id.source.jpeg"
[System.IO.File]::WriteAllBytes($srcPath, $bytes)
$line = "id=$id status=$($result.Status) downloaded=$($bytes.Length) " +
"original=$($result.Original.Width)x$($result.Original.Height) " +
"face=$($result.Face.Width)x$($result.Face.Height) " +
"processed=$($result.Processed.Width)x$($result.Processed.Height) " +
"jpegBytes=$($result.JpegBytes.Length) quality=$($result.JpegQuality) " +
"enhance=[$($result.Enhancement)] err=$($result.Error)"
Write-Host $line
if ($result.JpegBytes.Length -gt 0) {
$outPath = Join-Path $outDir "$id.processed.jpeg"
[System.IO.File]::WriteAllBytes($outPath, $result.JpegBytes)
Write-Host " source=$srcPath"
Write-Host " processed=$outPath"
}
}

55
Tests/run_photo_soak.ps1 Normal file
View File

@ -0,0 +1,55 @@
# Manual harness: repeatedly processes real + synthetic photos in a single process,
# mirroring how the service handles many employees per sync cycle.
# C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -File Tests\run_photo_soak.ps1 -Rounds 15
param([int]$Rounds = 15)
$dir = Join-Path $PSScriptRoot '..\bin\Debug\net48' | Resolve-Path
$log = Join-Path $env:TEMP 'hik_soak.txt'
Set-Content -Path $log -Value "soak start rounds=$Rounds"
[System.AppDomain]::CurrentDomain.add_AssemblyResolve({
param($sender, $e)
$name = ($e.Name -split ',')[0]
$path = Join-Path $dir "$name.dll"
if (Test-Path $path) { return [System.Reflection.Assembly]::LoadFrom($path) }
return $null
})
$asm = [System.Reflection.Assembly]::LoadFrom((Join-Path $dir 'HikvisionAttendanceService.exe'))
$type = $asm.GetType('HikvisionAttendanceService.EmployeePhotoFaceProcessor')
$method = $type.GetMethod('Process', [System.Reflection.BindingFlags]'Static,Public,NonPublic')
Add-Type -AssemblyName System.Drawing
$samples = @{}
foreach ($id in '142554', '144154', '149903') {
$p = Join-Path $env:TEMP "hik_photo_test\$id.source.jpeg"
if (Test-Path $p) { $samples[$id] = [System.IO.File]::ReadAllBytes($p) }
}
$bmp = New-Object System.Drawing.Bitmap 400, 400, ([System.Drawing.Imaging.PixelFormat]::Format24bppRgb)
$g = [System.Drawing.Graphics]::FromImage($bmp); $g.Clear([System.Drawing.Color]::SlateGray); $g.Dispose()
$ms = New-Object System.IO.MemoryStream
$bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Jpeg)
$samples['gray-noface'] = $ms.ToArray()
$samples['garbage'] = [byte[]]@(1, 2, 3, 4, 5)
$samples['empty'] = [byte[]]@()
$proc = [System.Diagnostics.Process]::GetCurrentProcess()
$sw = [System.Diagnostics.Stopwatch]::StartNew()
$counts = @{}
for ($i = 1; $i -le $Rounds; $i++) {
foreach ($key in $samples.Keys) {
$bytes = [byte[]]$samples[$key]
$r = $method.Invoke($null, @(, $bytes))
$k = "$key=$($r.Status)"
if (-not $counts.ContainsKey($k)) { $counts[$k] = 0 }
$counts[$k]++
}
}
$sw.Stop()
$proc.Refresh()
foreach ($k in ($counts.Keys | Sort-Object)) { Add-Content -Path $log -Value "$k count=$($counts[$k])"; Write-Host "$k count=$($counts[$k])" }
$line = "totalMs=$($sw.ElapsedMilliseconds) perCallMs=$([math]::Round($sw.ElapsedMilliseconds / ($Rounds * $samples.Count), 1)) workingSetMB=$([math]::Round($proc.WorkingSet64 / 1MB, 1)) handles=$($proc.HandleCount)"
Add-Content -Path $log -Value $line
Write-Host $line