v2 / vlib / os / notify / notify_test.c.v
169 lines · 145 sloc · 4.38 KB · dc96eb95ba0f24fa68aba040718b86bfe2280a33
Raw
1// vtest flaky: true
2// vtest retry: 3
3import os
4import os.notify
5
6fn test_level_trigger() {
7 // currently only linux and macos are supported
8 $if linux || macos {
9 mut notifier := notify.new()!
10 mut pipe := os.pipe()!
11 defer {
12 pipe.close()
13 notifier.close() or {}
14 }
15 notifier.add(pipe.read_fd, .read)!
16
17 pipe.write_string('foobar')!
18 mut n := ¬ifier
19 check_read_event(mut n, pipe.read_fd, 'foo')
20 check_read_event(mut n, pipe.read_fd, 'bar')
21
22 assert notifier.wait(0).len == 0
23 }
24}
25
26fn test_edge_trigger() {
27 // currently only linux and macos are supported
28 $if linux || macos {
29 mut notifier := notify.new()!
30 mut pipe := os.pipe()!
31 defer {
32 pipe.close()
33 notifier.close() or {}
34 }
35 notifier.add(pipe.read_fd, .read, .edge_trigger)!
36
37 mut n := ¬ifier
38
39 pipe.write_string('foobar')!
40 check_read_event(mut n, pipe.read_fd, 'foo')
41
42 $if linux {
43 assert notifier.wait(0).len == 0
44 }
45 $if macos {
46 /*
47 In the kqueue of macos, EV_CLEAR flag represents a clear event,
48 which is mainly used for pipeline and socket class events. When this flag is set,
49 kqueue will trigger the corresponding event when the data is readable or writable,
50 but it is not guaranteed that the event will only be triggered once.
51 Compared to EPOLLET, EV_CLEAR's behavior varies. In epoll, the edge triggered mode only triggers
52 an event once when the state changes from unreadable/non writable to readable/writable,
53 that is, when the data changes from unreadable to readable,
54 or when the data changes from unreadable to writable. In the kqueue of macos,
55 EV_CLEAR does not possess this precise edge triggering behavior.
56 Therefore, in the kqueue of macos, even if the data is not completely read,
57 it is possible to continue triggering read events. This means that if you don't process all the data,
58 the next kqueue event notification may still be triggered
59 */
60
61 // notifier.wait(0).len == 1 or 0
62 }
63
64 pipe.write_string('baz')!
65 check_read_event(mut n, pipe.read_fd, 'barbaz')
66 // we do not get an event because there is still data
67 // to be read
68 // assert notifier.wait(0).len == 0
69 // TODO: investigage why the above assert suddenly started failing on the latest Ubuntu kernel update:
70 // 5.11.0-37-generic #41~20.04.2-Ubuntu SMP Fri Sep 24 09:06:38 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
71 }
72}
73
74fn test_one_shot() {
75 $if linux || macos {
76 mut notifier := notify.new()!
77 mut pipe := os.pipe()!
78 defer {
79 pipe.close()
80 notifier.close() or {}
81 }
82 notifier.add(pipe.read_fd, .read, .one_shot)!
83
84 mut n := ¬ifier
85
86 pipe.write_string('foobar')!
87 check_read_event(mut n, pipe.read_fd, 'foo')
88 pipe.write_string('baz')!
89
90 assert notifier.wait(0).len == 0
91
92 // rearm
93 notifier.modify(pipe.read_fd, .read)!
94 check_read_event(mut n, pipe.read_fd, 'barbaz')
95 }
96}
97
98// Kqueue does not support 'hangup' event type.
99fn test_hangup() {
100 $if linux {
101 mut notifier := notify.new()!
102 mut pipe := os.pipe()!
103 defer {
104 os.fd_close(pipe.read_fd)
105 notifier.close() or {}
106 }
107 notifier.add(pipe.read_fd, .hangup)!
108
109 assert notifier.wait(0).len == 0
110
111 // closing on the writer end of the pipe will
112 // cause a hangup on the reader end
113 os.fd_close(pipe.write_fd)
114 events := notifier.wait(0)
115 assert events.len == 1
116 assert events[0].fd == pipe.read_fd
117 assert events[0].kind.has(.hangup)
118 }
119}
120
121fn test_write() {
122 $if linux || macos {
123 mut notifier := notify.new()!
124 mut pipe := os.pipe()!
125 defer {
126 pipe.close()
127 notifier.close() or {}
128 }
129
130 notifier.add(pipe.read_fd, .write)!
131 assert notifier.wait(0).len == 0
132
133 notifier.add(pipe.write_fd, .write)!
134 events := notifier.wait(0)
135 assert events.len == 1
136 assert events[0].fd == pipe.write_fd
137 assert events[0].kind.has(.write)
138 }
139}
140
141fn test_remove() {
142 $if linux || macos {
143 mut notifier := notify.new()!
144 mut pipe := os.pipe()!
145 defer {
146 pipe.close()
147 notifier.close() or {}
148 }
149
150 // level triggered - will keep getting events while
151 // there is data to read
152 notifier.add(pipe.read_fd, .read)!
153 pipe.write_string('foobar')!
154 assert notifier.wait(0).len == 1
155 assert notifier.wait(0).len == 1
156
157 notifier.remove(pipe.read_fd)!
158 assert notifier.wait(0).len == 0
159 }
160}
161
162fn check_read_event(mut notifier notify.FdNotifier, reader_fd int, expected string) {
163 events := notifier.wait(0)
164 assert events.len == 1
165 assert events[0].fd == reader_fd
166 assert events[0].kind.has(.read)
167 s, _ := os.fd_read(events[0].fd, expected.len)
168 assert s == expected
169}
170