Add daemon startup smoke test and let it run on a PC in debug_mode

v0.11.0 shipped a daemon binary that built fine but didn't actually serve
a working frontend. CI was green. Nothing in the pipeline asserted that
the built binary comes up and serves something.

Add daemon/tests/smoke.rs as an integration test that spawns the built
binary against a tempdir-backed config with debug_mode = true, picks an
ephemeral port, and asserts:

- GET /index.html is 2xx and the decompressed body contains "Rayhunter"
- GET /api/qmdl-manifest is 2xx
- the daemon exits cleanly on SIGINT

Captures the daemon's stderr into a buffer so startup/shutdown failures
print actionable context instead of just "did not start listening".

Runs as part of the regular cargo test invocation, no new CI job.

For the smoke test (and #826) to work, the daemon needs to come up on a
PC without /dev/diag, a screen, or wpa_supplicant. The DIAG read thread,
display driver, and key input were already gated on debug_mode. Gate the
two remaining device-dependent workers the same way:

- run_battery_notification_worker (polls battery sysfs paths)
- wifi_station::run_wifi_client (talks to wpa_supplicant)

doc/installing-from-source.md gains a "Running the daemon on your PC"
section. doc/porting.md drops its duplicate debug_mode line and links to
the new section.

Closes #826.
This commit is contained in:
Ember
2026-05-12 17:05:19 -07:00
committed by Cooper Quintin
parent 5636cf4311
commit c2ba5a2a6c
6 changed files with 256 additions and 13 deletions
+16 -12
View File
@@ -277,12 +277,14 @@ async fn run_with_config(
analysis_tx.clone(),
);
run_battery_notification_worker(
&task_tracker,
config.device.clone(),
notification_service.new_handler(),
shutdown_token.clone(),
);
if !config.debug_mode {
run_battery_notification_worker(
&task_tracker,
config.device.clone(),
notification_service.new_handler(),
shutdown_token.clone(),
);
}
run_notification_worker(
&task_tracker,
@@ -291,12 +293,14 @@ async fn run_with_config(
);
let wifi_status = Arc::new(RwLock::new(WifiStatus::default()));
wifi_station::run_wifi_client(
&task_tracker,
&config.wifi_config(),
shutdown_token.clone(),
wifi_status.clone(),
);
if !config.debug_mode {
wifi_station::run_wifi_client(
&task_tracker,
&config.wifi_config(),
shutdown_token.clone(),
wifi_status.clone(),
);
}
if !config.webdav.url.trim().is_empty() {
run_webdav_upload_worker(