LCOV - code coverage report
Current view: top level - src/plugins/mmapstorage - testmod_mmapstorage.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 543 611 88.9 %
Date: 2019-09-12 12:28:41 Functions: 32 32 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Tests for mmapstorage plugin
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : #define _XOPEN_SOURCE 600
      10             : 
      11             : /* -- Imports --------------------------------------------------------------------------------------------------------------------------- */
      12             : 
      13             : #include <fcntl.h> // fcntl(), open()
      14             : #include <stdio.h> // fopen(), fileno()
      15             : #include <stdlib.h>
      16             : #include <string.h>
      17             : #include <sys/mman.h>  // mmap()
      18             : #include <sys/stat.h>  // stat(), chmod()
      19             : #include <sys/types.h> // ftruncate ()
      20             : #include <sys/wait.h>  // waitpit()
      21             : #include <unistd.h>    // ftruncate(), pipe(), fork()
      22             : 
      23             : #include <kdbconfig.h>
      24             : #include <kdbprivate.h>
      25             : 
      26             : #include <tests_plugin.h>
      27             : 
      28             : #include "dynarray.h"
      29             : #include "internal.h"
      30             : #include "mmapstorage.h"
      31             : 
      32             : /* -- Macros ---------------------------------------------------------------------------------------------------------------------------- */
      33             : 
      34             : #define KEY_NAME_LENGTH 1000
      35             : #define NUM_DIR 10
      36             : #define NUM_KEY 10
      37             : 
      38             : #define TEST_ROOT_KEY "user/tests/mmapstorage"
      39             : 
      40             : /* -- KeySet test data ------------------------------------------------------------------------------------------------------------------ */
      41             : 
      42          40 : static KeySet * simpleTestKeySet (void)
      43             : {
      44          40 :         return ksNew (10, keyNew ("user/tests/mmapstorage/simpleKey", KEY_VALUE, "root key", KEY_END),
      45             :                       keyNew ("user/tests/mmapstorage/simpleKey/a", KEY_VALUE, "a value", KEY_END),
      46             :                       keyNew ("user/tests/mmapstorage/simpleKey/b", KEY_VALUE, "b value", KEY_END), KS_END);
      47             : }
      48             : 
      49          22 : static KeySet * metaTestKeySet (void)
      50             : {
      51          22 :         return ksNew (10,
      52             :                       keyNew ("user/tests/mmapstorage", KEY_VALUE, "root key", KEY_META, "a",
      53             :                               "b aksdjfh aksjdhf aklsjdhf aksljdhf aklsjdhf aksljdhf ", KEY_END),
      54             :                       keyNew ("user/tests/mmapstorage/a", KEY_VALUE, "a value", KEY_META, "ab",
      55             :                               "cd oiahsdkfhga sdjkfhgsuzdgf kashgdf aszgdf uashdf ", KEY_END),
      56             :                       keyNew ("user/tests/mmapstorage/b", KEY_VALUE, "b value", KEY_META, "longer val",
      57             :                               "here some even more with ugly €@\\1¹²³¼ chars", KEY_END),
      58             :                       KS_END);
      59             : }
      60             : 
      61             : typedef struct _binaryTest
      62             : {
      63             :         size_t A_size;
      64             :         ssize_t B_ssize;
      65             : } BinaryTest;
      66             : static BinaryTest binaryTestA = { .A_size = SIZE_MAX, .B_ssize = -1 };
      67             : 
      68           4 : static KeySet * otherMetaTestKeySet (void)
      69             : {
      70           4 :         return ksNew (
      71             :                 10, keyNew ("user/tests/mmapstorage", KEY_VALUE, "root key", KEY_META, "e", "other meta root", KEY_END),
      72             :                 keyNew ("user/tests/mmapstorage/f", KEY_VALUE, "f value", KEY_META, "foo", "some other key in the other meta keyset",
      73             :                         KEY_END),
      74             :                 keyNew ("user/tests/mmapstorage/i", KEY_VALUE, "i value", KEY_META, "i is quite valuable", "happy data is happy :)",
      75             :                         KEY_END),
      76             :                 keyNew ("user/tests/mmapstorage/j/k/l", KEY_VALUE, "jkl value", KEY_META, "where is everyone?", "don't panic", KEY_END),
      77             :                 keyNew ("user/tests/mmapstorage/m", KEY_BINARY, KEY_SIZE, sizeof (BinaryTest), KEY_VALUE, &(binaryTestA), KEY_END), KS_END);
      78             : }
      79             : 
      80           4 : static KeySet * largeTestKeySet (void)
      81             : {
      82             :         int i, j;
      83             :         char name[KEY_NAME_LENGTH + 1];
      84           4 :         char value[] = "data";
      85           4 :         KeySet * large = ksNew (NUM_KEY * NUM_DIR, KS_END);
      86             : 
      87          44 :         for (i = 0; i < NUM_DIR; i++)
      88             :         {
      89          40 :                 snprintf (name, KEY_NAME_LENGTH, "%s/%s%d", TEST_ROOT_KEY, "dir", i);
      90          40 :                 ksAppendKey (large, keyNew (name, KEY_VALUE, value, KEY_END));
      91         440 :                 for (j = 0; j < NUM_KEY; j++)
      92             :                 {
      93         400 :                         snprintf (name, KEY_NAME_LENGTH, "%s/%s%d/%s%d", TEST_ROOT_KEY, "dir", i, "key", j);
      94         400 :                         ksAppendKey (large, keyNew (name, KEY_VALUE, value, KEY_END));
      95             :                 }
      96             :         }
      97           4 :         return large;
      98             : }
      99             : 
     100             : /* -- Functions ------------------------------------------------------------------------------------------------------------------------- */
     101             : 
     102           2 : static void test_mmap_get_set_empty (const char * tmpFile)
     103             : {
     104           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     105           2 :         KeySet * conf = ksNew (0, KS_END);
     106           2 :         PLUGIN_OPEN ("mmapstorage");
     107             : 
     108           2 :         KeySet * ks = ksNew (0, KS_END);
     109           2 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     110           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     111             : 
     112           2 :         keyDel (parentKey);
     113           2 :         ksDel (ks);
     114           2 :         PLUGIN_CLOSE ();
     115           2 : }
     116             : 
     117           4 : static void test_mmap_get_set (const char * tmpFile)
     118             : {
     119           4 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     120           4 :         KeySet * conf = ksNew (0, KS_END);
     121           4 :         PLUGIN_OPEN ("mmapstorage");
     122           4 :         KeySet * ks = ksNew (0, KS_END);
     123             : 
     124           4 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     125           4 :         ksDel (ks);
     126           4 :         ks = simpleTestKeySet ();
     127           4 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     128           4 :         ksDel (ks);
     129           4 :         ks = ksNew (0, KS_END);
     130           4 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     131             : 
     132           4 :         KeySet * expected = simpleTestKeySet ();
     133           4 :         compare_keyset (expected, ks);
     134           4 :         compare_keyset (ks, expected);
     135             : 
     136           4 :         ksDel (expected);
     137           4 :         keyDel (parentKey);
     138           4 :         ksDel (ks);
     139           4 :         PLUGIN_CLOSE ();
     140           4 : }
     141             : 
     142           2 : static void test_mmap_set_get_global (const char * tmpFile)
     143             : {
     144           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     145           2 :         KeySet * conf = ksNew (0, KS_END);
     146           2 :         PLUGIN_OPEN ("mmapstorage");
     147           2 :         KeySet * ks = ksNew (0, KS_END);
     148             : 
     149           2 :         plugin->global = 0;
     150           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     151             : 
     152           2 :         plugin->global = ksNew (0, KS_END);
     153           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     154           2 :         ksDel (ks);
     155           2 :         ksDel (plugin->global);
     156             : 
     157           2 :         ks = metaTestKeySet ();
     158           2 :         plugin->global = simpleTestKeySet ();
     159           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     160           2 :         ksDel (ks);
     161           2 :         ksDel (plugin->global);
     162             : 
     163           2 :         plugin->global = ksNew (0, KS_END);
     164           2 :         ks = ksNew (0, KS_END);
     165           2 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     166             : 
     167           2 :         KeySet * expected = simpleTestKeySet ();
     168           2 :         compare_keyset (expected, plugin->global);
     169           2 :         compare_keyset (plugin->global, expected);
     170             : 
     171           2 :         ksDel (plugin->global);
     172           2 :         ksDel (expected);
     173           2 :         keyDel (parentKey);
     174           2 :         ksDel (ks);
     175           2 :         PLUGIN_CLOSE ();
     176           2 : }
     177             : 
     178           2 : static void test_mmap_get_global_after_reopen (const char * tmpFile)
     179             : {
     180           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     181           2 :         KeySet * conf = ksNew (0, KS_END);
     182           2 :         PLUGIN_OPEN ("mmapstorage");
     183           2 :         KeySet * ks = ksNew (0, KS_END);
     184           2 :         plugin->global = ksNew (0, KS_END);
     185             : 
     186           2 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     187             : 
     188           2 :         KeySet * expected_global = simpleTestKeySet ();
     189           2 :         compare_keyset (expected_global, plugin->global);
     190           2 :         compare_keyset (plugin->global, expected_global);
     191             : 
     192           2 :         KeySet * expected = metaTestKeySet ();
     193           2 :         compare_keyset (expected, ks);
     194           2 :         compare_keyset (ks, expected);
     195             : 
     196           2 :         ksDel (expected_global);
     197           2 :         ksDel (plugin->global);
     198           2 :         ksDel (expected);
     199           2 :         keyDel (parentKey);
     200           2 :         ksDel (ks);
     201           2 :         PLUGIN_CLOSE ();
     202           2 : }
     203             : 
     204           2 : static void test_mmap_set_get_global_metadata (const char * tmpFile)
     205             : {
     206           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     207           2 :         KeySet * conf = ksNew (0, KS_END);
     208           2 :         PLUGIN_OPEN ("mmapstorage");
     209             : 
     210           2 :         KeySet * ks = metaTestKeySet ();
     211           2 :         plugin->global = otherMetaTestKeySet ();
     212           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     213           2 :         ksDel (ks);
     214           2 :         ksDel (plugin->global);
     215             : 
     216           2 :         plugin->global = ksNew (0, KS_END);
     217           2 :         ks = ksNew (0, KS_END);
     218           2 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     219             : 
     220           2 :         KeySet * expected_global = otherMetaTestKeySet ();
     221           2 :         compare_keyset (expected_global, plugin->global);
     222           2 :         compare_keyset (plugin->global, expected_global);
     223           2 :         ksDel (expected_global);
     224             : 
     225           2 :         KeySet * expected = metaTestKeySet ();
     226           2 :         compare_keyset (expected, ks);
     227           2 :         compare_keyset (ks, expected);
     228           2 :         ksDel (expected);
     229             : 
     230           2 :         ksDel (plugin->global);
     231           2 :         keyDel (parentKey);
     232           2 :         ksDel (ks);
     233           2 :         PLUGIN_CLOSE ();
     234           2 : }
     235             : 
     236           2 : static void test_mmap_truncated_file (const char * tmpFile)
     237             : {
     238             :         // first write a mmap file
     239             :         {
     240           2 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     241           2 :                 KeySet * conf = ksNew (0, KS_END);
     242           2 :                 PLUGIN_OPEN ("mmapstorage");
     243             : 
     244           2 :                 KeySet * ks = simpleTestKeySet ();
     245           2 :                 succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     246             : 
     247           2 :                 keyDel (parentKey);
     248           2 :                 ksDel (ks);
     249           2 :                 PLUGIN_CLOSE ();
     250             :         }
     251             : 
     252             :         // now truncate the mmap file by the size of the mmap footer
     253             :         FILE * fp;
     254           2 :         if ((fp = fopen (tmpFile, "r+")) == 0)
     255             :         {
     256           0 :                 yield_error ("error opening file");
     257             :         }
     258             :         struct stat sbuf;
     259           2 :         if (stat (tmpFile, &sbuf) == -1)
     260             :         {
     261           0 :                 yield_error ("stat error");
     262             :         }
     263             : 
     264           2 :         int fd = fileno (fp);
     265           2 :         if ((ftruncate (fd, sbuf.st_size - sizeof (MmapFooter))) == -1)
     266             :         {
     267           0 :                 yield_error ("ftruncate error");
     268             :         }
     269           2 :         if (fp)
     270             :         {
     271           2 :                 fclose (fp);
     272             :         }
     273             : 
     274             :         // truncated file should be detected by mmapstorage
     275             :         {
     276             :                 // after the file was truncated, we expect an error here
     277           2 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     278           2 :                 KeySet * conf = ksNew (0, KS_END);
     279           2 :                 PLUGIN_OPEN ("mmapstorage");
     280             : 
     281           2 :                 KeySet * ks = ksNew (0, KS_END);
     282           2 :                 succeed_if (plugin->kdbGet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR, "kdbGet did not detect truncated file");
     283             : 
     284           2 :                 keyDel (parentKey);
     285           2 :                 ksDel (ks);
     286           2 :                 PLUGIN_CLOSE ();
     287             :         }
     288           2 : }
     289             : 
     290           2 : static void test_mmap_wrong_magic_number (const char * tmpFile)
     291             : {
     292             :         // first write a mmap file
     293             :         {
     294           2 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     295           2 :                 KeySet * conf = ksNew (0, KS_END);
     296           2 :                 PLUGIN_OPEN ("mmapstorage");
     297             : 
     298           2 :                 KeySet * ks = simpleTestKeySet ();
     299           2 :                 succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     300             : 
     301           2 :                 keyDel (parentKey);
     302           2 :                 ksDel (ks);
     303           2 :                 PLUGIN_CLOSE ();
     304             :         }
     305             : 
     306             :         // now manipulate magic number inside the mmap header
     307             :         FILE * fp;
     308           2 :         if ((fp = fopen (tmpFile, "r+")) == 0)
     309             :         {
     310           0 :                 yield_error ("fopen() error");
     311             :         }
     312             :         struct stat sbuf;
     313           2 :         if (stat (tmpFile, &sbuf) == -1)
     314             :         {
     315           0 :                 yield_error ("stat() error");
     316             :         }
     317             : 
     318           2 :         int fd = fileno (fp);
     319           2 :         char * mappedRegion = mmap (0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     320           2 :         if (mappedRegion == MAP_FAILED)
     321             :         {
     322             :                 ELEKTRA_LOG_WARNING ("error mapping file %s\nmmapSize: " ELEKTRA_STAT_ST_SIZE_F, tmpFile, sbuf.st_size);
     323           0 :                 yield_error ("mmap() error");
     324           0 :                 return;
     325             :         }
     326           2 :         if (fp)
     327             :         {
     328           2 :                 fclose (fp);
     329             :         }
     330             : 
     331           2 :         MmapHeader * mmapHeader = (MmapHeader *) mappedRegion;
     332           2 :         mmapHeader->mmapMagicNumber = ELEKTRA_MAGIC_MMAP_NUMBER - 1;
     333             : 
     334           2 :         if (msync ((void *) mappedRegion, sbuf.st_size, MS_SYNC) != 0)
     335             :         {
     336           0 :                 yield_error ("msync() error");
     337           0 :                 return;
     338             :         }
     339             : 
     340           2 :         if (munmap (mappedRegion, sbuf.st_size) != 0)
     341             :         {
     342           0 :                 yield_error ("munmap() error");
     343           0 :                 return;
     344             :         }
     345             : 
     346             :         // manipulated magic number should be detected now
     347             :         {
     348             :                 // we expect an error here
     349           2 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     350           2 :                 KeySet * conf = ksNew (0, KS_END);
     351           2 :                 PLUGIN_OPEN ("mmapstorage");
     352             : 
     353           2 :                 KeySet * ks = ksNew (0, KS_END);
     354           2 :                 succeed_if (plugin->kdbGet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR,
     355             :                             "kdbGet did not detect wrong magic number");
     356             : 
     357           2 :                 keyDel (parentKey);
     358           2 :                 ksDel (ks);
     359           2 :                 PLUGIN_CLOSE ();
     360             :         }
     361             : }
     362             : 
     363           2 : static void test_mmap_wrong_format_version (const char * tmpFile)
     364             : {
     365             :         // first write a mmap file
     366             :         {
     367           2 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     368           2 :                 KeySet * conf = ksNew (0, KS_END);
     369           2 :                 PLUGIN_OPEN ("mmapstorage");
     370             : 
     371           2 :                 KeySet * ks = simpleTestKeySet ();
     372           2 :                 succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     373             : 
     374           2 :                 keyDel (parentKey);
     375           2 :                 ksDel (ks);
     376           2 :                 PLUGIN_CLOSE ();
     377             :         }
     378             : 
     379             :         // set wrong version number in mmap header
     380             :         FILE * fp;
     381           2 :         if ((fp = fopen (tmpFile, "r+")) == 0)
     382             :         {
     383           0 :                 yield_error ("fopen() error");
     384             :         }
     385             :         struct stat sbuf;
     386           2 :         if (stat (tmpFile, &sbuf) == -1)
     387             :         {
     388           0 :                 yield_error ("stat() error");
     389             :         }
     390             : 
     391           2 :         int fd = fileno (fp);
     392           2 :         char * mappedRegion = mmap (0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     393           2 :         if (mappedRegion == MAP_FAILED)
     394             :         {
     395             :                 ELEKTRA_LOG_WARNING ("error mapping file %s\nmmapSize: " ELEKTRA_STAT_ST_SIZE_F, tmpFile, sbuf.st_size);
     396           0 :                 yield_error ("mmap() error");
     397           0 :                 return;
     398             :         }
     399           2 :         if (fp)
     400             :         {
     401           2 :                 fclose (fp);
     402             :         }
     403             : 
     404           2 :         MmapHeader * mmapHeader = (MmapHeader *) mappedRegion;
     405           2 :         mmapHeader->formatVersion = ELEKTRA_MMAP_FORMAT_VERSION + 1;
     406             : 
     407           2 :         if (msync ((void *) mappedRegion, sbuf.st_size, MS_SYNC) != 0)
     408             :         {
     409           0 :                 yield_error ("msync() error");
     410           0 :                 return;
     411             :         }
     412             : 
     413           2 :         if (munmap (mappedRegion, sbuf.st_size) != 0)
     414             :         {
     415           0 :                 yield_error ("munmap() error");
     416           0 :                 return;
     417             :         }
     418             : 
     419             :         // wrong format version should be detected now
     420             :         {
     421             :                 // we expect an error here
     422           2 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     423           2 :                 KeySet * conf = ksNew (0, KS_END);
     424           2 :                 PLUGIN_OPEN ("mmapstorage");
     425             : 
     426           2 :                 KeySet * ks = ksNew (0, KS_END);
     427           2 :                 succeed_if (plugin->kdbGet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR,
     428             :                             "kdbGet did not detect wrong format version");
     429             : 
     430           2 :                 keyDel (parentKey);
     431           2 :                 ksDel (ks);
     432           2 :                 PLUGIN_CLOSE ();
     433             :         }
     434             : }
     435             : 
     436           2 : static void test_mmap_wrong_magic_keyset (const char * tmpFile)
     437             : {
     438             :         // first write a mmap file
     439             :         {
     440           2 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     441           2 :                 KeySet * conf = ksNew (0, KS_END);
     442           2 :                 PLUGIN_OPEN ("mmapstorage");
     443             : 
     444           2 :                 KeySet * ks = simpleTestKeySet ();
     445           2 :                 succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     446             : 
     447           2 :                 keyDel (parentKey);
     448           2 :                 ksDel (ks);
     449           2 :                 PLUGIN_CLOSE ();
     450             :         }
     451             : 
     452             :         // now manipulate magic keyset inside the mapped region
     453             :         FILE * fp;
     454           2 :         if ((fp = fopen (tmpFile, "r+")) == 0)
     455             :         {
     456           0 :                 yield_error ("fopen() error");
     457             :         }
     458             :         struct stat sbuf;
     459           2 :         if (stat (tmpFile, &sbuf) == -1)
     460             :         {
     461           0 :                 yield_error ("stat() error");
     462             :         }
     463             : 
     464           2 :         int fd = fileno (fp);
     465           2 :         char * mappedRegion = mmap (0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     466           2 :         if (mappedRegion == MAP_FAILED)
     467             :         {
     468             :                 ELEKTRA_LOG_WARNING ("error mapping file %s\nmmapSize: " ELEKTRA_STAT_ST_SIZE_F, tmpFile, sbuf.st_size);
     469           0 :                 yield_error ("mmap() error");
     470           0 :                 return;
     471             :         }
     472           2 :         if (fp)
     473             :         {
     474           2 :                 fclose (fp);
     475             :         }
     476             : 
     477           2 :         KeySet * magicKs = (KeySet *) (mappedRegion + sizeof (MmapHeader));
     478           2 :         magicKs->size = 1234; // magic keyset contains SIZE_MAX here
     479             : 
     480           2 :         if (msync ((void *) mappedRegion, sbuf.st_size, MS_SYNC) != 0)
     481             :         {
     482           0 :                 yield_error ("msync() error");
     483           0 :                 return;
     484             :         }
     485             : 
     486           2 :         if (munmap (mappedRegion, sbuf.st_size) != 0)
     487             :         {
     488           0 :                 yield_error ("munmap() error");
     489           0 :                 return;
     490             :         }
     491             : 
     492             :         // manipulated magic keyset should be detected now
     493             :         {
     494             :                 // we expect an error here
     495           2 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     496           2 :                 KeySet * conf = ksNew (0, KS_END);
     497           2 :                 PLUGIN_OPEN ("mmapstorage");
     498             : 
     499           2 :                 KeySet * ks = ksNew (0, KS_END);
     500           2 :                 succeed_if (plugin->kdbGet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR,
     501             :                             "kdbGet did not detect wrong magic keyset");
     502             : 
     503           2 :                 keyDel (parentKey);
     504           2 :                 ksDel (ks);
     505           2 :                 PLUGIN_CLOSE ();
     506             :         }
     507             : }
     508             : 
     509           2 : static void test_mmap_set_get (const char * tmpFile)
     510             : {
     511           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     512           2 :         KeySet * conf = ksNew (0, KS_END);
     513           2 :         PLUGIN_OPEN ("mmapstorage");
     514           2 :         KeySet * ks = simpleTestKeySet ();
     515             : 
     516           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     517             : 
     518           2 :         KeySet * returned = ksNew (0, KS_END);
     519           2 :         succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful");
     520           2 :         KeySet * expected = simpleTestKeySet ();
     521           2 :         compare_keyset (expected, returned);
     522             : 
     523           2 :         ksDel (expected);
     524           2 :         ksDel (returned);
     525             : 
     526           2 :         keyDel (parentKey);
     527           2 :         ksDel (ks);
     528           2 :         PLUGIN_CLOSE ();
     529           2 : }
     530             : 
     531           2 : static void test_mmap_get_after_reopen (const char * tmpFile)
     532             : {
     533           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     534           2 :         KeySet * conf = ksNew (0, KS_END);
     535           2 :         PLUGIN_OPEN ("mmapstorage");
     536           2 :         KeySet * returned = ksNew (0, KS_END);
     537             : 
     538           2 :         succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful");
     539             : 
     540           2 :         KeySet * expected = simpleTestKeySet ();
     541           2 :         compare_keyset (expected, returned);
     542           2 :         ksDel (expected);
     543           2 :         ksDel (returned);
     544             : 
     545           2 :         keyDel (parentKey);
     546           2 :         PLUGIN_CLOSE ();
     547           2 : }
     548             : 
     549           2 : static void test_mmap_set_get_large_keyset (const char * tmpFile)
     550             : {
     551           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     552           2 :         KeySet * conf = ksNew (0, KS_END);
     553           2 :         PLUGIN_OPEN ("mmapstorage");
     554           2 :         KeySet * ks = largeTestKeySet ();
     555           2 :         KeySet * expected = ksDeepDup (ks);
     556             : 
     557           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     558           2 :         ksDel (ks);
     559             : 
     560           2 :         KeySet * returned = ksNew (0, KS_END);
     561           2 :         succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful");
     562             : 
     563           2 :         compare_keyset (expected, returned);
     564             : 
     565           2 :         ksDel (expected);
     566           2 :         ksDel (returned);
     567             : 
     568           2 :         keyDel (parentKey);
     569           2 :         PLUGIN_CLOSE ();
     570           2 : }
     571             : 
     572           2 : static void test_mmap_ks_copy (const char * tmpFile)
     573             : {
     574           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     575           2 :         KeySet * conf = ksNew (0, KS_END);
     576           2 :         PLUGIN_OPEN ("mmapstorage");
     577           2 :         KeySet * returned = simpleTestKeySet ();
     578             : 
     579           2 :         succeed_if (plugin->kdbSet (plugin, returned, parentKey) == 1, "kdbGet was not successful");
     580           2 :         ksDel (returned);
     581             : 
     582           2 :         returned = ksNew (0, KS_END);
     583           2 :         succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful");
     584             : 
     585           2 :         KeySet * expected = simpleTestKeySet ();
     586           2 :         compare_keyset (expected, returned);
     587             : 
     588           2 :         KeySet * copiedKs = ksNew (0, KS_END);
     589           2 :         ksCopy (copiedKs, returned);
     590           2 :         compare_keyset (expected, copiedKs);
     591             : 
     592           2 :         ksDel (copiedKs);
     593           2 :         ksDel (expected);
     594           2 :         ksDel (returned);
     595             : 
     596           2 :         keyDel (parentKey);
     597           2 :         PLUGIN_CLOSE ();
     598           2 : }
     599             : 
     600           2 : static void test_mmap_empty_after_clear (const char * tmpFile)
     601             : {
     602           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     603           2 :         KeySet * conf = ksNew (0, KS_END);
     604           2 :         PLUGIN_OPEN ("mmapstorage");
     605           2 :         KeySet * returned = ksNew (0, KS_END);
     606             : 
     607           2 :         succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful");
     608             : 
     609           2 :         succeed_if (ksGetSize (returned) == 0, "KeySet not empty after clear (or nullptr)");
     610             : 
     611           2 :         ksDel (returned);
     612           2 :         keyDel (parentKey);
     613           2 :         PLUGIN_CLOSE ();
     614           2 : }
     615             : 
     616           2 : static void test_mmap_meta (const char * tmpFile)
     617             : {
     618           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     619           2 :         KeySet * conf = ksNew (0, KS_END);
     620           2 :         PLUGIN_OPEN ("mmapstorage");
     621           2 :         KeySet * ks = metaTestKeySet ();
     622             : 
     623           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     624             : 
     625           2 :         KeySet * returned = ksNew (0, KS_END);
     626           2 :         succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful");
     627             : 
     628           2 :         KeySet * expected = metaTestKeySet ();
     629           2 :         compare_keyset (expected, returned);
     630             : 
     631           2 :         ksDel (expected);
     632           2 :         ksDel (returned);
     633             : 
     634           2 :         keyDel (parentKey);
     635           2 :         ksDel (ks);
     636           2 :         PLUGIN_CLOSE ();
     637           2 : }
     638             : 
     639           2 : static void test_mmap_meta_get_after_reopen (const char * tmpFile)
     640             : {
     641           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     642           2 :         KeySet * conf = ksNew (0, KS_END);
     643           2 :         PLUGIN_OPEN ("mmapstorage");
     644           2 :         KeySet * ks = ksNew (0, KS_END);
     645             : 
     646           2 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     647             : 
     648           2 :         KeySet * expected = metaTestKeySet ();
     649           2 :         compare_keyset (expected, ks);
     650             : 
     651           2 :         ksDel (expected);
     652           2 :         keyDel (parentKey);
     653           2 :         ksDel (ks);
     654           2 :         PLUGIN_CLOSE ();
     655           2 : }
     656             : 
     657           2 : static void test_mmap_metacopy (const char * tmpFile)
     658             : {
     659           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     660           2 :         KeySet * conf = ksNew (0, KS_END);
     661           2 :         PLUGIN_OPEN ("mmapstorage");
     662           2 :         KeySet * ks = metaTestKeySet ();
     663             : 
     664           2 :         Key * shareMeta = keyNew (0);
     665           2 :         keySetMeta (shareMeta, "sharedmeta", "shared meta key test");
     666             : 
     667             :         Key * current;
     668           2 :         ksRewind (ks);
     669          10 :         while ((current = ksNext (ks)) != 0)
     670             :         {
     671           6 :                 keyCopyMeta (current, shareMeta, "sharedmeta");
     672             :         }
     673           2 :         KeySet * expected = ksDeepDup (ks);
     674             : 
     675             : 
     676           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     677             : 
     678           2 :         KeySet * returned = ksNew (0, KS_END);
     679           2 :         succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful");
     680             : 
     681             : 
     682           2 :         compare_keyset (expected, returned);
     683             : 
     684           2 :         ksDel (expected);
     685           2 :         ksDel (returned);
     686             : 
     687           2 :         keyDel (parentKey);
     688           2 :         keyDel (shareMeta);
     689           2 :         ksDel (ks);
     690           2 :         PLUGIN_CLOSE ();
     691           2 : }
     692             : 
     693           2 : static void test_mmap_ks_copy_with_meta (const char * tmpFile)
     694             : {
     695           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     696           2 :         KeySet * conf = ksNew (0, KS_END);
     697           2 :         PLUGIN_OPEN ("mmapstorage");
     698           2 :         KeySet * ks = metaTestKeySet ();
     699           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     700           2 :         ksDel (ks);
     701             : 
     702           2 :         KeySet * returned = ksNew (0, KS_END);
     703             : 
     704           2 :         succeed_if (plugin->kdbGet (plugin, returned, parentKey) == 1, "kdbGet was not successful");
     705             : 
     706           2 :         KeySet * expected = metaTestKeySet ();
     707           2 :         compare_keyset (expected, returned);
     708             : 
     709           2 :         KeySet * copiedKs = ksNew (0, KS_END);
     710           2 :         ksCopy (copiedKs, returned);
     711           2 :         compare_keyset (expected, copiedKs);
     712             : 
     713           2 :         ksDel (copiedKs);
     714           2 :         ksDel (expected);
     715           2 :         ksDel (returned);
     716             : 
     717           2 :         keyDel (parentKey);
     718           2 :         PLUGIN_CLOSE ();
     719           2 : }
     720             : 
     721           2 : static void test_mmap_opmphm (const char * tmpFile)
     722             : {
     723           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     724           2 :         KeySet * conf = ksNew (0, KS_END);
     725           2 :         PLUGIN_OPEN ("mmapstorage");
     726           2 :         KeySet * ks = largeTestKeySet ();
     727             : 
     728           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     729           2 :         ksDel (ks);
     730             : 
     731           2 :         ks = ksNew (0, KS_END);
     732           2 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     733             : 
     734           2 :         const char * name = "user/tests/mmapstorage/dir7/key3";
     735           2 :         Key * found = ksLookupByName (ks, name, KDB_O_OPMPHM);
     736             : 
     737           2 :         if (!found)
     738             :         {
     739           0 :                 yield_error ("Key not found.")
     740             :         }
     741             : 
     742             :         // write keyset with OPMPHM structures
     743           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     744             : 
     745           2 :         ksDel (ks);
     746           2 :         keyDel (parentKey);
     747           2 :         PLUGIN_CLOSE ();
     748           2 : }
     749             : 
     750           4 : static void test_mmap_ksDupFun (const char * tmpFile, KeySet * copyFunction (const KeySet * source))
     751             : {
     752           4 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     753           4 :         KeySet * conf = ksNew (0, KS_END);
     754           4 :         PLUGIN_OPEN ("mmapstorage");
     755             : 
     756           4 :         KeySet * ks = simpleTestKeySet ();
     757           4 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     758           4 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     759           4 :         succeed_if ((ks->flags & KS_FLAG_MMAP_ARRAY) == KS_FLAG_MMAP_ARRAY, "KeySet array not in mmap");
     760             : 
     761           4 :         KeySet * dupKs = copyFunction (ks);
     762           4 :         compare_keyset (dupKs, ks);
     763           4 :         compare_keyset (ks, dupKs);
     764             : 
     765           4 :         ksDel (dupKs);
     766           4 :         keyDel (parentKey);
     767           4 :         ksDel (ks);
     768           4 :         PLUGIN_CLOSE ();
     769           4 : }
     770             : 
     771           2 : static void test_mmap_ksCopy (const char * tmpFile)
     772             : {
     773           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     774           2 :         KeySet * conf = ksNew (0, KS_END);
     775           2 :         PLUGIN_OPEN ("mmapstorage");
     776             : 
     777           2 :         KeySet * ks = simpleTestKeySet ();
     778           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     779           2 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     780           2 :         succeed_if ((ks->flags & KS_FLAG_MMAP_ARRAY) == KS_FLAG_MMAP_ARRAY, "KeySet array not in mmap");
     781             : 
     782           2 :         KeySet * copyKs = ksNew (0, KS_END);
     783           2 :         if (ksCopy (copyKs, ks) == 1)
     784             :         {
     785           2 :                 compare_keyset (copyKs, ks);
     786           2 :                 compare_keyset (ks, copyKs);
     787             :         }
     788             :         else
     789             :         {
     790           0 :                 yield_error ("ksCopy failed");
     791             :         }
     792             : 
     793           2 :         ksDel (copyKs);
     794           2 :         keyDel (parentKey);
     795           2 :         ksDel (ks);
     796           2 :         PLUGIN_CLOSE ();
     797           2 : }
     798             : 
     799           2 : static void test_mmap_open_pipe (void)
     800             : {
     801             :         // try writing to a non-regular file, we simply use a pipe here
     802             :         int pipefd[2];
     803           2 :         if (pipe (pipefd) != 0)
     804             :         {
     805           0 :                 yield_error ("pipe() error");
     806             :         }
     807             :         char pipeFile[1024];
     808           2 :         snprintf (pipeFile, 1024, "/dev/fd/%d", pipefd[1]);
     809           2 :         pipeFile[1023] = '\0';
     810             : 
     811           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, pipeFile, KEY_END);
     812           2 :         KeySet * conf = ksNew (0, KS_END);
     813           2 :         PLUGIN_OPEN ("mmapstorage");
     814             : 
     815           2 :         KeySet * ks = simpleTestKeySet ();
     816           2 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR, "kdbSet could write to pipe, but should not");
     817             : 
     818           2 :         keyDel (parentKey);
     819           2 :         ksDel (ks);
     820           2 :         PLUGIN_CLOSE ();
     821           2 : }
     822             : 
     823           2 : static void test_mmap_bad_file_permissions (const char * tmpFile)
     824             : {
     825             :         // try writing to a file with bad permissions
     826           2 :         if (getuid () == 0 || geteuid () == 0)
     827             :         {
     828           0 :                 printf ("Skipping file permission test for root.\n");
     829           0 :                 return;
     830             :         }
     831             : 
     832           2 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     833           2 :         KeySet * conf = ksNew (0, KS_END);
     834           2 :         PLUGIN_OPEN ("mmapstorage");
     835           2 :         KeySet * ks = ksNew (0, KS_END);
     836             : 
     837             :         FILE * fp;
     838           2 :         if ((fp = fopen (tmpFile, "r+")) == 0)
     839             :         {
     840           0 :                 yield_error ("error opening file");
     841             :         }
     842             : 
     843             :         struct stat sbuf;
     844           2 :         if (stat (tmpFile, &sbuf) == -1)
     845             :         {
     846           0 :                 yield_error ("stat() error");
     847             :         }
     848           2 :         fclose (fp);
     849             : 
     850           2 :         if (chmod (tmpFile, 0) != 0)
     851             :         {
     852           0 :                 yield_error ("chmod() failed");
     853             :         }
     854             : 
     855             :         // open() call should fail because file permissions were wrong
     856           2 :         succeed_if (plugin->kdbGet (plugin, ks, parentKey) == ELEKTRA_PLUGIN_STATUS_ERROR, "kdbGet did not detect bad file permissions");
     857             : 
     858           2 :         if (chmod (tmpFile, sbuf.st_mode) != 0)
     859             :         {
     860           0 :                 yield_error ("chmod() failed");
     861             :         }
     862             : 
     863           2 :         keyDel (parentKey);
     864           2 :         ksDel (ks);
     865           2 :         PLUGIN_CLOSE ();
     866             : }
     867             : 
     868           2 : static void test_mmap_unlink (const char * tmpFile)
     869             : {
     870             :         // test file unlinking by overwriting config file while mapped
     871             :         int parentPipe[2];
     872             :         int childPipe[2];
     873           2 :         if (pipe (parentPipe) != 0 || pipe (childPipe) != 0)
     874             :         {
     875           0 :                 yield_error ("pipe() error");
     876             :         }
     877             : 
     878             :         pid_t pid;
     879             :         char buf;
     880           2 :         pid = fork ();
     881             : 
     882           2 :         if (pid == -1)
     883             :         {
     884           0 :                 yield_error ("fork() error");
     885           0 :                 return;
     886             :         }
     887           2 :         else if (pid == 0)
     888             :         {
     889             :                 // child: open a config file and leave it mapped
     890           0 :                 int devnull = open ("/dev/null", O_RDWR);
     891           0 :                 if (devnull == -1) _Exit (EXIT_FAILURE);
     892             : 
     893             :                 // redirect any communication on standard file descriptors to /dev/null
     894           0 :                 close (STDIN_FILENO);
     895           0 :                 close (STDOUT_FILENO);
     896           0 :                 close (STDERR_FILENO);
     897           0 :                 if (dup (devnull) == -1) _Exit (EXIT_FAILURE);
     898           0 :                 if (dup (devnull) == -1) _Exit (EXIT_FAILURE);
     899           0 :                 if (dup (devnull) == -1) _Exit (EXIT_FAILURE);
     900           0 :                 close (childPipe[0]);
     901           0 :                 close (parentPipe[1]);
     902             : 
     903           0 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     904           0 :                 KeySet * conf = ksNew (0, KS_END);
     905           0 :                 PLUGIN_OPEN ("mmapstorage");
     906             : 
     907           0 :                 KeySet * ks = simpleTestKeySet ();
     908           0 :                 succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     909           0 :                 succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful");
     910             : 
     911           0 :                 if (write (childPipe[1], "a", 1) != 1) _Exit (EXIT_FAILURE); // signal parent that we are ready
     912           0 :                 close (childPipe[1]);
     913           0 :                 if (read (parentPipe[0], &buf, 1) != 1) _Exit (EXIT_FAILURE); // wait for parent
     914           0 :                 close (parentPipe[0]);
     915             : 
     916           0 :                 KeySet * expected = simpleTestKeySet ();
     917           0 :                 compare_keyset (expected, ks);
     918           0 :                 compare_keyset (ks, expected);
     919           0 :                 ksDel (expected);
     920           0 :                 keyDel (parentKey);
     921           0 :                 ksDel (ks);
     922           0 :                 PLUGIN_CLOSE ();
     923             : 
     924           0 :                 _Exit (EXIT_SUCCESS);
     925             :         }
     926             :         else
     927             :         {
     928             :                 // parent: try and destroy the file that the child has mapped
     929           2 :                 close (childPipe[1]);
     930           2 :                 close (parentPipe[0]);
     931           2 :                 if (read (childPipe[0], &buf, 1) != 1) _Exit (EXIT_FAILURE); // wait for child
     932           2 :                 close (childPipe[0]);
     933             : 
     934           2 :                 Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     935           2 :                 KeySet * conf = ksNew (0, KS_END);
     936           2 :                 PLUGIN_OPEN ("mmapstorage");
     937             : 
     938           2 :                 KeySet * ks = metaTestKeySet ();
     939           2 :                 succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     940           2 :                 if (write (parentPipe[1], "a", 1) != 1) _Exit (EXIT_FAILURE); // signal child that we are done
     941           2 :                 close (parentPipe[1]);
     942             : 
     943             :                 int status;
     944           2 :                 waitpid (pid, &status, 0);
     945           2 :                 if (status != 0) yield_error ("child process did not exit successfully.");
     946             : 
     947           2 :                 keyDel (parentKey);
     948           2 :                 ksDel (ks);
     949           2 :                 PLUGIN_CLOSE ();
     950             :         }
     951             : }
     952             : 
     953          20 : static void clearStorage (const char * tmpFile)
     954             : {
     955          20 :         Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END);
     956          20 :         KeySet * conf = ksNew (0, KS_END);
     957          20 :         PLUGIN_OPEN ("mmapstorage");
     958          20 :         KeySet * ks = ksNew (0, KS_END);
     959             : 
     960          20 :         succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful");
     961             : 
     962          20 :         keyDel (parentKey);
     963          20 :         ksDel (ks);
     964          20 :         PLUGIN_CLOSE ();
     965          20 : }
     966             : 
     967             : /* -- DynArray Tests -------------------------------------------------------------------------------------------------------------------- */
     968             : 
     969        1080 : static int cmpfunc (const void * a, const void * b)
     970             : {
     971        1080 :         return (*(int *) a - *(int *) b);
     972             : }
     973             : 
     974           2 : static void testDynArray (void)
     975             : {
     976           2 :         size_t testData[] = { 8466, 2651, 6624, 9575, 4628, 9361, 417,  8932, 4570, 343,  1866, 3135, 6617, 344,  9419, 2094, 5623,
     977             :                               4920, 2209, 8037, 8437, 7955, 5575, 8355, 1133, 6527, 8543, 3338, 1772, 2278, 7446, 8834, 7728, 665,
     978             :                               8519, 6079, 5060, 7429, 3843, 6923, 4073, 2245, 2784, 6620, 2887, 8497, 9360, 5752, 3195, 538,  1491,
     979             :                               8087, 8378, 5746, 4961, 5499, 8050, 2138, 1196, 1860, 4372, 6553, 4530, 8828, 4017, 9934, 3,    6274,
     980             :                               4405, 5021, 3416, 854,  4635, 9902, 5383, 7947, 5210, 8242, 1928, 3792, 7234, 759,  6571, 9514, 8451,
     981             :                               918,  9958, 1577, 96,   8644, 6815, 5584, 8585, 1252, 808,  5695, 910,  4157, 701,  77 };
     982             : 
     983           2 :         DynArray * dynArray = ELEKTRA_PLUGIN_FUNCTION (dynArrayNew) ();
     984             : 
     985         202 :         for (size_t i = 0; i < 100; ++i)
     986             :         {
     987         200 :                 ELEKTRA_PLUGIN_FUNCTION (dynArrayFindOrInsert) ((Key *) testData[i], dynArray);
     988             :         }
     989             : 
     990           2 :         qsort (testData, 100, sizeof (size_t), cmpfunc);
     991             : 
     992           2 :         int error = 0;
     993         202 :         for (size_t i = 0; i < 100; ++i)
     994             :         {
     995         200 :                 if (testData[i] != (size_t) dynArray->keyArray[i])
     996             :                 {
     997           0 :                         ++error;
     998             :                 }
     999             :         }
    1000             : 
    1001           2 :         succeed_if (error == 0, "dynArray does not sort array properly");
    1002             : 
    1003           2 :         ELEKTRA_PLUGIN_FUNCTION (dynArrayDelete) (dynArray);
    1004           2 : }
    1005             : 
    1006             : /* -- Main ------------------------------------------------------------------------------------------------------------------------------ */
    1007             : 
    1008           2 : int main (int argc, char ** argv)
    1009             : {
    1010           2 :         printf ("MMAPSTORAGE     TESTS\n");
    1011           2 :         printf ("==================\n\n");
    1012             : 
    1013           2 :         init (argc, argv);
    1014             : 
    1015           2 :         testDynArray ();
    1016             : 
    1017           2 :         const char * tmpFile = elektraFilename ();
    1018           2 :         printf ("%s\n", tmpFile);
    1019             : 
    1020             :         // call once before clearStorage, to test non existent file
    1021           2 :         test_mmap_get_set (tmpFile);
    1022             : 
    1023           2 :         test_mmap_set_get_global (tmpFile);
    1024           2 :         test_mmap_get_global_after_reopen (tmpFile);
    1025           2 :         test_mmap_set_get_global_metadata (tmpFile);
    1026             : 
    1027           2 :         clearStorage (tmpFile);
    1028           2 :         test_mmap_truncated_file (tmpFile);
    1029           2 :         test_mmap_wrong_magic_number (tmpFile);
    1030           2 :         test_mmap_wrong_format_version (tmpFile);
    1031           2 :         test_mmap_wrong_magic_keyset (tmpFile);
    1032             : 
    1033           2 :         clearStorage (tmpFile);
    1034           2 :         test_mmap_get_set_empty (tmpFile);
    1035             : 
    1036           2 :         clearStorage (tmpFile);
    1037           2 :         test_mmap_get_set (tmpFile);
    1038             : 
    1039           2 :         clearStorage (tmpFile);
    1040           2 :         test_mmap_set_get (tmpFile);
    1041           2 :         test_mmap_get_after_reopen (tmpFile);
    1042           2 :         test_mmap_set_get_large_keyset (tmpFile);
    1043           2 :         test_mmap_ks_copy (tmpFile);
    1044             : 
    1045           2 :         clearStorage (tmpFile);
    1046           2 :         test_mmap_empty_after_clear (tmpFile);
    1047             : 
    1048           2 :         test_mmap_meta (tmpFile);
    1049           2 :         test_mmap_meta_get_after_reopen (tmpFile);
    1050             : 
    1051           2 :         test_mmap_metacopy (tmpFile);
    1052             : 
    1053           2 :         clearStorage (tmpFile);
    1054           2 :         test_mmap_ks_copy_with_meta (tmpFile);
    1055             : 
    1056           2 :         clearStorage (tmpFile);
    1057           2 :         test_mmap_opmphm (tmpFile);
    1058             : 
    1059           2 :         clearStorage (tmpFile);
    1060           2 :         test_mmap_ksDupFun (tmpFile, ksDup);
    1061             : 
    1062           2 :         clearStorage (tmpFile);
    1063           2 :         test_mmap_ksDupFun (tmpFile, ksDeepDup);
    1064             : 
    1065           2 :         clearStorage (tmpFile);
    1066           2 :         test_mmap_ksCopy (tmpFile);
    1067             : 
    1068           2 :         test_mmap_open_pipe ();
    1069           2 :         test_mmap_bad_file_permissions (tmpFile);
    1070             : 
    1071           2 :         test_mmap_unlink (tmpFile);
    1072             : 
    1073           2 :         printf ("\ntestmod_mmapstorage RESULTS: %d test(s) done. %d error(s).\n", nbTest, nbError);
    1074             : 
    1075           2 :         return nbError;
    1076             : }

Generated by: LCOV version 1.13