Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Define a special test_case for failing tests.
[simgrid.git] / teshsuite / s4u / activity-lifecycle / activity-lifecycle.cpp
1 /* Copyright (c) 2010-2020. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #define CATCH_CONFIG_RUNNER // we supply our own main()
7
8 #include "../../src/include/catch.hpp"
9
10 #include <simgrid/s4u.hpp>
11 #include <xbt/config.hpp>
12
13 XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_test, "Messages specific for this s4u example");
14
15 std::vector<simgrid::s4u::Host*> all_hosts;
16
17 /* Helper function easing the testing of actor's ending condition */
18 static void assert_exit(bool exp_success, double duration)
19 {
20   double expected_time = simgrid::s4u::Engine::get_clock() + duration;
21   simgrid::s4u::this_actor::on_exit([exp_success, expected_time](bool got_failed) {
22     INFO("Check exit status. Expected: " << exp_success);
23     REQUIRE(exp_success == not got_failed);
24     INFO("Check date at exit. Expected: " << expected_time);
25     REQUIRE(simgrid::s4u::Engine::get_clock() == Approx(expected_time));
26     XBT_VERB("Checks on exit successful");
27   });
28 }
29
30 /* Helper function in charge of doing some sanity checks after each test */
31 static void assert_cleanup()
32 {
33   /* Check that no actor remain (but on host[0], where main_dispatcher lives */
34   for (unsigned int i = 0; i < all_hosts.size(); i++) {
35     std::vector<simgrid::s4u::ActorPtr> all_actors = all_hosts[i]->get_all_actors();
36     unsigned int expected_count = (i == 0) ? 1 : 0; // host[0] contains main_dispatcher, all other are empty
37     if (all_actors.size() != expected_count) {
38       INFO("Host " << all_hosts[i]->get_cname() << " contains " << all_actors.size() << " actors but " << expected_count
39                    << " are expected (i=" << i << "). Existing actors: ");
40       for (auto act : all_actors)
41         UNSCOPED_INFO(" - " << act->get_cname());
42       FAIL("This is wrong");
43     }
44   }
45   // TODO: Check that all LMM are empty
46 }
47
48 /**
49  ** Each tests
50  **/
51
52 /* We need an extra actor here, so that it can sleep until the end of each test */
53 #define BEGIN_SECTION(descr) SECTION(descr) { simgrid::s4u::Actor::create(descr, all_hosts[0], []()
54 #define END_SECTION })
55
56 TEST_CASE("Activity lifecycle: sleep activities")
57 {
58   XBT_INFO("#####[ launch next \"sleep\" test ]#####");
59
60   BEGIN_SECTION("sleep")
61   {
62     XBT_INFO("Launch a sleep(5), and let it proceed");
63     bool global = false;
64
65     simgrid::s4u::ActorPtr sleeper5 = simgrid::s4u::Actor::create("sleep5", all_hosts[1], [&global]() {
66       assert_exit(true, 5);
67       simgrid::s4u::this_actor::sleep_for(5);
68       global = true;
69     });
70
71     simgrid::s4u::this_actor::sleep_for(9);
72     INFO("Did the forked actor modify the global after sleeping, or was it killed before?");
73     REQUIRE(global);
74
75     END_SECTION;
76   }
77
78   BEGIN_SECTION("sleep killed at start")
79   {
80     XBT_INFO("Launch a sleep(5), and kill it right after start");
81     simgrid::s4u::ActorPtr sleeper5 = simgrid::s4u::Actor::create("sleep5_killed", all_hosts[1], []() {
82       assert_exit(false, 0);
83       simgrid::s4u::this_actor::sleep_for(5);
84       FAIL("I should be dead now");
85     });
86
87     simgrid::s4u::this_actor::yield();
88     sleeper5->kill();
89
90     END_SECTION;
91   }
92
93   BEGIN_SECTION("sleep killed in middle")
94   {
95     XBT_INFO("Launch a sleep(5), and kill it after 2 secs");
96     simgrid::s4u::ActorPtr sleeper5 = simgrid::s4u::Actor::create("sleep5_killed", all_hosts[1], []() {
97       assert_exit(false, 2);
98       simgrid::s4u::this_actor::sleep_for(5);
99       FAIL("I should be dead now");
100     });
101
102     simgrid::s4u::this_actor::sleep_for(2);
103     sleeper5->kill();
104
105     END_SECTION;
106   }
107
108   /* We cannot kill right at the end of the action because killer actors are always rescheduled to the end of the round
109    * to avoid that they exit before their victim dereferences their name */
110
111   BEGIN_SECTION("sleep restarted at start")
112   {
113     XBT_INFO("Launch a sleep(5), and restart its host right after start");
114     simgrid::s4u::ActorPtr sleeper5 = simgrid::s4u::Actor::create("sleep5_restarted", all_hosts[1], []() {
115       assert_exit(false, 0);
116       simgrid::s4u::this_actor::sleep_for(5);
117       FAIL("I should be dead now");
118     });
119
120     simgrid::s4u::this_actor::yield();
121     sleeper5->get_host()->turn_off();
122     sleeper5->get_host()->turn_on();
123
124     END_SECTION;
125   }
126
127   BEGIN_SECTION("sleep restarted in middle")
128   {
129     XBT_INFO("Launch a sleep(5), and restart its host after 2 secs");
130     simgrid::s4u::ActorPtr sleeper5 = simgrid::s4u::Actor::create("sleep5_restarted", all_hosts[1], []() {
131       assert_exit(false, 2);
132       simgrid::s4u::this_actor::sleep_for(5);
133       FAIL("I should be dead now");
134     });
135
136     simgrid::s4u::this_actor::sleep_for(2);
137     sleeper5->get_host()->turn_off();
138     sleeper5->get_host()->turn_on();
139
140     END_SECTION;
141   }
142
143   BEGIN_SECTION("sleep restarted at end")
144   {
145     XBT_INFO("Launch a sleep(5), and restart its host right when it stops");
146     bool sleeper_done = false;
147
148     simgrid::s4u::Actor::create("sleep5_restarted", all_hosts[1], [&sleeper_done]() {
149       assert_exit(true, 5);
150       simgrid::s4u::this_actor::sleep_for(5);
151       sleeper_done = true;
152     });
153
154     simgrid::s4u::Actor::create("killer", all_hosts[0], []() {
155       simgrid::s4u::this_actor::sleep_for(5);
156       XBT_VERB("Killer!");
157       all_hosts[1]->turn_off();
158       all_hosts[1]->turn_on();
159     });
160
161     simgrid::s4u::this_actor::sleep_for(9);
162     INFO("Was restarted actor already dead in the scheduling round during which the host_off simcall was issued?");
163     REQUIRE(sleeper_done);
164
165     END_SECTION;
166   }
167
168   BEGIN_SECTION("turn off its own host")
169   {
170     XBT_INFO("Launch a sleep(5), then saw off the branch it's sitting on");
171     simgrid::s4u::Actor::create("sleep5_restarted", all_hosts[1], []() {
172       assert_exit(false, 5);
173       simgrid::s4u::this_actor::sleep_for(5);
174       simgrid::s4u::this_actor::get_host()->turn_off();
175       FAIL("I should be dead now");
176     });
177
178     simgrid::s4u::this_actor::sleep_for(9);
179     all_hosts[1]->turn_on();
180
181     END_SECTION;
182   }
183
184   simgrid::s4u::this_actor::sleep_for(10);
185   assert_cleanup();
186 }
187
188 TEST_CASE("Activity lifecycle: exec activities")
189 {
190   XBT_INFO("#####[ launch next \"exec\" test ]#####");
191
192   BEGIN_SECTION("exec")
193   {
194     XBT_INFO("Launch a execute(5s), and let it proceed");
195     bool global = false;
196
197     simgrid::s4u::ActorPtr exec5 = simgrid::s4u::Actor::create("exec5", all_hosts[1], [&global]() {
198       assert_exit(true, 5.);
199       simgrid::s4u::this_actor::execute(500000000);
200       global = true;
201     });
202
203     simgrid::s4u::this_actor::sleep_for(9);
204     INFO("Did the forked actor modify the global after sleeping, or was it killed before?");
205     REQUIRE(global);
206
207     END_SECTION;
208   }
209
210   BEGIN_SECTION("exec killed at start")
211   {
212     XBT_INFO("Launch a execute(5s), and kill it right after start");
213     simgrid::s4u::ActorPtr exec5 = simgrid::s4u::Actor::create("exec5_killed", all_hosts[1], []() {
214       assert_exit(false, 0);
215       simgrid::s4u::this_actor::execute(500000000);
216       FAIL("I should be dead now");
217     });
218
219     simgrid::s4u::this_actor::yield();
220     exec5->kill();
221
222     END_SECTION;
223   }
224
225   BEGIN_SECTION("exec killed in middle")
226   {
227     XBT_INFO("Launch a execute(5s), and kill it after 2 secs");
228     simgrid::s4u::ActorPtr exec5 = simgrid::s4u::Actor::create("exec5_killed", all_hosts[1], []() {
229       assert_exit(false, 2);
230       simgrid::s4u::this_actor::execute(500000000);
231       FAIL("I should be dead now");
232     });
233
234     simgrid::s4u::this_actor::sleep_for(2);
235     exec5->kill();
236
237     END_SECTION;
238   }
239
240   BEGIN_SECTION("exec restarted at start")
241   {
242     XBT_INFO("Launch a execute(5s), and restart its host right after start");
243     simgrid::s4u::ActorPtr exec5 = simgrid::s4u::Actor::create("exec5_restarted", all_hosts[1], []() {
244       assert_exit(false, 0);
245       simgrid::s4u::this_actor::execute(500000000);
246       FAIL("I should be dead now");
247     });
248
249     simgrid::s4u::this_actor::yield();
250     exec5->get_host()->turn_off();
251     exec5->get_host()->turn_on();
252
253     END_SECTION;
254   }
255
256   BEGIN_SECTION("exec restarted in middle")
257   {
258     XBT_INFO("Launch a execute(5s), and restart its host after 2 secs");
259     simgrid::s4u::ActorPtr exec5 = simgrid::s4u::Actor::create("exec5_restarted", all_hosts[1], []() {
260       assert_exit(false, 2);
261       simgrid::s4u::this_actor::execute(500000000);
262       FAIL("I should be dead now");
263     });
264
265     simgrid::s4u::this_actor::sleep_for(2);
266     exec5->get_host()->turn_off();
267     exec5->get_host()->turn_on();
268
269     END_SECTION;
270   }
271
272   BEGIN_SECTION("exec restarted at end")
273   {
274     XBT_INFO("Launch a execute(5s), and restart its host right when it stops");
275     bool execution_done = false;
276
277     simgrid::s4u::Actor::create("exec5_restarted", all_hosts[1], [&execution_done]() {
278       assert_exit(true, 5);
279       simgrid::s4u::this_actor::execute(500000000);
280       execution_done = true;
281     });
282
283     simgrid::s4u::Actor::create("killer", all_hosts[0], []() {
284       simgrid::s4u::this_actor::sleep_for(5);
285       XBT_VERB("Killer!");
286       all_hosts[1]->turn_off();
287       all_hosts[1]->turn_on();
288     });
289
290     simgrid::s4u::this_actor::sleep_for(9);
291     INFO("Was restarted actor already dead in the scheduling round during which the host_off simcall was issued?");
292     REQUIRE(execution_done);
293
294     END_SECTION;
295   }
296
297   simgrid::s4u::this_actor::sleep_for(10);
298   assert_cleanup();
299 }
300
301 TEST_CASE("Activity lifecycle: comm activities")
302 {
303   XBT_INFO("#####[ launch next \"comm\" test ]#####");
304
305   BEGIN_SECTION("comm")
306   {
307     XBT_INFO("Launch a communication");
308     bool send_done = false;
309     bool recv_done = false;
310
311     simgrid::s4u::Actor::create("sender", all_hosts[1], [&send_done]() {
312       assert_exit(true, 5);
313       char* payload = xbt_strdup("toto");
314       simgrid::s4u::Mailbox::by_name("mb")->put(payload, 5000);
315       send_done = true;
316     });
317
318     simgrid::s4u::Actor::create("receiver", all_hosts[2], [&recv_done]() {
319       assert_exit(true, 5);
320       void* payload = simgrid::s4u::Mailbox::by_name("mb")->get();
321       xbt_free(payload);
322       recv_done = true;
323     });
324
325     simgrid::s4u::this_actor::sleep_for(9);
326     INFO("Sender or receiver killed somehow. It shouldn't");
327     REQUIRE(send_done);
328     REQUIRE(recv_done);
329
330     END_SECTION;
331   }
332
333   BEGIN_SECTION("comm dsend and quit (put before get)")
334   {
335     XBT_INFO("Launch a detached communication and end right after");
336     bool dsend_done = false;
337     bool recv_done  = false;
338
339     simgrid::s4u::ActorPtr sender = simgrid::s4u::Actor::create("sender", all_hosts[1], [&dsend_done]() {
340       assert_exit(true, 0);
341       char* payload = xbt_strdup("toto");
342       simgrid::s4u::Mailbox::by_name("mb")->put_init(payload, 1000)->detach();
343       dsend_done = true;
344     });
345
346     simgrid::s4u::Actor::create("receiver", all_hosts[2], [&recv_done]() {
347       assert_exit(true, 3);
348       simgrid::s4u::this_actor::sleep_for(2);
349       void* payload = simgrid::s4u::Mailbox::by_name("mb")->get();
350       xbt_free(payload);
351       recv_done = true;
352     });
353
354     // Sleep long enough to let the test ends by itself. 3 + surf_precision should be enough.
355     simgrid::s4u::this_actor::sleep_for(4);
356     INFO("Sender or receiver killed somehow. It shouldn't");
357     REQUIRE(dsend_done);
358     REQUIRE(recv_done);
359
360     END_SECTION;
361   }
362
363   BEGIN_SECTION("comm dsend and quit (get before put)")
364   {
365     XBT_INFO("Launch a detached communication and end right after");
366     bool dsend_done = false;
367     bool recv_done  = false;
368
369     simgrid::s4u::ActorPtr sender = simgrid::s4u::Actor::create("sender", all_hosts[1], [&dsend_done]() {
370       assert_exit(true, 2);
371       char* payload = xbt_strdup("toto");
372       simgrid::s4u::this_actor::sleep_for(2);
373       simgrid::s4u::Mailbox::by_name("mb")->put_init(payload, 1000)->detach();
374       dsend_done = true;
375     });
376
377     simgrid::s4u::Actor::create("receiver", all_hosts[2], [&recv_done]() {
378       assert_exit(true, 3);
379       void* payload = simgrid::s4u::Mailbox::by_name("mb")->get();
380       xbt_free(payload);
381       recv_done = true;
382     });
383
384     // Sleep long enough to let the test ends by itself. 3 + surf_precision should be enough.
385     simgrid::s4u::this_actor::sleep_for(4);
386     INFO("Sender or receiver killed somehow. It shouldn't");
387     REQUIRE(dsend_done);
388     REQUIRE(recv_done);
389
390     END_SECTION;
391   }
392
393   BEGIN_SECTION("comm kill sender")
394   {
395     XBT_INFO("Launch a communication and kill the sender");
396     bool send_done = false;
397     bool recv_done = false;
398
399     simgrid::s4u::ActorPtr sender = simgrid::s4u::Actor::create("sender", all_hosts[1], [&send_done]() {
400       assert_exit(false, 2);
401       // Encapsulate the payload in a std::unique_ptr so that it is correctly free'd when the sender is killed during
402       // its communication (thanks to RAII).  The pointer is then released when the communication is over.
403       std::unique_ptr<char, decltype(&xbt_free_f)> payload(xbt_strdup("toto"), &xbt_free_f);
404       simgrid::s4u::Mailbox::by_name("mb")->put(payload.get(), 5000);
405       payload.release();
406       send_done = true;
407     });
408
409     simgrid::s4u::Actor::create("receiver", all_hosts[2], [&recv_done]() {
410       assert_exit(true, 2);
411       void* payload = nullptr;
412       REQUIRE_THROWS_AS(payload = simgrid::s4u::Mailbox::by_name("mb")->get(), simgrid::NetworkFailureException);
413       xbt_free(payload);
414       recv_done = true;
415     });
416
417     simgrid::s4u::this_actor::sleep_for(2);
418     sender->kill();
419     // let the test ends by itself. waiting for surf_precision should be enough.
420     simgrid::s4u::this_actor::sleep_for(0.00001);
421
422     INFO("Sender was not killed properly or receiver killed somehow. It shouldn't");
423     REQUIRE(not send_done);
424     REQUIRE(recv_done);
425
426     END_SECTION;
427   }
428
429   BEGIN_SECTION("comm recv and kill")
430   {
431     XBT_INFO("Launch an actor that waits on a recv, kill its host");
432     bool in_on_exit              = false;
433     bool returned_from_main      = false;
434     bool in_catch_before_on_exit = false;
435     bool in_catch_after_on_exit  = false;
436     bool send_done               = false;
437
438     simgrid::s4u::ActorPtr receiver =
439         simgrid::s4u::Actor::create("receiver", all_hosts[1], [&in_on_exit, &returned_from_main,
440                                                                &in_catch_before_on_exit, &in_catch_after_on_exit]() {
441           assert_exit(false, 1);
442           try {
443             simgrid::s4u::Mailbox::by_name("mb")->get();
444           } catch (simgrid::NetworkFailureException const&) {
445             // Shouldn't get in here
446             in_catch_before_on_exit = not in_on_exit;
447             in_catch_after_on_exit  = in_on_exit;
448           }
449           returned_from_main = true;
450         });
451
452     receiver->on_exit([&in_on_exit](bool) { in_on_exit = true; });
453
454     simgrid::s4u::ActorPtr sender = simgrid::s4u::Actor::create("sender", all_hosts[2], [&send_done]() {
455       assert_exit(true, 1);
456       int data = 42;
457       REQUIRE_THROWS_AS(simgrid::s4u::Mailbox::by_name("mb")->put(&data, 100000), simgrid::NetworkFailureException);
458       send_done = true;
459     });
460
461     simgrid::s4u::this_actor::sleep_for(1);
462     receiver->get_host()->turn_off();
463
464     // Note: If we don't sleep here, we don't "see" the bug
465     simgrid::s4u::this_actor::sleep_for(1);
466
467     INFO("Receiver's on_exit function was never called");
468     REQUIRE(in_on_exit);
469     INFO("or receiver mistakenly went to catch clause (before the on_exit function was called)");
470     REQUIRE(not in_catch_before_on_exit);
471     INFO("or receiver mistakenly went to catch clause (after the on_exit function was called)");
472     REQUIRE(not in_catch_after_on_exit);
473     INFO("or receiver returned from main normally even though its host was killed");
474     REQUIRE(not returned_from_main);
475     INFO("or sender killed somehow, and it shouldn't");
476     REQUIRE(send_done);
477     receiver->get_host()->turn_on();
478
479     END_SECTION;
480   }
481
482   static auto test_link_off_helper = [](double delay) {
483     const double start = simgrid::s4u::Engine::get_clock();
484
485     simgrid::s4u::ActorPtr receiver = simgrid::s4u::Actor::create("receiver", all_hosts[1], [&start]() {
486       assert_exit(true, 9);
487       double milestone[5] = {0.5, 3.5, 4.5, 7.5, 9.0};
488       for (int i = 0; i < 5; i++)
489         milestone[i] += start;
490       for (int i = 0; i < 4; i++) {
491         simgrid::s4u::this_actor::sleep_until(milestone[i]);
492         try {
493           XBT_VERB("get(%c)", 'A' + i);
494           simgrid::s4u::Mailbox::by_name("mb")->get();
495           return;
496         } catch (simgrid::NetworkFailureException const&) {
497           XBT_VERB("got expected NetworkFailureException");
498         }
499       }
500       simgrid::s4u::this_actor::sleep_until(milestone[4]);
501     });
502
503     simgrid::s4u::ActorPtr sender = simgrid::s4u::Actor::create("sender", all_hosts[2], [&start]() {
504       assert_exit(true, 9);
505       int data            = 42;
506       double milestone[5] = {1.5, 2.5, 5.5, 6.5, 9.0};
507       for (int i = 0; i < 5; i++)
508         milestone[i] += start;
509       for (int i = 0; i < 2; i++) {
510         simgrid::s4u::this_actor::sleep_until(milestone[i]);
511         XBT_VERB("dsend(%c)", 'A' + i);
512         simgrid::s4u::Mailbox::by_name("mb")->put_init(&data, 100000)->detach();
513       }
514       for (int i = 2; i < 4; i++) {
515         simgrid::s4u::this_actor::sleep_until(milestone[i]);
516         try {
517           XBT_VERB("put(%c)", 'A' + i);
518           simgrid::s4u::Mailbox::by_name("mb")->put(&data, 100000);
519           return;
520         } catch (simgrid::NetworkFailureException const&) {
521           XBT_VERB("got expected NetworkFailureException");
522         }
523       }
524       simgrid::s4u::this_actor::sleep_until(milestone[4]);
525     });
526
527     for (int i = 0; i < 4; i++) {
528       XBT_VERB("##### %d / 4 #####", i + 1);
529       simgrid::s4u::this_actor::sleep_for(delay);
530       XBT_VERB("link off");
531       simgrid::s4u::Link::by_name("link1")->turn_off();
532       simgrid::s4u::this_actor::sleep_for(2.0 - delay);
533       XBT_VERB("link on");
534       simgrid::s4u::Link::by_name("link1")->turn_on();
535     }
536     simgrid::s4u::this_actor::sleep_for(1.5);
537   };
538
539   BEGIN_SECTION("comm turn link off before send/recv")
540   {
541     XBT_INFO("try to communicate with communicating link turned off before start");
542     test_link_off_helper(0.0);
543
544     END_SECTION;
545   }
546
547   BEGIN_SECTION("comm turn link off between send/recv")
548   {
549     XBT_INFO("try to communicate with communicating link turned off between send and receive");
550     test_link_off_helper(1.0);
551
552     END_SECTION;
553   }
554
555   BEGIN_SECTION("comm turn link off during transfer")
556   {
557     XBT_INFO("try to communicate with communicating link turned off during transfer");
558     test_link_off_helper(2.0);
559
560     END_SECTION;
561   }
562
563   BEGIN_SECTION("comm turn link off during wait_any")
564   {
565     XBT_INFO("try to communicate with communicating link turned off during wait_any");
566     simgrid::s4u::ActorPtr receiver = simgrid::s4u::Actor::create("receiver", all_hosts[1], []() {
567       assert_exit(true, 2);
568       int* data;
569       std::vector<simgrid::s4u::CommPtr> pending_comms;
570       simgrid::s4u::CommPtr comm = simgrid::s4u::Mailbox::by_name("mb")->get_async((void**)&data);
571       pending_comms.push_back(comm);
572       REQUIRE_THROWS_AS(simgrid::s4u::Comm::wait_any(&pending_comms), simgrid::NetworkFailureException);
573     });
574
575     simgrid::s4u::ActorPtr sender = simgrid::s4u::Actor::create("sender", all_hosts[2], []() {
576       assert_exit(true, 2);
577       int data                                  = 42;
578       REQUIRE_THROWS_AS(simgrid::s4u::Mailbox::by_name("mb")->put(&data, 100000), simgrid::NetworkFailureException);
579     });
580
581     simgrid::s4u::this_actor::sleep_for(2.0);
582     XBT_VERB("link off");
583     simgrid::s4u::Link::by_name("link1")->turn_off();
584     simgrid::s4u::this_actor::sleep_for(2.0);
585     XBT_VERB("link on");
586     simgrid::s4u::Link::by_name("link1")->turn_on();
587
588     END_SECTION;
589   }
590
591   simgrid::s4u::this_actor::sleep_for(10);
592   assert_cleanup();
593 }
594
595 int main(int argc, char* argv[])
596 {
597   simgrid::config::set_value("help-nostop", true);
598   simgrid::s4u::Engine e(&argc, argv);
599
600   std::string platf;
601   if (argc > 1) {
602     platf   = argv[1];
603     argv[1] = argv[0];
604     argv++;
605     argc--;
606   } else {
607     XBT_WARN("No platform file provided. Using './testing_platform.xml'");
608     platf = "./testing_platform.xml";
609   }
610   e.load_platform(platf);
611
612   int status = 42;
613   all_hosts = e.get_all_hosts();
614   simgrid::s4u::Actor::create("main_dispatcher", all_hosts[0],
615                               [&argc, &argv, &status]() { status = Catch::Session().run(argc, argv); });
616
617   e.run();
618   XBT_INFO("Simulation done");
619   return status;
620 }