Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
yangql
googletest
Commits
b8a03c80
Commit
b8a03c80
authored
Oct 28, 2018
by
Jerry Turcios
Browse files
Merge branch 'master' of
https://github.com/google/googletest
parents
299d098d
2e308484
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
107 additions
and
51 deletions
+107
-51
googletest/src/gtest-death-test.cc
googletest/src/gtest-death-test.cc
+107
-51
No files found.
googletest/src/gtest-death-test.cc
View file @
b8a03c80
...
@@ -64,6 +64,10 @@
...
@@ -64,6 +64,10 @@
# if GTEST_OS_FUCHSIA
# if GTEST_OS_FUCHSIA
# include <lib/fdio/io.h>
# include <lib/fdio/io.h>
# include <lib/fdio/spawn.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/processargs.h>
# include <zircon/syscalls.h>
# include <zircon/syscalls.h>
# include <zircon/syscalls/port.h>
# include <zircon/syscalls/port.h>
...
@@ -422,6 +426,9 @@ class DeathTestImpl : public DeathTest {
...
@@ -422,6 +426,9 @@ class DeathTestImpl : public DeathTest {
// case of unexpected codes.
// case of unexpected codes.
void
ReadAndInterpretStatusByte
();
void
ReadAndInterpretStatusByte
();
// Returns stderr output from the child process.
virtual
std
::
string
GetErrorLogs
();
private:
private:
// The textual content of the code this object is testing. This class
// The textual content of the code this object is testing. This class
// doesn't own this string and should not attempt to delete it.
// doesn't own this string and should not attempt to delete it.
...
@@ -490,6 +497,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() {
...
@@ -490,6 +497,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() {
set_read_fd
(
-
1
);
set_read_fd
(
-
1
);
}
}
std
::
string
DeathTestImpl
::
GetErrorLogs
()
{
return
GetCapturedStderr
();
}
// Signals that the death test code which should have exited, didn't.
// Signals that the death test code which should have exited, didn't.
// Should be called only in a death test child process.
// Should be called only in a death test child process.
// Writes a status byte to the child's status file descriptor, then
// Writes a status byte to the child's status file descriptor, then
...
@@ -558,7 +569,7 @@ bool DeathTestImpl::Passed(bool status_ok) {
...
@@ -558,7 +569,7 @@ bool DeathTestImpl::Passed(bool status_ok) {
if
(
!
spawned
())
if
(
!
spawned
())
return
false
;
return
false
;
const
std
::
string
error_message
=
Get
CapturedStderr
();
const
std
::
string
error_message
=
Get
ErrorLogs
();
bool
success
=
false
;
bool
success
=
false
;
Message
buffer
;
Message
buffer
;
...
@@ -810,12 +821,6 @@ class FuchsiaDeathTest : public DeathTestImpl {
...
@@ -810,12 +821,6 @@ class FuchsiaDeathTest : public DeathTestImpl {
const
char
*
file
,
const
char
*
file
,
int
line
)
int
line
)
:
DeathTestImpl
(
a_statement
,
a_regex
),
file_
(
file
),
line_
(
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.
// All of these virtual functions are inherited from DeathTest.
virtual
int
Wait
();
virtual
int
Wait
();
...
@@ -826,9 +831,12 @@ class FuchsiaDeathTest : public DeathTestImpl {
...
@@ -826,9 +831,12 @@ class FuchsiaDeathTest : public DeathTestImpl {
const
char
*
const
file_
;
const
char
*
const
file_
;
// The line number on which the death test is located.
// The line number on which the death test is located.
const
int
line_
;
const
int
line_
;
// The stderr data captured by the child process.
std
::
string
captured_stderr_
;
zx_handle_t
child_process_
=
ZX_HANDLE_INVALID
;
zx
::
process
child_process_
;
zx_handle_t
port_
=
ZX_HANDLE_INVALID
;
zx
::
port
port_
;
zx
::
socket
stderr_socket_
;
};
};
// Utility class for accumulating command-line arguments.
// Utility class for accumulating command-line arguments.
...
@@ -872,51 +880,74 @@ class Arguments {
...
@@ -872,51 +880,74 @@ class Arguments {
// status, or 0 if no child process exists. As a side effect, sets the
// status, or 0 if no child process exists. As a side effect, sets the
// outcome data member.
// outcome data member.
int
FuchsiaDeathTest
::
Wait
()
{
int
FuchsiaDeathTest
::
Wait
()
{
const
int
kProcessKey
=
0
;
const
int
kSocketKey
=
1
;
if
(
!
spawned
())
if
(
!
spawned
())
return
0
;
return
0
;
// Register to wait for the child process to terminate.
// Register to wait for the child process to terminate.
zx_status_t
status_zx
;
zx_status_t
status_zx
;
status_zx
=
zx_object_wait_async
(
child_process_
,
status_zx
=
child_process_
.
wait_async
(
port_
,
port_
,
kProcessKey
,
ZX_PROCESS_TERMINATED
,
ZX_WAIT_ASYNC_ONCE
);
0
/* key */
,
ZX_PROCESS_TERMINATED
,
ZX_WAIT_ASYNC_ONCE
);
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
// Register to wait for the socket to be readable or closed.
// Wait for it to terminate, or an exception to be received.
status_zx
=
stderr_socket_
.
wait_async
(
zx_
port_
packet_t
packet
;
port_
,
kSocketKey
,
ZX_SOCKET_READABLE
|
ZX_SOCKET_PEER_CLOSED
,
status_zx
=
zx_port_wait
(
port_
,
ZX_TIME_INFINITE
,
&
packet
);
ZX_WAIT_ASYNC_REPEATING
);
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
if
(
ZX_PKT_IS_EXCEPTION
(
packet
.
type
))
{
bool
process_terminated
=
false
;
// Process encountered an exception. Kill it directly rather than letting
bool
socket_closed
=
false
;
// other handlers process the event.
do
{
status_zx
=
zx_task_kill
(
child_process_
);
zx_port_packet_t
packet
=
{};
status_zx
=
port_
.
wait
(
zx
::
time
::
infinite
(),
&
packet
);
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
// Now wait for |child_process_| to terminate.
if
(
packet
.
key
==
kProcessKey
)
{
zx_signals_t
signals
=
0
;
if
(
ZX_PKT_IS_EXCEPTION
(
packet
.
type
))
{
status_zx
=
zx_object_wait_one
(
// Process encountered an exception. Kill it directly rather than
child_process_
,
ZX_PROCESS_TERMINATED
,
ZX_TIME_INFINITE
,
&
signals
);
// letting other handlers process the event. We will get a second
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
// kProcessKey event when the process actually terminates.
GTEST_DEATH_TEST_CHECK_
(
signals
&
ZX_PROCESS_TERMINATED
);
status_zx
=
child_process_
.
kill
();
}
else
{
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
// Process terminated.
}
else
{
GTEST_DEATH_TEST_CHECK_
(
ZX_PKT_IS_SIGNAL_ONE
(
packet
.
type
));
// Process terminated.
GTEST_DEATH_TEST_CHECK_
(
packet
.
signal
.
observed
&
ZX_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
();
ReadAndInterpretStatusByte
();
zx_info_process_t
buffer
;
zx_info_process_t
buffer
;
status_zx
=
zx_object_get_info
(
status_zx
=
child_process_
.
get_info
(
child_process_
,
ZX_INFO_PROCESS
,
&
buffer
,
sizeof
(
buffer
),
nullptr
,
nullptr
);
ZX_INFO_PROCESS
,
&
buffer
,
sizeof
(
buffer
),
nullptr
,
nullptr
);
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
GTEST_DEATH_TEST_CHECK_
(
status_zx
==
ZX_OK
);
GTEST_DEATH_TEST_CHECK_
(
buffer
.
exited
);
GTEST_DEATH_TEST_CHECK_
(
buffer
.
exited
);
...
@@ -943,7 +974,6 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
...
@@ -943,7 +974,6 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
return
EXECUTE_TEST
;
return
EXECUTE_TEST
;
}
}
CaptureStderr
();
// Flush the log buffers since the log streams are shared with the child.
// Flush the log buffers since the log streams are shared with the child.
FlushInfoLog
();
FlushInfoLog
();
...
@@ -970,29 +1000,55 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
...
@@ -970,29 +1000,55 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() {
set_read_fd
(
status
);
set_read_fd
(
status
);
// Set the pipe handle for the child.
// Set the pipe handle for the child.
fdio_spawn_action_t
add_handle_action
=
{};
fdio_spawn_action_t
spawn_actions
[
2
]
=
{};
add_handle_action
.
action
=
FDIO_SPAWN_ACTION_ADD_HANDLE
;
fdio_spawn_action_t
*
add_handle_action
=
&
spawn_actions
[
0
];
add_handle_action
.
h
.
id
=
PA_HND
(
type
,
kFuchsiaReadPipeFd
);
add_handle_action
->
action
=
FDIO_SPAWN_ACTION_ADD_HANDLE
;
add_handle_action
.
h
.
handle
=
child_pipe_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.
// Spawn the child process.
status
=
fdio_spawn_etc
(
ZX_HANDLE_INVALID
,
FDIO_SPAWN_CLONE_ALL
,
status
=
fdio_spawn_etc
(
args
.
Argv
()[
0
],
args
.
Argv
(),
nullptr
,
1
,
ZX_HANDLE_INVALID
,
FDIO_SPAWN_CLONE_ALL
,
args
.
Argv
()[
0
],
args
.
Argv
(),
&
add_handle_action
,
&
child_process_
,
nullptr
);
nullptr
,
2
,
spawn_actions
,
child_process_
.
reset_and_get_address
(),
nullptr
);
GTEST_DEATH_TEST_CHECK_
(
status
==
ZX_OK
);
GTEST_DEATH_TEST_CHECK_
(
status
==
ZX_OK
);
// Create an exception port and attach it to the |child_process_|, to allow
// Create an exception port and attach it to the |child_process_|, to allow
// us to suppress the system default exception handler from firing.
// 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
);
GTEST_DEATH_TEST_CHECK_
(
status
==
ZX_OK
);
status
=
zx_task_
bind_exception_port
(
status
=
child_process_
.
bind_exception_port
(
child_process_
,
port_
,
0
/* key */
,
0
/*options */
);
port_
,
0
/* key */
,
0
/*options */
);
GTEST_DEATH_TEST_CHECK_
(
status
==
ZX_OK
);
GTEST_DEATH_TEST_CHECK_
(
status
==
ZX_OK
);
set_spawned
(
true
);
set_spawned
(
true
);
return
OVERSEE_TEST
;
return
OVERSEE_TEST
;
}
}
std
::
string
FuchsiaDeathTest
::
GetErrorLogs
()
{
return
captured_stderr_
;
}
#else // We are neither on Windows, nor on Fuchsia.
#else // We are neither on Windows, nor on Fuchsia.
// ForkingDeathTest provides implementations for most of the abstract
// ForkingDeathTest provides implementations for most of the abstract
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment