--- phase: 02-acceptance-criteria-test-taxonomy-observability-spine plan: "03" subsystem: test-taxonomy tags: [pytest, markers, taxonomy, test-organization] dependency_graph: requires: [02-02] provides: [pytest-marker-taxonomy] affects: [02-04, 02-05] tech_stack: added: [] patterns: [module-level-pytestmark, pytest-marker-taxonomy] key_files: created: [] modified: - tests/test_acceptance.py - tests/test_accuracy.py - tests/test_api_flights.py - tests/test_chunk_manager.py - tests/test_coordinates.py - tests/test_database.py - tests/test_eskf.py - tests/test_gpr.py - tests/test_gps_input_encoding.py - tests/test_graph.py - tests/test_health.py - tests/test_mavlink.py - tests/test_metric.py - tests/test_models.py - tests/test_pipeline.py - tests/test_processor_full.py - tests/test_processor_pipe.py - tests/test_recovery.py - tests/test_rotation.py - tests/test_satellite.py - tests/test_schemas.py - tests/test_sitl_integration.py - tests/test_vo.py - tests/e2e/test_coord.py - tests/e2e/test_dataset_base.py - tests/e2e/test_download.py - tests/e2e/test_euroc_adapter.py - tests/e2e/test_euroc.py - tests/e2e/test_euroc_mh_all.py - tests/e2e/test_euroc_vo_only.py - tests/e2e/test_harness_smoke.py - tests/e2e/test_mars_lvig_adapter.py - tests/e2e/test_mars_lvig.py - tests/e2e/test_metrics.py - tests/e2e/test_synthetic_adapter.py - tests/e2e/test_vpair_adapter.py - tests/e2e/test_vpair.py decisions: - "test_models.py lacked import pytest — added import pytest + pytestmark together (Rule 2)" - "test_sitl_integration.py had bare pytestmark = pytest.mark.skipif(...) — converted to list form [pytest.mark.sitl, pytest.mark.skipif(...)] to combine category marker with skip guard" - "test_download.py and test_synthetic_adapter.py lacked import pytest — added import + pytestmark (Rule 2)" - "Plan says INTEGRATION (6) but table has 7 files — applied the authoritative table (7 files); plan must_haves correctly says 7 integration-marked files" metrics: duration: "~5 minutes" completed: "2026-05-11" tasks_completed: 4 files_modified: 37 --- # Phase 02 Plan 03: Apply Module-Level pytest Markers to 37 Test Files — Summary Applied `pytestmark = [pytest.mark.]` to all 37 test files (23 root + 14 e2e) per PATTERNS.md §1.1/§1.2 mapping. Zero test logic changes — only category markers added. ## Marker Assignment Table ### Root tests (tests/test_*.py) — 23 files | File | pytestmark | |------|------------| | tests/test_acceptance.py | `[pytest.mark.integration]` | | tests/test_accuracy.py | `[pytest.mark.integration]` | | tests/test_api_flights.py | `[pytest.mark.integration]` | | tests/test_chunk_manager.py | `[pytest.mark.unit]` | | tests/test_coordinates.py | `[pytest.mark.unit]` | | tests/test_database.py | `[pytest.mark.integration]` | | tests/test_eskf.py | `[pytest.mark.unit]` | | tests/test_gpr.py | `[pytest.mark.unit]` | | tests/test_gps_input_encoding.py | `[pytest.mark.blackbox]` | | tests/test_graph.py | `[pytest.mark.unit]` | | tests/test_health.py | `[pytest.mark.integration]` | | tests/test_mavlink.py | `[pytest.mark.unit]` | | tests/test_metric.py | `[pytest.mark.unit]` | | tests/test_models.py | `[pytest.mark.unit]` | | tests/test_pipeline.py | `[pytest.mark.unit]` | | tests/test_processor_full.py | `[pytest.mark.integration]` | | tests/test_processor_pipe.py | `[pytest.mark.integration]` | | tests/test_recovery.py | `[pytest.mark.unit]` | | tests/test_rotation.py | `[pytest.mark.unit]` | | tests/test_satellite.py | `[pytest.mark.unit]` | | tests/test_schemas.py | `[pytest.mark.unit]` | | tests/test_sitl_integration.py | `[pytest.mark.sitl, pytest.mark.skipif(...)]` | | tests/test_vo.py | `[pytest.mark.unit]` | ### E2E tests (tests/e2e/test_*.py) — 14 files | File | pytestmark | |------|------------| | tests/e2e/test_coord.py | `[pytest.mark.unit]` | | tests/e2e/test_dataset_base.py | `[pytest.mark.unit]` | | tests/e2e/test_download.py | `[pytest.mark.unit]` | | tests/e2e/test_euroc_adapter.py | `[pytest.mark.unit]` | | tests/e2e/test_euroc.py | `[pytest.mark.e2e]` | | tests/e2e/test_euroc_mh_all.py | `[pytest.mark.e2e]` | | tests/e2e/test_euroc_vo_only.py | `[pytest.mark.e2e]` | | tests/e2e/test_harness_smoke.py | `[pytest.mark.integration]` | | tests/e2e/test_mars_lvig_adapter.py | `[pytest.mark.unit]` | | tests/e2e/test_mars_lvig.py | `[pytest.mark.e2e]` | | tests/e2e/test_metrics.py | `[pytest.mark.unit]` | | tests/e2e/test_synthetic_adapter.py | `[pytest.mark.unit]` | | tests/e2e/test_vpair_adapter.py | `[pytest.mark.unit]` | | tests/e2e/test_vpair.py | `[pytest.mark.e2e]` | ## Per-Marker Collection Counts ``` unit 190 tests collected (14 root files + 8 e2e files = 22 unit-marked files) integration 69 tests collected (6 root files + 1 e2e file = 7 integration-marked files) blackbox 12 tests collected (1 root file) sitl 8 tests collected (1 root file, all skipped unless ARDUPILOT_SITL_HOST set) e2e 19 tests collected (5 e2e files, real-dataset required) Total: 298 tests ``` ## Coverage Union Check ``` Total collected: 298 Union (unit or integration or blackbox or sitl or e2e): 298 Orphans (not any marker): 0 Coverage: 100% ``` ## Logic-Diff Verification Only `pytestmark = [...]` lines and `import pytest` additions are present in test file diffs. The `tests/conftest.py` diff shown in `git diff tests/` is from plan 02-02 (AC traceability plugin), not from this plan's edits. ``` git diff tests/test_*.py tests/e2e/test_*.py | grep -E '^[-+]' | grep -vE '^(\+\+\+|---|@@|[-+]pytestmark|[-+]\s*$|[-+]import pytest$| [-+] pytest\.mark\.|[-+]\]$|[-+] not _SITL_AVAILABLE,$|[-+] reason=)' ``` Output: only `-)` → `+)]` (closing paren change in test_sitl_integration.py where skipif was converted from bare to list element). ## Final Regression Count ``` pytest tests/ -q --ignore=tests/e2e --strict-markers → 216 passed, 8 skipped (SITL) in 14.34s pytest tests/ -q --ignore=tests/e2e -m 'unit or integration or blackbox' --strict-markers → 216 passed, 8 deselected in 14.00s ``` Baseline parity: 216 >= 216. PASSED. ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 2 - Missing import] test_models.py lacked `import pytest`** - **Found during:** Task 1 pre-edit guard - **Issue:** `grep -L '^import pytest' tests/test_*.py` returned `tests/test_models.py` - **Fix:** Added `import pytest` before `pytestmark = [pytest.mark.unit]` - **Files modified:** tests/test_models.py **2. [Rule 2 - Missing import] test_download.py and test_synthetic_adapter.py lacked `import pytest`** - **Found during:** Task 2 pre-edit guard - **Issue:** `grep -L '^import pytest' tests/e2e/test_*.py` returned both files - **Fix:** Added `import pytest` + `pytestmark` together - **Files modified:** tests/e2e/test_download.py, tests/e2e/test_synthetic_adapter.py **3. [Rule 1 - Adaptation] test_sitl_integration.py had pre-existing `pytestmark = pytest.mark.skipif(...)`** - **Found during:** Task 1 pre-edit guard (already had `pytestmark` as a bare mark, not a list) - **Issue:** Simply replacing with `pytestmark = [pytest.mark.sitl]` would lose the skip guard - **Fix:** Converted to list form: `pytestmark = [pytest.mark.sitl, pytest.mark.skipif(...)]` - **Files modified:** tests/test_sitl_integration.py **4. [Rule 1 - Plan typo noted] Plan says INTEGRATION (6) but table lists 7 files** - **Found during:** Task 1 count verification - **Issue:** The plan's `` section header says "INTEGRATION (6)" but lists 7 files (test_acceptance, test_accuracy, test_api_flights, test_database, test_health, test_processor_full, test_processor_pipe). The `must_haves` section correctly says "7 integration-marked files". - **Fix:** Applied the authoritative table (7 files). The "(6)" heading is a typo in the plan. ## Files Not Modified (Exclusions Confirmed) - `tests/conftest.py`: unchanged by this plan (pre-existing 02-02 changes in git diff) - `tests/e2e/conftest.py`: unchanged - `tests/e2e/__init__.py`: unchanged ## Self-Check: PASSED All 37 test files carry a `pytestmark = [pytest.mark.]`. Coverage union = total = 298. 216 tests pass with `--strict-markers`. No test logic changed.