mirror of
https://github.com/v2fly/v2ray-core.git
synced 2026-07-30 11:40:53 -04:00
183 lines
4.1 KiB
Go
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)
|