Files
Lumotia/docs/architecture-map/03-audio-transcription/tests-and-fixtures.md
jars a1f3f3f134 docs: architecture map (initial 5-slice generation, 105 pages)
Five-slice navigable map of the entire codebase under
docs/architecture-map/. Each slice is a self-contained
breadcrumbed sub-tree:

  01-frontend (16)              Svelte/SvelteKit UI
  02-tauri-runtime (26)         src-tauri commands + lifecycle
  03-audio-transcription (16)   audio + transcription crates
  04-llm-formatting-mcp (19)    llm, ai-formatting, mcp, cloud
  05-core-storage-hotkey-build  core, storage, hotkey, workspace,
                          (26) CI, dev glue

Plus master README.md and data-flow-end-to-end.md tracing
audio bytes from microphone to FTS5 search to MCP read.

Generated by 5 parallel subagents on 2026/05/09 against
HEAD 3c47000. Each page has YAML frontmatter, file:line code
refs, sibling cross-links, plain-English summaries.

Aggregated debt surfaced (full lists in master README):
RB-08 macOS power assertion, schema head drift v14 vs v15,
VAD blocked on ort version conflict, streaming primitives
not wired into live.rs, no prompt versioning, MCP has no
auth, cloud-providers in-memory keystore, SettingsPage
2 484 LOC, commands/live.rs 1 737 LOC, dual theme system,
brand rename to Lumenote pending across the codebase.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:04:13 +01:00

87 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: Tests and fixtures
type: architecture-map-page
slice: 03-audio-transcription
last_verified: 2026/05/09
---
# Tests and fixtures
> **Where you are:** [Architecture map](../README.md) → [Audio + Transcription](README.md) → Tests and fixtures
**Plain English summary.** This slice has three categories of test. **Inline unit tests** under `#[cfg(test)] mod tests` exercise every public type (capture monitor detection, resampler duration preservation, RmsVadChunker state machine, LocalAgreement invariants, buffer trim bounds, model-manager hash and resume paths). **Integration tests** under `crates/transcription/tests/` exercise whisper-rs end-to-end with env-var-gated fixtures so CI without a model checkpoint exits quietly. **Test-only fixtures** include in-tree `tokio::net::TcpListener` HTTP servers that simulate Range / 5xx / no-Range-honour servers for the download stack.
## At a glance
- Crate: `magnotia-transcription` (mostly) and `magnotia-audio` (inline only).
- Paths:
- `crates/audio/src/{capture,decode,wav,resample,streaming_resample}.rs` — inline `#[cfg(test)]` modules.
- `crates/transcription/src/{model_manager,local_engine,transcriber,streaming/*}.rs` — inline `#[cfg(test)]` modules.
- `crates/transcription/tests/whisper_rs_smoke.rs` — env-gated load + transcribe.
- `crates/transcription/tests/jfk_bench.rs` — env-gated benchmark with cold/warm RTF.
- `crates/transcription/tests/thread_sweep.rs` — env-gated thread-count scaling sweep.
- External deps (dev): `tempfile 3`, `tokio` (rt, sync, net, io-util, macros), `num_cpus 1` (label-only).
## Inline unit tests (selected highlights)
### `magnotia-audio`
- `capture.rs:570``monitor_pattern_detection` for the PulseAudio / PipeWire heuristics.
- `decode.rs:262``mid_stream_io_error_propagates_instead_of_returning_partial_audio`. RB-09 regression: a flaky `MediaSource` (`FlakyCursor`, `decode.rs:203`) injects an I/O error after the probe header and asserts the function errors instead of returning `Ok(partial)`.
- `wav.rs:170``wav_writer_survives_crash`. Uses `std::mem::forget` to skip the hound finaliser, simulating a process kill, then asserts the flushed prefix is recoverable via `read_wav`.
- `wav.rs:235``read_wav_surfaces_truncated_sample_stream_errors`. 2026-04-22 regression: the previous `filter_map(|s| s.ok())` swallowed errors silently.
- `streaming_resample.rs:182``streaming_48k_to_16k_preserves_duration`. Pushes 1 s of 48 kHz audio in 700-sample chunks (forcing the residual-buffer path) and asserts the output is within 50 ms of 1 s at 16 kHz.
- `resample.rs:84``resample_preserves_approximate_duration`.
### `magnotia-transcription`
- `streaming/rms_vad.rs:371``:734` — comprehensive state-machine coverage: silence, hysteresis, onset gating, max-chunk continuity (`max_chunk_split_preserves_audio_contiguity`), padded-final-frame regression (`flush_preserves_hit_max_chunk_from_padded_final_frame`, `flush_preserves_end_of_utterance_chunk_from_padded_final_frame` — both 2026-04-22 CRITICAL C2 fixes), idempotent flush.
- `streaming/commit_policy.rs:212``:402` — LocalAgreement-n correctness: text-only equality, non-shrinkage invariant, defensive shorter-pass handling (`shorter_pass_after_commit_does_not_panic`, regression for the `latest[committed_count..]` panic), n=3 behaviour.
- `streaming/buffer_trim.rs:56``:206` — defensive non-finite handling, integration test against `LocalAgreement::last_committed_end_secs`, the long-session bound proof (`trim_bounds_buffer_over_long_session`).
- `model_manager.rs:339``:615` — three TcpListener-backed fixtures (`spawn_range_server`, `spawn_no_range_server`, `spawn_500_server`) drive `download_file` through the resume path, the ResumeUnsupported path (server returns 200 to a Range request), the 5xx rejection path, and the SHA-mismatch cleanup path.
- `local_engine.rs:218``engine_reports_not_available_before_loading`.
- `transcriber.rs:54``transcriber_trait_is_object_safe` (compile-time witness).
## Env-gated integration tests (`crates/transcription/tests/`)
All three skip silently if the env vars are unset, so `cargo test` on a fresh machine is a no-op for them.
### `whisper_rs_smoke.rs`
- Env vars: `MAGNOTIA_WHISPER_TEST_MODEL` (path to a ggml/gguf Whisper model).
- Loads the context, builds a state, calls `set_initial_prompt("Wren, CORBEL, ADHD")` (proves the API still exists), runs inference on 1 s of silence, exercises `full_n_segments` and `get_segment(i).to_str()`. Smoke test only; assertion is "did this run without panicking".
### `jfk_bench.rs`
- Env vars: `MAGNOTIA_WHISPER_TEST_MODEL`, `MAGNOTIA_WHISPER_TEST_AUDIO` (path to a 16 kHz mono 16-bit PCM WAV — assertions in the test enforce this format on the fixture, not the runtime).
- Reports cold-load time, cold-transcribe RTF, warm-transcribe RTF, peak RSS read from `/proc/{pid}/status`. Hardcodes `set_n_threads(6)` for both runs (so a sweep across thread counts is a separate test, not this one).
### `thread_sweep.rs`
- Same env vars as `jfk_bench.rs`. Adds `MAGNOTIA_POWER_STATE_OVERRIDE` (set internally per panel to `ac` or `battery`) so `inference_thread_count` returns its predicted pick for each combination of (power state × GPU offload) and the empirical RTF table can be compared against the helper's choice.
- Runs the JFK clip at `n_threads = 1, 2, 4, physical, logical` (plus `8` if logical ≥ 8), takes the min of two runs per setting, prints a four-panel table:
1. AC, CPU.
2. AC, GPU (Vulkan).
3. battery, CPU.
4. battery, GPU (Vulkan).
- Uses `num_cpus::get()` and `num_cpus::get_physical()` purely for the printed labels (`thread_sweep.rs:35`). The runtime helper `inference_thread_count(Workload::Whisper, gpu_offloaded)` does the actual prediction.
- `vulkan_runtime_ok` snapshot taken once via `cfg!(feature = "whisper-vulkan") && vulkan_loader_available()`.
## Watch-outs
- **All three integration tests are quiet on missing env vars.** A green `cargo test` does NOT mean the Whisper path works; it means "either the path works or you didn't set the env vars". CI configurations must explicitly set `MAGNOTIA_WHISPER_TEST_MODEL` to exercise these.
- **`jfk_bench.rs` hardcodes `n_threads = 6`.** Production code uses `inference_thread_count(Workload::Whisper, gpu_offloaded)` which is power-aware. Bench numbers are not directly comparable to runtime numbers without rerunning with the helper-picked thread count.
- **`thread_sweep.rs` mutates `MAGNOTIA_POWER_STATE_OVERRIDE` via `env::set_var`.** Globally process-wide. Concurrent tests in the same `cargo test` invocation that read `MAGNOTIA_POWER_STATE_OVERRIDE` will race. The test removes the var at the end (`thread_sweep.rs:94`).
- **`tempfile 3` is a dev-dep, not a runtime dep.** Production code never creates temp files.
- **`num_cpus = "1"` (the version, not "one CPU").** Test-only labelling; production uses the slice 5 helper.
- **In-tree HTTP fixtures use ephemeral ports (`bind 127.0.0.1:0`) and run on a tokio task.** No port-collision risk, but a paranoid sandbox that blocks raw TCP loopback would break these tests.
- **`ModelFile`'s `&'static str` fields force the test helper `leak()` (`model_manager.rs:462`).** Each test leaks a few small strings. Acceptable for one-shot tests; do not copy this pattern into production code.
## See also
- [Transcription model manager](transcription-model-manager.md) — the production code these download tests guard.
- [Transcription whisper](transcription-whisper.md) — the production code these integration tests guard.
- [Transcription streaming](transcription-streaming.md) — exhaustive unit-test coverage lives alongside this code.
- `docs/whisper-ecosystem/brief.md` — the source of the items (`#6, #8, #19, #21, #24, #25`) repeatedly referenced in test docstrings.
- `docs/code-review-2026-04-22.md` — the audit pass that produced the C2, RB-09, and `read_wav` regressions captured here.