Files
dnswatcher/internal/notify/notify_test.go
T
clawbot 5e2c456e85
check / check (push) Canceled after 0s
notify: the log names a notification endpoint, not its webhook URL (closes #288)
With debug logging on, each delivery logged the full Slack, Mattermost
or ntfy URL, whose path or query lets anyone who has it post to the
channel or topic. The two debug lines now give the endpoint's name and
the title; sendSlack is told which of Slack or Mattermost it sends to.
A webhook URL that does not parse gave a startup error quoting the
whole URL; it now gives only the reason. Errors from a failed request
come from the transport, not from an HTTP client, and carry no part of
the path or query; a test now checks that too.

Model: opus-5-5
2026-10-15 14:48:17 +02:00

118 lines
2.4 KiB
Go

package notify_test
import (
"testing"
"sneak.berlin/go/dnswatcher/internal/notify"
)
func TestValidateWebhookURLValid(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input string
wantURL string
}{
{
name: "valid https URL",
input: "https://hooks.slack.com/T00/B00",
wantURL: "https://hooks.slack.com/T00/B00",
},
{
name: "valid http URL",
input: "http://localhost:8080/webhook",
wantURL: "http://localhost:8080/webhook",
},
{
name: "https with query",
input: "https://ntfy.sh/topic?auth=tok",
wantURL: "https://ntfy.sh/topic?auth=tok",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := notify.ValidateWebhookURL(tt.input)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got.String() != tt.wantURL {
t.Errorf(
"got %q, want %q",
got.String(), tt.wantURL,
)
}
})
}
}
func TestValidateWebhookURLInvalid(t *testing.T) {
t.Parallel()
invalid := []struct {
name string
input string
}{
{"ftp scheme", "ftp://example.com/file"},
{"file scheme", "file:///etc/passwd"},
{"empty string", ""},
{"no scheme", "example.com/webhook"},
{"no host", "https:///path"},
}
for _, tt := range invalid {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := notify.ValidateWebhookURL(tt.input)
if err == nil {
t.Errorf(
"expected error for %q, got %v",
tt.input, got,
)
}
})
}
}
// TestValidateWebhookURLErrorOmitsURL checks that the error for a
// webhook URL that does not parse, here because a carriage return
// was left at its end, leaves out the URL's path and query: the
// error is logged at startup.
func TestValidateWebhookURLErrorOmitsURL(t *testing.T) {
t.Parallel()
_, err := notify.ValidateWebhookURL(
"https://hooks.example.com" + webhookPathAndQuery + "\r",
)
if err == nil {
t.Fatal("expected an error for a URL ending in a carriage return")
}
assertNoWebhookSecret(t, err.Error())
}
func TestIsAllowedScheme(t *testing.T) {
t.Parallel()
if !notify.IsAllowedScheme("https") {
t.Error("https should be allowed")
}
if !notify.IsAllowedScheme("http") {
t.Error("http should be allowed")
}
if notify.IsAllowedScheme("ftp") {
t.Error("ftp should not be allowed")
}
if notify.IsAllowedScheme("") {
t.Error("empty scheme should not be allowed")
}
}