mirror of
https://github.com/azaion/ui.git
synced 2026-06-21 16:01:11 +00:00
510df68bcf
Captures the full output of autodev existing-code Phase A through Step 4 (Code Testability Revision) for the Azaion UI workspace: - Step 1 Document: _docs/02_document/ (FINAL_report, architecture, glossary, components/, modules/, diagrams/, system-flows, module-layout) plus _docs/00_problem/ + _docs/01_solution/ + _docs/legacy/ + _docs/how_to_test + README. - Step 2 Architecture Baseline: architecture_compliance_baseline.md. - Step 3 Test Spec: _docs/02_document/tests/ (environment, test-data, blackbox/performance/resilience/security/ resource-limit tests, traceability-matrix), enum_spec_snapshot, expected_results/results_report.md (98 rows), plus the run-tests.sh + run-performance-tests.sh runners. - Step 4 Code Testability Revision: 01-testability-refactoring/ run dir (list-of-changes C01-C07, deferred_to_refactor, analysis/research_findings + refactoring_roadmap) and the 7 child task specs AZ-448..AZ-454 under _docs/02_tasks/todo/ plus _dependencies_table.md. - _docs/_autodev_state.md pins the cursor at Step 4 / refactor Phase 4 entry so /autodev resumes cleanly. Epic AZ-447 (UI testability gates) tracks the 7 child tasks that will land in subsequent commits. Co-authored-by: Cursor <cursoragent@cursor.com>
225 lines
8.0 KiB
Markdown
225 lines
8.0 KiB
Markdown
# Performance Tests
|
|
|
|
The Azaion UI is a thin SPA; the dominant performance concerns are bundle size, auth-refresh transparency, SSE responsiveness, and UI reflection of server-confirmed state changes. Server-side throughput is OUT of scope here — this file covers the UI's observable timing only.
|
|
|
|
### NFT-PERF-01: Initial JS bundle ≤ 2 MB gzipped
|
|
|
|
**Summary**: The sum of gzipped initial-route JS chunks in `dist/` stays within the architecture's stated budget.
|
|
**Traces to**: AC-11, O13
|
|
**Metric**: gzipped byte total of initial JS entries.
|
|
**Profile**: static
|
|
|
|
**Preconditions**:
|
|
- `bun run build` has produced `dist/`.
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Run `vite build` (or read the build manifest if already built) | `dist/` produced |
|
|
| 2 | Walk Vite's `manifest.json` to enumerate entry chunks (non-async) | list of initial chunks |
|
|
| 3 | Gzip-size each chunk (Node `zlib.gzipSync(content, {level:9})` or equivalent) | per-chunk size |
|
|
| 4 | Sum sizes | total bytes |
|
|
|
|
**Pass criteria**: total ≤ 2 097 152 bytes (2 MB). Documentary today — no CI gate (AC-11 status: "target, not currently enforced"). Test exists so the gate flips to blocking the day CI wires it up.
|
|
**Duration**: ≤ 60 s.
|
|
**Expected result source**: `results_report.md` row 40.
|
|
|
|
---
|
|
|
|
### NFT-PERF-02: Auth refresh — exactly one network round trip per cycle
|
|
|
|
**Summary**: A single 401-triggered refresh round consists of exactly one `POST /api/admin/auth/refresh` plus one retry of the original request.
|
|
**Traces to**: AC-01, AC-23
|
|
**Metric**: count of `/api/admin/auth/refresh` requests per refresh event.
|
|
**Profile**: fast
|
|
|
|
**Preconditions**:
|
|
- Authenticated session.
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Issue an authenticated request that returns 401 once, then 200 on retry | network log captured |
|
|
| 2 | Count refresh requests fired in the cycle | exactly 1 |
|
|
|
|
**Pass criteria**: refresh count == 1 per cycle (`results_report.md` row 12 — exact).
|
|
**Duration**: ≤ 5 s.
|
|
**Expected result source**: `results_report.md` row 12.
|
|
|
|
---
|
|
|
|
### NFT-PERF-03: SSE bearer-rotation reconnect ≤ 5 s
|
|
|
|
**Summary**: When the bearer rotates while N SSE streams are open, all streams close and reopen with the new token within 5 s.
|
|
**Traces to**: AC-24
|
|
**Metric**: per-EventSource time from `close()` observed to next `OPEN` readyState (after reconnect with new token).
|
|
**Profile**: fast — `quarantined` until SSE refresh-reconnect is implemented (Step 8 hardening)
|
|
|
|
**Preconditions**:
|
|
- Two EventSources open (live-GPS + annotation-status).
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Trigger a refresh that rotates the bearer | new bearer in memory |
|
|
| 2 | For each EventSource: time from old `close` to new `OPEN` | dt_i (ms) |
|
|
| 3 | Inspect new URLs for new token in query string | new `?token=` value |
|
|
|
|
**Pass criteria**: `max(dt_i) ≤ 5 000 ms`; both streams close+open exactly once (`results_report.md` row 13).
|
|
**Duration**: ≤ 30 s.
|
|
**Expected result source**: `results_report.md` row 13.
|
|
|
|
---
|
|
|
|
### NFT-PERF-04: Live-GPS SSE opens within 5 s of flight select
|
|
|
|
**Summary**: After clicking a flight in the Header, the live-GPS EventSource reaches `OPEN` quickly.
|
|
**Traces to**: AC-08
|
|
**Metric**: time from select-flight click to EventSource `readyState === 1` (OPEN).
|
|
**Profile**: e2e (suite live-gps simulator emits events at 1 Hz)
|
|
|
|
**Preconditions**:
|
|
- Authenticated; flight selectable.
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Click a flight | one EventSource constructed to `^/api/flights/[0-9]+/live-gps(\?|$)` |
|
|
| 2 | Wait for `OPEN` | dt (ms) |
|
|
|
|
**Pass criteria**: `dt ≤ 5 000 ms` (`results_report.md` row 34).
|
|
**Duration**: ≤ 10 s.
|
|
**Expected result source**: `results_report.md` row 34.
|
|
|
|
---
|
|
|
|
### NFT-PERF-05: Live-GPS SSE closes within 1 s of deselect
|
|
|
|
**Summary**: Deselecting the flight tears down the live-GPS stream promptly.
|
|
**Traces to**: AC-08
|
|
**Metric**: time from deselect to `CLOSED`.
|
|
**Profile**: e2e
|
|
|
|
**Preconditions**:
|
|
- Continuation of NFT-PERF-04.
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Deselect the flight | EventSource closes |
|
|
| 2 | Wait for `CLOSED` | dt (ms) |
|
|
|
|
**Pass criteria**: `dt ≤ 1 000 ms` and no remaining open live-GPS sources (`results_report.md` row 35).
|
|
**Duration**: ≤ 5 s.
|
|
**Expected result source**: `results_report.md` row 35.
|
|
|
|
---
|
|
|
|
### NFT-PERF-06: Annotation-status SSE unsubscribes within 1 s on page unmount
|
|
|
|
**Summary**: Navigating away from `/annotations` closes the status-events SSE within 1 s.
|
|
**Traces to**: AC-09
|
|
**Metric**: time from unmount to `CLOSED`.
|
|
**Profile**: fast
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Mount `/annotations` then unmount | EventSource transitions |
|
|
| 2 | Measure dt | ms |
|
|
|
|
**Pass criteria**: `dt ≤ 1 000 ms` (`results_report.md` row 25).
|
|
**Duration**: ≤ 5 s.
|
|
**Expected result source**: `results_report.md` row 25.
|
|
|
|
---
|
|
|
|
### NFT-PERF-07: Bulk-validate UI reflects new status within 2 s
|
|
|
|
**Summary**: After a successful bulk-validate, every selected row shows `Validated` quickly.
|
|
**Traces to**: AC-07
|
|
**Metric**: time from server 200 to last DOM row update.
|
|
**Profile**: fast
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Select N items, click Validate | request issued |
|
|
| 2 | Stub responds 200 | UI updates begin |
|
|
| 3 | Wait for all N rows to show `Validated` | dt (ms) |
|
|
|
|
**Pass criteria**: `dt ≤ 2 000 ms` (`results_report.md` row 37).
|
|
**Duration**: ≤ 5 s.
|
|
**Expected result source**: `results_report.md` row 37.
|
|
|
|
---
|
|
|
|
### NFT-PERF-08: Panel-width persistence debounce ≤ 1 s after resize-end
|
|
|
|
**Summary**: A drag-end on a resizable panel triggers a single PUT within 1 s (debounced).
|
|
**Traces to**: AC-21
|
|
**Metric**: time from `mouseup` (drag-end) to outbound PUT; PUT count per drag.
|
|
**Profile**: fast — `quarantined` until Step 4 writer is added
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Drag and release a divider | event captured |
|
|
| 2 | Wait for PUT or 1 s timeout | dt (ms); count |
|
|
|
|
**Pass criteria**: exactly 1 PUT within ≤ 1 000 ms; URL = `/api/annotations/settings/user`; body contains `panelWidths` (`results_report.md` row 64).
|
|
**Duration**: ≤ 5 s.
|
|
**Expected result source**: `results_report.md` row 64.
|
|
|
|
---
|
|
|
|
### NFT-PERF-09: Settings save error surfaces within 2 s
|
|
|
|
**Summary**: A 500 on settings save produces an error toast and resets the `saving` flag within 2 s.
|
|
**Traces to**: AC-27
|
|
**Metric**: time from server 500 to error visibility + state reset.
|
|
**Profile**: fast — `quarantined` until Step 4 try/finally fix
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Trigger save, stub responds 500 after T ms | failure delivered |
|
|
| 2 | Wait for error toast and `saving === false` | dt (ms) |
|
|
|
|
**Pass criteria**: `dt ≤ 2 000 ms` (`results_report.md` row 68).
|
|
**Duration**: ≤ 5 s.
|
|
**Expected result source**: `results_report.md` row 68.
|
|
|
|
---
|
|
|
|
### NFT-PERF-10: First Contentful Paint on `/flights` ≤ 3 s on mid-range edge hardware
|
|
|
|
**Summary**: A warm-cache load of the default authenticated route renders the main pane within 3 s.
|
|
**Traces to**: AC-11 (target), H2 (edge deploys)
|
|
**Metric**: `performance.getEntriesByName('first-contentful-paint')[0].startTime`.
|
|
**Profile**: e2e — documentary (no enforcement today; no AC binds a hard FCP budget)
|
|
|
|
**Preconditions**:
|
|
- Warm browser cache (second visit).
|
|
- Edge-profile container: 2 vCPU, 4 GB RAM (the hardware-assessment phase confirms the figure).
|
|
|
|
**Steps**:
|
|
|
|
| Step | Consumer Action | Measurement |
|
|
|------|----------------|-------------|
|
|
| 1 | Navigate to `/flights` post-login | navigation completes |
|
|
| 2 | Read FCP entry | ms |
|
|
|
|
**Pass criteria**: FCP ≤ 3 000 ms (row 98 — threshold_max).
|
|
**Duration**: ≤ 30 s.
|
|
**Expected result source**: `results_report.md` row 98.
|