mirror of
https://github.com/apernet/hysteria.git
synced 2025-04-03 20:47:38 +03:00
feat(wip): test reworks (need to add back traffic logger tests)
This commit is contained in:
parent
dd836b4496
commit
6172f2ac53
7 changed files with 131 additions and 618 deletions
|
@ -109,12 +109,12 @@ func (c *clientImpl) connect() error {
|
|||
_ = conn.CloseWithError(closeErrCodeProtocolError, "")
|
||||
}
|
||||
_ = pktConn.Close()
|
||||
return &coreErrs.ConnectError{Err: err}
|
||||
return coreErrs.ConnectError{Err: err}
|
||||
}
|
||||
if resp.StatusCode != protocol.StatusAuthOK {
|
||||
_ = conn.CloseWithError(closeErrCodeProtocolError, "")
|
||||
_ = pktConn.Close()
|
||||
return &coreErrs.AuthError{StatusCode: resp.StatusCode}
|
||||
return coreErrs.AuthError{StatusCode: resp.StatusCode}
|
||||
}
|
||||
// Auth OK
|
||||
udpEnabled, serverRx := protocol.AuthResponseDataFromHeader(resp.Header)
|
||||
|
|
|
@ -92,8 +92,8 @@ func TestClientServerTCPClose(t *testing.T) {
|
|||
_ = conn.Close()
|
||||
}
|
||||
|
||||
// TestServerUDPIdleTimeout tests whether the server's UDP idle timeout works correctly.
|
||||
func TestServerUDPIdleTimeout(t *testing.T) {
|
||||
// TestClientServerUDPIdleTimeout tests whether the server's UDP idle timeout works correctly.
|
||||
func TestClientServerUDPIdleTimeout(t *testing.T) {
|
||||
// Create server
|
||||
udpConn, udpAddr, err := serverConn()
|
||||
assert.NoError(t, err)
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
|
||||
// TestServerMasquerade is a test to ensure that the server behaves as a normal
|
||||
// HTTP/3 server when dealing with an unauthenticated client. This is mainly to
|
||||
// confirm that the server does not expose itself to active probers.
|
||||
// confirm that the server does not expose itself to active probing.
|
||||
func TestServerMasquerade(t *testing.T) {
|
||||
// Create server
|
||||
udpConn, udpAddr, err := serverConn()
|
||||
|
|
|
@ -1,43 +1,30 @@
|
|||
package integration_tests
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/apernet/hysteria/core/client"
|
||||
coreErrs "github.com/apernet/hysteria/core/errors"
|
||||
"github.com/apernet/hysteria/core/internal/integration_tests/mocks"
|
||||
"github.com/apernet/hysteria/core/server"
|
||||
)
|
||||
|
||||
// Smoke tests that act as a sanity check for client & server to ensure they can talk to each other correctly.
|
||||
|
||||
// TestClientNoServer tests how the client handles a server that doesn't exist.
|
||||
// The client should still be able to be created, but TCP & UDP requests should fail.
|
||||
// TestClientNoServer tests how the client handles a server address it cannot connect to.
|
||||
// NewClient should return a ConnectError.
|
||||
func TestClientNoServer(t *testing.T) {
|
||||
// Create client
|
||||
c, err := client.NewClient(&client.Config{
|
||||
ServerAddr: &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14514},
|
||||
ServerAddr: &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 55666},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating client:", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
var cErr *coreErrs.ConnectError
|
||||
|
||||
// Try TCP
|
||||
_, err = c.TCP("google.com:443")
|
||||
if !errors.As(err, &cErr) {
|
||||
t.Fatal("expected connect error from TCP")
|
||||
}
|
||||
|
||||
// Try UDP
|
||||
_, err = c.UDP()
|
||||
if !errors.As(err, &cErr) {
|
||||
t.Fatal("expected connect error from DialUDP")
|
||||
}
|
||||
assert.Nil(t, c)
|
||||
_, ok := err.(coreErrs.ConnectError)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
// TestClientServerBadAuth tests two things:
|
||||
|
@ -45,79 +32,82 @@ func TestClientNoServer(t *testing.T) {
|
|||
// - How the client handles failed authentication.
|
||||
func TestClientServerBadAuth(t *testing.T) {
|
||||
// Create server
|
||||
udpAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14514}
|
||||
udpConn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
udpConn, udpAddr, err := serverConn()
|
||||
assert.NoError(t, err)
|
||||
auth := mocks.NewMockAuthenticator(t)
|
||||
auth.EXPECT().Authenticate(mock.Anything, "badpassword", uint64(0)).Return(false, "").Once()
|
||||
s, err := server.NewServer(&server.Config{
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: &pwAuthenticator{
|
||||
Password: "correct password",
|
||||
ID: "nobody",
|
||||
},
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: auth,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer s.Close()
|
||||
go s.Serve()
|
||||
|
||||
// Create client
|
||||
c, err := client.NewClient(&client.Config{
|
||||
ServerAddr: udpAddr,
|
||||
Auth: "wrong password",
|
||||
Auth: "badpassword",
|
||||
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating client:", err)
|
||||
}
|
||||
assert.Nil(t, c)
|
||||
_, ok := err.(coreErrs.AuthError)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
// TestClientServerUDPDisabled tests how the client handles a server that does not support UDP.
|
||||
// UDP should return a DialError.
|
||||
func TestClientServerUDPDisabled(t *testing.T) {
|
||||
// Create server
|
||||
udpConn, udpAddr, err := serverConn()
|
||||
assert.NoError(t, err)
|
||||
auth := mocks.NewMockAuthenticator(t)
|
||||
auth.EXPECT().Authenticate(mock.Anything, mock.Anything, mock.Anything).Return(true, "nobody")
|
||||
s, err := server.NewServer(&server.Config{
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
DisableUDP: true,
|
||||
Authenticator: auth,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
defer s.Close()
|
||||
go s.Serve()
|
||||
|
||||
// Create client
|
||||
c, err := client.NewClient(&client.Config{
|
||||
ServerAddr: udpAddr,
|
||||
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
var aErr *coreErrs.AuthError
|
||||
|
||||
// Try TCP
|
||||
_, err = c.TCP("google.com:443")
|
||||
if !errors.As(err, &aErr) {
|
||||
t.Fatal("expected auth error from TCP")
|
||||
}
|
||||
|
||||
// Try UDP
|
||||
_, err = c.UDP()
|
||||
if !errors.As(err, &aErr) {
|
||||
t.Fatal("expected auth error from DialUDP")
|
||||
}
|
||||
conn, err := c.UDP()
|
||||
assert.Nil(t, conn)
|
||||
_, ok := err.(coreErrs.DialError)
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
// TestClientServerTCPEcho tests TCP forwarding using a TCP echo server.
|
||||
func TestClientServerTCPEcho(t *testing.T) {
|
||||
// Create server
|
||||
udpAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14514}
|
||||
udpConn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
udpConn, udpAddr, err := serverConn()
|
||||
assert.NoError(t, err)
|
||||
auth := mocks.NewMockAuthenticator(t)
|
||||
auth.EXPECT().Authenticate(mock.Anything, mock.Anything, mock.Anything).Return(true, "nobody")
|
||||
s, err := server.NewServer(&server.Config{
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: &pwAuthenticator{
|
||||
Password: "password",
|
||||
ID: "nobody",
|
||||
},
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: auth,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer s.Close()
|
||||
go s.Serve()
|
||||
|
||||
// Create TCP echo server
|
||||
echoTCPAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14515}
|
||||
echoListener, err := net.ListenTCP("tcp", echoTCPAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating TCP echo server:", err)
|
||||
}
|
||||
echoAddr := "127.0.0.1:22333"
|
||||
echoListener, err := net.Listen("tcp", echoAddr)
|
||||
assert.NoError(t, err)
|
||||
echoServer := &tcpEchoServer{Listener: echoListener}
|
||||
defer echoServer.Close()
|
||||
go echoServer.Serve()
|
||||
|
@ -125,65 +115,46 @@ func TestClientServerTCPEcho(t *testing.T) {
|
|||
// Create client
|
||||
c, err := client.NewClient(&client.Config{
|
||||
ServerAddr: udpAddr,
|
||||
Auth: "password",
|
||||
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating client:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
// Dial TCP
|
||||
conn, err := c.TCP(echoTCPAddr.String())
|
||||
if err != nil {
|
||||
t.Fatal("error dialing TCP:", err)
|
||||
}
|
||||
conn, err := c.TCP(echoAddr)
|
||||
assert.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
// Send and receive data
|
||||
sData := []byte("hello world")
|
||||
_, err = conn.Write(sData)
|
||||
if err != nil {
|
||||
t.Fatal("error writing to TCP:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
rData := make([]byte, len(sData))
|
||||
_, err = io.ReadFull(conn, rData)
|
||||
if err != nil {
|
||||
t.Fatal("error reading from TCP:", err)
|
||||
}
|
||||
if string(rData) != string(sData) {
|
||||
t.Fatalf("expected %q, got %q", sData, rData)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, sData, rData)
|
||||
}
|
||||
|
||||
// TestClientServerUDPEcho tests UDP forwarding using a UDP echo server.
|
||||
func TestClientServerUDPEcho(t *testing.T) {
|
||||
// Create server
|
||||
udpAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14514}
|
||||
udpConn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
udpConn, udpAddr, err := serverConn()
|
||||
assert.NoError(t, err)
|
||||
auth := mocks.NewMockAuthenticator(t)
|
||||
auth.EXPECT().Authenticate(mock.Anything, mock.Anything, mock.Anything).Return(true, "nobody")
|
||||
s, err := server.NewServer(&server.Config{
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: &pwAuthenticator{
|
||||
Password: "password",
|
||||
ID: "nobody",
|
||||
},
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: auth,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer s.Close()
|
||||
go s.Serve()
|
||||
|
||||
// Create UDP echo server
|
||||
echoUDPAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 55555}
|
||||
echoConn, err := net.ListenUDP("udp", echoUDPAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating UDP echo server:", err)
|
||||
}
|
||||
echoAddr := "127.0.0.1:22333"
|
||||
echoConn, err := net.ListenPacket("udp", echoAddr)
|
||||
assert.NoError(t, err)
|
||||
echoServer := &udpEchoServer{Conn: echoConn}
|
||||
defer echoServer.Close()
|
||||
go echoServer.Serve()
|
||||
|
@ -191,35 +162,22 @@ func TestClientServerUDPEcho(t *testing.T) {
|
|||
// Create client
|
||||
c, err := client.NewClient(&client.Config{
|
||||
ServerAddr: udpAddr,
|
||||
Auth: "password",
|
||||
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating client:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
// Listen UDP
|
||||
conn, err := c.UDP()
|
||||
if err != nil {
|
||||
t.Fatal("error listening UDP:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer conn.Close()
|
||||
|
||||
// Send and receive data
|
||||
sData := []byte("hello world")
|
||||
err = conn.Send(sData, echoUDPAddr.String())
|
||||
if err != nil {
|
||||
t.Fatal("error sending UDP:", err)
|
||||
}
|
||||
err = conn.Send(sData, echoAddr)
|
||||
assert.NoError(t, err)
|
||||
rData, rAddr, err := conn.Receive()
|
||||
if err != nil {
|
||||
t.Fatal("error receiving UDP:", err)
|
||||
}
|
||||
if string(rData) != string(sData) {
|
||||
t.Fatalf("expected %q, got %q", sData, rData)
|
||||
}
|
||||
if rAddr != echoUDPAddr.String() {
|
||||
t.Fatalf("expected %q, got %q", echoUDPAddr.String(), rAddr)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, sData, rData)
|
||||
assert.Equal(t, echoAddr, rAddr)
|
||||
}
|
||||
|
|
|
@ -9,9 +9,12 @@ import (
|
|||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"golang.org/x/time/rate"
|
||||
|
||||
"github.com/apernet/hysteria/core/client"
|
||||
"github.com/apernet/hysteria/core/internal/integration_tests/mocks"
|
||||
"github.com/apernet/hysteria/core/server"
|
||||
)
|
||||
|
||||
|
@ -26,9 +29,7 @@ func (s *tcpStressor) Run(t *testing.T) {
|
|||
// Make some random data
|
||||
sData := make([]byte, s.Size)
|
||||
_, err := rand.Read(sData)
|
||||
if err != nil {
|
||||
t.Fatal("error generating random data:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Run iterations
|
||||
for i := 0; i < s.Iterations; i++ {
|
||||
|
@ -57,9 +58,7 @@ func (s *tcpStressor) Run(t *testing.T) {
|
|||
}
|
||||
wg.Wait()
|
||||
|
||||
if len(errChan) > 0 {
|
||||
t.Fatal("error reading from TCP:", <-errChan)
|
||||
}
|
||||
assert.Empty(t, errChan)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,9 +75,7 @@ func (s *udpStressor) Run(t *testing.T) {
|
|||
// Make some random data
|
||||
sData := make([]byte, s.Size)
|
||||
_, err := rand.Read(sData)
|
||||
if err != nil {
|
||||
t.Fatal("error generating random data:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Due to UDP's unreliability, we need to limit the rate of sending
|
||||
// to reduce packet loss. This is hardcoded to 1 MiB/s for now.
|
||||
|
@ -123,39 +120,29 @@ func (s *udpStressor) Run(t *testing.T) {
|
|||
}
|
||||
wg.Wait()
|
||||
|
||||
if len(errChan) > 0 {
|
||||
t.Fatal("error reading from UDP:", <-errChan)
|
||||
}
|
||||
assert.Empty(t, errChan)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientServerTCPStress(t *testing.T) {
|
||||
// Create server
|
||||
udpAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14514}
|
||||
udpConn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
udpConn, udpAddr, err := serverConn()
|
||||
assert.NoError(t, err)
|
||||
auth := mocks.NewMockAuthenticator(t)
|
||||
auth.EXPECT().Authenticate(mock.Anything, mock.Anything, mock.Anything).Return(true, "nobody")
|
||||
s, err := server.NewServer(&server.Config{
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: &pwAuthenticator{
|
||||
Password: "password",
|
||||
ID: "nobody",
|
||||
},
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: auth,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer s.Close()
|
||||
go s.Serve()
|
||||
|
||||
// Create TCP echo server
|
||||
echoTCPAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14515}
|
||||
echoListener, err := net.ListenTCP("tcp", echoTCPAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating TCP echo server:", err)
|
||||
}
|
||||
echoAddr := "127.0.0.1:22333"
|
||||
echoListener, err := net.Listen("tcp", echoAddr)
|
||||
assert.NoError(t, err)
|
||||
echoServer := &tcpEchoServer{Listener: echoListener}
|
||||
defer echoServer.Close()
|
||||
go echoServer.Serve()
|
||||
|
@ -163,16 +150,13 @@ func TestClientServerTCPStress(t *testing.T) {
|
|||
// Create client
|
||||
c, err := client.NewClient(&client.Config{
|
||||
ServerAddr: udpAddr,
|
||||
Auth: "password",
|
||||
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating client:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
dialFunc := func() (net.Conn, error) {
|
||||
return c.TCP(echoTCPAddr.String())
|
||||
return c.TCP(echoAddr)
|
||||
}
|
||||
|
||||
t.Run("Single 500m", (&tcpStressor{DialFunc: dialFunc, Size: 524288000, Parallel: 1, Iterations: 1}).Run)
|
||||
|
@ -186,49 +170,38 @@ func TestClientServerTCPStress(t *testing.T) {
|
|||
|
||||
func TestClientServerUDPStress(t *testing.T) {
|
||||
// Create server
|
||||
udpAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14514}
|
||||
udpConn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
udpConn, udpAddr, err := serverConn()
|
||||
assert.NoError(t, err)
|
||||
auth := mocks.NewMockAuthenticator(t)
|
||||
auth.EXPECT().Authenticate(mock.Anything, mock.Anything, mock.Anything).Return(true, "nobody")
|
||||
s, err := server.NewServer(&server.Config{
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: &pwAuthenticator{
|
||||
Password: "password",
|
||||
ID: "nobody",
|
||||
},
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: auth,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer s.Close()
|
||||
go s.Serve()
|
||||
|
||||
// Create UDP echo server
|
||||
echoUDPAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14515}
|
||||
echoListener, err := net.ListenUDP("udp", echoUDPAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating UDP echo server:", err)
|
||||
}
|
||||
echoServer := &udpEchoServer{Conn: echoListener}
|
||||
echoAddr := "127.0.0.1:22333"
|
||||
echoConn, err := net.ListenPacket("udp", echoAddr)
|
||||
assert.NoError(t, err)
|
||||
echoServer := &udpEchoServer{Conn: echoConn}
|
||||
defer echoServer.Close()
|
||||
go echoServer.Serve()
|
||||
|
||||
// Create client
|
||||
c, err := client.NewClient(&client.Config{
|
||||
ServerAddr: udpAddr,
|
||||
Auth: "password",
|
||||
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating client:", err)
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
defer c.Close()
|
||||
|
||||
t.Run("Single 1000x100b", (&udpStressor{
|
||||
ListenFunc: c.UDP,
|
||||
ServerAddr: echoUDPAddr.String(),
|
||||
ServerAddr: echoAddr,
|
||||
Size: 100,
|
||||
Count: 1000,
|
||||
Parallel: 1,
|
||||
|
@ -236,7 +209,7 @@ func TestClientServerUDPStress(t *testing.T) {
|
|||
}).Run)
|
||||
t.Run("Single 1000x3k", (&udpStressor{
|
||||
ListenFunc: c.UDP,
|
||||
ServerAddr: echoUDPAddr.String(),
|
||||
ServerAddr: echoAddr,
|
||||
Size: 3000,
|
||||
Count: 1000,
|
||||
Parallel: 1,
|
||||
|
@ -245,7 +218,7 @@ func TestClientServerUDPStress(t *testing.T) {
|
|||
|
||||
t.Run("5 Sequential 1000x100b", (&udpStressor{
|
||||
ListenFunc: c.UDP,
|
||||
ServerAddr: echoUDPAddr.String(),
|
||||
ServerAddr: echoAddr,
|
||||
Size: 100,
|
||||
Count: 1000,
|
||||
Parallel: 1,
|
||||
|
@ -253,7 +226,7 @@ func TestClientServerUDPStress(t *testing.T) {
|
|||
}).Run)
|
||||
t.Run("5 Sequential 200x3k", (&udpStressor{
|
||||
ListenFunc: c.UDP,
|
||||
ServerAddr: echoUDPAddr.String(),
|
||||
ServerAddr: echoAddr,
|
||||
Size: 3000,
|
||||
Count: 200,
|
||||
Parallel: 1,
|
||||
|
@ -262,7 +235,7 @@ func TestClientServerUDPStress(t *testing.T) {
|
|||
|
||||
t.Run("2 Sequential 5 Parallel 1000x100b", (&udpStressor{
|
||||
ListenFunc: c.UDP,
|
||||
ServerAddr: echoUDPAddr.String(),
|
||||
ServerAddr: echoAddr,
|
||||
Size: 100,
|
||||
Count: 1000,
|
||||
Parallel: 5,
|
||||
|
@ -271,19 +244,10 @@ func TestClientServerUDPStress(t *testing.T) {
|
|||
|
||||
t.Run("2 Sequential 5 Parallel 200x3k", (&udpStressor{
|
||||
ListenFunc: c.UDP,
|
||||
ServerAddr: echoUDPAddr.String(),
|
||||
ServerAddr: echoAddr,
|
||||
Size: 3000,
|
||||
Count: 200,
|
||||
Parallel: 5,
|
||||
Iterations: 2,
|
||||
}).Run)
|
||||
|
||||
t.Run("10 Sequential 5 Parallel 200x3k", (&udpStressor{
|
||||
ListenFunc: c.UDP,
|
||||
ServerAddr: echoUDPAddr.String(),
|
||||
Size: 3000,
|
||||
Count: 200,
|
||||
Parallel: 5,
|
||||
Iterations: 10,
|
||||
}).Run)
|
||||
}
|
||||
|
|
|
@ -1,173 +0,0 @@
|
|||
package integration_tests
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/apernet/hysteria/core/client"
|
||||
"github.com/apernet/hysteria/core/server"
|
||||
)
|
||||
|
||||
type testTrafficLogger struct {
|
||||
Tx, Rx uint64
|
||||
Block atomic.Bool
|
||||
}
|
||||
|
||||
func (l *testTrafficLogger) Log(id string, tx, rx uint64) bool {
|
||||
atomic.AddUint64(&l.Tx, tx)
|
||||
atomic.AddUint64(&l.Rx, rx)
|
||||
return !l.Block.Load()
|
||||
}
|
||||
|
||||
func (l *testTrafficLogger) Get() (tx, rx uint64) {
|
||||
return atomic.LoadUint64(&l.Tx), atomic.LoadUint64(&l.Rx)
|
||||
}
|
||||
|
||||
func (l *testTrafficLogger) SetBlock(block bool) {
|
||||
l.Block.Store(block)
|
||||
}
|
||||
|
||||
func (l *testTrafficLogger) Reset() {
|
||||
atomic.StoreUint64(&l.Tx, 0)
|
||||
atomic.StoreUint64(&l.Rx, 0)
|
||||
}
|
||||
|
||||
// TestServerTrafficLogger tests that the server's TrafficLogger interface is working correctly.
|
||||
// More specifically, it tests that the server is correctly logging traffic in both directions,
|
||||
// and that it is correctly disconnecting clients when the traffic logger returns false.
|
||||
func TestServerTrafficLogger(t *testing.T) {
|
||||
tl := &testTrafficLogger{}
|
||||
|
||||
// Create server
|
||||
udpAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14514}
|
||||
udpConn, err := net.ListenUDP("udp", udpAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
s, err := server.NewServer(&server.Config{
|
||||
TLSConfig: serverTLSConfig(),
|
||||
Conn: udpConn,
|
||||
Authenticator: &pwAuthenticator{
|
||||
Password: "password",
|
||||
ID: "nobody",
|
||||
},
|
||||
TrafficLogger: tl,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating server:", err)
|
||||
}
|
||||
defer s.Close()
|
||||
go s.Serve()
|
||||
|
||||
// Create TCP double echo server
|
||||
// We use double echo to test that the traffic logger is correctly logging both directions.
|
||||
echoTCPAddr := &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 14515}
|
||||
echoListener, err := net.ListenTCP("tcp", echoTCPAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating TCP echo server:", err)
|
||||
}
|
||||
tEchoServer := &tcpDoubleEchoServer{Listener: echoListener}
|
||||
defer tEchoServer.Close()
|
||||
go tEchoServer.Serve()
|
||||
|
||||
// Create client
|
||||
c, err := client.NewClient(&client.Config{
|
||||
ServerAddr: udpAddr,
|
||||
Auth: "password",
|
||||
TLSConfig: client.TLSConfig{InsecureSkipVerify: true},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("error creating client:", err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
// Dial TCP
|
||||
tConn, err := c.TCP(echoTCPAddr.String())
|
||||
if err != nil {
|
||||
t.Fatal("error dialing TCP:", err)
|
||||
}
|
||||
defer tConn.Close()
|
||||
|
||||
// Send and receive TCP data
|
||||
sData := []byte("1234")
|
||||
_, err = tConn.Write(sData)
|
||||
if err != nil {
|
||||
t.Fatal("error writing to TCP:", err)
|
||||
}
|
||||
rData := make([]byte, len(sData)*2)
|
||||
_, err = io.ReadFull(tConn, rData)
|
||||
if err != nil {
|
||||
t.Fatal("error reading from TCP:", err)
|
||||
}
|
||||
expected := string(sData) + string(sData)
|
||||
if string(rData) != expected {
|
||||
t.Fatalf("expected %q, got %q", expected, string(rData))
|
||||
}
|
||||
|
||||
// Check traffic logger
|
||||
tx, rx := tl.Get()
|
||||
if tx != uint64(len(sData)) || rx != uint64(len(rData)) {
|
||||
t.Fatalf("expected TrafficLogger Tx=%d, Rx=%d, got Tx=%d, Rx=%d", len(sData), len(rData), tx, rx)
|
||||
}
|
||||
tl.Reset()
|
||||
|
||||
// Create UDP double echo server
|
||||
echoUDPAddr := &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 55555}
|
||||
echoConn, err := net.ListenUDP("udp", echoUDPAddr)
|
||||
if err != nil {
|
||||
t.Fatal("error creating UDP echo server:", err)
|
||||
}
|
||||
uEchoServer := &udpDoubleEchoServer{Conn: echoConn}
|
||||
defer uEchoServer.Close()
|
||||
go uEchoServer.Serve()
|
||||
|
||||
// Listen UDP
|
||||
uConn, err := c.UDP()
|
||||
if err != nil {
|
||||
t.Fatal("error listening UDP:", err)
|
||||
}
|
||||
defer uConn.Close()
|
||||
|
||||
// Send and receive UDP data
|
||||
sData = []byte("gucci gang")
|
||||
err = uConn.Send(sData, echoUDPAddr.String())
|
||||
if err != nil {
|
||||
t.Fatal("error sending UDP:", err)
|
||||
}
|
||||
for i := 0; i < 2; i++ {
|
||||
rData, rAddr, err := uConn.Receive()
|
||||
if err != nil {
|
||||
t.Fatal("error receiving UDP:", err)
|
||||
}
|
||||
if string(rData) != string(sData) {
|
||||
t.Fatalf("expected %q, got %q", string(sData), string(rData))
|
||||
}
|
||||
if rAddr != echoUDPAddr.String() {
|
||||
t.Fatalf("expected %q, got %q", echoUDPAddr.String(), rAddr)
|
||||
}
|
||||
}
|
||||
|
||||
// Check traffic logger
|
||||
tx, rx = tl.Get()
|
||||
if tx != uint64(len(sData)) || rx != uint64(len(sData)*2) {
|
||||
t.Fatalf("expected TrafficLogger Tx=%d, Rx=%d, got Tx=%d, Rx=%d", len(sData), len(sData)*2, tx, rx)
|
||||
}
|
||||
|
||||
// Check the disconnect client functionality
|
||||
tl.SetBlock(true)
|
||||
|
||||
// Send and receive TCP data again
|
||||
sData = []byte("1234")
|
||||
_, err = tConn.Write(sData)
|
||||
if err != nil {
|
||||
t.Fatal("error writing to TCP:", err)
|
||||
}
|
||||
// This should fail instantly without reading any data
|
||||
// io.Copy should return nil as EOF is treated as a non-error though
|
||||
n, err := io.Copy(io.Discard, tConn)
|
||||
if n != 0 || err != nil {
|
||||
t.Fatal("expected 0 bytes read and nil error, got", n, err)
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package integration_tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net"
|
||||
|
@ -35,18 +34,6 @@ func serverConn() (net.PacketConn, net.Addr, error) {
|
|||
return udpConn, udpAddr, nil
|
||||
}
|
||||
|
||||
type pwAuthenticator struct {
|
||||
Password string
|
||||
ID string
|
||||
}
|
||||
|
||||
func (a *pwAuthenticator) Authenticate(addr net.Addr, auth string, tx uint64) (ok bool, id string) {
|
||||
if auth != a.Password {
|
||||
return false, ""
|
||||
}
|
||||
return true, a.ID
|
||||
}
|
||||
|
||||
// tcpEchoServer is a TCP server that echoes what it reads from the connection.
|
||||
// It will never actively close the connection.
|
||||
type tcpEchoServer struct {
|
||||
|
@ -70,92 +57,6 @@ func (s *tcpEchoServer) Close() error {
|
|||
return s.Listener.Close()
|
||||
}
|
||||
|
||||
// tcpDoubleEchoServer is a TCP server that echoes twice what it reads from the connection.
|
||||
// It will never actively close the connection.
|
||||
type tcpDoubleEchoServer struct {
|
||||
Listener net.Listener
|
||||
}
|
||||
|
||||
func (s *tcpDoubleEchoServer) Serve() error {
|
||||
for {
|
||||
conn, err := s.Listener.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
_, _ = conn.Write(buf[:n])
|
||||
_, _ = conn.Write(buf[:n])
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *tcpDoubleEchoServer) Close() error {
|
||||
return s.Listener.Close()
|
||||
}
|
||||
|
||||
type sinkEvent struct {
|
||||
Data []byte
|
||||
Err error
|
||||
}
|
||||
|
||||
// tcpSinkServer is a TCP server that reads data from the connection,
|
||||
// and sends what it read to the channel when the connection is closed.
|
||||
type tcpSinkServer struct {
|
||||
Listener net.Listener
|
||||
Ch chan<- sinkEvent
|
||||
}
|
||||
|
||||
func (s *tcpSinkServer) Serve() error {
|
||||
for {
|
||||
conn, err := s.Listener.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
var buf bytes.Buffer
|
||||
_, err := io.Copy(&buf, conn)
|
||||
_ = conn.Close()
|
||||
s.Ch <- sinkEvent{Data: buf.Bytes(), Err: err}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *tcpSinkServer) Close() error {
|
||||
return s.Listener.Close()
|
||||
}
|
||||
|
||||
// tcpSenderServer is a TCP server that sends data to the connection,
|
||||
// and closes the connection when all data has been sent.
|
||||
type tcpSenderServer struct {
|
||||
Listener net.Listener
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (s *tcpSenderServer) Serve() error {
|
||||
for {
|
||||
conn, err := s.Listener.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
_, _ = conn.Write(s.Data)
|
||||
_ = conn.Close()
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *tcpSenderServer) Close() error {
|
||||
return s.Listener.Close()
|
||||
}
|
||||
|
||||
// udpEchoServer is a UDP server that echoes what it reads from the connection.
|
||||
// It will never actively close the connection.
|
||||
type udpEchoServer struct {
|
||||
|
@ -179,140 +80,3 @@ func (s *udpEchoServer) Serve() error {
|
|||
func (s *udpEchoServer) Close() error {
|
||||
return s.Conn.Close()
|
||||
}
|
||||
|
||||
// udpDoubleEchoServer is a UDP server that echoes twice what it reads from the connection.
|
||||
// It will never actively close the connection.
|
||||
type udpDoubleEchoServer struct {
|
||||
Conn net.PacketConn
|
||||
}
|
||||
|
||||
func (s *udpDoubleEchoServer) Serve() error {
|
||||
buf := make([]byte, 65536)
|
||||
for {
|
||||
n, addr, err := s.Conn.ReadFrom(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.Conn.WriteTo(buf[:n], addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.Conn.WriteTo(buf[:n], addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *udpDoubleEchoServer) Close() error {
|
||||
return s.Conn.Close()
|
||||
}
|
||||
|
||||
type connectEvent struct {
|
||||
Addr net.Addr
|
||||
ID string
|
||||
TX uint64
|
||||
}
|
||||
|
||||
type disconnectEvent struct {
|
||||
Addr net.Addr
|
||||
ID string
|
||||
Err error
|
||||
}
|
||||
|
||||
type tcpRequestEvent struct {
|
||||
Addr net.Addr
|
||||
ID string
|
||||
ReqAddr string
|
||||
}
|
||||
|
||||
type tcpErrorEvent struct {
|
||||
Addr net.Addr
|
||||
ID string
|
||||
ReqAddr string
|
||||
Err error
|
||||
}
|
||||
|
||||
type udpRequestEvent struct {
|
||||
Addr net.Addr
|
||||
ID string
|
||||
SessionID uint32
|
||||
}
|
||||
|
||||
type udpErrorEvent struct {
|
||||
Addr net.Addr
|
||||
ID string
|
||||
SessionID uint32
|
||||
Err error
|
||||
}
|
||||
|
||||
type channelEventLogger struct {
|
||||
ConnectEventCh chan connectEvent
|
||||
DisconnectEventCh chan disconnectEvent
|
||||
TCPRequestEventCh chan tcpRequestEvent
|
||||
TCPErrorEventCh chan tcpErrorEvent
|
||||
UDPRequestEventCh chan udpRequestEvent
|
||||
UDPErrorEventCh chan udpErrorEvent
|
||||
}
|
||||
|
||||
func (l *channelEventLogger) Connect(addr net.Addr, id string, tx uint64) {
|
||||
if l.ConnectEventCh != nil {
|
||||
l.ConnectEventCh <- connectEvent{
|
||||
Addr: addr,
|
||||
ID: id,
|
||||
TX: tx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *channelEventLogger) Disconnect(addr net.Addr, id string, err error) {
|
||||
if l.DisconnectEventCh != nil {
|
||||
l.DisconnectEventCh <- disconnectEvent{
|
||||
Addr: addr,
|
||||
ID: id,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *channelEventLogger) TCPRequest(addr net.Addr, id, reqAddr string) {
|
||||
if l.TCPRequestEventCh != nil {
|
||||
l.TCPRequestEventCh <- tcpRequestEvent{
|
||||
Addr: addr,
|
||||
ID: id,
|
||||
ReqAddr: reqAddr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *channelEventLogger) TCPError(addr net.Addr, id, reqAddr string, err error) {
|
||||
if l.TCPErrorEventCh != nil {
|
||||
l.TCPErrorEventCh <- tcpErrorEvent{
|
||||
Addr: addr,
|
||||
ID: id,
|
||||
ReqAddr: reqAddr,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *channelEventLogger) UDPRequest(addr net.Addr, id string, sessionID uint32, reqAddr string) {
|
||||
if l.UDPRequestEventCh != nil {
|
||||
l.UDPRequestEventCh <- udpRequestEvent{
|
||||
Addr: addr,
|
||||
ID: id,
|
||||
SessionID: sessionID,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *channelEventLogger) UDPError(addr net.Addr, id string, sessionID uint32, err error) {
|
||||
if l.UDPErrorEventCh != nil {
|
||||
l.UDPErrorEventCh <- udpErrorEvent{
|
||||
Addr: addr,
|
||||
ID: id,
|
||||
SessionID: sessionID,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue