LCOV - code coverage report
Current view: top level - tests - catch_timer.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 181 184 98.4 %
Date: 2024-09-14 18:11:21 Functions: 11 11 100.0 %
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          11 :     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           1 :         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 1.14

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