LCOV - code coverage report
Current view: top level - src/bindings/io/test - test_fd.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 170 201 84.6 %
Date: 2019-09-12 12:28:41 Functions: 14 17 82.4 %

          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             :  * In these tests `pipe()` is used to create file descriptors that can be used
       9             :  * for testing readability or writability. Additionally `pipe()` is POSIX
      10             :  * compliant making the tests more portable.
      11             :  */
      12             : 
      13             : #include <stdio.h>
      14             : #include <stdlib.h>
      15             : #include <string.h>
      16             : #include <unistd.h>
      17             : 
      18             : #include <tests.h>
      19             : 
      20             : #include "test.h"
      21             : #include <kdbio.h>
      22             : #include <kdbiotest.h>
      23             : 
      24             : #define FD_CONTROL_INTERVAL 200
      25             : 
      26             : #define FD_BUFFER_TESTDATA "T"
      27             : #define FD_BUFFER_TESTDATA_LENGTH 1
      28             : 
      29             : // Indices for array returned by pipe()
      30             : #define FD_READ_END 0
      31             : #define FD_WRITE_END 1
      32             : 
      33             : ElektraIoTestSuiteStop testStop;
      34             : 
      35             : int testSignalWritableCalled;
      36             : 
      37             : int testSignalReadableCalled;
      38             : 
      39             : int testUpdateEnabledCalled;
      40             : int testUpdateEnabledStep;
      41             : ElektraIoInterface * testUpdateEnabledBinding;
      42             : ElektraIoFdOperation * testUpdateEnabledFdOp;
      43             : 
      44             : int testUpdateFlagsCalled;
      45             : int testUpdateFlagsStep;
      46             : ElektraIoInterface * testUpdateFlagsBinding;
      47             : ElektraIoFdOperation * testUpdateFlagsFdOp;
      48             : 
      49             : int testRemoveCalled;
      50             : int testRemoveStep;
      51             : ElektraIoInterface * testRemoveBinding;
      52             : ElektraIoFdOperation * testRemoveFdOp;
      53             : 
      54           0 : static void testFdBasicsCallback (ElektraIoFdOperation * fdOp ELEKTRA_UNUSED, int flags ELEKTRA_UNUSED)
      55             : {
      56           0 :         yield_error ("should not be called");
      57           0 : }
      58             : 
      59           6 : static void testFdBasics (ElektraIoTestSuiteCreateBinding createBinding)
      60             : {
      61             :         int fds[2];
      62           6 :         if (pipe (fds) == -1)
      63             :         {
      64           0 :                 yield_error ("pipe() failed");
      65           0 :                 return;
      66             :         }
      67             : 
      68           6 :         ElektraIoFdOperation * fdOp = elektraIoNewFdOperation (fds[FD_READ_END], ELEKTRA_IO_WRITABLE, 0, testFdBasicsCallback, NULL);
      69             : 
      70           6 :         ElektraIoInterface * binding = createBinding ();
      71           6 :         succeed_if (elektraIoBindingAddFd (binding, fdOp), "addFd did not succeed");
      72           6 :         succeed_if (elektraIoBindingAddFd (binding, fdOp) == 0, "addFd: should not be able to reassign operation to a binding");
      73             : 
      74           6 :         elektraIoFdSetEnabled (fdOp, 1);
      75           6 :         succeed_if (elektraIoBindingUpdateFd (fdOp), "updateFd did not succeed");
      76             : 
      77           6 :         succeed_if (elektraIoBindingRemoveFd (fdOp), "removeFd did not succeed");
      78             : 
      79           6 :         succeed_if (elektraIoBindingAddFd (binding, fdOp), "addFd: should be able to assign operation after removal");
      80           6 :         succeed_if (elektraIoBindingRemoveFd (fdOp), "removeFd did not succeed");
      81           6 :         elektraIoBindingCleanup (binding);
      82           6 :         elektraFree (fdOp);
      83             : }
      84             : 
      85           0 : static void testFdShouldSignalXControl (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
      86             : {
      87           0 :         yield_error ("timeout; test failed");
      88           0 :         testStop ();
      89           0 : }
      90             : 
      91           6 : static void testFdShouldSignalWritableProbe (ElektraIoFdOperation * fdOp ELEKTRA_UNUSED, int flags)
      92             : {
      93           6 :         succeed_if (flags & ELEKTRA_IO_WRITABLE, "flags does not contain ELEKTRA_IO_WRITABLE");
      94           6 :         testSignalWritableCalled = 1;
      95           6 :         testStop ();
      96           6 : }
      97             : 
      98           6 : static void testFdShouldSignalWritable (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
      99             :                                         ElektraIoTestSuiteStop stop)
     100             : {
     101             :         int fds[2];
     102           6 :         if (pipe (fds) == -1)
     103             :         {
     104           0 :                 yield_error ("pipe() failed");
     105           0 :                 return;
     106             :         }
     107             : 
     108           6 :         ElektraIoFdOperation * fdOp =
     109           6 :                 elektraIoNewFdOperation (fds[FD_WRITE_END], ELEKTRA_IO_WRITABLE, 1, testFdShouldSignalWritableProbe, NULL);
     110             : 
     111           6 :         ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (FD_CONTROL_INTERVAL, 1, testFdShouldSignalXControl, NULL);
     112             : 
     113           6 :         ElektraIoInterface * binding = createBinding ();
     114           6 :         elektraIoBindingAddFd (binding, fdOp);
     115           6 :         elektraIoBindingAddTimer (binding, timerOp);
     116             : 
     117           6 :         testSignalWritableCalled = 0;
     118           6 :         testStop = stop;
     119             : 
     120           6 :         start ();
     121             : 
     122           6 :         succeed_if (testSignalWritableCalled, "callback was not called");
     123             : 
     124           6 :         elektraIoBindingRemoveFd (fdOp);
     125           6 :         elektraIoBindingRemoveTimer (timerOp);
     126           6 :         elektraIoBindingCleanup (binding);
     127           6 :         elektraFree (fdOp);
     128           6 :         elektraFree (timerOp);
     129           6 :         close (fds[FD_READ_END]);
     130           6 :         close (fds[FD_WRITE_END]);
     131             : }
     132             : 
     133           6 : static void testFdShouldSignalReadableProbe (ElektraIoFdOperation * fdOp, int flags)
     134             : {
     135             :         char buffer[FD_BUFFER_TESTDATA_LENGTH];
     136           6 :         succeed_if (read (elektraIoFdGetFd (fdOp), &buffer, FD_BUFFER_TESTDATA_LENGTH) == FD_BUFFER_TESTDATA_LENGTH, "read failed");
     137           6 :         succeed_if (strncmp (buffer, FD_BUFFER_TESTDATA, FD_BUFFER_TESTDATA_LENGTH) == 0, "did not read correct data");
     138             : 
     139           6 :         succeed_if (flags & ELEKTRA_IO_READABLE, "flags does not contain ELEKTRA_IO_READABLE");
     140           6 :         testSignalReadableCalled = 1;
     141           6 :         testStop ();
     142           6 : }
     143             : 
     144           6 : static void testFdShouldSignalReadable (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
     145             :                                         ElektraIoTestSuiteStop stop)
     146             : {
     147             :         int fds[2];
     148           6 :         if (pipe (fds) == -1)
     149             :         {
     150           0 :                 yield_error ("pipe() failed");
     151           0 :                 return;
     152             :         }
     153           6 :         char * buffer = FD_BUFFER_TESTDATA;
     154           6 :         succeed_if (write (fds[FD_WRITE_END], buffer, FD_BUFFER_TESTDATA_LENGTH) == FD_BUFFER_TESTDATA_LENGTH, "write failed");
     155             : 
     156           6 :         ElektraIoFdOperation * fdOp =
     157           6 :                 elektraIoNewFdOperation (fds[FD_READ_END], ELEKTRA_IO_READABLE, 1, testFdShouldSignalReadableProbe, NULL);
     158             : 
     159           6 :         ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (FD_CONTROL_INTERVAL, 1, testFdShouldSignalXControl, NULL);
     160             : 
     161           6 :         ElektraIoInterface * binding = createBinding ();
     162           6 :         elektraIoBindingAddFd (binding, fdOp);
     163           6 :         elektraIoBindingAddTimer (binding, timerOp);
     164             : 
     165           6 :         testSignalReadableCalled = 0;
     166           6 :         testStop = stop;
     167             : 
     168           6 :         start ();
     169             : 
     170           6 :         succeed_if (testSignalReadableCalled, "callback was not called");
     171             : 
     172           6 :         elektraIoBindingRemoveFd (fdOp);
     173           6 :         elektraIoBindingRemoveTimer (timerOp);
     174           6 :         elektraIoBindingCleanup (binding);
     175           6 :         elektraFree (fdOp);
     176           6 :         elektraFree (timerOp);
     177           6 :         close (fds[FD_READ_END]);
     178           6 :         close (fds[FD_WRITE_END]);
     179             : }
     180             : 
     181           6 : static void testFdShouldUpdateEnabledControl (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     182             : {
     183           6 :         switch (testUpdateEnabledStep)
     184             :         {
     185             :         case 0:
     186           6 :                 elektraIoFdSetEnabled (testUpdateEnabledFdOp, 1);
     187           6 :                 elektraIoBindingUpdateFd (testUpdateEnabledFdOp);
     188           6 :                 break;
     189             :         case 1:
     190           0 :                 yield_error ("timeout; test failed");
     191           0 :                 testStop ();
     192           0 :                 break;
     193             :         }
     194           6 :         testUpdateEnabledStep++;
     195           6 : }
     196             : 
     197           6 : static void testFdShouldUpdateEnabledProbe (ElektraIoFdOperation * fdOp ELEKTRA_UNUSED, int flags ELEKTRA_UNUSED)
     198             : {
     199           6 :         succeed_if (testUpdateEnabledStep != 0, "callback called before enabeld was updated");
     200           6 :         testUpdateEnabledCalled = 1;
     201           6 :         testStop ();
     202           6 : }
     203             : 
     204           6 : static void testFdShouldUpdateEnabled (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
     205             :                                        ElektraIoTestSuiteStop stop)
     206             : {
     207             :         int fds[2];
     208           6 :         if (pipe (fds) == -1)
     209             :         {
     210           0 :                 yield_error ("pipe() failed");
     211           0 :                 return;
     212             :         }
     213             : 
     214           6 :         ElektraIoFdOperation * fdOp = elektraIoNewFdOperation (fds[FD_WRITE_END], ELEKTRA_IO_WRITABLE,
     215             :                                                                0, // gets enabled by control timer
     216             :                                                                testFdShouldUpdateEnabledProbe, NULL);
     217             : 
     218           6 :         ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (FD_CONTROL_INTERVAL, 1, testFdShouldUpdateEnabledControl, NULL);
     219             : 
     220           6 :         ElektraIoInterface * binding = createBinding ();
     221           6 :         elektraIoBindingAddFd (binding, fdOp);
     222           6 :         elektraIoBindingAddTimer (binding, timerOp);
     223             : 
     224           6 :         testUpdateEnabledStep = 0;
     225           6 :         testUpdateEnabledBinding = binding;
     226           6 :         testUpdateEnabledFdOp = fdOp;
     227           6 :         testUpdateEnabledCalled = 0;
     228           6 :         testStop = stop;
     229             : 
     230           6 :         start ();
     231             : 
     232           6 :         succeed_if (testUpdateEnabledCalled, "callback was not called");
     233             : 
     234           6 :         elektraIoBindingRemoveFd (fdOp);
     235           6 :         elektraIoBindingRemoveTimer (timerOp);
     236           6 :         elektraIoBindingCleanup (binding);
     237           6 :         elektraFree (fdOp);
     238           6 :         elektraFree (timerOp);
     239           6 :         close (fds[FD_READ_END]);
     240           6 :         close (fds[FD_WRITE_END]);
     241             : }
     242             : 
     243           6 : static void testFdShouldUpdateFlagsControl (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     244             : {
     245           6 :         switch (testUpdateFlagsStep)
     246             :         {
     247             :         case 0:
     248           6 :                 elektraIoFdSetFlags (testUpdateFlagsFdOp, ELEKTRA_IO_WRITABLE);
     249           6 :                 elektraIoBindingUpdateFd (testUpdateFlagsFdOp);
     250           6 :                 break;
     251             :         case 1:
     252           0 :                 yield_error ("timeout; test failed");
     253           0 :                 testStop ();
     254           0 :                 break;
     255             :         }
     256           6 :         testUpdateFlagsStep++;
     257           6 : }
     258             : 
     259           6 : static void testFdShouldUpdateFlagsProbe (ElektraIoFdOperation * fdOp ELEKTRA_UNUSED, int flags ELEKTRA_UNUSED)
     260             : {
     261           6 :         succeed_if (testUpdateFlagsStep != 0, "callback called before flags were updated");
     262           6 :         testUpdateFlagsCalled = 1;
     263           6 :         testStop ();
     264           6 : }
     265             : 
     266           6 : static void testFdShouldUpdateFlags (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start,
     267             :                                      ElektraIoTestSuiteStop stop)
     268             : {
     269             :         int fds[2];
     270           6 :         if (pipe (fds) == -1)
     271             :         {
     272           0 :                 yield_error ("pipe() failed");
     273           0 :                 return;
     274             :         }
     275             : 
     276           6 :         ElektraIoFdOperation * fdOp = elektraIoNewFdOperation (fds[FD_WRITE_END],
     277             :                                                                ELEKTRA_IO_READABLE, // gets changed by control timer
     278             :                                                                1, testFdShouldUpdateFlagsProbe, NULL);
     279             : 
     280           6 :         ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (FD_CONTROL_INTERVAL, 1, testFdShouldUpdateFlagsControl, NULL);
     281             : 
     282           6 :         ElektraIoInterface * binding = createBinding ();
     283           6 :         elektraIoBindingAddFd (binding, fdOp);
     284           6 :         elektraIoBindingAddTimer (binding, timerOp);
     285             : 
     286           6 :         testUpdateFlagsStep = 0;
     287           6 :         testUpdateFlagsBinding = binding;
     288           6 :         testUpdateFlagsFdOp = fdOp;
     289           6 :         testUpdateFlagsCalled = 0;
     290           6 :         testStop = stop;
     291             : 
     292           6 :         start ();
     293             : 
     294           6 :         succeed_if (testUpdateFlagsCalled, "callback was not called");
     295             : 
     296           6 :         elektraIoBindingRemoveFd (fdOp);
     297           6 :         elektraIoBindingRemoveTimer (timerOp);
     298           6 :         elektraIoBindingCleanup (binding);
     299           6 :         elektraFree (fdOp);
     300           6 :         elektraFree (timerOp);
     301           6 :         close (fds[FD_READ_END]);
     302           6 :         close (fds[FD_WRITE_END]);
     303             : }
     304             : 
     305          12 : static void testFdShouldRemoveControl (ElektraIoTimerOperation * timerOp ELEKTRA_UNUSED)
     306             : {
     307          12 :         switch (testRemoveStep)
     308             :         {
     309             :         case 0:
     310           6 :                 elektraIoBindingRemoveFd (testRemoveFdOp);
     311           6 :                 char * buffer = "this should not fire the callback";
     312           6 :                 succeed_if (write (elektraIoFdGetFd (testRemoveFdOp), buffer, FD_BUFFER_TESTDATA_LENGTH) == FD_BUFFER_TESTDATA_LENGTH,
     313             :                             "write failed");
     314             :                 break;
     315             :         case 1:
     316           6 :                 testStop ();
     317           6 :                 break;
     318             :         }
     319          12 :         testRemoveStep++;
     320          12 : }
     321             : 
     322           0 : static void testFdShouldRemoveProbe (ElektraIoFdOperation * fdOp ELEKTRA_UNUSED, int flags ELEKTRA_UNUSED)
     323             : {
     324           0 :         succeed_if (testRemoveStep == 0, "callback called after fd was removed");
     325           0 :         testRemoveCalled = 1;
     326           0 :         testStop ();
     327           0 : }
     328             : 
     329           6 : static void testFdShouldRemove (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start, ElektraIoTestSuiteStop stop)
     330             : {
     331             :         int fds[2];
     332           6 :         if (pipe (fds) == -1)
     333             :         {
     334           0 :                 yield_error ("pipe() failed");
     335           0 :                 return;
     336             :         }
     337             : 
     338           6 :         ElektraIoFdOperation * fdOp = elektraIoNewFdOperation (fds[FD_WRITE_END],
     339             :                                                                ELEKTRA_IO_READABLE, // gets changed by control timer
     340             :                                                                1, testFdShouldRemoveProbe, NULL);
     341             : 
     342           6 :         ElektraIoTimerOperation * timerOp = elektraIoNewTimerOperation (FD_CONTROL_INTERVAL, 1, testFdShouldRemoveControl, NULL);
     343             : 
     344           6 :         ElektraIoInterface * binding = createBinding ();
     345           6 :         elektraIoBindingAddFd (binding, fdOp);
     346           6 :         elektraIoBindingAddTimer (binding, timerOp);
     347             : 
     348           6 :         testRemoveStep = 0;
     349           6 :         testRemoveBinding = binding;
     350           6 :         testRemoveFdOp = fdOp;
     351           6 :         testRemoveCalled = 0;
     352           6 :         testStop = stop;
     353             : 
     354           6 :         start ();
     355             : 
     356           6 :         succeed_if (testRemoveCalled == 0, "callback was called");
     357             : 
     358           6 :         if (testRemoveStep == 0)
     359             :         {
     360           0 :                 elektraIoBindingRemoveFd (fdOp);
     361             :         }
     362           6 :         elektraIoBindingRemoveTimer (timerOp);
     363           6 :         elektraIoBindingCleanup (binding);
     364           6 :         elektraFree (fdOp);
     365           6 :         elektraFree (timerOp);
     366           6 :         close (fds[FD_READ_END]);
     367           6 :         close (fds[FD_WRITE_END]);
     368             : }
     369             : 
     370             : /**
     371             :  * Test fd functions of the I/O binding returned by createBinding.
     372             :  * Requires the following operations: Fd, Timer
     373             :  *
     374             :  * @param createBinding binding creation function
     375             :  * @param start         starts I/O operations
     376             :  * @param stop          stops I/O operations
     377             :  */
     378           6 : void elektraIoTestSuiteFd (ElektraIoTestSuiteCreateBinding createBinding, ElektraIoTestSuiteStart start, ElektraIoTestSuiteStop stop)
     379             : {
     380           6 :         printf ("test file descriptor\n");
     381             : 
     382           6 :         testFdBasics (createBinding);
     383             : 
     384           6 :         testFdShouldSignalWritable (createBinding, start, stop);
     385             : 
     386           6 :         testFdShouldSignalReadable (createBinding, start, stop);
     387             : 
     388           6 :         testFdShouldUpdateEnabled (createBinding, start, stop);
     389             : 
     390           6 :         testFdShouldUpdateFlags (createBinding, start, stop);
     391             : 
     392           6 :         testFdShouldRemove (createBinding, start, stop);
     393           6 : }

Generated by: LCOV version 1.13