diff --git a/src/os/os_test.go b/src/os/os_test.go index 0a6be3516a..ad30756cbd 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -1696,11 +1696,35 @@ func TestChdirAndGetwd(t *testing.T) { // Test that Chdir+Getwd is program-wide. func TestProgWideChdir(t *testing.T) { const N = 10 - const ErrPwd = "Error!" - c := make(chan bool) - cpwd := make(chan string, N) + var wg sync.WaitGroup + hold := make(chan struct{}) + done := make(chan struct{}) + + d := t.TempDir() + oldwd, err := Getwd() + if err != nil { + t.Fatalf("Getwd: %v", err) + } + defer func() { + if err := Chdir(oldwd); err != nil { + // It's not safe to continue with tests if we can't get back to + // the original working directory. + panic(err) + } + }() + + // Note the deferred Wait must be called after the deferred close(done), + // to ensure the N goroutines have been released even if the main goroutine + // calls Fatalf. It must be called before the Chdir back to the original + // directory, and before the deferred deletion implied by TempDir, + // so as not to interfere while the N goroutines are still running. + defer wg.Wait() + defer close(done) + for i := 0; i < N; i++ { + wg.Add(1) go func(i int) { + defer wg.Done() // Lock half the goroutines in their own operating system // thread to exercise more scheduler possibilities. if i%2 == 1 { @@ -1711,57 +1735,48 @@ func TestProgWideChdir(t *testing.T) { // See issue 9428. runtime.LockOSThread() } - hasErr, closed := <-c - if !closed && hasErr { - cpwd <- ErrPwd + select { + case <-done: + return + case <-hold: + } + // Getwd might be wrong + f0, err := Stat(".") + if err != nil { + t.Error(err) return } pwd, err := Getwd() if err != nil { - t.Errorf("Getwd on goroutine %d: %v", i, err) - cpwd <- ErrPwd + t.Errorf("Getwd: %v", err) + return + } + if pwd != d { + t.Errorf("Getwd() = %q, want %q", pwd, d) + return + } + f1, err := Stat(pwd) + if err != nil { + t.Error(err) + return + } + if !SameFile(f0, f1) { + t.Errorf(`Samefile(Stat("."), Getwd()) reports false (%s != %s)`, f0.Name(), f1.Name()) return } - cpwd <- pwd }(i) } - oldwd, err := Getwd() - if err != nil { - c <- true - t.Fatalf("Getwd: %v", err) - } - d, err := MkdirTemp("", "test") - if err != nil { - c <- true - t.Fatalf("TempDir: %v", err) - } - defer func() { - if err := Chdir(oldwd); err != nil { - t.Fatalf("Chdir: %v", err) - } - RemoveAll(d) - }() - if err := Chdir(d); err != nil { - c <- true + if err = Chdir(d); err != nil { t.Fatalf("Chdir: %v", err) } // OS X sets TMPDIR to a symbolic link. // So we resolve our working directory again before the test. d, err = Getwd() if err != nil { - c <- true t.Fatalf("Getwd: %v", err) } - close(c) - for i := 0; i < N; i++ { - pwd := <-cpwd - if pwd == ErrPwd { - t.FailNow() - } - if pwd != d { - t.Errorf("Getwd returned %q; want %q", pwd, d) - } - } + close(hold) + wg.Wait() } func TestSeek(t *testing.T) {