Files
knowledge-governance/internal/qaopsmirror/master_inline_fields_integration_test.go
T
姚章浩 87f97a2f9b
build / build (push) Successful in 1m7s
feat(qaops): 完成详情下拉与每周自动保存草稿
详情使用共享主表字典,稀疏修改所选字段并保留原始问答及旧复核审计。
月周统计提供文本和下拉双入口;每租户每周一份持久草稿,按技能六节双语模板真实预填。
加入幂等自动保存、冲突保留、未知响应重试、切周及离开保护和schema58非破坏降级保护。

验证:完整make verify、隔离PostgreSQL全mirror竞态回归、真实恢复库浏览器验收通过。
浏览器实测字段精确读回、月周双输入、模板预填、MD/CSV、自动保存、冲突、失败重试与API重启恢复。
未连接或改写DobotAI生产源库,未运行付费模型;提交时尚未部署。
2026-10-20 05:44:02 +08:00

70 lines
2.8 KiB
Go

package qaopsmirror
import (
"context"
"encoding/json"
"knowledge-governance/internal/dobotaiops"
pg "knowledge-governance/internal/platform/postgres"
"testing"
"time"
)
func TestMasterInlineFieldPatchPersistsOnlyChosenField(t *testing.T) {
p := mirrorFixture(t)
ctx := context.Background()
s := NewStore(p, "fixture-inline-fields")
queue := pg.NewStore(p)
source := &fixtureSource{rows: []dobotaiops.MirrorRecord{fixtureEntry("inline-field", "first")}}
job := claimMirrorJob(t, s, queue, "inline-initial")
if e := s.HandleSync(ctx, *job, func(context.Context) (Source, error) { return source, nil }); e != nil {
t.Fatal(e)
}
if e := queue.Complete(ctx, job.ID, job.LeaseOwner, time.Now()); e != nil {
t.Fatal(e)
}
rec, e := s.GetMasterRecord(ctx, s.tenant, "inline-field")
if e != nil {
t.Fatal(e)
}
keys := []dobotaiops.QualityKey{{ID: rec.ID, InputHash: rec.QualityInputHash}}
before, e := s.ReadMasterQualityViews(ctx, keys)
if e != nil {
t.Fatal(e)
}
var original string
if e = p.QueryRow(ctx, `SELECT md5(payload::text||local_fields::text) FROM qa_ops_master_records WHERE tenant_key=$1 AND id=$2`, s.tenant, rec.ID).Scan(&original); e != nil {
t.Fatal(e)
}
q := MasterFieldPatch{InputHash: rec.QualityInputHash, InputEpoch: before[rec.ID].InputEpoch, BaseReviewRevision: before[rec.ID].Revision, Nonce: "fixture_inline_field_001", Fields: map[string]string{"product_category": "MG400"}}
receipt, e := s.PatchMasterFields(ctx, rec.ID, q, "fixture-admin")
if e != nil {
t.Fatalf("single-field persistent edit rejected: %v", e)
}
if receipt.SavedRevision != 1 || receipt.Replayed {
t.Fatalf("invalid receipt: %+v", receipt)
}
after, e := NewStore(p, s.tenant).ReadMasterQualityViews(ctx, keys)
if e != nil {
t.Fatal(e)
}
fresh, e := s.GetMasterRecord(ctx, s.tenant, rec.ID)
if e != nil || fresh.FieldEditRevision != 1 || fresh.MasterFields["product_category"] != "MG400" {
t.Fatalf("detail/list read model did not expose saved field version and value: %+v error=%v", fresh, e)
}
b, a := before[rec.ID], after[rec.ID]
b.Effective.ProductCategory = "MG400"
rawB, _ := json.Marshal(b)
rawA, _ := json.Marshal(a)
if string(rawB) != string(rawA) {
t.Fatalf("unselected conclusions/review provenance changed: before=%s after=%s", rawB, rawA)
}
var current string
var audits int
if e = p.QueryRow(ctx, `SELECT md5(payload::text||local_fields::text) FROM qa_ops_master_records WHERE tenant_key=$1 AND id=$2`, s.tenant, rec.ID).Scan(&current); e != nil || original != current {
t.Fatal("source/master payload or stored labels were rewritten", e)
}
if e = p.QueryRow(ctx, `SELECT count(*) FROM qa_ops_master_field_edits WHERE tenant_key=$1 AND record_id=$2`, s.tenant, rec.ID).Scan(&audits); e != nil || audits != 1 {
t.Fatal("field edit audit missing", e)
}
}