d0a45d563f
界面验收第三遍(禁止导入 → 需下架)暴露两处真问题: 1) 需下架车道死掉:判据 `retrieval_state='enabled'`,而 retrieval_state 在这套状态机里 描述「是否发布到生产」(unpublished/disabling/disabled/failed),全仓没有任何代码写过 'enabled',线上 5/5 发布单元都是 unpublished → 车道恒 0,界面「仍在知识库里的文件会 出现在这里」的承诺不成立。改为与设计注释一致的口径:仍在测试库存活(completed + 有 knowledge_id + 未 disabling/disabled)+ 来源项 policy_state='blocked'。 线上对照:旧判据 0 → 新判据 1,命中被禁止导入的 DH-AG95夹爪适配-指令协议.md; 修后页面显示「需下架(1)· 对内知识库 · 1 份仍在检索中」。新增集成测试覆盖 存活/未禁止/移除中/已移除/未上传五种情形(真实 Postgres + 独立 schema)。 2) 集成测试改到线上设置(直接踩到并已恢复):ui_settings_integration_test.go 只判断 TEST_DATABASE_URL 是否存在、无 schema 隔离,而它「创建候选并激活」——跑在共享库上会把 真实 active 设置挤成 retired。已先备份(backups/ui-settings/…pre-restore.jsonl),再用 单事务(先 retire 再 activate,uq_ui_setting_active 只允许一条 active)恢复 uis-d40ea1fc…(15/30/1800/7200 + https://weknora-test.dobot.cn/),并复核线上值。 根因修复:给该用例加 per-test schema 隔离,复跑后线上设置不再被改动。 同时把两处与事实不符的文案改实话(WeKnoraMonitor.tsx 需下架说明、SourceCatalogBrowser.tsx 禁止导入说明):移除走 test.remove 工作流(删除测试库知识条目,可再入库),入口当前由 变更集删除路径触发,页面尚无独立按钮——条目级列表与下架按钮列为待排期。
91 lines
4.1 KiB
Go
91 lines
4.1 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
|
|
"knowledge-governance/internal/platform/postgres"
|
|
)
|
|
|
|
// TestRealOverviewRemovalDemandCountsLiveBlockedPublications freezes the
|
|
// 需下架 lane definition after the 2026-10-10 UI acceptance run proved it dead:
|
|
// the SQL asked for `retrieval_state='enabled'`, a value this state machine
|
|
// never writes (retrieval_state describes production publication:
|
|
// unpublished/disabling/disabled/failed), so "把已入库的文件改成禁止导入后
|
|
// 车道仍显示 0" — the page promise in SourceCatalogBrowser ("仍在知识库里的文件
|
|
// 会出现在解析监控 → 需下架") did not hold.
|
|
//
|
|
// The lane must count knowledge that is still alive in the test/authoring KB
|
|
// (completed + real knowledge id + not already flagged/removed) whose source
|
|
// item has been marked 禁止导入, and must drop each row as soon as removal is
|
|
// under way ('disabling') or done ('disabled').
|
|
func TestRealOverviewRemovalDemandCountsLiveBlockedPublications(t *testing.T) {
|
|
ctx := context.Background()
|
|
pool, err := pgxpool.New(ctx, isolatedMetricsURL(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer pool.Close()
|
|
if err := postgres.ApplyMigrations(ctx, pool); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if _, err := pool.Exec(ctx, `INSERT INTO source_connections(id,source_type,name,enabled) VALUES('conn-removal','dingtalk','需下架用例',TRUE)`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
seedItem := func(itemID, stableID, policy string) {
|
|
if _, err := pool.Exec(ctx, `INSERT INTO source_items(id,source_connection_id,stable_external_id,canonical_uri_hash,title,item_type,policy_state)
|
|
VALUES($1,'conn-removal',$2,repeat('a',64),$2,'file',$3)`, itemID, stableID, policy); err != nil {
|
|
t.Fatalf("seed item %s: %v", itemID, err)
|
|
}
|
|
if _, err := pool.Exec(ctx, `INSERT INTO source_item_versions(id,source_item_id,revision,content_state) VALUES($1,$2,'r1','verified')`, "ver-"+itemID, itemID); err != nil {
|
|
t.Fatalf("seed version %s: %v", itemID, err)
|
|
}
|
|
}
|
|
seedPublication := func(publicationID, itemID, knowledgeID, processing, retrieval string) {
|
|
if _, err := pool.Exec(ctx, `INSERT INTO test_publications(id,source_item_version_id,test_kb_id,knowledge_id,ingest_state,processing_state,retrieval_state)
|
|
VALUES($1,$2,'kb-removal',$3,'uploaded',$4,$5)`, publicationID, "ver-"+itemID, knowledgeID, processing, retrieval); err != nil {
|
|
t.Fatalf("seed publication %s: %v", publicationID, err)
|
|
}
|
|
}
|
|
|
|
// Live in the test KB and now marked 禁止导入 → must be exposed.
|
|
seedItem("item-blocked", "blocked.md", "blocked")
|
|
seedPublication("pub-blocked", "item-blocked", "knowledge-blocked", "completed", "unpublished")
|
|
// Same shape but still routed internally → nothing to do.
|
|
seedItem("item-internal", "internal.md", "internal")
|
|
seedPublication("pub-internal", "item-internal", "knowledge-internal", "completed", "unpublished")
|
|
// Removal already running / already done → drop out of the lane.
|
|
seedItem("item-disabling", "disabling.md", "blocked")
|
|
seedPublication("pub-disabling", "item-disabling", "knowledge-disabling", "completed", "disabling")
|
|
seedItem("item-disabled", "disabled.md", "blocked")
|
|
seedPublication("pub-disabled", "item-disabled", "knowledge-disabled", "completed", "disabled")
|
|
// Blocked before it ever reached a KB → nothing live to remove.
|
|
seedItem("item-planned", "planned.md", "blocked")
|
|
seedPublication("pub-planned", "item-planned", "", "planned", "unpublished")
|
|
|
|
provider, err := NewRealProvider(RealProviderConfig{DB: metricsPool{pool: pool}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
overview, err := provider.Overview(ctx)
|
|
if err != nil {
|
|
t.Fatalf("overview: %v", err)
|
|
}
|
|
if len(overview.KnowledgeBases) != 1 {
|
|
t.Fatalf("expected one knowledge base row, got %#v", overview.KnowledgeBases)
|
|
}
|
|
progress := overview.KnowledgeBases[0]
|
|
if progress.NeedsRemoval != 1 {
|
|
t.Fatalf("needs_removal=%d, want 1 (live + blocked only)", progress.NeedsRemoval)
|
|
}
|
|
if progress.StalePlanned != 1 {
|
|
t.Fatalf("stale_planned=%d, want 1 (blocked before upload)", progress.StalePlanned)
|
|
}
|
|
if progress.Completed != 4 {
|
|
t.Fatalf("completed=%d, want 4", progress.Completed)
|
|
}
|
|
}
|