all: use testingutil.MinAllocsPerRun

There are a few remaining uses of testing.AllocsPerRun:
Two in which we only log the number of allocations,
and one in which dynamically calculate the allocations
target based on a different AllocsPerRun run.

This also allows us to tighten the "no allocs"
test in wgengine/filter.

Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This commit is contained in:
Josh Bleecher Snyder 2021-10-27 16:21:44 -07:00 committed by Josh Bleecher Snyder
parent 1df865a580
commit 94fb42d4b2
11 changed files with 63 additions and 58 deletions

View File

@ -14,6 +14,8 @@
"strings" "strings"
"testing" "testing"
"time" "time"
"tailscale.com/tstest"
) )
func TestFastShutdown(t *testing.T) { func TestFastShutdown(t *testing.T) {
@ -213,11 +215,11 @@ func TestEncodeSpecialCases(t *testing.T) {
func TestLoggerEncodeTextAllocs(t *testing.T) { func TestLoggerEncodeTextAllocs(t *testing.T) {
lg := &Logger{timeNow: time.Now} lg := &Logger{timeNow: time.Now}
inBuf := []byte("some text to encode") inBuf := []byte("some text to encode")
n := testing.AllocsPerRun(1000, func() { err := tstest.MinAllocsPerRun(t, 1, func() {
sink = lg.encodeText(inBuf, false) sink = lg.encodeText(inBuf, false)
}) })
if int(n) != 1 { if err != nil {
t.Logf("allocs = %d; want 1", int(n)) t.Fatal(err)
} }
} }
@ -298,15 +300,14 @@ func TestPublicIDUnmarshalText(t *testing.T) {
if id.String() != hexStr { if id.String() != hexStr {
t.Errorf("String = %q; want %q", id.String(), hexStr) t.Errorf("String = %q; want %q", id.String(), hexStr)
} }
err := tstest.MinAllocsPerRun(t, 0, func() {
n := int(testing.AllocsPerRun(1000, func() {
var id PublicID var id PublicID
if err := id.UnmarshalText(x); err != nil { if err := id.UnmarshalText(x); err != nil {
t.Fatal(err) t.Fatal(err)
} }
})) })
if n != 0 { if err != nil {
t.Errorf("allocs = %v; want 0", n) t.Fatal(err)
} }
} }

View File

@ -8,6 +8,8 @@
"os" "os"
"runtime" "runtime"
"testing" "testing"
"tailscale.com/tstest"
) )
func TestCurrentFileDescriptors(t *testing.T) { func TestCurrentFileDescriptors(t *testing.T) {
@ -19,11 +21,11 @@ func TestCurrentFileDescriptors(t *testing.T) {
t.Fatalf("got %v; want >= 3", n) t.Fatalf("got %v; want >= 3", n)
} }
allocs := int(testing.AllocsPerRun(100, func() { err := tstest.MinAllocsPerRun(t, 0, func() {
n = CurrentFDs() n = CurrentFDs()
})) })
if allocs != 0 { if err != nil {
t.Errorf("allocs = %v; want 0", allocs) t.Fatal(err)
} }
// Open some FDs. // Open some FDs.

View File

@ -952,7 +952,7 @@ func TestAllocs(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
query []byte query []byte
want int want uint64
}{ }{
// Name lowercasing, response slice created by dns.NewBuilder, // Name lowercasing, response slice created by dns.NewBuilder,
// and closure allocation from go call. // and closure allocation from go call.
@ -964,11 +964,11 @@ func TestAllocs(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
allocs := testing.AllocsPerRun(100, func() { err := tstest.MinAllocsPerRun(t, tt.want, func() {
syncRespond(r, tt.query) syncRespond(r, tt.query)
}) })
if int(allocs) > tt.want { if err != nil {
t.Errorf("%s: allocs = %v; want %v", tt.name, allocs, tt.want) t.Errorf("%s: %v", tt.name, err)
} }
} }
} }

View File

@ -8,6 +8,7 @@
"testing" "testing"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/tstest"
) )
func TestCache(t *testing.T) { func TestCache(t *testing.T) {
@ -67,7 +68,7 @@ func TestCache(t *testing.T) {
wantVal(k3, 30) wantVal(k3, 30)
wantLen(1) wantLen(1)
allocs := int(testing.AllocsPerRun(1000, func() { err := tstest.MinAllocsPerRun(t, 0, func() {
got, ok := c.Get(k3) got, ok := c.Get(k3)
if !ok { if !ok {
t.Fatal("missing k3") t.Fatal("missing k3")
@ -75,8 +76,8 @@ func TestCache(t *testing.T) {
if got != 30 { if got != 30 {
t.Fatalf("got = %d; want 30", got) t.Fatalf("got = %d; want 30", got)
} }
})) })
if allocs != 0 { if err != nil {
t.Errorf("allocs = %v; want 0", allocs) t.Error(err)
} }
} }

View File

@ -10,6 +10,7 @@
"testing" "testing"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/tstest"
"tailscale.com/types/ipproto" "tailscale.com/types/ipproto"
) )
@ -378,11 +379,11 @@ func TestParsedString(t *testing.T) {
}) })
} }
allocs := testing.AllocsPerRun(1000, func() { err := tstest.MinAllocsPerRun(t, 1, func() {
sinkString = tests[0].qdecode.String() sinkString = tests[0].qdecode.String()
}) })
if allocs != 1 { if err != nil {
t.Errorf("allocs = %v; want 1", allocs) t.Error(err)
} }
} }
@ -415,12 +416,12 @@ func TestDecode(t *testing.T) {
}) })
} }
allocs := testing.AllocsPerRun(1000, func() { err := tstest.MinAllocsPerRun(t, 0, func() {
var got Parsed var got Parsed
got.Decode(tests[0].buf) got.Decode(tests[0].buf)
}) })
if allocs != 0 { if err != nil {
t.Errorf("allocs = %v; want 0", allocs) t.Error(err)
} }
} }

View File

@ -370,7 +370,7 @@ func TestAllocs(t *testing.T) {
defer tun.Close() defer tun.Close()
buf := []byte{0x00} buf := []byte{0x00}
allocs := testing.AllocsPerRun(100, func() { err := tstest.MinAllocsPerRun(t, 0, func() {
_, err := ftun.Write(buf, 0) _, err := ftun.Write(buf, 0)
if err != nil { if err != nil {
t.Errorf("write: error: %v", err) t.Errorf("write: error: %v", err)
@ -378,8 +378,8 @@ func TestAllocs(t *testing.T) {
} }
}) })
if allocs > 0 { if err != nil {
t.Errorf("read allocs = %v; want 0", allocs) t.Error(err)
} }
} }

View File

@ -13,6 +13,7 @@
"time" "time"
"inet.af/netaddr" "inet.af/netaddr"
"tailscale.com/tstest"
"tailscale.com/types/key" "tailscale.com/types/key"
"tailscale.com/version" "tailscale.com/version"
) )
@ -541,11 +542,11 @@ func TestAppendKeyAllocs(t *testing.T) {
t.Skip("skipping in race detector") // append(b, make([]byte, N)...) not optimized in compiler with race t.Skip("skipping in race detector") // append(b, make([]byte, N)...) not optimized in compiler with race
} }
var k [32]byte var k [32]byte
n := int(testing.AllocsPerRun(1000, func() { err := tstest.MinAllocsPerRun(t, 1, func() {
sinkBytes = keyMarshalText("prefix", k) sinkBytes = keyMarshalText("prefix", k)
})) })
if n != 1 { if err != nil {
t.Fatalf("allocs = %v; want 1", n) t.Fatal(err)
} }
} }

View File

@ -8,6 +8,8 @@
"bytes" "bytes"
"encoding/json" "encoding/json"
"testing" "testing"
"tailscale.com/tstest"
) )
func TestKeyBasics(t *testing.T) { func TestKeyBasics(t *testing.T) {
@ -134,12 +136,11 @@ func TestPrivateKeyBasics(t *testing.T) {
func TestMarshalJSONAllocs(t *testing.T) { func TestMarshalJSONAllocs(t *testing.T) {
var k Key var k Key
f := testing.AllocsPerRun(100, func() { err := tstest.MinAllocsPerRun(t, 1, func() {
k.MarshalJSON() k.MarshalJSON()
}) })
n := int(f) if err != nil {
if n != 1 { t.Fatal(err)
t.Fatalf("max one alloc per Key.MarshalJSON, got %d", n)
} }
} }

View File

@ -8,6 +8,7 @@
"testing" "testing"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"tailscale.com/tstest"
) )
func TestParse(t *testing.T) { func TestParse(t *testing.T) {
@ -39,11 +40,11 @@ func TestParse(t *testing.T) {
if diff := cmp.Diff(gotParsed, test.parsed); diff != "" { if diff := cmp.Diff(gotParsed, test.parsed); diff != "" {
t.Errorf("parse(%q) diff (-got+want):\n%s", test.version, diff) t.Errorf("parse(%q) diff (-got+want):\n%s", test.version, diff)
} }
n := int(testing.AllocsPerRun(1000, func() { err := tstest.MinAllocsPerRun(t, 0, func() {
gotParsed, got = parse(test.version) gotParsed, got = parse(test.version)
})) })
if n != 0 { if err != nil {
t.Errorf("parse(%q) allocs = %d; want 0", test.version, n) t.Errorf("parse(%q): %v", test.version, err)
} }
} }
} }

View File

@ -17,6 +17,7 @@
"tailscale.com/net/packet" "tailscale.com/net/packet"
"tailscale.com/net/tsaddr" "tailscale.com/net/tsaddr"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
"tailscale.com/tstest"
"tailscale.com/tstime/rate" "tailscale.com/tstime/rate"
"tailscale.com/types/ipproto" "tailscale.com/types/ipproto"
"tailscale.com/types/logger" "tailscale.com/types/logger"
@ -189,23 +190,21 @@ func TestNoAllocs(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
dir direction dir direction
want int
packet []byte packet []byte
}{ }{
{"tcp4_in", in, 0, tcp4Packet}, {"tcp4_in", in, tcp4Packet},
{"tcp6_in", in, 0, tcp6Packet}, {"tcp6_in", in, tcp6Packet},
{"tcp4_out", out, 0, tcp4Packet}, {"tcp4_out", out, tcp4Packet},
{"tcp6_out", out, 0, tcp6Packet}, {"tcp6_out", out, tcp6Packet},
{"udp4_in", in, 0, udp4Packet}, {"udp4_in", in, udp4Packet},
{"udp6_in", in, 0, udp6Packet}, {"udp6_in", in, udp6Packet},
// One alloc is inevitable (an lru cache update) {"udp4_out", out, udp4Packet},
{"udp4_out", out, 1, udp4Packet}, {"udp6_out", out, udp6Packet},
{"udp6_out", out, 1, udp6Packet},
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
got := int(testing.AllocsPerRun(1000, func() { err := tstest.MinAllocsPerRun(t, 0, func() {
q := &packet.Parsed{} q := &packet.Parsed{}
q.Decode(test.packet) q.Decode(test.packet)
switch test.dir { switch test.dir {
@ -214,10 +213,9 @@ func TestNoAllocs(t *testing.T) {
case out: case out:
acl.RunOut(q, 0) acl.RunOut(q, 0)
} }
})) })
if err != nil {
if got > test.want { t.Error(err)
t.Errorf("got %d allocs per run; want at most %d", got, test.want)
} }
}) })
} }

View File

@ -44,7 +44,6 @@
"tailscale.com/types/wgkey" "tailscale.com/types/wgkey"
"tailscale.com/util/cibuild" "tailscale.com/util/cibuild"
"tailscale.com/util/racebuild" "tailscale.com/util/racebuild"
"tailscale.com/util/testingutil"
"tailscale.com/wgengine/filter" "tailscale.com/wgengine/filter"
"tailscale.com/wgengine/wgcfg" "tailscale.com/wgengine/wgcfg"
"tailscale.com/wgengine/wgcfg/nmcfg" "tailscale.com/wgengine/wgcfg/nmcfg"
@ -1353,7 +1352,7 @@ func TestReceiveFromAllocs(t *testing.T) {
} }
t.Logf("allowing %d allocs for Go version %q", maxAllocs, runtime.Version()) t.Logf("allowing %d allocs for Go version %q", maxAllocs, runtime.Version())
roundTrip := setUpReceiveFrom(t) roundTrip := setUpReceiveFrom(t)
err := testingutil.MinAllocsPerRun(t, uint64(maxAllocs), roundTrip) err := tstest.MinAllocsPerRun(t, uint64(maxAllocs), roundTrip)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }