static void test_double_get (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); KeySet * first = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, first, parentKey) == 1, "kdbGet was not successful"); KeySet * second = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, second, parentKey) == 1, "kdbGet was not successful"); succeed_if (first->array != second->array, "ks->array points to same thing"); compare_keyset (first, ks); compare_keyset (ks, first); compare_keyset (second, ks); compare_keyset (ks, second); ksDel (ks); ks = metaTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); KeySet * simple = simpleTestKeySet (); compare_keyset (first, simple); compare_keyset (second, simple); ksDel (first); ksDel (second); ksDel (simple); ksDel (ks); keyDel (parentKey); closeStoragePlugin (storagePlugin); }
static void test_mmap_ks_copy (const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * returned = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, returned, parentKey) == 1, "kdbGet was not successful"); ksDel (returned); returned = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful"); KeySet * expected = simpleTestKeySet (); compare_keyset (expected, returned); KeySet * copiedKs = ksNew (0, KS_END); ksCopy (copiedKs, returned); compare_keyset (expected, copiedKs); ksDel (copiedKs); ksDel (expected); ksDel (returned); keyDel (parentKey); PLUGIN_CLOSE (); }
static void test_ksPop (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); KeySet * poppedKeys = ksNew (0, KS_END); succeed_if (ksAppendKey (poppedKeys, ksPop (ks)) != -1, "ksAppendKey failed"); succeed_if (ksAppendKey (poppedKeys, ksPop (ks)) != -1, "ksAppendKey failed"); succeed_if (ksGetSize (ks) == 1, "ksGetSize after ksPop should be decremented"); succeed_if (ksAppendKey (poppedKeys, ksPop (ks)) != -1, "ksAppendKey failed"); succeed_if (ksGetSize (poppedKeys) == 3, "expecting three keys to be in ks"); succeed_if (ksPop (ks) == 0, "ks should be empty"); succeed_if (ksAppendKey (poppedKeys, ksPop (ks)) == -1, "ks should be empty, but is not"); KeySet * test = simpleTestKeySet (); compare_keyset (poppedKeys, test); ksDel (test); ksDel (poppedKeys); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
static void test_ksAppendKey (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = simpleTestKeySet (); ssize_t origSize = ksGetSize (ks); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); ssize_t appendSize = 0; Key * toAppend = keyNew (TEST_ROOT_KEY "/my/new/key", KEY_END); if ((appendSize = ksAppendKey (ks, toAppend)) == -1) { yield_error ("ksAppendKey failed"); } succeed_if (appendSize == (origSize + 1), "ksAppendKey after append should be incremented"); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); ksDel (ks); ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); ssize_t returnedSize = ksGetSize (ks); succeed_if (returnedSize == (origSize + 1), "ksGetSize after append should be incremented"); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
static void test_mmap_ksCopy (const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); succeed_if ((ks->flags & KS_FLAG_MMAP_ARRAY) == KS_FLAG_MMAP_ARRAY, "KeySet array not in mmap"); KeySet * copyKs = ksNew (0, KS_END); if (ksCopy (copyKs, ks) == 1) { compare_keyset (copyKs, ks); compare_keyset (ks, copyKs); } else { yield_error ("ksCopy failed"); } ksDel (copyKs); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); }
static void test_ksAppend (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); KeySet * toAppend = ksNew (10, keyNew ("user/tests/storage/zzzz", KEY_VALUE, "root key", KEY_END), keyNew ("user/tests/storage/simpleKey/c", KEY_VALUE, "c value", KEY_END), keyNew ("user/tests/storage/simpleKey/d", KEY_VALUE, "d value", KEY_END), KS_END); if (ksAppend (ks, toAppend) == -1) { yield_error ("ksAppend failed"); } succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); ksDel (ks); ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); ksDel (toAppend); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
static void test_ksCopy (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); KeySet * copyKs = ksNew (0, KS_END); if (ksCopy (copyKs, ks) == 1) { compare_keyset (copyKs, ks); compare_keyset (ks, copyKs); } else { yield_error ("ksCopy failed"); } ksDel (copyKs); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
static void test_ksLookupByName (const size_t storagePlugin, const char * tmpFile, option_t options) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); const char * name = "user/tests/storage/simpleKey/a"; Key * found = ksLookupByName (ks, name, options); succeed_if (found, "did not find key"); if (options == KDB_O_POP) { // make sure key is really popped keyDel (found); found = ksLookupByName (ks, name, 0); succeed_if (!found, "found key that should not exist"); } name = "user/tests/storage/simpleKey/foo"; found = ksLookupByName (ks, name, options); succeed_if (!found, "found key that should not exist"); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
static void test_mmap_truncated_file (const char * tmpFile) { // first write a mmap file { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); } // now truncate the mmap file by the size of the mmap footer FILE * fp; if ((fp = fopen (tmpFile, "r+")) == 0) { yield_error ("error opening file"); } struct stat sbuf; if (stat (tmpFile, &sbuf) == -1) { yield_error ("stat error"); } int fd = fileno (fp); if ((ftruncate (fd, sbuf.st_size - sizeof (MmapFooter))) == -1) { yield_error ("ftruncate error"); } if (fp) { fclose (fp); } // truncated file should be detected by mmapstorage { // after the file was truncated, we expect an error here Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR, "kdbGet did not detect truncated file"); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); } }
static void test_mmap_get_set (const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); ksDel (ks); ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); ksDel (ks); ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); KeySet * expected = simpleTestKeySet (); compare_keyset (expected, ks); compare_keyset (ks, expected); ksDel (expected); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); }
static void test_ksCut (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; // create keyset with some folder 'other' that we will then cut KeySet * ks = simpleTestKeySet (); KeySet * other = ksNew (10, keyNew ("user/tests/storage/other", KEY_VALUE, "other key", KEY_END), keyNew ("user/tests/storage/other/a", KEY_VALUE, "other a value", KEY_END), keyNew ("user/tests/storage/other/b", KEY_VALUE, "other b value", KEY_END), KS_END); if (ksAppend (ks, other) == -1) { yield_error ("ksAppend failed"); } succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); // now cut the 'other' folder Key * cutKey = keyNew ("user/tests/storage/other", KEY_END); KeySet * returned = ksCut (ks, cutKey); succeed_if (returned, "keyset is empty (does not contain the cut keyset)"); KeySet * simple = simpleTestKeySet (); compare_keyset (simple, ks); compare_keyset (other, returned); ksDel (other); ksDel (returned); ksDel (simple); keyDel (cutKey); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
static void test_ksDupFun (const size_t storagePlugin, const char * tmpFile, KeySet * copyFunction (const KeySet * source)) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); KeySet * dupKs = copyFunction (ks); compare_keyset (dupKs, ks); compare_keyset (ks, dupKs); ksDel (dupKs); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
static void test_mmap_ksDupFun (const char * tmpFile, KeySet * copyFunction (const KeySet * source)) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); succeed_if ((ks->flags & KS_FLAG_MMAP_ARRAY) == KS_FLAG_MMAP_ARRAY, "KeySet array not in mmap"); KeySet * dupKs = copyFunction (ks); compare_keyset (dupKs, ks); compare_keyset (ks, dupKs); ksDel (dupKs); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); }
static void test_ksGetSize (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = simpleTestKeySet (); ssize_t origSize = ksGetSize (ks); succeed_if (origSize > 0, "ks was empty before kdbSet"); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); ksDel (ks); ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); ssize_t returnedSize = ksGetSize (ks); succeed_if (origSize == returnedSize, "ksGetSize before and after kdbSet, kdbGet differ"); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
static void test_mmap_open_pipe (void) { // try writing to an invalid file, we simply use a pipe here int pipefd[2]; if (pipe (pipefd) != 0) { yield_error ("pipe() error"); } char pipeFile[1024]; sprintf (pipeFile, "/dev/fd/%d", pipefd[1]); pipeFile[1023] = '\0'; Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, pipeFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = simpleTestKeySet (); // truncate inside mmap plugin should fail here, since the pipe cannot be truncated succeed_if (plugin->kdbSet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR, "kdbSet did not detect error with the file"); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); }
static void test_mmap_wrong_magic_keyset (const char * tmpFile) { // first write a mmap file { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); } // now manipulate magic keyset inside the mapped region FILE * fp; if ((fp = fopen (tmpFile, "r+")) == 0) { yield_error ("fopen() error"); } struct stat sbuf; if (stat (tmpFile, &sbuf) == -1) { yield_error ("stat() error"); } int fd = fileno (fp); char * mappedRegion = mmap (0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mappedRegion == MAP_FAILED) { ELEKTRA_LOG_WARNING ("error mapping file %s\nmmapSize: " ELEKTRA_STAT_ST_SIZE_F, tmpFile, sbuf.st_size); yield_error ("mmap() error"); return; } if (fp) { fclose (fp); } KeySet * magicKs = (KeySet *) (mappedRegion + sizeof (MmapHeader)); magicKs->size = 1234; // magic keyset contains SIZE_MAX here if (msync ((void *) mappedRegion, sbuf.st_size, MS_SYNC) != 0) { yield_error ("msync() error"); return; } if (munmap (mappedRegion, sbuf.st_size) != 0) { yield_error ("munmap() error"); return; } // manipulated magic keyset should be detected now { // we expect an error here Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR, "kdbGet did not detect wrong magic keyset"); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); } }
static void test_mmap_unlink (const char * tmpFile) { // test file unlinking by overwriting config file while mapped int parentPipe[2]; int childPipe[2]; if (pipe (parentPipe) != 0 || pipe (childPipe) != 0) { yield_error ("pipe() error"); } pid_t pid; char buf; pid = fork (); if (pid == -1) { yield_error ("fork() error"); return; } else if (pid == 0) { // child: open a config file and leave it mapped int devnull = open ("/dev/null", O_RDWR); if (devnull == -1) _Exit (EXIT_FAILURE); // redirect any communication on standard file descriptors to /dev/null close (STDIN_FILENO); close (STDOUT_FILENO); close (STDERR_FILENO); if (dup (devnull) == -1) _Exit (EXIT_FAILURE); if (dup (devnull) == -1) _Exit (EXIT_FAILURE); if (dup (devnull) == -1) _Exit (EXIT_FAILURE); close (childPipe[0]); close (parentPipe[1]); Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); if (write (childPipe[1], "a", 1) != 1) _Exit (EXIT_FAILURE); // signal parent that we are ready close (childPipe[1]); if (read (parentPipe[0], &buf, 1) != 1) _Exit (EXIT_FAILURE); // wait for parent close (parentPipe[0]); KeySet * expected = simpleTestKeySet (); compare_keyset (expected, ks); compare_keyset (ks, expected); ksDel (expected); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); _Exit (EXIT_SUCCESS); } else { // parent: try and destroy the file that the child has mapped close (childPipe[1]); close (parentPipe[0]); if (read (childPipe[0], &buf, 1) != 1) _Exit (EXIT_FAILURE); // wait for child close (childPipe[0]); Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = metaTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); if (write (parentPipe[1], "a", 1) != 1) _Exit (EXIT_FAILURE); // signal child that we are done close (parentPipe[1]); int status; waitpid (pid, &status, 0); if (status != 0) yield_error ("child process did not exit successfully."); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); } }
static void test_mmap_wrong_format_version (const char * tmpFile) { // first write a mmap file { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = simpleTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); } // set wrong version number in mmap header FILE * fp; if ((fp = fopen (tmpFile, "r+")) == 0) { yield_error ("fopen() error"); } struct stat sbuf; if (stat (tmpFile, &sbuf) == -1) { yield_error ("stat() error"); } int fd = fileno (fp); char * mappedRegion = mmap (0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mappedRegion == MAP_FAILED) { ELEKTRA_LOG_WARNING ("error mapping file %s\nmmapSize: " ELEKTRA_STAT_ST_SIZE_F, tmpFile, sbuf.st_size); yield_error ("mmap() error"); return; } if (fp) { fclose (fp); } MmapHeader * mmapHeader = (MmapHeader *) mappedRegion; mmapHeader->formatVersion = ELEKTRA_MMAP_FORMAT_VERSION + 1; if (msync ((void *) mappedRegion, sbuf.st_size, MS_SYNC) != 0) { yield_error ("msync() error"); return; } if (munmap (mappedRegion, sbuf.st_size) != 0) { yield_error ("munmap() error"); return; } // wrong format version should be detected now { // we expect an error here Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); KeySet * conf = ksNew (0, KS_END); PLUGIN_OPEN ("mmapstorage"); KeySet * ks = ksNew (0, KS_END); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR, "kdbGet did not detect wrong format version"); keyDel (parentKey); ksDel (ks); PLUGIN_CLOSE (); } }