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) }