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 
30 extern "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++.hpp>
45 
46 #include "env.hpp"
47 #include "fs.hpp"
48 #include "process.hpp"
49 
50 // ------------------------------------------------------------------------
51 // Auxiliary functions.
52 // ------------------------------------------------------------------------
53 
54 static
55 void
touch(const std::string & path)56 touch(const std::string& path)
57 {
58     std::ofstream os(path.c_str());
59     if (!os)
60         ATF_FAIL("Could not create file " + path);
61     os.close();
62 }
63 
64 // ------------------------------------------------------------------------
65 // Helper tests for "atf-run_test".
66 // ------------------------------------------------------------------------
67 
68 ATF_TEST_CASE(pass);
ATF_TEST_CASE_HEAD(pass)69 ATF_TEST_CASE_HEAD(pass)
70 {
71     set_md_var("descr", "Helper test case for the t_integration test program");
72 }
ATF_TEST_CASE_BODY(pass)73 ATF_TEST_CASE_BODY(pass)
74 {
75 }
76 
77 ATF_TEST_CASE(config);
ATF_TEST_CASE_HEAD(config)78 ATF_TEST_CASE_HEAD(config)
79 {
80     set_md_var("descr", "Helper test case for the t_integration test program");
81 }
ATF_TEST_CASE_BODY(config)82 ATF_TEST_CASE_BODY(config)
83 {
84     std::cout << "1st: " << get_config_var("1st") << "\n";
85     std::cout << "2nd: " << get_config_var("2nd") << "\n";
86     std::cout << "3rd: " << get_config_var("3rd") << "\n";
87     std::cout << "4th: " << get_config_var("4th") << "\n";
88 }
89 
90 ATF_TEST_CASE(fds);
ATF_TEST_CASE_HEAD(fds)91 ATF_TEST_CASE_HEAD(fds)
92 {
93     set_md_var("descr", "Helper test case for the t_integration test program");
94 }
ATF_TEST_CASE_BODY(fds)95 ATF_TEST_CASE_BODY(fds)
96 {
97     std::cout << "msg1 to stdout" << "\n";
98     std::cout << "msg2 to stdout" << "\n";
99     std::cerr << "msg1 to stderr" << "\n";
100     std::cerr << "msg2 to stderr" << "\n";
101 }
102 
103 ATF_TEST_CASE_WITHOUT_HEAD(mux_streams);
ATF_TEST_CASE_BODY(mux_streams)104 ATF_TEST_CASE_BODY(mux_streams)
105 {
106     for (size_t i = 0; i < 10000; i++) {
107         switch (i % 5) {
108         case 0:
109             std::cout << "stdout " << i << "\n";
110             break;
111         case 1:
112             std::cerr << "stderr " << i << "\n";
113             break;
114         case 2:
115             std::cout << "stdout " << i << "\n";
116             std::cerr << "stderr " << i << "\n";
117             break;
118         case 3:
119             std::cout << "stdout " << i << "\n";
120             std::cout << "stdout " << i << "\n";
121             std::cerr << "stderr " << i << "\n";
122             break;
123         case 4:
124             std::cout << "stdout " << i << "\n";
125             std::cerr << "stderr " << i << "\n";
126             std::cerr << "stderr " << i << "\n";
127             break;
128         default:
129             std::abort();
130         }
131     }
132 }
133 
134 ATF_TEST_CASE(testvar);
ATF_TEST_CASE_HEAD(testvar)135 ATF_TEST_CASE_HEAD(testvar)
136 {
137     set_md_var("descr", "Helper test case for the t_integration test program");
138 }
ATF_TEST_CASE_BODY(testvar)139 ATF_TEST_CASE_BODY(testvar)
140 {
141     if (!has_config_var("testvar"))
142         fail("testvar variable not defined");
143     std::cout << "testvar: " << get_config_var("testvar") << "\n";
144 }
145 
146 ATF_TEST_CASE(env_list);
ATF_TEST_CASE_HEAD(env_list)147 ATF_TEST_CASE_HEAD(env_list)
148 {
149     set_md_var("descr", "Helper test case for the t_integration test program");
150 }
ATF_TEST_CASE_BODY(env_list)151 ATF_TEST_CASE_BODY(env_list)
152 {
153     const tools::process::status s =
154         tools::process::exec(tools::fs::path("env"),
155                            tools::process::argv_array("env", NULL),
156                            tools::process::stream_inherit(),
157                            tools::process::stream_inherit());
158     ATF_REQUIRE(s.exited());
159     ATF_REQUIRE(s.exitstatus() == EXIT_SUCCESS);
160 }
161 
162 ATF_TEST_CASE(env_home);
ATF_TEST_CASE_HEAD(env_home)163 ATF_TEST_CASE_HEAD(env_home)
164 {
165     set_md_var("descr", "Helper test case for the t_integration test program");
166 }
ATF_TEST_CASE_BODY(env_home)167 ATF_TEST_CASE_BODY(env_home)
168 {
169     ATF_REQUIRE(tools::env::has("HOME"));
170     tools::fs::path p(tools::env::get("HOME"));
171     tools::fs::file_info fi1(p);
172     tools::fs::file_info fi2(tools::fs::path("."));
173     ATF_REQUIRE_EQ(fi1.get_device(), fi2.get_device());
174     ATF_REQUIRE_EQ(fi1.get_inode(), fi2.get_inode());
175 }
176 
177 ATF_TEST_CASE(read_stdin);
ATF_TEST_CASE_HEAD(read_stdin)178 ATF_TEST_CASE_HEAD(read_stdin)
179 {
180     set_md_var("descr", "Helper test case for the t_integration test program");
181 }
ATF_TEST_CASE_BODY(read_stdin)182 ATF_TEST_CASE_BODY(read_stdin)
183 {
184     char buf[100];
185     ssize_t len = ::read(STDIN_FILENO, buf, sizeof(buf) - 1);
186     ATF_REQUIRE(len != -1);
187 
188     buf[len + 1] = '\0';
189     for (ssize_t i = 0; i < len; i++) {
190         if (buf[i] != '\0') {
191             fail("The stdin of the test case does not seem to be /dev/zero; "
192                  "got '" + std::string(buf) + "'");
193         }
194     }
195 }
196 
197 ATF_TEST_CASE(umask);
ATF_TEST_CASE_HEAD(umask)198 ATF_TEST_CASE_HEAD(umask)
199 {
200     set_md_var("descr", "Helper test case for the t_integration test program");
201 }
ATF_TEST_CASE_BODY(umask)202 ATF_TEST_CASE_BODY(umask)
203 {
204     mode_t m = ::umask(0);
205     std::cout << "umask: " << std::setw(4) << std::setfill('0')
206               << std::oct << m << "\n";
207     (void)::umask(m);
208 }
209 
210 ATF_TEST_CASE_WITH_CLEANUP(cleanup_states);
ATF_TEST_CASE_HEAD(cleanup_states)211 ATF_TEST_CASE_HEAD(cleanup_states)
212 {
213     set_md_var("descr", "Helper test case for the t_integration test program");
214 }
ATF_TEST_CASE_BODY(cleanup_states)215 ATF_TEST_CASE_BODY(cleanup_states)
216 {
217     touch(get_config_var("statedir") + "/to-delete");
218     touch(get_config_var("statedir") + "/to-stay");
219 
220     if (get_config_var("state") == "fail")
221         ATF_FAIL("On purpose");
222     else if (get_config_var("state") == "skip")
223         ATF_SKIP("On purpose");
224 }
ATF_TEST_CASE_CLEANUP(cleanup_states)225 ATF_TEST_CASE_CLEANUP(cleanup_states)
226 {
227     tools::fs::remove(tools::fs::path(get_config_var("statedir") + "/to-delete"));
228 }
229 
230 ATF_TEST_CASE_WITH_CLEANUP(cleanup_curdir);
ATF_TEST_CASE_HEAD(cleanup_curdir)231 ATF_TEST_CASE_HEAD(cleanup_curdir)
232 {
233     set_md_var("descr", "Helper test case for the t_integration test program");
234 }
ATF_TEST_CASE_BODY(cleanup_curdir)235 ATF_TEST_CASE_BODY(cleanup_curdir)
236 {
237     std::ofstream os("oldvalue");
238     if (!os)
239         ATF_FAIL("Failed to create oldvalue file");
240     os << 1234;
241     os.close();
242 }
ATF_TEST_CASE_CLEANUP(cleanup_curdir)243 ATF_TEST_CASE_CLEANUP(cleanup_curdir)
244 {
245     std::ifstream is("oldvalue");
246     if (is) {
247         int i;
248         is >> i;
249         std::cout << "Old value: " << i << "\n";
250         is.close();
251     }
252 }
253 
254 ATF_TEST_CASE(require_arch);
ATF_TEST_CASE_HEAD(require_arch)255 ATF_TEST_CASE_HEAD(require_arch)
256 {
257     set_md_var("descr", "Helper test case for the t_integration test program");
258     set_md_var("require.arch", get_config_var("arch", "not-set"));
259 }
ATF_TEST_CASE_BODY(require_arch)260 ATF_TEST_CASE_BODY(require_arch)
261 {
262 }
263 
264 ATF_TEST_CASE(require_config);
ATF_TEST_CASE_HEAD(require_config)265 ATF_TEST_CASE_HEAD(require_config)
266 {
267     set_md_var("descr", "Helper test case for the t_integration test program");
268     set_md_var("require.config", "var1 var2");
269 }
ATF_TEST_CASE_BODY(require_config)270 ATF_TEST_CASE_BODY(require_config)
271 {
272     std::cout << "var1: " << get_config_var("var1") << "\n";
273     std::cout << "var2: " << get_config_var("var2") << "\n";
274 }
275 
276 ATF_TEST_CASE(require_files);
ATF_TEST_CASE_HEAD(require_files)277 ATF_TEST_CASE_HEAD(require_files)
278 {
279     set_md_var("descr", "Helper test case for the t_integration test program");
280     set_md_var("require.files", get_config_var("files", "not-set"));
281 }
ATF_TEST_CASE_BODY(require_files)282 ATF_TEST_CASE_BODY(require_files)
283 {
284 }
285 
286 ATF_TEST_CASE(require_machine);
ATF_TEST_CASE_HEAD(require_machine)287 ATF_TEST_CASE_HEAD(require_machine)
288 {
289     set_md_var("descr", "Helper test case for the t_integration test program");
290     set_md_var("require.machine", get_config_var("machine", "not-set"));
291 }
ATF_TEST_CASE_BODY(require_machine)292 ATF_TEST_CASE_BODY(require_machine)
293 {
294 }
295 
296 ATF_TEST_CASE(require_progs);
ATF_TEST_CASE_HEAD(require_progs)297 ATF_TEST_CASE_HEAD(require_progs)
298 {
299     set_md_var("descr", "Helper test case for the t_integration test program");
300     set_md_var("require.progs", get_config_var("progs", "not-set"));
301 }
ATF_TEST_CASE_BODY(require_progs)302 ATF_TEST_CASE_BODY(require_progs)
303 {
304 }
305 
306 ATF_TEST_CASE(require_user);
ATF_TEST_CASE_HEAD(require_user)307 ATF_TEST_CASE_HEAD(require_user)
308 {
309     set_md_var("descr", "Helper test case for the t_integration test program");
310     set_md_var("require.user", get_config_var("user", "not-set"));
311 }
ATF_TEST_CASE_BODY(require_user)312 ATF_TEST_CASE_BODY(require_user)
313 {
314 }
315 
316 ATF_TEST_CASE(timeout);
ATF_TEST_CASE_HEAD(timeout)317 ATF_TEST_CASE_HEAD(timeout)
318 {
319     set_md_var("descr", "Helper test case for the t_integration test program");
320     set_md_var("timeout", "1");
321 }
ATF_TEST_CASE_BODY(timeout)322 ATF_TEST_CASE_BODY(timeout)
323 {
324     sleep(10);
325     touch(get_config_var("statedir") + "/finished");
326 }
327 
328 ATF_TEST_CASE(timeout_forkexit);
ATF_TEST_CASE_HEAD(timeout_forkexit)329 ATF_TEST_CASE_HEAD(timeout_forkexit)
330 {
331     set_md_var("descr", "Helper test case for the t_integration test program");
332 }
ATF_TEST_CASE_BODY(timeout_forkexit)333 ATF_TEST_CASE_BODY(timeout_forkexit)
334 {
335     pid_t pid = fork();
336     ATF_REQUIRE(pid != -1);
337 
338     if (pid == 0) {
339         sigset_t mask;
340         sigemptyset(&mask);
341 
342         std::cout << "Waiting in subprocess\n";
343         std::cout.flush();
344         ::sigsuspend(&mask);
345 
346         touch(get_config_var("statedir") + "/child-finished");
347         std::cout << "Subprocess exiting\n";
348         std::cout.flush();
349         exit(EXIT_SUCCESS);
350     } else {
351         // Don't wait for the child process and let atf-run deal with it.
352         touch(get_config_var("statedir") + "/parent-finished");
353         std::cout << "Parent process exiting\n";
354         ATF_PASS();
355     }
356 }
357 
358 ATF_TEST_CASE(use_fs);
ATF_TEST_CASE_HEAD(use_fs)359 ATF_TEST_CASE_HEAD(use_fs)
360 {
361     set_md_var("descr", "Helper test case for the t_integration test program");
362     set_md_var("use.fs", "this-is-deprecated");
363 }
ATF_TEST_CASE_BODY(use_fs)364 ATF_TEST_CASE_BODY(use_fs)
365 {
366     touch("test-file");
367 }
368 
369 // ------------------------------------------------------------------------
370 // Helper tests for "atf-report_test".
371 // ------------------------------------------------------------------------
372 
373 ATF_TEST_CASE(diff);
ATF_TEST_CASE_HEAD(diff)374 ATF_TEST_CASE_HEAD(diff)
375 {
376     set_md_var("descr", "Helper test case for the t_integration program");
377 }
ATF_TEST_CASE_BODY(diff)378 ATF_TEST_CASE_BODY(diff)
379 {
380     std::cout << "--- a	2007-11-04 14:00:41.000000000 +0100\n";
381     std::cout << "+++ b	2007-11-04 14:00:48.000000000 +0100\n";
382     std::cout << "@@ -1,7 +1,7 @@\n";
383     std::cout << " This test is meant to simulate a diff.\n";
384     std::cout << " Blank space at beginning of context lines must be "
385                  "preserved.\n";
386     std::cout << " \n";
387     std::cout << "-First original line.\n";
388     std::cout << "-Second original line.\n";
389     std::cout << "+First modified line.\n";
390     std::cout << "+Second modified line.\n";
391     std::cout << " \n";
392     std::cout << " EOF\n";
393 }
394 
395 // ------------------------------------------------------------------------
396 // Main.
397 // ------------------------------------------------------------------------
398 
ATF_INIT_TEST_CASES(tcs)399 ATF_INIT_TEST_CASES(tcs)
400 {
401     std::string which = tools::env::get("TESTCASE");
402 
403     // Add helper tests for atf-run_test.
404     if (which == "pass")
405         ATF_ADD_TEST_CASE(tcs, pass);
406     if (which == "config")
407         ATF_ADD_TEST_CASE(tcs, config);
408     if (which == "fds")
409         ATF_ADD_TEST_CASE(tcs, fds);
410     if (which == "mux_streams")
411         ATF_ADD_TEST_CASE(tcs, mux_streams);
412     if (which == "testvar")
413         ATF_ADD_TEST_CASE(tcs, testvar);
414     if (which == "env_list")
415         ATF_ADD_TEST_CASE(tcs, env_list);
416     if (which == "env_home")
417         ATF_ADD_TEST_CASE(tcs, env_home);
418     if (which == "read_stdin")
419         ATF_ADD_TEST_CASE(tcs, read_stdin);
420     if (which == "umask")
421         ATF_ADD_TEST_CASE(tcs, umask);
422     if (which == "cleanup_states")
423         ATF_ADD_TEST_CASE(tcs, cleanup_states);
424     if (which == "cleanup_curdir")
425         ATF_ADD_TEST_CASE(tcs, cleanup_curdir);
426     if (which == "require_arch")
427         ATF_ADD_TEST_CASE(tcs, require_arch);
428     if (which == "require_config")
429         ATF_ADD_TEST_CASE(tcs, require_config);
430     if (which == "require_files")
431         ATF_ADD_TEST_CASE(tcs, require_files);
432     if (which == "require_machine")
433         ATF_ADD_TEST_CASE(tcs, require_machine);
434     if (which == "require_progs")
435         ATF_ADD_TEST_CASE(tcs, require_progs);
436     if (which == "require_user")
437         ATF_ADD_TEST_CASE(tcs, require_user);
438     if (which == "timeout")
439         ATF_ADD_TEST_CASE(tcs, timeout);
440     if (which == "timeout_forkexit")
441         ATF_ADD_TEST_CASE(tcs, timeout_forkexit);
442     if (which == "use_fs")
443         ATF_ADD_TEST_CASE(tcs, use_fs);
444 
445     // Add helper tests for atf-report_test.
446     if (which == "diff")
447         ATF_ADD_TEST_CASE(tcs, diff);
448 }
449