Files
knowledge-governance/internal/platform/postgres/library_dispatch_test.go
T
姚章浩 8febe12d7d test(library): 隔离数据契约与 r11 身份自然键矩阵
真实本机 PG/ES/MinIO:v071 目录镜像 10 模式、结构引用/游标 15 模式、
8 表×2 外部范围身份矩阵、13 模式自然键(含软删除与合法同 parent 正例)、
备份期间三注入、收尾故障与授权撤销两个真实治理 PG 用例。

需隔离服务的用例在 test-scope.json 显式声明:普通 CI 跳过不算通过。
2026-11-01 11:35:09 +08:00

40 lines
1.8 KiB
Go

package postgres
import (
"context"
"knowledge-governance/internal/governance"
"testing"
"time"
)
func TestContractDispatchAttachFailureLeavesNoQueueOrBusinessJob(t *testing.T) {
store, pool := newIdentityStore(t)
ctx := context.Background()
now := time.Now().UTC()
if _, err := pool.Exec(ctx, `CREATE FUNCTION fail_dispatch_attach() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN IF NEW.queue_job_id <> '' THEN RAISE EXCEPTION 'injected attach failure'; END IF; RETURN NEW; END $$; CREATE TRIGGER fail_attach BEFORE UPDATE ON library_jobs FOR EACH ROW EXECUTE FUNCTION fail_dispatch_attach()`); err != nil {
t.Fatal(err)
}
job := governance.LibraryJob{ID: "atomic-dispatch", Scope: "internal", Kind: governance.LibraryJobSync, RequestDigest: "request", IdempotencyKey: "intent-atomic", TargetSnapshotID: "snapshot"}
if _, _, err := store.CreateLibraryDispatch(ctx, job, governance.SyncStages(), false, now); err == nil {
t.Fatal("injected attach did not fail")
}
var business, queue int
if err := pool.QueryRow(ctx, `SELECT (SELECT count(*) FROM library_jobs),(SELECT count(*) FROM jobs)`).Scan(&business, &queue); err != nil {
t.Fatal(err)
}
if business != 0 || queue != 0 {
t.Fatalf("partial dispatch escaped transaction: business=%d queue=%d", business, queue)
}
if _, err := pool.Exec(ctx, `DROP TRIGGER fail_attach ON library_jobs`); err != nil {
t.Fatal(err)
}
first, reused, err := store.CreateLibraryDispatch(ctx, job, governance.SyncStages(), false, now)
if err != nil || reused || first.QueueJobID == "" {
t.Fatalf("dispatch after failure: %+v %v %v", first, reused, err)
}
replay, reused, err := store.CreateLibraryDispatch(ctx, job, governance.SyncStages(), false, now)
if err != nil || !reused || replay.QueueJobID != first.QueueJobID {
t.Fatalf("dispatch replay: %+v %v %v", replay, reused, err)
}
}