2023-01-27 13:37:20 -08:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2020-02-05 14:16:58 -08:00
|
|
|
|
|
|
|
package controlclient
|
|
|
|
|
|
|
|
import (
|
2025-01-24 13:09:21 -08:00
|
|
|
"io"
|
2020-02-05 14:16:58 -08:00
|
|
|
"reflect"
|
2025-01-24 13:09:21 -08:00
|
|
|
"slices"
|
2020-02-05 14:16:58 -08:00
|
|
|
"testing"
|
2025-01-24 13:09:21 -08:00
|
|
|
|
|
|
|
"tailscale.com/types/netmap"
|
|
|
|
"tailscale.com/types/persist"
|
2020-02-05 14:16:58 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
func fieldsOf(t reflect.Type) (fields []string) {
|
2024-04-16 13:15:13 -07:00
|
|
|
for i := range t.NumField() {
|
2020-05-03 13:58:39 -07:00
|
|
|
if name := t.Field(i).Name; name != "_" {
|
|
|
|
fields = append(fields, name)
|
|
|
|
}
|
2020-02-05 14:16:58 -08:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestStatusEqual(t *testing.T) {
|
|
|
|
// Verify that the Equal method stays in sync with reality
|
2023-08-30 11:09:36 -07:00
|
|
|
equalHandles := []string{"Err", "URL", "NetMap", "Persist", "state"}
|
2024-02-08 17:34:22 -08:00
|
|
|
if have := fieldsOf(reflect.TypeFor[Status]()); !reflect.DeepEqual(have, equalHandles) {
|
2020-02-05 14:16:58 -08:00
|
|
|
t.Errorf("Status.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
|
|
|
|
have, equalHandles)
|
|
|
|
}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
a, b *Status
|
|
|
|
want bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
&Status{},
|
|
|
|
nil,
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
nil,
|
|
|
|
&Status{},
|
|
|
|
false,
|
|
|
|
},
|
2021-01-05 10:56:21 -08:00
|
|
|
{
|
|
|
|
nil,
|
|
|
|
nil,
|
|
|
|
true,
|
|
|
|
},
|
2020-02-05 14:16:58 -08:00
|
|
|
{
|
|
|
|
&Status{},
|
|
|
|
&Status{},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
2023-08-30 18:18:10 -07:00
|
|
|
&Status{},
|
2023-08-30 10:21:56 -07:00
|
|
|
&Status{state: StateAuthenticated},
|
2020-02-05 14:16:58 -08:00
|
|
|
false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
|
|
got := tt.a.Equal(tt.b)
|
|
|
|
if got != tt.want {
|
|
|
|
t.Errorf("%d. Equal = %v; want %v", i, got, tt.want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2025-01-24 13:09:21 -08:00
|
|
|
|
|
|
|
// tests [canSkipStatus].
|
|
|
|
func TestCanSkipStatus(t *testing.T) {
|
|
|
|
st := new(Status)
|
|
|
|
nm1 := &netmap.NetworkMap{}
|
|
|
|
nm2 := &netmap.NetworkMap{}
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
s1, s2 *Status
|
|
|
|
want bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "nil-s2",
|
|
|
|
s1: st,
|
|
|
|
s2: nil,
|
|
|
|
want: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "equal",
|
|
|
|
s1: st,
|
|
|
|
s2: st,
|
|
|
|
want: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "s1-error",
|
|
|
|
s1: &Status{Err: io.EOF, NetMap: nm1},
|
|
|
|
s2: &Status{NetMap: nm2},
|
|
|
|
want: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "s1-url",
|
|
|
|
s1: &Status{URL: "foo", NetMap: nm1},
|
|
|
|
s2: &Status{NetMap: nm2},
|
|
|
|
want: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "s1-persist-diff",
|
|
|
|
s1: &Status{Persist: new(persist.Persist).View(), NetMap: nm1},
|
|
|
|
s2: &Status{NetMap: nm2},
|
|
|
|
want: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "s1-state-diff",
|
|
|
|
s1: &Status{state: 123, NetMap: nm1},
|
|
|
|
s2: &Status{NetMap: nm2},
|
|
|
|
want: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "s1-no-netmap1",
|
|
|
|
s1: &Status{NetMap: nil},
|
|
|
|
s2: &Status{NetMap: nm2},
|
|
|
|
want: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "s1-no-netmap2",
|
|
|
|
s1: &Status{NetMap: nm1},
|
|
|
|
s2: &Status{NetMap: nil},
|
|
|
|
want: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "skip",
|
|
|
|
s1: &Status{NetMap: nm1},
|
|
|
|
s2: &Status{NetMap: nm2},
|
|
|
|
want: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
if got := canSkipStatus(tt.s1, tt.s2); got != tt.want {
|
|
|
|
t.Errorf("canSkipStatus = %v, want %v", got, tt.want)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
want := []string{"Err", "URL", "NetMap", "Persist", "state"}
|
|
|
|
if f := fieldsOf(reflect.TypeFor[Status]()); !slices.Equal(f, want) {
|
|
|
|
t.Errorf("Status fields = %q; this code was only written to handle fields %q", f, want)
|
|
|
|
}
|
|
|
|
}
|