LCOV - code coverage report
Current view: top level - tests - catch_cluck.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 932 979 95.2 %
Date: 2025-01-27 20:52:47 Functions: 35 37 94.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Copyright (c) 2016-2024  Made to Order Software Corp.  All Rights Reserved
       2             : //
       3             : // https://snapwebsites.org/project/cluck
       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 3 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
      17             : // along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18             : 
      19             : // self
      20             : //
      21             : #include    "catch_main.h"
      22             : 
      23             : 
      24             : 
      25             : // cluck
      26             : //
      27             : #include    <cluck/cluck.h>
      28             : #include    <cluck/cluck_status.h>
      29             : #include    <cluck/exception.h>
      30             : #include    <cluck/names.h>
      31             : #include    <cluck/version.h>
      32             : 
      33             : 
      34             : // eventdispatcher
      35             : //
      36             : #include    <eventdispatcher/communicator.h>
      37             : #include    <eventdispatcher/dispatcher.h>
      38             : #include    <eventdispatcher/names.h>
      39             : #include    <eventdispatcher/tcp_client_permanent_message_connection.h>
      40             : 
      41             : #include    <eventdispatcher/reporter/executor.h>
      42             : #include    <eventdispatcher/reporter/lexer.h>
      43             : #include    <eventdispatcher/reporter/parser.h>
      44             : #include    <eventdispatcher/reporter/state.h>
      45             : #include    <eventdispatcher/reporter/variable_string.h>
      46             : 
      47             : 
      48             : // advgetopt
      49             : //
      50             : #include    <advgetopt/utils.h>
      51             : 
      52             : 
      53             : // last include
      54             : //
      55             : #include    <snapdev/poison.h>
      56             : 
      57             : 
      58             : 
      59             : namespace
      60             : {
      61             : 
      62             : 
      63             : 
      64       10017 : addr::addr get_address()
      65             : {
      66       10017 :     addr::addr a;
      67       10017 :     sockaddr_in ip = {
      68             :         .sin_family = AF_INET,
      69       10017 :         .sin_port = htons(20002),
      70             :         .sin_addr = {
      71       10017 :             .s_addr = htonl(0x7f000001),
      72             :         },
      73             :         .sin_zero = {},
      74       10017 :     };
      75       10017 :     a.set_ipv4(ip);
      76       20034 :     return a;
      77           0 : }
      78             : 
      79             : 
      80             : // the cluck class requires a messenger to function, it is a client
      81             : // extension instead of a standalone client
      82             : //
      83             : class test_messenger
      84             :     : public ed::tcp_client_permanent_message_connection
      85             :     , public ed::manage_message_definition_paths
      86             : {
      87             : public:
      88             :     typedef std::shared_ptr<test_messenger> pointer_t;
      89             : 
      90             :     enum class sequence_t
      91             :     {
      92             :         SEQUENCE_SUCCESS,
      93             :         SEQUENCE_EXTENDED,
      94             :         SEQUENCE_EXTENDED_SMALL_GAP,
      95             :         SEQUENCE_FAIL_MISSING_LOCKED_PARAMETERS,
      96             :         SEQUENCE_FAIL_MISSING_UNLOCKED_PARAMETERS,
      97             :         SEQUENCE_SAFE_UNLOCKING,
      98             :         SEQUENCE_UNSAFE_UNLOCKING,
      99             :         SEQUENCE_INVALID_UNLOCKING,
     100             :         SEQUENCE_TRANSMISSION_REPORT,
     101             :         SEQUENCE_FAILED_TIMEOUT,
     102             :         SEQUENCE_FAILED_INVALID,
     103             :         SEQUENCE_FAILED_OTHER_ERROR,
     104             :         SEQUENCE_FAILED_ERROR_MISSING,
     105             :     };
     106             : 
     107       10017 :     test_messenger(
     108             :               addr::addr const & a
     109             :             , ed::mode_t mode
     110             :             , sequence_t sequence)
     111       10017 :         : tcp_client_permanent_message_connection(
     112             :               a
     113             :             , mode
     114             :             , ed::DEFAULT_PAUSE_BEFORE_RECONNECTING
     115             :             , true
     116             :             , "client")  // service name
     117             :         , manage_message_definition_paths(
     118             :                 // WARNING: the order matters, we want to test with our source
     119             :                 //          (i.e. original) files first
     120             :                 //
     121       20034 :                 SNAP_CATCH2_NAMESPACE::g_source_dir() + "/tests/message-definitions:"
     122       30051 :                     + SNAP_CATCH2_NAMESPACE::g_source_dir() + "/daemon/message-definitions:"
     123       30051 :                     + SNAP_CATCH2_NAMESPACE::g_dist_dir() + "/share/eventdispatcher/messages")
     124       10017 :         , f_sequence(sequence)
     125       30051 :         , f_dispatcher(std::make_shared<ed::dispatcher>(this))
     126             :     {
     127       10017 :         set_name("test_messenger");    // connection name
     128       10017 :         set_dispatcher(f_dispatcher);
     129             : 
     130       60102 :         f_dispatcher->add_matches({
     131       20034 :             DISPATCHER_MATCH("DATA", &test_messenger::msg_data),
     132       20034 :             DISPATCHER_CATCH_ALL(),
     133             :         });
     134             : 
     135             :         // further dispatcher initialization
     136             :         //
     137             : #ifdef _DEBUG
     138       10017 :         f_dispatcher->set_trace();
     139       10017 :         f_dispatcher->set_show_matches();
     140             : #endif
     141       10017 :     }
     142             : 
     143       10018 :     ed::dispatcher::pointer_t get_dispatcher() const
     144             :     {
     145       10018 :         return f_dispatcher;
     146             :     }
     147             : 
     148          15 :     virtual void process_connected() override
     149             :     {
     150             :         // always register at the time we connect
     151             :         //
     152          15 :         tcp_client_permanent_message_connection::process_connected();
     153             : 
     154          15 :         CATCH_REQUIRE_FALSE(f_guarded->is_locked());
     155          15 :         CATCH_REQUIRE_FALSE(f_guarded->is_busy());
     156          15 :         CATCH_REQUIRE(f_guarded->lock());
     157          15 :         CATCH_REQUIRE_FALSE(f_guarded->is_locked());
     158          15 :         CATCH_REQUIRE(f_guarded->is_busy());
     159          15 :     }
     160             : 
     161           9 :     bool lock_obtained(cluck::cluck * c)
     162             :     {
     163           9 :         CATCH_REQUIRE(c->is_locked());
     164           9 :         CATCH_REQUIRE(c->is_busy());
     165           9 :         CATCH_REQUIRE_FALSE(c->lock());
     166             : 
     167           9 :         CATCH_REQUIRE_THROWS_MATCHES(
     168             :               c->set_type(static_cast<cluck::type_t>(rand() % 3))
     169             :             , cluck::busy
     170             :             , Catch::Matchers::ExceptionMessage("cluck_exception: this cluck object is busy, you cannot change its type at the moment."));
     171             : 
     172           9 :         CATCH_REQUIRE(f_expect_lock_obtained);
     173             : 
     174           9 :         ++f_step;
     175           9 :         switch(f_sequence)
     176             :         {
     177           1 :         case sequence_t::SEQUENCE_SUCCESS:
     178             :             {
     179             :                 // in lock simple the cluck object is expected to
     180             :                 // automatically call the f_guarded->unlock() function
     181             :                 // so we do not need it here
     182             :                 //
     183           1 :                 f_expect_finally = true;
     184             :             }
     185           1 :             break;
     186             : 
     187           3 :         case sequence_t::SEQUENCE_EXTENDED:
     188             :             {
     189             :                 // the cluck object does that, not us!?
     190           3 :                 ed::message read;
     191           3 :                 read.set_service("tester");
     192           3 :                 read.set_command("READ");
     193           3 :                 read.add_parameter("size", 219);
     194           3 :                 if(!send_message(read, false))
     195             :                 {
     196           0 :                     throw std::runtime_error("could not send READ message");
     197             :                 }
     198             : 
     199             :                 // verify that we got the expected timeout date (within 1s)
     200             :                 //
     201           3 :                 cluck::timeout_t const now(snapdev::now());
     202           3 :                 cluck::timeout_t const next_hour(now + cluck::timeout_t(60 * 60, 0));
     203           3 :                 cluck::timeout_t const gap(next_hour - c->get_timeout_date());
     204           3 :                 cluck::timeout_t const min_limit(0, 0);
     205           3 :                 cluck::timeout_t const max_limit(1, 0);
     206           3 :                 CATCH_CHECK(gap >= min_limit);
     207           3 :                 CATCH_CHECK(gap <= max_limit);
     208           3 :             }
     209             :             break;
     210             : 
     211           1 :         case sequence_t::SEQUENCE_EXTENDED_SMALL_GAP:
     212             :             {
     213             :                 // the cluck object does that, not us!?
     214           1 :                 ed::message read;
     215           1 :                 read.set_service("tester");
     216           1 :                 read.set_command("READ");
     217           1 :                 read.add_parameter("size", 219);
     218           1 :                 if(!send_message(read, false))
     219             :                 {
     220           0 :                     throw std::runtime_error("could not send READ message");
     221             :                 }
     222             : 
     223             :                 // verify that we got the expected timeout date (within 1s)
     224             :                 //
     225           1 :                 cluck::timeout_t const now(snapdev::now());
     226           1 :                 cluck::timeout_t const next_hour(now + cluck::timeout_t(3, 0));
     227           1 :                 cluck::timeout_t const gap(next_hour - c->get_timeout_date());
     228           1 :                 cluck::timeout_t const min_limit(0, 0);
     229           1 :                 cluck::timeout_t const max_limit(1, 0);
     230           1 :                 CATCH_CHECK(gap >= min_limit);
     231           1 :                 CATCH_CHECK(gap <= max_limit);
     232           1 :             }
     233             :             break;
     234             : 
     235           1 :         case sequence_t::SEQUENCE_FAIL_MISSING_UNLOCKED_PARAMETERS:
     236             :             // send the UNLOCK immediately
     237             :             //
     238           1 :             c->unlock();
     239           1 :             break;
     240             : 
     241           3 :         case sequence_t::SEQUENCE_SAFE_UNLOCKING:
     242             :         case sequence_t::SEQUENCE_UNSAFE_UNLOCKING:
     243             :         case sequence_t::SEQUENCE_INVALID_UNLOCKING:
     244             :             // do nothing here, the server will send us an UNLOCKING message
     245             :             // withing a couple of seconds
     246             :             //
     247           3 :             break;
     248             : 
     249           0 :         default:
     250           0 :             throw std::runtime_error("unknown sequence of event!?");
     251             : 
     252             :         }
     253             : 
     254           9 :         return true;
     255             :     }
     256             : 
     257           9 :     bool lock_failed(cluck::cluck * c)
     258             :     {
     259           9 :         CATCH_REQUIRE_FALSE(c->is_locked());
     260             :         //CATCH_REQUIRE_FALSE(c->is_busy()); -- on error without any valid locking this is not reliable
     261             : 
     262           9 :         CATCH_REQUIRE(f_expect_lock_failed);
     263             : 
     264           9 :         switch(f_sequence)
     265             :         {
     266           1 :         case sequence_t::SEQUENCE_TRANSMISSION_REPORT:
     267           1 :             CATCH_REQUIRE(c->get_reason() == cluck::reason_t::CLUCK_REASON_TRANSMISSION_ERROR);
     268           1 :             f_expect_finally = true;
     269           1 :             break;
     270             : 
     271           1 :         case sequence_t::SEQUENCE_FAILED_TIMEOUT:
     272           1 :             CATCH_REQUIRE(c->get_reason() == cluck::reason_t::CLUCK_REASON_REMOTE_TIMEOUT);
     273           1 :             f_expect_finally = true;
     274           1 :             break;
     275             : 
     276           1 :         case sequence_t::SEQUENCE_FAILED_INVALID:
     277           1 :             CATCH_REQUIRE(c->get_reason() == cluck::reason_t::CLUCK_REASON_INVALID);
     278           1 :             f_expect_finally = true;
     279           1 :             break;
     280             : 
     281           1 :         case sequence_t::SEQUENCE_FAILED_OTHER_ERROR:
     282           1 :             CATCH_REQUIRE(c->get_reason() == cluck::reason_t::CLUCK_REASON_INVALID);
     283           1 :             f_expect_finally = true;
     284           1 :             break;
     285             : 
     286           0 :         case sequence_t::SEQUENCE_FAILED_ERROR_MISSING:
     287           0 :             CATCH_REQUIRE(c->get_reason() == cluck::reason_t::CLUCK_REASON_INVALID);
     288           0 :             f_expect_finally = true;
     289           0 :             break;
     290             : 
     291           5 :         default:
     292           5 :             break;
     293             : 
     294             :         }
     295             : 
     296           9 :         return true;
     297             :     }
     298             : 
     299          14 :     bool lock_finally(cluck::cluck * c)
     300             :     {
     301          14 :         CATCH_REQUIRE_FALSE(c->is_locked());
     302             :         //CATCH_REQUIRE_FALSE(c->is_busy()); -- on error we cannot be sure of this state
     303             : 
     304          14 :         CATCH_REQUIRE(f_expect_finally);
     305          14 :         f_expect_finally = false;
     306             : 
     307          14 :         switch(f_sequence)
     308             :         {
     309           0 :         case sequence_t::SEQUENCE_FAIL_MISSING_LOCKED_PARAMETERS:
     310           0 :             ++f_step;
     311           0 :             if(f_step < 5)
     312             :             {
     313             :                 // adjust the "select" value in the script
     314             :                 //
     315           0 :                 ed::message set_select;
     316           0 :                 set_select.set_server("my_server");
     317           0 :                 set_select.set_service("cluckd"); // sending to cluckd
     318           0 :                 set_select.set_command("SET_SELECT");
     319           0 :                 set_select.add_parameter("select", f_step);
     320           0 :                 send_message(set_select);
     321             : 
     322           0 :                 CATCH_REQUIRE(f_guarded->lock());
     323           0 :                 set_expect_finally(true);
     324             : 
     325             : //ed::message invalid;
     326             : //invalid.set_command("WHAT");
     327             : //invalid.add_parameter(cluck::g_name_cluck_param_message, "where is our INVALID message?");
     328             : //send_message(invalid);
     329           0 :             }
     330             :             else
     331             :             {
     332           0 :                 ed::message quit;
     333           0 :                 quit.set_server("my_server");
     334           0 :                 quit.set_service("cluckd"); // sending to cluckd
     335           0 :                 quit.set_command("QUIT");
     336           0 :                 send_message(quit);
     337           0 :             }
     338           0 :             break;
     339             : 
     340          14 :         default:
     341          14 :             break;
     342             : 
     343             :         }
     344             : 
     345          14 :         return true;
     346             :     }
     347             : 
     348          15 :     void set_expect_lock_obtained(bool expect_lock_obtained)
     349             :     {
     350          15 :         f_expect_lock_obtained = expect_lock_obtained;
     351          15 :     }
     352             : 
     353             :     bool get_expect_lock_obtained() const
     354             :     {
     355             :         return f_expect_lock_obtained;
     356             :     }
     357             : 
     358          11 :     void set_expect_lock_failed(bool expect_lock_failed)
     359             :     {
     360          11 :         f_expect_lock_failed = expect_lock_failed;
     361          11 :     }
     362             : 
     363             :     bool get_expect_lock_failed() const
     364             :     {
     365             :         return f_expect_lock_failed;
     366             :     }
     367             : 
     368          11 :     void set_expect_finally(bool expect_finally)
     369             :     {
     370          11 :         f_expect_finally = expect_finally;
     371          11 :     }
     372             : 
     373          15 :     bool get_expect_finally() const
     374             :     {
     375          15 :         return f_expect_finally;
     376             :     }
     377             : 
     378           4 :     void msg_data(ed::message & msg)
     379             :     {
     380           4 :         CATCH_REQUIRE(msg.get_sent_from_server() == "my_server");
     381           4 :         CATCH_REQUIRE(msg.get_sent_from_service() == "tester");
     382           4 :         CATCH_REQUIRE(msg.get_server() == "other_server");
     383           4 :         CATCH_REQUIRE(msg.get_service() == "cluck_test");
     384             : 
     385          12 :         std::string const data(msg.get_parameter("data"));
     386           4 :         std::int64_t const size(msg.get_integer_parameter("size"));
     387           4 :         CATCH_REQUIRE(data.size() == static_cast<std::string::size_type>(size));
     388             : 
     389           4 :         bool auto_unlock(true);
     390           4 :         if(msg.has_parameter("unlock"))
     391             :         {
     392           1 :             auto_unlock = advgetopt::is_true(msg.get_parameter("unlock"));
     393             :         }
     394           4 :         if(auto_unlock)
     395             :         {
     396           3 :             f_guarded->unlock();
     397             :         }
     398             : 
     399           4 :         f_expect_finally = true;
     400           8 :     }
     401             : 
     402           0 :     virtual void msg_reply_with_unknown(ed::message & msg) override
     403             :     {
     404           0 :         tcp_client_permanent_message_connection::msg_reply_with_unknown(msg);
     405             : 
     406             :         // note that the cluck class has no idea about the unknown
     407             :         // message so we do not get our finally() callback called
     408             :         // automatically here (we should not get UNKNOWN messages
     409             :         // about cluck anyway)
     410             :         //
     411           0 :         switch(f_sequence)
     412             :         {
     413           0 :         case sequence_t::SEQUENCE_FAIL_MISSING_LOCKED_PARAMETERS:
     414           0 :             f_guarded->unlock();
     415             : 
     416             : #if 0
     417             :             ++f_step;
     418             : std::cerr << "--- step [from UNKNOWN]: " << f_step << "\n";
     419             :             if(f_step < 4)
     420             :             {
     421             : 
     422             :                 // adjust the "select" value in the script
     423             :                 //
     424             :                 ed::message set_select;
     425             :                 set_select.set_server("my_server");
     426             :                 set_select.set_service("cluckd"); // sending to cluckd
     427             :                 set_select.set_command("SET_SELECT");
     428             :                 set_select.add_parameter("select", f_step);
     429             :                 send_message(set_select);
     430             : 
     431             :                 CATCH_REQUIRE(f_guarded->lock());
     432             :                 set_expect_finally(true);
     433             :             }
     434             : #endif
     435           0 :             break;
     436             : 
     437           0 :         default:
     438           0 :             break;
     439             : 
     440             :         }
     441           0 :     }
     442             : 
     443             :     void disconnect()
     444             :     {
     445             :         remove_from_communicator();
     446             : 
     447             :         ed::connection::pointer_t timer_ptr(f_timer.lock());
     448             :         if(timer_ptr != nullptr)
     449             :         {
     450             :             timer_ptr->remove_from_communicator();
     451             :         }
     452             :     }
     453             : 
     454          15 :     void set_timer(ed::connection::pointer_t done_timer)
     455             :     {
     456          15 :         f_timer = done_timer;
     457          15 :     }
     458             : 
     459          15 :     void set_guard(cluck::cluck::pointer_t guarded)
     460             :     {
     461          15 :         if(f_guarded != nullptr)
     462             :         {
     463           0 :             throw cluck::logic_error("f_guarded already set.");
     464             :         }
     465             : 
     466          15 :         f_guarded = guarded;
     467          15 :         f_lock_obtained_callback_id = f_guarded->add_lock_obtained_callback(std::bind(&test_messenger::lock_obtained, this, std::placeholders::_1));
     468          15 :         f_lock_failed_callback_id = f_guarded->add_lock_failed_callback(std::bind(&test_messenger::lock_failed, this, std::placeholders::_1));
     469          15 :         f_finally_callback_id = f_guarded->add_finally_callback(std::bind(&test_messenger::lock_finally, this, std::placeholders::_1));
     470          15 :     }
     471             : 
     472          15 :     void unset_guard()
     473             :     {
     474          15 :         if(f_guarded != nullptr)
     475             :         {
     476          15 :             f_guarded->remove_lock_obtained_callback(f_lock_obtained_callback_id);
     477          15 :             f_lock_obtained_callback_id = cluck::cluck::callback_manager_t::NULL_CALLBACK_ID;
     478             : 
     479          15 :             f_guarded->remove_lock_failed_callback(f_lock_failed_callback_id);
     480          15 :             f_lock_failed_callback_id = cluck::cluck::callback_manager_t::NULL_CALLBACK_ID;
     481             : 
     482          15 :             f_guarded->remove_finally_callback(f_finally_callback_id);
     483          15 :             f_finally_callback_id = cluck::cluck::callback_manager_t::NULL_CALLBACK_ID;
     484             : 
     485          15 :             f_guarded.reset();
     486             :         }
     487          15 :     }
     488             : 
     489             : private:
     490             :     // the sequence & step define the next action
     491             :     //
     492             :     sequence_t                  f_sequence = sequence_t::SEQUENCE_SUCCESS;
     493             :     ed::dispatcher::pointer_t   f_dispatcher = ed::dispatcher::pointer_t();
     494             :     int                         f_step = 0;
     495             :     bool                        f_expect_lock_obtained = false;
     496             :     bool                        f_expect_lock_failed = false;
     497             :     bool                        f_expect_finally = false;
     498             :     ed::connection::weak_pointer_t
     499             :                                 f_timer = ed::connection::weak_pointer_t();
     500             :     cluck::cluck::pointer_t     f_guarded = cluck::cluck::pointer_t();
     501             :     cluck::cluck::callback_manager_t::callback_id_t
     502             :                                 f_lock_obtained_callback_id = cluck::cluck::callback_manager_t::NULL_CALLBACK_ID;
     503             :     cluck::cluck::callback_manager_t::callback_id_t
     504             :                                 f_lock_failed_callback_id = cluck::cluck::callback_manager_t::NULL_CALLBACK_ID;
     505             :     cluck::cluck::callback_manager_t::callback_id_t
     506             :                                 f_finally_callback_id = cluck::cluck::callback_manager_t::NULL_CALLBACK_ID;
     507             : };
     508             : 
     509             : 
     510             : class test_timer
     511             :     : public ed::timer
     512             : {
     513             : public:
     514             :     typedef std::shared_ptr<test_timer> pointer_t;
     515             : 
     516          15 :     test_timer(test_messenger::pointer_t m)
     517          15 :         : timer(-1)
     518          15 :         , f_messenger(m)
     519             :     {
     520          15 :         set_name("test_timer");
     521          15 :     }
     522             : 
     523           0 :     void process_timeout()
     524             :     {
     525           0 :         remove_from_communicator();
     526           0 :         f_messenger->remove_from_communicator();
     527           0 :         f_timed_out = true;
     528           0 :     }
     529             : 
     530             :     bool timed_out_prima() const
     531             :     {
     532             :         return f_timed_out;
     533             :     }
     534             : 
     535             : private:
     536             :     test_messenger::pointer_t   f_messenger = test_messenger::pointer_t();
     537             :     bool                        f_timed_out = false;
     538             : };
     539             : 
     540             : 
     541             : cluck::timeout_t g_min_timeout[3] = {
     542             :     cluck::CLUCK_MINIMUM_TIMEOUT,
     543             :     cluck::CLUCK_MINIMUM_TIMEOUT,
     544             :     cluck::CLUCK_UNLOCK_MINIMUM_TIMEOUT,
     545             : };
     546             : 
     547             : cluck::timeout_t g_max_timeout[3] = {
     548             :     cluck::CLUCK_LOCK_OBTENTION_MAXIMUM_TIMEOUT,
     549             :     cluck::CLUCK_MAXIMUM_TIMEOUT,
     550             :     cluck::CLUCK_MAXIMUM_TIMEOUT,
     551             : };
     552             : 
     553             : cluck::timeout_t g_min_timeout_adjust[3] = {
     554             :     { cluck::CLUCK_MINIMUM_TIMEOUT.tv_sec - 1'000, cluck::CLUCK_MINIMUM_TIMEOUT.tv_nsec },
     555             :     { cluck::CLUCK_MINIMUM_TIMEOUT.tv_sec - 200'000, cluck::CLUCK_MINIMUM_TIMEOUT.tv_nsec },
     556             :     { cluck::CLUCK_UNLOCK_MINIMUM_TIMEOUT.tv_sec - 200'000, cluck::CLUCK_MINIMUM_TIMEOUT.tv_nsec },
     557             : };
     558             : 
     559             : cluck::timeout_t g_max_timeout_adjust[3] = {
     560             :     { cluck::CLUCK_LOCK_OBTENTION_MAXIMUM_TIMEOUT.tv_sec + 1'000, cluck::CLUCK_LOCK_OBTENTION_MAXIMUM_TIMEOUT.tv_nsec },
     561             :     { cluck::CLUCK_MAXIMUM_TIMEOUT.tv_sec + 200'000, cluck::CLUCK_MAXIMUM_TIMEOUT.tv_nsec },
     562             :     { cluck::CLUCK_MAXIMUM_TIMEOUT.tv_sec + 200'000, cluck::CLUCK_MAXIMUM_TIMEOUT.tv_nsec },
     563             : };
     564             : 
     565             : 
     566             : 
     567             : } // no name namespace
     568             : 
     569             : 
     570             : 
     571           9 : CATCH_TEST_CASE("cluck_client", "[cluck][client]")
     572             : {
     573          11 :     CATCH_START_SECTION("cluck_client: verify timeouts")
     574             :     {
     575             :         // in order to make sure we do not write and/or read from the
     576             :         // wrong variable, I use a loop to repeat the test and use
     577             :         // random values with the exception of the default value
     578             :         //
     579       10001 :         for(int count(0); count < 10'000; ++count)
     580             :         {
     581       10000 :             int const select(rand() % 3);
     582       10000 :             bool const use_default(rand() % 10 == 0);
     583       10000 :             if(use_default)
     584             :             {
     585        1015 :                 switch(select)
     586             :                 {
     587         342 :                 case 0: // lock obtention timeout
     588         342 :                     cluck::set_lock_obtention_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     589         342 :                     CATCH_REQUIRE(cluck::get_lock_obtention_timeout() == cluck::CLUCK_LOCK_OBTENTION_DEFAULT_TIMEOUT);
     590         342 :                     break;
     591             : 
     592         332 :                 case 1: // lock duration timeout
     593         332 :                     cluck::set_lock_duration_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     594         332 :                     CATCH_REQUIRE(cluck::get_lock_duration_timeout() == cluck::CLUCK_LOCK_DURATION_DEFAULT_TIMEOUT);
     595         332 :                     break;
     596             : 
     597         341 :                 case 2: // unlock timeout
     598         341 :                     cluck::set_unlock_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     599         341 :                     CATCH_REQUIRE(cluck::get_unlock_timeout() == cluck::CLUCK_UNLOCK_DEFAULT_TIMEOUT);
     600         341 :                     break;
     601             : 
     602             :                 }
     603             :             }
     604             :             else
     605             :             {
     606             :                 // compute distance (max - min)
     607             :                 //
     608        8985 :                 cluck::timeout_t const range(g_max_timeout_adjust[select] - g_min_timeout_adjust[select]);
     609             : 
     610             :                 // use a loop to make sure we do not select the default value
     611             :                 //
     612        8985 :                 cluck::timeout_t value;
     613             :                 do
     614             :                 {
     615             :                     // get value from [0...max - min]
     616             :                     //
     617        8985 :                     value = cluck::timeout_t(rand() % (range.tv_sec + 1), rand() % 1'000'000'000);
     618             : 
     619             :                     // adjust value from [min...max]
     620             :                     //
     621        8985 :                     value += g_min_timeout_adjust[select];
     622             :                 }
     623        8985 :                 while(value == cluck::CLUCK_DEFAULT_TIMEOUT);
     624             : 
     625        8985 :                 switch(select)
     626             :                 {
     627        3025 :                 case 0: // lock obtention timeout
     628        3025 :                     cluck::set_lock_obtention_timeout(value);
     629        3025 :                     if(value < g_min_timeout[0])
     630             :                     {
     631         547 :                         CATCH_REQUIRE(cluck::get_lock_obtention_timeout() == g_min_timeout[0]);
     632             :                     }
     633        2478 :                     else if(value > g_max_timeout[0])
     634             :                     {
     635         541 :                         CATCH_REQUIRE(cluck::get_lock_obtention_timeout() == g_max_timeout[0]);
     636             :                     }
     637             :                     else
     638             :                     {
     639             :                         // otherwise not clamped
     640             :                         //
     641        1937 :                         CATCH_REQUIRE(cluck::get_lock_obtention_timeout() == value);
     642             :                     }
     643        3025 :                     break;
     644             : 
     645        2999 :                 case 1: // lock duration timeout
     646        2999 :                     cluck::set_lock_duration_timeout(value);
     647        2999 :                     if(value < g_min_timeout[1])
     648             :                     {
     649         573 :                         CATCH_REQUIRE(cluck::get_lock_duration_timeout() == g_min_timeout[1]);
     650             :                     }
     651        2426 :                     else if(value > g_max_timeout[1])
     652             :                     {
     653         627 :                         CATCH_REQUIRE(cluck::get_lock_duration_timeout() == g_max_timeout[1]);
     654             :                     }
     655             :                     else
     656             :                     {
     657             :                         // otherwise not clamped
     658             :                         //
     659        1799 :                         CATCH_REQUIRE(cluck::get_lock_duration_timeout() == value);
     660             :                     }
     661        2999 :                     break;
     662             : 
     663        2961 :                 case 2: // unlock timeout
     664        2961 :                     cluck::set_unlock_timeout(value);
     665        2961 :                     if(value < g_min_timeout[2])
     666             :                     {
     667         567 :                         CATCH_REQUIRE(cluck::get_unlock_timeout() == g_min_timeout[2]);
     668             :                     }
     669        2394 :                     else if(value > g_max_timeout[2])
     670             :                     {
     671         602 :                         CATCH_REQUIRE(cluck::get_unlock_timeout() == g_max_timeout[2]);
     672             :                     }
     673             :                     else
     674             :                     {
     675             :                         // otherwise not clamped
     676             :                         //
     677        1792 :                         CATCH_REQUIRE(cluck::get_unlock_timeout() == value);
     678             :                     }
     679        2961 :                     break;
     680             : 
     681             :                 }
     682             :             }
     683             : 
     684       10000 :             test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
     685       20000 :                       get_address()
     686       10000 :                     , ed::mode_t::MODE_PLAIN
     687       40000 :                     , test_messenger::sequence_t::SEQUENCE_SUCCESS));
     688       10000 :             cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
     689             :                   "lock-timeouts"
     690             :                 , messenger
     691       20000 :                 , messenger->get_dispatcher()
     692       40000 :                 , cluck::mode_t::CLUCK_MODE_SIMPLE));
     693             : 
     694             :             // no need to add to the communicator, we just check the
     695             :             // timeouts and loop to the next test
     696             :             //
     697             :             //ed::communicator::instance()->add_connection(guarded);
     698             : 
     699       10000 :             CATCH_REQUIRE(guarded->get_name() == "cluck::lock-timeouts");
     700             : 
     701             :             // by default, a cluck object gets its timeout from the number
     702             :             // saved in the global variable which means it returns DEFAULT
     703             :             //
     704       10000 :             CATCH_REQUIRE(guarded->get_lock_obtention_timeout() == cluck::CLUCK_DEFAULT_TIMEOUT);
     705       10000 :             CATCH_REQUIRE(guarded->get_lock_duration_timeout() == cluck::CLUCK_DEFAULT_TIMEOUT);
     706       10000 :             CATCH_REQUIRE(guarded->get_unlock_timeout() == cluck::CLUCK_DEFAULT_TIMEOUT);
     707             : 
     708       10000 :             if(use_default)
     709             :             {
     710        1015 :                 switch(select)
     711             :                 {
     712         342 :                 case 0: // lock obtention timeout
     713         342 :                     guarded->set_lock_obtention_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     714         342 :                     CATCH_REQUIRE(guarded->get_lock_obtention_timeout() == cluck::CLUCK_DEFAULT_TIMEOUT);
     715         342 :                     break;
     716             : 
     717         332 :                 case 1: // lock duration timeout
     718         332 :                     guarded->set_lock_duration_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     719         332 :                     CATCH_REQUIRE(guarded->get_lock_duration_timeout() == cluck::CLUCK_DEFAULT_TIMEOUT);
     720         332 :                     break;
     721             : 
     722         341 :                 case 2: // unlock timeout
     723         341 :                     guarded->set_unlock_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     724         341 :                     CATCH_REQUIRE(guarded->get_unlock_timeout() == cluck::CLUCK_DEFAULT_TIMEOUT);
     725         341 :                     break;
     726             : 
     727             :                 }
     728             :             }
     729             :             else
     730             :             {
     731             :                 // compute distance (max - min)
     732             :                 //
     733        8985 :                 cluck::timeout_t const range(g_max_timeout_adjust[select] - g_min_timeout_adjust[select]);
     734             : 
     735             :                 // get value from [0...max - min]
     736             :                 //
     737        8985 :                 cluck::timeout_t value;
     738             : 
     739             :                 // use a loop to make sure we do not select the default
     740             :                 // value because that would not be as good a test and
     741             :                 // the clamping below would fail
     742             :                 //
     743             :                 do
     744             :                 {
     745        8985 :                     value = cluck::timeout_t(rand() % (range.tv_sec + 1), rand() % 1'000'000'000);
     746             : 
     747             :                     // adjust value from [min...max]
     748             :                     //
     749        8985 :                     value += g_min_timeout_adjust[select];
     750             :                 }
     751        8985 :                 while(value == cluck::CLUCK_DEFAULT_TIMEOUT);
     752             : 
     753        8985 :                 switch(select)
     754             :                 {
     755        3025 :                 case 0: // lock obtention timeout
     756        3025 :                     guarded->set_lock_obtention_timeout(value);
     757        3025 :                     if(value < g_min_timeout[0])
     758             :                     {
     759         492 :                         CATCH_REQUIRE(guarded->get_lock_obtention_timeout() == g_min_timeout[0]);
     760             :                     }
     761        2533 :                     else if(value > g_max_timeout[0])
     762             :                     {
     763         548 :                         CATCH_REQUIRE(guarded->get_lock_obtention_timeout() == g_max_timeout[0]);
     764             :                     }
     765             :                     else
     766             :                     {
     767             :                         // otherwise not clamped
     768             :                         //
     769        1985 :                         CATCH_REQUIRE(guarded->get_lock_obtention_timeout() == value);
     770             :                     }
     771        3025 :                     break;
     772             : 
     773        2999 :                 case 1: // lock duration timeout
     774        2999 :                     guarded->set_lock_duration_timeout(value);
     775        2999 :                     if(value < g_min_timeout[1])
     776             :                     {
     777         564 :                         CATCH_REQUIRE(guarded->get_lock_duration_timeout() == g_min_timeout[1]);
     778             :                     }
     779        2435 :                     else if(value > g_max_timeout[1])
     780             :                     {
     781         553 :                         CATCH_REQUIRE(guarded->get_lock_duration_timeout() == g_max_timeout[1]);
     782             :                     }
     783             :                     else
     784             :                     {
     785             :                         // otherwise not clamped
     786             :                         //
     787        1882 :                         CATCH_REQUIRE(guarded->get_lock_duration_timeout() == value);
     788             :                     }
     789        2999 :                     break;
     790             : 
     791        2961 :                 case 2: // unlock timeout
     792        2961 :                     guarded->set_unlock_timeout(value);
     793        2961 :                     if(value < g_min_timeout[2])
     794             :                     {
     795         612 :                         CATCH_REQUIRE(guarded->get_unlock_timeout() == g_min_timeout[2]);
     796             :                     }
     797        2349 :                     else if(value > g_max_timeout[2])
     798             :                     {
     799         587 :                         CATCH_REQUIRE(guarded->get_unlock_timeout() == g_max_timeout[2]);
     800             :                     }
     801             :                     else
     802             :                     {
     803             :                         // otherwise not clamped
     804             :                         //
     805        1762 :                         CATCH_REQUIRE(guarded->get_unlock_timeout() == value);
     806             :                     }
     807        2961 :                     break;
     808             : 
     809             :                 }
     810             :             }
     811             :         }
     812             :     }
     813          10 :     CATCH_END_SECTION()
     814             : 
     815          11 :     CATCH_START_SECTION("cluck_client: successful LOCK (simple)")
     816             :     {
     817           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
     818           1 :         std::string const filename(source_dir + "/tests/rprtr/successful_lock.rprtr");
     819           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
     820           1 :         CATCH_REQUIRE(l != nullptr);
     821           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
     822           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
     823           1 :         p->parse_program();
     824             : 
     825           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_string::pointer_t var(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::variable_string>("test_case", "string"));
     826           1 :         var->set_string("valid");
     827           1 :         s->set_variable(var);
     828             : 
     829           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
     830           1 :         e->start();
     831             : 
     832           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
     833           2 :                   get_address()
     834           1 :                 , ed::mode_t::MODE_PLAIN
     835           3 :                 , test_messenger::sequence_t::SEQUENCE_SUCCESS));
     836           1 :         ed::communicator::instance()->add_connection(messenger);
     837           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
     838           1 :         ed::communicator::instance()->add_connection(timer);
     839           1 :         messenger->set_timer(timer);
     840             : 
     841           1 :         bool was_ready(false);
     842           3 :         cluck::listen_to_cluck_status(
     843             :               messenger
     844           2 :             , messenger->get_dispatcher()
     845           2 :             , [&was_ready](ed::message & msg) {
     846           1 :                 if(msg.get_command() != cluck::g_name_cluck_cmd_lock_ready
     847           1 :                 && msg.get_command() != cluck::g_name_cluck_cmd_no_lock)
     848             :                 {
     849           0 :                     throw std::runtime_error("listen to cluck status receive an unexpected mesage.");
     850             :                 }
     851           1 :                 if(cluck::is_lock_ready())
     852             :                 {
     853           1 :                     was_ready = true;
     854             :                 }
     855           1 :             });
     856             : 
     857           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
     858             :               "lock-name"
     859             :             , messenger
     860           2 :             , messenger->get_dispatcher()
     861           3 :             , cluck::mode_t::CLUCK_MODE_SIMPLE));
     862           1 :         ed::communicator::instance()->add_connection(guarded);
     863           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_SIMPLE);
     864           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
     865           1 :         messenger->set_guard(guarded);
     866             : 
     867           1 :         e->set_thread_done_callback([messenger, timer, guarded]()
     868             :             {
     869           1 :                 ed::communicator::instance()->remove_connection(messenger);
     870           1 :                 ed::communicator::instance()->remove_connection(timer);
     871           1 :                 ed::communicator::instance()->remove_connection(guarded);
     872           1 :             });
     873             : 
     874           1 :         messenger->set_expect_lock_obtained(true);
     875           1 :         CATCH_REQUIRE(e->run());
     876             : 
     877           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
     878           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
     879           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_NONE);
     880           1 :         CATCH_REQUIRE(guarded->get_timeout_date() == cluck::timeout_t());
     881             : 
     882           1 :         messenger->unset_guard();
     883             : 
     884           1 :         CATCH_REQUIRE(was_ready);
     885           1 :     }
     886          10 :     CATCH_END_SECTION()
     887             : 
     888          11 :     CATCH_START_SECTION("cluck_client: successful LOCK (extended)")
     889             :     {
     890           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
     891           1 :         std::string const filename(source_dir + "/tests/rprtr/extended_lock.rprtr");
     892           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
     893           1 :         CATCH_REQUIRE(l != nullptr);
     894           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
     895           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
     896           1 :         p->parse_program();
     897             : 
     898           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
     899           1 :         e->start();
     900             : 
     901           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
     902           2 :                   get_address()
     903           1 :                 , ed::mode_t::MODE_PLAIN
     904           3 :                 , test_messenger::sequence_t::SEQUENCE_EXTENDED));
     905           1 :         ed::communicator::instance()->add_connection(messenger);
     906           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
     907           1 :         ed::communicator::instance()->add_connection(timer);
     908           1 :         messenger->set_timer(timer);
     909             : 
     910           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
     911             :               "lock-name"
     912             :             , messenger
     913           2 :             , messenger->get_dispatcher()
     914           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
     915           1 :         ed::communicator::instance()->add_connection(guarded);
     916           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
     917           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
     918           1 :         guarded->unlock(); // nothing happens, we're not locked
     919           1 :         guarded->set_type(cluck::type_t::CLUCK_TYPE_READ_ONLY);
     920           1 :         guarded->set_lock_obtention_timeout({ 10, 500'000'000 }); // 10.5s
     921           1 :         guarded->set_lock_duration_timeout({ 60 * 60, 0 }); // 1h
     922           1 :         guarded->set_unlock_timeout({ 0, 500'000'000 }); // 0.5s
     923           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_ONLY);
     924           1 :         messenger->set_guard(guarded);
     925             : 
     926           1 :         e->set_thread_done_callback([messenger, timer, guarded]()
     927             :             {
     928           1 :                 ed::communicator::instance()->remove_connection(messenger);
     929           1 :                 ed::communicator::instance()->remove_connection(timer);
     930           1 :                 ed::communicator::instance()->remove_connection(guarded);
     931           1 :             });
     932             : 
     933           1 :         messenger->set_expect_lock_obtained(true);
     934           1 :         CATCH_REQUIRE(e->run());
     935             : 
     936           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
     937           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
     938           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_NONE);
     939           1 :         CATCH_REQUIRE(guarded->get_timeout_date() == cluck::timeout_t());
     940             : 
     941           1 :         messenger->unset_guard();
     942           1 :     }
     943          10 :     CATCH_END_SECTION()
     944             : 
     945             :     // since I added the check_parameters() call, this test fails since
     946             :     // the callback doesn't get called
     947             :     //
     948             :     //CATCH_START_SECTION("cluck_client: failing LOCKED (invalid parameters)")
     949             :     //{
     950             :     //    std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
     951             :     //    std::string const filename(source_dir + "/tests/rprtr/invalid_parameters_lock.rprtr");
     952             :     //    SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
     953             :     //    CATCH_REQUIRE(l != nullptr);
     954             :     //    SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
     955             :     //    SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
     956             :     //    p->parse_program();
     957             : 
     958             :     //    SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
     959             :     //    e->start();
     960             : 
     961             :     //    test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
     962             :     //              get_address()
     963             :     //            , ed::mode_t::MODE_PLAIN
     964             :     //            , test_messenger::sequence_t::SEQUENCE_FAIL_MISSING_LOCKED_PARAMETERS));
     965             :     //    ed::communicator::instance()->add_connection(messenger);
     966             :     //    test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
     967             :     //    ed::communicator::instance()->add_connection(timer);
     968             :     //    messenger->set_timer(timer);
     969             : 
     970             :     //    cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
     971             :     //          "lock-name"
     972             :     //        , messenger
     973             :     //        , messenger->get_dispatcher()
     974             :     //        , cluck::mode_t::CLUCK_MODE_EXTENDED));
     975             :     //    ed::communicator::instance()->add_connection(guarded);
     976             :     //    CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
     977             :     //    CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
     978             :     //    messenger->set_guard(guarded);
     979             : 
     980             :     //    e->set_thread_done_callback([messenger, timer, guarded]()
     981             :     //        {
     982             :     //            ed::communicator::instance()->remove_connection(messenger);
     983             :     //            ed::communicator::instance()->remove_connection(timer);
     984             :     //            ed::communicator::instance()->remove_connection(guarded);
     985             :     //        });
     986             : 
     987             :     //    messenger->set_expect_lock_failed(true);
     988             :     //    messenger->set_expect_finally(true);
     989             :     //    CATCH_REQUIRE_FALSE(e->run());
     990             : 
     991             :     //    CATCH_REQUIRE(s->get_exit_code() == 0);
     992             :     //    CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
     993             :     //    CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_INVALID);
     994             :     //    CATCH_REQUIRE(guarded->get_timeout_date() == cluck::timeout_t());
     995             : 
     996             :     //    messenger->unset_guard();
     997             :     //}
     998             :     //CATCH_END_SECTION()
     999             : 
    1000          11 :     CATCH_START_SECTION("cluck_client: failing UNLOCKED (invalid object name)")
    1001             :     {
    1002           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1003           1 :         std::string const filename(source_dir + "/tests/rprtr/invalid_parameters_unlock.rprtr");
    1004           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1005           1 :         CATCH_REQUIRE(l != nullptr);
    1006           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1007           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1008           1 :         p->parse_program();
    1009             : 
    1010           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1011           1 :         e->start();
    1012             : 
    1013           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1014           2 :                   get_address()
    1015           1 :                 , ed::mode_t::MODE_PLAIN
    1016           3 :                 , test_messenger::sequence_t::SEQUENCE_FAIL_MISSING_UNLOCKED_PARAMETERS));
    1017           1 :         ed::communicator::instance()->add_connection(messenger);
    1018           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1019           1 :         ed::communicator::instance()->add_connection(timer);
    1020           1 :         messenger->set_timer(timer);
    1021             : 
    1022           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1023             :               "lock-name"
    1024             :             , messenger
    1025           2 :             , messenger->get_dispatcher()
    1026           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1027           1 :         ed::communicator::instance()->add_connection(guarded);
    1028           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1029           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1030           1 :         messenger->set_guard(guarded);
    1031             : 
    1032           1 :         e->set_thread_done_callback([messenger, timer, guarded]()
    1033             :             {
    1034           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1035           1 :                 ed::communicator::instance()->remove_connection(timer);
    1036           1 :                 ed::communicator::instance()->remove_connection(guarded);
    1037           1 :             });
    1038             : 
    1039           1 :         messenger->set_expect_lock_obtained(true);
    1040           1 :         messenger->set_expect_lock_failed(true);
    1041           1 :         messenger->set_expect_finally(true);
    1042           1 :         CATCH_REQUIRE(e->run());
    1043             : 
    1044           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1045           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1046           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_INVALID);
    1047           1 :         CATCH_REQUIRE(guarded->get_timeout_date() == cluck::timeout_t());
    1048             : 
    1049           1 :         messenger->unset_guard();
    1050           1 :     }
    1051          10 :     CATCH_END_SECTION()
    1052             : 
    1053          11 :     CATCH_START_SECTION("cluck_client: UNLOCKING--cluckd server safe timeout")
    1054             :     {
    1055           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1056           1 :         std::string const filename(source_dir + "/tests/rprtr/explicit_unlocking.rprtr");
    1057           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1058           1 :         CATCH_REQUIRE(l != nullptr);
    1059           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1060           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1061           1 :         p->parse_program();
    1062             : 
    1063           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1064           1 :         e->start();
    1065             : 
    1066           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1067           2 :                   get_address()
    1068           1 :                 , ed::mode_t::MODE_PLAIN
    1069           3 :                 , test_messenger::sequence_t::SEQUENCE_SAFE_UNLOCKING));
    1070           1 :         ed::communicator::instance()->add_connection(messenger);
    1071           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1072           1 :         ed::communicator::instance()->add_connection(timer);
    1073           1 :         messenger->set_timer(timer);
    1074             : 
    1075           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1076             :               "unlocking-lock"
    1077             :             , messenger
    1078           2 :             , messenger->get_dispatcher()
    1079           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1080             :         // although this is a safe unlocking (i.e. before the unlock timeout
    1081             :         // time) we would still timeout on our side if we added guarded to
    1082             :         // the communicator; so don't do that in this test
    1083             :         //
    1084             :         //ed::communicator::instance()->add_connection(guarded);
    1085           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1086           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1087           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1088           1 :         messenger->set_guard(guarded);
    1089             : 
    1090           1 :         e->set_thread_done_callback([messenger, timer]()
    1091             :             {
    1092           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1093           1 :                 ed::communicator::instance()->remove_connection(timer);
    1094             :                 //ed::communicator::instance()->remove_connection(guarded);
    1095           1 :             });
    1096             : 
    1097           1 :         messenger->set_expect_lock_obtained(true);
    1098           1 :         messenger->set_expect_lock_failed(true);
    1099           1 :         messenger->set_expect_finally(true);
    1100           1 :         CATCH_REQUIRE(e->run());
    1101             : 
    1102           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1103           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1104           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_NONE);
    1105           1 :         CATCH_REQUIRE(guarded->get_timeout_date() == cluck::timeout_t());
    1106             : 
    1107           1 :         messenger->unset_guard();
    1108           1 :     }
    1109          10 :     CATCH_END_SECTION()
    1110             : 
    1111          11 :     CATCH_START_SECTION("cluck_client: UNLOCKING--cluckd server late timeout")
    1112             :     {
    1113           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1114           1 :         std::string const filename(source_dir + "/tests/rprtr/late_explicit_unlocking.rprtr");
    1115           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1116           1 :         CATCH_REQUIRE(l != nullptr);
    1117           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1118           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1119           1 :         p->parse_program();
    1120             : 
    1121           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1122           1 :         e->start();
    1123             : 
    1124           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1125           2 :                   get_address()
    1126           1 :                 , ed::mode_t::MODE_PLAIN
    1127           3 :                 , test_messenger::sequence_t::SEQUENCE_UNSAFE_UNLOCKING));
    1128           1 :         ed::communicator::instance()->add_connection(messenger);
    1129           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1130           1 :         ed::communicator::instance()->add_connection(timer);
    1131           1 :         messenger->set_timer(timer);
    1132             : 
    1133           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1134             :               "unlocking-lock"
    1135             :             , messenger
    1136           2 :             , messenger->get_dispatcher()
    1137           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1138             :         // testing the remote timeout by receiving an UNLOCKING message
    1139             :         // so do not add the guarded timer to the communicator
    1140             :         //
    1141             :         //ed::communicator::instance()->add_connection(guarded);
    1142           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1143           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1144           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1145           1 :         guarded->set_lock_duration_timeout(cluck::timeout_t(1, 0));
    1146           1 :         guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1147           1 :         messenger->set_guard(guarded);
    1148             : 
    1149           1 :         e->set_thread_done_callback([messenger, timer]()
    1150             :             {
    1151           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1152           1 :                 ed::communicator::instance()->remove_connection(timer);
    1153             :                 //ed::communicator::instance()->remove_connection(guarded);
    1154           1 :             });
    1155             : 
    1156           1 :         messenger->set_expect_lock_obtained(true);
    1157           1 :         messenger->set_expect_lock_failed(true);
    1158           1 :         messenger->set_expect_finally(true);
    1159           1 :         CATCH_REQUIRE(e->run());
    1160             : 
    1161           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1162           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1163           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_REMOTE_TIMEOUT);
    1164             :         //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1165             : 
    1166           1 :         messenger->unset_guard();
    1167           1 :     }
    1168          10 :     CATCH_END_SECTION()
    1169             : 
    1170          11 :     CATCH_START_SECTION("cluck_client: UNLOCKING--invalid object name")
    1171             :     {
    1172           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1173           1 :         std::string const filename(source_dir + "/tests/rprtr/invalid_unlocking.rprtr");
    1174           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1175           1 :         CATCH_REQUIRE(l != nullptr);
    1176           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1177           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1178           1 :         p->parse_program();
    1179             : 
    1180           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1181           1 :         e->start();
    1182             : 
    1183           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1184           2 :                   get_address()
    1185           1 :                 , ed::mode_t::MODE_PLAIN
    1186           3 :                 , test_messenger::sequence_t::SEQUENCE_INVALID_UNLOCKING));
    1187           1 :         ed::communicator::instance()->add_connection(messenger);
    1188           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1189           1 :         ed::communicator::instance()->add_connection(timer);
    1190           1 :         messenger->set_timer(timer);
    1191             : 
    1192           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1193             :               "unlocking-lock"
    1194             :             , messenger
    1195           2 :             , messenger->get_dispatcher()
    1196           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1197             :         // here we again need to get the UNLOCKING even from the remote to
    1198             :         // verify the invalid object name; so we do not want to time out
    1199             :         // locally before the remote has a chance to send us the UNLOCKING
    1200             :         // event and we process it
    1201             :         //
    1202             :         //ed::communicator::instance()->add_connection(guarded);
    1203           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1204           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1205           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1206           1 :         guarded->set_lock_duration_timeout(cluck::timeout_t(1, 0));
    1207           1 :         guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1208           1 :         messenger->set_guard(guarded);
    1209             : 
    1210           1 :         e->set_thread_done_callback([messenger, timer]()
    1211             :             {
    1212           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1213           1 :                 ed::communicator::instance()->remove_connection(timer);
    1214             :                 //ed::communicator::instance()->remove_connection(guarded);
    1215           1 :             });
    1216             : 
    1217           1 :         messenger->set_expect_lock_obtained(true);
    1218           1 :         messenger->set_expect_lock_failed(true);
    1219           1 :         messenger->set_expect_finally(true);
    1220           1 :         CATCH_REQUIRE(e->run());
    1221             : 
    1222           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1223           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1224           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_INVALID);
    1225             :         //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1226             : 
    1227           1 :         messenger->unset_guard();
    1228           1 :     }
    1229          10 :     CATCH_END_SECTION()
    1230             : 
    1231          11 :     CATCH_START_SECTION("cluck_client: spurious TRANSMISSION_REPORT")
    1232             :     {
    1233           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1234           1 :         std::string const filename(source_dir + "/tests/rprtr/ignored_transmission_report.rprtr");
    1235           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1236           1 :         CATCH_REQUIRE(l != nullptr);
    1237           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1238           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1239           1 :         p->parse_program();
    1240             : 
    1241           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1242           1 :         e->start();
    1243             : 
    1244           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1245           2 :                   get_address()
    1246           1 :                 , ed::mode_t::MODE_PLAIN
    1247           3 :                 , test_messenger::sequence_t::SEQUENCE_EXTENDED));
    1248           1 :         ed::communicator::instance()->add_connection(messenger);
    1249           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1250           1 :         ed::communicator::instance()->add_connection(timer);
    1251           1 :         messenger->set_timer(timer);
    1252             : 
    1253           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1254             :               "lock-name"
    1255             :             , messenger
    1256           2 :             , messenger->get_dispatcher()
    1257           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1258             :         // here we again need to get the UNLOCKING even from the remote to
    1259             :         // verify the invalid object name; so we do not want to time out
    1260             :         // locally before the remote has a chance to send us the UNLOCKING
    1261             :         // event and we process it
    1262             :         //
    1263             :         //ed::communicator::instance()->add_connection(guarded);
    1264           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1265           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1266           1 :         guarded->set_type(cluck::type_t::CLUCK_TYPE_READ_ONLY);
    1267           1 :         guarded->set_lock_obtention_timeout({ 10, 500'000'000 }); // 10.5s
    1268           1 :         guarded->set_lock_duration_timeout({ 60 * 60, 0 }); // 1h
    1269           1 :         guarded->set_unlock_timeout({ 0, 500'000'000 }); // 0.5s
    1270           1 :         messenger->set_guard(guarded);
    1271             : 
    1272           1 :         e->set_thread_done_callback([messenger, timer, guarded]()
    1273             :             {
    1274           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1275           1 :                 ed::communicator::instance()->remove_connection(timer);
    1276           1 :                 ed::communicator::instance()->remove_connection(guarded);
    1277           1 :             });
    1278             : 
    1279           1 :         messenger->set_expect_lock_obtained(true);
    1280           1 :         CATCH_REQUIRE(e->run());
    1281             : 
    1282           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1283           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1284           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_NONE);
    1285             :         //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1286             : 
    1287           1 :         messenger->unset_guard();
    1288           1 :     }
    1289          10 :     CATCH_END_SECTION()
    1290             : 
    1291          11 :     CATCH_START_SECTION("cluck_client: TRANSMISSION_REPORT--could not send message to a cluck daemon")
    1292             :     {
    1293           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1294           1 :         std::string const filename(source_dir + "/tests/rprtr/transmission_report_not_sent.rprtr");
    1295           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1296           1 :         CATCH_REQUIRE(l != nullptr);
    1297           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1298           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1299           1 :         p->parse_program();
    1300             : 
    1301           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1302           1 :         e->start();
    1303             : 
    1304           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1305           2 :                   get_address()
    1306           1 :                 , ed::mode_t::MODE_PLAIN
    1307           3 :                 , test_messenger::sequence_t::SEQUENCE_TRANSMISSION_REPORT));
    1308           1 :         ed::communicator::instance()->add_connection(messenger);
    1309           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1310           1 :         ed::communicator::instance()->add_connection(timer);
    1311           1 :         messenger->set_timer(timer);
    1312             : 
    1313           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1314             :               "lock-not-received"
    1315             :             , messenger
    1316           2 :             , messenger->get_dispatcher()
    1317           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1318             :         // here we again need to get the UNLOCKING even from the remote to
    1319             :         // verify the invalid object name; so we do not want to time out
    1320             :         // locally before the remote has a chance to send us the UNLOCKING
    1321             :         // event and we process it
    1322             :         //
    1323             :         //ed::communicator::instance()->add_connection(guarded);
    1324           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1325           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1326           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1327           1 :         guarded->set_lock_duration_timeout(cluck::timeout_t(1, 0));
    1328           1 :         guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1329           1 :         messenger->set_guard(guarded);
    1330             : 
    1331           1 :         e->set_thread_done_callback([messenger, timer]()
    1332             :             {
    1333           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1334           1 :                 ed::communicator::instance()->remove_connection(timer);
    1335             :                 //ed::communicator::instance()->remove_connection(guarded);
    1336           1 :             });
    1337             : 
    1338           1 :         messenger->set_expect_lock_obtained(true);
    1339           1 :         messenger->set_expect_lock_failed(true);
    1340           1 :         messenger->set_expect_finally(true);
    1341           1 :         CATCH_REQUIRE(e->run());
    1342             : 
    1343           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1344           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1345           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_TRANSMISSION_ERROR);
    1346             :         //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1347             : 
    1348           1 :         messenger->unset_guard();
    1349           1 :     }
    1350          10 :     CATCH_END_SECTION()
    1351           9 : }
    1352             : 
    1353             : 
    1354           9 : CATCH_TEST_CASE("cluck_client_error", "[cluck][client][error]")
    1355             : {
    1356          11 :     CATCH_START_SECTION("cluck_client_error: messenger required")
    1357             :     {
    1358             :         // create a messenger so we have a dispatcher pointer
    1359             :         //
    1360           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1361           2 :                   get_address()
    1362           1 :                 , ed::mode_t::MODE_PLAIN
    1363           3 :                 , test_messenger::sequence_t::SEQUENCE_EXTENDED));
    1364             : 
    1365           6 :         CATCH_REQUIRE_THROWS_MATCHES(
    1366             :               std::make_shared<cluck::cluck>(
    1367             :                       "invalid-lock-setup"
    1368             :                     , test_messenger::pointer_t()
    1369             :                     , messenger->get_dispatcher()
    1370             :                     , cluck::mode_t::CLUCK_MODE_EXTENDED)
    1371             :             , cluck::invalid_parameter
    1372             :             , Catch::Matchers::ExceptionMessage("cluck_exception: messenger & dispatcher parameters must be defined in cluck::cluck() constructor."));
    1373           1 :     }
    1374          10 :     CATCH_END_SECTION()
    1375             : 
    1376          11 :     CATCH_START_SECTION("cluck_client_error: dispatcher required")
    1377             :     {
    1378             :         // create a messenger so we have a dispatcher pointer
    1379             :         //
    1380           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1381           2 :                   get_address()
    1382           1 :                 , ed::mode_t::MODE_PLAIN
    1383           3 :                 , test_messenger::sequence_t::SEQUENCE_EXTENDED));
    1384             : 
    1385           4 :         CATCH_REQUIRE_THROWS_MATCHES(
    1386             :               std::make_shared<cluck::cluck>(
    1387             :                       "invalid-lock-setup"
    1388             :                     , messenger
    1389             :                     , ed::dispatcher::pointer_t()
    1390             :                     , cluck::mode_t::CLUCK_MODE_EXTENDED)
    1391             :             , cluck::invalid_parameter
    1392             :             , Catch::Matchers::ExceptionMessage("cluck_exception: messenger & dispatcher parameters must be defined in cluck::cluck() constructor."));
    1393           1 :     }
    1394          10 :     CATCH_END_SECTION()
    1395             : 
    1396          11 :     CATCH_START_SECTION("cluck_client_error: LOCK_FAILED--pretend the LOCK times out")
    1397             :     {
    1398           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1399           1 :         std::string const filename(source_dir + "/tests/rprtr/failed_with_timeout.rprtr");
    1400           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1401           1 :         CATCH_REQUIRE(l != nullptr);
    1402           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1403           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1404           1 :         p->parse_program();
    1405             : 
    1406           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1407           1 :         e->start();
    1408             : 
    1409           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1410           2 :                   get_address()
    1411           1 :                 , ed::mode_t::MODE_PLAIN
    1412           3 :                 , test_messenger::sequence_t::SEQUENCE_FAILED_TIMEOUT));
    1413           1 :         ed::communicator::instance()->add_connection(messenger);
    1414           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1415           1 :         ed::communicator::instance()->add_connection(timer);
    1416           1 :         messenger->set_timer(timer);
    1417             : 
    1418           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1419             :               "lock-timeout"
    1420             :             , messenger
    1421           2 :             , messenger->get_dispatcher()
    1422           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1423             :         // here we again need to get the UNLOCKING even from the remote to
    1424             :         // verify the invalid object name; so we do not want to time out
    1425             :         // locally before the remote has a chance to send us the UNLOCKING
    1426             :         // event and we process it
    1427             :         //
    1428             :         //ed::communicator::instance()->add_connection(guarded);
    1429           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1430           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1431           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1432           1 :         guarded->set_lock_duration_timeout(cluck::timeout_t(1, 0));
    1433           1 :         guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1434           1 :         messenger->set_guard(guarded);
    1435             : 
    1436           1 :         e->set_thread_done_callback([messenger, timer]()
    1437             :             {
    1438           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1439           1 :                 ed::communicator::instance()->remove_connection(timer);
    1440             :                 //ed::communicator::instance()->remove_connection(guarded);
    1441           1 :             });
    1442             : 
    1443           1 :         messenger->set_expect_lock_obtained(true);
    1444           1 :         messenger->set_expect_lock_failed(true);
    1445           1 :         messenger->set_expect_finally(true);
    1446           1 :         CATCH_REQUIRE(e->run());
    1447             : 
    1448           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1449           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1450           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_REMOTE_TIMEOUT);
    1451             :         //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1452             : 
    1453           1 :         messenger->unset_guard();
    1454           1 :     }
    1455          10 :     CATCH_END_SECTION()
    1456             : 
    1457          11 :     CATCH_START_SECTION("cluck_client_error: LOCK_FAILED--invalid tag")
    1458             :     {
    1459           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1460           1 :         std::string const filename(source_dir + "/tests/rprtr/failed_with_invalid_tag.rprtr");
    1461           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1462           1 :         CATCH_REQUIRE(l != nullptr);
    1463           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1464           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1465           1 :         p->parse_program();
    1466             : 
    1467           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1468           1 :         e->start();
    1469             : 
    1470           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1471           2 :                   get_address()
    1472           1 :                 , ed::mode_t::MODE_PLAIN
    1473           3 :                 , test_messenger::sequence_t::SEQUENCE_FAILED_INVALID));
    1474           1 :         ed::communicator::instance()->add_connection(messenger);
    1475           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1476           1 :         ed::communicator::instance()->add_connection(timer);
    1477           1 :         messenger->set_timer(timer);
    1478             : 
    1479           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1480             :               "lock-timeout"
    1481             :             , messenger
    1482           2 :             , messenger->get_dispatcher()
    1483           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1484             :         // here we again need to get the UNLOCKING even from the remote to
    1485             :         // verify the invalid object name; so we do not want to time out
    1486             :         // locally before the remote has a chance to send us the UNLOCKING
    1487             :         // event and we process it
    1488             :         //
    1489             :         //ed::communicator::instance()->add_connection(guarded);
    1490           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1491           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1492           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1493           1 :         guarded->set_lock_duration_timeout(cluck::timeout_t(1, 0));
    1494           1 :         guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1495           1 :         messenger->set_guard(guarded);
    1496             : 
    1497           1 :         e->set_thread_done_callback([messenger, timer]()
    1498             :             {
    1499           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1500           1 :                 ed::communicator::instance()->remove_connection(timer);
    1501             :                 //ed::communicator::instance()->remove_connection(guarded);
    1502           1 :             });
    1503             : 
    1504           1 :         messenger->set_expect_lock_obtained(true);
    1505           1 :         messenger->set_expect_lock_failed(true);
    1506           1 :         messenger->set_expect_finally(true);
    1507           1 :         CATCH_REQUIRE(e->run());
    1508             : 
    1509           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1510           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1511           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_INVALID);
    1512             :         //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1513             : 
    1514           1 :         messenger->unset_guard();
    1515           1 :     }
    1516          10 :     CATCH_END_SECTION()
    1517             : 
    1518          11 :     CATCH_START_SECTION("cluck_client_error: LOCK_FAILED--other error (not timeout)")
    1519             :     {
    1520           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1521           1 :         std::string const filename(source_dir + "/tests/rprtr/failed_with_other_error.rprtr");
    1522           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1523           1 :         CATCH_REQUIRE(l != nullptr);
    1524           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1525           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1526           1 :         p->parse_program();
    1527             : 
    1528           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1529           1 :         e->start();
    1530             : 
    1531           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1532           2 :                   get_address()
    1533           1 :                 , ed::mode_t::MODE_PLAIN
    1534           3 :                 , test_messenger::sequence_t::SEQUENCE_FAILED_OTHER_ERROR));
    1535           1 :         ed::communicator::instance()->add_connection(messenger);
    1536           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1537           1 :         ed::communicator::instance()->add_connection(timer);
    1538           1 :         messenger->set_timer(timer);
    1539             : 
    1540           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1541             :               "lock-timeout"
    1542             :             , messenger
    1543           2 :             , messenger->get_dispatcher()
    1544           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1545             :         // here we again need to get the UNLOCKING even from the remote to
    1546             :         // verify the invalid object name; so we do not want to time out
    1547             :         // locally before the remote has a chance to send us the UNLOCKING
    1548             :         // event and we process it
    1549             :         //
    1550             :         //ed::communicator::instance()->add_connection(guarded);
    1551           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1552           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1553           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1554           1 :         guarded->set_lock_duration_timeout(cluck::timeout_t(1, 0));
    1555           1 :         guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1556           1 :         messenger->set_guard(guarded);
    1557             : 
    1558           1 :         e->set_thread_done_callback([messenger, timer]()
    1559             :             {
    1560           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1561           1 :                 ed::communicator::instance()->remove_connection(timer);
    1562             :                 //ed::communicator::instance()->remove_connection(guarded);
    1563           1 :             });
    1564             : 
    1565           1 :         messenger->set_expect_lock_obtained(true);
    1566           1 :         messenger->set_expect_lock_failed(true);
    1567           1 :         messenger->set_expect_finally(true);
    1568           1 :         CATCH_REQUIRE(e->run());
    1569             : 
    1570           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1571           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1572           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_INVALID);
    1573             :         //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1574             : 
    1575           1 :         messenger->unset_guard();
    1576           1 :     }
    1577          10 :     CATCH_END_SECTION()
    1578             : 
    1579             :     // since I implemented the message::check() test, this unit test does not
    1580             :     // work too well--we get errors and then finally is not called...
    1581             :     //
    1582             :     //CATCH_START_SECTION("cluck_client_error: LOCK_FAILED--error missing")
    1583             :     //{
    1584             :     //    std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1585             :     //    std::string const filename(source_dir + "/tests/rprtr/failed_with_error_missing.rprtr");
    1586             :     //    SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1587             :     //    CATCH_REQUIRE(l != nullptr);
    1588             :     //    SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1589             :     //    SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1590             :     //    p->parse_program();
    1591             : 
    1592             :     //    SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1593             :     //    e->start();
    1594             : 
    1595             :     //    test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1596             :     //              get_address()
    1597             :     //            , ed::mode_t::MODE_PLAIN
    1598             :     //            , test_messenger::sequence_t::SEQUENCE_FAILED_OTHER_ERROR));
    1599             :     //    ed::communicator::instance()->add_connection(messenger);
    1600             :     //    test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1601             :     //    ed::communicator::instance()->add_connection(timer);
    1602             :     //    messenger->set_timer(timer);
    1603             : 
    1604             :     //    cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1605             :     //          "lock-timeout"
    1606             :     //        , messenger
    1607             :     //        , messenger->get_dispatcher()
    1608             :     //        , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1609             :     //    // here we again need to get the UNLOCKING even from the remote to
    1610             :     //    // verify the invalid object name; so we do not want to time out
    1611             :     //    // locally before the remote has a chance to send us the UNLOCKING
    1612             :     //    // event and we process it
    1613             :     //    //
    1614             :     //    //ed::communicator::instance()->add_connection(guarded);
    1615             :     //    CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1616             :     //    CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1617             :     //    guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1618             :     //    guarded->set_lock_duration_timeout(cluck::timeout_t(1, 0));
    1619             :     //    guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1620             :     //    messenger->set_guard(guarded);
    1621             : 
    1622             :     //    e->set_thread_done_callback([messenger, timer]()
    1623             :     //        {
    1624             :     //            ed::communicator::instance()->remove_connection(messenger);
    1625             :     //            ed::communicator::instance()->remove_connection(timer);
    1626             :     //            //ed::communicator::instance()->remove_connection(guarded);
    1627             :     //        });
    1628             : 
    1629             :     //    messenger->set_expect_lock_obtained(true);
    1630             :     //    messenger->set_expect_lock_failed(true);
    1631             :     //    messenger->set_expect_finally(true);
    1632             :     //    CATCH_REQUIRE(e->run());
    1633             : 
    1634             :     //    CATCH_REQUIRE(s->get_exit_code() == 0);
    1635             :     //    CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1636             :     //    CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_INVALID);
    1637             :     //    //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1638             : 
    1639             :     //    messenger->unset_guard();
    1640             :     //}
    1641             :     //CATCH_END_SECTION()
    1642             : 
    1643          11 :     CATCH_START_SECTION("cluck_client_error: LOCK times out locally")
    1644             :     {
    1645           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1646           1 :         std::string const filename(source_dir + "/tests/rprtr/lock_timing_out.rprtr");
    1647           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1648           1 :         CATCH_REQUIRE(l != nullptr);
    1649           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1650           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1651           1 :         p->parse_program();
    1652             : 
    1653           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1654           1 :         e->start();
    1655             : 
    1656           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1657           2 :                   get_address()
    1658           1 :                 , ed::mode_t::MODE_PLAIN
    1659           3 :                 , test_messenger::sequence_t::SEQUENCE_EXTENDED));
    1660           1 :         ed::communicator::instance()->add_connection(messenger);
    1661           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1662           1 :         ed::communicator::instance()->add_connection(timer);
    1663           1 :         messenger->set_timer(timer);
    1664             : 
    1665           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1666             :               "lock-name"
    1667             :             , messenger
    1668           2 :             , messenger->get_dispatcher()
    1669           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1670           1 :         ed::communicator::instance()->add_connection(guarded);
    1671           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1672           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1673           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1674           1 :         guarded->set_lock_duration_timeout(cluck::timeout_t(1, 0));
    1675           1 :         guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1676           1 :         messenger->set_guard(guarded);
    1677             : 
    1678           1 :         e->set_thread_done_callback([messenger, timer, guarded]()
    1679             :             {
    1680           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1681           1 :                 ed::communicator::instance()->remove_connection(timer);
    1682           1 :                 ed::communicator::instance()->remove_connection(guarded);
    1683           1 :             });
    1684             : 
    1685           1 :         messenger->set_expect_lock_obtained(true);
    1686           1 :         messenger->set_expect_lock_failed(true);
    1687           1 :         messenger->set_expect_finally(true);
    1688           1 :         CATCH_REQUIRE(e->run());
    1689             : 
    1690           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1691           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1692           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_LOCAL_TIMEOUT);
    1693             :         //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1694             : 
    1695           1 :         messenger->unset_guard();
    1696           1 :     }
    1697          10 :     CATCH_END_SECTION()
    1698             : 
    1699          11 :     CATCH_START_SECTION("cluck_client_error: LOCKED timing out locally (LOCK works, get replay, never UNLOCK...)")
    1700             :     {
    1701           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1702           1 :         std::string const filename(source_dir + "/tests/rprtr/locked_timing_out.rprtr");
    1703           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1704           1 :         CATCH_REQUIRE(l != nullptr);
    1705           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1706           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1707           1 :         p->parse_program();
    1708             : 
    1709           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1710           1 :         e->start();
    1711             : 
    1712           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1713           2 :                   get_address()
    1714           1 :                 , ed::mode_t::MODE_PLAIN
    1715           3 :                 , test_messenger::sequence_t::SEQUENCE_EXTENDED_SMALL_GAP));
    1716           1 :         ed::communicator::instance()->add_connection(messenger);
    1717           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1718           1 :         ed::communicator::instance()->add_connection(timer);
    1719           1 :         messenger->set_timer(timer);
    1720             : 
    1721           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1722             :               "lock-name"
    1723             :             , messenger
    1724           2 :             , messenger->get_dispatcher()
    1725           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1726           1 :         ed::communicator::instance()->add_connection(guarded);
    1727           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1728           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1729           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1730           1 :         guarded->set_lock_duration_timeout(cluck::timeout_t(1, 0));
    1731           1 :         guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1732           1 :         messenger->set_guard(guarded);
    1733             : 
    1734           1 :         e->set_thread_done_callback([messenger, timer, guarded]()
    1735             :             {
    1736           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1737           1 :                 ed::communicator::instance()->remove_connection(timer);
    1738           1 :                 ed::communicator::instance()->remove_connection(guarded);
    1739           1 :             });
    1740             : 
    1741           1 :         messenger->set_expect_lock_obtained(true);
    1742           1 :         messenger->set_expect_lock_failed(true);
    1743           1 :         messenger->set_expect_finally(true);
    1744           1 :         CATCH_REQUIRE(e->run());
    1745             : 
    1746           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1747           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1748             : 
    1749             :         // although we timed out, the final reason is "none" because we
    1750             :         // could just send an UNLOCK and received the UNLOCKED as expected
    1751             :         //
    1752           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_NONE);
    1753             : 
    1754           1 :         messenger->unset_guard();
    1755           1 :     }
    1756          10 :     CATCH_END_SECTION()
    1757             : 
    1758          11 :     CATCH_START_SECTION("cluck_client_error: LOCKING timing out locally (LOCK+UNLOCK+UNLOCKING+sleep)")
    1759             :     {
    1760           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1761           1 :         std::string const filename(source_dir + "/tests/rprtr/locking_timing_out.rprtr");
    1762           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1763           1 :         CATCH_REQUIRE(l != nullptr);
    1764           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1765           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1766           1 :         p->parse_program();
    1767             : 
    1768           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1769           1 :         e->start();
    1770             : 
    1771           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1772           2 :                   get_address()
    1773           1 :                 , ed::mode_t::MODE_PLAIN
    1774           3 :                 , test_messenger::sequence_t::SEQUENCE_EXTENDED));
    1775           1 :         ed::communicator::instance()->add_connection(messenger);
    1776           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1777           1 :         ed::communicator::instance()->add_connection(timer);
    1778           1 :         messenger->set_timer(timer);
    1779             : 
    1780           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1781             :               "lock-name"
    1782             :             , messenger
    1783           2 :             , messenger->get_dispatcher()
    1784           3 :             , cluck::mode_t::CLUCK_MODE_EXTENDED));
    1785           1 :         ed::communicator::instance()->add_connection(guarded);
    1786           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_EXTENDED);
    1787           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1788           1 :         guarded->set_lock_obtention_timeout(cluck::timeout_t(1, 0));
    1789           1 :         guarded->set_lock_duration_timeout(cluck::timeout_t(60 * 60, 0));
    1790           1 :         guarded->set_unlock_timeout(cluck::timeout_t(1, 0));
    1791           1 :         messenger->set_guard(guarded);
    1792             : 
    1793           1 :         e->set_thread_done_callback([messenger, timer, guarded]()
    1794             :             {
    1795           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1796           1 :                 ed::communicator::instance()->remove_connection(timer);
    1797           1 :                 ed::communicator::instance()->remove_connection(guarded);
    1798           1 :             });
    1799             : 
    1800           1 :         messenger->set_expect_lock_obtained(true);
    1801           1 :         messenger->set_expect_lock_failed(true);
    1802           1 :         messenger->set_expect_finally(true);
    1803           1 :         CATCH_REQUIRE(e->run());
    1804             : 
    1805           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1806           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1807           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_LOCAL_TIMEOUT);
    1808             :         //CATCH_REQUIRE(guarded->get_timeout_date() == ...); -- we could test this with a proper range
    1809             : 
    1810           1 :         messenger->unset_guard();
    1811           1 :     }
    1812          10 :     CATCH_END_SECTION()
    1813             : 
    1814          11 :     CATCH_START_SECTION("cluck_client_error: LOCKED with invalid tag")
    1815             :     {
    1816           1 :         std::string const source_dir(SNAP_CATCH2_NAMESPACE::g_source_dir());
    1817           1 :         std::string const filename(source_dir + "/tests/rprtr/successful_lock.rprtr");
    1818           1 :         SNAP_CATCH2_NAMESPACE::reporter::lexer::pointer_t l(SNAP_CATCH2_NAMESPACE::reporter::create_lexer(filename));
    1819           1 :         CATCH_REQUIRE(l != nullptr);
    1820           1 :         SNAP_CATCH2_NAMESPACE::reporter::state::pointer_t s(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::state>());
    1821           1 :         SNAP_CATCH2_NAMESPACE::reporter::parser::pointer_t p(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::parser>(l, s));
    1822           1 :         p->parse_program();
    1823             : 
    1824           1 :         SNAP_CATCH2_NAMESPACE::reporter::variable_string::pointer_t var(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::variable_string>("test_case", "string"));
    1825           1 :         var->set_string("invalid_tag");
    1826           1 :         s->set_variable(var);
    1827             : 
    1828           1 :         SNAP_CATCH2_NAMESPACE::reporter::executor::pointer_t e(std::make_shared<SNAP_CATCH2_NAMESPACE::reporter::executor>(s));
    1829           1 :         e->start();
    1830             : 
    1831           1 :         test_messenger::pointer_t messenger(std::make_shared<test_messenger>(
    1832           2 :                   get_address()
    1833           1 :                 , ed::mode_t::MODE_PLAIN
    1834           3 :                 , test_messenger::sequence_t::SEQUENCE_SUCCESS));
    1835           1 :         ed::communicator::instance()->add_connection(messenger);
    1836           1 :         test_timer::pointer_t timer(std::make_shared<test_timer>(messenger));
    1837           1 :         ed::communicator::instance()->add_connection(timer);
    1838           1 :         messenger->set_timer(timer);
    1839             : 
    1840           1 :         bool was_ready(true);
    1841           3 :         cluck::listen_to_cluck_status(
    1842             :               messenger
    1843           2 :             , messenger->get_dispatcher()
    1844           2 :             , [&was_ready](ed::message & msg) {
    1845           1 :                 if(msg.get_command() != cluck::g_name_cluck_cmd_lock_ready
    1846           1 :                 && msg.get_command() != cluck::g_name_cluck_cmd_no_lock)
    1847             :                 {
    1848           0 :                     throw std::runtime_error("listen to cluck status receive an unexpected mesage.");
    1849             :                 }
    1850           1 :                 if(!cluck::is_lock_ready())
    1851             :                 {
    1852           1 :                     was_ready = false;
    1853             :                 }
    1854           1 :             });
    1855             : 
    1856           1 :         cluck::cluck::pointer_t guarded(std::make_shared<cluck::cluck>(
    1857             :               "lock-name"
    1858             :             , messenger
    1859           2 :             , messenger->get_dispatcher()
    1860           3 :             , cluck::mode_t::CLUCK_MODE_SIMPLE));
    1861           1 :         ed::communicator::instance()->add_connection(guarded);
    1862           1 :         CATCH_REQUIRE(guarded->get_mode() == cluck::mode_t::CLUCK_MODE_SIMPLE);
    1863           1 :         CATCH_REQUIRE(guarded->get_type() == cluck::type_t::CLUCK_TYPE_READ_WRITE);
    1864           1 :         messenger->set_guard(guarded);
    1865             : 
    1866           1 :         e->set_thread_done_callback([messenger, timer, guarded]()
    1867             :             {
    1868           1 :                 ed::communicator::instance()->remove_connection(messenger);
    1869           1 :                 ed::communicator::instance()->remove_connection(timer);
    1870           1 :                 ed::communicator::instance()->remove_connection(guarded);
    1871           1 :             });
    1872             : 
    1873           1 :         messenger->set_expect_lock_obtained(true);
    1874           3 :         CATCH_REQUIRE_THROWS_MATCHES(
    1875             :               //e->run() -- this one catches exceptions so bypass that
    1876             :               ed::communicator::instance()->run()
    1877             :             , ed::invalid_message
    1878             :             , Catch::Matchers::ExceptionMessage("event_dispatcher_exception: message::get_integer_parameter(): command \"LOCKED\" expected an integer for \"tag\" but \"bad_tag\" could not be converted."));
    1879             : 
    1880           1 :         CATCH_REQUIRE(s->get_exit_code() == 0);
    1881           1 :         CATCH_REQUIRE_FALSE(messenger->get_expect_finally());
    1882           1 :         CATCH_REQUIRE(guarded->get_reason() == cluck::reason_t::CLUCK_REASON_NONE);
    1883           1 :         CATCH_REQUIRE(guarded->get_timeout_date() == cluck::timeout_t());
    1884             : 
    1885           1 :         messenger->unset_guard();
    1886             : 
    1887             :         // the communicator daemon may still have connections because of
    1888             :         // the exception
    1889             :         //
    1890           2 :         ed::connection::vector_t connections(ed::communicator::instance()->get_connections());
    1891           1 :         for(auto c : connections)
    1892             :         {
    1893           0 :             ed::communicator::instance()->remove_connection(c);
    1894           0 :         }
    1895             : 
    1896           1 :         CATCH_REQUIRE_FALSE(was_ready);
    1897           1 :     }
    1898          10 :     CATCH_END_SECTION()
    1899           9 : }
    1900             : 
    1901             : 
    1902             : 
    1903             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.14

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