X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=tests%2Ftest-lockfile.c;h=d0c8dc48061af4e79241d6ef41043b16c13ca7af;hb=HEAD;hp=f0f4b010a112852c673900f61f15d851c940bb5b;hpb=a0bc29a541fc7dc6e20137d5558e2094d614e6ab;p=cascardo%2Fovs.git diff --git a/tests/test-lockfile.c b/tests/test-lockfile.c index f0f4b010a..d0c8dc480 100644 --- a/tests/test-lockfile.c +++ b/tests/test-lockfile.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Nicira Networks. + * Copyright (c) 2009, 2010, 2011, 2012, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,34 +15,45 @@ */ #include - +#undef NDEBUG #include "lockfile.h" - #include #include +#include #include #include - +#include "ovstest.h" #include "process.h" #include "timeval.h" #include "util.h" - -#undef NDEBUG -#include +#include "openvswitch/vlog.h" struct test { const char *name; void (*function)(void); }; -static const struct test tests[]; +static void run_help(void); + +#define CHECK(A, B) check(A, B, #A, #B, __FILE__, __LINE__) +static void +check(int a, int b, + const char *a_string, const char *b_string, const char *file, int line) +{ + if (a != b) { + fprintf(stderr, "%s:%d: expected %s == %s but %d != %d\n", + file, line, a_string, b_string, a, b); + fflush(stderr); + abort(); + } +} static void run_lock_and_unlock(void) { struct lockfile *lockfile; - assert(lockfile_lock("file", 0, &lockfile) == 0); + CHECK(lockfile_lock("file", &lockfile), 0); lockfile_unlock(lockfile); } @@ -51,10 +62,10 @@ run_lock_and_unlock_twice(void) { struct lockfile *lockfile; - assert(lockfile_lock("file", 0, &lockfile) == 0); + CHECK(lockfile_lock("file", &lockfile), 0); lockfile_unlock(lockfile); - assert(lockfile_lock("file", 0, &lockfile) == 0); + CHECK(lockfile_lock("file", &lockfile), 0); lockfile_unlock(lockfile); } @@ -63,8 +74,8 @@ run_lock_blocks_same_process(void) { struct lockfile *lockfile; - assert(lockfile_lock("file", 0, &lockfile) == 0); - assert(lockfile_lock("file", 0, &lockfile) == EDEADLK); + CHECK(lockfile_lock("file", &lockfile), 0); + CHECK(lockfile_lock("file", &lockfile), EDEADLK); lockfile_unlock(lockfile); } @@ -73,18 +84,18 @@ run_lock_blocks_same_process_twice(void) { struct lockfile *lockfile; - assert(lockfile_lock("file", 0, &lockfile) == 0); - assert(lockfile_lock("file", 0, &lockfile) == EDEADLK); - assert(lockfile_lock("file", 0, &lockfile) == EDEADLK); + CHECK(lockfile_lock("file", &lockfile), 0); + CHECK(lockfile_lock("file", &lockfile), EDEADLK); + CHECK(lockfile_lock("file", &lockfile), EDEADLK); lockfile_unlock(lockfile); } +#ifndef _WIN32 static enum { PARENT, CHILD } do_fork(void) { switch (fork()) { case 0: - time_postfork(); lockfile_postfork(); return CHILD; @@ -106,10 +117,10 @@ run_lock_blocks_other_process(void) * this function that does the wait() call. */ static struct lockfile *lockfile; - assert(lockfile_lock("file", 0, &lockfile) == 0); + CHECK(lockfile_lock("file", &lockfile), 0); if (do_fork() == CHILD) { lockfile_unlock(lockfile); - assert(lockfile_lock("file", 0, &lockfile) == EAGAIN); + CHECK(lockfile_lock("file", &lockfile), EAGAIN); exit(11); } } @@ -119,10 +130,10 @@ run_lock_twice_blocks_other_process(void) { struct lockfile *lockfile, *dummy; - assert(lockfile_lock("file", 0, &lockfile) == 0); - assert(lockfile_lock("file", 0, &dummy) == EDEADLK); + CHECK(lockfile_lock("file", &lockfile), 0); + CHECK(lockfile_lock("file", &dummy), EDEADLK); if (do_fork() == CHILD) { - assert(lockfile_lock("file", 0, &dummy) == EAGAIN); + CHECK(lockfile_lock("file", &dummy), EAGAIN); exit(11); } } @@ -132,90 +143,100 @@ run_lock_and_unlock_allows_other_process(void) { struct lockfile *lockfile; - assert(lockfile_lock("file", 0, &lockfile) == 0); + CHECK(lockfile_lock("file", &lockfile), 0); lockfile_unlock(lockfile); if (do_fork() == CHILD) { - assert(lockfile_lock("file", 0, &lockfile) == 0); + CHECK(lockfile_lock("file", &lockfile), 0); exit(11); } } +/* Checks that locking a dangling symlink works OK. (It used to hang.) */ static void -run_lock_timeout_gets_the_lock(void) +run_lock_symlink(void) { - struct lockfile *lockfile; + struct lockfile *a, *b, *dummy; + struct stat s; + + /* Create a symlink .a.~lock~ pointing to .b.~lock~. */ + CHECK(symlink(".b.~lock~", ".a.~lock~"), 0); + CHECK(lstat(".a.~lock~", &s), 0); + CHECK(S_ISLNK(s.st_mode) != 0, 1); + CHECK(stat(".a.~lock~", &s), -1); + CHECK(errno, ENOENT); + CHECK(stat(".b.~lock~", &s), -1); + CHECK(errno, ENOENT); + + CHECK(lockfile_lock("a", &a), 0); + CHECK(lockfile_lock("a", &dummy), EDEADLK); + CHECK(lockfile_lock("b", &dummy), EDEADLK); + lockfile_unlock(a); - assert(lockfile_lock("file", 0, &lockfile) == 0); + CHECK(lockfile_lock("b", &b), 0); + CHECK(lockfile_lock("b", &dummy), EDEADLK); + CHECK(lockfile_lock("a", &dummy), EDEADLK); + lockfile_unlock(b); - if (do_fork() == CHILD) { - lockfile_unlock(lockfile); - assert(lockfile_lock("file", TIME_UPDATE_INTERVAL * 3, - &lockfile) == 0); - exit(11); - } else { - long long int now = time_msec(); - while (time_msec() < now + TIME_UPDATE_INTERVAL) { - pause(); - } - lockfile_unlock(lockfile); - } + CHECK(lstat(".a.~lock~", &s), 0); + CHECK(S_ISLNK(s.st_mode) != 0, 1); + CHECK(stat(".a.~lock~", &s), 0); + CHECK(S_ISREG(s.st_mode) != 0, 1); + CHECK(stat(".b.~lock~", &s), 0); + CHECK(S_ISREG(s.st_mode) != 0, 1); } +/* Checks that locking a file that is itself a symlink yields a lockfile in the + * directory that the symlink points to, named for the target of the + * symlink. + * + * (That is, if "a" is a symlink to "dir/b", then "a"'s lockfile is named + * "dir/.b.~lock".) */ static void -run_lock_timeout_runs_out(void) +run_lock_symlink_to_dir(void) { - struct lockfile *lockfile; - - assert(lockfile_lock("file", 0, &lockfile) == 0); + struct lockfile *a, *dummy; + struct stat s; + + /* Create a symlink "a" pointing to "dir/b". */ + CHECK(mkdir("dir", 0700), 0); + CHECK(symlink("dir/b", "a"), 0); + CHECK(lstat("a", &s), 0); + CHECK(S_ISLNK(s.st_mode) != 0, 1); + + /* Lock 'a'. */ + CHECK(lockfile_lock("a", &a), 0); + CHECK(lstat("dir/.b.~lock~", &s), 0); + CHECK(S_ISREG(s.st_mode) != 0, 1); + CHECK(lstat(".a.~lock~", &s), -1); + CHECK(errno, ENOENT); + CHECK(lockfile_lock("dir/b", &dummy), EDEADLK); - if (do_fork() == CHILD) { - lockfile_unlock(lockfile); - assert(lockfile_lock("file", TIME_UPDATE_INTERVAL, - &lockfile) == ETIMEDOUT); - exit(11); - } else { - long long int now = time_msec(); - while (time_msec() < now + TIME_UPDATE_INTERVAL * 3) { - pause(); - } - lockfile_unlock(lockfile); - } + lockfile_unlock(a); } +#endif /* _WIN32 */ static void run_lock_multiple(void) { struct lockfile *a, *b, *c, *dummy; - assert(lockfile_lock("a", 0, &a) == 0); - assert(lockfile_lock("b", 0, &b) == 0); - assert(lockfile_lock("c", 0, &c) == 0); + CHECK(lockfile_lock("a", &a), 0); + CHECK(lockfile_lock("b", &b), 0); + CHECK(lockfile_lock("c", &c), 0); lockfile_unlock(a); - assert(lockfile_lock("a", 0, &a) == 0); - assert(lockfile_lock("a", 0, &dummy) == EDEADLK); + CHECK(lockfile_lock("a", &a), 0); + CHECK(lockfile_lock("a", &dummy), EDEADLK); lockfile_unlock(a); lockfile_unlock(b); - assert(lockfile_lock("a", 0, &a) == 0); + CHECK(lockfile_lock("a", &a), 0); lockfile_unlock(c); lockfile_unlock(a); } -static void -run_help(void) -{ - size_t i; - - printf("usage: %s TESTNAME\n" - "where TESTNAME is one of the following:\n", - program_name); - for (i = 0; tests[i].name; i++) { - fprintf(stderr, "\t%s\n", tests[i].name); - } -} static const struct test tests[] = { #define TEST(NAME) { #NAME, run_##NAME } @@ -223,29 +244,44 @@ static const struct test tests[] = { TEST(lock_and_unlock_twice), TEST(lock_blocks_same_process), TEST(lock_blocks_same_process_twice), +#ifndef _WIN32 TEST(lock_blocks_other_process), TEST(lock_twice_blocks_other_process), TEST(lock_and_unlock_allows_other_process), - TEST(lock_timeout_gets_the_lock), - TEST(lock_timeout_runs_out), + TEST(lock_symlink), + TEST(lock_symlink_to_dir), +#endif /* _WIN32 */ TEST(lock_multiple), TEST(help), - { 0, 0 } + { NULL, NULL } #undef TEST }; -int -main(int argc, char *argv[]) +static void +run_help(void) +{ + size_t i; + + printf("usage: %s TESTNAME\n" + "where TESTNAME is one of the following:\n", + program_name); + for (i = 0; tests[i].name; i++) { + fprintf(stderr, "\t%s\n", tests[i].name); + } +} + +static void +test_lockfile_main(int argc, char *argv[]) { size_t i; set_program_name(argv[0]); - time_init(); + vlog_set_pattern(VLF_CONSOLE, "%c|%p|%m"); + vlog_set_levels(NULL, VLF_SYSLOG, VLL_OFF); if (argc != 2) { ovs_fatal(0, "exactly one argument required; use \"%s help\" for help", program_name); - return 1; } for (i = 0; tests[i].name; i++) { @@ -256,6 +292,7 @@ main(int argc, char *argv[]) (tests[i].function)(); n_children = 0; +#ifndef _WIN32 while (wait(&status) > 0) { if (WIFEXITED(status) && WEXITSTATUS(status) == 11) { n_children++; @@ -267,6 +304,7 @@ main(int argc, char *argv[]) if (errno != ECHILD) { ovs_fatal(errno, "wait"); } +#endif /* _WIN32 */ printf("%s: success (%d child%s)\n", tests[i].name, n_children, n_children != 1 ? "ren" : ""); @@ -277,3 +315,4 @@ main(int argc, char *argv[]) argv[1], program_name); } +OVSTEST_REGISTER("test-lockfile", test_lockfile_main);