mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-25 14:56:25 -04:00
tstest, util/testenv: drop tstest's dependency on the testing package
Change tstest's exported functions (AssertNotParallel, Replace, Parallel, RequireRoot, SkipOnKernelVersions, MinAllocsPerRun, FixLogs, UnfixLogs, CheckIsZero, ResourceCheck) to take testenv.TB instead of testing.TB or *testing.T, so importing tstest from non-test code no longer links the testing package and its flag registration side effects into the binary. Add testenv.Verbose to replace the one use of testing.Verbose, and a deptest check to keep testing out of tstest's dependency graph. Callers are unaffected: *testing.T and testing.TB both satisfy testenv.TB. Updates tailscale/corp#45223 Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com> Change-Id: Ib373ff66ceff638d071582baf8367245987e9155
This commit is contained in:
committed by
Brad Fitzpatrick
parent
d11757863d
commit
3ccc7725a3
@@ -6,8 +6,9 @@
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"tailscale.com/util/testenv"
|
||||
)
|
||||
|
||||
// MinAllocsPerRun asserts that f can run with no more than target allocations.
|
||||
@@ -16,7 +17,7 @@
|
||||
//
|
||||
// MinAllocsPerRun sets GOMAXPROCS to 1 during its measurement and restores
|
||||
// it before returning.
|
||||
func MinAllocsPerRun(t *testing.T, target uint64, f func()) error {
|
||||
func MinAllocsPerRun(t testenv.TB, target uint64, f func()) error {
|
||||
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
|
||||
|
||||
var memstats runtime.MemStats
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"go4.org/mem"
|
||||
"tailscale.com/types/logger"
|
||||
@@ -17,7 +16,7 @@
|
||||
)
|
||||
|
||||
type testLogWriter struct {
|
||||
t *testing.T
|
||||
t testenv.TB
|
||||
}
|
||||
|
||||
func (w *testLogWriter) Write(b []byte) (int, error) {
|
||||
@@ -26,12 +25,12 @@ func (w *testLogWriter) Write(b []byte) (int, error) {
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func FixLogs(t *testing.T) {
|
||||
func FixLogs(t testenv.TB) {
|
||||
log.SetFlags(log.Ltime | log.Lshortfile)
|
||||
log.SetOutput(&testLogWriter{t})
|
||||
}
|
||||
|
||||
func UnfixLogs(t *testing.T) {
|
||||
func UnfixLogs(t testenv.TB) {
|
||||
defer log.SetOutput(os.Stderr)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
import (
|
||||
"net/netip"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"tailscale.com/util/testenv"
|
||||
)
|
||||
|
||||
// IsZeroable is the interface for things with an IsZero method.
|
||||
@@ -30,7 +31,7 @@ type IsZeroable interface {
|
||||
// The nonzeroValues map should contain non-zero values for each type that
|
||||
// exists in the type T or any contained types. Basic types like string, bool,
|
||||
// and numeric types are handled automatically.
|
||||
func CheckIsZero[T IsZeroable](t testing.TB, nonzeroValues map[reflect.Type]any) {
|
||||
func CheckIsZero[T IsZeroable](t testenv.TB, nonzeroValues map[reflect.Type]any) {
|
||||
t.Helper()
|
||||
|
||||
var zero T
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
"runtime/pprof"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"tailscale.com/util/testenv"
|
||||
)
|
||||
|
||||
// ResourceCheck takes a snapshot of the current goroutines and registers a
|
||||
@@ -19,7 +20,7 @@
|
||||
// can look at specific routines).
|
||||
//
|
||||
// It panics if called from a parallel test.
|
||||
func ResourceCheck(tb testing.TB) {
|
||||
func ResourceCheck(tb testenv.TB) {
|
||||
tb.Helper()
|
||||
|
||||
// Set an environment variable (anything at all) just for the
|
||||
@@ -48,7 +49,7 @@ func ResourceCheck(tb testing.TB) {
|
||||
// Parse and print goroutines.
|
||||
start := parseGoroutines(startStacks)
|
||||
end := parseGoroutines(endStacks)
|
||||
if testing.Verbose() {
|
||||
if testenv.Verbose() {
|
||||
tb.Logf("goroutines start:\n%s", printGoroutines(start))
|
||||
tb.Logf("goroutines end:\n%s", printGoroutines(end))
|
||||
}
|
||||
|
||||
@@ -2,18 +2,23 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
// Package tstest provides utilities for use in unit tests.
|
||||
//
|
||||
// It intentionally does not depend on the "testing" package (using
|
||||
// [testenv.TB] instead of testing.TB) so that importing it from
|
||||
// non-test code doesn't link the testing package and its flag
|
||||
// registration side effects into the binary.
|
||||
package tstest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"tailscale.com/envknob"
|
||||
"tailscale.com/types/logger"
|
||||
"tailscale.com/util/backoff"
|
||||
"tailscale.com/util/testenv"
|
||||
)
|
||||
|
||||
// AssertNotParallel asserts that t has not been marked as parallel.
|
||||
@@ -21,7 +26,7 @@
|
||||
//
|
||||
// Use this when a test modifies package-level globals or other shared
|
||||
// state that would be unsafe to modify concurrently with other tests.
|
||||
func AssertNotParallel(t testing.TB) {
|
||||
func AssertNotParallel(t testenv.TB) {
|
||||
t.Helper()
|
||||
t.Setenv("ASSERT_NOT_PARALLEL_TEST", "1") // panics if t.Parallel was called
|
||||
}
|
||||
@@ -32,7 +37,7 @@ func AssertNotParallel(t testing.TB) {
|
||||
// When target is a package-level variable, the caller should also call
|
||||
// [AssertNotParallel] to ensure the test is not running in parallel with
|
||||
// other tests that may access the same variable.
|
||||
func Replace[T any](t testing.TB, target *T, val T) {
|
||||
func Replace[T any](t testenv.TB, target *T, val T) {
|
||||
t.Helper()
|
||||
if target == nil {
|
||||
t.Fatalf("Replace: nil pointer")
|
||||
@@ -66,14 +71,14 @@ func WaitFor(maxWait time.Duration, try func() error) error {
|
||||
var serializeParallel = envknob.RegisterBool("TS_SERIAL_TESTS")
|
||||
|
||||
// Parallel calls t.Parallel, unless TS_SERIAL_TESTS is set true.
|
||||
func Parallel(t *testing.T) {
|
||||
func Parallel(t interface{ Parallel() }) {
|
||||
if !serializeParallel() {
|
||||
t.Parallel()
|
||||
}
|
||||
}
|
||||
|
||||
// RequireRoot skips the test if the current user is not root.
|
||||
func RequireRoot(tb testing.TB) {
|
||||
func RequireRoot(tb testenv.TB) {
|
||||
tb.Helper()
|
||||
if os.Getuid() != 0 {
|
||||
tb.Skip("skipping test; requires root")
|
||||
@@ -82,7 +87,7 @@ func RequireRoot(tb testing.TB) {
|
||||
|
||||
// SkipOnKernelVersions skips the test if the current
|
||||
// kernel version is in the specified list.
|
||||
func SkipOnKernelVersions(t testing.TB, issue string, versions ...string) {
|
||||
func SkipOnKernelVersions(t testenv.TB, issue string, versions ...string) {
|
||||
major, minor, patch := KernelVersion()
|
||||
if major == 0 && minor == 0 && patch == 0 {
|
||||
t.Logf("could not determine kernel version")
|
||||
|
||||
@@ -6,8 +6,18 @@
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"tailscale.com/tstest/deptest"
|
||||
)
|
||||
|
||||
func TestDeps(t *testing.T) {
|
||||
deptest.DepChecker{
|
||||
BadDeps: map[string]string{
|
||||
"testing": "do not link the testing package and its flag side effects into non-test binaries; use testenv.TB",
|
||||
},
|
||||
}.Check(t)
|
||||
}
|
||||
|
||||
func TestReplace(t *testing.T) {
|
||||
before := "before"
|
||||
done := false
|
||||
|
||||
@@ -22,6 +22,19 @@ func InTest() bool {
|
||||
})
|
||||
}
|
||||
|
||||
// Verbose reports whether the test binary is running with verbose
|
||||
// output (the -test.v flag), like testing.Verbose but without
|
||||
// importing the testing package.
|
||||
func Verbose() bool {
|
||||
f := flag.Lookup("test.v")
|
||||
if f == nil {
|
||||
return false
|
||||
}
|
||||
// The flag's String value is "false" when off, and "true" or
|
||||
// "test2json" when on.
|
||||
return f.Value.String() != "false"
|
||||
}
|
||||
|
||||
// TB is testing.TB, to avoid importing "testing" in non-test code.
|
||||
type TB interface {
|
||||
ArtifactDir() string
|
||||
|
||||
Reference in New Issue
Block a user