2022-07-01 12:22:22 +02:00
|
|
|
package measurexlite
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"crypto/tls"
|
|
|
|
"errors"
|
|
|
|
"net"
|
|
|
|
"reflect"
|
2022-08-17 09:19:11 +02:00
|
|
|
"syscall"
|
2022-07-01 12:22:22 +02:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2022-08-17 09:19:11 +02:00
|
|
|
"github.com/lucas-clemente/quic-go"
|
2022-07-01 12:22:22 +02:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/model"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/model/mocks"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/testingx"
|
2022-09-07 15:19:53 +02:00
|
|
|
utls "gitlab.com/yawning/utls.git"
|
2022-07-01 12:22:22 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestNewTrace(t *testing.T) {
|
|
|
|
t.Run("NewTrace correctly constructs a trace", func(t *testing.T) {
|
|
|
|
const index = 17
|
|
|
|
zeroTime := time.Now()
|
|
|
|
trace := NewTrace(index, zeroTime)
|
|
|
|
|
|
|
|
t.Run("Index", func(t *testing.T) {
|
|
|
|
if trace.Index != index {
|
|
|
|
t.Fatal("invalid index")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("NetworkEvent has the expected buffer size", func(t *testing.T) {
|
|
|
|
ff := &testingx.FakeFiller{}
|
|
|
|
var idx int
|
|
|
|
Loop:
|
|
|
|
for {
|
|
|
|
ev := &model.ArchivalNetworkEvent{}
|
|
|
|
ff.Fill(ev)
|
|
|
|
select {
|
2022-08-17 20:10:48 +02:00
|
|
|
case trace.networkEvent <- ev:
|
2022-07-01 12:22:22 +02:00
|
|
|
idx++
|
|
|
|
default:
|
|
|
|
break Loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if idx != NetworkEventBufferSize {
|
|
|
|
t.Fatal("invalid NetworkEvent channel buffer size")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-08-11 18:18:25 +02:00
|
|
|
t.Run("NewStdlibResolverFn is nil", func(t *testing.T) {
|
|
|
|
if trace.NewStdlibResolverFn != nil {
|
|
|
|
t.Fatal("expected nil NewStdlibResolverFn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-08-11 16:00:37 +02:00
|
|
|
t.Run("NewParallelUDPResolverFn is nil", func(t *testing.T) {
|
|
|
|
if trace.NewParallelUDPResolverFn != nil {
|
|
|
|
t.Fatal("expected nil NewParallelUDPResolverFn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("NewParallelDNSOverHTTPSResolverFn is nil", func(t *testing.T) {
|
|
|
|
if trace.NewParallelDNSOverHTTPSResolverFn != nil {
|
|
|
|
t.Fatal("expected nil NewParallelDNSOverHTTPSResolverFn")
|
2022-07-08 19:42:24 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-07-01 12:22:22 +02:00
|
|
|
t.Run("NewDialerWithoutResolverFn is nil", func(t *testing.T) {
|
|
|
|
if trace.NewDialerWithoutResolverFn != nil {
|
|
|
|
t.Fatal("expected nil NewDialerWithoutResolverFn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("NewTLSHandshakerStdlibFn is nil", func(t *testing.T) {
|
|
|
|
if trace.NewTLSHandshakerStdlibFn != nil {
|
|
|
|
t.Fatal("expected nil NewTLSHandshakerStdlibFn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-09-07 15:19:53 +02:00
|
|
|
t.Run("newTLShandshakerUTLSFn is nil", func(t *testing.T) {
|
|
|
|
if trace.NewTLSHandshakerUTLSFn != nil {
|
|
|
|
t.Fatal("expected nil NewTLSHandshakerUTLSfn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-08-17 09:19:11 +02:00
|
|
|
t.Run("NewQUICDialerWithoutResolverFn is nil", func(t *testing.T) {
|
|
|
|
if trace.NewQUICDialerWithoutResolverFn != nil {
|
|
|
|
t.Fatal("expected nil NewQUICDialerQithoutResolverFn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-08-22 14:21:32 +02:00
|
|
|
t.Run("dnsLookup has the expected buffer size", func(t *testing.T) {
|
2022-07-08 19:42:24 +02:00
|
|
|
ff := &testingx.FakeFiller{}
|
2022-08-11 16:00:37 +02:00
|
|
|
var idx int
|
|
|
|
Loop:
|
|
|
|
for {
|
|
|
|
ev := &model.ArchivalDNSLookupResult{}
|
|
|
|
ff.Fill(ev)
|
|
|
|
select {
|
2022-08-17 20:10:48 +02:00
|
|
|
case trace.dnsLookup <- ev:
|
2022-08-11 16:00:37 +02:00
|
|
|
idx++
|
|
|
|
default:
|
|
|
|
break Loop
|
2022-07-08 19:42:24 +02:00
|
|
|
}
|
|
|
|
}
|
2022-08-11 16:00:37 +02:00
|
|
|
if idx != DNSLookupBufferSize {
|
2022-08-22 14:21:32 +02:00
|
|
|
t.Fatal("invalid dnsLookup channel buffer size")
|
2022-08-11 16:00:37 +02:00
|
|
|
}
|
2022-07-08 19:42:24 +02:00
|
|
|
})
|
|
|
|
|
2022-08-22 14:21:32 +02:00
|
|
|
t.Run("delayedDNSResponse has the expected buffer size", func(t *testing.T) {
|
|
|
|
ff := &testingx.FakeFiller{}
|
|
|
|
var idx int
|
|
|
|
Loop:
|
|
|
|
for {
|
|
|
|
ev := &model.ArchivalDNSLookupResult{}
|
|
|
|
ff.Fill(ev)
|
|
|
|
select {
|
|
|
|
case trace.delayedDNSResponse <- ev:
|
|
|
|
idx++
|
|
|
|
default:
|
|
|
|
break Loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if idx != DelayedDNSResponseBufferSize {
|
|
|
|
t.Fatal("invalid delayedDNSResponse channel buffer size")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("tcpConnect has the expected buffer size", func(t *testing.T) {
|
2022-07-01 12:22:22 +02:00
|
|
|
ff := &testingx.FakeFiller{}
|
|
|
|
var idx int
|
|
|
|
Loop:
|
|
|
|
for {
|
|
|
|
ev := &model.ArchivalTCPConnectResult{}
|
|
|
|
ff.Fill(ev)
|
|
|
|
select {
|
2022-08-17 20:10:48 +02:00
|
|
|
case trace.tcpConnect <- ev:
|
2022-07-01 12:22:22 +02:00
|
|
|
idx++
|
|
|
|
default:
|
|
|
|
break Loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if idx != TCPConnectBufferSize {
|
2022-08-22 14:21:32 +02:00
|
|
|
t.Fatal("invalid tcpConnect channel buffer size")
|
2022-07-01 12:22:22 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-08-22 14:21:32 +02:00
|
|
|
t.Run("tlsHandshake has the expected buffer size", func(t *testing.T) {
|
2022-07-01 12:22:22 +02:00
|
|
|
ff := &testingx.FakeFiller{}
|
|
|
|
var idx int
|
|
|
|
Loop:
|
|
|
|
for {
|
|
|
|
ev := &model.ArchivalTLSOrQUICHandshakeResult{}
|
|
|
|
ff.Fill(ev)
|
|
|
|
select {
|
2022-08-17 20:10:48 +02:00
|
|
|
case trace.tlsHandshake <- ev:
|
2022-07-01 12:22:22 +02:00
|
|
|
idx++
|
|
|
|
default:
|
|
|
|
break Loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if idx != TLSHandshakeBufferSize {
|
2022-08-22 14:21:32 +02:00
|
|
|
t.Fatal("invalid tlsHandshake channel buffer size")
|
2022-07-01 12:22:22 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-08-22 14:21:32 +02:00
|
|
|
t.Run("quicHandshake has the expected buffer size", func(t *testing.T) {
|
2022-08-17 09:19:11 +02:00
|
|
|
ff := &testingx.FakeFiller{}
|
|
|
|
var idx int
|
|
|
|
Loop:
|
|
|
|
for {
|
|
|
|
ev := &model.ArchivalTLSOrQUICHandshakeResult{}
|
|
|
|
ff.Fill(ev)
|
|
|
|
select {
|
2022-08-17 20:10:48 +02:00
|
|
|
case trace.quicHandshake <- ev:
|
2022-08-17 09:19:11 +02:00
|
|
|
idx++
|
|
|
|
default:
|
|
|
|
break Loop
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if idx != QUICHandshakeBufferSize {
|
2022-08-22 14:21:32 +02:00
|
|
|
t.Fatal("invalid quicHandshake channel buffer size")
|
2022-08-17 09:19:11 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2022-07-01 12:22:22 +02:00
|
|
|
t.Run("TimeNowFn is nil", func(t *testing.T) {
|
|
|
|
if trace.TimeNowFn != nil {
|
|
|
|
t.Fatal("expected nil TimeNowFn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("ZeroTime", func(t *testing.T) {
|
|
|
|
if !trace.ZeroTime.Equal(zeroTime) {
|
|
|
|
t.Fatal("invalid zero time")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTrace(t *testing.T) {
|
2022-08-11 18:18:25 +02:00
|
|
|
t.Run("NewStdlibResolverFn works as intended", func(t *testing.T) {
|
|
|
|
t.Run("when not nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
|
|
|
NewStdlibResolverFn: func(logger model.Logger) model.Resolver {
|
|
|
|
return &mocks.Resolver{
|
|
|
|
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
|
|
|
|
return []string{}, mockedErr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
resolver := tx.newStdlibResolver(model.DiscardLogger)
|
|
|
|
ctx := context.Background()
|
|
|
|
addrs, err := resolver.LookupHost(ctx, "example.com")
|
|
|
|
if !errors.Is(err, mockedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if len(addrs) != 0 {
|
|
|
|
t.Fatal("expected array of size 0")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("when nil", func(t *testing.T) {
|
|
|
|
tx := &Trace{
|
|
|
|
NewParallelUDPResolverFn: nil,
|
|
|
|
}
|
|
|
|
resolver := tx.newStdlibResolver(model.DiscardLogger)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
cancel()
|
|
|
|
addrs, err := resolver.LookupHost(ctx, "example.com")
|
|
|
|
if err == nil || err.Error() != netxlite.FailureInterrupted {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if len(addrs) != 0 {
|
|
|
|
t.Fatal("expected array of size 0")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-08-11 16:00:37 +02:00
|
|
|
t.Run("NewParallelUDPResolverFn works as intended", func(t *testing.T) {
|
2022-07-08 19:42:24 +02:00
|
|
|
t.Run("when not nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
2022-08-11 16:00:37 +02:00
|
|
|
NewParallelUDPResolverFn: func(logger model.Logger, dialer model.Dialer, address string) model.Resolver {
|
2022-07-08 19:42:24 +02:00
|
|
|
return &mocks.Resolver{
|
|
|
|
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
|
|
|
|
return []string{}, mockedErr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
2022-08-11 16:00:37 +02:00
|
|
|
dialer := &mocks.Dialer{}
|
|
|
|
resolver := tx.newParallelUDPResolver(model.DiscardLogger, dialer, "1.1.1.1:53")
|
2022-07-08 19:42:24 +02:00
|
|
|
ctx := context.Background()
|
|
|
|
addrs, err := resolver.LookupHost(ctx, "example.com")
|
|
|
|
if !errors.Is(err, mockedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if len(addrs) != 0 {
|
|
|
|
t.Fatal("expected array of size 0")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("when nil", func(t *testing.T) {
|
|
|
|
tx := &Trace{
|
2022-08-11 16:00:37 +02:00
|
|
|
NewParallelUDPResolverFn: nil,
|
2022-07-08 19:42:24 +02:00
|
|
|
}
|
2022-08-11 16:00:37 +02:00
|
|
|
dialer := netxlite.NewDialerWithoutResolver(model.DiscardLogger)
|
|
|
|
resolver := tx.newParallelUDPResolver(model.DiscardLogger, dialer, "1.1.1.1:53")
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
cancel()
|
|
|
|
addrs, err := resolver.LookupHost(ctx, "example.com")
|
|
|
|
if err == nil || err.Error() != netxlite.FailureInterrupted {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if len(addrs) != 0 {
|
|
|
|
t.Fatal("expected array of size 0")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("NewParallelDNSOverHTTPSResolverFn works as intended", func(t *testing.T) {
|
|
|
|
t.Run("when not nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
|
|
|
NewParallelDNSOverHTTPSResolverFn: func(logger model.Logger, URL string) model.Resolver {
|
|
|
|
return &mocks.Resolver{
|
|
|
|
MockLookupHost: func(ctx context.Context, domain string) ([]string, error) {
|
|
|
|
return []string{}, mockedErr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
2022-07-08 19:42:24 +02:00
|
|
|
}
|
2022-08-11 18:18:25 +02:00
|
|
|
resolver := tx.newParallelDNSOverHTTPSResolver(model.DiscardLogger, "https://dns.google.com")
|
2022-07-08 19:42:24 +02:00
|
|
|
ctx := context.Background()
|
|
|
|
addrs, err := resolver.LookupHost(ctx, "example.com")
|
2022-08-11 16:00:37 +02:00
|
|
|
if !errors.Is(err, mockedErr) {
|
2022-07-08 19:42:24 +02:00
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
2022-08-11 16:00:37 +02:00
|
|
|
if len(addrs) != 0 {
|
|
|
|
t.Fatal("expected array of size 0")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("when nil", func(t *testing.T) {
|
|
|
|
tx := &Trace{
|
|
|
|
NewParallelDNSOverHTTPSResolverFn: nil,
|
2022-07-08 19:42:24 +02:00
|
|
|
}
|
2022-08-11 16:00:37 +02:00
|
|
|
resolver := tx.newParallelDNSOverHTTPSResolver(model.DiscardLogger, "https://dns.google.com")
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
cancel()
|
|
|
|
addrs, err := resolver.LookupHost(ctx, "example.com")
|
|
|
|
if err == nil || err.Error() != netxlite.FailureInterrupted {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if len(addrs) != 0 {
|
|
|
|
t.Fatal("expected array of size 0")
|
2022-07-08 19:42:24 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-07-01 12:22:22 +02:00
|
|
|
t.Run("NewDialerWithoutResolverFn works as intended", func(t *testing.T) {
|
|
|
|
t.Run("when not nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
|
|
|
NewDialerWithoutResolverFn: func(dl model.DebugLogger) model.Dialer {
|
|
|
|
return &mocks.Dialer{
|
|
|
|
MockDialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
|
|
|
return nil, mockedErr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
dialer := tx.NewDialerWithoutResolver(model.DiscardLogger)
|
|
|
|
ctx := context.Background()
|
|
|
|
conn, err := dialer.DialContext(ctx, "tcp", "1.1.1.1:443")
|
|
|
|
if !errors.Is(err, mockedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if conn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("when nil", func(t *testing.T) {
|
|
|
|
tx := &Trace{
|
|
|
|
NewDialerWithoutResolverFn: nil,
|
|
|
|
}
|
|
|
|
dialer := tx.NewDialerWithoutResolver(model.DiscardLogger)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
cancel() // fail immediately
|
|
|
|
conn, err := dialer.DialContext(ctx, "tcp", "1.1.1.1:443")
|
|
|
|
if err == nil || err.Error() != netxlite.FailureInterrupted {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if conn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("NewTLSHandshakerStdlibFn works as intended", func(t *testing.T) {
|
|
|
|
t.Run("when not nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
|
|
|
NewTLSHandshakerStdlibFn: func(dl model.DebugLogger) model.TLSHandshaker {
|
|
|
|
return &mocks.TLSHandshaker{
|
|
|
|
MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) {
|
|
|
|
return nil, tls.ConnectionState{}, mockedErr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
thx := tx.NewTLSHandshakerStdlib(model.DiscardLogger)
|
|
|
|
ctx := context.Background()
|
|
|
|
conn, state, err := thx.Handshake(ctx, &mocks.Conn{}, &tls.Config{})
|
|
|
|
if !errors.Is(err, mockedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if !reflect.ValueOf(state).IsZero() {
|
|
|
|
t.Fatal("state is not a zero value")
|
|
|
|
}
|
|
|
|
if conn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("when nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
|
|
|
NewTLSHandshakerStdlibFn: nil,
|
|
|
|
}
|
|
|
|
thx := tx.NewTLSHandshakerStdlib(model.DiscardLogger)
|
|
|
|
tcpConn := &mocks.Conn{
|
|
|
|
MockSetDeadline: func(t time.Time) error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
MockRemoteAddr: func() net.Addr {
|
|
|
|
return &mocks.Addr{
|
|
|
|
MockNetwork: func() string {
|
|
|
|
return "tcp"
|
|
|
|
},
|
|
|
|
MockString: func() string {
|
|
|
|
return "1.1.1.1:443"
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
2022-09-07 15:19:53 +02:00
|
|
|
MockWrite: func(b []byte) (int, error) {
|
|
|
|
return 0, mockedErr
|
|
|
|
},
|
|
|
|
MockClose: func() error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
tlsConfig := &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
conn, state, err := thx.Handshake(ctx, tcpConn, tlsConfig)
|
|
|
|
if !errors.Is(err, mockedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if !reflect.ValueOf(state).IsZero() {
|
|
|
|
t.Fatal("state is not a zero value")
|
|
|
|
}
|
|
|
|
if conn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("NewTLSHandshakerUTLSFn works as intended", func(t *testing.T) {
|
|
|
|
t.Run("when not nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
|
|
|
NewTLSHandshakerUTLSFn: func(dl model.DebugLogger, id *utls.ClientHelloID) model.TLSHandshaker {
|
|
|
|
return &mocks.TLSHandshaker{
|
|
|
|
MockHandshake: func(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) {
|
|
|
|
return nil, tls.ConnectionState{}, mockedErr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
thx := tx.NewTLSHandshakerUTLS(model.DiscardLogger, &utls.HelloGolang)
|
|
|
|
ctx := context.Background()
|
|
|
|
conn, state, err := thx.Handshake(ctx, &mocks.Conn{}, &tls.Config{})
|
|
|
|
if !errors.Is(err, mockedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if !reflect.ValueOf(state).IsZero() {
|
|
|
|
t.Fatal("state is not a zero value")
|
|
|
|
}
|
|
|
|
if conn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("when nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
|
|
|
NewTLSHandshakerStdlibFn: nil,
|
|
|
|
}
|
|
|
|
thx := tx.newTLSHandshakerUTLS(model.DiscardLogger, &utls.HelloGolang)
|
|
|
|
tcpConn := &mocks.Conn{
|
|
|
|
MockSetDeadline: func(t time.Time) error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
MockRemoteAddr: func() net.Addr {
|
|
|
|
return &mocks.Addr{
|
|
|
|
MockNetwork: func() string {
|
|
|
|
return "tcp"
|
|
|
|
},
|
|
|
|
MockString: func() string {
|
|
|
|
return "1.1.1.1:443"
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
2022-07-01 12:22:22 +02:00
|
|
|
MockWrite: func(b []byte) (int, error) {
|
|
|
|
return 0, mockedErr
|
|
|
|
},
|
|
|
|
MockClose: func() error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
tlsConfig := &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
conn, state, err := thx.Handshake(ctx, tcpConn, tlsConfig)
|
|
|
|
if !errors.Is(err, mockedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if !reflect.ValueOf(state).IsZero() {
|
|
|
|
t.Fatal("state is not a zero value")
|
|
|
|
}
|
|
|
|
if conn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-08-17 09:19:11 +02:00
|
|
|
t.Run("NewQUICDialerWithoutResolverFn works as intended", func(t *testing.T) {
|
|
|
|
t.Run("when not nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
|
|
|
NewQUICDialerWithoutResolverFn: func(listener model.QUICListener, dl model.DebugLogger) model.QUICDialer {
|
|
|
|
return &mocks.QUICDialer{
|
2022-08-19 11:26:50 +02:00
|
|
|
MockDialContext: func(ctx context.Context, address string,
|
2022-08-17 09:19:11 +02:00
|
|
|
tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlyConnection, error) {
|
|
|
|
return nil, mockedErr
|
|
|
|
},
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
qdx := tx.newQUICDialerWithoutResolver(&mocks.QUICListener{}, model.DiscardLogger)
|
|
|
|
ctx := context.Background()
|
2022-08-19 11:26:50 +02:00
|
|
|
qconn, err := qdx.DialContext(ctx, "1.1.1.1:443", &tls.Config{}, &quic.Config{})
|
2022-08-17 09:19:11 +02:00
|
|
|
if !errors.Is(err, mockedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if qconn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("when nil", func(t *testing.T) {
|
|
|
|
mockedErr := errors.New("mocked")
|
|
|
|
tx := &Trace{
|
|
|
|
NewQUICDialerWithoutResolverFn: nil, // explicit
|
|
|
|
}
|
|
|
|
pconn := &mocks.UDPLikeConn{
|
|
|
|
MockLocalAddr: func() net.Addr {
|
|
|
|
return &net.UDPAddr{
|
|
|
|
Port: 0,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
MockRemoteAddr: func() net.Addr {
|
|
|
|
return &net.UDPAddr{
|
|
|
|
Port: 0,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
MockSyscallConn: func() (syscall.RawConn, error) {
|
|
|
|
return nil, mockedErr
|
|
|
|
},
|
|
|
|
MockClose: func() error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
listener := &mocks.QUICListener{
|
|
|
|
MockListen: func(addr *net.UDPAddr) (model.UDPLikeConn, error) {
|
|
|
|
return pconn, nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
tlsConfig := &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
}
|
|
|
|
dialer := tx.newQUICDialerWithoutResolver(listener, model.DiscardLogger)
|
|
|
|
ctx := context.Background()
|
2022-08-19 11:26:50 +02:00
|
|
|
qconn, err := dialer.DialContext(ctx, "1.1.1.1:443", tlsConfig, &quic.Config{})
|
2022-08-17 09:19:11 +02:00
|
|
|
if !errors.Is(err, mockedErr) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if qconn != nil {
|
|
|
|
t.Fatal("expected nil conn")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
2022-07-01 12:22:22 +02:00
|
|
|
t.Run("TimeNowFn works as intended", func(t *testing.T) {
|
|
|
|
fixedTime := time.Date(2022, 01, 01, 00, 00, 00, 00, time.UTC)
|
|
|
|
tx := &Trace{
|
|
|
|
TimeNowFn: func() time.Time {
|
|
|
|
return fixedTime
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if !tx.TimeNow().Equal(fixedTime) {
|
|
|
|
t.Fatal("we cannot override time.Now calls")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("TimeSince works as intended", func(t *testing.T) {
|
|
|
|
t0 := time.Date(2022, 01, 01, 00, 00, 00, 00, time.UTC)
|
|
|
|
t1 := t0.Add(10 * time.Second)
|
|
|
|
tx := &Trace{
|
|
|
|
TimeNowFn: func() time.Time {
|
|
|
|
return t1
|
|
|
|
},
|
|
|
|
}
|
|
|
|
if tx.TimeSince(t0) != 10*time.Second {
|
|
|
|
t.Fatal("apparently Trace.Since is broken")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|