package warningnotify import ( "context" "errors" "testing" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts" ) type failureRecordingSender struct{ calls int } func (sender *failureRecordingSender) Send(ctx context.Context, batch Batch) error { sender.calls++ return errors.New("send failed") } func TestDispatchContinuesAfterDeliveryFailure(t *testing.T) { sender := &failureRecordingSender{} restore := SetSender(sender) defer restore() events := []Event{{TenantID: "tenant", ItemType: 1, ItemCode: "card", Category: "traffic", WarnMethods: MethodEmail, WarnEmails: "xxx@example.com", AppNotifyEnabled: true}} expected := len(BuildBatches(events)) if expected < 2 { t.Fatal("expected multiple channels") } if err := Dispatch(context.Background(), events); err == nil { t.Fatal("failure must propagate") } if sender.calls != expected { t.Fatalf("calls=%d expected=%d", sender.calls, expected) } } func TestBuildBatchesOnlyCreatesPlatformAndConfiguredChannels(t *testing.T) { batches := BuildBatches([]Event{{ Business: BusinessSimWarning, TenantID: "tenant", ItemCode: "card-1", WarnMethods: MethodEmail, WarnEmails: "xxx@example.com", AppNotifyEnabled: false, }}) methods := make(map[string]bool, len(batches)) for _, batch := range batches { methods[batch.Method] = true } for _, method := range []string{MethodPlatform, MethodEmail} { if !methods[method] { t.Errorf("expected %q batch to be generated", method) } } if methods[MethodWechat] { t.Error("wechat subscription batch must not be generated") } } func TestBuildBatchesIgnoresLegacyWechatFlag(t *testing.T) { for _, enabled := range []bool{false, true} { for _, business := range []string{BusinessSimWarning, BusinessTrafficCutoff} { batches := BuildBatches([]Event{{ Business: business, TenantID: "tenant", ItemCode: "card-1", AppNotifyEnabled: enabled, }}) if len(batches) != 1 || batches[0].Method != MethodPlatform { t.Errorf("business=%q enabled=%t: expected platform only, got %+v", business, enabled, batches) } } } } func TestEnterpriseWarningRecipientEligibility(t *testing.T) { if !enterpriseWarningRecipientEligible(consts.SysUserTypeSys, 175, 175, "") { t.Fatal("same-organization enterprise creator should be eligible") } for _, test := range []struct { name string userType string userDeptID int64 cardDeptID int64 }{ {name: "app user", userType: consts.SysUserTypeAPP, userDeptID: 175, cardDeptID: 175}, {name: "different organization", userType: consts.SysUserTypeSys, userDeptID: 176, cardDeptID: 175}, {name: "missing organization", userType: consts.SysUserTypeSys, userDeptID: 0, cardDeptID: 175}, } { t.Run(test.name, func(t *testing.T) { if enterpriseWarningRecipientEligible(test.userType, test.userDeptID, test.cardDeptID, "") { t.Fatal("recipient should not be eligible") } }) } } func TestEnterpriseWarningAncestorScope(t *testing.T) { for _, test := range []struct { name string ancestors string expected bool }{ {"direct descendant", "0,100,175,", true}, {"deep descendant", "0,100,175,185", true}, {"whitespace", "0, 175 ,185", true}, {"partial identifier", "0,100,1175,1750", false}, {"unrelated branch", "0,100,176", false}, {"missing path", "", false}, } { t.Run(test.name, func(t *testing.T) { if actual := enterpriseWarningRecipientEligible(consts.SysUserTypeSys, 175, 195, test.ancestors); actual != test.expected { t.Fatalf("eligible = %v, want %v", actual, test.expected) } }) } } func TestWechatTokenInvalidCodes(t *testing.T) { for _, code := range []int{40001, 40014, 42001} { if !warningWechatTokenInvalid(code) { t.Fatalf("code %d must refresh token", code) } } for _, code := range []int{0, 43101, 47003, 40003} { if warningWechatTokenInvalid(code) { t.Fatalf("code %d must not refresh token", code) } } } func TestWechatDefaultTemplateMatchesMiniProgram(t *testing.T) { const expected = "DMDP2PKktdtG1ES_3Ic1JcR0LGELQmWE6LunYyerHCY" if actual := wechatTemplateID(nil, consts.WarningWechatTemplateIDDefault); actual != expected { t.Fatalf("default template = %q, expected %q", actual, expected) } } func TestTrafficCutoffPlatformRecipientsExcludeCreator(t *testing.T) { got := platformAgentRecipientIDs(BusinessTrafficCutoff, []int64{130}, 1) if len(got) != 1 || got[0] != 130 { t.Fatalf("traffic cutoff recipients = %v, want [130] without admin creator 1", got) } } func TestOtherPlatformRecipientsRetainCreator(t *testing.T) { got := platformAgentRecipientIDs(BusinessSimWarning, []int64{130}, 1) if len(got) != 2 || got[0] != 130 || got[1] != 1 { t.Fatalf("regular warning recipients = %v, want [130 1]", got) } }