Thin Axum HTTP/JSON API over operations-test-results: ingest runs + read history for reports
| Tier | application |
| Role | unclassified (baselined) |
| Path | crates/application/test-results |
| Edition | 2021 |
| Targets | application_test_results, pg_api |
| Public items | 49 across 5 modules |
| Tests | 24 |
What it is for
application-test-results — a thin Axum HTTP/JSON API over operations_test_results::TestResultsService.
Two consumers: CI/external runners report results in (fat POST /runs/complete in one transaction, idempotency-keyed; or incremental), and a web report UI reads history out (keyset-paged runs, time-ranged metrics). Mount the router into any host via Extension so it never imposes its state type on the host (Gate 1.5 Q4). Tenant comes from the authenticated key, never the request body.
Plan + consensus: docs/userstories/sprint-0.42-test-results-api.md.
Capabilities
crate root
application-test-results — a thin Axum HTTP/JSON API over
| Item |
|---|
fn router(service : TestResultsService, config : ApiConfig) -> axum::Router |
capture (other)
Map browser-bridge telemetry (console / network / axe-accessibility) into
| Item |
|---|
pub const CONSOLE_CAP: usize |
pub const NETWORK_CAP: usize |
pub const AXE_CAP: usize |
fn norm_console(level : & str) -> & 'static str |
fn norm_axe(impact : & str) -> & 'static str |
fn norm_net(status : i64) -> & 'static str |
CapturedFinding
Map browser-bridge telemetry (console / network / axe-accessibility) into
| Item |
|---|
pub struct CapturedFinding |
fn console_findings(entries : & Value) ->(i64, Vec <CapturedFinding>) |
fn network_failures(entries : & Value) ->(i64, i64, Vec <CapturedFinding>) |
fn axe_findings(audit : & Value) ->(i64, Vec <CapturedFinding>) |
operations_test_results::FindingInput
Map browser-bridge telemetry (console / network / axe-accessibility) into
| Item |
|---|
operations_test_results::FindingInput :: fn from(c : CapturedFinding) -> Self |
cursor (other)
Keyset pagination cursor for GET /runs — encodes (started_at, id) so
| Item |
|---|
fn encode_run_cursor(started_at : DateTime <Utc>, id : Uuid) -> String |
fn decode_run_cursor(token : & str) -> Option <(DateTime <Utc>, Uuid)> |
fn clamp_limit(requested : Option <i64>) -> i64 |
CompleteRunReq
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct CompleteRunReq |
fn to_complete_run_input(req : CompleteRunReq, tenant_id : Uuid, default_project : & str,) -> Result <CompleteRunInput, ApiError> |
FindingReq
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct FindingReq |
FindingResp
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct FindingResp |
MetricPointResp
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct MetricPointResp |
MetricReq
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct MetricReq |
MetricResp
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct MetricResp |
MetricSeriesResp
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct MetricSeriesResp |
fn metric_series(name : & str, samples : & MetricSample) -> MetricSeriesResp |
ResultDetailResp
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct ResultDetailResp |
ResultReq
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct ResultReq |
RunCreatedResp
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct RunCreatedResp |
RunDetailResp
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct RunDetailResp |
fn run_detail_resp(run : & TestRun, results : & TestResult, metrics : & MetricSample, findings : & TestFinding,) -> RunDetailResp |
RunListResp
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct RunListResp |
RunSummaryResp
Request/response DTOs + mappers. API shapes are deliberately separate from
| Item |
|---|
pub struct RunSummaryResp |
fn run_summary(r : & TestRun) -> RunSummaryResp |
ApiError
API error type. Maps service/validation failures to HTTP status codes and a
| Item |
|---|
pub enum ApiError |
ApiError :: fn status(& self) -> StatusCode |
ApiError :: fn client_message(& self) -> String |
ApiError :: fn from(e : TestResultsError) -> Self |
ApiError :: fn into_response(self) -> Response |
handlers (other)
Axum handlers + state/config. Tenant is derived from the x-api-key header
| Item |
|---|
async fn list_runs(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Query(q) : Query <ListRunsQuery>,) -> Result <Json <RunListResp>, ApiError> |
async fn case_flake(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Path(case_key) : Path <String>, Query(q) : Query <FlakeQuery>,) -> Result <Json <operations_test_results::FlakeStats>, ApiError> |
async fn metric_budget(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Path(name) : Path <String>, Query(q) : Query <BudgetQuery>,) -> Result <Json <operations_test_results::BudgetStats>, ApiError> |
async fn metric_series_handler(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Query(q) : Query <MetricsQuery>,) -> Result <Json <MetricSeriesResp>, ApiError> |
ApiConfig
Axum handlers + state/config. Tenant is derived from the x-api-key header
| Item |
|---|
pub struct ApiConfig |
ApiState
Axum handlers + state/config. Tenant is derived from the x-api-key header
| Item |
|---|
pub struct ApiState |
async fn complete_run(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Json(req) : Json <CompleteRunReq>,) -> Result <(StatusCode, Json <RunCreatedResp>), ApiError> |
async fn get_run(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Path(id) : Path <Uuid>,) -> Result <Json <RunDetailResp>, ApiError> |
BudgetQuery
Axum handlers + state/config. Tenant is derived from the x-api-key header
| Item |
|---|
pub struct BudgetQuery |
FlakeQuery
Axum handlers + state/config. Tenant is derived from the x-api-key header
| Item |
|---|
pub struct FlakeQuery |
ListRunsQuery
Axum handlers + state/config. Tenant is derived from the x-api-key header
| Item |
|---|
pub struct ListRunsQuery |
MetricsQuery
Axum handlers + state/config. Tenant is derived from the x-api-key header
| Item |
|---|
pub struct MetricsQuery |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
application_test_results
capturecursordtoerrorhandlers
flowchart TD n_application_test_results["application_test_results"] n_application_test_results --> n_capture["capture"] n_application_test_results --> n_cursor["cursor"] n_application_test_results --> n_dto["dto"] n_application_test_results --> n_error["error"] n_application_test_results --> n_handlers["handlers"]
Public surface
`crate root`
| Item | What it is |
|---|---|
fn router(service : TestResultsService, config : ApiConfig) -> axum::Router | Build the mountable API router |
`capture`
| Item | What it is |
|---|---|
pub const CONSOLE_CAP: usize | — |
pub const NETWORK_CAP: usize | — |
pub const AXE_CAP: usize | — |
pub struct CapturedFinding | A finding ready to attach to a result |
operations_test_results::FindingInput :: fn from(c : CapturedFinding) -> Self | — |
fn norm_console(level : & str) -> & 'static str | console level → normalized severity (Gate 1.5 Q3). |
fn norm_axe(impact : & str) -> & 'static str | axe impact → normalized severity. |
fn norm_net(status : i64) -> & 'static str | HTTP status → normalized severity (4xx→warn, 5xx/blocked(0)→error). |
fn console_findings(entries : & Value) ->(i64, Vec <CapturedFinding>) | Console entries {level,text,url,...} → (error_count, findings) |
fn network_failures(entries : & Value) ->(i64, i64, Vec <CapturedFinding>) | Network entries {method,type,status,url,error?} → (request_count, failure_count, findings) |
fn axe_findings(audit : & Value) ->(i64, Vec <CapturedFinding>) | Axe audit {violations:{id,impact,help,nodes:[{target}}],violations_count} → (violation_count, findings) |
`cursor`
| Item | What it is |
|---|---|
fn encode_run_cursor(started_at : DateTime <Utc>, id : Uuid) -> String | Encode a (started_at, id) keyset into an opaque cursor token. |
fn decode_run_cursor(token : & str) -> Option <(DateTime <Utc>, Uuid)> | Decode a cursor token back to (started_at, id) |
fn clamp_limit(requested : Option <i64>) -> i64 | Clamp a requested page size to a sane range (default 50, 1..=200). |
`dto`
| Item | What it is |
|---|---|
pub struct MetricReq | — |
pub struct FindingReq | — |
pub struct ResultReq | — |
pub struct CompleteRunReq | Fat-ingest body for POST /runs/complete |
pub struct RunCreatedResp | — |
fn to_complete_run_input(req : CompleteRunReq, tenant_id : Uuid, default_project : & str,) -> Result <CompleteRunInput, ApiError> | Pure map of an authenticated request into the domain input |
pub struct RunSummaryResp | — |
fn run_summary(r : & TestRun) -> RunSummaryResp | — |
pub struct MetricResp | — |
pub struct FindingResp | — |
pub struct ResultDetailResp | — |
pub struct RunDetailResp | — |
pub struct RunListResp | — |
fn run_detail_resp(run : & TestRun, results : & TestResult, metrics : & MetricSample, findings : & TestFinding,) -> RunDetailResp | Assemble a run-detail response, nesting each result's metrics + findings by result_id. |
pub struct MetricPointResp | — |
pub struct MetricSeriesResp | — |
fn metric_series(name : & str, samples : & MetricSample) -> MetricSeriesResp | — |
`error`
| Item | What it is |
|---|---|
pub enum ApiError | — |
ApiError :: fn status(& self) -> StatusCode | — |
ApiError :: fn client_message(& self) -> String | Client-safe message (never leaks internal/DB detail). |
ApiError :: fn from(e : TestResultsError) -> Self | — |
ApiError :: fn into_response(self) -> Response | — |
`handlers`
| Item | What it is |
|---|---|
pub struct ApiConfig | Host-supplied config: the accepted API key and the tenant/project it maps to. |
pub struct ApiState | — |
async fn complete_run(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Json(req) : Json <CompleteRunReq>,) -> Result <(StatusCode, Json <RunCreatedResp>), ApiError> | POST /runs/complete — fat ingest: persist a whole run atomically. |
pub struct ListRunsQuery | — |
async fn list_runs(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Query(q) : Query <ListRunsQuery>,) -> Result <Json <RunListResp>, ApiError> | GET /runs — newest-first, keyset-paged |
async fn get_run(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Path(id) : Path <Uuid>,) -> Result <Json <RunDetailResp>, ApiError> | GET /runs/:id — run detail with results, each nesting its metrics + findings. |
pub struct MetricsQuery | — |
pub struct FlakeQuery | — |
async fn case_flake(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Path(case_key) : Path <String>, Query(q) : Query <FlakeQuery>,) -> Result <Json <operations_test_results::FlakeStats>, ApiError> | GET /cases/:case_key/flake — classify a case (stable/flaky/broken/erroring) from its result history |
pub struct BudgetQuery | — |
async fn metric_budget(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Path(name) : Path <String>, Query(q) : Query <BudgetQuery>,) -> Result <Json <operations_test_results::BudgetStats>, ApiError> | GET /metrics/:name/budget — adaptive budget for a metric: budget derived from its recent history, the newest sample checked against it. |
async fn metric_series_handler(State(state) : State <Arc <ApiState>>, headers : HeaderMap, Query(q) : Query <MetricsQuery>,) -> Result <Json <MetricSeriesResp>, ApiError> | GET /metrics?name= — newest-first samples of a metric (chart series). |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
ApiError | error::ApiError |
{ApiConfig,ApiState} | handlers::{ApiConfig,ApiState} |
Boundary
Reaches into operations.
Shares tier application with 120 other crates: application-agreements, application-ai, application-analytics, application-approvals, application-assessments, application-audit-log, application-auth, application-billing, … (120 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | application |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/application/test-results |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_application["application"] --> n_operations["operations"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `operations-test-results` | operations | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
axum | ^0.7 | multipart | no | always |
base64 | ^0.22 | — | no | always |
chrono | ^0.4 | serde | no | always |
serde | ^1 | derive | no | always |
serde_json | ^1 | — | no | always |
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json | no | always |
thiserror | ^2 | — | no | always |
tracing | ^0.1 | — | no | always |
uuid | ^1 | v4, v7, serde, js | no | always |
Development, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
http-body-util | ^0.1 | — | no | always |
tokio | ^1 | full | no | always |
tower | ^0.5 | util | no | always |
Build. None.
Depended on by. 1 workspace crate.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_operations_e2e_harness["operations-e2e-harness"] -->|uses| SELF SELF["application-test-results"] SELF -->|runtime| n_operations_test_results["operations-test-results"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.
Targets
| Kind | Name | Source |
|---|---|---|
| lib | application_test_results | `src/lib.rs` |
| test | pg_api | `tests/pg_api.rs` |
Error model
| Error type | Named by |
|---|---|
ApiError | case_flake, complete_run, get_run, list_runs, metric_budget, metric_series_handler, … (7 total) |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | yes |
| async runtime | none detected |
| database access | yes |
| network I/O | yes |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
1 workspace crate depends on this one: operations-e2e-harness.
Verification
| Kind | Count |
|---|---|
| Unit tests | 17 |
| Integration tests | 7 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
crate root | 1 | 0 | 0 |
capture | 10 | 0 | 4 |
cursor | 3 | 0 | 0 |
dto | 17 | 0 | 0 |
error | 1 | 0 | 0 |
handlers | 12 | 0 | 1 |
What the tests establish, by name:
bad_status_token_is_400—tests/pg_api.rsbudget_endpoint_flags_a_breach—tests/pg_api.rsflake_endpoint_classifies_alternating_as_flaky—tests/pg_api.rsget_run_unknown_id_is_404—tests/pg_api.rsget_runs_list_and_detail_roundtrip—tests/pg_api.rspost_runs_complete_ingests_and_persists—tests/pg_api.rswrong_api_key_is_401—tests/pg_api.rsaxe_maps_impact_and_target—src/capture.rscap_adds_truncation_marker—src/capture.rsconsole_only_errors_and_dedups—src/capture.rsempty_inputs_are_safe—src/capture.rsnetwork_failures_filter_and_classify—src/capture.rsseverity_normalization—src/capture.rsclamp_limit_bounds—src/cursor.rscursor_round_trips—src/cursor.rsmalformed_cursor_is_none—src/cursor.rsbad_kind_is_validation_400—src/dto.rsbad_run_status_is_validation_400—src/dto.rsmaps_valid_request_tenant_from_arg_not_body—src/dto.rsproject_from_body_overrides_default—src/dto.rsdb_error_maps_to_internal_500—src/error.rsinternal_message_does_not_leak—src/error.rsstatus_codes_per_variant—src/error.rsvalidation_errors_map_to_400—src/error.rs
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 22 | 49 |
Public modules with a //! block | 5 | 5 |
pie showData
title Public items with rustdoc
"Documented" : 22
"No rustdoc detected" : 27
Metrics
| Metric | Value |
|---|---|
| Rust source files | 6 |
| Source lines | 1099 |
| Code lines | 925 |
| Public API items | 49 |
| Public modules | 5 |
| Tests | 24 |
| Examples | 0 |
| Cargo features | 0 |
| Direct runtime dependencies | 10 |
| Workspace reverse dependencies | 1 |
pie showData
title Public API by kind
"constant" : 3
"enum" : 1
"function" : 20
"method" : 5
"struct" : 20
pie showData
title Rust source composition
"Code" : 925
"Blank or comment" : 174
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.