Files
Cognitive_Agent/N7Cockpit/scripts/test-remote-link.ps1

151 lines
5.8 KiB
PowerShell

[CmdletBinding()]
param(
[string]$AdbPath = 'D:\Android\Sdk\platform-tools\adb.exe',
[string]$ServerBaseUrl = 'http://127.0.0.1:8000',
[string]$TokenFile = "$env:LOCALAPPDATA\Temp\n7-device-token.txt",
[string]$PackageName = 'com.seeker.n7cockpit.remote',
[string]$ModeId = 'baby_nap',
[int]$TimeoutSeconds = 40,
[string]$ArtifactDirectory = ''
)
$ErrorActionPreference = 'Stop'
$projectRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
if (-not $ArtifactDirectory) {
$ArtifactDirectory = Join-Path $projectRoot 'artifacts\remote-link'
}
$buildConfig = Join-Path $projectRoot 'app\build\generated\source\buildConfig\debug\com\seeker\n7cockpit\BuildConfig.java'
if (-not (Test-Path -LiteralPath $TokenFile)) {
throw "The device token file does not exist: $TokenFile"
}
if (-not (Test-Path -LiteralPath $buildConfig)) {
throw 'Debug BuildConfig was not found. Build the remote debug APK first.'
}
$configText = Get-Content -LiteralPath $buildConfig -Raw -Encoding UTF8
if ($configText -notmatch 'ORCHESTRATOR_EXECUTION_TARGET\s*=\s*"dry_run"') {
throw 'Safety interlock: the APK execution target is not dry_run.'
}
if ($configText -notmatch 'ORCHESTRATOR_BASE_URL\s*=\s*"http://10\.0\.2\.2:8000"') {
throw 'This test only permits an emulator APK targeting 10.0.2.2:8000.'
}
$token = (Get-Content -LiteralPath $TokenFile -Raw).Trim()
if (-not $token) {
throw 'The device token is empty.'
}
$headers = @{ Authorization = "Bearer $token" }
$catalog = Invoke-RestMethod -Uri "$ServerBaseUrl/api/v1/vehicles/denza_n7/modes" `
-Headers $headers -TimeoutSec 5
$mode = @($catalog.modes | Where-Object { $_.id -eq $ModeId -and $_.origin -eq 'preset' })
if ($mode.Count -ne 1) {
throw "The preset is not unique in the server catalog: $ModeId"
}
$expectedModeName = [string]$mode[0].name
& (Join-Path $PSScriptRoot 'start-remote-app.ps1') -AdbPath $AdbPath `
-PackageName $PackageName | Out-Null
Start-Sleep -Seconds 1
# Standard 2560x1600 emulator: mode navigation, then the first preset button.
& $AdbPath shell input tap 94 406
Start-Sleep -Seconds 2
New-Item -ItemType Directory -Force -Path $ArtifactDirectory | Out-Null
& $AdbPath shell uiautomator dump /sdcard/n7-before-mode.xml | Out-Null
& $AdbPath pull /sdcard/n7-before-mode.xml (Join-Path $ArtifactDirectory 'before-mode.xml') | Out-Null
$beforeUi = Get-Content -LiteralPath (Join-Path $ArtifactDirectory 'before-mode.xml') `
-Raw -Encoding UTF8
if (-not $beforeUi.Contains('http://10.0.2.2:8000')) {
throw 'The Android mode page did not render its server connection.'
}
if (-not $beforeUi.Contains($expectedModeName)) {
throw "The Android mode page did not render the preset: $ModeId"
}
$baseline = Invoke-RestMethod `
-Uri "$ServerBaseUrl/api/v1/vehicles/denza_n7/events?after=0" `
-Headers $headers -TimeoutSec 5
$sequence = [long]$baseline.next_sequence
& $AdbPath shell input tap 1469 444
$deadline = (Get-Date).AddSeconds($TimeoutSeconds)
$observed = New-Object System.Collections.Generic.List[object]
$terminal = $null
do {
Start-Sleep -Seconds 1
$batch = Invoke-RestMethod `
-Uri "$ServerBaseUrl/api/v1/vehicles/denza_n7/events?after=$sequence" `
-Headers $headers -TimeoutSec 5
foreach ($event in @($batch.events)) {
$execution = $event.execution
if (-not $execution -and $event.data) {
$execution = $event.data.execution
}
if (-not $execution -or $execution.mode_id -ne $ModeId -or
$execution.source -ne 'android') {
continue
}
$observed.Add([pscustomobject]@{
sequence = [long]$event.sequence
execution_id = $execution.execution_id
status = $execution.status
target = $execution.execution_target
})
if ($execution.status -in @('succeeded', 'failed', 'cancelled')) {
$terminal = $execution
}
}
$sequence = [long]$batch.next_sequence
} while (-not $terminal -and (Get-Date) -lt $deadline)
if (-not $terminal) {
throw "No terminal mode event was received within $TimeoutSeconds seconds."
}
if ($terminal.execution_target -ne 'dry_run') {
throw "Safety failure: server execution target was $($terminal.execution_target)."
}
if ($terminal.status -ne 'succeeded') {
throw "Mode execution failed: $($terminal.status) $($terminal.error)"
}
$statusPath = Join-Path $ArtifactDirectory 'after-execution.xml'
$screenPath = Join-Path $ArtifactDirectory 'after-execution.png'
Start-Sleep -Seconds 2
& $AdbPath shell uiautomator dump /sdcard/n7-after-execution.xml | Out-Null
& $AdbPath pull /sdcard/n7-after-execution.xml $statusPath | Out-Null
& $AdbPath shell screencap -p /sdcard/n7-after-execution.png | Out-Null
& $AdbPath pull /sdcard/n7-after-execution.png $screenPath | Out-Null
$afterUi = Get-Content -LiteralPath $statusPath -Raw -Encoding UTF8
if (-not $afterUi.Contains($expectedModeName) -or -not $afterUi.Contains('100%')) {
throw 'The server task succeeded, but Android did not render terminal progress.'
}
if (-not $afterUi.Contains($terminal.execution_id)) {
throw 'The Android execution_id does not match the server execution_id.'
}
if (-not $afterUi.Contains('N7Cockpit')) {
throw 'Android did not render the expected source identity.'
}
$statuses = @($observed | Sort-Object sequence | Select-Object -ExpandProperty status)
foreach ($required in @('queued', 'executing', 'succeeded')) {
if ($required -notin $statuses) {
throw "The event stream is missing state: $required"
}
}
[pscustomobject]@{
Passed = $true
SafetyTarget = $terminal.execution_target
CanExecuted = $false
ModeId = $terminal.mode_id
ExecutionId = $terminal.execution_id
EventStates = ($statuses -join ' -> ')
AndroidStateSynchronized = $true
Screenshot = $screenPath
}