You've already forked agentic-coding-workflow
feat(workspace): WorktreeService with acquire/release state machine
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package workspace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newWtSvc(t *testing.T) (*worktreeService, *fakeRepo, *fakePA, *fakeGit, uuid.UUID) {
|
||||
t.Helper()
|
||||
pa := &fakePA{pid: uuid.New(), canRead: true, canWrite: true}
|
||||
gitr := &fakeGit{}
|
||||
repo := newFakeRepo()
|
||||
svc := NewWorktreeService(repo, noopAudit{}, gitr, pa, "/data").(*worktreeService)
|
||||
wsID := uuid.New()
|
||||
repo.wss[wsID] = &Workspace{ID: wsID, ProjectID: pa.pid, MainPath: "/data/main", DefaultBranch: "main"}
|
||||
return svc, repo, pa, gitr, wsID
|
||||
}
|
||||
|
||||
func TestWorktreeService_CreateAndList(t *testing.T) {
|
||||
t.Parallel()
|
||||
svc, _, _, _, wsID := newWtSvc(t)
|
||||
wt, err := svc.Create(context.Background(), Caller{UserID: uuid.New()}, wsID, CreateWorktreeInput{Branch: "feat-x"})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "feat-x", wt.Branch)
|
||||
require.Equal(t, WorktreeStatusIdle, wt.Status)
|
||||
}
|
||||
|
||||
func TestWorktreeService_AcquireIdempotent(t *testing.T) {
|
||||
t.Parallel()
|
||||
svc, _, _, _, wsID := newWtSvc(t)
|
||||
caller := Caller{UserID: uuid.New()}
|
||||
wt, err := svc.Create(context.Background(), caller, wsID, CreateWorktreeInput{Branch: "feat-y"})
|
||||
require.NoError(t, err)
|
||||
|
||||
a1, err := svc.Acquire(context.Background(), caller, wt.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, WorktreeStatusActive, a1.Status)
|
||||
a2, err := svc.Acquire(context.Background(), caller, wt.ID) // idempotent
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, a1.ID, a2.ID)
|
||||
}
|
||||
|
||||
func TestWorktreeService_AcquireConflict(t *testing.T) {
|
||||
t.Parallel()
|
||||
svc, _, _, _, wsID := newWtSvc(t)
|
||||
a := Caller{UserID: uuid.New()}
|
||||
b := Caller{UserID: uuid.New()}
|
||||
wt, err := svc.Create(context.Background(), a, wsID, CreateWorktreeInput{Branch: "feat-z"})
|
||||
require.NoError(t, err)
|
||||
_, err = svc.Acquire(context.Background(), a, wt.ID)
|
||||
require.NoError(t, err)
|
||||
_, err = svc.Acquire(context.Background(), b, wt.ID)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestWorktreeService_Release(t *testing.T) {
|
||||
t.Parallel()
|
||||
svc, _, _, _, wsID := newWtSvc(t)
|
||||
caller := Caller{UserID: uuid.New()}
|
||||
wt, err := svc.Create(context.Background(), caller, wsID, CreateWorktreeInput{Branch: "feat-r"})
|
||||
require.NoError(t, err)
|
||||
_, err = svc.Acquire(context.Background(), caller, wt.ID)
|
||||
require.NoError(t, err)
|
||||
_, err = svc.Release(context.Background(), caller, wt.ID)
|
||||
require.NoError(t, err)
|
||||
got, _ := svc.repo.GetWorktreeByID(context.Background(), wt.ID)
|
||||
require.Equal(t, WorktreeStatusIdle, got.Status)
|
||||
}
|
||||
|
||||
func TestWorktreeService_Delete_BlockedWhenActive(t *testing.T) {
|
||||
t.Parallel()
|
||||
svc, _, _, _, wsID := newWtSvc(t)
|
||||
caller := Caller{UserID: uuid.New()}
|
||||
wt, err := svc.Create(context.Background(), caller, wsID, CreateWorktreeInput{Branch: "feat-d"})
|
||||
require.NoError(t, err)
|
||||
_, err = svc.Acquire(context.Background(), caller, wt.ID)
|
||||
require.NoError(t, err)
|
||||
err = svc.Delete(context.Background(), caller, wt.ID)
|
||||
require.Error(t, err)
|
||||
}
|
||||
Reference in New Issue
Block a user