summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabrice de Gans-Riberi <fdegans@chromium.org>2018-05-01 23:20:31 (GMT)
committerFabrice de Gans-Riberi <fdegans@chromium.org>2018-05-01 23:22:09 (GMT)
commitd4b5281d110f0c8e7cb794737a7832a2408e8e0c (patch)
treee1cea1acc097f0b49f65dbba013acdbc3365c454
parent278aba369c41e90e9e77a6f51443beb3692919cf (diff)
downloadgoogletest-d4b5281d110f0c8e7cb794737a7832a2408e8e0c.zip
googletest-d4b5281d110f0c8e7cb794737a7832a2408e8e0c.tar.gz
googletest-d4b5281d110f0c8e7cb794737a7832a2408e8e0c.tar.bz2
Add Fuchsia support for death test.
-rw-r--r--googletest/include/gtest/gtest.h2
-rw-r--r--googletest/include/gtest/internal/gtest-port.h3
-rw-r--r--googletest/src/gtest-death-test.cc189
-rw-r--r--googletest/src/gtest-port.cc10
4 files changed, 200 insertions, 4 deletions
diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h
index a0592a8..e1e9c1b 100644
--- a/googletest/include/gtest/gtest.h
+++ b/googletest/include/gtest/gtest.h
@@ -172,6 +172,7 @@ class TestEventListenersAccessor;
class TestEventRepeater;
class UnitTestRecordPropertyTestHelper;
class WindowsDeathTest;
+class FuchsiaDeathTest;
class UnitTestImpl* GetUnitTestImpl();
void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
const std::string& message);
@@ -593,6 +594,7 @@ class GTEST_API_ TestResult {
friend class internal::TestResultAccessor;
friend class internal::UnitTestImpl;
friend class internal::WindowsDeathTest;
+ friend class internal::FuchsiaDeathTest;
// Gets the vector of TestPartResults.
const std::vector<TestPartResult>& test_part_results() const {
diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h
index e677cd9..fafb134 100644
--- a/googletest/include/gtest/internal/gtest-port.h
+++ b/googletest/include/gtest/internal/gtest-port.h
@@ -813,7 +813,8 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
(GTEST_OS_MAC && !GTEST_OS_IOS) || \
(GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
- GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || GTEST_OS_NETBSD)
+ GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD || \
+ GTEST_OS_NETBSD || GTEST_OS_FUCHSIA)
# define GTEST_HAS_DEATH_TEST 1
#endif
diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc
index 9ecab8f..eef6ed2 100644
--- a/googletest/src/gtest-death-test.cc
+++ b/googletest/src/gtest-death-test.cc
@@ -62,6 +62,11 @@
# include <spawn.h>
# endif // GTEST_OS_QNX
+# if GTEST_OS_FUCHSIA
+# include <launchpad/launchpad.h>
+# include <zircon/syscalls.h>
+# endif // GTEST_OS_FUCHSIA
+
#endif // GTEST_HAS_DEATH_TEST
#include "gtest/gtest-message.h"
@@ -127,7 +132,7 @@ static bool g_in_fast_death_test_child = false;
// tests. IMPORTANT: This is an internal utility. Using it may break the
// implementation of death tests. User code MUST NOT use it.
bool InDeathTestChild() {
-# if GTEST_OS_WINDOWS
+# if GTEST_OS_WINDOWS || GTEST_OS_FUCHSIA
// On Windows, death tests are thread-safe regardless of the value of the
// death_test_style flag.
@@ -216,7 +221,7 @@ bool ExitedUnsuccessfully(int exit_status) {
return !ExitedWithCode(0)(exit_status);
}
-# if !GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA
// Generates a textual failure message when a death test finds more than
// one thread running, or cannot determine the number of threads, prior
// to executing the given statement. It is the responsibility of the
@@ -781,7 +786,178 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
set_spawned(true);
return OVERSEE_TEST;
}
-# else // We are not on Windows.
+
+# elif GTEST_OS_FUCHSIA
+
+class FuchsiaDeathTest : public DeathTestImpl {
+ public:
+ FuchsiaDeathTest(const char* a_statement,
+ const RE* a_regex,
+ const char* file,
+ int line)
+ : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+ virtual TestRole AssumeRole();
+
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+
+ zx_handle_t child_process_;
+ // zx_handle_t crash_port_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() {
+ args_.push_back(NULL);
+ }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+
+ private:
+ std::vector<char*> args_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int FuchsiaDeathTest::Wait() {
+ if (!spawned())
+ return 0;
+
+ ReadAndInterpretStatusByte();
+
+ // Wait for child process to terminate.
+ zx_status_t status_zx;
+ zx_signals_t signals;
+ status_zx = zx_object_wait_one(
+ child_process_,
+ ZX_PROCESS_TERMINATED,
+ ZX_TIME_INFINITE,
+ &signals);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ // Do we need this?
+ // // Attempt to read the crash port.
+ // zx_port_packet_t packet;
+ // status = zx_port_wait(crash_port_, past, &packet, 1)
+ // if (status == ZX_ERR_TIMED_OUT) {
+ // // Process did not crash.
+ // set_outcome(LIVED);
+ // return status();
+ // }
+
+ zx_info_process_t buffer;
+ size_t actual;
+ size_t avail;
+ status_zx = zx_object_get_info(child_process_, ZX_INFO_PROCESS, &buffer, sizeof(buffer), &actual, &avail);
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+
+ GTEST_DEATH_TEST_CHECK_(buffer.exited);
+ set_status(buffer.return_code);
+ return status();
+}
+
+// The AssumeRole process for a Fuchsia death test. It creates a child
+// process with the same executable as the current process to run the
+// death test. The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != NULL) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ // Create the crash port to report on.
+ // zx_status_t status = zx_port_create(0, &crash_port_);
+ // GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ CaptureStderr();
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // Build the child process launcher.
+ launchpad_t* lp;
+ zx_status_t status;
+ status = launchpad_create(ZX_HANDLE_INVALID, "processname", &lp);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Build the writing pipe for the child.
+ int write_fd;
+ status = launchpad_add_pipe(lp, &write_fd, read_fd());
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Build the child command line.
+ const std::string filter_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "="
+ + info->test_case_name() + "." + info->name();
+ const std::string internal_flag =
+ std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "="
+ + file_ + "|" + StreamableToString(line_) + "|"
+ + StreamableToString(death_test_index) + "|"
+ + StreamableToString(write_fd);
+ Arguments args;
+ args.AddArguments(GetInjectableArgvs());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ status = launchpad_load_from_file(lp, args.Argv()[0]);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ status = launchpad_set_args(lp, GetArgvs().size() + 2, args.Argv());
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ // Launch the child process.
+ zx_handle_t proc;
+ const char* errmsg;
+ status = launchpad_go(lp, &proc, &errmsg);
+ GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+ child_process_ = proc;
+
+ // bind the crash port. This should be moved to before launching the process.
+ // FIXME: I don't think this is necessary
+ // status = zx_task_bind_exception_port(child_process_, crash_port_, 0xabcabc, 0);
+ // GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
+
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+#else // We are neither on Windows, nor on Fuchsia.
// ForkingDeathTest provides implementations for most of the abstract
// methods of the DeathTest interface. Only the AssumeRole method is
@@ -1204,6 +1380,13 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
*test = new WindowsDeathTest(statement, regex, file, line);
}
+# elif GTEST_OS_FUCHSIA
+
+ if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+ GTEST_FLAG(death_test_style) == "fast") {
+ *test = new FuchsiaDeathTest(statement, regex, file, line);
+ }
+
# else
if (GTEST_FLAG(death_test_style) == "threadsafe") {
diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc
index d32afb1..d632089 100644
--- a/googletest/src/gtest-port.cc
+++ b/googletest/src/gtest-port.cc
@@ -63,6 +63,10 @@
# include <sys/types.h>
#endif // GTEST_OS_AIX
+#if GTEST_OS_FUCHSIA
+# include <zircon/syscalls.h>
+#endif
+
#include "gtest/gtest-spi.h"
#include "gtest/gtest-message.h"
#include "gtest/internal/gtest-internal.h"
@@ -156,6 +160,12 @@ size_t GetThreadCount() {
}
}
+#elif GTEST_OS_FUCHSIA
+
+size_t GetThreadCount() {
+ return static_cast<size_t>(zx_system_get_num_cpus());
+}
+
#else
size_t GetThreadCount() {