diff --git a/go.mod b/go.mod index e5a265a..0883734 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module git.noahlan.cn/noahlan/nnet/v2 -go 1.25 +go 1.26.5 require ( github.com/gorilla/websocket v1.5.3 diff --git a/internal/server/helpers_test.go b/internal/server/helpers_test.go index 01a0692..2fae8de 100644 --- a/internal/server/helpers_test.go +++ b/internal/server/helpers_test.go @@ -3,6 +3,7 @@ package server import ( "testing" + protocolnnet "git.noahlan.cn/noahlan/nnet/v2/internal/protocol/nnet" internalunpacker "git.noahlan.cn/noahlan/nnet/v2/internal/unpacker" unpackerpkg "git.noahlan.cn/noahlan/nnet/v2/pkg/unpacker" ) @@ -46,3 +47,71 @@ func TestProcessDataWithUnpackerConsumesIncompleteInput(t *testing.T) { t.Fatalf("message=%q, want %q", string(messages[0]), "\x03abc") } } + +func TestProcessDataWithUnpackerIsolatesConnectionBuffers(t *testing.T) { + u1 := internalunpacker.NewLengthFieldUnpacker(unpackerpkg.LengthFieldUnpacker{ + LengthFieldOffset: 0, + LengthFieldLength: 1, + LengthAdjustment: 0, + InitialBytesToStrip: 0, + }) + u2 := internalunpacker.NewLengthFieldUnpacker(unpackerpkg.LengthFieldUnpacker{ + LengthFieldOffset: 0, + LengthFieldLength: 1, + LengthAdjustment: 0, + InitialBytesToStrip: 0, + }) + + messages, _, hasRemaining, err := processDataWithUnpacker([]byte{3, 'a'}, u1) + if err != nil { + t.Fatalf("first connection partial error: %v", err) + } + if len(messages) != 0 || !hasRemaining { + t.Fatalf("first connection messages=%d hasRemaining=%v, want 0/true", len(messages), hasRemaining) + } + + messages, _, hasRemaining, err = processDataWithUnpacker([]byte{1, 'z'}, u2) + if err != nil { + t.Fatalf("second connection complete error: %v", err) + } + if hasRemaining || len(messages) != 1 || string(messages[0]) != "\x01z" { + t.Fatalf("second connection messages=%q hasRemaining=%v, want isolated complete frame", messages, hasRemaining) + } + + messages, _, hasRemaining, err = processDataWithUnpacker([]byte{'b', 'c'}, u1) + if err != nil { + t.Fatalf("first connection completion error: %v", err) + } + if hasRemaining || len(messages) != 1 || string(messages[0]) != "\x03abc" { + t.Fatalf("first connection messages=%q hasRemaining=%v, want original buffered frame", messages, hasRemaining) + } +} + +func TestSplitWebSocketMessagesKeepsPartialFrameState(t *testing.T) { + protocol := protocolnnet.NewNNetProtocol("1.0") + provider, ok := protocol.(interface{ Unpacker() unpackerpkg.Unpacker }) + if !ok { + t.Fatal("protocol should provide an unpacker") + } + unpacker := provider.Unpacker() + packet, err := protocol.Encode([]byte("hello"), nil) + if err != nil { + t.Fatalf("encode error: %v", err) + } + + messages, err := splitWebSocketMessages(packet[:6], unpacker) + if err != nil { + t.Fatalf("partial split error: %v", err) + } + if len(messages) != 0 { + t.Fatalf("partial messages=%d, want 0", len(messages)) + } + + messages, err = splitWebSocketMessages(packet[6:], unpacker) + if err != nil { + t.Fatalf("completion split error: %v", err) + } + if len(messages) != 1 || string(messages[0]) != string(packet) { + t.Fatalf("messages=%q, want complete packet", messages) + } +}