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/process/status.hpp" 30 31 extern "C" { 32 #include <sys/wait.h> 33 34 #include <signal.h> 35 #include <unistd.h> 36 } 37 38 #include <cstdlib> 39 40 #include <atf-c++.hpp> 41 42 #include "utils/test_utils.ipp" 43 44 using utils::process::status; 45 46 47 namespace { 48 49 50 /// Body of a subprocess that exits with a particular exit status. 51 /// 52 /// \tparam ExitStatus The status to exit with. 53 template< int ExitStatus > 54 void child_exit(void) 55 { 56 std::exit(ExitStatus); 57 } 58 59 60 /// Body of a subprocess that sends a particular signal to itself. 61 /// 62 /// \tparam Signo The signal to send to self. 63 template< int Signo > 64 void child_signal(void) 65 { 66 ::kill(::getpid(), Signo); 67 } 68 69 70 /// Spawns a process and waits for completion. 71 /// 72 /// \param hook The function to run within the child. Should not return. 73 /// 74 /// \return The termination status of the spawned subprocess. 75 status 76 fork_and_wait(void (*hook)(void)) 77 { 78 pid_t pid = ::fork(); 79 ATF_REQUIRE(pid != -1); 80 if (pid == 0) { 81 hook(); 82 std::abort(); 83 } else { 84 int stat_loc; 85 ATF_REQUIRE(::waitpid(pid, &stat_loc, 0) != -1); 86 const status s = status(pid, stat_loc); 87 ATF_REQUIRE_EQ(pid, s.dead_pid()); 88 return s; 89 } 90 } 91 92 93 } // anonymous namespace 94 95 96 ATF_TEST_CASE_WITHOUT_HEAD(fake_exited) 97 ATF_TEST_CASE_BODY(fake_exited) 98 { 99 const status fake = status::fake_exited(123); 100 ATF_REQUIRE_EQ(-1, fake.dead_pid()); 101 ATF_REQUIRE(fake.exited()); 102 ATF_REQUIRE_EQ(123, fake.exitstatus()); 103 ATF_REQUIRE(!fake.signaled()); 104 } 105 106 107 ATF_TEST_CASE_WITHOUT_HEAD(fake_signaled) 108 ATF_TEST_CASE_BODY(fake_signaled) 109 { 110 const status fake = status::fake_signaled(567, true); 111 ATF_REQUIRE_EQ(-1, fake.dead_pid()); 112 ATF_REQUIRE(!fake.exited()); 113 ATF_REQUIRE(fake.signaled()); 114 ATF_REQUIRE_EQ(567, fake.termsig()); 115 ATF_REQUIRE(fake.coredump()); 116 } 117 118 119 ATF_TEST_CASE_WITHOUT_HEAD(output__exitstatus); 120 ATF_TEST_CASE_BODY(output__exitstatus) 121 { 122 const status fake = status::fake_exited(123); 123 std::ostringstream str; 124 str << fake; 125 ATF_REQUIRE_EQ("status{exitstatus=123}", str.str()); 126 } 127 128 129 ATF_TEST_CASE_WITHOUT_HEAD(output__signaled_without_core); 130 ATF_TEST_CASE_BODY(output__signaled_without_core) 131 { 132 const status fake = status::fake_signaled(8, false); 133 std::ostringstream str; 134 str << fake; 135 ATF_REQUIRE_EQ("status{termsig=8, coredump=false}", str.str()); 136 } 137 138 139 ATF_TEST_CASE_WITHOUT_HEAD(output__signaled_with_core); 140 ATF_TEST_CASE_BODY(output__signaled_with_core) 141 { 142 const status fake = status::fake_signaled(9, true); 143 std::ostringstream str; 144 str << fake; 145 ATF_REQUIRE_EQ("status{termsig=9, coredump=true}", str.str()); 146 } 147 148 149 ATF_TEST_CASE_WITHOUT_HEAD(integration__exited); 150 ATF_TEST_CASE_BODY(integration__exited) 151 { 152 const status exit_success = fork_and_wait(child_exit< EXIT_SUCCESS >); 153 ATF_REQUIRE(exit_success.exited()); 154 ATF_REQUIRE_EQ(EXIT_SUCCESS, exit_success.exitstatus()); 155 ATF_REQUIRE(!exit_success.signaled()); 156 157 const status exit_failure = fork_and_wait(child_exit< EXIT_FAILURE >); 158 ATF_REQUIRE(exit_failure.exited()); 159 ATF_REQUIRE_EQ(EXIT_FAILURE, exit_failure.exitstatus()); 160 ATF_REQUIRE(!exit_failure.signaled()); 161 } 162 163 164 ATF_TEST_CASE_WITHOUT_HEAD(integration__signaled); 165 ATF_TEST_CASE_BODY(integration__signaled) 166 { 167 const status sigterm = fork_and_wait(child_signal< SIGTERM >); 168 ATF_REQUIRE(!sigterm.exited()); 169 ATF_REQUIRE(sigterm.signaled()); 170 ATF_REQUIRE_EQ(SIGTERM, sigterm.termsig()); 171 ATF_REQUIRE(!sigterm.coredump()); 172 173 const status sigkill = fork_and_wait(child_signal< SIGKILL >); 174 ATF_REQUIRE(!sigkill.exited()); 175 ATF_REQUIRE(sigkill.signaled()); 176 ATF_REQUIRE_EQ(SIGKILL, sigkill.termsig()); 177 ATF_REQUIRE(!sigkill.coredump()); 178 } 179 180 181 ATF_TEST_CASE_WITHOUT_HEAD(integration__coredump); 182 ATF_TEST_CASE_BODY(integration__coredump) 183 { 184 utils::prepare_coredump_test(this); 185 186 const status coredump = fork_and_wait(child_signal< SIGQUIT >); 187 ATF_REQUIRE(!coredump.exited()); 188 ATF_REQUIRE(coredump.signaled()); 189 ATF_REQUIRE_EQ(SIGQUIT, coredump.termsig()); 190 #if !defined(WCOREDUMP) 191 expect_fail("Platform does not support checking for coredump"); 192 #endif 193 ATF_REQUIRE(coredump.coredump()); 194 } 195 196 197 ATF_INIT_TEST_CASES(tcs) 198 { 199 ATF_ADD_TEST_CASE(tcs, fake_exited); 200 ATF_ADD_TEST_CASE(tcs, fake_signaled); 201 202 ATF_ADD_TEST_CASE(tcs, output__exitstatus); 203 ATF_ADD_TEST_CASE(tcs, output__signaled_without_core); 204 ATF_ADD_TEST_CASE(tcs, output__signaled_with_core); 205 206 ATF_ADD_TEST_CASE(tcs, integration__exited); 207 ATF_ADD_TEST_CASE(tcs, integration__signaled); 208 ATF_ADD_TEST_CASE(tcs, integration__coredump); 209 } 210