feat(admin): add routed task evidence details

This commit is contained in:
QiuSW
2026-08-04 19:42:35 +08:00
parent 9a4d11f74b
commit 89648880bc
28 changed files with 2997 additions and 26 deletions
+80 -13
View File
@@ -26,18 +26,25 @@ func TestUpDownAndIdempotence(t *testing.T) {
if err := migrations.Up(context, database, directory); err != nil {
t.Fatalf("apply migrations: %v", err)
}
assertVersion(t, database, 2)
assertVersion(t, database, 3)
assertTableExists(t, database, "tasks", true)
assertTableExists(t, database, "spec_trials", false)
assertTableExists(t, database, "order_authorizations", true)
assertTableExists(t, database, "purchase_attempts", true)
assertTableExists(t, database, "order_submissions", true)
assertTableExists(t, database, "evidence_assets", true)
assertTableExists(t, database, "single_pass_upgrade_guard", false)
if err := migrations.Up(context, database, directory); err != nil {
t.Fatalf("reapply migrations: %v", err)
}
assertVersion(t, database, 3)
if err := migrations.Down(context, database, directory); err != nil {
t.Fatalf("roll back evidence migration: %v", err)
}
assertVersion(t, database, 2)
assertTableExists(t, database, "evidence_assets", false)
if err := migrations.Down(context, database, directory); err != nil {
t.Fatalf("roll back v2 migration: %v", err)
@@ -50,7 +57,7 @@ func TestUpDownAndIdempotence(t *testing.T) {
if err := migrations.Up(context, database, directory); err != nil {
t.Fatalf("reapply v2 after rollback: %v", err)
}
assertVersion(t, database, 2)
assertVersion(t, database, 3)
}
func TestUpgradePreservesManualDraftLosslessly(t *testing.T) {
@@ -69,7 +76,7 @@ func TestUpgradePreservesManualDraftLosslessly(t *testing.T) {
if err := migrations.Up(context.Background(), database, migrationDirectory(t)); err != nil {
t.Fatalf("upgrade v1 draft: %v", err)
}
assertVersion(t, database, 2)
assertVersion(t, database, 3)
var got struct {
id, source, sourceRef, title, goodsID, color, size, maxPrice, assetID, status, created, updated string
quantity, version int
@@ -218,6 +225,55 @@ func TestV2SchemaConstraintsAndRelationships(t *testing.T) {
}
}
func TestEvidenceSchemaConstraintsAndDowngradeGuard(t *testing.T) {
database := openTestDatabase(t)
if err := migrations.Up(context.Background(), database, migrationDirectory(t)); err != nil {
t.Fatalf("apply migrations: %v", err)
}
insertV2Task(t, database, "task-one", "MANUAL", "DRAFT")
insertV2Authorization(t, database, "auth-one", "task-one", 1, "start-one")
insertV2Attempt(t, database, "attempt-one", "task-one", "auth-one", 1)
insertV2Task(t, database, "task-two", "MANUAL", "DRAFT")
insertV2Authorization(t, database, "auth-two", "task-two", 1, "start-two")
insertV2Attempt(t, database, "attempt-two", "task-two", "auth-two", 1)
hash := strings.Repeat("a", 64)
insert := `INSERT INTO evidence_assets (id, upload_key, task_id, attempt_id, kind, privacy_tier, sha256, byte_size, content_type, width_px, height_px, storage_key, uploaded_by_device_id, captured_at, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
validArgs := []any{"asset-one", "upload-one", "task-one", "attempt-one", "SKU_PANEL_GATE_1", "INTERNAL_RAW", hash, 100, "image/png", 100, 100, "aa/" + hash + ".png", "device-one", migrationTime, migrationTime}
if _, err := database.Exec(insert, validArgs...); err != nil {
t.Fatalf("insert valid evidence: %v", err)
}
for name, mutate := range map[string]func([]any){
"attempt from another task": func(values []any) { values[0], values[1], values[3] = "bad-task", "upload-bad-task", "attempt-two" },
"unapproved kind": func(values []any) { values[0], values[1], values[4] = "bad-kind", "upload-bad-kind", "ORDER_CONFIRM" },
"wrong privacy": func(values []any) { values[0], values[1], values[5] = "bad-privacy", "upload-bad-privacy", "PUBLIC" },
"uppercase hash": func(values []any) {
values[0], values[1], values[6], values[11] = "bad-hash", "upload-bad-hash", strings.Repeat("A", 64), "AA/"+strings.Repeat("A", 64)+".png"
},
"too many pixels": func(values []any) {
values[0], values[1], values[9], values[10] = "bad-pixels", "upload-bad-pixels", 8192, 8192
},
"client path": func(values []any) { values[0], values[1], values[11] = "bad-path", "upload-bad-path", `..\secret.png` },
} {
t.Run(name, func(t *testing.T) {
values := append([]any(nil), validArgs...)
mutate(values)
if _, err := database.Exec(insert, values...); err == nil {
t.Fatal("invalid evidence row succeeded")
}
})
}
if err := migrations.Down(context.Background(), database, migrationDirectory(t)); err == nil {
t.Fatal("evidence-bearing schema downgraded successfully")
}
assertVersion(t, database, 3)
assertTableExists(t, database, "evidence_assets", true)
var count int
if err := database.QueryRow("SELECT COUNT(*) FROM evidence_assets").Scan(&count); err != nil || count != 1 {
t.Fatalf("evidence after rejected downgrade = %d, err=%v", count, err)
}
}
func TestDowngradeRejectsV2BusinessDataAtomically(t *testing.T) {
tests := []struct {
name string
@@ -244,9 +300,7 @@ func TestDowngradeRejectsV2BusinessDataAtomically(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
database := openTestDatabase(t)
if err := migrations.Up(context.Background(), database, migrationDirectory(t)); err != nil {
t.Fatalf("apply migrations: %v", err)
}
migrateToV2(t, database)
test.setup(t, database)
before := v2RowCount(t, database)
if err := migrations.Down(context.Background(), database, migrationDirectory(t)); err == nil {
@@ -271,6 +325,17 @@ func migrateToV1(t *testing.T, database *sql.DB) {
assertVersion(t, database, 1)
}
func migrateToV2(t *testing.T, database *sql.DB) {
t.Helper()
if err := migrations.Run(context.Background(), database, migrationDirectory(t), "up-by-one"); err != nil {
t.Fatalf("apply v1: %v", err)
}
if err := migrations.Run(context.Background(), database, migrationDirectory(t), "up-by-one"); err != nil {
t.Fatalf("apply v2: %v", err)
}
assertVersion(t, database, 2)
}
func insertV1Task(t *testing.T, database *sql.DB, id, source, status, price string) {
t.Helper()
if _, err := database.Exec(`INSERT INTO tasks (id, source, title, goods_id, sku_color, sku_size, quantity, max_total_price, status, created_at, updated_at) VALUES (?, ?, 'title', 'goods', 'white', 'XL', 1, ?, ?, ?, ?)`, id, source, price, status, migrationTime, migrationTime); err != nil {
@@ -390,12 +455,14 @@ func assertColumnType(t *testing.T, database *sql.DB, table, column, want string
}
}
func TestV2MigrationSQLDoesNotDisableForeignKeys(t *testing.T) {
contents, err := os.ReadFile(filepath.Join(migrationDirectory(t), "00002_single_pass_model.sql"))
if err != nil {
t.Fatalf("read migration: %v", err)
}
if strings.Contains(strings.ToUpper(string(contents)), "PRAGMA FOREIGN_KEYS = OFF") {
t.Fatal("migration disables foreign keys")
func TestMigrationsDoNotDisableForeignKeys(t *testing.T) {
for _, name := range []string{"00002_single_pass_model.sql", "00003_evidence_assets.sql"} {
contents, err := os.ReadFile(filepath.Join(migrationDirectory(t), name))
if err != nil {
t.Fatalf("read %s: %v", name, err)
}
if strings.Contains(strings.ToUpper(string(contents)), "PRAGMA FOREIGN_KEYS = OFF") {
t.Fatalf("%s disables foreign keys", name)
}
}
}