diff --git a/tstest/integration/nat/nat_test.go b/tstest/integration/nat/nat_test.go index 2c08d5d4f..45783aa75 100644 --- a/tstest/integration/nat/nat_test.go +++ b/tstest/integration/nat/nat_test.go @@ -1,6 +1,8 @@ package nat import ( + "bytes" + "cmp" "context" "encoding/json" "errors" @@ -23,6 +25,7 @@ "golang.org/x/sync/errgroup" "tailscale.com/client/tailscale" "tailscale.com/ipn/ipnstate" + "tailscale.com/syncs" "tailscale.com/tailcfg" "tailscale.com/tstest/natlab/vnet" ) @@ -121,7 +124,7 @@ func hardPMP(c *vnet.Config) *vnet.Node { fmt.Sprintf("10.7.%d.1/24", n), vnet.HardNAT, vnet.NATPMP)) } -func (nt *natTest) runTest(node1, node2 addNodeFunc) { +func (nt *natTest) runTest(node1, node2 addNodeFunc) pingRoute { t := nt.tb var c vnet.Config @@ -252,6 +255,7 @@ func (nt *natTest) runTest(node1, node2 addNodeFunc) { } route := classifyPing(pingRes) t.Logf("ping route: %v", route) + return route } func classifyPing(pr *ipnstate.PingResult) pingRoute { @@ -395,3 +399,88 @@ func TestHardOne2One(t *testing.T) { nt := newNatTest(t) nt.runTest(hard, one2one) } + +func TestGrid(t *testing.T) { + t.Parallel() + + type nodeType struct { + name string + fn addNodeFunc + } + types := []nodeType{ + {"easy", easy}, + {"hard", hard}, + {"easyPMP", easyPMP}, + {"hardPMP", hardPMP}, + {"one2one", one2one}, + } + + sem := syncs.NewSemaphore(2) + var ( + mu sync.Mutex + res = make(map[string]pingRoute) + ) + for i, a := range types { + for _, b := range types[i:] { + key := a.name + "-" + b.name + t.Run(key, func(t *testing.T) { + t.Parallel() + + sem.Acquire() + defer sem.Release() + + filename := key + ".cache" + contents, _ := os.ReadFile(filename) + route := pingRoute(strings.TrimSpace(string(contents))) + + if route == "" { + nt := newNatTest(t) + route = nt.runTest(a.fn, b.fn) + if err := os.WriteFile(filename, []byte(string(route)), 0666); err != nil { + t.Fatalf("writeFile: %v", err) + } + } + + mu.Lock() + defer mu.Unlock() + res[key] = route + t.Logf("results: %v", res) + }) + } + } + + t.Cleanup(func() { + mu.Lock() + defer mu.Unlock() + var hb bytes.Buffer + pf := func(format string, args ...interface{}) { + fmt.Fprintf(&hb, format, args...) + } + pf("") + pf("") + for _, a := range types { + pf("", a.name) + } + pf("\n") + + for _, a := range types { + pf("", a.name) + for _, b := range types { + key := a.name + "-" + b.name + key2 := b.name + "-" + a.name + v := cmp.Or(res[key], res[key2]) + if v == "derp" { + pf("", v) + } else { + pf("", v) + } + } + pf("\n") + } + pf("
%s
%s
%s
%s
") + + if err := os.WriteFile("grid.html", hb.Bytes(), 0666); err != nil { + t.Fatalf("writeFile: %v", err) + } + }) +}