LCOV - code coverage report
Current view: top level - src/plugins/dbus - testmod_dbus.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 228 0.0 %
Date: 2019-09-12 12:28:41 Functions: 0 12 0.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #include "dbus.h"
      10             : 
      11             : #include <stdio.h> // printf() & co
      12             : #include <time.h>  // time()
      13             : 
      14             : #include <tests.h>
      15             : #include <tests_plugin.h>
      16             : 
      17             : typedef struct
      18             : {
      19             :         char * lookupSignalName;
      20             :         char * receivedKeyName;
      21             : 
      22             :         DBusConnection * connection;
      23             :         int stop;
      24             : } TestContext;
      25             : 
      26             : #define TEST_TIMEOUT 1
      27             : #define TEST_DISPATCH_TIMEOUT 200
      28             : 
      29             : /** D-Bus bus type used by tests  */
      30             : DBusBusType testBusType;
      31             : 
      32             : /** key namespace to use for tests */
      33             : char * testKeyNamespace;
      34             : 
      35             : /**
      36             :  * @internal
      37             :  * Process D-Bus messages and check for expected message.
      38             :  *
      39             :  * @param  connection D-Bus connection
      40             :  * @param  message    received D-Bus message
      41             :  * @param  data       test context
      42             :  * @return            message handler result
      43             :  */
      44           0 : static DBusHandlerResult receiveMessageHandler (DBusConnection * connection ELEKTRA_UNUSED, DBusMessage * message, void * data)
      45             : {
      46           0 :         TestContext * context = (TestContext *) data;
      47             : 
      48           0 :         char * interface = "org.libelektra";
      49           0 :         if (dbus_message_is_signal (message, interface, context->lookupSignalName))
      50             :         {
      51             :                 char * keyName;
      52             :                 DBusError error;
      53           0 :                 dbus_error_init (&error);
      54             : 
      55             :                 // read key name from message
      56           0 :                 dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &keyName, DBUS_TYPE_INVALID);
      57           0 :                 if (dbus_error_is_set (&error))
      58             :                 {
      59             :                         ELEKTRA_LOG_WARNING ("Failed to read message: %s", error.message);
      60             :                 }
      61             :                 else
      62             :                 {
      63             :                         // Message received, stop dispatching
      64           0 :                         context->receivedKeyName = keyName;
      65           0 :                         context->stop = 1;
      66             :                 }
      67             : 
      68           0 :                 dbus_error_free (&error);
      69             :                 return DBUS_HANDLER_RESULT_HANDLED;
      70             :         }
      71             :         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
      72             : }
      73             : 
      74             : /**
      75             :  * @internal
      76             :  * Dispatch messages and declares timeout if dispatching is not stopped within
      77             :  * TEST_TIMEOUT.
      78             :  *
      79             :  * @param context test context
      80             :  */
      81           0 : static void runDispatch (TestContext * context)
      82             : {
      83             :         time_t now;
      84           0 :         time_t start = time (NULL);
      85           0 :         context->stop = 0;
      86           0 :         while (!context->stop && dbus_connection_read_write_dispatch (context->connection, TEST_DISPATCH_TIMEOUT))
      87             :         {
      88           0 :                 now = time (NULL);
      89             :                 // Stop dispatching after one second
      90           0 :                 if (now - start > TEST_TIMEOUT)
      91             :                 {
      92           0 :                         succeed_if (0, "timeout exceeded; test failed");
      93             :                         break;
      94             :                 }
      95             :         }
      96           0 : }
      97             : 
      98             : /**
      99             :  * @internal
     100             :  * Create new test context.
     101             :  *
     102             :  * @param  connection D-Bus connection
     103             :  * @param  signalName Expected signal name
     104             :  * @return            Context
     105             :  */
     106           0 : static TestContext * createTestContext (DBusConnection * connection, char * signalName)
     107             : {
     108           0 :         TestContext * context = elektraMalloc (sizeof *context);
     109           0 :         exit_if_fail (context, "malloc failed");
     110             : 
     111           0 :         context->lookupSignalName = signalName;
     112           0 :         context->connection = connection;
     113           0 :         context->receivedKeyName = "";
     114           0 :         return context;
     115             : }
     116             : 
     117             : /**
     118             :  * @internal
     119             :  * Get and setup D-Bus connection.
     120             :  *
     121             :  * @param  type D-Bus bus type
     122             :  * @return      D-Bus connection or NULL on error
     123             :  */
     124           0 : static DBusConnection * getDbusConnection (DBusBusType type)
     125             : {
     126             :         DBusError error;
     127           0 :         dbus_error_init (&error);
     128             : 
     129           0 :         DBusConnection * connection = dbus_bus_get (type, &error);
     130           0 :         if (connection == NULL)
     131             :         {
     132           0 :                 printf ("connect: Failed to open connection to %s message bus: %s\n", (type == DBUS_BUS_SYSTEM) ? "system" : "session",
     133             :                         error.message);
     134           0 :                 dbus_error_free (&error);
     135           0 :                 dbus_shutdown ();
     136           0 :                 return NULL;
     137             :         }
     138           0 :         dbus_error_free (&error);
     139             : 
     140           0 :         dbus_connection_set_exit_on_disconnect (connection, FALSE);
     141             : 
     142           0 :         return connection;
     143             : }
     144             : 
     145           0 : static int test_prerequisites (void)
     146             : {
     147           0 :         printf ("testing prerequisites\n");
     148           0 :         printf ("detecting available bus types - please ignore single error messages prefixed with \"connect:\"\n");
     149             : 
     150           0 :         DBusConnection * systemBus = getDbusConnection (DBUS_BUS_SYSTEM);
     151           0 :         DBusConnection * sessionBus = getDbusConnection (DBUS_BUS_SESSION);
     152             : 
     153           0 :         int success = 0;
     154           0 :         if (systemBus != NULL || sessionBus != NULL)
     155             :         {
     156             :                 // Set bus type for tests
     157             :                 // NOTE brew dbus on MacOs supports session by out of the box while session
     158             :                 // bus is not available without further configuration on Linux
     159           0 :                 if (systemBus)
     160             :                 {
     161           0 :                         testBusType = DBUS_BUS_SYSTEM;
     162           0 :                         testKeyNamespace = "system";
     163             :                 }
     164           0 :                 else if (sessionBus)
     165             :                 {
     166           0 :                         testBusType = DBUS_BUS_SESSION;
     167           0 :                         testKeyNamespace = "user";
     168             :                 }
     169             : 
     170             :                 success = 1;
     171             :         }
     172             : 
     173           0 :         if (systemBus) dbus_connection_unref (systemBus);
     174           0 :         if (sessionBus) dbus_connection_unref (sessionBus);
     175             : 
     176           0 :         return success;
     177             : }
     178             : 
     179           0 : static void test_keyAdded (void)
     180             : {
     181           0 :         printf ("test adding keys\n");
     182             : 
     183             :         // (namespace)/tests/foo
     184           0 :         Key * parentKey = keyNew (testKeyNamespace, KEY_END);
     185           0 :         keyAddName (parentKey, "tests/foo");
     186             : 
     187             :         // (namespace)/tests/foo/bar
     188           0 :         Key * toAdd = keyDup (parentKey);
     189           0 :         keyAddName (toAdd, "bar");
     190           0 :         keySetString (toAdd, "test");
     191             : 
     192           0 :         KeySet * ks = ksNew (0, KS_END);
     193             : 
     194           0 :         KeySet * conf = ksNew (0, KS_END);
     195           0 :         PLUGIN_OPEN ("dbus");
     196             : 
     197             :         // initial get to save current state
     198           0 :         plugin->kdbGet (plugin, ks, parentKey);
     199             : 
     200             :         // add key to keyset
     201           0 :         ksAppendKey (ks, toAdd);
     202             : 
     203           0 :         DBusConnection * connection = getDbusConnection (testBusType);
     204           0 :         TestContext * context = createTestContext (connection, "KeyAdded");
     205           0 :         elektraDbusSetupReceiveMessage (connection, receiveMessageHandler, (void *) context);
     206             : 
     207           0 :         plugin->kdbSet (plugin, ks, parentKey);
     208           0 :         runDispatch (context);
     209             : 
     210           0 :         succeed_if_same_string (keyName (toAdd), context->receivedKeyName);
     211             : 
     212           0 :         elektraFree (context);
     213           0 :         elektraDbusTeardownReceiveMessage (connection, receiveMessageHandler, (void *) context);
     214           0 :         dbus_connection_unref (connection);
     215           0 :         ksDel (ks);
     216           0 :         keyDel (parentKey);
     217           0 :         PLUGIN_CLOSE ();
     218           0 : }
     219             : 
     220           0 : static void test_keyChanged (void)
     221             : {
     222           0 :         printf ("test changing keys\n");
     223             : 
     224             :         // All keys created by keyNew have the KEY_FLAG_SYNC set and will be
     225             :         // detected as changed by the dbus plugin
     226             :         // This flag is only cleared after kdbSet or when keys come from a backend.
     227             : 
     228             :         // (namespace)/tests/foo
     229           0 :         Key * parentKey = keyNew (testKeyNamespace, KEY_END);
     230           0 :         keyAddName (parentKey, "tests/foo");
     231             : 
     232             :         // (namespace)/tests/foo/bar
     233           0 :         Key * toChange = keyDup (parentKey);
     234           0 :         keyAddName (toChange, "bar");
     235           0 :         keySetString (toChange, "test");
     236             : 
     237           0 :         KeySet * ks = ksNew (2, toChange, KS_END);
     238             : 
     239           0 :         KeySet * conf = ksNew (0, KS_END);
     240           0 :         PLUGIN_OPEN ("dbus");
     241             : 
     242             :         // initial get to save current state
     243           0 :         plugin->kdbGet (plugin, ks, parentKey);
     244             : 
     245             :         // change key in keyset
     246           0 :         keySetString (toChange, "new value");
     247             : 
     248           0 :         DBusConnection * connection = getDbusConnection (testBusType);
     249           0 :         TestContext * context = createTestContext (connection, "KeyChanged");
     250           0 :         elektraDbusSetupReceiveMessage (connection, receiveMessageHandler, (void *) context);
     251             : 
     252           0 :         plugin->kdbSet (plugin, ks, parentKey);
     253           0 :         runDispatch (context);
     254             : 
     255           0 :         succeed_if_same_string (keyName (toChange), context->receivedKeyName);
     256             : 
     257           0 :         elektraFree (context);
     258           0 :         elektraDbusTeardownReceiveMessage (connection, receiveMessageHandler, (void *) context);
     259           0 :         dbus_connection_unref (connection);
     260           0 :         ksDel (ks);
     261           0 :         keyDel (parentKey);
     262           0 :         PLUGIN_CLOSE ();
     263           0 : }
     264             : 
     265           0 : static void test_keyDeleted (void)
     266             : {
     267           0 :         printf ("test deleting keys\n");
     268             : 
     269             :         // (namespace)/tests/foo
     270           0 :         Key * parentKey = keyNew (testKeyNamespace, KEY_END);
     271           0 :         keyAddName (parentKey, "tests/foo");
     272             : 
     273             :         // (namespace)/tests/foo/bar
     274           0 :         Key * toDelete = keyDup (parentKey);
     275           0 :         keyAddName (toDelete, "bar");
     276           0 :         keySetString (toDelete, "test");
     277             : 
     278           0 :         KeySet * ks = ksNew (1, keyDup (toDelete), KS_END);
     279             : 
     280           0 :         KeySet * conf = ksNew (0, KS_END);
     281           0 :         PLUGIN_OPEN ("dbus");
     282             : 
     283             :         // initial get to save current state
     284           0 :         plugin->kdbGet (plugin, ks, parentKey);
     285             : 
     286             :         // remove key from keyset
     287           0 :         Key * deleted = ksLookup (ks, toDelete, KDB_O_POP);
     288           0 :         succeed_if (deleted != NULL, "key was not found");
     289             : 
     290           0 :         DBusConnection * connection = getDbusConnection (testBusType);
     291           0 :         TestContext * context = createTestContext (connection, "KeyDeleted");
     292           0 :         elektraDbusSetupReceiveMessage (connection, receiveMessageHandler, (void *) context);
     293             : 
     294           0 :         plugin->kdbSet (plugin, ks, parentKey);
     295           0 :         runDispatch (context);
     296             : 
     297           0 :         succeed_if_same_string (keyName (toDelete), context->receivedKeyName);
     298             : 
     299           0 :         elektraFree (context);
     300           0 :         elektraDbusTeardownReceiveMessage (connection, receiveMessageHandler, (void *) context);
     301           0 :         dbus_connection_unref (connection);
     302           0 :         keyDel (toDelete);
     303           0 :         ksDel (ks);
     304           0 :         keyDel (parentKey);
     305           0 :         PLUGIN_CLOSE ();
     306           0 : }
     307             : 
     308           0 : static void test_announceOnce (void)
     309             : {
     310           0 :         printf ("test announce once\n");
     311             : 
     312             :         // (namespace)/tests/foo
     313           0 :         Key * parentKey = keyNew (testKeyNamespace, KEY_END);
     314           0 :         keyAddName (parentKey, "tests/foo");
     315             : 
     316             :         // (namespace)/tests/foo/bar/#0
     317           0 :         Key * toAdd1 = keyDup (parentKey);
     318           0 :         keyAddName (toAdd1, "bar/#0");
     319           0 :         keySetString (toAdd1, "test");
     320             : 
     321             :         // (namespace)/tests/foo/bar/#1
     322           0 :         Key * toAdd2 = keyDup (toAdd1);
     323           0 :         keySetBaseName (toAdd2, "#1");
     324             : 
     325             :         // (namespace)/tests/foo/bar
     326           0 :         Key * toChange = keyDup (parentKey);
     327           0 :         keyAddName (toChange, "bar");
     328           0 :         keySetString (toChange, "test");
     329             : 
     330           0 :         KeySet * ks = ksNew (1, toChange, KS_END);
     331             : 
     332           0 :         KeySet * conf = ksNew (1, keyNew ("/announce", KEY_VALUE, "once", KEY_END), KS_END);
     333           0 :         PLUGIN_OPEN ("dbus");
     334             : 
     335             :         // initial get to save current state
     336           0 :         plugin->kdbGet (plugin, ks, parentKey);
     337             : 
     338             :         // modify keyset
     339           0 :         ksAppendKey (ks, toAdd1);
     340           0 :         ksAppendKey (ks, toAdd2);
     341           0 :         keySetString (toChange, "new value");
     342             : 
     343           0 :         DBusConnection * connection = getDbusConnection (testBusType);
     344           0 :         TestContext * context = createTestContext (connection, "Commit");
     345           0 :         elektraDbusSetupReceiveMessage (connection, receiveMessageHandler, (void *) context);
     346             : 
     347           0 :         plugin->kdbSet (plugin, ks, parentKey);
     348           0 :         runDispatch (context);
     349             : 
     350           0 :         succeed_if_same_string (keyName (parentKey), context->receivedKeyName);
     351             : 
     352           0 :         elektraFree (context);
     353           0 :         elektraDbusTeardownReceiveMessage (connection, receiveMessageHandler, (void *) context);
     354           0 :         dbus_connection_unref (connection);
     355           0 :         ksDel (ks);
     356           0 :         keyDel (parentKey);
     357           0 :         PLUGIN_CLOSE ();
     358           0 : }
     359             : 
     360           0 : static void test_cascadedChangeNotification (void)
     361             : {
     362           0 :         printf ("test change notification with cascaded parent key\n");
     363             : 
     364           0 :         Key * parentKey = keyNew ("/tests/foo", KEY_END);
     365             : 
     366             :         // (namespace)/tests/foo
     367           0 :         Key * completeParentKey = keyNew (testKeyNamespace, KEY_END);
     368           0 :         keyAddName (completeParentKey, "tests/foo");
     369             : 
     370             :         // (namespace)/tests/foo/bar
     371           0 :         Key * toAdd = keyDup (completeParentKey);
     372           0 :         keyAddName (toAdd, "bar");
     373           0 :         keySetString (toAdd, "test");
     374             : 
     375           0 :         KeySet * ks = ksNew (1, completeParentKey, KS_END);
     376             : 
     377           0 :         KeySet * conf = ksNew (0, KS_END);
     378           0 :         PLUGIN_OPEN ("dbus");
     379             : 
     380             :         // initial get to save current state
     381           0 :         plugin->kdbGet (plugin, ks, parentKey);
     382             : 
     383             :         // add key to keyset
     384           0 :         ksAppendKey (ks, toAdd);
     385             : 
     386           0 :         DBusConnection * connection = getDbusConnection (testBusType);
     387           0 :         TestContext * context = createTestContext (connection, "KeyAdded");
     388           0 :         elektraDbusSetupReceiveMessage (connection, receiveMessageHandler, (void *) context);
     389             : 
     390           0 :         plugin->kdbSet (plugin, ks, parentKey);
     391           0 :         runDispatch (context);
     392             : 
     393           0 :         succeed_if_same_string (keyName (toAdd), context->receivedKeyName);
     394             : 
     395           0 :         elektraFree (context);
     396           0 :         elektraDbusTeardownReceiveMessage (connection, receiveMessageHandler, (void *) context);
     397           0 :         dbus_connection_unref (connection);
     398           0 :         ksDel (ks);
     399           0 :         keyDel (parentKey);
     400           0 :         PLUGIN_CLOSE ();
     401           0 : }
     402             : 
     403           0 : static void test_cascadedAnnounceOnce (void)
     404             : {
     405           0 :         printf ("test announce once with cascaded parent key\n");
     406             : 
     407           0 :         Key * parentKey = keyNew ("/tests/foo", KEY_END);
     408             : 
     409             :         // (namespace)/tests/foo
     410           0 :         Key * completeParentKey = keyNew (testKeyNamespace, KEY_END);
     411           0 :         keyAddName (completeParentKey, "tests/foo");
     412             : 
     413             :         // (namespace)/tests/foo/bar
     414           0 :         Key * toAdd = keyDup (completeParentKey);
     415           0 :         keyAddName (toAdd, "bar");
     416           0 :         keySetString (toAdd, "test");
     417             : 
     418           0 :         KeySet * ks = ksNew (1, completeParentKey, KS_END);
     419             : 
     420           0 :         KeySet * conf = ksNew (1, keyNew ("/announce", KEY_VALUE, "once", KEY_END), KS_END);
     421           0 :         PLUGIN_OPEN ("dbus");
     422             : 
     423             :         // initial get to save current state
     424           0 :         plugin->kdbGet (plugin, ks, parentKey);
     425             : 
     426             :         // add key to keyset
     427           0 :         ksAppendKey (ks, toAdd);
     428             : 
     429           0 :         DBusConnection * connection = getDbusConnection (testBusType);
     430           0 :         TestContext * context = createTestContext (connection, "Commit");
     431           0 :         elektraDbusSetupReceiveMessage (connection, receiveMessageHandler, (void *) context);
     432             : 
     433           0 :         plugin->kdbSet (plugin, ks, parentKey);
     434           0 :         runDispatch (context);
     435             : 
     436           0 :         succeed_if_same_string (keyName (completeParentKey), context->receivedKeyName);
     437             : 
     438           0 :         elektraFree (context);
     439           0 :         elektraDbusTeardownReceiveMessage (connection, receiveMessageHandler, (void *) context);
     440           0 :         dbus_connection_unref (connection);
     441           0 :         ksDel (ks);
     442           0 :         keyDel (parentKey);
     443           0 :         PLUGIN_CLOSE ();
     444           0 : }
     445             : 
     446           0 : int main (int argc, char ** argv)
     447             : {
     448           0 :         printf ("DBUS TESTS\n");
     449           0 :         printf ("==========\n\n");
     450             : 
     451           0 :         init (argc, argv);
     452             : 
     453             :         // Test if dbus is available
     454           0 :         if (test_prerequisites ())
     455             :         {
     456             :                 // Test added, changed & deleted
     457           0 :                 test_keyAdded ();
     458           0 :                 test_keyChanged ();
     459           0 :                 test_keyDeleted ();
     460             : 
     461           0 :                 test_announceOnce ();
     462             : 
     463           0 :                 test_cascadedAnnounceOnce ();
     464           0 :                 test_cascadedChangeNotification ();
     465             :         }
     466             :         else
     467             :         {
     468           0 :                 printf ("warning no dbus daemon available; skipping tests that require dbus\n");
     469             :         }
     470             : 
     471           0 :         print_result ("testmod_dbus");
     472             : 
     473           0 :         dbus_shutdown ();
     474             : 
     475           0 :         return nbError;
     476             : }

Generated by: LCOV version 1.13