1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build linux
6// +build linux
7
8package fsnotify
9
10import (
11	"testing"
12	"time"
13
14	"golang.org/x/sys/unix"
15)
16
17type testFd [2]int
18
19func makeTestFd(t *testing.T) testFd {
20	var tfd testFd
21	errno := unix.Pipe(tfd[:])
22	if errno != nil {
23		t.Fatalf("Failed to create pipe: %v", errno)
24	}
25	return tfd
26}
27
28func (tfd testFd) fd() int {
29	return tfd[0]
30}
31
32func (tfd testFd) closeWrite(t *testing.T) {
33	errno := unix.Close(tfd[1])
34	if errno != nil {
35		t.Fatalf("Failed to close write end of pipe: %v", errno)
36	}
37}
38
39func (tfd testFd) put(t *testing.T) {
40	buf := make([]byte, 10)
41	_, errno := unix.Write(tfd[1], buf)
42	if errno != nil {
43		t.Fatalf("Failed to write to pipe: %v", errno)
44	}
45}
46
47func (tfd testFd) get(t *testing.T) {
48	buf := make([]byte, 10)
49	_, errno := unix.Read(tfd[0], buf)
50	if errno != nil {
51		t.Fatalf("Failed to read from pipe: %v", errno)
52	}
53}
54
55func (tfd testFd) close() {
56	unix.Close(tfd[1])
57	unix.Close(tfd[0])
58}
59
60func makePoller(t *testing.T) (testFd, *fdPoller) {
61	tfd := makeTestFd(t)
62	poller, err := newFdPoller(tfd.fd())
63	if err != nil {
64		t.Fatalf("Failed to create poller: %v", err)
65	}
66	return tfd, poller
67}
68
69func TestPollerWithBadFd(t *testing.T) {
70	_, err := newFdPoller(-1)
71	if err != unix.EBADF {
72		t.Fatalf("Expected EBADF, got: %v", err)
73	}
74}
75
76func TestPollerWithData(t *testing.T) {
77	tfd, poller := makePoller(t)
78	defer tfd.close()
79	defer poller.close()
80
81	tfd.put(t)
82	ok, err := poller.wait()
83	if err != nil {
84		t.Fatalf("poller failed: %v", err)
85	}
86	if !ok {
87		t.Fatalf("expected poller to return true")
88	}
89	tfd.get(t)
90}
91
92func TestPollerWithWakeup(t *testing.T) {
93	tfd, poller := makePoller(t)
94	defer tfd.close()
95	defer poller.close()
96
97	err := poller.wake()
98	if err != nil {
99		t.Fatalf("wake failed: %v", err)
100	}
101	ok, err := poller.wait()
102	if err != nil {
103		t.Fatalf("poller failed: %v", err)
104	}
105	if ok {
106		t.Fatalf("expected poller to return false")
107	}
108}
109
110func TestPollerWithClose(t *testing.T) {
111	tfd, poller := makePoller(t)
112	defer tfd.close()
113	defer poller.close()
114
115	tfd.closeWrite(t)
116	ok, err := poller.wait()
117	if err != nil {
118		t.Fatalf("poller failed: %v", err)
119	}
120	if !ok {
121		t.Fatalf("expected poller to return true")
122	}
123}
124
125func TestPollerWithWakeupAndData(t *testing.T) {
126	tfd, poller := makePoller(t)
127	defer tfd.close()
128	defer poller.close()
129
130	tfd.put(t)
131	err := poller.wake()
132	if err != nil {
133		t.Fatalf("wake failed: %v", err)
134	}
135
136	// both data and wakeup
137	ok, err := poller.wait()
138	if err != nil {
139		t.Fatalf("poller failed: %v", err)
140	}
141	if !ok {
142		t.Fatalf("expected poller to return true")
143	}
144
145	// data is still in the buffer, wakeup is cleared
146	ok, err = poller.wait()
147	if err != nil {
148		t.Fatalf("poller failed: %v", err)
149	}
150	if !ok {
151		t.Fatalf("expected poller to return true")
152	}
153
154	tfd.get(t)
155	// data is gone, only wakeup now
156	err = poller.wake()
157	if err != nil {
158		t.Fatalf("wake failed: %v", err)
159	}
160	ok, err = poller.wait()
161	if err != nil {
162		t.Fatalf("poller failed: %v", err)
163	}
164	if ok {
165		t.Fatalf("expected poller to return false")
166	}
167}
168
169func TestPollerConcurrent(t *testing.T) {
170	tfd, poller := makePoller(t)
171	defer tfd.close()
172	defer poller.close()
173
174	oks := make(chan bool)
175	live := make(chan bool)
176	defer close(live)
177	go func() {
178		defer close(oks)
179		for {
180			ok, err := poller.wait()
181			if err != nil {
182				t.Fatalf("poller failed: %v", err)
183			}
184			oks <- ok
185			if !<-live {
186				return
187			}
188		}
189	}()
190
191	// Try a write
192	select {
193	case <-time.After(50 * time.Millisecond):
194	case <-oks:
195		t.Fatalf("poller did not wait")
196	}
197	tfd.put(t)
198	if !<-oks {
199		t.Fatalf("expected true")
200	}
201	tfd.get(t)
202	live <- true
203
204	// Try a wakeup
205	select {
206	case <-time.After(50 * time.Millisecond):
207	case <-oks:
208		t.Fatalf("poller did not wait")
209	}
210	err := poller.wake()
211	if err != nil {
212		t.Fatalf("wake failed: %v", err)
213	}
214	if <-oks {
215		t.Fatalf("expected false")
216	}
217	live <- true
218
219	// Try a close
220	select {
221	case <-time.After(50 * time.Millisecond):
222	case <-oks:
223		t.Fatalf("poller did not wait")
224	}
225	tfd.closeWrite(t)
226	if !<-oks {
227		t.Fatalf("expected true")
228	}
229	tfd.get(t)
230}
231