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) } }