package sms import ( "strings" "testing" ) func TestDefaultConfigCoversRegisteredNodes(t *testing.T) { cfg := DefaultConfig() if cfg.Enabled { t.Fatal("默认配置的总开关必须关闭,避免未配置模板就产生短信费用") } for _, meta := range NodeMetas() { node, ok := cfg.Node(meta.Code) if !ok { t.Fatalf("默认配置缺少节点 %s", meta.Code) } if !node.Enabled { t.Fatalf("默认配置节点 %s 应默认启用", meta.Code) } if node.TemplateCode != "" { t.Fatalf("默认配置节点 %s 的模板 CODE 应为空,实际 %q", meta.Code, node.TemplateCode) } } if days := cfg.StaleDaysFor(NodeListingStalePriceSuggestion); days != DefaultStaleDays { t.Fatalf("StaleDaysFor() = %d, want %d", days, DefaultStaleDays) } } func TestParseConfigValueMergesAndFiltersUnknownNodes(t *testing.T) { cfg, err := ParseConfigValue(`{ "enabled": true, "nodes": { "order_handoff_assist": {"enabled": true, "template_code": " SMS_512540945 "}, "listing_stale_price_suggestion": {"enabled": false, "template_code": "SMS_1", "stale_days": 5}, "not_registered_node": {"enabled": true, "template_code": "SMS_BAD"} } }`) if err != nil { t.Fatalf("ParseConfigValue() error = %v", err) } if !cfg.Enabled { t.Fatal("ParseConfigValue() 应保留总开关") } if _, ok := cfg.Node("not_registered_node"); ok { t.Fatal("ParseConfigValue() 不应保留未登记节点") } node, ok := cfg.Node(NodeOrderHandoffAssist) if !ok || node.TemplateCode != "SMS_512540945" { t.Fatalf("handoff node = %+v, want template trimmed to SMS_512540945", node) } // 未在 JSON 中出现的已登记节点应保留默认值。 rejected, ok := cfg.Node(NodeListingReviewRejected) if !ok || !rejected.Enabled { t.Fatalf("未配置节点应保留默认值, got %+v ok=%v", rejected, ok) } stale, _ := cfg.Node(NodeListingStalePriceSuggestion) if stale.StaleDays != 5 { t.Fatalf("stale_days = %d, want 5", stale.StaleDays) } } func TestParseConfigValueEmptyAndInvalid(t *testing.T) { cfg, err := ParseConfigValue(" ") if err != nil { t.Fatalf("空配置不应报错: %v", err) } if cfg.Enabled { t.Fatal("空配置应回落到默认(总开关关闭)") } if _, err := ParseConfigValue("{not json}"); err == nil { t.Fatal("非法 JSON 应返回错误") } } func TestMarshalConfigNormalizes(t *testing.T) { raw, err := MarshalConfig(Config{ Enabled: true, Nodes: map[string]NodeConfig{ NodeListingReviewRejected: {Enabled: true, TemplateCode: " SMS_512520993 ", StaleDays: -3}, "unknown_node": {Enabled: true, TemplateCode: "SMS_X"}, NodeListingStalePriceSuggestion: {Enabled: true, TemplateCode: "SMS_512620985", StaleDays: 0}, }, }) if err != nil { t.Fatalf("MarshalConfig() error = %v", err) } if strings.Contains(raw, "unknown_node") { t.Fatalf("MarshalConfig() 不应输出未登记节点: %s", raw) } parsed, err := ParseConfigValue(raw) if err != nil { t.Fatalf("ParseConfigValue() error = %v", err) } rejected, _ := parsed.Node(NodeListingReviewRejected) if rejected.TemplateCode != "SMS_512520993" { t.Fatalf("template_code = %q, want SMS_512520993", rejected.TemplateCode) } if rejected.StaleDays != 0 { t.Fatalf("负的 stale_days 应被归零, got %d", rejected.StaleDays) } if days := parsed.StaleDaysFor(NodeListingStalePriceSuggestion); days != DefaultStaleDays { t.Fatalf("stale_days=0 时应回落默认值 %d, got %d", DefaultStaleDays, days) } } func TestConfigNodeActive(t *testing.T) { base := Config{ Enabled: true, Nodes: map[string]NodeConfig{ NodeListingReviewRejected: {Enabled: true, TemplateCode: "SMS_512520993"}, NodeOrderHandoffAssist: {Enabled: false, TemplateCode: "SMS_512540945"}, NodeListingStalePriceSuggestion: {Enabled: true, TemplateCode: ""}, }, } if !base.NodeActive(NodeListingReviewRejected) { t.Fatal("总开关与节点开关都开且模板非空时应可发送") } if base.NodeActive(NodeOrderHandoffAssist) { t.Fatal("节点关闭时不应发送") } if base.NodeActive(NodeListingStalePriceSuggestion) { t.Fatal("模板 CODE 为空时不应发送") } if base.NodeActive("unknown_node") { t.Fatal("未登记节点不应发送") } disabled := base disabled.Enabled = false if disabled.NodeActive(NodeListingReviewRejected) { t.Fatal("总开关关闭时不应发送") } } func TestIsKnownNode(t *testing.T) { for _, code := range []string{ NodeListingReviewRejected, NodeOrderHandoffAssist, NodeListingStalePriceSuggestion, } { if !IsKnownNode(code) { t.Fatalf("IsKnownNode(%q) = false, want true", code) } } if IsKnownNode("") || IsKnownNode("nope") { t.Fatal("未登记节点应为 false") } }