Home | History | Annotate | Line # | Download | only in engine
test_case_test.cpp revision 1.1.1.1.4.3
      1 // Copyright 2010 Google Inc.
      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 "engine/test_case.hpp"
     30 
     31 extern "C" {
     32 #include <sys/stat.h>
     33 
     34 #include <signal.h>
     35 #include <unistd.h>
     36 }
     37 
     38 #include <cerrno>
     39 #include <cstdlib>
     40 #include <fstream>
     41 #include <iostream>
     42 #include <sstream>
     43 #include <stdexcept>
     44 #include <string>
     45 
     46 #include <atf-c++.hpp>
     47 
     48 #include "engine/config.hpp"
     49 #include "engine/exceptions.hpp"
     50 #include "engine/kyuafile.hpp"
     51 #include "engine/test_program.hpp"
     52 #include "engine/test_result.hpp"
     53 #include "utils/config/tree.ipp"
     54 #include "utils/datetime.hpp"
     55 #include "utils/env.hpp"
     56 #include "utils/format/macros.hpp"
     57 #include "utils/fs/operations.hpp"
     58 #include "utils/noncopyable.hpp"
     59 #include "utils/optional.ipp"
     60 #include "utils/passwd.hpp"
     61 #include "utils/process/child.ipp"
     62 #include "utils/sanity.hpp"
     63 #include "utils/stream.hpp"
     64 
     65 namespace config = utils::config;
     66 namespace datetime = utils::datetime;
     67 namespace fs = utils::fs;
     68 namespace passwd = utils::passwd;
     69 namespace process = utils::process;
     70 
     71 using utils::none;
     72 using utils::optional;
     73 
     74 
     75 namespace {
     76 
     77 
     78 /// Test case hooks to capture stdout and stderr in memory.
     79 class capture_hooks : public engine::test_case_hooks {
     80 public:
     81     /// Contents of the stdout of the test case.
     82     std::string stdout_contents;
     83 
     84     /// Contents of the stderr of the test case.
     85     std::string stderr_contents;
     86 
     87     /// Stores the stdout of the test case into stdout_contents.
     88     ///
     89     /// \param file The path to the file containing the stdout.
     90     void
     91     got_stdout(const fs::path& file)
     92     {
     93         atf::utils::cat_file(file.str(), "helper stdout:");
     94         ATF_REQUIRE(stdout_contents.empty());
     95 
     96         std::ifstream input(file.c_str());
     97         ATF_REQUIRE(input);
     98         stdout_contents = utils::read_stream(input);
     99     }
    100 
    101     /// Stores the stderr of the test case into stderr_contents.
    102     ///
    103     /// \param file The path to the file containing the stderr.
    104     void
    105     got_stderr(const fs::path& file)
    106     {
    107         atf::utils::cat_file(file.str(), "helper stderr:");
    108         ATF_REQUIRE(stderr_contents.empty());
    109 
    110         std::ifstream input(file.c_str());
    111         ATF_REQUIRE(input);
    112         stderr_contents = utils::read_stream(input);
    113     }
    114 };
    115 
    116 
    117 /// Launcher for the helper test cases.
    118 ///
    119 /// This builder class can be used to construct the runtime state of the helper
    120 /// test cases and later run them.  The class also provides other helper methods
    121 /// to interact with the helper binary.
    122 class atf_helper : utils::noncopyable {
    123     /// Path to the test program's source directory.
    124     const fs::path _srcdir;
    125 
    126     /// The root of the test suite.
    127     fs::path _root;
    128 
    129     /// Path to the helper test program, relative to _root.
    130     fs::path _binary_path;
    131 
    132     /// Name of the helper test case to run.
    133     const std::string _name;
    134 
    135     /// Metadata of the test case.
    136     engine::metadata_builder _mdbuilder;
    137 
    138     /// Run-time configuration for the test case.
    139     config::tree _user_config;
    140 
    141 public:
    142     /// Constructs a new helper.
    143     ///
    144     /// \param atf_tc A pointer to the calling test case.  Needed to obtain
    145     ///     run-time configuration variables.
    146     /// \param name The name of the helper to run.
    147     atf_helper(const atf::tests::tc* atf_tc, const char* name) :
    148         _srcdir(atf_tc->get_config_var("srcdir")),
    149         _root(_srcdir),
    150         _binary_path("test_case_atf_helpers"),
    151         _name(name),
    152         _user_config(engine::default_config())
    153     {
    154         _user_config.set_string("architecture", "mock-architecture");
    155         _user_config.set_string("platform", "mock-platform");
    156     }
    157 
    158     /// Provides raw access to the run-time configuration.
    159     ///
    160     /// To override test-suite-specific variables, use set_config() as it
    161     /// abstracts away the name of the fake test suite.
    162     ///
    163     /// \returns A reference to the test case configuration.
    164     config::tree&
    165     config(void)
    166     {
    167         return _user_config;
    168     }
    169 
    170     /// Sets a test-suite-specific configuration variable for the helper.
    171     ///
    172     /// \param variable The name of the environment variable to set.
    173     /// \param value The value of the variable; must be convertible to a string.
    174     template< typename T >
    175     void
    176     set_config(const char* variable, const T& value)
    177     {
    178         _user_config.set_string(F("test_suites.the-suite.%s") % variable,
    179                                 F("%s") % value);
    180     }
    181 
    182     /// Sets a metadata variable for the helper.
    183     ///
    184     /// \param variable The name of the environment variable to set.
    185     /// \param value The value of the variable; must be convertible to a string.
    186     template< typename T >
    187     void
    188     set_metadata(const char* variable, const T& value)
    189     {
    190         _mdbuilder.set_string(variable, F("%s") % value);
    191     }
    192 
    193     /// Places the helper in a different location.
    194     ///
    195     /// This prepares the helper to be run from a different location than the
    196     /// source directory so that the runtime execution can be validated.
    197     ///
    198     /// \param new_binary_path The new path to the binary, relative to the test
    199     ///     suite root.
    200     /// \param new_root The new test suite root.
    201     ///
    202     /// \pre The directory holding the target test program must exist.
    203     ///     Otherwise, the relocation of the binary will fail.
    204     void
    205     move(const char* new_binary_path, const char* new_root)
    206     {
    207         _binary_path = fs::path(new_binary_path);
    208         _root = fs::path(new_root);
    209 
    210         const fs::path src_path = fs::path(_srcdir / "test_case_atf_helpers");
    211         const fs::path new_path = _root / _binary_path;
    212         ATF_REQUIRE(
    213             ::symlink(src_path.c_str(), new_path.c_str()) != -1);
    214     }
    215 
    216     /// Runs the helper.
    217     ///
    218     /// \return The result of the execution.
    219     engine::test_result
    220     run(void) const
    221     {
    222         engine::test_case_hooks dummy_hooks;
    223         return run(dummy_hooks);
    224     }
    225 
    226     /// Runs the helper.
    227     ///
    228     /// \param hooks The hooks to pass to the test case.
    229     ///
    230     /// \return The result of the execution.
    231     engine::test_result
    232     run(engine::test_case_hooks& hooks) const
    233     {
    234         const engine::test_program test_program(
    235             "atf", _binary_path, _root, "the-suite",
    236             engine::metadata_builder().build());
    237         const engine::test_case test_case("atf", test_program, _name,
    238                                           _mdbuilder.build());
    239 
    240         const fs::path workdir("work");
    241         fs::mkdir(workdir, 0755);
    242 
    243         const engine::test_result result = engine::run_test_case(
    244             &test_case, _user_config, hooks, workdir);
    245         ATF_REQUIRE(::rmdir(workdir.c_str()) != -1);
    246         return result;
    247     }
    248 };
    249 
    250 
    251 /// Hooks to retrieve stdout and stderr.
    252 class fetch_output_hooks : public engine::test_case_hooks {
    253 public:
    254     /// Copies the stdout of the test case outside of its work directory.
    255     ///
    256     /// \param file The location of the test case's stdout.
    257     void
    258     got_stdout(const fs::path& file)
    259     {
    260         atf::utils::copy_file(file.str(), "helper-stdout.txt");
    261         atf::utils::cat_file("helper-stdout.txt", "helper stdout: ");
    262     }
    263 
    264     /// Copies the stderr of the test case outside of its work directory.
    265     ///
    266     /// \param file The location of the test case's stderr.
    267     void
    268     got_stderr(const fs::path& file)
    269     {
    270         atf::utils::copy_file(file.str(), "helper-stderr.txt");
    271         atf::utils::cat_file("helper-stderr.txt", "helper stderr: ");
    272     }
    273 };
    274 
    275 
    276 /// Simplifies the execution of the helper test cases.
    277 class plain_helper {
    278     /// Path to the test program's source directory.
    279     const fs::path _srcdir;
    280 
    281     /// The root of the test suite.
    282     fs::path _root;
    283 
    284     /// Path to the helper test program, relative to _root.
    285     fs::path _binary_path;
    286 
    287     /// Optional timeout for the test program.
    288     optional< datetime::delta > _timeout;
    289 
    290 public:
    291     /// Constructs a new helper.
    292     ///
    293     /// \param atf_tc A pointer to the calling test case.  Needed to obtain
    294     ///     run-time configuration variables.
    295     /// \param name The name of the helper to run.
    296     /// \param timeout An optional timeout for the test case.
    297     plain_helper(const atf::tests::tc* atf_tc, const char* name,
    298                  const optional< datetime::delta > timeout = none) :
    299         _srcdir(atf_tc->get_config_var("srcdir")),
    300         _root(_srcdir),
    301         _binary_path("test_case_plain_helpers"),
    302         _timeout(timeout)
    303     {
    304         utils::setenv("TEST_CASE", name);
    305     }
    306 
    307     /// Sets an environment variable for the helper.
    308     ///
    309     /// This is simply syntactic sugar for utils::setenv.
    310     ///
    311     /// \param variable The name of the environment variable to set.
    312     /// \param value The value of the variable; must be convertible to a string.
    313     template< typename T >
    314     void
    315     set(const char* variable, const T& value)
    316     {
    317         utils::setenv(variable, F("%s") % value);
    318     }
    319 
    320     /// Places the helper in a different location.
    321     ///
    322     /// This prepares the helper to be run from a different location than the
    323     /// source directory so that the runtime execution can be validated.
    324     ///
    325     /// \param new_binary_path The new path to the binary, relative to the test
    326     ///     suite root.
    327     /// \param new_root The new test suite root.
    328     ///
    329     /// \pre The directory holding the target test program must exist.
    330     ///     Otherwise, the relocation of the binary will fail.
    331     void
    332     move(const char* new_binary_path, const char* new_root)
    333     {
    334         _binary_path = fs::path(new_binary_path);
    335         _root = fs::path(new_root);
    336 
    337         const fs::path src_path = fs::path(_srcdir) / "test_case_plain_helpers";
    338         const fs::path new_path = _root / _binary_path;
    339         ATF_REQUIRE(
    340             ::symlink(src_path.c_str(), new_path.c_str()) != -1);
    341     }
    342 
    343     /// Runs the helper.
    344     ///
    345     /// \param user_config The runtime engine configuration, if different to the
    346     /// defaults.
    347     ///
    348     /// \return The result of the execution.
    349     engine::test_result
    350     run(const config::tree& user_config = engine::default_config()) const
    351     {
    352         engine::metadata_builder mdbuilder;
    353         if (_timeout)
    354             mdbuilder.set_timeout(_timeout.get());
    355         const engine::test_program test_program(
    356             "plain", _binary_path, _root, "unit-tests", mdbuilder.build());
    357         const engine::test_cases_vector& tcs = test_program.test_cases();
    358         fetch_output_hooks fetcher;
    359         const engine::test_result result = engine::run_test_case(
    360             tcs[0].get(), user_config, fetcher, fs::path("."));
    361         std::cerr << "Result is: " << result << '\n';
    362         return result;
    363     }
    364 };
    365 
    366 
    367 /// Creates a mock tester that receives a signal.
    368 ///
    369 /// \param interface The name of the interface implemented by the tester.
    370 /// \param term_sig Signal to deliver to the tester.  If the tester does not
    371 ///     exit due to this reason, it exits with an arbitrary non-zero code.
    372 static void
    373 create_mock_tester_signal(const char* interface, const int term_sig)
    374 {
    375     const std::string tester_name = F("kyua-%s-tester") % interface;
    376 
    377     atf::utils::create_file(
    378         tester_name,
    379         F("#! /bin/sh\n"
    380           "echo 'stdout stuff'\n"
    381           "echo 'stderr stuff' 1>&2\n"
    382           "kill -%s $$\n"
    383           "echo 'not reachable' 1>&2\n"
    384           "exit 0\n") % term_sig);
    385     ATF_REQUIRE(::chmod(tester_name.c_str(), 0755) != -1);
    386 
    387     utils::setenv("KYUA_TESTERSDIR", fs::current_path().str());
    388 }
    389 
    390 
    391 }  // anonymous namespace
    392 
    393 
    394 ATF_TEST_CASE_WITHOUT_HEAD(test_case__ctor_and_getters)
    395 ATF_TEST_CASE_BODY(test_case__ctor_and_getters)
    396 {
    397     const engine::metadata md = engine::metadata_builder()
    398         .add_custom("first", "value")
    399         .build();
    400     const engine::test_program test_program(
    401         "mock", fs::path("abc"), fs::path("unused-root"),
    402         "unused-suite-name", engine::metadata_builder().build());
    403     const engine::test_case test_case("mock", test_program, "foo", md);
    404     ATF_REQUIRE_EQ(&test_program, &test_case.container_test_program());
    405     ATF_REQUIRE_EQ("foo", test_case.name());
    406     ATF_REQUIRE(md == test_case.get_metadata());
    407 }
    408 
    409 
    410 ATF_TEST_CASE_WITHOUT_HEAD(test_case__fake_result)
    411 ATF_TEST_CASE_BODY(test_case__fake_result)
    412 {
    413     const engine::test_result result(engine::test_result::skipped,
    414                                      "Some reason");
    415     const engine::test_program test_program(
    416         "mock", fs::path("abc"), fs::path("unused-root"),
    417         "unused-suite-name", engine::metadata_builder().build());
    418     const engine::test_case test_case("mock", test_program, "__foo__",
    419                                       "Some description", result);
    420     ATF_REQUIRE_EQ(&test_program, &test_case.container_test_program());
    421     ATF_REQUIRE_EQ("__foo__", test_case.name());
    422     ATF_REQUIRE(result == test_case.fake_result().get());
    423 }
    424 
    425 
    426 ATF_TEST_CASE_WITHOUT_HEAD(test_case__operators_eq_and_ne__copy);
    427 ATF_TEST_CASE_BODY(test_case__operators_eq_and_ne__copy)
    428 {
    429     const engine::test_program tp(
    430         "plain", fs::path("non-existent"), fs::path("."), "suite-name",
    431         engine::metadata_builder().build());
    432 
    433     const engine::test_case tc1("plain", tp, "name",
    434                                 engine::metadata_builder().build());
    435     const engine::test_case tc2 = tc1;
    436     ATF_REQUIRE(  tc1 == tc2);
    437     ATF_REQUIRE(!(tc1 != tc2));
    438 }
    439 
    440 
    441 ATF_TEST_CASE_WITHOUT_HEAD(test_case__output);
    442 ATF_TEST_CASE_BODY(test_case__output)
    443 {
    444     const engine::test_program tp(
    445         "plain", fs::path("non-existent"), fs::path("."), "suite-name",
    446         engine::metadata_builder().build());
    447 
    448     const engine::test_case tc1(
    449         "plain", tp, "the-name", engine::metadata_builder()
    450         .add_allowed_platform("foo").add_custom("X-bar", "baz").build());
    451     std::ostringstream str;
    452     str << tc1;
    453     ATF_REQUIRE_EQ(
    454         "test_case{interface='plain', name='the-name', "
    455         "metadata=metadata{allowed_architectures='', allowed_platforms='foo', "
    456         "custom.X-bar='baz', description='', has_cleanup='false', "
    457         "required_configs='', required_files='', required_memory='0', "
    458         "required_programs='', required_user='', timeout='300'}}",
    459         str.str());
    460 }
    461 
    462 
    463 ATF_TEST_CASE_WITHOUT_HEAD(test_case__operators_eq_and_ne__not_copy);
    464 ATF_TEST_CASE_BODY(test_case__operators_eq_and_ne__not_copy)
    465 {
    466     const std::string base_interface("plain");
    467     const engine::test_program base_tp(
    468         "plain", fs::path("non-existent"), fs::path("."), "suite-name",
    469         engine::metadata_builder().build());
    470     const std::string base_name("name");
    471     const engine::metadata base_metadata = engine::metadata_builder()
    472         .add_custom("X-foo", "bar")
    473         .build();
    474 
    475     const engine::test_case base_tc(base_interface, base_tp, base_name,
    476                                     base_metadata);
    477 
    478     // Construct with all same values.
    479     {
    480         const engine::test_case other_tc(base_interface, base_tp, base_name,
    481                                         base_metadata);
    482 
    483         ATF_REQUIRE(  base_tc == other_tc);
    484         ATF_REQUIRE(!(base_tc != other_tc));
    485     }
    486 
    487     // Different interface.
    488     {
    489         const engine::test_case other_tc("atf", base_tp, base_name,
    490                                          base_metadata);
    491 
    492         ATF_REQUIRE(!(base_tc == other_tc));
    493         ATF_REQUIRE(  base_tc != other_tc);
    494     }
    495 
    496     // Different test program, different identifier.
    497     {
    498         const engine::test_program other_tp(
    499             "plain", fs::path("another-name"), fs::path("."), "suite2-name",
    500         engine::metadata_builder().build());
    501         const engine::test_case other_tc(base_interface, other_tp, base_name,
    502                                          base_metadata);
    503 
    504         ATF_REQUIRE(!(base_tc == other_tc));
    505         ATF_REQUIRE(  base_tc != other_tc);
    506     }
    507 
    508     // Different test program, same identifier.  Cannot be detected!
    509     {
    510         const engine::test_program other_tp(
    511             "plain", fs::path("non-existent"), fs::path("."), "suite2-name",
    512         engine::metadata_builder().build());
    513         const engine::test_case other_tc(base_interface, other_tp, base_name,
    514                                          base_metadata);
    515 
    516         ATF_REQUIRE(  base_tc == other_tc);
    517         ATF_REQUIRE(!(base_tc != other_tc));
    518     }
    519 
    520     // Different name.
    521     {
    522         const engine::test_case other_tc(base_interface, base_tp, "other",
    523                                          base_metadata);
    524 
    525         ATF_REQUIRE(!(base_tc == other_tc));
    526         ATF_REQUIRE(  base_tc != other_tc);
    527     }
    528 
    529     // Different metadata.
    530     {
    531         const engine::test_case other_tc(base_interface, base_tp, base_name,
    532                                          engine::metadata_builder().build());
    533 
    534         ATF_REQUIRE(!(base_tc == other_tc));
    535         ATF_REQUIRE(  base_tc != other_tc);
    536     }
    537 }
    538 
    539 
    540 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__tester_crashes);
    541 ATF_TEST_CASE_BODY(run_test_case__tester_crashes)
    542 {
    543     atf_helper helper(this, "pass");
    544     helper.move("program", ".");
    545     create_mock_tester_signal("atf", SIGSEGV);
    546     capture_hooks hooks;
    547     const engine::test_result result = helper.run(hooks);
    548 
    549     ATF_REQUIRE(engine::test_result::broken == result.type());
    550     ATF_REQUIRE_MATCH("Tester received signal.*bug", result.reason());
    551 
    552     ATF_REQUIRE_EQ("stdout stuff\n", hooks.stdout_contents);
    553     ATF_REQUIRE_EQ("stderr stuff\n", hooks.stderr_contents);
    554 }
    555 
    556 
    557 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__current_directory);
    558 ATF_TEST_CASE_BODY(run_test_case__atf__current_directory)
    559 {
    560     atf_helper helper(this, "pass");
    561     helper.move("program", ".");
    562     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    563                    helper.run());
    564 }
    565 
    566 
    567 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__subdirectory);
    568 ATF_TEST_CASE_BODY(run_test_case__atf__subdirectory)
    569 {
    570     atf_helper helper(this, "pass");
    571     ATF_REQUIRE(::mkdir("dir1", 0755) != -1);
    572     ATF_REQUIRE(::mkdir("dir1/dir2", 0755) != -1);
    573     helper.move("dir2/program", "dir1");
    574     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    575                    helper.run());
    576 }
    577 
    578 
    579 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__config_variables);
    580 ATF_TEST_CASE_BODY(run_test_case__atf__config_variables)
    581 {
    582     atf_helper helper(this, "create_cookie_in_control_dir");
    583     helper.set_config("control_dir", fs::current_path());
    584     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    585                    helper.run());
    586 
    587     if (!fs::exists(fs::path("cookie")))
    588         fail("The cookie was not created where we expected; the test program "
    589              "probably received an invalid configuration variable");
    590 }
    591 
    592 
    593 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__cleanup_shares_workdir);
    594 ATF_TEST_CASE_BODY(run_test_case__atf__cleanup_shares_workdir)
    595 {
    596     atf_helper helper(this, "check_cleanup_workdir");
    597     helper.set_metadata("has_cleanup", "true");
    598     helper.set_config("control_dir", fs::current_path());
    599     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped,
    600                                        "cookie created"), helper.run());
    601 
    602     if (fs::exists(fs::path("missing_cookie")))
    603         fail("The cleanup part did not see the cookie; the work directory "
    604              "is probably not shared");
    605     if (fs::exists(fs::path("invalid_cookie")))
    606         fail("The cleanup part read an invalid cookie");
    607     if (!fs::exists(fs::path("cookie_ok")))
    608         fail("The cleanup part was not executed");
    609 }
    610 
    611 
    612 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__has_cleanup__atf__false);
    613 ATF_TEST_CASE_BODY(run_test_case__atf__has_cleanup__atf__false)
    614 {
    615     atf_helper helper(this, "create_cookie_from_cleanup");
    616     helper.set_metadata("has_cleanup", "false");
    617     helper.set_config("control_dir", fs::current_path());
    618     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    619                    helper.run());
    620 
    621     if (fs::exists(fs::path("cookie")))
    622         fail("The cleanup part was executed even though the test case set "
    623              "has.cleanup to false");
    624 }
    625 
    626 
    627 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__has_cleanup__atf__true);
    628 ATF_TEST_CASE_BODY(run_test_case__atf__has_cleanup__atf__true)
    629 {
    630     atf_helper helper(this, "create_cookie_from_cleanup");
    631     helper.set_metadata("has_cleanup", "true");
    632     helper.set_config("control_dir", fs::current_path());
    633     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    634                    helper.run());
    635 
    636     if (!fs::exists(fs::path("cookie")))
    637         fail("The cleanup part was not executed even though the test case set "
    638              "has.cleanup to true");
    639 }
    640 
    641 
    642 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__kill_children);
    643 ATF_TEST_CASE_BODY(run_test_case__atf__kill_children)
    644 {
    645     atf_helper helper(this, "spawn_blocking_child");
    646     helper.set_config("control_dir", fs::current_path());
    647     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    648                    helper.run());
    649 
    650     if (!fs::exists(fs::path("pid")))
    651         fail("The pid file was not created");
    652     std::ifstream pidfile("pid");
    653     ATF_REQUIRE(pidfile);
    654     pid_t pid;
    655     pidfile >> pid;
    656     pidfile.close();
    657 
    658     int attempts = 30;
    659 retry:
    660     if (::kill(pid, SIGCONT) != -1 || errno != ESRCH) {
    661         // Looks like the subchild did not die.
    662         //
    663         // Note that this might be inaccurate for two reasons:
    664         // 1) The system may have spawned a new process with the same pid as
    665         //    our subchild... but in practice, this does not happen because
    666         //    most systems do not immediately reuse pid numbers.  If that
    667         //    happens... well, we get a false test failure.
    668         // 2) We ran so fast that even if the process was sent a signal to
    669         //    die, it has not had enough time to process it yet.  This is why
    670         //    we retry this a few times.
    671         if (attempts > 0) {
    672             std::cout << "Subprocess not dead yet; retrying wait\n";
    673             --attempts;
    674             ::usleep(100000);
    675             goto retry;
    676         }
    677         fail(F("The subprocess %s of our child was not killed") % pid);
    678     }
    679 }
    680 
    681 
    682 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__isolation);
    683 ATF_TEST_CASE_BODY(run_test_case__atf__isolation)
    684 {
    685     atf_helper helper(this, "validate_isolation");
    686     // Simple checks to make sure that the test case has been isolated.
    687     utils::setenv("HOME", "fake-value");
    688     utils::setenv("LANG", "C");
    689     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    690                    helper.run());
    691 }
    692 
    693 
    694 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__allowed_architectures);
    695 ATF_TEST_CASE_BODY(run_test_case__atf__allowed_architectures)
    696 {
    697     atf_helper helper(this, "create_cookie_in_control_dir");
    698     helper.set_metadata("allowed_architectures", "i386 x86_64");
    699     helper.config().set_string("architecture", "powerpc");
    700     helper.config().set_string("platform", "");
    701     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Current "
    702                                        "architecture 'powerpc' not supported"),
    703                    helper.run());
    704 
    705     if (fs::exists(fs::path("cookie")))
    706         fail("The test case was not really skipped when the requirements "
    707              "check failed");
    708 }
    709 
    710 
    711 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__allowed_platforms);
    712 ATF_TEST_CASE_BODY(run_test_case__atf__allowed_platforms)
    713 {
    714     atf_helper helper(this, "create_cookie_in_control_dir");
    715     helper.set_metadata("allowed_platforms", "i386 amd64");
    716     helper.config().set_string("architecture", "");
    717     helper.config().set_string("platform", "macppc");
    718     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Current "
    719                                        "platform 'macppc' not supported"),
    720                    helper.run());
    721 
    722     if (fs::exists(fs::path("cookie")))
    723         fail("The test case was not really skipped when the requirements "
    724              "check failed");
    725 }
    726 
    727 
    728 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__required_configs);
    729 ATF_TEST_CASE_BODY(run_test_case__atf__required_configs)
    730 {
    731     atf_helper helper(this, "create_cookie_in_control_dir");
    732     helper.set_metadata("required_configs", "used-var");
    733     helper.set_config("control_dir", fs::current_path());
    734     helper.set_config("unused-var", "value");
    735     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Required "
    736                                        "configuration property 'used-var' not "
    737                                        "defined"),
    738                    helper.run());
    739 
    740     if (fs::exists(fs::path("cookie")))
    741         fail("The test case was not really skipped when the requirements "
    742              "check failed");
    743 }
    744 
    745 
    746 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__required_programs);
    747 ATF_TEST_CASE_BODY(run_test_case__atf__required_programs)
    748 {
    749     atf_helper helper(this, "create_cookie_in_control_dir");
    750     helper.set_metadata("required_programs", "/non-existent/program");
    751     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Required "
    752                                        "program '/non-existent/program' not "
    753                                        "found"),
    754                    helper.run());
    755 
    756     if (fs::exists(fs::path("cookie")))
    757         fail("The test case was not really skipped when the requirements "
    758              "check failed");
    759 }
    760 
    761 
    762 ATF_TEST_CASE(run_test_case__atf__required_user__atf__root__atf__ok);
    763 ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__root__atf__ok)
    764 {
    765     set_md_var("require.user", "root");
    766 }
    767 ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__root__atf__ok)
    768 {
    769     atf_helper helper(this, "create_cookie_in_workdir");
    770     helper.set_metadata("required_user", "root");
    771     ATF_REQUIRE(passwd::current_user().is_root());
    772     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    773                    helper.run());
    774 }
    775 
    776 
    777 ATF_TEST_CASE(run_test_case__atf__required_user__atf__root__atf__skip);
    778 ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__root__atf__skip)
    779 {
    780     set_md_var("require.user", "unprivileged");
    781 }
    782 ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__root__atf__skip)
    783 {
    784     atf_helper helper(this, "create_cookie_in_workdir");
    785     helper.set_metadata("required_user", "root");
    786     ATF_REQUIRE(!passwd::current_user().is_root());
    787     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Requires "
    788                                        "root privileges"),
    789                    helper.run());
    790 }
    791 
    792 
    793 ATF_TEST_CASE(run_test_case__atf__required_user__atf__unprivileged__atf__ok);
    794 ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__unprivileged__atf__ok)
    795 {
    796     set_md_var("require.user", "unprivileged");
    797 }
    798 ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__unprivileged__atf__ok)
    799 {
    800     atf_helper helper(this, "create_cookie_in_workdir");
    801     helper.set_metadata("required_user", "unprivileged");
    802     ATF_REQUIRE(!helper.config().is_set("unprivileged_user"));
    803     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    804                    helper.run());
    805 }
    806 
    807 
    808 ATF_TEST_CASE(run_test_case__atf__required_user__atf__unprivileged__atf__skip);
    809 ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__unprivileged__atf__skip)
    810 {
    811     set_md_var("require.user", "root");
    812 }
    813 ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__unprivileged__atf__skip)
    814 {
    815     atf_helper helper(this, "create_cookie_in_workdir");
    816     helper.set_metadata("required_user", "unprivileged");
    817     ATF_REQUIRE(!helper.config().is_set("unprivileged_user"));
    818     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Requires "
    819                                        "an unprivileged user but the "
    820                                        "unprivileged-user configuration "
    821                                        "variable is not defined"),
    822                    helper.run());
    823 }
    824 
    825 
    826 ATF_TEST_CASE(run_test_case__atf__required_user__atf__unprivileged__atf__drop);
    827 ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__unprivileged__atf__drop)
    828 {
    829     set_md_var("require.config", "unprivileged-user");
    830     set_md_var("require.user", "root");
    831 }
    832 ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__unprivileged__atf__drop)
    833 {
    834     atf_helper helper(this, "check_unprivileged");
    835     helper.set_metadata("required_user", "unprivileged");
    836     helper.config().set< engine::user_node >(
    837         "unprivileged_user",
    838         passwd::find_user_by_name(get_config_var("unprivileged-user")));
    839     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    840                    helper.run());
    841 }
    842 
    843 
    844 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__timeout_body);
    845 ATF_TEST_CASE_BODY(run_test_case__atf__timeout_body)
    846 {
    847     atf_helper helper(this, "timeout_body");
    848     helper.set_metadata("timeout", "1");
    849     helper.set_config("control_dir", fs::current_path());
    850     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::broken,
    851                                        "Test case body timed out"),
    852                    helper.run());
    853 
    854     if (fs::exists(fs::path("cookie")))
    855         fail("It seems that the test case was not killed after it timed out");
    856 }
    857 
    858 
    859 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__timeout_cleanup);
    860 ATF_TEST_CASE_BODY(run_test_case__atf__timeout_cleanup)
    861 {
    862     atf_helper helper(this, "timeout_cleanup");
    863     helper.set_metadata("has_cleanup", "true");
    864     helper.set_metadata("timeout", "1");
    865     helper.set_config("control_dir", fs::current_path());
    866     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::broken,
    867                                        "Test case cleanup timed out"),
    868                    helper.run());
    869 
    870     if (fs::exists(fs::path("cookie")))
    871         fail("It seems that the test case was not killed after it timed out");
    872 }
    873 
    874 
    875 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__stacktrace__atf__body);
    876 ATF_TEST_CASE_BODY(run_test_case__atf__stacktrace__atf__body)
    877 {
    878     atf_helper helper(this, "crash");
    879     capture_hooks hooks;
    880     const engine::test_result result = helper.run(hooks);
    881     ATF_REQUIRE(engine::test_result::broken == result.type());
    882     ATF_REQUIRE_MATCH("received signal.*core dumped", result.reason());
    883 
    884     ATF_REQUIRE(!atf::utils::grep_string("attempting to gather stack trace",
    885                                          hooks.stdout_contents));
    886     ATF_REQUIRE( atf::utils::grep_string("attempting to gather stack trace",
    887                                          hooks.stderr_contents));
    888 }
    889 
    890 
    891 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__stacktrace__atf__cleanup);
    892 ATF_TEST_CASE_BODY(run_test_case__atf__stacktrace__atf__cleanup)
    893 {
    894     atf_helper helper(this, "crash_cleanup");
    895     helper.set_metadata("has_cleanup", "true");
    896     capture_hooks hooks;
    897     const engine::test_result result = helper.run(hooks);
    898     ATF_REQUIRE(engine::test_result::broken == result.type());
    899     ATF_REQUIRE_MATCH(F("cleanup received signal %s") % SIGABRT,
    900                       result.reason());
    901 
    902     ATF_REQUIRE(!atf::utils::grep_string("attempting to gather stack trace",
    903                                          hooks.stdout_contents));
    904     ATF_REQUIRE( atf::utils::grep_string("attempting to gather stack trace",
    905                                          hooks.stderr_contents));
    906 }
    907 
    908 
    909 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__missing_results_file);
    910 ATF_TEST_CASE_BODY(run_test_case__atf__missing_results_file)
    911 {
    912     atf_helper helper(this, "crash");
    913     const engine::test_result result = helper.run();
    914     ATF_REQUIRE(engine::test_result::broken == result.type());
    915     // Need to match instead of doing an explicit comparison because the string
    916     // may include the "core dumped" substring.
    917     ATF_REQUIRE_MATCH(F("test case received signal %s") % SIGABRT,
    918                       result.reason());
    919 }
    920 
    921 
    922 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__missing_test_program);
    923 ATF_TEST_CASE_BODY(run_test_case__atf__missing_test_program)
    924 {
    925     atf_helper helper(this, "crash");
    926     ATF_REQUIRE(::mkdir("dir", 0755) != -1);
    927     helper.move("test_case_atf_helpers", "dir");
    928     ATF_REQUIRE(::unlink("dir/test_case_atf_helpers") != -1);
    929     const engine::test_result result = helper.run();
    930     ATF_REQUIRE(engine::test_result::broken == result.type());
    931     ATF_REQUIRE_MATCH("Test program does not exist", result.reason());
    932 }
    933 
    934 
    935 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__output);
    936 ATF_TEST_CASE_BODY(run_test_case__atf__output)
    937 {
    938     atf_helper helper(this, "output");
    939     helper.set_metadata("has_cleanup", "true");
    940 
    941     capture_hooks hooks;
    942     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    943                    helper.run(hooks));
    944 
    945     ATF_REQUIRE_EQ("Body message to stdout\nCleanup message to stdout\n",
    946                    hooks.stdout_contents);
    947     ATF_REQUIRE_EQ("Body message to stderr\nCleanup message to stderr\n",
    948                    hooks.stderr_contents);
    949 }
    950 
    951 
    952 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__result_pass);
    953 ATF_TEST_CASE_BODY(run_test_case__plain__result_pass)
    954 {
    955     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    956                    plain_helper(this, "pass").run());
    957 }
    958 
    959 
    960 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__result_fail);
    961 ATF_TEST_CASE_BODY(run_test_case__plain__result_fail)
    962 {
    963     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::failed,
    964                                        "Returned non-success exit status 8"),
    965                    plain_helper(this, "fail").run());
    966 }
    967 
    968 
    969 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__result_crash);
    970 ATF_TEST_CASE_BODY(run_test_case__plain__result_crash)
    971 {
    972     const engine::test_result result = plain_helper(this, "crash").run();
    973     ATF_REQUIRE(engine::test_result::broken == result.type());
    974     ATF_REQUIRE_MATCH(F("Received signal %s") % SIGABRT, result.reason());
    975 }
    976 
    977 
    978 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__current_directory);
    979 ATF_TEST_CASE_BODY(run_test_case__plain__current_directory)
    980 {
    981     plain_helper helper(this, "pass");
    982     helper.move("program", ".");
    983     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    984                    helper.run());
    985 }
    986 
    987 
    988 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__subdirectory);
    989 ATF_TEST_CASE_BODY(run_test_case__plain__subdirectory)
    990 {
    991     plain_helper helper(this, "pass");
    992     ATF_REQUIRE(::mkdir("dir1", 0755) != -1);
    993     ATF_REQUIRE(::mkdir("dir1/dir2", 0755) != -1);
    994     helper.move("dir2/program", "dir1");
    995     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
    996                    helper.run());
    997 }
    998 
    999 
   1000 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__kill_children);
   1001 ATF_TEST_CASE_BODY(run_test_case__plain__kill_children)
   1002 {
   1003     plain_helper helper(this, "spawn_blocking_child");
   1004     helper.set("CONTROL_DIR", fs::current_path());
   1005     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
   1006                    helper.run());
   1007 
   1008     if (!fs::exists(fs::path("pid")))
   1009         fail("The pid file was not created");
   1010     std::ifstream pidfile("pid");
   1011     ATF_REQUIRE(pidfile);
   1012     pid_t pid;
   1013     pidfile >> pid;
   1014     pidfile.close();
   1015 
   1016     int attempts = 30;
   1017 retry:
   1018     if (::kill(pid, SIGCONT) != -1 || errno != ESRCH) {
   1019         // Looks like the subchild did not die.
   1020         //
   1021         // Note that this might be inaccurate for two reasons:
   1022         // 1) The system may have spawned a new process with the same pid as
   1023         //    our subchild... but in practice, this does not happen because
   1024         //    most systems do not immediately reuse pid numbers.  If that
   1025         //    happens... well, we get a false test failure.
   1026         // 2) We ran so fast that even if the process was sent a signal to
   1027         //    die, it has not had enough time to process it yet.  This is why
   1028         //    we retry this a few times.
   1029         if (attempts > 0) {
   1030             std::cout << "Subprocess not dead yet; retrying wait\n";
   1031             --attempts;
   1032             ::usleep(100000);
   1033             goto retry;
   1034         }
   1035         fail(F("The subprocess %s of our child was not killed") % pid);
   1036     }
   1037 }
   1038 
   1039 
   1040 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__isolation);
   1041 ATF_TEST_CASE_BODY(run_test_case__plain__isolation)
   1042 {
   1043     const plain_helper helper(this, "validate_isolation");
   1044     utils::setenv("TEST_CASE", "validate_isolation");
   1045     // Simple checks to make sure that the test case has been isolated.
   1046     utils::setenv("HOME", "fake-value");
   1047     utils::setenv("LANG", "C");
   1048     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
   1049                    helper.run());
   1050 }
   1051 
   1052 
   1053 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__timeout);
   1054 ATF_TEST_CASE_BODY(run_test_case__plain__timeout)
   1055 {
   1056     plain_helper helper(this, "timeout",
   1057                         utils::make_optional(datetime::delta(1, 0)));
   1058     helper.set("CONTROL_DIR", fs::current_path());
   1059     ATF_REQUIRE_EQ(engine::test_result(engine::test_result::broken,
   1060                                        "Test case timed out"),
   1061                    helper.run());
   1062 
   1063     if (fs::exists(fs::path("cookie")))
   1064         fail("It seems that the test case was not killed after it timed out");
   1065 }
   1066 
   1067 
   1068 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__stacktrace);
   1069 ATF_TEST_CASE_BODY(run_test_case__plain__stacktrace)
   1070 {
   1071     plain_helper helper(this, "crash");
   1072     helper.set("CONTROL_DIR", fs::current_path());
   1073 
   1074     const engine::test_result result = plain_helper(this, "crash").run();
   1075     ATF_REQUIRE(engine::test_result::broken == result.type());
   1076     ATF_REQUIRE_MATCH(F("Received signal %s") % SIGABRT, result.reason());
   1077 
   1078     ATF_REQUIRE(!atf::utils::grep_file("attempting to gather stack trace",
   1079                                        "helper-stdout.txt"));
   1080     ATF_REQUIRE( atf::utils::grep_file("attempting to gather stack trace",
   1081                                        "helper-stderr.txt"));
   1082 }
   1083 
   1084 
   1085 ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__missing_test_program);
   1086 ATF_TEST_CASE_BODY(run_test_case__plain__missing_test_program)
   1087 {
   1088     plain_helper helper(this, "pass");
   1089     ATF_REQUIRE(::mkdir("dir", 0755) != -1);
   1090     helper.move("test_case_helpers", "dir");
   1091     ATF_REQUIRE(::unlink("dir/test_case_helpers") != -1);
   1092     const engine::test_result result = helper.run();
   1093     ATF_REQUIRE(engine::test_result::broken == result.type());
   1094     ATF_REQUIRE_MATCH("Test program does not exist", result.reason());
   1095 }
   1096 
   1097 
   1098 ATF_INIT_TEST_CASES(tcs)
   1099 {
   1100     ATF_ADD_TEST_CASE(tcs, test_case__ctor_and_getters);
   1101     ATF_ADD_TEST_CASE(tcs, test_case__fake_result);
   1102 
   1103     ATF_ADD_TEST_CASE(tcs, test_case__operators_eq_and_ne__copy);
   1104     ATF_ADD_TEST_CASE(tcs, test_case__operators_eq_and_ne__not_copy);
   1105 
   1106     ATF_ADD_TEST_CASE(tcs, test_case__output);
   1107 
   1108     ATF_ADD_TEST_CASE(tcs, run_test_case__tester_crashes);
   1109 
   1110     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__current_directory);
   1111     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__subdirectory);
   1112     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__config_variables);
   1113     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__cleanup_shares_workdir);
   1114     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__has_cleanup__atf__false);
   1115     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__has_cleanup__atf__true);
   1116     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__kill_children);
   1117     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__isolation);
   1118     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__allowed_architectures);
   1119     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__allowed_platforms);
   1120     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_configs);
   1121     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_programs);
   1122     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__root__atf__ok);
   1123     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__root__atf__skip);
   1124     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__unprivileged__atf__ok);
   1125     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__unprivileged__atf__skip);
   1126     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__unprivileged__atf__drop);
   1127     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__timeout_body);
   1128     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__timeout_cleanup);
   1129     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__stacktrace__atf__body);
   1130     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__stacktrace__atf__cleanup);
   1131     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__missing_results_file);
   1132     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__missing_test_program);
   1133     ATF_ADD_TEST_CASE(tcs, run_test_case__atf__output);
   1134 
   1135     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__result_pass);
   1136     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__result_fail);
   1137     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__result_crash);
   1138     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__current_directory);
   1139     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__subdirectory);
   1140     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__kill_children);
   1141     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__isolation);
   1142     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__timeout);
   1143     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__stacktrace);
   1144     ATF_ADD_TEST_CASE(tcs, run_test_case__plain__missing_test_program);
   1145 
   1146     // TODO(jmmv): Add test cases for debug.
   1147 }
   1148