package workspace import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "testing" "github.com/go-chi/chi/v5" "github.com/google/uuid" "github.com/stretchr/testify/require" "github.com/yan1h/agent-coding-workflow/internal/transport/http/middleware" ) // fakeWS / fakeWT / fakeGOP 是 handler 单测用的桩(只覆盖必要方法)。 type fakeWS struct{ created *Workspace } func (f *fakeWS) Create(_ context.Context, _ Caller, _ string, _ CreateWorkspaceInput) (*Workspace, error) { w := &Workspace{ID: uuid.New(), Slug: "ws1", Name: "W1", SyncStatus: SyncStatusCloning} f.created = w return w, nil } func (f *fakeWS) Get(_ context.Context, _ Caller, id uuid.UUID) (*Workspace, error) { return &Workspace{ID: id, Slug: "ws1"}, nil } func (f *fakeWS) List(_ context.Context, _ Caller, _ string) ([]*Workspace, error) { return nil, nil } func (f *fakeWS) Update(_ context.Context, _ Caller, id uuid.UUID, _ UpdateWorkspaceInput) (*Workspace, error) { return &Workspace{ID: id}, nil } func (f *fakeWS) Delete(_ context.Context, _ Caller, _ uuid.UUID) error { return nil } func (f *fakeWS) Sync(_ context.Context, _ Caller, id uuid.UUID) (*Workspace, error) { return &Workspace{ID: id, SyncStatus: SyncStatusIdle}, nil } func (f *fakeWS) UpsertCredential(_ context.Context, _ Caller, _ uuid.UUID, _ UpsertCredentialInput) (*Credential, error) { return &Credential{Kind: CredKindPAT, Fingerprint: "****abcd"}, nil } func (f *fakeWS) GetCredentialMeta(_ context.Context, _ Caller, _ uuid.UUID) (*Credential, error) { return &Credential{Kind: CredKindNone}, nil } func (f *fakeWS) ListBranches(_ context.Context, _ Caller, _ uuid.UUID) ([]string, error) { return []string{"main", "develop"}, nil } // fakeResolver 把固定 token 解码为 uuid(沿 internal/project handler_test.go 模式)。 type fakeResolver struct{ valid map[string]uuid.UUID } func (f *fakeResolver) ResolveSession(_ context.Context, token string) (uuid.UUID, bool, error) { uid, ok := f.valid[token] return uid, ok, nil } // fakeAdmin 始终返回 false。 type fakeAdmin struct{} func (fakeAdmin) IsAdmin(_ context.Context, _ uuid.UUID) (bool, error) { return false, nil } func TestHandler_CreateWorkspace_Smoke(t *testing.T) { t.Parallel() ws := &fakeWS{} uid := uuid.New() tok := "tok-1" resolver := &fakeResolver{valid: map[string]uuid.UUID{tok: uid}} h := NewHandler(ws, nil, nil, resolver, fakeAdmin{}) r := chi.NewRouter() r.Use(middleware.RequestID) h.Mount(r) body, _ := json.Marshal(createWorkspaceReq{ Slug: "ws1", Name: "W1", GitRemoteURL: "https://x", Credential: credentialBody{Kind: "none"}, }) req := httptest.NewRequest("POST", "/api/v1/projects/p/workspaces", bytes.NewReader(body)) req.Header.Set("Authorization", "Bearer "+tok) w := httptest.NewRecorder() r.ServeHTTP(w, req) require.Equal(t, http.StatusCreated, w.Code) } func TestHandler_ListBranches_Smoke(t *testing.T) { t.Parallel() ws := &fakeWS{} uid := uuid.New() tok := "tok-branches" resolver := &fakeResolver{valid: map[string]uuid.UUID{tok: uid}} h := NewHandler(ws, nil, nil, resolver, fakeAdmin{}) r := chi.NewRouter() r.Use(middleware.RequestID) h.Mount(r) wsID := uuid.New() req := httptest.NewRequest("GET", "/api/v1/workspaces/"+wsID.String()+"/branches", nil) req.Header.Set("Authorization", "Bearer "+tok) w := httptest.NewRecorder() r.ServeHTTP(w, req) require.Equal(t, http.StatusOK, w.Code) var resp branchListResp require.NoError(t, json.NewDecoder(w.Body).Decode(&resp)) require.Equal(t, []string{"main", "develop"}, resp.Branches) }