aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJerry Turcios <jerryturcios08@gmail.com>2018-10-28 14:17:19 -0400
committerJerry Turcios <jerryturcios08@gmail.com>2018-10-28 14:17:19 -0400
commitb8a03c80ad59a4735f852ab13725f2d14ead424f (patch)
tree8eec625e4179a579ff4af3dde21ca16fac023684
parent299d098daa16533a11cd9070d170d3d95c0793f5 (diff)
parent2e308484d9693f8251748c295f6ed7ed25d767eb (diff)
downloadgoogletest-b8a03c80ad59a4735f852ab13725f2d14ead424f.tar.gz
googletest-b8a03c80ad59a4735f852ab13725f2d14ead424f.tar.bz2
googletest-b8a03c80ad59a4735f852ab13725f2d14ead424f.zip
Merge branch 'master' of https://github.com/google/googletest
-rw-r--r--googletest/src/gtest-death-test.cc158
1 files changed, 107 insertions, 51 deletions
diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc
index b3a572a1..2c15fdcc 100644
--- a/googletest/src/gtest-death-test.cc
+++ b/googletest/src/gtest-death-test.cc
@@ -64,6 +64,10 @@
# if GTEST_OS_FUCHSIA
# include <lib/fdio/io.h>
# include <lib/fdio/spawn.h>
+# include <lib/fdio/util.h>
+# include <lib/zx/socket.h>
+# include <lib/zx/port.h>
+# include <lib/zx/process.h>
# include <zircon/processargs.h>
# include <zircon/syscalls.h>
# include <zircon/syscalls/port.h>
@@ -422,6 +426,9 @@ class DeathTestImpl : public DeathTest {
// case of unexpected codes.
void ReadAndInterpretStatusByte();
+ // Returns stderr output from the child process.
+ virtual std::string GetErrorLogs();
+
private:
// The textual content of the code this object is testing. This class
// doesn't own this string and should not attempt to delete it.
@@ -490,6 +497,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() {
set_read_fd(-1);
}
+std::string DeathTestImpl::GetErrorLogs() {
+ return GetCapturedStderr();
+}
+
// Signals that the death test code which should have exited, didn't.
// Should be called only in a death test child process.
// Writes a status byte to the child's status file descriptor, then
@@ -558,7 +569,7 @@ bool DeathTestImpl::Passed(bool status_ok) {
if (!spawned())
return false;
- const std::string error_message = GetCapturedStderr();
+ const std::string error_message = GetErrorLogs();
bool success = false;
Message buffer;
@@ -810,12 +821,6 @@ class FuchsiaDeathTest : public DeathTestImpl {
const char* file,
int line)
: DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {}
- virtual ~FuchsiaDeathTest() {
- zx_status_t status = zx_handle_close(child_process_);
- GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
- status = zx_handle_close(port_);
- GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
- }
// All of these virtual functions are inherited from DeathTest.
virtual int Wait();
@@ -826,9 +831,12 @@ class FuchsiaDeathTest : public DeathTestImpl {
const char* const file_;
// The line number on which the death test is located.
const int line_;
+ // The stderr data captured by the child process.
+ std::string captured_stderr_;
- zx_handle_t child_process_ = ZX_HANDLE_INVALID;
- zx_handle_t port_ = ZX_HANDLE_INVALID;
+ zx::process child_process_;
+ zx::port port_;
+ zx::socket stderr_socket_;
};
// Utility class for accumulating command-line arguments.
@@ -872,51 +880,74 @@ class Arguments {
// status, or 0 if no child process exists. As a side effect, sets the
// outcome data member.
int FuchsiaDeathTest::Wait() {
+ const int kProcessKey = 0;
+ const int kSocketKey = 1;
+
if (!spawned())
return 0;
// Register to wait for the child process to terminate.
zx_status_t status_zx;
- status_zx = zx_object_wait_async(child_process_,
- port_,
- 0 /* key */,
- ZX_PROCESS_TERMINATED,
- ZX_WAIT_ASYNC_ONCE);
+ status_zx = child_process_.wait_async(
+ port_, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE);
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
-
- // Wait for it to terminate, or an exception to be received.
- zx_port_packet_t packet;
- status_zx = zx_port_wait(port_, ZX_TIME_INFINITE, &packet);
+ // Register to wait for the socket to be readable or closed.
+ status_zx = stderr_socket_.wait_async(
+ port_, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED,
+ ZX_WAIT_ASYNC_REPEATING);
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
- if (ZX_PKT_IS_EXCEPTION(packet.type)) {
- // Process encountered an exception. Kill it directly rather than letting
- // other handlers process the event.
- status_zx = zx_task_kill(child_process_);
+ bool process_terminated = false;
+ bool socket_closed = false;
+ do {
+ zx_port_packet_t packet = {};
+ status_zx = port_.wait(zx::time::infinite(), &packet);
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
- // Now wait for |child_process_| to terminate.
- zx_signals_t signals = 0;
- status_zx = zx_object_wait_one(
- child_process_, ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE, &signals);
- GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
- GTEST_DEATH_TEST_CHECK_(signals & ZX_PROCESS_TERMINATED);
- } else {
- // Process terminated.
- GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
- GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED);
- }
+ if (packet.key == kProcessKey) {
+ if (ZX_PKT_IS_EXCEPTION(packet.type)) {
+ // Process encountered an exception. Kill it directly rather than
+ // letting other handlers process the event. We will get a second
+ // kProcessKey event when the process actually terminates.
+ status_zx = child_process_.kill();
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
+ } else {
+ // Process terminated.
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type));
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED);
+ process_terminated = true;
+ }
+ } else if (packet.key == kSocketKey) {
+ GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_REP(packet.type));
+ if (packet.signal.observed & ZX_SOCKET_READABLE) {
+ // Read data from the socket.
+ constexpr size_t kBufferSize = 1024;
+ do {
+ size_t old_length = captured_stderr_.length();
+ size_t bytes_read = 0;
+ captured_stderr_.resize(old_length + kBufferSize);
+ status_zx = stderr_socket_.read(
+ 0, &captured_stderr_.front() + old_length, kBufferSize,
+ &bytes_read);
+ captured_stderr_.resize(old_length + bytes_read);
+ } while (status_zx == ZX_OK);
+ if (status_zx == ZX_ERR_PEER_CLOSED) {
+ socket_closed = true;
+ } else {
+ GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT);
+ }
+ } else {
+ GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED);
+ socket_closed = true;
+ }
+ }
+ } while (!process_terminated && !socket_closed);
ReadAndInterpretStatusByte();
zx_info_process_t buffer;
- status_zx = zx_object_get_info(
- child_process_,
- ZX_INFO_PROCESS,
- &buffer,
- sizeof(buffer),
- nullptr,
- nullptr);
+ status_zx = child_process_.get_info(
+ ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr);
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK);
GTEST_DEATH_TEST_CHECK_(buffer.exited);
@@ -943,7 +974,6 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
return EXECUTE_TEST;
}
- CaptureStderr();
// Flush the log buffers since the log streams are shared with the child.
FlushInfoLog();
@@ -970,29 +1000,55 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
set_read_fd(status);
// Set the pipe handle for the child.
- fdio_spawn_action_t add_handle_action = {};
- add_handle_action.action = FDIO_SPAWN_ACTION_ADD_HANDLE;
- add_handle_action.h.id = PA_HND(type, kFuchsiaReadPipeFd);
- add_handle_action.h.handle = child_pipe_handle;
+ fdio_spawn_action_t spawn_actions[2] = {};
+ fdio_spawn_action_t* add_handle_action = &spawn_actions[0];
+ add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
+ add_handle_action->h.id = PA_HND(type, kFuchsiaReadPipeFd);
+ add_handle_action->h.handle = child_pipe_handle;
+
+ // Create a socket pair will be used to receive the child process' stderr.
+ zx::socket stderr_producer_socket;
+ status =
+ zx::socket::create(0, &stderr_producer_socket, &stderr_socket_);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+ int stderr_producer_fd = -1;
+ zx_handle_t producer_handle[1] = { stderr_producer_socket.release() };
+ uint32_t producer_handle_type[1] = { PA_FDIO_SOCKET };
+ status = fdio_create_fd(
+ producer_handle, producer_handle_type, 1, &stderr_producer_fd);
+ GTEST_DEATH_TEST_CHECK_(status >= 0);
+
+ // Make the stderr socket nonblocking.
+ GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0);
+
+ fdio_spawn_action_t* add_stderr_action = &spawn_actions[1];
+ add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD;
+ add_stderr_action->fd.local_fd = stderr_producer_fd;
+ add_stderr_action->fd.target_fd = STDERR_FILENO;
// Spawn the child process.
- status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL,
- args.Argv()[0], args.Argv(), nullptr, 1,
- &add_handle_action, &child_process_, nullptr);
+ status = fdio_spawn_etc(
+ ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(),
+ nullptr, 2, spawn_actions, child_process_.reset_and_get_address(),
+ nullptr);
GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
// Create an exception port and attach it to the |child_process_|, to allow
// us to suppress the system default exception handler from firing.
- status = zx_port_create(0, &port_);
+ status = zx::port::create(0, &port_);
GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
- status = zx_task_bind_exception_port(
- child_process_, port_, 0 /* key */, 0 /*options */);
+ status = child_process_.bind_exception_port(
+ port_, 0 /* key */, 0 /*options */);
GTEST_DEATH_TEST_CHECK_(status == ZX_OK);
set_spawned(true);
return OVERSEE_TEST;
}
+std::string FuchsiaDeathTest::GetErrorLogs() {
+ return captured_stderr_;
+}
+
#else // We are neither on Windows, nor on Fuchsia.
// ForkingDeathTest provides implementations for most of the abstract