feat: complete cmpp gateway delivery recovery workflows

This commit is contained in:
hectorzhao
2026-07-08 16:30:06 +08:00
parent cc628d0214
commit 8144f08652
60 changed files with 8901 additions and 94 deletions
@@ -0,0 +1,95 @@
package upstream
import (
"strings"
"testing"
)
func TestSplitSubmitContentUCS2LongMessage(t *testing.T) {
content := strings.Repeat("测试", 40)
parts, err := splitSubmitContent(8, content)
if err != nil {
t.Fatalf("splitSubmitContent returned error: %v", err)
}
if len(parts) < 2 {
t.Fatalf("expected multipart content, got %d part", len(parts))
}
total := uint8(len(parts))
ref := []byte(parts[0].MsgContent)[3]
for i, part := range parts {
if part.PkTotal != total {
t.Fatalf("part %d PkTotal = %d, want %d", i, part.PkTotal, total)
}
if part.PkNumber != uint8(i+1) {
t.Fatalf("part %d PkNumber = %d, want %d", i, part.PkNumber, i+1)
}
if part.TpUdhi != 1 {
t.Fatalf("part %d TpUdhi = %d, want 1", i, part.TpUdhi)
}
raw := []byte(part.MsgContent)
if len(raw) > maxSingleMessageBytes {
t.Fatalf("part %d length = %d, want <= %d", i, len(raw), maxSingleMessageBytes)
}
if raw[0] != 0x05 || raw[1] != 0x00 || raw[2] != 0x03 {
t.Fatalf("part %d missing standard concat UDH: %v", i, raw[:concatUDHLength])
}
if raw[3] != ref || raw[4] != total || raw[5] != uint8(i+1) {
t.Fatalf("part %d UDH = %v, ref=%d total=%d number=%d", i, raw[:concatUDHLength], ref, total, i+1)
}
if len(raw[concatUDHLength:])%2 != 0 {
t.Fatalf("part %d UCS2 payload length must be even, got %d", i, len(raw[concatUDHLength:]))
}
}
}
func TestSplitSubmitContentSingleShortMessage(t *testing.T) {
parts, err := splitSubmitContent(15, "hello")
if err != nil {
t.Fatalf("splitSubmitContent returned error: %v", err)
}
if len(parts) != 1 {
t.Fatalf("expected one part, got %d", len(parts))
}
if parts[0].PkTotal != 1 || parts[0].PkNumber != 1 || parts[0].TpUdhi != 0 {
t.Fatalf("unexpected single part metadata: %+v", parts[0])
}
}
func TestAssembleLongUplinkOutOfOrder(t *testing.T) {
content := strings.Repeat("上行", 40)
parts, err := splitSubmitContent(8, content)
if err != nil {
t.Fatalf("splitSubmitContent returned error: %v", err)
}
if len(parts) < 2 {
t.Fatalf("expected multipart content, got %d part", len(parts))
}
assemblies := map[string]*longUplinkAssembly{}
key := "channel:phone:dest:ref"
for i := len(parts) - 1; i >= 0; i-- {
_, total, number, payload, ok := parseConcatSegment(parts[i].MsgContent)
if !ok {
t.Fatalf("part %d did not parse as concat segment", i)
}
assembled, complete, err := assembleLongUplink(assemblies, key, 8, total, number, payload)
if err != nil {
t.Fatalf("assembleLongUplink returned error: %v", err)
}
if i > 0 && complete {
t.Fatalf("assembly completed before all parts arrived")
}
if i == 0 {
if !complete {
t.Fatalf("assembly did not complete after all parts arrived")
}
if assembled != content {
t.Fatalf("assembled content mismatch: got %q want %q", assembled, content)
}
}
}
if len(assemblies) != 0 {
t.Fatalf("expected completed assembly to be removed, got %d", len(assemblies))
}
}