]> Cypherpunks repositories - gostls13.git/commitdiff
testing: make TempDir idempotent for both Cleanup and Benchmark
authorChangkun Ou <hi@changkun.us>
Fri, 28 Aug 2020 10:13:37 +0000 (12:13 +0200)
committerEmmanuel Odeke <emm.odeke@gmail.com>
Sat, 5 Sep 2020 04:21:49 +0000 (04:21 +0000)
Ensures that calling TempDir() in either of Cleanup or Benchmark
doesn't cause test failures which were previously caused by the
created directory having been deleted after the first run, yet
we prevented the recreation of the directory due to our selection
of concurrency primitive sync.Once. This change recreates the
temporary directory if it doesn't exist, regardless of how
many times Cleanup and Benchmark are invoked.

Fixes #41062

Change-Id: I925d9f7207d7c369a193d1e17da7a59a586244a7
Reviewed-on: https://go-review.googlesource.com/c/go/+/251297
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/testing/testing.go
src/testing/testing_test.go

index a64206f349233b9d9069b7412468fe62d9943ae3..66f296234a5b1a7ffa12b18d47091c6abb158b79 100644 (file)
@@ -413,10 +413,10 @@ type common struct {
        signal   chan bool // To signal a test is done.
        sub      []*T      // Queue of subtests to be run in parallel.
 
-       tempDirOnce sync.Once
-       tempDir     string
-       tempDirErr  error
-       tempDirSeq  int32
+       tempDirMu  sync.Mutex
+       tempDir    string
+       tempDirErr error
+       tempDirSeq int32
 }
 
 // Short reports whether the -test.short flag is set.
@@ -903,7 +903,19 @@ var tempDirReplacer struct {
 func (c *common) TempDir() string {
        // Use a single parent directory for all the temporary directories
        // created by a test, each numbered sequentially.
-       c.tempDirOnce.Do(func() {
+       c.tempDirMu.Lock()
+       var nonExistent bool
+       if c.tempDir == "" { // Usually the case with js/wasm
+               nonExistent = true
+       } else {
+               _, err := os.Stat(c.tempDir)
+               nonExistent = os.IsNotExist(err)
+               if err != nil && !nonExistent {
+                       c.Fatalf("TempDir: %v", err)
+               }
+       }
+
+       if nonExistent {
                c.Helper()
 
                // ioutil.TempDir doesn't like path separators in its pattern,
@@ -921,7 +933,9 @@ func (c *common) TempDir() string {
                                }
                        })
                }
-       })
+       }
+       c.tempDirMu.Unlock()
+
        if c.tempDirErr != nil {
                c.Fatalf("TempDir: %v", c.tempDirErr)
        }
index dbef7066e0e8c121b0bc7c3e6c628ce3482651d4..d665a334e4d179cda97751319920c4a822dadd91 100644 (file)
@@ -19,6 +19,38 @@ func TestMain(m *testing.M) {
        os.Exit(m.Run())
 }
 
+func TestTempDirInCleanup(t *testing.T) {
+       var dir string
+
+       t.Run("test", func(t *testing.T) {
+               t.Cleanup(func() {
+                       dir = t.TempDir()
+               })
+               _ = t.TempDir()
+       })
+
+       fi, err := os.Stat(dir)
+       if fi != nil {
+               t.Fatalf("Directory %q from user Cleanup still exists", dir)
+       }
+       if !os.IsNotExist(err) {
+               t.Fatalf("Unexpected error: %v", err)
+       }
+}
+
+func TestTempDirInBenchmark(t *testing.T) {
+       testing.Benchmark(func(b *testing.B) {
+               if !b.Run("test", func(b *testing.B) {
+                       // Add a loop so that the test won't fail. See issue 38677.
+                       for i := 0; i < b.N; i++ {
+                               _ = b.TempDir()
+                       }
+               }) {
+                       t.Fatal("Sub test failure in a benchmark")
+               }
+       })
+}
+
 func TestTempDir(t *testing.T) {
        testTempDir(t)
        t.Run("InSubtest", testTempDir)