summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/advanced.md52
-rw-r--r--googlemock/test/gmock-internal-utils_test.cc6
-rw-r--r--googletest/include/gtest/gtest.h6
-rw-r--r--googletest/include/gtest/internal/gtest-port.h120
-rw-r--r--googletest/src/gtest-port.cc21
-rw-r--r--googletest/src/gtest.cc13
-rw-r--r--googletest/test/googletest-port-test.cc12
-rwxr-xr-xgoogletest/test/gtest_test_utils.py81
8 files changed, 127 insertions, 184 deletions
diff --git a/docs/advanced.md b/docs/advanced.md
index c71ba413..b18be2dc 100644
--- a/docs/advanced.md
+++ b/docs/advanced.md
@@ -1919,6 +1919,58 @@ time.
If you combine this with `--gtest_repeat=N`, googletest will pick a different
random seed and re-shuffle the tests in each iteration.
+### Distributing Test Functions to Multiple Machines
+
+If you have more than one machine you can use to run a test program, you might
+want to run the test functions in parallel and get the result faster. We call
+this technique *sharding*, where each machine is called a *shard*.
+
+GoogleTest is compatible with test sharding. To take advantage of this feature,
+your test runner (not part of GoogleTest) needs to do the following:
+
+1. Allocate a number of machines (shards) to run the tests.
+1. On each shard, set the `GTEST_TOTAL_SHARDS` environment variable to the total
+ number of shards. It must be the same for all shards.
+1. On each shard, set the `GTEST_SHARD_INDEX` environment variable to the index
+ of the shard. Different shards must be assigned different indices, which
+ must be in the range `[0, GTEST_TOTAL_SHARDS - 1]`.
+1. Run the same test program on all shards. When GoogleTest sees the above two
+ environment variables, it will select a subset of the test functions to run.
+ Across all shards, each test function in the program will be run exactly
+ once.
+1. Wait for all shards to finish, then collect and report the results.
+
+Your project may have tests that were written without GoogleTest and thus don't
+understand this protocol. In order for your test runner to figure out which test
+supports sharding, it can set the environment variable `GTEST_SHARD_STATUS_FILE`
+to a non-existent file path. If a test program supports sharding, it will create
+this file to acknowledge that fact; otherwise it will not create it. The actual
+contents of the file are not important at this time, although we may put some
+useful information in it in the future.
+
+Here's an example to make it clear. Suppose you have a test program `foo_test`
+that contains the following 5 test functions:
+
+```
+TEST(A, V)
+TEST(A, W)
+TEST(B, X)
+TEST(B, Y)
+TEST(B, Z)
+```
+
+Suppose you have 3 machines at your disposal. To run the test functions in
+parallel, you would set `GTEST_TOTAL_SHARDS` to 3 on all machines, and set
+`GTEST_SHARD_INDEX` to 0, 1, and 2 on the machines respectively. Then you would
+run the same `foo_test` on each machine.
+
+GoogleTest reserves the right to change how the work is distributed across the
+shards, but here's one possible scenario:
+
+* Machine #0 runs `A.V` and `B.X`.
+* Machine #1 runs `A.W` and `B.Y`.
+* Machine #2 runs `B.Z`.
+
### Controlling Test Output
#### Colored Terminal Output
diff --git a/googlemock/test/gmock-internal-utils_test.cc b/googlemock/test/gmock-internal-utils_test.cc
index 8722418e..fbb6a83d 100644
--- a/googlemock/test/gmock-internal-utils_test.cc
+++ b/googlemock/test/gmock-internal-utils_test.cc
@@ -394,7 +394,7 @@ TEST_F(LogIsVisibleTest, WorksWhenVerbosityIsWarning) {
// and log severity.
void TestLogWithSeverity(const std::string& verbosity, LogSeverity severity,
bool should_print) {
- const std::string old_flag = GMOCK_FLAG(verbose);
+ const std::string old_flag = GMOCK_FLAG_GET(verbose);
GMOCK_FLAG_SET(verbose, verbosity);
CaptureStdout();
Log(severity, "Test log.\n", 0);
@@ -413,7 +413,7 @@ void TestLogWithSeverity(const std::string& verbosity, LogSeverity severity,
// Tests that when the stack_frames_to_skip parameter is negative,
// Log() doesn't include the stack trace in the output.
TEST(LogTest, NoStackTraceWhenStackFramesToSkipIsNegative) {
- const std::string saved_flag = GMOCK_FLAG(verbose);
+ const std::string saved_flag = GMOCK_FLAG_GET(verbose);
GMOCK_FLAG_SET(verbose, kInfoVerbosity);
CaptureStdout();
Log(kInfo, "Test log.\n", -1);
@@ -499,7 +499,7 @@ TEST(LogTest, OnlyWarningsArePrintedWhenVerbosityIsInvalid) {
// Verifies that Log() behaves correctly for the given verbosity level
// and log severity.
std::string GrabOutput(void(*logger)(), const char* verbosity) {
- const std::string saved_flag = GMOCK_FLAG(verbose);
+ const std::string saved_flag = GMOCK_FLAG_GET(verbose);
GMOCK_FLAG_SET(verbose, verbosity);
CaptureStdout();
logger();
diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h
index fe9b4332..db4c6203 100644
--- a/googletest/include/gtest/gtest.h
+++ b/googletest/include/gtest/gtest.h
@@ -1123,8 +1123,8 @@ class TestEventListener {
// Fired before the test starts.
virtual void OnTestStart(const TestInfo& test_info) = 0;
- // Fired when skipping a test
- virtual void OnTestSkipped(const TestInfo& test_info) = 0;
+ // Fired when a test is disabled
+ virtual void OnTestDisabled(const TestInfo& test_info) {}
// Fired after a failed assertion or a SUCCEED() invocation.
// If you want to throw an exception from this function to skip to the next
@@ -1175,7 +1175,7 @@ class EmptyTestEventListener : public TestEventListener {
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
void OnTestStart(const TestInfo& /*test_info*/) override {}
- void OnTestSkipped(const TestInfo& /*test_info*/) override {}
+ void OnTestDisabled(const TestInfo& /*test_info*/) override {}
void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {}
void OnTestEnd(const TestInfo& /*test_info*/) override {}
void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {}
diff --git a/googletest/include/gtest/internal/gtest-port.h b/googletest/include/gtest/internal/gtest-port.h
index d3eab57b..cc6fa6b3 100644
--- a/googletest/include/gtest/internal/gtest-port.h
+++ b/googletest/include/gtest/internal/gtest-port.h
@@ -260,9 +260,17 @@
#include <string.h>
#include <cerrno>
+// #include <condition_variable> // Guarded by GTEST_IS_THREADSAFE below
#include <cstdint>
+#include <iostream>
#include <limits>
+#include <locale>
+#include <memory>
+#include <string>
+// #include <mutex> // Guarded by GTEST_IS_THREADSAFE below
+#include <tuple>
#include <type_traits>
+#include <vector>
#ifndef _WIN32_WCE
# include <sys/types.h>
@@ -274,13 +282,6 @@
# include <TargetConditionals.h>
#endif
-#include <iostream> // NOLINT
-#include <locale>
-#include <memory>
-#include <string> // NOLINT
-#include <tuple>
-#include <vector> // NOLINT
-
#include "gtest/internal/custom/gtest-port.h"
#include "gtest/internal/gtest-port-arch.h"
@@ -757,6 +758,12 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
#endif // GTEST_IS_THREADSAFE
+#if GTEST_IS_THREADSAFE
+// Some platforms don't support including these threading related headers.
+#include <condition_variable> // NOLINT
+#include <mutex> // NOLINT
+#endif // GTEST_IS_THREADSAFE
+
// GTEST_API_ qualifies all symbols that must be exported. The definitions below
// are guarded by #ifndef to give embedders a chance to define GTEST_API_ in
// gtest/internal/custom/gtest-port.h
@@ -1161,71 +1168,8 @@ void ClearInjectableArgvs();
// Defines synchronization primitives.
#if GTEST_IS_THREADSAFE
-# if GTEST_HAS_PTHREAD
-// Sleeps for (roughly) n milliseconds. This function is only for testing
-// Google Test's own constructs. Don't use it in user tests, either
-// directly or indirectly.
-inline void SleepMilliseconds(int n) {
- const timespec time = {
- 0, // 0 seconds.
- n * 1000L * 1000L, // And n ms.
- };
- nanosleep(&time, nullptr);
-}
-# endif // GTEST_HAS_PTHREAD
-
-# if GTEST_HAS_NOTIFICATION_
-// Notification has already been imported into the namespace.
-// Nothing to do here.
-
-# elif GTEST_HAS_PTHREAD
-// Allows a controller thread to pause execution of newly created
-// threads until notified. Instances of this class must be created
-// and destroyed in the controller thread.
-//
-// This class is only for testing Google Test's own constructs. Do not
-// use it in user tests, either directly or indirectly.
-class Notification {
- public:
- Notification() : notified_(false) {
- GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, nullptr));
- }
- ~Notification() {
- pthread_mutex_destroy(&mutex_);
- }
-
- // Notifies all threads created with this notification to start. Must
- // be called from the controller thread.
- void Notify() {
- pthread_mutex_lock(&mutex_);
- notified_ = true;
- pthread_mutex_unlock(&mutex_);
- }
-
- // Blocks until the controller thread notifies. Must be called from a test
- // thread.
- void WaitForNotification() {
- for (;;) {
- pthread_mutex_lock(&mutex_);
- const bool notified = notified_;
- pthread_mutex_unlock(&mutex_);
- if (notified)
- break;
- SleepMilliseconds(10);
- }
- }
-
- private:
- pthread_mutex_t mutex_;
- bool notified_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
-};
-
-# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
-
-GTEST_API_ void SleepMilliseconds(int n);
+# if GTEST_OS_WINDOWS
// Provides leak-safe Windows kernel handle ownership.
// Used in death tests and in threading support.
class GTEST_API_ AutoHandle {
@@ -1254,23 +1198,45 @@ class GTEST_API_ AutoHandle {
GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
};
+# endif
+# if GTEST_HAS_NOTIFICATION_
+// Notification has already been imported into the namespace.
+// Nothing to do here.
+
+# else
// Allows a controller thread to pause execution of newly created
// threads until notified. Instances of this class must be created
// and destroyed in the controller thread.
//
// This class is only for testing Google Test's own constructs. Do not
// use it in user tests, either directly or indirectly.
+// TODO(b/203539622): Replace unconditionally with absl::Notification.
class GTEST_API_ Notification {
public:
- Notification();
- void Notify();
- void WaitForNotification();
+ Notification() : notified_(false) {}
+ Notification(const Notification&) = delete;
+ Notification& operator=(const Notification&) = delete;
- private:
- AutoHandle event_;
+ // Notifies all threads created with this notification to start. Must
+ // be called from the controller thread.
+ void Notify() {
+ std::lock_guard<std::mutex> lock(mu_);
+ notified_ = true;
+ cv_.notify_all();
+ }
+
+ // Blocks until the controller thread notifies. Must be called from a test
+ // thread.
+ void WaitForNotification() {
+ std::unique_lock<std::mutex> lock(mu_);
+ cv_.wait(lock, [this]() { return notified_; });
+ }
- GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+ private:
+ std::mutex mu_;
+ std::condition_variable cv_;
+ bool notified_;
};
# endif // GTEST_HAS_NOTIFICATION_
diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc
index c3c93e61..f63625b5 100644
--- a/googletest/src/gtest-port.cc
+++ b/googletest/src/gtest-port.cc
@@ -280,10 +280,6 @@ size_t GetThreadCount() {
#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
-void SleepMilliseconds(int n) {
- ::Sleep(static_cast<DWORD>(n));
-}
-
AutoHandle::AutoHandle()
: handle_(INVALID_HANDLE_VALUE) {}
@@ -322,23 +318,6 @@ bool AutoHandle::IsCloseable() const {
return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE;
}
-Notification::Notification()
- : event_(::CreateEvent(nullptr, // Default security attributes.
- TRUE, // Do not reset automatically.
- FALSE, // Initially unset.
- nullptr)) { // Anonymous event.
- GTEST_CHECK_(event_.Get() != nullptr);
-}
-
-void Notification::Notify() {
- GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE);
-}
-
-void Notification::WaitForNotification() {
- GTEST_CHECK_(
- ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0);
-}
-
Mutex::Mutex()
: owner_thread_id_(0),
type_(kDynamic),
diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc
index 5d654de3..3eb9505f 100644
--- a/googletest/src/gtest.cc
+++ b/googletest/src/gtest.cc
@@ -2857,8 +2857,7 @@ void UnitTestImpl::RegisterParameterizedTests() {
void TestInfo::Run() {
TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
if (!should_run_) {
- if (is_disabled_)
- repeater->OnTestSkipped(*this);
+ if (is_disabled_) repeater->OnTestDisabled(*this);
return;
}
@@ -3397,7 +3396,7 @@ class PrettyUnitTestResultPrinter : public TestEventListener {
#endif // OnTestCaseStart
void OnTestStart(const TestInfo& test_info) override;
- void OnTestSkipped(const TestInfo& test_info) override;
+ void OnTestDisabled(const TestInfo& test_info) override;
void OnTestPartResult(const TestPartResult& result) override;
void OnTestEnd(const TestInfo& test_info) override;
@@ -3497,7 +3496,7 @@ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
fflush(stdout);
}
-void PrettyUnitTestResultPrinter::OnTestSkipped(const TestInfo& test_info) {
+void PrettyUnitTestResultPrinter::OnTestDisabled(const TestInfo& test_info) {
ColoredPrintf(GTestColor::kYellow, "[ DISABLED ] ");
PrintTestName(test_info.test_suite_name(), test_info.name());
printf("\n");
@@ -3706,7 +3705,7 @@ class BriefUnitTestResultPrinter : public TestEventListener {
#endif // OnTestCaseStart
void OnTestStart(const TestInfo& /*test_info*/) override {}
- void OnTestSkipped(const TestInfo& /*test_info*/) override {}
+ void OnTestDisabled(const TestInfo& /*test_info*/) override {}
void OnTestPartResult(const TestPartResult& result) override;
void OnTestEnd(const TestInfo& test_info) override;
@@ -3813,7 +3812,7 @@ class TestEventRepeater : public TestEventListener {
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
void OnTestSuiteStart(const TestSuite& parameter) override;
void OnTestStart(const TestInfo& test_info) override;
- void OnTestSkipped(const TestInfo& test_info) override;
+ void OnTestDisabled(const TestInfo& test_info) override;
void OnTestPartResult(const TestPartResult& result) override;
void OnTestEnd(const TestInfo& test_info) override;
// Legacy API is deprecated but still available
@@ -3884,7 +3883,7 @@ GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite)
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite)
GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
-GTEST_REPEATER_METHOD_(OnTestSkipped, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestDisabled, TestInfo)
GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
diff --git a/googletest/test/googletest-port-test.cc b/googletest/test/googletest-port-test.cc
index 16d30c46..b14e1f76 100644
--- a/googletest/test/googletest-port-test.cc
+++ b/googletest/test/googletest-port-test.cc
@@ -36,8 +36,10 @@
# include <time.h>
#endif // GTEST_OS_MAC
+#include <chrono> // NOLINT
#include <list>
#include <memory>
+#include <thread> // NOLINT
#include <utility> // For std::pair and std::make_pair.
#include <vector>
@@ -333,7 +335,7 @@ TEST(GetThreadCountTest, ReturnsCorrectValue) {
break;
}
- SleepMilliseconds(100);
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
// Retry if an arbitrary other thread was created or destroyed.
@@ -1050,7 +1052,7 @@ class AtomicCounterWithMutex {
int temp = value_;
{
// We need to put up a memory barrier to prevent reads and writes to
- // value_ rearranged with the call to SleepMilliseconds when observed
+ // value_ rearranged with the call to sleep_for when observed
// from other threads.
#if GTEST_HAS_PTHREAD
// On POSIX, locking a mutex puts up a memory barrier. We cannot use
@@ -1061,7 +1063,8 @@ class AtomicCounterWithMutex {
pthread_mutex_init(&memory_barrier_mutex, nullptr));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex));
- SleepMilliseconds(static_cast<int>(random_.Generate(30)));
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds(random_.Generate(30)));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex));
@@ -1069,7 +1072,8 @@ class AtomicCounterWithMutex {
// On Windows, performing an interlocked access puts up a memory barrier.
volatile LONG dummy = 0;
::InterlockedIncrement(&dummy);
- SleepMilliseconds(static_cast<int>(random_.Generate(30)));
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds(random_.Generate(30)));
::InterlockedIncrement(&dummy);
#else
# error "Memory barrier not implemented on this platform."
diff --git a/googletest/test/gtest_test_utils.py b/googletest/test/gtest_test_utils.py
index 13fc6f59..eecc5334 100755
--- a/googletest/test/gtest_test_utils.py
+++ b/googletest/test/gtest_test_utils.py
@@ -32,6 +32,7 @@
# pylint: disable-msg=C6204
import os
+import subprocess
import sys
IS_WINDOWS = os.name == 'nt'
@@ -42,13 +43,6 @@ import atexit
import shutil
import tempfile
import unittest as _test_module
-
-try:
- import subprocess
- _SUBPROCESS_MODULE_AVAILABLE = True
-except:
- import popen2
- _SUBPROCESS_MODULE_AVAILABLE = False
# pylint: enable-msg=C6204
GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT'
@@ -224,69 +218,18 @@ class Subprocess:
combined in a string.
"""
- # The subprocess module is the preferable way of running programs
- # since it is available and behaves consistently on all platforms,
- # including Windows. But it is only available starting in python 2.4.
- # In earlier python versions, we revert to the popen2 module, which is
- # available in python 2.0 and later but doesn't provide required
- # functionality (Popen4) under Windows. This allows us to support Mac
- # OS X 10.4 Tiger, which has python 2.3 installed.
- if _SUBPROCESS_MODULE_AVAILABLE:
- if capture_stderr:
- stderr = subprocess.STDOUT
- else:
- stderr = subprocess.PIPE
-
- p = subprocess.Popen(command,
- stdout=subprocess.PIPE, stderr=stderr,
- cwd=working_dir, universal_newlines=True, env=env)
- # communicate returns a tuple with the file object for the child's
- # output.
- self.output = p.communicate()[0]
- self._return_code = p.returncode
+ if capture_stderr:
+ stderr = subprocess.STDOUT
else:
- old_dir = os.getcwd()
-
- def _ReplaceEnvDict(dest, src):
- # Changes made by os.environ.clear are not inheritable by child
- # processes until Python 2.6. To produce inheritable changes we have
- # to delete environment items with the del statement.
- for key in dest.keys():
- del dest[key]
- dest.update(src)
-
- # When 'env' is not None, backup the environment variables and replace
- # them with the passed 'env'. When 'env' is None, we simply use the
- # current 'os.environ' for compatibility with the subprocess.Popen
- # semantics used above.
- if env is not None:
- old_environ = os.environ.copy()
- _ReplaceEnvDict(os.environ, env)
-
- try:
- if working_dir is not None:
- os.chdir(working_dir)
- if capture_stderr:
- p = popen2.Popen4(command)
- else:
- p = popen2.Popen3(command)
- p.tochild.close()
- self.output = p.fromchild.read()
- ret_code = p.wait()
- finally:
- os.chdir(old_dir)
-
- # Restore the old environment variables
- # if they were replaced.
- if env is not None:
- _ReplaceEnvDict(os.environ, old_environ)
-
- # Converts ret_code to match the semantics of
- # subprocess.Popen.returncode.
- if os.WIFSIGNALED(ret_code):
- self._return_code = -os.WTERMSIG(ret_code)
- else: # os.WIFEXITED(ret_code) should return True here.
- self._return_code = os.WEXITSTATUS(ret_code)
+ stderr = subprocess.PIPE
+
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE, stderr=stderr,
+ cwd=working_dir, universal_newlines=True, env=env)
+ # communicate returns a tuple with the file object for the child's
+ # output.
+ self.output = p.communicate()[0]
+ self._return_code = p.returncode
if bool(self._return_code & 0x80000000):
self.terminated_by_signal = True