test-fs-event.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  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. #include "uv.h"
  22. #include "task.h"
  23. #include <string.h>
  24. #include <fcntl.h>
  25. #ifndef HAVE_KQUEUE
  26. # if defined(__APPLE__) || \
  27. defined(__DragonFly__) || \
  28. defined(__FreeBSD__) || \
  29. defined(__OpenBSD__) || \
  30. defined(__NetBSD__)
  31. # define HAVE_KQUEUE 1
  32. # endif
  33. #endif
  34. static uv_fs_event_t fs_event;
  35. static const char file_prefix[] = "fsevent-";
  36. static uv_timer_t timer;
  37. static int timer_cb_called;
  38. static int close_cb_called;
  39. static const int fs_event_file_count = 128;
  40. static int fs_event_created;
  41. static int fs_event_cb_called;
  42. #if defined(PATH_MAX)
  43. static char fs_event_filename[PATH_MAX];
  44. #else
  45. static char fs_event_filename[1024];
  46. #endif /* defined(PATH_MAX) */
  47. static int timer_cb_touch_called;
  48. static void fs_event_unlink_files(uv_timer_t* handle, int status);
  49. static void create_dir(uv_loop_t* loop, const char* name) {
  50. int r;
  51. uv_fs_t req;
  52. r = uv_fs_mkdir(loop, &req, name, 0755, NULL);
  53. ASSERT(r == 0 || r == UV_EEXIST);
  54. uv_fs_req_cleanup(&req);
  55. }
  56. static void create_file(uv_loop_t* loop, const char* name) {
  57. int r;
  58. uv_file file;
  59. uv_fs_t req;
  60. r = uv_fs_open(loop, &req, name, O_WRONLY | O_CREAT,
  61. S_IWUSR | S_IRUSR, NULL);
  62. ASSERT(r >= 0);
  63. file = r;
  64. uv_fs_req_cleanup(&req);
  65. r = uv_fs_close(loop, &req, file, NULL);
  66. ASSERT(r == 0);
  67. uv_fs_req_cleanup(&req);
  68. }
  69. static void touch_file(uv_loop_t* loop, const char* name) {
  70. int r;
  71. uv_file file;
  72. uv_fs_t req;
  73. r = uv_fs_open(loop, &req, name, O_RDWR, 0, NULL);
  74. ASSERT(r >= 0);
  75. file = r;
  76. uv_fs_req_cleanup(&req);
  77. r = uv_fs_write(loop, &req, file, "foo", 4, -1, NULL);
  78. ASSERT(r >= 0);
  79. uv_fs_req_cleanup(&req);
  80. r = uv_fs_close(loop, &req, file, NULL);
  81. ASSERT(r == 0);
  82. uv_fs_req_cleanup(&req);
  83. }
  84. static void close_cb(uv_handle_t* handle) {
  85. ASSERT(handle != NULL);
  86. close_cb_called++;
  87. }
  88. static void fail_cb(uv_fs_event_t* handle,
  89. const char* path,
  90. int events,
  91. int status) {
  92. ASSERT(0 && "fail_cb called");
  93. }
  94. static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
  95. int events, int status) {
  96. ++fs_event_cb_called;
  97. ASSERT(handle == &fs_event);
  98. ASSERT(status == 0);
  99. ASSERT(events == UV_RENAME);
  100. ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
  101. ASSERT(0 == uv_fs_event_stop(handle));
  102. uv_close((uv_handle_t*)handle, close_cb);
  103. }
  104. static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
  105. const char* filename,
  106. int events,
  107. int status) {
  108. fs_event_cb_called++;
  109. ASSERT(handle == &fs_event);
  110. ASSERT(status == 0);
  111. ASSERT(events == UV_RENAME);
  112. ASSERT(filename == NULL ||
  113. strncmp(filename, file_prefix, sizeof(file_prefix) - 1) == 0);
  114. /* Stop watching dir when received events about all files:
  115. * both create and close events */
  116. if (fs_event_cb_called == 2 * fs_event_file_count) {
  117. ASSERT(0 == uv_fs_event_stop(handle));
  118. uv_close((uv_handle_t*) handle, close_cb);
  119. }
  120. }
  121. static const char* fs_event_get_filename(int i) {
  122. snprintf(fs_event_filename,
  123. sizeof(fs_event_filename),
  124. "watch_dir/%s%d",
  125. file_prefix,
  126. i);
  127. return fs_event_filename;
  128. }
  129. static void fs_event_create_files(uv_timer_t* handle, int status) {
  130. int i;
  131. /* Already created all files */
  132. if (fs_event_created == fs_event_file_count) {
  133. uv_close((uv_handle_t*) &timer, close_cb);
  134. return;
  135. }
  136. /* Create all files */
  137. for (i = 0; i < 16; i++, fs_event_created++)
  138. create_file(handle->loop, fs_event_get_filename(i));
  139. /* And unlink them */
  140. ASSERT(0 == uv_timer_start(&timer, fs_event_unlink_files, 50, 0));
  141. }
  142. void fs_event_unlink_files(uv_timer_t* handle, int status) {
  143. int r;
  144. int i;
  145. /* NOTE: handle might be NULL if invoked not as timer callback */
  146. /* Unlink all files */
  147. for (i = 0; i < 16; i++) {
  148. r = remove(fs_event_get_filename(i));
  149. if (handle != NULL)
  150. ASSERT(r == 0);
  151. }
  152. /* And create them again */
  153. if (handle != NULL)
  154. ASSERT(0 == uv_timer_start(&timer, fs_event_create_files, 50, 0));
  155. }
  156. static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
  157. int events, int status) {
  158. ++fs_event_cb_called;
  159. ASSERT(handle == &fs_event);
  160. ASSERT(status == 0);
  161. ASSERT(events == UV_CHANGE);
  162. ASSERT(filename == NULL || strcmp(filename, "file2") == 0);
  163. ASSERT(0 == uv_fs_event_stop(handle));
  164. uv_close((uv_handle_t*)handle, close_cb);
  165. }
  166. static void timer_cb_close_handle(uv_timer_t* timer, int status) {
  167. uv_handle_t* handle;
  168. ASSERT(timer != NULL);
  169. ASSERT(status == 0);
  170. handle = timer->data;
  171. uv_close((uv_handle_t*)timer, NULL);
  172. uv_close((uv_handle_t*)handle, close_cb);
  173. }
  174. static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
  175. const char* filename, int events, int status) {
  176. ASSERT(fs_event_cb_called == 0);
  177. ++fs_event_cb_called;
  178. ASSERT(handle == &fs_event);
  179. ASSERT(status == 0);
  180. ASSERT(events == UV_CHANGE);
  181. ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
  182. /* Regression test for SunOS: touch should generate just one event. */
  183. {
  184. static uv_timer_t timer;
  185. uv_timer_init(handle->loop, &timer);
  186. timer.data = handle;
  187. uv_timer_start(&timer, timer_cb_close_handle, 250, 0);
  188. }
  189. }
  190. static void timer_cb_file(uv_timer_t* handle, int status) {
  191. ++timer_cb_called;
  192. if (timer_cb_called == 1) {
  193. touch_file(handle->loop, "watch_dir/file1");
  194. } else {
  195. touch_file(handle->loop, "watch_dir/file2");
  196. uv_close((uv_handle_t*)handle, close_cb);
  197. }
  198. }
  199. static void timer_cb_touch(uv_timer_t* timer, int status) {
  200. ASSERT(status == 0);
  201. uv_close((uv_handle_t*)timer, NULL);
  202. touch_file(timer->loop, "watch_file");
  203. timer_cb_touch_called++;
  204. }
  205. static void timer_cb_watch_twice(uv_timer_t* handle, int status) {
  206. uv_fs_event_t* handles = handle->data;
  207. uv_close((uv_handle_t*) (handles + 0), NULL);
  208. uv_close((uv_handle_t*) (handles + 1), NULL);
  209. uv_close((uv_handle_t*) handle, NULL);
  210. }
  211. TEST_IMPL(fs_event_watch_dir) {
  212. uv_loop_t* loop = uv_default_loop();
  213. int r;
  214. /* Setup */
  215. fs_event_unlink_files(NULL, 0);
  216. remove("watch_dir/file2");
  217. remove("watch_dir/file1");
  218. remove("watch_dir/");
  219. create_dir(loop, "watch_dir");
  220. r = uv_fs_event_init(loop, &fs_event);
  221. ASSERT(r == 0);
  222. r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
  223. ASSERT(r == 0);
  224. r = uv_timer_init(loop, &timer);
  225. ASSERT(r == 0);
  226. r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
  227. ASSERT(r == 0);
  228. uv_run(loop, UV_RUN_DEFAULT);
  229. ASSERT(fs_event_cb_called == 2 * fs_event_file_count);
  230. ASSERT(fs_event_created == fs_event_file_count);
  231. ASSERT(close_cb_called == 2);
  232. /* Cleanup */
  233. fs_event_unlink_files(NULL, 0);
  234. remove("watch_dir/file2");
  235. remove("watch_dir/file1");
  236. remove("watch_dir/");
  237. MAKE_VALGRIND_HAPPY();
  238. return 0;
  239. }
  240. TEST_IMPL(fs_event_watch_file) {
  241. uv_loop_t* loop = uv_default_loop();
  242. int r;
  243. /* Setup */
  244. remove("watch_dir/file2");
  245. remove("watch_dir/file1");
  246. remove("watch_dir/");
  247. create_dir(loop, "watch_dir");
  248. create_file(loop, "watch_dir/file1");
  249. create_file(loop, "watch_dir/file2");
  250. r = uv_fs_event_init(loop, &fs_event);
  251. ASSERT(r == 0);
  252. r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file2", 0);
  253. ASSERT(r == 0);
  254. r = uv_timer_init(loop, &timer);
  255. ASSERT(r == 0);
  256. r = uv_timer_start(&timer, timer_cb_file, 100, 100);
  257. ASSERT(r == 0);
  258. uv_run(loop, UV_RUN_DEFAULT);
  259. ASSERT(fs_event_cb_called == 1);
  260. ASSERT(timer_cb_called == 2);
  261. ASSERT(close_cb_called == 2);
  262. /* Cleanup */
  263. remove("watch_dir/file2");
  264. remove("watch_dir/file1");
  265. remove("watch_dir/");
  266. MAKE_VALGRIND_HAPPY();
  267. return 0;
  268. }
  269. TEST_IMPL(fs_event_watch_file_twice) {
  270. const char path[] = "test/fixtures/empty_file";
  271. uv_fs_event_t watchers[2];
  272. uv_timer_t timer;
  273. uv_loop_t* loop;
  274. loop = uv_default_loop();
  275. timer.data = watchers;
  276. ASSERT(0 == uv_fs_event_init(loop, watchers + 0));
  277. ASSERT(0 == uv_fs_event_start(watchers + 0, fail_cb, path, 0));
  278. ASSERT(0 == uv_fs_event_init(loop, watchers + 1));
  279. ASSERT(0 == uv_fs_event_start(watchers + 1, fail_cb, path, 0));
  280. ASSERT(0 == uv_timer_init(loop, &timer));
  281. ASSERT(0 == uv_timer_start(&timer, timer_cb_watch_twice, 10, 0));
  282. ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
  283. MAKE_VALGRIND_HAPPY();
  284. return 0;
  285. }
  286. TEST_IMPL(fs_event_watch_file_current_dir) {
  287. uv_timer_t timer;
  288. uv_loop_t* loop;
  289. int r;
  290. loop = uv_default_loop();
  291. /* Setup */
  292. remove("watch_file");
  293. create_file(loop, "watch_file");
  294. r = uv_fs_event_init(loop, &fs_event);
  295. ASSERT(r == 0);
  296. r = uv_fs_event_start(&fs_event,
  297. fs_event_cb_file_current_dir,
  298. "watch_file",
  299. 0);
  300. ASSERT(r == 0);
  301. r = uv_timer_init(loop, &timer);
  302. ASSERT(r == 0);
  303. r = uv_timer_start(&timer, timer_cb_touch, 1, 0);
  304. ASSERT(r == 0);
  305. ASSERT(timer_cb_touch_called == 0);
  306. ASSERT(fs_event_cb_called == 0);
  307. ASSERT(close_cb_called == 0);
  308. uv_run(loop, UV_RUN_DEFAULT);
  309. ASSERT(timer_cb_touch_called == 1);
  310. ASSERT(fs_event_cb_called == 1);
  311. ASSERT(close_cb_called == 1);
  312. /* Cleanup */
  313. remove("watch_file");
  314. MAKE_VALGRIND_HAPPY();
  315. return 0;
  316. }
  317. TEST_IMPL(fs_event_no_callback_after_close) {
  318. uv_loop_t* loop = uv_default_loop();
  319. int r;
  320. /* Setup */
  321. remove("watch_dir/file1");
  322. remove("watch_dir/");
  323. create_dir(loop, "watch_dir");
  324. create_file(loop, "watch_dir/file1");
  325. r = uv_fs_event_init(loop, &fs_event);
  326. ASSERT(r == 0);
  327. r = uv_fs_event_start(&fs_event,
  328. fs_event_cb_file,
  329. "watch_dir/file1",
  330. 0);
  331. ASSERT(r == 0);
  332. uv_close((uv_handle_t*)&fs_event, close_cb);
  333. touch_file(loop, "watch_dir/file1");
  334. uv_run(loop, UV_RUN_DEFAULT);
  335. ASSERT(fs_event_cb_called == 0);
  336. ASSERT(close_cb_called == 1);
  337. /* Cleanup */
  338. remove("watch_dir/file1");
  339. remove("watch_dir/");
  340. MAKE_VALGRIND_HAPPY();
  341. return 0;
  342. }
  343. TEST_IMPL(fs_event_no_callback_on_close) {
  344. uv_loop_t* loop = uv_default_loop();
  345. int r;
  346. /* Setup */
  347. remove("watch_dir/file1");
  348. remove("watch_dir/");
  349. create_dir(loop, "watch_dir");
  350. create_file(loop, "watch_dir/file1");
  351. r = uv_fs_event_init(loop, &fs_event);
  352. ASSERT(r == 0);
  353. r = uv_fs_event_start(&fs_event,
  354. fs_event_cb_file,
  355. "watch_dir/file1",
  356. 0);
  357. ASSERT(r == 0);
  358. uv_close((uv_handle_t*)&fs_event, close_cb);
  359. uv_run(loop, UV_RUN_DEFAULT);
  360. ASSERT(fs_event_cb_called == 0);
  361. ASSERT(close_cb_called == 1);
  362. /* Cleanup */
  363. remove("watch_dir/file1");
  364. remove("watch_dir/");
  365. MAKE_VALGRIND_HAPPY();
  366. return 0;
  367. }
  368. static void fs_event_fail(uv_fs_event_t* handle, const char* filename,
  369. int events, int status) {
  370. ASSERT(0 && "should never be called");
  371. }
  372. static void timer_cb(uv_timer_t* handle, int status) {
  373. int r;
  374. ASSERT(status == 0);
  375. r = uv_fs_event_init(handle->loop, &fs_event);
  376. ASSERT(r == 0);
  377. r = uv_fs_event_start(&fs_event, fs_event_fail, ".", 0);
  378. ASSERT(r == 0);
  379. uv_close((uv_handle_t*)&fs_event, close_cb);
  380. uv_close((uv_handle_t*)handle, close_cb);
  381. }
  382. TEST_IMPL(fs_event_immediate_close) {
  383. uv_timer_t timer;
  384. uv_loop_t* loop;
  385. int r;
  386. loop = uv_default_loop();
  387. r = uv_timer_init(loop, &timer);
  388. ASSERT(r == 0);
  389. r = uv_timer_start(&timer, timer_cb, 1, 0);
  390. ASSERT(r == 0);
  391. uv_run(loop, UV_RUN_DEFAULT);
  392. ASSERT(close_cb_called == 2);
  393. MAKE_VALGRIND_HAPPY();
  394. return 0;
  395. }
  396. TEST_IMPL(fs_event_close_with_pending_event) {
  397. uv_loop_t* loop;
  398. int r;
  399. loop = uv_default_loop();
  400. create_dir(loop, "watch_dir");
  401. create_file(loop, "watch_dir/file");
  402. r = uv_fs_event_init(loop, &fs_event);
  403. ASSERT(r == 0);
  404. r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir", 0);
  405. ASSERT(r == 0);
  406. /* Generate an fs event. */
  407. touch_file(loop, "watch_dir/file");
  408. uv_close((uv_handle_t*)&fs_event, close_cb);
  409. uv_run(loop, UV_RUN_DEFAULT);
  410. ASSERT(close_cb_called == 1);
  411. /* Clean up */
  412. remove("watch_dir/file");
  413. remove("watch_dir/");
  414. MAKE_VALGRIND_HAPPY();
  415. return 0;
  416. }
  417. #if defined(HAVE_KQUEUE)
  418. /* kqueue doesn't register fs events if you don't have an active watcher.
  419. * The file descriptor needs to be part of the kqueue set of interest and
  420. * that's not the case until we actually enter the event loop.
  421. */
  422. TEST_IMPL(fs_event_close_in_callback) {
  423. fprintf(stderr, "Skipping test, doesn't work with kqueue.\n");
  424. return 0;
  425. }
  426. #else /* !HAVE_KQUEUE */
  427. static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename,
  428. int events, int status) {
  429. ASSERT(status == 0);
  430. ASSERT(fs_event_cb_called < 3);
  431. ++fs_event_cb_called;
  432. if (fs_event_cb_called == 3) {
  433. uv_close((uv_handle_t*) handle, close_cb);
  434. }
  435. }
  436. TEST_IMPL(fs_event_close_in_callback) {
  437. uv_loop_t* loop;
  438. int r;
  439. loop = uv_default_loop();
  440. create_dir(loop, "watch_dir");
  441. create_file(loop, "watch_dir/file1");
  442. create_file(loop, "watch_dir/file2");
  443. create_file(loop, "watch_dir/file3");
  444. create_file(loop, "watch_dir/file4");
  445. create_file(loop, "watch_dir/file5");
  446. r = uv_fs_event_init(loop, &fs_event);
  447. ASSERT(r == 0);
  448. r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0);
  449. ASSERT(r == 0);
  450. /* Generate a couple of fs events. */
  451. touch_file(loop, "watch_dir/file1");
  452. touch_file(loop, "watch_dir/file2");
  453. touch_file(loop, "watch_dir/file3");
  454. touch_file(loop, "watch_dir/file4");
  455. touch_file(loop, "watch_dir/file5");
  456. uv_run(loop, UV_RUN_DEFAULT);
  457. ASSERT(close_cb_called == 1);
  458. ASSERT(fs_event_cb_called == 3);
  459. /* Clean up */
  460. remove("watch_dir/file1");
  461. remove("watch_dir/file2");
  462. remove("watch_dir/file3");
  463. remove("watch_dir/file4");
  464. remove("watch_dir/file5");
  465. remove("watch_dir/");
  466. MAKE_VALGRIND_HAPPY();
  467. return 0;
  468. }
  469. #endif /* HAVE_KQUEUE */
  470. TEST_IMPL(fs_event_start_and_close) {
  471. uv_loop_t* loop;
  472. uv_fs_event_t fs_event1;
  473. uv_fs_event_t fs_event2;
  474. int r;
  475. loop = uv_default_loop();
  476. create_dir(loop, "watch_dir");
  477. r = uv_fs_event_init(loop, &fs_event1);
  478. ASSERT(r == 0);
  479. r = uv_fs_event_start(&fs_event1, fs_event_cb_dir, "watch_dir", 0);
  480. ASSERT(r == 0);
  481. r = uv_fs_event_init(loop, &fs_event2);
  482. ASSERT(r == 0);
  483. r = uv_fs_event_start(&fs_event2, fs_event_cb_dir, "watch_dir", 0);
  484. ASSERT(r == 0);
  485. uv_close((uv_handle_t*) &fs_event2, close_cb);
  486. uv_close((uv_handle_t*) &fs_event1, close_cb);
  487. uv_run(loop, UV_RUN_DEFAULT);
  488. ASSERT(close_cb_called == 2);
  489. remove("watch_dir/");
  490. MAKE_VALGRIND_HAPPY();
  491. return 0;
  492. }
  493. #if defined(__APPLE__)
  494. static int fs_event_error_reported;
  495. static void fs_event_error_report_cb(uv_fs_event_t* handle,
  496. const char* filename,
  497. int events,
  498. int status) {
  499. if (status != 0)
  500. fs_event_error_reported = status;
  501. }
  502. static void timer_cb_nop(uv_timer_t* handle, int status) {
  503. ++timer_cb_called;
  504. uv_close((uv_handle_t*) handle, close_cb);
  505. }
  506. static void fs_event_error_report_close_cb(uv_handle_t* handle) {
  507. ASSERT(handle != NULL);
  508. close_cb_called++;
  509. /* handle is allocated on-stack, no need to free it */
  510. }
  511. TEST_IMPL(fs_event_error_reporting) {
  512. unsigned int i;
  513. uv_loop_t* loops[1024];
  514. uv_fs_event_t events[ARRAY_SIZE(loops)];
  515. uv_loop_t* loop;
  516. uv_fs_event_t* event;
  517. TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3);
  518. remove("watch_dir/");
  519. create_dir(uv_default_loop(), "watch_dir");
  520. /* Create a lot of loops, and start FSEventStream in each of them.
  521. * Eventually, this should create enough streams to make FSEventStreamStart()
  522. * fail.
  523. */
  524. for (i = 0; i < ARRAY_SIZE(loops); i++) {
  525. loop = uv_loop_new();
  526. event = &events[i];
  527. ASSERT(loop != NULL);
  528. loops[i] = loop;
  529. timer_cb_called = 0;
  530. close_cb_called = 0;
  531. ASSERT(0 == uv_fs_event_init(loop, event));
  532. ASSERT(0 == uv_fs_event_start(event,
  533. fs_event_error_report_cb,
  534. "watch_dir",
  535. 0));
  536. uv_unref((uv_handle_t*) event);
  537. /* Let loop run for some time */
  538. ASSERT(0 == uv_timer_init(loop, &timer));
  539. ASSERT(0 == uv_timer_start(&timer, timer_cb_nop, 2, 0));
  540. uv_run(loop, UV_RUN_DEFAULT);
  541. ASSERT(1 == timer_cb_called);
  542. ASSERT(1 == close_cb_called);
  543. if (fs_event_error_reported != 0)
  544. break;
  545. }
  546. /* At least one loop should fail */
  547. ASSERT(fs_event_error_reported == UV_EMFILE);
  548. /* Stop and close all events, and destroy loops */
  549. do {
  550. loop = loops[i];
  551. event = &events[i];
  552. ASSERT(0 == uv_fs_event_stop(event));
  553. uv_ref((uv_handle_t*) event);
  554. uv_close((uv_handle_t*) event, fs_event_error_report_close_cb);
  555. close_cb_called = 0;
  556. uv_run(loop, UV_RUN_DEFAULT);
  557. ASSERT(close_cb_called == 1);
  558. uv_loop_delete(loop);
  559. loops[i] = NULL;
  560. } while (i-- != 0);
  561. remove("watch_dir/");
  562. MAKE_VALGRIND_HAPPY();
  563. return 0;
  564. }
  565. #else /* !defined(__APPLE__) */
  566. TEST_IMPL(fs_event_error_reporting) {
  567. /* No-op, needed only for FSEvents backend */
  568. MAKE_VALGRIND_HAPPY();
  569. return 0;
  570. }
  571. #endif /* defined(__APPLE__) */