test_case_test.cpp revision 1.1.1.1 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 jmmv } // anonymous namespace
368 1.1 jmmv
369 1.1 jmmv
370 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(test_case__ctor_and_getters)
371 1.1 jmmv ATF_TEST_CASE_BODY(test_case__ctor_and_getters)
372 1.1 jmmv {
373 1.1 jmmv const engine::metadata md = engine::metadata_builder()
374 1.1 jmmv .add_custom("first", "value")
375 1.1 jmmv .build();
376 1.1 jmmv const engine::test_program test_program(
377 1.1 jmmv "mock", fs::path("abc"), fs::path("unused-root"),
378 1.1 jmmv "unused-suite-name", engine::metadata_builder().build());
379 1.1 jmmv const engine::test_case test_case("mock", test_program, "foo", md);
380 1.1 jmmv ATF_REQUIRE_EQ(&test_program, &test_case.container_test_program());
381 1.1 jmmv ATF_REQUIRE_EQ("foo", test_case.name());
382 1.1 jmmv ATF_REQUIRE(md == test_case.get_metadata());
383 1.1 jmmv }
384 1.1 jmmv
385 1.1 jmmv
386 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(test_case__fake_result)
387 1.1 jmmv ATF_TEST_CASE_BODY(test_case__fake_result)
388 1.1 jmmv {
389 1.1 jmmv const engine::test_result result(engine::test_result::skipped,
390 1.1 jmmv "Some reason");
391 1.1 jmmv const engine::test_program test_program(
392 1.1 jmmv "mock", fs::path("abc"), fs::path("unused-root"),
393 1.1 jmmv "unused-suite-name", engine::metadata_builder().build());
394 1.1 jmmv const engine::test_case test_case("mock", test_program, "__foo__",
395 1.1 jmmv "Some description", result);
396 1.1 jmmv ATF_REQUIRE_EQ(&test_program, &test_case.container_test_program());
397 1.1 jmmv ATF_REQUIRE_EQ("__foo__", test_case.name());
398 1.1 jmmv ATF_REQUIRE(result == test_case.fake_result().get());
399 1.1 jmmv }
400 1.1 jmmv
401 1.1 jmmv
402 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(test_case__operators_eq_and_ne__copy);
403 1.1 jmmv ATF_TEST_CASE_BODY(test_case__operators_eq_and_ne__copy)
404 1.1 jmmv {
405 1.1 jmmv const engine::test_program tp(
406 1.1 jmmv "plain", fs::path("non-existent"), fs::path("."), "suite-name",
407 1.1 jmmv engine::metadata_builder().build());
408 1.1 jmmv
409 1.1 jmmv const engine::test_case tc1("plain", tp, "name",
410 1.1 jmmv engine::metadata_builder().build());
411 1.1 jmmv const engine::test_case tc2 = tc1;
412 1.1 jmmv ATF_REQUIRE( tc1 == tc2);
413 1.1 jmmv ATF_REQUIRE(!(tc1 != tc2));
414 1.1 jmmv }
415 1.1 jmmv
416 1.1 jmmv
417 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(test_case__output);
418 1.1 jmmv ATF_TEST_CASE_BODY(test_case__output)
419 1.1 jmmv {
420 1.1 jmmv const engine::test_program tp(
421 1.1 jmmv "plain", fs::path("non-existent"), fs::path("."), "suite-name",
422 1.1 jmmv engine::metadata_builder().build());
423 1.1 jmmv
424 1.1 jmmv const engine::test_case tc1(
425 1.1 jmmv "plain", tp, "the-name", engine::metadata_builder()
426 1.1 jmmv .add_allowed_platform("foo").add_custom("X-bar", "baz").build());
427 1.1 jmmv std::ostringstream str;
428 1.1 jmmv str << tc1;
429 1.1 jmmv ATF_REQUIRE_EQ(
430 1.1 jmmv "test_case{interface='plain', name='the-name', "
431 1.1 jmmv "metadata=metadata{allowed_architectures='', allowed_platforms='foo', "
432 1.1 jmmv "custom.X-bar='baz', description='', has_cleanup='false', "
433 1.1 jmmv "required_configs='', required_files='', required_memory='0', "
434 1.1 jmmv "required_programs='', required_user='', timeout='300'}}",
435 1.1 jmmv str.str());
436 1.1 jmmv }
437 1.1 jmmv
438 1.1 jmmv
439 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(test_case__operators_eq_and_ne__not_copy);
440 1.1 jmmv ATF_TEST_CASE_BODY(test_case__operators_eq_and_ne__not_copy)
441 1.1 jmmv {
442 1.1 jmmv const std::string base_interface("plain");
443 1.1 jmmv const engine::test_program base_tp(
444 1.1 jmmv "plain", fs::path("non-existent"), fs::path("."), "suite-name",
445 1.1 jmmv engine::metadata_builder().build());
446 1.1 jmmv const std::string base_name("name");
447 1.1 jmmv const engine::metadata base_metadata = engine::metadata_builder()
448 1.1 jmmv .add_custom("X-foo", "bar")
449 1.1 jmmv .build();
450 1.1 jmmv
451 1.1 jmmv const engine::test_case base_tc(base_interface, base_tp, base_name,
452 1.1 jmmv base_metadata);
453 1.1 jmmv
454 1.1 jmmv // Construct with all same values.
455 1.1 jmmv {
456 1.1 jmmv const engine::test_case other_tc(base_interface, base_tp, base_name,
457 1.1 jmmv base_metadata);
458 1.1 jmmv
459 1.1 jmmv ATF_REQUIRE( base_tc == other_tc);
460 1.1 jmmv ATF_REQUIRE(!(base_tc != other_tc));
461 1.1 jmmv }
462 1.1 jmmv
463 1.1 jmmv // Different interface.
464 1.1 jmmv {
465 1.1 jmmv const engine::test_case other_tc("atf", base_tp, base_name,
466 1.1 jmmv base_metadata);
467 1.1 jmmv
468 1.1 jmmv ATF_REQUIRE(!(base_tc == other_tc));
469 1.1 jmmv ATF_REQUIRE( base_tc != other_tc);
470 1.1 jmmv }
471 1.1 jmmv
472 1.1 jmmv // Different test program, different identifier.
473 1.1 jmmv {
474 1.1 jmmv const engine::test_program other_tp(
475 1.1 jmmv "plain", fs::path("another-name"), fs::path("."), "suite2-name",
476 1.1 jmmv engine::metadata_builder().build());
477 1.1 jmmv const engine::test_case other_tc(base_interface, other_tp, base_name,
478 1.1 jmmv base_metadata);
479 1.1 jmmv
480 1.1 jmmv ATF_REQUIRE(!(base_tc == other_tc));
481 1.1 jmmv ATF_REQUIRE( base_tc != other_tc);
482 1.1 jmmv }
483 1.1 jmmv
484 1.1 jmmv // Different test program, same identifier. Cannot be detected!
485 1.1 jmmv {
486 1.1 jmmv const engine::test_program other_tp(
487 1.1 jmmv "plain", fs::path("non-existent"), fs::path("."), "suite2-name",
488 1.1 jmmv engine::metadata_builder().build());
489 1.1 jmmv const engine::test_case other_tc(base_interface, other_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 name.
497 1.1 jmmv {
498 1.1 jmmv const engine::test_case other_tc(base_interface, base_tp, "other",
499 1.1 jmmv base_metadata);
500 1.1 jmmv
501 1.1 jmmv ATF_REQUIRE(!(base_tc == other_tc));
502 1.1 jmmv ATF_REQUIRE( base_tc != other_tc);
503 1.1 jmmv }
504 1.1 jmmv
505 1.1 jmmv // Different metadata.
506 1.1 jmmv {
507 1.1 jmmv const engine::test_case other_tc(base_interface, base_tp, base_name,
508 1.1 jmmv engine::metadata_builder().build());
509 1.1 jmmv
510 1.1 jmmv ATF_REQUIRE(!(base_tc == other_tc));
511 1.1 jmmv ATF_REQUIRE( base_tc != other_tc);
512 1.1 jmmv }
513 1.1 jmmv }
514 1.1 jmmv
515 1.1 jmmv
516 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__current_directory);
517 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__current_directory)
518 1.1 jmmv {
519 1.1 jmmv atf_helper helper(this, "pass");
520 1.1 jmmv helper.move("program", ".");
521 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
522 1.1 jmmv helper.run());
523 1.1 jmmv }
524 1.1 jmmv
525 1.1 jmmv
526 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__subdirectory);
527 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__subdirectory)
528 1.1 jmmv {
529 1.1 jmmv atf_helper helper(this, "pass");
530 1.1 jmmv ATF_REQUIRE(::mkdir("dir1", 0755) != -1);
531 1.1 jmmv ATF_REQUIRE(::mkdir("dir1/dir2", 0755) != -1);
532 1.1 jmmv helper.move("dir2/program", "dir1");
533 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
534 1.1 jmmv helper.run());
535 1.1 jmmv }
536 1.1 jmmv
537 1.1 jmmv
538 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__config_variables);
539 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__config_variables)
540 1.1 jmmv {
541 1.1 jmmv atf_helper helper(this, "create_cookie_in_control_dir");
542 1.1 jmmv helper.set_config("control_dir", fs::current_path());
543 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
544 1.1 jmmv helper.run());
545 1.1 jmmv
546 1.1 jmmv if (!fs::exists(fs::path("cookie")))
547 1.1 jmmv fail("The cookie was not created where we expected; the test program "
548 1.1 jmmv "probably received an invalid configuration variable");
549 1.1 jmmv }
550 1.1 jmmv
551 1.1 jmmv
552 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__cleanup_shares_workdir);
553 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__cleanup_shares_workdir)
554 1.1 jmmv {
555 1.1 jmmv atf_helper helper(this, "check_cleanup_workdir");
556 1.1 jmmv helper.set_metadata("has_cleanup", "true");
557 1.1 jmmv helper.set_config("control_dir", fs::current_path());
558 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped,
559 1.1 jmmv "cookie created"), helper.run());
560 1.1 jmmv
561 1.1 jmmv if (fs::exists(fs::path("missing_cookie")))
562 1.1 jmmv fail("The cleanup part did not see the cookie; the work directory "
563 1.1 jmmv "is probably not shared");
564 1.1 jmmv if (fs::exists(fs::path("invalid_cookie")))
565 1.1 jmmv fail("The cleanup part read an invalid cookie");
566 1.1 jmmv if (!fs::exists(fs::path("cookie_ok")))
567 1.1 jmmv fail("The cleanup part was not executed");
568 1.1 jmmv }
569 1.1 jmmv
570 1.1 jmmv
571 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__has_cleanup__atf__false);
572 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__has_cleanup__atf__false)
573 1.1 jmmv {
574 1.1 jmmv atf_helper helper(this, "create_cookie_from_cleanup");
575 1.1 jmmv helper.set_metadata("has_cleanup", "false");
576 1.1 jmmv helper.set_config("control_dir", fs::current_path());
577 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
578 1.1 jmmv helper.run());
579 1.1 jmmv
580 1.1 jmmv if (fs::exists(fs::path("cookie")))
581 1.1 jmmv fail("The cleanup part was executed even though the test case set "
582 1.1 jmmv "has.cleanup to false");
583 1.1 jmmv }
584 1.1 jmmv
585 1.1 jmmv
586 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__has_cleanup__atf__true);
587 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__has_cleanup__atf__true)
588 1.1 jmmv {
589 1.1 jmmv atf_helper helper(this, "create_cookie_from_cleanup");
590 1.1 jmmv helper.set_metadata("has_cleanup", "true");
591 1.1 jmmv helper.set_config("control_dir", fs::current_path());
592 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
593 1.1 jmmv helper.run());
594 1.1 jmmv
595 1.1 jmmv if (!fs::exists(fs::path("cookie")))
596 1.1 jmmv fail("The cleanup part was not executed even though the test case set "
597 1.1 jmmv "has.cleanup to true");
598 1.1 jmmv }
599 1.1 jmmv
600 1.1 jmmv
601 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__kill_children);
602 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__kill_children)
603 1.1 jmmv {
604 1.1 jmmv atf_helper helper(this, "spawn_blocking_child");
605 1.1 jmmv helper.set_config("control_dir", fs::current_path());
606 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
607 1.1 jmmv helper.run());
608 1.1 jmmv
609 1.1 jmmv if (!fs::exists(fs::path("pid")))
610 1.1 jmmv fail("The pid file was not created");
611 1.1 jmmv std::ifstream pidfile("pid");
612 1.1 jmmv ATF_REQUIRE(pidfile);
613 1.1 jmmv pid_t pid;
614 1.1 jmmv pidfile >> pid;
615 1.1 jmmv pidfile.close();
616 1.1 jmmv
617 1.1 jmmv int attempts = 30;
618 1.1 jmmv retry:
619 1.1 jmmv if (::kill(pid, SIGCONT) != -1 || errno != ESRCH) {
620 1.1 jmmv // Looks like the subchild did not die.
621 1.1 jmmv //
622 1.1 jmmv // Note that this might be inaccurate for two reasons:
623 1.1 jmmv // 1) The system may have spawned a new process with the same pid as
624 1.1 jmmv // our subchild... but in practice, this does not happen because
625 1.1 jmmv // most systems do not immediately reuse pid numbers. If that
626 1.1 jmmv // happens... well, we get a false test failure.
627 1.1 jmmv // 2) We ran so fast that even if the process was sent a signal to
628 1.1 jmmv // die, it has not had enough time to process it yet. This is why
629 1.1 jmmv // we retry this a few times.
630 1.1 jmmv if (attempts > 0) {
631 1.1 jmmv std::cout << "Subprocess not dead yet; retrying wait\n";
632 1.1 jmmv --attempts;
633 1.1 jmmv ::usleep(100000);
634 1.1 jmmv goto retry;
635 1.1 jmmv }
636 1.1 jmmv fail(F("The subprocess %s of our child was not killed") % pid);
637 1.1 jmmv }
638 1.1 jmmv }
639 1.1 jmmv
640 1.1 jmmv
641 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__isolation);
642 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__isolation)
643 1.1 jmmv {
644 1.1 jmmv atf_helper helper(this, "validate_isolation");
645 1.1 jmmv // Simple checks to make sure that the test case has been isolated.
646 1.1 jmmv utils::setenv("HOME", "fake-value");
647 1.1 jmmv utils::setenv("LANG", "C");
648 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
649 1.1 jmmv helper.run());
650 1.1 jmmv }
651 1.1 jmmv
652 1.1 jmmv
653 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__allowed_architectures);
654 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__allowed_architectures)
655 1.1 jmmv {
656 1.1 jmmv atf_helper helper(this, "create_cookie_in_control_dir");
657 1.1 jmmv helper.set_metadata("allowed_architectures", "i386 x86_64");
658 1.1 jmmv helper.config().set_string("architecture", "powerpc");
659 1.1 jmmv helper.config().set_string("platform", "");
660 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Current "
661 1.1 jmmv "architecture 'powerpc' not supported"),
662 1.1 jmmv helper.run());
663 1.1 jmmv
664 1.1 jmmv if (fs::exists(fs::path("cookie")))
665 1.1 jmmv fail("The test case was not really skipped when the requirements "
666 1.1 jmmv "check failed");
667 1.1 jmmv }
668 1.1 jmmv
669 1.1 jmmv
670 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__allowed_platforms);
671 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__allowed_platforms)
672 1.1 jmmv {
673 1.1 jmmv atf_helper helper(this, "create_cookie_in_control_dir");
674 1.1 jmmv helper.set_metadata("allowed_platforms", "i386 amd64");
675 1.1 jmmv helper.config().set_string("architecture", "");
676 1.1 jmmv helper.config().set_string("platform", "macppc");
677 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Current "
678 1.1 jmmv "platform 'macppc' not supported"),
679 1.1 jmmv helper.run());
680 1.1 jmmv
681 1.1 jmmv if (fs::exists(fs::path("cookie")))
682 1.1 jmmv fail("The test case was not really skipped when the requirements "
683 1.1 jmmv "check failed");
684 1.1 jmmv }
685 1.1 jmmv
686 1.1 jmmv
687 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__required_configs);
688 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__required_configs)
689 1.1 jmmv {
690 1.1 jmmv atf_helper helper(this, "create_cookie_in_control_dir");
691 1.1 jmmv helper.set_metadata("required_configs", "used-var");
692 1.1 jmmv helper.set_config("control_dir", fs::current_path());
693 1.1 jmmv helper.set_config("unused-var", "value");
694 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Required "
695 1.1 jmmv "configuration property 'used-var' not "
696 1.1 jmmv "defined"),
697 1.1 jmmv helper.run());
698 1.1 jmmv
699 1.1 jmmv if (fs::exists(fs::path("cookie")))
700 1.1 jmmv fail("The test case was not really skipped when the requirements "
701 1.1 jmmv "check failed");
702 1.1 jmmv }
703 1.1 jmmv
704 1.1 jmmv
705 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__required_programs);
706 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__required_programs)
707 1.1 jmmv {
708 1.1 jmmv atf_helper helper(this, "create_cookie_in_control_dir");
709 1.1 jmmv helper.set_metadata("required_programs", "/non-existent/program");
710 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Required "
711 1.1 jmmv "program '/non-existent/program' not "
712 1.1 jmmv "found"),
713 1.1 jmmv helper.run());
714 1.1 jmmv
715 1.1 jmmv if (fs::exists(fs::path("cookie")))
716 1.1 jmmv fail("The test case was not really skipped when the requirements "
717 1.1 jmmv "check failed");
718 1.1 jmmv }
719 1.1 jmmv
720 1.1 jmmv
721 1.1 jmmv ATF_TEST_CASE(run_test_case__atf__required_user__atf__root__atf__ok);
722 1.1 jmmv ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__root__atf__ok)
723 1.1 jmmv {
724 1.1 jmmv set_md_var("require.user", "root");
725 1.1 jmmv }
726 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__root__atf__ok)
727 1.1 jmmv {
728 1.1 jmmv atf_helper helper(this, "create_cookie_in_workdir");
729 1.1 jmmv helper.set_metadata("required_user", "root");
730 1.1 jmmv ATF_REQUIRE(passwd::current_user().is_root());
731 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
732 1.1 jmmv helper.run());
733 1.1 jmmv }
734 1.1 jmmv
735 1.1 jmmv
736 1.1 jmmv ATF_TEST_CASE(run_test_case__atf__required_user__atf__root__atf__skip);
737 1.1 jmmv ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__root__atf__skip)
738 1.1 jmmv {
739 1.1 jmmv set_md_var("require.user", "unprivileged");
740 1.1 jmmv }
741 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__root__atf__skip)
742 1.1 jmmv {
743 1.1 jmmv atf_helper helper(this, "create_cookie_in_workdir");
744 1.1 jmmv helper.set_metadata("required_user", "root");
745 1.1 jmmv ATF_REQUIRE(!passwd::current_user().is_root());
746 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Requires "
747 1.1 jmmv "root privileges"),
748 1.1 jmmv helper.run());
749 1.1 jmmv }
750 1.1 jmmv
751 1.1 jmmv
752 1.1 jmmv ATF_TEST_CASE(run_test_case__atf__required_user__atf__unprivileged__atf__ok);
753 1.1 jmmv ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__unprivileged__atf__ok)
754 1.1 jmmv {
755 1.1 jmmv set_md_var("require.user", "unprivileged");
756 1.1 jmmv }
757 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__unprivileged__atf__ok)
758 1.1 jmmv {
759 1.1 jmmv atf_helper helper(this, "create_cookie_in_workdir");
760 1.1 jmmv helper.set_metadata("required_user", "unprivileged");
761 1.1 jmmv ATF_REQUIRE(!helper.config().is_set("unprivileged_user"));
762 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
763 1.1 jmmv helper.run());
764 1.1 jmmv }
765 1.1 jmmv
766 1.1 jmmv
767 1.1 jmmv ATF_TEST_CASE(run_test_case__atf__required_user__atf__unprivileged__atf__skip);
768 1.1 jmmv ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__unprivileged__atf__skip)
769 1.1 jmmv {
770 1.1 jmmv set_md_var("require.user", "root");
771 1.1 jmmv }
772 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__unprivileged__atf__skip)
773 1.1 jmmv {
774 1.1 jmmv atf_helper helper(this, "create_cookie_in_workdir");
775 1.1 jmmv helper.set_metadata("required_user", "unprivileged");
776 1.1 jmmv ATF_REQUIRE(!helper.config().is_set("unprivileged_user"));
777 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::skipped, "Requires "
778 1.1 jmmv "an unprivileged user but the "
779 1.1 jmmv "unprivileged-user configuration "
780 1.1 jmmv "variable is not defined"),
781 1.1 jmmv helper.run());
782 1.1 jmmv }
783 1.1 jmmv
784 1.1 jmmv
785 1.1 jmmv ATF_TEST_CASE(run_test_case__atf__required_user__atf__unprivileged__atf__drop);
786 1.1 jmmv ATF_TEST_CASE_HEAD(run_test_case__atf__required_user__atf__unprivileged__atf__drop)
787 1.1 jmmv {
788 1.1 jmmv set_md_var("require.config", "unprivileged-user");
789 1.1 jmmv set_md_var("require.user", "root");
790 1.1 jmmv }
791 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__required_user__atf__unprivileged__atf__drop)
792 1.1 jmmv {
793 1.1 jmmv atf_helper helper(this, "check_unprivileged");
794 1.1 jmmv helper.set_metadata("required_user", "unprivileged");
795 1.1 jmmv helper.config().set< engine::user_node >(
796 1.1 jmmv "unprivileged_user",
797 1.1 jmmv passwd::find_user_by_name(get_config_var("unprivileged-user")));
798 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
799 1.1 jmmv helper.run());
800 1.1 jmmv }
801 1.1 jmmv
802 1.1 jmmv
803 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__timeout_body);
804 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__timeout_body)
805 1.1 jmmv {
806 1.1 jmmv atf_helper helper(this, "timeout_body");
807 1.1 jmmv helper.set_metadata("timeout", "1");
808 1.1 jmmv helper.set_config("control_dir", fs::current_path());
809 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::broken,
810 1.1 jmmv "Test case body timed out"),
811 1.1 jmmv helper.run());
812 1.1 jmmv
813 1.1 jmmv if (fs::exists(fs::path("cookie")))
814 1.1 jmmv fail("It seems that the test case was not killed after it timed out");
815 1.1 jmmv }
816 1.1 jmmv
817 1.1 jmmv
818 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__timeout_cleanup);
819 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__timeout_cleanup)
820 1.1 jmmv {
821 1.1 jmmv atf_helper helper(this, "timeout_cleanup");
822 1.1 jmmv helper.set_metadata("has_cleanup", "true");
823 1.1 jmmv helper.set_metadata("timeout", "1");
824 1.1 jmmv helper.set_config("control_dir", fs::current_path());
825 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::broken,
826 1.1 jmmv "Test case cleanup timed out"),
827 1.1 jmmv helper.run());
828 1.1 jmmv
829 1.1 jmmv if (fs::exists(fs::path("cookie")))
830 1.1 jmmv fail("It seems that the test case was not killed after it timed out");
831 1.1 jmmv }
832 1.1 jmmv
833 1.1 jmmv
834 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__stacktrace__atf__body);
835 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__stacktrace__atf__body)
836 1.1 jmmv {
837 1.1 jmmv atf_helper helper(this, "crash");
838 1.1 jmmv capture_hooks hooks;
839 1.1 jmmv const engine::test_result result = helper.run(hooks);
840 1.1 jmmv ATF_REQUIRE(engine::test_result::broken == result.type());
841 1.1 jmmv ATF_REQUIRE_MATCH("received signal.*core dumped", result.reason());
842 1.1 jmmv
843 1.1 jmmv ATF_REQUIRE(!atf::utils::grep_string("attempting to gather stack trace",
844 1.1 jmmv hooks.stdout_contents));
845 1.1 jmmv ATF_REQUIRE( atf::utils::grep_string("attempting to gather stack trace",
846 1.1 jmmv hooks.stderr_contents));
847 1.1 jmmv }
848 1.1 jmmv
849 1.1 jmmv
850 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__stacktrace__atf__cleanup);
851 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__stacktrace__atf__cleanup)
852 1.1 jmmv {
853 1.1 jmmv atf_helper helper(this, "crash_cleanup");
854 1.1 jmmv helper.set_metadata("has_cleanup", "true");
855 1.1 jmmv capture_hooks hooks;
856 1.1 jmmv const engine::test_result result = helper.run(hooks);
857 1.1 jmmv ATF_REQUIRE(engine::test_result::broken == result.type());
858 1.1 jmmv ATF_REQUIRE_MATCH(F("cleanup received signal %s") % SIGABRT,
859 1.1 jmmv result.reason());
860 1.1 jmmv
861 1.1 jmmv ATF_REQUIRE(!atf::utils::grep_string("attempting to gather stack trace",
862 1.1 jmmv hooks.stdout_contents));
863 1.1 jmmv ATF_REQUIRE( atf::utils::grep_string("attempting to gather stack trace",
864 1.1 jmmv hooks.stderr_contents));
865 1.1 jmmv }
866 1.1 jmmv
867 1.1 jmmv
868 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__missing_results_file);
869 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__missing_results_file)
870 1.1 jmmv {
871 1.1 jmmv atf_helper helper(this, "crash");
872 1.1 jmmv const engine::test_result result = helper.run();
873 1.1 jmmv ATF_REQUIRE(engine::test_result::broken == result.type());
874 1.1 jmmv // Need to match instead of doing an explicit comparison because the string
875 1.1 jmmv // may include the "core dumped" substring.
876 1.1 jmmv ATF_REQUIRE_MATCH(F("test case received signal %s") % SIGABRT,
877 1.1 jmmv result.reason());
878 1.1 jmmv }
879 1.1 jmmv
880 1.1 jmmv
881 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__missing_test_program);
882 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__missing_test_program)
883 1.1 jmmv {
884 1.1 jmmv atf_helper helper(this, "crash");
885 1.1 jmmv ATF_REQUIRE(::mkdir("dir", 0755) != -1);
886 1.1 jmmv helper.move("test_case_atf_helpers", "dir");
887 1.1 jmmv ATF_REQUIRE(::unlink("dir/test_case_atf_helpers") != -1);
888 1.1 jmmv const engine::test_result result = helper.run();
889 1.1 jmmv ATF_REQUIRE(engine::test_result::broken == result.type());
890 1.1 jmmv ATF_REQUIRE_MATCH("Test program does not exist", result.reason());
891 1.1 jmmv }
892 1.1 jmmv
893 1.1 jmmv
894 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__atf__output);
895 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__atf__output)
896 1.1 jmmv {
897 1.1 jmmv atf_helper helper(this, "output");
898 1.1 jmmv helper.set_metadata("has_cleanup", "true");
899 1.1 jmmv
900 1.1 jmmv capture_hooks hooks;
901 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
902 1.1 jmmv helper.run(hooks));
903 1.1 jmmv
904 1.1 jmmv ATF_REQUIRE_EQ("Body message to stdout\nCleanup message to stdout\n",
905 1.1 jmmv hooks.stdout_contents);
906 1.1 jmmv ATF_REQUIRE_EQ("Body message to stderr\nCleanup message to stderr\n",
907 1.1 jmmv hooks.stderr_contents);
908 1.1 jmmv }
909 1.1 jmmv
910 1.1 jmmv
911 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__result_pass);
912 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__result_pass)
913 1.1 jmmv {
914 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
915 1.1 jmmv plain_helper(this, "pass").run());
916 1.1 jmmv }
917 1.1 jmmv
918 1.1 jmmv
919 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__result_fail);
920 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__result_fail)
921 1.1 jmmv {
922 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::failed,
923 1.1 jmmv "Returned non-success exit status 8"),
924 1.1 jmmv plain_helper(this, "fail").run());
925 1.1 jmmv }
926 1.1 jmmv
927 1.1 jmmv
928 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__result_crash);
929 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__result_crash)
930 1.1 jmmv {
931 1.1 jmmv const engine::test_result result = plain_helper(this, "crash").run();
932 1.1 jmmv ATF_REQUIRE(engine::test_result::broken == result.type());
933 1.1 jmmv ATF_REQUIRE_MATCH(F("Received signal %s") % SIGABRT, result.reason());
934 1.1 jmmv }
935 1.1 jmmv
936 1.1 jmmv
937 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__current_directory);
938 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__current_directory)
939 1.1 jmmv {
940 1.1 jmmv plain_helper helper(this, "pass");
941 1.1 jmmv helper.move("program", ".");
942 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
943 1.1 jmmv helper.run());
944 1.1 jmmv }
945 1.1 jmmv
946 1.1 jmmv
947 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__subdirectory);
948 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__subdirectory)
949 1.1 jmmv {
950 1.1 jmmv plain_helper helper(this, "pass");
951 1.1 jmmv ATF_REQUIRE(::mkdir("dir1", 0755) != -1);
952 1.1 jmmv ATF_REQUIRE(::mkdir("dir1/dir2", 0755) != -1);
953 1.1 jmmv helper.move("dir2/program", "dir1");
954 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
955 1.1 jmmv helper.run());
956 1.1 jmmv }
957 1.1 jmmv
958 1.1 jmmv
959 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__kill_children);
960 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__kill_children)
961 1.1 jmmv {
962 1.1 jmmv plain_helper helper(this, "spawn_blocking_child");
963 1.1 jmmv helper.set("CONTROL_DIR", fs::current_path());
964 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
965 1.1 jmmv helper.run());
966 1.1 jmmv
967 1.1 jmmv if (!fs::exists(fs::path("pid")))
968 1.1 jmmv fail("The pid file was not created");
969 1.1 jmmv std::ifstream pidfile("pid");
970 1.1 jmmv ATF_REQUIRE(pidfile);
971 1.1 jmmv pid_t pid;
972 1.1 jmmv pidfile >> pid;
973 1.1 jmmv pidfile.close();
974 1.1 jmmv
975 1.1 jmmv int attempts = 30;
976 1.1 jmmv retry:
977 1.1 jmmv if (::kill(pid, SIGCONT) != -1 || errno != ESRCH) {
978 1.1 jmmv // Looks like the subchild did not die.
979 1.1 jmmv //
980 1.1 jmmv // Note that this might be inaccurate for two reasons:
981 1.1 jmmv // 1) The system may have spawned a new process with the same pid as
982 1.1 jmmv // our subchild... but in practice, this does not happen because
983 1.1 jmmv // most systems do not immediately reuse pid numbers. If that
984 1.1 jmmv // happens... well, we get a false test failure.
985 1.1 jmmv // 2) We ran so fast that even if the process was sent a signal to
986 1.1 jmmv // die, it has not had enough time to process it yet. This is why
987 1.1 jmmv // we retry this a few times.
988 1.1 jmmv if (attempts > 0) {
989 1.1 jmmv std::cout << "Subprocess not dead yet; retrying wait\n";
990 1.1 jmmv --attempts;
991 1.1 jmmv ::usleep(100000);
992 1.1 jmmv goto retry;
993 1.1 jmmv }
994 1.1 jmmv fail(F("The subprocess %s of our child was not killed") % pid);
995 1.1 jmmv }
996 1.1 jmmv }
997 1.1 jmmv
998 1.1 jmmv
999 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__isolation);
1000 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__isolation)
1001 1.1 jmmv {
1002 1.1 jmmv const plain_helper helper(this, "validate_isolation");
1003 1.1 jmmv utils::setenv("TEST_CASE", "validate_isolation");
1004 1.1 jmmv // Simple checks to make sure that the test case has been isolated.
1005 1.1 jmmv utils::setenv("HOME", "fake-value");
1006 1.1 jmmv utils::setenv("LANG", "C");
1007 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::passed),
1008 1.1 jmmv helper.run());
1009 1.1 jmmv }
1010 1.1 jmmv
1011 1.1 jmmv
1012 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__timeout);
1013 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__timeout)
1014 1.1 jmmv {
1015 1.1 jmmv plain_helper helper(this, "timeout",
1016 1.1 jmmv utils::make_optional(datetime::delta(1, 0)));
1017 1.1 jmmv helper.set("CONTROL_DIR", fs::current_path());
1018 1.1 jmmv ATF_REQUIRE_EQ(engine::test_result(engine::test_result::broken,
1019 1.1 jmmv "Test case timed out"),
1020 1.1 jmmv helper.run());
1021 1.1 jmmv
1022 1.1 jmmv if (fs::exists(fs::path("cookie")))
1023 1.1 jmmv fail("It seems that the test case was not killed after it timed out");
1024 1.1 jmmv }
1025 1.1 jmmv
1026 1.1 jmmv
1027 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__stacktrace);
1028 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__stacktrace)
1029 1.1 jmmv {
1030 1.1 jmmv plain_helper helper(this, "crash");
1031 1.1 jmmv helper.set("CONTROL_DIR", fs::current_path());
1032 1.1 jmmv
1033 1.1 jmmv const engine::test_result result = plain_helper(this, "crash").run();
1034 1.1 jmmv ATF_REQUIRE(engine::test_result::broken == result.type());
1035 1.1 jmmv ATF_REQUIRE_MATCH(F("Received signal %s") % SIGABRT, result.reason());
1036 1.1 jmmv
1037 1.1 jmmv ATF_REQUIRE(!atf::utils::grep_file("attempting to gather stack trace",
1038 1.1 jmmv "helper-stdout.txt"));
1039 1.1 jmmv ATF_REQUIRE( atf::utils::grep_file("attempting to gather stack trace",
1040 1.1 jmmv "helper-stderr.txt"));
1041 1.1 jmmv }
1042 1.1 jmmv
1043 1.1 jmmv
1044 1.1 jmmv ATF_TEST_CASE_WITHOUT_HEAD(run_test_case__plain__missing_test_program);
1045 1.1 jmmv ATF_TEST_CASE_BODY(run_test_case__plain__missing_test_program)
1046 1.1 jmmv {
1047 1.1 jmmv plain_helper helper(this, "pass");
1048 1.1 jmmv ATF_REQUIRE(::mkdir("dir", 0755) != -1);
1049 1.1 jmmv helper.move("test_case_helpers", "dir");
1050 1.1 jmmv ATF_REQUIRE(::unlink("dir/test_case_helpers") != -1);
1051 1.1 jmmv const engine::test_result result = helper.run();
1052 1.1 jmmv ATF_REQUIRE(engine::test_result::broken == result.type());
1053 1.1 jmmv ATF_REQUIRE_MATCH("Test program does not exist", result.reason());
1054 1.1 jmmv }
1055 1.1 jmmv
1056 1.1 jmmv
1057 1.1 jmmv ATF_INIT_TEST_CASES(tcs)
1058 1.1 jmmv {
1059 1.1 jmmv ATF_ADD_TEST_CASE(tcs, test_case__ctor_and_getters);
1060 1.1 jmmv ATF_ADD_TEST_CASE(tcs, test_case__fake_result);
1061 1.1 jmmv
1062 1.1 jmmv ATF_ADD_TEST_CASE(tcs, test_case__operators_eq_and_ne__copy);
1063 1.1 jmmv ATF_ADD_TEST_CASE(tcs, test_case__operators_eq_and_ne__not_copy);
1064 1.1 jmmv
1065 1.1 jmmv ATF_ADD_TEST_CASE(tcs, test_case__output);
1066 1.1 jmmv
1067 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__current_directory);
1068 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__subdirectory);
1069 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__config_variables);
1070 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__cleanup_shares_workdir);
1071 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__has_cleanup__atf__false);
1072 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__has_cleanup__atf__true);
1073 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__kill_children);
1074 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__isolation);
1075 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__allowed_architectures);
1076 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__allowed_platforms);
1077 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_configs);
1078 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_programs);
1079 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__root__atf__ok);
1080 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__root__atf__skip);
1081 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__unprivileged__atf__ok);
1082 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__unprivileged__atf__skip);
1083 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__required_user__atf__unprivileged__atf__drop);
1084 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__timeout_body);
1085 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__timeout_cleanup);
1086 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__stacktrace__atf__body);
1087 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__stacktrace__atf__cleanup);
1088 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__missing_results_file);
1089 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__missing_test_program);
1090 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__atf__output);
1091 1.1 jmmv
1092 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__result_pass);
1093 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__result_fail);
1094 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__result_crash);
1095 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__current_directory);
1096 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__subdirectory);
1097 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__kill_children);
1098 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__isolation);
1099 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__timeout);
1100 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__stacktrace);
1101 1.1 jmmv ATF_ADD_TEST_CASE(tcs, run_test_case__plain__missing_test_program);
1102 1.1 jmmv
1103 1.1 jmmv // TODO(jmmv): Add test cases for debug.
1104 1.1 jmmv }
1105