LCOV - code coverage report
Current view: top level - src/bindings/io/test - test_timer.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 164 175 93.7 %
Date: 2019-09-12 12:28:41 Functions: 13 16 81.2 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Tests for I/O bindings
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : 
      10             : #include <stdio.h>
      11             : #include <stdlib.h>
      12             : #include <string.h>
      13             : 
      14             : #include <kdbhelper.h>
      15             : #include <tests.h>
      16             : 
      17             : #include "test.h"
      18             : #include <kdbio.h>
      19             : #include <kdbiotest.h>
      20             : 
      21             : #define TIMER_TEST_INTERVAL 250
      22             : #define TIMER_TEST_TIMES 3
      23             : #define TIMER_DIFF_WARNING_THRESHOLD 5
      24             : #define TIMER_DIFF_ERROR_THRESHOLD (TIMER_DIFF_WARNING_THRESHOLD * 100)
      25             : 
      26             : // Control interval is 50ms * 5 = 250ms for the probe interval
      27             : // To check for the change (enabled or interval) we need control to run 5 + 1 times
      28             : #define TIMER_CHANGE_CONTROL_INTERVAL 50
      29             : #define TIMER_CHANGE_TIMES 6
      30             : 
      31             : #define TIMER_CHANGE_SECOND_INTERVAL TIMER_TEST_INTERVAL - TIMER_CHANGE_CONTROL_INTERVAL
      32             : #define TIMER_CHANGE_PROBE_TIMES 2
      33             : 
      34             : ElektraIoTestSuiteStop testStop;
      35             : struct timespec testTimeStarted;
      36             : 
      37             : int testCallbackOnceCalled;
      38             : struct timespec testCallbackOnceTimeCalled;
      39             : 
      40             : int testCallbackAtIntervalsCounter;
      41             : struct timespec testCallbackAtIntervalsTimeCalled[TIMER_TEST_TIMES];
      42             : 
      43             : int testUpdateEnabledControlCalled;
      44             : int testUpdateEnabledProbeCalled;
      45             : ElektraIoTimerOperation * testUpdateEnabledTimerProbe;
      46             : ElektraIoInterface * testUpdateEnabledBinding;
      47             : 
      48             : int testUpdateIntervalControlCalled;
      49             : int testUpdateIntervalProbeCalled;
      50             : ElektraIoTimerOperation * testUpdateIntervalTimerProbe;
      51             : ElektraIoInterface * testUpdateIntervalBinding;
      52             : struct timespec testUpdateIntervalTimeCalled, testUpdateIntervalTimeCalledLast;
      53             : 
      54             : int testRemoveControlCalled;
      55             : int testRemoveProbeCalled;
      56             : ElektraIoTimerOperation * testRemoveTimerProbe;
      57             : ElektraIoInterface * testRemoveBinding;
      58             : 
      59           0 : static void testTimerBasicsCallback (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
      60             : {
      61           0 :         yield_error ("should not be called");
      62           0 : }
      63             : 
      64           6 : static void testTimerBasics (ElektraIoTestSuiteCreateBinding createBinding)
      65             : {
      66           6 :         ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 0, testTimerBasicsCallback, NULL);
      67             : 
      68           6 :         ElektraIoInterface * binding = createBinding ();
      69           6 :         succeed_if (elektraIoBindingAddTimer (binding, timerOp), "addTimer did not succeed");
      70           6 :         succeed_if (elektraIoBindingAddTimer (binding, timerOp) == 0, "addTimer: should not be able to reassign operation to a binding");
      71             : 
      72           6 :         elektraIoTimerSetEnabled (timerOp, 1);
      73           6 :         succeed_if (elektraIoBindingUpdateTimer (timerOp), "updateTimer did not succeed");
      74             : 
      75           6 :         succeed_if (elektraIoBindingRemoveTimer (timerOp), "removeTimer did not succeed");
      76             : 
      77           6 :         succeed_if (elektraIoBindingAddTimer (binding, timerOp), "addTimer: should be able to assign operation after removal");
      78           6 :         succeed_if (elektraIoBindingRemoveTimer (timerOp), "removeTimer did not succeed");
      79           6 :         elektraIoBindingCleanup (binding);
      80           6 :         elektraFree (timerOp);
      81           6 : }
      82             : 
      83           6 : static void testTimerShouldCallbackOnceElapsed (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
      84             : {
      85           6 :         testCallbackOnceCalled = 1;
      86           6 :         elektraIoTestSuiteUtilGetCurrentTime (&testCallbackOnceTimeCalled);
      87           6 :         testStop ();
      88           6 : }
      89             : 
      90           6 : static void testTimerShouldCallbackOnce (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
      91             :                                          ElektraIoTestSuiteStop stop)
      92             : {
      93           6 :         ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldCallbackOnceElapsed, NULL);
      94             : 
      95           6 :         ElektraIoInterface * binding = createBinding ();
      96           6 :         elektraIoBindingAddTimer (binding, timerOp);
      97             : 
      98           6 :         testStop = stop;
      99           6 :         testCallbackOnceCalled = 0;
     100             : 
     101           6 :         elektraIoTestSuiteUtilGetCurrentTime (&testTimeStarted);
     102             : 
     103           6 :         start ();
     104             : 
     105           6 :         succeed_if (testCallbackOnceCalled, "callback was not called");
     106             : 
     107           6 :         long diff = elektraIoTestSuiteUtilGetTimeDifference (testTimeStarted, testCallbackOnceTimeCalled);
     108           6 :         int deviation = labs (TIMER_TEST_INTERVAL - diff);
     109           6 :         if (deviation > TIMER_DIFF_WARNING_THRESHOLD)
     110             :         {
     111           2 :                 printf ("testTimerShouldCallbackOnce (warning): measured %ldms, expected %dms - deviation %dms.\n", diff,
     112             :                         TIMER_TEST_INTERVAL, deviation);
     113             :         }
     114           6 :         succeed_if (deviation <= TIMER_DIFF_ERROR_THRESHOLD, "timer interval not within error threshold");
     115             : 
     116           6 :         elektraIoBindingRemoveTimer (timerOp);
     117           6 :         elektraIoBindingCleanup (binding);
     118           6 :         elektraFree (timerOp);
     119           6 : }
     120             : 
     121          18 : static void testTimerShouldCallbackAtIntervalsCallback (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     122             : {
     123          18 :         testCallbackAtIntervalsCounter--;
     124          18 :         elektraIoTestSuiteUtilGetCurrentTime (&testCallbackAtIntervalsTimeCalled[testCallbackAtIntervalsCounter]);
     125             : 
     126          18 :         if (testCallbackAtIntervalsCounter == 0)
     127             :         {
     128           6 :                 testStop ();
     129             :         }
     130          18 : }
     131             : 
     132           6 : static void testTimerShouldCallbackAtIntervals (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
     133             :                                                 ElektraIoTestSuiteStop stop)
     134             : {
     135           6 :         ElektraIoTimerOperation * timerOp =
     136             :                 elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldCallbackAtIntervalsCallback, NULL);
     137             : 
     138           6 :         ElektraIoInterface * binding = createBinding ();
     139           6 :         elektraIoBindingAddTimer (binding, timerOp);
     140             : 
     141           6 :         testCallbackAtIntervalsCounter = TIMER_TEST_TIMES;
     142           6 :         testStop = stop;
     143             : 
     144           6 :         elektraIoTestSuiteUtilGetCurrentTime (&testTimeStarted);
     145             : 
     146           6 :         start ();
     147             : 
     148           6 :         succeed_if (testCallbackAtIntervalsCounter == 0, "intervals timer not called the required amount of times");
     149             : 
     150             :         // Verify intervals
     151           6 :         struct timespec lastTime = testTimeStarted;
     152          24 :         for (int i = TIMER_TEST_TIMES - 1; i >= 0; i--)
     153             :         {
     154          18 :                 long diff = elektraIoTestSuiteUtilGetTimeDifference (lastTime, testCallbackAtIntervalsTimeCalled[i]);
     155          18 :                 int deviation = labs (TIMER_TEST_INTERVAL - diff);
     156          18 :                 if (deviation > TIMER_DIFF_WARNING_THRESHOLD)
     157             :                 {
     158           1 :                         printf ("testTimerShouldCallbackAtIntervals (warning): measured %ldms, expected %dms - deviation %dms.\n", diff,
     159             :                                 TIMER_TEST_INTERVAL, deviation);
     160             :                 }
     161          18 :                 succeed_if (deviation <= TIMER_DIFF_ERROR_THRESHOLD, "timer interval not within error threshold");
     162             : 
     163          18 :                 lastTime = testCallbackAtIntervalsTimeCalled[i];
     164             :         }
     165             : 
     166           6 :         elektraIoBindingRemoveTimer (timerOp);
     167           6 :         elektraIoBindingCleanup (binding);
     168           6 :         elektraFree (timerOp);
     169           6 : }
     170             : 
     171          36 : static void testTimerShouldChangeEnabledControl (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     172             : {
     173          36 :         testUpdateEnabledControlCalled--;
     174             : 
     175             :         // Disable probe timer on first run
     176          36 :         if (testUpdateEnabledControlCalled == TIMER_CHANGE_TIMES - 1)
     177             :         {
     178           6 :                 elektraIoTimerSetEnabled (testUpdateEnabledTimerProbe, 0);
     179           6 :                 elektraIoBindingUpdateTimer (testUpdateEnabledTimerProbe);
     180             :         }
     181             : 
     182          36 :         if (testUpdateEnabledControlCalled == 0 || testUpdateEnabledProbeCalled > 1)
     183             :         {
     184           6 :                 testStop ();
     185             :         }
     186          36 : }
     187             : 
     188           0 : static void testTimerShouldChangeEnabledProbe (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     189             : {
     190           0 :         testUpdateEnabledProbeCalled++;
     191           0 : }
     192             : 
     193           6 : static void testTimerShouldChangeEnabled (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
     194             :                                           ElektraIoTestSuiteStop stop)
     195             : {
     196           6 :         ElektraIoTimerOperation * timerControl =
     197             :                 elektraIoNewTimerOperation (TIMER_CHANGE_CONTROL_INTERVAL, 1, testTimerShouldChangeEnabledControl, NULL);
     198             : 
     199           6 :         ElektraIoTimerOperation * timerProbe = elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldChangeEnabledProbe, NULL);
     200             : 
     201           6 :         ElektraIoInterface * binding = createBinding ();
     202           6 :         elektraIoBindingAddTimer (binding, timerControl);
     203           6 :         elektraIoBindingAddTimer (binding, timerProbe);
     204             : 
     205           6 :         testStop = stop;
     206           6 :         testUpdateEnabledControlCalled = TIMER_CHANGE_TIMES;
     207           6 :         testUpdateEnabledProbeCalled = 0;
     208           6 :         testUpdateEnabledTimerProbe = timerProbe;
     209           6 :         testUpdateEnabledBinding = binding;
     210             : 
     211           6 :         start ();
     212             : 
     213           6 :         succeed_if (testUpdateEnabledProbeCalled == 0, "timer callback was not disabled");
     214           6 :         succeed_if (testUpdateEnabledControlCalled == 0, "timout control callback was not called required amount of times");
     215             : 
     216           6 :         elektraIoBindingRemoveTimer (timerControl);
     217           6 :         elektraIoBindingRemoveTimer (timerProbe);
     218           6 :         elektraIoBindingCleanup (binding);
     219           6 :         elektraFree (timerControl);
     220           6 :         elektraFree (timerProbe);
     221           6 : }
     222             : 
     223          74 : static void testTimerShouldChangeIntervalControl (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     224             : {
     225          74 :         testUpdateIntervalControlCalled++;
     226             : 
     227             :         // Change probe interval on first run, before probe was run
     228          74 :         if (testUpdateIntervalControlCalled == 1)
     229             :         {
     230           6 :                 elektraIoTimerSetInterval (testUpdateIntervalTimerProbe, TIMER_CHANGE_SECOND_INTERVAL);
     231           6 :                 elektraIoBindingUpdateTimer (testUpdateIntervalTimerProbe);
     232             :         }
     233             : 
     234          74 :         if (testUpdateIntervalProbeCalled > TIMER_CHANGE_PROBE_TIMES)
     235             :         {
     236           6 :                 testStop ();
     237             :         }
     238          74 : }
     239             : 
     240          18 : static void testTimerShouldChangeIntervalProbe (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     241             : {
     242          18 :         testUpdateIntervalTimeCalledLast = testUpdateIntervalTimeCalled;
     243          18 :         elektraIoTestSuiteUtilGetCurrentTime (&testUpdateIntervalTimeCalled);
     244             : 
     245          18 :         testUpdateIntervalProbeCalled++;
     246          18 : }
     247             : 
     248           6 : static void testTimerShouldChangeInterval (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
     249             :                                            ElektraIoTestSuiteStop stop)
     250             : {
     251             :         // Control timer will change interval
     252           6 :         ElektraIoTimerOperation * timerControl =
     253             :                 elektraIoNewTimerOperation (TIMER_CHANGE_CONTROL_INTERVAL, 1, testTimerShouldChangeIntervalControl, NULL);
     254             : 
     255             :         // Probe will just count and measure time
     256           6 :         ElektraIoTimerOperation * timerProbe =
     257             :                 elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldChangeIntervalProbe, NULL);
     258             : 
     259           6 :         ElektraIoInterface * binding = createBinding ();
     260           6 :         elektraIoBindingAddTimer (binding, timerControl);
     261           6 :         elektraIoBindingAddTimer (binding, timerProbe);
     262             : 
     263           6 :         testStop = stop;
     264           6 :         testUpdateIntervalControlCalled = 0;
     265           6 :         testUpdateIntervalProbeCalled = 0;
     266           6 :         testUpdateIntervalTimerProbe = timerProbe;
     267           6 :         testUpdateIntervalBinding = binding;
     268             : 
     269           6 :         elektraIoTestSuiteUtilGetCurrentTime (&testTimeStarted);
     270             : 
     271           6 :         start ();
     272             : 
     273           6 :         succeed_if (testUpdateIntervalProbeCalled == TIMER_TEST_TIMES, "timer was not called the required amount of times");
     274             : 
     275             :         // Verify last interval
     276           6 :         long diff = elektraIoTestSuiteUtilGetTimeDifference (testUpdateIntervalTimeCalledLast, testUpdateIntervalTimeCalled);
     277           6 :         int deviation = labs (TIMER_CHANGE_SECOND_INTERVAL - diff);
     278           6 :         if (deviation > TIMER_DIFF_WARNING_THRESHOLD)
     279             :         {
     280           0 :                 printf ("testTimerShouldCallbackAtIntervals (warning): measured %ldms, expected %dms - deviation %dms.\n", diff,
     281             :                         TIMER_CHANGE_SECOND_INTERVAL, deviation);
     282             :         }
     283           6 :         succeed_if (deviation <= TIMER_DIFF_ERROR_THRESHOLD, "timer interval not within threshold");
     284             : 
     285           6 :         elektraIoBindingRemoveTimer (timerControl);
     286           6 :         elektraIoBindingRemoveTimer (timerProbe);
     287           6 :         elektraIoBindingCleanup (binding);
     288           6 :         elektraFree (timerControl);
     289           6 :         elektraFree (timerProbe);
     290           6 : }
     291             : 
     292          36 : static void testTimerShouldRemoveControl (ElektraIoTimerOperation * idleInfo ELEKTRA_UNUSED)
     293             : {
     294          36 :         testRemoveControlCalled--;
     295             : 
     296             :         // Disable probe timer on first run
     297          36 :         if (testRemoveControlCalled == TIMER_CHANGE_TIMES - 1)
     298             :         {
     299           6 :                 elektraIoBindingRemoveTimer (testRemoveTimerProbe);
     300             :         }
     301             : 
     302          36 :         if (testRemoveControlCalled == 0 || testRemoveProbeCalled > 1)
     303             :         {
     304           6 :                 testStop ();
     305             :         }
     306          36 : }
     307             : 
     308           0 : static void testTimerShouldRemoveProbe (ElektraIoTimerOperation * idleInfo ELEKTRA_UNUSED)
     309             : {
     310           0 :         testRemoveProbeCalled++;
     311           0 : }
     312             : 
     313           6 : static void testTimerShouldRemove (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
     314             :                                    ElektraIoTestSuiteStop stop)
     315             : {
     316           6 :         ElektraIoTimerOperation * timerControl =
     317             :                 elektraIoNewTimerOperation (TIMER_CHANGE_CONTROL_INTERVAL, 1, testTimerShouldRemoveControl, NULL);
     318             : 
     319           6 :         ElektraIoTimerOperation * timerProbe = elektraIoNewTimerOperation (TIMER_TEST_INTERVAL, 1, testTimerShouldRemoveProbe, NULL);
     320             : 
     321           6 :         ElektraIoInterface * binding = createBinding ();
     322           6 :         elektraIoBindingAddTimer (binding, timerControl);
     323           6 :         elektraIoBindingAddTimer (binding, timerProbe);
     324             : 
     325           6 :         testStop = stop;
     326           6 :         testRemoveControlCalled = TIMER_CHANGE_TIMES;
     327           6 :         testRemoveProbeCalled = 0;
     328           6 :         testRemoveTimerProbe = timerProbe;
     329           6 :         testRemoveBinding = binding;
     330             : 
     331           6 :         start ();
     332             : 
     333           6 :         succeed_if (testRemoveProbeCalled == 0, "timer callback was not removed");
     334           6 :         succeed_if (testRemoveControlCalled == 0, "timout control callback was not called required amount of times");
     335             : 
     336           6 :         elektraIoBindingRemoveTimer (timerControl);
     337           6 :         if (testRemoveProbeCalled != 0)
     338             :         {
     339           0 :                 elektraIoBindingRemoveTimer (timerProbe);
     340             :         }
     341           6 :         elektraIoBindingCleanup (binding);
     342           6 :         elektraFree (timerControl);
     343           6 :         elektraFree (timerProbe);
     344           6 : }
     345             : 
     346             : /**
     347             :  * Test timer functions of the I/O binding returned by createBinding.
     348             :  * Requires the following operations: Timer
     349             :  *
     350             :  * @param createBinding binding creation function
     351             :  * @param start         starts I/O operations
     352             :  * @param stop          stops I/O operations
     353             :  */
     354           6 : void elektraIoTestSuiteTimer (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start, ElektraIoTestSuiteStop stop)
     355             : {
     356           6 :         printf ("test timer\n");
     357             : 
     358           6 :         testTimerBasics (createBinding);
     359             : 
     360           6 :         testTimerShouldCallbackOnce (createBinding, start, stop);
     361             : 
     362           6 :         testTimerShouldCallbackAtIntervals (createBinding, start, stop);
     363             : 
     364           6 :         testTimerShouldChangeEnabled (createBinding, start, stop);
     365             : 
     366           6 :         testTimerShouldChangeInterval (createBinding, start, stop);
     367             : 
     368           6 :         testTimerShouldRemove (createBinding, start, stop);
     369           6 : }

Generated by: LCOV version 1.13