mirror of
https://github.com/netbirdio/netbird.git
synced 2026-07-16 11:39:57 +00:00
102 lines
3.5 KiB
Go
102 lines
3.5 KiB
Go
//go:build !js
|
|
|
|
package client
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/netbirdio/netbird/client/iface"
|
|
"github.com/netbirdio/netbird/shared/relay/client/dialer"
|
|
netErr "github.com/netbirdio/netbird/shared/relay/client/dialer/net"
|
|
"github.com/netbirdio/netbird/shared/relay/client/dialer/quic"
|
|
"github.com/netbirdio/netbird/shared/relay/client/dialer/ws"
|
|
)
|
|
|
|
// TestDatagramSizedCapability locks the capability the generic fallback relies
|
|
// on: QUIC is datagram-sized, WebSocket is not.
|
|
func TestDatagramSizedCapability(t *testing.T) {
|
|
assert.True(t, dialer.IsDatagramSized(quic.Dialer{}), "QUIC must advertise datagram-sized")
|
|
assert.False(t, dialer.IsDatagramSized(ws.Dialer{}), "WebSocket must not advertise datagram-sized")
|
|
}
|
|
|
|
func protocols(dialers []dialer.DialeFn) []string {
|
|
out := make([]string, len(dialers))
|
|
for i, d := range dialers {
|
|
out[i] = d.Protocol()
|
|
}
|
|
return out
|
|
}
|
|
|
|
func TestGetDialers(t *testing.T) {
|
|
const url = "rels://relay.example:443"
|
|
|
|
tests := []struct {
|
|
name string
|
|
mode string
|
|
mtu uint16
|
|
preferWS bool
|
|
want []string
|
|
}{
|
|
{name: "auto races quic and ws", mode: "auto", mtu: iface.DefaultMTU, want: []string{"quic", "ws"}},
|
|
{name: "ws pinned", mode: "ws", mtu: iface.DefaultMTU, want: []string{"ws"}},
|
|
{name: "quic pinned", mode: "quic", mtu: iface.DefaultMTU, want: []string{"quic"}},
|
|
{name: "prefer-quic orders quic first", mode: "prefer-quic", mtu: iface.DefaultMTU, want: []string{"quic", "ws"}},
|
|
{name: "prefer-ws orders ws first", mode: "prefer-ws", mtu: iface.DefaultMTU, want: []string{"ws", "quic"}},
|
|
{name: "mtu above default forces ws", mode: "auto", mtu: iface.DefaultMTU + 100, want: []string{"ws"}},
|
|
{name: "sticky fallback forces ws in auto", mode: "auto", mtu: iface.DefaultMTU, preferWS: true, want: []string{"ws"}},
|
|
{name: "sticky fallback forces ws in prefer-quic", mode: "prefer-quic", mtu: iface.DefaultMTU, preferWS: true, want: []string{"ws"}},
|
|
{name: "quic pin overrides sticky fallback", mode: "quic", mtu: iface.DefaultMTU, preferWS: true, want: []string{"quic"}},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Setenv(EnvRelayTransport, tc.mode)
|
|
if tc.mode == "" {
|
|
os.Unsetenv(EnvRelayTransport)
|
|
}
|
|
|
|
tf := newTransportFallback()
|
|
if tc.preferWS {
|
|
tf.recordFailure(url)
|
|
}
|
|
|
|
c := &Client{
|
|
log: log.WithField("test", t.Name()),
|
|
connectionURL: url,
|
|
mtu: tc.mtu,
|
|
transportFallback: tf,
|
|
}
|
|
|
|
assert.Equal(t, tc.want, protocols(c.getDialers(transportModeFromEnv())))
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestStickyFallbackAfterDatagramTooLarge verifies the full chain: an oversized
|
|
// datagram records a fallback that makes the next dial pick WebSocket, the way a
|
|
// reconnect would after the connection is closed.
|
|
func TestStickyFallbackAfterDatagramTooLarge(t *testing.T) {
|
|
const url = "rels://relay.example:443"
|
|
t.Setenv(EnvRelayTransport, string(TransportModeAuto))
|
|
|
|
c := &Client{
|
|
log: log.WithField("test", t.Name()),
|
|
connectionURL: url,
|
|
mtu: iface.DefaultMTU,
|
|
transportFallback: newTransportFallback(),
|
|
}
|
|
|
|
// First dial races both transports.
|
|
assert.Equal(t, []string{"quic", "ws"}, protocols(c.getDialers(transportModeFromEnv())))
|
|
|
|
// An oversized datagram records the fallback for this server.
|
|
c.onDatagramTooLarge(&closeTrackingConn{}, netErr.ErrDatagramTooLarge)
|
|
|
|
// The reconnect now sticks to WebSocket.
|
|
assert.Equal(t, []string{"ws"}, protocols(c.getDialers(transportModeFromEnv())))
|
|
}
|