Wire intent→coordinator DocResolver confirm cards→action_executor kinds for comment, reopen, pending-supplements query, and real submit-review execution.
180 lines
5.8 KiB
Go
180 lines
5.8 KiB
Go
package supplementimpact_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"chat-agent-system/internal/docgov"
|
|
"chat-agent-system/internal/notification"
|
|
"chat-agent-system/internal/supplementimpact"
|
|
"chat-agent-system/internal/traceimpact"
|
|
)
|
|
|
|
type stubAnalyzer struct{ report *traceimpact.Report }
|
|
|
|
func (s stubAnalyzer) Analyze(_ context.Context, _ int64, _ traceimpact.DocRef, _ []traceimpact.DocRef) (*traceimpact.Report, error) {
|
|
return s.report, nil
|
|
}
|
|
|
|
type stubDocs struct {
|
|
docs map[string]*docgov.DocumentRecord
|
|
}
|
|
|
|
func (s stubDocs) GetDocument(_ context.Context, id string) (*docgov.DocumentRecord, error) {
|
|
return s.docs[id], nil
|
|
}
|
|
|
|
func TestCreateBatchSnapshotsClaimAndBusy(t *testing.T) {
|
|
store := supplementimpact.NewMemStore()
|
|
claimedAt := time.Now()
|
|
svc := &supplementimpact.Service{
|
|
Store: store,
|
|
Analyze: stubAnalyzer{report: &traceimpact.Report{
|
|
CoverageStatus: "confirmed_impact",
|
|
Impacts: []traceimpact.Impact{
|
|
{DocID: "doc_a", ItemKey: "UR-1", ImpactType: "confirmed_impact", Depth: 1, Reason: "hit"},
|
|
},
|
|
}},
|
|
Docs: stubDocs{docs: map[string]*docgov.DocumentRecord{
|
|
"doc_a": {DocID: "doc_a", Title: "需求", AuthorID: 9, AuthorClaimed: true, AuthorClaimedAt: &claimedAt},
|
|
}},
|
|
}
|
|
b, err := svc.CreateFromSupplement(context.Background(), 1, 2, "sess", "补充市场", "UR-1 目标市场改为欧盟")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(b.Items) != 1 || !b.Items[0].AuthorClaimedSnapshot {
|
|
t.Fatalf("want claimed snapshot, got %+v", b.Items)
|
|
}
|
|
}
|
|
|
|
type stubPropose struct {
|
|
lastDoc string
|
|
prop *docgov.ChangeProposal
|
|
}
|
|
|
|
func (s *stubPropose) ProposeModification(_ context.Context, docID, _, _, _, _ string) (*docgov.ChangeProposal, error) {
|
|
s.lastDoc = docID
|
|
if s.prop == nil {
|
|
s.prop = &docgov.ChangeProposal{ProposalID: "prop_test_1", DocID: docID, Status: docgov.ProposalPendingAuthorApproval}
|
|
}
|
|
return s.prop, nil
|
|
}
|
|
|
|
type stubNotify struct{ n int }
|
|
|
|
func (s *stubNotify) UpsertDocumentDigest(_ context.Context, _ notification.UpsertDigestParams) error {
|
|
s.n++
|
|
return nil
|
|
}
|
|
|
|
func TestDecideClaimedProducesProposal(t *testing.T) {
|
|
store := supplementimpact.NewMemStore()
|
|
claimedAt := time.Now()
|
|
prop := &stubPropose{}
|
|
notify := &stubNotify{}
|
|
svc := &supplementimpact.Service{
|
|
Store: store,
|
|
Analyze: stubAnalyzer{report: &traceimpact.Report{
|
|
CoverageStatus: "confirmed_impact",
|
|
Impacts: []traceimpact.Impact{
|
|
{DocID: "doc_a", ItemKey: "UR-1", ImpactType: "confirmed_impact", Depth: 1, Reason: "hit"},
|
|
},
|
|
}},
|
|
Docs: stubDocs{docs: map[string]*docgov.DocumentRecord{
|
|
"doc_a": {DocID: "doc_a", Title: "需求", AuthorID: 9, AuthorClaimed: true, AuthorClaimedAt: &claimedAt, CurrentState: docgov.StateDrafting},
|
|
}},
|
|
Propose: prop,
|
|
Notify: notify,
|
|
}
|
|
b, err := svc.CreateFromSupplement(context.Background(), 1, 2, "sess", "补充市场", "UR-1 目标市场改为欧盟")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out, err := svc.Decide(context.Background(), supplementimpact.DecisionCommand{
|
|
BatchID: b.BatchID, ActorUserID: 2, Kind: "confirm",
|
|
SelectedDocIDs: []string{"doc_a"}, DecisionNonce: b.DecisionNonce,
|
|
DecisionDigest: "d1", ExpectedRevision: b.Revision,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(out.Items) != 1 || out.Items[0].Outcome != supplementimpact.OutcomeProposalPending {
|
|
t.Fatalf("want proposal_pending, got %+v", out.Items)
|
|
}
|
|
if prop.lastDoc != "doc_a" || notify.n != 1 {
|
|
t.Fatalf("propose/notify not called: doc=%s notify=%d", prop.lastDoc, notify.n)
|
|
}
|
|
}
|
|
|
|
type stubPending struct {
|
|
n int
|
|
last docgov.RecordPendingSupplementInput
|
|
}
|
|
|
|
func (s *stubPending) RecordPendingSupplement(_ context.Context, in docgov.RecordPendingSupplementInput) (*docgov.PendingSupplement, error) {
|
|
s.n++
|
|
s.last = in
|
|
return &docgov.PendingSupplement{DocID: in.DocID, Status: docgov.PendingSupplementPending}, nil
|
|
}
|
|
|
|
type capturingNotify struct {
|
|
params []notification.UpsertDigestParams
|
|
}
|
|
|
|
func (s *capturingNotify) UpsertDocumentDigest(_ context.Context, p notification.UpsertDigestParams) error {
|
|
s.params = append(s.params, p)
|
|
return nil
|
|
}
|
|
|
|
func TestDecideLockedSkipsAndRecordsPending(t *testing.T) {
|
|
store := supplementimpact.NewMemStore()
|
|
pending := &stubPending{}
|
|
notify := &capturingNotify{}
|
|
svc := &supplementimpact.Service{
|
|
Store: store,
|
|
Analyze: stubAnalyzer{report: &traceimpact.Report{
|
|
CoverageStatus: "confirmed_impact",
|
|
Impacts: []traceimpact.Impact{
|
|
{DocID: "doc_locked", ItemKey: "UR-1", ImpactType: "confirmed_impact", Depth: 1, Reason: "locked hit"},
|
|
},
|
|
}},
|
|
Docs: stubDocs{docs: map[string]*docgov.DocumentRecord{
|
|
"doc_locked": {
|
|
DocID: "doc_locked", Title: "锁定文档", AuthorID: 1, ReviewerID: 7,
|
|
CurrentState: docgov.StateReviewing, IsLocked: true, AuthorClaimed: true,
|
|
},
|
|
}},
|
|
Pending: pending,
|
|
Notify: notify,
|
|
}
|
|
b, err := svc.CreateFromSupplement(context.Background(), 1, 2, "sess", "锁定期补充", "UR-1 变更")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(b.Items) != 1 || !b.Items[0].LockedSnapshot || b.Items[0].BusySnapshot {
|
|
t.Fatalf("want locked snapshot without busy, got %+v", b.Items[0])
|
|
}
|
|
out, err := svc.Decide(context.Background(), supplementimpact.DecisionCommand{
|
|
BatchID: b.BatchID, ActorUserID: 2, Kind: "confirm",
|
|
SelectedDocIDs: []string{"doc_locked"}, DecisionNonce: b.DecisionNonce,
|
|
DecisionDigest: "d1", ExpectedRevision: b.Revision,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if out.Items[0].Outcome != supplementimpact.OutcomeSkippedLocked {
|
|
t.Fatalf("want skipped_locked, got %s", out.Items[0].Outcome)
|
|
}
|
|
if pending.n != 1 || pending.last.DocID != "doc_locked" {
|
|
t.Fatalf("pending ledger not recorded: %+v", pending)
|
|
}
|
|
if len(notify.params) != 1 || notify.params[0].UserID != 7 {
|
|
t.Fatalf("want reviewer notified, got %+v", notify.params)
|
|
}
|
|
if notify.params[0].DigestKind != notification.DigestKindPendingSupplements {
|
|
t.Fatalf("want pending_supplements digest, got %s", notify.params[0].DigestKind)
|
|
}
|
|
}
|