Files
Agent-System/internal/docgov/lease_test.go
T
weichenandCursor 7b48ca2ecc fix(docgov): assert edit duty before lease; project via SaveDocumentContent
Unauthorized actors no longer grab leases; controlled PATCH projects through
DocGov so author_last_edited and audit survive, with idempotent retry on failure.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-13 09:32:08 +00:00

122 lines
3.7 KiB
Go

package docgov_test
import (
"context"
"errors"
"testing"
"time"
"chat-agent-system/internal/docgov"
)
func TestEditLeaseMutexAndCommentGate(t *testing.T) {
engine := docgov.NewGovernanceEngine(nil)
ctx := context.Background()
docID := "doc_lease_test_001"
_, err := engine.CreateOrGetDocument(ctx, docID, 1, "intake", "摸底纪要", "V0.1", "",
1, "作者", 2, "审核", 3, "批准")
if err != nil {
t.Fatalf("create: %v", err)
}
doc, err := engine.AcquireLease(ctx, docgov.LeaseAcquireRequest{
DocID: docID,
HolderType: docgov.LeaseHolderSquad,
HolderID: "run_1",
TTL: 5 * time.Minute,
})
if err != nil {
t.Fatalf("acquire: %v", err)
}
if !doc.HasActiveLease(time.Now()) {
t.Fatal("expected active lease")
}
_, err = engine.AcquireLease(ctx, docgov.LeaseAcquireRequest{
DocID: docID,
HolderType: docgov.LeaseHolderHuman,
HolderID: "42",
TTL: 5 * time.Minute,
})
if !errors.Is(err, docgov.ErrDocumentBusy) {
t.Fatalf("expected ErrDocumentBusy, got %v", err)
}
_, err = engine.AddComment(ctx, docID, 2, "审核人", docgov.RoleReviewer, "## 结论", docgov.CommentGeneral, "请补充")
if !errors.Is(err, docgov.ErrDocumentBusy) {
t.Fatalf("comment should be blocked while leased, got %v", err)
}
_, err = engine.CheckModificationPermission(ctx, docID, docgov.RoleSystem)
if !errors.Is(err, docgov.ErrDocumentBusy) {
t.Fatalf("modification check should be busy, got %v", err)
}
if _, err := engine.ReleaseLease(ctx, docID, string(docgov.LeaseHolderSquad), "run_1"); err != nil {
t.Fatalf("release: %v", err)
}
_, err = engine.AddComment(ctx, docID, 2, "审核人", docgov.RoleReviewer, "## 结论", docgov.CommentGeneral, "请补充")
if err != nil {
t.Fatalf("comment after release should succeed: %v", err)
}
}
func TestSameHolderRenewLease(t *testing.T) {
engine := docgov.NewGovernanceEngine(nil)
ctx := context.Background()
docID := "doc_lease_renew_001"
_, _ = engine.CreateOrGetDocument(ctx, docID, 1, "intake", "摸底", "V0.1", "", 1, "a", 2, "b", 3, "c")
_, err := engine.AcquireLease(ctx, docgov.LeaseAcquireRequest{
DocID: docID, HolderType: docgov.LeaseHolderHuman, HolderID: "1", TTL: time.Minute,
})
if err != nil {
t.Fatal(err)
}
doc, err := engine.AcquireLease(ctx, docgov.LeaseAcquireRequest{
DocID: docID, HolderType: docgov.LeaseHolderHuman, HolderID: "1", TTL: 10 * time.Minute,
})
if err != nil {
t.Fatalf("renew should succeed: %v", err)
}
if doc.LeaseExpiresAt == nil || time.Until(*doc.LeaseExpiresAt) < 5*time.Minute {
t.Fatalf("expected renewed TTL, expires=%v", doc.LeaseExpiresAt)
}
}
func TestAssertHumanCanEdit_ChecksDutyBeforeLease(t *testing.T) {
engine := docgov.NewGovernanceEngine(nil)
ctx := context.Background()
docID := "doc_assert_order_001"
_, err := engine.CreateOrGetDocument(ctx, docID, 1, "intake", "摸底", "V0.1", "",
1, "作者", 2, "审核", 3, "批准")
if err != nil {
t.Fatal(err)
}
// Non-author must fail without becoming lease holder.
if err := engine.AssertHumanCanEdit(ctx, docID, 99, docgov.RoleAuthor); err == nil {
t.Fatal("non-author AssertHumanCanEdit must fail")
}
doc, err := engine.GetDocument(ctx, docID)
if err != nil {
t.Fatal(err)
}
if doc.HasActiveLease(time.Now()) && doc.LeaseHolderID == "99" {
t.Fatal("unauthorized actor must not hold human lease")
}
if err := engine.AssertHumanCanEdit(ctx, docID, 1, docgov.RoleAuthor); err != nil {
t.Fatalf("author AssertHumanCanEdit: %v", err)
}
doc, err = engine.GetDocument(ctx, docID)
if err != nil {
t.Fatal(err)
}
if !doc.HasActiveLease(time.Now()) || doc.LeaseHolderType != docgov.LeaseHolderHuman || doc.LeaseHolderID != "1" {
t.Fatalf("author should hold human lease after assert, got type=%s id=%s", doc.LeaseHolderType, doc.LeaseHolderID)
}
}