Files
memby/server/internal/store/integrations_test.go
T
2026-08-14 09:40:03 +12:00

96 lines
3.6 KiB
Go

package store
import (
"strings"
"testing"
)
const sampleWebhook = "https://discord.com/api/webhooks/1234567890/abcdefSECRETtoken"
// The redaction rule is the one thing here that must not be got wrong. The webhook URL is
// the credential: anybody holding it can post into the household's channel, and this
// console is read over the open internet.
func TestRedactNeverReturnsTheWebhookAddress(t *testing.T) {
redacted := Integration{ID: "a", Name: "Family", URL: sampleWebhook}.Redact()
if redacted.URL != "" {
t.Fatalf("the webhook address must never leave the server, got %q", redacted.URL)
}
if strings.Contains(redacted.Hint, "SECRET") {
t.Fatalf("the hint leaked part of the token: %q", redacted.Hint)
}
if !redacted.HasURL {
t.Fatal("the console still has to know one is configured")
}
}
func TestRedactHintNamesTheChannelSoRowsAreTellableApart(t *testing.T) {
redacted := Integration{ID: "a", URL: sampleWebhook}.Redact()
if !strings.Contains(redacted.Hint, "1234567890") {
t.Fatalf("the hint should carry the channel id, got %q", redacted.Hint)
}
}
func TestRedactSaysNothingWhenNothingIsConfigured(t *testing.T) {
redacted := Integration{ID: "a"}.Redact()
if redacted.HasURL || redacted.Hint != "" {
t.Fatalf("an unconfigured integration should claim nothing, got %+v", redacted)
}
}
func TestNormalizeRefusesToEnableAnIntegrationWithNoDestination(t *testing.T) {
// A switch reading "on" over something that can never deliver is the state the
// subtitle settings deliberately refuse too.
settings := normalizeIntegrations(IntegrationSettings{Integrations: []Integration{
{ID: "a", Enabled: true, URL: " "},
}})
if settings.Integrations[0].Enabled {
t.Fatal("an integration with no address must not be stored as enabled")
}
}
func TestNormalizeDropsDuplicateAndAnonymousRows(t *testing.T) {
settings := normalizeIntegrations(IntegrationSettings{Integrations: []Integration{
{ID: "a", URL: sampleWebhook},
{ID: "a", URL: sampleWebhook},
{ID: " ", URL: sampleWebhook},
}})
if len(settings.Integrations) != 1 {
t.Fatalf("expected one surviving row, got %d", len(settings.Integrations))
}
}
func TestNormalizeDeduplicatesTheEventSelection(t *testing.T) {
// A repeated event would deliver the same message twice to one channel.
settings := normalizeIntegrations(IntegrationSettings{Integrations: []Integration{
{ID: "a", URL: sampleWebhook, Events: []string{"auth.login", "auth.login", " ", "device.registered"}},
}})
events := settings.Integrations[0].Events
if len(events) != 2 || events[0] != "auth.login" || events[1] != "device.registered" {
t.Fatalf("unexpected selection %v", events)
}
}
func TestNormalizeBoundsTheList(t *testing.T) {
// Every event costs one outbound request per enabled destination.
many := make([]Integration, MaxIntegrations+5)
for i := range many {
many[i] = Integration{ID: string(rune('a'+i%26)) + itoa(i), URL: sampleWebhook}
}
settings := normalizeIntegrations(IntegrationSettings{Integrations: many})
if len(settings.Integrations) != MaxIntegrations {
t.Fatalf("expected the list capped at %d, got %d", MaxIntegrations, len(settings.Integrations))
}
}
func TestNormalizeDefaultsTheKindSoAnOlderDocumentStillDelivers(t *testing.T) {
// The kind was introduced with the second transport in mind; a row written before it
// has none, and reading that as "no transport" would silently stop delivering.
settings := normalizeIntegrations(IntegrationSettings{Integrations: []Integration{
{ID: "a", URL: sampleWebhook},
}})
if settings.Integrations[0].Kind != IntegrationDiscord {
t.Fatalf("expected a default kind, got %q", settings.Integrations[0].Kind)
}
}