Files
WhispAssist/docs/06-test-strategy.md
T

10 KiB

06 — Test Strategy

Testing mirrors the architecture (per-service) and the roadmap (per-phase). Every requirement ID has at least one test that asserts its acceptance criteria. A phase is "done" only when its suite is green and the cross-cutting gates pass.

Test levels

Level Scope Tooling
Unit One module/function; pure logic, parsers, mappers Rust #[cfg(test)]; Vitest (frontend)
Service/integration One service against real deps (SQLite, files, Ollama, models) Rust integration tests in /tests
Contract Tauri command/event payload shapes match 04-api-contracts.md shared TS↔Rust fixtures, schema assertions
End-to-end Full flows through the UI (record→notes→summary) Tauri WebDriver / Playwright-style harness
Non-functional Performance, resource, privacy egress Criterion benches; resource probes; network monitor

Key fixtures (/tests/fixtures)

  • Short stereo WAVs with known content (1-speaker, 2-speaker, overlap, silence, device-glitch).
  • A golden transcript.json for deterministic alignment/merge tests.
  • A small synthetic .pst with known events/attendees (or a generator script) — never real mail.
  • A canned Ollama response set (recorded) for offline LLM tests + a live-Ollama opt-in lane.
  • A disposable WebDAV server for sync tests (rclone serve webdav or a throwaway Nextcloud/Seafile container) + mocked OAuth responses for the secondary providers.

Per-phase suites

P1 — capture + CPU transcription

  • Unit: WAV writer produces valid headers/duration; ring buffer bounded + lossless under load.
  • Service: capture a fixed audio source → byte-accurate audio.wav (FR-CAP-1/2).
  • Service: feed a known WAV through the CPU Transcriber → expected segments within tolerance (FR-TRX-1).
  • E2E: start→speak→segments appear via transcript://segment; stop→idle (FR-CAP-3, FR-TRX-2).
  • NFR: idle audit — 0 audio threads / 0 polling timers after stop (NFR-RES-1).
  • Service: retention OFF (default) → no audio.wav after finalize; retention ON → playable audio.wav retained; toggling mid-meeting takes effect (FR-REC-1/3).
  • Unit/E2E: consent notice shown before first retained recording; acknowledgment persists and is not re-shown (FR-REC-2).

P2 — storage, notes, recovery

  • Unit: schema migrations apply forward cleanly; Markdown assembly is speaker-tagged + deterministic.
  • Service: create→finalize→get round-trips meeting + transcript (FR-STORE-1/5).
  • Service: crash-recovery — write working audio, kill process, relaunch → meeting recovering, re-transcribe succeeds (FR-REL-1, NFR-REL-3).
  • Service: retention deletes oldest past cap; refuses to touch an in-progress meeting (FR-STORE-2).
  • Service: working-WAV deletion on finalize happens only after transcript is finalized; a crash before finalize leaves a recoverable WAV regardless of retention setting (FR-REC-4).
  • Contract: .md export round-trips notes (FR-NOTE-3); bundle export contains audio+transcript+notes.

P3 — hardware + models

  • Unit: backend ranking honors NPU→NVIDIA→AMD→Intel→CPU; override respected (FR-HW-2).
  • Service: same WAV across available backends → equivalent segments (FR-TRX-5).
  • Service: simulated backend failure → hardware://changed + CPU fallback, no abort (FR-HW-4).
  • NFR bench: accelerated RTF < CPU RTF on capable hardware; latency target met (NFR-PERF-1/2).
  • Service: model download/remove with progress; corrupt/aborted download handled (FR-MODEL-1).

P4 — diarization & naming

  • Service: 2-speaker fixture → ≥2 speaker IDs; alignment overlap accuracy ≥ threshold (FR-SPK-1).
  • Unit: rename applies to all of a speaker's segments at render; storage IDs unchanged (FR-SPK-5).
  • Unit: merge(from=[S2,S3], into=S1) updates notes/export; idempotent (FR-SPK-3).
  • E2E: in-session naming updates live view (FR-SPK-2).

P5 — LLM

  • Service (recorded): prompt assembly includes transcript+metadata+template; output parsed into action items (FR-LLM-2/3).
  • Service: streaming tokens arrive via llm://token; summary.json persisted (FR-LLM-4).
  • Unit: local-endpoint guard flags non-loopback hosts → banner (FR-LLM-6, FR-SEC-1).
  • Resilience: provider off/unreachable → core app unaffected, clear status (FR-LLM-1/5).
  • Live lane (opt-in): against a real local Ollama, end-to-end summary sanity check.

P6 — calendar / .pst

  • Service: parse synthetic .pst → expected events + attendees; password path; corrupt file → non-fatal error surfaced (FR-CAL-1).
  • Unit: attendee list populates speaker-naming dropdown; "add new name" path (FR-SPK-4).
  • Service: attach meeting↔event persists link; participant continuity across meetings (FR-CAL-2/4).

P7 — UX / accessibility / privacy

  • E2E: theme follows OS + override; keyboard-only core flows (FR-UX-2/3).
  • A11y: automated axe-style audit (labels/roles/contrast) passes (FR-UX-4).
  • Service: privacy_self_check reports only allowed egress incl. configured sync targets with correct third-party/TLS labeling; backend/endpoint accurate (FR-SEC-2).
  • NFR: cold-start time under target; model lazy-load verified (NFR-PERF-4).

P8 — advanced

  • FTS search relevance on fixture corpus (FR-SEARCH-1); tag/filter correctness (FR-SEARCH-2).
  • Template application structures notes by type (FR-NOTE-5).
  • PDF/Word export renders offline + opens (FR-NOTE-4); bulk export by range/tag (FR-STORE-4).
  • Reminder fires locally (FR-CAL-5). Encryption: locked store unreadable without vault password; unlock round-trips (FR-SEC-3).

P9 — remote sync / upload

  • Service: sync disabled (default) → no sync_jobs enqueued, no sync hosts in the egress allowlist, nothing uploads (FR-SYNC-1). This is the most important sync test.
  • Service (WebDAV against rclone serve webdav or a disposable Nextcloud/Seafile container): finalize → selected artifacts land at the correct remote path (FR-SYNC-2/3).
  • Service: test_sync_target succeeds with good creds, fails clearly with bad creds/URL (FR-SYNC-4).
  • Resilience: kill the network mid-upload → job failed, retried with backoff, completes; unchanged re-upload is skipped via SHA-256; large-file resumable/chunked path exercised (FR-SYNC-5).
  • Security: credentials never written to settings.json/wa.db (assert by scanning both); list_sync_targets never returns secrets (FR-SYNC-6). Plaintext http:// refused unless explicit LAN opt-in (FR-SYNC-7).
  • Unit: host-allowlist derivation includes only enabled targets; disabling a target removes its host.
  • Secondary (mocked OAuth): PKCE loopback flow links an account; token stored in credential store; third-party banner shown (FR-SYNC-8/9). Optional: encrypt-before-upload yields ciphertext remotely (FR-SYNC-10).

P10 — external AI & coding-agent integration

  • Service: all off (default) → no AI host on the allowlist, MCP port closed, no briefs exposed. This is the most important P10 test.
  • Service (10a): summary routes to a mocked OpenAI-compatible and a mocked Anthropic endpoint (correct /v1/chat/completions vs /v1/messages shapes); API key read from the credential store, never from settings/DB; host appears on the allowlist only when configured (FR-AI-1/2).
  • Service (10b): with the MCP server enabled, an in-process MCP client calls get_feature_brief and receives a schema-valid brief; tools-only surface (no required resources/prompts) (FR-MCP-2/4).
  • Security: MCP server binds to loopback only (assert it does not bind a non-loopback address), requires a token, and opens no outbound socket — the egress test is unchanged with MCP on (FR-MCP-7, NFR-SEC-5). Recordings are not served unless expose_recordings is true (FR-MCP-3).
  • Audit: every tool call appends an mcp_access_log row / mcp://access event (FR-MCP-5).
  • Unit (M1 — feature briefs, no network): (1) parse_brief splits a golden ## Title/## Problem/## Desired Outcome/## Acceptance Criteria reply into the right fields, and an empty/malformed reply yields empty fields without panicking. (2) FeatureBriefBuilder over a golden transcript, driven by a MockLlmProvider that returns a fixed sectioned reply, produces a schema-valid FeatureBrief with non-empty acceptance_criteria and satisfies the grounding invariant: every context_excerpts[].text is a verbatim substring of some transcript segment (never model paraphrase). (3) Command-level: create_feature_brief with the LLM off/unreachable returns Err and writes no briefs/*.json and no feature_briefs row (no partial artifacts).
  • (10c, when built) push: AgentRunner invokes a stub CLI with the brief; IssueTracker creates a mocked GitHub issue and (optional) Copilot assignment (FR-AGENT-1/2).

Cross-cutting gates (run in CI every change)

  1. Privacy egress test (FR-SEC-1): run a representative flow under a network monitor; assert no outbound connection except hosts on the settings-derived allowlist — the configured LLM/AI provider endpoint, enabled sync target hosts, a configured task tracker, and explicit model-download hosts. With nothing configured, assert zero egress. Enabling the MCP server must not change the egress set (it is inbound/loopback). Any off-allowlist connection blocks merge. This is the product's most important automated guarantee.
  2. Build matrix: CPU-only build must always pass; accelerated features (CUDA/Vulkan/DirectML) built on capable runners, skipped (not failed) where hardware/SDK is absent (NFR-MNT-4).
  3. Lint/format: cargo fmt --check, cargo clippy -- -D warnings, Prettier, ESLint, tsc.
  4. Contract check: TS client types and Rust command/event payloads validated against shared fixtures so the IPC boundary can't silently drift.

Performance & resource benchmarks (tracked over time)

  • Real-time latency per phrase by backend (NFR-PERF-1).
  • 60-min batch wall-clock vs meeting length by backend (NFR-PERF-2).
  • Idle CPU/memory snapshot (NFR-RES-1); recording CPU on CPU-only laptop (NFR-RES-2).
  • Cold-start to interactive (NFR-PERF-4). Regressions beyond a threshold fail the bench gate.

Manual / exploratory checklist (pre-release)

Real meeting dogfood; device hot-swap mid-recording; very long (2 h) meeting; low-disk during capture; abrupt power loss (recover from audio); high-DPI + both themes; screen-reader pass.

Definition of done (recap from CLAUDE.md)

Compiles, no clippy warnings, requirement acceptance criteria met, named phase tests pass, docs updated if contracts/behavior changed.