fix: negotiate downstream cmpp protocol versions
This commit is contained in:
@@ -93,6 +93,8 @@ func (m *memoryRecoveryStore) GetAccountRecoveryStatus(_ context.Context, accoun
|
||||
}
|
||||
|
||||
func TestInboundServerAuthenticatesAndSubmits(t *testing.T) {
|
||||
resetDownstreamRegistry()
|
||||
defer resetDownstreamRegistry()
|
||||
account := "100001"
|
||||
password := "secret-hash"
|
||||
var gotAuth authRequest
|
||||
@@ -103,7 +105,7 @@ func TestInboundServerAuthenticatesAndSubmits(t *testing.T) {
|
||||
if err := json.NewDecoder(r.Body).Decode(&gotAuth); err != nil {
|
||||
t.Fatalf("decode auth: %v", err)
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(authResponse{PasswordCipher: password})
|
||||
_ = json.NewEncoder(w).Encode(authResponse{PasswordCipher: password, Account: account, EnterpriseCode: account})
|
||||
case "/api/gateway/events/inbound/submit":
|
||||
if err := json.NewDecoder(r.Body).Decode(&gotSubmit); err != nil {
|
||||
t.Fatalf("decode submit: %v", err)
|
||||
@@ -186,6 +188,92 @@ func TestInboundServerAuthenticatesAndSubmits(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInboundServerNegotiatesCMPP2AndUsesAuthenticatedAccountForSubmit(t *testing.T) {
|
||||
resetDownstreamRegistry()
|
||||
defer resetDownstreamRegistry()
|
||||
account := "100001"
|
||||
password := "secret-hash"
|
||||
var gotSubmit submitRequest
|
||||
submitCalls := 0
|
||||
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: "SP0001"})
|
||||
case "/api/gateway/events/inbound/submit":
|
||||
submitCalls++
|
||||
if err := json.NewDecoder(r.Body).Decode(&gotSubmit); err != nil {
|
||||
t.Fatalf("decode submit: %v", err)
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(submitResponse{Accepted: true, MessageID: "MSG-CMPP2"})
|
||||
case "/api/gateway/events/downstream/pending":
|
||||
_ = json.NewEncoder(w).Encode([]pendingDelivery{})
|
||||
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)
|
||||
}
|
||||
content, err := cmpputils.Utf8ToUcs2("测试CMPP2")
|
||||
if err != nil {
|
||||
t.Fatalf("encode content: %v", err)
|
||||
}
|
||||
_, err = client.SendReqPkt(&cmpp.Cmpp2SubmitReqPkt{
|
||||
PkTotal: 1, PkNumber: 1, RegisteredDelivery: 1, MsgLevel: 1,
|
||||
ServiceId: "cmpp", FeeUserType: 2, FeeTerminalId: "13500002696",
|
||||
MsgFmt: 8, MsgSrc: "SP0001", FeeType: "02", FeeCode: "0",
|
||||
SrcId: "10690000", DestUsrTl: 1, DestTerminalId: []string{"13500002696"},
|
||||
MsgLength: uint8(len(content)), MsgContent: content,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("send CMPP2 submit: %v", err)
|
||||
}
|
||||
rsp := recvSubmitRsp20(t, client)
|
||||
if rsp.Result != 0 || rsp.MsgId == 0 {
|
||||
t.Fatalf("unexpected CMPP2 submit response: %+v", rsp)
|
||||
}
|
||||
if gotSubmit.Account != account || gotSubmit.PhoneNumber != "13500002696" || gotSubmit.Content != "测试CMPP2" {
|
||||
t.Fatalf("unexpected CMPP2 submit payload: %+v", gotSubmit)
|
||||
}
|
||||
_, err = client.SendReqPkt(&cmpp.Cmpp2SubmitReqPkt{
|
||||
PkTotal: 1, PkNumber: 1, RegisteredDelivery: 1, MsgLevel: 1,
|
||||
ServiceId: "cmpp", FeeUserType: 2, FeeTerminalId: "13500002696",
|
||||
MsgFmt: 8, MsgSrc: "BAD001", FeeType: "02", FeeCode: "0",
|
||||
SrcId: "10690000", DestUsrTl: 1, DestTerminalId: []string{"13500002696"},
|
||||
MsgLength: uint8(len(content)), MsgContent: content,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("send mismatched enterprise code: %v", err)
|
||||
}
|
||||
if rejected := recvSubmitRsp20(t, client); rejected.Result != 9 {
|
||||
t.Fatalf("expected enterprise code rejection, got %+v", rejected)
|
||||
}
|
||||
if submitCalls != 1 {
|
||||
t.Fatalf("submit API calls = %d, want 1", submitCalls)
|
||||
}
|
||||
delivered, err := PushReceipt(DownstreamReceipt{
|
||||
MessageID: "MSG-CMPP2", PhoneNumber: "13500002696", ReceiptStatus: "delivered",
|
||||
DeliveredAt: time.Now().UTC().Format(time.RFC3339Nano),
|
||||
})
|
||||
if err != nil || !delivered {
|
||||
t.Fatalf("push CMPP2 receipt delivered=%v err=%v", delivered, err)
|
||||
}
|
||||
deliver := recvDeliver20(t, client)
|
||||
if deliver.RegisterDelivery != 1 {
|
||||
t.Fatalf("expected CMPP2 receipt deliver, got %+v", deliver)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostIncludesAPIErrorResponseBody(t *testing.T) {
|
||||
api := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
@@ -259,20 +347,21 @@ func TestSetInboundSubmitResponseSupportsCMPP2AndCMPP3(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInboundClientProtocolUsesConnectRequestVersion(t *testing.T) {
|
||||
func TestFindSessionByConnUsesAuthenticatedConnection(t *testing.T) {
|
||||
resetDownstreamRegistry()
|
||||
defer resetDownstreamRegistry()
|
||||
conn := &cmpp.Conn{}
|
||||
downstreamRegistry.byAccount["100001"] = &downstreamSession{
|
||||
session := &downstreamSession{
|
||||
account: "100001",
|
||||
protocol: "cmpp20",
|
||||
conn: conn,
|
||||
}
|
||||
if got := inboundClientProtocol("100001", conn, "cmpp30"); got != "cmpp20" {
|
||||
t.Fatalf("protocol = %s, want cmpp20", got)
|
||||
downstreamRegistry.byConn[conn] = session
|
||||
if got := findSessionByConn(conn); got != session {
|
||||
t.Fatalf("unexpected session: %+v", got)
|
||||
}
|
||||
if got := inboundClientProtocol("missing", conn, "cmpp30"); got != "cmpp30" {
|
||||
t.Fatalf("fallback protocol = %s, want cmpp30", got)
|
||||
if got := findSessionByConn(&cmpp.Conn{}); got != nil {
|
||||
t.Fatalf("expected missing session, got %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,11 +535,28 @@ func recvDeliver(t *testing.T, client *cmpp.Client) *cmpp.Cmpp3DeliverReqPkt {
|
||||
return nil
|
||||
}
|
||||
|
||||
func recvDeliver20(t *testing.T, client *cmpp.Client) *cmpp.Cmpp2DeliverReqPkt {
|
||||
t.Helper()
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
packet, err := client.RecvAndUnpackPkt(200 * time.Millisecond)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if deliver, ok := packet.(*cmpp.Cmpp2DeliverReqPkt); ok {
|
||||
return deliver
|
||||
}
|
||||
}
|
||||
t.Fatal("timed out waiting CMPP2 deliver request")
|
||||
return nil
|
||||
}
|
||||
|
||||
func resetDownstreamRegistry() {
|
||||
downstreamRegistry.Lock()
|
||||
defer downstreamRegistry.Unlock()
|
||||
downstreamRegistry.byAccount = make(map[string]*downstreamSession)
|
||||
downstreamRegistry.byMessageID = make(map[string]*downstreamSession)
|
||||
downstreamRegistry.byConn = make(map[*cmpp.Conn]*downstreamSession)
|
||||
}
|
||||
|
||||
func reserveTCPAddr(t *testing.T) string {
|
||||
@@ -481,3 +587,19 @@ func recvSubmitRsp(t *testing.T, client *cmpp.Client) *cmpp.Cmpp3SubmitRspPkt {
|
||||
t.Fatal("timed out waiting submit response")
|
||||
return nil
|
||||
}
|
||||
|
||||
func recvSubmitRsp20(t *testing.T, client *cmpp.Client) *cmpp.Cmpp2SubmitRspPkt {
|
||||
t.Helper()
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
packet, err := client.RecvAndUnpackPkt(200 * time.Millisecond)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if rsp, ok := packet.(*cmpp.Cmpp2SubmitRspPkt); ok {
|
||||
return rsp
|
||||
}
|
||||
}
|
||||
t.Fatal("timed out waiting CMPP2 submit response")
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user