106 lines
3.9 KiB
Go
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")
|
|
}
|
|
}
|