Files
ntfy-discord/internal/discord/fuzz_test.go
Billy D. f97ad0e7cb
Some checks failed
Build and Push / build (push) Failing after 4m36s
Build and Push / test (push) Has been cancelled
feat: implement ntfy-discord bridge in Go
- SSE subscription to ntfy with auto-reconnect
- Discord webhook integration with embed formatting
- Priority to color mapping, tag to emoji conversion
- Native HashiCorp Vault support (Kubernetes + token auth)
- Hot reload secrets via fsnotify or Vault polling
- Prometheus metrics (/metrics endpoint)
- Health/ready endpoints for Kubernetes probes
- Comprehensive unit tests and fuzz tests
- Multi-stage Docker build (~10MB scratch image)
- CI/CD pipeline for Gitea Actions
2026-02-02 18:13:55 -05:00

126 lines
3.0 KiB
Go

package discord
import (
"encoding/json"
"testing"
"git.daviestechlabs.io/daviestechlabs/ntfy-discord/internal/ntfy"
)
// FuzzBuildEmbed tests that embed building doesn't panic on arbitrary input
func FuzzBuildEmbed(f *testing.F) {
// Seed with normal inputs
f.Add("Test Title", "Test message body", 3, "warning", "test-topic", "https://example.com")
f.Add("", "", 0, "", "", "")
f.Add("Alert!", "Critical issue detected", 5, "fire", "alerts", "")
// Edge cases
f.Add("x", "y", -1, "unknown", "t", "not-a-url")
f.Add("x", "y", 100, "", "", "")
f.Add("🔥 Fire Alert", "💀 Something broke", 5, "skull", "test", "")
// Long strings
longStr := ""
for i := 0; i < 10000; i++ {
longStr += "x"
}
f.Add(longStr, longStr, 3, "tag", "topic", "https://example.com")
// Special characters
f.Add("Title\x00with\x00nulls", "Message\nwith\nnewlines", 3, "tag", "topic", "")
f.Add("<script>alert('xss')</script>", "```code```", 3, "", "", "")
f.Add("Title\t\r\n", "Body\t\r\n", 3, "", "", "")
f.Fuzz(func(t *testing.T, title, message string, priority int, tag, topic, click string) {
msg := ntfy.Message{
Title: title,
Message: message,
Priority: priority,
Tags: []string{tag},
Topic: topic,
Click: click,
Time: 1706803200,
}
client := NewClient()
// Should never panic
embed := client.buildEmbed(msg)
// Resulting embed should be valid
if embed.Footer == nil {
t.Error("Footer should never be nil")
}
// Color should always be set to a valid value
if embed.Color == 0 {
t.Error("Color should never be 0")
}
})
}
// FuzzExtractEmoji tests emoji extraction doesn't panic
func FuzzExtractEmoji(f *testing.F) {
// Valid tags
f.Add("warning")
f.Add("fire")
f.Add("check")
f.Add("rocket")
// Edge cases
f.Add("")
f.Add("unknown_tag")
f.Add("WARNING") // uppercase
f.Add("WaRnInG") // mixed case
f.Add("\x00")
f.Add("tag with spaces")
f.Add("émoji")
f.Add("🔥") // emoji as tag
f.Add("a]b[c{d}") // special chars
f.Fuzz(func(t *testing.T, tag string) {
client := NewClient()
// Should never panic
tags := []string{tag}
_ = client.extractEmoji(tags)
// Multiple tags
_ = client.extractEmoji([]string{tag, tag, tag})
// Empty slice
_ = client.extractEmoji([]string{})
// Nil slice
_ = client.extractEmoji(nil)
})
}
// FuzzWebhookPayloadJSON tests JSON marshaling of payloads
func FuzzWebhookPayloadJSON(f *testing.F) {
f.Add("Title", "Description", 3066993, "Topic", "value", "footer")
f.Fuzz(func(t *testing.T, title, desc string, color int, fieldName, fieldValue, footer string) {
payload := WebhookPayload{
Embeds: []Embed{
{
Title: title,
Description: desc,
Color: color,
Fields: []Field{
{Name: fieldName, Value: fieldValue, Inline: true},
},
Footer: &Footer{Text: footer},
},
},
}
// Marshaling should not panic
_, err := json.Marshal(payload)
if err != nil {
// JSON encoding errors are acceptable for invalid UTF-8
// but should not panic
}
})
}