dcdc8d1ddd
全栈知识治理平台首次入库(P1-P10 + 发布链路模拟验证闭环): - 治理核心:源目录/变更集/人工审核/发布批次/发布执行(fail-closed 闸口) - 测试通道:WeKnora 测试 KB 上传/轮询/验收;poll 完成时写入 parser_generation/index_generation,修复 manual/seed 路径发布闸口永久拦截 - 发布适配器 v071(本地 source=测试角色 / 云端 target=生产角色 模拟验证通过): * ES 导出/导入 mapping 自适应(.keyword 子字段、可选 tenant_id) * OSS locator 支持嵌套 scheme;chunks.seq_id 由目标序列分配 * bundle 归档同身份重试原子替换;verifier 按 bundle chunk_type 计数 * 回滚 job payload 支持 prior_execution_id(strict 解码) - 三通道发布+回滚演练实测:publish 4/4 verified,检索命中, rollback 4/4 rolled_back,目标端 PG is_enabled=false、ES is_enabled=false - 前端 A·Data-console 风格全站统一,120 用例通过 - 门禁:go vet / go test 全包通过,gofmt 干净
119 lines
4.3 KiB
Go
119 lines
4.3 KiB
Go
package testweknora
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"knowledge-governance/internal/governance"
|
|
"knowledge-governance/internal/jobs"
|
|
postgresstore "knowledge-governance/internal/platform/postgres"
|
|
"knowledge-governance/internal/platform/weknora"
|
|
)
|
|
|
|
func TestValidateHandlerAppendsDeterministicChecksAndManualRetrieval(t *testing.T) {
|
|
client := &validateClientStub{
|
|
knowledge: weknora.Knowledge{ID: "knowledge-1", KnowledgeBaseID: "kb-1"},
|
|
chunkTotal: 3,
|
|
}
|
|
store := &validateStoreStub{publication: postgresstore.PublicationForValidation{
|
|
ID: "publication-1", TestKBID: "kb-1", KnowledgeID: "knowledge-1",
|
|
}}
|
|
now := time.Date(2026, time.September, 4, 4, 10, 0, 0, time.UTC)
|
|
handler, err := NewValidateHandler(ValidateHandlerConfig{
|
|
Store: store, Client: client, RunID: "run-1", PolicyVersion: "structural-v1",
|
|
Now: func() time.Time { return now },
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := handler.Handle(context.Background(), jobs.Job{Payload: []byte(`{"publication_id":"publication-1"}`)}); err != nil {
|
|
t.Fatalf("Handle() error = %v", err)
|
|
}
|
|
if len(store.appended) != 3 {
|
|
t.Fatalf("appended = %d, want 3: %#v", len(store.appended), store.appended)
|
|
}
|
|
byType := map[string]governance.AcceptanceResult{}
|
|
for _, result := range store.appended {
|
|
byType[result.CheckType] = result
|
|
}
|
|
if byType["knowledge_exists"].State != governance.AcceptancePassed {
|
|
t.Fatalf("knowledge_exists = %#v", byType["knowledge_exists"])
|
|
}
|
|
if byType["chunks_present"].State != governance.AcceptancePassed {
|
|
t.Fatalf("chunks_present = %#v", byType["chunks_present"])
|
|
}
|
|
if byType["retrieval_hit"].State != governance.AcceptanceManualRequired {
|
|
t.Fatalf("retrieval_hit = %#v", byType["retrieval_hit"])
|
|
}
|
|
for _, result := range store.appended {
|
|
if result.PublicationID != "publication-1" || result.RunID != "run-1" || result.ObservedAt != now {
|
|
t.Fatalf("acceptance metadata = %#v", result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidateHandlerFailsChecksWithoutAborting(t *testing.T) {
|
|
client := &validateClientStub{
|
|
knowledge: weknora.Knowledge{ID: "knowledge-mismatch", KnowledgeBaseID: "kb-other"},
|
|
chunkTotal: 0,
|
|
}
|
|
store := &validateStoreStub{publication: postgresstore.PublicationForValidation{
|
|
ID: "publication-1", TestKBID: "kb-1", KnowledgeID: "knowledge-1",
|
|
}}
|
|
handler, err := NewValidateHandler(ValidateHandlerConfig{
|
|
Store: store, Client: client, RunID: "run-2", PolicyVersion: "structural-v1",
|
|
Now: func() time.Time { return time.Date(2026, time.September, 4, 4, 11, 0, 0, time.UTC) },
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := handler.Handle(context.Background(), jobs.Job{Payload: []byte(`{"publication_id":"publication-1"}`)}); err != nil {
|
|
t.Fatalf("Handle() error = %v", err)
|
|
}
|
|
if len(store.appended) != 3 {
|
|
t.Fatalf("appended = %d, want 3", len(store.appended))
|
|
}
|
|
byType := map[string]governance.AcceptanceResult{}
|
|
for _, result := range store.appended {
|
|
byType[result.CheckType] = result
|
|
}
|
|
if byType["knowledge_exists"].State != governance.AcceptanceFailed || byType["chunks_present"].State != governance.AcceptanceFailed {
|
|
t.Fatalf("failed checks = %#v", store.appended)
|
|
}
|
|
if byType["retrieval_hit"].State != governance.AcceptanceManualRequired {
|
|
t.Fatalf("retrieval still manual = %#v", byType["retrieval_hit"])
|
|
}
|
|
}
|
|
|
|
type validateStoreStub struct {
|
|
publication postgresstore.PublicationForValidation
|
|
appended []governance.AcceptanceResult
|
|
}
|
|
|
|
func (store *validateStoreStub) LoadPublicationForValidation(context.Context, string) (postgresstore.PublicationForValidation, error) {
|
|
return store.publication, nil
|
|
}
|
|
|
|
func (store *validateStoreStub) AppendAcceptanceResult(_ context.Context, result governance.AcceptanceResult) error {
|
|
store.appended = append(store.appended, result)
|
|
return nil
|
|
}
|
|
|
|
type validateClientStub struct {
|
|
knowledge weknora.Knowledge
|
|
chunkTotal int64
|
|
}
|
|
|
|
func (client *validateClientStub) GetKnowledge(context.Context, string) (weknora.Knowledge, error) {
|
|
return client.knowledge, nil
|
|
}
|
|
|
|
func (client *validateClientStub) ListChunks(context.Context, string, int, int, []string) ([]weknora.Chunk, int64, error) {
|
|
chunks := make([]weknora.Chunk, 0, client.chunkTotal)
|
|
for i := int64(0); i < client.chunkTotal; i++ {
|
|
chunks = append(chunks, weknora.Chunk{ID: "chunk", KnowledgeID: "knowledge-1"})
|
|
}
|
|
return chunks, client.chunkTotal, nil
|
|
}
|