claude: add tests for tcp and ntp to consolidate functionality

This commit is contained in:
Patricio Whittingslow
2026-03-08 19:42:48 -03:00
parent 97acaa2cb3
commit 6b06cb1237
5 changed files with 707 additions and 0 deletions
+162
View File
@@ -0,0 +1,162 @@
package tcp
import (
"net"
"net/netip"
"testing"
"time"
)
func newConfiguredConn(t *testing.T) *Conn {
t.Helper()
var conn Conn
err := conn.Configure(ConnConfig{
RxBuf: make([]byte, 512),
TxBuf: make([]byte, 512),
TxPacketQueueSize: 4,
})
if err != nil {
t.Fatal(err)
}
return &conn
}
func TestConn_SetDeadline_Closed(t *testing.T) {
conn := newConfiguredConn(t)
err := conn.SetDeadline(time.Now().Add(time.Second))
if err == nil {
t.Fatal("SetDeadline on closed conn should fail")
}
}
func TestConn_SetReadDeadline_Closed(t *testing.T) {
conn := newConfiguredConn(t)
err := conn.SetReadDeadline(time.Now().Add(time.Second))
if err == nil {
t.Fatal("SetReadDeadline on closed conn should fail")
}
}
func TestConn_SetWriteDeadline_Closed(t *testing.T) {
conn := newConfiguredConn(t)
err := conn.SetWriteDeadline(time.Now().Add(time.Second))
if err == nil {
t.Fatal("SetWriteDeadline on closed conn should fail")
}
}
func TestConn_OpenActive_InvalidAddr(t *testing.T) {
conn := newConfiguredConn(t)
err := conn.OpenActive(1234, netip.AddrPort{}, 100)
if err == nil {
t.Fatal("OpenActive with invalid addr should fail")
}
}
func TestConn_OpenListen(t *testing.T) {
conn := newConfiguredConn(t)
err := conn.OpenListen(8080, 100)
if err != nil {
t.Fatal(err)
}
if conn.State() != StateListen {
t.Fatalf("expected StateListen, got %s", conn.State())
}
if conn.LocalPort() != 8080 {
t.Fatalf("expected port 8080, got %d", conn.LocalPort())
}
}
func TestConn_Close_Abort(t *testing.T) {
conn := newConfiguredConn(t)
err := conn.OpenListen(8080, 100)
if err != nil {
t.Fatal(err)
}
conn.Abort()
if conn.State() != StateClosed {
t.Fatalf("expected StateClosed after Abort, got %s", conn.State())
}
}
func TestConn_ReadWrite_Closed(t *testing.T) {
conn := newConfiguredConn(t)
_, err := conn.Write([]byte("hello"))
if err == nil {
t.Fatal("Write on closed conn should fail")
}
buf := make([]byte, 64)
_, err = conn.Read(buf)
if err == nil {
t.Fatal("Read on closed conn should fail")
}
}
func TestConn_Flush_Closed(t *testing.T) {
conn := newConfiguredConn(t)
err := conn.Flush()
if err == nil {
t.Fatal("Flush on closed conn should fail")
}
}
func TestConn_BufferedUnsent(t *testing.T) {
conn := newConfiguredConn(t)
if conn.BufferedUnsent() != 0 {
t.Fatalf("expected 0, got %d", conn.BufferedUnsent())
}
}
func TestConn_InternalHandler(t *testing.T) {
conn := newConfiguredConn(t)
h := conn.InternalHandler()
if h == nil {
t.Fatal("InternalHandler returned nil")
}
}
func TestConn_Configure_Twice(t *testing.T) {
conn := newConfiguredConn(t)
err := conn.Configure(ConnConfig{
RxBuf: make([]byte, 1024),
TxBuf: make([]byte, 1024),
TxPacketQueueSize: 8,
})
if err != nil {
t.Fatalf("reconfigure should succeed: %v", err)
}
}
func TestConn_OpenActive_IPv6(t *testing.T) {
conn := newConfiguredConn(t)
addr6 := netip.AddrFrom16([16]byte{0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
remote := netip.AddrPortFrom(addr6, 443)
err := conn.OpenActive(1234, remote, 200)
if err != nil {
t.Fatal(err)
}
raddr := conn.RemoteAddr()
if len(raddr) != 16 {
t.Fatalf("expected 16-byte remote addr, got %d", len(raddr))
}
}
func TestConn_Protocol(t *testing.T) {
var conn Conn
if conn.Protocol() != 6 { // TCP protocol number
t.Fatalf("expected protocol 6, got %d", conn.Protocol())
}
}
func TestConn_ImplementsNetConn(t *testing.T) {
conn := newConfiguredConn(t)
var _ interface {
SetDeadline(time.Time) error
SetReadDeadline(time.Time) error
SetWriteDeadline(time.Time) error
Read([]byte) (int, error)
Write([]byte) (int, error)
Close() error
} = conn
_ = net.ErrClosed
}
+165
View File
@@ -0,0 +1,165 @@
package tcp
import "testing"
// setIPv4Version sets the IP version nibble to 4 at the given offset,
// as required by Drain's call to internal.SetIPAddrs.
func setIPv4Version(carrier []byte, offsetToIP int) {
carrier[offsetToIP] = 0x45 // version=4, IHL=5 (20 bytes)
}
func TestRSTQueue_QueueAndDrain(t *testing.T) {
var q RSTQueue
if q.Pending() != 0 {
t.Fatal("new queue should be empty")
}
srcAddr := [4]byte{10, 0, 0, 1}
q.Queue(srcAddr[:], 8080, 1234, 100, 200, FlagRST|FlagACK)
if q.Pending() != 1 {
t.Fatalf("expected 1 pending, got %d", q.Pending())
}
carrier := make([]byte, 256)
const offsetToIP = 14
const offsetToTCP = 34
setIPv4Version(carrier, offsetToIP)
n, err := q.Drain(carrier, offsetToIP, offsetToTCP)
if err != nil {
t.Fatal(err)
}
if n != sizeHeaderTCP {
t.Fatalf("expected %d bytes written, got %d", sizeHeaderTCP, n)
}
if q.Pending() != 0 {
t.Fatal("queue should be empty after drain")
}
tfrm, err := NewFrame(carrier[offsetToTCP:])
if err != nil {
t.Fatal(err)
}
if tfrm.SourcePort() != 1234 {
t.Errorf("source port = %d; want 1234", tfrm.SourcePort())
}
if tfrm.DestinationPort() != 8080 {
t.Errorf("dest port = %d; want 8080", tfrm.DestinationPort())
}
seg := tfrm.Segment(0)
if seg.SEQ != 100 {
t.Errorf("SEQ = %d; want 100", seg.SEQ)
}
if seg.ACK != 200 {
t.Errorf("ACK = %d; want 200", seg.ACK)
}
if !seg.Flags.HasAll(FlagRST | FlagACK) {
t.Errorf("flags = %s; want RST|ACK", seg.Flags)
}
}
func TestRSTQueue_DrainEmpty(t *testing.T) {
var q RSTQueue
carrier := make([]byte, 256)
n, err := q.Drain(carrier, 14, 34)
if err != nil {
t.Fatal(err)
}
if n != 0 {
t.Fatalf("drain of empty queue should return 0, got %d", n)
}
}
func TestRSTQueue_DrainNegativeOffset(t *testing.T) {
var q RSTQueue
q.Queue([]byte{10, 0, 0, 1}, 80, 1234, 0, 0, FlagRST)
carrier := make([]byte, 256)
n, err := q.Drain(carrier, -1, 34)
if err != nil {
t.Fatal(err)
}
if n != 0 {
t.Fatalf("drain with negative offsetToIP should return 0, got %d", n)
}
}
func TestRSTQueue_Full(t *testing.T) {
var q RSTQueue
addr := []byte{10, 0, 0, 1}
for i := 0; i < 4; i++ {
q.Queue(addr, uint16(i), 1234, Value(i), 0, FlagRST)
}
if q.Pending() != 4 {
t.Fatalf("expected 4 pending, got %d", q.Pending())
}
// Overflow should be silently dropped.
q.Queue(addr, 9999, 1234, 0, 0, FlagRST)
if q.Pending() != 4 {
t.Fatalf("expected 4 pending after overflow, got %d", q.Pending())
}
}
func TestRSTQueue_NonIPv4Dropped(t *testing.T) {
var q RSTQueue
addr6 := make([]byte, 16)
q.Queue(addr6, 80, 1234, 0, 0, FlagRST)
if q.Pending() != 0 {
t.Fatalf("non-IPv4 should be dropped, got %d pending", q.Pending())
}
}
func TestRSTQueue_LIFO(t *testing.T) {
var q RSTQueue
addr := []byte{10, 0, 0, 1}
q.Queue(addr, 1000, 1234, 0, 0, FlagRST)
q.Queue(addr, 2000, 1234, 0, 0, FlagRST)
carrier := make([]byte, 256)
const offsetToIP = 14
const offsetToTCP = 34
setIPv4Version(carrier, offsetToIP)
// Drain returns last-in first (LIFO).
n, err := q.Drain(carrier, offsetToIP, offsetToTCP)
if err != nil || n == 0 {
t.Fatal("drain failed")
}
tfrm, _ := NewFrame(carrier[offsetToTCP:])
if tfrm.DestinationPort() != 2000 {
t.Errorf("expected LIFO order: first drain dest port = %d; want 2000", tfrm.DestinationPort())
}
}
func TestRSTQueue_MultipleDrains(t *testing.T) {
var q RSTQueue
addr := []byte{10, 0, 0, 1}
q.Queue(addr, 1000, 100, 0, 0, FlagRST)
q.Queue(addr, 2000, 200, 0, 0, FlagRST)
q.Queue(addr, 3000, 300, 0, 0, FlagRST)
carrier := make([]byte, 256)
const offsetToIP = 14
const offsetToTCP = 34
// Drain all 3 entries.
for i := 0; i < 3; i++ {
setIPv4Version(carrier, offsetToIP)
n, err := q.Drain(carrier, offsetToIP, offsetToTCP)
if err != nil {
t.Fatal(err)
}
if n != sizeHeaderTCP {
t.Fatalf("drain %d: expected %d bytes, got %d", i, sizeHeaderTCP, n)
}
}
if q.Pending() != 0 {
t.Fatal("queue should be empty")
}
// Fourth drain should return 0.
n, _ := q.Drain(carrier, offsetToIP, offsetToTCP)
if n != 0 {
t.Fatal("expected 0 from empty queue")
}
}