LCOV - code coverage report
Current view: top level - tests - catch_timer.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 98.4 % 184 181
Test Date: 2025-05-30 15:24:13 Functions: 100.0 % 11 11
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2012-2024  Made to Order Software Corp.  All Rights Reserved
       2              : //
       3              : // https://snapwebsites.org/project/eventdispatcher
       4              : // contact@m2osw.com
       5              : //
       6              : // This program is free software; you can redistribute it and/or modify
       7              : // it under the terms of the GNU General Public License as published by
       8              : // the Free Software Foundation; either version 2 of the License, or
       9              : // (at your option) any later version.
      10              : //
      11              : // This program is distributed in the hope that it will be useful,
      12              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : // GNU General Public License for more details.
      15              : //
      16              : // You should have received a copy of the GNU General Public License along
      17              : // with this program; if not, write to the Free Software Foundation, Inc.,
      18              : // 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      19              : 
      20              : // test standalone header
      21              : //
      22              : #include    <eventdispatcher/timer.h>
      23              : 
      24              : 
      25              : // self
      26              : //
      27              : #include    "catch_main.h"
      28              : 
      29              : 
      30              : // eventdispatcher
      31              : //
      32              : #include    <eventdispatcher/communicator.h>
      33              : #include    <eventdispatcher/dispatcher.h>
      34              : 
      35              : 
      36              : // C
      37              : //
      38              : #include    <unistd.h>
      39              : 
      40              : 
      41              : // last include
      42              : //
      43              : #include    <snapdev/poison.h>
      44              : 
      45              : 
      46              : 
      47              : 
      48              : namespace
      49              : {
      50              : 
      51              : 
      52              : 
      53              : // use a timer to test various general connection function
      54              : //
      55              : class timer_test
      56              :     : public ed::timer
      57              : {
      58              : public:
      59              :     typedef std::shared_ptr<timer_test>        pointer_t;
      60              : 
      61              :                     timer_test();
      62              : 
      63              :     virtual void    process_timeout() override;
      64              :     virtual void    connection_added() override;
      65              :     virtual void    connection_removed() override;
      66              : 
      67              :     void            set_expect_timeout(bool expect_timeout);
      68              :     void            set_expect_add(bool expect_add);
      69              :     bool            get_expect_add() const;
      70              :     void            set_expect_remove(bool expect_remove);
      71              :     bool            get_expect_remove() const;
      72              : 
      73              : private:
      74              :     bool            f_expect_timeout = false;
      75              :     bool            f_expect_add = false;
      76              :     bool            f_expect_remove = false;
      77              : };
      78              : 
      79              : 
      80              : 
      81           11 : timer_test::timer_test()
      82           11 :     : timer(1'000'000)  // 1s
      83              : {
      84           33 :     set_name("timer");
      85           11 : }
      86              : 
      87              : 
      88            1 : void timer_test::process_timeout()
      89              : {
      90            1 :     if(!f_expect_timeout)
      91              :     {
      92            0 :         throw std::runtime_error("unexpectedly got process_timeout() called.");
      93              :     }
      94            1 :     f_expect_timeout = false;
      95              : 
      96            1 :     remove_from_communicator();
      97            1 : }
      98              : 
      99              : 
     100            5 : void timer_test::connection_added()
     101              : {
     102            5 :     if(!f_expect_add)
     103              :     {
     104            0 :         throw std::runtime_error("unexpectedly got added to communicator.");
     105              :     }
     106            5 :     f_expect_add = false;
     107              : 
     108            5 :     connection::connection_added();
     109            5 : }
     110              : 
     111              : 
     112            5 : void timer_test::connection_removed()
     113              : {
     114            5 :     if(!f_expect_remove)
     115              :     {
     116            0 :         throw std::runtime_error("unexpectedly got removed to communicator.");
     117              :     }
     118            5 :     f_expect_remove = false;
     119              : 
     120            5 :     connection::connection_removed();
     121            5 : }
     122              : 
     123              : 
     124            2 : void timer_test::set_expect_timeout(bool expect_timeout)
     125              : {
     126            2 :     f_expect_timeout = expect_timeout;
     127            2 : }
     128              : 
     129              : 
     130            5 : void timer_test::set_expect_add(bool expect_add)
     131              : {
     132            5 :     f_expect_add = expect_add;
     133            5 : }
     134              : 
     135              : 
     136            5 : bool timer_test::get_expect_add() const
     137              : {
     138            5 :     return f_expect_add;
     139              : }
     140              : 
     141              : 
     142            5 : void timer_test::set_expect_remove(bool expect_remove)
     143              : {
     144            5 :     f_expect_remove = expect_remove;
     145            5 : }
     146              : 
     147              : 
     148            5 : bool timer_test::get_expect_remove() const
     149              : {
     150            5 :     return f_expect_remove;
     151              : }
     152              : 
     153              : 
     154              : 
     155              : } // no name namespace
     156              : 
     157              : 
     158              : 
     159            6 : CATCH_TEST_CASE("timer", "[timer]")
     160              : {
     161            6 :     CATCH_START_SECTION("Timer connection")
     162              :     {
     163            1 :         ed::communicator::pointer_t communicator(ed::communicator::instance());
     164              : 
     165              :         // pretend we add a timer, nullptr is ignored
     166              :         //
     167            1 :         CATCH_REQUIRE_FALSE(communicator->add_connection(timer_test::pointer_t()));
     168            1 :         CATCH_REQUIRE(communicator->get_connections().empty());
     169              : 
     170            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     171              : 
     172            1 :         CATCH_REQUIRE(t->get_name() == "timer");
     173              : 
     174            3 :         t->set_name("my-timer");
     175            1 :         CATCH_REQUIRE(t->get_name() == "my-timer");
     176              : 
     177            1 :         CATCH_REQUIRE_FALSE(t->is_listener());
     178            1 :         CATCH_REQUIRE_FALSE(t->is_signal());
     179            1 :         CATCH_REQUIRE_FALSE(t->is_reader());
     180            1 :         CATCH_REQUIRE_FALSE(t->is_writer());
     181            1 :         CATCH_REQUIRE(t->get_socket() == -1);
     182            1 :         CATCH_REQUIRE(t->valid_socket());
     183              : 
     184            1 :         CATCH_REQUIRE(t->is_enabled());
     185            1 :         t->set_enable(false);
     186            1 :         CATCH_REQUIRE_FALSE(t->is_enabled());
     187            1 :         t->set_enable(true);
     188            1 :         CATCH_REQUIRE(t->is_enabled());
     189              : 
     190            1 :         CATCH_REQUIRE(t->get_priority() == ed::EVENT_DEFAULT_PRIORITY);
     191            1 :         t->set_priority(33);
     192            1 :         CATCH_REQUIRE(t->get_priority() == 33);
     193              : 
     194              :         // make sure the sorting works as expected
     195              :         {
     196            1 :             timer_test::pointer_t t2(std::make_shared<timer_test>());
     197            1 :             CATCH_REQUIRE(ed::connection::compare(t, t2));
     198            1 :             CATCH_REQUIRE_FALSE(ed::connection::compare(t2, t));
     199              : 
     200            1 :             t->set_priority(145);
     201            1 :             CATCH_REQUIRE(t->get_priority() == 145);
     202              : 
     203            1 :             CATCH_REQUIRE_FALSE(ed::connection::compare(t, t2));
     204            1 :             CATCH_REQUIRE(ed::connection::compare(t2, t));
     205            1 :         }
     206              : 
     207            1 :         CATCH_REQUIRE(t->get_event_limit() == 5); // TODO: make 5 a constant
     208            1 :         t->set_event_limit(10);
     209            1 :         CATCH_REQUIRE(t->get_event_limit() == 10);
     210              : 
     211            1 :         CATCH_REQUIRE(t->get_processing_time_limit() == 500'000); // TODO: make 500_000 a constant
     212            1 :         t->set_processing_time_limit(1'200'999);
     213            1 :         CATCH_REQUIRE(t->get_processing_time_limit() == 1'200'999);
     214              : 
     215            1 :         CATCH_REQUIRE(t->get_timeout_delay() == 1'000'000);
     216            1 :         t->set_timeout_delay(5'000'000);
     217            1 :         CATCH_REQUIRE(t->get_timeout_delay() == 5'000'000);
     218            1 :         snapdev::timespec_ex const duration(11, 345'678'183);
     219            1 :         t->set_timeout_delay(duration);
     220            1 :         CATCH_REQUIRE(t->get_timeout_delay() == 11'345'678);
     221              : 
     222            1 :         snapdev::timespec_ex const date(snapdev::now() + snapdev::timespec_ex(30, 500'000'000));
     223            1 :         t->set_timeout_date(date);
     224            1 :         CATCH_REQUIRE(t->get_timeout_date() == date.to_usec());
     225              : 
     226              :         // make sure it works even though it does nothing
     227              :         //
     228            1 :         t->non_blocking();
     229            1 :         t->keep_alive();
     230              : 
     231            1 :         CATCH_REQUIRE_FALSE(t->is_done());
     232            1 :         t->mark_done();
     233            1 :         CATCH_REQUIRE(t->is_done());
     234            1 :         t->mark_not_done();
     235            1 :         CATCH_REQUIRE_FALSE(t->is_done());
     236            1 :     }
     237            6 :     CATCH_END_SECTION()
     238              : 
     239            6 :     CATCH_START_SECTION("Timer add/remove connection")
     240              :     {
     241            1 :         ed::communicator::pointer_t communicator(ed::communicator::instance());
     242              : 
     243            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     244              : 
     245            1 :         t->set_expect_add(true);
     246            1 :         CATCH_REQUIRE(communicator->add_connection(t));
     247            1 :         CATCH_REQUIRE_FALSE(t->get_expect_add());
     248            1 :         CATCH_REQUIRE_FALSE(communicator->add_connection(t)); // duplicate is ignored
     249            1 :         ed::connection::vector_t const & connections(communicator->get_connections());
     250            1 :         CATCH_REQUIRE(connections.size() == 1);
     251            1 :         CATCH_REQUIRE(connections[0] == t);
     252              : 
     253            1 :         t->set_expect_remove(true);
     254            1 :         communicator->remove_connection(t);
     255            1 :         CATCH_REQUIRE_FALSE(t->get_expect_remove());
     256            1 :     }
     257            6 :     CATCH_END_SECTION()
     258              : 
     259            6 :     CATCH_START_SECTION("Timer add connection, remove on process_error()")
     260              :     {
     261            1 :         ed::communicator::pointer_t communicator(ed::communicator::instance());
     262              : 
     263            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     264              : 
     265            1 :         t->set_expect_add(true);
     266            1 :         CATCH_REQUIRE(communicator->add_connection(t));
     267            1 :         CATCH_REQUIRE_FALSE(t->get_expect_add());
     268              : 
     269            1 :         t->set_expect_remove(true);
     270            1 :         t->process_error();
     271            1 :         CATCH_REQUIRE_FALSE(t->get_expect_remove());
     272            1 :     }
     273            6 :     CATCH_END_SECTION()
     274              : 
     275            6 :     CATCH_START_SECTION("Timer add connection, expect process_timeout()")
     276              :     {
     277            1 :         ed::communicator::pointer_t communicator(ed::communicator::instance());
     278              : 
     279            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     280              : 
     281            1 :         t->set_expect_add(true);
     282            1 :         CATCH_REQUIRE(communicator->add_connection(t));
     283            1 :         CATCH_REQUIRE_FALSE(t->get_expect_add());
     284              : 
     285            1 :         snapdev::timespec_ex const start(snapdev::now());
     286            1 :         t->set_expect_timeout(true);
     287            1 :         t->set_expect_remove(true);
     288            1 :         communicator->run();
     289            1 :         t->set_expect_timeout(false);
     290            1 :         CATCH_REQUIRE_FALSE(t->get_expect_remove());
     291            1 :         snapdev::timespec_ex const end(snapdev::now());
     292            1 :         snapdev::timespec_ex const duration(end - start);
     293            1 :         CATCH_REQUIRE(duration.tv_sec >= 1);
     294            1 :     }
     295            6 :     CATCH_END_SECTION()
     296              : 
     297            6 :     CATCH_START_SECTION("Timer add connection, remove on process_hup()")
     298              :     {
     299            1 :         ed::communicator::pointer_t communicator(ed::communicator::instance());
     300              : 
     301            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     302              : 
     303            1 :         t->set_expect_add(true);
     304            1 :         CATCH_REQUIRE(communicator->add_connection(t));
     305            1 :         CATCH_REQUIRE_FALSE(t->get_expect_add());
     306              : 
     307            1 :         t->set_expect_remove(true);
     308            1 :         t->process_hup();
     309            1 :         CATCH_REQUIRE_FALSE(t->get_expect_remove());
     310            1 :     }
     311            6 :     CATCH_END_SECTION()
     312              : 
     313            6 :     CATCH_START_SECTION("Timer add connection, remove on process_invalid()")
     314              :     {
     315            1 :         ed::communicator::pointer_t communicator(ed::communicator::instance());
     316              : 
     317            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     318              : 
     319            1 :         t->set_expect_add(true);
     320            1 :         CATCH_REQUIRE(communicator->add_connection(t));
     321            1 :         CATCH_REQUIRE_FALSE(t->get_expect_add());
     322              : 
     323            1 :         t->set_expect_remove(true);
     324            1 :         t->process_invalid();
     325            1 :         CATCH_REQUIRE_FALSE(t->get_expect_remove());
     326            1 :     }
     327            6 :     CATCH_END_SECTION()
     328            6 : }
     329              : 
     330              : 
     331            4 : CATCH_TEST_CASE("timer_errors", "[timer][error]")
     332              : {
     333            4 :     CATCH_START_SECTION("timer: invalid priority (too small)")
     334              :     {
     335            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     336          101 :         for(ed::priority_t p(ed::EVENT_MIN_PRIORITY - 100); p < ed::EVENT_MIN_PRIORITY; ++p)
     337              :         {
     338          100 :             CATCH_REQUIRE_THROWS_MATCHES(
     339              :                   t->set_priority(p)
     340              :                 , ed::parameter_error
     341              :                 , Catch::Matchers::ExceptionMessage(
     342              :                       "parameter_error: connection::set_priority(): priority out of range, this instance of connection accepts priorities between "
     343              :                     + std::to_string(ed::EVENT_MIN_PRIORITY)
     344              :                     + " and "
     345              :                     + std::to_string(ed::EVENT_MAX_PRIORITY)
     346              :                     + "."));
     347              :         }
     348            1 :     }
     349            4 :     CATCH_END_SECTION()
     350              : 
     351            4 :     CATCH_START_SECTION("timer: invalid priority (too large)")
     352              :     {
     353            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     354          100 :         for(ed::priority_t p(ed::EVENT_MAX_PRIORITY + 1); p < ed::EVENT_MAX_PRIORITY + 100; ++p)
     355              :         {
     356           99 :             CATCH_REQUIRE_THROWS_MATCHES(
     357              :                   t->set_priority(p)
     358              :                 , ed::parameter_error
     359              :                 , Catch::Matchers::ExceptionMessage(
     360              :                       "parameter_error: connection::set_priority(): priority out of range, this instance of connection accepts priorities between "
     361              :                     + std::to_string(ed::EVENT_MIN_PRIORITY)
     362              :                     + " and "
     363              :                     + std::to_string(ed::EVENT_MAX_PRIORITY)
     364              :                     + "."));
     365              :         }
     366            1 :     }
     367            4 :     CATCH_END_SECTION()
     368              : 
     369            4 :     CATCH_START_SECTION("timer: invalid timeout delay (too small)")
     370              :     {
     371            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     372          111 :         for(std::int64_t us(-100); us < 10; ++us)
     373              :         {
     374          110 :             if(us == -1)
     375              :             {
     376              :                 // -1 is similar to turning off the timer
     377              :                 //
     378            1 :                 continue;
     379              :             }
     380              : 
     381          109 :             CATCH_REQUIRE_THROWS_MATCHES(
     382              :                   t->set_timeout_delay(us)
     383              :                 , ed::parameter_error
     384              :                 , Catch::Matchers::ExceptionMessage(
     385              :                       "parameter_error: connection::set_timeout_delay(): timeout_us parameter cannot be less than 10 unless it is exactly -1, "
     386              :                     + std::to_string(us)
     387              :                     + " is not valid."));
     388              :         }
     389            1 :     }
     390            4 :     CATCH_END_SECTION()
     391              : 
     392            4 :     CATCH_START_SECTION("timer: invalid timeout date (too small)")
     393              :     {
     394            1 :         timer_test::pointer_t t(std::make_shared<timer_test>());
     395          100 :         for(std::int64_t date(-100); date < -1; ++date)
     396              :         {
     397           99 :             CATCH_REQUIRE_THROWS_MATCHES(
     398              :                   t->set_timeout_date(date)
     399              :                 , ed::parameter_error
     400              :                 , Catch::Matchers::ExceptionMessage(
     401              :                       "parameter_error: connection::set_timeout_date(): date_us parameter cannot be less than -1, "
     402              :                     + std::to_string(date)
     403              :                     + " is not valid."));
     404              :         }
     405            1 :     }
     406            4 :     CATCH_END_SECTION()
     407            4 : }
     408              : 
     409              : 
     410              : 
     411              : // vim: ts=4 sw=4 et
        

Generated by: LCOV version 2.0-1

Snap C++ | List of projects | List of versions