fix: reject CMPP daily limit synchronously

This commit is contained in:
hectorzhao
2026-07-22 17:09:44 +08:00
parent 66bc230d7e
commit 55019443c0
7 changed files with 112 additions and 20 deletions
+56
View File
@@ -12,6 +12,7 @@ import (
"reflect"
"strings"
"sync"
"sync/atomic"
"testing"
"time"
@@ -310,6 +311,61 @@ func TestSubmitResponsePrecedesQueuedFailureReceipt(t *testing.T) {
}
}
func TestDailyLimitRejectsSubmitSynchronouslyWithoutPendingReceipt(t *testing.T) {
resetDownstreamRegistry()
defer resetDownstreamRegistry()
account := "100001"
password := "secret-hash"
var pendingCalls atomic.Int32
api := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/gateway/events/inbound/authenticate":
_ = json.NewEncoder(w).Encode(authResponse{PasswordCipher: password, Account: account, EnterpriseCode: account})
case "/api/gateway/events/inbound/submit":
_ = json.NewEncoder(w).Encode(submitResponse{Accepted: false, Result: 8, MessageID: "MSG-LIMIT"})
case "/api/gateway/events/downstream/pending":
pendingCalls.Add(1)
_ = json.NewEncoder(w).Encode([]pendingDelivery{})
case "/api/gateway/events/inbound/connection":
w.WriteHeader(http.StatusOK)
default:
t.Fatalf("unexpected api path: %s", r.URL.Path)
}
}))
defer api.Close()
addr := reserveTCPAddr(t)
go func() { _ = (Server{Addr: addr, APIBaseURL: api.URL + "/api"}).ListenAndServe() }()
time.Sleep(300 * time.Millisecond)
client := cmpp.NewClient(cmpp.V20)
defer client.Disconnect()
if err := client.Connect(addr, account, password, 2*time.Second); err != nil {
t.Fatalf("connect CMPP2 inbound: %v", err)
}
time.Sleep(100 * time.Millisecond)
pendingCallsAfterBind := pendingCalls.Load()
content, _ := cmpputils.Utf8ToUcs2("日限额拒绝")
if _, err := client.SendReqPkt(&cmpp.Cmpp2SubmitReqPkt{
PkTotal: 1, PkNumber: 1, RegisteredDelivery: 1, MsgLevel: 1,
ServiceId: "cmpp", FeeUserType: 2, FeeTerminalId: "13500002696",
MsgFmt: 8, MsgSrc: account, FeeType: "02", FeeCode: "0", SrcId: "10690000",
DestUsrTl: 1, DestTerminalId: []string{"13500002696"}, MsgLength: uint8(len(content)), MsgContent: content,
}); err != nil {
t.Fatalf("send submit: %v", err)
}
rsp := recvSubmitRsp20(t, client)
if rsp.Result != 8 || rsp.MsgId != 0 {
t.Fatalf("expected synchronous daily-limit result=8 without Msg_Id, got %+v", rsp)
}
time.Sleep(100 * time.Millisecond)
if pendingCalls.Load() != pendingCallsAfterBind {
t.Fatalf("daily-limit rejection must not add downstream receipt polling, before=%d after=%d", pendingCallsAfterBind, pendingCalls.Load())
}
}
func TestReceiptWithoutOriginalSequenceIsUnrecoverable(t *testing.T) {
resetDownstreamRegistry()
defer resetDownstreamRegistry()