@ -5,7 +5,9 @@ package relayserver
import (
import (
"errors"
"errors"
"net/netip"
"reflect"
"reflect"
"slices"
"testing"
"testing"
"tailscale.com/ipn"
"tailscale.com/ipn"
@ -17,14 +19,20 @@ import (
"tailscale.com/types/key"
"tailscale.com/types/key"
"tailscale.com/types/logger"
"tailscale.com/types/logger"
"tailscale.com/types/ptr"
"tailscale.com/types/ptr"
"tailscale.com/types/views"
)
)
func Test_extension_profileStateChanged ( t * testing . T ) {
func Test_extension_profileStateChanged ( t * testing . T ) {
prefsWithPortOne := ipn . Prefs { RelayServerPort : ptr . To ( 1 ) }
prefsWithPortOne := ipn . Prefs { RelayServerPort : ptr . To ( 1 ) }
prefsWithNilPort := ipn . Prefs { RelayServerPort : nil }
prefsWithNilPort := ipn . Prefs { RelayServerPort : nil }
prefsWithPortOneRelayEndpoints := ipn . Prefs {
RelayServerPort : ptr . To ( 1 ) ,
RelayServerStaticEndpoints : [ ] netip . AddrPort { netip . MustParseAddrPort ( "127.0.0.1:7777" ) } ,
}
type fields struct {
type fields struct {
port * int
port * int
staticEndpoints views . Slice [ netip . AddrPort ]
rs relayServer
rs relayServer
}
}
type args struct {
type args struct {
@ -38,6 +46,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
wantPort * int
wantPort * int
wantRelayServerFieldNonNil bool
wantRelayServerFieldNonNil bool
wantRelayServerFieldMutated bool
wantRelayServerFieldMutated bool
wantEndpoints [ ] netip . AddrPort
} {
} {
{
{
name : "no changes non-nil port previously running" ,
name : "no changes non-nil port previously running" ,
@ -53,6 +62,52 @@ func Test_extension_profileStateChanged(t *testing.T) {
wantRelayServerFieldNonNil : true ,
wantRelayServerFieldNonNil : true ,
wantRelayServerFieldMutated : false ,
wantRelayServerFieldMutated : false ,
} ,
} ,
{
name : "set addr ports unchanged port previously running" ,
fields : fields {
port : ptr . To ( 1 ) ,
rs : mockRelayServerNotZeroVal ( ) ,
} ,
args : args {
prefs : prefsWithPortOneRelayEndpoints . View ( ) ,
sameNode : true ,
} ,
wantPort : ptr . To ( 1 ) ,
wantRelayServerFieldNonNil : true ,
wantRelayServerFieldMutated : false ,
wantEndpoints : prefsWithPortOneRelayEndpoints . RelayServerStaticEndpoints ,
} ,
{
name : "set addr ports not previously running" ,
fields : fields {
port : nil ,
rs : nil ,
} ,
args : args {
prefs : prefsWithPortOneRelayEndpoints . View ( ) ,
sameNode : true ,
} ,
wantPort : ptr . To ( 1 ) ,
wantRelayServerFieldNonNil : true ,
wantRelayServerFieldMutated : true ,
wantEndpoints : prefsWithPortOneRelayEndpoints . RelayServerStaticEndpoints ,
} ,
{
name : "clear addr ports unchanged port previously running" ,
fields : fields {
port : ptr . To ( 1 ) ,
staticEndpoints : views . SliceOf ( prefsWithPortOneRelayEndpoints . RelayServerStaticEndpoints ) ,
rs : mockRelayServerNotZeroVal ( ) ,
} ,
args : args {
prefs : prefsWithPortOne . View ( ) ,
sameNode : true ,
} ,
wantPort : ptr . To ( 1 ) ,
wantRelayServerFieldNonNil : true ,
wantRelayServerFieldMutated : false ,
wantEndpoints : nil ,
} ,
{
{
name : "prefs port nil" ,
name : "prefs port nil" ,
fields : fields {
fields : fields {
@ -160,6 +215,7 @@ func Test_extension_profileStateChanged(t *testing.T) {
return & mockRelayServer { } , nil
return & mockRelayServer { } , nil
}
}
e . port = tt . fields . port
e . port = tt . fields . port
e . staticEndpoints = tt . fields . staticEndpoints
e . rs = tt . fields . rs
e . rs = tt . fields . rs
defer e . Shutdown ( )
defer e . Shutdown ( )
e . profileStateChanged ( ipn . LoginProfileView { } , tt . args . prefs , tt . args . sameNode )
e . profileStateChanged ( ipn . LoginProfileView { } , tt . args . prefs , tt . args . sameNode )
@ -174,24 +230,34 @@ func Test_extension_profileStateChanged(t *testing.T) {
if tt . wantRelayServerFieldMutated != ! reflect . DeepEqual ( tt . fields . rs , e . rs ) {
if tt . wantRelayServerFieldMutated != ! reflect . DeepEqual ( tt . fields . rs , e . rs ) {
t . Errorf ( "wantRelayServerFieldMutated: %v != !reflect.DeepEqual(tt.fields.rs, e.rs): %v" , tt . wantRelayServerFieldMutated , ! reflect . DeepEqual ( tt . fields . rs , e . rs ) )
t . Errorf ( "wantRelayServerFieldMutated: %v != !reflect.DeepEqual(tt.fields.rs, e.rs): %v" , tt . wantRelayServerFieldMutated , ! reflect . DeepEqual ( tt . fields . rs , e . rs ) )
}
}
if ! slices . Equal ( tt . wantEndpoints , e . staticEndpoints . AsSlice ( ) ) {
t . Errorf ( "wantEndpoints: %v != %v" , tt . wantEndpoints , e . staticEndpoints . AsSlice ( ) )
}
if e . rs != nil && ! slices . Equal ( tt . wantEndpoints , e . rs . ( * mockRelayServer ) . addrPorts . AsSlice ( ) ) {
t . Errorf ( "wantEndpoints: %v != %v" , tt . wantEndpoints , e . rs . ( * mockRelayServer ) . addrPorts . AsSlice ( ) )
}
} )
} )
}
}
}
}
func mockRelayServerNotZeroVal ( ) * mockRelayServer {
func mockRelayServerNotZeroVal ( ) * mockRelayServer {
return & mockRelayServer { true }
return & mockRelayServer { set : true }
}
}
type mockRelayServer struct {
type mockRelayServer struct {
set bool
set bool
addrPorts views . Slice [ netip . AddrPort ]
}
}
func ( m ockRelayServer) Close ( ) error { return nil }
func ( m * m ockRelayServer) Close ( ) error { return nil }
func ( m ockRelayServer) AllocateEndpoint ( _ , _ key . DiscoPublic ) ( endpoint . ServerEndpoint , error ) {
func ( m * m ockRelayServer) AllocateEndpoint ( _ , _ key . DiscoPublic ) ( endpoint . ServerEndpoint , error ) {
return endpoint . ServerEndpoint { } , errors . New ( "not implemented" )
return endpoint . ServerEndpoint { } , errors . New ( "not implemented" )
}
}
func ( mockRelayServer ) GetSessions ( ) [ ] status . ServerSession { return nil }
func ( m * mockRelayServer ) GetSessions ( ) [ ] status . ServerSession { return nil }
func ( mockRelayServer ) SetDERPMapView ( tailcfg . DERPMapView ) { return }
func ( m * mockRelayServer ) SetDERPMapView ( tailcfg . DERPMapView ) { return }
func ( m * mockRelayServer ) SetStaticAddrPorts ( aps views . Slice [ netip . AddrPort ] ) {
m . addrPorts = aps
}
type mockSafeBackend struct {
type mockSafeBackend struct {
sys * tsd . System
sys * tsd . System