perf(cmpp): process inbound submits within client window
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -237,6 +238,116 @@ func TestInboundServerAuthenticatesAndSubmits(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestInboundServerProcessesSubmitWithinAuthenticatedConnectionWindow(t *testing.T) {
|
||||
resetDownstreamRegistry()
|
||||
defer resetDownstreamRegistry()
|
||||
account := "100020"
|
||||
password := "window-secret"
|
||||
firstStarted := make(chan struct{})
|
||||
secondStarted := make(chan struct{})
|
||||
releaseFirst := make(chan struct{})
|
||||
var releaseOnce sync.Once
|
||||
defer releaseOnce.Do(func() { close(releaseFirst) })
|
||||
var calls 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, WindowSize: 2,
|
||||
})
|
||||
case "/api/gateway/events/inbound/submit":
|
||||
call := calls.Add(1)
|
||||
if call == 1 {
|
||||
close(firstStarted)
|
||||
<-releaseFirst
|
||||
} else {
|
||||
close(secondStarted)
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(submitResponse{Accepted: true, MessageID: fmt.Sprintf("MSG-WINDOW-%d", call)})
|
||||
case "/api/gateway/events/inbound/connection", "/api/gateway/events/protocol-log":
|
||||
w.WriteHeader(http.StatusOK)
|
||||
case "/api/gateway/events/downstream/pending":
|
||||
_ = json.NewEncoder(w).Encode([]pendingDelivery{})
|
||||
default:
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}))
|
||||
defer api.Close()
|
||||
|
||||
addr := reserveTCPAddr(t)
|
||||
go func() {
|
||||
_ = (Server{Addr: addr, APIBaseURL: api.URL + "/api", MaxSubmitConcurrency: 2}).ListenAndServe()
|
||||
}()
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
|
||||
client := cmpp.NewClient(cmpp.V30)
|
||||
defer client.Disconnect()
|
||||
if err := client.Connect(addr, account, password, 2*time.Second); err != nil {
|
||||
t.Fatalf("connect inbound cmpp: %v", err)
|
||||
}
|
||||
packet := func(phone string) *cmpp.Cmpp3SubmitReqPkt {
|
||||
return &cmpp.Cmpp3SubmitReqPkt{
|
||||
PkTotal: 1, PkNumber: 1, RegisteredDelivery: 1, MsgLevel: 1,
|
||||
ServiceId: "cmpp", FeeUserType: 2, FeeTerminalId: phone, MsgFmt: 0,
|
||||
MsgSrc: account, FeeType: "02", FeeCode: "0", SrcId: "10690000",
|
||||
DestUsrTl: 1, DestTerminalId: []string{phone}, MsgLength: 6, MsgContent: "window",
|
||||
}
|
||||
}
|
||||
firstSequence, err := client.SendReqPkt(packet("13800000001"))
|
||||
if err != nil {
|
||||
t.Fatalf("send first submit: %v", err)
|
||||
}
|
||||
<-firstStarted
|
||||
secondSequence, err := client.SendReqPkt(packet("13800000002"))
|
||||
if err != nil {
|
||||
t.Fatalf("send second submit: %v", err)
|
||||
}
|
||||
select {
|
||||
case <-secondStarted:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("second Submit did not enter the authenticated connection window")
|
||||
}
|
||||
response := recvSubmitRsp(t, client)
|
||||
if response.SeqId != secondSequence {
|
||||
t.Fatalf("first completed response sequence=%d, want second sequence=%d (first=%d)", response.SeqId, secondSequence, firstSequence)
|
||||
}
|
||||
releaseOnce.Do(func() { close(releaseFirst) })
|
||||
response = recvSubmitRsp(t, client)
|
||||
if response.SeqId != firstSequence {
|
||||
t.Fatalf("released response sequence=%d, want first sequence=%d", response.SeqId, firstSequence)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoundedSubmitWindowAndAggregateSlotSnapshot(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
application int
|
||||
maximum int
|
||||
want int
|
||||
}{
|
||||
{application: 0, maximum: 0, want: 1},
|
||||
{application: 32, maximum: 64, want: 32},
|
||||
{application: 32, maximum: 16, want: 16},
|
||||
{application: 2048, maximum: 2048, want: 1024},
|
||||
} {
|
||||
if got := boundedSubmitWindow(test.application, test.maximum); got != test.want {
|
||||
t.Fatalf("boundedSubmitWindow(%d, %d)=%d, want %d", test.application, test.maximum, got, test.want)
|
||||
}
|
||||
}
|
||||
|
||||
resetDownstreamRegistry()
|
||||
defer resetDownstreamRegistry()
|
||||
firstCounter := &atomic.Int64{}
|
||||
secondCounter := &atomic.Int64{}
|
||||
firstCounter.Store(3)
|
||||
secondCounter.Store(1)
|
||||
downstreamRegistry.byConn[&cmpp.Conn{}] = &downstreamSession{windowSize: 32, submitInFlight: firstCounter}
|
||||
downstreamRegistry.byConn[&cmpp.Conn{}] = &downstreamSession{windowSize: 16, submitInFlight: secondCounter}
|
||||
configured, inFlight := SubmitSlotSnapshot()
|
||||
if configured != 48 || inFlight != 4 {
|
||||
t.Fatalf("slot snapshot configured=%d in_flight=%d, want 48/4", configured, inFlight)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeInboundLongMessageStripsConcatUDHBeforeUCS2Decode(t *testing.T) {
|
||||
payload, err := cmpputils.Utf8ToUcs2("【深圳市合正物业服务有限公司】第一片正文")
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user