xref: /freebsd-src/contrib/kyua/engine/scheduler_test.cpp (revision b0d29bc47dba79f6f38e67eabadfb4b32ffd9390)
1*b0d29bc4SBrooks Davis // Copyright 2014 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis //   without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis 
29*b0d29bc4SBrooks Davis #include "engine/scheduler.hpp"
30*b0d29bc4SBrooks Davis 
31*b0d29bc4SBrooks Davis extern "C" {
32*b0d29bc4SBrooks Davis #include <sys/types.h>
33*b0d29bc4SBrooks Davis 
34*b0d29bc4SBrooks Davis #include <signal.h>
35*b0d29bc4SBrooks Davis #include <unistd.h>
36*b0d29bc4SBrooks Davis }
37*b0d29bc4SBrooks Davis 
38*b0d29bc4SBrooks Davis #include <cstdlib>
39*b0d29bc4SBrooks Davis #include <fstream>
40*b0d29bc4SBrooks Davis #include <iostream>
41*b0d29bc4SBrooks Davis #include <string>
42*b0d29bc4SBrooks Davis 
43*b0d29bc4SBrooks Davis #include <atf-c++.hpp>
44*b0d29bc4SBrooks Davis 
45*b0d29bc4SBrooks Davis #include "engine/config.hpp"
46*b0d29bc4SBrooks Davis #include "engine/exceptions.hpp"
47*b0d29bc4SBrooks Davis #include "model/context.hpp"
48*b0d29bc4SBrooks Davis #include "model/metadata.hpp"
49*b0d29bc4SBrooks Davis #include "model/test_case.hpp"
50*b0d29bc4SBrooks Davis #include "model/test_program.hpp"
51*b0d29bc4SBrooks Davis #include "model/test_result.hpp"
52*b0d29bc4SBrooks Davis #include "utils/config/tree.ipp"
53*b0d29bc4SBrooks Davis #include "utils/datetime.hpp"
54*b0d29bc4SBrooks Davis #include "utils/defs.hpp"
55*b0d29bc4SBrooks Davis #include "utils/env.hpp"
56*b0d29bc4SBrooks Davis #include "utils/format/containers.ipp"
57*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
58*b0d29bc4SBrooks Davis #include "utils/fs/operations.hpp"
59*b0d29bc4SBrooks Davis #include "utils/fs/path.hpp"
60*b0d29bc4SBrooks Davis #include "utils/optional.ipp"
61*b0d29bc4SBrooks Davis #include "utils/passwd.hpp"
62*b0d29bc4SBrooks Davis #include "utils/process/status.hpp"
63*b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
64*b0d29bc4SBrooks Davis #include "utils/stacktrace.hpp"
65*b0d29bc4SBrooks Davis #include "utils/stream.hpp"
66*b0d29bc4SBrooks Davis #include "utils/test_utils.ipp"
67*b0d29bc4SBrooks Davis #include "utils/text/exceptions.hpp"
68*b0d29bc4SBrooks Davis #include "utils/text/operations.ipp"
69*b0d29bc4SBrooks Davis 
70*b0d29bc4SBrooks Davis namespace config = utils::config;
71*b0d29bc4SBrooks Davis namespace datetime = utils::datetime;
72*b0d29bc4SBrooks Davis namespace fs = utils::fs;
73*b0d29bc4SBrooks Davis namespace passwd = utils::passwd;
74*b0d29bc4SBrooks Davis namespace process = utils::process;
75*b0d29bc4SBrooks Davis namespace scheduler = engine::scheduler;
76*b0d29bc4SBrooks Davis namespace text = utils::text;
77*b0d29bc4SBrooks Davis 
78*b0d29bc4SBrooks Davis using utils::none;
79*b0d29bc4SBrooks Davis using utils::optional;
80*b0d29bc4SBrooks Davis 
81*b0d29bc4SBrooks Davis 
82*b0d29bc4SBrooks Davis namespace {
83*b0d29bc4SBrooks Davis 
84*b0d29bc4SBrooks Davis 
85*b0d29bc4SBrooks Davis /// Checks if a string starts with a prefix.
86*b0d29bc4SBrooks Davis ///
87*b0d29bc4SBrooks Davis /// \param str The string to be tested.
88*b0d29bc4SBrooks Davis /// \param prefix The prefix to look for.
89*b0d29bc4SBrooks Davis ///
90*b0d29bc4SBrooks Davis /// \return True if the string is prefixed as specified.
91*b0d29bc4SBrooks Davis static bool
starts_with(const std::string & str,const std::string & prefix)92*b0d29bc4SBrooks Davis starts_with(const std::string& str, const std::string& prefix)
93*b0d29bc4SBrooks Davis {
94*b0d29bc4SBrooks Davis     return (str.length() >= prefix.length() &&
95*b0d29bc4SBrooks Davis             str.substr(0, prefix.length()) == prefix);
96*b0d29bc4SBrooks Davis }
97*b0d29bc4SBrooks Davis 
98*b0d29bc4SBrooks Davis 
99*b0d29bc4SBrooks Davis /// Strips a prefix from a string and converts the rest to an integer.
100*b0d29bc4SBrooks Davis ///
101*b0d29bc4SBrooks Davis /// \param str The string to be tested.
102*b0d29bc4SBrooks Davis /// \param prefix The prefix to strip from the string.
103*b0d29bc4SBrooks Davis ///
104*b0d29bc4SBrooks Davis /// \return The part of the string after the prefix converted to an integer.
105*b0d29bc4SBrooks Davis static int
suffix_to_int(const std::string & str,const std::string & prefix)106*b0d29bc4SBrooks Davis suffix_to_int(const std::string& str, const std::string& prefix)
107*b0d29bc4SBrooks Davis {
108*b0d29bc4SBrooks Davis     PRE(starts_with(str, prefix));
109*b0d29bc4SBrooks Davis     try {
110*b0d29bc4SBrooks Davis         return text::to_type< int >(str.substr(prefix.length()));
111*b0d29bc4SBrooks Davis     } catch (const text::value_error& error) {
112*b0d29bc4SBrooks Davis         std::cerr << F("Failed: %s\n") % error.what();
113*b0d29bc4SBrooks Davis         std::abort();
114*b0d29bc4SBrooks Davis     }
115*b0d29bc4SBrooks Davis }
116*b0d29bc4SBrooks Davis 
117*b0d29bc4SBrooks Davis 
118*b0d29bc4SBrooks Davis /// Mock interface definition for testing.
119*b0d29bc4SBrooks Davis ///
120*b0d29bc4SBrooks Davis /// This scheduler interface does not execute external binaries.  It is designed
121*b0d29bc4SBrooks Davis /// to simulate the scheduler of various programs with different exit statuses.
122*b0d29bc4SBrooks Davis class mock_interface : public scheduler::interface {
123*b0d29bc4SBrooks Davis     /// Executes the subprocess simulating an exec.
124*b0d29bc4SBrooks Davis     ///
125*b0d29bc4SBrooks Davis     /// This is just a simple wrapper over _exit(2) because we cannot use
126*b0d29bc4SBrooks Davis     /// std::exit on exit from this mock interface.  The reason is that we do
127*b0d29bc4SBrooks Davis     /// not want to invoke any destructors as otherwise we'd clear up the global
128*b0d29bc4SBrooks Davis     /// scheduler state by mistake.  This wouldn't be a major problem if it
129*b0d29bc4SBrooks Davis     /// wasn't because doing so deletes on-disk files and we want to leave them
130*b0d29bc4SBrooks Davis     /// in place so that the parent process can test for them!
131*b0d29bc4SBrooks Davis     ///
132*b0d29bc4SBrooks Davis     /// \param exit_code Exit code.
133*b0d29bc4SBrooks Davis     void
do_exit(const int exit_code) const134*b0d29bc4SBrooks Davis     do_exit(const int exit_code) const UTILS_NORETURN
135*b0d29bc4SBrooks Davis     {
136*b0d29bc4SBrooks Davis         std::cout.flush();
137*b0d29bc4SBrooks Davis         std::cerr.flush();
138*b0d29bc4SBrooks Davis         ::_exit(exit_code);
139*b0d29bc4SBrooks Davis     }
140*b0d29bc4SBrooks Davis 
141*b0d29bc4SBrooks Davis     /// Executes a test case that creates various files and then fails.
142*b0d29bc4SBrooks Davis     void
exec_create_files_and_fail(void) const143*b0d29bc4SBrooks Davis     exec_create_files_and_fail(void) const UTILS_NORETURN
144*b0d29bc4SBrooks Davis     {
145*b0d29bc4SBrooks Davis         std::cerr << "This should not be clobbered\n";
146*b0d29bc4SBrooks Davis         atf::utils::create_file("first file", "");
147*b0d29bc4SBrooks Davis         atf::utils::create_file("second-file", "");
148*b0d29bc4SBrooks Davis         fs::mkdir_p(fs::path("dir1/dir2"), 0755);
149*b0d29bc4SBrooks Davis         ::kill(::getpid(), SIGTERM);
150*b0d29bc4SBrooks Davis         std::abort();
151*b0d29bc4SBrooks Davis     }
152*b0d29bc4SBrooks Davis 
153*b0d29bc4SBrooks Davis     /// Executes a test case that deletes all files in the current directory.
154*b0d29bc4SBrooks Davis     ///
155*b0d29bc4SBrooks Davis     /// This is intended to validate that the test runs in an empty directory,
156*b0d29bc4SBrooks Davis     /// separate from any control files that the scheduler may have created.
157*b0d29bc4SBrooks Davis     void
exec_delete_all(void) const158*b0d29bc4SBrooks Davis     exec_delete_all(void) const UTILS_NORETURN
159*b0d29bc4SBrooks Davis     {
160*b0d29bc4SBrooks Davis         const int exit_code = ::system("rm *") == -1
161*b0d29bc4SBrooks Davis             ? EXIT_FAILURE : EXIT_SUCCESS;
162*b0d29bc4SBrooks Davis 
163*b0d29bc4SBrooks Davis         // Recreate our own cookie.
164*b0d29bc4SBrooks Davis         atf::utils::create_file("exec_test_was_called", "");
165*b0d29bc4SBrooks Davis 
166*b0d29bc4SBrooks Davis         do_exit(exit_code);
167*b0d29bc4SBrooks Davis     }
168*b0d29bc4SBrooks Davis 
169*b0d29bc4SBrooks Davis     /// Executes a test case that returns a specific exit code.
170*b0d29bc4SBrooks Davis     ///
171*b0d29bc4SBrooks Davis     /// \param exit_code Exit status to terminate the program with.
172*b0d29bc4SBrooks Davis     void
exec_exit(const int exit_code) const173*b0d29bc4SBrooks Davis     exec_exit(const int exit_code) const UTILS_NORETURN
174*b0d29bc4SBrooks Davis     {
175*b0d29bc4SBrooks Davis         do_exit(exit_code);
176*b0d29bc4SBrooks Davis     }
177*b0d29bc4SBrooks Davis 
178*b0d29bc4SBrooks Davis     /// Executes a test case that just fails.
179*b0d29bc4SBrooks Davis     void
exec_fail(void) const180*b0d29bc4SBrooks Davis     exec_fail(void) const UTILS_NORETURN
181*b0d29bc4SBrooks Davis     {
182*b0d29bc4SBrooks Davis         std::cerr << "This should not be clobbered\n";
183*b0d29bc4SBrooks Davis         ::kill(::getpid(), SIGTERM);
184*b0d29bc4SBrooks Davis         std::abort();
185*b0d29bc4SBrooks Davis     }
186*b0d29bc4SBrooks Davis 
187*b0d29bc4SBrooks Davis     /// Executes a test case that prints all input parameters to the functor.
188*b0d29bc4SBrooks Davis     ///
189*b0d29bc4SBrooks Davis     /// \param test_program The test program to execute.
190*b0d29bc4SBrooks Davis     /// \param test_case_name Name of the test case to invoke, which must be a
191*b0d29bc4SBrooks Davis     ///     number.
192*b0d29bc4SBrooks Davis     /// \param vars User-provided variables to pass to the test program.
193*b0d29bc4SBrooks Davis     void
exec_print_params(const model::test_program & test_program,const std::string & test_case_name,const config::properties_map & vars) const194*b0d29bc4SBrooks Davis     exec_print_params(const model::test_program& test_program,
195*b0d29bc4SBrooks Davis                       const std::string& test_case_name,
196*b0d29bc4SBrooks Davis                       const config::properties_map& vars) const
197*b0d29bc4SBrooks Davis         UTILS_NORETURN
198*b0d29bc4SBrooks Davis     {
199*b0d29bc4SBrooks Davis         std::cout << F("Test program: %s\n") % test_program.relative_path();
200*b0d29bc4SBrooks Davis         std::cout << F("Test case: %s\n") % test_case_name;
201*b0d29bc4SBrooks Davis         for (config::properties_map::const_iterator iter = vars.begin();
202*b0d29bc4SBrooks Davis              iter != vars.end(); ++iter) {
203*b0d29bc4SBrooks Davis             std::cout << F("%s=%s\n") % (*iter).first % (*iter).second;
204*b0d29bc4SBrooks Davis         }
205*b0d29bc4SBrooks Davis 
206*b0d29bc4SBrooks Davis         std::cerr << F("stderr: %s\n") % test_case_name;
207*b0d29bc4SBrooks Davis 
208*b0d29bc4SBrooks Davis         do_exit(EXIT_SUCCESS);
209*b0d29bc4SBrooks Davis     }
210*b0d29bc4SBrooks Davis 
211*b0d29bc4SBrooks Davis public:
212*b0d29bc4SBrooks Davis     /// Executes a test program's list operation.
213*b0d29bc4SBrooks Davis     ///
214*b0d29bc4SBrooks Davis     /// This method is intended to be called within a subprocess and is expected
215*b0d29bc4SBrooks Davis     /// to terminate execution either by exec(2)ing the test program or by
216*b0d29bc4SBrooks Davis     /// exiting with a failure.
217*b0d29bc4SBrooks Davis     ///
218*b0d29bc4SBrooks Davis     /// \param test_program The test program to execute.
219*b0d29bc4SBrooks Davis     /// \param vars User-provided variables to pass to the test program.
220*b0d29bc4SBrooks Davis     void
exec_list(const model::test_program & test_program,const config::properties_map & vars) const221*b0d29bc4SBrooks Davis     exec_list(const model::test_program& test_program,
222*b0d29bc4SBrooks Davis               const config::properties_map& vars)
223*b0d29bc4SBrooks Davis         const UTILS_NORETURN
224*b0d29bc4SBrooks Davis     {
225*b0d29bc4SBrooks Davis         const std::string name = test_program.absolute_path().leaf_name();
226*b0d29bc4SBrooks Davis 
227*b0d29bc4SBrooks Davis         std::cerr << name;
228*b0d29bc4SBrooks Davis         std::cerr.flush();
229*b0d29bc4SBrooks Davis         if (name == "check_i_exist") {
230*b0d29bc4SBrooks Davis             if (fs::exists(test_program.absolute_path())) {
231*b0d29bc4SBrooks Davis                 std::cout << "found\n";
232*b0d29bc4SBrooks Davis                 do_exit(EXIT_SUCCESS);
233*b0d29bc4SBrooks Davis             } else {
234*b0d29bc4SBrooks Davis                 std::cout << "not_found\n";
235*b0d29bc4SBrooks Davis                 do_exit(EXIT_FAILURE);
236*b0d29bc4SBrooks Davis             }
237*b0d29bc4SBrooks Davis         } else if (name == "empty") {
238*b0d29bc4SBrooks Davis             do_exit(EXIT_SUCCESS);
239*b0d29bc4SBrooks Davis         } else if (name == "misbehave") {
240*b0d29bc4SBrooks Davis             utils::abort_without_coredump();
241*b0d29bc4SBrooks Davis         } else if (name == "timeout") {
242*b0d29bc4SBrooks Davis             std::cout << "sleeping\n";
243*b0d29bc4SBrooks Davis             std::cout.flush();
244*b0d29bc4SBrooks Davis             ::sleep(100);
245*b0d29bc4SBrooks Davis             utils::abort_without_coredump();
246*b0d29bc4SBrooks Davis         } else if (name == "vars") {
247*b0d29bc4SBrooks Davis             for (config::properties_map::const_iterator iter = vars.begin();
248*b0d29bc4SBrooks Davis                  iter != vars.end(); ++iter) {
249*b0d29bc4SBrooks Davis                 std::cout << F("%s_%s\n") % (*iter).first % (*iter).second;
250*b0d29bc4SBrooks Davis             }
251*b0d29bc4SBrooks Davis             do_exit(15);
252*b0d29bc4SBrooks Davis         } else {
253*b0d29bc4SBrooks Davis             std::abort();
254*b0d29bc4SBrooks Davis         }
255*b0d29bc4SBrooks Davis     }
256*b0d29bc4SBrooks Davis 
257*b0d29bc4SBrooks Davis     /// Computes the test cases list of a test program.
258*b0d29bc4SBrooks Davis     ///
259*b0d29bc4SBrooks Davis     /// \param status The termination status of the subprocess used to execute
260*b0d29bc4SBrooks Davis     ///     the exec_test() method or none if the test timed out.
261*b0d29bc4SBrooks Davis     /// \param stdout_path Path to the file containing the stdout of the test.
262*b0d29bc4SBrooks Davis     /// \param stderr_path Path to the file containing the stderr of the test.
263*b0d29bc4SBrooks Davis     ///
264*b0d29bc4SBrooks Davis     /// \return A list of test cases.
265*b0d29bc4SBrooks Davis     model::test_cases_map
parse_list(const optional<process::status> & status,const fs::path & stdout_path,const fs::path & stderr_path) const266*b0d29bc4SBrooks Davis     parse_list(const optional< process::status >& status,
267*b0d29bc4SBrooks Davis                const fs::path& stdout_path,
268*b0d29bc4SBrooks Davis                const fs::path& stderr_path) const
269*b0d29bc4SBrooks Davis     {
270*b0d29bc4SBrooks Davis         const std::string name = utils::read_file(stderr_path);
271*b0d29bc4SBrooks Davis         if (name == "check_i_exist") {
272*b0d29bc4SBrooks Davis             ATF_REQUIRE(status.get().exited());
273*b0d29bc4SBrooks Davis             ATF_REQUIRE_EQ(EXIT_SUCCESS, status.get().exitstatus());
274*b0d29bc4SBrooks Davis         } else if (name == "empty") {
275*b0d29bc4SBrooks Davis             ATF_REQUIRE(status.get().exited());
276*b0d29bc4SBrooks Davis             ATF_REQUIRE_EQ(EXIT_SUCCESS, status.get().exitstatus());
277*b0d29bc4SBrooks Davis         } else if (name == "misbehave") {
278*b0d29bc4SBrooks Davis             throw std::runtime_error("misbehaved in parse_list");
279*b0d29bc4SBrooks Davis         } else if (name == "timeout") {
280*b0d29bc4SBrooks Davis             ATF_REQUIRE(!status);
281*b0d29bc4SBrooks Davis         } else if (name == "vars") {
282*b0d29bc4SBrooks Davis             ATF_REQUIRE(status.get().exited());
283*b0d29bc4SBrooks Davis             ATF_REQUIRE_EQ(15, status.get().exitstatus());
284*b0d29bc4SBrooks Davis         } else {
285*b0d29bc4SBrooks Davis             ATF_FAIL("Invalid stderr contents; got " + name);
286*b0d29bc4SBrooks Davis         }
287*b0d29bc4SBrooks Davis 
288*b0d29bc4SBrooks Davis         model::test_cases_map_builder test_cases_builder;
289*b0d29bc4SBrooks Davis 
290*b0d29bc4SBrooks Davis         std::ifstream input(stdout_path.c_str());
291*b0d29bc4SBrooks Davis         ATF_REQUIRE(input);
292*b0d29bc4SBrooks Davis         std::string line;
293*b0d29bc4SBrooks Davis         while (std::getline(input, line).good()) {
294*b0d29bc4SBrooks Davis             test_cases_builder.add(line);
295*b0d29bc4SBrooks Davis         }
296*b0d29bc4SBrooks Davis 
297*b0d29bc4SBrooks Davis         return test_cases_builder.build();
298*b0d29bc4SBrooks Davis     }
299*b0d29bc4SBrooks Davis 
300*b0d29bc4SBrooks Davis     /// Executes a test case of the test program.
301*b0d29bc4SBrooks Davis     ///
302*b0d29bc4SBrooks Davis     /// This method is intended to be called within a subprocess and is expected
303*b0d29bc4SBrooks Davis     /// to terminate execution either by exec(2)ing the test program or by
304*b0d29bc4SBrooks Davis     /// exiting with a failure.
305*b0d29bc4SBrooks Davis     ///
306*b0d29bc4SBrooks Davis     /// \param test_program The test program to execute.
307*b0d29bc4SBrooks Davis     /// \param test_case_name Name of the test case to invoke.
308*b0d29bc4SBrooks Davis     /// \param vars User-provided variables to pass to the test program.
309*b0d29bc4SBrooks Davis     /// \param control_directory Directory where the interface may place control
310*b0d29bc4SBrooks Davis     ///     files.
311*b0d29bc4SBrooks Davis     void
exec_test(const model::test_program & test_program,const std::string & test_case_name,const config::properties_map & vars,const fs::path & control_directory) const312*b0d29bc4SBrooks Davis     exec_test(const model::test_program& test_program,
313*b0d29bc4SBrooks Davis               const std::string& test_case_name,
314*b0d29bc4SBrooks Davis               const config::properties_map& vars,
315*b0d29bc4SBrooks Davis               const fs::path& control_directory) const
316*b0d29bc4SBrooks Davis     {
317*b0d29bc4SBrooks Davis         const fs::path cookie = control_directory / "exec_test_was_called";
318*b0d29bc4SBrooks Davis         std::ofstream control_file(cookie.c_str());
319*b0d29bc4SBrooks Davis         if (!control_file) {
320*b0d29bc4SBrooks Davis             std::cerr << "Failed to create " << cookie << '\n';
321*b0d29bc4SBrooks Davis             std::abort();
322*b0d29bc4SBrooks Davis         }
323*b0d29bc4SBrooks Davis         control_file << test_case_name;
324*b0d29bc4SBrooks Davis         control_file.close();
325*b0d29bc4SBrooks Davis 
326*b0d29bc4SBrooks Davis         if (test_case_name == "check_i_exist") {
327*b0d29bc4SBrooks Davis             do_exit(fs::exists(test_program.absolute_path()) ? 0 : 1);
328*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "cleanup_timeout")) {
329*b0d29bc4SBrooks Davis             exec_exit(EXIT_SUCCESS);
330*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "create_files_and_fail")) {
331*b0d29bc4SBrooks Davis             exec_create_files_and_fail();
332*b0d29bc4SBrooks Davis         } else if (test_case_name == "delete_all") {
333*b0d29bc4SBrooks Davis             exec_delete_all();
334*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "exit ")) {
335*b0d29bc4SBrooks Davis             exec_exit(suffix_to_int(test_case_name, "exit "));
336*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "fail")) {
337*b0d29bc4SBrooks Davis             exec_fail();
338*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "fail_body_fail_cleanup")) {
339*b0d29bc4SBrooks Davis             exec_fail();
340*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "fail_body_pass_cleanup")) {
341*b0d29bc4SBrooks Davis             exec_fail();
342*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "pass_body_fail_cleanup")) {
343*b0d29bc4SBrooks Davis             exec_exit(EXIT_SUCCESS);
344*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "print_params")) {
345*b0d29bc4SBrooks Davis             exec_print_params(test_program, test_case_name, vars);
346*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "skip_body_pass_cleanup")) {
347*b0d29bc4SBrooks Davis             exec_exit(EXIT_SUCCESS);
348*b0d29bc4SBrooks Davis         } else {
349*b0d29bc4SBrooks Davis             std::cerr << "Unknown test case " << test_case_name << '\n';
350*b0d29bc4SBrooks Davis             std::abort();
351*b0d29bc4SBrooks Davis         }
352*b0d29bc4SBrooks Davis     }
353*b0d29bc4SBrooks Davis 
354*b0d29bc4SBrooks Davis     /// Executes a test cleanup routine of the test program.
355*b0d29bc4SBrooks Davis     ///
356*b0d29bc4SBrooks Davis     /// This method is intended to be called within a subprocess and is expected
357*b0d29bc4SBrooks Davis     /// to terminate execution either by exec(2)ing the test program or by
358*b0d29bc4SBrooks Davis     /// exiting with a failure.
359*b0d29bc4SBrooks Davis     ///
360*b0d29bc4SBrooks Davis     /// \param test_case_name Name of the test case to invoke.
361*b0d29bc4SBrooks Davis     void
exec_cleanup(const model::test_program &,const std::string & test_case_name,const config::properties_map &,const fs::path &) const362*b0d29bc4SBrooks Davis     exec_cleanup(const model::test_program& /* test_program */,
363*b0d29bc4SBrooks Davis                  const std::string& test_case_name,
364*b0d29bc4SBrooks Davis                  const config::properties_map& /* vars */,
365*b0d29bc4SBrooks Davis                  const fs::path& /* control_directory */) const
366*b0d29bc4SBrooks Davis     {
367*b0d29bc4SBrooks Davis         std::cout << "exec_cleanup was called\n";
368*b0d29bc4SBrooks Davis         std::cout.flush();
369*b0d29bc4SBrooks Davis 
370*b0d29bc4SBrooks Davis         if (starts_with(test_case_name, "cleanup_timeout")) {
371*b0d29bc4SBrooks Davis             ::sleep(100);
372*b0d29bc4SBrooks Davis             std::abort();
373*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "fail_body_fail_cleanup")) {
374*b0d29bc4SBrooks Davis             exec_fail();
375*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "fail_body_pass_cleanup")) {
376*b0d29bc4SBrooks Davis             exec_exit(EXIT_SUCCESS);
377*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "pass_body_fail_cleanup")) {
378*b0d29bc4SBrooks Davis             exec_fail();
379*b0d29bc4SBrooks Davis         } else if (starts_with(test_case_name, "skip_body_pass_cleanup")) {
380*b0d29bc4SBrooks Davis             exec_exit(EXIT_SUCCESS);
381*b0d29bc4SBrooks Davis         } else {
382*b0d29bc4SBrooks Davis             std::cerr << "Should not have been called for a test without "
383*b0d29bc4SBrooks Davis                 "a cleanup routine" << '\n';
384*b0d29bc4SBrooks Davis             std::abort();
385*b0d29bc4SBrooks Davis         }
386*b0d29bc4SBrooks Davis     }
387*b0d29bc4SBrooks Davis 
388*b0d29bc4SBrooks Davis     /// Computes the result of a test case based on its termination status.
389*b0d29bc4SBrooks Davis     ///
390*b0d29bc4SBrooks Davis     /// \param status The termination status of the subprocess used to execute
391*b0d29bc4SBrooks Davis     ///     the exec_test() method or none if the test timed out.
392*b0d29bc4SBrooks Davis     /// \param control_directory Path to the directory where the interface may
393*b0d29bc4SBrooks Davis     ///     have placed control files.
394*b0d29bc4SBrooks Davis     /// \param stdout_path Path to the file containing the stdout of the test.
395*b0d29bc4SBrooks Davis     /// \param stderr_path Path to the file containing the stderr of the test.
396*b0d29bc4SBrooks Davis     ///
397*b0d29bc4SBrooks Davis     /// \return A test result.
398*b0d29bc4SBrooks Davis     model::test_result
compute_result(const optional<process::status> & status,const fs::path & control_directory,const fs::path & stdout_path,const fs::path & stderr_path) const399*b0d29bc4SBrooks Davis     compute_result(const optional< process::status >& status,
400*b0d29bc4SBrooks Davis                    const fs::path& control_directory,
401*b0d29bc4SBrooks Davis                    const fs::path& stdout_path,
402*b0d29bc4SBrooks Davis                    const fs::path& stderr_path) const
403*b0d29bc4SBrooks Davis     {
404*b0d29bc4SBrooks Davis         // Do not use any ATF_* macros here.  Some of the tests below invoke
405*b0d29bc4SBrooks Davis         // this code in a subprocess, and terminating such subprocess due to a
406*b0d29bc4SBrooks Davis         // failed ATF_* macro yields mysterious failures that are incredibly
407*b0d29bc4SBrooks Davis         // hard to debug.  (Case in point: the signal_handling test is racy by
408*b0d29bc4SBrooks Davis         // nature, and the test run by exec_test() above may not have created
409*b0d29bc4SBrooks Davis         // the cookie we expect below.  We don't want to "silently" exit if the
410*b0d29bc4SBrooks Davis         // file is not there.)
411*b0d29bc4SBrooks Davis 
412*b0d29bc4SBrooks Davis         if (!status) {
413*b0d29bc4SBrooks Davis             return model::test_result(model::test_result_broken,
414*b0d29bc4SBrooks Davis                                       "Timed out");
415*b0d29bc4SBrooks Davis         }
416*b0d29bc4SBrooks Davis 
417*b0d29bc4SBrooks Davis         if (status.get().exited()) {
418*b0d29bc4SBrooks Davis             // Only sanity-check the work directory-related parameters in case
419*b0d29bc4SBrooks Davis             // of a clean exit.  In all other cases, there is no guarantee that
420*b0d29bc4SBrooks Davis             // these were ever created.
421*b0d29bc4SBrooks Davis             const fs::path cookie = control_directory / "exec_test_was_called";
422*b0d29bc4SBrooks Davis             if (!atf::utils::file_exists(cookie.str())) {
423*b0d29bc4SBrooks Davis                 return model::test_result(
424*b0d29bc4SBrooks Davis                     model::test_result_broken,
425*b0d29bc4SBrooks Davis                     "compute_result's control_directory does not seem to point "
426*b0d29bc4SBrooks Davis                     "to the right location");
427*b0d29bc4SBrooks Davis             }
428*b0d29bc4SBrooks Davis             const std::string test_case_name = utils::read_file(cookie);
429*b0d29bc4SBrooks Davis 
430*b0d29bc4SBrooks Davis             if (!atf::utils::file_exists(stdout_path.str())) {
431*b0d29bc4SBrooks Davis                 return model::test_result(
432*b0d29bc4SBrooks Davis                     model::test_result_broken,
433*b0d29bc4SBrooks Davis                     "compute_result's stdout_path does not exist");
434*b0d29bc4SBrooks Davis             }
435*b0d29bc4SBrooks Davis             if (!atf::utils::file_exists(stderr_path.str())) {
436*b0d29bc4SBrooks Davis                 return model::test_result(
437*b0d29bc4SBrooks Davis                     model::test_result_broken,
438*b0d29bc4SBrooks Davis                     "compute_result's stderr_path does not exist");
439*b0d29bc4SBrooks Davis             }
440*b0d29bc4SBrooks Davis 
441*b0d29bc4SBrooks Davis             if (test_case_name == "skip_body_pass_cleanup") {
442*b0d29bc4SBrooks Davis                 return model::test_result(
443*b0d29bc4SBrooks Davis                     model::test_result_skipped,
444*b0d29bc4SBrooks Davis                     F("Exit %s") % status.get().exitstatus());
445*b0d29bc4SBrooks Davis             } else {
446*b0d29bc4SBrooks Davis                 return model::test_result(
447*b0d29bc4SBrooks Davis                     model::test_result_passed,
448*b0d29bc4SBrooks Davis                     F("Exit %s") % status.get().exitstatus());
449*b0d29bc4SBrooks Davis             }
450*b0d29bc4SBrooks Davis         } else {
451*b0d29bc4SBrooks Davis             return model::test_result(
452*b0d29bc4SBrooks Davis                 model::test_result_failed,
453*b0d29bc4SBrooks Davis                 F("Signal %s") % status.get().termsig());
454*b0d29bc4SBrooks Davis         }
455*b0d29bc4SBrooks Davis     }
456*b0d29bc4SBrooks Davis };
457*b0d29bc4SBrooks Davis 
458*b0d29bc4SBrooks Davis 
459*b0d29bc4SBrooks Davis }  // anonymous namespace
460*b0d29bc4SBrooks Davis 
461*b0d29bc4SBrooks Davis 
462*b0d29bc4SBrooks Davis /// Runs list_tests on the scheduler and returns the results.
463*b0d29bc4SBrooks Davis ///
464*b0d29bc4SBrooks Davis /// \param test_name The name of the test supported by our exec_list function.
465*b0d29bc4SBrooks Davis /// \param user_config Optional user settings for the test.
466*b0d29bc4SBrooks Davis ///
467*b0d29bc4SBrooks Davis /// \return The loaded list of test cases.
468*b0d29bc4SBrooks Davis static model::test_cases_map
check_integration_list(const char * test_name,const fs::path root,const config::tree & user_config=engine::empty_config ())469*b0d29bc4SBrooks Davis check_integration_list(const char* test_name, const fs::path root,
470*b0d29bc4SBrooks Davis                        const config::tree& user_config = engine::empty_config())
471*b0d29bc4SBrooks Davis {
472*b0d29bc4SBrooks Davis     const model::test_program program = model::test_program_builder(
473*b0d29bc4SBrooks Davis         "mock", fs::path(test_name), root, "the-suite")
474*b0d29bc4SBrooks Davis         .build();
475*b0d29bc4SBrooks Davis 
476*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
477*b0d29bc4SBrooks Davis     const model::test_cases_map test_cases = handle.list_tests(&program,
478*b0d29bc4SBrooks Davis                                                                user_config);
479*b0d29bc4SBrooks Davis     handle.cleanup();
480*b0d29bc4SBrooks Davis 
481*b0d29bc4SBrooks Davis     return test_cases;
482*b0d29bc4SBrooks Davis }
483*b0d29bc4SBrooks Davis 
484*b0d29bc4SBrooks Davis 
485*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__list_some);
ATF_TEST_CASE_BODY(integration__list_some)486*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__list_some)
487*b0d29bc4SBrooks Davis {
488*b0d29bc4SBrooks Davis     config::tree user_config = engine::empty_config();
489*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.the-suite.first", "test");
490*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.the-suite.second", "TEST");
491*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.abc.unused", "unused");
492*b0d29bc4SBrooks Davis 
493*b0d29bc4SBrooks Davis     const model::test_cases_map test_cases = check_integration_list(
494*b0d29bc4SBrooks Davis         "vars", fs::path("."), user_config);
495*b0d29bc4SBrooks Davis 
496*b0d29bc4SBrooks Davis     const model::test_cases_map exp_test_cases = model::test_cases_map_builder()
497*b0d29bc4SBrooks Davis         .add("first_test").add("second_TEST").build();
498*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_test_cases, test_cases);
499*b0d29bc4SBrooks Davis }
500*b0d29bc4SBrooks Davis 
501*b0d29bc4SBrooks Davis 
502*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__list_check_paths);
ATF_TEST_CASE_BODY(integration__list_check_paths)503*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__list_check_paths)
504*b0d29bc4SBrooks Davis {
505*b0d29bc4SBrooks Davis     fs::mkdir_p(fs::path("dir1/dir2/dir3"), 0755);
506*b0d29bc4SBrooks Davis     atf::utils::create_file("dir1/dir2/dir3/check_i_exist", "");
507*b0d29bc4SBrooks Davis 
508*b0d29bc4SBrooks Davis     const model::test_cases_map test_cases = check_integration_list(
509*b0d29bc4SBrooks Davis         "dir2/dir3/check_i_exist", fs::path("dir1"));
510*b0d29bc4SBrooks Davis 
511*b0d29bc4SBrooks Davis     const model::test_cases_map exp_test_cases = model::test_cases_map_builder()
512*b0d29bc4SBrooks Davis         .add("found").build();
513*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_test_cases, test_cases);
514*b0d29bc4SBrooks Davis }
515*b0d29bc4SBrooks Davis 
516*b0d29bc4SBrooks Davis 
517*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__list_timeout);
ATF_TEST_CASE_BODY(integration__list_timeout)518*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__list_timeout)
519*b0d29bc4SBrooks Davis {
520*b0d29bc4SBrooks Davis     scheduler::list_timeout = datetime::delta(1, 0);
521*b0d29bc4SBrooks Davis     const model::test_cases_map test_cases = check_integration_list(
522*b0d29bc4SBrooks Davis         "timeout", fs::path("."));
523*b0d29bc4SBrooks Davis 
524*b0d29bc4SBrooks Davis     const model::test_cases_map exp_test_cases = model::test_cases_map_builder()
525*b0d29bc4SBrooks Davis         .add("sleeping").build();
526*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_test_cases, test_cases);
527*b0d29bc4SBrooks Davis }
528*b0d29bc4SBrooks Davis 
529*b0d29bc4SBrooks Davis 
530*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__list_fail);
ATF_TEST_CASE_BODY(integration__list_fail)531*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__list_fail)
532*b0d29bc4SBrooks Davis {
533*b0d29bc4SBrooks Davis     const model::test_cases_map test_cases = check_integration_list(
534*b0d29bc4SBrooks Davis         "misbehave", fs::path("."));
535*b0d29bc4SBrooks Davis 
536*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(1, test_cases.size());
537*b0d29bc4SBrooks Davis     const model::test_case& test_case = test_cases.begin()->second;
538*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("__test_cases_list__", test_case.name());
539*b0d29bc4SBrooks Davis     ATF_REQUIRE(test_case.fake_result());
540*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(model::test_result_broken,
541*b0d29bc4SBrooks Davis                                       "misbehaved in parse_list"),
542*b0d29bc4SBrooks Davis                    test_case.fake_result().get());
543*b0d29bc4SBrooks Davis }
544*b0d29bc4SBrooks Davis 
545*b0d29bc4SBrooks Davis 
546*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__list_empty);
ATF_TEST_CASE_BODY(integration__list_empty)547*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__list_empty)
548*b0d29bc4SBrooks Davis {
549*b0d29bc4SBrooks Davis     const model::test_cases_map test_cases = check_integration_list(
550*b0d29bc4SBrooks Davis         "empty", fs::path("."));
551*b0d29bc4SBrooks Davis 
552*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(1, test_cases.size());
553*b0d29bc4SBrooks Davis     const model::test_case& test_case = test_cases.begin()->second;
554*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("__test_cases_list__", test_case.name());
555*b0d29bc4SBrooks Davis     ATF_REQUIRE(test_case.fake_result());
556*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(model::test_result_broken,
557*b0d29bc4SBrooks Davis                                       "Empty test cases list"),
558*b0d29bc4SBrooks Davis                    test_case.fake_result().get());
559*b0d29bc4SBrooks Davis }
560*b0d29bc4SBrooks Davis 
561*b0d29bc4SBrooks Davis 
562*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__run_one);
ATF_TEST_CASE_BODY(integration__run_one)563*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__run_one)
564*b0d29bc4SBrooks Davis {
565*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
566*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite")
567*b0d29bc4SBrooks Davis         .add_test_case("exit 41").build_ptr();
568*b0d29bc4SBrooks Davis 
569*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
570*b0d29bc4SBrooks Davis 
571*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
572*b0d29bc4SBrooks Davis 
573*b0d29bc4SBrooks Davis     const scheduler::exec_handle exec_handle = handle.spawn_test(
574*b0d29bc4SBrooks Davis         program, "exit 41", user_config);
575*b0d29bc4SBrooks Davis 
576*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
577*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
578*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
579*b0d29bc4SBrooks Davis             result_handle.get());
580*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exec_handle, result_handle->original_pid());
581*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(model::test_result_passed, "Exit 41"),
582*b0d29bc4SBrooks Davis                    test_result_handle->test_result());
583*b0d29bc4SBrooks Davis     result_handle->cleanup();
584*b0d29bc4SBrooks Davis     result_handle.reset();
585*b0d29bc4SBrooks Davis 
586*b0d29bc4SBrooks Davis     handle.cleanup();
587*b0d29bc4SBrooks Davis }
588*b0d29bc4SBrooks Davis 
589*b0d29bc4SBrooks Davis 
590*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__run_many);
ATF_TEST_CASE_BODY(integration__run_many)591*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__run_many)
592*b0d29bc4SBrooks Davis {
593*b0d29bc4SBrooks Davis     static const std::size_t num_test_programs = 30;
594*b0d29bc4SBrooks Davis 
595*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
596*b0d29bc4SBrooks Davis 
597*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
598*b0d29bc4SBrooks Davis 
599*b0d29bc4SBrooks Davis     // We mess around with the "current time" below, so make sure the tests do
600*b0d29bc4SBrooks Davis     // not spuriously exceed their deadline by bumping it to a large number.
601*b0d29bc4SBrooks Davis     const model::metadata infinite_timeout = model::metadata_builder()
602*b0d29bc4SBrooks Davis         .set_timeout(datetime::delta(1000000L, 0)).build();
603*b0d29bc4SBrooks Davis 
604*b0d29bc4SBrooks Davis     std::size_t total_tests = 0;
605*b0d29bc4SBrooks Davis     std::map< scheduler::exec_handle, model::test_program_ptr >
606*b0d29bc4SBrooks Davis         exp_test_programs;
607*b0d29bc4SBrooks Davis     std::map< scheduler::exec_handle, std::string > exp_test_case_names;
608*b0d29bc4SBrooks Davis     std::map< scheduler::exec_handle, datetime::timestamp > exp_start_times;
609*b0d29bc4SBrooks Davis     std::map< scheduler::exec_handle, int > exp_exit_statuses;
610*b0d29bc4SBrooks Davis     for (std::size_t i = 0; i < num_test_programs; ++i) {
611*b0d29bc4SBrooks Davis         const std::string test_case_0 = F("exit %s") % (i * 3 + 0);
612*b0d29bc4SBrooks Davis         const std::string test_case_1 = F("exit %s") % (i * 3 + 1);
613*b0d29bc4SBrooks Davis         const std::string test_case_2 = F("exit %s") % (i * 3 + 2);
614*b0d29bc4SBrooks Davis 
615*b0d29bc4SBrooks Davis         const model::test_program_ptr program = model::test_program_builder(
616*b0d29bc4SBrooks Davis             "mock", fs::path(F("program-%s") % i),
617*b0d29bc4SBrooks Davis             fs::current_path(), "the-suite")
618*b0d29bc4SBrooks Davis             .set_metadata(infinite_timeout)
619*b0d29bc4SBrooks Davis             .add_test_case(test_case_0)
620*b0d29bc4SBrooks Davis             .add_test_case(test_case_1)
621*b0d29bc4SBrooks Davis             .add_test_case(test_case_2)
622*b0d29bc4SBrooks Davis             .build_ptr();
623*b0d29bc4SBrooks Davis 
624*b0d29bc4SBrooks Davis         const datetime::timestamp start_time = datetime::timestamp::from_values(
625*b0d29bc4SBrooks Davis             2014, 12, 8, 9, 40, 0, i);
626*b0d29bc4SBrooks Davis 
627*b0d29bc4SBrooks Davis         scheduler::exec_handle exec_handle;
628*b0d29bc4SBrooks Davis 
629*b0d29bc4SBrooks Davis         datetime::set_mock_now(start_time);
630*b0d29bc4SBrooks Davis         exec_handle = handle.spawn_test(program, test_case_0, user_config);
631*b0d29bc4SBrooks Davis         exp_test_programs.insert(std::make_pair(exec_handle, program));
632*b0d29bc4SBrooks Davis         exp_test_case_names.insert(std::make_pair(exec_handle, test_case_0));
633*b0d29bc4SBrooks Davis         exp_start_times.insert(std::make_pair(exec_handle, start_time));
634*b0d29bc4SBrooks Davis         exp_exit_statuses.insert(std::make_pair(exec_handle, i * 3));
635*b0d29bc4SBrooks Davis         ++total_tests;
636*b0d29bc4SBrooks Davis 
637*b0d29bc4SBrooks Davis         datetime::set_mock_now(start_time);
638*b0d29bc4SBrooks Davis         exec_handle = handle.spawn_test(program, test_case_1, user_config);
639*b0d29bc4SBrooks Davis         exp_test_programs.insert(std::make_pair(exec_handle, program));
640*b0d29bc4SBrooks Davis         exp_test_case_names.insert(std::make_pair(exec_handle, test_case_1));
641*b0d29bc4SBrooks Davis         exp_start_times.insert(std::make_pair(exec_handle, start_time));
642*b0d29bc4SBrooks Davis         exp_exit_statuses.insert(std::make_pair(exec_handle, i * 3 + 1));
643*b0d29bc4SBrooks Davis         ++total_tests;
644*b0d29bc4SBrooks Davis 
645*b0d29bc4SBrooks Davis         datetime::set_mock_now(start_time);
646*b0d29bc4SBrooks Davis         exec_handle = handle.spawn_test(program, test_case_2, user_config);
647*b0d29bc4SBrooks Davis         exp_test_programs.insert(std::make_pair(exec_handle, program));
648*b0d29bc4SBrooks Davis         exp_test_case_names.insert(std::make_pair(exec_handle, test_case_2));
649*b0d29bc4SBrooks Davis         exp_start_times.insert(std::make_pair(exec_handle, start_time));
650*b0d29bc4SBrooks Davis         exp_exit_statuses.insert(std::make_pair(exec_handle, i * 3 + 2));
651*b0d29bc4SBrooks Davis         ++total_tests;
652*b0d29bc4SBrooks Davis     }
653*b0d29bc4SBrooks Davis 
654*b0d29bc4SBrooks Davis     for (std::size_t i = 0; i < total_tests; ++i) {
655*b0d29bc4SBrooks Davis         const datetime::timestamp end_time = datetime::timestamp::from_values(
656*b0d29bc4SBrooks Davis             2014, 12, 8, 9, 50, 10, i);
657*b0d29bc4SBrooks Davis         datetime::set_mock_now(end_time);
658*b0d29bc4SBrooks Davis         scheduler::result_handle_ptr result_handle = handle.wait_any();
659*b0d29bc4SBrooks Davis         const scheduler::test_result_handle* test_result_handle =
660*b0d29bc4SBrooks Davis             dynamic_cast< const scheduler::test_result_handle* >(
661*b0d29bc4SBrooks Davis                 result_handle.get());
662*b0d29bc4SBrooks Davis 
663*b0d29bc4SBrooks Davis         const scheduler::exec_handle exec_handle =
664*b0d29bc4SBrooks Davis             result_handle->original_pid();
665*b0d29bc4SBrooks Davis 
666*b0d29bc4SBrooks Davis         const model::test_program_ptr test_program = exp_test_programs.find(
667*b0d29bc4SBrooks Davis             exec_handle)->second;
668*b0d29bc4SBrooks Davis         const std::string& test_case_name = exp_test_case_names.find(
669*b0d29bc4SBrooks Davis             exec_handle)->second;
670*b0d29bc4SBrooks Davis         const datetime::timestamp& start_time = exp_start_times.find(
671*b0d29bc4SBrooks Davis             exec_handle)->second;
672*b0d29bc4SBrooks Davis         const int exit_status = exp_exit_statuses.find(exec_handle)->second;
673*b0d29bc4SBrooks Davis 
674*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(model::test_result(model::test_result_passed,
675*b0d29bc4SBrooks Davis                                           F("Exit %s") % exit_status),
676*b0d29bc4SBrooks Davis                        test_result_handle->test_result());
677*b0d29bc4SBrooks Davis 
678*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(test_program, test_result_handle->test_program());
679*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(test_case_name, test_result_handle->test_case_name());
680*b0d29bc4SBrooks Davis 
681*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(start_time, result_handle->start_time());
682*b0d29bc4SBrooks Davis         ATF_REQUIRE_EQ(end_time, result_handle->end_time());
683*b0d29bc4SBrooks Davis 
684*b0d29bc4SBrooks Davis         result_handle->cleanup();
685*b0d29bc4SBrooks Davis 
686*b0d29bc4SBrooks Davis         ATF_REQUIRE(!atf::utils::file_exists(
687*b0d29bc4SBrooks Davis                         result_handle->stdout_file().str()));
688*b0d29bc4SBrooks Davis         ATF_REQUIRE(!atf::utils::file_exists(
689*b0d29bc4SBrooks Davis                         result_handle->stderr_file().str()));
690*b0d29bc4SBrooks Davis         ATF_REQUIRE(!atf::utils::file_exists(
691*b0d29bc4SBrooks Davis                         result_handle->work_directory().str()));
692*b0d29bc4SBrooks Davis 
693*b0d29bc4SBrooks Davis         result_handle.reset();
694*b0d29bc4SBrooks Davis     }
695*b0d29bc4SBrooks Davis 
696*b0d29bc4SBrooks Davis     handle.cleanup();
697*b0d29bc4SBrooks Davis }
698*b0d29bc4SBrooks Davis 
699*b0d29bc4SBrooks Davis 
700*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__run_check_paths);
ATF_TEST_CASE_BODY(integration__run_check_paths)701*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__run_check_paths)
702*b0d29bc4SBrooks Davis {
703*b0d29bc4SBrooks Davis     fs::mkdir_p(fs::path("dir1/dir2/dir3"), 0755);
704*b0d29bc4SBrooks Davis     atf::utils::create_file("dir1/dir2/dir3/program", "");
705*b0d29bc4SBrooks Davis 
706*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
707*b0d29bc4SBrooks Davis         "mock", fs::path("dir2/dir3/program"), fs::path("dir1"), "the-suite")
708*b0d29bc4SBrooks Davis         .add_test_case("check_i_exist").build_ptr();
709*b0d29bc4SBrooks Davis 
710*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
711*b0d29bc4SBrooks Davis 
712*b0d29bc4SBrooks Davis     (void)handle.spawn_test(program, "check_i_exist", engine::default_config());
713*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
714*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
715*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
716*b0d29bc4SBrooks Davis             result_handle.get());
717*b0d29bc4SBrooks Davis 
718*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(model::test_result_passed, "Exit 0"),
719*b0d29bc4SBrooks Davis                    test_result_handle->test_result());
720*b0d29bc4SBrooks Davis 
721*b0d29bc4SBrooks Davis     result_handle->cleanup();
722*b0d29bc4SBrooks Davis     result_handle.reset();
723*b0d29bc4SBrooks Davis 
724*b0d29bc4SBrooks Davis     handle.cleanup();
725*b0d29bc4SBrooks Davis }
726*b0d29bc4SBrooks Davis 
727*b0d29bc4SBrooks Davis 
728*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__parameters_and_output);
ATF_TEST_CASE_BODY(integration__parameters_and_output)729*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__parameters_and_output)
730*b0d29bc4SBrooks Davis {
731*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
732*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite")
733*b0d29bc4SBrooks Davis         .add_test_case("print_params").build_ptr();
734*b0d29bc4SBrooks Davis 
735*b0d29bc4SBrooks Davis     config::tree user_config = engine::empty_config();
736*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.the-suite.one", "first variable");
737*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.the-suite.two", "second variable");
738*b0d29bc4SBrooks Davis 
739*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
740*b0d29bc4SBrooks Davis 
741*b0d29bc4SBrooks Davis     const scheduler::exec_handle exec_handle = handle.spawn_test(
742*b0d29bc4SBrooks Davis         program, "print_params", user_config);
743*b0d29bc4SBrooks Davis 
744*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
745*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
746*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
747*b0d29bc4SBrooks Davis             result_handle.get());
748*b0d29bc4SBrooks Davis 
749*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exec_handle, result_handle->original_pid());
750*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(program, test_result_handle->test_program());
751*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("print_params", test_result_handle->test_case_name());
752*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(model::test_result_passed, "Exit 0"),
753*b0d29bc4SBrooks Davis                    test_result_handle->test_result());
754*b0d29bc4SBrooks Davis 
755*b0d29bc4SBrooks Davis     const fs::path stdout_file = result_handle->stdout_file();
756*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::compare_file(
757*b0d29bc4SBrooks Davis         stdout_file.str(),
758*b0d29bc4SBrooks Davis         "Test program: the-program\n"
759*b0d29bc4SBrooks Davis         "Test case: print_params\n"
760*b0d29bc4SBrooks Davis         "one=first variable\n"
761*b0d29bc4SBrooks Davis         "two=second variable\n"));
762*b0d29bc4SBrooks Davis     const fs::path stderr_file = result_handle->stderr_file();
763*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::compare_file(
764*b0d29bc4SBrooks Davis         stderr_file.str(), "stderr: print_params\n"));
765*b0d29bc4SBrooks Davis 
766*b0d29bc4SBrooks Davis     result_handle->cleanup();
767*b0d29bc4SBrooks Davis     ATF_REQUIRE(!fs::exists(stdout_file));
768*b0d29bc4SBrooks Davis     ATF_REQUIRE(!fs::exists(stderr_file));
769*b0d29bc4SBrooks Davis     result_handle.reset();
770*b0d29bc4SBrooks Davis 
771*b0d29bc4SBrooks Davis     handle.cleanup();
772*b0d29bc4SBrooks Davis }
773*b0d29bc4SBrooks Davis 
774*b0d29bc4SBrooks Davis 
775*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__fake_result);
ATF_TEST_CASE_BODY(integration__fake_result)776*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__fake_result)
777*b0d29bc4SBrooks Davis {
778*b0d29bc4SBrooks Davis     const model::test_result fake_result(model::test_result_skipped,
779*b0d29bc4SBrooks Davis                                          "Some fake details");
780*b0d29bc4SBrooks Davis 
781*b0d29bc4SBrooks Davis     model::test_cases_map test_cases;
782*b0d29bc4SBrooks Davis     test_cases.insert(model::test_cases_map::value_type(
783*b0d29bc4SBrooks Davis         "__fake__", model::test_case("__fake__", "ABC", fake_result)));
784*b0d29bc4SBrooks Davis 
785*b0d29bc4SBrooks Davis     const model::test_program_ptr program(new model::test_program(
786*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite",
787*b0d29bc4SBrooks Davis         model::metadata_builder().build(), test_cases));
788*b0d29bc4SBrooks Davis 
789*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
790*b0d29bc4SBrooks Davis 
791*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
792*b0d29bc4SBrooks Davis 
793*b0d29bc4SBrooks Davis     (void)handle.spawn_test(program, "__fake__", user_config);
794*b0d29bc4SBrooks Davis 
795*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
796*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
797*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
798*b0d29bc4SBrooks Davis             result_handle.get());
799*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(fake_result, test_result_handle->test_result());
800*b0d29bc4SBrooks Davis     result_handle->cleanup();
801*b0d29bc4SBrooks Davis     result_handle.reset();
802*b0d29bc4SBrooks Davis 
803*b0d29bc4SBrooks Davis     handle.cleanup();
804*b0d29bc4SBrooks Davis }
805*b0d29bc4SBrooks Davis 
806*b0d29bc4SBrooks Davis 
807*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__cleanup__head_skips);
ATF_TEST_CASE_BODY(integration__cleanup__head_skips)808*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__cleanup__head_skips)
809*b0d29bc4SBrooks Davis {
810*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
811*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite")
812*b0d29bc4SBrooks Davis         .add_test_case("skip_me",
813*b0d29bc4SBrooks Davis                        model::metadata_builder()
814*b0d29bc4SBrooks Davis                        .add_required_config("variable-that-does-not-exist")
815*b0d29bc4SBrooks Davis                        .set_has_cleanup(true)
816*b0d29bc4SBrooks Davis                        .build())
817*b0d29bc4SBrooks Davis         .build_ptr();
818*b0d29bc4SBrooks Davis 
819*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
820*b0d29bc4SBrooks Davis 
821*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
822*b0d29bc4SBrooks Davis 
823*b0d29bc4SBrooks Davis     (void)handle.spawn_test(program, "skip_me", user_config);
824*b0d29bc4SBrooks Davis 
825*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
826*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
827*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
828*b0d29bc4SBrooks Davis             result_handle.get());
829*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(
830*b0d29bc4SBrooks Davis                        model::test_result_skipped,
831*b0d29bc4SBrooks Davis                        "Required configuration property "
832*b0d29bc4SBrooks Davis                        "'variable-that-does-not-exist' not defined"),
833*b0d29bc4SBrooks Davis                    test_result_handle->test_result());
834*b0d29bc4SBrooks Davis     ATF_REQUIRE(!atf::utils::grep_file("exec_cleanup was called",
835*b0d29bc4SBrooks Davis                                        result_handle->stdout_file().str()));
836*b0d29bc4SBrooks Davis     result_handle->cleanup();
837*b0d29bc4SBrooks Davis     result_handle.reset();
838*b0d29bc4SBrooks Davis 
839*b0d29bc4SBrooks Davis     handle.cleanup();
840*b0d29bc4SBrooks Davis }
841*b0d29bc4SBrooks Davis 
842*b0d29bc4SBrooks Davis 
843*b0d29bc4SBrooks Davis /// Runs a test to verify the behavior of cleanup routines.
844*b0d29bc4SBrooks Davis ///
845*b0d29bc4SBrooks Davis /// \param test_case The name of the test case to invoke.
846*b0d29bc4SBrooks Davis /// \param exp_result The expected test result of the execution.
847*b0d29bc4SBrooks Davis static void
do_cleanup_test(const char * test_case,const model::test_result & exp_result)848*b0d29bc4SBrooks Davis do_cleanup_test(const char* test_case,
849*b0d29bc4SBrooks Davis                 const model::test_result& exp_result)
850*b0d29bc4SBrooks Davis {
851*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
852*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite")
853*b0d29bc4SBrooks Davis         .add_test_case(test_case)
854*b0d29bc4SBrooks Davis         .set_metadata(model::metadata_builder().set_has_cleanup(true).build())
855*b0d29bc4SBrooks Davis         .build_ptr();
856*b0d29bc4SBrooks Davis 
857*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
858*b0d29bc4SBrooks Davis 
859*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
860*b0d29bc4SBrooks Davis 
861*b0d29bc4SBrooks Davis     (void)handle.spawn_test(program, test_case, user_config);
862*b0d29bc4SBrooks Davis 
863*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
864*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
865*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
866*b0d29bc4SBrooks Davis             result_handle.get());
867*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_result, test_result_handle->test_result());
868*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::compare_file(
869*b0d29bc4SBrooks Davis         result_handle->stdout_file().str(),
870*b0d29bc4SBrooks Davis         "exec_cleanup was called\n"));
871*b0d29bc4SBrooks Davis     result_handle->cleanup();
872*b0d29bc4SBrooks Davis     result_handle.reset();
873*b0d29bc4SBrooks Davis 
874*b0d29bc4SBrooks Davis     handle.cleanup();
875*b0d29bc4SBrooks Davis }
876*b0d29bc4SBrooks Davis 
877*b0d29bc4SBrooks Davis 
878*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__cleanup__body_skips);
ATF_TEST_CASE_BODY(integration__cleanup__body_skips)879*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__cleanup__body_skips)
880*b0d29bc4SBrooks Davis {
881*b0d29bc4SBrooks Davis     do_cleanup_test(
882*b0d29bc4SBrooks Davis         "skip_body_pass_cleanup",
883*b0d29bc4SBrooks Davis         model::test_result(model::test_result_skipped, "Exit 0"));
884*b0d29bc4SBrooks Davis }
885*b0d29bc4SBrooks Davis 
886*b0d29bc4SBrooks Davis 
887*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__cleanup__body_bad__cleanup_ok);
ATF_TEST_CASE_BODY(integration__cleanup__body_bad__cleanup_ok)888*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__cleanup__body_bad__cleanup_ok)
889*b0d29bc4SBrooks Davis {
890*b0d29bc4SBrooks Davis     do_cleanup_test(
891*b0d29bc4SBrooks Davis         "fail_body_pass_cleanup",
892*b0d29bc4SBrooks Davis         model::test_result(model::test_result_failed, "Signal 15"));
893*b0d29bc4SBrooks Davis }
894*b0d29bc4SBrooks Davis 
895*b0d29bc4SBrooks Davis 
896*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__cleanup__body_ok__cleanup_bad);
ATF_TEST_CASE_BODY(integration__cleanup__body_ok__cleanup_bad)897*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__cleanup__body_ok__cleanup_bad)
898*b0d29bc4SBrooks Davis {
899*b0d29bc4SBrooks Davis     do_cleanup_test(
900*b0d29bc4SBrooks Davis         "pass_body_fail_cleanup",
901*b0d29bc4SBrooks Davis         model::test_result(model::test_result_broken, "Test case cleanup "
902*b0d29bc4SBrooks Davis                            "did not terminate successfully"));
903*b0d29bc4SBrooks Davis }
904*b0d29bc4SBrooks Davis 
905*b0d29bc4SBrooks Davis 
906*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__cleanup__body_bad__cleanup_bad);
ATF_TEST_CASE_BODY(integration__cleanup__body_bad__cleanup_bad)907*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__cleanup__body_bad__cleanup_bad)
908*b0d29bc4SBrooks Davis {
909*b0d29bc4SBrooks Davis     do_cleanup_test(
910*b0d29bc4SBrooks Davis         "fail_body_fail_cleanup",
911*b0d29bc4SBrooks Davis         model::test_result(model::test_result_failed, "Signal 15"));
912*b0d29bc4SBrooks Davis }
913*b0d29bc4SBrooks Davis 
914*b0d29bc4SBrooks Davis 
915*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__cleanup__timeout);
ATF_TEST_CASE_BODY(integration__cleanup__timeout)916*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__cleanup__timeout)
917*b0d29bc4SBrooks Davis {
918*b0d29bc4SBrooks Davis     scheduler::cleanup_timeout = datetime::delta(1, 0);
919*b0d29bc4SBrooks Davis     do_cleanup_test(
920*b0d29bc4SBrooks Davis         "cleanup_timeout",
921*b0d29bc4SBrooks Davis         model::test_result(model::test_result_broken, "Test case cleanup "
922*b0d29bc4SBrooks Davis                            "timed out"));
923*b0d29bc4SBrooks Davis }
924*b0d29bc4SBrooks Davis 
925*b0d29bc4SBrooks Davis 
926*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__check_requirements);
ATF_TEST_CASE_BODY(integration__check_requirements)927*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__check_requirements)
928*b0d29bc4SBrooks Davis {
929*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
930*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite")
931*b0d29bc4SBrooks Davis         .add_test_case("exit 12")
932*b0d29bc4SBrooks Davis         .set_metadata(model::metadata_builder()
933*b0d29bc4SBrooks Davis                       .add_required_config("abcde").build())
934*b0d29bc4SBrooks Davis         .build_ptr();
935*b0d29bc4SBrooks Davis 
936*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
937*b0d29bc4SBrooks Davis 
938*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
939*b0d29bc4SBrooks Davis 
940*b0d29bc4SBrooks Davis     (void)handle.spawn_test(program, "exit 12", user_config);
941*b0d29bc4SBrooks Davis 
942*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
943*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
944*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
945*b0d29bc4SBrooks Davis             result_handle.get());
946*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(
947*b0d29bc4SBrooks Davis                        model::test_result_skipped,
948*b0d29bc4SBrooks Davis                        "Required configuration property 'abcde' not defined"),
949*b0d29bc4SBrooks Davis                    test_result_handle->test_result());
950*b0d29bc4SBrooks Davis     result_handle->cleanup();
951*b0d29bc4SBrooks Davis     result_handle.reset();
952*b0d29bc4SBrooks Davis 
953*b0d29bc4SBrooks Davis     handle.cleanup();
954*b0d29bc4SBrooks Davis }
955*b0d29bc4SBrooks Davis 
956*b0d29bc4SBrooks Davis 
957*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__stacktrace);
ATF_TEST_CASE_BODY(integration__stacktrace)958*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__stacktrace)
959*b0d29bc4SBrooks Davis {
960*b0d29bc4SBrooks Davis     utils::prepare_coredump_test(this);
961*b0d29bc4SBrooks Davis 
962*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
963*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite")
964*b0d29bc4SBrooks Davis         .add_test_case("unknown-dumps-core").build_ptr();
965*b0d29bc4SBrooks Davis 
966*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
967*b0d29bc4SBrooks Davis 
968*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
969*b0d29bc4SBrooks Davis 
970*b0d29bc4SBrooks Davis     (void)handle.spawn_test(program, "unknown-dumps-core", user_config);
971*b0d29bc4SBrooks Davis 
972*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
973*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
974*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
975*b0d29bc4SBrooks Davis             result_handle.get());
976*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(model::test_result_failed,
977*b0d29bc4SBrooks Davis                                       F("Signal %s") % SIGABRT),
978*b0d29bc4SBrooks Davis                    test_result_handle->test_result());
979*b0d29bc4SBrooks Davis     ATF_REQUIRE(!atf::utils::grep_file("attempting to gather stack trace",
980*b0d29bc4SBrooks Davis                                        result_handle->stdout_file().str()));
981*b0d29bc4SBrooks Davis     ATF_REQUIRE( atf::utils::grep_file("attempting to gather stack trace",
982*b0d29bc4SBrooks Davis                                        result_handle->stderr_file().str()));
983*b0d29bc4SBrooks Davis     result_handle->cleanup();
984*b0d29bc4SBrooks Davis     result_handle.reset();
985*b0d29bc4SBrooks Davis 
986*b0d29bc4SBrooks Davis     handle.cleanup();
987*b0d29bc4SBrooks Davis }
988*b0d29bc4SBrooks Davis 
989*b0d29bc4SBrooks Davis 
990*b0d29bc4SBrooks Davis /// Runs a test to verify the dumping of the list of existing files on failure.
991*b0d29bc4SBrooks Davis ///
992*b0d29bc4SBrooks Davis /// \param test_case The name of the test case to invoke.
993*b0d29bc4SBrooks Davis /// \param exp_stderr Expected contents of stderr.
994*b0d29bc4SBrooks Davis static void
do_check_list_files_on_failure(const char * test_case,const char * exp_stderr)995*b0d29bc4SBrooks Davis do_check_list_files_on_failure(const char* test_case, const char* exp_stderr)
996*b0d29bc4SBrooks Davis {
997*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
998*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite")
999*b0d29bc4SBrooks Davis         .add_test_case(test_case).build_ptr();
1000*b0d29bc4SBrooks Davis 
1001*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
1002*b0d29bc4SBrooks Davis 
1003*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
1004*b0d29bc4SBrooks Davis 
1005*b0d29bc4SBrooks Davis     (void)handle.spawn_test(program, test_case, user_config);
1006*b0d29bc4SBrooks Davis 
1007*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
1008*b0d29bc4SBrooks Davis     atf::utils::cat_file(result_handle->stdout_file().str(), "child stdout: ");
1009*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::compare_file(result_handle->stdout_file().str(),
1010*b0d29bc4SBrooks Davis                                          ""));
1011*b0d29bc4SBrooks Davis     atf::utils::cat_file(result_handle->stderr_file().str(), "child stderr: ");
1012*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::compare_file(result_handle->stderr_file().str(),
1013*b0d29bc4SBrooks Davis                                          exp_stderr));
1014*b0d29bc4SBrooks Davis     result_handle->cleanup();
1015*b0d29bc4SBrooks Davis     result_handle.reset();
1016*b0d29bc4SBrooks Davis 
1017*b0d29bc4SBrooks Davis     handle.cleanup();
1018*b0d29bc4SBrooks Davis }
1019*b0d29bc4SBrooks Davis 
1020*b0d29bc4SBrooks Davis 
1021*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__list_files_on_failure__none);
ATF_TEST_CASE_BODY(integration__list_files_on_failure__none)1022*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__list_files_on_failure__none)
1023*b0d29bc4SBrooks Davis {
1024*b0d29bc4SBrooks Davis     do_check_list_files_on_failure("fail", "This should not be clobbered\n");
1025*b0d29bc4SBrooks Davis }
1026*b0d29bc4SBrooks Davis 
1027*b0d29bc4SBrooks Davis 
1028*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__list_files_on_failure__some);
ATF_TEST_CASE_BODY(integration__list_files_on_failure__some)1029*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__list_files_on_failure__some)
1030*b0d29bc4SBrooks Davis {
1031*b0d29bc4SBrooks Davis     do_check_list_files_on_failure(
1032*b0d29bc4SBrooks Davis         "create_files_and_fail",
1033*b0d29bc4SBrooks Davis         "This should not be clobbered\n"
1034*b0d29bc4SBrooks Davis         "Files left in work directory after failure: "
1035*b0d29bc4SBrooks Davis         "dir1, first file, second-file\n");
1036*b0d29bc4SBrooks Davis }
1037*b0d29bc4SBrooks Davis 
1038*b0d29bc4SBrooks Davis 
1039*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(integration__prevent_clobbering_control_files);
ATF_TEST_CASE_BODY(integration__prevent_clobbering_control_files)1040*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(integration__prevent_clobbering_control_files)
1041*b0d29bc4SBrooks Davis {
1042*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
1043*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite")
1044*b0d29bc4SBrooks Davis         .add_test_case("delete_all").build_ptr();
1045*b0d29bc4SBrooks Davis 
1046*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
1047*b0d29bc4SBrooks Davis 
1048*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
1049*b0d29bc4SBrooks Davis 
1050*b0d29bc4SBrooks Davis     (void)handle.spawn_test(program, "delete_all", user_config);
1051*b0d29bc4SBrooks Davis 
1052*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.wait_any();
1053*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
1054*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
1055*b0d29bc4SBrooks Davis             result_handle.get());
1056*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(model::test_result_passed, "Exit 0"),
1057*b0d29bc4SBrooks Davis                    test_result_handle->test_result());
1058*b0d29bc4SBrooks Davis     result_handle->cleanup();
1059*b0d29bc4SBrooks Davis     result_handle.reset();
1060*b0d29bc4SBrooks Davis 
1061*b0d29bc4SBrooks Davis     handle.cleanup();
1062*b0d29bc4SBrooks Davis }
1063*b0d29bc4SBrooks Davis 
1064*b0d29bc4SBrooks Davis 
1065*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(debug_test);
ATF_TEST_CASE_BODY(debug_test)1066*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(debug_test)
1067*b0d29bc4SBrooks Davis {
1068*b0d29bc4SBrooks Davis     const model::test_program_ptr program = model::test_program_builder(
1069*b0d29bc4SBrooks Davis         "mock", fs::path("the-program"), fs::current_path(), "the-suite")
1070*b0d29bc4SBrooks Davis         .add_test_case("print_params").build_ptr();
1071*b0d29bc4SBrooks Davis 
1072*b0d29bc4SBrooks Davis     config::tree user_config = engine::empty_config();
1073*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.the-suite.one", "first variable");
1074*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.the-suite.two", "second variable");
1075*b0d29bc4SBrooks Davis 
1076*b0d29bc4SBrooks Davis     scheduler::scheduler_handle handle = scheduler::setup();
1077*b0d29bc4SBrooks Davis 
1078*b0d29bc4SBrooks Davis     const fs::path stdout_file("custom-stdout.txt");
1079*b0d29bc4SBrooks Davis     const fs::path stderr_file("custom-stderr.txt");
1080*b0d29bc4SBrooks Davis 
1081*b0d29bc4SBrooks Davis     scheduler::result_handle_ptr result_handle = handle.debug_test(
1082*b0d29bc4SBrooks Davis         program, "print_params", user_config, stdout_file, stderr_file);
1083*b0d29bc4SBrooks Davis     const scheduler::test_result_handle* test_result_handle =
1084*b0d29bc4SBrooks Davis         dynamic_cast< const scheduler::test_result_handle* >(
1085*b0d29bc4SBrooks Davis             result_handle.get());
1086*b0d29bc4SBrooks Davis 
1087*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(program, test_result_handle->test_program());
1088*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ("print_params", test_result_handle->test_case_name());
1089*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(model::test_result(model::test_result_passed, "Exit 0"),
1090*b0d29bc4SBrooks Davis                    test_result_handle->test_result());
1091*b0d29bc4SBrooks Davis 
1092*b0d29bc4SBrooks Davis     // The original output went to a file.  It's only an artifact of
1093*b0d29bc4SBrooks Davis     // debug_test() that we later get a copy in our own files.
1094*b0d29bc4SBrooks Davis     ATF_REQUIRE(stdout_file != result_handle->stdout_file());
1095*b0d29bc4SBrooks Davis     ATF_REQUIRE(stderr_file != result_handle->stderr_file());
1096*b0d29bc4SBrooks Davis 
1097*b0d29bc4SBrooks Davis     result_handle->cleanup();
1098*b0d29bc4SBrooks Davis     result_handle.reset();
1099*b0d29bc4SBrooks Davis 
1100*b0d29bc4SBrooks Davis     handle.cleanup();
1101*b0d29bc4SBrooks Davis 
1102*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::compare_file(
1103*b0d29bc4SBrooks Davis         stdout_file.str(),
1104*b0d29bc4SBrooks Davis         "Test program: the-program\n"
1105*b0d29bc4SBrooks Davis         "Test case: print_params\n"
1106*b0d29bc4SBrooks Davis         "one=first variable\n"
1107*b0d29bc4SBrooks Davis         "two=second variable\n"));
1108*b0d29bc4SBrooks Davis     ATF_REQUIRE(atf::utils::compare_file(
1109*b0d29bc4SBrooks Davis         stderr_file.str(), "stderr: print_params\n"));
1110*b0d29bc4SBrooks Davis }
1111*b0d29bc4SBrooks Davis 
1112*b0d29bc4SBrooks Davis 
1113*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(ensure_valid_interface);
ATF_TEST_CASE_BODY(ensure_valid_interface)1114*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(ensure_valid_interface)
1115*b0d29bc4SBrooks Davis {
1116*b0d29bc4SBrooks Davis     scheduler::ensure_valid_interface("mock");
1117*b0d29bc4SBrooks Davis 
1118*b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW_RE(engine::error, "Unsupported test interface 'mock2'",
1119*b0d29bc4SBrooks Davis                          scheduler::ensure_valid_interface("mock2"));
1120*b0d29bc4SBrooks Davis     scheduler::register_interface(
1121*b0d29bc4SBrooks Davis         "mock2", std::shared_ptr< scheduler::interface >(new mock_interface()));
1122*b0d29bc4SBrooks Davis     scheduler::ensure_valid_interface("mock2");
1123*b0d29bc4SBrooks Davis 
1124*b0d29bc4SBrooks Davis     // Standard interfaces should not be present unless registered.
1125*b0d29bc4SBrooks Davis     ATF_REQUIRE_THROW_RE(engine::error, "Unsupported test interface 'plain'",
1126*b0d29bc4SBrooks Davis                          scheduler::ensure_valid_interface("plain"));
1127*b0d29bc4SBrooks Davis }
1128*b0d29bc4SBrooks Davis 
1129*b0d29bc4SBrooks Davis 
1130*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(registered_interface_names);
ATF_TEST_CASE_BODY(registered_interface_names)1131*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(registered_interface_names)
1132*b0d29bc4SBrooks Davis {
1133*b0d29bc4SBrooks Davis     std::set< std::string > exp_names;
1134*b0d29bc4SBrooks Davis 
1135*b0d29bc4SBrooks Davis     exp_names.insert("mock");
1136*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_names, scheduler::registered_interface_names());
1137*b0d29bc4SBrooks Davis 
1138*b0d29bc4SBrooks Davis     scheduler::register_interface(
1139*b0d29bc4SBrooks Davis         "mock2", std::shared_ptr< scheduler::interface >(new mock_interface()));
1140*b0d29bc4SBrooks Davis     exp_names.insert("mock2");
1141*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_names, scheduler::registered_interface_names());
1142*b0d29bc4SBrooks Davis }
1143*b0d29bc4SBrooks Davis 
1144*b0d29bc4SBrooks Davis 
1145*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(current_context);
ATF_TEST_CASE_BODY(current_context)1146*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(current_context)
1147*b0d29bc4SBrooks Davis {
1148*b0d29bc4SBrooks Davis     const model::context context = scheduler::current_context();
1149*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(fs::current_path(), context.cwd());
1150*b0d29bc4SBrooks Davis     ATF_REQUIRE(utils::getallenv() == context.env());
1151*b0d29bc4SBrooks Davis }
1152*b0d29bc4SBrooks Davis 
1153*b0d29bc4SBrooks Davis 
1154*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(generate_config__empty);
ATF_TEST_CASE_BODY(generate_config__empty)1155*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(generate_config__empty)
1156*b0d29bc4SBrooks Davis {
1157*b0d29bc4SBrooks Davis     const config::tree user_config = engine::empty_config();
1158*b0d29bc4SBrooks Davis 
1159*b0d29bc4SBrooks Davis     const config::properties_map exp_props;
1160*b0d29bc4SBrooks Davis 
1161*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_props,
1162*b0d29bc4SBrooks Davis                    scheduler::generate_config(user_config, "missing"));
1163*b0d29bc4SBrooks Davis }
1164*b0d29bc4SBrooks Davis 
1165*b0d29bc4SBrooks Davis 
1166*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(generate_config__no_matches);
ATF_TEST_CASE_BODY(generate_config__no_matches)1167*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(generate_config__no_matches)
1168*b0d29bc4SBrooks Davis {
1169*b0d29bc4SBrooks Davis     config::tree user_config = engine::empty_config();
1170*b0d29bc4SBrooks Davis     user_config.set_string("architecture", "foo");
1171*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.one.var1", "value 1");
1172*b0d29bc4SBrooks Davis 
1173*b0d29bc4SBrooks Davis     const config::properties_map exp_props;
1174*b0d29bc4SBrooks Davis 
1175*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_props,
1176*b0d29bc4SBrooks Davis                    scheduler::generate_config(user_config, "two"));
1177*b0d29bc4SBrooks Davis }
1178*b0d29bc4SBrooks Davis 
1179*b0d29bc4SBrooks Davis 
1180*b0d29bc4SBrooks Davis ATF_TEST_CASE_WITHOUT_HEAD(generate_config__some_matches);
ATF_TEST_CASE_BODY(generate_config__some_matches)1181*b0d29bc4SBrooks Davis ATF_TEST_CASE_BODY(generate_config__some_matches)
1182*b0d29bc4SBrooks Davis {
1183*b0d29bc4SBrooks Davis     std::vector< passwd::user > mock_users;
1184*b0d29bc4SBrooks Davis     mock_users.push_back(passwd::user("nobody", 1234, 5678));
1185*b0d29bc4SBrooks Davis     passwd::set_mock_users_for_testing(mock_users);
1186*b0d29bc4SBrooks Davis 
1187*b0d29bc4SBrooks Davis     config::tree user_config = engine::empty_config();
1188*b0d29bc4SBrooks Davis     user_config.set_string("architecture", "foo");
1189*b0d29bc4SBrooks Davis     user_config.set_string("unprivileged_user", "nobody");
1190*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.one.var1", "value 1");
1191*b0d29bc4SBrooks Davis     user_config.set_string("test_suites.two.var2", "value 2");
1192*b0d29bc4SBrooks Davis 
1193*b0d29bc4SBrooks Davis     config::properties_map exp_props;
1194*b0d29bc4SBrooks Davis     exp_props["unprivileged-user"] = "nobody";
1195*b0d29bc4SBrooks Davis     exp_props["var1"] = "value 1";
1196*b0d29bc4SBrooks Davis 
1197*b0d29bc4SBrooks Davis     ATF_REQUIRE_EQ(exp_props,
1198*b0d29bc4SBrooks Davis                    scheduler::generate_config(user_config, "one"));
1199*b0d29bc4SBrooks Davis }
1200*b0d29bc4SBrooks Davis 
1201*b0d29bc4SBrooks Davis 
ATF_INIT_TEST_CASES(tcs)1202*b0d29bc4SBrooks Davis ATF_INIT_TEST_CASES(tcs)
1203*b0d29bc4SBrooks Davis {
1204*b0d29bc4SBrooks Davis     scheduler::register_interface(
1205*b0d29bc4SBrooks Davis         "mock", std::shared_ptr< scheduler::interface >(new mock_interface()));
1206*b0d29bc4SBrooks Davis 
1207*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__list_some);
1208*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__list_check_paths);
1209*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__list_timeout);
1210*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__list_fail);
1211*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__list_empty);
1212*b0d29bc4SBrooks Davis 
1213*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__run_one);
1214*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__run_many);
1215*b0d29bc4SBrooks Davis 
1216*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__run_check_paths);
1217*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__parameters_and_output);
1218*b0d29bc4SBrooks Davis 
1219*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__fake_result);
1220*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__cleanup__head_skips);
1221*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__cleanup__body_skips);
1222*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__cleanup__body_ok__cleanup_bad);
1223*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__cleanup__body_bad__cleanup_ok);
1224*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__cleanup__body_bad__cleanup_bad);
1225*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__cleanup__timeout);
1226*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__check_requirements);
1227*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__stacktrace);
1228*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__list_files_on_failure__none);
1229*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__list_files_on_failure__some);
1230*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, integration__prevent_clobbering_control_files);
1231*b0d29bc4SBrooks Davis 
1232*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, debug_test);
1233*b0d29bc4SBrooks Davis 
1234*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, ensure_valid_interface);
1235*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, registered_interface_names);
1236*b0d29bc4SBrooks Davis 
1237*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, current_context);
1238*b0d29bc4SBrooks Davis 
1239*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, generate_config__empty);
1240*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, generate_config__no_matches);
1241*b0d29bc4SBrooks Davis     ATF_ADD_TEST_CASE(tcs, generate_config__some_matches);
1242*b0d29bc4SBrooks Davis }
1243