Files
knowledge-governance/cmd/test-weknora-probe/main.go
T
zheromiku dcdc8d1ddd feat: 知识治理平台(含已验证发布/回滚契约)
全栈知识治理平台首次入库(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 干净
2026-09-30 10:54:06 +08:00

131 lines
4.1 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"io"
"log"
"net/url"
"os"
"path/filepath"
"strings"
"time"
"github.com/jackc/pgx/v5/pgxpool"
postgresstore "knowledge-governance/internal/platform/postgres"
"knowledge-governance/internal/platform/weknora"
"knowledge-governance/internal/workflows/testweknora"
)
type probeConfig struct {
DatabaseURL string
Concurrency int
Online bool
BaseURL string
APIKeyFile string
ChunkSampleEvery int
}
func main() {
if err := run(context.Background(), os.Args[1:], os.Getenv, os.Stdout); err != nil {
log.Fatal(err)
}
}
func run(ctx context.Context, args []string, getenv func(string) string, stdout io.Writer) error {
config, err := parseProbeConfig(args, getenv)
if err != nil {
return err
}
pool, err := pgxpool.New(ctx, config.DatabaseURL)
if err != nil {
return fmt.Errorf("open database: %w", err)
}
defer pool.Close()
if err := pool.Ping(ctx); err != nil {
return fmt.Errorf("ping database: %w", err)
}
store := postgresstore.NewStore(pool)
legacy, err := store.ListLegacyVerificationCandidates(ctx)
if err != nil {
return err
}
candidates := make([]testweknora.LegacyCandidate, 0, len(legacy))
for _, candidate := range legacy {
candidates = append(candidates, testweknora.LegacyCandidate{
ID: candidate.ID, TestKBID: candidate.TestKBID, KnowledgeID: candidate.KnowledgeID,
})
}
if !config.Online {
_, _ = io.WriteString(stdout, testweknora.FormatDryRunReport(candidates, config.Concurrency))
return nil
}
apiKey, err := weknora.ReadAPIKeyFile(config.APIKeyFile)
if err != nil {
return fmt.Errorf("read test WeKnora API key: %w", err)
}
client, err := weknora.NewClient(weknora.ClientConfig{
BaseURL: config.BaseURL,
APIKey: apiKey,
Timeout: 30 * time.Second,
})
if err != nil {
return fmt.Errorf("create test WeKnora client: %w", err)
}
report, err := testweknora.VerifyLegacyConcurrent(ctx, client, candidates, config.ChunkSampleEvery, config.Concurrency)
if err != nil {
return fmt.Errorf("verify historical test publications: %w", err)
}
_, _ = io.WriteString(stdout, testweknora.FormatLegacyVerificationReport(report))
return nil
}
func parseProbeConfig(args []string, getenv func(string) string) (probeConfig, error) {
flags := flag.NewFlagSet("test-weknora-probe", flag.ContinueOnError)
flags.SetOutput(io.Discard)
databaseURL := flags.String("database-url", "", "PostgreSQL connection URL (or DATABASE_URL)")
concurrency := flags.Int("concurrency", 4, "planned read-only verify concurrency for the online phase")
online := flags.Bool("online", false, "run authenticated read-only verification")
baseURL := flags.String("base-url", "", "HTTPS WeKnora base URL")
apiKeyFile := flags.String("api-key-file", "", "mode-0600 WeKnora API key file")
chunkSampleEvery := flags.Int("chunk-sample-every", 25, "check one completed Knowledge chunk count every N items; 0 disables")
if err := flags.Parse(args); err != nil {
return probeConfig{}, fmt.Errorf("parse arguments: %w", err)
}
if *databaseURL == "" {
*databaseURL = getenv("DATABASE_URL")
}
if *databaseURL == "" {
return probeConfig{}, fmt.Errorf("-database-url or DATABASE_URL is required")
}
if *concurrency < 1 || *concurrency > 16 || *chunkSampleEvery < 0 {
return probeConfig{}, fmt.Errorf("concurrency must be 1..16 and chunk-sample-every must be non-negative")
}
if *baseURL == "" {
*baseURL = getenv("TEST_WEKNORA_BASE_URL")
}
if *apiKeyFile == "" {
*apiKeyFile = getenv("TEST_WEKNORA_API_KEY_FILE")
}
if *online {
parsed, err := url.Parse(strings.TrimSpace(*baseURL))
if err != nil || parsed.Scheme != "https" || parsed.Host == "" || parsed.User != nil {
return probeConfig{}, fmt.Errorf("online verification requires an HTTPS base-url")
}
if !filepath.IsAbs(*apiKeyFile) {
return probeConfig{}, fmt.Errorf("online verification requires an absolute api-key-file")
}
}
return probeConfig{
DatabaseURL: *databaseURL,
Concurrency: *concurrency,
Online: *online,
BaseURL: strings.TrimRight(strings.TrimSpace(*baseURL), "/"),
APIKeyFile: *apiKeyFile,
ChunkSampleEvery: *chunkSampleEvery,
}, nil
}