Change-Id: I41d1c2bf20ae6dfbb071020d9dc2b742e7995835
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2024-08-08 13:46:55 -07:00
parent 0bff2dfa56
commit 9cfc83982f

View File

@ -1,6 +1,8 @@
package nat package nat
import ( import (
"bytes"
"cmp"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
@ -23,6 +25,7 @@
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
"tailscale.com/client/tailscale" "tailscale.com/client/tailscale"
"tailscale.com/ipn/ipnstate" "tailscale.com/ipn/ipnstate"
"tailscale.com/syncs"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/tstest/natlab/vnet" "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)) 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 t := nt.tb
var c vnet.Config var c vnet.Config
@ -252,6 +255,7 @@ func (nt *natTest) runTest(node1, node2 addNodeFunc) {
} }
route := classifyPing(pingRes) route := classifyPing(pingRes)
t.Logf("ping route: %v", route) t.Logf("ping route: %v", route)
return route
} }
func classifyPing(pr *ipnstate.PingResult) pingRoute { func classifyPing(pr *ipnstate.PingResult) pingRoute {
@ -395,3 +399,88 @@ func TestHardOne2One(t *testing.T) {
nt := newNatTest(t) nt := newNatTest(t)
nt.runTest(hard, one2one) 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("<html><table border=1 cellpadding=5>")
pf("<tr><td></td>")
for _, a := range types {
pf("<td><b>%s</b></td>", a.name)
}
pf("</tr>\n")
for _, a := range types {
pf("<tr><td><b>%s</b></td>", 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("<td><div style='color: red; font-weight: bold'>%s</div></td>", v)
} else {
pf("<td>%s</td>", v)
}
}
pf("</tr>\n")
}
pf("</table></html>")
if err := os.WriteFile("grid.html", hb.Bytes(), 0666); err != nil {
t.Fatalf("writeFile: %v", err)
}
})
}