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