#include #include #include #include #include "util.h" #include "alias.h" #include "test-log.h" #include #include "globals.c" #include "../libmultipath/alias.c" #if INT_MAX == 0x7fffffff /* user_friendly_name for map #INT_MAX */ #define MPATH_ID_INT_MAX "fxshrxw" /* ... and one less */ #define MPATH_ID_INT_MAX_m1 "fxshrxv" /* ... and one more */ #define MPATH_ID_INT_MAX_p1 "fxshrxx" #endif void __wrap_rewind(FILE *stream) {} char *__wrap_fgets(char *buf, int n, FILE *stream) { char *val = mock_ptr_type(char *); if (!val) return NULL; strlcpy(buf, val, n); return buf; } static int __set_errno(int err) { if (err >= 0) { errno = 0; return err; } else { errno = -err; return -1; } } off_t __wrap_lseek(int fd, off_t offset, int whence) { return __set_errno(mock_type(int)); } ssize_t __wrap_write(int fd, const void *buf, size_t count) { check_expected(count); check_expected(buf); return __set_errno(mock_type(int)); } int __wrap_ftruncate(int fd, off_t length) { check_expected(length); return __set_errno(mock_type(int)); } static void fd_mpatha(void **state) { char buf[32]; int rc; rc = format_devname(buf, 1, sizeof(buf), "FOO"); assert_int_equal(rc, 4); assert_string_equal(buf, "FOOa"); } static void fd_mpathz(void **state) { /* This also tests a "short" buffer, see fd_mpath_short1 */ char buf[5]; int rc; rc = format_devname(buf, 26, sizeof(buf), "FOO"); assert_int_equal(rc, 4); assert_string_equal(buf, "FOOz"); } static void fd_mpathaa(void **state) { char buf[32]; int rc; rc = format_devname(buf, 26 + 1, sizeof(buf), "FOO"); assert_int_equal(rc, 5); assert_string_equal(buf, "FOOaa"); } static void fd_mpathzz(void **state) { char buf[32]; int rc; rc = format_devname(buf, 26*26 + 26, sizeof(buf), "FOO"); assert_int_equal(rc, 5); assert_string_equal(buf, "FOOzz"); } static void fd_mpathaaa(void **state) { char buf[32]; int rc; rc = format_devname(buf, 26*26 + 27, sizeof(buf), "FOO"); assert_int_equal(rc, 6); assert_string_equal(buf, "FOOaaa"); } static void fd_mpathzzz(void **state) { char buf[32]; int rc; rc = format_devname(buf, 26*26*26 + 26*26 + 26, sizeof(buf), "FOO"); assert_int_equal(rc, 6); assert_string_equal(buf, "FOOzzz"); } static void fd_mpathaaaa(void **state) { char buf[32]; int rc; rc = format_devname(buf, 26*26*26 + 26*26 + 27, sizeof(buf), "FOO"); assert_int_equal(rc, 7); assert_string_equal(buf, "FOOaaaa"); } static void fd_mpathzzzz(void **state) { char buf[32]; int rc; rc = format_devname(buf, 26*26*26*26 + 26*26*26 + 26*26 + 26, sizeof(buf), "FOO"); assert_int_equal(rc, 7); assert_string_equal(buf, "FOOzzzz"); } #ifdef MPATH_ID_INT_MAX static void fd_mpath_max(void **state) { char buf[32]; int rc; rc = format_devname(buf, INT_MAX, sizeof(buf), ""); assert_int_equal(rc, strlen(MPATH_ID_INT_MAX)); assert_string_equal(buf, MPATH_ID_INT_MAX); } #endif static void fd_mpath_max1(void **state) { char buf[32]; int rc; rc = format_devname(buf, INT_MIN, sizeof(buf), ""); assert_int_equal(rc, -1); } static void fd_mpath_short(void **state) { char buf[4]; int rc; rc = format_devname(buf, 1, sizeof(buf), "FOO"); assert_int_equal(rc, -1); } static void fd_mpath_short1(void **state) { char buf[5]; int rc; rc = format_devname(buf, 27, sizeof(buf), "FOO"); assert_int_equal(rc, -1); } static int test_format_devname(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(fd_mpatha), cmocka_unit_test(fd_mpathz), cmocka_unit_test(fd_mpathaa), cmocka_unit_test(fd_mpathzz), cmocka_unit_test(fd_mpathaaa), cmocka_unit_test(fd_mpathzzz), cmocka_unit_test(fd_mpathaaaa), cmocka_unit_test(fd_mpathzzzz), #ifdef MPATH_ID_INT_MAX cmocka_unit_test(fd_mpath_max), #endif cmocka_unit_test(fd_mpath_max1), cmocka_unit_test(fd_mpath_short), cmocka_unit_test(fd_mpath_short1), }; return cmocka_run_group_tests(tests, NULL, NULL); } static void sd_mpatha(void **state) { int rc = scan_devname("MPATHa", "MPATH"); assert_int_equal(rc, 1); } /* * Text after whitespace is ignored. But an overlong input * errors out, even if it's just whitespace. * It's kind of strange that scan_devname() treats whitespace * like this. But I'm not sure if some corner case depends * on this behavior. */ static void sd_mpatha_spc(void **state) { int rc = scan_devname("MPATHa 00", "MPATH"); assert_int_equal(rc, 1); } static void sd_mpatha_tab(void **state) { int rc = scan_devname("MPATHa\t00", "MPATH"); assert_int_equal(rc, 1); } static void sd_overlong(void **state) { int rc = scan_devname("MPATHa ", "MPATH"); assert_int_equal(rc, -1); } static void sd_overlong1(void **state) { int rc = scan_devname("MPATHabcdefgh", "MPATH"); assert_int_equal(rc, -1); } static void sd_noprefix(void **state) { int rc = scan_devname("MPATHa", NULL); assert_int_equal(rc, -1); } static void sd_nomatchprefix(void **state) { int rc = scan_devname("MPATHa", "mpath"); assert_int_equal(rc, -1); } static void sd_eq_prefix(void **state) { int rc = scan_devname("MPATH", "MPATH"); assert_int_equal(rc, -1); } static void sd_bad_1(void **state) { int rc = scan_devname("MPATH0", "MPATH"); assert_int_equal(rc, -1); } static void sd_bad_2(void **state) { int rc = scan_devname("MPATHa0c", "MPATH"); assert_int_equal(rc, -1); } #ifdef MPATH_ID_INT_MAX static void sd_max(void **state) { int rc = scan_devname("MPATH" MPATH_ID_INT_MAX, "MPATH"); assert_int_equal(rc, INT_MAX); } static void sd_max_p1(void **state) { int rc = scan_devname("MPATH" MPATH_ID_INT_MAX_p1, "MPATH"); assert_int_equal(rc, -1); } #endif static void sd_fd_many(void **state) { char buf[32]; int rc, i; for (i = 1; i < 5000; i++) { rc = format_devname(buf, i, sizeof(buf), "MPATH"); assert_in_range(rc, 6, 8); rc = scan_devname(buf, "MPATH"); assert_int_equal(rc, i); } } static void sd_fd_random(void **state) { char buf[32]; int rc, i, n; srandom(1); for (i = 1; i < 1000; i++) { n = random() & 0xffff; rc = format_devname(buf, n, sizeof(buf), "MPATH"); assert_in_range(rc, 6, 9); rc = scan_devname(buf, "MPATH"); assert_int_equal(rc, n); } } static int test_scan_devname(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(sd_mpatha), cmocka_unit_test(sd_mpatha_spc), cmocka_unit_test(sd_mpatha_tab), cmocka_unit_test(sd_overlong), cmocka_unit_test(sd_overlong1), cmocka_unit_test(sd_noprefix), cmocka_unit_test(sd_nomatchprefix), cmocka_unit_test(sd_eq_prefix), cmocka_unit_test(sd_bad_1), cmocka_unit_test(sd_bad_2), #ifdef MPATH_ID_INT_MAX cmocka_unit_test(sd_max), cmocka_unit_test(sd_max_p1), #endif cmocka_unit_test(sd_fd_many), cmocka_unit_test(sd_fd_random), }; return cmocka_run_group_tests(tests, NULL, NULL); } static void lb_empty(void **state) { int rc; char *alias; will_return(__wrap_fgets, NULL); expect_condlog(3, "No matching wwid [WWID0] in bindings file.\n"); rc = lookup_binding(NULL, "WWID0", &alias, NULL); assert_int_equal(rc, 1); assert_ptr_equal(alias, NULL); } static void lb_match_a(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHa WWID0\n"); expect_condlog(3, "Found matching wwid [WWID0] in bindings file." " Setting alias to MPATHa\n"); rc = lookup_binding(NULL, "WWID0", &alias, "MPATH"); assert_int_equal(rc, 0); assert_ptr_not_equal(alias, NULL); assert_string_equal(alias, "MPATHa"); free(alias); } static void lb_nomatch_a(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, NULL); expect_condlog(3, "No matching wwid [WWID1] in bindings file.\n"); rc = lookup_binding(NULL, "WWID1", &alias, "MPATH"); assert_int_equal(rc, 2); assert_ptr_equal(alias, NULL); } static void lb_match_c(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, "MPATHc WWID1\n"); expect_condlog(3, "Found matching wwid [WWID1] in bindings file." " Setting alias to MPATHc\n"); rc = lookup_binding(NULL, "WWID1", &alias, "MPATH"); assert_int_equal(rc, 0); assert_ptr_not_equal(alias, NULL); assert_string_equal(alias, "MPATHc"); free(alias); } static void lb_nomatch_a_c(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, "MPATHc WWID1\n"); will_return(__wrap_fgets, NULL); expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); assert_int_equal(rc, 2); assert_ptr_equal(alias, NULL); } static void lb_nomatch_c_a(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHc WWID1\n"); will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, NULL); expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); assert_int_equal(rc, 2); assert_ptr_equal(alias, NULL); } static void lb_nomatch_a_b(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, "MPATHz WWID26\n"); will_return(__wrap_fgets, "MPATHb WWID1\n"); will_return(__wrap_fgets, NULL); expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); assert_int_equal(rc, 3); assert_ptr_equal(alias, NULL); } static void lb_nomatch_a_b_bad(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, "MPATHz WWID26\n"); will_return(__wrap_fgets, "MPATHb\n"); will_return(__wrap_fgets, NULL); expect_condlog(3, "Ignoring malformed line 3 in bindings file\n"); expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); assert_int_equal(rc, 3); assert_ptr_equal(alias, NULL); } static void lb_nomatch_b_a(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHb WWID1\n"); will_return(__wrap_fgets, "MPATHz WWID26\n"); will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, NULL); expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); assert_int_equal(rc, 27); assert_ptr_equal(alias, NULL); } #ifdef MPATH_ID_INT_MAX static void lb_nomatch_int_max(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHb WWID1\n"); will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX " WWIDMAX\n"); will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, NULL); expect_condlog(0, "no more available user_friendly_names\n"); rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); assert_int_equal(rc, -1); assert_ptr_equal(alias, NULL); } static void lb_nomatch_int_max_m1(void **state) { int rc; char *alias; will_return(__wrap_fgets, "MPATHb WWID1\n"); will_return(__wrap_fgets, "MPATH" MPATH_ID_INT_MAX_m1 " WWIDMAX\n"); will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, NULL); expect_condlog(3, "No matching wwid [WWID2] in bindings file.\n"); rc = lookup_binding(NULL, "WWID2", &alias, "MPATH"); assert_int_equal(rc, INT_MAX); assert_ptr_equal(alias, NULL); } #endif static int test_lookup_binding(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(lb_empty), cmocka_unit_test(lb_match_a), cmocka_unit_test(lb_nomatch_a), cmocka_unit_test(lb_match_c), cmocka_unit_test(lb_nomatch_a_c), cmocka_unit_test(lb_nomatch_c_a), cmocka_unit_test(lb_nomatch_a_b), cmocka_unit_test(lb_nomatch_a_b_bad), cmocka_unit_test(lb_nomatch_b_a), #ifdef MPATH_ID_INT_MAX cmocka_unit_test(lb_nomatch_int_max), cmocka_unit_test(lb_nomatch_int_max_m1), #endif }; return cmocka_run_group_tests(tests, NULL, NULL); } static void rl_empty(void **state) { int rc; char buf[WWID_SIZE]; buf[0] = '\0'; will_return(__wrap_fgets, NULL); expect_condlog(3, "No matching alias [MPATHa] in bindings file.\n"); rc = rlookup_binding(NULL, buf, "MPATHa"); assert_int_equal(rc, -1); assert_string_equal(buf, ""); } static void rl_match_a(void **state) { int rc; char buf[WWID_SIZE]; buf[0] = '\0'; will_return(__wrap_fgets, "MPATHa WWID0\n"); expect_condlog(3, "Found matching alias [MPATHa] in bindings file.\n" "Setting wwid to WWID0\n"); rc = rlookup_binding(NULL, buf, "MPATHa"); assert_int_equal(rc, 0); assert_string_equal(buf, "WWID0"); } static void rl_nomatch_a(void **state) { int rc; char buf[WWID_SIZE]; buf[0] = '\0'; will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, NULL); expect_condlog(3, "No matching alias [MPATHb] in bindings file.\n"); rc = rlookup_binding(NULL, buf, "MPATHb"); assert_int_equal(rc, -1); assert_string_equal(buf, ""); } static void rl_malformed_a(void **state) { int rc; char buf[WWID_SIZE]; buf[0] = '\0'; will_return(__wrap_fgets, "MPATHa \n"); will_return(__wrap_fgets, NULL); expect_condlog(3, "Ignoring malformed line 1 in bindings file\n"); expect_condlog(3, "No matching alias [MPATHa] in bindings file.\n"); rc = rlookup_binding(NULL, buf, "MPATHa"); assert_int_equal(rc, -1); assert_string_equal(buf, ""); } static void rl_overlong_a(void **state) { int rc; char buf[WWID_SIZE]; char line[WWID_SIZE + 10]; snprintf(line, sizeof(line), "MPATHa "); memset(line + strlen(line), 'W', sizeof(line) - 2 - strlen(line)); snprintf(line + sizeof(line) - 2, 2, "\n"); buf[0] = '\0'; will_return(__wrap_fgets, line); will_return(__wrap_fgets, NULL); expect_condlog(3, "Ignoring too large wwid at 1 in bindings file\n"); expect_condlog(3, "No matching alias [MPATHa] in bindings file.\n"); rc = rlookup_binding(NULL, buf, "MPATHa"); assert_int_equal(rc, -1); assert_string_equal(buf, ""); } static void rl_match_b(void **state) { int rc; char buf[WWID_SIZE]; buf[0] = '\0'; will_return(__wrap_fgets, "MPATHa WWID0\n"); will_return(__wrap_fgets, "MPATHz WWID26\n"); will_return(__wrap_fgets, "MPATHb WWID2\n"); expect_condlog(3, "Found matching alias [MPATHb] in bindings file.\n" "Setting wwid to WWID2\n"); rc = rlookup_binding(NULL, buf, "MPATHb"); assert_int_equal(rc, 0); assert_string_equal(buf, "WWID2"); } static int test_rlookup_binding(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(rl_empty), cmocka_unit_test(rl_match_a), cmocka_unit_test(rl_nomatch_a), cmocka_unit_test(rl_malformed_a), cmocka_unit_test(rl_overlong_a), cmocka_unit_test(rl_match_b), }; return cmocka_run_group_tests(tests, NULL, NULL); } static void al_a(void **state) { static const char ln[] = "MPATHa WWIDa\n"; char *alias; will_return(__wrap_lseek, 0); expect_value(__wrap_write, count, strlen(ln)); expect_string(__wrap_write, buf, ln); will_return(__wrap_write, strlen(ln)); expect_condlog(3, "Created new binding [MPATHa] for WWID [WWIDa]\n"); alias = allocate_binding(0, "WWIDa", 1, "MPATH"); assert_ptr_not_equal(alias, NULL); assert_string_equal(alias, "MPATHa"); } static void al_zz(void **state) { static const char ln[] = "MPATHzz WWIDzz\n"; char *alias; will_return(__wrap_lseek, 0); expect_value(__wrap_write, count, strlen(ln)); expect_string(__wrap_write, buf, ln); will_return(__wrap_write, strlen(ln)); expect_condlog(3, "Created new binding [MPATHzz] for WWID [WWIDzz]\n"); alias = allocate_binding(0, "WWIDzz", 26*26 + 26, "MPATH"); assert_ptr_not_equal(alias, NULL); assert_string_equal(alias, "MPATHzz"); } static void al_0(void **state) { char *alias; expect_condlog(0, "allocate_binding: cannot allocate new binding for id 0\n"); alias = allocate_binding(0, "WWIDa", 0, "MPATH"); assert_ptr_equal(alias, NULL); } static void al_m2(void **state) { char *alias; expect_condlog(0, "allocate_binding: cannot allocate new binding for id -2\n"); alias = allocate_binding(0, "WWIDa", -2, "MPATH"); assert_ptr_equal(alias, NULL); } static void al_lseek_err(void **state) { char *alias; will_return(__wrap_lseek, -ENODEV); expect_condlog(0, "Cannot seek to end of bindings file : No such device\n"); alias = allocate_binding(0, "WWIDa", 1, "MPATH"); assert_ptr_equal(alias, NULL); } static void al_write_err(void **state) { static const char ln[] = "MPATHa WWIDa\n"; const int offset = 20; char *alias; will_return(__wrap_lseek, offset); expect_value(__wrap_write, count, strlen(ln)); expect_string(__wrap_write, buf, ln); will_return(__wrap_write, strlen(ln) - 1); expect_value(__wrap_ftruncate, length, offset); will_return(__wrap_ftruncate, 0); expect_condlog(0, "Cannot write binding to bindings file : Success\n"); alias = allocate_binding(0, "WWIDa", 1, "MPATH"); assert_ptr_equal(alias, NULL); } static int test_allocate_binding(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(al_a), cmocka_unit_test(al_zz), cmocka_unit_test(al_0), cmocka_unit_test(al_m2), cmocka_unit_test(al_lseek_err), cmocka_unit_test(al_write_err), }; return cmocka_run_group_tests(tests, NULL, NULL); } int main(void) { int ret = 0; ret += test_format_devname(); ret += test_scan_devname(); ret += test_lookup_binding(); ret += test_rlookup_binding(); ret += test_allocate_binding(); return ret; }