xref: /freebsd/contrib/kyua/utils/sanity_test.cpp (revision b0d29bc47dba79f6f38e67eabadfb4b32ffd9390)
1 // Copyright 2010 The Kyua Authors.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 //   notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 //   notice, this list of conditions and the following disclaimer in the
12 //   documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 //   may be used to endorse or promote products derived from this software
15 //   without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #include "utils/sanity.hpp"
30 
31 extern "C" {
32 #include <signal.h>
33 #include <unistd.h>
34 }
35 
36 #include <cstdlib>
37 #include <iostream>
38 
39 #include <atf-c++.hpp>
40 
41 #include "utils/format/macros.hpp"
42 #include "utils/fs/path.hpp"
43 #include "utils/process/child.ipp"
44 #include "utils/process/status.hpp"
45 #include "utils/test_utils.ipp"
46 
47 namespace fs = utils::fs;
48 namespace process = utils::process;
49 
50 
51 #define FILE_REGEXP __FILE__ ":[0-9]+: "
52 
53 
54 static const fs::path Stdout_File("stdout.txt");
55 static const fs::path Stderr_File("stderr.txt");
56 
57 
58 #if NDEBUG
59 static bool NDebug = true;
60 #else
61 static bool NDebug = false;
62 #endif
63 
64 
65 template< typename Function >
66 static process::status
run_test(Function function)67 run_test(Function function)
68 {
69     utils::avoid_coredump_on_crash();
70 
71     const process::status status = process::child::fork_files(
72         function, Stdout_File, Stderr_File)->wait();
73     atf::utils::cat_file(Stdout_File.str(), "Helper stdout: ");
74     atf::utils::cat_file(Stderr_File.str(), "Helper stderr: ");
75     return status;
76 }
77 
78 
79 static void
verify_success(const process::status & status)80 verify_success(const process::status& status)
81 {
82     ATF_REQUIRE(status.exited());
83     ATF_REQUIRE_EQ(EXIT_SUCCESS, status.exitstatus());
84     ATF_REQUIRE(atf::utils::grep_file("Before test", Stdout_File.str()));
85     ATF_REQUIRE(atf::utils::grep_file("After test", Stdout_File.str()));
86 }
87 
88 
89 static void
verify_failed(const process::status & status,const char * type,const char * exp_message,const bool check_ndebug)90 verify_failed(const process::status& status, const char* type,
91               const char* exp_message, const bool check_ndebug)
92 {
93     if (check_ndebug && NDebug) {
94         std::cout << "Built with NDEBUG; skipping verification\n";
95         verify_success(status);
96     } else {
97         ATF_REQUIRE(status.signaled());
98         ATF_REQUIRE_EQ(SIGABRT, status.termsig());
99         ATF_REQUIRE(atf::utils::grep_file("Before test", Stdout_File.str()));
100         ATF_REQUIRE(!atf::utils::grep_file("After test", Stdout_File.str()));
101         if (exp_message != NULL)
102             ATF_REQUIRE(atf::utils::grep_file(F(FILE_REGEXP "%s: %s") %
103                                               type % exp_message,
104                                               Stderr_File.str()));
105         else
106             ATF_REQUIRE(atf::utils::grep_file(F(FILE_REGEXP "%s") % type,
107                                               Stderr_File.str()));
108     }
109 }
110 
111 
112 template< bool Expression, bool WithMessage >
113 static void
do_inv_test(void)114 do_inv_test(void)
115 {
116     std::cout << "Before test\n";
117     if (WithMessage)
118         INV_MSG(Expression, "Custom message");
119     else
120         INV(Expression);
121     std::cout << "After test\n";
122     std::exit(EXIT_SUCCESS);
123 }
124 
125 
126 ATF_TEST_CASE_WITHOUT_HEAD(inv__holds);
ATF_TEST_CASE_BODY(inv__holds)127 ATF_TEST_CASE_BODY(inv__holds)
128 {
129     const process::status status = run_test(do_inv_test< true, false >);
130     verify_success(status);
131 }
132 
133 
134 ATF_TEST_CASE_WITHOUT_HEAD(inv__triggers_default_message);
ATF_TEST_CASE_BODY(inv__triggers_default_message)135 ATF_TEST_CASE_BODY(inv__triggers_default_message)
136 {
137     const process::status status = run_test(do_inv_test< false, false >);
138     verify_failed(status, "Invariant check failed", "Expression", true);
139 }
140 
141 
142 ATF_TEST_CASE_WITHOUT_HEAD(inv__triggers_custom_message);
ATF_TEST_CASE_BODY(inv__triggers_custom_message)143 ATF_TEST_CASE_BODY(inv__triggers_custom_message)
144 {
145     const process::status status = run_test(do_inv_test< false, true >);
146     verify_failed(status, "Invariant check failed", "Custom", true);
147 }
148 
149 
150 template< bool Expression, bool WithMessage >
151 static void
do_pre_test(void)152 do_pre_test(void)
153 {
154     std::cout << "Before test\n";
155     if (WithMessage)
156         PRE_MSG(Expression, "Custom message");
157     else
158         PRE(Expression);
159     std::cout << "After test\n";
160     std::exit(EXIT_SUCCESS);
161 }
162 
163 
164 ATF_TEST_CASE_WITHOUT_HEAD(pre__holds);
ATF_TEST_CASE_BODY(pre__holds)165 ATF_TEST_CASE_BODY(pre__holds)
166 {
167     const process::status status = run_test(do_pre_test< true, false >);
168     verify_success(status);
169 }
170 
171 
172 ATF_TEST_CASE_WITHOUT_HEAD(pre__triggers_default_message);
ATF_TEST_CASE_BODY(pre__triggers_default_message)173 ATF_TEST_CASE_BODY(pre__triggers_default_message)
174 {
175     const process::status status = run_test(do_pre_test< false, false >);
176     verify_failed(status, "Precondition check failed", "Expression", true);
177 }
178 
179 
180 ATF_TEST_CASE_WITHOUT_HEAD(pre__triggers_custom_message);
ATF_TEST_CASE_BODY(pre__triggers_custom_message)181 ATF_TEST_CASE_BODY(pre__triggers_custom_message)
182 {
183     const process::status status = run_test(do_pre_test< false, true >);
184     verify_failed(status, "Precondition check failed", "Custom", true);
185 }
186 
187 
188 template< bool Expression, bool WithMessage >
189 static void
do_post_test(void)190 do_post_test(void)
191 {
192     std::cout << "Before test\n";
193     if (WithMessage)
194         POST_MSG(Expression, "Custom message");
195     else
196         POST(Expression);
197     std::cout << "After test\n";
198     std::exit(EXIT_SUCCESS);
199 }
200 
201 
202 ATF_TEST_CASE_WITHOUT_HEAD(post__holds);
ATF_TEST_CASE_BODY(post__holds)203 ATF_TEST_CASE_BODY(post__holds)
204 {
205     const process::status status = run_test(do_post_test< true, false >);
206     verify_success(status);
207 }
208 
209 
210 ATF_TEST_CASE_WITHOUT_HEAD(post__triggers_default_message);
ATF_TEST_CASE_BODY(post__triggers_default_message)211 ATF_TEST_CASE_BODY(post__triggers_default_message)
212 {
213     const process::status status = run_test(do_post_test< false, false >);
214     verify_failed(status, "Postcondition check failed", "Expression", true);
215 }
216 
217 
218 ATF_TEST_CASE_WITHOUT_HEAD(post__triggers_custom_message);
ATF_TEST_CASE_BODY(post__triggers_custom_message)219 ATF_TEST_CASE_BODY(post__triggers_custom_message)
220 {
221     const process::status status = run_test(do_post_test< false, true >);
222     verify_failed(status, "Postcondition check failed", "Custom", true);
223 }
224 
225 
226 template< bool WithMessage >
227 static void
do_unreachable_test(void)228 do_unreachable_test(void)
229 {
230     std::cout << "Before test\n";
231     if (WithMessage)
232         UNREACHABLE_MSG("Custom message");
233     else
234         UNREACHABLE;
235     std::cout << "After test\n";
236     std::exit(EXIT_SUCCESS);
237 }
238 
239 
240 ATF_TEST_CASE_WITHOUT_HEAD(unreachable__default_message);
ATF_TEST_CASE_BODY(unreachable__default_message)241 ATF_TEST_CASE_BODY(unreachable__default_message)
242 {
243     const process::status status = run_test(do_unreachable_test< false >);
244     verify_failed(status, "Unreachable point reached", NULL, false);
245 }
246 
247 
248 ATF_TEST_CASE_WITHOUT_HEAD(unreachable__custom_message);
ATF_TEST_CASE_BODY(unreachable__custom_message)249 ATF_TEST_CASE_BODY(unreachable__custom_message)
250 {
251     const process::status status = run_test(do_unreachable_test< true >);
252     verify_failed(status, "Unreachable point reached", "Custom", false);
253 }
254 
255 
256 template< int Signo >
257 static void
do_crash_handler_test(void)258 do_crash_handler_test(void)
259 {
260     utils::install_crash_handlers("test-log.txt");
261     ::kill(::getpid(), Signo);
262     std::cout << "After signal\n";
263     std::exit(EXIT_FAILURE);
264 }
265 
266 
267 template< int Signo >
268 static void
crash_handler_test(void)269 crash_handler_test(void)
270 {
271     utils::avoid_coredump_on_crash();
272 
273     const process::status status = run_test(do_crash_handler_test< Signo >);
274     ATF_REQUIRE(status.signaled());
275     ATF_REQUIRE_EQ(Signo, status.termsig());
276     ATF_REQUIRE(atf::utils::grep_file(F("Fatal signal %s") % Signo,
277                                       Stderr_File.str()));
278     ATF_REQUIRE(atf::utils::grep_file("Log file is test-log.txt",
279                                       Stderr_File.str()));
280     ATF_REQUIRE(!atf::utils::grep_file("After signal", Stdout_File.str()));
281 }
282 
283 
284 ATF_TEST_CASE_WITHOUT_HEAD(install_crash_handlers__sigabrt);
ATF_TEST_CASE_BODY(install_crash_handlers__sigabrt)285 ATF_TEST_CASE_BODY(install_crash_handlers__sigabrt)
286 {
287     crash_handler_test< SIGABRT >();
288 }
289 
290 
291 ATF_TEST_CASE_WITHOUT_HEAD(install_crash_handlers__sigbus);
ATF_TEST_CASE_BODY(install_crash_handlers__sigbus)292 ATF_TEST_CASE_BODY(install_crash_handlers__sigbus)
293 {
294     crash_handler_test< SIGBUS >();
295 }
296 
297 
298 ATF_TEST_CASE_WITHOUT_HEAD(install_crash_handlers__sigsegv);
ATF_TEST_CASE_BODY(install_crash_handlers__sigsegv)299 ATF_TEST_CASE_BODY(install_crash_handlers__sigsegv)
300 {
301     crash_handler_test< SIGSEGV >();
302 }
303 
304 
ATF_INIT_TEST_CASES(tcs)305 ATF_INIT_TEST_CASES(tcs)
306 {
307     ATF_ADD_TEST_CASE(tcs, inv__holds);
308     ATF_ADD_TEST_CASE(tcs, inv__triggers_default_message);
309     ATF_ADD_TEST_CASE(tcs, inv__triggers_custom_message);
310     ATF_ADD_TEST_CASE(tcs, pre__holds);
311     ATF_ADD_TEST_CASE(tcs, pre__triggers_default_message);
312     ATF_ADD_TEST_CASE(tcs, pre__triggers_custom_message);
313     ATF_ADD_TEST_CASE(tcs, post__holds);
314     ATF_ADD_TEST_CASE(tcs, post__triggers_default_message);
315     ATF_ADD_TEST_CASE(tcs, post__triggers_custom_message);
316     ATF_ADD_TEST_CASE(tcs, unreachable__default_message);
317     ATF_ADD_TEST_CASE(tcs, unreachable__custom_message);
318 
319     ATF_ADD_TEST_CASE(tcs, install_crash_handlers__sigabrt);
320     ATF_ADD_TEST_CASE(tcs, install_crash_handlers__sigbus);
321     ATF_ADD_TEST_CASE(tcs, install_crash_handlers__sigsegv);
322 }
323