package taskdetail import ( "context" "database/sql" "errors" "path/filepath" "runtime" "strings" "testing" "cmbuyer/admin/internal/migrations" "cmbuyer/admin/internal/storage/sqlite" ) const ( detailTask = "a3c9f507-7473-4fa6-8d71-8786c34c6301" detailAuth = "b3c9f507-7473-4fa6-8d71-8786c34c6301" detailTry = "c3c9f507-7473-4fa6-8d71-8786c34c6301" ) func TestSQLiteStoreReturnsOnlyPersistedAuditFacts(t *testing.T) { database := openDetailDatabase(t) timestamp := "2026-08-04T00:00:00Z" if _, err := database.Exec(`INSERT INTO tasks (id, source, title, goods_id, sku_color, sku_size, quantity, max_total_price, status, version, created_at, updated_at) VALUES (?, 'MANUAL', 'shirt', '123', 'black', 'M', 2, '30.00', 'CLAIMED', 3, ?, ?)`, detailTask, timestamp, timestamp); err != nil { t.Fatalf("insert task: %v", err) } if _, err := database.Exec(`INSERT INTO order_authorizations (id, task_id, task_version, start_key, goods_id, sku_color, sku_size, quantity, total_price_cap, status, created_by, created_at, expires_at) VALUES (?, ?, 2, 'start', '123', 'black', 'M', 2, '30.00', 'CLAIMED', 'admin', ?, ?)`, detailAuth, detailTask, timestamp, timestamp); err != nil { t.Fatalf("insert authorization: %v", err) } if _, err := database.Exec(`INSERT INTO purchase_attempts (id, task_id, authorization_id, claim_generation, status, started_at) VALUES (?, ?, ?, 1, 'CLAIMED', ?)`, detailTry, detailTask, detailAuth, timestamp); err != nil { t.Fatalf("insert attempt: %v", err) } hash := strings.Repeat("a", 64) if _, err := database.Exec(`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 ('d3c9f507-7473-4fa6-8d71-8786c34c6301', 'upload', ?, ?, 'SKU_PANEL_GATE_1', 'INTERNAL_RAW', ?, 100, 'image/png', 10, 20, ?, 'device', ?, ?)`, detailTask, detailTry, hash, "aa/"+hash+".png", timestamp, timestamp); err != nil { t.Fatalf("insert evidence: %v", err) } store, err := NewSQLiteStore(database) if err != nil { t.Fatalf("NewSQLiteStore: %v", err) } detail, err := store.Get(context.Background(), detailTask) if err != nil { t.Fatalf("Get: %v", err) } if detail.Task.ID != detailTask || detail.Task.Status != "CLAIMED" || len(detail.Authorizations) != 1 || len(detail.Attempts) != 1 || len(detail.Evidence) != 1 || len(detail.Submissions) != 0 { t.Fatalf("detail = %#v", detail) } if detail.Attempts[0].Gate1UnitPrice != nil || detail.Attempts[0].FailureCode != nil { t.Fatalf("missing attempt facts were fabricated: %#v", detail.Attempts[0]) } } func TestSQLiteStoreFailsClosedForMalformedAndMissingIDs(t *testing.T) { database := openDetailDatabase(t) store, err := NewSQLiteStore(database) if err != nil { t.Fatalf("NewSQLiteStore: %v", err) } for _, id := range []string{"../database", "not-a-uuid", "a3c9f507-7473-1fa6-8d71-8786c34c6301"} { if _, err := store.Get(context.Background(), id); !errors.Is(err, ErrNotFound) { t.Fatalf("Get(%q) error = %v", id, err) } } } func openDetailDatabase(t *testing.T) *sql.DB { t.Helper() database, err := sqlite.Open(filepath.Join(t.TempDir(), "details.db")) if err != nil { t.Fatalf("open database: %v", err) } t.Cleanup(func() { _ = database.Close() }) _, file, _, ok := runtime.Caller(0) if !ok { t.Fatal("locate migration directory") } if err := migrations.Up(context.Background(), database, filepath.Join(filepath.Dir(file), "..", "..", "migrations")); err != nil { t.Fatalf("migrate database: %v", err) } return database }