]> git.proxmox.com Git - rustc.git/blob - src/libuv/test/test-fs-event.c
Imported Upstream version 0.7
[rustc.git] / src / libuv / test / test-fs-event.c
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 #include <fcntl.h>
27
28 #ifndef HAVE_KQUEUE
29 # if defined(__APPLE__) || \
30 defined(__DragonFly__) || \
31 defined(__FreeBSD__) || \
32 defined(__OpenBSD__) || \
33 defined(__NetBSD__)
34 # define HAVE_KQUEUE 1
35 # endif
36 #endif
37
38 static uv_fs_event_t fs_event;
39 static uv_timer_t timer;
40 static int timer_cb_called = 0;
41 static int close_cb_called = 0;
42 static int fs_event_cb_called = 0;
43 static int timer_cb_touch_called = 0;
44
45 static void create_dir(uv_loop_t* loop, const char* name) {
46 int r;
47 uv_fs_t req;
48 r = uv_fs_mkdir(loop, &req, name, 0755, NULL);
49 ASSERT(r == 0 || uv_last_error(loop).code == UV_EEXIST);
50 uv_fs_req_cleanup(&req);
51 }
52
53 static void create_file(uv_loop_t* loop, const char* name) {
54 int r;
55 uv_file file;
56 uv_fs_t req;
57
58 r = uv_fs_open(loop, &req, name, O_WRONLY | O_CREAT,
59 S_IWRITE | S_IREAD, NULL);
60 ASSERT(r != -1);
61 file = r;
62 uv_fs_req_cleanup(&req);
63 r = uv_fs_close(loop, &req, file, NULL);
64 ASSERT(r == 0);
65 uv_fs_req_cleanup(&req);
66 }
67
68 static void touch_file(uv_loop_t* loop, const char* name) {
69 int r;
70 uv_file file;
71 uv_fs_t req;
72
73 r = uv_fs_open(loop, &req, name, O_RDWR, 0, NULL);
74 ASSERT(r != -1);
75 file = r;
76 uv_fs_req_cleanup(&req);
77
78 r = uv_fs_write(loop, &req, file, "foo", 4, -1, NULL);
79 ASSERT(r != -1);
80 uv_fs_req_cleanup(&req);
81
82 r = uv_fs_close(loop, &req, file, NULL);
83 ASSERT(r != -1);
84 uv_fs_req_cleanup(&req);
85 }
86
87 static void close_cb(uv_handle_t* handle) {
88 ASSERT(handle != NULL);
89 close_cb_called++;
90 }
91
92 static void fail_cb(uv_fs_event_t* handle,
93 const char* path,
94 int events,
95 int status) {
96 ASSERT(0 && "fail_cb called");
97 }
98
99 static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
100 int events, int status) {
101 ++fs_event_cb_called;
102 ASSERT(handle == &fs_event);
103 ASSERT(status == 0);
104 ASSERT(events == UV_RENAME);
105 ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
106 uv_close((uv_handle_t*)handle, close_cb);
107 }
108
109 static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
110 int events, int status) {
111 ++fs_event_cb_called;
112 ASSERT(handle == &fs_event);
113 ASSERT(status == 0);
114 ASSERT(events == UV_CHANGE);
115 ASSERT(filename == NULL || strcmp(filename, "file2") == 0);
116 uv_close((uv_handle_t*)handle, close_cb);
117 }
118
119 static void timer_cb_close_handle(uv_timer_t* timer, int status) {
120 uv_handle_t* handle;
121
122 ASSERT(timer != NULL);
123 ASSERT(status == 0);
124 handle = timer->data;
125
126 uv_close((uv_handle_t*)timer, NULL);
127 uv_close((uv_handle_t*)handle, close_cb);
128 }
129
130 static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
131 const char* filename, int events, int status) {
132 ASSERT(fs_event_cb_called == 0);
133 ++fs_event_cb_called;
134
135 ASSERT(handle == &fs_event);
136 ASSERT(status == 0);
137 ASSERT(events == UV_CHANGE);
138 ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
139
140 /* Regression test for SunOS: touch should generate just one event. */
141 {
142 static uv_timer_t timer;
143 uv_timer_init(handle->loop, &timer);
144 timer.data = handle;
145 uv_timer_start(&timer, timer_cb_close_handle, 250, 0);
146 }
147 }
148
149 static void timer_cb_dir(uv_timer_t* handle, int status) {
150 ++timer_cb_called;
151 create_file(handle->loop, "watch_dir/file1");
152 uv_close((uv_handle_t*)handle, close_cb);
153 }
154
155 static void timer_cb_file(uv_timer_t* handle, int status) {
156 ++timer_cb_called;
157
158 if (timer_cb_called == 1) {
159 touch_file(handle->loop, "watch_dir/file1");
160 } else {
161 touch_file(handle->loop, "watch_dir/file2");
162 uv_close((uv_handle_t*)handle, close_cb);
163 }
164 }
165
166 static void timer_cb_touch(uv_timer_t* timer, int status) {
167 ASSERT(status == 0);
168 uv_close((uv_handle_t*)timer, NULL);
169 touch_file(timer->loop, "watch_file");
170 timer_cb_touch_called++;
171 }
172
173 static void timer_cb_watch_twice(uv_timer_t* handle, int status) {
174 uv_fs_event_t* handles = handle->data;
175 uv_close((uv_handle_t*) (handles + 0), NULL);
176 uv_close((uv_handle_t*) (handles + 1), NULL);
177 uv_close((uv_handle_t*) handle, NULL);
178 }
179
180 TEST_IMPL(fs_event_watch_dir) {
181 uv_loop_t* loop = uv_default_loop();
182 int r;
183
184 /* Setup */
185 remove("watch_dir/file2");
186 remove("watch_dir/file1");
187 remove("watch_dir/");
188 create_dir(loop, "watch_dir");
189
190 r = uv_fs_event_init(loop, &fs_event, "watch_dir", fs_event_cb_dir, 0);
191 ASSERT(r != -1);
192 r = uv_timer_init(loop, &timer);
193 ASSERT(r != -1);
194 r = uv_timer_start(&timer, timer_cb_dir, 100, 0);
195 ASSERT(r != -1);
196
197 uv_run(loop, UV_RUN_DEFAULT);
198
199 ASSERT(fs_event_cb_called == 1);
200 ASSERT(timer_cb_called == 1);
201 ASSERT(close_cb_called == 2);
202
203 /* Cleanup */
204 remove("watch_dir/file2");
205 remove("watch_dir/file1");
206 remove("watch_dir/");
207
208 MAKE_VALGRIND_HAPPY();
209 return 0;
210 }
211
212 TEST_IMPL(fs_event_watch_file) {
213 uv_loop_t* loop = uv_default_loop();
214 int r;
215
216 /* Setup */
217 remove("watch_dir/file2");
218 remove("watch_dir/file1");
219 remove("watch_dir/");
220 create_dir(loop, "watch_dir");
221 create_file(loop, "watch_dir/file1");
222 create_file(loop, "watch_dir/file2");
223
224 r = uv_fs_event_init(loop, &fs_event, "watch_dir/file2", fs_event_cb_file, 0);
225 ASSERT(r != -1);
226 r = uv_timer_init(loop, &timer);
227 ASSERT(r != -1);
228 r = uv_timer_start(&timer, timer_cb_file, 100, 100);
229 ASSERT(r != -1);
230
231 uv_run(loop, UV_RUN_DEFAULT);
232
233 ASSERT(fs_event_cb_called == 1);
234 ASSERT(timer_cb_called == 2);
235 ASSERT(close_cb_called == 2);
236
237 /* Cleanup */
238 remove("watch_dir/file2");
239 remove("watch_dir/file1");
240 remove("watch_dir/");
241
242 MAKE_VALGRIND_HAPPY();
243 return 0;
244 }
245
246 TEST_IMPL(fs_event_watch_file_twice) {
247 const char path[] = "test/fixtures/empty_file";
248 uv_fs_event_t watchers[2];
249 uv_timer_t timer;
250 uv_loop_t* loop;
251
252 loop = uv_default_loop();
253 timer.data = watchers;
254
255 ASSERT(0 == uv_fs_event_init(loop, watchers + 0, path, fail_cb, 0));
256 ASSERT(0 == uv_fs_event_init(loop, watchers + 1, path, fail_cb, 0));
257 ASSERT(0 == uv_timer_init(loop, &timer));
258 ASSERT(0 == uv_timer_start(&timer, timer_cb_watch_twice, 10, 0));
259 ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
260
261 MAKE_VALGRIND_HAPPY();
262 return 0;
263 }
264
265 TEST_IMPL(fs_event_watch_file_current_dir) {
266 uv_timer_t timer;
267 uv_loop_t* loop;
268 int r;
269
270 loop = uv_default_loop();
271
272 /* Setup */
273 remove("watch_file");
274 create_file(loop, "watch_file");
275
276 r = uv_fs_event_init(loop, &fs_event, "watch_file",
277 fs_event_cb_file_current_dir, 0);
278 ASSERT(r != -1);
279
280 r = uv_timer_init(loop, &timer);
281 ASSERT(r == 0);
282
283 r = uv_timer_start(&timer, timer_cb_touch, 1, 0);
284 ASSERT(r == 0);
285
286 ASSERT(timer_cb_touch_called == 0);
287 ASSERT(fs_event_cb_called == 0);
288 ASSERT(close_cb_called == 0);
289
290 uv_run(loop, UV_RUN_DEFAULT);
291
292 ASSERT(timer_cb_touch_called == 1);
293 ASSERT(fs_event_cb_called == 1);
294 ASSERT(close_cb_called == 1);
295
296 /* Cleanup */
297 remove("watch_file");
298
299 MAKE_VALGRIND_HAPPY();
300 return 0;
301 }
302
303 TEST_IMPL(fs_event_no_callback_after_close) {
304 uv_loop_t* loop = uv_default_loop();
305 int r;
306
307 /* Setup */
308 remove("watch_dir/file1");
309 remove("watch_dir/");
310 create_dir(loop, "watch_dir");
311 create_file(loop, "watch_dir/file1");
312
313 r = uv_fs_event_init(loop,
314 &fs_event,
315 "watch_dir/file1",
316 fs_event_cb_file,
317 0);
318 ASSERT(r != -1);
319
320 uv_close((uv_handle_t*)&fs_event, close_cb);
321 touch_file(loop, "watch_dir/file1");
322 uv_run(loop, UV_RUN_DEFAULT);
323
324 ASSERT(fs_event_cb_called == 0);
325 ASSERT(close_cb_called == 1);
326
327 /* Cleanup */
328 remove("watch_dir/file1");
329 remove("watch_dir/");
330
331 MAKE_VALGRIND_HAPPY();
332 return 0;
333 }
334
335 TEST_IMPL(fs_event_no_callback_on_close) {
336 uv_loop_t* loop = uv_default_loop();
337 int r;
338
339 /* Setup */
340 remove("watch_dir/file1");
341 remove("watch_dir/");
342 create_dir(loop, "watch_dir");
343 create_file(loop, "watch_dir/file1");
344
345 r = uv_fs_event_init(loop,
346 &fs_event,
347 "watch_dir/file1",
348 fs_event_cb_file,
349 0);
350 ASSERT(r != -1);
351
352 uv_close((uv_handle_t*)&fs_event, close_cb);
353
354 uv_run(loop, UV_RUN_DEFAULT);
355
356 ASSERT(fs_event_cb_called == 0);
357 ASSERT(close_cb_called == 1);
358
359 /* Cleanup */
360 remove("watch_dir/file1");
361 remove("watch_dir/");
362
363 MAKE_VALGRIND_HAPPY();
364 return 0;
365 }
366
367
368 static void fs_event_fail(uv_fs_event_t* handle, const char* filename,
369 int events, int status) {
370 ASSERT(0 && "should never be called");
371 }
372
373
374 static void timer_cb(uv_timer_t* handle, int status) {
375 int r;
376
377 ASSERT(status == 0);
378
379 r = uv_fs_event_init(handle->loop, &fs_event, ".", fs_event_fail, 0);
380 ASSERT(r == 0);
381
382 uv_close((uv_handle_t*)&fs_event, close_cb);
383 uv_close((uv_handle_t*)handle, close_cb);
384 }
385
386
387 TEST_IMPL(fs_event_immediate_close) {
388 uv_timer_t timer;
389 uv_loop_t* loop;
390 int r;
391
392 loop = uv_default_loop();
393
394 r = uv_timer_init(loop, &timer);
395 ASSERT(r == 0);
396
397 r = uv_timer_start(&timer, timer_cb, 1, 0);
398 ASSERT(r == 0);
399
400 uv_run(loop, UV_RUN_DEFAULT);
401
402 ASSERT(close_cb_called == 2);
403
404 MAKE_VALGRIND_HAPPY();
405 return 0;
406 }
407
408
409 TEST_IMPL(fs_event_close_with_pending_event) {
410 uv_loop_t* loop;
411 int r;
412
413 loop = uv_default_loop();
414
415 create_dir(loop, "watch_dir");
416 create_file(loop, "watch_dir/file");
417
418 r = uv_fs_event_init(loop, &fs_event, "watch_dir", fs_event_fail, 0);
419 ASSERT(r == 0);
420
421 /* Generate an fs event. */
422 touch_file(loop, "watch_dir/file");
423
424 uv_close((uv_handle_t*)&fs_event, close_cb);
425
426 uv_run(loop, UV_RUN_DEFAULT);
427
428 ASSERT(close_cb_called == 1);
429
430 /* Clean up */
431 remove("watch_dir/file");
432 remove("watch_dir/");
433
434 MAKE_VALGRIND_HAPPY();
435 return 0;
436 }
437
438 #if defined(HAVE_KQUEUE)
439
440 /* kqueue doesn't register fs events if you don't have an active watcher.
441 * The file descriptor needs to be part of the kqueue set of interest and
442 * that's not the case until we actually enter the event loop.
443 */
444 TEST_IMPL(fs_event_close_in_callback) {
445 fprintf(stderr, "Skipping test, doesn't work with kqueue.\n");
446 return 0;
447 }
448
449 #else /* !HAVE_KQUEUE */
450
451 static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
452 int events, int status) {
453 ASSERT(status == 0);
454
455 ASSERT(fs_event_cb_called < 3);
456 ++fs_event_cb_called;
457
458 if (fs_event_cb_called == 3) {
459 uv_close((uv_handle_t*) handle, close_cb);
460 }
461 }
462
463
464 TEST_IMPL(fs_event_close_in_callback) {
465 uv_loop_t* loop;
466 int r;
467
468 loop = uv_default_loop();
469
470 create_dir(loop, "watch_dir");
471 create_file(loop, "watch_dir/file1");
472 create_file(loop, "watch_dir/file2");
473 create_file(loop, "watch_dir/file3");
474 create_file(loop, "watch_dir/file4");
475 create_file(loop, "watch_dir/file5");
476
477 r = uv_fs_event_init(loop, &fs_event, "watch_dir", fs_event_cb_close, 0);
478 ASSERT(r == 0);
479
480 /* Generate a couple of fs events. */
481 touch_file(loop, "watch_dir/file1");
482 touch_file(loop, "watch_dir/file2");
483 touch_file(loop, "watch_dir/file3");
484 touch_file(loop, "watch_dir/file4");
485 touch_file(loop, "watch_dir/file5");
486
487 uv_run(loop, UV_RUN_DEFAULT);
488
489 ASSERT(close_cb_called == 1);
490 ASSERT(fs_event_cb_called == 3);
491
492 /* Clean up */
493 remove("watch_dir/file1");
494 remove("watch_dir/file2");
495 remove("watch_dir/file3");
496 remove("watch_dir/file4");
497 remove("watch_dir/file5");
498 remove("watch_dir/");
499
500 MAKE_VALGRIND_HAPPY();
501 return 0;
502 }
503
504 #endif /* HAVE_KQUEUE */