Files
knowledge-governance/internal/httpapi/library_flow_test.go
T
姚章浩 98294b9583
build / build (push) Failing after 24s
fix(library): 统一执行身份、终态收尾、准入与数据身份
why:审计 19 项(12 P1 / 7 P2)来自同一批根因,逐点试错会把协议撕成十几份:
  · 意图与执行混为一谈(F01/F15):`library.sync:<scope>:<快照>` 是终身幂等键,
    A→B→A 的第三次发布拿到第一次的历史成功作业,什么都不做;
  · 版本行既是实体又是事件(F02/F09):主键只由 (kind,scope,快照) 决定、写入是
    upsert,第二个作业覆盖 `source_job_id`/`evidence`/`created_at`;
  · 接管没有代次(F13):两个 worker 都能认领同一 pending 作业,失租的旧执行还能
    写业务状态、释放别人的维护锁;
  · 早退与终态没有统一政策(F03/F04/F05/F06):半写窗口的前置检查失败会重新开门、
    服务起不来也照样开入口、journal 终态后收尾不可重建、恢复成功不回写 current;
  · 数据身份与准入各写一套(F07/F08/F14/F17):接管丢了复用语义、全库搬运不改
    location_hash、通用入口可造 library.* 作业、目标模型从没被问过;
  · 存储/容量/UI/CI 判据各自为政(F10/F11/F12/F16/F18/F19)。

what:按批准的一套协议集中实施(详见 handoffs/release-consolidated-implementation/
current-contract.md):
  · operation(一次明确意图)/ attempt(epoch 代次)/ 不可变版本事件 / current 指针;
    治理库迁移 76,只动治理库,不碰 WeKnora Schema/源码/镜像;
  · 所有业务状态、阶段、版本事件、维护锁写入带 epoch 守卫(失租代次写不进去);
    心跳失租立刻取消 handler;
  · 半写窗口早退保持关闭;服务未全部健康绝不开入口;journal 终态可从持久事实重建
    收尾;恢复成功登记 recovery 事件并推进 current;
  · worker 在动维护前核对业务行/kind/scope/队列关联;通用入口拒绝 library.*;
  · 全库搬运重算 location_hash 并与文档级导入共用实现;接管消费写集合的复用决定;
    发布前核目标实时模型契约、容量门禁前置;
  · 存储保护闭包改为全量依赖、类型只认显式登记、保护未知则不出可删候选;
  · 页面核 HTTP 状态与结构、恢复纳入轮询、Wiki 差异覆盖标题/摘要/父级。

how:`make verify` rc=0(16 项必需检查全绿,含 go test 全量与前端 485 例);
`go vet ./...` rc=0;`npx tsc -p tsconfig.json --noEmit` rc=0;逐项负例见各包测试
(F03/F04/F08/F12/F13/F14/F16/F18/F19 都有先红后绿记录)。
未执行:治理库迁移到任何已有库、真实 PG/ES/S3/WeKnora 集成、故障注入、部署。
2026-10-30 16:14:54 +08:00

528 lines
23 KiB
Go

package httpapi
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"knowledge-governance/internal/governance"
)
// 生产闸口与整库状态契约的针对性测试:不做数据库集成,只验证
// "证据不齐就不建作业" 与 "三类版本不互相顶替" 这两条硬规则。
// 复用既有 fakeJobStore 提供 Store 的其余方法,只覆盖整库作业这几个。
type fakeLibraryStore struct {
fakeJobStore
grant *governance.LibraryReleaseAuthorization
versions []governance.LibraryVersion
jobs []governance.LibraryJob
createN int
lastJob governance.LibraryJob
lastState governance.LibraryJobState
// current 让用例表达"窗口列表里看不到、但精确查询能查到当前生效版本"这一现场形状;
// currentErr 表达"读不到"(调用方必须 fail closed,不许当成没有生效版本)。
current *governance.LibraryVersion
currentErr error
// operations/lastOperation 记录"意图身份":重放与换键的差别在这里表达(F01)。
operations map[string]governance.LibraryOperation
lastOperation governance.LibraryOperation
}
func (f *fakeLibraryStore) CreateLibraryJob(_ context.Context, job governance.LibraryJob, _ []string, _ time.Time) (governance.LibraryJob, bool, error) {
f.createN++
f.lastJob = job
return job, false, nil
}
// EnsureLibraryOperation 在 fake 里就是"同键同摘要 ⇒ 同一条意图":测试用例靠它表达
// "重放命中同意图 / 换键是新意图"(F01),不需要真实库。
func (f *fakeLibraryStore) EnsureLibraryOperation(_ context.Context, op governance.LibraryOperation) (governance.LibraryOperation, bool, error) {
if f.operations == nil {
f.operations = map[string]governance.LibraryOperation{}
}
if existing, ok := f.operations[op.OperationKey]; ok {
if existing.RequestDigest != op.RequestDigest {
return existing, false, governance.ErrLibraryOperationConflict
}
return existing, false, nil
}
f.operations[op.OperationKey] = op
f.lastOperation = op
return op, true, nil
}
func (f *fakeLibraryStore) LibraryJob(_ context.Context, id string) (governance.LibraryJob, error) {
return governance.LibraryJob{ID: id}, nil
}
func (f *fakeLibraryStore) ListLibraryJobs(_ context.Context, scope string, _ int) ([]governance.LibraryJob, error) {
result := make([]governance.LibraryJob, 0, len(f.jobs))
for _, job := range f.jobs {
if job.Scope == scope {
result = append(result, job)
}
}
return result, nil
}
func (f *fakeLibraryStore) RecordLibraryVersion(_ context.Context, version governance.LibraryVersion) error {
f.versions = append(f.versions, version)
return nil
}
func (f *fakeLibraryStore) LibraryVersions(_ context.Context, scope string, _ int) ([]governance.LibraryVersion, error) {
result := make([]governance.LibraryVersion, 0, len(f.versions))
for _, version := range f.versions {
if version.Scope == scope {
result = append(result, version)
}
}
return result, nil
}
// 当前生效版本是精确查询:这里刻意只按 (scope, kind, 未顶替) 过滤,不模拟分页窗口,
// 与真实 Store 的契约一致(窗口只用于展示列表)。
func (f *fakeLibraryStore) LibraryCurrentVersion(_ context.Context, scope string) (governance.LibraryVersion, bool, error) {
if f.currentErr != nil {
return governance.LibraryVersion{}, false, f.currentErr
}
if f.current != nil {
return *f.current, true, nil
}
for _, version := range f.versions {
if version.Scope == scope && version.Kind == governance.LibraryVersionProductionEffective && version.SupersededAt == nil {
return version, true, nil
}
}
return governance.LibraryVersion{}, false, nil
}
func (f *fakeLibraryStore) LibraryVersionOfSnapshot(_ context.Context, scope string, kind governance.LibraryVersionKind,
snapshotID string) (governance.LibraryVersion, bool, error) {
for _, version := range f.versions {
if version.Scope == scope && version.Kind == kind && version.SnapshotID == snapshotID {
return version, true, nil
}
}
return governance.LibraryVersion{}, false, nil
}
func (f *fakeLibraryStore) UpdateLibraryStage(_ context.Context, _, _, _ string, _, _, _, _ *int64, _ string, _ time.Time) error {
return nil
}
func (f *fakeLibraryStore) AdvanceLibraryJob(_ context.Context, _ string, state governance.LibraryJobState, _, _, _, _, _ string, _ time.Time) error {
f.lastState = state
return nil
}
func (f *fakeLibraryStore) CreateLibraryAuthorization(_ context.Context, item governance.LibraryReleaseAuthorization) error {
f.grant = &item
return nil
}
func (f *fakeLibraryStore) ActiveLibraryAuthorization(_ context.Context, scope, snapshotID, digest string, now time.Time) (governance.LibraryReleaseAuthorization, bool, error) {
if f.grant == nil || f.grant.Scope != scope || f.grant.SnapshotID != snapshotID || f.grant.ParamsDigest != digest {
return governance.LibraryReleaseAuthorization{}, false, nil
}
if !f.grant.ValidAt(now) {
return governance.LibraryReleaseAuthorization{}, false, nil
}
return *f.grant, true, nil
}
func (f *fakeLibraryStore) LibraryAuthorizations(context.Context, string, int) ([]governance.LibraryReleaseAuthorization, error) {
if f.grant == nil {
return nil, nil
}
return []governance.LibraryReleaseAuthorization{*f.grant}, nil
}
func (f *fakeLibraryStore) RevokeLibraryAuthorization(context.Context, string, time.Time) error {
return nil
}
func (f *fakeLibraryStore) AttachLibraryQueueJob(_ context.Context, _, _ string, _ time.Time) error {
return nil
}
func (f *fakeLibraryStore) CancelLibraryJob(_ context.Context, _, _ string, _ time.Time) error {
f.lastState = governance.LibraryJobCancelled
return nil
}
func TestLibrarySyncGateRequiresEveryPieceOfEvidence(t *testing.T) {
known := libraryKnownView{State: "known", Version: &libraryVersionView{ID: "v1"}}
cases := []struct {
name string
config Config
production libraryKnownView
prebackup libraryKnownView
target string
allowed bool
reason string
}{
{
name: "default installation is closed",
config: Config{},
production: libraryKnownView{State: "unknown"},
prebackup: libraryKnownView{State: "unknown"},
target: "snap-1",
allowed: false,
reason: "生产写入闸口关闭",
},
{
name: "flags on but restore evidence missing",
config: Config{ProductionReleaseRequestsEnabled: true,
LibraryProductionDatabaseURL: "postgres://prod.invalid/db", LibraryProductionInternalKB: "kb-int"},
production: known,
prebackup: known,
target: "snap-1",
allowed: false,
reason: "没有已核验的生产恢复演练证据",
},
{
name: "capacity budget missing blocks even when everything else is present",
config: Config{ProductionReleaseRequestsEnabled: true, ProductionBackupRestoreVerified: true,
LibraryProductionDatabaseURL: "postgres://prod.invalid/db", LibraryProductionInternalKB: "kb-int"},
production: known,
prebackup: known,
target: "snap-1",
allowed: false,
reason: "容量预算未设置",
},
{
name: "everything present",
config: Config{ProductionReleaseRequestsEnabled: true, ProductionBackupRestoreVerified: true,
LibraryProductionDatabaseURL: "postgres://prod.invalid/db", LibraryProductionInternalKB: "kb-int", LibraryCapacityBudgetBytes: 1 << 40},
production: known,
prebackup: known,
target: "snap-1",
allowed: true,
},
}
for _, testCase := range cases {
t.Run(testCase.name, func(t *testing.T) {
gate := librarySyncGateWithGrant(testCase.config, testCase.production, testCase.prebackup, testCase.target, true)
if gate.SyncAllowed != testCase.allowed {
t.Fatalf("sync_allowed = %v, want %v (%v)", gate.SyncAllowed, testCase.allowed, gate.Reasons)
}
if testCase.reason != "" {
joined := strings.Join(gate.Reasons, "|")
if !strings.Contains(joined, testCase.reason) {
t.Fatalf("reasons %v missing %q", gate.Reasons, testCase.reason)
}
}
})
}
}
// 闸口关闭时 POST /api/v1/library/syncs 必须直接拒绝,并且**不创建**作业:
// 不能留下一个永远失败的空作业,也不能让按钮看起来接通了。
func TestLibrarySyncEnqueueRefusesWithoutCreatingJob(t *testing.T) {
store := &fakeLibraryStore{}
config := Config{Store: store}
request := httptest.NewRequest(http.MethodPost, "/api/v1/library/syncs",
strings.NewReader(`{"scope":"internal","target_snapshot_id":"snap-1"}`))
recorder := httptest.NewRecorder()
librarySyncEnqueue(recorder, request, config)
if recorder.Code != http.StatusServiceUnavailable {
t.Fatalf("status = %d, want 503", recorder.Code)
}
if store.createN != 0 {
t.Fatalf("created %d jobs while gate is closed", store.createN)
}
var body struct {
Code string `json:"code"`
Reasons []string `json:"reasons"`
}
if err := json.Unmarshal(recorder.Body.Bytes(), &body); err != nil {
t.Fatalf("decode body: %v", err)
}
if body.Code != "library_sync_blocked" || len(body.Reasons) == 0 {
t.Fatalf("unexpected refusal body: %s", recorder.Body.String())
}
}
// 预备份是作业内第一步生成的,不能拿"启动前还没有预备份"当门禁:
// 否则预备份只能由作业生成、作业又要求预备份,永远启动不了。
// 但"上一次预备份失败"必须阻断重试。
func TestLibrarySyncEnqueueDoesNotRequirePrebackupBeforeStart(t *testing.T) {
store := &fakeLibraryStore{}
config := Config{Store: store, ProductionReleaseRequestsEnabled: true, ProductionBackupRestoreVerified: true,
LibraryProductionDatabaseURL: "postgres://prod.invalid/db", LibraryProductionInternalKB: "kb-int",
LibraryCapacityBudgetBytes: 1 << 40}
gate := librarySyncGateWithGrant(config, libraryKnownView{State: "known"}, libraryKnownView{State: "unknown"}, "snap-1", true)
if !gate.SyncAllowed {
t.Fatalf("missing prebackup must not block the start: %v", gate.Reasons)
}
failed := librarySyncGateWithGrant(config, libraryKnownView{State: "known"},
libraryKnownView{State: "failed"}, "snap-1", true)
if failed.SyncAllowed || !strings.Contains(strings.Join(failed.Reasons, "|"), "预备份失败") {
t.Fatalf("failed prebackup must block: %v", failed.Reasons)
}
}
// 首次发布:生产没有生效版本,但目标为空 = 合法空基线。
func TestLibrarySyncGateAllowsFirstPublishOnEmptyBaseline(t *testing.T) {
config := Config{ProductionReleaseRequestsEnabled: true, ProductionBackupRestoreVerified: true,
LibraryProductionDatabaseURL: "postgres://prod.invalid/db", LibraryProductionInternalKB: "kb-int",
LibraryCapacityBudgetBytes: 1 << 40}
empty := libraryKnownView{State: "unknown", EmptyBaseline: true}
if gate := librarySyncGateWithGrant(config, empty, libraryKnownView{State: "unknown"}, "snap-1", true); !gate.SyncAllowed {
t.Fatalf("empty production must be a legal first-publish baseline: %v", gate.Reasons)
}
// 非空但没有权威版本:仍然阻断。
if gate := librarySyncGateWithGrant(config, libraryKnownView{State: "unknown"}, libraryKnownView{State: "unknown"}, "snap-1", true); gate.SyncAllowed {
t.Fatal("unknown non-empty production must block")
}
}
// 上一次预备份失败时必须阻断重试(预备份本身是作业内生成的,不能当启动前门禁)。
func TestLibrarySyncEnqueueRequiresPrebackupForTarget(t *testing.T) {
store := &fakeLibraryStore{versions: []governance.LibraryVersion{{
ID: "ver-prod-1", Scope: "internal", Kind: governance.LibraryVersionProductionEffective,
SnapshotID: "prod-snap", VersionLabel: "prod-2026.10", CreatedAt: time.Now().UTC(),
}, {
ID: "ver-backup-1", Scope: "internal", Kind: governance.LibraryVersionProductionPrebackup,
SnapshotID: "snap-1", CreatedAt: time.Now().UTC(),
}}}
config := Config{Store: store, ProductionReleaseRequestsEnabled: true, ProductionBackupRestoreVerified: true,
LibraryProductionDatabaseURL: "postgres://prod.invalid/db", LibraryProductionInternalKB: "kb-int",
LibraryCapacityBudgetBytes: 1 << 40}
request := httptest.NewRequest(http.MethodPost, "/api/v1/library/syncs",
strings.NewReader(`{"scope":"internal","target_snapshot_id":"snap-1"}`))
recorder := httptest.NewRecorder()
librarySyncEnqueue(recorder, request, config)
// 没有授权仍然 503,但原因里不能再出现"还没有生产预备份"这种死循环门禁。
if recorder.Code != http.StatusServiceUnavailable {
t.Fatalf("status = %d, want 503", recorder.Code)
}
if strings.Contains(recorder.Body.String(), "还没有生产预备份") {
t.Fatalf("start gate must not require a prebackup that only the job can create: %s", recorder.Body.String())
}
}
// 证据齐全 + 有效授权时才会真正建作业并入队;缺授权一律拒绝且不建作业。
func TestLibrarySyncEnqueueCreatesJobOnlyWithGrant(t *testing.T) {
target := "snap-1"
digest, err := librarySyncParamsDigest("internal", target)
if err != nil {
t.Fatal(err)
}
store := &fakeLibraryStore{versions: []governance.LibraryVersion{
{ID: "ver-prod", Scope: "internal", Kind: governance.LibraryVersionProductionEffective,
SnapshotID: "prod-snap", VersionLabel: "prod-2026.10", CreatedAt: time.Now().UTC()},
{ID: "ver-backup", Scope: "internal", Kind: governance.LibraryVersionProductionPrebackup,
SnapshotID: target, CreatedAt: time.Now().UTC()},
}}
store.enqueueEchoRequestedID = true
config := Config{Store: store, ProductionReleaseRequestsEnabled: true, ProductionBackupRestoreVerified: true,
LibraryProductionDatabaseURL: "postgres://prod.invalid/db", LibraryProductionInternalKB: "kb-int", LibraryCapacityBudgetBytes: 1 << 40}
body := `{"scope":"internal","target_snapshot_id":"` + target + `"}`
// 先没有授权
recorder := httptest.NewRecorder()
librarySyncEnqueue(recorder, httptest.NewRequest(http.MethodPost, "/api/v1/library/syncs", strings.NewReader(body)), config)
if recorder.Code != http.StatusServiceUnavailable {
t.Fatalf("without grant status=%d body=%s", recorder.Code, recorder.Body.String())
}
if store.createN != 0 {
t.Fatal("must not create a job without a grant")
}
// 补上绑定同一目标与快照的授权
now := time.Now().UTC()
store.grant = &governance.LibraryReleaseAuthorization{ID: "auth-1", Scope: "internal", SnapshotID: target,
ParamsDigest: digest, AuthorizedBy: "admin", ExpiresAt: now.Add(30 * time.Minute), CreatedAt: now}
recorder = httptest.NewRecorder()
librarySyncEnqueue(recorder, httptest.NewRequest(http.MethodPost, "/api/v1/library/syncs", strings.NewReader(body)), config)
if recorder.Code != http.StatusAccepted {
t.Fatalf("with grant status=%d body=%s", recorder.Code, recorder.Body.String())
}
if store.createN != 1 {
t.Fatalf("created=%d, want 1", store.createN)
}
if store.enqueued.Type != "library.sync" {
t.Fatalf("enqueued type=%q, want library.sync", store.enqueued.Type)
}
if !strings.Contains(string(store.enqueued.Payload), store.lastJob.ID) {
t.Fatalf("queue payload must carry the library job id: %s", store.enqueued.Payload)
}
}
// 真实现场(2026-10-29 16:59 的按版本恢复):恢复作业登记了"恢复前备份",
// 但那份备份的内容就是**恢复前**的生产状态,永远不可能等于测试封存快照。
// 旧逻辑只认"与测试封存同快照的预备份",于是刚备份完就显示"尚未创建/无记录"。
func TestLibraryOverviewShowsLatestPrebackupWhenTargetDiffers(t *testing.T) {
root := libraryFixtureRoot(t)
sealed := sealSharedVersions(t, root, 1, 4)[0]
now := time.Now().UTC()
store := &fakeLibraryStore{versions: []governance.LibraryVersion{
{ID: "ver-effective", Scope: "internal", Kind: governance.LibraryVersionProductionEffective,
SnapshotID: "prod-restored-snapshot", CreatedAt: now},
{ID: "ver-prebackup", Scope: "internal", Kind: governance.LibraryVersionProductionPrebackup,
SnapshotID: "snap-before-restore", SourceJobID: "librestore-internal-1", CreatedAt: now.Add(-time.Second)},
{ID: "ver-sealed", Scope: "internal", Kind: governance.LibraryVersionTestSealed,
SnapshotID: sealed, CreatedAt: now.Add(-2 * time.Hour)},
}}
config := Config{Store: store, LibraryArchiveRoot: root, LibraryCapacityBudgetBytes: 1 << 30}
request := httptest.NewRequest(http.MethodGet, "/api/v1/library/overview?scope=internal", nil)
recorder := httptest.NewRecorder()
libraryOverviewHandler(recorder, request, config)
if recorder.Code != http.StatusOK {
t.Fatalf("status = %d: %s", recorder.Code, recorder.Body.String())
}
var body struct {
Production libraryKnownView `json:"production"`
Prebackup libraryKnownView `json:"prebackup"`
Versions []libraryVersionRef `json:"versions"`
TestSealed *librarySnapshotView `json:"test_sealed"`
Gate struct {
SyncAllowed bool `json:"sync_allowed"`
Reasons []string `json:"reasons"`
} `json:"gate"`
}
if err := json.Unmarshal(recorder.Body.Bytes(), &body); err != nil {
t.Fatalf("decode overview: %v", err)
}
if body.TestSealed == nil || body.TestSealed.SnapshotID != sealed {
t.Fatalf("test sealed candidate must be the registered one: %+v", body.TestSealed)
}
if body.Prebackup.State != "known" || body.Prebackup.Version == nil ||
body.Prebackup.Version.ID != "ver-prebackup" || body.Prebackup.Version.SourceJobID != "librestore-internal-1" {
t.Fatalf("latest registered prebackup must be visible with its job: %+v", body.Prebackup)
}
if body.Prebackup.BoundToTarget {
t.Fatal("a restore prebackup is not the publish target snapshot")
}
// 三类版本都要出现在轻量清单里,页面才能给每份归档写对类型。
if len(body.Versions) != 3 {
t.Fatalf("versions = %+v", body.Versions)
}
for _, reason := range body.Gate.Reasons {
if strings.Contains(reason, "预备份") {
t.Fatalf("a registered prebackup must not be reported as missing: %q", reason)
}
}
}
// 三类版本必须分开读:production_effective 才是生产当前,测试封存不能顶替。
func TestLibraryOverviewKeepsVersionKindsSeparate(t *testing.T) {
now := time.Now().UTC()
store := &fakeLibraryStore{versions: []governance.LibraryVersion{
{ID: "ver-test", Scope: "internal", Kind: governance.LibraryVersionTestSealed, SnapshotID: "snap-1", CreatedAt: now},
{ID: "ver-prod", Scope: "internal", Kind: governance.LibraryVersionProductionEffective,
SnapshotID: "prod-snap", VersionLabel: "prod-2026.10", CreatedAt: now},
{ID: "ver-backup-other", Scope: "internal", Kind: governance.LibraryVersionProductionPrebackup,
SnapshotID: "other-snap", CreatedAt: now},
}}
config := Config{Store: store, LibraryArchiveRoot: t.TempDir()}
request := httptest.NewRequest(http.MethodGet, "/api/v1/library/overview?scope=internal", nil)
recorder := httptest.NewRecorder()
libraryOverviewHandler(recorder, request, config)
if recorder.Code != http.StatusOK {
t.Fatalf("status = %d: %s", recorder.Code, recorder.Body.String())
}
var body struct {
Production libraryKnownView `json:"production"`
Prebackup libraryKnownView `json:"prebackup"`
Versions []libraryVersionRef `json:"versions"`
Diff struct {
State string `json:"state"`
} `json:"diff"`
Gate struct {
SyncAllowed bool `json:"sync_allowed"`
} `json:"gate"`
}
if err := json.Unmarshal(recorder.Body.Bytes(), &body); err != nil {
t.Fatalf("decode overview: %v", err)
}
if body.Production.State != "known" || body.Production.Version == nil || body.Production.Version.ID != "ver-prod" {
t.Fatalf("production must be the effective version, got %+v", body.Production)
}
// 预备份按"最近一次生产写入前的备份"显示:归档不可用时没有可匹配的目标,
// 但登记过的预备份必须仍然可见(否则真备份了却显示"尚未创建"),
// 并且明确标出它并不是本次拟发布快照。
if body.Prebackup.State != "known" || body.Prebackup.Version == nil || body.Prebackup.Version.ID != "ver-backup-other" {
t.Fatalf("registered prebackup must stay visible: %+v", body.Prebackup)
}
if body.Prebackup.BoundToTarget {
t.Fatalf("prebackup must not claim to be the publish target without one: %+v", body.Prebackup)
}
if len(body.Versions) != 3 {
t.Fatalf("overview must expose every registered version kind, got %+v", body.Versions)
}
if body.Diff.State != "unknown" {
t.Fatalf("diff must be unknown until the comparison is wired, got %q", body.Diff.State)
}
if body.Gate.SyncAllowed {
t.Fatal("gate must stay closed")
}
}
// 现场形状:历史把生效版本挤出了展示窗口(LibraryVersions 返回空),但"当前生效版本"
// 精确查询仍读得到它。同步闸口必须据此认为生产已有权威版本:
// 读成"没有"会把一次不必要的覆盖放行,并把人推向"重新建基线"。
func TestLibrarySyncEnqueueUsesExactCurrentVersionBeyondWindow(t *testing.T) {
target := "snap-1"
digest, err := librarySyncParamsDigest("internal", target)
if err != nil {
t.Fatal(err)
}
now := time.Now().UTC()
store := &fakeLibraryStore{
// 窗口:故意什么都不返回(模拟生效版本掉出"最近 N 条")。
versions: []governance.LibraryVersion{},
current: &governance.LibraryVersion{ID: "ver-prod", Scope: "internal",
Kind: governance.LibraryVersionProductionEffective, SnapshotID: "prod-snap",
VersionLabel: "prod-2026.10", CreatedAt: now.Add(-72 * time.Hour)},
}
store.enqueueEchoRequestedID = true
store.grant = &governance.LibraryReleaseAuthorization{ID: "auth-1", Scope: "internal", SnapshotID: target,
ParamsDigest: digest, AuthorizedBy: "admin", ExpiresAt: now.Add(30 * time.Minute), CreatedAt: now}
config := Config{Store: store, ProductionReleaseRequestsEnabled: true, ProductionBackupRestoreVerified: true,
LibraryProductionDatabaseURL: "postgres://prod.invalid/db", LibraryProductionInternalKB: "kb-int",
LibraryCapacityBudgetBytes: 1 << 40}
body := `{"scope":"internal","target_snapshot_id":"` + target + `"}`
recorder := httptest.NewRecorder()
librarySyncEnqueue(recorder, httptest.NewRequest(http.MethodPost, "/api/v1/library/syncs", strings.NewReader(body)), config)
if recorder.Code != http.StatusAccepted {
t.Fatalf("status=%d body=%s(窗口外读到生效版本时闸口不该拒绝)", recorder.Code, recorder.Body.String())
}
if store.createN != 1 {
t.Fatalf("created=%d, want 1", store.createN)
}
}
// 读不到当前生效版本时不许猜:fail closed(500)且不创建作业。
func TestLibrarySyncEnqueueFailsClosedWhenCurrentVersionUnreadable(t *testing.T) {
target := "snap-1"
digest, err := librarySyncParamsDigest("internal", target)
if err != nil {
t.Fatal(err)
}
now := time.Now().UTC()
store := &fakeLibraryStore{currentErr: errors.New("version storage down")}
store.grant = &governance.LibraryReleaseAuthorization{ID: "auth-1", Scope: "internal", SnapshotID: target,
ParamsDigest: digest, AuthorizedBy: "admin", ExpiresAt: now.Add(30 * time.Minute), CreatedAt: now}
config := Config{Store: store, ProductionReleaseRequestsEnabled: true, ProductionBackupRestoreVerified: true,
LibraryProductionDatabaseURL: "postgres://prod.invalid/db", LibraryProductionInternalKB: "kb-int",
LibraryCapacityBudgetBytes: 1 << 40}
recorder := httptest.NewRecorder()
librarySyncEnqueue(recorder, httptest.NewRequest(http.MethodPost, "/api/v1/library/syncs",
strings.NewReader(`{"scope":"internal","target_snapshot_id":"`+target+`"}`)), config)
if recorder.Code != http.StatusInternalServerError {
t.Fatalf("status=%d body=%s", recorder.Code, recorder.Body.String())
}
if store.createN != 0 {
t.Fatalf("created %d jobs while the current version was unreadable", store.createN)
}
}