package logingate import ( "bytes" "net" "testing" "time" "ananta-ps/internal/config" "ananta-ps/pkg/protocol" ) type recordingConn struct{ bytes.Buffer } func (c *recordingConn) Close() error { return nil } func (c *recordingConn) LocalAddr() net.Addr { return &net.TCPAddr{} } func (c *recordingConn) RemoteAddr() net.Addr { return &net.TCPAddr{} } func (c *recordingConn) SetDeadline(time.Time) error { return nil } func (c *recordingConn) SetReadDeadline(time.Time) error { return nil } func (c *recordingConn) SetWriteDeadline(time.Time) error { return nil } func TestColdLoginRoleList(t *testing.T) { cfg := &config.Config{Login: config.LoginSettings{RoleListMode: "list"}, Player: config.PlayerConfig{Pid: 100}} srv := New(cfg) conn := &recordingConn{} sess := &Session{conn: conn} // Invoke ID zero is valid: packet kind, rather than ID, controls replies. if err := srv.dispatch(sess, &protocol.RpcPacket{Kind: protocol.PacketKindInvoke, MethodID: 34529582}); err != nil { t.Fatal(err) } f, err := protocol.ReadFrame(conn, nil) if err != nil { t.Fatal(err) } if pkt := protocol.ParseRpcPacket(f.Payload); pkt.Kind != protocol.PacketKindReturn || pkt.InvokeID != 0 { t.Fatalf("missing invoke response: %+v", pkt) } f, err = protocol.ReadFrame(conn, nil) if err != nil { t.Fatal(err) } pkt := protocol.ParseRpcPacket(f.Payload) if pkt.MethodID != 35167428 || !bytes.Equal(pkt.Body, []byte{0xff, 1}) { t.Fatalf("malformed role list: %+v", pkt) } if err := srv.dispatch(sess, &protocol.RpcPacket{Kind: protocol.PacketKindNotify, MethodID: 34700853}); err != nil { t.Fatal(err) } if conn.Len() != 0 { t.Fatal("reply emitted for notify") } } func TestStopClosesIdleHandshake(t *testing.T) { srv := New(&config.Config{Network: config.NetworkConfig{BindHost: "127.0.0.1", LoginPorts: []int{0}}}) if err := srv.Start(); err != nil { t.Fatal(err) } conn, err := net.DialTimeout("tcp", srv.listeners[0].Addr().String(), time.Second) if err != nil { t.Fatal(err) } defer conn.Close() deadline := time.Now().Add(time.Second) for { srv.mu.Lock() n := len(srv.connections) srv.mu.Unlock() if n == 1 { break } if time.Now().After(deadline) { t.Fatal("connection not accepted") } time.Sleep(time.Millisecond) } done := make(chan struct{}) go func() { srv.Stop(); close(done) }() select { case <-done: case <-time.After(time.Second): t.Fatal("Stop blocked") } conn.SetReadDeadline(time.Now().Add(time.Second)) if _, err := conn.Read(make([]byte, 1)); err == nil { t.Fatal("idle socket survived Stop") } }