diff --git a/tests/install/e2e-assets/handoff-trace/sitecustomize.py b/tests/install/e2e-assets/handoff-trace/sitecustomize.py index 87d9ffd808..2d57411022 100644 --- a/tests/install/e2e-assets/handoff-trace/sitecustomize.py +++ b/tests/install/e2e-assets/handoff-trace/sitecustomize.py @@ -7,9 +7,31 @@ import os if os.environ.get("GITHUB_ACTIONS") == "true" and os.environ.get("HERMES_E2E_HANDOFF_TRACE"): import faulthandler + import sys from pathlib import Path _directory = Path(os.environ["HERMES_E2E_HANDOFF_TRACE"]) _directory.mkdir(parents=True, exist_ok=True) _stream = (_directory / f"python-stacks-{os.getpid()}.log").open("a", encoding="utf-8") + _stream.write(f"started pid={os.getpid()} parent={os.getppid()} executable={sys.executable}\n") + _stream.flush() faulthandler.dump_traceback_later(90, repeat=True, file=_stream) + + # Call boundaries locate an early exit before the first timed stack dump. + # Never record arguments, frame locals, or return values. + _watched = { + "cmd_update", "_cmd_update_impl", "_run_pre_update_backup", + "_pause_windows_gateways_for_update", "find_gateway_pids", + "_scan_gateway_pids", "_get_service_pids", "_install_hangup_protection", + "_finalize_update_output", "load_config", "is_installed", + } + + def _trace_calls(frame, event, arg): + if event in ("call", "return") and frame.f_code.co_name in _watched: + _stream.write(f"{event} {frame.f_code.co_filename}:{frame.f_lineno} {frame.f_code.co_name}\n") + _stream.flush() + elif event == "c_call" and getattr(arg, "__name__", "") in {"kill", "_exit", "abort"}: + _stream.write(f"c_call {frame.f_code.co_filename}:{frame.f_lineno} {arg.__name__}\n") + _stream.flush() + + sys.setprofile(_trace_calls) diff --git a/tests/install/e2e-assets/july-handoff-diagnostics.ps1 b/tests/install/e2e-assets/july-handoff-diagnostics.ps1 index dc64fd9b65..de9e5790f8 100644 --- a/tests/install/e2e-assets/july-handoff-diagnostics.ps1 +++ b/tests/install/e2e-assets/july-handoff-diagnostics.ps1 @@ -59,15 +59,19 @@ Write-Section "meta" Write-Output ("utc={0} workroot={1}" -f (Get-Date).ToUniversalTime().ToString("o"), $WorkRoot) Write-Section "processes" -$procs = @(Get-CimInstance Win32_Process -ErrorAction SilentlyContinue) -if ($procs.Count -eq 0) { - Write-Output "Get-CimInstance returned nothing" -} +$procs = @(Get-CimInstance Win32_Process -ErrorAction Continue) +Write-Output "CIM process count=$($procs.Count)" +# The updater PID is authoritative even when its argv uses unnormalized paths. +$ownerPath = Join-Path $WorkRoot "hermes-home\.hermes-update-in-progress" +$ownerPid = if (Test-Path $ownerPath) { (Get-Content $ownerPath -First 1).Trim() } else { "" } +Get-Process -ErrorAction Continue | Where-Object { $_.Id -eq $ownerPid -or $_.Path -like '*hermes-desktop-gui-e2e*' } | + Select-Object Id, ProcessName, Path, CPU, WorkingSet64 | Format-List | Out-String | Write-Output $rootPids = @{} foreach ($p in $procs) { $exe = [string]$p.ExecutablePath $cmd = [string]$p.CommandLine - $ref = ($exe -like "$WorkRoot\*") -or ($cmd -like "*$WorkRoot\*") + if ($exe) { $exe = [System.IO.Path]::GetFullPath($exe) } + $ref = ($exe -like "$WorkRoot\*") -or ($p.ProcessId -eq $ownerPid) if ($ref) { $rootPids[[uint32]$p.ProcessId] = $true } } # Expand descendants transitively (both directions of interest: children of