Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
7ced8e4
Phase 1: Lock migration scope and acceptance gates
Kane610 Apr 29, 2026
3a6fd06
Phase 2: Add aiohttp-native test fixtures and request capture helper
Kane610 Apr 29, 2026
72b64e2
Phase 3: Replace core handler tests with aiohttp_server parity tests
Kane610 Apr 29, 2026
1dfd087
Phase 4: Replace auth and query edge-case tests with aiohttp_server p…
Kane610 Apr 29, 2026
0dd9585
Phase 5: Replace remaining parameter and application suites
Kane610 Apr 29, 2026
21eb2a1
Phase 6: Migrate additional suites off respx
Kane610 Apr 29, 2026
1d15d13
Phase 6: Migrate mqtt and user management tests off respx
Kane610 Apr 29, 2026
504832f
Phase 6: Migrate PIR sensor configuration tests off respx
Kane610 Apr 29, 2026
6bb0acc
Phase 6: Migrate light control tests off respx
Kane610 Apr 29, 2026
861b505
Phase 6: Migrate light and view area tests off respx
Kane610 Apr 29, 2026
cb53a4c
Phase 6: Migrate PTZ tests off respx
Kane610 Apr 29, 2026
25f1d18
Phase 6: Migrate vapix integration tests off respx
Kane610 Apr 29, 2026
837a5b8
Drop remaining respx fixture coupling
Kane610 Apr 29, 2026
390ea9e
Phase 7: Extract shared respx shim helper
Kane610 Apr 29, 2026
b855286
Phase 8: Add runtime httpx-removal implementation plan
Kane610 Apr 29, 2026
ca3e5a1
Phase 9: Add aiohttp performance evaluation matrix
Kane610 Apr 29, 2026
c38f533
Phase 10: Add architecture sign-off and rollback gates
Kane610 Apr 29, 2026
a2daa64
feat: Pilot consolidated mock server fixture with test_applications r…
Kane610 Apr 29, 2026
e9a0837
feat: Extend fixture to capture request payloads and refactor fence_g…
Kane610 Apr 29, 2026
454c2fb
docs: Update pilot summary with fence_guard refactoring results and p…
Kane610 Apr 29, 2026
a7559e0
test: step 1 migrate user_groups handlers to aiohttp_mock_server
Kane610 Apr 29, 2026
5ac7711
test: step 2 migrate stream_profiles handlers to aiohttp_mock_server
Kane610 Apr 29, 2026
44caed5
test: step 3 migrate motion_guard handlers to aiohttp_mock_server
Kane610 Apr 29, 2026
68559fd
test: step 4 migrate loitering_guard handlers to aiohttp_mock_server
Kane610 Apr 29, 2026
d3dc903
test: step 5 migrate vmd4 handlers to aiohttp_mock_server
Kane610 Apr 29, 2026
205ec01
test: step 6 migrate port_management handlers to aiohttp_mock_server …
Kane610 Apr 29, 2026
eee27b1
test: steps 6-7 migrate port_management and mqtt handlers to aiohttp_…
Kane610 Apr 29, 2026
7123fb4
test: step 8 migrate pir_sensor_configuration handlers to aiohttp_moc…
Kane610 Apr 29, 2026
fd09621
test: step 9 migrate pwdgrp helper setup to aiohttp_mock_server
Kane610 Apr 29, 2026
911715e
test: step 10 migrate event_instances SOAP handlers to aiohttp_mock_s…
Kane610 Apr 29, 2026
77ee816
test: step 11 migrate object_analytics handlers to aiohttp_mock_server
Kane610 Apr 29, 2026
41ed648
test: step 12 add capture_body support and remove pwdgrp custom handler
Kane610 Apr 29, 2026
f1ab65f
test: step 13 migrate basic_device_info manual aiohttp setup to share…
Kane610 Apr 29, 2026
802c20f
test: step 14 migrate api_discovery manual aiohttp setup to shared fi…
Kane610 Apr 29, 2026
4f63a1e
test: step 15 migrate auth_scheme manual aiohttp setup to shared fixture
Kane610 Apr 29, 2026
71180ef
test: step 16 migrate http_client_compat manual aiohttp setup to shar…
Kane610 Apr 29, 2026
a55a930
test: step 17 migrate parameters brand tests to shared fixture
Kane610 Apr 29, 2026
94c9923
test: step 18 migrate parameters io_port tests to shared fixture
Kane610 Apr 29, 2026
2ff0c57
test: step 19 migrate parameters param_cgi test to shared fixture
Kane610 Apr 29, 2026
8631523
test: step 20 migrate parameters stream_profile test to shared fixture
Kane610 Apr 29, 2026
71fe45c
test: step 21 migrate parameters properties tests to shared fixture
Kane610 Apr 29, 2026
bcbc1b5
test: step 22 migrate parameters image tests to shared fixture
Kane610 Apr 29, 2026
f08ec7f
test: step 23 migrate port_cgi tests to shared fixture
Kane610 Apr 30, 2026
133a578
test: step 24 migrate parameters ptz tests to shared fixture
Kane610 Apr 30, 2026
4bb4a7b
test: step 25 simplify port_management fixture usage
Kane610 Apr 30, 2026
f023073
test: step 26 migrate respx shim helper to shared fixture
Kane610 Apr 30, 2026
395c4a0
refactor(tests): rename respx_shim -> http_route_mock with neutral na…
Kane610 Apr 30, 2026
af6c742
refactor(tests): add section markers and http_route_mock fixtures to …
Kane610 Apr 30, 2026
e8a62f1
test(conftest): add contract tests for http_route_mock fixtures
Kane610 Apr 30, 2026
fefe17a
refactor(tests): consume shared http_route_mock fixture in single-dev…
Kane610 Apr 30, 2026
0b46edb
refactor(tests): use http_route_mock_factory thin adapter in test_vapix
Kane610 Apr 30, 2026
02e9175
docs(contributing): add HTTP fixture selection guide and extraction g…
Kane610 Apr 30, 2026
ae34d02
docs(contributing): tighten fixture chooser guidance
Kane610 Apr 30, 2026
4db4e40
refactor(tests): consolidate canonical device fixtures
Kane610 Apr 30, 2026
27fe4c9
refactor(tests): simplify unused aiohttp_mock_server results
Kane610 Apr 30, 2026
7add2bd
refactor(tests): use fixture-managed aiohttp session cleanup
Kane610 Apr 30, 2026
98cc5ab
refactor(tests): rename aiohttp_session fixture to session
Kane610 Apr 30, 2026
117f0b8
refactor(tests): restore route-based DSL pattern with http_route_mock
Kane610 Apr 30, 2026
7c4f184
refactor(tests): convert remaining route-DSL tests from aiohttp_mock_…
Kane610 Apr 30, 2026
6b07f60
refactor(tests): extract shared mock response builder
Kane610 Apr 30, 2026
adf87dc
refactor(tests): centralize mock device port binding
Kane610 Apr 30, 2026
213193f
refactor(tests): deduplicate route side-effect exception handling
Kane610 Apr 30, 2026
24e857c
refactor(tests): support explicit body matching in route mock
Kane610 Apr 30, 2026
a3cbe4f
docs(tests): add fixture selection guidance for HTTP mocks
Kane610 Apr 30, 2026
d21650e
fix(tests): correct payload capture exception handling
Kane610 Apr 30, 2026
d2f5202
docs(tests): clarify vapix multi-device fixture override
Kane610 Apr 30, 2026
786301d
test(tests): lock route body-matching semantics
Kane610 Apr 30, 2026
b0d6148
docs(contributing): clarify route body matching and fixture overrides
Kane610 Apr 30, 2026
fc5ffdb
refactor(tests): replace httpx.AsyncClient with aiohttp session fixtu…
Kane610 Apr 30, 2026
45d2dd0
refactor(tests): replace httpx transport sentinels with stdlib except…
Kane610 Apr 30, 2026
a01e03c
refactor(tests): use SimulateTimeout/ConnectionError/RequestError sen…
Kane610 Apr 30, 2026
b994c1f
chore(tests): remove stale httpx references
Kane610 Apr 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/aiohttp-performance-matrix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Aiohttp Performance Evaluation Matrix

## Context

- Date: 2026-04-29
- Branch: feature/aiohttp-test-migration
- Runtime: Python 3.14.2 via `uv run`
- Host: local development machine (macOS)

## Method

Each suite was executed 3 times with `pytest --no-cov` to reduce coverage overhead and
capture relative runtime consistency.

Commands:

1. `uv run pytest --no-cov tests/test_http_client_compat.py`
2. `uv run pytest --no-cov tests/test_vapix.py tests/test_ptz.py tests/test_view_areas.py tests/test_light_control.py`
3. `uv run pytest --no-cov tests/test_vapix.py tests/test_ptz.py tests/test_view_areas.py tests/test_light_control.py tests/test_mqtt.py tests/test_pwdgrp_cgi.py tests/test_stream_profiles.py tests/test_user_groups.py tests/test_event_instances.py tests/test_port_management.py tests/test_pir_sensor_configuration.py`

## Results

| Matrix Group | Passed Tests | Run 1 (s) | Run 2 (s) | Run 3 (s) | Avg (s) | Min (s) | Max (s) |
|---|---:|---:|---:|---:|---:|---:|---:|
| compat | 10 | 0.03 | 0.03 | 0.02 | 0.03 | 0.02 | 0.03 |
| handlers | 113 | 0.42 | 0.47 | 0.46 | 0.45 | 0.42 | 0.47 |
| phase6plus | 154 | 0.58 | 0.54 | 0.55 | 0.56 | 0.54 | 0.58 |

## Interpretation

1. Aiohttp-focused integration suites remain stable and low-latency on repeated runs.
2. Runtime spread is narrow for all groups, indicating no obvious regression drift.
3. The broader migrated suite (`phase6plus`) stays under one second across all samples.

## Exit Decision

Phase 9 acceptance is met: the aiohttp performance matrix has been executed and
recorded with repeatable timing data for representative migrated suites.
78 changes: 78 additions & 0 deletions .github/final-architecture-signoff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Final Architecture Sign-Off And Rollback Gates

## Decision Summary

The aiohttp-first migration architecture is approved for completion based on:

1. Test-layer migration from respx/httpx coupling to aiohttp_server parity coverage.
2. Consolidated shared shim utilities for migrated suites.
3. Runtime httpx-removal implementation plan documented and scoped.
4. Performance matrix confirming stable runtime behavior on representative suites.

## Signed-Off Architecture State

1. Initialization model remains phase-driven:
- API_DISCOVERY
- PARAM_CGI_FALLBACK
- APPLICATION

2. Handler registration and grouped initialization behavior are preserved.

3. Request/response behavior parity is maintained across migrated tests:
- status-code error translation,
- auth fallback behavior,
- namespace-aware/event parsing expectations.

4. Planned runtime simplification is constrained and reversible:
- move to aiohttp-only runtime sessions,
- preserve existing request error semantics,
- preserve auth retry behavior for AUTO mode.

## Release Gates

All gates must be green before rollout:

1. Linting: `uv run ruff check .`
2. Formatting: `uv run ruff format --check .`
3. Typing: `uv run mypy axis`
4. Tests: `uv run pytest`
5. Migration docs current:
- `.github/httpx-removal-implementation-plan.md`
- `.github/aiohttp-performance-matrix.md`

## Rollback Gates And Triggers

Rollback to pre-change baseline is required if any trigger occurs after runtime
httpx removal implementation begins:

1. Functional trigger:
- auth negotiation failures or increased 401/403 responses in supported devices.

2. Reliability trigger:
- sustained request timeout/connection-error regression outside historical bounds.

3. Compatibility trigger:
- regressions in API discovery, param.cgi fallback, or application handler
initialization ordering.

4. Quality trigger:
- failure to satisfy lint/type/test release gates.

## Rollback Procedure

1. Revert runtime-removal commits from the feature branch.
2. Restore last green commit set with full test migration and green CI.
3. Re-run full validation matrix.
4. Publish incident note in PR with root-cause and adjusted rollout plan.

## Operational Notes

1. Keep `uv.lock` updates isolated from migration intent unless dependency inputs
changed intentionally.
2. Preserve incremental commit discipline for any follow-up runtime changes.
3. Maintain PR checklist and commit ledger updates per increment.

## Phase 10 Exit Criteria

Phase 10 is complete when this sign-off is present in-repo and PR tracking marks
the final architecture sign-off and rollback gates as complete.
108 changes: 108 additions & 0 deletions .github/httpx-removal-implementation-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Runtime HTTPX Removal Implementation Plan

## Scope

This plan defines how runtime support for `httpx` will be removed while preserving
existing behavior for Axis request handling, auth fallback, and error semantics.

The test migration has already moved request/response test behavior to
`aiohttp_server`-backed flows. Remaining Phase 8 work is runtime-only.

## Current Runtime Coupling (Inventory)

1. `axis/interfaces/vapix.py`
- Imports `httpx` and supports two request engines (`httpx` and `aiohttp`).
- Constructs `httpx.BasicAuth` and `httpx.DigestAuth` for non-`aiohttp` sessions.
- Routes requests through `_perform_httpx_request` when session is not `aiohttp`.
- Maps `httpx.TimeoutException`, `httpx.TransportError`, and
`httpx.RequestError` to `RequestError`.
- Uses `httpx.DigestAuth` type checks for AUTO fallback behavior.

2. `axis/models/configuration.py`
- `Configuration.session` is typed as `AsyncClient | ClientSession`.
- Type-checking import references `httpx.AsyncClient`.

3. `pyproject.toml`
- Runtime dependency list includes `httpx>=0.26`.
- Optional pinned requirements include `httpx==0.28.1`.

4. Tests
- `tests/test_configuration.py` still validates `httpx.AsyncClient` acceptance in
`Configuration`.
- `tests/test_vapix.py` and `tests/respx_shim.py` reference `httpx` exceptions to
assert request-error translation behavior.
- `tests/test_http_client_compat.py` already validates `aiohttp` runtime behavior.

## Target Runtime Contract

1. Runtime session type is `aiohttp.ClientSession` only.
2. Runtime auth types are `aiohttp.BasicAuth` or digest handled by
`AiohttpDigestAuth` / `DigestAuthMiddleware` when available.
3. Request execution path is single-engine (`aiohttp`) only.
4. Public behavior remains unchanged:
- same `RequestError` mapping for timeout/connection/general request failures,
- same status-code-to-Axis-error mapping,
- same AUTO auth fallback semantics.

## Ordered Execution Plan

1. Narrow configuration typing to `aiohttp.ClientSession`
- Update `axis/models/configuration.py` to remove `httpx.AsyncClient` references
and define `HTTPSession = ClientSession`.
- Update tests that currently expect mixed-session acceptance.

2. Remove dual-engine request logic from `Vapix`
- Delete `_perform_httpx_request`, `_httpx_session`, `_httpx_auth`, and
`_client_name` branching.
- Remove `httpx.BasicAuth`/`httpx.DigestAuth` construction paths.
- Keep `_perform_aiohttp_request` as the single request engine.

3. Preserve exception mapping semantics without `httpx`
- Replace explicit `httpx` exception branches with `aiohttp` and generic timeout
handling while preserving current `RequestError` messages:
- timeout -> `RequestError("Timeout")`
- connection issues -> `RequestError("Connection error: ...")`
- other client errors -> `RequestError("Unknown error: ...")`

4. Adjust AUTO auth fallback checks
- Replace `httpx.DigestAuth`-specific checks in `_should_retry_with_basic` with
client-agnostic state checks that still enforce one retry.

5. Update dependency metadata
- Remove `httpx` from runtime dependencies in `pyproject.toml`.
- Remove pinned `httpx` entry from `project.optional-dependencies.requirements`.

6. Update tests to reflect aiohttp-only runtime
- Replace or remove tests that assert `httpx.AsyncClient` compatibility in
`tests/test_configuration.py`.
- Keep and extend `tests/test_http_client_compat.py` for auth and request parity.
- Update `tests/test_vapix.py` and `tests/respx_shim.py` to avoid direct `httpx`
exception dependencies while preserving equivalent behavior assertions.

7. Validation gates
- `uv run ruff check axis tests`
- `uv run ruff format --check axis tests`
- `uv run mypy axis`
- targeted pytest for touched suites first
- `uv run pytest`

## Risks And Mitigations

1. Risk: subtle auth regression in AUTO mode.
- Mitigation: retain and expand fallback tests around `WWW-Authenticate` handling.

2. Risk: changed exception text breaks downstream consumers/tests.
- Mitigation: preserve existing `RequestError` message strings verbatim.

3. Risk: digest middleware availability differs by aiohttp version.
- Mitigation: keep current middleware availability guard and digest helper fallback.

## Exit Criteria

Phase 8 is complete when all are true:

1. Runtime package no longer depends on `httpx`.
2. Production code under `axis/` has no `import httpx` references.
3. `Configuration` and `Vapix` are aiohttp-only at runtime.
4. Existing request/auth/error behavior is preserved by tests.
5. Full lint/type/test matrix passes.
Loading