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