Source file src/testing/testing_test.go

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package testing_test
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"errors"
    11  	"fmt"
    12  	"internal/race"
    13  	"internal/testenv"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"regexp"
    18  	"runtime"
    19  	"slices"
    20  	"strings"
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  )
    25  
    26  // This is exactly what a test would do without a TestMain.
    27  // It's here only so that there is at least one package in the
    28  // standard library with a TestMain, so that code is executed.
    29  
    30  func TestMain(m *testing.M) {
    31  	if os.Getenv("GO_WANT_RACE_BEFORE_TESTS") == "1" {
    32  		doRace()
    33  	}
    34  
    35  	m.Run()
    36  
    37  	// Note: m.Run currently prints the final "PASS" line, so if any race is
    38  	// reported here (after m.Run but before the process exits), it will print
    39  	// "PASS", then print the stack traces for the race, then exit with nonzero
    40  	// status.
    41  	//
    42  	// This is a somewhat fundamental race: because the race detector hooks into
    43  	// the runtime at a very low level, no matter where we put the printing it
    44  	// would be possible to report a race that occurs afterward. However, we could
    45  	// theoretically move the printing after TestMain, which would at least do a
    46  	// better job of diagnosing races in cleanup functions within TestMain itself.
    47  }
    48  
    49  func TestTempDirInCleanup(t *testing.T) {
    50  	var dir string
    51  
    52  	t.Run("test", func(t *testing.T) {
    53  		t.Cleanup(func() {
    54  			dir = t.TempDir()
    55  		})
    56  		_ = t.TempDir()
    57  	})
    58  
    59  	fi, err := os.Stat(dir)
    60  	if fi != nil {
    61  		t.Fatalf("Directory %q from user Cleanup still exists", dir)
    62  	}
    63  	if !os.IsNotExist(err) {
    64  		t.Fatalf("Unexpected error: %v", err)
    65  	}
    66  }
    67  
    68  func TestTempDirInBenchmark(t *testing.T) {
    69  	testing.Benchmark(func(b *testing.B) {
    70  		if !b.Run("test", func(b *testing.B) {
    71  			// Add a loop so that the test won't fail. See issue 38677.
    72  			for i := 0; i < b.N; i++ {
    73  				_ = b.TempDir()
    74  			}
    75  		}) {
    76  			t.Fatal("Sub test failure in a benchmark")
    77  		}
    78  	})
    79  }
    80  
    81  func TestTempDir(t *testing.T) {
    82  	testTempDir(t)
    83  	t.Run("InSubtest", testTempDir)
    84  	t.Run("test/subtest", testTempDir)
    85  	t.Run("test\\subtest", testTempDir)
    86  	t.Run("test:subtest", testTempDir)
    87  	t.Run("test/..", testTempDir)
    88  	t.Run("../test", testTempDir)
    89  	t.Run("test[]", testTempDir)
    90  	t.Run("test*", testTempDir)
    91  	t.Run("äöüéè", testTempDir)
    92  	t.Run(strings.Repeat("a", 300), testTempDir)
    93  }
    94  
    95  func testTempDir(t *testing.T) {
    96  	dirCh := make(chan string, 1)
    97  	t.Cleanup(func() {
    98  		// Verify directory has been removed.
    99  		select {
   100  		case dir := <-dirCh:
   101  			fi, err := os.Stat(dir)
   102  			if os.IsNotExist(err) {
   103  				// All good
   104  				return
   105  			}
   106  			if err != nil {
   107  				t.Fatal(err)
   108  			}
   109  			t.Errorf("directory %q still exists: %v, isDir=%v", dir, fi, fi.IsDir())
   110  		default:
   111  			if !t.Failed() {
   112  				t.Fatal("never received dir channel")
   113  			}
   114  		}
   115  	})
   116  
   117  	dir := t.TempDir()
   118  	if dir == "" {
   119  		t.Fatal("expected dir")
   120  	}
   121  	dir2 := t.TempDir()
   122  	if dir == dir2 {
   123  		t.Fatal("subsequent calls to TempDir returned the same directory")
   124  	}
   125  	if filepath.Dir(dir) != filepath.Dir(dir2) {
   126  		t.Fatalf("calls to TempDir do not share a parent; got %q, %q", dir, dir2)
   127  	}
   128  	dirCh <- dir
   129  	fi, err := os.Stat(dir)
   130  	if err != nil {
   131  		t.Fatal(err)
   132  	}
   133  	if !fi.IsDir() {
   134  		t.Errorf("dir %q is not a dir", dir)
   135  	}
   136  	files, err := os.ReadDir(dir)
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  	if len(files) > 0 {
   141  		t.Errorf("unexpected %d files in TempDir: %v", len(files), files)
   142  	}
   143  
   144  	glob := filepath.Join(dir, "*.txt")
   145  	if _, err := filepath.Glob(glob); err != nil {
   146  		t.Error(err)
   147  	}
   148  }
   149  
   150  func TestTempDirGOTMPDIR(t *testing.T) {
   151  	// The first call to t.TempDir will create a parent temporary directory
   152  	// that will contain all temporary directories created by TempDir.
   153  	//
   154  	// Use os.TempDir (not t.TempDir) to get a temporary directory,
   155  	// set GOTMPDIR to that directory,
   156  	// and then verify that t.TempDir creates a directory in GOTMPDIR.
   157  	customTmpDir := filepath.Join(os.TempDir(), "custom-gotmpdir-test")
   158  	if err := os.MkdirAll(customTmpDir, 0777); err != nil {
   159  		t.Fatal(err)
   160  	}
   161  	defer os.RemoveAll(customTmpDir)
   162  
   163  	t.Setenv("GOTMPDIR", customTmpDir)
   164  
   165  	dir := t.TempDir()
   166  	if dir == "" {
   167  		t.Fatal("expected dir")
   168  	}
   169  
   170  	if !strings.HasPrefix(dir, customTmpDir) {
   171  		t.Errorf("TempDir did not use GOTMPDIR: got %q, want prefix %q", dir, customTmpDir)
   172  	}
   173  
   174  	fi, err := os.Stat(dir)
   175  	if err != nil {
   176  		t.Fatal(err)
   177  	}
   178  	if !fi.IsDir() {
   179  		t.Errorf("dir %q is not a dir", dir)
   180  	}
   181  }
   182  
   183  func TestSetenv(t *testing.T) {
   184  	tests := []struct {
   185  		name               string
   186  		key                string
   187  		initialValueExists bool
   188  		initialValue       string
   189  		newValue           string
   190  	}{
   191  		{
   192  			name:               "initial value exists",
   193  			key:                "GO_TEST_KEY_1",
   194  			initialValueExists: true,
   195  			initialValue:       "111",
   196  			newValue:           "222",
   197  		},
   198  		{
   199  			name:               "initial value exists but empty",
   200  			key:                "GO_TEST_KEY_2",
   201  			initialValueExists: true,
   202  			initialValue:       "",
   203  			newValue:           "222",
   204  		},
   205  		{
   206  			name:               "initial value is not exists",
   207  			key:                "GO_TEST_KEY_3",
   208  			initialValueExists: false,
   209  			initialValue:       "",
   210  			newValue:           "222",
   211  		},
   212  	}
   213  
   214  	for _, test := range tests {
   215  		if test.initialValueExists {
   216  			if err := os.Setenv(test.key, test.initialValue); err != nil {
   217  				t.Fatalf("unable to set env: got %v", err)
   218  			}
   219  		} else {
   220  			os.Unsetenv(test.key)
   221  		}
   222  
   223  		t.Run(test.name, func(t *testing.T) {
   224  			t.Setenv(test.key, test.newValue)
   225  			if os.Getenv(test.key) != test.newValue {
   226  				t.Fatalf("unexpected value after t.Setenv: got %s, want %s", os.Getenv(test.key), test.newValue)
   227  			}
   228  		})
   229  
   230  		got, exists := os.LookupEnv(test.key)
   231  		if got != test.initialValue {
   232  			t.Fatalf("unexpected value after t.Setenv cleanup: got %s, want %s", got, test.initialValue)
   233  		}
   234  		if exists != test.initialValueExists {
   235  			t.Fatalf("unexpected value after t.Setenv cleanup: got %t, want %t", exists, test.initialValueExists)
   236  		}
   237  	}
   238  }
   239  
   240  func expectParallelConflict(t *testing.T) {
   241  	want := testing.ParallelConflict
   242  	if got := recover(); got != want {
   243  		t.Fatalf("expected panic; got %#v want %q", got, want)
   244  	}
   245  }
   246  
   247  func testWithParallelAfter(t *testing.T, fn func(*testing.T)) {
   248  	defer expectParallelConflict(t)
   249  
   250  	fn(t)
   251  	t.Parallel()
   252  }
   253  
   254  func testWithParallelBefore(t *testing.T, fn func(*testing.T)) {
   255  	defer expectParallelConflict(t)
   256  
   257  	t.Parallel()
   258  	fn(t)
   259  }
   260  
   261  func testWithParallelParentBefore(t *testing.T, fn func(*testing.T)) {
   262  	t.Parallel()
   263  
   264  	t.Run("child", func(t *testing.T) {
   265  		defer expectParallelConflict(t)
   266  
   267  		fn(t)
   268  	})
   269  }
   270  
   271  func testWithParallelGrandParentBefore(t *testing.T, fn func(*testing.T)) {
   272  	t.Parallel()
   273  
   274  	t.Run("child", func(t *testing.T) {
   275  		t.Run("grand-child", func(t *testing.T) {
   276  			defer expectParallelConflict(t)
   277  
   278  			fn(t)
   279  		})
   280  	})
   281  }
   282  
   283  func tSetenv(t *testing.T) {
   284  	t.Setenv("GO_TEST_KEY_1", "value")
   285  }
   286  
   287  func TestSetenvWithParallelAfter(t *testing.T) {
   288  	testWithParallelAfter(t, tSetenv)
   289  }
   290  
   291  func TestSetenvWithParallelBefore(t *testing.T) {
   292  	testWithParallelBefore(t, tSetenv)
   293  }
   294  
   295  func TestSetenvWithParallelParentBefore(t *testing.T) {
   296  	testWithParallelParentBefore(t, tSetenv)
   297  }
   298  
   299  func TestSetenvWithParallelGrandParentBefore(t *testing.T) {
   300  	testWithParallelGrandParentBefore(t, tSetenv)
   301  }
   302  
   303  func tChdir(t *testing.T) {
   304  	t.Chdir(t.TempDir())
   305  }
   306  
   307  func TestChdirWithParallelAfter(t *testing.T) {
   308  	testWithParallelAfter(t, tChdir)
   309  }
   310  
   311  func TestChdirWithParallelBefore(t *testing.T) {
   312  	testWithParallelBefore(t, tChdir)
   313  }
   314  
   315  func TestChdirWithParallelParentBefore(t *testing.T) {
   316  	testWithParallelParentBefore(t, tChdir)
   317  }
   318  
   319  func TestChdirWithParallelGrandParentBefore(t *testing.T) {
   320  	testWithParallelGrandParentBefore(t, tChdir)
   321  }
   322  
   323  func TestChdir(t *testing.T) {
   324  	oldDir, err := os.Getwd()
   325  	if err != nil {
   326  		t.Fatal(err)
   327  	}
   328  	defer os.Chdir(oldDir)
   329  
   330  	// The "relative" test case relies on tmp not being a symlink.
   331  	tmp, err := filepath.EvalSymlinks(t.TempDir())
   332  	if err != nil {
   333  		t.Fatal(err)
   334  	}
   335  	rel, err := filepath.Rel(oldDir, tmp)
   336  	if err != nil {
   337  		// If GOROOT is on C: volume and tmp is on the D: volume, there
   338  		// is no relative path between them, so skip that test case.
   339  		rel = "skip"
   340  	}
   341  
   342  	for _, tc := range []struct {
   343  		name, dir, pwd string
   344  		extraChdir     bool
   345  	}{
   346  		{
   347  			name: "absolute",
   348  			dir:  tmp,
   349  			pwd:  tmp,
   350  		},
   351  		{
   352  			name: "relative",
   353  			dir:  rel,
   354  			pwd:  tmp,
   355  		},
   356  		{
   357  			name: "current (absolute)",
   358  			dir:  oldDir,
   359  			pwd:  oldDir,
   360  		},
   361  		{
   362  			name: "current (relative) with extra os.Chdir",
   363  			dir:  ".",
   364  			pwd:  oldDir,
   365  
   366  			extraChdir: true,
   367  		},
   368  	} {
   369  		t.Run(tc.name, func(t *testing.T) {
   370  			if tc.dir == "skip" {
   371  				t.Skipf("skipping test because there is no relative path between %s and %s", oldDir, tmp)
   372  			}
   373  			if !filepath.IsAbs(tc.pwd) {
   374  				t.Fatalf("Bad tc.pwd: %q (must be absolute)", tc.pwd)
   375  			}
   376  
   377  			t.Chdir(tc.dir)
   378  
   379  			newDir, err := os.Getwd()
   380  			if err != nil {
   381  				t.Fatal(err)
   382  			}
   383  			if newDir != tc.pwd {
   384  				t.Fatalf("failed to chdir to %q: getwd: got %q, want %q", tc.dir, newDir, tc.pwd)
   385  			}
   386  
   387  			switch runtime.GOOS {
   388  			case "windows", "plan9":
   389  				// Windows and Plan 9 do not use the PWD variable.
   390  			default:
   391  				if pwd := os.Getenv("PWD"); pwd != tc.pwd {
   392  					t.Fatalf("PWD: got %q, want %q", pwd, tc.pwd)
   393  				}
   394  			}
   395  
   396  			if tc.extraChdir {
   397  				os.Chdir("..")
   398  			}
   399  		})
   400  
   401  		newDir, err := os.Getwd()
   402  		if err != nil {
   403  			t.Fatal(err)
   404  		}
   405  		if newDir != oldDir {
   406  			t.Fatalf("failed to restore wd to %s: getwd: %s", oldDir, newDir)
   407  		}
   408  	}
   409  }
   410  
   411  // testingTrueInInit is part of TestTesting.
   412  var testingTrueInInit = false
   413  
   414  // testingTrueInPackageVarInit is part of TestTesting.
   415  var testingTrueInPackageVarInit = testing.Testing()
   416  
   417  // init is part of TestTesting.
   418  func init() {
   419  	if testing.Testing() {
   420  		testingTrueInInit = true
   421  	}
   422  }
   423  
   424  var testingProg = `
   425  package main
   426  
   427  import (
   428  	"fmt"
   429  	"testing"
   430  )
   431  
   432  func main() {
   433  	fmt.Println(testing.Testing())
   434  }
   435  `
   436  
   437  func TestTesting(t *testing.T) {
   438  	if !testing.Testing() {
   439  		t.Errorf("testing.Testing() == %t, want %t", testing.Testing(), true)
   440  	}
   441  	if !testingTrueInInit {
   442  		t.Errorf("testing.Testing() called by init function == %t, want %t", testingTrueInInit, true)
   443  	}
   444  	if !testingTrueInPackageVarInit {
   445  		t.Errorf("testing.Testing() variable initialized as %t, want %t", testingTrueInPackageVarInit, true)
   446  	}
   447  
   448  	if testing.Short() {
   449  		t.Skip("skipping building a binary in short mode")
   450  	}
   451  	testenv.MustHaveGoRun(t)
   452  
   453  	fn := filepath.Join(t.TempDir(), "x.go")
   454  	if err := os.WriteFile(fn, []byte(testingProg), 0644); err != nil {
   455  		t.Fatal(err)
   456  	}
   457  
   458  	cmd := testenv.Command(t, testenv.GoToolPath(t), "run", fn)
   459  	out, err := cmd.CombinedOutput()
   460  	if err != nil {
   461  		t.Fatalf("%v failed: %v\n%s", cmd, err, out)
   462  	}
   463  
   464  	s := string(bytes.TrimSpace(out))
   465  	if s != "false" {
   466  		t.Errorf("in non-test testing.Test() returned %q, want %q", s, "false")
   467  	}
   468  }
   469  
   470  // runTest runs a helper test with -test.v, ignoring its exit status.
   471  // runTest both logs and returns the test output.
   472  func runTest(t *testing.T, test string, args ...string) []byte {
   473  	t.Helper()
   474  
   475  	testenv.MustHaveExec(t)
   476  
   477  	cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+test+"$", "-test.bench="+test, "-test.v", "-test.parallel=2", "-test.benchtime=2x")
   478  	cmd = testenv.CleanCmdEnv(cmd)
   479  	cmd.Env = append(cmd.Env, "GO_WANT_HELPER_PROCESS=1")
   480  	cmd.Args = append(cmd.Args, args...)
   481  	out, err := cmd.CombinedOutput()
   482  	t.Logf("%v: %v\n%s", cmd, err, out)
   483  
   484  	return out
   485  }
   486  
   487  // doRace provokes a data race that generates a race detector report if run
   488  // under the race detector and is otherwise benign.
   489  func doRace() {
   490  	var x int
   491  	c1 := make(chan bool)
   492  	go func() {
   493  		x = 1 // racy write
   494  		c1 <- true
   495  	}()
   496  	_ = x // racy read
   497  	<-c1
   498  }
   499  
   500  func TestRaceReports(t *testing.T) {
   501  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
   502  		// Generate a race detector report in a sub test.
   503  		t.Run("Sub", func(t *testing.T) {
   504  			doRace()
   505  		})
   506  		return
   507  	}
   508  
   509  	out := runTest(t, "TestRaceReports")
   510  
   511  	// We should see at most one race detector report.
   512  	c := bytes.Count(out, []byte("race detected"))
   513  	want := 0
   514  	if race.Enabled {
   515  		want = 1
   516  	}
   517  	if c != want {
   518  		t.Errorf("got %d race reports, want %d", c, want)
   519  	}
   520  }
   521  
   522  // Issue #60083. This used to fail on the race builder.
   523  func TestRaceName(t *testing.T) {
   524  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
   525  		doRace()
   526  		return
   527  	}
   528  
   529  	out := runTest(t, "TestRaceName")
   530  
   531  	if regexp.MustCompile(`=== NAME\s*$`).Match(out) {
   532  		t.Errorf("incorrectly reported test with no name")
   533  	}
   534  }
   535  
   536  func TestRaceSubReports(t *testing.T) {
   537  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
   538  		t.Parallel()
   539  		c1 := make(chan bool, 1)
   540  		t.Run("sub", func(t *testing.T) {
   541  			t.Run("subsub1", func(t *testing.T) {
   542  				t.Parallel()
   543  				doRace()
   544  				c1 <- true
   545  			})
   546  			t.Run("subsub2", func(t *testing.T) {
   547  				t.Parallel()
   548  				doRace()
   549  				<-c1
   550  			})
   551  		})
   552  		doRace()
   553  		return
   554  	}
   555  
   556  	out := runTest(t, "TestRaceSubReports")
   557  
   558  	// There should be three race reports: one for each subtest, and one for the
   559  	// race after the subtests complete. Note that because the subtests run in
   560  	// parallel, the race stacks may both be printed in with one or the other
   561  	// test's logs.
   562  	cReport := bytes.Count(out, []byte("race detected during execution of test"))
   563  	wantReport := 0
   564  	if race.Enabled {
   565  		wantReport = 3
   566  	}
   567  	if cReport != wantReport {
   568  		t.Errorf("got %d race reports, want %d", cReport, wantReport)
   569  	}
   570  
   571  	// Regardless of when the stacks are printed, we expect each subtest to be
   572  	// marked as failed, and that failure should propagate up to the parents.
   573  	cFail := bytes.Count(out, []byte("--- FAIL:"))
   574  	wantFail := 0
   575  	if race.Enabled {
   576  		wantFail = 4
   577  	}
   578  	if cFail != wantFail {
   579  		t.Errorf(`got %d "--- FAIL:" lines, want %d`, cReport, wantReport)
   580  	}
   581  }
   582  
   583  func TestRaceInCleanup(t *testing.T) {
   584  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
   585  		t.Cleanup(doRace)
   586  		t.Parallel()
   587  		t.Run("sub", func(t *testing.T) {
   588  			t.Parallel()
   589  			// No race should be reported for sub.
   590  		})
   591  		return
   592  	}
   593  
   594  	out := runTest(t, "TestRaceInCleanup")
   595  
   596  	// There should be one race report, for the parent test only.
   597  	cReport := bytes.Count(out, []byte("race detected during execution of test"))
   598  	wantReport := 0
   599  	if race.Enabled {
   600  		wantReport = 1
   601  	}
   602  	if cReport != wantReport {
   603  		t.Errorf("got %d race reports, want %d", cReport, wantReport)
   604  	}
   605  
   606  	// Only the parent test should be marked as failed.
   607  	// (The subtest does not race, and should pass.)
   608  	cFail := bytes.Count(out, []byte("--- FAIL:"))
   609  	wantFail := 0
   610  	if race.Enabled {
   611  		wantFail = 1
   612  	}
   613  	if cFail != wantFail {
   614  		t.Errorf(`got %d "--- FAIL:" lines, want %d`, cReport, wantReport)
   615  	}
   616  }
   617  
   618  func TestDeepSubtestRace(t *testing.T) {
   619  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
   620  		t.Run("sub", func(t *testing.T) {
   621  			t.Run("subsub", func(t *testing.T) {
   622  				t.Run("subsubsub", func(t *testing.T) {
   623  					doRace()
   624  				})
   625  			})
   626  			doRace()
   627  		})
   628  		return
   629  	}
   630  
   631  	out := runTest(t, "TestDeepSubtestRace")
   632  
   633  	c := bytes.Count(out, []byte("race detected during execution of test"))
   634  	want := 0
   635  	// There should be two race reports.
   636  	if race.Enabled {
   637  		want = 2
   638  	}
   639  	if c != want {
   640  		t.Errorf("got %d race reports, want %d", c, want)
   641  	}
   642  }
   643  
   644  func TestRaceDuringParallelFailsAllSubtests(t *testing.T) {
   645  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
   646  		var ready sync.WaitGroup
   647  		ready.Add(2)
   648  		done := make(chan struct{})
   649  		go func() {
   650  			ready.Wait()
   651  			doRace() // This race happens while both subtests are running.
   652  			close(done)
   653  		}()
   654  
   655  		t.Run("sub", func(t *testing.T) {
   656  			t.Run("subsub1", func(t *testing.T) {
   657  				t.Parallel()
   658  				ready.Done()
   659  				<-done
   660  			})
   661  			t.Run("subsub2", func(t *testing.T) {
   662  				t.Parallel()
   663  				ready.Done()
   664  				<-done
   665  			})
   666  		})
   667  
   668  		return
   669  	}
   670  
   671  	out := runTest(t, "TestRaceDuringParallelFailsAllSubtests")
   672  
   673  	c := bytes.Count(out, []byte("race detected during execution of test"))
   674  	want := 0
   675  	// Each subtest should report the race independently.
   676  	if race.Enabled {
   677  		want = 2
   678  	}
   679  	if c != want {
   680  		t.Errorf("got %d race reports, want %d", c, want)
   681  	}
   682  }
   683  
   684  func TestRaceBeforeParallel(t *testing.T) {
   685  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
   686  		t.Run("sub", func(t *testing.T) {
   687  			doRace()
   688  			t.Parallel()
   689  		})
   690  		return
   691  	}
   692  
   693  	out := runTest(t, "TestRaceBeforeParallel")
   694  
   695  	c := bytes.Count(out, []byte("race detected during execution of test"))
   696  	want := 0
   697  	// We should see one race detector report.
   698  	if race.Enabled {
   699  		want = 1
   700  	}
   701  	if c != want {
   702  		t.Errorf("got %d race reports, want %d", c, want)
   703  	}
   704  }
   705  
   706  func TestRaceBeforeTests(t *testing.T) {
   707  	cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^$")
   708  	cmd = testenv.CleanCmdEnv(cmd)
   709  	cmd.Env = append(cmd.Env, "GO_WANT_RACE_BEFORE_TESTS=1")
   710  	out, _ := cmd.CombinedOutput()
   711  	t.Logf("%s", out)
   712  
   713  	c := bytes.Count(out, []byte("race detected outside of test execution"))
   714  
   715  	want := 0
   716  	if race.Enabled {
   717  		want = 1
   718  	}
   719  	if c != want {
   720  		t.Errorf("got %d race reports; want %d", c, want)
   721  	}
   722  }
   723  
   724  func TestBenchmarkRace(t *testing.T) {
   725  	out := runTest(t, "BenchmarkRacy")
   726  	c := bytes.Count(out, []byte("race detected during execution of test"))
   727  
   728  	want := 0
   729  	// We should see one race detector report.
   730  	if race.Enabled {
   731  		want = 1
   732  	}
   733  	if c != want {
   734  		t.Errorf("got %d race reports; want %d", c, want)
   735  	}
   736  }
   737  
   738  func TestBenchmarkRaceBLoop(t *testing.T) {
   739  	out := runTest(t, "BenchmarkBLoopRacy")
   740  	c := bytes.Count(out, []byte("race detected during execution of test"))
   741  
   742  	want := 0
   743  	// We should see one race detector report.
   744  	if race.Enabled {
   745  		want = 1
   746  	}
   747  	if c != want {
   748  		t.Errorf("got %d race reports; want %d", c, want)
   749  	}
   750  }
   751  
   752  func BenchmarkRacy(b *testing.B) {
   753  	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
   754  		b.Skipf("skipping intentionally-racy benchmark")
   755  	}
   756  	for i := 0; i < b.N; i++ {
   757  		doRace()
   758  	}
   759  }
   760  
   761  func BenchmarkBLoopRacy(b *testing.B) {
   762  	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
   763  		b.Skipf("skipping intentionally-racy benchmark")
   764  	}
   765  	for b.Loop() {
   766  		doRace()
   767  	}
   768  }
   769  
   770  func TestBenchmarkSubRace(t *testing.T) {
   771  	out := runTest(t, "BenchmarkSubRacy")
   772  	c := bytes.Count(out, []byte("race detected during execution of test"))
   773  
   774  	want := 0
   775  	// We should see 3 race detector reports:
   776  	// one in the sub-bencmark, one in the parent afterward,
   777  	// and one in b.Loop.
   778  	if race.Enabled {
   779  		want = 3
   780  	}
   781  	if c != want {
   782  		t.Errorf("got %d race reports; want %d", c, want)
   783  	}
   784  }
   785  
   786  func BenchmarkSubRacy(b *testing.B) {
   787  	if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
   788  		b.Skipf("skipping intentionally-racy benchmark")
   789  	}
   790  
   791  	b.Run("non-racy", func(b *testing.B) {
   792  		tot := 0
   793  		for i := 0; i < b.N; i++ {
   794  			tot++
   795  		}
   796  		_ = tot
   797  	})
   798  
   799  	b.Run("racy", func(b *testing.B) {
   800  		for i := 0; i < b.N; i++ {
   801  			doRace()
   802  		}
   803  	})
   804  
   805  	b.Run("racy-bLoop", func(b *testing.B) {
   806  		for b.Loop() {
   807  			doRace()
   808  		}
   809  	})
   810  
   811  	doRace() // should be reported separately
   812  }
   813  
   814  func TestRunningTests(t *testing.T) {
   815  	t.Parallel()
   816  
   817  	// Regression test for https://go.dev/issue/64404:
   818  	// on timeout, the "running tests" message should not include
   819  	// tests that are waiting on parked subtests.
   820  
   821  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
   822  		for i := 0; i < 2; i++ {
   823  			t.Run(fmt.Sprintf("outer%d", i), func(t *testing.T) {
   824  				t.Parallel()
   825  				for j := 0; j < 2; j++ {
   826  					t.Run(fmt.Sprintf("inner%d", j), func(t *testing.T) {
   827  						t.Parallel()
   828  						for {
   829  							time.Sleep(1 * time.Millisecond)
   830  						}
   831  					})
   832  				}
   833  			})
   834  		}
   835  	}
   836  
   837  	timeout := 10 * time.Millisecond
   838  	for {
   839  		cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$", "-test.timeout="+timeout.String(), "-test.parallel=4")
   840  		cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
   841  		out, err := cmd.CombinedOutput()
   842  		t.Logf("%v:\n%s", cmd, out)
   843  		if _, ok := err.(*exec.ExitError); !ok {
   844  			t.Fatal(err)
   845  		}
   846  
   847  		// Because the outer subtests (and TestRunningTests itself) are marked as
   848  		// parallel, their test functions return (and are no longer “running”)
   849  		// before the inner subtests are released to run and hang.
   850  		// Only those inner subtests should be reported as running.
   851  		want := []string{
   852  			"TestRunningTests/outer0/inner0",
   853  			"TestRunningTests/outer0/inner1",
   854  			"TestRunningTests/outer1/inner0",
   855  			"TestRunningTests/outer1/inner1",
   856  		}
   857  
   858  		got, ok := parseRunningTests(out)
   859  		if slices.Equal(got, want) {
   860  			break
   861  		}
   862  		if ok {
   863  			t.Logf("found running tests:\n%s\nwant:\n%s", strings.Join(got, "\n"), strings.Join(want, "\n"))
   864  		} else {
   865  			t.Logf("no running tests found")
   866  		}
   867  		t.Logf("retrying with longer timeout")
   868  		timeout *= 2
   869  	}
   870  }
   871  
   872  func TestRunningTestsInCleanup(t *testing.T) {
   873  	t.Parallel()
   874  
   875  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
   876  		for i := 0; i < 2; i++ {
   877  			t.Run(fmt.Sprintf("outer%d", i), func(t *testing.T) {
   878  				// Not parallel: we expect to see only one outer test,
   879  				// stuck in cleanup after its subtest finishes.
   880  
   881  				t.Cleanup(func() {
   882  					for {
   883  						time.Sleep(1 * time.Millisecond)
   884  					}
   885  				})
   886  
   887  				for j := 0; j < 2; j++ {
   888  					t.Run(fmt.Sprintf("inner%d", j), func(t *testing.T) {
   889  						t.Parallel()
   890  					})
   891  				}
   892  			})
   893  		}
   894  	}
   895  
   896  	timeout := 10 * time.Millisecond
   897  	for {
   898  		cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^"+t.Name()+"$", "-test.timeout="+timeout.String())
   899  		cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1")
   900  		out, err := cmd.CombinedOutput()
   901  		t.Logf("%v:\n%s", cmd, out)
   902  		if _, ok := err.(*exec.ExitError); !ok {
   903  			t.Fatal(err)
   904  		}
   905  
   906  		// TestRunningTestsInCleanup is blocked in the call to t.Run,
   907  		// but its test function has not yet returned so it should still
   908  		// be considered to be running.
   909  		// outer1 hasn't even started yet, so only outer0 and the top-level
   910  		// test function should be reported as running.
   911  		want := []string{
   912  			"TestRunningTestsInCleanup",
   913  			"TestRunningTestsInCleanup/outer0",
   914  		}
   915  
   916  		got, ok := parseRunningTests(out)
   917  		if slices.Equal(got, want) {
   918  			break
   919  		}
   920  		if ok {
   921  			t.Logf("found running tests:\n%s\nwant:\n%s", strings.Join(got, "\n"), strings.Join(want, "\n"))
   922  		} else {
   923  			t.Logf("no running tests found")
   924  		}
   925  		t.Logf("retrying with longer timeout")
   926  		timeout *= 2
   927  	}
   928  }
   929  
   930  func parseRunningTests(out []byte) (runningTests []string, ok bool) {
   931  	inRunningTests := false
   932  	for line := range strings.SplitSeq(string(out), "\n") {
   933  		if inRunningTests {
   934  			// Package testing adds one tab, the panic printer adds another.
   935  			if trimmed, ok := strings.CutPrefix(line, "\t\t"); ok {
   936  				if name, _, ok := strings.Cut(trimmed, " "); ok {
   937  					runningTests = append(runningTests, name)
   938  					continue
   939  				}
   940  			}
   941  
   942  			// This line is not the name of a running test.
   943  			return runningTests, true
   944  		}
   945  
   946  		if strings.TrimSpace(line) == "running tests:" {
   947  			inRunningTests = true
   948  		}
   949  	}
   950  
   951  	return nil, false
   952  }
   953  
   954  func TestConcurrentRun(t *testing.T) {
   955  	// Regression test for https://go.dev/issue/64402:
   956  	// this deadlocked after https://go.dev/cl/506755.
   957  
   958  	block := make(chan struct{})
   959  	var ready, done sync.WaitGroup
   960  	for i := 0; i < 2; i++ {
   961  		ready.Add(1)
   962  		done.Add(1)
   963  		go t.Run("", func(*testing.T) {
   964  			ready.Done()
   965  			<-block
   966  			done.Done()
   967  		})
   968  	}
   969  	ready.Wait()
   970  	close(block)
   971  	done.Wait()
   972  }
   973  
   974  func TestParentRun(t1 *testing.T) {
   975  	// Regression test for https://go.dev/issue/64402:
   976  	// this deadlocked after https://go.dev/cl/506755.
   977  
   978  	t1.Run("outer", func(t2 *testing.T) {
   979  		t2.Log("Hello outer!")
   980  		t1.Run("not_inner", func(t3 *testing.T) { // Note: this is t1.Run, not t2.Run.
   981  			t3.Log("Hello inner!")
   982  		})
   983  	})
   984  }
   985  
   986  func TestContext(t *testing.T) {
   987  	ctx := t.Context()
   988  	if err := ctx.Err(); err != nil {
   989  		t.Fatalf("expected non-canceled context, got %v", err)
   990  	}
   991  
   992  	var innerCtx context.Context
   993  	t.Run("inner", func(t *testing.T) {
   994  		innerCtx = t.Context()
   995  		if err := innerCtx.Err(); err != nil {
   996  			t.Fatalf("expected inner test to not inherit canceled context, got %v", err)
   997  		}
   998  	})
   999  	t.Run("inner2", func(t *testing.T) {
  1000  		if !errors.Is(innerCtx.Err(), context.Canceled) {
  1001  			t.Fatal("expected context of sibling test to be canceled after its test function finished")
  1002  		}
  1003  	})
  1004  
  1005  	t.Cleanup(func() {
  1006  		if !errors.Is(ctx.Err(), context.Canceled) {
  1007  			t.Fatal("expected context canceled before cleanup")
  1008  		}
  1009  	})
  1010  }
  1011  
  1012  // TestAttrExample is used by TestAttrSet,
  1013  // and also serves as a convenient test to run that sets an attribute.
  1014  func TestAttrExample(t *testing.T) {
  1015  	t.Attr("key", "value")
  1016  }
  1017  
  1018  func TestAttrSet(t *testing.T) {
  1019  	out := string(runTest(t, "TestAttrExample"))
  1020  
  1021  	want := "=== ATTR  TestAttrExample key value\n"
  1022  	if !strings.Contains(out, want) {
  1023  		t.Errorf("expected output containing %q, got:\n%q", want, out)
  1024  	}
  1025  }
  1026  
  1027  func TestAttrInvalid(t *testing.T) {
  1028  	tests := []struct {
  1029  		key   string
  1030  		value string
  1031  	}{
  1032  		{"k ey", "value"},
  1033  		{"k\tey", "value"},
  1034  		{"k\rey", "value"},
  1035  		{"k\ney", "value"},
  1036  		{"key", "val\rue"},
  1037  		{"key", "val\nue"},
  1038  	}
  1039  
  1040  	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
  1041  		for i, test := range tests {
  1042  			t.Run(fmt.Sprint(i), func(t *testing.T) {
  1043  				t.Attr(test.key, test.value)
  1044  			})
  1045  		}
  1046  		return
  1047  	}
  1048  
  1049  	out := string(runTest(t, "TestAttrInvalid"))
  1050  
  1051  	for i := range tests {
  1052  		want := fmt.Sprintf("--- FAIL: TestAttrInvalid/%v ", i)
  1053  		if !strings.Contains(out, want) {
  1054  			t.Errorf("expected output containing %q, got:\n%q", want, out)
  1055  		}
  1056  	}
  1057  }
  1058  
  1059  const artifactContent = "It belongs in a museum.\n"
  1060  
  1061  func TestArtifactDirExample(t *testing.T) {
  1062  	os.WriteFile(filepath.Join(t.ArtifactDir(), "artifact"), []byte(artifactContent), 0o666)
  1063  }
  1064  
  1065  func TestArtifactDirDefault(t *testing.T) {
  1066  	tempDir := t.TempDir()
  1067  	t.Chdir(tempDir)
  1068  	out := runTest(t, "TestArtifactDirExample", "-test.artifacts")
  1069  	checkArtifactDir(t, out, "TestArtifactDirExample", tempDir)
  1070  }
  1071  
  1072  func TestArtifactDirSpecified(t *testing.T) {
  1073  	tempDir := t.TempDir()
  1074  	out := runTest(t, "TestArtifactDirExample", "-test.artifacts", "-test.outputdir="+tempDir)
  1075  	checkArtifactDir(t, out, "TestArtifactDirExample", tempDir)
  1076  }
  1077  
  1078  func TestArtifactDirNoArtifacts(t *testing.T) {
  1079  	t.Chdir(t.TempDir())
  1080  	out := string(runTest(t, "TestArtifactDirExample"))
  1081  	if strings.Contains(out, "=== ARTIFACTS") {
  1082  		t.Errorf("expected output with no === ARTIFACTS, got\n%q", out)
  1083  	}
  1084  	ents, err := os.ReadDir(".")
  1085  	if err != nil {
  1086  		t.Fatal(err)
  1087  	}
  1088  	for _, e := range ents {
  1089  		t.Errorf("unexpected file in current directory after test: %v", e.Name())
  1090  	}
  1091  }
  1092  
  1093  func TestArtifactDirSubtestExample(t *testing.T) {
  1094  	t.Run("Subtest", func(t *testing.T) {
  1095  		os.WriteFile(filepath.Join(t.ArtifactDir(), "artifact"), []byte(artifactContent), 0o666)
  1096  	})
  1097  }
  1098  
  1099  func TestArtifactDirInSubtest(t *testing.T) {
  1100  	tempDir := t.TempDir()
  1101  	out := runTest(t, "TestArtifactDirSubtestExample/Subtest", "-test.artifacts", "-test.outputdir="+tempDir)
  1102  	checkArtifactDir(t, out, "TestArtifactDirSubtestExample/Subtest", tempDir)
  1103  }
  1104  
  1105  func TestArtifactDirLongTestNameExample(t *testing.T) {
  1106  	name := strings.Repeat("x", 256)
  1107  	t.Run(name, func(t *testing.T) {
  1108  		os.WriteFile(filepath.Join(t.ArtifactDir(), "artifact"), []byte(artifactContent), 0o666)
  1109  	})
  1110  }
  1111  
  1112  func TestArtifactDirWithLongTestName(t *testing.T) {
  1113  	tempDir := t.TempDir()
  1114  	out := runTest(t, "TestArtifactDirLongTestNameExample", "-test.artifacts", "-test.outputdir="+tempDir)
  1115  	checkArtifactDir(t, out, `TestArtifactDirLongTestNameExample/\w+`, tempDir)
  1116  }
  1117  
  1118  func TestArtifactDirConsistent(t *testing.T) {
  1119  	a := t.ArtifactDir()
  1120  	b := t.ArtifactDir()
  1121  	if a != b {
  1122  		t.Errorf("t.ArtifactDir is not consistent between calls: %q, %q", a, b)
  1123  	}
  1124  }
  1125  
  1126  func checkArtifactDir(t *testing.T, out []byte, testName, outputDir string) {
  1127  	t.Helper()
  1128  
  1129  	re := regexp.MustCompile(`=== ARTIFACTS ` + testName + ` ([^\n]+)`)
  1130  	match := re.FindSubmatch(out)
  1131  	if match == nil {
  1132  		t.Fatalf("expected output matching %q, got\n%q", re, out)
  1133  	}
  1134  	artifactDir := string(match[1])
  1135  
  1136  	// Verify that the artifact directory is contained in the expected output directory.
  1137  	relDir, err := filepath.Rel(outputDir, artifactDir)
  1138  	if err != nil {
  1139  		t.Fatal(err)
  1140  	}
  1141  	if !filepath.IsLocal(relDir) {
  1142  		t.Fatalf("want artifact directory contained in %q, got %q", outputDir, artifactDir)
  1143  	}
  1144  
  1145  	for _, part := range strings.Split(relDir, string(os.PathSeparator)) {
  1146  		const maxSize = 64
  1147  		if len(part) > maxSize {
  1148  			t.Errorf("artifact directory %q contains component >%v characters long: %q", relDir, maxSize, part)
  1149  		}
  1150  	}
  1151  
  1152  	got, err := os.ReadFile(filepath.Join(artifactDir, "artifact"))
  1153  	if err != nil || string(got) != artifactContent {
  1154  		t.Errorf("reading artifact in %q: got %q, %v; want %q", artifactDir, got, err, artifactContent)
  1155  	}
  1156  }
  1157  
  1158  func TestBenchmarkBLoopIterationCorrect(t *testing.T) {
  1159  	out := runTest(t, "BenchmarkBLoopPrint")
  1160  	c := bytes.Count(out, []byte("Printing from BenchmarkBLoopPrint"))
  1161  
  1162  	want := 2
  1163  	if c != want {
  1164  		t.Errorf("got %d loop iterations; want %d", c, want)
  1165  	}
  1166  
  1167  	// b.Loop() will only rampup once.
  1168  	c = bytes.Count(out, []byte("Ramping up from BenchmarkBLoopPrint"))
  1169  	want = 1
  1170  	if c != want {
  1171  		t.Errorf("got %d loop rampup; want %d", c, want)
  1172  	}
  1173  
  1174  	re := regexp.MustCompile(`BenchmarkBLoopPrint(-[0-9]+)?\s+2\s+[0-9]+\s+ns/op`)
  1175  	if !re.Match(out) {
  1176  		t.Error("missing benchmark output")
  1177  	}
  1178  }
  1179  
  1180  func TestBenchmarkBNIterationCorrect(t *testing.T) {
  1181  	out := runTest(t, "BenchmarkBNPrint")
  1182  	c := bytes.Count(out, []byte("Printing from BenchmarkBNPrint"))
  1183  
  1184  	// runTest sets benchtime=2x, with semantics specified in #32051 it should
  1185  	// run 3 times.
  1186  	want := 3
  1187  	if c != want {
  1188  		t.Errorf("got %d loop iterations; want %d", c, want)
  1189  	}
  1190  
  1191  	// b.N style fixed iteration loop will rampup twice:
  1192  	// One in run1(), the other in launch
  1193  	c = bytes.Count(out, []byte("Ramping up from BenchmarkBNPrint"))
  1194  	want = 2
  1195  	if c != want {
  1196  		t.Errorf("got %d loop rampup; want %d", c, want)
  1197  	}
  1198  }
  1199  
  1200  func BenchmarkBLoopPrint(b *testing.B) {
  1201  	b.Logf("Ramping up from BenchmarkBLoopPrint")
  1202  	for b.Loop() {
  1203  		b.Logf("Printing from BenchmarkBLoopPrint")
  1204  	}
  1205  }
  1206  
  1207  func BenchmarkBNPrint(b *testing.B) {
  1208  	b.Logf("Ramping up from BenchmarkBNPrint")
  1209  	for i := 0; i < b.N; i++ {
  1210  		b.Logf("Printing from BenchmarkBNPrint")
  1211  	}
  1212  }
  1213  
  1214  func TestArtifactDir(t *testing.T) {
  1215  	t.Log(t.ArtifactDir())
  1216  }
  1217  

View as plain text