2023-01-27 21:37:20 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2020-02-16 06:23:58 +00:00
|
|
|
|
2023-01-21 04:34:19 +00:00
|
|
|
package tailcfg_test
|
2020-02-16 06:23:58 +00:00
|
|
|
|
|
|
|
import (
|
2020-06-19 02:32:55 +00:00
|
|
|
"encoding"
|
2021-04-01 21:44:40 +00:00
|
|
|
"encoding/json"
|
2022-07-26 03:55:44 +00:00
|
|
|
"net/netip"
|
2022-08-11 16:24:07 +00:00
|
|
|
"os"
|
2020-02-16 06:23:58 +00:00
|
|
|
"reflect"
|
2022-08-11 16:24:07 +00:00
|
|
|
"regexp"
|
|
|
|
"strconv"
|
2020-06-19 02:32:55 +00:00
|
|
|
"strings"
|
2020-02-16 06:23:58 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2023-01-21 04:34:19 +00:00
|
|
|
. "tailscale.com/tailcfg"
|
2021-09-03 20:17:46 +00:00
|
|
|
"tailscale.com/types/key"
|
2023-04-13 17:12:31 +00:00
|
|
|
"tailscale.com/types/ptr"
|
2022-08-11 16:24:07 +00:00
|
|
|
"tailscale.com/util/must"
|
2020-02-16 06:23:58 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func fieldsOf(t reflect.Type) (fields []string) {
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
|
|
fields = append(fields, t.Field(i).Name)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-02-18 03:33:01 +00:00
|
|
|
func TestHostinfoEqual(t *testing.T) {
|
2020-02-25 22:05:17 +00:00
|
|
|
hiHandles := []string{
|
2022-09-11 17:57:18 +00:00
|
|
|
"IPNVersion",
|
|
|
|
"FrontendLogID",
|
|
|
|
"BackendLogID",
|
|
|
|
"OS",
|
|
|
|
"OSVersion",
|
|
|
|
"Container",
|
|
|
|
"Env",
|
|
|
|
"Distro",
|
|
|
|
"DistroVersion",
|
|
|
|
"DistroCodeName",
|
2023-02-27 17:58:54 +00:00
|
|
|
"App",
|
2022-09-11 17:57:18 +00:00
|
|
|
"Desktop",
|
|
|
|
"Package",
|
|
|
|
"DeviceModel",
|
2023-01-29 22:04:40 +00:00
|
|
|
"PushDeviceToken",
|
2022-09-11 17:57:18 +00:00
|
|
|
"Hostname",
|
|
|
|
"ShieldsUp",
|
|
|
|
"ShareeNode",
|
2022-09-13 14:09:57 +00:00
|
|
|
"NoLogsNoSupport",
|
2022-11-16 04:30:53 +00:00
|
|
|
"WireIngress",
|
2023-01-21 18:04:43 +00:00
|
|
|
"AllowsUpdate",
|
2023-01-22 18:16:15 +00:00
|
|
|
"Machine",
|
2022-09-11 17:57:18 +00:00
|
|
|
"GoArch",
|
2023-01-22 18:16:15 +00:00
|
|
|
"GoArchVar",
|
2022-09-11 17:57:18 +00:00
|
|
|
"GoVersion",
|
|
|
|
"RoutableIPs",
|
|
|
|
"RequestTags",
|
|
|
|
"Services",
|
|
|
|
"NetInfo",
|
|
|
|
"SSH_HostKeys",
|
|
|
|
"Cloud",
|
|
|
|
"Userspace",
|
|
|
|
"UserspaceRouter",
|
2023-06-16 17:04:07 +00:00
|
|
|
"Location",
|
2020-02-25 22:05:17 +00:00
|
|
|
}
|
2020-02-18 03:33:01 +00:00
|
|
|
if have := fieldsOf(reflect.TypeOf(Hostinfo{})); !reflect.DeepEqual(have, hiHandles) {
|
|
|
|
t.Errorf("Hostinfo.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
|
|
|
|
have, hiHandles)
|
|
|
|
}
|
|
|
|
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
nets := func(strs ...string) (ns []netip.Prefix) {
|
2020-02-18 03:33:01 +00:00
|
|
|
for _, s := range strs {
|
2022-07-26 03:55:44 +00:00
|
|
|
n, err := netip.ParsePrefix(s)
|
2020-02-18 03:33:01 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2020-03-17 03:27:00 +00:00
|
|
|
ns = append(ns, n)
|
2020-02-18 03:33:01 +00:00
|
|
|
}
|
|
|
|
return ns
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
a, b *Hostinfo
|
|
|
|
want bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
nil,
|
|
|
|
nil,
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{},
|
|
|
|
nil,
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
nil,
|
|
|
|
&Hostinfo{},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{},
|
|
|
|
&Hostinfo{},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
&Hostinfo{IPNVersion: "1"},
|
|
|
|
&Hostinfo{IPNVersion: "2"},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{IPNVersion: "2"},
|
|
|
|
&Hostinfo{IPNVersion: "2"},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
&Hostinfo{FrontendLogID: "1"},
|
|
|
|
&Hostinfo{FrontendLogID: "2"},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{FrontendLogID: "2"},
|
|
|
|
&Hostinfo{FrontendLogID: "2"},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
&Hostinfo{BackendLogID: "1"},
|
|
|
|
&Hostinfo{BackendLogID: "2"},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{BackendLogID: "2"},
|
|
|
|
&Hostinfo{BackendLogID: "2"},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
&Hostinfo{OS: "windows"},
|
|
|
|
&Hostinfo{OS: "linux"},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{OS: "windows"},
|
|
|
|
&Hostinfo{OS: "windows"},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
&Hostinfo{Hostname: "vega"},
|
|
|
|
&Hostinfo{Hostname: "iris"},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{Hostname: "vega"},
|
|
|
|
&Hostinfo{Hostname: "vega"},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
&Hostinfo{RoutableIPs: nil},
|
|
|
|
&Hostinfo{RoutableIPs: nets("10.0.0.0/16")},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.1.0/24")},
|
|
|
|
&Hostinfo{RoutableIPs: nets("10.2.0.0/16", "192.168.2.0/24")},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.1.0/24")},
|
|
|
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.2.0/24")},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.1.0/24")},
|
|
|
|
&Hostinfo{RoutableIPs: nets("10.1.0.0/16", "192.168.1.0/24")},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
|
2020-05-01 05:01:27 +00:00
|
|
|
{
|
|
|
|
&Hostinfo{RequestTags: []string{"abc", "def"}},
|
|
|
|
&Hostinfo{RequestTags: []string{"abc", "def"}},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{RequestTags: []string{"abc", "def"}},
|
|
|
|
&Hostinfo{RequestTags: []string{"abc", "123"}},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{RequestTags: []string{}},
|
|
|
|
&Hostinfo{RequestTags: []string{"abc"}},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
|
2020-02-18 03:33:01 +00:00
|
|
|
{
|
2021-04-01 16:54:54 +00:00
|
|
|
&Hostinfo{Services: []Service{{Proto: TCP, Port: 1234, Description: "foo"}}},
|
|
|
|
&Hostinfo{Services: []Service{{Proto: UDP, Port: 2345, Description: "bar"}}},
|
2020-02-18 03:33:01 +00:00
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
2021-04-01 16:54:54 +00:00
|
|
|
&Hostinfo{Services: []Service{{Proto: TCP, Port: 1234, Description: "foo"}}},
|
|
|
|
&Hostinfo{Services: []Service{{Proto: TCP, Port: 1234, Description: "foo"}}},
|
2020-02-18 03:33:01 +00:00
|
|
|
true,
|
|
|
|
},
|
2020-12-01 02:05:51 +00:00
|
|
|
{
|
|
|
|
&Hostinfo{ShareeNode: true},
|
|
|
|
&Hostinfo{},
|
|
|
|
false,
|
|
|
|
},
|
2022-02-17 23:00:41 +00:00
|
|
|
{
|
|
|
|
&Hostinfo{SSH_HostKeys: []string{"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO.... root@bar"}},
|
|
|
|
&Hostinfo{},
|
|
|
|
false,
|
|
|
|
},
|
2023-02-27 17:58:54 +00:00
|
|
|
{
|
|
|
|
&Hostinfo{App: "golink"},
|
|
|
|
&Hostinfo{App: "abc"},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{App: "golink"},
|
|
|
|
&Hostinfo{App: "golink"},
|
|
|
|
true,
|
|
|
|
},
|
2020-02-18 03:33:01 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-22 23:04:44 +00:00
|
|
|
func TestHostinfoHowEqual(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
a, b *Hostinfo
|
|
|
|
want []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
a: nil,
|
|
|
|
b: nil,
|
|
|
|
want: nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
a: new(Hostinfo),
|
|
|
|
b: nil,
|
|
|
|
want: []string{"nil"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
a: nil,
|
|
|
|
b: new(Hostinfo),
|
|
|
|
want: []string{"nil"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
a: new(Hostinfo),
|
|
|
|
b: new(Hostinfo),
|
|
|
|
want: nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
a: &Hostinfo{
|
|
|
|
IPNVersion: "1",
|
|
|
|
ShieldsUp: false,
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("1.2.3.0/24")},
|
2021-12-22 23:04:44 +00:00
|
|
|
},
|
|
|
|
b: &Hostinfo{
|
|
|
|
IPNVersion: "2",
|
|
|
|
ShieldsUp: true,
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("1.2.3.0/25")},
|
2021-12-22 23:04:44 +00:00
|
|
|
},
|
|
|
|
want: []string{"IPNVersion", "ShieldsUp", "RoutableIPs"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
a: &Hostinfo{
|
|
|
|
IPNVersion: "1",
|
|
|
|
},
|
|
|
|
b: &Hostinfo{
|
|
|
|
IPNVersion: "2",
|
|
|
|
NetInfo: new(NetInfo),
|
|
|
|
},
|
|
|
|
want: []string{"IPNVersion", "NetInfo.nil"},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
a: &Hostinfo{
|
|
|
|
IPNVersion: "1",
|
|
|
|
NetInfo: &NetInfo{
|
|
|
|
WorkingIPv6: "true",
|
|
|
|
HavePortMap: true,
|
|
|
|
LinkType: "foo",
|
|
|
|
PreferredDERP: 123,
|
|
|
|
DERPLatency: map[string]float64{
|
|
|
|
"foo": 1.0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
b: &Hostinfo{
|
|
|
|
IPNVersion: "2",
|
|
|
|
NetInfo: &NetInfo{},
|
|
|
|
},
|
|
|
|
want: []string{"IPNVersion", "NetInfo.WorkingIPv6", "NetInfo.HavePortMap", "NetInfo.PreferredDERP", "NetInfo.LinkType", "NetInfo.DERPLatency"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for i, tt := range tests {
|
|
|
|
got := tt.a.HowUnequal(tt.b)
|
|
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
|
|
t.Errorf("%d. got %q; want %q", i, got, tt.want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-07 18:50:08 +00:00
|
|
|
func TestHostinfoTailscaleSSHEnabled(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
hi *Hostinfo
|
|
|
|
want bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
nil,
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Hostinfo{SSH_HostKeys: []string{"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO.... root@bar"}},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, tt := range tests {
|
|
|
|
got := tt.hi.TailscaleSSHEnabled()
|
|
|
|
if got != tt.want {
|
|
|
|
t.Errorf("%d. got %v; want %v", i, got, tt.want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-16 06:23:58 +00:00
|
|
|
func TestNodeEqual(t *testing.T) {
|
2021-01-05 21:52:33 +00:00
|
|
|
nodeHandles := []string{
|
2021-01-27 16:50:31 +00:00
|
|
|
"ID", "StableID", "Name", "User", "Sharer",
|
2022-08-12 19:34:25 +00:00
|
|
|
"Key", "KeyExpiry", "KeySignature", "Machine", "DiscoKey",
|
2021-01-05 21:52:33 +00:00
|
|
|
"Addresses", "AllowedIPs", "Endpoints", "DERP", "Hostinfo",
|
2023-01-19 20:40:58 +00:00
|
|
|
"Created", "Cap", "Tags", "PrimaryRoutes",
|
2023-07-08 04:29:54 +00:00
|
|
|
"LastSeen", "Online", "MachineAuthorized",
|
2023-09-18 15:52:22 +00:00
|
|
|
"Capabilities", "CapMap",
|
2022-11-02 20:13:26 +00:00
|
|
|
"UnsignedPeerAPIOnly",
|
2021-01-27 16:50:31 +00:00
|
|
|
"ComputedName", "computedHostIfDifferent", "ComputedNameWithHost",
|
2023-03-03 00:05:07 +00:00
|
|
|
"DataPlaneAuditLogID", "Expired", "SelfNodeV4MasqAddrForThisPeer",
|
2023-09-19 00:03:53 +00:00
|
|
|
"SelfNodeV6MasqAddrForThisPeer", "IsWireGuardOnly", "ExitNodeDNSResolvers",
|
2021-01-05 21:52:33 +00:00
|
|
|
}
|
2020-02-16 06:23:58 +00:00
|
|
|
if have := fieldsOf(reflect.TypeOf(Node{})); !reflect.DeepEqual(have, nodeHandles) {
|
|
|
|
t.Errorf("Node.Equal check might be out of sync\nfields: %q\nhandled: %q\n",
|
|
|
|
have, nodeHandles)
|
|
|
|
}
|
|
|
|
|
2021-10-28 17:39:56 +00:00
|
|
|
n1 := key.NewNode().Public()
|
2021-09-03 20:17:46 +00:00
|
|
|
m1 := key.NewMachine().Public()
|
2020-02-16 06:23:58 +00:00
|
|
|
now := time.Now()
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
a, b *Node
|
|
|
|
want bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
&Node{},
|
|
|
|
nil,
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
nil,
|
|
|
|
&Node{},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{},
|
|
|
|
&Node{},
|
|
|
|
true,
|
2021-01-21 02:34:50 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{},
|
|
|
|
&Node{},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{ID: 1},
|
|
|
|
&Node{},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{ID: 1},
|
|
|
|
&Node{ID: 1},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{StableID: "node-abcd"},
|
|
|
|
&Node{},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{StableID: "node-abcd"},
|
|
|
|
&Node{StableID: "node-abcd"},
|
|
|
|
true,
|
2020-02-16 06:23:58 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{User: 0},
|
|
|
|
&Node{User: 1},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{User: 1},
|
|
|
|
&Node{User: 1},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
2021-11-02 03:55:52 +00:00
|
|
|
&Node{Key: n1},
|
|
|
|
&Node{Key: key.NewNode().Public()},
|
2020-02-16 06:23:58 +00:00
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
2021-11-02 03:55:52 +00:00
|
|
|
&Node{Key: n1},
|
|
|
|
&Node{Key: n1},
|
2020-02-16 06:23:58 +00:00
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{KeyExpiry: now},
|
|
|
|
&Node{KeyExpiry: now.Add(60 * time.Second)},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{KeyExpiry: now},
|
|
|
|
&Node{KeyExpiry: now},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
2021-09-03 20:17:46 +00:00
|
|
|
&Node{Machine: m1},
|
|
|
|
&Node{Machine: key.NewMachine().Public()},
|
2020-02-16 06:23:58 +00:00
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
2021-09-03 20:17:46 +00:00
|
|
|
&Node{Machine: m1},
|
|
|
|
&Node{Machine: m1},
|
2020-02-16 06:23:58 +00:00
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
&Node{Addresses: []netip.Prefix{}},
|
2020-02-16 06:23:58 +00:00
|
|
|
&Node{Addresses: nil},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
&Node{Addresses: []netip.Prefix{}},
|
|
|
|
&Node{Addresses: []netip.Prefix{}},
|
2020-02-16 06:23:58 +00:00
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
&Node{AllowedIPs: []netip.Prefix{}},
|
2020-02-16 06:23:58 +00:00
|
|
|
&Node{AllowedIPs: nil},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
&Node{Addresses: []netip.Prefix{}},
|
|
|
|
&Node{Addresses: []netip.Prefix{}},
|
2020-02-16 06:23:58 +00:00
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
2023-10-01 04:05:02 +00:00
|
|
|
&Node{Endpoints: []netip.AddrPort{}},
|
2020-02-16 06:23:58 +00:00
|
|
|
&Node{Endpoints: nil},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
2023-10-01 04:05:02 +00:00
|
|
|
&Node{Endpoints: []netip.AddrPort{}},
|
|
|
|
&Node{Endpoints: []netip.AddrPort{}},
|
2020-02-16 06:23:58 +00:00
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
2022-02-15 16:19:44 +00:00
|
|
|
&Node{Hostinfo: (&Hostinfo{Hostname: "alice"}).View()},
|
|
|
|
&Node{Hostinfo: (&Hostinfo{Hostname: "bob"}).View()},
|
2020-02-16 06:23:58 +00:00
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
2022-02-15 16:19:44 +00:00
|
|
|
&Node{Hostinfo: (&Hostinfo{}).View()},
|
|
|
|
&Node{Hostinfo: (&Hostinfo{}).View()},
|
2020-02-16 06:23:58 +00:00
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{Created: now},
|
|
|
|
&Node{Created: now.Add(60 * time.Second)},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{Created: now},
|
|
|
|
&Node{Created: now},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{LastSeen: &now},
|
|
|
|
&Node{LastSeen: nil},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{LastSeen: &now},
|
|
|
|
&Node{LastSeen: &now},
|
|
|
|
true,
|
|
|
|
},
|
2020-08-11 02:45:20 +00:00
|
|
|
{
|
|
|
|
&Node{DERP: "foo"},
|
|
|
|
&Node{DERP: "bar"},
|
|
|
|
false,
|
|
|
|
},
|
2021-10-20 21:26:31 +00:00
|
|
|
{
|
|
|
|
&Node{Tags: []string{"tag:foo"}},
|
|
|
|
&Node{Tags: []string{"tag:foo"}},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{Tags: []string{"tag:foo", "tag:bar"}},
|
|
|
|
&Node{Tags: []string{"tag:bar"}},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{Tags: []string{"tag:foo"}},
|
|
|
|
&Node{Tags: []string{"tag:bar"}},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{Tags: []string{"tag:foo"}},
|
|
|
|
&Node{},
|
|
|
|
false,
|
|
|
|
},
|
2023-01-10 17:55:43 +00:00
|
|
|
{
|
|
|
|
&Node{Expired: true},
|
|
|
|
&Node{},
|
|
|
|
false,
|
|
|
|
},
|
2023-03-03 00:05:07 +00:00
|
|
|
{
|
|
|
|
&Node{},
|
2023-04-13 17:12:31 +00:00
|
|
|
&Node{SelfNodeV4MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("100.64.0.1"))},
|
2023-03-03 00:05:07 +00:00
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
2023-04-13 17:12:31 +00:00
|
|
|
&Node{SelfNodeV4MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("100.64.0.1"))},
|
|
|
|
&Node{SelfNodeV4MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("100.64.0.1"))},
|
2023-03-03 00:05:07 +00:00
|
|
|
true,
|
|
|
|
},
|
2023-09-19 00:03:53 +00:00
|
|
|
{
|
|
|
|
&Node{},
|
|
|
|
&Node{SelfNodeV6MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("2001::3456"))},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{SelfNodeV6MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("2001::3456"))},
|
|
|
|
&Node{SelfNodeV6MasqAddrForThisPeer: ptr.To(netip.MustParseAddr("2001::3456"))},
|
|
|
|
true,
|
|
|
|
},
|
2023-09-18 15:52:22 +00:00
|
|
|
{
|
|
|
|
&Node{
|
|
|
|
CapMap: NodeCapMap{
|
|
|
|
"foo": []RawMessage{`"foo"`},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
&Node{
|
|
|
|
CapMap: NodeCapMap{
|
|
|
|
"foo": []RawMessage{`"foo"`},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{
|
|
|
|
CapMap: NodeCapMap{
|
|
|
|
"bar": []RawMessage{`"foo"`},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
&Node{
|
|
|
|
CapMap: NodeCapMap{
|
|
|
|
"foo": []RawMessage{`"bar"`},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
&Node{
|
|
|
|
CapMap: NodeCapMap{
|
|
|
|
"foo": nil,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
&Node{
|
|
|
|
CapMap: NodeCapMap{
|
|
|
|
"foo": []RawMessage{`"bar"`},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
false,
|
|
|
|
},
|
2020-02-16 06:23:58 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-04 06:21:56 +00:00
|
|
|
|
|
|
|
func TestNetInfoFields(t *testing.T) {
|
|
|
|
handled := []string{
|
|
|
|
"MappingVariesByDestIP",
|
|
|
|
"HairPinning",
|
|
|
|
"WorkingIPv6",
|
2022-07-18 23:56:10 +00:00
|
|
|
"OSHasIPv6",
|
2020-03-04 06:21:56 +00:00
|
|
|
"WorkingUDP",
|
2022-08-04 21:10:13 +00:00
|
|
|
"WorkingICMPv4",
|
2021-03-09 23:09:10 +00:00
|
|
|
"HavePortMap",
|
2020-07-06 20:51:17 +00:00
|
|
|
"UPnP",
|
|
|
|
"PMP",
|
|
|
|
"PCP",
|
2020-03-04 06:21:56 +00:00
|
|
|
"PreferredDERP",
|
|
|
|
"LinkType",
|
|
|
|
"DERPLatency",
|
2023-08-15 21:52:04 +00:00
|
|
|
"FirewallMode",
|
2020-03-04 06:21:56 +00:00
|
|
|
}
|
|
|
|
if have := fieldsOf(reflect.TypeOf(NetInfo{})); !reflect.DeepEqual(have, handled) {
|
|
|
|
t.Errorf("NetInfo.Clone/BasicallyEqually check might be out of sync\nfields: %q\nhandled: %q\n",
|
|
|
|
have, handled)
|
|
|
|
}
|
|
|
|
}
|
2020-06-19 02:32:55 +00:00
|
|
|
|
|
|
|
type keyIn interface {
|
|
|
|
String() string
|
|
|
|
MarshalText() ([]byte, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
func testKey(t *testing.T, prefix string, in keyIn, out encoding.TextUnmarshaler) {
|
|
|
|
got, err := in.MarshalText()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if err := out.UnmarshalText(got); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if s := in.String(); string(got) != s {
|
|
|
|
t.Errorf("MarshalText = %q != String %q", got, s)
|
|
|
|
}
|
|
|
|
if !strings.HasPrefix(string(got), prefix) {
|
|
|
|
t.Errorf("%q didn't start with prefix %q", got, prefix)
|
|
|
|
}
|
|
|
|
if reflect.ValueOf(out).Elem().Interface() != in {
|
|
|
|
t.Errorf("mismatch after unmarshal")
|
|
|
|
}
|
|
|
|
}
|
2020-07-27 17:40:34 +00:00
|
|
|
|
|
|
|
func TestCloneUser(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
u *User
|
|
|
|
}{
|
|
|
|
{"nil_logins", &User{}},
|
|
|
|
{"zero_logins", &User{Logins: make([]LoginID, 0)}},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
u2 := tt.u.Clone()
|
|
|
|
if !reflect.DeepEqual(tt.u, u2) {
|
|
|
|
t.Errorf("not equal")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCloneNode(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
v *Node
|
|
|
|
}{
|
|
|
|
{"nil_fields", &Node{}},
|
|
|
|
{"zero_fields", &Node{
|
all: convert more code to use net/netip directly
perl -i -npe 's,netaddr.IPPrefixFrom,netip.PrefixFrom,' $(git grep -l -F netaddr.)
perl -i -npe 's,netaddr.IPPortFrom,netip.AddrPortFrom,' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPrefix,netip.Prefix,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPPort,netip.AddrPort,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IP\b,netip.Addr,g' $(git grep -l -F netaddr. )
perl -i -npe 's,netaddr.IPv6Raw\b,netip.AddrFrom16,g' $(git grep -l -F netaddr. )
goimports -w .
Then delete some stuff from the net/netaddr shim package which is no
longer neeed.
Updates #5162
Change-Id: Ia7a86893fe21c7e3ee1ec823e8aba288d4566cd8
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2022-07-26 04:14:09 +00:00
|
|
|
Addresses: make([]netip.Prefix, 0),
|
|
|
|
AllowedIPs: make([]netip.Prefix, 0),
|
2023-10-01 04:05:02 +00:00
|
|
|
Endpoints: make([]netip.AddrPort, 0),
|
2020-07-27 17:40:34 +00:00
|
|
|
}},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
v2 := tt.v.Clone()
|
|
|
|
if !reflect.DeepEqual(tt.v, v2) {
|
|
|
|
t.Errorf("not equal")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2021-04-01 21:44:40 +00:00
|
|
|
|
|
|
|
func TestUserProfileJSONMarshalForMac(t *testing.T) {
|
|
|
|
// Old macOS clients had a bug where they required
|
|
|
|
// UserProfile.Roles to be non-null. Lock that in
|
|
|
|
// 1.0.x/1.2.x clients are gone in the wild.
|
|
|
|
// See mac commit 0242c08a2ca496958027db1208f44251bff8488b (Sep 30).
|
|
|
|
// It was fixed in at least 1.4.x, and perhaps 1.2.x.
|
|
|
|
j, err := json.Marshal(UserProfile{})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
const wantSub = `"Roles":[]`
|
|
|
|
if !strings.Contains(string(j), wantSub) {
|
|
|
|
t.Fatalf("didn't contain %#q; got: %s", wantSub, j)
|
|
|
|
}
|
|
|
|
|
|
|
|
// And back:
|
|
|
|
var up UserProfile
|
|
|
|
if err := json.Unmarshal(j, &up); err != nil {
|
|
|
|
t.Fatalf("Unmarshal: %v", err)
|
|
|
|
}
|
|
|
|
}
|
tailcfg: add Endpoint, EndpointType, MapRequest.EndpointType
Track endpoints internally with a new tailcfg.Endpoint type that
includes a typed netaddr.IPPort (instead of just a string) and
includes a type for how that endpoint was discovered (STUN, local,
etc).
Use []tailcfg.Endpoint instead of []string internally.
At the last second, send it to the control server as the existing
[]string for endpoints, but also include a new parallel
MapRequest.EndpointType []tailcfg.EndpointType, so the control server
can start filtering out less-important endpoint changes from
new-enough clients. Notably, STUN-discovered endpoints can be filtered
out from 1.6+ clients, as they can discover them amongst each other
via CallMeMaybe disco exchanges started over DERP. And STUN endpoints
change a lot, causing a lot of MapResposne updates. But portmapped
endpoints are worth keeping for now, as they they work right away
without requiring the firewall traversal extra RTT dance.
End result will be less control->client bandwidth. (despite negligible
increase in client->control bandwidth)
Updates tailscale/corp#1543
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
2021-04-12 20:24:29 +00:00
|
|
|
|
|
|
|
func TestEndpointTypeMarshal(t *testing.T) {
|
|
|
|
eps := []EndpointType{
|
|
|
|
EndpointUnknownType,
|
|
|
|
EndpointLocal,
|
|
|
|
EndpointSTUN,
|
|
|
|
EndpointPortmapped,
|
|
|
|
EndpointSTUN4LocalPort,
|
|
|
|
}
|
|
|
|
got, err := json.Marshal(eps)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
const want = `[0,1,2,3,4]`
|
|
|
|
if string(got) != want {
|
|
|
|
t.Errorf("got %s; want %s", got, want)
|
|
|
|
}
|
|
|
|
}
|
2021-05-08 00:01:44 +00:00
|
|
|
|
2021-09-14 16:00:04 +00:00
|
|
|
func TestRegisterRequestNilClone(t *testing.T) {
|
|
|
|
var nilReq *RegisterRequest
|
|
|
|
got := nilReq.Clone()
|
|
|
|
if got != nil {
|
|
|
|
t.Errorf("got = %v; want nil", got)
|
|
|
|
}
|
|
|
|
}
|
2022-08-11 16:24:07 +00:00
|
|
|
|
|
|
|
// Tests that CurrentCapabilityVersion is bumped when the comment block above it gets bumped.
|
|
|
|
// We've screwed this up several times.
|
|
|
|
func TestCurrentCapabilityVersion(t *testing.T) {
|
|
|
|
f := must.Get(os.ReadFile("tailcfg.go"))
|
2022-09-08 04:57:16 +00:00
|
|
|
matches := regexp.MustCompile(`(?m)^//[\s-]+(\d+): \d\d\d\d-\d\d-\d\d: `).FindAllStringSubmatch(string(f), -1)
|
2022-08-11 16:24:07 +00:00
|
|
|
max := 0
|
|
|
|
for _, m := range matches {
|
|
|
|
n := must.Get(strconv.Atoi(m[1]))
|
|
|
|
if n > max {
|
|
|
|
max = n
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if CapabilityVersion(max) != CurrentCapabilityVersion {
|
|
|
|
t.Errorf("CurrentCapabilityVersion = %d; want %d", CurrentCapabilityVersion, max)
|
|
|
|
}
|
|
|
|
}
|
2023-09-09 20:52:28 +00:00
|
|
|
|
|
|
|
func TestUnmarshalHealth(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
in string // MapResponse JSON
|
|
|
|
want []string // MapResponse.Health wanted value post-unmarshal
|
|
|
|
}{
|
|
|
|
{in: `{}`},
|
|
|
|
{in: `{"Health":null}`},
|
|
|
|
{in: `{"Health":[]}`, want: []string{}},
|
|
|
|
{in: `{"Health":["bad"]}`, want: []string{"bad"}},
|
|
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
|
|
var mr MapResponse
|
|
|
|
if err := json.Unmarshal([]byte(tt.in), &mr); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(mr.Health, tt.want) {
|
|
|
|
t.Errorf("for %#q: got %v; want %v", tt.in, mr.Health, tt.want)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-18 16:40:14 +00:00
|
|
|
|
|
|
|
func TestRawMessage(t *testing.T) {
|
|
|
|
// Create a few types of json.RawMessages and then marshal them back and
|
|
|
|
// forth to make sure they round-trip.
|
|
|
|
|
|
|
|
type rule struct {
|
|
|
|
Ports []int `json:",omitempty"`
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
val map[string][]rule
|
|
|
|
wire map[string][]RawMessage
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "nil",
|
|
|
|
val: nil,
|
|
|
|
wire: nil,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "empty",
|
|
|
|
val: map[string][]rule{},
|
|
|
|
wire: map[string][]RawMessage{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "one",
|
|
|
|
val: map[string][]rule{
|
|
|
|
"foo": {{Ports: []int{1, 2, 3}}},
|
|
|
|
},
|
|
|
|
wire: map[string][]RawMessage{
|
|
|
|
"foo": {
|
|
|
|
`{"Ports":[1,2,3]}`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "many",
|
|
|
|
val: map[string][]rule{
|
|
|
|
"foo": {{Ports: []int{1, 2, 3}}},
|
|
|
|
"bar": {{Ports: []int{4, 5, 6}}, {Ports: []int{7, 8, 9}}},
|
|
|
|
"baz": nil,
|
|
|
|
"abc": {},
|
|
|
|
"def": {{}},
|
|
|
|
},
|
|
|
|
wire: map[string][]RawMessage{
|
|
|
|
"foo": {
|
|
|
|
`{"Ports":[1,2,3]}`,
|
|
|
|
},
|
|
|
|
"bar": {
|
|
|
|
`{"Ports":[4,5,6]}`,
|
|
|
|
`{"Ports":[7,8,9]}`,
|
|
|
|
},
|
|
|
|
"baz": nil,
|
|
|
|
"abc": {},
|
|
|
|
"def": {"{}"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
j := must.Get(json.Marshal(tc.val))
|
|
|
|
var gotWire map[string][]RawMessage
|
|
|
|
if err := json.Unmarshal(j, &gotWire); err != nil {
|
|
|
|
t.Fatalf("unmarshal: %v", err)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(gotWire, tc.wire) {
|
|
|
|
t.Errorf("got %#v; want %#v", gotWire, tc.wire)
|
|
|
|
}
|
|
|
|
|
|
|
|
j = must.Get(json.Marshal(tc.wire))
|
|
|
|
var gotVal map[string][]rule
|
|
|
|
if err := json.Unmarshal(j, &gotVal); err != nil {
|
|
|
|
t.Fatalf("unmarshal: %v", err)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(gotVal, tc.val) {
|
|
|
|
t.Errorf("got %#v; want %#v", gotVal, tc.val)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|