mirror of
https://github.com/cloudflare/cloudflared
synced 2026-06-08 13:33:07 +00:00
52519f67e8
The bump of the QUIC library introduces a cyclic dependency between the connection and quic modules hence it is necessary to break this coupling. Right now, the connection module depends on the quic module for the datagram v2/v3 and to which a QUIC connection (currently an interface) is passed. As it is there is no issue however, under the hood, interface is a wrapper around an UDP connection and a QUIC connection meaning this type must be exposed to the quic module since the QUIC Connection will no longer be a interface but a struct. Given the above, these changes introduce an interface, QUICConnection, with the surface used today in cloudflared and a struct, ConnWithCloser, that implements said interface within the quic module. Closes TUN-10563
109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
package quic
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/quic-go/quic-go"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// mockCloser is an [io.Closer] that returns a configurable error.
|
|
type mockCloser struct {
|
|
closeErr error
|
|
}
|
|
|
|
func (m *mockCloser) Close() error {
|
|
return m.closeErr
|
|
}
|
|
|
|
// mockQuicConnection is a minimal test double for [quic.Connection].
|
|
type mockQuicConnection struct {
|
|
quic.Connection
|
|
closeWithErrorErr error
|
|
}
|
|
|
|
func (m *mockQuicConnection) CloseWithError(_ quic.ApplicationErrorCode, _ string) error {
|
|
return m.closeWithErrorErr
|
|
}
|
|
|
|
func TestNewConnWithCloser_NilConn(t *testing.T) {
|
|
t.Parallel()
|
|
conn, err := NewQUICConnection(nil, &mockCloser{})
|
|
require.ErrorIs(t, err, ErrNilQuicConnection)
|
|
require.Nil(t, conn)
|
|
}
|
|
|
|
func TestNewConnWithCloser_NilCloser(t *testing.T) {
|
|
t.Parallel()
|
|
conn, err := NewQUICConnection(&mockQuicConnection{}, nil)
|
|
require.ErrorIs(t, err, ErrNilCloser)
|
|
require.Nil(t, conn)
|
|
}
|
|
|
|
func TestNewConnWithCloser_Success(t *testing.T) {
|
|
t.Parallel()
|
|
qc := &mockQuicConnection{}
|
|
cl := &mockCloser{}
|
|
conn, err := NewQUICConnection(qc, cl)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, conn)
|
|
}
|
|
|
|
func TestConnWithCloser_CloseWithError_BothSucceed(t *testing.T) {
|
|
t.Parallel()
|
|
qc := &mockQuicConnection{}
|
|
cl := &mockCloser{}
|
|
conn, err := NewQUICConnection(qc, cl)
|
|
require.NoError(t, err)
|
|
|
|
err = conn.CloseWithError(0, "test")
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func TestConnWithCloser_CloseWithError_QuicFails(t *testing.T) {
|
|
t.Parallel()
|
|
quicErr := errors.New("quic close failed")
|
|
qc := &mockQuicConnection{closeWithErrorErr: quicErr}
|
|
cl := &mockCloser{}
|
|
conn, err := NewQUICConnection(qc, cl)
|
|
require.NoError(t, err)
|
|
|
|
err = conn.CloseWithError(0, "test")
|
|
require.ErrorIs(t, err, quicErr)
|
|
}
|
|
|
|
func TestConnWithCloser_CloseWithError_CloserFails(t *testing.T) {
|
|
t.Parallel()
|
|
closerErr := errors.New("closer failed")
|
|
qc := &mockQuicConnection{}
|
|
cl := &mockCloser{closeErr: closerErr}
|
|
conn, err := NewQUICConnection(qc, cl)
|
|
require.NoError(t, err)
|
|
|
|
err = conn.CloseWithError(0, "test")
|
|
require.ErrorIs(t, err, closerErr)
|
|
}
|
|
|
|
func TestConnWithCloser_CloseWithError_BothFail(t *testing.T) {
|
|
t.Parallel()
|
|
quicErr := errors.New("quic close failed")
|
|
closerErr := errors.New("closer failed")
|
|
qc := &mockQuicConnection{closeWithErrorErr: quicErr}
|
|
cl := &mockCloser{closeErr: closerErr}
|
|
conn, err := NewQUICConnection(qc, cl)
|
|
require.NoError(t, err)
|
|
|
|
err = conn.CloseWithError(0, "test")
|
|
require.ErrorIs(t, err, quicErr)
|
|
require.ErrorIs(t, err, closerErr)
|
|
}
|
|
|
|
// TestConnWithCloser_ImplementsInterface is a runtime assertion that
|
|
// *ConnWithCloser satisfies QUICConnection. The compile-time assertion is in
|
|
// quic_connection.go.
|
|
func TestConnWithCloser_ImplementsInterface(t *testing.T) {
|
|
t.Parallel()
|
|
var _ QUICConnection = (*ConnWithCloser)(nil)
|
|
}
|