package vendor import ( "encoding/json" "strings" "testing" "with_you/internal/config" ) // TestPayloadEmptyConfigMatchesLegacy 验证:未配置任何 channel/模板时, // Factory 产出的推送 payload 与改动前 BuildNotification 行为一致。 // // 改动前 BuildNotification(title, body, "message", extras) 产出: // notification: { alert, android:{alert,title,extras:{notification_type}+extras,priority:1}, ios:{alert:{title,body},sound:default,badge:+1,extras} } // options: { time_to_live: 86400, apns_production } // 无 third_party_channel func TestPayloadEmptyConfigMatchesLegacy(t *testing.T) { factory := NewFactory() cfg := config.ChannelConfig{} // 全空配置 params := MessageParams{ Scene: SceneChat, Title: "张三", Body: "你好", MessageType: "message", Extra: map[string]any{ "message_id": "m1", "conversation_id": "c1", "sender_id": "u1", "category": "chat", }, } payload := factory.Build(params, cfg) // 1. TPC 必须为 nil(无 third_party_channel 下发,与改动前一致) if payload.TPC != nil { t.Fatalf("TPC should be nil when all channel config empty, got: %+v", payload.TPC) } notif := payload.Notification if notif == nil || notif.Android == nil || notif.IOS == nil { t.Fatalf("notification/android/ios must not be nil") } // 2. Android 字段对比 if notif.Android.Alert != "你好" || notif.Android.Title != "张三" || notif.Android.Priority != 1 { t.Errorf("Android basic fields mismatch: %+v", notif.Android) } if notif.Android.ChannelID != "" { t.Errorf("Android.ChannelID = %q, want empty", notif.Android.ChannelID) } if notif.Android.Extras["notification_type"] != "message" || notif.Android.Extras["message_id"] != "m1" { t.Errorf("Android.Extras mismatch: %+v", notif.Android.Extras) } // 3. iOS 字段对比 if notif.IOS.Sound != "default" || notif.IOS.Badge != "+1" { t.Errorf("IOS basic fields mismatch: %+v", notif.IOS) } if notif.IOS.ThreadID != "" { t.Errorf("IOS.ThreadID = %q, want empty", notif.IOS.ThreadID) } if notif.IOS.Extras["notification_type"] != "message" { t.Errorf("IOS.Extras[notification_type] mismatch: %+v", notif.IOS.Extras) } // 4. 序列化 JSON 确认厂商私有字段不出现 jsonBytes, err := json.Marshal(notif) if err != nil { t.Fatalf("marshal: %v", err) } jsonStr := string(jsonBytes) for _, key := range []string{`"channel_id"`, `"thread-id"`, `"third_party_channel"`, `"mi_template"`, `"private_msg_template_id"`} { if strings.Contains(jsonStr, key) { t.Errorf("notification JSON should not contain %s when config empty, got: %s", key, jsonStr) } } t.Logf("notification JSON: %s", jsonStr) } // TestPayloadWithChannelConfig 验证:配置 channel_id 后正确下发,且不影响通用通知字段 func TestPayloadWithChannelConfig(t *testing.T) { factory := NewFactory() cfg := config.ChannelConfig{ System: "sys_channel", Chat: "chat_channel", } params := MessageParams{Scene: SceneChat, Title: "T", Body: "B", MessageType: "chat_message"} payload := factory.Build(params, cfg) // 通用通知仍正常 if payload.Notification.Android.Title != "T" { t.Errorf("Android.Title = %q, want T", payload.Notification.Android.Title) } // Android channel_id 跟随场景(chat) if payload.Notification.Android.ChannelID != "chat_channel" { t.Errorf("Android.ChannelID = %q, want chat_channel", payload.Notification.Android.ChannelID) } // TPC 各厂商 channel_id 下发(华为/VIVO 等回退全局) if payload.TPC == nil { t.Fatal("TPC should not be nil when channel config present") } if payload.TPC.Huawei["channel_id"] != "chat_channel" { t.Errorf("Huawei channel_id = %v, want chat_channel", payload.TPC.Huawei["channel_id"]) } t.Logf("TPC JSON: %s", mustJSON(payload.TPC)) } // TestPayloadXiaomiTemplateOptional 验证:仅配 channel_id 不配模板时,小米不下发模板字段 func TestPayloadXiaomiTemplateOptional(t *testing.T) { factory := NewFactory() cfg := config.ChannelConfig{ Vendor: config.VendorChannel{ Xiaomi: config.VendorChannelID{Chat: "mi_chat"}, }, } params := MessageParams{Scene: SceneChat, Title: "T", Body: "B"} payload := factory.Build(params, cfg) if payload.TPC == nil || payload.TPC.Xiaomi == nil { t.Fatal("Xiaomi TPC should exist") } if _, ok := payload.TPC.Xiaomi["mi_template_id"]; ok { t.Error("Xiaomi should NOT contain mi_template_id when template not configured") } if payload.TPC.Xiaomi["channel_id"] != "mi_chat" { t.Errorf("Xiaomi channel_id = %v, want mi_chat", payload.TPC.Xiaomi["channel_id"]) } } func mustJSON(v any) string { b, _ := json.Marshal(v) return string(b) }