mattermost-push-proxy-router/router_test.go
Felipe M. 3c6fea8a46
All checks were successful
Release / release (push) Successful in 2m26s
CI / goreleaser-lint (push) Successful in 6s
CI / format (push) Successful in 28s
CI / test (push) Successful in 1m20s
CI / lint (push) Successful in 2m36s
CI / build (push) Successful in 34s
feat: add Mattermost push proxy prefix router
Implement a stateless Go service that routes /api/v1/send_push and /api/v1/ack
by platform prefix to configured backends, enabling mixed official and custom
mobile clients on a single PushNotificationServer URL.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-26 10:03:43 +02:00

169 lines
3.8 KiB
Go

package main
import (
"os"
"path/filepath"
"testing"
"time"
)
func TestStripVersionSuffix(t *testing.T) {
tests := []struct {
in, want string
}{
{"apple_rn", "apple_rn"},
{"apple_rn-v2", "apple_rn"},
{"apple_bubbles-v3", "apple_bubbles"},
{"android", "android"},
}
for _, tt := range tests {
if got := stripVersionSuffix(tt.in); got != tt.want {
t.Errorf("stripVersionSuffix(%q) = %q, want %q", tt.in, got, tt.want)
}
}
}
func TestExtractPlatform(t *testing.T) {
tests := []struct {
name string
body string
want string
wantErr bool
}{
{
name: "platform field",
body: `{"platform":"apple_bubbles","device_id":"abc123","server_id":"srv"}`,
want: "apple_bubbles",
},
{
name: "platform with version suffix",
body: `{"platform":"apple_rn-v2","device_id":"abc123","server_id":"srv"}`,
want: "apple_rn",
},
{
name: "device_id prefix fallback",
body: `{"device_id":"android_rn:token123","server_id":"srv"}`,
want: "android_rn",
},
{
name: "missing platform",
body: `{"device_id":"abc123","server_id":"srv"}`,
wantErr: true,
},
{
name: "invalid json",
body: `{`,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := extractPlatform([]byte(tt.body))
if tt.wantErr {
if err == nil {
t.Fatal("expected error")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != tt.want {
t.Fatalf("extractPlatform() = %q, want %q", got, tt.want)
}
})
}
}
func TestBackendForPlatform(t *testing.T) {
cfg := Config{
Routes: []Route{
{Prefixes: []string{"apple_bubbles"}, URL: "http://custom-proxy:8067"},
{Prefixes: []string{"apple_rn", "android_rn"}, URL: "https://push.mattermost.com"},
},
}
tests := []struct {
platform string
wantURL string
wantOK bool
}{
{"apple_bubbles", "http://custom-proxy:8067", true},
{"apple_rn", "https://push.mattermost.com", true},
{"android_rn", "https://push.mattermost.com", true},
{"apple_rn-v2", "https://push.mattermost.com", true},
{"unknown", "", false},
}
for _, tt := range tests {
url, ok := cfg.BackendForPlatform(tt.platform)
if ok != tt.wantOK {
t.Errorf("BackendForPlatform(%q) ok = %v, want %v", tt.platform, ok, tt.wantOK)
}
if url != tt.wantURL {
t.Errorf("BackendForPlatform(%q) url = %q, want %q", tt.platform, url, tt.wantURL)
}
}
}
func TestLoadConfigRequiresConfigFile(t *testing.T) {
t.Setenv("CONFIG_FILE", "")
_, err := LoadConfig()
if err == nil {
t.Fatal("expected error when CONFIG_FILE is unset")
}
}
func TestLoadConfigFromFile(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "router.toml")
content := `
listen = ":9090"
request_timeout_sec = 30
[[routes]]
prefixes = ["apple_bubbles"]
url = "http://localhost:8067"
`
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
t.Fatal(err)
}
t.Setenv("CONFIG_FILE", path)
t.Setenv("PORT", "")
cfg, err := LoadConfig()
if err != nil {
t.Fatalf("LoadConfig() error: %v", err)
}
if cfg.Port != "9090" {
t.Fatalf("Port = %q, want 9090", cfg.Port)
}
if cfg.RequestTimeout != 30*time.Second {
t.Fatalf("RequestTimeout = %v", cfg.RequestTimeout)
}
if len(cfg.Routes) != 1 || cfg.Routes[0].URL != "http://localhost:8067" {
t.Fatalf("Routes = %#v", cfg.Routes)
}
}
func TestNormalizeRoutesRejectsDuplicatePrefix(t *testing.T) {
_, err := normalizeRoutes([]routeConfig{
{Prefixes: []string{"apple_rn"}, URL: "http://a.example"},
{Prefixes: []string{"apple_rn"}, URL: "http://b.example"},
})
if err == nil {
t.Fatal("expected duplicate prefix error")
}
}
func TestNormalizeRoutesRequiresRoutes(t *testing.T) {
_, err := normalizeRoutes(nil)
if err == nil {
t.Fatal("expected error for empty routes")
}
}