agent-orchestrator/backend/internal/httpd/controllers/prs_test.go

160 lines
5.0 KiB
Go

package controllers_test
import (
"context"
"io"
"log/slog"
"net/http"
"net/http/httptest"
"testing"
"github.com/aoagents/agent-orchestrator/backend/internal/config"
"github.com/aoagents/agent-orchestrator/backend/internal/httpd"
prsvc "github.com/aoagents/agent-orchestrator/backend/internal/service/pr"
)
type fakePRService struct {
mergeResult prsvc.MergeResult
mergeErr error
resolveResult prsvc.ResolveResult
resolveErr error
}
func (f *fakePRService) Merge(_ context.Context, _ string) (prsvc.MergeResult, error) {
return f.mergeResult, f.mergeErr
}
func (f *fakePRService) ResolveComments(_ context.Context, _ string, _ []string) (prsvc.ResolveResult, error) {
return f.resolveResult, f.resolveErr
}
func newPRTestServer(t *testing.T, svc prsvc.ActionManager) *httptest.Server {
t.Helper()
log := slog.New(slog.NewTextHandler(io.Discard, nil))
srv := httptest.NewServer(httpd.NewRouterWithControl(config.Config{}, log, nil, httpd.APIDeps{PRs: svc}, httpd.ControlDeps{}))
t.Cleanup(srv.Close)
return srv
}
// ---- Nil service → 503 SCM_NOT_CONFIGURED ----
func TestPRsRoutes_NilService_MergeReturns501(t *testing.T) {
srv := newPRTestServer(t, nil)
body, status, headers := doRequest(t, srv, "POST", "/api/v1/prs/1/merge", "")
assertJSON(t, headers)
assertErrorCode(t, body, status, http.StatusNotImplemented, "NOT_IMPLEMENTED")
}
func TestPRsRoutes_NilService_ResolveCommentsReturns501(t *testing.T) {
srv := newPRTestServer(t, nil)
body, status, headers := doRequest(t, srv, "POST", "/api/v1/prs/1/resolve-comments", "")
assertJSON(t, headers)
assertErrorCode(t, body, status, http.StatusNotImplemented, "NOT_IMPLEMENTED")
}
// ---- Merge: 200 ----
func TestPRsRoutes_Merge_200(t *testing.T) {
svc := &fakePRService{mergeResult: prsvc.MergeResult{PRNumber: 42, Method: "squash"}}
srv := newPRTestServer(t, svc)
body, status, _ := doRequest(t, srv, "POST", "/api/v1/prs/42/merge", "")
if status != http.StatusOK {
t.Fatalf("status = %d, want 200; body=%s", status, body)
}
var resp struct {
OK bool `json:"ok"`
PRNumber int `json:"prNumber"`
Method string `json:"method"`
}
mustJSON(t, body, &resp)
if !resp.OK || resp.PRNumber != 42 || resp.Method != "squash" {
t.Errorf("resp = %+v, want {ok:true prNumber:42 method:squash}", resp)
}
}
// ---- Merge: 404 ----
func TestPRsRoutes_Merge_404(t *testing.T) {
svc := &fakePRService{mergeErr: prsvc.ErrPRNotFound}
srv := newPRTestServer(t, svc)
body, status, headers := doRequest(t, srv, "POST", "/api/v1/prs/99/merge", "")
assertJSON(t, headers)
assertErrorCode(t, body, status, http.StatusNotFound, "PR_NOT_FOUND")
}
// ---- Merge: 409 ----
func TestPRsRoutes_Merge_409(t *testing.T) {
svc := &fakePRService{mergeErr: prsvc.ErrPRNotMergeable}
srv := newPRTestServer(t, svc)
body, status, headers := doRequest(t, srv, "POST", "/api/v1/prs/1/merge", "")
assertJSON(t, headers)
assertErrorCode(t, body, status, http.StatusConflict, "PR_NOT_MERGEABLE")
}
// ---- Merge: 422 ----
func TestPRsRoutes_Merge_422(t *testing.T) {
svc := &fakePRService{mergeErr: prsvc.ErrPRPreconditions}
srv := newPRTestServer(t, svc)
body, status, headers := doRequest(t, srv, "POST", "/api/v1/prs/1/merge", "")
assertJSON(t, headers)
assertErrorCode(t, body, status, http.StatusUnprocessableEntity, "PR_PRECONDITIONS_UNMET")
}
// ---- ResolveComments: 200 ----
func TestPRsRoutes_ResolveComments_200(t *testing.T) {
svc := &fakePRService{resolveResult: prsvc.ResolveResult{Resolved: 3}}
srv := newPRTestServer(t, svc)
body, status, _ := doRequest(t, srv, "POST", "/api/v1/prs/42/resolve-comments", `{"commentIds":["T_1","T_2","T_3"]}`)
if status != http.StatusOK {
t.Fatalf("status = %d, want 200; body=%s", status, body)
}
var resp struct {
OK bool `json:"ok"`
Resolved int `json:"resolved"`
}
mustJSON(t, body, &resp)
if !resp.OK || resp.Resolved != 3 {
t.Errorf("resp = %+v, want {ok:true resolved:3}", resp)
}
}
func TestPRsRoutes_ResolveComments_200_NoBody(t *testing.T) {
svc := &fakePRService{resolveResult: prsvc.ResolveResult{Resolved: 2}}
srv := newPRTestServer(t, svc)
body, status, _ := doRequest(t, srv, "POST", "/api/v1/prs/42/resolve-comments", "")
if status != http.StatusOK {
t.Fatalf("status = %d, want 200; body=%s", status, body)
}
}
// ---- ResolveComments: 404 ----
func TestPRsRoutes_ResolveComments_404(t *testing.T) {
svc := &fakePRService{resolveErr: prsvc.ErrPRNotFound}
srv := newPRTestServer(t, svc)
body, status, headers := doRequest(t, srv, "POST", "/api/v1/prs/99/resolve-comments", "")
assertJSON(t, headers)
assertErrorCode(t, body, status, http.StatusNotFound, "PR_NOT_FOUND")
}
// ---- ResolveComments: 422 ----
func TestPRsRoutes_ResolveComments_422(t *testing.T) {
svc := &fakePRService{resolveErr: prsvc.ErrNothingToResolve}
srv := newPRTestServer(t, svc)
body, status, headers := doRequest(t, srv, "POST", "/api/v1/prs/1/resolve-comments", "")
assertJSON(t, headers)
assertErrorCode(t, body, status, http.StatusUnprocessableEntity, "NOTHING_TO_RESOLVE")
}