package app import ( "net/http" "net/http/httptest" "strings" "testing" "time" "git.warky.dev/wdevs/amcs/internal/config" ) func TestParseWebhookThoughtRequestRequiresJSON(t *testing.T) { req := httptestRequest("text/plain", `{"content":"hello"}`) _, err := parseWebhookThoughtRequest(req) if err == nil { t.Fatal("expected error for non-json content type") } } func TestParseWebhookThoughtRequestRequiresContent(t *testing.T) { req := httptestRequest("application/json", `{"source":"n8n"}`) _, err := parseWebhookThoughtRequest(req) if err == nil || !strings.Contains(err.Error(), "content is required") { t.Fatalf("error = %v, want content required", err) } } func TestBuildWebhookMetadataUsesHeaderIdempotencyAndSanitizesMetadata(t *testing.T) { now := time.Date(2026, 7, 15, 4, 0, 0, 0, time.UTC) got := buildWebhookMetadata(webhookThoughtRequest{ ExternalID: " ext-1 ", Metadata: map[string]any{ "service": "n8n", "unsafe": struct{}{}, "nested": map[string]any{"ok": true}, }, }, " key-1 ", now) if got.IDempotencyKey != "key-1" { t.Fatalf("IDempotencyKey = %q, want key-1", got.IDempotencyKey) } if got.ExternalID != "ext-1" { t.Fatalf("ExternalID = %q, want ext-1", got.ExternalID) } if got.ReceivedAt != "2026-07-15T04:00:00Z" { t.Fatalf("ReceivedAt = %q", got.ReceivedAt) } if _, ok := got.SourceMetadata["unsafe"]; ok { t.Fatal("unsafe metadata value was not removed") } if got.SourceMetadata["service"] != "n8n" { t.Fatalf("service metadata = %#v", got.SourceMetadata["service"]) } } func TestNormalizeWebhookThoughtMetadata(t *testing.T) { webhookMeta := buildWebhookMetadata(webhookThoughtRequest{IDempotencyKey: "abc"}, "", time.Date(2026, 7, 15, 4, 0, 0, 0, time.UTC)) got := normalizeWebhookThoughtMetadata(webhookThoughtRequest{ Source: "github", Type: "task", Topics: []string{"ci", "ci", ""}, People: []string{" Sam "}, }, webhookMeta, config.CaptureConfig{}) if got.Source != "github" { t.Fatalf("Source = %q, want github", got.Source) } if got.Type != "task" { t.Fatalf("Type = %q, want task", got.Type) } if len(got.Topics) != 1 || got.Topics[0] != "ci" { t.Fatalf("Topics = %#v, want [ci]", got.Topics) } if got.Webhook == nil || got.Webhook.IDempotencyKey != "abc" { t.Fatalf("Webhook = %#v, want idempotency key abc", got.Webhook) } } func httptestRequest(contentType, body string) *http.Request { req := httptest.NewRequest(http.MethodPost, "/webhooks/thoughts", strings.NewReader(body)) req.Header.Set("Content-Type", contentType) return req }