package chat import ( "context" "fmt" "strings" "testing" "chat-agent-system/internal/bizdev" "chat-agent-system/internal/config" "chat-agent-system/internal/coordinator" "chat-agent-system/internal/docgov" ) func TestExecuteAction_DocGovReviewApprove(t *testing.T) { cfg := &config.Config{DataDir: t.TempDir()} svc := bizdev.MustNewService(t, cfg) docGov := bizdev.Snapshot(svc).Gov ctx := context.Background() docID := "doc_proj1_research" _, err := docGov.CreateOrGetDocument( ctx, docID, 1, "research", "调研报告", "V0.5", "", 1, "张工", 2, "李主管", 3, "王总监", ) if err != nil { t.Fatalf("CreateOrGetDocument: %v", err) } _ = docGov.MarkDocumentContentUpdated(ctx, docID, "hash1", false) _, _ = docGov.SubmitForReview(ctx, docID, 1, docgov.RoleAuthor, "张工") sess := &Session{ UserID: 2, Actions: &ActionServices{DocGov: docGov}, } action := &coordinator.PendingAction{ Kind: "docgov.review_approve", DocID: docID, Comment: "同意", } userCtx := &coordinator.UserProjectContext{ User: coordinator.UserInfo{ID: "2", Name: "李主管"}, } result, err := sess.executeAction(ctx, action, userCtx) if err != nil { t.Fatalf("executeAction failed: %v", err) } if result.DocState != string(docgov.StateApproving) { t.Fatalf("expected approving state, got %s", result.DocState) } reply := renderActionReply(action, result, nil) if reply == "" { t.Fatal("expected non-empty reply") } } func TestExecuteAction_SubmitReviewAndComment(t *testing.T) { cfg := &config.Config{DataDir: t.TempDir()} svc := bizdev.MustNewService(t, cfg) docGov := bizdev.Snapshot(svc).Gov ctx := context.Background() docID := "doc_proj1_intake" _, err := docGov.CreateOrGetDocument( ctx, docID, 1, "intake", "需求收集表", "V0.1", "", 1, "张工", 2, "李主管", 3, "王总监", ) if err != nil { t.Fatalf("create: %v", err) } _ = docGov.MarkDocumentContentUpdated(ctx, docID, "hash1", false) sess := &Session{UserID: 1, ProjectID: 1, Actions: &ActionServices{DocGov: docGov}} userCtx := &coordinator.UserProjectContext{User: coordinator.UserInfo{ID: "1", Name: "张工"}} res, err := sess.executeAction(ctx, &coordinator.PendingAction{Kind: "docgov.submit_review", DocID: docID}, userCtx) if err != nil { t.Fatalf("submit: %v", err) } if res.DocState != string(docgov.StateReviewing) { t.Fatalf("state=%s", res.DocState) } _, err = sess.executeAction(ctx, &coordinator.PendingAction{ Kind: "docgov.comment_add", DocID: docID, Role: "reviewer", Section: "s1", Comment: "请补充风险", Reason: "suggestion", }, &coordinator.UserProjectContext{User: coordinator.UserInfo{ID: "2", Name: "李主管"}}) if err != nil { // author can also comment in reviewing; use reviewer id t.Fatalf("comment add: %v", err) } sess.UserID = 2 _, err = sess.executeAction(ctx, &coordinator.PendingAction{ Kind: "docgov.comment_resolve", DocID: docID, Role: "reviewer", Section: "s1", }, &coordinator.UserProjectContext{User: coordinator.UserInfo{ID: "2", Name: "李主管"}}) if err != nil { t.Fatalf("comment resolve: %v", err) } } type stubReopen struct { reqErr error aprErr error } func (s *stubReopen) ListPendingReopens(context.Context, int64) ([]ReopenRequestView, error) { return nil, nil } func (s *stubReopen) RequestReopenByDoc(context.Context, int64, string, string, int64) (ReopenRequestView, error) { if s.reqErr != nil { return ReopenRequestView{}, s.reqErr } return ReopenRequestView{ID: 9, Status: "pending"}, nil } func (s *stubReopen) ApproveReopenByID(context.Context, int64, int64, int64) (ReopenRequestView, error) { if s.aprErr != nil { return ReopenRequestView{}, s.aprErr } return ReopenRequestView{ID: 9, Status: "approved"}, nil } func TestExecuteAction_ReopenPaths(t *testing.T) { sess := &Session{ UserID: 1, ProjectID: 1, Actions: &ActionServices{Reopens: &stubReopen{}}, } userCtx := &coordinator.UserProjectContext{User: coordinator.UserInfo{ID: "1", Name: "A"}} res, err := sess.executeAction(context.Background(), &coordinator.PendingAction{ Kind: "docgov.reopen_request", TaskKey: "intake", Reason: "需补充", }, userCtx) if err != nil { t.Fatal(err) } if res.Message == "" { t.Fatal("expected message") } res, err = sess.executeAction(context.Background(), &coordinator.PendingAction{ Kind: "docgov.reopen_approve", RequestID: 9, }, userCtx) if err != nil { t.Fatal(err) } if res.Message == "" { t.Fatal("expected approve message") } sess.Actions.Reopens = &stubReopen{reqErr: fmt.Errorf("无权申请重开")} _, err = sess.executeAction(context.Background(), &coordinator.PendingAction{ Kind: "docgov.reopen_request", TaskKey: "intake", Reason: "x", }, userCtx) if err == nil { t.Fatal("expected permission failure") } reply := renderActionReply(&coordinator.PendingAction{Kind: "docgov.reopen_request", DocID: "d"}, nil, err) if reply == "" || !strings.Contains(reply, "无权") { t.Fatalf("reply=%s", reply) } }