1 // Copyright 2015 The Kyua Authors. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of Google Inc. nor the names of its contributors 14 // may be used to endorse or promote products derived from this software 15 // without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include "utils/process/executor.ipp" 30 31 extern "C" { 32 #include <sys/types.h> 33 #include <sys/time.h> 34 #include <sys/wait.h> 35 36 #include <signal.h> 37 #include <unistd.h> 38 } 39 40 #include <cerrno> 41 #include <cstdlib> 42 #include <fstream> 43 #include <iostream> 44 #include <vector> 45 46 #include <atf-c++.hpp> 47 48 #include "utils/datetime.hpp" 49 #include "utils/defs.hpp" 50 #include "utils/env.hpp" 51 #include "utils/format/containers.ipp" 52 #include "utils/format/macros.hpp" 53 #include "utils/fs/operations.hpp" 54 #include "utils/fs/path.hpp" 55 #include "utils/optional.ipp" 56 #include "utils/passwd.hpp" 57 #include "utils/process/status.hpp" 58 #include "utils/sanity.hpp" 59 #include "utils/signals/exceptions.hpp" 60 #include "utils/stacktrace.hpp" 61 #include "utils/text/exceptions.hpp" 62 #include "utils/text/operations.ipp" 63 64 namespace datetime = utils::datetime; 65 namespace executor = utils::process::executor; 66 namespace fs = utils::fs; 67 namespace passwd = utils::passwd; 68 namespace process = utils::process; 69 namespace signals = utils::signals; 70 namespace text = utils::text; 71 72 using utils::none; 73 using utils::optional; 74 75 76 /// Large timeout for the processes we spawn. 77 /// 78 /// This number is supposed to be (much) larger than the timeout of the test 79 /// cases that use it so that children processes are not killed spuriously. 80 static const datetime::delta infinite_timeout(1000000, 0); 81 82 83 static void do_exit(const int) UTILS_NORETURN; 84 85 86 /// Terminates a subprocess without invoking destructors. 87 /// 88 /// This is just a simple wrapper over _exit(2) because we cannot use std::exit 89 /// on exit from a subprocess. The reason is that we do not want to invoke any 90 /// destructors as otherwise we'd clear up the global executor state by mistake. 91 /// This wouldn't be a major problem if it wasn't because doing so deletes 92 /// on-disk files and we want to leave them in place so that the parent process 93 /// can test for them! 94 /// 95 /// \param exit_code Code to exit with. 96 static void 97 do_exit(const int exit_code) 98 { 99 std::cout.flush(); 100 std::cerr.flush(); 101 ::_exit(exit_code); 102 } 103 104 105 /// Subprocess that creates a cookie file in its work directory. 106 class child_create_cookie { 107 /// Name of the cookie to create. 108 const std::string _cookie_name; 109 110 public: 111 /// Constructor. 112 /// 113 /// \param cookie_name Name of the cookie to create. 114 child_create_cookie(const std::string& cookie_name) : 115 _cookie_name(cookie_name) 116 { 117 } 118 119 /// Runs the subprocess. 120 void 121 operator()(const fs::path& /* control_directory */) 122 UTILS_NORETURN 123 { 124 std::cout << "Creating cookie: " << _cookie_name << " (stdout)\n"; 125 std::cerr << "Creating cookie: " << _cookie_name << " (stderr)\n"; 126 atf::utils::create_file(_cookie_name, ""); 127 do_exit(EXIT_SUCCESS); 128 } 129 }; 130 131 132 static void child_delete_all(const fs::path&) UTILS_NORETURN; 133 134 135 /// Subprocess that deletes all files in the current directory. 136 /// 137 /// This is intended to validate that the test runs in an empty directory, 138 /// separate from any control files that the executor may have created. 139 /// 140 /// \param control_directory Directory where control files separate from the 141 /// work directory can be placed. 142 static void 143 child_delete_all(const fs::path& control_directory) 144 { 145 const fs::path cookie = control_directory / "exec_was_called"; 146 std::ofstream control_file(cookie.c_str()); 147 if (!control_file) { 148 std::cerr << "Failed to create " << cookie << '\n'; 149 std::abort(); 150 } 151 152 const int exit_code = ::system("rm *") == -1 153 ? EXIT_FAILURE : EXIT_SUCCESS; 154 do_exit(exit_code); 155 } 156 157 158 static void child_dump_unprivileged_user(const fs::path&) UTILS_NORETURN; 159 160 161 /// Subprocess that dumps user configuration. 162 static void 163 child_dump_unprivileged_user(const fs::path& /* control_directory */) 164 { 165 const passwd::user current_user = passwd::current_user(); 166 std::cout << F("UID = %s\n") % current_user.uid; 167 do_exit(EXIT_SUCCESS); 168 } 169 170 171 /// Subprocess that returns a specific exit code. 172 class child_exit { 173 /// Exit code to return. 174 int _exit_code; 175 176 public: 177 /// Constructor. 178 /// 179 /// \param exit_code Exit code to return. 180 child_exit(const int exit_code) : _exit_code(exit_code) 181 { 182 } 183 184 /// Runs the subprocess. 185 void 186 operator()(const fs::path& /* control_directory */) 187 UTILS_NORETURN 188 { 189 do_exit(_exit_code); 190 } 191 }; 192 193 194 static void child_pause(const fs::path&) UTILS_NORETURN; 195 196 197 /// Subprocess that just blocks. 198 static void 199 child_pause(const fs::path& /* control_directory */) 200 { 201 sigset_t mask; 202 sigemptyset(&mask); 203 for (;;) { 204 ::sigsuspend(&mask); 205 } 206 std::abort(); 207 } 208 209 210 static void child_print(const fs::path&) UTILS_NORETURN; 211 212 213 /// Subprocess that writes to stdout and stderr. 214 static void 215 child_print(const fs::path& /* control_directory */) 216 { 217 std::cout << "stdout: some text\n"; 218 std::cerr << "stderr: some other text\n"; 219 220 do_exit(EXIT_SUCCESS); 221 } 222 223 224 /// Subprocess that sleeps for a period of time before exiting. 225 class child_sleep { 226 /// Seconds to sleep for before termination. 227 int _seconds; 228 229 public: 230 /// Construtor. 231 /// 232 /// \param seconds Seconds to sleep for before termination. 233 child_sleep(const int seconds) : _seconds(seconds) 234 { 235 } 236 237 /// Runs the subprocess. 238 void 239 operator()(const fs::path& /* control_directory */) 240 UTILS_NORETURN 241 { 242 ::sleep(_seconds); 243 do_exit(EXIT_SUCCESS); 244 } 245 }; 246 247 248 static void child_spawn_blocking_child(const fs::path&) UTILS_NORETURN; 249 250 251 /// Subprocess that spawns a subchild that gets stuck. 252 /// 253 /// Used by the caller to validate that the whole process tree is terminated 254 /// when this subprocess is killed. 255 static void 256 child_spawn_blocking_child( 257 const fs::path& /* control_directory */) 258 { 259 pid_t pid = ::fork(); 260 if (pid == -1) { 261 std::cerr << "Cannot fork subprocess\n"; 262 do_exit(EXIT_FAILURE); 263 } else if (pid == 0) { 264 for (;;) 265 ::pause(); 266 } else { 267 const fs::path name = fs::path(utils::getenv("CONTROL_DIR").get()) / 268 "pid"; 269 std::ofstream pidfile(name.c_str()); 270 if (!pidfile) { 271 std::cerr << "Failed to create the pidfile\n"; 272 do_exit(EXIT_FAILURE); 273 } 274 pidfile << pid; 275 pidfile.close(); 276 do_exit(EXIT_SUCCESS); 277 } 278 } 279 280 281 static void child_validate_isolation(const fs::path&) UTILS_NORETURN; 282 283 284 /// Subprocess that checks if isolate_child() has been called. 285 static void 286 child_validate_isolation(const fs::path& /* control_directory */) 287 { 288 if (utils::getenv("HOME").get() == "fake-value") { 289 std::cerr << "HOME not reset\n"; 290 do_exit(EXIT_FAILURE); 291 } 292 if (utils::getenv("LANG")) { 293 std::cerr << "LANG not unset\n"; 294 do_exit(EXIT_FAILURE); 295 } 296 do_exit(EXIT_SUCCESS); 297 } 298 299 300 /// Invokes executor::spawn() with default arguments. 301 /// 302 /// \param handle The executor on which to invoke spawn(). 303 /// \param args Arguments to the binary. 304 /// \param timeout Maximum time the program can run for. 305 /// \param unprivileged_user If set, user to switch to when running the child 306 /// program. 307 /// \param stdout_target If not none, file to which to write the stdout of the 308 /// test case. 309 /// \param stderr_target If not none, file to which to write the stderr of the 310 /// test case. 311 /// 312 /// \return The exec handle for the spawned binary. 313 template< class Hook > 314 static executor::exec_handle 315 do_spawn(executor::executor_handle& handle, Hook hook, 316 const datetime::delta& timeout = infinite_timeout, 317 const optional< passwd::user > unprivileged_user = none, 318 const optional< fs::path > stdout_target = none, 319 const optional< fs::path > stderr_target = none) 320 { 321 const executor::exec_handle exec_handle = handle.spawn< Hook >( 322 hook, timeout, unprivileged_user, stdout_target, stderr_target); 323 return exec_handle; 324 } 325 326 327 /// Checks for a specific exit status in the status of a exit_handle. 328 /// 329 /// \param exit_status The expected exit status. 330 /// \param status The value of exit_handle.status(). 331 /// 332 /// \post Terminates the calling test case if the status does not match the 333 /// required value. 334 static void 335 require_exit(const int exit_status, const optional< process::status > status) 336 { 337 ATF_REQUIRE(status); 338 ATF_REQUIRE(status.get().exited()); 339 ATF_REQUIRE_EQ(exit_status, status.get().exitstatus()); 340 } 341 342 343 /// Ensures that a killed process is gone. 344 /// 345 /// The way we do this is by sending an idempotent signal to the given PID 346 /// and checking if the signal was delivered. If it was, the process is 347 /// still alive; if it was not, then it is gone. 348 /// 349 /// Note that this might be inaccurate for two reasons: 350 /// 351 /// 1) The system may have spawned a new process with the same pid as 352 /// our subchild... but in practice, this does not happen because 353 /// most systems do not immediately reuse pid numbers. If that 354 /// happens... well, we get a false test failure. 355 /// 356 /// 2) We ran so fast that even if the process was sent a signal to 357 /// die, it has not had enough time to process it yet. This is why 358 /// we retry this a few times. 359 /// 360 /// \param pid PID of the process to check. 361 static void 362 ensure_dead(const pid_t pid) 363 { 364 int attempts = 30; 365 retry: 366 if (::kill(pid, SIGCONT) != -1 || errno != ESRCH) { 367 if (attempts > 0) { 368 std::cout << "Subprocess not dead yet; retrying wait\n"; 369 --attempts; 370 ::usleep(100000); 371 goto retry; 372 } 373 ATF_FAIL(F("The subprocess %s of our child was not killed") % pid); 374 } 375 } 376 377 378 ATF_TEST_CASE_WITHOUT_HEAD(integration__run_one); 379 ATF_TEST_CASE_BODY(integration__run_one) 380 { 381 executor::executor_handle handle = executor::setup(); 382 383 const executor::exec_handle exec_handle = do_spawn(handle, child_exit(41)); 384 385 executor::exit_handle exit_handle = handle.wait_any(); 386 ATF_REQUIRE_EQ(exec_handle.pid(), exit_handle.original_pid()); 387 require_exit(41, exit_handle.status()); 388 exit_handle.cleanup(); 389 390 handle.cleanup(); 391 } 392 393 394 ATF_TEST_CASE_WITHOUT_HEAD(integration__run_many); 395 ATF_TEST_CASE_BODY(integration__run_many) 396 { 397 static const std::size_t num_children = 30; 398 399 executor::executor_handle handle = executor::setup(); 400 401 std::size_t total_children = 0; 402 std::map< int, int > exp_exit_statuses; 403 std::map< int, datetime::timestamp > exp_start_times; 404 for (std::size_t i = 0; i < num_children; ++i) { 405 const datetime::timestamp start_time = datetime::timestamp::from_values( 406 2014, 12, 8, 9, 40, 0, i); 407 408 for (std::size_t j = 0; j < 3; j++) { 409 const std::size_t id = i * 3 + j; 410 411 datetime::set_mock_now(start_time); 412 const int pid = do_spawn(handle, child_exit(id)).pid(); 413 exp_exit_statuses.insert(std::make_pair(pid, id)); 414 exp_start_times.insert(std::make_pair(pid, start_time)); 415 ++total_children; 416 } 417 } 418 419 for (std::size_t i = 0; i < total_children; ++i) { 420 const datetime::timestamp end_time = datetime::timestamp::from_values( 421 2014, 12, 8, 9, 50, 10, i); 422 datetime::set_mock_now(end_time); 423 executor::exit_handle exit_handle = handle.wait_any(); 424 const int original_pid = exit_handle.original_pid(); 425 426 const int exit_status = exp_exit_statuses.find(original_pid)->second; 427 const datetime::timestamp& start_time = exp_start_times.find( 428 original_pid)->second; 429 430 require_exit(exit_status, exit_handle.status()); 431 432 ATF_REQUIRE_EQ(start_time, exit_handle.start_time()); 433 ATF_REQUIRE_EQ(end_time, exit_handle.end_time()); 434 435 exit_handle.cleanup(); 436 437 ATF_REQUIRE(!atf::utils::file_exists( 438 exit_handle.stdout_file().str())); 439 ATF_REQUIRE(!atf::utils::file_exists( 440 exit_handle.stderr_file().str())); 441 ATF_REQUIRE(!atf::utils::file_exists( 442 exit_handle.work_directory().str())); 443 } 444 445 handle.cleanup(); 446 } 447 448 449 ATF_TEST_CASE_WITHOUT_HEAD(integration__parameters_and_output); 450 ATF_TEST_CASE_BODY(integration__parameters_and_output) 451 { 452 executor::executor_handle handle = executor::setup(); 453 454 const executor::exec_handle exec_handle = do_spawn(handle, child_print); 455 456 executor::exit_handle exit_handle = handle.wait_any(); 457 458 ATF_REQUIRE_EQ(exec_handle.pid(), exit_handle.original_pid()); 459 460 require_exit(EXIT_SUCCESS, exit_handle.status()); 461 462 const fs::path stdout_file = exit_handle.stdout_file(); 463 ATF_REQUIRE(atf::utils::compare_file( 464 stdout_file.str(), "stdout: some text\n")); 465 const fs::path stderr_file = exit_handle.stderr_file(); 466 ATF_REQUIRE(atf::utils::compare_file( 467 stderr_file.str(), "stderr: some other text\n")); 468 469 exit_handle.cleanup(); 470 ATF_REQUIRE(!fs::exists(stdout_file)); 471 ATF_REQUIRE(!fs::exists(stderr_file)); 472 473 handle.cleanup(); 474 } 475 476 477 ATF_TEST_CASE_WITHOUT_HEAD(integration__custom_output_files); 478 ATF_TEST_CASE_BODY(integration__custom_output_files) 479 { 480 executor::executor_handle handle = executor::setup(); 481 482 const fs::path stdout_file("custom-stdout.txt"); 483 const fs::path stderr_file("custom-stderr.txt"); 484 485 const executor::exec_handle exec_handle = do_spawn( 486 handle, child_print, infinite_timeout, none, 487 utils::make_optional(stdout_file), 488 utils::make_optional(stderr_file)); 489 490 executor::exit_handle exit_handle = handle.wait_any(); 491 492 ATF_REQUIRE_EQ(exec_handle.pid(), exit_handle.original_pid()); 493 494 require_exit(EXIT_SUCCESS, exit_handle.status()); 495 496 ATF_REQUIRE_EQ(stdout_file, exit_handle.stdout_file()); 497 ATF_REQUIRE_EQ(stderr_file, exit_handle.stderr_file()); 498 499 exit_handle.cleanup(); 500 501 handle.cleanup(); 502 503 // Must compare after cleanup to ensure the files did not get deleted. 504 ATF_REQUIRE(atf::utils::compare_file( 505 stdout_file.str(), "stdout: some text\n")); 506 ATF_REQUIRE(atf::utils::compare_file( 507 stderr_file.str(), "stderr: some other text\n")); 508 } 509 510 511 ATF_TEST_CASE_WITHOUT_HEAD(integration__timestamps); 512 ATF_TEST_CASE_BODY(integration__timestamps) 513 { 514 executor::executor_handle handle = executor::setup(); 515 516 const datetime::timestamp start_time = datetime::timestamp::from_values( 517 2014, 12, 8, 9, 35, 10, 1000); 518 const datetime::timestamp end_time = datetime::timestamp::from_values( 519 2014, 12, 8, 9, 35, 20, 2000); 520 521 datetime::set_mock_now(start_time); 522 do_spawn(handle, child_exit(70)); 523 524 datetime::set_mock_now(end_time); 525 executor::exit_handle exit_handle = handle.wait_any(); 526 527 require_exit(70, exit_handle.status()); 528 529 ATF_REQUIRE_EQ(start_time, exit_handle.start_time()); 530 ATF_REQUIRE_EQ(end_time, exit_handle.end_time()); 531 exit_handle.cleanup(); 532 533 handle.cleanup(); 534 } 535 536 537 ATF_TEST_CASE_WITHOUT_HEAD(integration__files); 538 ATF_TEST_CASE_BODY(integration__files) 539 { 540 executor::executor_handle handle = executor::setup(); 541 542 do_spawn(handle, child_create_cookie("cookie.12345")); 543 544 executor::exit_handle exit_handle = handle.wait_any(); 545 546 ATF_REQUIRE(atf::utils::file_exists( 547 (exit_handle.work_directory() / "cookie.12345").str())); 548 549 exit_handle.cleanup(); 550 551 ATF_REQUIRE(!atf::utils::file_exists(exit_handle.stdout_file().str())); 552 ATF_REQUIRE(!atf::utils::file_exists(exit_handle.stderr_file().str())); 553 ATF_REQUIRE(!atf::utils::file_exists(exit_handle.work_directory().str())); 554 555 handle.cleanup(); 556 } 557 558 559 ATF_TEST_CASE_WITHOUT_HEAD(integration__followup); 560 ATF_TEST_CASE_BODY(integration__followup) 561 { 562 executor::executor_handle handle = executor::setup(); 563 564 (void)handle.spawn(child_create_cookie("cookie.1"), infinite_timeout, none); 565 executor::exit_handle exit_1_handle = handle.wait_any(); 566 567 (void)handle.spawn_followup(child_create_cookie("cookie.2"), exit_1_handle, 568 infinite_timeout); 569 executor::exit_handle exit_2_handle = handle.wait_any(); 570 571 ATF_REQUIRE_EQ(exit_1_handle.stdout_file(), exit_2_handle.stdout_file()); 572 ATF_REQUIRE_EQ(exit_1_handle.stderr_file(), exit_2_handle.stderr_file()); 573 ATF_REQUIRE_EQ(exit_1_handle.control_directory(), 574 exit_2_handle.control_directory()); 575 ATF_REQUIRE_EQ(exit_1_handle.work_directory(), 576 exit_2_handle.work_directory()); 577 578 (void)handle.spawn_followup(child_create_cookie("cookie.3"), exit_2_handle, 579 infinite_timeout); 580 exit_2_handle.cleanup(); 581 exit_1_handle.cleanup(); 582 executor::exit_handle exit_3_handle = handle.wait_any(); 583 584 ATF_REQUIRE_EQ(exit_1_handle.stdout_file(), exit_3_handle.stdout_file()); 585 ATF_REQUIRE_EQ(exit_1_handle.stderr_file(), exit_3_handle.stderr_file()); 586 ATF_REQUIRE_EQ(exit_1_handle.control_directory(), 587 exit_3_handle.control_directory()); 588 ATF_REQUIRE_EQ(exit_1_handle.work_directory(), 589 exit_3_handle.work_directory()); 590 591 ATF_REQUIRE(atf::utils::file_exists( 592 (exit_1_handle.work_directory() / "cookie.1").str())); 593 ATF_REQUIRE(atf::utils::file_exists( 594 (exit_1_handle.work_directory() / "cookie.2").str())); 595 ATF_REQUIRE(atf::utils::file_exists( 596 (exit_1_handle.work_directory() / "cookie.3").str())); 597 598 ATF_REQUIRE(atf::utils::compare_file( 599 exit_1_handle.stdout_file().str(), 600 "Creating cookie: cookie.1 (stdout)\n" 601 "Creating cookie: cookie.2 (stdout)\n" 602 "Creating cookie: cookie.3 (stdout)\n")); 603 604 ATF_REQUIRE(atf::utils::compare_file( 605 exit_1_handle.stderr_file().str(), 606 "Creating cookie: cookie.1 (stderr)\n" 607 "Creating cookie: cookie.2 (stderr)\n" 608 "Creating cookie: cookie.3 (stderr)\n")); 609 610 exit_3_handle.cleanup(); 611 612 ATF_REQUIRE(!atf::utils::file_exists(exit_1_handle.stdout_file().str())); 613 ATF_REQUIRE(!atf::utils::file_exists(exit_1_handle.stderr_file().str())); 614 ATF_REQUIRE(!atf::utils::file_exists(exit_1_handle.work_directory().str())); 615 616 handle.cleanup(); 617 } 618 619 620 ATF_TEST_CASE_WITHOUT_HEAD(integration__output_files_always_exist); 621 ATF_TEST_CASE_BODY(integration__output_files_always_exist) 622 { 623 executor::executor_handle handle = executor::setup(); 624 625 // This test is racy: we specify a very short timeout for the subprocess so 626 // that we cause the subprocess to exit before it has had time to set up the 627 // output files. However, for scheduling reasons, the subprocess may 628 // actually run to completion before the timer triggers. Retry this a few 629 // times to attempt to catch a "good test". 630 for (int i = 0; i < 50; i++) { 631 const executor::exec_handle exec_handle = 632 do_spawn(handle, child_exit(0), datetime::delta(0, 100000)); 633 executor::exit_handle exit_handle = handle.wait(exec_handle); 634 ATF_REQUIRE(fs::exists(exit_handle.stdout_file())); 635 ATF_REQUIRE(fs::exists(exit_handle.stderr_file())); 636 exit_handle.cleanup(); 637 } 638 639 handle.cleanup(); 640 } 641 642 643 ATF_TEST_CASE(integration__timeouts); 644 ATF_TEST_CASE_HEAD(integration__timeouts) 645 { 646 set_md_var("timeout", "60"); 647 } 648 ATF_TEST_CASE_BODY(integration__timeouts) 649 { 650 executor::executor_handle handle = executor::setup(); 651 652 const executor::exec_handle exec_handle1 = 653 do_spawn(handle, child_sleep(30), datetime::delta(2, 0)); 654 const executor::exec_handle exec_handle2 = 655 do_spawn(handle, child_sleep(40), datetime::delta(5, 0)); 656 const executor::exec_handle exec_handle3 = 657 do_spawn(handle, child_exit(15)); 658 659 { 660 executor::exit_handle exit_handle = handle.wait_any(); 661 ATF_REQUIRE_EQ(exec_handle3.pid(), exit_handle.original_pid()); 662 require_exit(15, exit_handle.status()); 663 exit_handle.cleanup(); 664 } 665 666 { 667 executor::exit_handle exit_handle = handle.wait_any(); 668 ATF_REQUIRE_EQ(exec_handle1.pid(), exit_handle.original_pid()); 669 ATF_REQUIRE(!exit_handle.status()); 670 const datetime::delta duration = 671 exit_handle.end_time() - exit_handle.start_time(); 672 ATF_REQUIRE(duration < datetime::delta(10, 0)); 673 ATF_REQUIRE(duration >= datetime::delta(2, 0)); 674 exit_handle.cleanup(); 675 } 676 677 { 678 executor::exit_handle exit_handle = handle.wait_any(); 679 ATF_REQUIRE_EQ(exec_handle2.pid(), exit_handle.original_pid()); 680 ATF_REQUIRE(!exit_handle.status()); 681 const datetime::delta duration = 682 exit_handle.end_time() - exit_handle.start_time(); 683 ATF_REQUIRE(duration < datetime::delta(10, 0)); 684 ATF_REQUIRE(duration >= datetime::delta(4, 0)); 685 exit_handle.cleanup(); 686 } 687 688 handle.cleanup(); 689 } 690 691 692 ATF_TEST_CASE(integration__unprivileged_user); 693 ATF_TEST_CASE_HEAD(integration__unprivileged_user) 694 { 695 set_md_var("require.config", "unprivileged-user"); 696 set_md_var("require.user", "root"); 697 } 698 ATF_TEST_CASE_BODY(integration__unprivileged_user) 699 { 700 executor::executor_handle handle = executor::setup(); 701 702 const passwd::user unprivileged_user = passwd::find_user_by_name( 703 get_config_var("unprivileged-user")); 704 705 do_spawn(handle, child_dump_unprivileged_user, 706 infinite_timeout, utils::make_optional(unprivileged_user)); 707 708 executor::exit_handle exit_handle = handle.wait_any(); 709 ATF_REQUIRE(atf::utils::compare_file( 710 exit_handle.stdout_file().str(), 711 F("UID = %s\n") % unprivileged_user.uid)); 712 exit_handle.cleanup(); 713 714 handle.cleanup(); 715 } 716 717 718 ATF_TEST_CASE_WITHOUT_HEAD(integration__auto_cleanup); 719 ATF_TEST_CASE_BODY(integration__auto_cleanup) 720 { 721 std::vector< int > pids; 722 std::vector< fs::path > paths; 723 { 724 executor::executor_handle handle = executor::setup(); 725 726 pids.push_back(do_spawn(handle, child_exit(10)).pid()); 727 pids.push_back(do_spawn(handle, child_exit(20)).pid()); 728 729 // This invocation is never waited for below. This is intentional: we 730 // want the destructor to clean the "leaked" test automatically so that 731 // the clean up of the parent work directory also happens correctly. 732 pids.push_back(do_spawn(handle, child_pause).pid()); 733 734 executor::exit_handle exit_handle1 = handle.wait_any(); 735 paths.push_back(exit_handle1.stdout_file()); 736 paths.push_back(exit_handle1.stderr_file()); 737 paths.push_back(exit_handle1.work_directory()); 738 739 executor::exit_handle exit_handle2 = handle.wait_any(); 740 paths.push_back(exit_handle2.stdout_file()); 741 paths.push_back(exit_handle2.stderr_file()); 742 paths.push_back(exit_handle2.work_directory()); 743 } 744 for (std::vector< int >::const_iterator iter = pids.begin(); 745 iter != pids.end(); ++iter) { 746 ensure_dead(*iter); 747 } 748 for (std::vector< fs::path >::const_iterator iter = paths.begin(); 749 iter != paths.end(); ++iter) { 750 ATF_REQUIRE(!atf::utils::file_exists((*iter).str())); 751 } 752 } 753 754 755 /// Ensures that interrupting an executor cleans things up correctly. 756 /// 757 /// This test scenario is tricky. We spawn a master child process that runs the 758 /// executor code and we send a signal to it externally. The child process 759 /// spawns a bunch of tests that block indefinitely and tries to wait for their 760 /// results. When the signal is received, we expect an interrupt_error to be 761 /// raised, which in turn should clean up all test resources and exit the master 762 /// child process successfully. 763 /// 764 /// \param signo Signal to deliver to the executor. 765 static void 766 do_signal_handling_test(const int signo) 767 { 768 static const char* cookie = "spawned.txt"; 769 770 const pid_t pid = ::fork(); 771 ATF_REQUIRE(pid != -1); 772 if (pid == 0) { 773 static const std::size_t num_children = 3; 774 775 optional< fs::path > root_work_directory; 776 try { 777 executor::executor_handle handle = executor::setup(); 778 root_work_directory = handle.root_work_directory(); 779 780 for (std::size_t i = 0; i < num_children; ++i) { 781 std::cout << "Spawned child number " << i << '\n'; 782 do_spawn(handle, child_pause); 783 } 784 785 std::cout << "Creating " << cookie << " cookie\n"; 786 atf::utils::create_file(cookie, ""); 787 788 std::cout << "Waiting for subprocess termination\n"; 789 for (std::size_t i = 0; i < num_children; ++i) { 790 executor::exit_handle exit_handle = handle.wait_any(); 791 // We may never reach this point in the test, but if we do let's 792 // make sure the subprocess was terminated as expected. 793 if (exit_handle.status()) { 794 if (exit_handle.status().get().signaled() && 795 exit_handle.status().get().termsig() == SIGKILL) { 796 // OK. 797 } else { 798 std::cerr << "Child exited with unexpected code: " 799 << exit_handle.status().get(); 800 std::exit(EXIT_FAILURE); 801 } 802 } else { 803 std::cerr << "Child timed out\n"; 804 std::exit(EXIT_FAILURE); 805 } 806 exit_handle.cleanup(); 807 } 808 std::cerr << "Terminating without reception of signal\n"; 809 std::exit(EXIT_FAILURE); 810 } catch (const signals::interrupted_error& unused_error) { 811 std::cerr << "Terminating due to interrupted_error\n"; 812 // We never kill ourselves until the cookie is created, so it is 813 // guaranteed that the optional root_work_directory has been 814 // initialized at this point. 815 if (atf::utils::file_exists(root_work_directory.get().str())) { 816 // Some cleanup did not happen; error out. 817 std::exit(EXIT_FAILURE); 818 } else { 819 std::exit(EXIT_SUCCESS); 820 } 821 } 822 std::abort(); 823 } 824 825 std::cout << "Waiting for " << cookie << " cookie creation\n"; 826 while (!atf::utils::file_exists(cookie)) { 827 // Wait for processes. 828 } 829 ATF_REQUIRE(::unlink(cookie) != -1); 830 std::cout << "Killing process\n"; 831 ATF_REQUIRE(::kill(pid, signo) != -1); 832 833 int status; 834 std::cout << "Waiting for process termination\n"; 835 ATF_REQUIRE(::waitpid(pid, &status, 0) != -1); 836 ATF_REQUIRE(WIFEXITED(status)); 837 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 838 } 839 840 841 ATF_TEST_CASE_WITHOUT_HEAD(integration__signal_handling); 842 ATF_TEST_CASE_BODY(integration__signal_handling) 843 { 844 // This test scenario is racy so run it multiple times to have higher 845 // chances of exposing problems. 846 const std::size_t rounds = 20; 847 848 for (std::size_t i = 0; i < rounds; ++i) { 849 std::cout << F("Testing round %s\n") % i; 850 do_signal_handling_test(SIGHUP); 851 do_signal_handling_test(SIGINT); 852 do_signal_handling_test(SIGTERM); 853 } 854 } 855 856 857 ATF_TEST_CASE_WITHOUT_HEAD(integration__isolate_child_is_called); 858 ATF_TEST_CASE_BODY(integration__isolate_child_is_called) 859 { 860 executor::executor_handle handle = executor::setup(); 861 862 utils::setenv("HOME", "fake-value"); 863 utils::setenv("LANG", "es_ES"); 864 do_spawn(handle, child_validate_isolation); 865 866 executor::exit_handle exit_handle = handle.wait_any(); 867 require_exit(EXIT_SUCCESS, exit_handle.status()); 868 exit_handle.cleanup(); 869 870 handle.cleanup(); 871 } 872 873 874 ATF_TEST_CASE_WITHOUT_HEAD(integration__process_group_is_terminated); 875 ATF_TEST_CASE_BODY(integration__process_group_is_terminated) 876 { 877 utils::setenv("CONTROL_DIR", fs::current_path().str()); 878 879 executor::executor_handle handle = executor::setup(); 880 do_spawn(handle, child_spawn_blocking_child); 881 882 executor::exit_handle exit_handle = handle.wait_any(); 883 require_exit(EXIT_SUCCESS, exit_handle.status()); 884 exit_handle.cleanup(); 885 886 handle.cleanup(); 887 888 if (!fs::exists(fs::path("pid"))) 889 fail("The pid file was not created"); 890 891 std::ifstream pidfile("pid"); 892 ATF_REQUIRE(pidfile); 893 pid_t pid; 894 pidfile >> pid; 895 pidfile.close(); 896 897 ensure_dead(pid); 898 } 899 900 901 ATF_TEST_CASE_WITHOUT_HEAD(integration__prevent_clobbering_control_files); 902 ATF_TEST_CASE_BODY(integration__prevent_clobbering_control_files) 903 { 904 executor::executor_handle handle = executor::setup(); 905 906 do_spawn(handle, child_delete_all); 907 908 executor::exit_handle exit_handle = handle.wait_any(); 909 require_exit(EXIT_SUCCESS, exit_handle.status()); 910 ATF_REQUIRE(atf::utils::file_exists( 911 (exit_handle.control_directory() / "exec_was_called").str())); 912 ATF_REQUIRE(!atf::utils::file_exists( 913 (exit_handle.work_directory() / "exec_was_called").str())); 914 exit_handle.cleanup(); 915 916 handle.cleanup(); 917 } 918 919 920 ATF_INIT_TEST_CASES(tcs) 921 { 922 ATF_ADD_TEST_CASE(tcs, integration__run_one); 923 ATF_ADD_TEST_CASE(tcs, integration__run_many); 924 925 ATF_ADD_TEST_CASE(tcs, integration__parameters_and_output); 926 ATF_ADD_TEST_CASE(tcs, integration__custom_output_files); 927 ATF_ADD_TEST_CASE(tcs, integration__timestamps); 928 ATF_ADD_TEST_CASE(tcs, integration__files); 929 930 ATF_ADD_TEST_CASE(tcs, integration__followup); 931 932 ATF_ADD_TEST_CASE(tcs, integration__output_files_always_exist); 933 ATF_ADD_TEST_CASE(tcs, integration__timeouts); 934 ATF_ADD_TEST_CASE(tcs, integration__unprivileged_user); 935 ATF_ADD_TEST_CASE(tcs, integration__auto_cleanup); 936 ATF_ADD_TEST_CASE(tcs, integration__signal_handling); 937 ATF_ADD_TEST_CASE(tcs, integration__isolate_child_is_called); 938 ATF_ADD_TEST_CASE(tcs, integration__process_group_is_terminated); 939 ATF_ADD_TEST_CASE(tcs, integration__prevent_clobbering_control_files); 940 } 941