refactor: move ErrorWrapperQUICDialer to errorsx (#420)
I needed to add some tests as integration tests due to circular imports, but this is ~fine because we quite likely want many integration tests in the errorsx package anyway. Part of https://github.com/ooni/probe/issues/1505.
This commit is contained in:
parent
5c52d99d57
commit
ec350cba1a
|
@ -171,7 +171,7 @@ func NewQUICDialer(config Config) QUICDialer {
|
|||
var d quicdialer.ContextDialer = &netxlite.QUICDialerQUICGo{
|
||||
QUICListener: ql,
|
||||
}
|
||||
d = quicdialer.ErrorWrapperDialer{Dialer: d}
|
||||
d = &errorsx.ErrorWrapperQUICDialer{Dialer: d}
|
||||
if config.TLSSaver != nil {
|
||||
d = quicdialer.HandshakeSaver{Saver: config.TLSSaver, Dialer: d}
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
package quicdialer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/ooni/probe-cli/v3/internal/errorsx"
|
||||
)
|
||||
|
||||
// ErrorWrapperDialer is a dialer that performs quic err wrapping
|
||||
type ErrorWrapperDialer struct {
|
||||
Dialer ContextDialer
|
||||
}
|
||||
|
||||
// DialContext implements ContextDialer.DialContext
|
||||
func (d ErrorWrapperDialer) DialContext(
|
||||
ctx context.Context, network string, host string,
|
||||
tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlySession, error) {
|
||||
sess, err := d.Dialer.DialContext(ctx, network, host, tlsCfg, cfg)
|
||||
err = errorsx.SafeErrWrapperBuilder{
|
||||
Classifier: errorsx.ClassifyQUICFailure,
|
||||
Error: err,
|
||||
Operation: errorsx.QUICHandshakeOperation,
|
||||
}.MaybeBuild()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sess, nil
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
package quicdialer_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/ooni/probe-cli/v3/internal/engine/netx/quicdialer"
|
||||
"github.com/ooni/probe-cli/v3/internal/errorsx"
|
||||
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||
)
|
||||
|
||||
func TestErrorWrapperFailure(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
d := quicdialer.ErrorWrapperDialer{
|
||||
Dialer: MockDialer{Sess: nil, Err: io.EOF}}
|
||||
sess, err := d.DialContext(
|
||||
ctx, "udp", "www.google.com:443", &tls.Config{}, &quic.Config{})
|
||||
if sess != nil {
|
||||
t.Fatal("expected a nil sess here")
|
||||
}
|
||||
errorWrapperCheckErr(t, err, errorsx.QUICHandshakeOperation)
|
||||
}
|
||||
|
||||
func errorWrapperCheckErr(t *testing.T, err error, op string) {
|
||||
if !errors.Is(err, io.EOF) {
|
||||
t.Fatal("expected another error here")
|
||||
}
|
||||
var errWrapper *errorsx.ErrWrapper
|
||||
if !errors.As(err, &errWrapper) {
|
||||
t.Fatal("cannot cast to ErrWrapper")
|
||||
}
|
||||
if errWrapper.Operation != op {
|
||||
t.Fatal("unexpected Operation")
|
||||
}
|
||||
if errWrapper.Failure != errorsx.FailureEOFError {
|
||||
t.Fatal("unexpected failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorWrapperInvalidCertificate(t *testing.T) {
|
||||
nextprotos := []string{"h3"}
|
||||
servername := "example.com"
|
||||
tlsConf := &tls.Config{
|
||||
NextProtos: nextprotos,
|
||||
ServerName: servername,
|
||||
}
|
||||
|
||||
dlr := quicdialer.ErrorWrapperDialer{Dialer: &netxlite.QUICDialerQUICGo{
|
||||
QUICListener: &netxlite.QUICListenerStdlib{},
|
||||
}}
|
||||
// use Google IP
|
||||
sess, err := dlr.DialContext(context.Background(), "udp",
|
||||
"216.58.212.164:443", tlsConf, &quic.Config{})
|
||||
if err == nil {
|
||||
t.Fatal("expected an error here")
|
||||
}
|
||||
if sess != nil {
|
||||
t.Fatal("expected nil sess here")
|
||||
}
|
||||
if err.Error() != errorsx.FailureSSLInvalidCertificate {
|
||||
t.Fatal("unexpected failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorWrapperSuccess(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
tlsConf := &tls.Config{
|
||||
NextProtos: []string{"h3"},
|
||||
ServerName: "www.google.com",
|
||||
}
|
||||
d := quicdialer.ErrorWrapperDialer{Dialer: &netxlite.QUICDialerQUICGo{
|
||||
QUICListener: &netxlite.QUICListenerStdlib{},
|
||||
}}
|
||||
sess, err := d.DialContext(ctx, "udp", "216.58.212.164:443", tlsConf, &quic.Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sess == nil {
|
||||
t.Fatal("expected non-nil sess here")
|
||||
}
|
||||
}
|
54
internal/errorsx/integration_test.go
Normal file
54
internal/errorsx/integration_test.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package errorsx_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"testing"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/ooni/probe-cli/v3/internal/errorsx"
|
||||
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
||||
)
|
||||
|
||||
func TestErrorWrapperQUICDialerInvalidCertificate(t *testing.T) {
|
||||
nextprotos := []string{"h3"}
|
||||
servername := "example.com"
|
||||
tlsConf := &tls.Config{
|
||||
NextProtos: nextprotos,
|
||||
ServerName: servername,
|
||||
}
|
||||
|
||||
dlr := &errorsx.ErrorWrapperQUICDialer{Dialer: &netxlite.QUICDialerQUICGo{
|
||||
QUICListener: &netxlite.QUICListenerStdlib{},
|
||||
}}
|
||||
// use Google IP
|
||||
sess, err := dlr.DialContext(context.Background(), "udp",
|
||||
"216.58.212.164:443", tlsConf, &quic.Config{})
|
||||
if err == nil {
|
||||
t.Fatal("expected an error here")
|
||||
}
|
||||
if sess != nil {
|
||||
t.Fatal("expected nil sess here")
|
||||
}
|
||||
if err.Error() != errorsx.FailureSSLInvalidCertificate {
|
||||
t.Fatal("unexpected failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorWrapperQUICDialerSuccess(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
tlsConf := &tls.Config{
|
||||
NextProtos: []string{"h3"},
|
||||
ServerName: "www.google.com",
|
||||
}
|
||||
d := &errorsx.ErrorWrapperQUICDialer{Dialer: &netxlite.QUICDialerQUICGo{
|
||||
QUICListener: &netxlite.QUICListenerStdlib{},
|
||||
}}
|
||||
sess, err := d.DialContext(ctx, "udp", "216.58.212.164:443", tlsConf, &quic.Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sess == nil {
|
||||
t.Fatal("expected non-nil sess here")
|
||||
}
|
||||
}
|
38
internal/errorsx/quic.go
Normal file
38
internal/errorsx/quic.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
package errorsx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
)
|
||||
|
||||
// QUICContextDialer is a dialer for QUIC using Context.
|
||||
type QUICContextDialer interface {
|
||||
// DialContext establishes a new QUIC session using the given
|
||||
// network and address. The tlsConfig and the quicConfig arguments
|
||||
// MUST NOT be nil. Returns either the session or an error.
|
||||
DialContext(ctx context.Context, network, address string,
|
||||
tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error)
|
||||
}
|
||||
|
||||
// ErrorWrapperQUICDialer is a dialer that performs quic err wrapping
|
||||
type ErrorWrapperQUICDialer struct {
|
||||
Dialer QUICContextDialer
|
||||
}
|
||||
|
||||
// DialContext implements ContextDialer.DialContext
|
||||
func (d *ErrorWrapperQUICDialer) DialContext(
|
||||
ctx context.Context, network string, host string,
|
||||
tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlySession, error) {
|
||||
sess, err := d.Dialer.DialContext(ctx, network, host, tlsCfg, cfg)
|
||||
err = SafeErrWrapperBuilder{
|
||||
Classifier: ClassifyQUICFailure,
|
||||
Error: err,
|
||||
Operation: QUICHandshakeOperation,
|
||||
}.MaybeBuild()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sess, nil
|
||||
}
|
39
internal/errorsx/quic_test.go
Normal file
39
internal/errorsx/quic_test.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package errorsx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/lucas-clemente/quic-go"
|
||||
"github.com/ooni/probe-cli/v3/internal/netxmocks"
|
||||
)
|
||||
|
||||
func TestErrorWrapperQUICDialerFailure(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
d := &ErrorWrapperQUICDialer{Dialer: &netxmocks.QUICContextDialer{
|
||||
MockDialContext: func(ctx context.Context, network, address string, tlsConfig *tls.Config, quicConfig *quic.Config) (quic.EarlySession, error) {
|
||||
return nil, io.EOF
|
||||
},
|
||||
}}
|
||||
sess, err := d.DialContext(
|
||||
ctx, "udp", "www.google.com:443", &tls.Config{}, &quic.Config{})
|
||||
if sess != nil {
|
||||
t.Fatal("expected a nil sess here")
|
||||
}
|
||||
if !errors.Is(err, io.EOF) {
|
||||
t.Fatal("expected another error here")
|
||||
}
|
||||
var errWrapper *ErrWrapper
|
||||
if !errors.As(err, &errWrapper) {
|
||||
t.Fatal("cannot cast to ErrWrapper")
|
||||
}
|
||||
if errWrapper.Operation != QUICHandshakeOperation {
|
||||
t.Fatal("unexpected Operation")
|
||||
}
|
||||
if errWrapper.Failure != FailureEOFError {
|
||||
t.Fatal("unexpected failure")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user