Files
Agent-System/internal/bizdev/document_duty_resolve_test.go
weichenandCursor 67b3b5e070 test: cover duty lock, heal/revoke skip, and instance duty adapter
Unit evidence for AE5a/AE5b filters; optional PG cases when
TEST_DATABASE_URL is set.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-17 09:59:38 +00:00

129 lines
4.0 KiB
Go

package bizdev
import (
"context"
"testing"
"chat-agent-system/internal/docduty"
"chat-agent-system/internal/docgov"
)
type fakeInstanceDuty struct {
author, reviewer, approver int64
policy string
governed bool
err error
called bool
}
func (f *fakeInstanceDuty) ResolveGovernedDuty(_ context.Context, _ int64, _ string) (int64, int64, int64, string, bool, error) {
f.called = true
return f.author, f.reviewer, f.approver, f.policy, f.governed, f.err
}
func TestResolveTaskDocumentDuties_UsesCreatorNotHardcodedReviewer(t *testing.T) {
req := TaskRunRequest{
UserID: 170, ProjectID: 6145,
AuthorName: "编制人A",
}
got, _, _ := resolveTaskDocumentDuties(context.Background(), nil, req, nil)
if got.Author.UserID != 170 {
t.Fatalf("author want 170 got %+v", got.Author)
}
if got.Reviewer.UserID == 2 || got.Approver.UserID == 3 {
t.Fatalf("must not invent hardcoded 2/3: %+v", got)
}
if got.Reviewer.UserID != 0 {
t.Fatalf("no project members → reviewer empty, got %+v", got.Reviewer)
}
}
func TestResolveTaskDocumentDuties_IgnoresNonMemberRequestReviewer(t *testing.T) {
req := TaskRunRequest{
UserID: 170, ReviewerID: 2, ReviewerName: "审核负责人",
}
got, _, _ := resolveTaskDocumentDuties(context.Background(), nil, req, nil)
if got.Reviewer.UserID != 0 {
t.Fatalf("request reviewer 2 is not a member: %+v", got.Reviewer)
}
}
func TestResolveTaskDocumentDuties_GovernedUsesInstance(t *testing.T) {
src := &fakeInstanceDuty{
author: 9, reviewer: 9, approver: 9,
policy: "author_only", governed: true,
}
req := TaskRunRequest{
UserID: 170, ProjectID: 42, TaskKey: "intake",
AuthorName: "编制人A", ReviewerID: 2,
}
got, policy, governed := resolveTaskDocumentDuties(context.Background(), nil, req, src)
if !governed || policy != "author_only" {
t.Fatalf("governed=%v policy=%q", governed, policy)
}
if got.Author.UserID != 9 || got.Reviewer.UserID != 9 || got.Approver.UserID != 9 {
t.Fatalf("want A/A/A=9, got %+v", got)
}
if !src.called {
t.Fatal("expected ResolveGovernedDuty called")
}
}
func TestResolveTaskDocumentDuties_UngovernedFallsBack(t *testing.T) {
src := &fakeInstanceDuty{governed: false}
req := TaskRunRequest{
UserID: 170, ProjectID: 42, TaskKey: "intake",
AuthorName: "编制人A",
}
got, policy, governed := resolveTaskDocumentDuties(context.Background(), nil, req, src)
if governed || policy != "" {
t.Fatalf("want ungoverned, got governed=%v policy=%q", governed, policy)
}
if got.Author.UserID != 170 {
t.Fatalf("author want 170 got %+v", got.Author)
}
if got.Reviewer.UserID != 0 {
t.Fatalf("no members → reviewer empty, got %+v", got.Reviewer)
}
}
func TestGovernedSkipsMemoryHealOverwrite(t *testing.T) {
doc := &docgov.DocumentRecord{
DocID: "doc_x", AuthorID: 9, AuthorName: "A",
ReviewerID: 9, ReviewerName: "A",
ApproverID: 9, ApproverName: "A",
DutyLocked: true, DutyPolicy: "author_only",
}
assigned := docduty.Binding{
Author: docduty.Holder{UserID: 1, Name: "作者"},
Reviewer: docduty.Holder{UserID: 2, Name: "审核"},
Approver: docduty.Holder{UserID: 3, Name: "批准"},
}
memberIDs := map[int64]struct{}{1: {}, 2: {}, 3: {}, 9: {}}
governed := true
if !governed {
next, _ := docduty.HealBinding(bindingFromDoc(doc), assigned, memberIDs)
writeBindingToDoc(doc, next)
}
if doc.ReviewerID != 9 || doc.ApproverID != 9 {
t.Fatalf("governed must keep A/A/A, got R=%d Ap=%d", doc.ReviewerID, doc.ApproverID)
}
doc2 := &docgov.DocumentRecord{
DocID: "doc_y", AuthorID: 9, ReviewerID: 9, ApproverID: 9,
}
next, changed := docduty.HealBinding(bindingFromDoc(doc2), assigned, memberIDs)
if !changed {
t.Fatal("expected heal change for ungoverned path")
}
writeBindingToDoc(doc2, next)
if doc2.ReviewerID != 2 || doc2.ApproverID != 3 {
t.Fatalf("ungoverned heal want 2/3, got R=%d Ap=%d", doc2.ReviewerID, doc2.ApproverID)
}
}
func TestBindingFromDocRoundTrip(t *testing.T) {
_ = docduty.Binding{}
}