This commit is contained in:
David Matson 2025-02-17 11:40:58 -08:00 committed by GitHub
commit a7585f5bfe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 152 additions and 27 deletions

View File

@ -14,6 +14,7 @@ Chris Taylor <taylorc@google.com>
Dan Egnor <egnor@google.com> Dan Egnor <egnor@google.com>
Dave MacLachlan <dmaclach@gmail.com> Dave MacLachlan <dmaclach@gmail.com>
David Anderson <danderson@google.com> David Anderson <danderson@google.com>
David Matson
Dean Sturtevant Dean Sturtevant
Eric Roman <eroman@chromium.org> Eric Roman <eroman@chromium.org>
Gene Volovich <gv@cite.com> Gene Volovich <gv@cite.com>

View File

@ -707,7 +707,8 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
#if defined(GTEST_OS_LINUX) || defined(GTEST_OS_GNU_KFREEBSD) || \ #if defined(GTEST_OS_LINUX) || defined(GTEST_OS_GNU_KFREEBSD) || \
defined(GTEST_OS_DRAGONFLY) || defined(GTEST_OS_FREEBSD) || \ defined(GTEST_OS_DRAGONFLY) || defined(GTEST_OS_FREEBSD) || \
defined(GTEST_OS_NETBSD) || defined(GTEST_OS_OPENBSD) || \ defined(GTEST_OS_NETBSD) || defined(GTEST_OS_OPENBSD) || \
defined(GTEST_OS_GNU_HURD) || defined(GTEST_OS_MAC) defined(GTEST_OS_GNU_HURD) || defined(GTEST_OS_MAC) || \
defined(GTEST_OS_WINDOWS)
#define GTEST_CAN_STREAM_RESULTS_ 1 #define GTEST_CAN_STREAM_RESULTS_ 1
#else #else
#define GTEST_CAN_STREAM_RESULTS_ 0 #define GTEST_CAN_STREAM_RESULTS_ 0
@ -945,6 +946,18 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
#define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ #define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
#endif #endif
#if GTEST_CAN_STREAM_RESULTS_
#if GTEST_OS_WINDOWS
#define NOMINMAX
#include <WinSock2.h> // NOLINT
#else // GTEST_OS_WINDOWS
#include <arpa/inet.h> // NOLINT
#include <netdb.h> // NOLINT
#endif // GTEST_OS_WINDOWS
#endif // GTEST_CAN_STREAM_RESULTS_
namespace testing { namespace testing {
class Message; class Message;
@ -2195,6 +2208,27 @@ GTEST_DISABLE_MSC_DEPRECATED_POP_()
[[noreturn]] inline void Abort() { abort(); } [[noreturn]] inline void Abort() { abort(); }
#endif // GTEST_OS_WINDOWS_MOBILE #endif // GTEST_OS_WINDOWS_MOBILE
// Sockets porting.
#if GTEST_CAN_STREAM_RESULTS_
int SocketStartup();
int Socket(int domain, int type, int protocol);
int GetAddrInfo(const char* nodename,
const char* servname,
const struct addrinfo* hints,
struct addrinfo** res);
void FreeAddrInfo(struct addrinfo* ai);
int Connect(int sockfd, const struct sockaddr* addr, size_t addrlen);
const char* GaiStrError(int errcode);
#endif // GTEST_CAN_STREAM_RESULTS_
} // namespace posix } // namespace posix
// MSVC "deprecates" snprintf and issues warnings wherever it is used. In // MSVC "deprecates" snprintf and issues warnings wherever it is used. In

View File

@ -51,11 +51,6 @@
#include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-port.h"
#if GTEST_CAN_STREAM_RESULTS_
#include <arpa/inet.h> // NOLINT
#include <netdb.h> // NOLINT
#endif
#ifdef GTEST_OS_WINDOWS #ifdef GTEST_OS_WINDOWS
#include <windows.h> // NOLINT #include <windows.h> // NOLINT
#endif // GTEST_OS_WINDOWS #endif // GTEST_OS_WINDOWS
@ -1071,7 +1066,7 @@ class TestResultAccessor {
#if GTEST_CAN_STREAM_RESULTS_ #if GTEST_CAN_STREAM_RESULTS_
// Streams test results to the given port on the given host machine. // Streams test results to the given port on the given host machine.
class StreamingListener : public EmptyTestEventListener { class GTEST_API_ StreamingListener : public EmptyTestEventListener {
public: public:
// Abstract base class for writing strings to a socket. // Abstract base class for writing strings to a socket.
class AbstractSocketWriter { class AbstractSocketWriter {
@ -1105,8 +1100,9 @@ class StreamingListener : public EmptyTestEventListener {
GTEST_CHECK_(sockfd_ != -1) GTEST_CHECK_(sockfd_ != -1)
<< "Send() can be called only when there is a connection."; << "Send() can be called only when there is a connection.";
const auto len = static_cast<size_t>(message.length()); const auto len = static_cast<unsigned int>(message.length());
if (write(sockfd_, message.c_str(), len) != static_cast<ssize_t>(len)) { if (posix::Write(sockfd_, message.c_str(), len) !=
static_cast<int>(len)) {
GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to "
<< host_name_ << ":" << port_num_; << host_name_ << ":" << port_num_;
} }
@ -1121,7 +1117,7 @@ class StreamingListener : public EmptyTestEventListener {
GTEST_CHECK_(sockfd_ != -1) GTEST_CHECK_(sockfd_ != -1)
<< "CloseConnection() can be called only when there is a connection."; << "CloseConnection() can be called only when there is a connection.";
close(sockfd_); posix::Close(sockfd_);
sockfd_ = -1; sockfd_ = -1;
} }

View File

@ -1430,5 +1430,98 @@ const char* StringFromGTestEnv(const char* flag, const char* default_value) {
#endif // defined(GTEST_GET_STRING_FROM_ENV_) #endif // defined(GTEST_GET_STRING_FROM_ENV_)
} }
#if GTEST_CAN_STREAM_RESULTS_
namespace posix {
#if GTEST_OS_WINDOWS
#include <WinSock2.h> // NOLINT
#include <ws2tcpip.h> // NOLINT
#pragma comment(lib, "Ws2_32.lib")
int SocketStartup() {
WSADATA winsockVersion{};
int startupError{ WSAStartup(MAKEWORD(2, 2), &winsockVersion) };
if (startupError)
{
return startupError;
}
if (LOBYTE(winsockVersion.wVersion) != 2 ||
HIBYTE(winsockVersion.wVersion) != 2)
{
return -1;
}
return 0;
}
int Socket(int domain, int type, int protocol)
{
return static_cast<int>(socket(domain, type, protocol));
}
int GetAddrInfo(const char* nodename,
const char* servname,
const struct addrinfo* hints,
struct addrinfo** res)
{
return getaddrinfo(nodename, servname, hints, res);
}
void FreeAddrInfo(struct addrinfo* ai)
{
freeaddrinfo(ai);
}
int Connect(int sockfd, const struct sockaddr* addr, size_t addrlen)
{
return connect(sockfd, addr, static_cast<int>(addrlen));
}
const char* GaiStrError(int errcode)
{
return gai_strerrorA(errcode);
}
#else // GTEST_OS_WINDOWS
#include <arpa/inet.h> // NOLINT
#include <netdb.h> // NOLINT
#include <sys/socket.h> // NOLINT
#include <sys/types.h> // NOLINT
int SocketStartup() {
return 0;
}
int Socket(int domain, int type, int protocol) {
return socket(domain, type, protocol);
}
int GetAddrInfo(const char* nodename,
const char* servname,
const struct addrinfo* hints,
struct addrinfo** res) {
return getaddrinfo(nodename, servname, hints, res);
}
void FreeAddrInfo(struct addrinfo* ai) { freeaddrinfo(ai); }
int Connect(int sockfd, const struct sockaddr* addr, size_t addrlen) {
return connect(sockfd, addr, static_cast<socklen_t>(addrlen));
}
const char* GaiStrError(int errcode) { return gai_strerror(errcode); }
#endif // GTEST_OS_WINDOWS
} // namespace posix
#endif // GTEST_CAN_STREAM_RESULTS_
} // namespace internal } // namespace internal
} // namespace testing } // namespace testing

View File

@ -122,13 +122,6 @@
#include <stdexcept> #include <stdexcept>
#endif #endif
#if GTEST_CAN_STREAM_RESULTS_
#include <arpa/inet.h> // NOLINT
#include <netdb.h> // NOLINT
#include <sys/socket.h> // NOLINT
#include <sys/types.h> // NOLINT
#endif
#include "src/gtest-internal-inl.h" #include "src/gtest-internal-inl.h"
#ifdef GTEST_OS_WINDOWS #ifdef GTEST_OS_WINDOWS
@ -379,7 +372,7 @@ GTEST_DEFINE_string_(
testing::internal::StringFromGTestEnv("stream_result_to", ""), testing::internal::StringFromGTestEnv("stream_result_to", ""),
"This flag specifies the host name and the port number on which to stream " "This flag specifies the host name and the port number on which to stream "
"test results. Example: \"localhost:555\". The flag is effective only on " "test results. Example: \"localhost:555\". The flag is effective only on "
"Linux and macOS."); "Linux, macOS, and Windows.");
GTEST_DEFINE_bool_( GTEST_DEFINE_bool_(
throw_on_failure, throw_on_failure,
@ -5006,6 +4999,11 @@ void StreamingListener::SocketWriter::MakeConnection() {
GTEST_CHECK_(sockfd_ == -1) GTEST_CHECK_(sockfd_ == -1)
<< "MakeConnection() can't be called when there is already a connection."; << "MakeConnection() can't be called when there is already a connection.";
if (!posix::SocketStartup()) {
GTEST_LOG_(WARNING) << "Socket startup failed.";
return;
}
addrinfo hints; addrinfo hints;
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses.
@ -5014,28 +5012,31 @@ void StreamingListener::SocketWriter::MakeConnection() {
// Use the getaddrinfo() to get a linked list of IP addresses for // Use the getaddrinfo() to get a linked list of IP addresses for
// the given host name. // the given host name.
const int error_num = const int error_num = posix::GetAddrInfo(host_name_.c_str(),
getaddrinfo(host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); port_num_.c_str(),
&hints,
&servinfo);
if (error_num != 0) { if (error_num != 0) {
GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: "
<< gai_strerror(error_num); << posix::GaiStrError(error_num);
} }
// Loop through all the results and connect to the first we can. // Loop through all the results and connect to the first we can.
for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr; for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != nullptr;
cur_addr = cur_addr->ai_next) { cur_addr = cur_addr->ai_next) {
sockfd_ = socket(cur_addr->ai_family, cur_addr->ai_socktype, sockfd_ = posix::Socket(cur_addr->ai_family, cur_addr->ai_socktype,
cur_addr->ai_protocol); cur_addr->ai_protocol);
if (sockfd_ != -1) { if (sockfd_ != -1) {
// Connect the client socket to the server socket. // Connect the client socket to the server socket.
if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { if (posix::Connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) ==
close(sockfd_); -1) {
posix::Close(sockfd_);
sockfd_ = -1; sockfd_ = -1;
} }
} }
} }
freeaddrinfo(servinfo); // all done with this structure posix::FreeAddrInfo(servinfo); // all done with this structure
if (sockfd_ == -1) { if (sockfd_ == -1) {
GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to "

View File

@ -144,7 +144,7 @@ class GTestHelpTest(gtest_test_utils.TestCase):
self.assertTrue(HELP_REGEX.search(output), output) self.assertTrue(HELP_REGEX.search(output), output)
if IS_DARWIN or IS_LINUX or IS_GNUHURD or is_bsd_based_os(): if IS_DARWIN or IS_LINUX or IS_GNUHURD or is_bsd_based_os() or IS_WINDOWS:
self.assertIn(STREAM_RESULT_TO_FLAG, output) self.assertIn(STREAM_RESULT_TO_FLAG, output)
else: else:
self.assertNotIn(STREAM_RESULT_TO_FLAG, output) self.assertNotIn(STREAM_RESULT_TO_FLAG, output)