proto-socket/go/test/communicator_test.go
toki 7f8771b89e refactor: implement HeartbeatMixin for heartbeat handling
- Dart: Replace ResponseChecker with HeartbeatMixin
- Dart: Remove heartbeat-related fields from ProtobufClient/Server
- Dart: Add HeartbeatMixin for cleaner heartbeat logic
- Go: Add timeout test in communicator_test.go
- Go: Add heartbeat_test.go with heartbeat functionality tests
- Go: Add TLS test in tls_test.go
- Go: Add message type mismatch tests
- Go: Improve tcp_test.go and ws_test.go with comprehensive tests
- Dart: Add comprehensive socket_test.dart with multiple test scenarios
- Add untracked documentation files
2026-04-11 16:33:40 +09:00

122 lines
2.9 KiB
Go

package toki_socket_test
import (
"strings"
"sync"
"testing"
"time"
"google.golang.org/protobuf/proto"
toki "toki-labs.com/toki_socket/go"
"toki-labs.com/toki_socket/go/packets"
)
type fakeTransport struct {
mu sync.Mutex
packets []*packets.PacketBase
}
func (f *fakeTransport) WritePacket(base *packets.PacketBase) error {
f.mu.Lock()
defer f.mu.Unlock()
f.packets = append(f.packets, base)
return nil
}
func (f *fakeTransport) Close() error {
return nil
}
func (f *fakeTransport) sent() []*packets.PacketBase {
f.mu.Lock()
defer f.mu.Unlock()
return append([]*packets.PacketBase{}, f.packets...)
}
func testParserMap() toki.ParserMap {
return toki.ParserMap{
toki.TypeNameOf(&packets.TestData{}): func(b []byte) (proto.Message, error) {
m := &packets.TestData{}
return m, proto.Unmarshal(b, m)
},
}
}
func TestSendRequestTypeMismatch(t *testing.T) {
transport := &fakeTransport{}
communicator := toki.NewCommunicator(transport, testParserMap())
defer communicator.Close()
errCh := make(chan error, 1)
go func() {
_, err := toki.SendRequestTyped[*packets.TestData, *packets.TestData](
communicator,
&packets.TestData{Index: 1, Message: "hello"},
time.Second,
)
errCh <- err
}()
var requestNonce int32
for deadline := time.Now().Add(time.Second); time.Now().Before(deadline); {
sent := transport.sent()
if len(sent) == 1 {
requestNonce = sent[0].GetNonce()
break
}
time.Sleep(time.Millisecond)
}
if requestNonce == 0 {
t.Fatal("request packet was not sent")
}
hb, err := proto.Marshal(&packets.HeartBeat{})
if err != nil {
t.Fatal(err)
}
communicator.OnReceivedData(toki.TypeNameOf(&packets.HeartBeat{}), hb, 0, requestNonce)
err = <-errCh
if err == nil {
t.Fatal("expected response type mismatch error")
}
}
func TestSendRequestTimeout(t *testing.T) {
transport := &fakeTransport{}
communicator := toki.NewCommunicator(transport, testParserMap())
defer communicator.Close()
_, err := toki.SendRequestTyped[*packets.TestData, *packets.TestData](
communicator,
&packets.TestData{Index: 1, Message: "no response"},
25*time.Millisecond,
)
if err == nil {
t.Fatal("expected request timeout error")
}
if !strings.Contains(err.Error(), "timeout") {
t.Fatalf("expected timeout error, got %v", err)
}
if len(transport.sent()) != 1 {
t.Fatalf("expected one request packet to be sent, got %d", len(transport.sent()))
}
}
func TestListenerAndRequestListenerConflict(t *testing.T) {
transport := &fakeTransport{}
communicator := toki.NewCommunicator(transport, testParserMap())
defer communicator.Close()
toki.AddListenerTyped[*packets.TestData](communicator, func(*packets.TestData) {})
defer func() {
if recover() == nil {
t.Fatal("expected panic")
}
}()
toki.AddRequestListenerTyped[*packets.TestData, *packets.TestData](communicator, func(req *packets.TestData) (*packets.TestData, error) {
return req, nil
})
}