166 lines
3.7 KiB
Go
166 lines
3.7 KiB
Go
// Copyright (c) 2024-2026 Lethean Contributors
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
package levin
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestConnection_RoundTrip(t *testing.T) {
|
|
a, b := net.Pipe()
|
|
defer a.Close()
|
|
defer b.Close()
|
|
|
|
sender := NewConnection(a)
|
|
receiver := NewConnection(b)
|
|
|
|
payload := []byte("hello levin")
|
|
cmd := CommandHandshake
|
|
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
errCh <- sender.WritePacket(cmd, payload, true)
|
|
}()
|
|
|
|
h, data, err := receiver.ReadPacket()
|
|
require.NoError(t, err)
|
|
require.NoError(t, <-errCh)
|
|
|
|
assert.Equal(t, cmd, h.Command)
|
|
assert.True(t, h.ExpectResponse)
|
|
assert.Equal(t, FlagRequest, h.Flags)
|
|
assert.Equal(t, LevinProtocolVersion, h.ProtocolVersion)
|
|
assert.Equal(t, Signature, h.Signature)
|
|
assert.Equal(t, uint64(len(payload)), h.PayloadSize)
|
|
assert.Equal(t, payload, data)
|
|
}
|
|
|
|
func TestConnection_EmptyPayload(t *testing.T) {
|
|
a, b := net.Pipe()
|
|
defer a.Close()
|
|
defer b.Close()
|
|
|
|
sender := NewConnection(a)
|
|
receiver := NewConnection(b)
|
|
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
errCh <- sender.WritePacket(CommandPing, nil, false)
|
|
}()
|
|
|
|
h, data, err := receiver.ReadPacket()
|
|
require.NoError(t, err)
|
|
require.NoError(t, <-errCh)
|
|
|
|
assert.Equal(t, CommandPing, h.Command)
|
|
assert.False(t, h.ExpectResponse)
|
|
assert.Equal(t, uint64(0), h.PayloadSize)
|
|
assert.Nil(t, data)
|
|
}
|
|
|
|
func TestConnection_Response(t *testing.T) {
|
|
a, b := net.Pipe()
|
|
defer a.Close()
|
|
defer b.Close()
|
|
|
|
sender := NewConnection(a)
|
|
receiver := NewConnection(b)
|
|
|
|
payload := []byte("response data")
|
|
retCode := ReturnErrFormat
|
|
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
errCh <- sender.WriteResponse(CommandHandshake, payload, retCode)
|
|
}()
|
|
|
|
h, data, err := receiver.ReadPacket()
|
|
require.NoError(t, err)
|
|
require.NoError(t, <-errCh)
|
|
|
|
assert.Equal(t, CommandHandshake, h.Command)
|
|
assert.False(t, h.ExpectResponse)
|
|
assert.Equal(t, retCode, h.ReturnCode)
|
|
assert.Equal(t, FlagResponse, h.Flags)
|
|
assert.Equal(t, payload, data)
|
|
}
|
|
|
|
func TestConnection_PayloadTooBig(t *testing.T) {
|
|
a, b := net.Pipe()
|
|
defer a.Close()
|
|
defer b.Close()
|
|
|
|
receiver := NewConnection(b)
|
|
receiver.MaxPayloadSize = 10
|
|
|
|
// Manually craft a valid header with PayloadSize = 20 (exceeds limit of 10
|
|
// but is under the package-level MaxPayloadSize so DecodeHeader succeeds).
|
|
h := &Header{
|
|
Signature: Signature,
|
|
PayloadSize: 20,
|
|
ExpectResponse: false,
|
|
Command: CommandPing,
|
|
ReturnCode: ReturnOK,
|
|
Flags: FlagRequest,
|
|
ProtocolVersion: LevinProtocolVersion,
|
|
}
|
|
hdrBytes := EncodeHeader(h)
|
|
|
|
errCh := make(chan error, 1)
|
|
go func() {
|
|
_, err := a.Write(hdrBytes[:])
|
|
errCh <- err
|
|
}()
|
|
|
|
_, _, err := receiver.ReadPacket()
|
|
require.Error(t, err)
|
|
assert.ErrorIs(t, err, ErrPayloadTooBig)
|
|
|
|
require.NoError(t, <-errCh)
|
|
}
|
|
|
|
func TestConnection_ReadTimeout(t *testing.T) {
|
|
a, b := net.Pipe()
|
|
defer a.Close()
|
|
defer b.Close()
|
|
|
|
receiver := NewConnection(b)
|
|
receiver.ReadTimeout = 50 * time.Millisecond
|
|
|
|
// Do not write anything — the reader should time out.
|
|
_, _, err := receiver.ReadPacket()
|
|
require.Error(t, err)
|
|
|
|
// Verify it is a timeout error.
|
|
netErr, ok := err.(net.Error)
|
|
require.True(t, ok, "expected net.Error, got %T", err)
|
|
assert.True(t, netErr.Timeout(), "expected timeout error")
|
|
}
|
|
|
|
func TestConnection_RemoteAddr(t *testing.T) {
|
|
a, b := net.Pipe()
|
|
defer a.Close()
|
|
defer b.Close()
|
|
|
|
conn := NewConnection(a)
|
|
addr := conn.RemoteAddr()
|
|
assert.NotEmpty(t, addr)
|
|
}
|
|
|
|
func TestConnection_Close(t *testing.T) {
|
|
a, b := net.Pipe()
|
|
defer b.Close()
|
|
|
|
conn := NewConnection(a)
|
|
require.NoError(t, conn.Close())
|
|
|
|
// Writing to a closed connection should fail.
|
|
err := conn.WritePacket(CommandPing, nil, false)
|
|
require.Error(t, err)
|
|
}
|