LCOV - code coverage report
Current view: top level - tests - catch_cluck.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 95.0 % 979 930
Test Date: 2025-08-17 08:58:50 Functions: 91.9 % 37 34
Legend: Lines: hit not hit

            Line data    Source code
       1              : // Copyright (c) 2016-2025  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        40068 :                     + SNAP_CATCH2_NAMESPACE::g_source_dir() + "/daemon/message-definitions:"
     123        40068 :                     + SNAP_CATCH2_NAMESPACE::g_dist_dir() + "/share/eventdispatcher/messages")
     124        10017 :         , f_sequence(sequence)
     125        50085 :         , f_dispatcher(std::make_shared<ed::dispatcher>(this))
     126              :     {
     127        30051 :         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        50085 :     }
     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           27 :         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            9 :                 read.set_service("tester");
     192            9 :                 read.set_command("READ");
     193            9 :                 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            3 :                 read.set_service("tester");
     216            3 :                 read.set_command("READ");
     217            3 :                 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           12 :         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           12 :         if(msg.has_parameter("unlock"))
     391              :         {
     392            3 :             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           45 :         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         1052 :                 switch(select)
     586              :                 {
     587          324 :                 case 0: // lock obtention timeout
     588          324 :                     cluck::set_lock_obtention_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     589          324 :                     CATCH_REQUIRE(cluck::get_lock_obtention_timeout() == cluck::CLUCK_LOCK_OBTENTION_DEFAULT_TIMEOUT);
     590          324 :                     break;
     591              : 
     592          377 :                 case 1: // lock duration timeout
     593          377 :                     cluck::set_lock_duration_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     594          377 :                     CATCH_REQUIRE(cluck::get_lock_duration_timeout() == cluck::CLUCK_LOCK_DURATION_DEFAULT_TIMEOUT);
     595          377 :                     break;
     596              : 
     597          351 :                 case 2: // unlock timeout
     598          351 :                     cluck::set_unlock_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     599          351 :                     CATCH_REQUIRE(cluck::get_unlock_timeout() == cluck::CLUCK_UNLOCK_DEFAULT_TIMEOUT);
     600          351 :                     break;
     601              : 
     602              :                 }
     603              :             }
     604              :             else
     605              :             {
     606              :                 // compute distance (max - min)
     607              :                 //
     608         8948 :                 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         8948 :                 cluck::timeout_t value;
     613              :                 do
     614              :                 {
     615              :                     // get value from [0...max - min]
     616              :                     //
     617         8948 :                     value = cluck::timeout_t(rand() % (range.tv_sec + 1), rand() % 1'000'000'000);
     618              : 
     619              :                     // adjust value from [min...max]
     620              :                     //
     621         8948 :                     value += g_min_timeout_adjust[select];
     622              :                 }
     623         8948 :                 while(value == cluck::CLUCK_DEFAULT_TIMEOUT);
     624              : 
     625         8948 :                 switch(select)
     626              :                 {
     627         2976 :                 case 0: // lock obtention timeout
     628         2976 :                     cluck::set_lock_obtention_timeout(value);
     629         2976 :                     if(value < g_min_timeout[0])
     630              :                     {
     631          515 :                         CATCH_REQUIRE(cluck::get_lock_obtention_timeout() == g_min_timeout[0]);
     632              :                     }
     633         2461 :                     else if(value > g_max_timeout[0])
     634              :                     {
     635          497 :                         CATCH_REQUIRE(cluck::get_lock_obtention_timeout() == g_max_timeout[0]);
     636              :                     }
     637              :                     else
     638              :                     {
     639              :                         // otherwise not clamped
     640              :                         //
     641         1964 :                         CATCH_REQUIRE(cluck::get_lock_obtention_timeout() == value);
     642              :                     }
     643         2976 :                     break;
     644              : 
     645         2956 :                 case 1: // lock duration timeout
     646         2956 :                     cluck::set_lock_duration_timeout(value);
     647         2956 :                     if(value < g_min_timeout[1])
     648              :                     {
     649          630 :                         CATCH_REQUIRE(cluck::get_lock_duration_timeout() == g_min_timeout[1]);
     650              :                     }
     651         2326 :                     else if(value > g_max_timeout[1])
     652              :                     {
     653          569 :                         CATCH_REQUIRE(cluck::get_lock_duration_timeout() == g_max_timeout[1]);
     654              :                     }
     655              :                     else
     656              :                     {
     657              :                         // otherwise not clamped
     658              :                         //
     659         1757 :                         CATCH_REQUIRE(cluck::get_lock_duration_timeout() == value);
     660              :                     }
     661         2956 :                     break;
     662              : 
     663         3016 :                 case 2: // unlock timeout
     664         3016 :                     cluck::set_unlock_timeout(value);
     665         3016 :                     if(value < g_min_timeout[2])
     666              :                     {
     667          636 :                         CATCH_REQUIRE(cluck::get_unlock_timeout() == g_min_timeout[2]);
     668              :                     }
     669         2380 :                     else if(value > g_max_timeout[2])
     670              :                     {
     671          582 :                         CATCH_REQUIRE(cluck::get_unlock_timeout() == g_max_timeout[2]);
     672              :                     }
     673              :                     else
     674              :                     {
     675              :                         // otherwise not clamped
     676              :                         //
     677         1798 :                         CATCH_REQUIRE(cluck::get_unlock_timeout() == value);
     678              :                     }
     679         3016 :                     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         1052 :                 switch(select)
     711              :                 {
     712          324 :                 case 0: // lock obtention timeout
     713          324 :                     guarded->set_lock_obtention_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     714          324 :                     CATCH_REQUIRE(guarded->get_lock_obtention_timeout() == cluck::CLUCK_DEFAULT_TIMEOUT);
     715          324 :                     break;
     716              : 
     717          377 :                 case 1: // lock duration timeout
     718          377 :                     guarded->set_lock_duration_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     719          377 :                     CATCH_REQUIRE(guarded->get_lock_duration_timeout() == cluck::CLUCK_DEFAULT_TIMEOUT);
     720          377 :                     break;
     721              : 
     722          351 :                 case 2: // unlock timeout
     723          351 :                     guarded->set_unlock_timeout(cluck::CLUCK_DEFAULT_TIMEOUT);
     724          351 :                     CATCH_REQUIRE(guarded->get_unlock_timeout() == cluck::CLUCK_DEFAULT_TIMEOUT);
     725          351 :                     break;
     726              : 
     727              :                 }
     728              :             }
     729              :             else
     730              :             {
     731              :                 // compute distance (max - min)
     732              :                 //
     733         8948 :                 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         8948 :                 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         8948 :                     value = cluck::timeout_t(rand() % (range.tv_sec + 1), rand() % 1'000'000'000);
     746              : 
     747              :                     // adjust value from [min...max]
     748              :                     //
     749         8948 :                     value += g_min_timeout_adjust[select];
     750              :                 }
     751         8948 :                 while(value == cluck::CLUCK_DEFAULT_TIMEOUT);
     752              : 
     753         8948 :                 switch(select)
     754              :                 {
     755         2976 :                 case 0: // lock obtention timeout
     756         2976 :                     guarded->set_lock_obtention_timeout(value);
     757         2976 :                     if(value < g_min_timeout[0])
     758              :                     {
     759          535 :                         CATCH_REQUIRE(guarded->get_lock_obtention_timeout() == g_min_timeout[0]);
     760              :                     }
     761         2441 :                     else if(value > g_max_timeout[0])
     762              :                     {
     763          549 :                         CATCH_REQUIRE(guarded->get_lock_obtention_timeout() == g_max_timeout[0]);
     764              :                     }
     765              :                     else
     766              :                     {
     767              :                         // otherwise not clamped
     768              :                         //
     769         1892 :                         CATCH_REQUIRE(guarded->get_lock_obtention_timeout() == value);
     770              :                     }
     771         2976 :                     break;
     772              : 
     773         2956 :                 case 1: // lock duration timeout
     774         2956 :                     guarded->set_lock_duration_timeout(value);
     775         2956 :                     if(value < g_min_timeout[1])
     776              :                     {
     777          602 :                         CATCH_REQUIRE(guarded->get_lock_duration_timeout() == g_min_timeout[1]);
     778              :                     }
     779         2354 :                     else if(value > g_max_timeout[1])
     780              :                     {
     781          574 :                         CATCH_REQUIRE(guarded->get_lock_duration_timeout() == g_max_timeout[1]);
     782              :                     }
     783              :                     else
     784              :                     {
     785              :                         // otherwise not clamped
     786              :                         //
     787         1780 :                         CATCH_REQUIRE(guarded->get_lock_duration_timeout() == value);
     788              :                     }
     789         2956 :                     break;
     790              : 
     791         3016 :                 case 2: // unlock timeout
     792         3016 :                     guarded->set_unlock_timeout(value);
     793         3016 :                     if(value < g_min_timeout[2])
     794              :                     {
     795          596 :                         CATCH_REQUIRE(guarded->get_unlock_timeout() == g_min_timeout[2]);
     796              :                     }
     797         2420 :                     else if(value > g_max_timeout[2])
     798              :                     {
     799          589 :                         CATCH_REQUIRE(guarded->get_unlock_timeout() == g_max_timeout[2]);
     800              :                     }
     801              :                     else
     802              :                     {
     803              :                         // otherwise not clamped
     804              :                         //
     805         1831 :                         CATCH_REQUIRE(guarded->get_unlock_timeout() == value);
     806              :                     }
     807         3016 :                     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            3 :         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            5 :         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            9 :         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            7 :         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            3 :         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            5 :         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            0 :                 ed::communicator::instance()->remove_connection(messenger);
    1869            0 :                 ed::communicator::instance()->remove_connection(timer);
    1870            0 :                 ed::communicator::instance()->remove_connection(guarded);
    1871            0 :             });
    1872              : 
    1873            1 :         messenger->set_expect_lock_obtained(true);
    1874            5 :         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            1 :         ed::connection::vector_t connections(ed::communicator::instance()->get_connections());
    1891            6 :         for(auto c : connections)
    1892              :         {
    1893            5 :             ed::communicator::instance()->remove_connection(c);
    1894            5 :         }
    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 2.0-1

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