1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
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:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
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
29 # if defined(__APPLE__) || \
30 defined(__DragonFly__) || \
31 defined(__FreeBSD__) || \
32 defined(__OpenBSD__) || \
34 # define HAVE_KQUEUE 1
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;
45 static void create_dir(uv_loop_t
* loop
, const char* name
) {
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
);
53 static void create_file(uv_loop_t
* loop
, const char* name
) {
58 r
= uv_fs_open(loop
, &req
, name
, O_WRONLY
| O_CREAT
,
59 S_IWRITE
| S_IREAD
, NULL
);
62 uv_fs_req_cleanup(&req
);
63 r
= uv_fs_close(loop
, &req
, file
, NULL
);
65 uv_fs_req_cleanup(&req
);
68 static void touch_file(uv_loop_t
* loop
, const char* name
) {
73 r
= uv_fs_open(loop
, &req
, name
, O_RDWR
, 0, NULL
);
76 uv_fs_req_cleanup(&req
);
78 r
= uv_fs_write(loop
, &req
, file
, "foo", 4, -1, NULL
);
80 uv_fs_req_cleanup(&req
);
82 r
= uv_fs_close(loop
, &req
, file
, NULL
);
84 uv_fs_req_cleanup(&req
);
87 static void close_cb(uv_handle_t
* handle
) {
88 ASSERT(handle
!= NULL
);
92 static void fail_cb(uv_fs_event_t
* handle
,
96 ASSERT(0 && "fail_cb called");
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
);
104 ASSERT(events
== UV_RENAME
);
105 ASSERT(filename
== NULL
|| strcmp(filename
, "file1") == 0);
106 uv_close((uv_handle_t
*)handle
, close_cb
);
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
);
114 ASSERT(events
== UV_CHANGE
);
115 ASSERT(filename
== NULL
|| strcmp(filename
, "file2") == 0);
116 uv_close((uv_handle_t
*)handle
, close_cb
);
119 static void timer_cb_close_handle(uv_timer_t
* timer
, int status
) {
122 ASSERT(timer
!= NULL
);
124 handle
= timer
->data
;
126 uv_close((uv_handle_t
*)timer
, NULL
);
127 uv_close((uv_handle_t
*)handle
, close_cb
);
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
;
135 ASSERT(handle
== &fs_event
);
137 ASSERT(events
== UV_CHANGE
);
138 ASSERT(filename
== NULL
|| strcmp(filename
, "watch_file") == 0);
140 /* Regression test for SunOS: touch should generate just one event. */
142 static uv_timer_t timer
;
143 uv_timer_init(handle
->loop
, &timer
);
145 uv_timer_start(&timer
, timer_cb_close_handle
, 250, 0);
149 static void timer_cb_dir(uv_timer_t
* handle
, int status
) {
151 create_file(handle
->loop
, "watch_dir/file1");
152 uv_close((uv_handle_t
*)handle
, close_cb
);
155 static void timer_cb_file(uv_timer_t
* handle
, int status
) {
158 if (timer_cb_called
== 1) {
159 touch_file(handle
->loop
, "watch_dir/file1");
161 touch_file(handle
->loop
, "watch_dir/file2");
162 uv_close((uv_handle_t
*)handle
, close_cb
);
166 static void timer_cb_touch(uv_timer_t
* timer
, int status
) {
168 uv_close((uv_handle_t
*)timer
, NULL
);
169 touch_file(timer
->loop
, "watch_file");
170 timer_cb_touch_called
++;
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
);
180 TEST_IMPL(fs_event_watch_dir
) {
181 uv_loop_t
* loop
= uv_default_loop();
185 remove("watch_dir/file2");
186 remove("watch_dir/file1");
187 remove("watch_dir/");
188 create_dir(loop
, "watch_dir");
190 r
= uv_fs_event_init(loop
, &fs_event
, "watch_dir", fs_event_cb_dir
, 0);
192 r
= uv_timer_init(loop
, &timer
);
194 r
= uv_timer_start(&timer
, timer_cb_dir
, 100, 0);
197 uv_run(loop
, UV_RUN_DEFAULT
);
199 ASSERT(fs_event_cb_called
== 1);
200 ASSERT(timer_cb_called
== 1);
201 ASSERT(close_cb_called
== 2);
204 remove("watch_dir/file2");
205 remove("watch_dir/file1");
206 remove("watch_dir/");
208 MAKE_VALGRIND_HAPPY();
212 TEST_IMPL(fs_event_watch_file
) {
213 uv_loop_t
* loop
= uv_default_loop();
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");
224 r
= uv_fs_event_init(loop
, &fs_event
, "watch_dir/file2", fs_event_cb_file
, 0);
226 r
= uv_timer_init(loop
, &timer
);
228 r
= uv_timer_start(&timer
, timer_cb_file
, 100, 100);
231 uv_run(loop
, UV_RUN_DEFAULT
);
233 ASSERT(fs_event_cb_called
== 1);
234 ASSERT(timer_cb_called
== 2);
235 ASSERT(close_cb_called
== 2);
238 remove("watch_dir/file2");
239 remove("watch_dir/file1");
240 remove("watch_dir/");
242 MAKE_VALGRIND_HAPPY();
246 TEST_IMPL(fs_event_watch_file_twice
) {
247 const char path
[] = "test/fixtures/empty_file";
248 uv_fs_event_t watchers
[2];
252 loop
= uv_default_loop();
253 timer
.data
= watchers
;
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
));
261 MAKE_VALGRIND_HAPPY();
265 TEST_IMPL(fs_event_watch_file_current_dir
) {
270 loop
= uv_default_loop();
273 remove("watch_file");
274 create_file(loop
, "watch_file");
276 r
= uv_fs_event_init(loop
, &fs_event
, "watch_file",
277 fs_event_cb_file_current_dir
, 0);
280 r
= uv_timer_init(loop
, &timer
);
283 r
= uv_timer_start(&timer
, timer_cb_touch
, 1, 0);
286 ASSERT(timer_cb_touch_called
== 0);
287 ASSERT(fs_event_cb_called
== 0);
288 ASSERT(close_cb_called
== 0);
290 uv_run(loop
, UV_RUN_DEFAULT
);
292 ASSERT(timer_cb_touch_called
== 1);
293 ASSERT(fs_event_cb_called
== 1);
294 ASSERT(close_cb_called
== 1);
297 remove("watch_file");
299 MAKE_VALGRIND_HAPPY();
303 TEST_IMPL(fs_event_no_callback_after_close
) {
304 uv_loop_t
* loop
= uv_default_loop();
308 remove("watch_dir/file1");
309 remove("watch_dir/");
310 create_dir(loop
, "watch_dir");
311 create_file(loop
, "watch_dir/file1");
313 r
= uv_fs_event_init(loop
,
320 uv_close((uv_handle_t
*)&fs_event
, close_cb
);
321 touch_file(loop
, "watch_dir/file1");
322 uv_run(loop
, UV_RUN_DEFAULT
);
324 ASSERT(fs_event_cb_called
== 0);
325 ASSERT(close_cb_called
== 1);
328 remove("watch_dir/file1");
329 remove("watch_dir/");
331 MAKE_VALGRIND_HAPPY();
335 TEST_IMPL(fs_event_no_callback_on_close
) {
336 uv_loop_t
* loop
= uv_default_loop();
340 remove("watch_dir/file1");
341 remove("watch_dir/");
342 create_dir(loop
, "watch_dir");
343 create_file(loop
, "watch_dir/file1");
345 r
= uv_fs_event_init(loop
,
352 uv_close((uv_handle_t
*)&fs_event
, close_cb
);
354 uv_run(loop
, UV_RUN_DEFAULT
);
356 ASSERT(fs_event_cb_called
== 0);
357 ASSERT(close_cb_called
== 1);
360 remove("watch_dir/file1");
361 remove("watch_dir/");
363 MAKE_VALGRIND_HAPPY();
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");
374 static void timer_cb(uv_timer_t
* handle
, int status
) {
379 r
= uv_fs_event_init(handle
->loop
, &fs_event
, ".", fs_event_fail
, 0);
382 uv_close((uv_handle_t
*)&fs_event
, close_cb
);
383 uv_close((uv_handle_t
*)handle
, close_cb
);
387 TEST_IMPL(fs_event_immediate_close
) {
392 loop
= uv_default_loop();
394 r
= uv_timer_init(loop
, &timer
);
397 r
= uv_timer_start(&timer
, timer_cb
, 1, 0);
400 uv_run(loop
, UV_RUN_DEFAULT
);
402 ASSERT(close_cb_called
== 2);
404 MAKE_VALGRIND_HAPPY();
409 TEST_IMPL(fs_event_close_with_pending_event
) {
413 loop
= uv_default_loop();
415 create_dir(loop
, "watch_dir");
416 create_file(loop
, "watch_dir/file");
418 r
= uv_fs_event_init(loop
, &fs_event
, "watch_dir", fs_event_fail
, 0);
421 /* Generate an fs event. */
422 touch_file(loop
, "watch_dir/file");
424 uv_close((uv_handle_t
*)&fs_event
, close_cb
);
426 uv_run(loop
, UV_RUN_DEFAULT
);
428 ASSERT(close_cb_called
== 1);
431 remove("watch_dir/file");
432 remove("watch_dir/");
434 MAKE_VALGRIND_HAPPY();
438 #if defined(HAVE_KQUEUE)
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.
444 TEST_IMPL(fs_event_close_in_callback
) {
445 fprintf(stderr
, "Skipping test, doesn't work with kqueue.\n");
449 #else /* !HAVE_KQUEUE */
451 static void fs_event_cb_close(uv_fs_event_t
* handle
, const char* filename
,
452 int events
, int status
) {
455 ASSERT(fs_event_cb_called
< 3);
456 ++fs_event_cb_called
;
458 if (fs_event_cb_called
== 3) {
459 uv_close((uv_handle_t
*) handle
, close_cb
);
464 TEST_IMPL(fs_event_close_in_callback
) {
468 loop
= uv_default_loop();
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");
477 r
= uv_fs_event_init(loop
, &fs_event
, "watch_dir", fs_event_cb_close
, 0);
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");
487 uv_run(loop
, UV_RUN_DEFAULT
);
489 ASSERT(close_cb_called
== 1);
490 ASSERT(fs_event_cb_called
== 3);
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/");
500 MAKE_VALGRIND_HAPPY();
504 #endif /* HAVE_KQUEUE */