Files
superwork/tui/internal/webhook/server_test.go
T
2026-06-23 05:02:15 +08:00

215 lines
6.4 KiB
Go

package webhook_test
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"superwork-tui/internal/webhook"
)
func post(t *testing.T, srv *webhook.Server, path, eventHeader, body string) *httptest.ResponseRecorder {
t.Helper()
req := httptest.NewRequest(http.MethodPost, path, bytes.NewBufferString(body))
req.Header.Set("X-Gitea-Event", eventHeader)
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
srv.ServeHTTP(w, req)
return w
}
func TestServer_PREvent(t *testing.T) {
var got webhook.Event
srv := webhook.NewServer(func(e webhook.Event) { got = e })
payload := `{"action":"opened","pull_request":{"number":7,"html_url":"http://x/pr/7","head":{"ref":"feat/my-branch"},"title":"My PR","body":"Closes #3"}}`
w := post(t, srv, "/webhook", "pull_request", payload)
if w.Code != 200 {
t.Fatalf("want 200, got %d", w.Code)
}
pr, ok := got.(webhook.PrEvent)
if !ok {
t.Fatalf("want PrEvent, got %T", got)
}
if pr.Action != "opened" {
t.Errorf("action: want opened, got %q", pr.Action)
}
if pr.PR != "7" {
t.Errorf("pr: want 7, got %q", pr.PR)
}
if pr.Branch != "feat/my-branch" {
t.Errorf("branch: %q", pr.Branch)
}
if pr.HTMLUrl != "http://x/pr/7" {
t.Errorf("htmlUrl: %q", pr.HTMLUrl)
}
if pr.Title != "My PR" {
t.Errorf("title: %q", pr.Title)
}
if pr.Body != "Closes #3" {
t.Errorf("body: %q", pr.Body)
}
if pr.IssueNumber != 0 {
t.Errorf("issueNumber should be 0 on canonical route, got %d", pr.IssueNumber)
}
}
func TestServer_PREventLegacyRoute(t *testing.T) {
var got webhook.Event
srv := webhook.NewServer(func(e webhook.Event) { got = e })
payload := `{"action":"opened","pull_request":{"number":7,"html_url":"http://x/pr/7","head":{"ref":"feat/x"},"title":"T","body":""}}`
w := post(t, srv, "/webhook/42", "pull_request", payload)
if w.Code != 200 {
t.Fatalf("want 200, got %d", w.Code)
}
pr := got.(webhook.PrEvent)
if pr.IssueNumber != 42 {
t.Errorf("issueNumber: want 42, got %d", pr.IssueNumber)
}
}
func TestServer_IssueEvent(t *testing.T) {
var got webhook.Event
srv := webhook.NewServer(func(e webhook.Event) { got = e })
payload := `{"action":"opened","issue":{"number":5,"html_url":"http://x/issues/5","title":"Issue title","body":"some body"}}`
w := post(t, srv, "/webhook", "issues", payload)
if w.Code != 200 {
t.Fatalf("want 200, got %d", w.Code)
}
ev, ok := got.(webhook.IssueEvent)
if !ok {
t.Fatalf("want IssueEvent, got %T", got)
}
if ev.Action != "opened" {
t.Errorf("action: %q", ev.Action)
}
if ev.IssueNumber != 5 {
t.Errorf("issueNumber: %d", ev.IssueNumber)
}
if ev.Title != "Issue title" {
t.Errorf("title: %q", ev.Title)
}
if ev.Body != "some body" {
t.Errorf("body: %q", ev.Body)
}
if ev.HTMLUrl != "http://x/issues/5" {
t.Errorf("htmlUrl: %q", ev.HTMLUrl)
}
}
func TestServer_IssueCommentEvent_OnPR(t *testing.T) {
var got webhook.Event
srv := webhook.NewServer(func(e webhook.Event) { got = e })
// issue.pull_request non-null → prNumber = issue.number
payload := `{"action":"created","issue":{"number":9,"pull_request":{"merged_at":null}},"comment":{"body":"<!-- spx:review=1 -->","html_url":"http://x/c/1"}}`
w := post(t, srv, "/webhook", "issue_comment", payload)
if w.Code != 200 {
t.Fatalf("want 200, got %d", w.Code)
}
ev, ok := got.(webhook.IssueCommentEvent)
if !ok {
t.Fatalf("want IssueCommentEvent, got %T", got)
}
if ev.IssueNumber != 9 {
t.Errorf("issueNumber: %d", ev.IssueNumber)
}
if ev.PRNumber != 9 {
t.Errorf("prNumber: want 9 (PR comment), got %d", ev.PRNumber)
}
if ev.CommentBody != "<!-- spx:review=1 -->" {
t.Errorf("commentBody: %q", ev.CommentBody)
}
}
func TestServer_IssueCommentEvent_NotOnPR(t *testing.T) {
var got webhook.Event
srv := webhook.NewServer(func(e webhook.Event) { got = e })
payload := `{"action":"created","issue":{"number":9},"comment":{"body":"hello","html_url":"http://x/c/2"}}`
w := post(t, srv, "/webhook", "issue_comment", payload)
if w.Code != 200 {
t.Fatalf("want 200, got %d", w.Code)
}
ev := got.(webhook.IssueCommentEvent)
if ev.PRNumber != 0 {
t.Errorf("prNumber: want 0 (not a PR), got %d", ev.PRNumber)
}
}
func TestServer_PushEvent(t *testing.T) {
var got webhook.Event
srv := webhook.NewServer(func(e webhook.Event) { got = e })
payload := `{"ref":"refs/heads/main"}`
w := post(t, srv, "/webhook", "push", payload)
if w.Code != 200 {
t.Fatalf("want 200, got %d", w.Code)
}
ev, ok := got.(webhook.PushEvent)
if !ok {
t.Fatalf("want PushEvent, got %T", got)
}
if ev.Branch != "main" {
t.Errorf("branch: want main, got %q", ev.Branch)
}
}
func TestServer_MalformedJSON_Returns400(t *testing.T) {
called := false
srv := webhook.NewServer(func(e webhook.Event) { called = true })
w := post(t, srv, "/webhook", "pull_request", "{bad json")
if w.Code != 400 {
t.Fatalf("want 400, got %d", w.Code)
}
if called {
t.Error("OnEvent should not be called for malformed JSON")
}
}
func TestServer_WrongMethod_Returns405(t *testing.T) {
srv := webhook.NewServer(func(e webhook.Event) {})
req := httptest.NewRequest(http.MethodGet, "/webhook", nil)
w := httptest.NewRecorder()
srv.ServeHTTP(w, req)
if w.Code != 405 {
t.Fatalf("want 405, got %d", w.Code)
}
}
func TestServer_UnknownPath_Returns404(t *testing.T) {
srv := webhook.NewServer(func(e webhook.Event) {})
req := httptest.NewRequest(http.MethodPost, "/unknown", nil)
w := httptest.NewRecorder()
srv.ServeHTTP(w, req)
if w.Code != 404 {
t.Fatalf("want 404, got %d", w.Code)
}
}
func TestServer_NonMatchingEventHeader_Returns200_NoEvent(t *testing.T) {
called := false
srv := webhook.NewServer(func(e webhook.Event) { called = true })
// push event but missing ref → null parse → no event emitted, still 200
w := post(t, srv, "/webhook", "push", `{"action":"opened"}`)
if w.Code != 200 {
t.Fatalf("want 200, got %d", w.Code)
}
if called {
t.Error("OnEvent should not be called when event doesn't parse")
}
}
func TestServer_ResponseBodyIsJSON(t *testing.T) {
srv := webhook.NewServer(func(e webhook.Event) {})
payload := `{"action":"opened","pull_request":{"number":1,"html_url":"http://x","head":{"ref":"x"},"title":"","body":""}}`
w := post(t, srv, "/webhook", "pull_request", payload)
var resp map[string]any
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
t.Fatalf("response not JSON: %v", err)
}
if resp["ok"] != true {
t.Errorf("want ok:true, got %v", resp["ok"])
}
}