feat: troppa roba davvero
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
# Backend Testing Strategy
|
||||
|
||||
## Goal
|
||||
Replace the current mostly mocked backend suite with a professional layered strategy that:
|
||||
- keeps fast unit tests
|
||||
- adds realistic integration coverage with real app wiring
|
||||
- adds an external performance/load harness
|
||||
- minimizes monkeypatch use in behavior-level tests
|
||||
|
||||
This strategy is backend-only. Frontend automation is not part of this phase.
|
||||
|
||||
## Current State
|
||||
- Tooling:
|
||||
- pytest only
|
||||
- no async test helpers
|
||||
- no realistic HTTP/WebSocket client beyond `TestClient`
|
||||
- no containerized test infra
|
||||
- no benchmark/load tooling
|
||||
- Problems:
|
||||
- custom `FastAPI()` test app in `backend/tests/conftest.py`
|
||||
- heavy monkeypatching of router dependencies
|
||||
- almost no real lifecycle/integration confidence
|
||||
- no system perf or throughput measurements
|
||||
|
||||
## Target Test Pyramid
|
||||
|
||||
### 1. Unit tests
|
||||
Purpose:
|
||||
- pure logic only
|
||||
- parser/validator/serialization helpers
|
||||
- deterministic error mapping
|
||||
|
||||
Rules:
|
||||
- monkeypatch allowed only at narrow technical seams
|
||||
- no network, no Mongo, no Docker, no filesystem mutation beyond temp dirs
|
||||
|
||||
Examples:
|
||||
- proxy code validation
|
||||
- mode/protocol validation
|
||||
- template metadata normalization
|
||||
- health result shaping helpers
|
||||
|
||||
### 2. Integration tests
|
||||
Purpose:
|
||||
- real FastAPI app
|
||||
- real startup/shutdown
|
||||
- real Mongo-backed repositories
|
||||
- realistic temp runtime directories
|
||||
- real HTTP and WebSocket behavior
|
||||
|
||||
Recommended tooling:
|
||||
- `pytest-asyncio`
|
||||
- `httpx`
|
||||
- `asgi-lifespan`
|
||||
- `testcontainers[mongodb]`
|
||||
|
||||
Rules:
|
||||
- use the actual app from `app.main`, not a bespoke test app
|
||||
- override as little as possible
|
||||
- prefer seeded fixtures over monkeypatching repositories
|
||||
- temp runtime dirs are acceptable; fake repositories are not
|
||||
|
||||
Coverage to add:
|
||||
- auth login/logout with real repository behavior
|
||||
- proxy create/update/delete against real Mongo
|
||||
- health history endpoints with persisted samples
|
||||
- logs and health websocket auth and streaming
|
||||
- startup reconciliation with persisted runtime state
|
||||
- failure-path integration for runtime validation and cleanup
|
||||
|
||||
### 3. System tests
|
||||
Purpose:
|
||||
- realistic end-to-end control plane on a running stack
|
||||
- optional and slower than integration tests
|
||||
|
||||
Scope:
|
||||
- backend process
|
||||
- Mongo container
|
||||
- optional playground/docker service fixture
|
||||
- real HTTP calls and websocket clients
|
||||
|
||||
Use for:
|
||||
- reverse-mode service remap
|
||||
- mitmdump orphan recovery
|
||||
- runtime artifact cleanup
|
||||
- template apply/save behavior at the API level
|
||||
|
||||
## Fixture Architecture
|
||||
|
||||
### Core fixtures
|
||||
- `mongo_container`
|
||||
- real Mongo container started once per session
|
||||
- `app_settings`
|
||||
- isolated env/config for test DB, auth credentials, runtime dirs
|
||||
- `real_app`
|
||||
- imported from `app.main`
|
||||
- `lifespan_app`
|
||||
- app with startup/shutdown active
|
||||
- `http_client`
|
||||
- async `httpx.AsyncClient`
|
||||
- `auth_token`
|
||||
- produced through real login endpoint
|
||||
- `runtime_dir`
|
||||
- temp dir for scripts/config/logs
|
||||
- `seed_proxy`
|
||||
- repository-backed fixture that inserts a real proxy document
|
||||
|
||||
### Markers
|
||||
- `unit`
|
||||
- `integration`
|
||||
- `api`
|
||||
- `websocket`
|
||||
- `slow`
|
||||
- `requires_docker`
|
||||
- `perf`
|
||||
|
||||
These should drive selective local and CI runs.
|
||||
|
||||
## Monkeypatch Policy
|
||||
|
||||
Allowed:
|
||||
- forcing subprocess failure
|
||||
- forcing clock/timeouts
|
||||
- fault injection into low-level boundaries
|
||||
- temp path redirection where isolation is needed
|
||||
|
||||
Not the default:
|
||||
- patching repository functions in router tests
|
||||
- patching service functions in API behavior tests
|
||||
- bypassing authentication for general API coverage
|
||||
|
||||
Rule of thumb:
|
||||
- if the test is about endpoint behavior, use the real endpoint stack
|
||||
- if the test is about pure logic, isolate it completely
|
||||
|
||||
## Performance and Load Harness
|
||||
|
||||
### Tool choice
|
||||
Use `k6` as the primary external load tool.
|
||||
|
||||
Reason:
|
||||
- good HTTP load support
|
||||
- scriptable scenarios
|
||||
- usable for websocket-related smoke scenarios
|
||||
- clearer reporting than ad-hoc shell loops
|
||||
|
||||
### Perf layout
|
||||
Add a dedicated non-default perf layer, for example under:
|
||||
- `backend/perf/`
|
||||
|
||||
Include:
|
||||
- startup script or instructions
|
||||
- scenario scripts
|
||||
- seeded data setup
|
||||
- report capture format
|
||||
|
||||
### Baseline scenarios
|
||||
1. Read-heavy API latency
|
||||
- `GET /proxy`
|
||||
- `GET /proxy/{port}/health/history`
|
||||
- measure latency percentiles and RPS
|
||||
|
||||
2. Control-plane mutation loop
|
||||
- create/update/start/stop/delete proxy in repeated cycles
|
||||
- measure failure rate and latency
|
||||
|
||||
3. WebSocket fan-out
|
||||
- concurrent clients on logs and health streams
|
||||
- verify stability under multiple listeners
|
||||
|
||||
4. Health monitor cost
|
||||
- N running proxies with scheduled checks
|
||||
- measure API latency degradation and monitor lag
|
||||
|
||||
### Perf outputs
|
||||
For each scenario record:
|
||||
- concurrency
|
||||
- duration
|
||||
- warmup
|
||||
- RPS
|
||||
- p50/p95/p99 latency
|
||||
- error rate
|
||||
- environment notes
|
||||
|
||||
These should not be strict CI gates initially; they should establish baselines first.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
### Phase 1
|
||||
- Add pytest markers and split directories by layer.
|
||||
- Introduce async test dependencies and real app client fixtures.
|
||||
- Keep existing suite running.
|
||||
|
||||
### Phase 2
|
||||
- Convert router tests away from broad monkeypatching.
|
||||
- Replace bespoke app fixture with real lifespan-backed app in integration tests.
|
||||
- Add Mongo testcontainer fixture.
|
||||
|
||||
### Phase 3
|
||||
- Add websocket integration tests.
|
||||
- Add startup/recovery/runtime integration tests.
|
||||
- Shrink old unit/API tests where they duplicate new integration coverage.
|
||||
|
||||
### Phase 4
|
||||
- Introduce `k6` perf scripts and documentation.
|
||||
- Add baseline measurement workflow for local runs and CI nightly/optional jobs.
|
||||
|
||||
## Acceptance Criteria
|
||||
- Fast local unit suite remains available.
|
||||
- Integration suite uses the real app and real Mongo.
|
||||
- WebSocket paths are tested without bypassing core auth behavior.
|
||||
- Router-level monkeypatching is no longer the dominant pattern.
|
||||
- Reverse-mode lifecycle and recovery get realistic coverage.
|
||||
- Perf/load scripts exist and produce repeatable latency/RPS baselines.
|
||||
|
||||
Reference in New Issue
Block a user