feat(receiver): storage layer and webhook payload compat
Dual-dialect store (SQLite via modernc.org, MySQL via go-sql-driver, both pure Go) with order-tolerant start/complete upserts, filtered and paginated listing, and aggregate queries (per-day, top domains, query types, statuses, duration percentiles, top clients). Sender gains optional EXPLOREDNS_WEBHOOK_TOKEN bearer auth; a round-trip test pins receiver structs byte-compatible with the sender payloads. Note: go directive moves to 1.25.0, required by modernc.org/sqlite. CI reads the version from go.mod so GOTOOLCHAIN=local stays satisfied. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d96f25b1d6
commit
e8f56a1ef4
+31
-1
@@ -235,7 +235,37 @@ func TestWebhook_RetriesOnceOnFailure(t *testing.T) {
|
||||
func TestWebhook_NilReporterSafe(t *testing.T) {
|
||||
var wr *webhookReporter
|
||||
wr.send("start", map[string]string{"event": "start"}) // must not panic
|
||||
if newWebhookReporter("") != nil {
|
||||
if newWebhookReporter("", "token") != nil {
|
||||
t.Fatal("empty URL should disable the webhook reporter")
|
||||
}
|
||||
}
|
||||
|
||||
// TestWebhook_BearerToken verifies the Authorization header is sent exactly
|
||||
// when a token is configured (EXPLOREDNS_WEBHOOK_TOKEN on the real path).
|
||||
func TestWebhook_BearerToken(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name, token, wantAuth string
|
||||
}{
|
||||
{"token set", "s3cret", "Bearer s3cret"},
|
||||
{"token unset", "", ""},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
done := make(chan string, 1)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
done <- r.Header.Get("Authorization")
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
newWebhookReporter(ts.URL, tc.token).send("start", map[string]string{"event": "start"})
|
||||
|
||||
select {
|
||||
case got := <-done:
|
||||
if got != tc.wantAuth {
|
||||
t.Fatalf("Authorization = %q, want %q", got, tc.wantAuth)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("webhook was not delivered")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user