package diagnostics import ( "context" "errors" "os" "testing" "data-terminal-cloud/internal/audit" "data-terminal-cloud/internal/database" "data-terminal-cloud/internal/idempotency" "data-terminal-cloud/internal/identity" "github.com/google/uuid" ) func TestAcceptanceSnapshotIsAuditedIdempotentAndTenantScoped(t *testing.T) { databaseURL := os.Getenv("TEST_DATABASE_URL") if databaseURL == "" { t.Skip("TEST_DATABASE_URL is not set") } ctx := context.Background() pool, err := database.Open(ctx, databaseURL, "acceptance-snapshot-test") if err != nil { t.Fatal(err) } defer pool.Close() service, err := NewService(pool, idempotency.NewExecutor(pool), audit.NewRepository()) if err != nil { t.Fatal(err) } admin := identity.Principal{Issuer: "http://localhost:58180/realms/voice-local", Subject: "00000000-0000-0000-0000-000000000101"} tenantPublicID := "10000000-0000-0000-0000-000000000010" key := "acceptance-snapshot-" + uuid.NewString() requestID := "acceptance-snapshot-test-" + uuid.NewString() alertID := uuid.NewString() missingConversationID := uuid.NewString() defer func() { _, _ = pool.Exec(context.Background(), `DELETE FROM audit_event WHERE request_id=$1`, requestID) _, _ = pool.Exec(context.Background(), `DELETE FROM idempotency_record WHERE idempotency_key=$1`, key) _, _ = pool.Exec(context.Background(), `DELETE FROM alert_incident WHERE public_id=$1::uuid`, alertID) }() if _, err = pool.Exec(ctx, `INSERT INTO alert_incident(public_id,tenant_id,rule_code,category,severity,status,fingerprint,title,summary,resource_type,resource_public_id,first_detected_at,last_detected_at) VALUES($1::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'ACCEPTANCE_SNAPSHOT_TEST','TECHNICAL','HIGH','OPEN',$2,'验收快照合成阻断','验证缺失资源定位','conversation',$3::uuid,now(),now())`, alertID, "acceptance-snapshot-test:"+alertID, missingConversationID); err != nil { t.Fatal(err) } input := AcceptanceSnapshotInput{ CandidateVersion: "0.50.0-rc.1", BuildDigest: "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Environment: "LAB", RunType: "REAL_DEVICE_PROVIDER", Scope: "本地真实OIDC与平台技术预检", RequiredDependencies: []string{ "oidc_jwks", }, Reason: "生成可归档的阶段8技术验收证据", } first, created, err := service.ExportAcceptanceSnapshot(ctx, admin, tenantPublicID, key, requestID, input) if err != nil || !created { t.Fatalf("first=%+v created=%t err=%v", first, created, err) } if first.ID == "" || first.Database.MigrationVersion < 39 || first.Database.Dirty || first.RedactionPolicy != "ops-acceptance-minimal-v1" || len(first.ExternalDependencies) != 1 || len(first.Gates) != 7 { t.Fatalf("unexpected snapshot=%+v", first) } if first.ExternalDependencies[0].Dependency != "oidc_jwks" || first.ExternalDependencies[0].ServiceName != "api" { t.Fatalf("unexpected dependency=%+v", first.ExternalDependencies[0]) } var foundBlockingAlert bool for _, item := range first.Alerts.BlockingItems { if item.ID == alertID { foundBlockingAlert = item.RuleCode == "ACCEPTANCE_SNAPSHOT_TEST" && item.ResourceID == missingConversationID && item.ResourceState == "MISSING" } } if !foundBlockingAlert || first.Alerts.Blocking == 0 || first.Gates[5].Code != "critical_alerts_clear" || first.Gates[5].Satisfied { t.Fatalf("blocking alert evidence=%+v gates=%+v", first.Alerts, first.Gates) } if first.Gates[6].Code != "platform_health_current" || first.PlatformHealth.State == "" { t.Fatalf("platform health=%+v gates=%+v", first.PlatformHealth, first.Gates) } replayed, createdAgain, err := service.ExportAcceptanceSnapshot(ctx, admin, tenantPublicID, key, requestID, input) if err != nil || createdAgain || replayed.ID != first.ID || !replayed.GeneratedAt.Equal(first.GeneratedAt) { t.Fatalf("replayed=%+v created=%t err=%v", replayed, createdAgain, err) } if _, _, err = service.ExportAcceptanceSnapshot(ctx, admin, "20000000-0000-0000-0000-000000000010", "cross-"+key, requestID, input); !errors.Is(err, ErrAccessDenied) { t.Fatalf("cross tenant error=%v", err) } }