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