LCOV - code coverage report
Current view: top level - src/plugins/zeromqsend - testmod_zeromqsend.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 143 0.0 %
Date: 2019-09-12 12:28:41 Functions: 0 7 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 "zeromqsend.h"
      10             : 
      11             : #include <stdio.h>  // printf() & co
      12             : #include <time.h>   // time()
      13             : #include <unistd.h> // usleep()
      14             : 
      15             : #include <kdberrors.h>   // TIMEOUT ERROR
      16             : #include <kdbioplugin.h> // ElektraIoPluginSetBinding
      17             : 
      18             : #include <tests.h>
      19             : #include <tests_plugin.h>
      20             : 
      21             : #include <pthread.h>
      22             : 
      23             : /** change type received by readNotificationFromTestSocket() */
      24             : char * receivedChangeType;
      25             : 
      26             : /** key name received by readNotificationFromTestSocket() */
      27             : char * receivedKeyName;
      28             : 
      29             : /** variable indicating that a timeout occurred while receiving */
      30             : int receiveTimeout;
      31             : 
      32             : /** zmq context for tests */
      33             : void * context;
      34             : 
      35             : /** time in microseconds before a new socket is created. leaves the system some after binding a socket again */
      36             : #define TIME_HOLDOFF (1000 * 1000)
      37             : 
      38             : /** timeout for tests in seconds */
      39             : #define TEST_TIMEOUT 20
      40             : 
      41             : /** endpoint for tests */
      42             : #define TEST_ENDPOINT "tcp://127.0.0.1:6002"
      43             : 
      44             : /** extended timeouts for tests */
      45             : #define TESTCONFIG_CONNECT_TIMEOUT "5000"
      46             : #define TESTCONFIG_SUBSCRIBE_TIMEOUT "5000"
      47             : 
      48             : /**
      49             :  * Create subscriber socket for tests.
      50             :  * @internal
      51             :  *
      52             :  * @param  subscribeFilter filter for subscriptions
      53             :  * @return                 new socket
      54             :  */
      55           0 : static void * createTestSocket (char * subscribeFilter)
      56             : {
      57             :         // leave the system some time before binding again
      58           0 :         usleep (TIME_HOLDOFF);
      59             : 
      60           0 :         void * subSocket = zmq_socket (context, ZMQ_SUB);
      61           0 :         int result = zmq_bind (subSocket, TEST_ENDPOINT);
      62           0 :         if (result != 0)
      63             :         {
      64           0 :                 yield_error ("zmq_bind failed");
      65           0 :                 printf ("zmq error was: %s\n", zmq_strerror (zmq_errno ()));
      66           0 :                 exit (-1);
      67             :         }
      68           0 :         if (subscribeFilter != NULL)
      69             :         {
      70           0 :                 exit_if_fail (zmq_setsockopt (subSocket, ZMQ_SUBSCRIBE, subscribeFilter, elektraStrLen (subscribeFilter)) == 0,
      71             :                               "subscribe failed"); // subscribe to all messages
      72             :         }
      73           0 :         return subSocket;
      74             : }
      75             : 
      76             : /**
      77             :  * Main function for notification reader thread.
      78             :  *
      79             :  * Sets global variables receivedKeyName and receivedChangeType.
      80             :  *
      81             :  * @internal
      82             :  *
      83             :  * @param  subSocket socket to read messages from
      84             :  * @return           always NULL
      85             :  */
      86           0 : static void * notificationReaderThreadMain (void * filter)
      87             : {
      88           0 :         void * subSocket = createTestSocket ((char *) filter);
      89             : 
      90           0 :         time_t start = time (NULL);
      91             : 
      92             :         zmq_msg_t message;
      93           0 :         zmq_msg_init (&message);
      94             :         int more;
      95           0 :         size_t moreSize = sizeof (more);
      96             :         int rc;
      97           0 :         int partCounter = 0;
      98           0 :         int maxParts = 2; // change type and key name
      99             :         int lastErrno;
     100             :         do
     101             :         {
     102           0 :                 usleep (100 * 1000); // wait 100 ms
     103             : 
     104           0 :                 lastErrno = 0;
     105           0 :                 int result = zmq_msg_recv (&message, subSocket, ZMQ_DONTWAIT);
     106             : 
     107             :                 // check for timeout
     108           0 :                 if (time (NULL) - start > TEST_TIMEOUT)
     109             :                 {
     110           0 :                         receiveTimeout = 1;
     111           0 :                         receivedChangeType = NULL;
     112           0 :                         receivedKeyName = NULL;
     113           0 :                         zmq_msg_close (&message);
     114           0 :                         zmq_close (subSocket);
     115           0 :                         return NULL;
     116             :                 }
     117             : 
     118             :                 // check for errors
     119           0 :                 if (result == -1)
     120             :                 {
     121           0 :                         lastErrno = zmq_errno ();
     122           0 :                         if (lastErrno != EAGAIN)
     123             :                         {
     124           0 :                                 yield_error ("zmq_msg_recv failed");
     125           0 :                                 printf ("zmq_msg_recv failed: %s\n", zmq_strerror (lastErrno));
     126           0 :                                 zmq_msg_close (&message);
     127           0 :                                 zmq_close (subSocket);
     128           0 :                                 return NULL;
     129             :                         }
     130             :                 }
     131             :                 else
     132             :                 {
     133           0 :                         rc = zmq_getsockopt (subSocket, ZMQ_RCVMORE, &more, &moreSize);
     134           0 :                         if (rc < 0)
     135             :                         {
     136           0 :                                 yield_error ("zmq_getsockopt failed");
     137           0 :                                 printf ("zmq_getsockopt failed: %s\n", zmq_strerror (zmq_errno ()));
     138           0 :                                 zmq_msg_close (&message);
     139           0 :                                 zmq_close (subSocket);
     140           0 :                                 return NULL;
     141             :                         }
     142             : 
     143           0 :                         int length = zmq_msg_size (&message);
     144           0 :                         char * buffer = elektraStrNDup (zmq_msg_data (&message), length + 1);
     145           0 :                         buffer[length] = '\0';
     146             : 
     147           0 :                         switch (partCounter)
     148             :                         {
     149             :                         case 0:
     150           0 :                                 receivedChangeType = buffer;
     151           0 :                                 break;
     152             :                         case 1:
     153           0 :                                 receivedKeyName = buffer;
     154           0 :                                 break;
     155             :                         default:
     156           0 :                                 yield_error ("test inconsistency");
     157             :                         }
     158             : 
     159           0 :                         partCounter++;
     160             :                 }
     161           0 :         } while (lastErrno == EAGAIN || (more && partCounter < maxParts));
     162             : 
     163           0 :         zmq_msg_close (&message);
     164           0 :         zmq_close (subSocket);
     165             : 
     166           0 :         return NULL;
     167             : }
     168             : 
     169             : /**
     170             :  * Create and start thread for reading notifications.
     171             :  * @internal
     172             :  *
     173             :  * @param  filter subscription filter
     174             :  * @return        new thread
     175             :  */
     176           0 : static pthread_t * startNotificationReaderThread (char * filter)
     177             : {
     178           0 :         pthread_t * thread = elektraMalloc (sizeof *thread);
     179           0 :         pthread_create (thread, NULL, notificationReaderThreadMain, filter);
     180           0 :         return thread;
     181             : }
     182             : 
     183           0 : static void test_commit (void)
     184             : {
     185           0 :         printf ("test commit notification\n");
     186             : 
     187           0 :         Key * parentKey = keyNew ("system/tests/foo", KEY_END);
     188           0 :         Key * toAdd = keyNew ("system/tests/foo/bar", KEY_END);
     189           0 :         KeySet * ks = ksNew (0, KS_END);
     190             : 
     191           0 :         KeySet * conf = ksNew (3, keyNew ("/endpoint", KEY_VALUE, TEST_ENDPOINT, KEY_END),
     192             :                                keyNew ("/connectTimeout", KEY_VALUE, TESTCONFIG_CONNECT_TIMEOUT, KEY_END),
     193             :                                keyNew ("/subscribeTimeout", KEY_VALUE, TESTCONFIG_SUBSCRIBE_TIMEOUT, KEY_END), KS_END);
     194           0 :         PLUGIN_OPEN ("zeromqsend");
     195             : 
     196             :         // initial get to save current state
     197           0 :         plugin->kdbGet (plugin, ks, parentKey);
     198             : 
     199             :         // add key to keyset
     200           0 :         ksAppendKey (ks, toAdd);
     201             : 
     202           0 :         receiveTimeout = 0;
     203           0 :         receivedKeyName = NULL;
     204           0 :         receivedChangeType = NULL;
     205             : 
     206           0 :         pthread_t * thread = startNotificationReaderThread ("Commit");
     207           0 :         plugin->kdbSet (plugin, ks, parentKey);
     208           0 :         pthread_join (*thread, NULL);
     209             : 
     210           0 :         succeed_if (receiveTimeout == 0, "receiving did time out");
     211           0 :         succeed_if (!keyGetMeta (parentKey, "warnings"), "warning meta key was set");
     212           0 :         succeed_if_same_string ("Commit", receivedChangeType);
     213           0 :         succeed_if_same_string (keyName (parentKey), receivedKeyName);
     214             : 
     215           0 :         ksDel (ks);
     216           0 :         keyDel (parentKey);
     217           0 :         PLUGIN_CLOSE ();
     218           0 :         elektraFree (receivedKeyName);
     219           0 :         elektraFree (receivedChangeType);
     220           0 :         elektraFree (thread);
     221           0 : }
     222             : 
     223           0 : static void test_timeoutConnect (void)
     224             : {
     225           0 :         printf ("test connect timeout\n");
     226             : 
     227           0 :         Key * parentKey = keyNew ("system/tests/foo", KEY_END);
     228           0 :         Key * toAdd = keyNew ("system/tests/foo/bar", KEY_END);
     229           0 :         KeySet * ks = ksNew (0, KS_END);
     230             : 
     231           0 :         KeySet * conf = ksNew (3, keyNew ("/endpoint", KEY_VALUE, TEST_ENDPOINT, KEY_END),
     232             :                                keyNew ("/connectTimeout", KEY_VALUE, TESTCONFIG_CONNECT_TIMEOUT, KEY_END),
     233             :                                keyNew ("/subscribeTimeout", KEY_VALUE, TESTCONFIG_SUBSCRIBE_TIMEOUT, KEY_END), KS_END);
     234           0 :         PLUGIN_OPEN ("zeromqsend");
     235             : 
     236             :         // initial get to save current state
     237           0 :         plugin->kdbGet (plugin, ks, parentKey);
     238             : 
     239             :         // add key to keyset
     240           0 :         ksAppendKey (ks, toAdd);
     241             : 
     242           0 :         plugin->kdbSet (plugin, ks, parentKey);
     243             : 
     244           0 :         char * expectedWarningNumber = elektraFormat ("%s", ELEKTRA_ERROR_INSTALLATION);
     245           0 :         succeed_if (keyGetMeta (parentKey, "warnings"), "warning meta key was not set");
     246           0 :         succeed_if_same_string (expectedWarningNumber, keyValue (keyGetMeta (parentKey, "warnings/#00/number")));
     247             : 
     248           0 :         ksDel (ks);
     249           0 :         keyDel (parentKey);
     250           0 :         PLUGIN_CLOSE ();
     251           0 :         elektraFree (expectedWarningNumber);
     252           0 : }
     253             : 
     254           0 : static void test_timeoutSubscribe (void)
     255             : {
     256           0 :         printf ("test subscribe message timeout\n");
     257             : 
     258           0 :         Key * parentKey = keyNew ("system/tests/foo", KEY_END);
     259           0 :         Key * toAdd = keyNew ("system/tests/foo/bar", KEY_END);
     260           0 :         KeySet * ks = ksNew (0, KS_END);
     261             : 
     262           0 :         KeySet * conf = ksNew (3, keyNew ("/endpoint", KEY_VALUE, TEST_ENDPOINT, KEY_END),
     263             :                                keyNew ("/connectTimeout", KEY_VALUE, TESTCONFIG_CONNECT_TIMEOUT, KEY_END),
     264             :                                keyNew ("/subscribeTimeout", KEY_VALUE, TESTCONFIG_SUBSCRIBE_TIMEOUT, KEY_END), KS_END);
     265           0 :         PLUGIN_OPEN ("zeromqsend");
     266             : 
     267             :         // initial get to save current state
     268           0 :         plugin->kdbGet (plugin, ks, parentKey);
     269             : 
     270             :         // add key to keyset
     271           0 :         ksAppendKey (ks, toAdd);
     272             : 
     273           0 :         receiveTimeout = 0;
     274           0 :         receivedKeyName = NULL;
     275           0 :         receivedChangeType = NULL;
     276             : 
     277             :         // do not subscribe to Commit messages, this makes the plugin timeout due to no subscribers
     278           0 :         pthread_t * thread = startNotificationReaderThread (NULL);
     279             : 
     280           0 :         plugin->kdbSet (plugin, ks, parentKey);
     281             :         // without timeout we won't return here
     282             : 
     283           0 :         pthread_join (*thread, NULL);
     284             : 
     285           0 :         succeed_if (receiveTimeout, "receiving did not time out");
     286           0 :         succeed_if (receivedKeyName == NULL, "received key name should be unchanged");
     287           0 :         succeed_if (receivedChangeType == NULL, "received change type should be unchanged");
     288             : 
     289           0 :         ksDel (ks);
     290           0 :         keyDel (parentKey);
     291           0 :         PLUGIN_CLOSE ();
     292           0 :         elektraFree (receivedKeyName);
     293           0 :         elektraFree (receivedChangeType);
     294           0 :         elektraFree (thread);
     295           0 : }
     296             : 
     297           0 : int main (int argc, char ** argv)
     298             : {
     299           0 :         printf ("ZEROMQSEND TESTS\n");
     300           0 :         printf ("================\n\n");
     301             : 
     302           0 :         init (argc, argv);
     303             : 
     304             :         int major, minor, patch;
     305           0 :         zmq_version (&major, &minor, &patch);
     306           0 :         printf ("zeromq version is %d.%d.%d\n", major, minor, patch);
     307             : 
     308           0 :         context = zmq_ctx_new ();
     309             : 
     310             :         // Test notification from plugin
     311           0 :         test_commit ();
     312             : 
     313             :         // test timeouts
     314           0 :         test_timeoutConnect ();
     315           0 :         test_timeoutSubscribe ();
     316             : 
     317           0 :         print_result ("testmod_zeromqsend");
     318             : 
     319           0 :         zmq_ctx_destroy (context);
     320             : 
     321           0 :         return nbError;
     322             : }

Generated by: LCOV version 1.13