You've already forked agentic-coding-workflow
bugfix
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
package changerequest
|
||||
|
||||
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/infra/errs"
|
||||
"github.com/yan1h/agent-coding-workflow/internal/transport/http/middleware"
|
||||
)
|
||||
|
||||
// fakeSvc implements Service for handler tests.
|
||||
type fakeSvc struct {
|
||||
mergeErr error
|
||||
cr *ChangeRequest
|
||||
}
|
||||
|
||||
func (f *fakeSvc) Create(_ context.Context, c Caller, wsID uuid.UUID, _ CreateInput) (*ChangeRequest, error) {
|
||||
return &ChangeRequest{ID: uuid.New(), WorkspaceID: wsID, Number: 1, State: StateOpen, ReviewVerdict: VerdictPending, CreatedBy: c.UserID}, nil
|
||||
}
|
||||
func (f *fakeSvc) Get(_ context.Context, _ Caller, id uuid.UUID) (*ChangeRequest, error) {
|
||||
return &ChangeRequest{ID: id, State: StateOpen}, nil
|
||||
}
|
||||
func (f *fakeSvc) GetByNumber(_ context.Context, _ Caller, _ string, n int) (*ChangeRequest, error) {
|
||||
return &ChangeRequest{ID: uuid.New(), Number: n}, nil
|
||||
}
|
||||
func (f *fakeSvc) ListByWorkspace(_ context.Context, _ Caller, wsID uuid.UUID) ([]*ChangeRequest, error) {
|
||||
return []*ChangeRequest{{ID: uuid.New(), WorkspaceID: wsID, Number: 1}}, nil
|
||||
}
|
||||
func (f *fakeSvc) Review(_ context.Context, _ Caller, id uuid.UUID, v Verdict, _ string) (*ChangeRequest, error) {
|
||||
return &ChangeRequest{ID: id, ReviewVerdict: v}, nil
|
||||
}
|
||||
func (f *fakeSvc) Merge(_ context.Context, _ Caller, id uuid.UUID, _ string) (*ChangeRequest, error) {
|
||||
if f.mergeErr != nil {
|
||||
return nil, f.mergeErr
|
||||
}
|
||||
return &ChangeRequest{ID: id, State: StateMerged}, nil
|
||||
}
|
||||
func (f *fakeSvc) SyncStatus(_ context.Context, _ Caller, id uuid.UUID) (*ChangeRequest, error) {
|
||||
return &ChangeRequest{ID: id, CIState: CISuccess}, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type fakeAdmin struct{}
|
||||
|
||||
func (fakeAdmin) IsAdmin(_ context.Context, _ uuid.UUID) (bool, error) { return false, nil }
|
||||
|
||||
func newTestHandler(svc Service, tok string, uid uuid.UUID) chi.Router {
|
||||
resolver := &fakeResolver{valid: map[string]uuid.UUID{tok: uid}}
|
||||
h := NewHandler(svc, resolver, fakeAdmin{})
|
||||
r := chi.NewRouter()
|
||||
r.Use(middleware.RequestID)
|
||||
h.Mount(r)
|
||||
return r
|
||||
}
|
||||
|
||||
func TestHandler_Unauthenticated(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := newTestHandler(&fakeSvc{}, "tok", uuid.New())
|
||||
req := httptest.NewRequest("GET", "/api/v1/workspaces/"+uuid.NewString()+"/change-requests", nil)
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusUnauthorized, w.Code)
|
||||
}
|
||||
|
||||
func TestHandler_CreateAndList(t *testing.T) {
|
||||
t.Parallel()
|
||||
uid := uuid.New()
|
||||
r := newTestHandler(&fakeSvc{}, "tok", uid)
|
||||
wsID := uuid.New()
|
||||
|
||||
body, _ := json.Marshal(createReq{SourceBranch: "feat", Title: "T"})
|
||||
req := httptest.NewRequest("POST", "/api/v1/workspaces/"+wsID.String()+"/change-requests", bytes.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer tok")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusCreated, w.Code)
|
||||
|
||||
req = httptest.NewRequest("GET", "/api/v1/workspaces/"+wsID.String()+"/change-requests", nil)
|
||||
req.Header.Set("Authorization", "Bearer tok")
|
||||
w = httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusOK, w.Code)
|
||||
}
|
||||
|
||||
func TestHandler_MergeGateReturns412(t *testing.T) {
|
||||
t.Parallel()
|
||||
svc := &fakeSvc{mergeErr: errs.New(errs.CodeFailedPrecondition, "merge blocked: review not approved")}
|
||||
r := newTestHandler(svc, "tok", uuid.New())
|
||||
|
||||
req := httptest.NewRequest("POST", "/api/v1/change-requests/"+uuid.NewString()+"/merge", nil)
|
||||
req.Header.Set("Authorization", "Bearer tok")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusPreconditionFailed, w.Code)
|
||||
}
|
||||
|
||||
func TestHandler_MergeHappyPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := newTestHandler(&fakeSvc{}, "tok", uuid.New())
|
||||
|
||||
req := httptest.NewRequest("POST", "/api/v1/change-requests/"+uuid.NewString()+"/merge", bytes.NewReader([]byte(`{"method":"squash"}`)))
|
||||
req.Header.Set("Authorization", "Bearer tok")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var resp changeRequestResp
|
||||
require.NoError(t, json.NewDecoder(w.Body).Decode(&resp))
|
||||
require.Equal(t, string(StateMerged), resp.State)
|
||||
}
|
||||
|
||||
func TestHandler_Review(t *testing.T) {
|
||||
t.Parallel()
|
||||
r := newTestHandler(&fakeSvc{}, "tok", uuid.New())
|
||||
|
||||
body, _ := json.Marshal(reviewReq{Verdict: "approved", Note: "lgtm"})
|
||||
req := httptest.NewRequest("POST", "/api/v1/change-requests/"+uuid.NewString()+"/review", bytes.NewReader(body))
|
||||
req.Header.Set("Authorization", "Bearer tok")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
require.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var resp changeRequestResp
|
||||
require.NoError(t, json.NewDecoder(w.Body).Decode(&resp))
|
||||
require.Equal(t, "approved", resp.ReviewVerdict)
|
||||
}
|
||||
Reference in New Issue
Block a user