Mercurial
comparison third_party/libuv/test/test-fs-event.c @ 160:948de3f54cea
[ThirdParty] Added libuv
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 14 Jan 2026 19:39:52 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 159:05cf9467a1c3 | 160:948de3f54cea |
|---|---|
| 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 } |