package librarystack import ( "knowledge-governance/internal/appconfig" "knowledge-governance/internal/objectgateway" "testing" ) // DS01-F1:正式装配必须把 scope/instance/真实 attempt 身份传到 adapter;快照绑定 // 不再来自这里(来源/写前镜像只从原 WriteSet 与 backup 引用取得)。 func TestRestoreDispatchWiringUsesRealClaim(t *testing.T) { config := appconfig.Config{ LibraryTargetInstance: "inst-prod", LibraryProductionDatabaseURL: "postgres://user:pass@127.0.0.1:5432/kg_prod?sslmode=disable", LibraryProductionInternalKB: "kb-internal", LibraryProductionExternalKB: "kb-external", } claim := objectgateway.Claim{ JobID: "job-window", OperationID: "op-original", Owner: "worker-1#queue#job-window", AttemptEpoch: 3, RecoveryJobID: "queue-recovery", RecoveryOperationID: "op-recovery", } wiring, err := RestoreDispatchWiringFor(config, "internal", claim) if err != nil { t.Fatalf("real wiring: %v", err) } if wiring.Scope != "internal" || wiring.Instance != "inst-prod" { t.Fatalf("scope/instance = %q/%q", wiring.Scope, wiring.Instance) } if wiring.TargetIdentity == "" || wiring.TargetIdentity == "unconfigured" { t.Fatalf("target identity = %q", wiring.TargetIdentity) } if wiring.OperationID != claim.OperationID || wiring.WindowJobID != claim.JobID || wiring.AttemptOwner != claim.Owner || wiring.AttemptEpoch != claim.AttemptEpoch { t.Fatalf("attempt identity not propagated: %+v", wiring) } if wiring.RecoveryJobID != claim.RecoveryJobID || wiring.RecoveryOperationID != claim.RecoveryOperationID { t.Fatalf("recovery delivery identity not propagated: %+v", wiring) } // 自动回滚(非恢复 worker)没有 recovery 投递身份,必须保持为空。 rollback, err := RestoreDispatchWiringFor(config, "internal", objectgateway.Claim{ JobID: "job-window", OperationID: "op-original", Owner: "worker-1#queue#job-window", AttemptEpoch: 3}) if err != nil { t.Fatal(err) } if rollback.RecoveryJobID != "" || rollback.RecoveryOperationID != "" { t.Fatalf("rollback wiring invented a recovery identity: %+v", rollback) } } func TestRestoreDispatchWiringFailsClosed(t *testing.T) { config := appconfig.Config{ LibraryTargetInstance: "inst-prod", LibraryProductionDatabaseURL: "postgres://user:pass@127.0.0.1:5432/kg_prod?sslmode=disable", LibraryProductionInternalKB: "kb-internal", } if _, err := RestoreDispatchWiringFor(config, "internal", objectgateway.Claim{}); err == nil { t.Fatal("missing attempt identity was accepted") } if _, err := RestoreDispatchWiringFor(config, "tenant-wide", objectgateway.Claim{ JobID: "j", OperationID: "o", Owner: "w", AttemptEpoch: 1}); err == nil { t.Fatal("unknown scope was accepted") } if _, err := RestoreDispatchWiringFor(config, "external", objectgateway.Claim{ JobID: "j", OperationID: "o", Owner: "w", AttemptEpoch: 1}); err == nil { t.Fatal("external scope without its knowledge base was accepted") } if _, err := RestoreDispatchWiringFor(config, "internal", objectgateway.Claim{ JobID: "j", OperationID: "o", Owner: "w", AttemptEpoch: 1, RecoveryJobID: "q"}); err == nil { t.Fatal("partial recovery delivery identity was accepted") } unconfigured := config unconfigured.LibraryProductionDatabaseURL = "" if _, err := RestoreDispatchWiringFor(unconfigured, "internal", objectgateway.Claim{ JobID: "j", OperationID: "o", Owner: "w", AttemptEpoch: 1}); err == nil { t.Fatal("unconfigured target database was accepted as a dispatch target") } } func TestObjectAddressingMatchesProvider(t *testing.T) { for _, provider := range []string{"oss", "s3", "minio"} { t.Run(provider, func(t *testing.T) { config := appconfig.Config{LibraryProductionDatabaseURL: "configured", LibraryProductionElasticURL: "configured", LibraryProductionTenantID: 1, LibraryProductionInternalKB: "kb-target", LibraryProductionS3Endpoint: "https://storage.example", LibraryProductionS3Bucket: "test-bucket", LibraryProductionS3AccessKey: "fixture", LibraryProductionS3SecretKey: "fixture", LibraryProductionS3Provider: provider} scope, err := scopeConfigOf(config, "internal") if err != nil { t.Fatal(err) } if scope.s3.ForcePathStyle != (provider == "minio") { t.Fatalf("provider %s: ForcePathStyle=%v", provider, scope.s3.ForcePathStyle) } }) } }