Home | History | Annotate | Line # | Download | only in test
      1 /* Copyright libuv project 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 #include <fcntl.h>
     25 #include <string.h>
     26 
     27 static uv_fs_t opendir_req;
     28 static uv_fs_t readdir_req;
     29 static uv_fs_t closedir_req;
     30 
     31 static uv_dirent_t dirents[1];
     32 static uv_dirent_t symlink_dirents[2];
     33 
     34 static int empty_opendir_cb_count;
     35 static int empty_closedir_cb_count;
     36 
     37 static void cleanup_test_files(void) {
     38   uv_fs_t req;
     39 
     40   uv_fs_unlink(NULL, &req, "test_dir/file1", NULL);
     41   uv_fs_req_cleanup(&req);
     42   uv_fs_unlink(NULL, &req, "test_dir/file2", NULL);
     43   uv_fs_req_cleanup(&req);
     44   uv_fs_rmdir(NULL, &req, "test_dir/test_subdir", NULL);
     45   uv_fs_req_cleanup(&req);
     46   uv_fs_rmdir(NULL, &req, "test_dir", NULL);
     47   uv_fs_req_cleanup(&req);
     48 }
     49 
     50 static void empty_closedir_cb(uv_fs_t* req) {
     51   ASSERT_PTR_EQ(req, &closedir_req);
     52   ASSERT_EQ(req->fs_type, UV_FS_CLOSEDIR);
     53   ASSERT_OK(req->result);
     54   ++empty_closedir_cb_count;
     55   uv_fs_req_cleanup(req);
     56 }
     57 
     58 static void empty_readdir_cb(uv_fs_t* req) {
     59   uv_dir_t* dir;
     60   int r;
     61 
     62   ASSERT_PTR_EQ(req, &readdir_req);
     63   ASSERT_EQ(req->fs_type, UV_FS_READDIR);
     64   ASSERT_OK(req->result);
     65   dir = req->ptr;
     66   uv_fs_req_cleanup(req);
     67   r = uv_fs_closedir(uv_default_loop(),
     68                      &closedir_req,
     69                      dir,
     70                      empty_closedir_cb);
     71   ASSERT_OK(r);
     72 }
     73 
     74 static void empty_opendir_cb(uv_fs_t* req) {
     75   uv_dir_t* dir;
     76   int r;
     77 
     78   ASSERT_PTR_EQ(req, &opendir_req);
     79   ASSERT_EQ(req->fs_type, UV_FS_OPENDIR);
     80   ASSERT_OK(req->result);
     81   ASSERT_NOT_NULL(req->ptr);
     82   dir = req->ptr;
     83   dir->dirents = dirents;
     84   dir->nentries = ARRAY_SIZE(dirents);
     85   r = uv_fs_readdir(uv_default_loop(),
     86                     &readdir_req,
     87                     dir,
     88                     empty_readdir_cb);
     89   ASSERT_OK(r);
     90   uv_fs_req_cleanup(req);
     91   ++empty_opendir_cb_count;
     92 }
     93 
     94 /*
     95  * This test makes sure that both synchronous and asynchronous flavors
     96  * of the uv_fs_opendir() -> uv_fs_readdir() -> uv_fs_closedir() sequence work
     97  * as expected when processing an empty directory.
     98  */
     99 TEST_IMPL(fs_readdir_empty_dir) {
    100   const char* path;
    101   uv_fs_t mkdir_req;
    102   uv_fs_t rmdir_req;
    103   int r;
    104   int nb_entries_read;
    105   uv_dir_t* dir;
    106 
    107   path = "./empty_dir/";
    108   uv_fs_mkdir(uv_default_loop(), &mkdir_req, path, 0777, NULL);
    109   uv_fs_req_cleanup(&mkdir_req);
    110 
    111   /* Fill the req to ensure that required fields are cleaned up. */
    112   memset(&opendir_req, 0xdb, sizeof(opendir_req));
    113 
    114   /* Testing the synchronous flavor. */
    115   r = uv_fs_opendir(uv_default_loop(),
    116                     &opendir_req,
    117                     path,
    118                     NULL);
    119   ASSERT_OK(r);
    120   ASSERT_EQ(opendir_req.fs_type, UV_FS_OPENDIR);
    121   ASSERT_OK(opendir_req.result);
    122   ASSERT_NOT_NULL(opendir_req.ptr);
    123   dir = opendir_req.ptr;
    124   uv_fs_req_cleanup(&opendir_req);
    125 
    126   /* Fill the req to ensure that required fields are cleaned up. */
    127   memset(&readdir_req, 0xdb, sizeof(readdir_req));
    128   dir->dirents = dirents;
    129   dir->nentries = ARRAY_SIZE(dirents);
    130   nb_entries_read = uv_fs_readdir(uv_default_loop(),
    131                                   &readdir_req,
    132                                   dir,
    133                                   NULL);
    134   ASSERT_OK(nb_entries_read);
    135   uv_fs_req_cleanup(&readdir_req);
    136 
    137   /* Fill the req to ensure that required fields are cleaned up. */
    138   memset(&closedir_req, 0xdb, sizeof(closedir_req));
    139   uv_fs_closedir(uv_default_loop(), &closedir_req, dir, NULL);
    140   ASSERT_OK(closedir_req.result);
    141   uv_fs_req_cleanup(&closedir_req);
    142 
    143   /* Testing the asynchronous flavor. */
    144 
    145   /* Fill the req to ensure that required fields are cleaned up. */
    146   memset(&opendir_req, 0xdb, sizeof(opendir_req));
    147   memset(&readdir_req, 0xdb, sizeof(readdir_req));
    148   memset(&closedir_req, 0xdb, sizeof(closedir_req));
    149 
    150   r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, empty_opendir_cb);
    151   ASSERT_OK(r);
    152   ASSERT_OK(empty_opendir_cb_count);
    153   ASSERT_OK(empty_closedir_cb_count);
    154   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
    155   ASSERT_OK(r);
    156   ASSERT_EQ(1, empty_opendir_cb_count);
    157   ASSERT_EQ(1, empty_closedir_cb_count);
    158   uv_fs_rmdir(uv_default_loop(), &rmdir_req, path, NULL);
    159   uv_fs_req_cleanup(&rmdir_req);
    160   MAKE_VALGRIND_HAPPY(uv_default_loop());
    161   return 0;
    162 }
    163 
    164 /*
    165  * This test makes sure that reading a non-existing directory with
    166  * uv_fs_{open,read}_dir() returns proper error codes.
    167  */
    168 
    169 static int non_existing_opendir_cb_count;
    170 
    171 static void non_existing_opendir_cb(uv_fs_t* req) {
    172   ASSERT_PTR_EQ(req, &opendir_req);
    173   ASSERT_EQ(req->fs_type, UV_FS_OPENDIR);
    174   ASSERT_EQ(req->result, UV_ENOENT);
    175   ASSERT_NULL(req->ptr);
    176 
    177   uv_fs_req_cleanup(req);
    178   ++non_existing_opendir_cb_count;
    179 }
    180 
    181 TEST_IMPL(fs_readdir_non_existing_dir) {
    182   const char* path;
    183   int r;
    184 
    185   path = "./non-existing-dir/";
    186 
    187   /* Fill the req to ensure that required fields are cleaned up. */
    188   memset(&opendir_req, 0xdb, sizeof(opendir_req));
    189 
    190   /* Testing the synchronous flavor. */
    191   r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, NULL);
    192   ASSERT_EQ(r, UV_ENOENT);
    193   ASSERT_EQ(opendir_req.fs_type, UV_FS_OPENDIR);
    194   ASSERT_EQ(opendir_req.result, UV_ENOENT);
    195   ASSERT_NULL(opendir_req.ptr);
    196   uv_fs_req_cleanup(&opendir_req);
    197 
    198   /* Fill the req to ensure that required fields are cleaned up. */
    199   memset(&opendir_req, 0xdb, sizeof(opendir_req));
    200 
    201   /* Testing the async flavor. */
    202   r = uv_fs_opendir(uv_default_loop(),
    203                     &opendir_req,
    204                     path,
    205                     non_existing_opendir_cb);
    206   ASSERT_OK(r);
    207   ASSERT_OK(non_existing_opendir_cb_count);
    208   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
    209   ASSERT_OK(r);
    210   ASSERT_EQ(1, non_existing_opendir_cb_count);
    211 
    212   MAKE_VALGRIND_HAPPY(uv_default_loop());
    213   return 0;
    214 }
    215 
    216 /*
    217  * This test makes sure that reading a file as a directory reports correct
    218  * error codes.
    219  */
    220 
    221 static int file_opendir_cb_count;
    222 
    223 static void file_opendir_cb(uv_fs_t* req) {
    224   ASSERT_PTR_EQ(req, &opendir_req);
    225   ASSERT_EQ(req->fs_type, UV_FS_OPENDIR);
    226   ASSERT_EQ(req->result, UV_ENOTDIR);
    227   ASSERT_NULL(req->ptr);
    228 
    229   uv_fs_req_cleanup(req);
    230   ++file_opendir_cb_count;
    231 }
    232 
    233 TEST_IMPL(fs_readdir_file) {
    234   const char* path;
    235   int r;
    236 
    237   path = "test/fixtures/empty_file";
    238 
    239   /* Fill the req to ensure that required fields are cleaned up. */
    240   memset(&opendir_req, 0xdb, sizeof(opendir_req));
    241 
    242   /* Testing the synchronous flavor. */
    243   r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, NULL);
    244 
    245   ASSERT_EQ(r, UV_ENOTDIR);
    246   ASSERT_EQ(opendir_req.fs_type, UV_FS_OPENDIR);
    247   ASSERT_EQ(opendir_req.result, UV_ENOTDIR);
    248   ASSERT_NULL(opendir_req.ptr);
    249 
    250   uv_fs_req_cleanup(&opendir_req);
    251 
    252   /* Fill the req to ensure that required fields are cleaned up. */
    253   memset(&opendir_req, 0xdb, sizeof(opendir_req));
    254 
    255   /* Testing the async flavor. */
    256   r = uv_fs_opendir(uv_default_loop(), &opendir_req, path, file_opendir_cb);
    257   ASSERT_OK(r);
    258   ASSERT_OK(file_opendir_cb_count);
    259   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
    260   ASSERT_OK(r);
    261   ASSERT_EQ(1, file_opendir_cb_count);
    262   MAKE_VALGRIND_HAPPY(uv_default_loop());
    263   return 0;
    264 }
    265 
    266 /*
    267  * This test makes sure that reading a non-empty directory with
    268  * uv_fs_{open,read}_dir() returns proper directory entries, including the
    269  * correct entry types.
    270  */
    271 
    272 static int non_empty_opendir_cb_count;
    273 static int non_empty_readdir_cb_count;
    274 static int non_empty_closedir_cb_count;
    275 
    276 static void non_empty_closedir_cb(uv_fs_t* req) {
    277   ASSERT_PTR_EQ(req, &closedir_req);
    278   ASSERT_OK(req->result);
    279   uv_fs_req_cleanup(req);
    280   ++non_empty_closedir_cb_count;
    281 }
    282 
    283 static void non_empty_readdir_cb(uv_fs_t* req) {
    284   uv_dir_t* dir;
    285 
    286   ASSERT_PTR_EQ(req, &readdir_req);
    287   ASSERT_EQ(req->fs_type, UV_FS_READDIR);
    288   dir = req->ptr;
    289 
    290   if (req->result == 0) {
    291     uv_fs_req_cleanup(req);
    292     ASSERT_EQ(3, non_empty_readdir_cb_count);
    293     uv_fs_closedir(uv_default_loop(),
    294                    &closedir_req,
    295                    dir,
    296                    non_empty_closedir_cb);
    297   } else {
    298     ASSERT_EQ(1, req->result);
    299     ASSERT_PTR_EQ(dir->dirents, dirents);
    300     ASSERT(strcmp(dirents[0].name, "file1") == 0 ||
    301            strcmp(dirents[0].name, "file2") == 0 ||
    302            strcmp(dirents[0].name, "test_subdir") == 0);
    303 #ifdef HAVE_DIRENT_TYPES
    304     if (!strcmp(dirents[0].name, "test_subdir"))
    305       ASSERT_EQ(dirents[0].type, UV_DIRENT_DIR);
    306     else
    307       ASSERT_EQ(dirents[0].type, UV_DIRENT_FILE);
    308 #else
    309     ASSERT_EQ(dirents[0].type, UV_DIRENT_UNKNOWN);
    310 #endif /* HAVE_DIRENT_TYPES */
    311 
    312     ++non_empty_readdir_cb_count;
    313     uv_fs_req_cleanup(req);
    314     dir->dirents = dirents;
    315     dir->nentries = ARRAY_SIZE(dirents);
    316     uv_fs_readdir(uv_default_loop(),
    317                   &readdir_req,
    318                   dir,
    319                   non_empty_readdir_cb);
    320   }
    321 }
    322 
    323 static void non_empty_opendir_cb(uv_fs_t* req) {
    324   uv_dir_t* dir;
    325   int r;
    326 
    327   ASSERT_PTR_EQ(req, &opendir_req);
    328   ASSERT_EQ(req->fs_type, UV_FS_OPENDIR);
    329   ASSERT_OK(req->result);
    330   ASSERT_NOT_NULL(req->ptr);
    331 
    332   dir = req->ptr;
    333   dir->dirents = dirents;
    334   dir->nentries = ARRAY_SIZE(dirents);
    335 
    336   r = uv_fs_readdir(uv_default_loop(),
    337                     &readdir_req,
    338                     dir,
    339                     non_empty_readdir_cb);
    340   ASSERT_OK(r);
    341   uv_fs_req_cleanup(req);
    342   ++non_empty_opendir_cb_count;
    343 }
    344 
    345 TEST_IMPL(fs_readdir_non_empty_dir) {
    346   size_t entries_count;
    347   uv_fs_t mkdir_req;
    348   uv_fs_t rmdir_req;
    349   uv_fs_t create_req;
    350   uv_fs_t close_req;
    351   uv_dir_t* dir;
    352   int r;
    353 
    354   cleanup_test_files();
    355 
    356   r = uv_fs_mkdir(uv_default_loop(), &mkdir_req, "test_dir", 0755, NULL);
    357   ASSERT_OK(r);
    358 
    359   /* Create two files synchronously. */
    360   r = uv_fs_open(uv_default_loop(),
    361                  &create_req,
    362                  "test_dir/file1",
    363                  UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR,
    364                  NULL);
    365   ASSERT_GE(r, 0);
    366   uv_fs_req_cleanup(&create_req);
    367   r = uv_fs_close(uv_default_loop(),
    368                   &close_req,
    369                   create_req.result,
    370                   NULL);
    371   ASSERT_OK(r);
    372   uv_fs_req_cleanup(&close_req);
    373 
    374   r = uv_fs_open(uv_default_loop(),
    375                  &create_req,
    376                  "test_dir/file2",
    377                  UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR,
    378                  NULL);
    379   ASSERT_GE(r, 0);
    380   uv_fs_req_cleanup(&create_req);
    381   r = uv_fs_close(uv_default_loop(),
    382                   &close_req,
    383                   create_req.result,
    384                   NULL);
    385   ASSERT_OK(r);
    386   uv_fs_req_cleanup(&close_req);
    387 
    388   r = uv_fs_mkdir(uv_default_loop(),
    389                   &mkdir_req,
    390                   "test_dir/test_subdir",
    391                   0755,
    392                   NULL);
    393   ASSERT_OK(r);
    394   uv_fs_req_cleanup(&mkdir_req);
    395 
    396   /* Fill the req to ensure that required fields are cleaned up. */
    397   memset(&opendir_req, 0xdb, sizeof(opendir_req));
    398 
    399   /* Testing the synchronous flavor. */
    400   r = uv_fs_opendir(uv_default_loop(), &opendir_req, "test_dir", NULL);
    401   ASSERT_OK(r);
    402   ASSERT_EQ(opendir_req.fs_type, UV_FS_OPENDIR);
    403   ASSERT_OK(opendir_req.result);
    404   ASSERT_NOT_NULL(opendir_req.ptr);
    405 
    406   entries_count = 0;
    407   dir = opendir_req.ptr;
    408   dir->dirents = dirents;
    409   dir->nentries = ARRAY_SIZE(dirents);
    410   uv_fs_req_cleanup(&opendir_req);
    411 
    412   while (uv_fs_readdir(uv_default_loop(),
    413                        &readdir_req,
    414                        dir,
    415                        NULL) != 0) {
    416   ASSERT(strcmp(dirents[0].name, "file1") == 0 ||
    417          strcmp(dirents[0].name, "file2") == 0 ||
    418          strcmp(dirents[0].name, "test_subdir") == 0);
    419 #ifdef HAVE_DIRENT_TYPES
    420     if (!strcmp(dirents[0].name, "test_subdir"))
    421       ASSERT_EQ(dirents[0].type, UV_DIRENT_DIR);
    422     else
    423       ASSERT_EQ(dirents[0].type, UV_DIRENT_FILE);
    424 #else
    425     ASSERT_EQ(dirents[0].type, UV_DIRENT_UNKNOWN);
    426 #endif /* HAVE_DIRENT_TYPES */
    427     uv_fs_req_cleanup(&readdir_req);
    428     ++entries_count;
    429   }
    430 
    431   ASSERT_EQ(3, entries_count);
    432   uv_fs_req_cleanup(&readdir_req);
    433 
    434   /* Fill the req to ensure that required fields are cleaned up. */
    435   memset(&closedir_req, 0xdb, sizeof(closedir_req));
    436   uv_fs_closedir(uv_default_loop(), &closedir_req, dir, NULL);
    437   ASSERT_OK(closedir_req.result);
    438   uv_fs_req_cleanup(&closedir_req);
    439 
    440   /* Testing the asynchronous flavor. */
    441 
    442   /* Fill the req to ensure that required fields are cleaned up. */
    443   memset(&opendir_req, 0xdb, sizeof(opendir_req));
    444 
    445   r = uv_fs_opendir(uv_default_loop(),
    446                     &opendir_req,
    447                     "test_dir",
    448                     non_empty_opendir_cb);
    449   ASSERT_OK(r);
    450   ASSERT_OK(non_empty_opendir_cb_count);
    451   ASSERT_OK(non_empty_closedir_cb_count);
    452   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
    453   ASSERT_OK(r);
    454   ASSERT_EQ(1, non_empty_opendir_cb_count);
    455   ASSERT_EQ(1, non_empty_closedir_cb_count);
    456 
    457   uv_fs_rmdir(uv_default_loop(), &rmdir_req, "test_subdir", NULL);
    458   uv_fs_req_cleanup(&rmdir_req);
    459 
    460   cleanup_test_files();
    461   MAKE_VALGRIND_HAPPY(uv_default_loop());
    462   return 0;
    463  }
    464 
    465 static void readdir_symlink_readdir_cb(uv_fs_t* req) {
    466   uv_dir_t* dir;
    467 
    468   ASSERT_PTR_EQ(req, &readdir_req);
    469   ASSERT_EQ(req->fs_type, UV_FS_READDIR);
    470   dir = req->ptr;
    471 
    472   if (req->result == 0) {
    473     uv_fs_req_cleanup(req);
    474     ASSERT_EQ(3, non_empty_readdir_cb_count);
    475     uv_fs_closedir(uv_default_loop(),
    476                    &closedir_req,
    477                    dir,
    478                    non_empty_closedir_cb);
    479   } else {
    480     if (strcmp(symlink_dirents[0].name, "test_symlink") == 0) {
    481       ASSERT_EQ(symlink_dirents[0].type, UV_DIRENT_LINK);
    482     } else {
    483       ASSERT_EQ(symlink_dirents[1].type, UV_DIRENT_LINK);
    484     }
    485     uv_fs_req_cleanup(req);
    486   }
    487 }
    488 
    489 static void readdir_symlink_opendir_cb(uv_fs_t* req) {
    490   uv_dir_t* dir;
    491   int r;
    492 
    493   ASSERT_PTR_EQ(req, &opendir_req);
    494   ASSERT_EQ(req->fs_type, UV_FS_OPENDIR);
    495   ASSERT_OK(req->result);
    496   ASSERT_NOT_NULL(req->ptr);
    497 
    498   dir = req->ptr;
    499   dir->dirents = symlink_dirents;
    500   dir->nentries = ARRAY_SIZE(symlink_dirents);
    501 
    502   r = uv_fs_readdir(uv_default_loop(),
    503                     &readdir_req,
    504                     dir,
    505                     readdir_symlink_readdir_cb);
    506   ASSERT_OK(r);
    507   uv_fs_req_cleanup(req);
    508 }
    509 
    510 static void cleanup_symlink_test_files(void) {
    511   uv_fs_t req;
    512 
    513   uv_fs_rmdir(NULL, &req, "test_symlink_dir/test_subdir", NULL);
    514   uv_fs_req_cleanup(&req);
    515   uv_fs_unlink(NULL, &req, "test_symlink_dir/test_symlink", NULL);
    516   uv_fs_req_cleanup(&req);
    517   uv_fs_rmdir(NULL, &req, "test_symlink_dir", NULL);
    518   uv_fs_req_cleanup(&req);
    519 }
    520 
    521 TEST_IMPL(fs_readdir_symlink) {
    522 
    523   uv_fs_t mkdir_req;
    524   uv_fs_t symlink_req;
    525   int r;
    526 
    527   cleanup_symlink_test_files();
    528 
    529   r = uv_fs_mkdir(uv_default_loop(), &mkdir_req, "test_symlink_dir", 0755, NULL);
    530   ASSERT_OK(r);
    531 
    532   r = uv_fs_mkdir(uv_default_loop(), &mkdir_req, "test_symlink_dir/test_subdir", 0755, NULL);
    533   ASSERT_OK(r);
    534 
    535   r = uv_fs_symlink(uv_default_loop(), &symlink_req, "test_symlink_dir/test_subdir", "test_symlink_dir/test_symlink", UV_FS_SYMLINK_DIR, NULL);
    536   ASSERT_OK(r);
    537 
    538   r = uv_fs_opendir(uv_default_loop(), &opendir_req, "test_symlink_dir", readdir_symlink_opendir_cb);
    539   ASSERT_OK(r);
    540 
    541   r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);
    542   ASSERT_OK(r);
    543 
    544   cleanup_symlink_test_files();
    545 
    546   MAKE_VALGRIND_HAPPY(uv_default_loop());
    547   return 0;
    548 }
    549