mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-09 22:33:37 +00:00
Update Rust code for nested API schema types
Update all struct constructions in demo data and server handlers to match the new nested sub-schemas. Fix aggregate usage handler to use AggregateUsageTotals wrapper, ModelReference, and TokenUsage. Update test assertions from flat field paths to nested paths. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
736d4f8ba6
commit
a7083bb165
2 changed files with 204 additions and 393 deletions
|
|
@ -443,7 +443,7 @@ pub async fn list_workflow_runs(
|
|||
) -> Response {
|
||||
let items: Vec<_> = runs::list_items()
|
||||
.into_iter()
|
||||
.filter(|r| r.workflow == name)
|
||||
.filter(|r| r.workflow.slug == name)
|
||||
.collect();
|
||||
paginated_response(items, &pagination)
|
||||
}
|
||||
|
|
@ -508,7 +508,7 @@ pub async fn create_session_stub(
|
|||
let now = "2026-03-06T16:00:00Z";
|
||||
(
|
||||
StatusCode::CREATED,
|
||||
Json(serde_json::json!({"id": id, "title": "New session", "model": "Opus 4.6", "created_at": now, "updated_at": now})),
|
||||
Json(serde_json::json!({"id": id, "title": "New session", "model": {"id": "Opus 4.6"}, "created_at": now, "updated_at": now})),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
|
@ -702,357 +702,191 @@ mod runs {
|
|||
vec![
|
||||
RunListItem {
|
||||
id: "run-1".into(),
|
||||
repo: "api-server".into(),
|
||||
repository: RepositoryReference { name: "api-server".into() },
|
||||
title: "Add rate limiting to auth endpoints".into(),
|
||||
workflow: "implement".into(),
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
status: BoardColumn::Working,
|
||||
number: None,
|
||||
additions: None,
|
||||
deletions: None,
|
||||
checks: vec![],
|
||||
elapsed_secs: Some(420.0),
|
||||
elapsed_warning: Some(false),
|
||||
resources: Some("4 CPU / 8 GB".into()),
|
||||
comments: Some(0),
|
||||
pull_request: None,
|
||||
timings: Some(RunTimings { elapsed_secs: 420.0, elapsed_warning: Some(false) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-a1b2c3d4".into(), resources: Some(SandboxResources { cpu: 4, memory: 8 }) }),
|
||||
question: None,
|
||||
sandbox_id: Some("sb-a1b2c3d4".into()),
|
||||
created_at: ts("2026-03-06T14:30:00Z"),
|
||||
},
|
||||
RunListItem {
|
||||
id: "run-2".into(),
|
||||
repo: "web-dashboard".into(),
|
||||
repository: RepositoryReference { name: "web-dashboard".into() },
|
||||
title: "Migrate to React Router v7".into(),
|
||||
workflow: "implement".into(),
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
status: BoardColumn::Working,
|
||||
number: None,
|
||||
additions: None,
|
||||
deletions: None,
|
||||
checks: vec![],
|
||||
elapsed_secs: Some(8100.0),
|
||||
elapsed_warning: Some(false),
|
||||
resources: Some("8 CPU / 16 GB".into()),
|
||||
comments: Some(0),
|
||||
pull_request: None,
|
||||
timings: Some(RunTimings { elapsed_secs: 8100.0, elapsed_warning: Some(false) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-e5f6g7h8".into(), resources: Some(SandboxResources { cpu: 8, memory: 16 }) }),
|
||||
question: None,
|
||||
sandbox_id: Some("sb-e5f6g7h8".into()),
|
||||
created_at: ts("2026-03-06T12:00:00Z"),
|
||||
},
|
||||
RunListItem {
|
||||
id: "run-3".into(),
|
||||
repo: "cli-tools".into(),
|
||||
repository: RepositoryReference { name: "cli-tools".into() },
|
||||
title: "Fix config parsing for nested values".into(),
|
||||
workflow: "fix_build".into(),
|
||||
workflow: WorkflowReference { slug: "fix_build".into() },
|
||||
status: BoardColumn::Working,
|
||||
number: None,
|
||||
additions: None,
|
||||
deletions: None,
|
||||
checks: vec![],
|
||||
elapsed_secs: Some(2700.0),
|
||||
elapsed_warning: Some(false),
|
||||
resources: Some("2 CPU / 4 GB".into()),
|
||||
comments: Some(0),
|
||||
pull_request: None,
|
||||
timings: Some(RunTimings { elapsed_secs: 2700.0, elapsed_warning: Some(false) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-i9j0k1l2".into(), resources: Some(SandboxResources { cpu: 2, memory: 4 }) }),
|
||||
question: None,
|
||||
sandbox_id: Some("sb-i9j0k1l2".into()),
|
||||
created_at: ts("2026-03-05T09:20:00Z"),
|
||||
},
|
||||
RunListItem {
|
||||
id: "run-4".into(),
|
||||
repo: "api-server".into(),
|
||||
repository: RepositoryReference { name: "api-server".into() },
|
||||
title: "Update OpenAPI spec for v3".into(),
|
||||
workflow: "expand".into(),
|
||||
workflow: WorkflowReference { slug: "expand".into() },
|
||||
status: BoardColumn::Pending,
|
||||
number: None,
|
||||
additions: Some(567),
|
||||
deletions: Some(234),
|
||||
checks: vec![],
|
||||
elapsed_secs: Some(4320.0),
|
||||
elapsed_warning: Some(false),
|
||||
resources: None,
|
||||
comments: Some(0),
|
||||
question: Some("Accept or push for another round?".into()),
|
||||
sandbox_id: Some("sb-q7r8s9t0".into()),
|
||||
pull_request: Some(RunPullRequest { number: 0, additions: Some(567), deletions: Some(234), comments: Some(0), checks: vec![] }),
|
||||
timings: Some(RunTimings { elapsed_secs: 4320.0, elapsed_warning: Some(false) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-q7r8s9t0".into(), resources: None }),
|
||||
question: Some(RunQuestion { text: "Accept or push for another round?".into() }),
|
||||
created_at: ts("2026-03-04T15:00:00Z"),
|
||||
},
|
||||
RunListItem {
|
||||
id: "run-5".into(),
|
||||
repo: "shared-types".into(),
|
||||
repository: RepositoryReference { name: "shared-types".into() },
|
||||
title: "Add pipeline event types".into(),
|
||||
workflow: "implement".into(),
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
status: BoardColumn::Pending,
|
||||
number: None,
|
||||
additions: Some(145),
|
||||
deletions: Some(23),
|
||||
checks: vec![],
|
||||
elapsed_secs: Some(1680.0),
|
||||
elapsed_warning: Some(false),
|
||||
resources: None,
|
||||
comments: Some(0),
|
||||
question: Some("Proceed from investigation to fix?".into()),
|
||||
sandbox_id: Some("sb-u1v2w3x4".into()),
|
||||
pull_request: Some(RunPullRequest { number: 0, additions: Some(145), deletions: Some(23), comments: Some(0), checks: vec![] }),
|
||||
timings: Some(RunTimings { elapsed_secs: 1680.0, elapsed_warning: Some(false) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-u1v2w3x4".into(), resources: None }),
|
||||
question: Some(RunQuestion { text: "Proceed from investigation to fix?".into() }),
|
||||
created_at: ts("2026-03-04T10:00:00Z"),
|
||||
},
|
||||
RunListItem {
|
||||
id: "run-6".into(),
|
||||
repo: "web-dashboard".into(),
|
||||
repository: RepositoryReference { name: "web-dashboard".into() },
|
||||
title: "Add dark mode toggle".into(),
|
||||
workflow: "implement".into(),
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
status: BoardColumn::Review,
|
||||
number: Some(889),
|
||||
additions: Some(234),
|
||||
deletions: Some(67),
|
||||
checks: vec![
|
||||
CheckRun {
|
||||
name: "lint".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(23.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "typecheck".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(72.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "unit-tests".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(154.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "integration-tests".into(),
|
||||
status: CheckRunStatus::Failure,
|
||||
duration_secs: Some(296.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "e2e / chrome".into(),
|
||||
status: CheckRunStatus::Failure,
|
||||
duration_secs: Some(182.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "build".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(105.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "coverage".into(),
|
||||
status: CheckRunStatus::Skipped,
|
||||
duration_secs: None,
|
||||
},
|
||||
],
|
||||
elapsed_secs: Some(2100.0),
|
||||
elapsed_warning: Some(false),
|
||||
resources: None,
|
||||
comments: Some(4),
|
||||
pull_request: Some(RunPullRequest {
|
||||
number: 889,
|
||||
additions: Some(234),
|
||||
deletions: Some(67),
|
||||
comments: Some(4),
|
||||
checks: vec![
|
||||
CheckRun { name: "lint".into(), status: CheckRunStatus::Success, duration_secs: Some(23.0) },
|
||||
CheckRun { name: "typecheck".into(), status: CheckRunStatus::Success, duration_secs: Some(72.0) },
|
||||
CheckRun { name: "unit-tests".into(), status: CheckRunStatus::Success, duration_secs: Some(154.0) },
|
||||
CheckRun { name: "integration-tests".into(), status: CheckRunStatus::Failure, duration_secs: Some(296.0) },
|
||||
CheckRun { name: "e2e / chrome".into(), status: CheckRunStatus::Failure, duration_secs: Some(182.0) },
|
||||
CheckRun { name: "build".into(), status: CheckRunStatus::Success, duration_secs: Some(105.0) },
|
||||
CheckRun { name: "coverage".into(), status: CheckRunStatus::Skipped, duration_secs: None },
|
||||
],
|
||||
}),
|
||||
timings: Some(RunTimings { elapsed_secs: 2100.0, elapsed_warning: Some(false) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-m3n4o5p6".into(), resources: None }),
|
||||
question: None,
|
||||
sandbox_id: Some("sb-m3n4o5p6".into()),
|
||||
created_at: ts("2026-03-03T16:45:00Z"),
|
||||
},
|
||||
RunListItem {
|
||||
id: "run-7".into(),
|
||||
repo: "infrastructure".into(),
|
||||
repository: RepositoryReference { name: "infrastructure".into() },
|
||||
title: "Terraform module for Redis cluster".into(),
|
||||
workflow: "implement".into(),
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
status: BoardColumn::Review,
|
||||
number: Some(156),
|
||||
additions: Some(412),
|
||||
deletions: Some(0),
|
||||
checks: vec![
|
||||
CheckRun {
|
||||
name: "lint".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(18.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "typecheck".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(56.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "unit-tests".into(),
|
||||
status: CheckRunStatus::Pending,
|
||||
duration_secs: None,
|
||||
},
|
||||
CheckRun {
|
||||
name: "integration-tests".into(),
|
||||
status: CheckRunStatus::Queued,
|
||||
duration_secs: None,
|
||||
},
|
||||
CheckRun {
|
||||
name: "build".into(),
|
||||
status: CheckRunStatus::Pending,
|
||||
duration_secs: None,
|
||||
},
|
||||
],
|
||||
elapsed_secs: Some(720.0),
|
||||
elapsed_warning: Some(false),
|
||||
resources: None,
|
||||
comments: Some(1),
|
||||
pull_request: Some(RunPullRequest {
|
||||
number: 156,
|
||||
additions: Some(412),
|
||||
deletions: Some(0),
|
||||
comments: Some(1),
|
||||
checks: vec![
|
||||
CheckRun { name: "lint".into(), status: CheckRunStatus::Success, duration_secs: Some(18.0) },
|
||||
CheckRun { name: "typecheck".into(), status: CheckRunStatus::Success, duration_secs: Some(56.0) },
|
||||
CheckRun { name: "unit-tests".into(), status: CheckRunStatus::Pending, duration_secs: None },
|
||||
CheckRun { name: "integration-tests".into(), status: CheckRunStatus::Queued, duration_secs: None },
|
||||
CheckRun { name: "build".into(), status: CheckRunStatus::Pending, duration_secs: None },
|
||||
],
|
||||
}),
|
||||
timings: Some(RunTimings { elapsed_secs: 720.0, elapsed_warning: Some(false) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-y5z6a7b8".into(), resources: None }),
|
||||
question: None,
|
||||
sandbox_id: Some("sb-y5z6a7b8".into()),
|
||||
created_at: ts("2026-03-03T11:00:00Z"),
|
||||
},
|
||||
RunListItem {
|
||||
id: "run-8".into(),
|
||||
repo: "api-server".into(),
|
||||
repository: RepositoryReference { name: "api-server".into() },
|
||||
title: "Implement webhook retry logic".into(),
|
||||
workflow: "implement".into(),
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
status: BoardColumn::Merge,
|
||||
number: Some(1249),
|
||||
additions: Some(189),
|
||||
deletions: Some(45),
|
||||
checks: vec![
|
||||
CheckRun {
|
||||
name: "lint".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(21.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "typecheck".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(68.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "unit-tests".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(192.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "integration-tests".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(334.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "e2e / chrome".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(262.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "e2e / firefox".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(285.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "build".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(121.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "deploy-preview".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(93.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "security-scan".into(),
|
||||
status: CheckRunStatus::Skipped,
|
||||
duration_secs: None,
|
||||
},
|
||||
CheckRun {
|
||||
name: "performance".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(138.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "bundle-size".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(34.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "accessibility".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(72.0),
|
||||
},
|
||||
],
|
||||
elapsed_secs: Some(259200.0),
|
||||
elapsed_warning: Some(true),
|
||||
resources: None,
|
||||
comments: Some(7),
|
||||
pull_request: Some(RunPullRequest {
|
||||
number: 1249,
|
||||
additions: Some(189),
|
||||
deletions: Some(45),
|
||||
comments: Some(7),
|
||||
checks: vec![
|
||||
CheckRun { name: "lint".into(), status: CheckRunStatus::Success, duration_secs: Some(21.0) },
|
||||
CheckRun { name: "typecheck".into(), status: CheckRunStatus::Success, duration_secs: Some(68.0) },
|
||||
CheckRun { name: "unit-tests".into(), status: CheckRunStatus::Success, duration_secs: Some(192.0) },
|
||||
CheckRun { name: "integration-tests".into(), status: CheckRunStatus::Success, duration_secs: Some(334.0) },
|
||||
CheckRun { name: "e2e / chrome".into(), status: CheckRunStatus::Success, duration_secs: Some(262.0) },
|
||||
CheckRun { name: "e2e / firefox".into(), status: CheckRunStatus::Success, duration_secs: Some(285.0) },
|
||||
CheckRun { name: "build".into(), status: CheckRunStatus::Success, duration_secs: Some(121.0) },
|
||||
CheckRun { name: "deploy-preview".into(), status: CheckRunStatus::Success, duration_secs: Some(93.0) },
|
||||
CheckRun { name: "security-scan".into(), status: CheckRunStatus::Skipped, duration_secs: None },
|
||||
CheckRun { name: "performance".into(), status: CheckRunStatus::Success, duration_secs: Some(138.0) },
|
||||
CheckRun { name: "bundle-size".into(), status: CheckRunStatus::Success, duration_secs: Some(34.0) },
|
||||
CheckRun { name: "accessibility".into(), status: CheckRunStatus::Success, duration_secs: Some(72.0) },
|
||||
],
|
||||
}),
|
||||
timings: Some(RunTimings { elapsed_secs: 259200.0, elapsed_warning: Some(true) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-c9d0e1f2".into(), resources: None }),
|
||||
question: None,
|
||||
sandbox_id: Some("sb-c9d0e1f2".into()),
|
||||
created_at: ts("2026-02-28T14:00:00Z"),
|
||||
},
|
||||
RunListItem {
|
||||
id: "run-9".into(),
|
||||
repo: "cli-tools".into(),
|
||||
repository: RepositoryReference { name: "cli-tools".into() },
|
||||
title: "Add --verbose flag to run command".into(),
|
||||
workflow: "expand".into(),
|
||||
workflow: WorkflowReference { slug: "expand".into() },
|
||||
status: BoardColumn::Merge,
|
||||
number: Some(430),
|
||||
additions: Some(56),
|
||||
deletions: Some(12),
|
||||
checks: vec![
|
||||
CheckRun {
|
||||
name: "lint".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(15.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "typecheck".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(48.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "unit-tests".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(116.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "build".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(82.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "coverage".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(124.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "bundle-size".into(),
|
||||
status: CheckRunStatus::Skipped,
|
||||
duration_secs: None,
|
||||
},
|
||||
],
|
||||
elapsed_secs: Some(3900.0),
|
||||
elapsed_warning: Some(false),
|
||||
resources: None,
|
||||
comments: Some(2),
|
||||
pull_request: Some(RunPullRequest {
|
||||
number: 430,
|
||||
additions: Some(56),
|
||||
deletions: Some(12),
|
||||
comments: Some(2),
|
||||
checks: vec![
|
||||
CheckRun { name: "lint".into(), status: CheckRunStatus::Success, duration_secs: Some(15.0) },
|
||||
CheckRun { name: "typecheck".into(), status: CheckRunStatus::Success, duration_secs: Some(48.0) },
|
||||
CheckRun { name: "unit-tests".into(), status: CheckRunStatus::Success, duration_secs: Some(116.0) },
|
||||
CheckRun { name: "build".into(), status: CheckRunStatus::Success, duration_secs: Some(82.0) },
|
||||
CheckRun { name: "coverage".into(), status: CheckRunStatus::Success, duration_secs: Some(124.0) },
|
||||
CheckRun { name: "bundle-size".into(), status: CheckRunStatus::Skipped, duration_secs: None },
|
||||
],
|
||||
}),
|
||||
timings: Some(RunTimings { elapsed_secs: 3900.0, elapsed_warning: Some(false) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-g3h4i5j6".into(), resources: None }),
|
||||
question: None,
|
||||
sandbox_id: Some("sb-g3h4i5j6".into()),
|
||||
created_at: ts("2026-02-27T09:00:00Z"),
|
||||
},
|
||||
RunListItem {
|
||||
id: "run-10".into(),
|
||||
repo: "shared-types".into(),
|
||||
repository: RepositoryReference { name: "shared-types".into() },
|
||||
title: "Export utility type helpers".into(),
|
||||
workflow: "sync_drift".into(),
|
||||
workflow: WorkflowReference { slug: "sync_drift".into() },
|
||||
status: BoardColumn::Merge,
|
||||
number: Some(76),
|
||||
additions: Some(34),
|
||||
deletions: Some(8),
|
||||
checks: vec![
|
||||
CheckRun {
|
||||
name: "lint".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(12.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "typecheck".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(34.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "unit-tests".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(75.0),
|
||||
},
|
||||
CheckRun {
|
||||
name: "build".into(),
|
||||
status: CheckRunStatus::Success,
|
||||
duration_secs: Some(58.0),
|
||||
},
|
||||
],
|
||||
elapsed_secs: Some(2880.0),
|
||||
elapsed_warning: Some(false),
|
||||
resources: None,
|
||||
comments: Some(0),
|
||||
pull_request: Some(RunPullRequest {
|
||||
number: 76,
|
||||
additions: Some(34),
|
||||
deletions: Some(8),
|
||||
comments: Some(0),
|
||||
checks: vec![
|
||||
CheckRun { name: "lint".into(), status: CheckRunStatus::Success, duration_secs: Some(12.0) },
|
||||
CheckRun { name: "typecheck".into(), status: CheckRunStatus::Success, duration_secs: Some(34.0) },
|
||||
CheckRun { name: "unit-tests".into(), status: CheckRunStatus::Success, duration_secs: Some(75.0) },
|
||||
CheckRun { name: "build".into(), status: CheckRunStatus::Success, duration_secs: Some(58.0) },
|
||||
],
|
||||
}),
|
||||
timings: Some(RunTimings { elapsed_secs: 2880.0, elapsed_warning: Some(false) }),
|
||||
sandbox: Some(RunSandbox { id: "sb-k7l8m9n0".into(), resources: None }),
|
||||
question: None,
|
||||
sandbox_id: Some("sb-k7l8m9n0".into()),
|
||||
created_at: ts("2026-02-26T08:00:00Z"),
|
||||
},
|
||||
]
|
||||
|
|
@ -1137,36 +971,28 @@ mod runs {
|
|||
RunUsage {
|
||||
stages: vec![
|
||||
UsageStage {
|
||||
stage: "Detect Drift".into(),
|
||||
model: "Opus 4.6".into(),
|
||||
input_tokens: 12480,
|
||||
output_tokens: 3210,
|
||||
stage: UsageStageRef { id: "detect-drift".into(), name: "Detect Drift".into() },
|
||||
model: ModelReference { id: "Opus 4.6".into() },
|
||||
usage: TokenUsage { input_tokens: 12480, output_tokens: 3210, cost: 0.48 },
|
||||
runtime_secs: 72.0,
|
||||
cost: 0.48,
|
||||
},
|
||||
UsageStage {
|
||||
stage: "Propose Changes".into(),
|
||||
model: "Gemini 3.1".into(),
|
||||
input_tokens: 28640,
|
||||
output_tokens: 8750,
|
||||
stage: UsageStageRef { id: "propose-changes".into(), name: "Propose Changes".into() },
|
||||
model: ModelReference { id: "Gemini 3.1".into() },
|
||||
usage: TokenUsage { input_tokens: 28640, output_tokens: 8750, cost: 0.72 },
|
||||
runtime_secs: 154.0,
|
||||
cost: 0.72,
|
||||
},
|
||||
UsageStage {
|
||||
stage: "Review Changes".into(),
|
||||
model: "Codex 5.3".into(),
|
||||
input_tokens: 9120,
|
||||
output_tokens: 2640,
|
||||
stage: UsageStageRef { id: "review-changes".into(), name: "Review Changes".into() },
|
||||
model: ModelReference { id: "Codex 5.3".into() },
|
||||
usage: TokenUsage { input_tokens: 9120, output_tokens: 2640, cost: 0.19 },
|
||||
runtime_secs: 45.0,
|
||||
cost: 0.19,
|
||||
},
|
||||
UsageStage {
|
||||
stage: "Apply Changes".into(),
|
||||
model: "Opus 4.6".into(),
|
||||
input_tokens: 21300,
|
||||
output_tokens: 6480,
|
||||
stage: UsageStageRef { id: "apply-changes".into(), name: "Apply Changes".into() },
|
||||
model: ModelReference { id: "Opus 4.6".into() },
|
||||
usage: TokenUsage { input_tokens: 21300, output_tokens: 6480, cost: 0.87 },
|
||||
runtime_secs: 118.0,
|
||||
cost: 0.87,
|
||||
},
|
||||
],
|
||||
totals: UsageTotals {
|
||||
|
|
@ -1177,25 +1003,19 @@ mod runs {
|
|||
},
|
||||
by_model: vec![
|
||||
UsageByModel {
|
||||
model: "Opus 4.6".into(),
|
||||
model: ModelReference { id: "Opus 4.6".into() },
|
||||
stages: 2,
|
||||
input_tokens: 33780,
|
||||
output_tokens: 9690,
|
||||
cost: 1.35,
|
||||
usage: TokenUsage { input_tokens: 33780, output_tokens: 9690, cost: 1.35 },
|
||||
},
|
||||
UsageByModel {
|
||||
model: "Gemini 3.1".into(),
|
||||
model: ModelReference { id: "Gemini 3.1".into() },
|
||||
stages: 1,
|
||||
input_tokens: 28640,
|
||||
output_tokens: 8750,
|
||||
cost: 0.72,
|
||||
usage: TokenUsage { input_tokens: 28640, output_tokens: 8750, cost: 0.72 },
|
||||
},
|
||||
UsageByModel {
|
||||
model: "Codex 5.3".into(),
|
||||
model: ModelReference { id: "Codex 5.3".into() },
|
||||
stages: 1,
|
||||
input_tokens: 9120,
|
||||
output_tokens: 2640,
|
||||
cost: 0.19,
|
||||
usage: TokenUsage { input_tokens: 9120, output_tokens: 2640, cost: 0.19 },
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
@ -1255,32 +1075,28 @@ mod usage {
|
|||
|
||||
pub fn aggregate() -> AggregateUsage {
|
||||
AggregateUsage {
|
||||
total_runs: 9,
|
||||
total_input_tokens: 643_860,
|
||||
total_output_tokens: 189_720,
|
||||
total_cost: 20.34,
|
||||
total_runtime_secs: 3_501.0,
|
||||
totals: AggregateUsageTotals {
|
||||
runs: 9,
|
||||
input_tokens: 643_860,
|
||||
output_tokens: 189_720,
|
||||
cost: 20.34,
|
||||
runtime_secs: 3_501.0,
|
||||
},
|
||||
by_model: vec![
|
||||
UsageByModel {
|
||||
model: "Opus 4.6".into(),
|
||||
model: ModelReference { id: "Opus 4.6".into() },
|
||||
stages: 18,
|
||||
input_tokens: 304_020,
|
||||
output_tokens: 87_210,
|
||||
cost: 12.15,
|
||||
usage: TokenUsage { input_tokens: 304_020, output_tokens: 87_210, cost: 12.15 },
|
||||
},
|
||||
UsageByModel {
|
||||
model: "Gemini 3.1".into(),
|
||||
model: ModelReference { id: "Gemini 3.1".into() },
|
||||
stages: 9,
|
||||
input_tokens: 257_760,
|
||||
output_tokens: 78_750,
|
||||
cost: 6.48,
|
||||
usage: TokenUsage { input_tokens: 257_760, output_tokens: 78_750, cost: 6.48 },
|
||||
},
|
||||
UsageByModel {
|
||||
model: "Codex 5.3".into(),
|
||||
model: ModelReference { id: "Codex 5.3".into() },
|
||||
stages: 9,
|
||||
input_tokens: 82_080,
|
||||
output_tokens: 23_760,
|
||||
cost: 1.71,
|
||||
usage: TokenUsage { input_tokens: 82_080, output_tokens: 23_760, cost: 1.71 },
|
||||
},
|
||||
],
|
||||
}
|
||||
|
|
@ -1296,33 +1112,29 @@ mod workflows {
|
|||
name: "Fix Build".into(),
|
||||
slug: "fix_build".into(),
|
||||
filename: "fix_build.dot".into(),
|
||||
last_run: Some("2 hours ago".into()),
|
||||
last_run: Some(WorkflowLastRun { label: "2 hours ago".into() }),
|
||||
schedule: None,
|
||||
next_run: None,
|
||||
},
|
||||
WorkflowListItem {
|
||||
name: "Implement Feature".into(),
|
||||
slug: "implement".into(),
|
||||
filename: "implement.dot".into(),
|
||||
last_run: Some("4 days ago".into()),
|
||||
last_run: Some(WorkflowLastRun { label: "4 days ago".into() }),
|
||||
schedule: None,
|
||||
next_run: None,
|
||||
},
|
||||
WorkflowListItem {
|
||||
name: "Sync Drift".into(),
|
||||
slug: "sync_drift".into(),
|
||||
filename: "sync_drift.dot".into(),
|
||||
last_run: Some("1 day ago".into()),
|
||||
last_run: Some(WorkflowLastRun { label: "1 day ago".into() }),
|
||||
schedule: None,
|
||||
next_run: None,
|
||||
},
|
||||
WorkflowListItem {
|
||||
name: "Expand Product".into(),
|
||||
slug: "expand".into(),
|
||||
filename: "expand.dot".into(),
|
||||
last_run: Some("2 weeks ago".into()),
|
||||
last_run: Some(WorkflowLastRun { label: "2 weeks ago".into() }),
|
||||
schedule: None,
|
||||
next_run: None,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
|
@ -2212,9 +2024,8 @@ mod verifications {
|
|||
fn recent_results_from_def(defs: &[RecentResultDef]) -> Vec<RecentControlResult> {
|
||||
defs.iter()
|
||||
.map(|r| RecentControlResult {
|
||||
run_id: r.run_id.into(),
|
||||
run_title: r.run_title.into(),
|
||||
workflow: r.workflow.into(),
|
||||
run: RunReference { id: r.run_id.into(), title: r.run_title.into() },
|
||||
workflow: WorkflowReference { slug: r.workflow.into() },
|
||||
result: r.result,
|
||||
timestamp: r.timestamp.into(),
|
||||
})
|
||||
|
|
@ -2293,7 +2104,7 @@ mod verifications {
|
|||
slug: ctrl.slug.into(),
|
||||
description: ctrl.description.into(),
|
||||
type_: ctrl.type_,
|
||||
category: cat.name.into(),
|
||||
category: CategoryReference { name: cat.name.into() },
|
||||
},
|
||||
performance: ControlPerformance {
|
||||
mode: ctrl.mode,
|
||||
|
|
@ -2345,9 +2156,8 @@ mod retros {
|
|||
pub fn list_items() -> Vec<RetroListItem> {
|
||||
vec![
|
||||
RetroListItem {
|
||||
run_id: "run-1".into(),
|
||||
workflow_name: "implement".into(),
|
||||
goal: "Add rate limiting to auth endpoints".into(),
|
||||
run: RunReference { id: "run-1".into(), title: "Add rate limiting to auth endpoints".into() },
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
timestamp: ts("2026-02-28T14:32:00Z"),
|
||||
smoothness: Some(SmoothnessRating::Smooth),
|
||||
stats: RetroStats {
|
||||
|
|
@ -2366,9 +2176,8 @@ mod retros {
|
|||
friction_point_count: 0,
|
||||
},
|
||||
RetroListItem {
|
||||
run_id: "run-2".into(),
|
||||
workflow_name: "implement".into(),
|
||||
goal: "Migrate to React Router v7".into(),
|
||||
run: RunReference { id: "run-2".into(), title: "Migrate to React Router v7".into() },
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
timestamp: ts("2026-02-28T10:15:00Z"),
|
||||
smoothness: Some(SmoothnessRating::Bumpy),
|
||||
stats: RetroStats {
|
||||
|
|
@ -2390,9 +2199,8 @@ mod retros {
|
|||
friction_point_count: 2,
|
||||
},
|
||||
RetroListItem {
|
||||
run_id: "run-6".into(),
|
||||
workflow_name: "implement".into(),
|
||||
goal: "Add dark mode toggle".into(),
|
||||
run: RunReference { id: "run-6".into(), title: "Add dark mode toggle".into() },
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
timestamp: ts("2026-02-27T16:45:00Z"),
|
||||
smoothness: Some(SmoothnessRating::Effortless),
|
||||
stats: RetroStats {
|
||||
|
|
@ -2410,9 +2218,8 @@ mod retros {
|
|||
friction_point_count: 0,
|
||||
},
|
||||
RetroListItem {
|
||||
run_id: "run-3".into(),
|
||||
workflow_name: "fix_build".into(),
|
||||
goal: "Fix config parsing for nested values".into(),
|
||||
run: RunReference { id: "run-3".into(), title: "Fix config parsing for nested values".into() },
|
||||
workflow: WorkflowReference { slug: "fix_build".into() },
|
||||
timestamp: ts("2026-02-27T09:20:00Z"),
|
||||
smoothness: Some(SmoothnessRating::Struggled),
|
||||
stats: RetroStats {
|
||||
|
|
@ -2431,9 +2238,8 @@ mod retros {
|
|||
friction_point_count: 3,
|
||||
},
|
||||
RetroListItem {
|
||||
run_id: "run-8".into(),
|
||||
workflow_name: "implement".into(),
|
||||
goal: "Implement webhook retry logic".into(),
|
||||
run: RunReference { id: "run-8".into(), title: "Implement webhook retry logic".into() },
|
||||
workflow: WorkflowReference { slug: "implement".into() },
|
||||
timestamp: ts("2026-02-26T11:00:00Z"),
|
||||
smoothness: Some(SmoothnessRating::Smooth),
|
||||
stats: RetroStats {
|
||||
|
|
@ -2478,7 +2284,7 @@ mod sessions {
|
|||
SessionListItem {
|
||||
id: uid(S1),
|
||||
title: "Add rate limiting to auth endpoints".into(),
|
||||
model: "Opus 4.6".into(),
|
||||
model: ModelReference { id: "Opus 4.6".into() },
|
||||
last_message_preview: "Done. I've created the rate limiter and wired it up...".into(),
|
||||
created_at: ts("2026-03-06T14:30:00Z"),
|
||||
updated_at: ts("2026-03-06T15:45:00Z"),
|
||||
|
|
@ -2486,7 +2292,7 @@ mod sessions {
|
|||
SessionListItem {
|
||||
id: uid(S2),
|
||||
title: "Fix config parsing for nested values".into(),
|
||||
model: "Sonnet 4.6".into(),
|
||||
model: ModelReference { id: "Sonnet 4.6".into() },
|
||||
last_message_preview: "Fixed. The parser now tracks the current section header...".into(),
|
||||
created_at: ts("2026-03-06T12:30:00Z"),
|
||||
updated_at: ts("2026-03-06T13:15:00Z"),
|
||||
|
|
@ -2494,7 +2300,7 @@ mod sessions {
|
|||
SessionListItem {
|
||||
id: uid(S3),
|
||||
title: "Migrate to React Router v7".into(),
|
||||
model: "Opus 4.6".into(),
|
||||
model: ModelReference { id: "Opus 4.6".into() },
|
||||
last_message_preview: "You're on React Router 6.22. The migration to v7 involves...".into(),
|
||||
created_at: ts("2026-03-05T10:00:00Z"),
|
||||
updated_at: ts("2026-03-05T11:30:00Z"),
|
||||
|
|
@ -2502,7 +2308,7 @@ mod sessions {
|
|||
SessionListItem {
|
||||
id: uid(S4),
|
||||
title: "Add dark mode toggle".into(),
|
||||
model: "Sonnet 4.6".into(),
|
||||
model: ModelReference { id: "Sonnet 4.6".into() },
|
||||
last_message_preview: "Added a dark mode toggle to the settings panel with system preference detection.".into(),
|
||||
created_at: ts("2026-03-05T09:00:00Z"),
|
||||
updated_at: ts("2026-03-05T09:45:00Z"),
|
||||
|
|
@ -2510,7 +2316,7 @@ mod sessions {
|
|||
SessionListItem {
|
||||
id: uid(S5),
|
||||
title: "Update OpenAPI spec for v3".into(),
|
||||
model: "Opus 4.6".into(),
|
||||
model: ModelReference { id: "Opus 4.6".into() },
|
||||
last_message_preview: "Updated all endpoint schemas to v3 format with discriminated unions.".into(),
|
||||
created_at: ts("2026-03-05T08:00:00Z"),
|
||||
updated_at: ts("2026-03-05T08:30:00Z"),
|
||||
|
|
@ -2518,7 +2324,7 @@ mod sessions {
|
|||
SessionListItem {
|
||||
id: uid(S6),
|
||||
title: "Terraform module for Redis cluster".into(),
|
||||
model: "Opus 4.6".into(),
|
||||
model: ModelReference { id: "Opus 4.6".into() },
|
||||
last_message_preview: "Created the module with 3-node cluster, automatic failover, and encryption at rest.".into(),
|
||||
created_at: ts("2026-03-03T15:00:00Z"),
|
||||
updated_at: ts("2026-03-03T16:00:00Z"),
|
||||
|
|
@ -2526,7 +2332,7 @@ mod sessions {
|
|||
SessionListItem {
|
||||
id: uid(S7),
|
||||
title: "Add pipeline event types".into(),
|
||||
model: "Sonnet 4.6".into(),
|
||||
model: ModelReference { id: "Sonnet 4.6".into() },
|
||||
last_message_preview: "Added PipelineStarted, StageCompleted, and PipelineFailed event types.".into(),
|
||||
created_at: ts("2026-03-01T11:00:00Z"),
|
||||
updated_at: ts("2026-03-01T12:00:00Z"),
|
||||
|
|
@ -2534,7 +2340,7 @@ mod sessions {
|
|||
SessionListItem {
|
||||
id: uid(S8),
|
||||
title: "Implement webhook retry logic".into(),
|
||||
model: "Opus 4.6".into(),
|
||||
model: ModelReference { id: "Opus 4.6".into() },
|
||||
last_message_preview: "Implemented exponential backoff with jitter, max 5 retries over 24 hours.".into(),
|
||||
created_at: ts("2026-02-28T09:00:00Z"),
|
||||
updated_at: ts("2026-02-28T10:00:00Z"),
|
||||
|
|
@ -2546,7 +2352,7 @@ mod sessions {
|
|||
let parsed = id.parse::<Uuid>().ok()?;
|
||||
match parsed.as_u128() {
|
||||
S1 => Some(SessionDetail {
|
||||
id: uid(S1), title: "Add rate limiting to auth endpoints".into(), model: "Opus 4.6".into(), created_at: ts("2026-03-06T14:30:00Z"), updated_at: ts("2026-03-06T15:45:00Z"),
|
||||
id: uid(S1), title: "Add rate limiting to auth endpoints".into(), model: ModelReference { id: "Opus 4.6".into() }, created_at: ts("2026-03-06T14:30:00Z"), updated_at: ts("2026-03-06T15:45:00Z"),
|
||||
turns: vec![
|
||||
SessionTurn::UserTurn(UserTurn { kind: UserTurnKind::User, content: "Add rate limiting to the auth endpoints. We're getting hit with brute force attempts on /api/auth/login and /api/auth/register. Use a sliding window approach with Redis, 10 requests per minute per IP.".into(), created_at: ts("2026-02-28T10:00:00Z") }),
|
||||
SessionTurn::AssistantTurn(AssistantTurn { kind: AssistantTurnKind::Assistant, content: "I'll implement sliding window rate limiting using Redis. Let me first look at the existing auth routes and middleware setup.".into(), created_at: ts("2026-02-28T10:00:15Z") }),
|
||||
|
|
@ -2565,7 +2371,7 @@ mod sessions {
|
|||
],
|
||||
}),
|
||||
S2 => Some(SessionDetail {
|
||||
id: uid(S2), title: "Fix config parsing for nested values".into(), model: "Sonnet 4.6".into(), created_at: ts("2026-03-06T12:30:00Z"), updated_at: ts("2026-03-06T13:15:00Z"),
|
||||
id: uid(S2), title: "Fix config parsing for nested values".into(), model: ModelReference { id: "Sonnet 4.6".into() }, created_at: ts("2026-03-06T12:30:00Z"), updated_at: ts("2026-03-06T13:15:00Z"),
|
||||
turns: vec![
|
||||
SessionTurn::UserTurn(UserTurn { kind: UserTurnKind::User, content: "The CLI crashes when parsing nested TOML config values like [database.connection]. Can you debug and fix this?".into(), created_at: ts("2026-02-28T10:00:00Z") }),
|
||||
SessionTurn::AssistantTurn(AssistantTurn { kind: AssistantTurnKind::Assistant, content: "Let me look at the config parser to understand how nested keys are handled.".into(), created_at: ts("2026-02-28T10:00:12Z") }),
|
||||
|
|
@ -2581,7 +2387,7 @@ mod sessions {
|
|||
],
|
||||
}),
|
||||
S3 => Some(SessionDetail {
|
||||
id: uid(S3), title: "Migrate to React Router v7".into(), model: "Opus 4.6".into(), created_at: ts("2026-03-05T10:00:00Z"), updated_at: ts("2026-03-05T11:30:00Z"),
|
||||
id: uid(S3), title: "Migrate to React Router v7".into(), model: ModelReference { id: "Opus 4.6".into() }, created_at: ts("2026-03-05T10:00:00Z"), updated_at: ts("2026-03-05T11:30:00Z"),
|
||||
turns: vec![
|
||||
SessionTurn::UserTurn(UserTurn { kind: UserTurnKind::User, content: "Help me migrate our app from React Router v6 to v7. We're using createBrowserRouter with data loaders.".into(), created_at: ts("2026-02-26T10:00:00Z") }),
|
||||
SessionTurn::AssistantTurn(AssistantTurn { kind: AssistantTurnKind::Assistant, content: "I'll audit your current router setup and identify what needs to change for v7. Let me scan the codebase.".into(), created_at: ts("2026-02-26T10:00:10Z") }),
|
||||
|
|
|
|||
|
|
@ -315,19 +315,23 @@ async fn get_aggregate_usage(
|
|||
.by_model
|
||||
.iter()
|
||||
.map(|(model, totals)| arc_types::UsageByModel {
|
||||
model: model.clone(),
|
||||
model: arc_types::ModelReference { id: model.clone() },
|
||||
stages: totals.stages,
|
||||
input_tokens: totals.input_tokens,
|
||||
output_tokens: totals.output_tokens,
|
||||
cost: totals.cost,
|
||||
usage: arc_types::TokenUsage {
|
||||
input_tokens: totals.input_tokens,
|
||||
output_tokens: totals.output_tokens,
|
||||
cost: totals.cost,
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
let response = arc_types::AggregateUsage {
|
||||
total_runs: agg.total_runs,
|
||||
total_input_tokens: by_model.iter().map(|m| m.input_tokens).sum(),
|
||||
total_output_tokens: by_model.iter().map(|m| m.output_tokens).sum(),
|
||||
total_cost: by_model.iter().map(|m| m.cost).sum(),
|
||||
total_runtime_secs: agg.total_runtime_secs,
|
||||
totals: arc_types::AggregateUsageTotals {
|
||||
runs: agg.total_runs,
|
||||
input_tokens: by_model.iter().map(|m| m.usage.input_tokens).sum(),
|
||||
output_tokens: by_model.iter().map(|m| m.usage.output_tokens).sum(),
|
||||
cost: by_model.iter().map(|m| m.usage.cost).sum(),
|
||||
runtime_secs: agg.total_runtime_secs,
|
||||
},
|
||||
by_model,
|
||||
};
|
||||
(StatusCode::OK, Json(response)).into_response()
|
||||
|
|
@ -377,7 +381,7 @@ async fn list_runs(
|
|||
.map(|(id, managed_run)| RunStatusResponse {
|
||||
id: id.clone(),
|
||||
status: managed_run.status,
|
||||
error: managed_run.error.clone(),
|
||||
error: managed_run.error.as_ref().map(|msg| arc_types::RunError { message: msg.clone() }),
|
||||
queue_position: queue_positions.get(id).copied(),
|
||||
created_at: managed_run.created_at,
|
||||
})
|
||||
|
|
@ -458,6 +462,7 @@ async fn start_run(
|
|||
queue_position: None,
|
||||
created_at,
|
||||
}),
|
||||
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
|
@ -690,7 +695,7 @@ async fn get_run_status(
|
|||
Json(RunStatusResponse {
|
||||
id: id.clone(),
|
||||
status: managed_run.status,
|
||||
error: managed_run.error.clone(),
|
||||
error: managed_run.error.as_ref().map(|msg| arc_types::RunError { message: msg.clone() }),
|
||||
created_at: managed_run.created_at,
|
||||
queue_position,
|
||||
}),
|
||||
|
|
@ -1506,11 +1511,11 @@ mod tests {
|
|||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
||||
let body = body_json(response.into_body()).await;
|
||||
assert_eq!(body["total_runs"].as_i64().unwrap(), 0);
|
||||
assert_eq!(body["total_input_tokens"].as_i64().unwrap(), 0);
|
||||
assert_eq!(body["total_output_tokens"].as_i64().unwrap(), 0);
|
||||
assert_eq!(body["total_cost"].as_f64().unwrap(), 0.0);
|
||||
assert_eq!(body["total_runtime_secs"].as_f64().unwrap(), 0.0);
|
||||
assert_eq!(body["totals"]["runs"].as_i64().unwrap(), 0);
|
||||
assert_eq!(body["totals"]["input_tokens"].as_i64().unwrap(), 0);
|
||||
assert_eq!(body["totals"]["output_tokens"].as_i64().unwrap(), 0);
|
||||
assert_eq!(body["totals"]["cost"].as_f64().unwrap(), 0.0);
|
||||
assert_eq!(body["totals"]["runtime_secs"].as_f64().unwrap(), 0.0);
|
||||
assert!(body["by_model"].as_array().unwrap().is_empty());
|
||||
}
|
||||
|
||||
|
|
@ -1562,7 +1567,7 @@ mod tests {
|
|||
assert_eq!(response.status(), StatusCode::OK);
|
||||
|
||||
let body = body_json(response.into_body()).await;
|
||||
assert_eq!(body["total_runs"].as_i64().unwrap(), 1);
|
||||
assert_eq!(body["totals"]["runs"].as_i64().unwrap(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue