| // Copyright 2015 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // +build darwin dragonfly freebsd linux netbsd openbsd | |
| package os_test | |
| import ( | |
| "bufio" | |
| "bytes" | |
| "fmt" | |
| "io" | |
| "io/ioutil" | |
| "os" | |
| "path/filepath" | |
| "runtime" | |
| "sync" | |
| "syscall" | |
| "testing" | |
| "time" | |
| ) | |
| // Issue 24164. | |
| func TestFifoEOF(t *testing.T) { | |
| switch runtime.GOOS { | |
| case "android": | |
| t.Skip("skipping on Android; mkfifo syscall not available") | |
| case "openbsd": | |
| // On OpenBSD 6.2 this test just hangs for some reason. | |
| t.Skip("skipping on OpenBSD; issue 25877") | |
| } | |
| dir, err := ioutil.TempDir("", "TestFifoEOF") | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| defer os.RemoveAll(dir) | |
| fifoName := filepath.Join(dir, "fifo") | |
| if err := syscall.Mkfifo(fifoName, 0600); err != nil { | |
| t.Fatal(err) | |
| } | |
| var wg sync.WaitGroup | |
| wg.Add(1) | |
| go func() { | |
| defer wg.Done() | |
| w, err := os.OpenFile(fifoName, os.O_WRONLY, 0) | |
| if err != nil { | |
| t.Error(err) | |
| return | |
| } | |
| defer func() { | |
| if err := w.Close(); err != nil { | |
| t.Errorf("error closing writer: %v", err) | |
| } | |
| }() | |
| for i := 0; i < 3; i++ { | |
| time.Sleep(10 * time.Millisecond) | |
| _, err := fmt.Fprintf(w, "line %d\n", i) | |
| if err != nil { | |
| t.Errorf("error writing to fifo: %v", err) | |
| return | |
| } | |
| } | |
| time.Sleep(10 * time.Millisecond) | |
| }() | |
| defer wg.Wait() | |
| r, err := os.Open(fifoName) | |
| if err != nil { | |
| t.Fatal(err) | |
| } | |
| done := make(chan bool) | |
| go func() { | |
| defer close(done) | |
| defer func() { | |
| if err := r.Close(); err != nil { | |
| t.Errorf("error closing reader: %v", err) | |
| } | |
| }() | |
| rbuf := bufio.NewReader(r) | |
| for { | |
| b, err := rbuf.ReadBytes('\n') | |
| if err == io.EOF { | |
| break | |
| } | |
| if err != nil { | |
| t.Error(err) | |
| return | |
| } | |
| t.Logf("%s\n", bytes.TrimSpace(b)) | |
| } | |
| }() | |
| select { | |
| case <-done: | |
| // Test succeeded. | |
| case <-time.After(time.Second): | |
| t.Error("timed out waiting for read") | |
| // Close the reader to force the read to complete. | |
| r.Close() | |
| } | |
| } |