You've already forked agentic-coding-workflow
feat(project): RequirementService with phase state machine + close/reopen
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/yan1h/agent-coding-workflow/internal/infra/errs"
|
||||
)
|
||||
|
||||
func newReqSvc(repo *fakeRepo) (RequirementService, ProjectService, *spyAudit) {
|
||||
spy := &spyAudit{}
|
||||
return NewRequirementService(repo, spy), NewProjectService(repo, spy), spy
|
||||
}
|
||||
|
||||
func TestRequirementService_Create_HappyAndAutoIncrement(t *testing.T) {
|
||||
repo := newFakeRepo()
|
||||
owner := uuid.New()
|
||||
seedProject(t, repo, owner)
|
||||
svc, _, spy := newReqSvc(repo)
|
||||
caller := Caller{UserID: owner}
|
||||
|
||||
r1, err := svc.Create(context.Background(), caller, "demo", CreateRequirementInput{Title: "First"})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, r1.Number)
|
||||
|
||||
r2, err := svc.Create(context.Background(), caller, "demo", CreateRequirementInput{Title: "Second"})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, r2.Number)
|
||||
|
||||
require.Contains(t, spy.actions(), "requirement.create")
|
||||
}
|
||||
|
||||
func TestRequirementService_PhaseChange_FollowsEnum(t *testing.T) {
|
||||
repo := newFakeRepo()
|
||||
owner := uuid.New()
|
||||
seedProject(t, repo, owner)
|
||||
svc, _, _ := newReqSvc(repo)
|
||||
caller := Caller{UserID: owner}
|
||||
r, err := svc.Create(context.Background(), caller, "demo", CreateRequirementInput{Title: "T"})
|
||||
require.NoError(t, err)
|
||||
|
||||
// 任意跳跃合法:planning → reviewing
|
||||
out, err := svc.ChangePhase(context.Background(), caller, "demo", r.Number, PhaseReviewing)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, PhaseReviewing, out.Phase)
|
||||
|
||||
// 非枚举字符串 → invalid
|
||||
_, err = svc.ChangePhase(context.Background(), caller, "demo", r.Number, "bogus")
|
||||
ae, ok := errs.As(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, errs.CodeInvalidInput, ae.Code)
|
||||
}
|
||||
|
||||
func TestRequirementService_PhaseChange_BlockedWhenClosed(t *testing.T) {
|
||||
repo := newFakeRepo()
|
||||
owner := uuid.New()
|
||||
seedProject(t, repo, owner)
|
||||
svc, _, _ := newReqSvc(repo)
|
||||
caller := Caller{UserID: owner}
|
||||
r, err := svc.Create(context.Background(), caller, "demo", CreateRequirementInput{Title: "T"})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, svc.Close(context.Background(), caller, "demo", r.Number))
|
||||
|
||||
_, err = svc.ChangePhase(context.Background(), caller, "demo", r.Number, PhaseAuditing)
|
||||
ae, ok := errs.As(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, errs.CodeRequirementClosed, ae.Code)
|
||||
}
|
||||
|
||||
func TestRequirementService_Write_BlockedWhenProjectArchived(t *testing.T) {
|
||||
repo := newFakeRepo()
|
||||
owner := uuid.New()
|
||||
seedProject(t, repo, owner)
|
||||
reqSvc, projSvc, _ := newReqSvc(repo)
|
||||
caller := Caller{UserID: owner}
|
||||
require.NoError(t, projSvc.Archive(context.Background(), caller, "demo"))
|
||||
|
||||
_, err := reqSvc.Create(context.Background(), caller, "demo", CreateRequirementInput{Title: "X"})
|
||||
ae, ok := errs.As(err)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, errs.CodeProjectArchived, ae.Code)
|
||||
}
|
||||
|
||||
func TestRequirementService_Reopen_AllowsPhaseAgain(t *testing.T) {
|
||||
repo := newFakeRepo()
|
||||
owner := uuid.New()
|
||||
seedProject(t, repo, owner)
|
||||
svc, _, _ := newReqSvc(repo)
|
||||
caller := Caller{UserID: owner}
|
||||
r, err := svc.Create(context.Background(), caller, "demo", CreateRequirementInput{Title: "T"})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, svc.Close(context.Background(), caller, "demo", r.Number))
|
||||
require.NoError(t, svc.Reopen(context.Background(), caller, "demo", r.Number))
|
||||
|
||||
out, err := svc.ChangePhase(context.Background(), caller, "demo", r.Number, PhaseDone)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, PhaseDone, out.Phase)
|
||||
}
|
||||
Reference in New Issue
Block a user