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
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:
@@ -21,7 +21,7 @@ pub async fn create_template(
|
||||
) -> SaasResult<PromptTemplateInfo> {
|
||||
let id = uuid::Uuid::new_v4().to_string();
|
||||
let version_id = uuid::Uuid::new_v4().to_string();
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
let now = chrono::Utc::now();
|
||||
let vars_json = variables.unwrap_or(serde_json::json!([])).to_string();
|
||||
|
||||
// 插入模板
|
||||
@@ -53,7 +53,7 @@ pub async fn create_template(
|
||||
pub async fn get_template(db: &PgPool, id: &str) -> SaasResult<PromptTemplateInfo> {
|
||||
let row: Option<PromptTemplateRow> =
|
||||
sqlx::query_as(
|
||||
"SELECT id, name, category, description, source, current_version, status, created_at, updated_at
|
||||
"SELECT id, name, category, description, source, current_version, status, created_at::TEXT, updated_at::TEXT
|
||||
FROM prompt_templates WHERE id = $1"
|
||||
).bind(id).fetch_optional(db).await?;
|
||||
|
||||
@@ -66,7 +66,7 @@ pub async fn get_template(db: &PgPool, id: &str) -> SaasResult<PromptTemplateInf
|
||||
pub async fn get_template_by_name(db: &PgPool, name: &str) -> SaasResult<PromptTemplateInfo> {
|
||||
let row: Option<PromptTemplateRow> =
|
||||
sqlx::query_as(
|
||||
"SELECT id, name, category, description, source, current_version, status, created_at, updated_at
|
||||
"SELECT id, name, category, description, source, current_version, status, created_at::TEXT, updated_at::TEXT
|
||||
FROM prompt_templates WHERE name = $1"
|
||||
).bind(name).fetch_optional(db).await?;
|
||||
|
||||
@@ -84,7 +84,7 @@ pub async fn list_templates(
|
||||
let (page, page_size, offset) = normalize_pagination(query.page, query.page_size);
|
||||
|
||||
let count_sql = "SELECT COUNT(*) FROM prompt_templates WHERE ($1 IS NULL OR category = $1) AND ($2 IS NULL OR source = $2) AND ($3 IS NULL OR status = $3)";
|
||||
let data_sql = "SELECT id, name, category, description, source, current_version, status, created_at, updated_at \
|
||||
let data_sql = "SELECT id, name, category, description, source, current_version, status, created_at::TEXT, updated_at::TEXT \
|
||||
FROM prompt_templates WHERE ($1 IS NULL OR category = $1) AND ($2 IS NULL OR source = $2) AND ($3 IS NULL OR status = $3) ORDER BY updated_at DESC LIMIT $4 OFFSET $5";
|
||||
|
||||
let total: i64 = sqlx::query_scalar(count_sql)
|
||||
@@ -115,7 +115,7 @@ pub async fn update_template(
|
||||
description: Option<&str>,
|
||||
status: Option<&str>,
|
||||
) -> SaasResult<PromptTemplateInfo> {
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
let now = chrono::Utc::now();
|
||||
|
||||
if let Some(desc) = description {
|
||||
sqlx::query("UPDATE prompt_templates SET description = $1, updated_at = $2 WHERE id = $3")
|
||||
@@ -147,7 +147,7 @@ pub async fn create_version(
|
||||
|
||||
let new_version = tmpl.current_version + 1;
|
||||
let version_id = uuid::Uuid::new_v4().to_string();
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
let now = chrono::Utc::now();
|
||||
let vars_json = variables.unwrap_or(serde_json::json!([])).to_string();
|
||||
|
||||
sqlx::query(
|
||||
@@ -170,7 +170,7 @@ pub async fn create_version(
|
||||
pub async fn get_version(db: &PgPool, version_id: &str) -> SaasResult<PromptVersionInfo> {
|
||||
let row: Option<PromptVersionRow> =
|
||||
sqlx::query_as(
|
||||
"SELECT id, template_id, version, system_prompt, user_prompt_template, variables, changelog, min_app_version, created_at
|
||||
"SELECT id, template_id, version, system_prompt, user_prompt_template, variables, changelog, min_app_version, created_at::TEXT
|
||||
FROM prompt_versions WHERE id = $1"
|
||||
).bind(version_id).fetch_optional(db).await?;
|
||||
|
||||
@@ -187,7 +187,7 @@ pub async fn get_current_version(db: &PgPool, template_name: &str) -> SaasResult
|
||||
|
||||
let row: Option<PromptVersionRow> =
|
||||
sqlx::query_as(
|
||||
"SELECT id, template_id, version, system_prompt, user_prompt_template, variables, changelog, min_app_version, created_at
|
||||
"SELECT id, template_id, version, system_prompt, user_prompt_template, variables, changelog, min_app_version, created_at::TEXT
|
||||
FROM prompt_versions WHERE template_id = $1 AND version = $2"
|
||||
).bind(&tmpl.id).bind(tmpl.current_version).fetch_optional(db).await?;
|
||||
|
||||
@@ -205,7 +205,7 @@ pub async fn list_versions(
|
||||
) -> SaasResult<Vec<PromptVersionInfo>> {
|
||||
let rows: Vec<PromptVersionRow> =
|
||||
sqlx::query_as(
|
||||
"SELECT id, template_id, version, system_prompt, user_prompt_template, variables, changelog, min_app_version, created_at
|
||||
"SELECT id, template_id, version, system_prompt, user_prompt_template, variables, changelog, min_app_version, created_at::TEXT
|
||||
FROM prompt_versions WHERE template_id = $1 ORDER BY version DESC"
|
||||
).bind(template_id).fetch_all(db).await?;
|
||||
|
||||
@@ -230,7 +230,7 @@ pub async fn rollback_version(
|
||||
return Err(SaasError::NotFound(format!("版本 {} 不存在", target_version)));
|
||||
}
|
||||
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
let now = chrono::Utc::now();
|
||||
sqlx::query("UPDATE prompt_templates SET current_version = $1, updated_at = $2 WHERE id = $3")
|
||||
.bind(target_version).bind(&now).bind(template_id)
|
||||
.execute(db).await?;
|
||||
@@ -267,7 +267,7 @@ pub async fn check_updates(
|
||||
});
|
||||
|
||||
// 更新同步状态
|
||||
let now = chrono::Utc::now().to_rfc3339();
|
||||
let now = chrono::Utc::now();
|
||||
sqlx::query(
|
||||
"INSERT INTO prompt_sync_status (device_id, template_id, synced_version, synced_at)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
@@ -317,7 +317,7 @@ pub async fn get_sync_status(
|
||||
device_id: &str,
|
||||
) -> SaasResult<Vec<PromptSyncStatusRow>> {
|
||||
let rows = sqlx::query_as::<_, PromptSyncStatusRow>(
|
||||
"SELECT device_id, template_id, synced_version, synced_at \
|
||||
"SELECT device_id, template_id, synced_version, synced_at::TEXT \
|
||||
FROM prompt_sync_status \
|
||||
WHERE device_id = $1 \
|
||||
ORDER BY synced_at DESC \
|
||||
|
||||
Reference in New Issue
Block a user