Index: sandbox/linux/tests/unit_tests.cc |
diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc |
index 105c45bc58926f9a36a81a4bd527745aff573b99..e770bf57f62273dfc06996d353a47c7460d30312 100644 |
--- a/sandbox/linux/tests/unit_tests.cc |
+++ b/sandbox/linux/tests/unit_tests.cc |
@@ -9,11 +9,20 @@ |
#include "base/file_util.h" |
#include "sandbox/linux/tests/unit_tests.h" |
+namespace { |
+ std::string TestFailedMessage(const std::string& msg) { |
+ return msg.empty() ? "" : "Actual test failure: " + msg; |
+ } |
+} |
+ |
namespace sandbox { |
static const int kExpectedValue = 42; |
+static const int kIgnoreThisTest = 43; |
+static const int kExitWithAssertionFailure = 1; |
-void UnitTests::RunTestInProcess(UnitTests::Test test, void *arg) { |
+void UnitTests::RunTestInProcess(UnitTests::Test test, void *arg, |
+ DeathCheck death, const void *death_aux) { |
// Runs a test in a sub-process. This is necessary for most of the code |
// in the BPF sandbox, as it potentially makes global state changes and as |
// it also tends to raise fatal errors, if the code has been used in an |
@@ -41,24 +50,41 @@ void UnitTests::RunTestInProcess(UnitTests::Test test, void *arg) { |
} |
(void)HANDLE_EINTR(close(fds[1])); |
- std::vector<char> msg; |
+ std::vector<char> msg_buf; |
ssize_t rc; |
do { |
const unsigned int kCapacity = 256; |
- size_t len = msg.size(); |
- msg.resize(len + kCapacity); |
- rc = HANDLE_EINTR(read(fds[0], &msg[len], kCapacity)); |
- msg.resize(len + std::max(rc, static_cast<ssize_t>(0))); |
+ size_t len = msg_buf.size(); |
+ msg_buf.resize(len + kCapacity); |
+ rc = HANDLE_EINTR(read(fds[0], &msg_buf[len], kCapacity)); |
+ msg_buf.resize(len + std::max(rc, static_cast<ssize_t>(0))); |
} while (rc > 0); |
- std::string details; |
- if (!msg.empty()) { |
- details = "Actual test failure: " + std::string(msg.begin(), msg.end()); |
- } |
(void)HANDLE_EINTR(close(fds[0])); |
+ std::string msg(msg_buf.begin(), msg_buf.end()); |
int status = 0; |
int waitpid_returned = HANDLE_EINTR(waitpid(pid, &status, 0)); |
- ASSERT_EQ(pid, waitpid_returned) << details; |
+ ASSERT_EQ(pid, waitpid_returned) << TestFailedMessage(msg); |
+ |
+ // At run-time, we sometimes decide that a test shouldn't actually |
+ // run (e.g. when testing sandbox features on a kernel that doesn't |
+ // have sandboxing support). When that happens, don't attempt to |
+ // call the "death" function, as it might be looking for a |
+ // death-test condition that would never have triggered. |
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != kIgnoreThisTest || |
+ !msg.empty()) { |
+ // We use gtest's ASSERT_XXX() macros instead of the DeathCheck |
+ // functions. This means, on failure, "return" is called. This |
+ // only works correctly, if the call of the "death" callback is |
+ // the very last thing in our function. |
+ death(status, msg, death_aux); |
+ } |
+} |
+ |
+void UnitTests::DeathSuccess(int status, const std::string& msg, |
+ const void *) { |
+ std::string details(TestFailedMessage(msg)); |
+ |
bool subprocess_terminated_normally = WIFEXITED(status); |
ASSERT_TRUE(subprocess_terminated_normally) << details; |
int subprocess_exit_status = WEXITSTATUS(status); |
@@ -67,11 +93,52 @@ void UnitTests::RunTestInProcess(UnitTests::Test test, void *arg) { |
EXPECT_FALSE(subprocess_exited_but_printed_messages) << details; |
} |
+void UnitTests::DeathMessage(int status, const std::string& msg, |
+ const void *aux) { |
+ std::string details(TestFailedMessage(msg)); |
+ const char *expected_msg = static_cast<const char *>(aux); |
+ |
+ bool subprocess_terminated_normally = WIFEXITED(status); |
+ ASSERT_TRUE(subprocess_terminated_normally) << details; |
+ int subprocess_exit_status = WEXITSTATUS(status); |
+ ASSERT_EQ(kExitWithAssertionFailure, subprocess_exit_status) << details; |
+ bool subprocess_exited_without_matching_message = |
+ msg.find(expected_msg) == std::string::npos; |
+ EXPECT_FALSE(subprocess_exited_without_matching_message) << details; |
+} |
+ |
+void UnitTests::DeathExitCode(int status, const std::string& msg, |
+ const void *aux) { |
+ int expected_exit_code = static_cast<int>(reinterpret_cast<intptr_t>(aux)); |
+ std::string details(TestFailedMessage(msg)); |
+ |
+ bool subprocess_terminated_normally = WIFEXITED(status); |
+ ASSERT_TRUE(subprocess_terminated_normally) << details; |
+ int subprocess_exit_status = WEXITSTATUS(status); |
+ ASSERT_EQ(subprocess_exit_status, expected_exit_code) << details; |
+} |
+ |
+void UnitTests::DeathBySignal(int status, const std::string& msg, |
+ const void *aux) { |
+ int expected_signo = static_cast<int>(reinterpret_cast<intptr_t>(aux)); |
+ std::string details(TestFailedMessage(msg)); |
+ |
+ bool subprocess_terminated_by_signal = WIFSIGNALED(status); |
+ ASSERT_TRUE(subprocess_terminated_by_signal) << details; |
+ int subprocess_signal_number = WTERMSIG(status); |
+ ASSERT_EQ(subprocess_signal_number, expected_signo) << details; |
+} |
+ |
void UnitTests::AssertionFailure(const char *expr, const char *file, |
int line) { |
fprintf(stderr, "%s:%d:%s", file, line, expr); |
fflush(stderr); |
- _exit(1); |
+ _exit(kExitWithAssertionFailure); |
+} |
+ |
+void UnitTests::IgnoreThisTest() { |
+ fflush(stderr); |
+ _exit(kIgnoreThisTest); |
} |
} // namespace |