Files
x/internal/net/transport_test.go
T
ginuerzh ef58909fb7 fix(dialer): correct inverted setMark on FreeBSD/OpenBSD
Fix setMark early-return conditions that were inverted relative to
Linux: on FreeBSD (SO_USER_COOKIE) and OpenBSD (SO_RTABLE), a
non-zero mark was short-circuited instead of applied, disabling
socket marking entirely.

Also fix GetClientIP to trim leading whitespace from X-Forwarded-For
entries (per RFC 7239), and fix Body.Read to subtract len(b) instead
of n from recordSize when a single read exceeds the remaining quota.

Add unit tests for internal/net/ (addr, dialer, http, ip, net, pipe,
transport, resolve, proxyproto, udp).
2026-05-21 20:58:48 +08:00

110 lines
2.4 KiB
Go

package net
import (
"errors"
"io"
"testing"
)
// mockReadWriter implements io.ReadWriter
type mockReadWriter struct {
data []byte
readPos int
readErr error
writeBuf []byte
}
func (m *mockReadWriter) Read(p []byte) (int, error) {
if m.readErr != nil {
return 0, m.readErr
}
if m.readPos >= len(m.data) {
return 0, io.EOF
}
n := copy(p, m.data[m.readPos:])
m.readPos += n
return n, nil
}
func (m *mockReadWriter) Write(p []byte) (int, error) {
m.writeBuf = append(m.writeBuf, p...)
return len(p), nil
}
func TestTransport_Normal(t *testing.T) {
rw1 := &mockReadWriter{data: []byte("from rw1")}
rw2 := &mockReadWriter{data: []byte("from rw2")}
done := make(chan struct{}, 2)
go func() {
_ = CopyBuffer(rw1, rw2, 1024)
done <- struct{}{}
}()
go func() {
_ = CopyBuffer(rw2, rw1, 1024)
done <- struct{}{}
}()
// Wait for both goroutines to complete
<-done
<-done
// rw2 receives data from rw1
if string(rw2.writeBuf) != "from rw1" {
t.Errorf("rw2.writeBuf = %q, want %q", string(rw2.writeBuf), "from rw1")
}
// rw1 receives data from rw2
if string(rw1.writeBuf) != "from rw2" {
t.Errorf("rw1.writeBuf = %q, want %q", string(rw1.writeBuf), "from rw2")
}
}
func TestTransport_ReadError(t *testing.T) {
readErr := errors.New("read failure")
rw1 := &mockReadWriter{readErr: readErr}
rw2 := &mockReadWriter{data: []byte("from rw2")}
err := Transport(rw1, rw2)
if err == nil {
t.Error("expected error, got nil")
}
}
func TestCopyBuffer(t *testing.T) {
src := &mockReadWriter{data: []byte("test data")}
dst := &mockReadWriter{}
err := CopyBuffer(dst, src, 1024)
if err != nil {
t.Fatal(err)
}
if string(dst.writeBuf) != "test data" {
t.Errorf("dst.writeBuf = %q, want %q", string(dst.writeBuf), "test data")
}
}
func TestCopyBuffer_ReadError(t *testing.T) {
readErr := errors.New("read failure")
src := &mockReadWriter{readErr: readErr}
dst := &mockReadWriter{}
err := CopyBuffer(dst, src, 1024)
if err == nil {
t.Error("expected error, got nil")
}
}
func TestTransport_EOFIgnored(t *testing.T) {
// Transport treats io.EOF as non-error.
// Both goroutines return nil/EOF → Transport should return nil.
rw1 := &mockReadWriter{data: []byte("data")}
rw2 := &mockReadWriter{data: []byte("")} // empty data → immediate EOF
err := Transport(rw1, rw2)
if err != nil {
t.Errorf("expected nil (EOF is not an error), got %v", err)
}
}