LCOV - code coverage report
Current view: top level - tests - test-lockfile.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 115 129 89.1 %
Date: 2016-09-14 01:02:56 Functions: 15 16 93.8 %
Branches: 20 29 69.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2009, 2010, 2011, 2012, 2014 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #undef NDEBUG
      19                 :            : #include "lockfile.h"
      20                 :            : #include <errno.h>
      21                 :            : #include <stdlib.h>
      22                 :            : #include <sys/stat.h>
      23                 :            : #include <sys/wait.h>
      24                 :            : #include <unistd.h>
      25                 :            : #include "ovstest.h"
      26                 :            : #include "process.h"
      27                 :            : #include "timeval.h"
      28                 :            : #include "util.h"
      29                 :            : #include "openvswitch/vlog.h"
      30                 :            : 
      31                 :            : struct test {
      32                 :            :     const char *name;
      33                 :            :     void (*function)(void);
      34                 :            : };
      35                 :            : 
      36                 :            : static void run_help(void);
      37                 :            : 
      38                 :            : #define CHECK(A, B) check(A, B, #A, #B, __FILE__, __LINE__)
      39                 :            : static void
      40                 :         50 : check(int a, int b,
      41                 :            :       const char *a_string, const char *b_string, const char *file, int line)
      42                 :            : {
      43         [ -  + ]:         50 :     if (a != b) {
      44                 :          0 :         fprintf(stderr, "%s:%d: expected %s == %s but %d != %d\n",
      45                 :            :                 file, line, a_string, b_string, a, b);
      46                 :          0 :         fflush(stderr);
      47                 :          0 :         abort();
      48                 :            :     }
      49                 :         50 : }
      50                 :            : 
      51                 :            : static void
      52                 :          1 : run_lock_and_unlock(void)
      53                 :            : {
      54                 :            :     struct lockfile *lockfile;
      55                 :            : 
      56                 :          1 :     CHECK(lockfile_lock("file", &lockfile), 0);
      57                 :          1 :     lockfile_unlock(lockfile);
      58                 :          1 : }
      59                 :            : 
      60                 :            : static void
      61                 :          1 : run_lock_and_unlock_twice(void)
      62                 :            : {
      63                 :            :     struct lockfile *lockfile;
      64                 :            : 
      65                 :          1 :     CHECK(lockfile_lock("file", &lockfile), 0);
      66                 :          1 :     lockfile_unlock(lockfile);
      67                 :            : 
      68                 :          1 :     CHECK(lockfile_lock("file", &lockfile), 0);
      69                 :          1 :     lockfile_unlock(lockfile);
      70                 :          1 : }
      71                 :            : 
      72                 :            : static void
      73                 :          1 : run_lock_blocks_same_process(void)
      74                 :            : {
      75                 :            :     struct lockfile *lockfile;
      76                 :            : 
      77                 :          1 :     CHECK(lockfile_lock("file", &lockfile), 0);
      78                 :          1 :     CHECK(lockfile_lock("file", &lockfile), EDEADLK);
      79                 :          1 :     lockfile_unlock(lockfile);
      80                 :          1 : }
      81                 :            : 
      82                 :            : static void
      83                 :          1 : run_lock_blocks_same_process_twice(void)
      84                 :            : {
      85                 :            :     struct lockfile *lockfile;
      86                 :            : 
      87                 :          1 :     CHECK(lockfile_lock("file", &lockfile), 0);
      88                 :          1 :     CHECK(lockfile_lock("file", &lockfile), EDEADLK);
      89                 :          1 :     CHECK(lockfile_lock("file", &lockfile), EDEADLK);
      90                 :          1 :     lockfile_unlock(lockfile);
      91                 :          1 : }
      92                 :            : 
      93                 :            : #ifndef _WIN32
      94                 :            : static enum { PARENT, CHILD }
      95                 :          3 : do_fork(void)
      96                 :            : {
      97      [ +  +  - ]:          3 :     switch (fork()) {
      98                 :            :     case 0:
      99                 :          3 :         lockfile_postfork();
     100                 :          3 :         return CHILD;
     101                 :            : 
     102                 :            :     default:
     103                 :          3 :         return PARENT;
     104                 :            : 
     105                 :            :     case -1:
     106                 :            :         /* Error. */
     107                 :          0 :         ovs_fatal(errno, "fork failed");
     108                 :            :     }
     109                 :            : }
     110                 :            : 
     111                 :            : static void
     112                 :          1 : run_lock_blocks_other_process(void)
     113                 :            : {
     114                 :            :     /* Making this static prevents a memory leak warning from valgrind for the
     115                 :            :      * parent process, which cannot easily unlock (and free) 'lockfile' because
     116                 :            :      * it can only do so after the child has exited, and it's the caller of
     117                 :            :      * this function that does the wait() call. */
     118                 :            :     static struct lockfile *lockfile;
     119                 :            : 
     120                 :          1 :     CHECK(lockfile_lock("file", &lockfile), 0);
     121         [ +  + ]:          1 :     if (do_fork() == CHILD) {
     122                 :          1 :         lockfile_unlock(lockfile);
     123                 :          1 :         CHECK(lockfile_lock("file", &lockfile), EAGAIN);
     124                 :          1 :         exit(11);
     125                 :            :     }
     126                 :          1 : }
     127                 :            : 
     128                 :            : static void
     129                 :          1 : run_lock_twice_blocks_other_process(void)
     130                 :            : {
     131                 :            :     struct lockfile *lockfile, *dummy;
     132                 :            : 
     133                 :          1 :     CHECK(lockfile_lock("file", &lockfile), 0);
     134                 :          1 :     CHECK(lockfile_lock("file", &dummy), EDEADLK);
     135         [ +  + ]:          1 :     if (do_fork() == CHILD) {
     136                 :          1 :         CHECK(lockfile_lock("file", &dummy), EAGAIN);
     137                 :          1 :         exit(11);
     138                 :            :     }
     139                 :          1 : }
     140                 :            : 
     141                 :            : static void
     142                 :          1 : run_lock_and_unlock_allows_other_process(void)
     143                 :            : {
     144                 :            :     struct lockfile *lockfile;
     145                 :            : 
     146                 :          1 :     CHECK(lockfile_lock("file", &lockfile), 0);
     147                 :          1 :     lockfile_unlock(lockfile);
     148                 :            : 
     149         [ +  + ]:          1 :     if (do_fork() == CHILD) {
     150                 :          1 :         CHECK(lockfile_lock("file", &lockfile), 0);
     151                 :          1 :         exit(11);
     152                 :            :     }
     153                 :          1 : }
     154                 :            : 
     155                 :            : /* Checks that locking a dangling symlink works OK.  (It used to hang.) */
     156                 :            : static void
     157                 :          1 : run_lock_symlink(void)
     158                 :            : {
     159                 :            :     struct lockfile *a, *b, *dummy;
     160                 :            :     struct stat s;
     161                 :            : 
     162                 :            :     /* Create a symlink .a.~lock~ pointing to .b.~lock~. */
     163                 :          1 :     CHECK(symlink(".b.~lock~", ".a.~lock~"), 0);
     164                 :          1 :     CHECK(lstat(".a.~lock~", &s), 0);
     165                 :          1 :     CHECK(S_ISLNK(s.st_mode) != 0, 1);
     166                 :          1 :     CHECK(stat(".a.~lock~", &s), -1);
     167                 :          1 :     CHECK(errno, ENOENT);
     168                 :          1 :     CHECK(stat(".b.~lock~", &s), -1);
     169                 :          1 :     CHECK(errno, ENOENT);
     170                 :            : 
     171                 :          1 :     CHECK(lockfile_lock("a", &a), 0);
     172                 :          1 :     CHECK(lockfile_lock("a", &dummy), EDEADLK);
     173                 :          1 :     CHECK(lockfile_lock("b", &dummy), EDEADLK);
     174                 :          1 :     lockfile_unlock(a);
     175                 :            : 
     176                 :          1 :     CHECK(lockfile_lock("b", &b), 0);
     177                 :          1 :     CHECK(lockfile_lock("b", &dummy), EDEADLK);
     178                 :          1 :     CHECK(lockfile_lock("a", &dummy), EDEADLK);
     179                 :          1 :     lockfile_unlock(b);
     180                 :            : 
     181                 :          1 :     CHECK(lstat(".a.~lock~", &s), 0);
     182                 :          1 :     CHECK(S_ISLNK(s.st_mode) != 0, 1);
     183                 :          1 :     CHECK(stat(".a.~lock~", &s), 0);
     184                 :          1 :     CHECK(S_ISREG(s.st_mode) != 0, 1);
     185                 :          1 :     CHECK(stat(".b.~lock~", &s), 0);
     186                 :          1 :     CHECK(S_ISREG(s.st_mode) != 0, 1);
     187                 :          1 : }
     188                 :            : 
     189                 :            : /* Checks that locking a file that is itself a symlink yields a lockfile in the
     190                 :            :  * directory that the symlink points to, named for the target of the
     191                 :            :  * symlink.
     192                 :            :  *
     193                 :            :  * (That is, if "a" is a symlink to "dir/b", then "a"'s lockfile is named
     194                 :            :  * "dir/.b.~lock".) */
     195                 :            : static void
     196                 :          1 : run_lock_symlink_to_dir(void)
     197                 :            : {
     198                 :            :     struct lockfile *a, *dummy;
     199                 :            :     struct stat s;
     200                 :            : 
     201                 :            :     /* Create a symlink "a" pointing to "dir/b". */
     202                 :          1 :     CHECK(mkdir("dir", 0700), 0);
     203                 :          1 :     CHECK(symlink("dir/b", "a"), 0);
     204                 :          1 :     CHECK(lstat("a", &s), 0);
     205                 :          1 :     CHECK(S_ISLNK(s.st_mode) != 0, 1);
     206                 :            : 
     207                 :            :     /* Lock 'a'. */
     208                 :          1 :     CHECK(lockfile_lock("a", &a), 0);
     209                 :          1 :     CHECK(lstat("dir/.b.~lock~", &s), 0);
     210                 :          1 :     CHECK(S_ISREG(s.st_mode) != 0, 1);
     211                 :          1 :     CHECK(lstat(".a.~lock~", &s), -1);
     212                 :          1 :     CHECK(errno, ENOENT);
     213                 :          1 :     CHECK(lockfile_lock("dir/b", &dummy), EDEADLK);
     214                 :            : 
     215                 :          1 :     lockfile_unlock(a);
     216                 :          1 : }
     217                 :            : #endif /* _WIN32 */
     218                 :            : 
     219                 :            : static void
     220                 :          1 : run_lock_multiple(void)
     221                 :            : {
     222                 :            :     struct lockfile *a, *b, *c, *dummy;
     223                 :            : 
     224                 :          1 :     CHECK(lockfile_lock("a", &a), 0);
     225                 :          1 :     CHECK(lockfile_lock("b", &b), 0);
     226                 :          1 :     CHECK(lockfile_lock("c", &c), 0);
     227                 :            : 
     228                 :          1 :     lockfile_unlock(a);
     229                 :          1 :     CHECK(lockfile_lock("a", &a), 0);
     230                 :          1 :     CHECK(lockfile_lock("a", &dummy), EDEADLK);
     231                 :          1 :     lockfile_unlock(a);
     232                 :            : 
     233                 :          1 :     lockfile_unlock(b);
     234                 :          1 :     CHECK(lockfile_lock("a", &a), 0);
     235                 :            : 
     236                 :          1 :     lockfile_unlock(c);
     237                 :          1 :     lockfile_unlock(a);
     238                 :          1 : }
     239                 :            : 
     240                 :            : 
     241                 :            : static const struct test tests[] = {
     242                 :            : #define TEST(NAME) { #NAME, run_##NAME }
     243                 :            :     TEST(lock_and_unlock),
     244                 :            :     TEST(lock_and_unlock_twice),
     245                 :            :     TEST(lock_blocks_same_process),
     246                 :            :     TEST(lock_blocks_same_process_twice),
     247                 :            : #ifndef _WIN32
     248                 :            :     TEST(lock_blocks_other_process),
     249                 :            :     TEST(lock_twice_blocks_other_process),
     250                 :            :     TEST(lock_and_unlock_allows_other_process),
     251                 :            :     TEST(lock_symlink),
     252                 :            :     TEST(lock_symlink_to_dir),
     253                 :            : #endif /* _WIN32 */
     254                 :            :     TEST(lock_multiple),
     255                 :            :     TEST(help),
     256                 :            :     { NULL, NULL }
     257                 :            : #undef TEST
     258                 :            : };
     259                 :            : 
     260                 :            : static void
     261                 :          0 : run_help(void)
     262                 :            : {
     263                 :            :     size_t i;
     264                 :            : 
     265                 :          0 :     printf("usage: %s TESTNAME\n"
     266                 :            :            "where TESTNAME is one of the following:\n",
     267                 :            :            program_name);
     268         [ #  # ]:          0 :     for (i = 0; tests[i].name; i++) {
     269                 :          0 :         fprintf(stderr, "\t%s\n", tests[i].name);
     270                 :            :     }
     271                 :          0 : }
     272                 :            : 
     273                 :            : static void
     274                 :         10 : test_lockfile_main(int argc, char *argv[])
     275                 :            : {
     276                 :            :     size_t i;
     277                 :            : 
     278                 :         10 :     set_program_name(argv[0]);
     279                 :         10 :     vlog_set_pattern(VLF_CONSOLE, "%c|%p|%m");
     280                 :         10 :     vlog_set_levels(NULL, VLF_SYSLOG, VLL_OFF);
     281                 :            : 
     282         [ -  + ]:         10 :     if (argc != 2) {
     283                 :          0 :         ovs_fatal(0, "exactly one argument required; use \"%s help\" for help",
     284                 :            :                   program_name);
     285                 :            :     }
     286                 :            : 
     287         [ +  - ]:         55 :     for (i = 0; tests[i].name; i++) {
     288         [ +  + ]:         55 :         if (!strcmp(argv[1], tests[i].name)) {
     289                 :            :             int n_children;
     290                 :            :             int status;
     291                 :            : 
     292                 :         10 :             (tests[i].function)();
     293                 :            : 
     294                 :         10 :             n_children = 0;
     295                 :            : #ifndef _WIN32
     296         [ +  + ]:         13 :             while (wait(&status) > 0) {
     297 [ +  - ][ +  - ]:          3 :                 if (WIFEXITED(status) && WEXITSTATUS(status) == 11) {
     298                 :          3 :                     n_children++;
     299                 :            :                 } else {
     300                 :          0 :                     ovs_fatal(0, "child exited in unexpected way: %s",
     301                 :            :                               process_status_msg(status));
     302                 :            :                 }
     303                 :            :             }
     304         [ -  + ]:         10 :             if (errno != ECHILD) {
     305                 :          0 :                 ovs_fatal(errno, "wait");
     306                 :            :             }
     307                 :            : #endif /* _WIN32 */
     308                 :            : 
     309         [ +  + ]:         10 :             printf("%s: success (%d child%s)\n",
     310                 :            :                    tests[i].name, n_children, n_children != 1 ? "ren" : "");
     311                 :         10 :             exit(0);
     312                 :            :         }
     313                 :            :     }
     314                 :          0 :     ovs_fatal(0, "unknown test \"%s\"; use \"%s help\" for help",
     315                 :          0 :               argv[1], program_name);
     316                 :            : }
     317                 :            : 
     318                 :       1184 : OVSTEST_REGISTER("test-lockfile", test_lockfile_main);

Generated by: LCOV version 1.12