|
|
|
@ -16,6 +16,8 @@ import (
|
|
|
|
|
"tailscale.com/tailcfg"
|
|
|
|
|
"tailscale.com/types/key"
|
|
|
|
|
"tailscale.com/types/netmap"
|
|
|
|
|
"tailscale.com/types/opt"
|
|
|
|
|
"tailscale.com/util/must"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func TestUndeltaPeers(t *testing.T) {
|
|
|
|
@ -449,3 +451,152 @@ func TestNetmapForResponse(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TestDeltaDebug tests that tailcfg.Debug values can be omitted in MapResposnes
|
|
|
|
|
// entirely or have their opt.Bool values unspecified between MapResponses in a
|
|
|
|
|
// session and that should mean no change. (as of capver 37). But two Debug
|
|
|
|
|
// fields existed prior to capver 37 that weren't opt.Bool; we test that we both
|
|
|
|
|
// still accept the non-opt.Bool form from control for RandomizeClientPort and
|
|
|
|
|
// ForceBackgroundSTUN and also accept the new form, keeping the old form in
|
|
|
|
|
// sync.
|
|
|
|
|
func TestDeltaDebug(t *testing.T) {
|
|
|
|
|
type step struct {
|
|
|
|
|
got *tailcfg.Debug
|
|
|
|
|
want *tailcfg.Debug
|
|
|
|
|
}
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
steps []step
|
|
|
|
|
}{
|
|
|
|
|
{
|
|
|
|
|
name: "nothing-to-nothing",
|
|
|
|
|
steps: []step{
|
|
|
|
|
{nil, nil},
|
|
|
|
|
{nil, nil},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "sticky-with-old-style-randomize-client-port",
|
|
|
|
|
steps: []step{
|
|
|
|
|
{
|
|
|
|
|
&tailcfg.Debug{RandomizeClientPort: true},
|
|
|
|
|
&tailcfg.Debug{
|
|
|
|
|
RandomizeClientPort: true,
|
|
|
|
|
SetRandomizeClientPort: "true",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
nil, // not sent by server
|
|
|
|
|
&tailcfg.Debug{
|
|
|
|
|
RandomizeClientPort: true,
|
|
|
|
|
SetRandomizeClientPort: "true",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "sticky-with-new-style-randomize-client-port",
|
|
|
|
|
steps: []step{
|
|
|
|
|
{
|
|
|
|
|
&tailcfg.Debug{SetRandomizeClientPort: "true"},
|
|
|
|
|
&tailcfg.Debug{
|
|
|
|
|
RandomizeClientPort: true,
|
|
|
|
|
SetRandomizeClientPort: "true",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
nil, // not sent by server
|
|
|
|
|
&tailcfg.Debug{
|
|
|
|
|
RandomizeClientPort: true,
|
|
|
|
|
SetRandomizeClientPort: "true",
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "opt-bool-sticky-changing-over-time",
|
|
|
|
|
steps: []step{
|
|
|
|
|
{nil, nil},
|
|
|
|
|
{nil, nil},
|
|
|
|
|
{
|
|
|
|
|
&tailcfg.Debug{OneCGNATRoute: "true"},
|
|
|
|
|
&tailcfg.Debug{OneCGNATRoute: "true"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
nil,
|
|
|
|
|
&tailcfg.Debug{OneCGNATRoute: "true"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
&tailcfg.Debug{OneCGNATRoute: "false"},
|
|
|
|
|
&tailcfg.Debug{OneCGNATRoute: "false"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
nil,
|
|
|
|
|
&tailcfg.Debug{OneCGNATRoute: "false"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "legacy-ForceBackgroundSTUN",
|
|
|
|
|
steps: []step{
|
|
|
|
|
{
|
|
|
|
|
&tailcfg.Debug{ForceBackgroundSTUN: true},
|
|
|
|
|
&tailcfg.Debug{ForceBackgroundSTUN: true, SetForceBackgroundSTUN: "true"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "opt-bool-SetForceBackgroundSTUN",
|
|
|
|
|
steps: []step{
|
|
|
|
|
{
|
|
|
|
|
&tailcfg.Debug{SetForceBackgroundSTUN: "true"},
|
|
|
|
|
&tailcfg.Debug{ForceBackgroundSTUN: true, SetForceBackgroundSTUN: "true"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
name: "server-reset-to-default",
|
|
|
|
|
steps: []step{
|
|
|
|
|
{
|
|
|
|
|
&tailcfg.Debug{SetForceBackgroundSTUN: "true"},
|
|
|
|
|
&tailcfg.Debug{ForceBackgroundSTUN: true, SetForceBackgroundSTUN: "true"},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
&tailcfg.Debug{SetForceBackgroundSTUN: "unset"},
|
|
|
|
|
&tailcfg.Debug{ForceBackgroundSTUN: false, SetForceBackgroundSTUN: "unset"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
ms := newTestMapSession(t)
|
|
|
|
|
for stepi, s := range tt.steps {
|
|
|
|
|
nm := ms.netmapForResponse(&tailcfg.MapResponse{Debug: s.got})
|
|
|
|
|
if !reflect.DeepEqual(nm.Debug, s.want) {
|
|
|
|
|
t.Errorf("unexpected result at step index %v; got: %s", stepi, must.Get(json.Marshal(nm.Debug)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Verifies that copyDebugOptBools doesn't missing any opt.Bools.
|
|
|
|
|
func TestCopyDebugOptBools(t *testing.T) {
|
|
|
|
|
rt := reflect.TypeOf(tailcfg.Debug{})
|
|
|
|
|
for i := 0; i < rt.NumField(); i++ {
|
|
|
|
|
sf := rt.Field(i)
|
|
|
|
|
if sf.Type != reflect.TypeOf(opt.Bool("")) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
var src, dst tailcfg.Debug
|
|
|
|
|
reflect.ValueOf(&src).Elem().Field(i).Set(reflect.ValueOf(opt.Bool("true")))
|
|
|
|
|
if src == (tailcfg.Debug{}) {
|
|
|
|
|
t.Fatalf("failed to set field %v", sf.Name)
|
|
|
|
|
}
|
|
|
|
|
copyDebugOptBools(&dst, &src)
|
|
|
|
|
if src != dst {
|
|
|
|
|
t.Fatalf("copyDebugOptBools didn't copy field %v", sf.Name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|