Files
chenhg5-cc-connect/core/webhook_test.go
chenhg5 6ae088a658 feat(webhook): add webhook server for external integrations
Add webhook server functionality with configurable authentication, path and port settings. Supports triggering agent prompts or executing shell commands via HTTP POST requests. Includes webhook configuration in config, example documentation in config.example.toml, implementation with tests, and integration into main application startup/shutdown.

generated by llmgit

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-14 11:33:59 +08:00

105 lines
3.0 KiB
Go

package core
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
)
func TestWebhookServer_AuthBearer(t *testing.T) {
ws := NewWebhookServer(0, "my-secret", "/hook")
r := httptest.NewRequest(http.MethodPost, "/hook", nil)
r.Header.Set("Authorization", "Bearer my-secret")
if !ws.authenticate(r) {
t.Error("expected auth to succeed with correct Bearer token")
}
r.Header.Set("Authorization", "Bearer wrong")
if ws.authenticate(r) {
t.Error("expected auth to fail with wrong Bearer token")
}
}
func TestWebhookServer_AuthHeader(t *testing.T) {
ws := NewWebhookServer(0, "tok123", "/hook")
r := httptest.NewRequest(http.MethodPost, "/hook", nil)
r.Header.Set("X-Webhook-Token", "tok123")
if !ws.authenticate(r) {
t.Error("expected auth to succeed with X-Webhook-Token")
}
}
func TestWebhookServer_AuthQuery(t *testing.T) {
ws := NewWebhookServer(0, "qsecret", "/hook")
r := httptest.NewRequest(http.MethodPost, "/hook?token=qsecret", nil)
if !ws.authenticate(r) {
t.Error("expected auth to succeed with query token")
}
}
func TestWebhookServer_NoTokenRequired(t *testing.T) {
ws := NewWebhookServer(0, "", "/hook")
r := httptest.NewRequest(http.MethodPost, "/hook", nil)
if !ws.authenticate(r) {
t.Error("expected auth to pass when no token configured")
}
}
func TestWebhookServer_HandleHook_MethodNotAllowed(t *testing.T) {
ws := NewWebhookServer(0, "", "/hook")
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/hook", nil)
ws.handleHook(w, r)
if w.Code != http.StatusMethodNotAllowed {
t.Errorf("expected 405, got %d", w.Code)
}
}
func TestWebhookServer_HandleHook_Unauthorized(t *testing.T) {
ws := NewWebhookServer(0, "secret", "/hook")
w := httptest.NewRecorder()
body, _ := json.Marshal(WebhookRequest{SessionKey: "tg:1:1", Prompt: "hi"})
r := httptest.NewRequest(http.MethodPost, "/hook", bytes.NewReader(body))
ws.handleHook(w, r)
if w.Code != http.StatusUnauthorized {
t.Errorf("expected 401, got %d", w.Code)
}
}
func TestWebhookServer_HandleHook_Validation(t *testing.T) {
ws := NewWebhookServer(0, "", "/hook")
tests := []struct {
name string
body WebhookRequest
code int
}{
{"missing session_key", WebhookRequest{Prompt: "hi"}, http.StatusBadRequest},
{"missing prompt and exec", WebhookRequest{SessionKey: "tg:1:1"}, http.StatusBadRequest},
{"both prompt and exec", WebhookRequest{SessionKey: "tg:1:1", Prompt: "hi", Exec: "ls"}, http.StatusBadRequest},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := httptest.NewRecorder()
body, _ := json.Marshal(tt.body)
r := httptest.NewRequest(http.MethodPost, "/hook", bytes.NewReader(body))
ws.handleHook(w, r)
if w.Code != tt.code {
t.Errorf("expected %d, got %d: %s", tt.code, w.Code, w.Body.String())
}
})
}
}
func TestWebhookServer_DefaultValues(t *testing.T) {
ws := NewWebhookServer(0, "", "")
if ws.port != 9111 {
t.Errorf("expected default port 9111, got %d", ws.port)
}
if ws.path != "/hook" {
t.Errorf("expected default path /hook, got %s", ws.path)
}
}