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