|
|
|
|
@ -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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|