fix(e2e): authenticate multi-role docgov steps in pi-agent lifecycle test

Align seeded user IDs and use per-role Bearer tokens so review reject/approve actions run as the assigned reviewer instead of the legacy fallback principal.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
weichen
2026-09-12 05:34:50 +00:00
co-authored by Cursor
parent dff1d60c48
commit 686d39ec62
+43 -39
View File
@@ -75,13 +75,41 @@ func TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E(t *testing.T) {
intendedUse := "神经外科与肝胆外科精密手术中利用 24kHz-35kHz 超声微幅振动选择性粉碎并吸引病灶组织,保留邻近大血管与神经"
targetMarket := "中国NMPA三类创新医疗器械"
authorID := int64(1)
// 与 dev 种子账号对齐(internal/auth/store.go)
authorID := int64(2) // zhanggong / 张工
authorName := "张工"
reviewerID := int64(2)
reviewerID := int64(3) // lizhuguan / 李主管
reviewerName := "李主管"
approverID := int64(3)
approverID := int64(4) // wangzong / 王总监
approverName := "王总监"
authorToken := loginTestUser(t, ts.Config.Handler, "zhanggong", "123456")
reviewerToken := loginTestUser(t, ts.Config.Handler, "lizhuguan", "123456")
approverToken := loginTestUser(t, ts.Config.Handler, "wangzong", "123456")
authedPost := func(path, token string, payload any) (*http.Response, error) {
b, _ := json.Marshal(payload)
req, err := http.NewRequest(http.MethodPost, ts.URL+path, bytes.NewReader(b))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
withBearerAuth(req, token)
return client.Do(req)
}
expectOK := func(label string, resp *http.Response, err error) {
t.Helper()
if err != nil {
t.Fatalf("%s: %v", label, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var buf bytes.Buffer
_, _ = buf.ReadFrom(resp.Body)
t.Fatalf("%s: HTTP %d body=%s", label, resp.StatusCode, buf.String())
}
}
sessionID := fmt.Sprintf("sess_cusa_%d", time.Now().UnixNano())
// 4. 【编制人·张工】登录与立项阶段对话 (穿插非工作流问答 + 行业标准咨询)
@@ -319,12 +347,8 @@ func TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E(t *testing.T) {
"user_id": authorID,
"user_name": authorName,
}
cb, _ := json.Marshal(claimReq)
respClaim, err := client.Post(ts.URL+"/api/v1/docgov/claim", "application/json", bytes.NewReader(cb))
if err != nil || respClaim.StatusCode != http.StatusOK {
t.Fatalf("claim failed: %v", err)
}
respClaim.Body.Close()
respClaim, err := authedPost("/api/v1/docgov/claim", authorToken, claimReq)
expectOK("claim", respClaim, err)
t.Logf("✓ [张工] 成功认领受控文档: DocID=%s", targetDocID)
// 8.2 编制人【张工】送审 (进入 StateReviewing)
@@ -333,12 +357,8 @@ func TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E(t *testing.T) {
"author_id": authorID,
"note": "初稿编制完成,已包含 24kHz/35kHz 双频超声与灌注吸引合规说明,请主管审核。",
}
sb, _ := json.Marshal(submitReq)
respSub, err := client.Post(ts.URL+"/api/v1/docgov/submit-review", "application/json", bytes.NewReader(sb))
if err != nil || respSub.StatusCode != http.StatusOK {
t.Fatalf("submit-review failed: %v", err)
}
respSub.Body.Close()
respSub, err := authedPost("/api/v1/docgov/submit-review", authorToken, submitReq)
expectOK("submit-review", respSub, err)
t.Logf("✓ [张工] 提交审核成功,文档进入锁定审核态")
// 8.3 【审核人·李主管】介入并添加批注
@@ -367,12 +387,8 @@ func TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E(t *testing.T) {
"action": "reject",
"reason": "缺少高频电刀共模互扰防范机制论证,打回草稿态由编制人张工补充后重新送审。",
}
rjb, _ := json.Marshal(rejReq)
respRej, err := client.Post(ts.URL+"/api/v1/docgov/review-decision", "application/json", bytes.NewReader(rjb))
if err != nil || respRej.StatusCode != http.StatusOK {
t.Fatalf("review reject failed: %v", err)
}
respRej.Body.Close()
respRej, err := authedPost("/api/v1/docgov/review-decision", reviewerToken, rejReq)
expectOK("review reject", respRej, err)
t.Logf("✓ [李主管] 驳回成功,受控文档自动解锁并退回 drafting 状态")
// 8.5 编制人【张工】再次送审
@@ -381,12 +397,8 @@ func TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E(t *testing.T) {
"author_id": authorID,
"note": "已补充 GB 9706.202 绝缘隔离与高频消磁屏蔽方案,重新送审。",
}
sb2, _ := json.Marshal(submitReq2)
respSub2, err := client.Post(ts.URL+"/api/v1/docgov/submit-review", "application/json", bytes.NewReader(sb2))
if err != nil || respSub2.StatusCode != http.StatusOK {
t.Fatalf("resubmit failed: %v", err)
}
respSub2.Body.Close()
respSub2, err := authedPost("/api/v1/docgov/submit-review", authorToken, submitReq2)
expectOK("resubmit", respSub2, err)
t.Logf("✓ [张工] 补充材料后再次送审成功")
// 8.6 【审核人·李主管】第二次审核 -> 审核通过 (Pass)
@@ -397,12 +409,8 @@ func TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E(t *testing.T) {
"action": "approve",
"comment": "方案已完善,GB 9706.202 及 YY 0644 检验项齐备,同意流转至王总监终审。",
}
pb, _ := json.Marshal(passReq)
respPass, err := client.Post(ts.URL+"/api/v1/docgov/review-decision", "application/json", bytes.NewReader(pb))
if err != nil || respPass.StatusCode != http.StatusOK {
t.Fatalf("review approve failed: %v", err)
}
respPass.Body.Close()
respPass, err := authedPost("/api/v1/docgov/review-decision", reviewerToken, passReq)
expectOK("review approve", respPass, err)
t.Logf("✓ [李主管] 审核通过,文档流转至待批准态 (StateApproving)")
// 8.7 【批准人·王总监】最终批准 (Approve)
@@ -413,12 +421,8 @@ func TestPiAgent_FullLifecycle_MultiRole_RealWorld_E2E(t *testing.T) {
"action": "approve",
"comment": "符合创新微创手术吸引系统三年规划,同意立项并进入工程实施与核价锁定。",
}
apb, _ := json.Marshal(apprReq)
respAppr, err := client.Post(ts.URL+"/api/v1/docgov/approver-decision", "application/json", bytes.NewReader(apb))
if err != nil || respAppr.StatusCode != http.StatusOK {
t.Fatalf("approver decision failed: %v", err)
}
respAppr.Body.Close()
respAppr, err := authedPost("/api/v1/docgov/approver-decision", approverToken, apprReq)
expectOK("approver decision", respAppr, err)
t.Logf("✓ [王总监] 最终批准成功,文档彻底锁定生效归档 (StateApproved)")
// 9. 验证全生命周期数据落盘与审计追溯