xref: /libuv/test/test-fs-event.c (revision 9dddebab)
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 #if defined(__APPLE__) && !TARGET_OS_IPHONE
29 # include <AvailabilityMacros.h>
30 #endif
31 
32 static uv_fs_event_t fs_event;
33 static const char file_prefix[] = "fsevent-";
34 static const int fs_event_file_count = 16;
35 #if defined(__APPLE__) || defined(_WIN32)
36 static const char file_prefix_in_subdir[] = "subdir";
37 static int fs_multievent_cb_called;
38 #endif
39 static uv_timer_t timer;
40 static int timer_cb_called;
41 static int close_cb_called;
42 static int fs_event_created;
43 static int fs_event_removed;
44 static int fs_event_cb_called;
45 #if defined(PATH_MAX)
46 static char fs_event_filename[PATH_MAX];
47 #else
48 static char fs_event_filename[1024];
49 #endif  /* defined(PATH_MAX) */
50 static int timer_cb_touch_called;
51 static int timer_cb_exact_called;
52 
fs_event_fail(uv_fs_event_t * handle,const char * filename,int events,int status)53 static void fs_event_fail(uv_fs_event_t* handle,
54                           const char* filename,
55                           int events,
56                           int status) {
57   ASSERT(0 && "should never be called");
58 }
59 
create_dir(const char * name)60 static void create_dir(const char* name) {
61   int r;
62   uv_fs_t req;
63   r = uv_fs_mkdir(NULL, &req, name, 0755, NULL);
64   ASSERT(r == 0 || r == UV_EEXIST);
65   uv_fs_req_cleanup(&req);
66 }
67 
create_file(const char * name)68 static void create_file(const char* name) {
69   int r;
70   uv_file file;
71   uv_fs_t req;
72 
73   r = uv_fs_open(NULL, &req, name, UV_FS_O_WRONLY | UV_FS_O_CREAT,
74                  S_IWUSR | S_IRUSR,
75                  NULL);
76   ASSERT_GE(r, 0);
77   file = r;
78   uv_fs_req_cleanup(&req);
79   r = uv_fs_close(NULL, &req, file, NULL);
80   ASSERT_OK(r);
81   uv_fs_req_cleanup(&req);
82 }
83 
delete_dir(const char * name)84 static int delete_dir(const char* name) {
85   int r;
86   uv_fs_t req;
87   r = uv_fs_rmdir(NULL, &req, name, NULL);
88   uv_fs_req_cleanup(&req);
89   return r;
90 }
91 
delete_file(const char * name)92 static int delete_file(const char* name) {
93   int r;
94   uv_fs_t req;
95   r = uv_fs_unlink(NULL, &req, name, NULL);
96   uv_fs_req_cleanup(&req);
97   return r;
98 }
99 
touch_file(const char * name)100 static void touch_file(const char* name) {
101   int r;
102   uv_file file;
103   uv_fs_t req;
104   uv_buf_t buf;
105 
106   r = uv_fs_open(NULL, &req, name, UV_FS_O_RDWR, 0, NULL);
107   ASSERT_GE(r, 0);
108   file = r;
109   uv_fs_req_cleanup(&req);
110 
111   buf = uv_buf_init("foo", 4);
112   r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
113   ASSERT_GE(r, 0);
114   uv_fs_req_cleanup(&req);
115 
116   r = uv_fs_close(NULL, &req, file, NULL);
117   ASSERT_OK(r);
118   uv_fs_req_cleanup(&req);
119 }
120 
close_cb(uv_handle_t * handle)121 static void close_cb(uv_handle_t* handle) {
122   ASSERT_NOT_NULL(handle);
123   close_cb_called++;
124 }
125 
fail_cb(uv_fs_event_t * handle,const char * path,int events,int status)126 static void fail_cb(uv_fs_event_t* handle,
127                     const char* path,
128                     int events,
129                     int status) {
130   ASSERT(0 && "fail_cb called");
131 }
132 
fs_event_cb_dir(uv_fs_event_t * handle,const char * filename,int events,int status)133 static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
134   int events, int status) {
135   ++fs_event_cb_called;
136   ASSERT_PTR_EQ(handle, &fs_event);
137   ASSERT_OK(status);
138   ASSERT_EQ(events, UV_CHANGE);
139   #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
140   ASSERT_OK(strcmp(filename, "file1"));
141   #else
142   ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
143   #endif
144   ASSERT_OK(uv_fs_event_stop(handle));
145   uv_close((uv_handle_t*)handle, close_cb);
146 }
147 
fs_event_cb_del_dir(uv_fs_event_t * handle,const char * filename,int events,int status)148 static void fs_event_cb_del_dir(uv_fs_event_t* handle,
149                                 const char* filename,
150                                 int events,
151                                 int status) {
152   ++fs_event_cb_called;
153   ASSERT_PTR_EQ(handle, &fs_event);
154   ASSERT_OK(status);
155   ASSERT(events == UV_CHANGE || events == UV_RENAME);
156   ASSERT_OK(strcmp(filename, "watch_del_dir"));
157   ASSERT_OK(uv_fs_event_stop(handle));
158   uv_close((uv_handle_t*)handle, close_cb);
159 }
160 
fs_event_get_filename(int i)161 static const char* fs_event_get_filename(int i) {
162   snprintf(fs_event_filename,
163            sizeof(fs_event_filename),
164            "watch_dir/%s%d",
165            file_prefix,
166            i);
167   return fs_event_filename;
168 }
169 
fs_event_create_files(uv_timer_t * handle)170 static void fs_event_create_files(uv_timer_t* handle) {
171   /* Make sure we're not attempting to create files we do not intend */
172   ASSERT_LT(fs_event_created, fs_event_file_count);
173 
174   /* Create the file */
175   create_file(fs_event_get_filename(fs_event_created));
176 
177   if (++fs_event_created < fs_event_file_count) {
178     /* Create another file on a different event loop tick.  We do it this way
179      * to avoid fs events coalescing into one fs event. */
180     ASSERT_OK(uv_timer_start(&timer, fs_event_create_files, 100, 0));
181   }
182 }
183 
fs_event_del_dir(uv_timer_t * handle)184 static void fs_event_del_dir(uv_timer_t* handle) {
185   int r;
186 
187   r = delete_dir("watch_del_dir");
188   ASSERT_OK(r);
189 
190   uv_close((uv_handle_t*)handle, close_cb);
191 }
192 
fs_event_unlink_files(uv_timer_t * handle)193 static void fs_event_unlink_files(uv_timer_t* handle) {
194   int r;
195   int i;
196 
197   /* NOTE: handle might be NULL if invoked not as timer callback */
198   if (handle == NULL) {
199     /* Unlink all files */
200     for (i = 0; i < 16; i++) {
201       r = delete_file(fs_event_get_filename(i));
202       if (handle != NULL)
203         ASSERT_OK(r);
204     }
205   } else {
206     /* Make sure we're not attempting to remove files we do not intend */
207     ASSERT_LT(fs_event_removed, fs_event_file_count);
208 
209     /* Remove the file */
210     ASSERT_OK(delete_file(fs_event_get_filename(fs_event_removed)));
211 
212     if (++fs_event_removed < fs_event_file_count) {
213       /* Remove another file on a different event loop tick.  We do it this way
214        * to avoid fs events coalescing into one fs event. */
215       ASSERT_OK(uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
216     }
217   }
218 }
219 
fs_event_cb_dir_multi_file(uv_fs_event_t * handle,const char * filename,int events,int status)220 static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
221                                        const char* filename,
222                                        int events,
223                                        int status) {
224   fs_event_cb_called++;
225   ASSERT_PTR_EQ(handle, &fs_event);
226   ASSERT_OK(status);
227   ASSERT(events == UV_CHANGE || events == UV_RENAME);
228 #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
229   ASSERT_NOT_NULL(filename);
230   ASSERT_MEM_EQ(filename, file_prefix, sizeof(file_prefix) - 1);
231 #else
232   if (filename != NULL)
233     ASSERT_MEM_EQ(filename, file_prefix, sizeof(file_prefix) - 1);
234 #endif
235 
236   if (fs_event_created + fs_event_removed == fs_event_file_count) {
237     /* Once we've processed all create events, delete all files */
238     ASSERT_OK(uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
239   } else if (fs_event_cb_called == 2 * fs_event_file_count) {
240     /* Once we've processed all create and delete events, stop watching */
241     uv_close((uv_handle_t*) &timer, close_cb);
242     uv_close((uv_handle_t*) handle, close_cb);
243   }
244 }
245 
246 #if defined(__APPLE__) || defined(_WIN32)
fs_event_get_filename_in_subdir(int i)247 static const char* fs_event_get_filename_in_subdir(int i) {
248   snprintf(fs_event_filename,
249            sizeof(fs_event_filename),
250            "watch_dir/subdir/%s%d",
251            file_prefix,
252            i);
253   return fs_event_filename;
254 }
255 
fs_event_create_files_in_subdir(uv_timer_t * handle)256 static void fs_event_create_files_in_subdir(uv_timer_t* handle) {
257   /* Make sure we're not attempting to create files we do not intend */
258   ASSERT_LT(fs_event_created, fs_event_file_count);
259 
260   /* Create the file */
261   create_file(fs_event_get_filename_in_subdir(fs_event_created));
262 
263   if (++fs_event_created < fs_event_file_count) {
264     /* Create another file on a different event loop tick.  We do it this way
265      * to avoid fs events coalescing into one fs event. */
266     ASSERT_OK(uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0));
267   }
268 }
269 
fs_event_unlink_files_in_subdir(uv_timer_t * handle)270 static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) {
271   int r;
272   int i;
273 
274   /* NOTE: handle might be NULL if invoked not as timer callback */
275   if (handle == NULL) {
276     /* Unlink all files */
277     for (i = 0; i < 16; i++) {
278       r = delete_file(fs_event_get_filename_in_subdir(i));
279       if (handle != NULL)
280         ASSERT_OK(r);
281     }
282   } else {
283     /* Make sure we're not attempting to remove files we do not intend */
284     ASSERT_LT(fs_event_removed, fs_event_file_count);
285 
286     /* Remove the file */
287     ASSERT_OK(delete_file(fs_event_get_filename_in_subdir(fs_event_removed)));
288 
289     if (++fs_event_removed < fs_event_file_count) {
290       /* Remove another file on a different event loop tick.  We do it this way
291        * to avoid fs events coalescing into one fs event. */
292       ASSERT_OK(uv_timer_start(&timer,
293                                fs_event_unlink_files_in_subdir,
294                                1,
295                                0));
296     }
297   }
298 }
299 
fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t * handle,const char * filename,int events,int status)300 static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
301                                                  const char* filename,
302                                                  int events,
303                                                  int status) {
304 #ifdef _WIN32
305   /* Each file created (or deleted) will cause this callback to be called twice
306    * under Windows: once with the name of the file, and second time with the
307    * name of the directory. We will ignore the callback for the directory
308    * itself. */
309   if (filename && strcmp(filename, file_prefix_in_subdir) == 0)
310     return;
311 #endif
312   /* It may happen that the "subdir" creation event is captured even though
313    * we started watching after its actual creation.
314    */
315   if (strcmp(filename, "subdir") == 0)
316     return;
317 
318   fs_multievent_cb_called++;
319   ASSERT_PTR_EQ(handle, &fs_event);
320   ASSERT_OK(status);
321   ASSERT(events == UV_CHANGE || events == UV_RENAME);
322   #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
323   ASSERT_OK(strncmp(filename,
324                     file_prefix_in_subdir,
325                     sizeof(file_prefix_in_subdir) - 1));
326   #else
327   ASSERT_NE(filename == NULL ||
328             strncmp(filename,
329                     file_prefix_in_subdir,
330                     sizeof(file_prefix_in_subdir) - 1) == 0, 0);
331   #endif
332 
333   if (fs_event_created == fs_event_file_count &&
334       fs_multievent_cb_called == fs_event_created) {
335     /* Once we've processed all create events, delete all files */
336     ASSERT_OK(uv_timer_start(&timer,
337                              fs_event_unlink_files_in_subdir,
338                              1,
339                              0));
340   } else if (fs_multievent_cb_called == 2 * fs_event_file_count) {
341     /* Once we've processed all create and delete events, stop watching */
342     ASSERT_EQ(fs_event_removed, fs_event_file_count);
343     uv_close((uv_handle_t*) &timer, close_cb);
344     uv_close((uv_handle_t*) handle, close_cb);
345   }
346 }
347 #endif
348 
fs_event_cb_file(uv_fs_event_t * handle,const char * filename,int events,int status)349 static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
350   int events, int status) {
351   ++fs_event_cb_called;
352   ASSERT_PTR_EQ(handle, &fs_event);
353   ASSERT_OK(status);
354   ASSERT_EQ(events, UV_CHANGE);
355   #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
356   ASSERT_OK(strcmp(filename, "file2"));
357   #else
358   ASSERT(filename == NULL || strcmp(filename, "file2") == 0);
359   #endif
360   ASSERT_OK(uv_fs_event_stop(handle));
361   uv_close((uv_handle_t*)handle, close_cb);
362 }
363 
fs_event_cb_file_current_dir(uv_fs_event_t * handle,const char * filename,int events,int status)364 static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
365   const char* filename, int events, int status) {
366   ++fs_event_cb_called;
367 
368   ASSERT_PTR_EQ(handle, &fs_event);
369   ASSERT_OK(status);
370   ASSERT_EQ(events, UV_CHANGE);
371   #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
372   ASSERT_OK(strcmp(filename, "watch_file"));
373   #else
374   ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
375   #endif
376 
377   uv_close((uv_handle_t*)handle, close_cb);
378 }
379 
timer_cb_file(uv_timer_t * handle)380 static void timer_cb_file(uv_timer_t* handle) {
381   ++timer_cb_called;
382 
383   if (timer_cb_called == 1) {
384     touch_file("watch_dir/file1");
385   } else {
386     touch_file("watch_dir/file2");
387     uv_close((uv_handle_t*)handle, close_cb);
388   }
389 }
390 
timer_cb_touch(uv_timer_t * timer)391 static void timer_cb_touch(uv_timer_t* timer) {
392   uv_close((uv_handle_t*)timer, NULL);
393   touch_file((char*) timer->data);
394   timer_cb_touch_called++;
395 }
396 
timer_cb_exact(uv_timer_t * handle)397 static void timer_cb_exact(uv_timer_t* handle) {
398   int r;
399 
400   if (timer_cb_exact_called == 0) {
401     touch_file("watch_dir/file.js");
402   } else {
403     uv_close((uv_handle_t*)handle, NULL);
404     r = uv_fs_event_stop(&fs_event);
405     ASSERT_OK(r);
406     uv_close((uv_handle_t*) &fs_event, NULL);
407   }
408 
409   ++timer_cb_exact_called;
410 }
411 
timer_cb_watch_twice(uv_timer_t * handle)412 static void timer_cb_watch_twice(uv_timer_t* handle) {
413   uv_fs_event_t* handles = handle->data;
414   uv_close((uv_handle_t*) (handles + 0), NULL);
415   uv_close((uv_handle_t*) (handles + 1), NULL);
416   uv_close((uv_handle_t*) handle, NULL);
417 }
418 
fs_event_cb_close(uv_fs_event_t * handle,const char * filename,int events,int status)419 static void fs_event_cb_close(uv_fs_event_t* handle,
420                               const char* filename,
421                               int events,
422                               int status) {
423   ASSERT_OK(status);
424 
425   ASSERT_LT(fs_event_cb_called, 3);
426   ++fs_event_cb_called;
427 
428   if (fs_event_cb_called == 3) {
429     uv_close((uv_handle_t*) handle, close_cb);
430   }
431 }
432 
433 
TEST_IMPL(fs_event_watch_dir)434 TEST_IMPL(fs_event_watch_dir) {
435 #if defined(NO_FS_EVENTS)
436   RETURN_SKIP(NO_FS_EVENTS);
437 #elif defined(__MVS__)
438   RETURN_SKIP("Directory watching not supported on this platform.");
439 #elif defined(__APPLE__) && defined(__TSAN__)
440   RETURN_SKIP("Times out under TSAN.");
441 #endif
442 
443   uv_loop_t* loop = uv_default_loop();
444   int r;
445 
446   /* Setup */
447   fs_event_unlink_files(NULL);
448   delete_file("watch_dir/file2");
449   delete_file("watch_dir/file1");
450   delete_dir("watch_dir/");
451   create_dir("watch_dir");
452 
453   r = uv_fs_event_init(loop, &fs_event);
454   ASSERT_OK(r);
455   r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
456   ASSERT_OK(r);
457   r = uv_timer_init(loop, &timer);
458   ASSERT_OK(r);
459   r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
460   ASSERT_OK(r);
461 
462   uv_run(loop, UV_RUN_DEFAULT);
463 
464   ASSERT_EQ(fs_event_cb_called, fs_event_created + fs_event_removed);
465   ASSERT_EQ(2, close_cb_called);
466 
467   /* Cleanup */
468   fs_event_unlink_files(NULL);
469   delete_file("watch_dir/file2");
470   delete_file("watch_dir/file1");
471   delete_dir("watch_dir/");
472 
473   MAKE_VALGRIND_HAPPY(loop);
474   return 0;
475 }
476 
TEST_IMPL(fs_event_watch_delete_dir)477 TEST_IMPL(fs_event_watch_delete_dir) {
478 #if defined(NO_FS_EVENTS)
479   RETURN_SKIP(NO_FS_EVENTS);
480 #elif defined(__MVS__)
481   RETURN_SKIP("Directory watching not supported on this platform.");
482 #elif defined(__APPLE__) && defined(__TSAN__)
483   RETURN_SKIP("Times out under TSAN.");
484 #endif
485 
486   uv_loop_t* loop = uv_default_loop();
487   int r;
488 
489   /* Setup */
490   fs_event_unlink_files(NULL);
491   delete_dir("watch_del_dir/");
492   create_dir("watch_del_dir");
493 
494   r = uv_fs_event_init(loop, &fs_event);
495   ASSERT_OK(r);
496   r = uv_fs_event_start(&fs_event, fs_event_cb_del_dir, "watch_del_dir", 0);
497   ASSERT_OK(r);
498   r = uv_timer_init(loop, &timer);
499   ASSERT_OK(r);
500   r = uv_timer_start(&timer, fs_event_del_dir, 100, 0);
501   ASSERT_OK(r);
502 
503   uv_run(loop, UV_RUN_DEFAULT);
504 
505   ASSERT_EQ(1, fs_event_cb_called);
506   ASSERT_EQ(2, close_cb_called);
507 
508   /* Cleanup */
509   fs_event_unlink_files(NULL);
510 
511   MAKE_VALGRIND_HAPPY(loop);
512   return 0;
513 }
514 
515 
TEST_IMPL(fs_event_watch_dir_recursive)516 TEST_IMPL(fs_event_watch_dir_recursive) {
517 #if defined(__APPLE__) && defined(__TSAN__)
518   RETURN_SKIP("Times out under TSAN.");
519 #elif defined(__APPLE__) || defined(_WIN32)
520   uv_loop_t* loop;
521   int r;
522   uv_fs_event_t fs_event_root;
523 
524   /* Setup */
525   loop = uv_default_loop();
526   fs_event_unlink_files(NULL);
527   delete_file("watch_dir/file2");
528   delete_file("watch_dir/file1");
529   delete_dir("watch_dir/subdir");
530   delete_dir("watch_dir/");
531   create_dir("watch_dir");
532   create_dir("watch_dir/subdir");
533 
534   r = uv_fs_event_init(loop, &fs_event);
535   ASSERT_OK(r);
536   r = uv_fs_event_start(&fs_event,
537                         fs_event_cb_dir_multi_file_in_subdir,
538                         "watch_dir",
539                         UV_FS_EVENT_RECURSIVE);
540   ASSERT_OK(r);
541   r = uv_timer_init(loop, &timer);
542   ASSERT_OK(r);
543   r = uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0);
544   ASSERT_OK(r);
545 
546 #ifndef _WIN32
547   /* Also try to watch the root directory.
548    * This will be noisier, so we're just checking for any couple events to happen. */
549   r = uv_fs_event_init(loop, &fs_event_root);
550   ASSERT_OK(r);
551   r = uv_fs_event_start(&fs_event_root,
552                         fs_event_cb_close,
553                         "/",
554                         UV_FS_EVENT_RECURSIVE);
555   ASSERT_OK(r);
556 #else
557   fs_event_cb_called += 3;
558   close_cb_called += 1;
559   (void)fs_event_root;
560 #endif
561 
562   uv_run(loop, UV_RUN_DEFAULT);
563 
564   ASSERT_EQ(fs_multievent_cb_called, fs_event_created + fs_event_removed);
565   ASSERT_EQ(3, fs_event_cb_called);
566   ASSERT_EQ(3, close_cb_called);
567 
568   /* Cleanup */
569   fs_event_unlink_files_in_subdir(NULL);
570   delete_file("watch_dir/file2");
571   delete_file("watch_dir/file1");
572   delete_dir("watch_dir/subdir");
573   delete_dir("watch_dir/");
574 
575   MAKE_VALGRIND_HAPPY(loop);
576   return 0;
577 #else
578   RETURN_SKIP("Recursive directory watching not supported on this platform.");
579 #endif
580 }
581 
582 #ifdef _WIN32
TEST_IMPL(fs_event_watch_dir_short_path)583 TEST_IMPL(fs_event_watch_dir_short_path) {
584   uv_loop_t* loop;
585   uv_fs_t req;
586   int has_shortnames;
587   int r;
588 
589   /* Setup */
590   loop = uv_default_loop();
591   delete_file("watch_dir/file1");
592   delete_dir("watch_dir/");
593   create_dir("watch_dir");
594   create_file("watch_dir/file1");
595 
596   /* Newer version of Windows ship with
597      HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation
598      not equal to 0. So we verify the files we created are addressable by a 8.3
599      short name */
600   has_shortnames = uv_fs_stat(NULL, &req, "watch_~1", NULL) != UV_ENOENT;
601   if (has_shortnames) {
602     r = uv_fs_event_init(loop, &fs_event);
603     ASSERT_OK(r);
604     r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_~1", 0);
605     ASSERT_OK(r);
606     r = uv_timer_init(loop, &timer);
607     ASSERT_OK(r);
608     r = uv_timer_start(&timer, timer_cb_file, 100, 0);
609     ASSERT_OK(r);
610 
611     uv_run(loop, UV_RUN_DEFAULT);
612 
613     ASSERT_EQ(1, fs_event_cb_called);
614     ASSERT_EQ(1, timer_cb_called);
615     ASSERT_EQ(1, close_cb_called);
616   }
617 
618   /* Cleanup */
619   delete_file("watch_dir/file1");
620   delete_dir("watch_dir/");
621 
622   MAKE_VALGRIND_HAPPY(loop);
623 
624   if (!has_shortnames)
625     RETURN_SKIP("Was not able to address files with 8.3 short name.");
626 
627   return 0;
628 }
629 #endif
630 
631 
TEST_IMPL(fs_event_watch_file)632 TEST_IMPL(fs_event_watch_file) {
633 #if defined(NO_FS_EVENTS)
634   RETURN_SKIP(NO_FS_EVENTS);
635 #endif
636 
637   uv_loop_t* loop = uv_default_loop();
638   int r;
639 
640   /* Setup */
641   delete_file("watch_dir/file2");
642   delete_file("watch_dir/file1");
643   delete_dir("watch_dir/");
644   create_dir("watch_dir");
645   create_file("watch_dir/file1");
646   create_file("watch_dir/file2");
647 
648   r = uv_fs_event_init(loop, &fs_event);
649   ASSERT_OK(r);
650   r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file2", 0);
651   ASSERT_OK(r);
652   r = uv_timer_init(loop, &timer);
653   ASSERT_OK(r);
654   r = uv_timer_start(&timer, timer_cb_file, 100, 100);
655   ASSERT_OK(r);
656 
657   uv_run(loop, UV_RUN_DEFAULT);
658 
659   ASSERT_EQ(1, fs_event_cb_called);
660   ASSERT_EQ(2, timer_cb_called);
661   ASSERT_EQ(2, close_cb_called);
662 
663   /* Cleanup */
664   delete_file("watch_dir/file2");
665   delete_file("watch_dir/file1");
666   delete_dir("watch_dir/");
667 
668   MAKE_VALGRIND_HAPPY(loop);
669   return 0;
670 }
671 
TEST_IMPL(fs_event_watch_file_exact_path)672 TEST_IMPL(fs_event_watch_file_exact_path) {
673   /*
674     This test watches a file named "file.jsx" and modifies a file named
675     "file.js". The test verifies that no events occur for file.jsx.
676   */
677 
678 #if defined(NO_FS_EVENTS)
679   RETURN_SKIP(NO_FS_EVENTS);
680 #endif
681 
682   uv_loop_t* loop;
683   int r;
684 
685   loop = uv_default_loop();
686 
687   /* Setup */
688   delete_file("watch_dir/file.js");
689   delete_file("watch_dir/file.jsx");
690   delete_dir("watch_dir/");
691   create_dir("watch_dir");
692   create_file("watch_dir/file.js");
693   create_file("watch_dir/file.jsx");
694 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12)
695   /* Empirically, FSEvents seems to (reliably) report the preceding
696    * create_file events prior to macOS 10.11.6 in the subsequent fs_watch
697    * creation, but that behavior hasn't been observed to occur on newer
698    * versions. Give a long delay here to let the system settle before running
699    * the test. */
700   uv_sleep(1100);
701   uv_update_time(loop);
702 #endif
703 
704   r = uv_fs_event_init(loop, &fs_event);
705   ASSERT_OK(r);
706   r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0);
707   ASSERT_OK(r);
708   r = uv_timer_init(loop, &timer);
709   ASSERT_OK(r);
710   r = uv_timer_start(&timer, timer_cb_exact, 100, 100);
711   ASSERT_OK(r);
712   r = uv_run(loop, UV_RUN_DEFAULT);
713   ASSERT_OK(r);
714   ASSERT_EQ(2, timer_cb_exact_called);
715 
716   /* Cleanup */
717   delete_file("watch_dir/file.js");
718   delete_file("watch_dir/file.jsx");
719   delete_dir("watch_dir/");
720 
721   MAKE_VALGRIND_HAPPY(loop);
722   return 0;
723 }
724 
TEST_IMPL(fs_event_watch_file_twice)725 TEST_IMPL(fs_event_watch_file_twice) {
726 #if defined(NO_FS_EVENTS)
727   RETURN_SKIP(NO_FS_EVENTS);
728 #endif
729   const char path[] = "test/fixtures/empty_file";
730   uv_fs_event_t watchers[2];
731   uv_timer_t timer;
732   uv_loop_t* loop;
733 
734   loop = uv_default_loop();
735   timer.data = watchers;
736 
737   ASSERT_OK(uv_fs_event_init(loop, watchers + 0));
738   ASSERT_OK(uv_fs_event_start(watchers + 0, fail_cb, path, 0));
739   ASSERT_OK(uv_fs_event_init(loop, watchers + 1));
740   ASSERT_OK(uv_fs_event_start(watchers + 1, fail_cb, path, 0));
741   ASSERT_OK(uv_timer_init(loop, &timer));
742   ASSERT_OK(uv_timer_start(&timer, timer_cb_watch_twice, 10, 0));
743   ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
744 
745   MAKE_VALGRIND_HAPPY(loop);
746   return 0;
747 }
748 
TEST_IMPL(fs_event_watch_file_current_dir)749 TEST_IMPL(fs_event_watch_file_current_dir) {
750 #if defined(NO_FS_EVENTS)
751   RETURN_SKIP(NO_FS_EVENTS);
752 #endif
753   uv_timer_t timer;
754   uv_loop_t* loop;
755   int r;
756 
757   loop = uv_default_loop();
758 
759   /* Setup */
760   delete_file("watch_file");
761   create_file("watch_file");
762 #if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12)
763   /* Empirically, kevent seems to (sometimes) report the preceding
764    * create_file events prior to macOS 10.11.6 in the subsequent fs_event_start
765    * So let the system settle before running the test. */
766   uv_sleep(1100);
767   uv_update_time(loop);
768 #endif
769 
770   r = uv_fs_event_init(loop, &fs_event);
771   ASSERT_OK(r);
772   r = uv_fs_event_start(&fs_event,
773                         fs_event_cb_file_current_dir,
774                         "watch_file",
775                         0);
776   ASSERT_OK(r);
777 
778 
779   r = uv_timer_init(loop, &timer);
780   ASSERT_OK(r);
781 
782   timer.data = "watch_file";
783   r = uv_timer_start(&timer, timer_cb_touch, 1100, 0);
784   ASSERT_OK(r);
785 
786   ASSERT_OK(timer_cb_touch_called);
787   ASSERT_OK(fs_event_cb_called);
788   ASSERT_OK(close_cb_called);
789 
790   uv_run(loop, UV_RUN_DEFAULT);
791 
792   ASSERT_EQ(1, timer_cb_touch_called);
793   /* FSEvents on macOS sometimes sends one change event, sometimes two. */
794   ASSERT_NE(0, fs_event_cb_called);
795   ASSERT_EQ(1, close_cb_called);
796 
797   /* Cleanup */
798   delete_file("watch_file");
799 
800   MAKE_VALGRIND_HAPPY(loop);
801   return 0;
802 }
803 
804 #ifdef _WIN32
TEST_IMPL(fs_event_watch_file_root_dir)805 TEST_IMPL(fs_event_watch_file_root_dir) {
806   uv_loop_t* loop;
807   int r;
808 
809   const char* sys_drive = getenv("SystemDrive");
810   char path[] = "\\\\?\\X:\\bootsect.bak";
811 
812   ASSERT_NOT_NULL(sys_drive);
813   strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1);
814 
815   loop = uv_default_loop();
816 
817   r = uv_fs_event_init(loop, &fs_event);
818   ASSERT_OK(r);
819   r = uv_fs_event_start(&fs_event, fail_cb, path, 0);
820   if (r == UV_ENOENT)
821     RETURN_SKIP("bootsect.bak doesn't exist in system root.\n");
822   ASSERT_OK(r);
823 
824   uv_close((uv_handle_t*) &fs_event, NULL);
825 
826   MAKE_VALGRIND_HAPPY(loop);
827   return 0;
828 }
829 #endif
830 
TEST_IMPL(fs_event_no_callback_after_close)831 TEST_IMPL(fs_event_no_callback_after_close) {
832 #if defined(NO_FS_EVENTS)
833   RETURN_SKIP(NO_FS_EVENTS);
834 #endif
835 
836   uv_loop_t* loop = uv_default_loop();
837   int r;
838 
839   /* Setup */
840   delete_file("watch_dir/file1");
841   delete_dir("watch_dir/");
842   create_dir("watch_dir");
843   create_file("watch_dir/file1");
844 
845   r = uv_fs_event_init(loop, &fs_event);
846   ASSERT_OK(r);
847   r = uv_fs_event_start(&fs_event,
848                         fs_event_cb_file,
849                         "watch_dir/file1",
850                         0);
851   ASSERT_OK(r);
852 
853 
854   uv_close((uv_handle_t*)&fs_event, close_cb);
855   touch_file("watch_dir/file1");
856   uv_run(loop, UV_RUN_DEFAULT);
857 
858   ASSERT_OK(fs_event_cb_called);
859   ASSERT_EQ(1, close_cb_called);
860 
861   /* Cleanup */
862   delete_file("watch_dir/file1");
863   delete_dir("watch_dir/");
864 
865   MAKE_VALGRIND_HAPPY(loop);
866   return 0;
867 }
868 
TEST_IMPL(fs_event_no_callback_on_close)869 TEST_IMPL(fs_event_no_callback_on_close) {
870 #if defined(NO_FS_EVENTS)
871   RETURN_SKIP(NO_FS_EVENTS);
872 #endif
873 
874   uv_loop_t* loop = uv_default_loop();
875   int r;
876 
877   /* Setup */
878   delete_file("watch_dir/file1");
879   delete_dir("watch_dir/");
880   create_dir("watch_dir");
881   create_file("watch_dir/file1");
882 
883   r = uv_fs_event_init(loop, &fs_event);
884   ASSERT_OK(r);
885   r = uv_fs_event_start(&fs_event,
886                         fs_event_cb_file,
887                         "watch_dir/file1",
888                         0);
889   ASSERT_OK(r);
890 
891   uv_close((uv_handle_t*)&fs_event, close_cb);
892 
893   uv_run(loop, UV_RUN_DEFAULT);
894 
895   ASSERT_OK(fs_event_cb_called);
896   ASSERT_EQ(1, close_cb_called);
897 
898   /* Cleanup */
899   delete_file("watch_dir/file1");
900   delete_dir("watch_dir/");
901 
902   MAKE_VALGRIND_HAPPY(loop);
903   return 0;
904 }
905 
906 
timer_cb(uv_timer_t * handle)907 static void timer_cb(uv_timer_t* handle) {
908   int r;
909 
910   r = uv_fs_event_init(handle->loop, &fs_event);
911   ASSERT_OK(r);
912   r = uv_fs_event_start(&fs_event, fs_event_fail, ".", 0);
913   ASSERT_OK(r);
914 
915   uv_close((uv_handle_t*)&fs_event, close_cb);
916   uv_close((uv_handle_t*)handle, close_cb);
917 }
918 
919 
TEST_IMPL(fs_event_immediate_close)920 TEST_IMPL(fs_event_immediate_close) {
921 #if defined(NO_FS_EVENTS)
922   RETURN_SKIP(NO_FS_EVENTS);
923 #endif
924   uv_timer_t timer;
925   uv_loop_t* loop;
926   int r;
927 
928   loop = uv_default_loop();
929 
930   r = uv_timer_init(loop, &timer);
931   ASSERT_OK(r);
932 
933   r = uv_timer_start(&timer, timer_cb, 1, 0);
934   ASSERT_OK(r);
935 
936   uv_run(loop, UV_RUN_DEFAULT);
937 
938   ASSERT_EQ(2, close_cb_called);
939 
940   MAKE_VALGRIND_HAPPY(loop);
941   return 0;
942 }
943 
944 
TEST_IMPL(fs_event_close_with_pending_event)945 TEST_IMPL(fs_event_close_with_pending_event) {
946 #if defined(NO_FS_EVENTS)
947   RETURN_SKIP(NO_FS_EVENTS);
948 #endif
949   uv_loop_t* loop;
950   int r;
951 
952   loop = uv_default_loop();
953 
954   create_dir("watch_dir");
955   create_file("watch_dir/file");
956 
957   r = uv_fs_event_init(loop, &fs_event);
958   ASSERT_OK(r);
959   r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir", 0);
960   ASSERT_OK(r);
961 
962   /* Generate an fs event. */
963   touch_file("watch_dir/file");
964 
965   uv_close((uv_handle_t*)&fs_event, close_cb);
966 
967   uv_run(loop, UV_RUN_DEFAULT);
968 
969   ASSERT_EQ(1, close_cb_called);
970 
971   /* Clean up */
972   delete_file("watch_dir/file");
973   delete_dir("watch_dir/");
974 
975   MAKE_VALGRIND_HAPPY(loop);
976   return 0;
977 }
978 
TEST_IMPL(fs_event_close_with_pending_delete_event)979 TEST_IMPL(fs_event_close_with_pending_delete_event) {
980 #if defined(NO_FS_EVENTS)
981   RETURN_SKIP(NO_FS_EVENTS);
982 #endif
983   uv_loop_t* loop;
984   int r;
985 
986   loop = uv_default_loop();
987 
988   create_dir("watch_dir");
989   create_file("watch_dir/file");
990 
991   r = uv_fs_event_init(loop, &fs_event);
992   ASSERT_OK(r);
993   r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file", 0);
994   ASSERT_OK(r);
995 
996   /* Generate an fs event. */
997   delete_file("watch_dir/file");
998 
999   /* Allow time for the remove event to propagate to the pending list. */
1000   /* XXX - perhaps just for __sun? */
1001   uv_sleep(1100);
1002   uv_update_time(loop);
1003 
1004   uv_close((uv_handle_t*)&fs_event, close_cb);
1005 
1006   uv_run(loop, UV_RUN_DEFAULT);
1007 
1008   ASSERT_EQ(1, close_cb_called);
1009 
1010   /* Clean up */
1011   delete_dir("watch_dir/");
1012 
1013   MAKE_VALGRIND_HAPPY(loop);
1014   return 0;
1015 }
1016 
TEST_IMPL(fs_event_close_in_callback)1017 TEST_IMPL(fs_event_close_in_callback) {
1018 #if defined(NO_FS_EVENTS)
1019   RETURN_SKIP(NO_FS_EVENTS);
1020 #elif defined(__MVS__)
1021   RETURN_SKIP("Directory watching not supported on this platform.");
1022 #elif defined(__APPLE__) && defined(__TSAN__)
1023   RETURN_SKIP("Times out under TSAN.");
1024 #endif
1025   uv_loop_t* loop;
1026   int r;
1027 
1028   loop = uv_default_loop();
1029 
1030   fs_event_unlink_files(NULL);
1031   create_dir("watch_dir");
1032 
1033   r = uv_fs_event_init(loop, &fs_event);
1034   ASSERT_OK(r);
1035   r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0);
1036   ASSERT_OK(r);
1037 
1038   r = uv_timer_init(loop, &timer);
1039   ASSERT_OK(r);
1040   r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
1041   ASSERT_OK(r);
1042 
1043   uv_run(loop, UV_RUN_DEFAULT);
1044 
1045   uv_close((uv_handle_t*)&timer, close_cb);
1046 
1047   uv_run(loop, UV_RUN_ONCE);
1048 
1049   ASSERT_EQ(2, close_cb_called);
1050   ASSERT_EQ(3, fs_event_cb_called);
1051 
1052   /* Clean up */
1053   fs_event_unlink_files(NULL);
1054   delete_dir("watch_dir/");
1055 
1056   MAKE_VALGRIND_HAPPY(loop);
1057   return 0;
1058 }
1059 
TEST_IMPL(fs_event_start_and_close)1060 TEST_IMPL(fs_event_start_and_close) {
1061 #if defined(NO_FS_EVENTS)
1062   RETURN_SKIP(NO_FS_EVENTS);
1063 #endif
1064   uv_loop_t* loop;
1065   uv_fs_event_t fs_event1;
1066   uv_fs_event_t fs_event2;
1067   int r;
1068 
1069   loop = uv_default_loop();
1070 
1071   create_dir("watch_dir");
1072 
1073   r = uv_fs_event_init(loop, &fs_event1);
1074   ASSERT_OK(r);
1075   r = uv_fs_event_start(&fs_event1, fs_event_cb_dir, "watch_dir", 0);
1076   ASSERT_OK(r);
1077 
1078   r = uv_fs_event_init(loop, &fs_event2);
1079   ASSERT_OK(r);
1080   r = uv_fs_event_start(&fs_event2, fs_event_cb_dir, "watch_dir", 0);
1081   ASSERT_OK(r);
1082 
1083   uv_close((uv_handle_t*) &fs_event2, close_cb);
1084   uv_close((uv_handle_t*) &fs_event1, close_cb);
1085 
1086   uv_run(loop, UV_RUN_DEFAULT);
1087 
1088   ASSERT_EQ(2, close_cb_called);
1089 
1090   delete_dir("watch_dir/");
1091   MAKE_VALGRIND_HAPPY(loop);
1092   return 0;
1093 }
1094 
TEST_IMPL(fs_event_getpath)1095 TEST_IMPL(fs_event_getpath) {
1096 #if defined(NO_FS_EVENTS)
1097   RETURN_SKIP(NO_FS_EVENTS);
1098 #endif
1099   uv_loop_t* loop = uv_default_loop();
1100   unsigned i;
1101   int r;
1102   char buf[1024];
1103   size_t len;
1104   const char* const watch_dir[] = {
1105     "watch_dir",
1106     "watch_dir/",
1107     "watch_dir///",
1108     "watch_dir/subfolder/..",
1109     "watch_dir//subfolder//..//",
1110   };
1111 
1112   create_dir("watch_dir");
1113   create_dir("watch_dir/subfolder");
1114 
1115 
1116   for (i = 0; i < ARRAY_SIZE(watch_dir); i++) {
1117     r = uv_fs_event_init(loop, &fs_event);
1118     ASSERT_OK(r);
1119     len = sizeof buf;
1120     r = uv_fs_event_getpath(&fs_event, buf, &len);
1121     ASSERT_EQ(r, UV_EINVAL);
1122     r = uv_fs_event_start(&fs_event, fail_cb, watch_dir[i], 0);
1123     ASSERT_OK(r);
1124     len = 0;
1125     r = uv_fs_event_getpath(&fs_event, buf, &len);
1126     ASSERT_EQ(r, UV_ENOBUFS);
1127     ASSERT_LT(len, sizeof buf); /* sanity check */
1128     ASSERT_EQ(len, strlen(watch_dir[i]) + 1);
1129     r = uv_fs_event_getpath(&fs_event, buf, &len);
1130     ASSERT_OK(r);
1131     ASSERT_EQ(len, strlen(watch_dir[i]));
1132     ASSERT(strcmp(buf, watch_dir[i]) == 0);
1133     r = uv_fs_event_stop(&fs_event);
1134     ASSERT_OK(r);
1135     uv_close((uv_handle_t*) &fs_event, close_cb);
1136 
1137     uv_run(loop, UV_RUN_DEFAULT);
1138 
1139     ASSERT_EQ(1, close_cb_called);
1140     close_cb_called = 0;
1141   }
1142 
1143   delete_dir("watch_dir/");
1144   MAKE_VALGRIND_HAPPY(loop);
1145   return 0;
1146 }
1147 
TEST_IMPL(fs_event_watch_invalid_path)1148 TEST_IMPL(fs_event_watch_invalid_path) {
1149 #if defined(NO_FS_EVENTS)
1150   RETURN_SKIP(NO_FS_EVENTS);
1151 #endif
1152 
1153   uv_loop_t* loop;
1154   int r;
1155 
1156   loop = uv_default_loop();
1157   r = uv_fs_event_init(loop, &fs_event);
1158   ASSERT_OK(r);
1159   r = uv_fs_event_start(&fs_event, fs_event_cb_file, "<:;", 0);
1160   ASSERT(r);
1161   ASSERT_OK(uv_is_active((uv_handle_t*) &fs_event));
1162   r = uv_fs_event_start(&fs_event, fs_event_cb_file, "", 0);
1163   ASSERT(r);
1164   ASSERT_OK(uv_is_active((uv_handle_t*) &fs_event));
1165   MAKE_VALGRIND_HAPPY(loop);
1166   return 0;
1167 }
1168 
1169 static int fs_event_cb_stop_calls;
1170 
fs_event_cb_stop(uv_fs_event_t * handle,const char * path,int events,int status)1171 static void fs_event_cb_stop(uv_fs_event_t* handle, const char* path,
1172                              int events, int status) {
1173   uv_fs_event_stop(handle);
1174   fs_event_cb_stop_calls++;
1175 }
1176 
TEST_IMPL(fs_event_stop_in_cb)1177 TEST_IMPL(fs_event_stop_in_cb) {
1178   uv_fs_event_t fs;
1179   uv_timer_t timer;
1180   char path[] = "fs_event_stop_in_cb.txt";
1181 
1182 #if defined(NO_FS_EVENTS)
1183   RETURN_SKIP(NO_FS_EVENTS);
1184 #endif
1185 
1186   delete_file(path);
1187   create_file(path);
1188 
1189   ASSERT_OK(uv_fs_event_init(uv_default_loop(), &fs));
1190   ASSERT_OK(uv_fs_event_start(&fs, fs_event_cb_stop, path, 0));
1191 
1192   /* Note: timer_cb_touch() closes the handle. */
1193   timer.data = path;
1194   ASSERT_OK(uv_timer_init(uv_default_loop(), &timer));
1195   ASSERT_OK(uv_timer_start(&timer, timer_cb_touch, 100, 0));
1196 
1197   ASSERT_OK(fs_event_cb_stop_calls);
1198   ASSERT_OK(timer_cb_touch_called);
1199 
1200   ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1201 
1202   ASSERT_EQ(1, fs_event_cb_stop_calls);
1203   ASSERT_EQ(1, timer_cb_touch_called);
1204 
1205   uv_close((uv_handle_t*) &fs, NULL);
1206   ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1207   ASSERT_EQ(1, fs_event_cb_stop_calls);
1208 
1209   delete_file(path);
1210 
1211   MAKE_VALGRIND_HAPPY(uv_default_loop());
1212   return 0;
1213 }
1214