diff --git a/tailcfg/tailcfg.go b/tailcfg/tailcfg.go index 2404b6bb8..e2f5812f6 100644 --- a/tailcfg/tailcfg.go +++ b/tailcfg/tailcfg.go @@ -571,12 +571,31 @@ func (h *Hostinfo) Equal(h2 *Hostinfo) bool { if h == nil && h2 == nil { return true } - if (h == nil) != (h2 == nil) { + if h == nil || h2 == nil { return false } return reflect.DeepEqual(h, h2) } +// BasicallyEqual reports whether h and h2 are equal other than the +// NetInfo DERP latency timing. (see NetInfo.BasicallyEqual). +func (h *Hostinfo) BasicallyEqual(h2 *Hostinfo) bool { + if h == nil && h2 == nil { + return true + } + if h == nil || h2 == nil { + return false + } + a := *h + b := *h2 + if !a.NetInfo.BasicallyEqual(b.NetInfo) { + return false + } + a.NetInfo = nil + b.NetInfo = nil + return a.Equal(&b) +} + // SignatureType specifies a scheme for signing RegisterRequest messages. It // specifies the crypto algorithms to use, the contents of what is signed, and // any other relevant details. Historically, requests were unsigned so the zero diff --git a/tailcfg/tailcfg_test.go b/tailcfg/tailcfg_test.go index 071a88a90..109aeb965 100644 --- a/tailcfg/tailcfg_test.go +++ b/tailcfg/tailcfg_test.go @@ -190,6 +190,75 @@ func TestHostinfoEqual(t *testing.T) { } } +func TestHostinfoBasicallyEqual(t *testing.T) { + tests := []struct { + a, b *Hostinfo + want bool + }{ + { + want: true, + }, + { + a: new(Hostinfo), + b: new(Hostinfo), + want: true, + }, + { + a: &Hostinfo{}, + b: &Hostinfo{ + NetInfo: &NetInfo{}, + }, + want: false, // one's nil, the other's not + }, + { + a: &Hostinfo{ + NetInfo: &NetInfo{}, + }, + b: &Hostinfo{ + NetInfo: &NetInfo{}, + }, + want: true, + }, + { + a: &Hostinfo{ + NetInfo: &NetInfo{}, + }, + b: &Hostinfo{ + NetInfo: &NetInfo{ + DERPLatency: map[string]float64{ // ignored + "1": 1.0, + "2": 2.0, + }, + }, + }, + want: true, + }, + { + a: &Hostinfo{ + NetInfo: &NetInfo{ + PreferredDERP: 1, + }, + }, + b: &Hostinfo{ + NetInfo: &NetInfo{ + PreferredDERP: 2, // differs + DERPLatency: map[string]float64{ // ignored + "1": 1.0, + "2": 2.0, + }, + }, + }, + want: false, + }, + } + for i, tt := range tests { + got := tt.a.BasicallyEqual(tt.b) + if got != tt.want { + t.Errorf("%d. BasicallyEqual = %v; want %v", i, got, tt.want) + } + } +} + func TestNodeEqual(t *testing.T) { nodeHandles := []string{ "ID", "StableID", "Name", "User", "Sharer",