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