LCOV - code coverage report
Current view: top level - src/plugins/zeromqrecv - testmod_zeromqrecv.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 113 120 94.2 %
Date: 2019-09-12 12:28:41 Functions: 7 8 87.5 %

          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 "zeromqrecv.h"
      10             : 
      11             : #include <stdio.h>  // printf() & co
      12             : #include <time.h>   // time()
      13             : #include <unistd.h> // usleep()
      14             : 
      15             : #include <kdbio/uv.h>    // elektraIoUvNew()
      16             : #include <kdbioplugin.h> // ElektraIoPluginSetBinding
      17             : 
      18             : #include <tests.h>
      19             : #include <tests_plugin.h>
      20             : 
      21             : #include <uv.h>
      22             : 
      23             : /** zmq context for tests */
      24             : void * context;
      25             : 
      26             : /** time in microseconds to wait until zmq connections are established and sending & receiving works */
      27             : #define TIME_SETTLE_US (1000 * 1000)
      28             : 
      29             : /** time (100ms in microseconds) before a new socket is created. leaves the system some after binding a socket again */
      30             : #define TIME_HOLDOFF (100 * 1000)
      31             : 
      32             : /** timeout for tests in seconds */
      33             : #define TEST_TIMEOUT 10
      34             : 
      35             : Key * test_callbackKey;
      36             : uv_loop_t * test_callbackLoop;
      37             : int test_incompleteMessageTimeout;
      38             : 
      39             : /**
      40             :  * @internal
      41             :  * Create publisher socket for tests.
      42             :  *
      43             :  * @return  new socket
      44             :  */
      45           4 : static void * createTestSocket (void)
      46             : {
      47             :         // leave the system some time before binding again
      48           4 :         usleep (TIME_HOLDOFF);
      49             : 
      50           4 :         void * pubSocket = zmq_socket (context, ZMQ_PUB);
      51           4 :         int result = zmq_bind (pubSocket, "tcp://*:6001");
      52           4 :         if (result != 0)
      53             :         {
      54           0 :                 yield_error ("zmq_bind failed");
      55           0 :                 printf ("zmq error was: %s\n", zmq_strerror (zmq_errno ()));
      56           0 :                 exit (-1);
      57             :         }
      58             : 
      59           4 :         return pubSocket;
      60             : }
      61             : 
      62             : /**
      63             :  * @internal
      64             :  * Send a notification over a socket.
      65             :  *
      66             :  * @param socket     ZeroMq socket
      67             :  * @param changeType change type
      68             :  * @param keyName    key name
      69             :  */
      70           2 : static void sendTestNotification (void * socket, char * changeType, char * keyName)
      71             : {
      72           2 :         succeed_if (zmq_send (socket, changeType, elektraStrLen (changeType), ZMQ_SNDMORE) != -1, "failed to send change type");
      73           2 :         succeed_if (zmq_send (socket, keyName, elektraStrLen (keyName), 0) != -1, "failed to send key name");
      74           2 : }
      75             : 
      76             : /**
      77             :  * @internal
      78             :  * Called by plugin when a notification was received.
      79             :  * The key is saved to be evaluated by the current test and the event loop is
      80             :  * stopped.
      81             :  *
      82             :  * @see ElektraNotificationCallback (kdbnotificationinternal.h)
      83             :  *
      84             :  * @param key     changed key
      85             :  * @param context notification callback context
      86             :  */
      87           2 : static void test_notificationCallback (Key * key, ElektraNotificationCallbackContext * callbackContext ELEKTRA_UNUSED)
      88             : {
      89           2 :         test_callbackKey = key;
      90           2 :         uv_stop (test_callbackLoop);
      91           2 : }
      92             : 
      93             : /**
      94             :  * Timeout for tests.
      95             :  *
      96             :  * Creates a failure and stops the event loop
      97             :  *
      98             :  * @param timerOp timer operation
      99             :  */
     100           0 : static void test_timerCallback (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     101             : {
     102           0 :         yield_error ("timeout exceeded; test failed");
     103           0 :         uv_stop (test_callbackLoop);
     104           0 : }
     105             : 
     106             : /**
     107             :  * Timeout for incomplete message test.
     108             :  *
     109             :  * Creates stops the event loop
     110             :  *
     111             :  * @param timerOp timer operation
     112             :  */
     113           2 : static void test_timerCallbackIncomplete (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     114             : {
     115           2 :         test_incompleteMessageTimeout = 1;
     116           2 :         uv_stop (test_callbackLoop);
     117           2 : }
     118             : 
     119           2 : static void test_commit (uv_loop_t * loop, ElektraIoInterface * binding)
     120             : {
     121           2 :         printf ("test commit notification\n");
     122             : 
     123           2 :         KeySet * conf = ksNew (0, KS_END);
     124           2 :         PLUGIN_OPEN ("zeromqrecv");
     125             : 
     126           2 :         void * pubSocket = createTestSocket ();
     127             : 
     128             :         // set io binding
     129           2 :         size_t func = elektraPluginGetFunction (plugin, "setIoBinding");
     130           2 :         exit_if_fail (func, "could not get function setIoBinding");
     131           2 :         KeySet * setIoBindingParams =
     132           2 :                 ksNew (1, keyNew ("/ioBinding", KEY_BINARY, KEY_SIZE, sizeof (binding), KEY_VALUE, &binding, KEY_END), KS_END);
     133           2 :         ElektraIoPluginSetBinding setIoBinding = (ElektraIoPluginSetBinding) func;
     134           2 :         setIoBinding (plugin, setIoBindingParams);
     135           2 :         ksDel (setIoBindingParams);
     136             : 
     137             :         // open notification
     138           2 :         func = elektraPluginGetFunction (plugin, "openNotification");
     139           2 :         exit_if_fail (func, "could not get function openNotification");
     140           2 :         KeySet * openNotificationParams = ksNew (2, keyNew ("/callback", KEY_FUNC, test_notificationCallback, KEY_END), KS_END);
     141           2 :         ElektraNotificationOpenNotification openNotification = (ElektraNotificationOpenNotification) func;
     142           2 :         openNotification (plugin, openNotificationParams);
     143           2 :         ksDel (openNotificationParams);
     144             : 
     145           2 :         usleep (TIME_SETTLE_US);
     146             : 
     147           2 :         char * changeType = "Commit";
     148           2 :         char * expectedKeyName = "system/foo/bar";
     149           2 :         sendTestNotification (pubSocket, changeType, expectedKeyName);
     150             : 
     151           2 :         ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (TEST_TIMEOUT * 1000, 1, test_timerCallback, NULL);
     152           2 :         elektraIoBindingAddTimer (binding, timerOp);
     153             : 
     154           2 :         test_callbackKey = NULL;
     155           2 :         test_callbackLoop = loop;
     156           2 :         uv_run (loop, UV_RUN_DEFAULT);
     157             : 
     158           2 :         succeed_if_same_string (expectedKeyName, keyName (test_callbackKey));
     159             : 
     160             :         // close notification
     161           2 :         func = elektraPluginGetFunction (plugin, "closeNotification");
     162           2 :         exit_if_fail (func, "could not get function closeNotification");
     163           2 :         ElektraNotificationCloseNotification closeNotification = (ElektraNotificationCloseNotification) func;
     164           2 :         closeNotification (plugin, NULL);
     165             : 
     166           2 :         zmq_close (pubSocket);
     167             : 
     168           2 :         elektraIoBindingRemoveTimer (timerOp);
     169           2 :         elektraFree (timerOp);
     170           2 :         keyDel (test_callbackKey);
     171           2 :         PLUGIN_CLOSE ();
     172           2 : }
     173             : 
     174           2 : static void test_incompleteMessage (uv_loop_t * loop, ElektraIoInterface * binding)
     175             : {
     176           2 :         printf ("test incomplete message\n");
     177             : 
     178           2 :         KeySet * conf = ksNew (0, KS_END);
     179           2 :         PLUGIN_OPEN ("zeromqrecv");
     180             : 
     181           2 :         void * pubSocket = createTestSocket ();
     182             : 
     183             :         // set io binding
     184           2 :         size_t func = elektraPluginGetFunction (plugin, "setIoBinding");
     185           2 :         exit_if_fail (func, "could not get function setIoBinding");
     186           2 :         KeySet * setIoBindingParams =
     187           2 :                 ksNew (1, keyNew ("/ioBinding", KEY_BINARY, KEY_SIZE, sizeof (binding), KEY_VALUE, &binding, KEY_END), KS_END);
     188           2 :         ElektraIoPluginSetBinding setIoBinding = (ElektraIoPluginSetBinding) func;
     189           2 :         setIoBinding (plugin, setIoBindingParams);
     190           2 :         ksDel (setIoBindingParams);
     191             : 
     192             :         // open notification
     193           2 :         func = elektraPluginGetFunction (plugin, "openNotification");
     194           2 :         exit_if_fail (func, "could not get function openNotification");
     195           2 :         KeySet * openNotificationParams = ksNew (2, keyNew ("/callback", KEY_FUNC, test_notificationCallback, KEY_END), KS_END);
     196           2 :         ElektraNotificationOpenNotification openNotification = (ElektraNotificationOpenNotification) func;
     197           2 :         openNotification (plugin, openNotificationParams);
     198           2 :         ksDel (openNotificationParams);
     199             : 
     200           2 :         usleep (TIME_SETTLE_US);
     201             : 
     202           2 :         char * changeType = "KeyChanged";
     203           2 :         char * expectedKeyName = "system/foo/bar";
     204             :         // send message parts as standalone messages
     205           2 :         succeed_if (zmq_send (pubSocket, changeType, elektraStrLen (changeType), 0 /* no ZMQ_SNDMORE here */) != -1,
     206             :                     "failed to send change type");
     207           2 :         succeed_if (zmq_send (pubSocket, expectedKeyName, elektraStrLen (expectedKeyName), 0) != -1, "failed to send change type");
     208             : 
     209           2 :         ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (TEST_TIMEOUT * 1000, 1, test_timerCallbackIncomplete, NULL);
     210           2 :         elektraIoBindingAddTimer (binding, timerOp);
     211             : 
     212           2 :         test_callbackKey = NULL;
     213           2 :         test_callbackLoop = loop;
     214           2 :         test_incompleteMessageTimeout = 0;
     215           2 :         uv_run (loop, UV_RUN_DEFAULT);
     216             : 
     217           2 :         succeed_if (test_incompleteMessageTimeout, "test did not timeout");
     218           2 :         succeed_if (test_callbackKey == NULL, "should not receive key");
     219             : 
     220             :         // close notification
     221           2 :         func = elektraPluginGetFunction (plugin, "closeNotification");
     222           2 :         exit_if_fail (func, "could not get function closeNotification");
     223           2 :         ElektraNotificationCloseNotification closeNotification = (ElektraNotificationCloseNotification) func;
     224           2 :         closeNotification (plugin, NULL);
     225             : 
     226           2 :         zmq_close (pubSocket);
     227             : 
     228           2 :         elektraIoBindingRemoveTimer (timerOp);
     229           2 :         elektraFree (timerOp);
     230           2 :         PLUGIN_CLOSE ();
     231           2 : }
     232             : 
     233           2 : int main (int argc, char ** argv)
     234             : {
     235           2 :         printf ("ZEROMQRECV TESTS\n");
     236           2 :         printf ("================\n\n");
     237             : 
     238           2 :         init (argc, argv);
     239             : 
     240             :         int major, minor, patch;
     241           2 :         zmq_version (&major, &minor, &patch);
     242           2 :         printf ("zeromq version is %d.%d.%d\n", major, minor, patch);
     243             : 
     244           2 :         context = zmq_ctx_new ();
     245             : 
     246           2 :         uv_loop_t * loop = uv_default_loop ();
     247           2 :         ElektraIoInterface * binding = elektraIoUvNew (loop);
     248             : 
     249           2 :         test_commit (loop, binding);
     250           2 :         test_incompleteMessage (loop, binding);
     251             : 
     252           2 :         print_result ("testmod_zeromqrecv");
     253             : 
     254           2 :         elektraIoBindingCleanup (binding);
     255             : 
     256           2 :         zmq_ctx_destroy (context);
     257             : 
     258           2 :         while (uv_run (loop, UV_RUN_NOWAIT) != 0)
     259             :                 ;
     260             : #ifdef HAVE_LIBUV1
     261           2 :         uv_loop_close (loop);
     262             : #elif HAVE_LIBUV0
     263             :         uv_loop_delete (loop);
     264             : #endif
     265           2 :         return nbError;
     266             : }

Generated by: LCOV version 1.13