1//
2// Automated Testing Framework (atf)
3//
4// Copyright (c) 2007 The NetBSD Foundation, Inc.
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
10// 1. Redistributions of source code must retain the above copyright
11//    notice, this list of conditions and the following disclaimer.
12// 2. Redistributions in binary form must reproduce the above copyright
13//    notice, this list of conditions and the following disclaimer in the
14//    documentation and/or other materials provided with the distribution.
15//
16// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
30extern "C" {
31#include <sys/stat.h>
32
33#include <signal.h>
34#include <unistd.h>
35}
36
37#include <cstdlib>
38#include <fstream>
39#include <iomanip>
40#include <ios>
41#include <iostream>
42#include <string>
43
44#include "atf-c++/macros.hpp"
45
46#include "atf-c++/detail/env.hpp"
47#include "atf-c++/detail/fs.hpp"
48#include "atf-c++/detail/process.hpp"
49#include "atf-c++/detail/sanity.hpp"
50
51// ------------------------------------------------------------------------
52// Auxiliary functions.
53// ------------------------------------------------------------------------
54
55static
56void
57touch(const std::string& path)
58{
59    std::ofstream os(path.c_str());
60    if (!os)
61        ATF_FAIL("Could not create file " + path);
62    os.close();
63}
64
65// ------------------------------------------------------------------------
66// Helper tests for "t_integration".
67// ------------------------------------------------------------------------
68
69ATF_TEST_CASE(pass);
70ATF_TEST_CASE_HEAD(pass)
71{
72    set_md_var("descr", "Helper test case for the t_integration test program");
73}
74ATF_TEST_CASE_BODY(pass)
75{
76}
77
78ATF_TEST_CASE(config);
79ATF_TEST_CASE_HEAD(config)
80{
81    set_md_var("descr", "Helper test case for the t_integration test program");
82}
83ATF_TEST_CASE_BODY(config)
84{
85    std::cout << "1st: " << get_config_var("1st") << "\n";
86    std::cout << "2nd: " << get_config_var("2nd") << "\n";
87    std::cout << "3rd: " << get_config_var("3rd") << "\n";
88    std::cout << "4th: " << get_config_var("4th") << "\n";
89}
90
91ATF_TEST_CASE(fds);
92ATF_TEST_CASE_HEAD(fds)
93{
94    set_md_var("descr", "Helper test case for the t_integration test program");
95}
96ATF_TEST_CASE_BODY(fds)
97{
98    std::cout << "msg1 to stdout" << "\n";
99    std::cout << "msg2 to stdout" << "\n";
100    std::cerr << "msg1 to stderr" << "\n";
101    std::cerr << "msg2 to stderr" << "\n";
102}
103
104ATF_TEST_CASE_WITHOUT_HEAD(mux_streams);
105ATF_TEST_CASE_BODY(mux_streams)
106{
107    for (size_t i = 0; i < 10000; i++) {
108        switch (i % 5) {
109        case 0:
110            std::cout << "stdout " << i << "\n";
111            break;
112        case 1:
113            std::cerr << "stderr " << i << "\n";
114            break;
115        case 2:
116            std::cout << "stdout " << i << "\n";
117            std::cerr << "stderr " << i << "\n";
118            break;
119        case 3:
120            std::cout << "stdout " << i << "\n";
121            std::cout << "stdout " << i << "\n";
122            std::cerr << "stderr " << i << "\n";
123            break;
124        case 4:
125            std::cout << "stdout " << i << "\n";
126            std::cerr << "stderr " << i << "\n";
127            std::cerr << "stderr " << i << "\n";
128            break;
129        default:
130            UNREACHABLE;
131        }
132    }
133}
134
135ATF_TEST_CASE(testvar);
136ATF_TEST_CASE_HEAD(testvar)
137{
138    set_md_var("descr", "Helper test case for the t_integration test program");
139}
140ATF_TEST_CASE_BODY(testvar)
141{
142    if (!has_config_var("testvar"))
143        fail("testvar variable not defined");
144    std::cout << "testvar: " << get_config_var("testvar") << "\n";
145}
146
147ATF_TEST_CASE(env_list);
148ATF_TEST_CASE_HEAD(env_list)
149{
150    set_md_var("descr", "Helper test case for the t_integration test program");
151}
152ATF_TEST_CASE_BODY(env_list)
153{
154    const atf::process::status s =
155        atf::process::exec(atf::fs::path("env"),
156                           atf::process::argv_array("env", NULL),
157                           atf::process::stream_inherit(),
158                           atf::process::stream_inherit());
159    ATF_REQUIRE(s.exited());
160    ATF_REQUIRE(s.exitstatus() == EXIT_SUCCESS);
161}
162
163ATF_TEST_CASE(env_home);
164ATF_TEST_CASE_HEAD(env_home)
165{
166    set_md_var("descr", "Helper test case for the t_integration test program");
167}
168ATF_TEST_CASE_BODY(env_home)
169{
170    ATF_REQUIRE(atf::env::has("HOME"));
171    atf::fs::path p(atf::env::get("HOME"));
172    atf::fs::file_info fi1(p);
173    atf::fs::file_info fi2(atf::fs::path("."));
174    ATF_REQUIRE_EQ(fi1.get_device(), fi2.get_device());
175    ATF_REQUIRE_EQ(fi1.get_inode(), fi2.get_inode());
176}
177
178ATF_TEST_CASE(read_stdin);
179ATF_TEST_CASE_HEAD(read_stdin)
180{
181    set_md_var("descr", "Helper test case for the t_integration test program");
182}
183ATF_TEST_CASE_BODY(read_stdin)
184{
185    char buf[100];
186    ssize_t len = ::read(STDIN_FILENO, buf, sizeof(buf) - 1);
187    ATF_REQUIRE(len != -1);
188
189    buf[len + 1] = '\0';
190    for (ssize_t i = 0; i < len; i++) {
191        if (buf[i] != '\0') {
192            fail("The stdin of the test case does not seem to be /dev/zero; "
193                 "got '" + std::string(buf) + "'");
194        }
195    }
196}
197
198ATF_TEST_CASE(umask);
199ATF_TEST_CASE_HEAD(umask)
200{
201    set_md_var("descr", "Helper test case for the t_integration test program");
202}
203ATF_TEST_CASE_BODY(umask)
204{
205    mode_t m = ::umask(0);
206    std::cout << "umask: " << std::setw(4) << std::setfill('0')
207              << std::oct << m << "\n";
208    (void)::umask(m);
209}
210
211ATF_TEST_CASE_WITH_CLEANUP(cleanup_states);
212ATF_TEST_CASE_HEAD(cleanup_states)
213{
214    set_md_var("descr", "Helper test case for the t_integration test program");
215}
216ATF_TEST_CASE_BODY(cleanup_states)
217{
218    touch(get_config_var("statedir") + "/to-delete");
219    touch(get_config_var("statedir") + "/to-stay");
220
221    if (get_config_var("state") == "fail")
222        ATF_FAIL("On purpose");
223    else if (get_config_var("state") == "skip")
224        ATF_SKIP("On purpose");
225}
226ATF_TEST_CASE_CLEANUP(cleanup_states)
227{
228    atf::fs::remove(atf::fs::path(get_config_var("statedir") + "/to-delete"));
229}
230
231ATF_TEST_CASE_WITH_CLEANUP(cleanup_curdir);
232ATF_TEST_CASE_HEAD(cleanup_curdir)
233{
234    set_md_var("descr", "Helper test case for the t_integration test program");
235}
236ATF_TEST_CASE_BODY(cleanup_curdir)
237{
238    std::ofstream os("oldvalue");
239    if (!os)
240        ATF_FAIL("Failed to create oldvalue file");
241    os << 1234;
242    os.close();
243}
244ATF_TEST_CASE_CLEANUP(cleanup_curdir)
245{
246    std::ifstream is("oldvalue");
247    if (is) {
248        int i;
249        is >> i;
250        std::cout << "Old value: " << i << "\n";
251        is.close();
252    }
253}
254
255ATF_TEST_CASE(require_arch);
256ATF_TEST_CASE_HEAD(require_arch)
257{
258    set_md_var("descr", "Helper test case for the t_integration test program");
259    set_md_var("require.arch", get_config_var("arch", "not-set"));
260}
261ATF_TEST_CASE_BODY(require_arch)
262{
263}
264
265ATF_TEST_CASE(require_config);
266ATF_TEST_CASE_HEAD(require_config)
267{
268    set_md_var("descr", "Helper test case for the t_integration test program");
269    set_md_var("require.config", "var1 var2");
270}
271ATF_TEST_CASE_BODY(require_config)
272{
273    std::cout << "var1: " << get_config_var("var1") << "\n";
274    std::cout << "var2: " << get_config_var("var2") << "\n";
275}
276
277ATF_TEST_CASE(require_files);
278ATF_TEST_CASE_HEAD(require_files)
279{
280    set_md_var("descr", "Helper test case for the t_integration test program");
281    set_md_var("require.files", get_config_var("files", "not-set"));
282}
283ATF_TEST_CASE_BODY(require_files)
284{
285}
286
287ATF_TEST_CASE(require_machine);
288ATF_TEST_CASE_HEAD(require_machine)
289{
290    set_md_var("descr", "Helper test case for the t_integration test program");
291    set_md_var("require.machine", get_config_var("machine", "not-set"));
292}
293ATF_TEST_CASE_BODY(require_machine)
294{
295}
296
297ATF_TEST_CASE(require_progs);
298ATF_TEST_CASE_HEAD(require_progs)
299{
300    set_md_var("descr", "Helper test case for the t_integration test program");
301    set_md_var("require.progs", get_config_var("progs", "not-set"));
302}
303ATF_TEST_CASE_BODY(require_progs)
304{
305}
306
307ATF_TEST_CASE(require_user);
308ATF_TEST_CASE_HEAD(require_user)
309{
310    set_md_var("descr", "Helper test case for the t_integration test program");
311    set_md_var("require.user", get_config_var("user", "not-set"));
312}
313ATF_TEST_CASE_BODY(require_user)
314{
315}
316
317ATF_TEST_CASE(timeout);
318ATF_TEST_CASE_HEAD(timeout)
319{
320    set_md_var("descr", "Helper test case for the t_integration test program");
321    set_md_var("timeout", "1");
322}
323ATF_TEST_CASE_BODY(timeout)
324{
325    sleep(10);
326    touch(get_config_var("statedir") + "/finished");
327}
328
329ATF_TEST_CASE(timeout_forkexit);
330ATF_TEST_CASE_HEAD(timeout_forkexit)
331{
332    set_md_var("descr", "Helper test case for the t_integration test program");
333}
334ATF_TEST_CASE_BODY(timeout_forkexit)
335{
336    pid_t pid = fork();
337    ATF_REQUIRE(pid != -1);
338
339    if (pid == 0) {
340        sigset_t mask;
341        sigemptyset(&mask);
342
343        std::cout << "Waiting in subprocess\n";
344        std::cout.flush();
345        ::sigsuspend(&mask);
346
347        touch(get_config_var("statedir") + "/child-finished");
348        std::cout << "Subprocess exiting\n";
349        std::cout.flush();
350        exit(EXIT_SUCCESS);
351    } else {
352        // Don't wait for the child process and let atf-run deal with it.
353        touch(get_config_var("statedir") + "/parent-finished");
354        std::cout << "Parent process exiting\n";
355        ATF_PASS();
356    }
357}
358
359ATF_TEST_CASE(use_fs);
360ATF_TEST_CASE_HEAD(use_fs)
361{
362    set_md_var("descr", "Helper test case for the t_integration test program");
363    set_md_var("use.fs", "this-is-deprecated");
364}
365ATF_TEST_CASE_BODY(use_fs)
366{
367    touch("test-file");
368}
369
370// ------------------------------------------------------------------------
371// Main.
372// ------------------------------------------------------------------------
373
374ATF_INIT_TEST_CASES(tcs)
375{
376    std::string which = atf::env::get("TESTCASE");
377
378    // Add helper tests for t_integration.
379    if (which == "pass")
380        ATF_ADD_TEST_CASE(tcs, pass);
381    if (which == "config")
382        ATF_ADD_TEST_CASE(tcs, config);
383    if (which == "fds")
384        ATF_ADD_TEST_CASE(tcs, fds);
385    if (which == "mux_streams")
386        ATF_ADD_TEST_CASE(tcs, mux_streams);
387    if (which == "testvar")
388        ATF_ADD_TEST_CASE(tcs, testvar);
389    if (which == "env_list")
390        ATF_ADD_TEST_CASE(tcs, env_list);
391    if (which == "env_home")
392        ATF_ADD_TEST_CASE(tcs, env_home);
393    if (which == "read_stdin")
394        ATF_ADD_TEST_CASE(tcs, read_stdin);
395    if (which == "umask")
396        ATF_ADD_TEST_CASE(tcs, umask);
397    if (which == "cleanup_states")
398        ATF_ADD_TEST_CASE(tcs, cleanup_states);
399    if (which == "cleanup_curdir")
400        ATF_ADD_TEST_CASE(tcs, cleanup_curdir);
401    if (which == "require_arch")
402        ATF_ADD_TEST_CASE(tcs, require_arch);
403    if (which == "require_config")
404        ATF_ADD_TEST_CASE(tcs, require_config);
405    if (which == "require_files")
406        ATF_ADD_TEST_CASE(tcs, require_files);
407    if (which == "require_machine")
408        ATF_ADD_TEST_CASE(tcs, require_machine);
409    if (which == "require_progs")
410        ATF_ADD_TEST_CASE(tcs, require_progs);
411    if (which == "require_user")
412        ATF_ADD_TEST_CASE(tcs, require_user);
413    if (which == "timeout")
414        ATF_ADD_TEST_CASE(tcs, timeout);
415    if (which == "timeout_forkexit")
416        ATF_ADD_TEST_CASE(tcs, timeout_forkexit);
417    if (which == "use_fs")
418        ATF_ADD_TEST_CASE(tcs, use_fs);
419}
420