This commit is contained in:
2026-06-23 05:02:15 +08:00
commit e6f1776d4f
264 changed files with 54215 additions and 0 deletions
+163
View File
@@ -0,0 +1,163 @@
package webhook_test
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net"
"net/http"
"testing"
"time"
"superwork-tui/internal/webhook"
)
// freePort returns a random available TCP port on localhost.
func freePort(t *testing.T) int {
t.Helper()
l, err := net.Listen("tcp", ":0")
if err != nil {
t.Fatalf("freePort: %v", err)
}
port := l.Addr().(*net.TCPAddr).Port
l.Close()
return port
}
func TestServerLifecycle_EventArrivesViaChannel(t *testing.T) {
ch := make(chan webhook.Event, 4)
srv := webhook.NewServer(func(ev webhook.Event) {
ch <- ev
})
port := freePort(t)
addr := fmt.Sprintf(":%d", port)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
errCh := make(chan error, 1)
go func() {
errCh <- srv.Start(ctx, addr)
}()
// Wait until the server accepts connections.
deadline := time.Now().Add(2 * time.Second)
for time.Now().Before(deadline) {
conn, err := net.DialTimeout("tcp", addr, 50*time.Millisecond)
if err == nil {
conn.Close()
break
}
time.Sleep(20 * time.Millisecond)
}
// POST a push event.
payload := map[string]any{
"ref": "refs/heads/main",
}
body, _ := json.Marshal(payload)
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
fmt.Sprintf("http://localhost%s/webhook", addr), bytes.NewReader(body))
if err != nil {
t.Fatalf("build request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitea-Event", "push")
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("POST /webhook: %v", err)
}
resp.Body.Close()
if resp.StatusCode != http.StatusOK {
t.Fatalf("want 200, got %d", resp.StatusCode)
}
// Expect a PushEvent on the channel.
select {
case ev := <-ch:
pushEv, ok := ev.(webhook.PushEvent)
if !ok {
t.Fatalf("want PushEvent, got %T", ev)
}
if pushEv.Branch != "main" {
t.Errorf("want Branch=main, got %q", pushEv.Branch)
}
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for PushEvent")
}
// Cancel context → server shuts down; Start should return.
cancel()
select {
case <-errCh:
// OK — server stopped
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for server shutdown")
}
}
func TestServerLifecycle_IssueCommentEvent(t *testing.T) {
ch := make(chan webhook.Event, 4)
srv := webhook.NewServer(func(ev webhook.Event) {
ch <- ev
})
port := freePort(t)
addr := fmt.Sprintf(":%d", port)
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
go srv.Start(ctx, addr) //nolint:errcheck
deadline := time.Now().Add(2 * time.Second)
for time.Now().Before(deadline) {
conn, err := net.DialTimeout("tcp", addr, 50*time.Millisecond)
if err == nil {
conn.Close()
break
}
time.Sleep(20 * time.Millisecond)
}
payload := map[string]any{
"action": "created",
"issue": map[string]any{
"number": float64(42),
},
"comment": map[string]any{
"body": "<!-- spx:review=1 -->\nLooks good",
"html_url": "https://example.com/comment/1",
},
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequestWithContext(ctx, http.MethodPost,
fmt.Sprintf("http://localhost%s/webhook", addr), bytes.NewReader(body))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Gitea-Event", "issue_comment")
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("POST /webhook: %v", err)
}
resp.Body.Close()
select {
case ev := <-ch:
ce, ok := ev.(webhook.IssueCommentEvent)
if !ok {
t.Fatalf("want IssueCommentEvent, got %T", ev)
}
if ce.IssueNumber != 42 {
t.Errorf("want IssueNumber=42, got %d", ce.IssueNumber)
}
if !webhook.IsReviewMarker(ce.CommentBody) {
t.Errorf("expected comment to contain review marker")
}
case <-time.After(2 * time.Second):
t.Fatal("timed out waiting for IssueCommentEvent")
}
}