xref: /freebsd/contrib/kyua/utils/process/executor_test.cpp (revision a90b9d0159070121c221b966469c3e36d912bf82)
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