feat(wip): more test reworks

This commit is contained in:
Toby 2023-07-26 16:35:25 -07:00
parent 6172f2ac53
commit 37385f623f
8 changed files with 411 additions and 118 deletions

View file

@ -241,7 +241,6 @@ func TestClientServerUDPStress(t *testing.T) {
Parallel: 5,
Iterations: 2,
}).Run)
t.Run("2 Sequential 5 Parallel 200x3k", (&udpStressor{
ListenFunc: c.UDP,
ServerAddr: echoAddr,

View file

@ -1,9 +1,10 @@
package obfs
import (
"bytes"
"crypto/rand"
"testing"
"github.com/stretchr/testify/assert"
)
func BenchmarkSalamanderObfuscator_Obfuscate(b *testing.B) {
@ -36,21 +37,9 @@ func TestSalamanderObfuscator(t *testing.T) {
for i := 0; i < 1000; i++ {
_, _ = rand.Read(in)
n := o.Obfuscate(in, oOut)
if n == 0 {
t.Fatal("Failed to obfuscate")
}
if n != len(in)+smSaltLen {
t.Fatal("Wrong obfuscated length")
}
assert.Equal(t, len(in)+smSaltLen, n)
n = o.Deobfuscate(oOut[:n], dOut)
if n == 0 {
t.Fatal("Failed to deobfuscate")
}
if n != len(in) {
t.Fatal("Wrong deobfuscated length")
}
if !bytes.Equal(in, dOut[:n]) {
t.Fatal("Deobfuscated data mismatch")
}
assert.Equal(t, len(in), n)
assert.Equal(t, in, dOut[:n])
}
}

View file

@ -0,0 +1,12 @@
with-expecter: true
inpackage: true
dir: .
packages:
github.com/apernet/hysteria/extras/outbounds:
interfaces:
PluggableOutbound:
config:
mockname: mockPluggableOutbound
UDPConn:
config:
mockname: mockUDPConn

View file

@ -21,8 +21,8 @@ import (
// difference, we need a special PluggableOutboundAdapter to convert between the two
// for use in Hysteria core config.
type PluggableOutbound interface {
DialTCP(reqAddr *AddrEx) (net.Conn, error)
ListenUDP() (UDPConn, error)
TCP(reqAddr *AddrEx) (net.Conn, error)
UDP(reqAddr *AddrEx) (UDPConn, error)
}
type UDPConn interface {
@ -60,7 +60,7 @@ type PluggableOutboundAdapter struct {
PluggableOutbound
}
func (a *PluggableOutboundAdapter) DialTCP(reqAddr string) (net.Conn, error) {
func (a *PluggableOutboundAdapter) TCP(reqAddr string) (net.Conn, error) {
host, port, err := net.SplitHostPort(reqAddr)
if err != nil {
return nil, err
@ -69,14 +69,25 @@ func (a *PluggableOutboundAdapter) DialTCP(reqAddr string) (net.Conn, error) {
if err != nil {
return nil, err
}
return a.PluggableOutbound.DialTCP(&AddrEx{
return a.PluggableOutbound.TCP(&AddrEx{
Host: host,
Port: uint16(portInt),
})
}
func (a *PluggableOutboundAdapter) DialUDP() (server.UDPConn, error) {
conn, err := a.PluggableOutbound.ListenUDP()
func (a *PluggableOutboundAdapter) UDP(reqAddr string) (server.UDPConn, error) {
host, port, err := net.SplitHostPort(reqAddr)
if err != nil {
return nil, err
}
portInt, err := strconv.Atoi(port)
if err != nil {
return nil, err
}
conn, err := a.PluggableOutbound.UDP(&AddrEx{
Host: host,
Port: uint16(portInt),
})
if err != nil {
return nil, err
}

View file

@ -1,103 +1,52 @@
package outbounds
import (
"errors"
"net"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)
var errWrongAddr = errors.New("wrong addr")
type mockPluggableOutbound struct{}
func (m *mockPluggableOutbound) DialTCP(reqAddr *AddrEx) (net.Conn, error) {
if !reflect.DeepEqual(reqAddr, &AddrEx{
Host: "correct_host_1",
Port: 34567,
ResolveInfo: nil,
}) {
return nil, errWrongAddr
}
return nil, nil
}
func (m *mockPluggableOutbound) ListenUDP() (UDPConn, error) {
return &mockUDPConn{}, nil
}
type mockUDPConn struct{}
func (u *mockUDPConn) ReadFrom(b []byte) (int, *AddrEx, error) {
for i := range b {
b[i] = 1
}
return len(b), &AddrEx{
Host: "correct_host_2",
Port: 54321,
ResolveInfo: nil,
}, nil
}
func (u *mockUDPConn) WriteTo(b []byte, addr *AddrEx) (int, error) {
if !reflect.DeepEqual(addr, &AddrEx{
Host: "correct_host_3",
Port: 22334,
ResolveInfo: nil,
}) {
return 0, errWrongAddr
}
return len(b), nil
}
func (u *mockUDPConn) Close() error {
return nil
}
func TestPluggableOutboundAdapter(t *testing.T) {
adapter := &PluggableOutboundAdapter{
PluggableOutbound: &mockPluggableOutbound{},
}
// TCP with correct addr
_, err := adapter.DialTCP("correct_host_1:34567")
if err != nil {
t.Fatal("TCP with correct addr failed", err)
}
// TCP with wrong addr
_, err = adapter.DialTCP("wrong_host_1:34567")
if err != errWrongAddr {
t.Fatal("TCP with wrong addr should fail, got", err)
}
// DialUDP
uConn, err := adapter.DialUDP()
if err != nil {
t.Fatal("DialUDP failed", err)
}
// ReadFrom
b := make([]byte, 10)
n, addr, err := uConn.ReadFrom(b)
if err != nil {
t.Fatal("ReadFrom failed", err)
}
if n != 10 || addr != "correct_host_2:54321" {
t.Fatalf("ReadFrom got wrong result, n: %d, addr: %s", n, addr)
}
// WriteTo with correct addr
n, err = uConn.WriteTo(b, "correct_host_3:22334")
if err != nil {
t.Fatal("WriteTo with correct addr failed", err)
}
if n != 10 {
t.Fatalf("WriteTo with correct addr got wrong result, n: %d", n)
}
// WriteTo with wrong addr
n, err = uConn.WriteTo(b, "wrong_host_3:22334")
if err != errWrongAddr {
t.Fatal("WriteTo with wrong addr should fail, got", err)
}
// Close
err = uConn.Close()
if err != nil {
t.Fatal("Close failed", err)
}
ob := newMockPluggableOutbound(t)
adapter := &PluggableOutboundAdapter{ob}
ob.EXPECT().TCP(&AddrEx{
Host: "only.fans",
Port: 443,
}).Return(nil, nil).Once()
conn, err := adapter.TCP("only.fans:443")
assert.Nil(t, conn)
assert.Nil(t, err)
mc := newMockUDPConn(t)
mc.EXPECT().ReadFrom(mock.Anything).RunAndReturn(func(bs []byte) (int, *AddrEx, error) {
return copy(bs, "gura"), &AddrEx{
Host: "gura.com",
Port: 2333,
}, nil
}).Once()
mc.EXPECT().WriteTo(mock.Anything, &AddrEx{
Host: "hololive.tv",
Port: 8999,
}).RunAndReturn(func(bs []byte, addr *AddrEx) (int, error) {
return len(bs), nil
}).Once()
ob.EXPECT().UDP(&AddrEx{
Host: "hololive.tv",
Port: 8999,
}).Return(mc, nil).Once()
uConn, err := adapter.UDP("hololive.tv:8999")
assert.Nil(t, err)
assert.NotNil(t, uConn)
n, err := uConn.WriteTo([]byte("gura"), "hololive.tv:8999")
assert.Nil(t, err)
assert.Equal(t, 4, n)
bs := make([]byte, 1024)
n, addr, err := uConn.ReadFrom(bs)
assert.Nil(t, err)
assert.Equal(t, 4, n)
assert.Equal(t, "gura", string(bs[:n]))
assert.Equal(t, "gura.com:2333", addr)
}

View file

@ -0,0 +1,144 @@
// Code generated by mockery v2.32.0. DO NOT EDIT.
package outbounds
import (
net "net"
mock "github.com/stretchr/testify/mock"
)
// mockPluggableOutbound is an autogenerated mock type for the PluggableOutbound type
type mockPluggableOutbound struct {
mock.Mock
}
type mockPluggableOutbound_Expecter struct {
mock *mock.Mock
}
func (_m *mockPluggableOutbound) EXPECT() *mockPluggableOutbound_Expecter {
return &mockPluggableOutbound_Expecter{mock: &_m.Mock}
}
// TCP provides a mock function with given fields: reqAddr
func (_m *mockPluggableOutbound) TCP(reqAddr *AddrEx) (net.Conn, error) {
ret := _m.Called(reqAddr)
var r0 net.Conn
var r1 error
if rf, ok := ret.Get(0).(func(*AddrEx) (net.Conn, error)); ok {
return rf(reqAddr)
}
if rf, ok := ret.Get(0).(func(*AddrEx) net.Conn); ok {
r0 = rf(reqAddr)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(net.Conn)
}
}
if rf, ok := ret.Get(1).(func(*AddrEx) error); ok {
r1 = rf(reqAddr)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// mockPluggableOutbound_TCP_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TCP'
type mockPluggableOutbound_TCP_Call struct {
*mock.Call
}
// TCP is a helper method to define mock.On call
// - reqAddr *AddrEx
func (_e *mockPluggableOutbound_Expecter) TCP(reqAddr interface{}) *mockPluggableOutbound_TCP_Call {
return &mockPluggableOutbound_TCP_Call{Call: _e.mock.On("TCP", reqAddr)}
}
func (_c *mockPluggableOutbound_TCP_Call) Run(run func(reqAddr *AddrEx)) *mockPluggableOutbound_TCP_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(*AddrEx))
})
return _c
}
func (_c *mockPluggableOutbound_TCP_Call) Return(_a0 net.Conn, _a1 error) *mockPluggableOutbound_TCP_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *mockPluggableOutbound_TCP_Call) RunAndReturn(run func(*AddrEx) (net.Conn, error)) *mockPluggableOutbound_TCP_Call {
_c.Call.Return(run)
return _c
}
// UDP provides a mock function with given fields: reqAddr
func (_m *mockPluggableOutbound) UDP(reqAddr *AddrEx) (UDPConn, error) {
ret := _m.Called(reqAddr)
var r0 UDPConn
var r1 error
if rf, ok := ret.Get(0).(func(*AddrEx) (UDPConn, error)); ok {
return rf(reqAddr)
}
if rf, ok := ret.Get(0).(func(*AddrEx) UDPConn); ok {
r0 = rf(reqAddr)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(UDPConn)
}
}
if rf, ok := ret.Get(1).(func(*AddrEx) error); ok {
r1 = rf(reqAddr)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// mockPluggableOutbound_UDP_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UDP'
type mockPluggableOutbound_UDP_Call struct {
*mock.Call
}
// UDP is a helper method to define mock.On call
// - reqAddr *AddrEx
func (_e *mockPluggableOutbound_Expecter) UDP(reqAddr interface{}) *mockPluggableOutbound_UDP_Call {
return &mockPluggableOutbound_UDP_Call{Call: _e.mock.On("UDP", reqAddr)}
}
func (_c *mockPluggableOutbound_UDP_Call) Run(run func(reqAddr *AddrEx)) *mockPluggableOutbound_UDP_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(*AddrEx))
})
return _c
}
func (_c *mockPluggableOutbound_UDP_Call) Return(_a0 UDPConn, _a1 error) *mockPluggableOutbound_UDP_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *mockPluggableOutbound_UDP_Call) RunAndReturn(run func(*AddrEx) (UDPConn, error)) *mockPluggableOutbound_UDP_Call {
_c.Call.Return(run)
return _c
}
// newMockPluggableOutbound creates a new instance of mockPluggableOutbound. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func newMockPluggableOutbound(t interface {
mock.TestingT
Cleanup(func())
}) *mockPluggableOutbound {
mock := &mockPluggableOutbound{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -0,0 +1,187 @@
// Code generated by mockery v2.32.0. DO NOT EDIT.
package outbounds
import mock "github.com/stretchr/testify/mock"
// mockUDPConn is an autogenerated mock type for the UDPConn type
type mockUDPConn struct {
mock.Mock
}
type mockUDPConn_Expecter struct {
mock *mock.Mock
}
func (_m *mockUDPConn) EXPECT() *mockUDPConn_Expecter {
return &mockUDPConn_Expecter{mock: &_m.Mock}
}
// Close provides a mock function with given fields:
func (_m *mockUDPConn) Close() error {
ret := _m.Called()
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// mockUDPConn_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
type mockUDPConn_Close_Call struct {
*mock.Call
}
// Close is a helper method to define mock.On call
func (_e *mockUDPConn_Expecter) Close() *mockUDPConn_Close_Call {
return &mockUDPConn_Close_Call{Call: _e.mock.On("Close")}
}
func (_c *mockUDPConn_Close_Call) Run(run func()) *mockUDPConn_Close_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *mockUDPConn_Close_Call) Return(_a0 error) *mockUDPConn_Close_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *mockUDPConn_Close_Call) RunAndReturn(run func() error) *mockUDPConn_Close_Call {
_c.Call.Return(run)
return _c
}
// ReadFrom provides a mock function with given fields: b
func (_m *mockUDPConn) ReadFrom(b []byte) (int, *AddrEx, error) {
ret := _m.Called(b)
var r0 int
var r1 *AddrEx
var r2 error
if rf, ok := ret.Get(0).(func([]byte) (int, *AddrEx, error)); ok {
return rf(b)
}
if rf, ok := ret.Get(0).(func([]byte) int); ok {
r0 = rf(b)
} else {
r0 = ret.Get(0).(int)
}
if rf, ok := ret.Get(1).(func([]byte) *AddrEx); ok {
r1 = rf(b)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*AddrEx)
}
}
if rf, ok := ret.Get(2).(func([]byte) error); ok {
r2 = rf(b)
} else {
r2 = ret.Error(2)
}
return r0, r1, r2
}
// mockUDPConn_ReadFrom_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadFrom'
type mockUDPConn_ReadFrom_Call struct {
*mock.Call
}
// ReadFrom is a helper method to define mock.On call
// - b []byte
func (_e *mockUDPConn_Expecter) ReadFrom(b interface{}) *mockUDPConn_ReadFrom_Call {
return &mockUDPConn_ReadFrom_Call{Call: _e.mock.On("ReadFrom", b)}
}
func (_c *mockUDPConn_ReadFrom_Call) Run(run func(b []byte)) *mockUDPConn_ReadFrom_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].([]byte))
})
return _c
}
func (_c *mockUDPConn_ReadFrom_Call) Return(_a0 int, _a1 *AddrEx, _a2 error) *mockUDPConn_ReadFrom_Call {
_c.Call.Return(_a0, _a1, _a2)
return _c
}
func (_c *mockUDPConn_ReadFrom_Call) RunAndReturn(run func([]byte) (int, *AddrEx, error)) *mockUDPConn_ReadFrom_Call {
_c.Call.Return(run)
return _c
}
// WriteTo provides a mock function with given fields: b, addr
func (_m *mockUDPConn) WriteTo(b []byte, addr *AddrEx) (int, error) {
ret := _m.Called(b, addr)
var r0 int
var r1 error
if rf, ok := ret.Get(0).(func([]byte, *AddrEx) (int, error)); ok {
return rf(b, addr)
}
if rf, ok := ret.Get(0).(func([]byte, *AddrEx) int); ok {
r0 = rf(b, addr)
} else {
r0 = ret.Get(0).(int)
}
if rf, ok := ret.Get(1).(func([]byte, *AddrEx) error); ok {
r1 = rf(b, addr)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// mockUDPConn_WriteTo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteTo'
type mockUDPConn_WriteTo_Call struct {
*mock.Call
}
// WriteTo is a helper method to define mock.On call
// - b []byte
// - addr *AddrEx
func (_e *mockUDPConn_Expecter) WriteTo(b interface{}, addr interface{}) *mockUDPConn_WriteTo_Call {
return &mockUDPConn_WriteTo_Call{Call: _e.mock.On("WriteTo", b, addr)}
}
func (_c *mockUDPConn_WriteTo_Call) Run(run func(b []byte, addr *AddrEx)) *mockUDPConn_WriteTo_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].([]byte), args[1].(*AddrEx))
})
return _c
}
func (_c *mockUDPConn_WriteTo_Call) Return(_a0 int, _a1 error) *mockUDPConn_WriteTo_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *mockUDPConn_WriteTo_Call) RunAndReturn(run func([]byte, *AddrEx) (int, error)) *mockUDPConn_WriteTo_Call {
_c.Call.Return(run)
return _c
}
// newMockUDPConn creates a new instance of mockUDPConn. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func newMockUDPConn(t interface {
mock.TestingT
Cleanup(func())
}) *mockUDPConn {
mock := &mockUDPConn{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -29,6 +29,7 @@ type directOutbound struct {
DeviceName string // For UDP binding
}
/*
// NewDirectOutboundSimple creates a new directOutbound with the given mode,
// without binding to a specific device. Works on all platforms.
func NewDirectOutboundSimple(mode DirectOutboundMode) PluggableOutbound {
@ -39,6 +40,7 @@ func NewDirectOutboundSimple(mode DirectOutboundMode) PluggableOutbound {
},
}
}
*/
// resolve is our built-in DNS resolver for handling the case when
// AddrEx.ResolveInfo is nil.