Files
v2fly/common/packetswitch/interconnect/networkLayer_cable_test.go
T
2026-02-20 11:43:33 +00:00

183 lines
4.1 KiB
Go

package interconnect
import (
"context"
"fmt"
"sync"
"testing"
"time"
"github.com/v2fly/v2ray-core/v5/common/packetswitch"
)
type testWriter struct {
mu sync.Mutex
received [][]byte
ch chan []byte
}
func newTestWriter(bufSize int) *testWriter {
w := &testWriter{ch: make(chan []byte, bufSize)}
return w
}
func (w *testWriter) Write(p []byte) (int, error) {
// copy payload
cp := make([]byte, len(p))
copy(cp, p)
w.mu.Lock()
w.received = append(w.received, cp)
w.mu.Unlock()
select {
case w.ch <- cp:
default:
}
return len(p), nil
}
func (w *testWriter) ReceivedAll() [][]byte {
w.mu.Lock()
defer w.mu.Unlock()
out := make([][]byte, len(w.received))
copy(out, w.received)
return out
}
func TestCable_HappyPath(t *testing.T) {
c, err := NewNetworkLayerCable(context.Background())
if err != nil {
t.Fatalf("failed to create cable: %v", err)
}
l := c.GetLSideDevice()
r := c.GetRSideDevice()
wL := newTestWriter(4)
wR := newTestWriter(4)
if err := l.OnAttach(wL); err != nil {
t.Fatalf("attach left failed: %v", err)
}
if err := r.OnAttach(wR); err != nil {
t.Fatalf("attach right failed: %v", err)
}
payloadL := []byte("from-left")
n, err := l.Write(payloadL)
if err != nil {
t.Fatalf("write left failed: %v", err)
}
if n != len(payloadL) {
t.Fatalf("write returned wrong length: %d", n)
}
select {
case got := <-wR.ch:
if string(got) != string(payloadL) {
t.Fatalf("unexpected payload at right: %s", string(got))
}
case <-time.After(500 * time.Millisecond):
t.Fatalf("timeout waiting for payload on right")
}
payloadR := []byte("from-right")
n, err = r.Write(payloadR)
if err != nil {
t.Fatalf("write right failed: %v", err)
}
if n != len(payloadR) {
t.Fatalf("write returned wrong length: %d", n)
}
select {
case got := <-wL.ch:
if string(got) != string(payloadR) {
t.Fatalf("unexpected payload at left: %s", string(got))
}
case <-time.After(500 * time.Millisecond):
t.Fatalf("timeout waiting for payload on left")
}
}
func TestCable_NoPeer(t *testing.T) {
c, _ := NewNetworkLayerCable(context.Background())
l := c.GetLSideDevice()
wL := newTestWriter(1)
if err := l.OnAttach(wL); err != nil {
t.Fatalf("attach left failed: %v", err)
}
if n, err := l.Write([]byte("x")); err == nil || n != 0 {
t.Fatalf("expected write to fail when no peer attached got n=%d err=%v", n, err)
}
}
func TestCable_DoubleAttachAndClose(t *testing.T) {
c, _ := NewNetworkLayerCable(context.Background())
l := c.GetLSideDevice()
w1 := newTestWriter(1)
w2 := newTestWriter(1)
if err := l.OnAttach(w1); err != nil {
t.Fatalf("attach left failed: %v", err)
}
if err := l.OnAttach(w2); err == nil {
t.Fatalf("expected second attach to fail")
}
r := c.GetRSideDevice()
wr := newTestWriter(2)
if err := r.OnAttach(wr); err != nil {
t.Fatalf("attach right failed: %v", err)
}
// close left and ensure right cannot write
if err := l.Close(); err != nil {
t.Fatalf("close left failed: %v", err)
}
if n, err := r.Write([]byte("hello")); err == nil || n != 0 {
t.Fatalf("expected write from right to fail after left closed got n=%d err=%v", n, err)
}
}
func TestCable_ConcurrentWrites(t *testing.T) {
c, _ := NewNetworkLayerCable(context.Background())
l := c.GetLSideDevice()
r := c.GetRSideDevice()
wL := newTestWriter(100)
wR := newTestWriter(100)
if err := l.OnAttach(wL); err != nil {
t.Fatalf("attach left failed: %v", err)
}
if err := r.OnAttach(wR); err != nil {
t.Fatalf("attach right failed: %v", err)
}
var wg sync.WaitGroup
count := 200
wg.Add(count * 2)
for i := 0; i < count; i++ {
payloadL := []byte(fmt.Sprintf("L-%d", i%10))
payloadR := []byte(fmt.Sprintf("R-%d", i%10))
go func(p []byte) {
defer wg.Done()
_, _ = l.Write(p)
}(payloadL)
go func(p []byte) {
defer wg.Done()
_, _ = r.Write(p)
}(payloadR)
}
wg.Wait()
// drain channels (best-effort)
timed := time.After(500 * time.Millisecond)
for {
select {
case <-wL.ch:
case <-wR.ch:
case <-timed:
return
}
}
}
// ensure testWriter implements the interface
var _ packetswitch.NetworkLayerPacketWriter = (*testWriter)(nil)