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