@ -12,6 +12,7 @@ import (
xmaps "golang.org/x/exp/maps"
"golang.org/x/net/dns/dnsmessage"
"tailscale.com/appc/appctest"
"tailscale.com/util/mak"
"tailscale.com/util/must"
)
@ -44,31 +45,31 @@ func TestUpdateDomains(t *testing.T) {
}
func TestUpdateRoutes ( t * testing . T ) {
rc := & r outeCollector{ }
rc := & appctest. R outeCollector{ }
a := NewAppConnector ( t . Logf , rc )
routes := [ ] netip . Prefix { netip . MustParsePrefix ( "192.0.2.0/24" ) }
a . updateRoutes ( routes )
if ! slices . EqualFunc ( routes , rc . routes , prefixEqual ) {
t . Fatalf ( "got %v, want %v" , rc . routes , routes )
if ! slices . EqualFunc ( routes , rc . Routes ( ) , prefixEqual ) {
t . Fatalf ( "got %v, want %v" , rc . Routes ( ) , routes )
}
}
func TestUpdateRoutesUnadvertisesContainedRoutes ( t * testing . T ) {
rc := & r outeCollector{ }
rc := & appctest. R outeCollector{ }
a := NewAppConnector ( t . Logf , rc )
mak . Set ( & a . domains , "example.com" , [ ] netip . Addr { netip . MustParseAddr ( "192.0.2.1" ) } )
rc . routes = [ ] netip . Prefix { netip . MustParsePrefix ( "192.0.2.1/32" ) }
rc . SetRoutes ( [ ] netip . Prefix { netip . MustParsePrefix ( "192.0.2.1/32" ) } )
routes := [ ] netip . Prefix { netip . MustParsePrefix ( "192.0.2.0/24" ) }
a . updateRoutes ( routes )
if ! slices . EqualFunc ( routes , rc . routes , prefixEqual ) {
t . Fatalf ( "got %v, want %v" , rc . routes , routes )
if ! slices . EqualFunc ( routes , rc . Routes ( ) , prefixEqual ) {
t . Fatalf ( "got %v, want %v" , rc . Routes ( ) , routes )
}
}
func TestDomainRoutes ( t * testing . T ) {
rc := & r outeCollector{ }
rc := & appctest. R outeCollector{ }
a := NewAppConnector ( t . Logf , rc )
a . updateDomains ( [ ] string { "example.com" } )
a . ObserveDNSResponse ( dnsResponse ( "example.com." , "192.0.0.8" ) )
@ -83,12 +84,12 @@ func TestDomainRoutes(t *testing.T) {
}
func TestObserveDNSResponse ( t * testing . T ) {
rc := & r outeCollector{ }
rc := & appctest. R outeCollector{ }
a := NewAppConnector ( t . Logf , rc )
// a has no domains configured, so it should not advertise any routes
a . ObserveDNSResponse ( dnsResponse ( "example.com." , "192.0.0.8" ) )
if got , want := rc . routes , ( [ ] netip . Prefix ) ( nil ) ; ! slices . Equal ( got , want ) {
if got , want := rc . Routes ( ) , ( [ ] netip . Prefix ) ( nil ) ; ! slices . Equal ( got , want ) {
t . Errorf ( "got %v; want %v" , got , want )
}
@ -96,21 +97,21 @@ func TestObserveDNSResponse(t *testing.T) {
a . updateDomains ( [ ] string { "example.com" } )
a . ObserveDNSResponse ( dnsResponse ( "example.com." , "192.0.0.8" ) )
if got , want := rc . routes , wantRoutes ; ! slices . Equal ( got , want ) {
if got , want := rc . Routes ( ) , wantRoutes ; ! slices . Equal ( got , want ) {
t . Errorf ( "got %v; want %v" , got , want )
}
wantRoutes = append ( wantRoutes , netip . MustParsePrefix ( "2001:db8::1/128" ) )
a . ObserveDNSResponse ( dnsResponse ( "example.com." , "2001:db8::1" ) )
if got , want := rc . routes , wantRoutes ; ! slices . Equal ( got , want ) {
if got , want := rc . Routes ( ) , wantRoutes ; ! slices . Equal ( got , want ) {
t . Errorf ( "got %v; want %v" , got , want )
}
// don't re-advertise routes that have already been advertised
a . ObserveDNSResponse ( dnsResponse ( "example.com." , "2001:db8::1" ) )
if ! slices . Equal ( rc . routes , wantRoutes ) {
t . Errorf ( "rc. routes: got %v; want %v", rc . routes , wantRoutes )
if ! slices . Equal ( rc . Routes ( ) , wantRoutes ) {
t . Errorf ( "rc. Routes(): got %v; want %v", rc . Routes ( ) , wantRoutes )
}
// don't advertise addresses that are already in a control provided route
@ -118,8 +119,8 @@ func TestObserveDNSResponse(t *testing.T) {
a . updateRoutes ( [ ] netip . Prefix { pfx } )
wantRoutes = append ( wantRoutes , pfx )
a . ObserveDNSResponse ( dnsResponse ( "example.com." , "192.0.2.1" ) )
if ! slices . Equal ( rc . routes , wantRoutes ) {
t . Errorf ( "rc. routes: got %v; want %v", rc . routes , wantRoutes )
if ! slices . Equal ( rc . Routes ( ) , wantRoutes ) {
t . Errorf ( "rc. Routes(): got %v; want %v", rc . Routes ( ) , wantRoutes )
}
if ! slices . Contains ( a . domains [ "example.com" ] , netip . MustParseAddr ( "192.0.2.1" ) ) {
t . Errorf ( "missing %v from %v" , "192.0.2.1" , a . domains [ "exmaple.com" ] )
@ -127,12 +128,12 @@ func TestObserveDNSResponse(t *testing.T) {
}
func TestWildcardDomains ( t * testing . T ) {
rc := & r outeCollector{ }
rc := & appctest. R outeCollector{ }
a := NewAppConnector ( t . Logf , rc )
a . updateDomains ( [ ] string { "*.example.com" } )
a . ObserveDNSResponse ( dnsResponse ( "foo.example.com." , "192.0.0.8" ) )
if got , want := rc . routes , [ ] netip . Prefix { netip . MustParsePrefix ( "192.0.0.8/32" ) } ; ! slices . Equal ( got , want ) {
if got , want := rc . Routes ( ) , [ ] netip . Prefix { netip . MustParsePrefix ( "192.0.0.8/32" ) } ; ! slices . Equal ( got , want ) {
t . Errorf ( "routes: got %v; want %v" , got , want )
}
if got , want := a . wildcards , [ ] string { "example.com" } ; ! slices . Equal ( got , want ) {
@ -191,30 +192,6 @@ func dnsResponse(domain, address string) []byte {
return must . Get ( b . Finish ( ) )
}
// routeCollector is a test helper that collects the list of routes advertised
type routeCollector struct {
routes [ ] netip . Prefix
}
// routeCollector implements RouteAdvertiser
var _ RouteAdvertiser = ( * routeCollector ) ( nil )
func ( rc * routeCollector ) AdvertiseRoute ( pfx netip . Prefix ) error {
rc . routes = append ( rc . routes , pfx )
return nil
}
func ( rc * routeCollector ) UnadvertiseRoute ( pfx netip . Prefix ) error {
routes := rc . routes
rc . routes = rc . routes [ : 0 ]
for _ , r := range routes {
if r != pfx {
rc . routes = append ( rc . routes , r )
}
}
return nil
}
func prefixEqual ( a , b netip . Prefix ) bool {
return a . Addr ( ) . Compare ( b . Addr ( ) ) == 0 && a . Bits ( ) == b . Bits ( )
return a == b
}