Source file
src/os/fifo_test.go
Documentation: os
1
2
3
4
5
6
7 package os_test
8
9 import (
10 "errors"
11 "internal/syscall/unix"
12 "internal/testenv"
13 "io/fs"
14 "os"
15 "path/filepath"
16 "strconv"
17 "sync"
18 "syscall"
19 "testing"
20 )
21
22 func TestFifoEOF(t *testing.T) {
23 t.Parallel()
24
25 dir := t.TempDir()
26 fifoName := filepath.Join(dir, "fifo")
27 if err := syscall.Mkfifo(fifoName, 0600); err != nil {
28 t.Fatal(err)
29 }
30
31
32
33
34
35
36
37
38
39
40
41 rc := make(chan *os.File, 1)
42 go func() {
43 r, err := os.Open(fifoName)
44 if err != nil {
45 t.Error(err)
46 }
47 rc <- r
48 }()
49
50 w, err := os.OpenFile(fifoName, os.O_WRONLY, 0)
51 if err != nil {
52 t.Error(err)
53 }
54
55 r := <-rc
56 if t.Failed() {
57 if r != nil {
58 r.Close()
59 }
60 if w != nil {
61 w.Close()
62 }
63 return
64 }
65
66 testPipeEOF(t, r, w)
67 }
68
69
70 func TestNonPollable(t *testing.T) {
71 if testing.Short() {
72 t.Skip("skipping test with tight loops in short mode")
73 }
74
75
76
77
78
79 const nonPollable = "/dev/net/tun"
80
81 f, err := os.OpenFile(nonPollable, os.O_RDWR, 0)
82 if err != nil {
83 if errors.Is(err, fs.ErrNotExist) || errors.Is(err, fs.ErrPermission) || testenv.SyscallIsNotSupported(err) {
84 t.Skipf("can't open %q: %v", nonPollable, err)
85 }
86 t.Fatal(err)
87 }
88 f.Close()
89
90
91
92
93
94 const attempts = 20000
95
96 start := make(chan bool)
97 var wg sync.WaitGroup
98 wg.Add(1)
99 defer wg.Wait()
100 go func() {
101 defer wg.Done()
102 close(start)
103 for i := 0; i < attempts; i++ {
104 f, err := os.OpenFile(nonPollable, os.O_RDWR, 0)
105 if err != nil {
106 t.Error(err)
107 return
108 }
109 if err := f.Close(); err != nil {
110 t.Error(err)
111 return
112 }
113 }
114 }()
115
116 dir := t.TempDir()
117 <-start
118 for i := 0; i < attempts; i++ {
119 name := filepath.Join(dir, strconv.Itoa(i))
120 if err := syscall.Mkfifo(name, 0o600); err != nil {
121 t.Fatal(err)
122 }
123
124 rd, err := os.OpenFile(name, os.O_RDONLY|syscall.O_NONBLOCK, 0o600)
125 if err != nil {
126 t.Fatal(err)
127 }
128 wr, err := os.OpenFile(name, os.O_WRONLY|syscall.O_NONBLOCK, 0o600)
129 if err != nil {
130 t.Fatal(err)
131 }
132 const msg = "message"
133 if _, err := wr.Write([]byte(msg)); err != nil {
134 if errors.Is(err, syscall.EAGAIN) || errors.Is(err, syscall.ENOBUFS) {
135 t.Logf("ignoring write error %v", err)
136 rd.Close()
137 wr.Close()
138 continue
139 }
140 t.Fatalf("write to fifo %d failed: %v", i, err)
141 }
142 if _, err := rd.Read(make([]byte, len(msg))); err != nil {
143 if errors.Is(err, syscall.EAGAIN) || errors.Is(err, syscall.ENOBUFS) {
144 t.Logf("ignoring read error %v", err)
145 rd.Close()
146 wr.Close()
147 continue
148 }
149 t.Fatalf("read from fifo %d failed; %v", i, err)
150 }
151 if err := rd.Close(); err != nil {
152 t.Fatal(err)
153 }
154 if err := wr.Close(); err != nil {
155 t.Fatal(err)
156 }
157 }
158 }
159
160
161 func TestOpenFileNonBlocking(t *testing.T) {
162 exe, err := os.Executable()
163 if err != nil {
164 t.Skipf("can't find executable: %v", err)
165 }
166 f, err := os.OpenFile(exe, os.O_RDONLY|syscall.O_NONBLOCK, 0666)
167 if err != nil {
168 t.Fatal(err)
169 }
170 defer f.Close()
171 nonblock, err := unix.IsNonblock(int(f.Fd()))
172 if err != nil {
173 t.Fatal(err)
174 }
175 if !nonblock {
176 t.Errorf("file opened with O_NONBLOCK but in blocking mode")
177 }
178 }
179
180 func TestNewFileNonBlocking(t *testing.T) {
181 var p [2]int
182 if err := syscall.Pipe(p[:]); err != nil {
183 t.Fatal(err)
184 }
185 if err := syscall.SetNonblock(p[0], true); err != nil {
186 t.Fatal(err)
187 }
188 f := os.NewFile(uintptr(p[0]), "pipe")
189 nonblock, err := unix.IsNonblock(p[0])
190 if err != nil {
191 t.Fatal(err)
192 }
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
View as plain text