chore: establish local platform baseline

This commit is contained in:
Codex Local
2026-08-26 06:41:54 +08:00
commit 29bdf4900f
575 changed files with 95644 additions and 0 deletions
@@ -0,0 +1,138 @@
package privacy
import (
"context"
"os"
"testing"
"data-terminal-cloud/internal/cache"
"data-terminal-cloud/internal/database"
"data-terminal-cloud/internal/outbox"
"github.com/jackc/pgx/v5/pgxpool"
)
const (
privacyDeleteSubjectID = "90000000-0000-0000-0000-000000000741"
privacyDeleteSubjectPublicID = "90000000-0000-0000-0000-000000000742"
privacyDeleteRequestID = "90000000-0000-0000-0000-000000000743"
privacyDeleteRequestPublicID = "90000000-0000-0000-0000-000000000744"
)
type privacyDeleteStore struct {
removed []string
}
func (s *privacyDeleteStore) Remove(_ context.Context, reference string) error {
s.removed = append(s.removed, reference)
return nil
}
func TestDeleteProcessorReconcilesAllSubsystemsAndCreatesTombstone(t *testing.T) {
databaseURL := os.Getenv("TEST_DATABASE_URL")
redisAddress := os.Getenv("TEST_REDIS_ADDR")
if databaseURL == "" || redisAddress == "" {
t.Skip("TEST_DATABASE_URL and TEST_REDIS_ADDR are required")
}
ctx := context.Background()
pool, err := database.Open(ctx, databaseURL, "privacy-delete-test")
if err != nil {
t.Fatal(err)
}
defer pool.Close()
cleanupPrivacyDeleteFixture(t, ctx, pool)
defer cleanupPrivacyDeleteFixture(t, context.Background(), pool)
if _, err := pool.Exec(ctx, `INSERT INTO subject_profile (
id,public_id,tenant_id,household_id,preferred_name,status
) VALUES (
$1::uuid,$2::uuid,'10000000-0000-0000-0000-000000000001',
'10000000-0000-0000-0000-000000000201','隐私删除集成长者','active'
)`, privacyDeleteSubjectID, privacyDeleteSubjectPublicID); err != nil {
t.Fatal(err)
}
if _, err := pool.Exec(ctx, `INSERT INTO privacy_request (
id,public_id,tenant_id,subject_id,request_type,scope,requested_by,idempotency_key,request_digest
) VALUES (
$1::uuid,$2::uuid,'10000000-0000-0000-0000-000000000001',$3::uuid,
'DELETE','{"reason_code":"subject_request"}'::jsonb,
'10000000-0000-0000-0000-000000000101','privacy-delete-integration',repeat('9',64)
)`, privacyDeleteRequestID, privacyDeleteRequestPublicID, privacyDeleteSubjectID); err != nil {
t.Fatal(err)
}
if _, err := pool.Exec(ctx, `INSERT INTO export_task (
id,public_id,tenant_id,subject_id,requested_by,scope,status,object_ref,object_size,content_digest,
expires_at,completed_at,idempotency_key,request_digest
) VALUES (
'90000000-0000-0000-0000-000000000745','90000000-0000-0000-0000-000000000746',
'10000000-0000-0000-0000-000000000001',$1::uuid,'10000000-0000-0000-0000-000000000101',
'{}'::jsonb,'READY','privacy-delete/export.zip',128,repeat('a',64),now()+interval '1 hour',now(),
'privacy-delete-export-integration',repeat('b',64)
)`, privacyDeleteSubjectID); err != nil {
t.Fatal(err)
}
if _, err := pool.Exec(ctx, `INSERT INTO privacy_subtask (
public_id,privacy_request_id,subsystem,target_type,target_ref
) SELECT gen_random_uuid(),$1::uuid,subsystem,'subject_data',subsystem
FROM unnest(ARRAY['redis','export_files','object_storage','pgvector','provider_index','postgresql']) AS subsystem`, privacyDeleteRequestID); err != nil {
t.Fatal(err)
}
redisClient := cache.Open(redisAddress, "", 0)
defer redisClient.Close()
store := &privacyDeleteStore{}
processor, err := NewDeleteProcessor(pool, redisClient, store)
if err != nil {
t.Fatal(err)
}
if err := processor.Handle(ctx, outbox.Event{AggregateID: privacyDeleteRequestID}); err != nil {
t.Fatal(err)
}
var requestStatus, subjectStatus, preferredName string
var completed, skipped, tombstones, audits int
if err := pool.QueryRow(ctx, `SELECT status FROM privacy_request WHERE id=$1::uuid`, privacyDeleteRequestID).Scan(&requestStatus); err != nil {
t.Fatal(err)
}
if err := pool.QueryRow(ctx, `SELECT status,preferred_name FROM subject_profile WHERE id=$1::uuid`, privacyDeleteSubjectID).Scan(&subjectStatus, &preferredName); err != nil {
t.Fatal(err)
}
if err := pool.QueryRow(ctx, `SELECT count(*) FILTER(WHERE status='COMPLETED'),count(*) FILTER(WHERE status='SKIPPED') FROM privacy_subtask WHERE privacy_request_id=$1::uuid`, privacyDeleteRequestID).Scan(&completed, &skipped); err != nil {
t.Fatal(err)
}
if err := pool.QueryRow(ctx, `SELECT count(*) FROM tombstone WHERE deletion_request_id=$1::uuid`, privacyDeleteRequestID).Scan(&tombstones); err != nil {
t.Fatal(err)
}
if err := pool.QueryRow(ctx, `SELECT count(*) FROM audit_event WHERE action='privacy.delete.complete' AND resource_id=$1::uuid`, privacyDeleteRequestPublicID).Scan(&audits); err != nil {
t.Fatal(err)
}
var exportStatus string
var exportReference *string
if err := pool.QueryRow(ctx, `SELECT status,object_ref FROM export_task WHERE id='90000000-0000-0000-0000-000000000745'::uuid`).Scan(&exportStatus, &exportReference); err != nil {
t.Fatal(err)
}
if requestStatus != "COMPLETED" || subjectStatus != "deleted" || preferredName != "[已删除]" || completed != 5 || skipped != 1 || tombstones != 1 || audits != 1 || len(store.removed) != 1 || store.removed[0] != "privacy-delete/export.zip" || exportStatus != "EXPIRED" || exportReference != nil {
t.Fatalf("request=%s subject=%s name=%q completed=%d skipped=%d tombstones=%d audits=%d removed=%v", requestStatus, subjectStatus, preferredName, completed, skipped, tombstones, audits, store.removed)
}
if err := processor.Handle(ctx, outbox.Event{AggregateID: privacyDeleteRequestID}); err != nil {
t.Fatal(err)
}
if err := processor.Handle(ctx, outbox.Event{AggregateID: "90000000-0000-0000-0000-000000000799"}); err != nil {
t.Fatalf("missing deletion request error=%v", err)
}
}
func cleanupPrivacyDeleteFixture(t *testing.T, ctx context.Context, pool *pgxpool.Pool) {
t.Helper()
statements := []string{
`DELETE FROM tombstone WHERE deletion_request_id='90000000-0000-0000-0000-000000000743'::uuid`,
`DELETE FROM audit_event WHERE action='privacy.delete.complete' AND resource_id='90000000-0000-0000-0000-000000000744'::uuid`,
`DELETE FROM privacy_request WHERE id='90000000-0000-0000-0000-000000000743'::uuid`,
`DELETE FROM export_task WHERE id='90000000-0000-0000-0000-000000000745'::uuid`,
`DELETE FROM subject_profile WHERE id='90000000-0000-0000-0000-000000000741'::uuid`,
}
for _, statement := range statements {
if _, err := pool.Exec(ctx, statement); err != nil {
t.Fatalf("cleanup privacy delete fixture: %v", err)
}
}
}