Testing and Code Coverage Policy
This document outlines the testing strategies, pipeline configurations, and code coverage rules used in Fovux MCP.
1. Test Execution Pipelines
To balance rapid feedback loops during PR reviews with thorough correctness guarantees, Fovux separates verification into two main pipelines:
Fast PR Checks
- Scope: Linting (
ruff), strict type checking (mypy), and unit tests. - Trigger: Runs automatically on every pull request and push.
- Command:
pnpm check(Studio) andtask test:fast(MCP server backend). - Execution: Runs only unit tests that do not require external network access, physical GPUs,
or long-running training loops (
not slow and not integration and not gpu).
Nightly / Scheduled Checks
- Scope: Exhaustive integration testing, mutation testing, and performance benchmark tracking.
- Trigger: Runs on a nightly cron job or scheduled execution.
- Command:
task test:cov(full coverage) andtask ci. - Execution: Executes end-to-end training runs (with
FOVUX_RUN_SLOW_TESTS=1enabled), full ONNX/TFLite export pipelines, live RTSP stream mocks, and mutation tests (mutmut).
2. Golden Dataset Contract
Golden dataset edge cases are generated deterministically in
tests/unit/tools/test_golden_dataset.py. The fixture creates a compact YOLO-style dataset with:
- Unicode folder and file names;
- corrupt and empty image cases;
- missing labels;
- class-count and class-id mismatches;
- duplicate/leakage cases across train and validation splits;
- Windows-style path separators inside
data.yaml.
This keeps the corpus reproducible without committing large binary assets. Any new dataset-quality
rule must either extend this fixture or add another deterministic fixture under tests/fixtures/.
3. Runtime and Export Contract Coverage
Runtime-heavy paths are covered with contract or mocked integration tests so fast PR checks remain usable while still protecting behavior:
| Area | Primary coverage | Strategy |
|---|---|---|
| Training worker | tests/unit/test_train_worker.py, tests/integration/test_pipeline_integration.py |
Mocked worker launch/status plus module-entry coverage. |
| ONNX/TFLite export | tests/unit/tools/test_export.py, tests/integration/test_pipeline_integration.py |
Mocked Ultralytics export and parity checks. |
| Image/batch inference | tests/unit/tools/test_diagnostics_tools.py, tests/unit/tools/test_inference_management.py |
Mocked model predictions and serialized-output assertions. |
| RTSP inference | tests/unit/tools/test_inference_management.py, tests/integration/test_pipeline_integration.py |
Fake capture/writer objects, reconnect loops, and frame-processing counters. |
| Dataset benchmarks | tests/bench/test_dataset_benchmarks.py |
pytest-benchmark baselines for inspection and duplicate detection. |
Coverage Signals and Merge Authority
The merge-blocking authority is the required ci-required aggregate. Its quality lane enforces
85% backend line coverage and a 45% Studio line-coverage floor, then validates both
artifacts with scripts/check_coverage_reports.py before any external upload. Missing, empty,
below-threshold, or cross-routed reports fail the required lane. Studio LCOV is source-only;
test/** helpers are excluded before report generation.
Coverage is generated and routed as follows:
| Surface | Required report | Required threshold | External routing |
|---|---|---|---|
| Python backend | fovux-mcp/coverage.xml |
85% lines | Codecov flag/component backend; Sonar Python coverage |
| Fovux Studio | fovux-studio/coverage/lcov.info |
45% lines | Codecov flag/component studio; Sonar JavaScript/TypeScript coverage |
SonarQube Cloud Automatic Analysis was disabled on 2026-07-22 because that mode does not ingest external coverage reports or repository scanner properties. The required quality lane now runs the SHA-pinned Sonar scanner after report validation and waits up to 300 seconds for the Sonar quality gate. For pull requests, Sonar's new-code baseline is the target branch and the scanner consumes the same backend XML and Studio LCOV artifacts produced by the required lane.
Codecov uploads remain OIDC-based. The combined project status uses an explicit 80% target and
the patch status uses an 85% target; both allow 1% tolerance and are non-informational, so
their GitHub pass/fail state matches the thresholds shown in the Codecov comment. Codecov waits for
exactly two coverage uploads (backend and studio), does not wait for unrelated CI providers,
and uses an explicit final send-notifications step after all coverage and test-result uploads. The
manual trigger produces one finalized status/comment set and surfaces processing errors. This keeps
the external signal prompt and observable without making it the repository's merge authority.
Backend and Studio remain separate through non-carryforward flags and named components. The
documented backend omit list is mirrored in Codecov ignore and Sonar coverage exclusions so both
services evaluate the same source scope. Component floors remain informational at 85% for the
backend and 45% for Studio. The Studio floor is a truthful ratchet baseline above which
coverage must remain while new-code patch coverage stays at 85%; it must only move upward as
coverage improves. Codecov supplies detailed diff diagnostics; ci-required remains the branch-rule
merge authority so an external service delay cannot redefine the repository's deterministic coverage
gate.
Sonar can display 0.0% Coverage on New Code when new_lines_to_cover is zero. In that case the
value means the pull request introduced no coverable production lines; it is not evidence that the
Cobertura or LCOV reports were missing. Report-ingestion health is instead confirmed by non-zero
project coverage/line counts and by the required pre-upload validator.
4. Code Coverage Omit List & Rationales
To maintain a meaningful coverage gate (minimum 85% required on included files), we exclude certain entry points and integration-heavy adapters where line-by-line coverage checks produce brittle or low-value tests. Below is the list of omitted paths and their rationales:
| Excluded File/Pattern | Rationale | How It Is Verified |
|---|---|---|
**/__main__.py |
CLI/Module entry point. Contains only bootstrap boilerplate. | Covered via CLI command execution smoke tests. |
**/cli.py |
Typer command-line interface logic. Primarily configuration and parsing. | Verified via end-to-end subprocess tests in the test suite. |
**/core/dataset_utils.py |
Filesystem and dataset-discovery helper paths are better validated through tool-level fixtures. | Covered by dataset inspect/validate/convert/split tests and golden dataset fixtures. |
**/core/train_worker.py |
Detached backend worker process logic designed to run in a separate process. | Tested via mock subprocess spawning tests and E2E training logs. |
**/core/ultralytics_adapter.py |
Third-party Ultralytics library adapter wrapper. | Checked indirectly via training, eval, and inference tool suites. |
**/tools/export_tflite.py |
Integration with external TensorFlow/Keras libraries for compilation. | Covered by mock integration tests verifying correct exported file paths. |
**/tools/deployment_advise.py |
Target advice is rule-table oriented and hardware-dependent. | Covered by focused deployment advice unit tests and release docs truth checks. |
**/tools/demo_init.py |
Demo scaffold generation is template-heavy and validated through command/output contracts. | Covered by demo/tool documentation checks and planned Studio onboarding smoke tests. |
**/tools/infer_image.py |
YOLO prediction pipeline that interacts with model weights. | Tested via mock inference contract checks and PIL verification. |
**/tools/infer_rtsp.py |
Live RTSP video capture loop which runs raw OpenCV frame streams. | Verified using mocked video captures and reconnect loops. |
**/tools/run_compare.py |
Run comparison depends on generated run artifacts and registry state. | Covered by run management, lineage ledger, and run comparison tool tests. |
**/tools/sync_to_mlflow.py |
Integration with external MLflow tracker API endpoints. | Verified using focused unit tests and API contract checks. |
5. Mutation Testing Gate
We use mutmut for mutation testing to verify the strength of our test suite.
- Mutation testing systematically modifies code statements (e.g. changing < to <=) and runs the
test suite.
- If the test suite still passes, the mutant "survived", indicating a gap in test coverage or assertions.
- We target core algorithmic code under src/fovux/core/ and require 0 surviving mutants in critical
paths.
6. Performance Baselines
We track execution latency for key operations to prevent performance regressions.
- Tools: pytest-benchmark measures the operations per second (OPS) of critical functions.
- Monitored Paths: Duplicate image detection and dataset inspection pipelines.
- Enforcement: Benchmarks are run nightly to ensure operations do not degrade past established baseline durations.