1/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 */
21
22#include "uv.h"
23#include "task.h"
24
25#include <string.h>
26
27#define FIXTURE "testfile"
28
29static void timer_cb(uv_timer_t* handle);
30static void close_cb(uv_handle_t* handle);
31static void poll_cb(uv_fs_poll_t* handle,
32 int status,
33 const uv_stat_t* prev,
34 const uv_stat_t* curr);
35
36static void poll_cb_fail(uv_fs_poll_t* handle,
37 int status,
38 const uv_stat_t* prev,
39 const uv_stat_t* curr);
40static void poll_cb_noop(uv_fs_poll_t* handle,
41 int status,
42 const uv_stat_t* prev,
43 const uv_stat_t* curr);
44
45static uv_fs_poll_t poll_handle;
46static uv_timer_t timer_handle;
47static uv_loop_t* loop;
48
49static int poll_cb_called;
50static int timer_cb_called;
51static int close_cb_called;
52
53
54static void touch_file(const char* path) {
55 static int count;
56 FILE* fp;
57 int i;
58
59 ASSERT((fp = fopen(FIXTURE, "w+")));
60
61 /* Need to change the file size because the poller may not pick up
62 * sub-second mtime changes.
63 */
64 i = ++count;
65
66 while (i--)
67 fputc('*', fp);
68
69 fclose(fp);
70}
71
72
73static void close_cb(uv_handle_t* handle) {
74 close_cb_called++;
75}
76
77
78static void timer_cb(uv_timer_t* handle) {
79 touch_file(FIXTURE);
80 timer_cb_called++;
81}
82
83
84static void poll_cb_fail(uv_fs_poll_t* handle,
85 int status,
86 const uv_stat_t* prev,
87 const uv_stat_t* curr) {
88 ASSERT(0 && "fail_cb called");
89}
90
91static void poll_cb_noop(uv_fs_poll_t* handle,
92 int status,
93 const uv_stat_t* prev,
94 const uv_stat_t* curr) {
95}
96
97
98static void poll_cb(uv_fs_poll_t* handle,
99 int status,
100 const uv_stat_t* prev,
101 const uv_stat_t* curr) {
102 uv_stat_t zero_statbuf;
103
104 memset(&zero_statbuf, 0, sizeof(zero_statbuf));
105
106 ASSERT(handle == &poll_handle);
107 ASSERT(1 == uv_is_active((uv_handle_t*) handle));
108 ASSERT(prev != NULL);
109 ASSERT(curr != NULL);
110
111 switch (poll_cb_called++) {
112 case 0:
113 ASSERT(status == UV_ENOENT);
114 ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
115 ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
116 touch_file(FIXTURE);
117 break;
118
119 case 1:
120 ASSERT(status == 0);
121 ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
122 ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
123 ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 20, 0));
124 break;
125
126 case 2:
127 ASSERT(status == 0);
128 ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
129 ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
130 ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 200, 0));
131 break;
132
133 case 3:
134 ASSERT(status == 0);
135 ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
136 ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
137 remove(FIXTURE);
138 break;
139
140 case 4:
141 ASSERT(status == UV_ENOENT);
142 ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf)));
143 ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf)));
144 uv_close((uv_handle_t*)handle, close_cb);
145 break;
146
147 default:
148 ASSERT(0);
149 }
150}
151
152
153TEST_IMPL(fs_poll) {
154 loop = uv_default_loop();
155
156 remove(FIXTURE);
157
158 ASSERT(0 == uv_timer_init(loop, &timer_handle));
159 ASSERT(0 == uv_fs_poll_init(loop, &poll_handle));
160 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb, FIXTURE, 100));
161 ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
162
163 ASSERT(poll_cb_called == 5);
164 ASSERT(timer_cb_called == 2);
165 ASSERT(close_cb_called == 1);
166
167 MAKE_VALGRIND_HAPPY();
168 return 0;
169}
170
171
172TEST_IMPL(fs_poll_getpath) {
173 char buf[1024];
174 size_t len;
175 loop = uv_default_loop();
176
177 remove(FIXTURE);
178
179 ASSERT(0 == uv_fs_poll_init(loop, &poll_handle));
180 len = sizeof buf;
181 ASSERT(UV_EINVAL == uv_fs_poll_getpath(&poll_handle, buf, &len));
182 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100));
183 len = sizeof buf;
184 ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len));
185 ASSERT(buf[len - 1] != 0);
186 ASSERT(buf[len] == '\0');
187 ASSERT(0 == memcmp(buf, FIXTURE, len));
188
189 uv_close((uv_handle_t*) &poll_handle, close_cb);
190
191 ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
192
193 ASSERT(close_cb_called == 1);
194
195 MAKE_VALGRIND_HAPPY();
196 return 0;
197}
198
199
200TEST_IMPL(fs_poll_close_request) {
201 uv_loop_t loop;
202 uv_fs_poll_t poll_handle;
203
204 remove(FIXTURE);
205
206 ASSERT(0 == uv_loop_init(&loop));
207
208 ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle));
209 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100));
210 uv_close((uv_handle_t*) &poll_handle, close_cb);
211 while (close_cb_called == 0)
212 uv_run(&loop, UV_RUN_ONCE);
213 ASSERT(close_cb_called == 1);
214
215 ASSERT(0 == uv_loop_close(&loop));
216
217 MAKE_VALGRIND_HAPPY();
218 return 0;
219}
220
221TEST_IMPL(fs_poll_close_request_multi_start_stop) {
222 uv_loop_t loop;
223 uv_fs_poll_t poll_handle;
224 int i;
225
226 remove(FIXTURE);
227
228 ASSERT(0 == uv_loop_init(&loop));
229
230 ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle));
231
232 for (i = 0; i < 10; ++i) {
233 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100));
234 ASSERT(0 == uv_fs_poll_stop(&poll_handle));
235 }
236 uv_close((uv_handle_t*) &poll_handle, close_cb);
237 while (close_cb_called == 0)
238 uv_run(&loop, UV_RUN_ONCE);
239 ASSERT(close_cb_called == 1);
240
241 ASSERT(0 == uv_loop_close(&loop));
242
243 MAKE_VALGRIND_HAPPY();
244 return 0;
245}
246
247TEST_IMPL(fs_poll_close_request_multi_stop_start) {
248 uv_loop_t loop;
249 uv_fs_poll_t poll_handle;
250 int i;
251
252 remove(FIXTURE);
253
254 ASSERT(0 == uv_loop_init(&loop));
255
256 ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle));
257
258 for (i = 0; i < 10; ++i) {
259 ASSERT(0 == uv_fs_poll_stop(&poll_handle));
260 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100));
261 }
262 uv_close((uv_handle_t*) &poll_handle, close_cb);
263 while (close_cb_called == 0)
264 uv_run(&loop, UV_RUN_ONCE);
265 ASSERT(close_cb_called == 1);
266
267 ASSERT(0 == uv_loop_close(&loop));
268
269 MAKE_VALGRIND_HAPPY();
270 return 0;
271}
272
273TEST_IMPL(fs_poll_close_request_stop_when_active) {
274 /* Regression test for https://github.com/libuv/libuv/issues/2287. */
275 uv_loop_t loop;
276 uv_fs_poll_t poll_handle;
277
278 remove(FIXTURE);
279
280 ASSERT(0 == uv_loop_init(&loop));
281
282 /* Set up all handles. */
283 ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle));
284 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_noop, FIXTURE, 100));
285 uv_run(&loop, UV_RUN_ONCE);
286
287 /* Close the timer handle, and do not crash. */
288 ASSERT(0 == uv_fs_poll_stop(&poll_handle));
289 uv_run(&loop, UV_RUN_ONCE);
290
291 /* Clean up after the test. */
292 uv_close((uv_handle_t*) &poll_handle, close_cb);
293 uv_run(&loop, UV_RUN_ONCE);
294 ASSERT(close_cb_called == 1);
295
296 ASSERT(0 == uv_loop_close(&loop));
297
298 MAKE_VALGRIND_HAPPY();
299 return 0;
300}
301