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
31extern "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
64namespace datetime = utils::datetime;
65namespace executor = utils::process::executor;
66namespace fs = utils::fs;
67namespace passwd = utils::passwd;
68namespace process = utils::process;
69namespace signals = utils::signals;
70namespace text = utils::text;
71
72using utils::none;
73using 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.
80static const datetime::delta infinite_timeout(1000000, 0);
81
82
83static 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.
96static void
97do_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.
106class child_create_cookie {
107    /// Name of the cookie to create.
108    const std::string _cookie_name;
109
110public:
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
132static 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.
142static void
143child_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
158static void child_dump_unprivileged_user(const fs::path&) UTILS_NORETURN;
159
160
161/// Subprocess that dumps user configuration.
162static void
163child_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.
172class child_exit {
173    /// Exit code to return.
174    int _exit_code;
175
176public:
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
194static void child_pause(const fs::path&) UTILS_NORETURN;
195
196
197/// Subprocess that just blocks.
198static void
199child_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
210static void child_print(const fs::path&) UTILS_NORETURN;
211
212
213/// Subprocess that writes to stdout and stderr.
214static void
215child_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.
225class child_sleep {
226    /// Seconds to sleep for before termination.
227    int _seconds;
228
229public:
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
248static 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.
255static void
256child_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
281static void child_validate_isolation(const fs::path&) UTILS_NORETURN;
282
283
284/// Subprocess that checks if isolate_child() has been called.
285static void
286child_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.
313template< class Hook >
314static executor::exec_handle
315do_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.
334static void
335require_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.
361static void
362ensure_dead(const pid_t pid)
363{
364    int attempts = 30;
365retry:
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
378ATF_TEST_CASE_WITHOUT_HEAD(integration__run_one);
379ATF_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
394ATF_TEST_CASE_WITHOUT_HEAD(integration__run_many);
395ATF_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
449ATF_TEST_CASE_WITHOUT_HEAD(integration__parameters_and_output);
450ATF_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
477ATF_TEST_CASE_WITHOUT_HEAD(integration__custom_output_files);
478ATF_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
511ATF_TEST_CASE_WITHOUT_HEAD(integration__timestamps);
512ATF_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
537ATF_TEST_CASE_WITHOUT_HEAD(integration__files);
538ATF_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
559ATF_TEST_CASE_WITHOUT_HEAD(integration__followup);
560ATF_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
620ATF_TEST_CASE_WITHOUT_HEAD(integration__output_files_always_exist);
621ATF_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
643ATF_TEST_CASE(integration__timeouts);
644ATF_TEST_CASE_HEAD(integration__timeouts)
645{
646    set_md_var("timeout", "60");
647}
648ATF_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
692ATF_TEST_CASE(integration__unprivileged_user);
693ATF_TEST_CASE_HEAD(integration__unprivileged_user)
694{
695    set_md_var("require.config", "unprivileged-user");
696    set_md_var("require.user", "root");
697}
698ATF_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
718ATF_TEST_CASE_WITHOUT_HEAD(integration__auto_cleanup);
719ATF_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.
765static void
766do_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
841ATF_TEST_CASE_WITHOUT_HEAD(integration__signal_handling);
842ATF_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
857ATF_TEST_CASE_WITHOUT_HEAD(integration__isolate_child_is_called);
858ATF_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
874ATF_TEST_CASE_WITHOUT_HEAD(integration__process_group_is_terminated);
875ATF_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
901ATF_TEST_CASE_WITHOUT_HEAD(integration__prevent_clobbering_control_files);
902ATF_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
920ATF_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