Source file
src/os/fifo_test.go
1
2
3
4
5
6
7 package os_test
8
9 import (
10 "errors"
11 "internal/syscall/unix"
12 "internal/testenv"
13 "io"
14 "io/fs"
15 "os"
16 "path/filepath"
17 "strconv"
18 "sync"
19 "syscall"
20 "testing"
21 "time"
22 )
23
24 func TestFifoEOF(t *testing.T) {
25 t.Parallel()
26
27 dir := t.TempDir()
28 fifoName := filepath.Join(dir, "fifo")
29 if err := syscall.Mkfifo(fifoName, 0600); err != nil {
30 t.Fatal(err)
31 }
32
33
34
35
36
37
38
39
40
41
42
43 rc := make(chan *os.File, 1)
44 go func() {
45 r, err := os.Open(fifoName)
46 if err != nil {
47 t.Error(err)
48 }
49 rc <- r
50 }()
51
52 w, err := os.OpenFile(fifoName, os.O_WRONLY, 0)
53 if err != nil {
54 t.Error(err)
55 }
56
57 r := <-rc
58 if t.Failed() {
59 if r != nil {
60 r.Close()
61 }
62 if w != nil {
63 w.Close()
64 }
65 return
66 }
67
68 testPipeEOF(t, r, w)
69 }
70
71
72 func TestNonPollable(t *testing.T) {
73 if testing.Short() {
74 t.Skip("skipping test with tight loops in short mode")
75 }
76
77
78
79
80
81 const nonPollable = "/dev/net/tun"
82
83 f, err := os.OpenFile(nonPollable, os.O_RDWR, 0)
84 if err != nil {
85 if errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrPermission) || testenv.SyscallIsNotSupported(err) {
86 t.Skipf("can't open %q: %v", nonPollable, err)
87 }
88 t.Fatal(err)
89 }
90 f.Close()
91
92
93
94
95
96 const attempts = 20000
97
98 start := make(chan bool)
99 var wg sync.WaitGroup
100 wg.Add(1)
101 defer wg.Wait()
102 go func() {
103 defer wg.Done()
104 close(start)
105 for i := 0; i < attempts; i++ {
106 f, err := os.OpenFile(nonPollable, os.O_RDWR, 0)
107 if err != nil {
108 t.Error(err)
109 return
110 }
111 if err := f.Close(); err != nil {
112 t.Error(err)
113 return
114 }
115 }
116 }()
117
118 dir := t.TempDir()
119 <-start
120 for i := 0; i < attempts; i++ {
121 name := filepath.Join(dir, strconv.Itoa(i))
122 if err := syscall.Mkfifo(name, 0o600); err != nil {
123 t.Fatal(err)
124 }
125
126 rd, err := os.OpenFile(name, os.O_RDONLY|syscall.O_NONBLOCK, 0o600)
127 if err != nil {
128 t.Fatal(err)
129 }
130 wr, err := os.OpenFile(name, os.O_WRONLY|syscall.O_NONBLOCK, 0o600)
131 if err != nil {
132 t.Fatal(err)
133 }
134 const msg = "message"
135 if _, err := wr.Write([]byte(msg)); err != nil {
136 if errors.Is(err, syscall.EAGAIN) || errors.Is(err, syscall.ENOBUFS) {
137 t.Logf("ignoring write error %v", err)
138 rd.Close()
139 wr.Close()
140 continue
141 }
142 t.Fatalf("write to fifo %d failed: %v", i, err)
143 }
144 if _, err := rd.Read(make([]byte, len(msg))); err != nil {
145 if errors.Is(err, syscall.EAGAIN) || errors.Is(err, syscall.ENOBUFS) {
146 t.Logf("ignoring read error %v", err)
147 rd.Close()
148 wr.Close()
149 continue
150 }
151 t.Fatalf("read from fifo %d failed; %v", i, err)
152 }
153 if err := rd.Close(); err != nil {
154 t.Fatal(err)
155 }
156 if err := wr.Close(); err != nil {
157 t.Fatal(err)
158 }
159 }
160 }
161
162
163 func TestOpenFileNonBlocking(t *testing.T) {
164 exe := testenv.Executable(t)
165 f, err := os.OpenFile(exe, os.O_RDONLY|syscall.O_NONBLOCK, 0666)
166 if err != nil {
167 t.Fatal(err)
168 }
169 defer f.Close()
170 nonblock, err := unix.IsNonblock(int(f.Fd()))
171 if err != nil {
172 t.Fatal(err)
173 }
174 if !nonblock {
175 t.Errorf("file opened with O_NONBLOCK but in blocking mode")
176 }
177 }
178
179 func TestNewFileNonBlocking(t *testing.T) {
180 var p [2]int
181 if err := syscall.Pipe(p[:]); err != nil {
182 t.Fatal(err)
183 }
184 if err := syscall.SetNonblock(p[0], true); err != nil {
185 t.Fatal(err)
186 }
187 f := os.NewFile(uintptr(p[0]), "pipe")
188 nonblock, err := unix.IsNonblock(p[0])
189 if err != nil {
190 t.Fatal(err)
191 }
192 defer f.Close()
193 if !nonblock {
194 t.Error("pipe blocking after NewFile")
195 }
196 fd := f.Fd()
197 if fd != uintptr(p[0]) {
198 t.Errorf("Fd returned %d, want %d", fd, p[0])
199 }
200 nonblock, err = unix.IsNonblock(p[0])
201 if err != nil {
202 t.Fatal(err)
203 }
204 if !nonblock {
205 t.Error("pipe blocking after Fd")
206 }
207 }
208
209 func TestFIFONonBlockingEOF(t *testing.T) {
210 fifoName := filepath.Join(t.TempDir(), "issue-66239-fifo")
211 if err := syscall.Mkfifo(fifoName, 0600); err != nil {
212 t.Fatalf("Error creating fifo: %v", err)
213 }
214
215 r, err := os.OpenFile(fifoName, os.O_RDONLY|syscall.O_NONBLOCK, os.ModeNamedPipe)
216 if err != nil {
217 t.Fatalf("Error opening fifo for read: %v", err)
218 }
219 defer r.Close()
220
221 w, err := os.OpenFile(fifoName, os.O_WRONLY, os.ModeNamedPipe)
222 if err != nil {
223 t.Fatalf("Error opening fifo for write: %v", err)
224 }
225 defer w.Close()
226
227 data := "Hello Gophers!"
228 if _, err := w.WriteString(data); err != nil {
229 t.Fatalf("Error writing to fifo: %v", err)
230 }
231
232
233
234 time.AfterFunc(200*time.Millisecond, func() {
235 if err := w.Close(); err != nil {
236 t.Errorf("Error closing writer: %v", err)
237 }
238 })
239
240 buf := make([]byte, len(data))
241 n, err := io.ReadAtLeast(r, buf, len(data))
242 if n != len(data) || string(buf) != data || err != nil {
243 t.Errorf("ReadAtLeast: %v; got %q, want %q", err, buf, data)
244 return
245 }
246
247
248
249
250 for {
251 _, err = r.Read(buf)
252 if errors.Is(err, io.EOF) {
253 break
254 }
255 if err != nil && !errors.Is(err, syscall.EAGAIN) {
256 t.Errorf("Error reading bytes from fifo: %v", err)
257 return
258 }
259 }
260 }
261
View as plain text