// 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 {
// 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) {