agent-orchestrator/backend/internal/service/pr/manager_test.go

88 lines
3.0 KiB
Go

package pr
import (
"context"
"testing"
"time"
"github.com/aoagents/agent-orchestrator/backend/internal/domain"
"github.com/aoagents/agent-orchestrator/backend/internal/ports"
)
type fakeWriter struct {
pr map[domain.SessionID]domain.PullRequest
comments map[string][]domain.PullRequestComment
checks []domain.PullRequestCheck
}
func (f *fakeWriter) WritePR(_ context.Context, pr domain.PullRequest, checks []domain.PullRequestCheck, comments []domain.PullRequestComment) error {
f.pr[pr.SessionID] = pr
f.checks = append(f.checks, checks...)
f.comments[pr.URL] = comments
return nil
}
type fakeLifecycle struct {
observed []ports.PRObservation
}
func (f *fakeLifecycle) ApplyPRObservation(_ context.Context, _ domain.SessionID, o ports.PRObservation) error {
f.observed = append(f.observed, o)
return nil
}
func newPRManager() (*Manager, *fakeWriter, *fakeLifecycle) {
fw := &fakeWriter{pr: map[domain.SessionID]domain.PullRequest{}, comments: map[string][]domain.PullRequestComment{}}
fl := &fakeLifecycle{}
m := New(Deps{
Writer: fw,
Lifecycle: fl,
Clock: func() time.Time { return time.Unix(1, 0).UTC() },
})
return m, fw, fl
}
func TestApplyObservation_WritesPRChecksAndComments(t *testing.T) {
m, fw, fl := newPRManager()
o := ports.PRObservation{
Fetched: true, URL: "https://example/pr/1", Number: 1, CI: domain.CIFailing,
Checks: []ports.PRCheckObservation{{Name: "build", CommitHash: "c1", Status: domain.PRCheckFailed, LogTail: "boom"}},
Comments: []ports.PRCommentObservation{{ID: "1", Author: "greptileai", Body: "use a constant here"}},
}
if err := m.ApplyObservation(context.Background(), "mer-1", o); err != nil {
t.Fatal(err)
}
if got := fw.pr["mer-1"]; got.URL != o.URL || got.CI != domain.CIFailing {
t.Fatalf("pr not written: %+v", got)
}
if len(fw.checks) != 1 || fw.checks[0].CreatedAt.IsZero() {
t.Fatalf("checks not normalized: %+v", fw.checks)
}
if len(fw.comments[o.URL]) != 1 || fw.comments[o.URL][0].CreatedAt.IsZero() {
t.Fatalf("comments not normalized: %+v", fw.comments)
}
if len(fl.observed) != 1 || fl.observed[0].URL != o.URL {
t.Fatalf("PR observation should be forwarded to lifecycle, got %v", fl.observed)
}
}
func TestApplyObservation_MergedForwardsToLifecycle(t *testing.T) {
m, _, fl := newPRManager()
if err := m.ApplyObservation(context.Background(), "mer-1", ports.PRObservation{Fetched: true, URL: "pr1", Number: 1, Merged: true}); err != nil {
t.Fatal(err)
}
if len(fl.observed) != 1 || !fl.observed[0].Merged {
t.Fatalf("merged PR should be forwarded to lifecycle, got %v", fl.observed)
}
}
func TestApplyObservation_FailedFetchIsDropped(t *testing.T) {
m, fw, fl := newPRManager()
if err := m.ApplyObservation(context.Background(), "mer-1", ports.PRObservation{Fetched: false, URL: "pr1", CI: domain.CIFailing}); err != nil {
t.Fatal(err)
}
if len(fw.pr) != 0 || len(fl.observed) != 0 {
t.Fatalf("failed fetch must write nothing, pr=%v observed=%v", fw.pr, fl.observed)
}
}