Files
GaCy-GO/internal/gameserver/session_batch_test.go
T

106 lines
3.9 KiB
Go

package gameserver
import (
"bytes"
"encoding/binary"
"testing"
kcplib "gac-hkrpg-go/pkg/kcp"
)
// A single UDP datagram can contain multiple complete KCP messages. Each
// handler must receive its own payload even when the receive buffer is reused.
func TestConsumeKeepsBatchedPacketBodiesIndependent(t *testing.T) {
const firstID, secondID uint16 = 65000, 65001
for _, id := range []uint16{firstID, secondID} {
if _, ok := rawHandlers[id]; ok {
t.Fatalf("test handler %d already registered", id)
}
if _, ok := typedHandlers[id]; ok {
t.Fatalf("test handler %d already registered", id)
}
if _, ok := dummyResponses[id]; ok {
t.Fatalf("test command %d has dummy response", id)
}
}
got := map[uint16]string{}
rawHandlers[firstID] = func(_ *Session, body []byte) error { got[firstID] = string(body); return nil }
rawHandlers[secondID] = func(_ *Session, body []byte) error { got[secondID] = string(body); return nil }
defer delete(rawHandlers, firstID)
defer delete(rawHandlers, secondID)
const conv, token uint32 = 77, 88
segment := func(seq uint32, frame []byte) []byte {
out := make([]byte, kcplib.Overhead+len(frame))
binary.LittleEndian.PutUint32(out[0:], conv)
binary.LittleEndian.PutUint32(out[4:], token)
out[8] = kcplib.CmdPush
binary.LittleEndian.PutUint16(out[10:], 128)
binary.LittleEndian.PutUint32(out[16:], seq)
binary.LittleEndian.PutUint32(out[24:], uint32(len(frame)))
copy(out[kcplib.Overhead:], frame)
return out
}
first := (&NetPacket{CmdType: firstID, Body: []byte("first")}).Encode()
second := (&NetPacket{CmdType: secondID, Body: []byte("other")}).Encode()
datagram := append(segment(0, first), segment(1, second)...)
s := NewSession(func([]byte) error { return nil }, conv, token)
defer s.Close()
if err := s.Consume(datagram); err != nil {
t.Fatal(err)
}
if got[firstID] != "first" || got[secondID] != "other" {
t.Fatalf("batched payloads corrupted: %#v", got)
}
}
func TestConsumeOutOfOrderFragmentsAndFollowingPacket(t *testing.T) {
const firstID, secondID uint16 = 65002, 65003
for _, id := range []uint16{firstID, secondID} {
if _, ok := rawHandlers[id]; ok {
t.Fatalf("test handler %d already registered", id)
}
if _, ok := typedHandlers[id]; ok {
t.Fatalf("test handler %d already registered", id)
}
if _, ok := dummyResponses[id]; ok {
t.Fatalf("test command %d has dummy response", id)
}
}
got := map[uint16][]byte{}
rawHandlers[firstID] = func(_ *Session, body []byte) error { got[firstID] = append([]byte(nil), body...); return nil }
rawHandlers[secondID] = func(_ *Session, body []byte) error { got[secondID] = append([]byte(nil), body...); return nil }
defer delete(rawHandlers, firstID)
defer delete(rawHandlers, secondID)
const conv, token uint32 = 77, 88
segment := func(seq uint32, fragment byte, frame []byte) []byte {
out := make([]byte, kcplib.Overhead+len(frame))
binary.LittleEndian.PutUint32(out[0:], conv)
binary.LittleEndian.PutUint32(out[4:], token)
out[8], out[9] = kcplib.CmdPush, fragment
binary.LittleEndian.PutUint16(out[10:], 128)
binary.LittleEndian.PutUint32(out[16:], seq)
binary.LittleEndian.PutUint32(out[24:], uint32(len(frame)))
copy(out[kcplib.Overhead:], frame)
return out
}
payload := bytes.Repeat([]byte("first-fragment-"), 120)
frame := (&NetPacket{CmdType: firstID, Body: payload}).Encode()
following := (&NetPacket{CmdType: secondID, Body: []byte("next")}).Encode()
s := NewSession(func([]byte) error { return nil }, conv, token)
defer s.Close()
if err := s.Consume(segment(1, 0, frame[800:])); err != nil {
t.Fatal(err)
}
if len(got) != 0 {
t.Fatal("dispatched an incomplete out-of-order message")
}
combined := append(segment(0, 1, frame[:800]), segment(2, 0, following)...)
if err := s.Consume(combined); err != nil {
t.Fatal(err)
}
if !bytes.Equal(got[firstID], payload) || string(got[secondID]) != "next" {
t.Fatal("fragmented or following packet body was corrupted")
}
}