libuv-svace-build

Форк
0
/
test-fs-event.c 
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_IPHONE
29
# include <AvailabilityMacros.h>
30
#endif
31

32
static uv_fs_event_t fs_event;
33
static const char file_prefix[] = "fsevent-";
34
static const int fs_event_file_count = 16;
35
#if defined(__APPLE__) || defined(_WIN32)
36
static const char file_prefix_in_subdir[] = "subdir";
37
static int fs_multievent_cb_called;
38
#endif
39
static uv_timer_t timer;
40
static int timer_cb_called;
41
static int close_cb_called;
42
static int fs_event_created;
43
static int fs_event_removed;
44
static int fs_event_cb_called;
45
#if defined(PATH_MAX)
46
static char fs_event_filename[PATH_MAX];
47
#else
48
static char fs_event_filename[1024];
49
#endif  /* defined(PATH_MAX) */
50
static int timer_cb_touch_called;
51
static int timer_cb_exact_called;
52

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 void touch_file(const char* name) {
85
  int r;
86
  uv_file file;
87
  uv_fs_t req;
88
  uv_buf_t buf;
89

90
  r = uv_fs_open(NULL, &req, name, UV_FS_O_RDWR, 0, NULL);
91
  ASSERT_GE(r, 0);
92
  file = r;
93
  uv_fs_req_cleanup(&req);
94

95
  buf = uv_buf_init("foo", 4);
96
  r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
97
  ASSERT_GE(r, 0);
98
  uv_fs_req_cleanup(&req);
99

100
  r = uv_fs_close(NULL, &req, file, NULL);
101
  ASSERT_OK(r);
102
  uv_fs_req_cleanup(&req);
103
}
104

105
static void close_cb(uv_handle_t* handle) {
106
  ASSERT_NOT_NULL(handle);
107
  close_cb_called++;
108
}
109

110
static void fail_cb(uv_fs_event_t* handle,
111
                    const char* path,
112
                    int events,
113
                    int status) {
114
  ASSERT(0 && "fail_cb called");
115
}
116

117
static void fs_event_cb_dir(uv_fs_event_t* handle, const char* filename,
118
  int events, int status) {
119
  ++fs_event_cb_called;
120
  ASSERT_PTR_EQ(handle, &fs_event);
121
  ASSERT_OK(status);
122
  ASSERT_EQ(events, UV_CHANGE);
123
  #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
124
  ASSERT_OK(strcmp(filename, "file1"));
125
  #else
126
  ASSERT(filename == NULL || strcmp(filename, "file1") == 0);
127
  #endif
128
  ASSERT_OK(uv_fs_event_stop(handle));
129
  uv_close((uv_handle_t*)handle, close_cb);
130
}
131

132
static const char* fs_event_get_filename(int i) {
133
  snprintf(fs_event_filename,
134
           sizeof(fs_event_filename),
135
           "watch_dir/%s%d",
136
           file_prefix,
137
           i);
138
  return fs_event_filename;
139
}
140

141
static void fs_event_create_files(uv_timer_t* handle) {
142
  /* Make sure we're not attempting to create files we do not intend */
143
  ASSERT_LT(fs_event_created, fs_event_file_count);
144

145
  /* Create the file */
146
  create_file(fs_event_get_filename(fs_event_created));
147

148
  if (++fs_event_created < fs_event_file_count) {
149
    /* Create another file on a different event loop tick.  We do it this way
150
     * to avoid fs events coalescing into one fs event. */
151
    ASSERT_OK(uv_timer_start(&timer, fs_event_create_files, 100, 0));
152
  }
153
}
154

155
static void fs_event_unlink_files(uv_timer_t* handle) {
156
  int r;
157
  int i;
158

159
  /* NOTE: handle might be NULL if invoked not as timer callback */
160
  if (handle == NULL) {
161
    /* Unlink all files */
162
    for (i = 0; i < 16; i++) {
163
      r = remove(fs_event_get_filename(i));
164
      if (handle != NULL)
165
        ASSERT_OK(r);
166
    }
167
  } else {
168
    /* Make sure we're not attempting to remove files we do not intend */
169
    ASSERT_LT(fs_event_removed, fs_event_file_count);
170

171
    /* Remove the file */
172
    ASSERT_OK(remove(fs_event_get_filename(fs_event_removed)));
173

174
    if (++fs_event_removed < fs_event_file_count) {
175
      /* Remove another file on a different event loop tick.  We do it this way
176
       * to avoid fs events coalescing into one fs event. */
177
      ASSERT_OK(uv_timer_start(&timer, fs_event_unlink_files, 1, 0));
178
    }
179
  }
180
}
181

182
static void fs_event_cb_dir_multi_file(uv_fs_event_t* handle,
183
                                       const char* filename,
184
                                       int events,
185
                                       int status) {
186
  fs_event_cb_called++;
187
  ASSERT_PTR_EQ(handle, &fs_event);
188
  ASSERT_OK(status);
189
  ASSERT(events == UV_CHANGE || events == UV_RENAME);
190
#if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
191
  ASSERT_NOT_NULL(filename);
192
  ASSERT_MEM_EQ(filename, file_prefix, sizeof(file_prefix) - 1);
193
#else
194
  if (filename != NULL)
195
    ASSERT_MEM_EQ(filename, file_prefix, sizeof(file_prefix) - 1);
196
#endif
197

198
  if (fs_event_created + fs_event_removed == fs_event_file_count) {
199
    /* Once we've processed all create events, delete all files */
200
    ASSERT_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 */
203
    uv_close((uv_handle_t*) &timer, close_cb);
204
    uv_close((uv_handle_t*) handle, close_cb);
205
  }
206
}
207

208
#if defined(__APPLE__) || defined(_WIN32)
209
static const char* fs_event_get_filename_in_subdir(int i) {
210
  snprintf(fs_event_filename,
211
           sizeof(fs_event_filename),
212
           "watch_dir/subdir/%s%d",
213
           file_prefix,
214
           i);
215
  return fs_event_filename;
216
}
217

218
static 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 */
220
  ASSERT_LT(fs_event_created, fs_event_file_count);
221

222
  /* Create the file */
223
  create_file(fs_event_get_filename_in_subdir(fs_event_created));
224

225
  if (++fs_event_created < fs_event_file_count) {
226
    /* Create another file on a different event loop tick.  We do it this way
227
     * to avoid fs events coalescing into one fs event. */
228
    ASSERT_OK(uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0));
229
  }
230
}
231

232
static void fs_event_unlink_files_in_subdir(uv_timer_t* handle) {
233
  int r;
234
  int i;
235

236
  /* NOTE: handle might be NULL if invoked not as timer callback */
237
  if (handle == NULL) {
238
    /* Unlink all files */
239
    for (i = 0; i < 16; i++) {
240
      r = remove(fs_event_get_filename_in_subdir(i));
241
      if (handle != NULL)
242
        ASSERT_OK(r);
243
    }
244
  } else {
245
    /* Make sure we're not attempting to remove files we do not intend */
246
    ASSERT_LT(fs_event_removed, fs_event_file_count);
247

248
    /* Remove the file */
249
    ASSERT_OK(remove(fs_event_get_filename_in_subdir(fs_event_removed)));
250

251
    if (++fs_event_removed < fs_event_file_count) {
252
      /* Remove another file on a different event loop tick.  We do it this way
253
       * to avoid fs events coalescing into one fs event. */
254
      ASSERT_OK(uv_timer_start(&timer,
255
                               fs_event_unlink_files_in_subdir,
256
                               1,
257
                               0));
258
    }
259
  }
260
}
261

262
static void fs_event_cb_dir_multi_file_in_subdir(uv_fs_event_t* handle,
263
                                                 const char* filename,
264
                                                 int events,
265
                                                 int status) {
266
#ifdef _WIN32
267
  /* Each file created (or deleted) will cause this callback to be called twice
268
   * 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. */
271
  if (filename && strcmp(filename, file_prefix_in_subdir) == 0)
272
    return;
273
#endif
274
  /* It may happen that the "subdir" creation event is captured even though
275
   * we started watching after its actual creation.
276
   */
277
  if (strcmp(filename, "subdir") == 0)
278
    return;
279

280
  fs_multievent_cb_called++;
281
  ASSERT_PTR_EQ(handle, &fs_event);
282
  ASSERT_OK(status);
283
  ASSERT(events == UV_CHANGE || events == UV_RENAME);
284
  #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
285
  ASSERT_OK(strncmp(filename,
286
                    file_prefix_in_subdir,
287
                    sizeof(file_prefix_in_subdir) - 1));
288
  #else
289
  ASSERT_NE(filename == NULL ||
290
            strncmp(filename,
291
                    file_prefix_in_subdir,
292
                    sizeof(file_prefix_in_subdir) - 1) == 0, 0);
293
  #endif
294

295
  if (fs_event_created == fs_event_file_count &&
296
      fs_multievent_cb_called == fs_event_created) {
297
    /* Once we've processed all create events, delete all files */
298
    ASSERT_OK(uv_timer_start(&timer,
299
                             fs_event_unlink_files_in_subdir,
300
                             1,
301
                             0));
302
  } else if (fs_multievent_cb_called == 2 * fs_event_file_count) {
303
    /* Once we've processed all create and delete events, stop watching */
304
    ASSERT_EQ(fs_event_removed, fs_event_file_count);
305
    uv_close((uv_handle_t*) &timer, close_cb);
306
    uv_close((uv_handle_t*) handle, close_cb);
307
  }
308
}
309
#endif
310

311
static void fs_event_cb_file(uv_fs_event_t* handle, const char* filename,
312
  int events, int status) {
313
  ++fs_event_cb_called;
314
  ASSERT_PTR_EQ(handle, &fs_event);
315
  ASSERT_OK(status);
316
  ASSERT_EQ(events, UV_CHANGE);
317
  #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
318
  ASSERT_OK(strcmp(filename, "file2"));
319
  #else
320
  ASSERT(filename == NULL || strcmp(filename, "file2") == 0);
321
  #endif
322
  ASSERT_OK(uv_fs_event_stop(handle));
323
  uv_close((uv_handle_t*)handle, close_cb);
324
}
325

326
static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
327
  const char* filename, int events, int status) {
328
  ++fs_event_cb_called;
329

330
  ASSERT_PTR_EQ(handle, &fs_event);
331
  ASSERT_OK(status);
332
  ASSERT_EQ(events, UV_CHANGE);
333
  #if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)
334
  ASSERT_OK(strcmp(filename, "watch_file"));
335
  #else
336
  ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
337
  #endif
338

339
  uv_close((uv_handle_t*)handle, close_cb);
340
}
341

342
static void timer_cb_file(uv_timer_t* handle) {
343
  ++timer_cb_called;
344

345
  if (timer_cb_called == 1) {
346
    touch_file("watch_dir/file1");
347
  } else {
348
    touch_file("watch_dir/file2");
349
    uv_close((uv_handle_t*)handle, close_cb);
350
  }
351
}
352

353
static void timer_cb_touch(uv_timer_t* timer) {
354
  uv_close((uv_handle_t*)timer, NULL);
355
  touch_file((char*) timer->data);
356
  timer_cb_touch_called++;
357
}
358

359
static void timer_cb_exact(uv_timer_t* handle) {
360
  int r;
361

362
  if (timer_cb_exact_called == 0) {
363
    touch_file("watch_dir/file.js");
364
  } else {
365
    uv_close((uv_handle_t*)handle, NULL);
366
    r = uv_fs_event_stop(&fs_event);
367
    ASSERT_OK(r);
368
    uv_close((uv_handle_t*) &fs_event, NULL);
369
  }
370

371
  ++timer_cb_exact_called;
372
}
373

374
static void timer_cb_watch_twice(uv_timer_t* handle) {
375
  uv_fs_event_t* handles = handle->data;
376
  uv_close((uv_handle_t*) (handles + 0), NULL);
377
  uv_close((uv_handle_t*) (handles + 1), NULL);
378
  uv_close((uv_handle_t*) handle, NULL);
379
}
380

381
static void fs_event_cb_close(uv_fs_event_t* handle,
382
                              const char* filename,
383
                              int events,
384
                              int status) {
385
  ASSERT_OK(status);
386

387
  ASSERT_LT(fs_event_cb_called, 3);
388
  ++fs_event_cb_called;
389

390
  if (fs_event_cb_called == 3) {
391
    uv_close((uv_handle_t*) handle, close_cb);
392
  }
393
}
394

395

396
TEST_IMPL(fs_event_watch_dir) {
397
#if defined(NO_FS_EVENTS)
398
  RETURN_SKIP(NO_FS_EVENTS);
399
#elif defined(__MVS__)
400
  RETURN_SKIP("Directory watching not supported on this platform.");
401
#elif defined(__APPLE__) && defined(__TSAN__)
402
  RETURN_SKIP("Times out under TSAN.");
403
#endif
404

405
  uv_loop_t* loop = uv_default_loop();
406
  int r;
407

408
  /* Setup */
409
  fs_event_unlink_files(NULL);
410
  remove("watch_dir/file2");
411
  remove("watch_dir/file1");
412
  remove("watch_dir/");
413
  create_dir("watch_dir");
414

415
  r = uv_fs_event_init(loop, &fs_event);
416
  ASSERT_OK(r);
417
  r = uv_fs_event_start(&fs_event, fs_event_cb_dir_multi_file, "watch_dir", 0);
418
  ASSERT_OK(r);
419
  r = uv_timer_init(loop, &timer);
420
  ASSERT_OK(r);
421
  r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
422
  ASSERT_OK(r);
423

424
  uv_run(loop, UV_RUN_DEFAULT);
425

426
  ASSERT_EQ(fs_event_cb_called, fs_event_created + fs_event_removed);
427
  ASSERT_EQ(2, close_cb_called);
428

429
  /* Cleanup */
430
  fs_event_unlink_files(NULL);
431
  remove("watch_dir/file2");
432
  remove("watch_dir/file1");
433
  remove("watch_dir/");
434

435
  MAKE_VALGRIND_HAPPY(loop);
436
  return 0;
437
}
438

439

440
TEST_IMPL(fs_event_watch_dir_recursive) {
441
#if defined(__APPLE__) && defined(__TSAN__)
442
  RETURN_SKIP("Times out under TSAN.");
443
#elif defined(__APPLE__) || defined(_WIN32)
444
  uv_loop_t* loop;
445
  int r;
446
  uv_fs_event_t fs_event_root;
447

448
  /* Setup */
449
  loop = uv_default_loop();
450
  fs_event_unlink_files(NULL);
451
  remove("watch_dir/file2");
452
  remove("watch_dir/file1");
453
  remove("watch_dir/subdir");
454
  remove("watch_dir/");
455
  create_dir("watch_dir");
456
  create_dir("watch_dir/subdir");
457

458
  r = uv_fs_event_init(loop, &fs_event);
459
  ASSERT_OK(r);
460
  r = uv_fs_event_start(&fs_event,
461
                        fs_event_cb_dir_multi_file_in_subdir,
462
                        "watch_dir",
463
                        UV_FS_EVENT_RECURSIVE);
464
  ASSERT_OK(r);
465
  r = uv_timer_init(loop, &timer);
466
  ASSERT_OK(r);
467
  r = uv_timer_start(&timer, fs_event_create_files_in_subdir, 100, 0);
468
  ASSERT_OK(r);
469

470
#ifndef _WIN32
471
  /* Also try to watch the root directory.
472
   * This will be noisier, so we're just checking for any couple events to happen. */
473
  r = uv_fs_event_init(loop, &fs_event_root);
474
  ASSERT_OK(r);
475
  r = uv_fs_event_start(&fs_event_root,
476
                        fs_event_cb_close,
477
                        "/",
478
                        UV_FS_EVENT_RECURSIVE);
479
  ASSERT_OK(r);
480
#else
481
  fs_event_cb_called += 3;
482
  close_cb_called += 1;
483
  (void)fs_event_root;
484
#endif
485

486
  uv_run(loop, UV_RUN_DEFAULT);
487

488
  ASSERT_EQ(fs_multievent_cb_called, fs_event_created + fs_event_removed);
489
  ASSERT_EQ(3, fs_event_cb_called);
490
  ASSERT_EQ(3, close_cb_called);
491

492
  /* Cleanup */
493
  fs_event_unlink_files_in_subdir(NULL);
494
  remove("watch_dir/file2");
495
  remove("watch_dir/file1");
496
  remove("watch_dir/subdir");
497
  remove("watch_dir/");
498

499
  MAKE_VALGRIND_HAPPY(loop);
500
  return 0;
501
#else
502
  RETURN_SKIP("Recursive directory watching not supported on this platform.");
503
#endif
504
}
505

506
#ifdef _WIN32
507
TEST_IMPL(fs_event_watch_dir_short_path) {
508
  uv_loop_t* loop;
509
  uv_fs_t req;
510
  int has_shortnames;
511
  int r;
512

513
  /* Setup */
514
  loop = uv_default_loop();
515
  remove("watch_dir/file1");
516
  remove("watch_dir/");
517
  create_dir("watch_dir");
518
  create_file("watch_dir/file1");
519

520
  /* Newer version of Windows ship with
521
     HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation
522
     not equal to 0. So we verify the files we created are addressable by a 8.3
523
     short name */
524
  has_shortnames = uv_fs_stat(NULL, &req, "watch_~1", NULL) != UV_ENOENT;
525
  if (has_shortnames) {
526
    r = uv_fs_event_init(loop, &fs_event);
527
    ASSERT_OK(r);
528
    r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_~1", 0);
529
    ASSERT_OK(r);
530
    r = uv_timer_init(loop, &timer);
531
    ASSERT_OK(r);
532
    r = uv_timer_start(&timer, timer_cb_file, 100, 0);
533
    ASSERT_OK(r);
534

535
    uv_run(loop, UV_RUN_DEFAULT);
536

537
    ASSERT_EQ(1, fs_event_cb_called);
538
    ASSERT_EQ(1, timer_cb_called);
539
    ASSERT_EQ(1, close_cb_called);
540
  }
541

542
  /* Cleanup */
543
  remove("watch_dir/file1");
544
  remove("watch_dir/");
545

546
  MAKE_VALGRIND_HAPPY(loop);
547

548
  if (!has_shortnames)
549
    RETURN_SKIP("Was not able to address files with 8.3 short name.");
550

551
  return 0;
552
}
553
#endif
554

555

556
TEST_IMPL(fs_event_watch_file) {
557
#if defined(NO_FS_EVENTS)
558
  RETURN_SKIP(NO_FS_EVENTS);
559
#endif
560

561
  uv_loop_t* loop = uv_default_loop();
562
  int r;
563

564
  /* Setup */
565
  remove("watch_dir/file2");
566
  remove("watch_dir/file1");
567
  remove("watch_dir/");
568
  create_dir("watch_dir");
569
  create_file("watch_dir/file1");
570
  create_file("watch_dir/file2");
571

572
  r = uv_fs_event_init(loop, &fs_event);
573
  ASSERT_OK(r);
574
  r = uv_fs_event_start(&fs_event, fs_event_cb_file, "watch_dir/file2", 0);
575
  ASSERT_OK(r);
576
  r = uv_timer_init(loop, &timer);
577
  ASSERT_OK(r);
578
  r = uv_timer_start(&timer, timer_cb_file, 100, 100);
579
  ASSERT_OK(r);
580

581
  uv_run(loop, UV_RUN_DEFAULT);
582

583
  ASSERT_EQ(1, fs_event_cb_called);
584
  ASSERT_EQ(2, timer_cb_called);
585
  ASSERT_EQ(2, close_cb_called);
586

587
  /* Cleanup */
588
  remove("watch_dir/file2");
589
  remove("watch_dir/file1");
590
  remove("watch_dir/");
591

592
  MAKE_VALGRIND_HAPPY(loop);
593
  return 0;
594
}
595

596
TEST_IMPL(fs_event_watch_file_exact_path) {
597
  /*
598
    This 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)
603
  RETURN_SKIP(NO_FS_EVENTS);
604
#endif
605

606
  uv_loop_t* loop;
607
  int r;
608

609
  loop = uv_default_loop();
610

611
  /* Setup */
612
  remove("watch_dir/file.js");
613
  remove("watch_dir/file.jsx");
614
  remove("watch_dir/");
615
  create_dir("watch_dir");
616
  create_file("watch_dir/file.js");
617
  create_file("watch_dir/file.jsx");
618
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12)
619
  /* Empirically, FSEvents seems to (reliably) report the preceding
620
   * 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. */
624
  uv_sleep(1100);
625
  uv_update_time(loop);
626
#endif
627

628
  r = uv_fs_event_init(loop, &fs_event);
629
  ASSERT_OK(r);
630
  r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file.jsx", 0);
631
  ASSERT_OK(r);
632
  r = uv_timer_init(loop, &timer);
633
  ASSERT_OK(r);
634
  r = uv_timer_start(&timer, timer_cb_exact, 100, 100);
635
  ASSERT_OK(r);
636
  r = uv_run(loop, UV_RUN_DEFAULT);
637
  ASSERT_OK(r);
638
  ASSERT_EQ(2, timer_cb_exact_called);
639

640
  /* Cleanup */
641
  remove("watch_dir/file.js");
642
  remove("watch_dir/file.jsx");
643
  remove("watch_dir/");
644

645
  MAKE_VALGRIND_HAPPY(loop);
646
  return 0;
647
}
648

649
TEST_IMPL(fs_event_watch_file_twice) {
650
#if defined(NO_FS_EVENTS)
651
  RETURN_SKIP(NO_FS_EVENTS);
652
#endif
653
  const char path[] = "test/fixtures/empty_file";
654
  uv_fs_event_t watchers[2];
655
  uv_timer_t timer;
656
  uv_loop_t* loop;
657

658
  loop = uv_default_loop();
659
  timer.data = watchers;
660

661
  ASSERT_OK(uv_fs_event_init(loop, watchers + 0));
662
  ASSERT_OK(uv_fs_event_start(watchers + 0, fail_cb, path, 0));
663
  ASSERT_OK(uv_fs_event_init(loop, watchers + 1));
664
  ASSERT_OK(uv_fs_event_start(watchers + 1, fail_cb, path, 0));
665
  ASSERT_OK(uv_timer_init(loop, &timer));
666
  ASSERT_OK(uv_timer_start(&timer, timer_cb_watch_twice, 10, 0));
667
  ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
668

669
  MAKE_VALGRIND_HAPPY(loop);
670
  return 0;
671
}
672

673
TEST_IMPL(fs_event_watch_file_current_dir) {
674
#if defined(NO_FS_EVENTS)
675
  RETURN_SKIP(NO_FS_EVENTS);
676
#endif
677
  uv_timer_t timer;
678
  uv_loop_t* loop;
679
  int r;
680

681
  loop = uv_default_loop();
682

683
  /* Setup */
684
  remove("watch_file");
685
  create_file("watch_file");
686
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12)
687
  /* Empirically, kevent seems to (sometimes) report the preceding
688
   * 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. */
690
  uv_sleep(1100);
691
  uv_update_time(loop);
692
#endif
693

694
  r = uv_fs_event_init(loop, &fs_event);
695
  ASSERT_OK(r);
696
  r = uv_fs_event_start(&fs_event,
697
                        fs_event_cb_file_current_dir,
698
                        "watch_file",
699
                        0);
700
  ASSERT_OK(r);
701

702

703
  r = uv_timer_init(loop, &timer);
704
  ASSERT_OK(r);
705

706
  timer.data = "watch_file";
707
  r = uv_timer_start(&timer, timer_cb_touch, 1100, 0);
708
  ASSERT_OK(r);
709

710
  ASSERT_OK(timer_cb_touch_called);
711
  ASSERT_OK(fs_event_cb_called);
712
  ASSERT_OK(close_cb_called);
713

714
  uv_run(loop, UV_RUN_DEFAULT);
715

716
  ASSERT_EQ(1, timer_cb_touch_called);
717
  /* FSEvents on macOS sometimes sends one change event, sometimes two. */
718
  ASSERT_NE(0, fs_event_cb_called);
719
  ASSERT_EQ(1, close_cb_called);
720

721
  /* Cleanup */
722
  remove("watch_file");
723

724
  MAKE_VALGRIND_HAPPY(loop);
725
  return 0;
726
}
727

728
#ifdef _WIN32
729
TEST_IMPL(fs_event_watch_file_root_dir) {
730
  uv_loop_t* loop;
731
  int r;
732

733
  const char* sys_drive = getenv("SystemDrive");
734
  char path[] = "\\\\?\\X:\\bootsect.bak";
735

736
  ASSERT_NOT_NULL(sys_drive);
737
  strncpy(path + sizeof("\\\\?\\") - 1, sys_drive, 1);
738

739
  loop = uv_default_loop();
740

741
  r = uv_fs_event_init(loop, &fs_event);
742
  ASSERT_OK(r);
743
  r = uv_fs_event_start(&fs_event, fail_cb, path, 0);
744
  if (r == UV_ENOENT)
745
    RETURN_SKIP("bootsect.bak doesn't exist in system root.\n");
746
  ASSERT_OK(r);
747

748
  uv_close((uv_handle_t*) &fs_event, NULL);
749

750
  MAKE_VALGRIND_HAPPY(loop);
751
  return 0;
752
}
753
#endif
754

755
TEST_IMPL(fs_event_no_callback_after_close) {
756
#if defined(NO_FS_EVENTS)
757
  RETURN_SKIP(NO_FS_EVENTS);
758
#endif
759

760
  uv_loop_t* loop = uv_default_loop();
761
  int r;
762

763
  /* Setup */
764
  remove("watch_dir/file1");
765
  remove("watch_dir/");
766
  create_dir("watch_dir");
767
  create_file("watch_dir/file1");
768

769
  r = uv_fs_event_init(loop, &fs_event);
770
  ASSERT_OK(r);
771
  r = uv_fs_event_start(&fs_event,
772
                        fs_event_cb_file,
773
                        "watch_dir/file1",
774
                        0);
775
  ASSERT_OK(r);
776

777

778
  uv_close((uv_handle_t*)&fs_event, close_cb);
779
  touch_file("watch_dir/file1");
780
  uv_run(loop, UV_RUN_DEFAULT);
781

782
  ASSERT_OK(fs_event_cb_called);
783
  ASSERT_EQ(1, close_cb_called);
784

785
  /* Cleanup */
786
  remove("watch_dir/file1");
787
  remove("watch_dir/");
788

789
  MAKE_VALGRIND_HAPPY(loop);
790
  return 0;
791
}
792

793
TEST_IMPL(fs_event_no_callback_on_close) {
794
#if defined(NO_FS_EVENTS)
795
  RETURN_SKIP(NO_FS_EVENTS);
796
#endif
797

798
  uv_loop_t* loop = uv_default_loop();
799
  int r;
800

801
  /* Setup */
802
  remove("watch_dir/file1");
803
  remove("watch_dir/");
804
  create_dir("watch_dir");
805
  create_file("watch_dir/file1");
806

807
  r = uv_fs_event_init(loop, &fs_event);
808
  ASSERT_OK(r);
809
  r = uv_fs_event_start(&fs_event,
810
                        fs_event_cb_file,
811
                        "watch_dir/file1",
812
                        0);
813
  ASSERT_OK(r);
814

815
  uv_close((uv_handle_t*)&fs_event, close_cb);
816

817
  uv_run(loop, UV_RUN_DEFAULT);
818

819
  ASSERT_OK(fs_event_cb_called);
820
  ASSERT_EQ(1, close_cb_called);
821

822
  /* Cleanup */
823
  remove("watch_dir/file1");
824
  remove("watch_dir/");
825

826
  MAKE_VALGRIND_HAPPY(loop);
827
  return 0;
828
}
829

830

831
static void timer_cb(uv_timer_t* handle) {
832
  int r;
833

834
  r = uv_fs_event_init(handle->loop, &fs_event);
835
  ASSERT_OK(r);
836
  r = uv_fs_event_start(&fs_event, fs_event_fail, ".", 0);
837
  ASSERT_OK(r);
838

839
  uv_close((uv_handle_t*)&fs_event, close_cb);
840
  uv_close((uv_handle_t*)handle, close_cb);
841
}
842

843

844
TEST_IMPL(fs_event_immediate_close) {
845
#if defined(NO_FS_EVENTS)
846
  RETURN_SKIP(NO_FS_EVENTS);
847
#endif
848
  uv_timer_t timer;
849
  uv_loop_t* loop;
850
  int r;
851

852
  loop = uv_default_loop();
853

854
  r = uv_timer_init(loop, &timer);
855
  ASSERT_OK(r);
856

857
  r = uv_timer_start(&timer, timer_cb, 1, 0);
858
  ASSERT_OK(r);
859

860
  uv_run(loop, UV_RUN_DEFAULT);
861

862
  ASSERT_EQ(2, close_cb_called);
863

864
  MAKE_VALGRIND_HAPPY(loop);
865
  return 0;
866
}
867

868

869
TEST_IMPL(fs_event_close_with_pending_event) {
870
#if defined(NO_FS_EVENTS)
871
  RETURN_SKIP(NO_FS_EVENTS);
872
#endif
873
  uv_loop_t* loop;
874
  int r;
875

876
  loop = uv_default_loop();
877

878
  create_dir("watch_dir");
879
  create_file("watch_dir/file");
880

881
  r = uv_fs_event_init(loop, &fs_event);
882
  ASSERT_OK(r);
883
  r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir", 0);
884
  ASSERT_OK(r);
885

886
  /* Generate an fs event. */
887
  touch_file("watch_dir/file");
888

889
  uv_close((uv_handle_t*)&fs_event, close_cb);
890

891
  uv_run(loop, UV_RUN_DEFAULT);
892

893
  ASSERT_EQ(1, close_cb_called);
894

895
  /* Clean up */
896
  remove("watch_dir/file");
897
  remove("watch_dir/");
898

899
  MAKE_VALGRIND_HAPPY(loop);
900
  return 0;
901
}
902

903
TEST_IMPL(fs_event_close_with_pending_delete_event) {
904
#if defined(NO_FS_EVENTS)
905
  RETURN_SKIP(NO_FS_EVENTS);
906
#endif
907
  uv_loop_t* loop;
908
  int r;
909

910
  loop = uv_default_loop();
911

912
  create_dir("watch_dir");
913
  create_file("watch_dir/file");
914

915
  r = uv_fs_event_init(loop, &fs_event);
916
  ASSERT_OK(r);
917
  r = uv_fs_event_start(&fs_event, fs_event_fail, "watch_dir/file", 0);
918
  ASSERT_OK(r);
919

920
  /* Generate an fs event. */
921
  remove("watch_dir/file");
922

923
  /* Allow time for the remove event to propagate to the pending list. */
924
  /* XXX - perhaps just for __sun? */
925
  uv_sleep(1100);
926
  uv_update_time(loop);
927

928
  uv_close((uv_handle_t*)&fs_event, close_cb);
929

930
  uv_run(loop, UV_RUN_DEFAULT);
931

932
  ASSERT_EQ(1, close_cb_called);
933

934
  /* Clean up */
935
  remove("watch_dir/");
936

937
  MAKE_VALGRIND_HAPPY(loop);
938
  return 0;
939
}
940

941
TEST_IMPL(fs_event_close_in_callback) {
942
#if defined(NO_FS_EVENTS)
943
  RETURN_SKIP(NO_FS_EVENTS);
944
#elif defined(__MVS__)
945
  RETURN_SKIP("Directory watching not supported on this platform.");
946
#elif defined(__APPLE__) && defined(__TSAN__)
947
  RETURN_SKIP("Times out under TSAN.");
948
#endif
949
  uv_loop_t* loop;
950
  int r;
951

952
  loop = uv_default_loop();
953

954
  fs_event_unlink_files(NULL);
955
  create_dir("watch_dir");
956

957
  r = uv_fs_event_init(loop, &fs_event);
958
  ASSERT_OK(r);
959
  r = uv_fs_event_start(&fs_event, fs_event_cb_close, "watch_dir", 0);
960
  ASSERT_OK(r);
961

962
  r = uv_timer_init(loop, &timer);
963
  ASSERT_OK(r);
964
  r = uv_timer_start(&timer, fs_event_create_files, 100, 0);
965
  ASSERT_OK(r);
966

967
  uv_run(loop, UV_RUN_DEFAULT);
968

969
  uv_close((uv_handle_t*)&timer, close_cb);
970

971
  uv_run(loop, UV_RUN_ONCE);
972

973
  ASSERT_EQ(2, close_cb_called);
974
  ASSERT_EQ(3, fs_event_cb_called);
975

976
  /* Clean up */
977
  fs_event_unlink_files(NULL);
978
  remove("watch_dir/");
979

980
  MAKE_VALGRIND_HAPPY(loop);
981
  return 0;
982
}
983

984
TEST_IMPL(fs_event_start_and_close) {
985
#if defined(NO_FS_EVENTS)
986
  RETURN_SKIP(NO_FS_EVENTS);
987
#endif
988
  uv_loop_t* loop;
989
  uv_fs_event_t fs_event1;
990
  uv_fs_event_t fs_event2;
991
  int r;
992

993
  loop = uv_default_loop();
994

995
  create_dir("watch_dir");
996

997
  r = uv_fs_event_init(loop, &fs_event1);
998
  ASSERT_OK(r);
999
  r = uv_fs_event_start(&fs_event1, fs_event_cb_dir, "watch_dir", 0);
1000
  ASSERT_OK(r);
1001

1002
  r = uv_fs_event_init(loop, &fs_event2);
1003
  ASSERT_OK(r);
1004
  r = uv_fs_event_start(&fs_event2, fs_event_cb_dir, "watch_dir", 0);
1005
  ASSERT_OK(r);
1006

1007
  uv_close((uv_handle_t*) &fs_event2, close_cb);
1008
  uv_close((uv_handle_t*) &fs_event1, close_cb);
1009

1010
  uv_run(loop, UV_RUN_DEFAULT);
1011

1012
  ASSERT_EQ(2, close_cb_called);
1013

1014
  remove("watch_dir/");
1015
  MAKE_VALGRIND_HAPPY(loop);
1016
  return 0;
1017
}
1018

1019
TEST_IMPL(fs_event_getpath) {
1020
#if defined(NO_FS_EVENTS)
1021
  RETURN_SKIP(NO_FS_EVENTS);
1022
#endif
1023
  uv_loop_t* loop = uv_default_loop();
1024
  unsigned i;
1025
  int r;
1026
  char buf[1024];
1027
  size_t len;
1028
  const char* const watch_dir[] = {
1029
    "watch_dir",
1030
    "watch_dir/",
1031
    "watch_dir///",
1032
    "watch_dir/subfolder/..",
1033
    "watch_dir//subfolder//..//",
1034
  };
1035

1036
  create_dir("watch_dir");
1037
  create_dir("watch_dir/subfolder");
1038

1039

1040
  for (i = 0; i < ARRAY_SIZE(watch_dir); i++) {
1041
    r = uv_fs_event_init(loop, &fs_event);
1042
    ASSERT_OK(r);
1043
    len = sizeof buf;
1044
    r = uv_fs_event_getpath(&fs_event, buf, &len);
1045
    ASSERT_EQ(r, UV_EINVAL);
1046
    r = uv_fs_event_start(&fs_event, fail_cb, watch_dir[i], 0);
1047
    ASSERT_OK(r);
1048
    len = 0;
1049
    r = uv_fs_event_getpath(&fs_event, buf, &len);
1050
    ASSERT_EQ(r, UV_ENOBUFS);
1051
    ASSERT_LT(len, sizeof buf); /* sanity check */
1052
    ASSERT_EQ(len, strlen(watch_dir[i]) + 1);
1053
    r = uv_fs_event_getpath(&fs_event, buf, &len);
1054
    ASSERT_OK(r);
1055
    ASSERT_EQ(len, strlen(watch_dir[i]));
1056
    ASSERT(strcmp(buf, watch_dir[i]) == 0);
1057
    r = uv_fs_event_stop(&fs_event);
1058
    ASSERT_OK(r);
1059
    uv_close((uv_handle_t*) &fs_event, close_cb);
1060

1061
    uv_run(loop, UV_RUN_DEFAULT);
1062

1063
    ASSERT_EQ(1, close_cb_called);
1064
    close_cb_called = 0;
1065
  }
1066

1067
  remove("watch_dir/");
1068
  MAKE_VALGRIND_HAPPY(loop);
1069
  return 0;
1070
}
1071

1072
#if defined(__APPLE__)
1073

1074
static int fs_event_error_reported;
1075

1076
static void fs_event_error_report_cb(uv_fs_event_t* handle,
1077
                                     const char* filename,
1078
                                     int events,
1079
                                     int status) {
1080
  if (status != 0)
1081
    fs_event_error_reported = status;
1082
}
1083

1084
static void timer_cb_nop(uv_timer_t* handle) {
1085
  ++timer_cb_called;
1086
  uv_close((uv_handle_t*) handle, close_cb);
1087
}
1088

1089
static void fs_event_error_report_close_cb(uv_handle_t* handle) {
1090
  ASSERT_NOT_NULL(handle);
1091
  close_cb_called++;
1092

1093
  /* handle is allocated on-stack, no need to free it */
1094
}
1095

1096

1097
TEST_IMPL(fs_event_error_reporting) {
1098
  unsigned int i;
1099
  uv_loop_t loops[1024];
1100
  uv_fs_event_t events[ARRAY_SIZE(loops)];
1101
  uv_loop_t* loop;
1102
  uv_fs_event_t* event;
1103

1104
  TEST_FILE_LIMIT(ARRAY_SIZE(loops) * 3);
1105

1106
  remove("watch_dir/");
1107
  create_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
   */
1113
  for (i = 0; i < ARRAY_SIZE(loops); i++) {
1114
    loop = &loops[i];
1115
    ASSERT_OK(uv_loop_init(loop));
1116
    event = &events[i];
1117

1118
    timer_cb_called = 0;
1119
    close_cb_called = 0;
1120
    ASSERT_OK(uv_fs_event_init(loop, event));
1121
    ASSERT_OK(uv_fs_event_start(event,
1122
                                fs_event_error_report_cb,
1123
                                "watch_dir",
1124
                                0));
1125
    uv_unref((uv_handle_t*) event);
1126

1127
    /* Let loop run for some time */
1128
    ASSERT_OK(uv_timer_init(loop, &timer));
1129
    ASSERT_OK(uv_timer_start(&timer, timer_cb_nop, 2, 0));
1130
    uv_run(loop, UV_RUN_DEFAULT);
1131
    ASSERT_EQ(1, timer_cb_called);
1132
    ASSERT_EQ(1, close_cb_called);
1133
    if (fs_event_error_reported != 0)
1134
      break;
1135
  }
1136

1137
  /* At least one loop should fail */
1138
  ASSERT_EQ(fs_event_error_reported, UV_EMFILE);
1139

1140
  /* Stop and close all events, and destroy loops */
1141
  do {
1142
    loop = &loops[i];
1143
    event = &events[i];
1144

1145
    ASSERT_OK(uv_fs_event_stop(event));
1146
    uv_ref((uv_handle_t*) event);
1147
    uv_close((uv_handle_t*) event, fs_event_error_report_close_cb);
1148

1149
    close_cb_called = 0;
1150
    uv_run(loop, UV_RUN_DEFAULT);
1151
    ASSERT_EQ(1, close_cb_called);
1152

1153
    uv_loop_close(loop);
1154
  } while (i-- != 0);
1155

1156
  remove("watch_dir/");
1157
  MAKE_VALGRIND_HAPPY(uv_default_loop());
1158
  return 0;
1159
}
1160

1161
#else  /* !defined(__APPLE__) */
1162

1163
TEST_IMPL(fs_event_error_reporting) {
1164
  /* No-op, needed only for FSEvents backend */
1165

1166
  MAKE_VALGRIND_HAPPY(uv_default_loop());
1167
  return 0;
1168
}
1169

1170
#endif  /* defined(__APPLE__) */
1171

1172
TEST_IMPL(fs_event_watch_invalid_path) {
1173
#if defined(NO_FS_EVENTS)
1174
  RETURN_SKIP(NO_FS_EVENTS);
1175
#endif
1176

1177
  uv_loop_t* loop;
1178
  int r;
1179

1180
  loop = uv_default_loop();
1181
  r = uv_fs_event_init(loop, &fs_event);
1182
  ASSERT_OK(r);
1183
  r = uv_fs_event_start(&fs_event, fs_event_cb_file, "<:;", 0);
1184
  ASSERT(r);
1185
  ASSERT_OK(uv_is_active((uv_handle_t*) &fs_event));
1186
  r = uv_fs_event_start(&fs_event, fs_event_cb_file, "", 0);
1187
  ASSERT(r);
1188
  ASSERT_OK(uv_is_active((uv_handle_t*) &fs_event));
1189
  MAKE_VALGRIND_HAPPY(loop);
1190
  return 0;
1191
}
1192

1193
static int fs_event_cb_stop_calls;
1194

1195
static void fs_event_cb_stop(uv_fs_event_t* handle, const char* path,
1196
                             int events, int status) {
1197
  uv_fs_event_stop(handle);
1198
  fs_event_cb_stop_calls++;
1199
}
1200

1201
TEST_IMPL(fs_event_stop_in_cb) {
1202
  uv_fs_event_t fs;
1203
  uv_timer_t timer;
1204
  char path[] = "fs_event_stop_in_cb.txt";
1205

1206
#if defined(NO_FS_EVENTS)
1207
  RETURN_SKIP(NO_FS_EVENTS);
1208
#endif
1209

1210
  remove(path);
1211
  create_file(path);
1212

1213
  ASSERT_OK(uv_fs_event_init(uv_default_loop(), &fs));
1214
  ASSERT_OK(uv_fs_event_start(&fs, fs_event_cb_stop, path, 0));
1215

1216
  /* Note: timer_cb_touch() closes the handle. */
1217
  timer.data = path;
1218
  ASSERT_OK(uv_timer_init(uv_default_loop(), &timer));
1219
  ASSERT_OK(uv_timer_start(&timer, timer_cb_touch, 100, 0));
1220

1221
  ASSERT_OK(fs_event_cb_stop_calls);
1222
  ASSERT_OK(timer_cb_touch_called);
1223

1224
  ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1225

1226
  ASSERT_EQ(1, fs_event_cb_stop_calls);
1227
  ASSERT_EQ(1, timer_cb_touch_called);
1228

1229
  uv_close((uv_handle_t*) &fs, NULL);
1230
  ASSERT_OK(uv_run(uv_default_loop(), UV_RUN_DEFAULT));
1231
  ASSERT_EQ(1, fs_event_cb_stop_calls);
1232

1233
  remove(path);
1234

1235
  MAKE_VALGRIND_HAPPY(uv_default_loop());
1236
  return 0;
1237
}
1238

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.