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, err := os.Executable()
165 if err != nil {
166 t.Skipf("can't find executable: %v", err)
167 }
168 f, err := os.OpenFile(exe, os.O_RDONLY|syscall.O_NONBLOCK, 0666)
169 if err != nil {
170 t.Fatal(err)
171 }
172 defer f.Close()
173 nonblock, err := unix.IsNonblock(int(f.Fd()))
174 if err != nil {
175 t.Fatal(err)
176 }
177 if !nonblock {
178 t.Errorf("file opened with O_NONBLOCK but in blocking mode")
179 }
180 }
181
182 func TestNewFileNonBlocking(t *testing.T) {
183 var p [2]int
184 if err := syscall.Pipe(p[:]); err != nil {
185 t.Fatal(err)
186 }
187 if err := syscall.SetNonblock(p[0], true); err != nil {
188 t.Fatal(err)
189 }
190 f := os.NewFile(uintptr(p[0]), "pipe")
191 nonblock, err := unix.IsNonblock(p[0])
192 if err != nil {
193 t.Fatal(err)
194 }
195 defer f.Close()
196 if !nonblock {
197 t.Error("pipe blocking after NewFile")
198 }
199 fd := f.Fd()
200 if fd != uintptr(p[0]) {
201 t.Errorf("Fd returned %d, want %d", fd, p[0])
202 }
203 nonblock, err = unix.IsNonblock(p[0])
204 if err != nil {
205 t.Fatal(err)
206 }
207 if !nonblock {
208 t.Error("pipe blocking after Fd")
209 }
210 }
211
212 func TestFIFONonBlockingEOF(t *testing.T) {
213 fifoName := filepath.Join(t.TempDir(), "issue-66239-fifo")
214 if err := syscall.Mkfifo(fifoName, 0600); err != nil {
215 t.Fatalf("Error creating fifo: %v", err)
216 }
217
218 r, err := os.OpenFile(fifoName, os.O_RDONLY|syscall.O_NONBLOCK, os.ModeNamedPipe)
219 if err != nil {
220 t.Fatalf("Error opening fifo for read: %v", err)
221 }
222 defer r.Close()
223
224 w, err := os.OpenFile(fifoName, os.O_WRONLY, os.ModeNamedPipe)
225 if err != nil {
226 t.Fatalf("Error opening fifo for write: %v", err)
227 }
228 defer w.Close()
229
230 data := "Hello Gophers!"
231 if _, err := w.WriteString(data); err != nil {
232 t.Fatalf("Error writing to fifo: %v", err)
233 }
234
235
236
237 time.AfterFunc(200*time.Millisecond, func() {
238 if err := w.Close(); err != nil {
239 t.Errorf("Error closing writer: %v", err)
240 }
241 })
242
243 buf := make([]byte, len(data))
244 n, err := io.ReadAtLeast(r, buf, len(data))
245 if n != len(data) || string(buf) != data || err != nil {
246 t.Errorf("ReadAtLeast: %v; got %q, want %q", err, buf, data)
247 return
248 }
249
250
251
252
253 for {
254 _, err = r.Read(buf)
255 if errors.Is(err, io.EOF) {
256 break
257 }
258 if err != nil && !errors.Is(err, syscall.EAGAIN) {
259 t.Errorf("Error reading bytes from fifo: %v", err)
260 return
261 }
262 }
263 }
264
View as plain text