feat: complete Epic 1 production foundation
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
use crank_registry::{
|
||||
CreateInvocationLogRequest, InvocationHistoryLossCategory, InvocationHistoryWriteOutcome,
|
||||
ListInvocationLogsQuery, UsageBucket, UsageQuery,
|
||||
};
|
||||
use sqlx::Row;
|
||||
|
||||
use super::common::{TestDatabase, test_invocation_log};
|
||||
use super::common::{TestDatabase, test_invocation_log, test_operation, test_workspace_id};
|
||||
|
||||
#[tokio::test]
|
||||
async fn invocation_history_write_returns_typed_loss_without_error_details() {
|
||||
@@ -29,3 +31,115 @@ async fn invocation_history_write_returns_typed_loss_without_error_details() {
|
||||
);
|
||||
database.cleanup().await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "production-size query-plan evidence: inserts 1,000,000 invocation_logs rows"]
|
||||
async fn production_size_invocation_history_queries_stay_bounded() {
|
||||
let database = TestDatabase::new().await;
|
||||
let registry = database.registry().await;
|
||||
let pool = database.raw_pool().await;
|
||||
let operation = test_operation("op_history_scale", 1, crank_core::OperationStatus::Draft);
|
||||
|
||||
registry
|
||||
.create_operation(&test_workspace_id(), &operation, None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
sqlx::query(
|
||||
r#"
|
||||
insert into invocation_logs (
|
||||
id, workspace_id, operation_id, operation_version, source, level, status,
|
||||
tool_name, message, request_id, trace_id, status_code, duration_ms,
|
||||
error_kind, execution_stage, execution_error_code, retryability, outcome_certainty,
|
||||
request_preview_json, response_preview_json, created_at
|
||||
)
|
||||
select
|
||||
'log_scale_' || series::text,
|
||||
'ws_default',
|
||||
'op_history_scale',
|
||||
1,
|
||||
'admin_test_run',
|
||||
'info',
|
||||
case when series % 10 = 0 then 'error' else 'ok' end,
|
||||
'scale_tool',
|
||||
'scale invocation',
|
||||
'018f0000-0000-7000-8000-' || lpad(series::text, 12, '0'),
|
||||
'0af7651916cd43dd8448eb211c80319c',
|
||||
case when series % 10 = 0 then 500 else 200 end,
|
||||
20 + (series % 250),
|
||||
null,
|
||||
'runtime',
|
||||
case when series % 10 = 0 then 'runtime_internal' else null end,
|
||||
'never',
|
||||
'certain',
|
||||
'{"input":"bounded"}'::jsonb,
|
||||
'{"ok":true}'::jsonb,
|
||||
'2026-03-25T00:00:00Z'::timestamptz + (series || ' seconds')::interval
|
||||
from generate_series(1, 1000000) as series
|
||||
"#,
|
||||
)
|
||||
.execute(&pool)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let page = registry
|
||||
.list_invocation_logs(ListInvocationLogsQuery {
|
||||
workspace_id: &test_workspace_id(),
|
||||
level: None,
|
||||
status: None,
|
||||
outcome_group: None,
|
||||
search_text: None,
|
||||
source: None,
|
||||
operation_id: Some(&operation.id),
|
||||
agent_id: None,
|
||||
created_after: Some("2026-03-25T00:00:00Z"),
|
||||
created_before: Some("2026-04-06T00:00:00Z"),
|
||||
cursor_created_at: None,
|
||||
cursor_id: None,
|
||||
limit: 101,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(page.len(), 101);
|
||||
|
||||
let summary = registry
|
||||
.summarize_usage(UsageQuery {
|
||||
workspace_id: &test_workspace_id(),
|
||||
period: crank_core::UsagePeriod::Last7Days,
|
||||
source: None,
|
||||
created_after: "2026-03-25T00:00:00Z",
|
||||
created_before: "2026-04-06T00:00:00Z",
|
||||
bucket: UsageBucket::Day,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(summary.rollup.calls_total, 1_000_000);
|
||||
|
||||
let explain = sqlx::query(
|
||||
r#"
|
||||
explain
|
||||
select id
|
||||
from invocation_logs
|
||||
where workspace_id = 'ws_default'
|
||||
and operation_id = 'op_history_scale'
|
||||
and created_at >= '2026-03-25T00:00:00Z'::timestamptz
|
||||
and created_at < '2026-04-06T00:00:00Z'::timestamptz
|
||||
order by created_at desc, id desc
|
||||
limit 101
|
||||
"#,
|
||||
)
|
||||
.fetch_all(&pool)
|
||||
.await
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|row| row.get::<String, _>(0))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
assert!(
|
||||
explain.contains("Index Scan") || explain.contains("Bitmap Index Scan"),
|
||||
"{explain}"
|
||||
);
|
||||
assert!(!explain.contains("Seq Scan"), "{explain}");
|
||||
|
||||
database.cleanup().await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user