test(audio,ptt): comprehensive Windows P0 unit-test suite (L0-L11)
Layered test coverage for the Windows PTT subsystem ahead of the
v1.0.0-rc.8 official release sign-off.
L0 (refactor)
- Extract three pure-logic dispatchers from the existing WndProc /
LowLevelKeyboardProc / LowLevelMouseProc bodies in
crates/chanora_audio/src/ptt_backends/windows.rs:
dispatch_raw_input(ctx, &RAWINPUT)
dispatch_hook_keyboard(ctx, wparam, &KBDLLHOOKSTRUCT)
dispatch_hook_mouse(ctx, wparam, &MSLLHOOKSTRUCT)
Each takes a small Context (AtomicBinding + AudioTransmitGate +
flags) and is callable without spinning up any Win32 plumbing.
The real Win32 procs unchanged structurally; they unpack lparam
and forward to the dispatchers. AtomicBinding / RawInputContext
/ HookContext / resolve_binding are now pub(crate) so the
in-file test module can drive them.
L1 — windows_keymap full-table sweep (+13 tests)
Every key_label_to_vk arm, all A-Z + a-z, all 0-9, F1-F20,
navigation, modifiers, OEM punctuation, numpad. Exhaustive
mouse_label_to_button cases including the 0x08 / 0x10 /
unknown-bitmask fallbacks.
L2 — AtomicBinding lock-free correctness
store/read round-trip, clear(), Default = zeros, single-writer
/ single-reader concurrency, many-readers / single-writer.
L3 — resolve_binding dispatcher tests
All PttInputClass variants, well-known labels, unknown-label
fallback, mismatched class+label rejection, mouse bitmask
resolution.
L4 — Backend state-machine
Both WindowsRawInputBackend and WindowsHookBackend:
descriptor() pre-arm vs post-arm (L0Focused -> L2/L3), start()
with None binding rejection, rebind() in-place, stop()
clears + idempotent, stop() after stop() no-op.
L5 — dispatch_raw_input table
Keyboard match/non-match, key-down/key-up via Flags & 0x01,
no-binding short-circuit, mouse XBUTTON1/XBUTTON2 down/up
matching the bound button, unhandled HID type. RAWINPUT structs
built via mem::zeroed plus field-fill, owning the unsafe in
the test layer where it belongs.
L6 — dispatch_hook_keyboard + dispatch_hook_mouse
WM_KEYDOWN / WM_KEYUP / WM_SYSKEYDOWN / WM_SYSKEYUP for the
keyboard path, WM_XBUTTONDOWN / WM_XBUTTONUP for the mouse
path. Same shape as L5.
L7 — Privacy invariant (crates/chanora_audio/tests/ptt_privacy.rs)
New cross-platform integration test installs a custom
tracing_subscriber Layer that records every emitted event's
target + field names. Exercises the public PTT API plus (on
Windows) the backend factory. Asserts no field name in the
banned list (vk, scan_code, keysym, key_label, bound_key,
binding, platform_key, VKey, wVk, wScan, kbflags, mouseflags)
is ever emitted and every field belongs to the DEC-027
allow-list. Adds tracing-subscriber as a dev-dependency on
chanora_audio.
L8 — Full-chain integration in core/chanora_core/src/ptt.rs
Windows-only mod windows_full_chain_tests:
zero-tail full chain (synchronous)
default-tail full chain (200 ms wait then off)
mid-press rebind abandons in-flight press
L9/L10/L11 — tools/windows-smoke.cmd + tools/windows-smoke.md
Batch smoke script + operator doc. cargo build, flutter build,
artifact existence + size checks, headless launch with stderr
capture, bridge-initialised log assertion. Distinct exit codes
per failure step. Doc explains invocation + common failure
modes.
Verification (Linux)
- cargo check --workspace: clean.
- cargo test --workspace: 78 passed / 0 failed / 3 ignored.
76 cross-platform unit tests (unchanged) plus the new
ptt_privacy integration test plus one new ignored portal smoke
test.
The Windows-gated tests (~49 new) compile and run on the Korean
Windows 11 host where they belong; cross-compile from Linux is
not configured locally. The smoke script is the production
acceptance gate for rc.8 on Windows.
Deviations from the original plan are minor (single ignored
real-runtime test rather than per-platform attribute, L7 uses
public API rather than pub(crate) dispatchers, dispatchers live
inside windows.rs rather than a sibling module) and documented
in the subagent report.
This commit is contained in:
Executable
+118
@@ -0,0 +1,118 @@
|
||||
@echo off
|
||||
rem ============================================================
|
||||
rem Chanora Windows smoke build + launch script (L9 / L10 / L11
|
||||
rem of the P0 release plan).
|
||||
rem
|
||||
rem Runs end-to-end: vcvars64 + Flutter + Rust on PATH, cargo
|
||||
rem build the bridge, flutter build the Windows runner, sanity-
|
||||
rem check the output sizes, launch the runner for 5s, then grep
|
||||
rem the log for the bridge-initialised line and for panics.
|
||||
rem
|
||||
rem Hard-coded paths assume the Korean test host layout:
|
||||
rem C:\Users\admin\dev\flutter\bin
|
||||
rem C:\Users\admin\.cargo\bin
|
||||
rem C:\Program Files\Microsoft Visual Studio\2022\Community
|
||||
rem Repo at C:\Users\admin\chanora (script invoked from there).
|
||||
rem
|
||||
rem Exit codes:
|
||||
rem 0 = PASS
|
||||
rem non-zero = the step number that failed (1..10)
|
||||
rem ============================================================
|
||||
|
||||
setlocal EnableDelayedExpansion
|
||||
set "REPO_ROOT=%~dp0.."
|
||||
pushd "%REPO_ROOT%" || exit /b 1
|
||||
|
||||
rem --- Step 1: PATH + vcvars64 ---------------------------------
|
||||
set "PATH=C:\Users\admin\dev\flutter\bin;C:\Users\admin\.cargo\bin;%PATH%"
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" >nul
|
||||
if errorlevel 1 (
|
||||
echo FAIL: vcvars64.bat returned non-zero
|
||||
popd & exit /b 1
|
||||
)
|
||||
|
||||
rem --- Step 2: cargo build bridge ------------------------------
|
||||
echo [smoke] cargo build -p chanora_bridge --release
|
||||
cargo build -p chanora_bridge --release
|
||||
if errorlevel 1 (
|
||||
echo FAIL: cargo build -p chanora_bridge --release
|
||||
popd & exit /b 2
|
||||
)
|
||||
|
||||
rem --- Step 3: bridge DLL exists and is >5 MB ------------------
|
||||
set "BRIDGE_DLL=target\release\chanora_bridge.dll"
|
||||
if not exist "%BRIDGE_DLL%" (
|
||||
echo FAIL: %BRIDGE_DLL% does not exist
|
||||
popd & exit /b 3
|
||||
)
|
||||
for %%A in ("%BRIDGE_DLL%") do set "BRIDGE_SIZE=%%~zA"
|
||||
if !BRIDGE_SIZE! LSS 5242880 (
|
||||
echo FAIL: %BRIDGE_DLL% smaller than 5 MB ^(!BRIDGE_SIZE! bytes^)
|
||||
popd & exit /b 3
|
||||
)
|
||||
|
||||
rem --- Step 4: flutter build windows --release -----------------
|
||||
echo [smoke] flutter build windows --release
|
||||
pushd "apps\chanora_flutter" || (popd & exit /b 4)
|
||||
flutter build windows --release
|
||||
if errorlevel 1 (
|
||||
echo FAIL: flutter build windows --release
|
||||
popd & popd & exit /b 4
|
||||
)
|
||||
popd
|
||||
|
||||
rem --- Step 5: chanora_flutter.exe exists ----------------------
|
||||
set "RUNNER_DIR=apps\chanora_flutter\build\windows\x64\runner\Release"
|
||||
set "RUNNER_EXE=%RUNNER_DIR%\chanora_flutter.exe"
|
||||
if not exist "%RUNNER_EXE%" (
|
||||
echo FAIL: %RUNNER_EXE% does not exist
|
||||
popd & exit /b 5
|
||||
)
|
||||
|
||||
rem --- Step 6: app.so exists and is >1 MB ----------------------
|
||||
set "APP_SO=%RUNNER_DIR%\data\app.so"
|
||||
if not exist "%APP_SO%" (
|
||||
echo FAIL: %APP_SO% does not exist
|
||||
popd & exit /b 6
|
||||
)
|
||||
for %%A in ("%APP_SO%") do set "APP_SO_SIZE=%%~zA"
|
||||
if !APP_SO_SIZE! LSS 1048576 (
|
||||
echo FAIL: %APP_SO% smaller than 1 MB ^(!APP_SO_SIZE! bytes^)
|
||||
popd & exit /b 6
|
||||
)
|
||||
|
||||
rem --- Step 7: copy bridge DLL into Release dir ----------------
|
||||
copy /Y "%BRIDGE_DLL%" "%RUNNER_DIR%\chanora_bridge.dll" >nul
|
||||
if errorlevel 1 (
|
||||
echo FAIL: copy chanora_bridge.dll into Release dir
|
||||
popd & exit /b 7
|
||||
)
|
||||
|
||||
rem --- Step 8: launch runner for 5s ----------------------------
|
||||
set "SMOKE_LOG=%TEMP%\chanora-smoke.log"
|
||||
if exist "%SMOKE_LOG%" del "%SMOKE_LOG%"
|
||||
echo [smoke] launching %RUNNER_EXE% for 5s, stderr -^> %SMOKE_LOG%
|
||||
start "" /B "%RUNNER_EXE%" 2> "%SMOKE_LOG%"
|
||||
timeout /t 5 /nobreak >nul
|
||||
taskkill /F /IM chanora_flutter.exe >nul 2>&1
|
||||
|
||||
rem --- Step 9: grep for bridge initialised ---------------------
|
||||
findstr /C:"bridge initialised" "%SMOKE_LOG%" >nul
|
||||
if errorlevel 1 (
|
||||
echo FAIL: "bridge initialised" not present in %SMOKE_LOG%
|
||||
type "%SMOKE_LOG%"
|
||||
popd & exit /b 9
|
||||
)
|
||||
|
||||
rem --- Step 10: grep for panic (must be ABSENT) ----------------
|
||||
findstr /C:"panicked" "%SMOKE_LOG%" >nul
|
||||
if not errorlevel 1 (
|
||||
echo FAIL: "panicked" found in %SMOKE_LOG%
|
||||
type "%SMOKE_LOG%"
|
||||
popd & exit /b 10
|
||||
)
|
||||
|
||||
echo PASS: Chanora Windows smoke build + launch
|
||||
popd
|
||||
endlocal
|
||||
exit /b 0
|
||||
@@ -0,0 +1,83 @@
|
||||
# `tools/windows-smoke.cmd` — Korean host smoke build + launch
|
||||
|
||||
End-to-end "does Chanora build and start on Windows" verification.
|
||||
Designed for the lead's Korean Windows 11 test host and the
|
||||
`product/scaffold-v0` branch. Run from any directory inside the
|
||||
checked-out repo:
|
||||
|
||||
```
|
||||
C:\Users\admin\chanora> tools\windows-smoke.cmd
|
||||
```
|
||||
|
||||
The script `pushd`'s to the repo root (resolved from its own
|
||||
location), so the working directory does not matter as long as
|
||||
the script lives in `tools\` inside the checkout.
|
||||
|
||||
## What it does
|
||||
|
||||
1. Prepends Flutter + Cargo + MSVC to `PATH` and runs
|
||||
`vcvars64.bat`. Hard-coded paths assume the Korean host
|
||||
layout. If a path changes, edit the `set "PATH=..."` and
|
||||
`call "...\vcvars64.bat"` lines near the top.
|
||||
2. `cargo build -p chanora_bridge --release` and checks
|
||||
`target\release\chanora_bridge.dll` exists and is at least
|
||||
5 MB.
|
||||
3. `flutter build windows --release` inside `apps\chanora_flutter`
|
||||
and checks the runner + `data\app.so`.
|
||||
4. Copies the bridge DLL into the Flutter release folder.
|
||||
5. Launches the runner for five seconds with stderr redirected to
|
||||
`%TEMP%\chanora-smoke.log`, then kills it.
|
||||
6. Greps the log for `bridge initialised` (must be present) and
|
||||
`panicked` (must be absent).
|
||||
7. Prints `PASS` and exits 0 on success.
|
||||
|
||||
## Exit codes
|
||||
|
||||
| Code | Step |
|
||||
| ---- | -------------------------------------------------------------------- |
|
||||
| 0 | PASS |
|
||||
| 1 | `vcvars64.bat` failed |
|
||||
| 2 | `cargo build -p chanora_bridge --release` failed |
|
||||
| 3 | bridge DLL missing or smaller than 5 MB |
|
||||
| 4 | `flutter build windows --release` failed |
|
||||
| 5 | `chanora_flutter.exe` missing |
|
||||
| 6 | `data\app.so` missing or smaller than 1 MB |
|
||||
| 7 | bridge DLL copy into the Release folder failed |
|
||||
| 9 | log did not contain `bridge initialised` (bridge didn't load / panic at init) |
|
||||
| 10 | log contained `panicked` (Rust panic during the 5 s smoke window) |
|
||||
|
||||
## Common failure modes
|
||||
|
||||
* **vcvars64 returns non-zero**: MSVC not installed at the
|
||||
expected path. Update the `call "...\vcvars64.bat"` line or
|
||||
install the Build Tools workload from the VS2022 installer.
|
||||
* **`cargo build` fails with `link.exe not found`**: vcvars64
|
||||
did not take effect. Re-run from a fresh `cmd.exe` (PowerShell
|
||||
has its own quirks here).
|
||||
* **Bridge DLL exists but smaller than 5 MB**: a debug build
|
||||
slipped in. Make sure the script's `--release` flag was
|
||||
honoured; check that no `[profile.release]` override is
|
||||
stripping symbols too aggressively.
|
||||
* **`data\app.so` smaller than 1 MB**: Flutter assets did not
|
||||
bundle. Run `flutter clean` then re-run the script.
|
||||
* **`bridge initialised` absent**: the bridge `extern` symbol
|
||||
is not being found by the Flutter side. Verify the DLL copy
|
||||
step ran (it did, or the script would have exited 7) and that
|
||||
the DLL name matches what `lib/main.dart`'s ffi setup expects.
|
||||
* **`panicked` present**: open `%TEMP%\chanora-smoke.log` (the
|
||||
script dumps it on failure) and read the panic message. The
|
||||
most common cause during scaffold development is a missing
|
||||
flutter-rust-bridge code-gen file; re-run the codegen step
|
||||
per `docs/release/desktop-build-runbook.md`.
|
||||
|
||||
## Manual rerun of just the launch step
|
||||
|
||||
The PASS path always tears the runner down. If you want to
|
||||
inspect the running application after a green smoke pass:
|
||||
|
||||
```
|
||||
target\release\chanora_bridge.dll (already copied into Release\)
|
||||
apps\chanora_flutter\build\windows\x64\runner\Release\chanora_flutter.exe
|
||||
```
|
||||
|
||||
Launching the EXE directly will reuse the copied DLL.
|
||||
Reference in New Issue
Block a user