From 4ad1243332266d643d287b36832e89c5ad8930a5 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 21 Jul 2026 04:03:33 +0000 Subject: [PATCH] util/testenv: add ArtifactDir, Attr, Output methods to TB The TB interface exists to mirror testing.TB without importing the testing package, but it had fallen behind: Go 1.25 added Attr and Output, and Go 1.26 added ArtifactDir. Add the missing methods and a reflection-based test that TB has every exported method of testing.TB, so future additions to testing.TB fail a test instead of silently diverging. It can't be a compile-time assertion because testing.TB has an unexported method. Updates #16330 Updates #18682 Signed-off-by: Brad Fitzpatrick Change-Id: I9ba093afefdf3a6311ef4648bc1a13add9af453d --- util/testenv/testenv.go | 4 ++++ util/testenv/testenv_test.go | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/util/testenv/testenv.go b/util/testenv/testenv.go index 1ae1fe8a8..c6792bb4f 100644 --- a/util/testenv/testenv.go +++ b/util/testenv/testenv.go @@ -8,6 +8,7 @@ package testenv import ( "context" "flag" + "io" "tailscale.com/types/lazy" ) @@ -23,6 +24,8 @@ func InTest() bool { // TB is testing.TB, to avoid importing "testing" in non-test code. type TB interface { + ArtifactDir() string + Attr(key, value string) Cleanup(func()) Error(args ...any) Errorf(format string, args ...any) @@ -35,6 +38,7 @@ type TB interface { Log(args ...any) Logf(format string, args ...any) Name() string + Output() io.Writer Setenv(key, value string) Chdir(dir string) Skip(args ...any) diff --git a/util/testenv/testenv_test.go b/util/testenv/testenv_test.go index 3001d19eb..181f017f7 100644 --- a/util/testenv/testenv_test.go +++ b/util/testenv/testenv_test.go @@ -4,6 +4,7 @@ package testenv import ( + "reflect" "testing" "tailscale.com/tstest/deptest" @@ -29,3 +30,24 @@ func TestInParallelTestFalse(t *testing.T) { t.Fatal("InParallelTest should return false before t.Parallel has been called") } } + +// TestMatchesTestingTB verifies that TB has every exported method of +// testing.TB, with matching signatures. It can't be a compile-time +// assertion because testing.TB has an unexported method. +func TestMatchesTestingTB(t *testing.T) { + want := reflect.TypeFor[testing.TB]() + got := reflect.TypeFor[TB]() + for m := range want.Methods() { + if m.PkgPath != "" { + continue // unexported + } + gm, ok := got.MethodByName(m.Name) + if !ok { + t.Errorf("TB lacks method %s%v", m.Name, m.Type) + continue + } + if gm.Type != m.Type { + t.Errorf("TB method %s has type %v; want %v", m.Name, gm.Type, m.Type) + } + } +}