All checks were successful
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>
169 lines
3.8 KiB
Go
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")
|
|
}
|
|
}
|