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