test(saas): Phase 1 integration tests — billing + scheduled_task + knowledge (68 tests)
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

- Fix TIMESTAMPTZ decode errors: add ::TEXT cast to all SELECT queries
  where Row structs use String for TIMESTAMPTZ columns (~22 locations)
- Fix Axum 0.7 route params: {id} → :id in billing/knowledge/scheduled_task routes
- Fix JSONB bind: scheduled_task INSERT uses ::jsonb cast for input_payload
- Add billing_test.rs (14 tests): plans, subscription, usage, payments, invoices
- Add scheduled_task_test.rs (12 tests): CRUD, validation, isolation
- Add knowledge_test.rs (20 tests): categories, items, versions, search, analytics, permissions
- Fix auth test regression: 6 tests were failing due to TIMESTAMPTZ type mismatch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-04-07 14:25:34 +08:00
parent a5b887051d
commit 7de486bfca
27 changed files with 1317 additions and 187 deletions

View File

@@ -146,7 +146,7 @@ pub async fn list_operation_logs(
let rows: Vec<OperationLogRow> =
sqlx::query_as(
"SELECT id, account_id, action, target_type, target_id, details, ip_address, created_at
"SELECT id, account_id, action, target_type, target_id, details, ip_address, created_at::TEXT
FROM operation_logs ORDER BY created_at DESC LIMIT $1 OFFSET $2"
)
.bind(page_size as i64)
@@ -186,13 +186,11 @@ pub async fn dashboard_stats(
let today_start = chrono::Utc::now()
.date_naive()
.and_hms_opt(0, 0, 0).expect("midnight is always valid")
.and_utc()
.to_rfc3339();
.and_utc();
let tomorrow_start = (chrono::Utc::now() + chrono::Duration::days(1))
.date_naive()
.and_hms_opt(0, 0, 0).expect("midnight is always valid")
.and_utc()
.to_rfc3339();
.and_utc();
let today_row: DashboardTodayRow = sqlx::query_as(
"SELECT
(SELECT COUNT(*) FROM relay_tasks WHERE created_at >= $1 AND created_at < $2) as tasks_today,
@@ -248,7 +246,7 @@ pub async fn register_device(
let device_name = if req.device_name.is_empty() { "Unknown" } else { &req.device_name };
let platform = if req.platform.is_empty() { "unknown" } else { &req.platform };
let now = chrono::Utc::now().to_rfc3339();
let now = chrono::Utc::now();
let device_uuid = uuid::Uuid::new_v4().to_string();
// UPSERT: 已存在则更新 last_seen_at不存在则插入
@@ -285,7 +283,7 @@ pub async fn device_heartbeat(
.and_then(|v| v.as_str())
.ok_or_else(|| SaasError::InvalidInput("缺少 device_id".into()))?;
let now = chrono::Utc::now().to_rfc3339();
let now = chrono::Utc::now();
// Also update platform/app_version if provided (supports client upgrades)
let platform = req.get("platform").and_then(|v| v.as_str());