Merge branch 'google:master' into master

This commit is contained in:
Anthony Graca 2021-11-05 14:43:58 -07:00 committed by GitHub
commit 2eebf3732a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 137 additions and 178 deletions

View File

@ -1919,6 +1919,58 @@ time.
If you combine this with `--gtest_repeat=N`, googletest will pick a different If you combine this with `--gtest_repeat=N`, googletest will pick a different
random seed and re-shuffle the tests in each iteration. 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 ### Controlling Test Output
#### Colored Terminal Output #### Colored Terminal Output

View File

@ -394,7 +394,7 @@ TEST_F(LogIsVisibleTest, WorksWhenVerbosityIsWarning) {
// and log severity. // and log severity.
void TestLogWithSeverity(const std::string& verbosity, LogSeverity severity, void TestLogWithSeverity(const std::string& verbosity, LogSeverity severity,
bool should_print) { 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); GMOCK_FLAG_SET(verbose, verbosity);
CaptureStdout(); CaptureStdout();
Log(severity, "Test log.\n", 0); 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, // Tests that when the stack_frames_to_skip parameter is negative,
// Log() doesn't include the stack trace in the output. // Log() doesn't include the stack trace in the output.
TEST(LogTest, NoStackTraceWhenStackFramesToSkipIsNegative) { 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); GMOCK_FLAG_SET(verbose, kInfoVerbosity);
CaptureStdout(); CaptureStdout();
Log(kInfo, "Test log.\n", -1); Log(kInfo, "Test log.\n", -1);
@ -499,7 +499,7 @@ TEST(LogTest, OnlyWarningsArePrintedWhenVerbosityIsInvalid) {
// Verifies that Log() behaves correctly for the given verbosity level // Verifies that Log() behaves correctly for the given verbosity level
// and log severity. // and log severity.
std::string GrabOutput(void(*logger)(), const char* verbosity) { 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); GMOCK_FLAG_SET(verbose, verbosity);
CaptureStdout(); CaptureStdout();
logger(); logger();

View File

@ -1123,6 +1123,9 @@ class TestEventListener {
// Fired before the test starts. // Fired before the test starts.
virtual void OnTestStart(const TestInfo& test_info) = 0; virtual void OnTestStart(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. // Fired after a failed assertion or a SUCCEED() invocation.
// If you want to throw an exception from this function to skip to the next // If you want to throw an exception from this function to skip to the next
// TEST, it must be AssertionException defined above, or inherited from it. // TEST, it must be AssertionException defined above, or inherited from it.
@ -1172,6 +1175,7 @@ class EmptyTestEventListener : public TestEventListener {
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
void OnTestStart(const TestInfo& /*test_info*/) override {} void OnTestStart(const TestInfo& /*test_info*/) override {}
void OnTestDisabled(const TestInfo& /*test_info*/) override {}
void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {} void OnTestPartResult(const TestPartResult& /*test_part_result*/) override {}
void OnTestEnd(const TestInfo& /*test_info*/) override {} void OnTestEnd(const TestInfo& /*test_info*/) override {}
void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {} void OnTestSuiteEnd(const TestSuite& /*test_suite*/) override {}

View File

@ -260,9 +260,17 @@
#include <string.h> #include <string.h>
#include <cerrno> #include <cerrno>
// #include <condition_variable> // Guarded by GTEST_IS_THREADSAFE below
#include <cstdint> #include <cstdint>
#include <iostream>
#include <limits> #include <limits>
#include <locale>
#include <memory>
#include <string>
// #include <mutex> // Guarded by GTEST_IS_THREADSAFE below
#include <tuple>
#include <type_traits> #include <type_traits>
#include <vector>
#ifndef _WIN32_WCE #ifndef _WIN32_WCE
# include <sys/types.h> # include <sys/types.h>
@ -274,13 +282,6 @@
# include <TargetConditionals.h> # include <TargetConditionals.h>
#endif #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/custom/gtest-port.h"
#include "gtest/internal/gtest-port-arch.h" #include "gtest/internal/gtest-port-arch.h"
@ -757,6 +758,12 @@ typedef struct _RTL_CRITICAL_SECTION GTEST_CRITICAL_SECTION;
#endif // GTEST_IS_THREADSAFE #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 // 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 // are guarded by #ifndef to give embedders a chance to define GTEST_API_ in
// gtest/internal/custom/gtest-port.h // gtest/internal/custom/gtest-port.h
@ -1161,71 +1168,8 @@ void ClearInjectableArgvs();
// Defines synchronization primitives. // Defines synchronization primitives.
#if GTEST_IS_THREADSAFE #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. // Provides leak-safe Windows kernel handle ownership.
// Used in death tests and in threading support. // Used in death tests and in threading support.
class GTEST_API_ AutoHandle { class GTEST_API_ AutoHandle {
@ -1254,23 +1198,45 @@ class GTEST_API_ AutoHandle {
GTEST_DISALLOW_COPY_AND_ASSIGN_(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 // Allows a controller thread to pause execution of newly created
// threads until notified. Instances of this class must be created // threads until notified. Instances of this class must be created
// and destroyed in the controller thread. // and destroyed in the controller thread.
// //
// This class is only for testing Google Test's own constructs. Do not // This class is only for testing Google Test's own constructs. Do not
// use it in user tests, either directly or indirectly. // use it in user tests, either directly or indirectly.
// TODO(b/203539622): Replace unconditionally with absl::Notification.
class GTEST_API_ Notification { class GTEST_API_ Notification {
public: public:
Notification(); Notification() : notified_(false) {}
void Notify(); Notification(const Notification&) = delete;
void WaitForNotification(); Notification& operator=(const Notification&) = delete;
// 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_; });
}
private: private:
AutoHandle event_; std::mutex mu_;
std::condition_variable cv_;
GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); bool notified_;
}; };
# endif // GTEST_HAS_NOTIFICATION_ # endif // GTEST_HAS_NOTIFICATION_

View File

@ -280,10 +280,6 @@ size_t GetThreadCount() {
#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS #if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
void SleepMilliseconds(int n) {
::Sleep(static_cast<DWORD>(n));
}
AutoHandle::AutoHandle() AutoHandle::AutoHandle()
: handle_(INVALID_HANDLE_VALUE) {} : handle_(INVALID_HANDLE_VALUE) {}
@ -322,23 +318,6 @@ bool AutoHandle::IsCloseable() const {
return handle_ != nullptr && handle_ != INVALID_HANDLE_VALUE; 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() Mutex::Mutex()
: owner_thread_id_(0), : owner_thread_id_(0),
type_(kDynamic), type_(kDynamic),

View File

@ -2855,20 +2855,20 @@ void UnitTestImpl::RegisterParameterizedTests() {
// Creates the test object, runs it, records its result, and then // Creates the test object, runs it, records its result, and then
// deletes it. // deletes it.
void TestInfo::Run() { void TestInfo::Run() {
if (!should_run_) return; TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
if (!should_run_) {
if (is_disabled_) repeater->OnTestDisabled(*this);
return;
}
// Tells UnitTest where to store test result. // Tells UnitTest where to store test result.
internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
impl->set_current_test_info(this); impl->set_current_test_info(this);
TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
// Notifies the unit test event listeners that a test is about to start. // Notifies the unit test event listeners that a test is about to start.
repeater->OnTestStart(*this); repeater->OnTestStart(*this);
result_.set_start_timestamp(internal::GetTimeInMillis()); result_.set_start_timestamp(internal::GetTimeInMillis());
internal::Timer timer; internal::Timer timer;
impl->os_stack_trace_getter()->UponLeavingGTest(); impl->os_stack_trace_getter()->UponLeavingGTest();
// Creates the test object. // Creates the test object.
@ -3398,6 +3398,7 @@ class PrettyUnitTestResultPrinter : public TestEventListener {
#endif // OnTestCaseStart #endif // OnTestCaseStart
void OnTestStart(const TestInfo& test_info) override; void OnTestStart(const TestInfo& test_info) override;
void OnTestDisabled(const TestInfo& test_info) override;
void OnTestPartResult(const TestPartResult& result) override; void OnTestPartResult(const TestPartResult& result) override;
void OnTestEnd(const TestInfo& test_info) override; void OnTestEnd(const TestInfo& test_info) override;
@ -3497,6 +3498,13 @@ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
fflush(stdout); fflush(stdout);
} }
void PrettyUnitTestResultPrinter::OnTestDisabled(const TestInfo& test_info) {
ColoredPrintf(GTestColor::kYellow, "[ DISABLED ] ");
PrintTestName(test_info.test_suite_name(), test_info.name());
printf("\n");
fflush(stdout);
}
// Called after an assertion failure. // Called after an assertion failure.
void PrettyUnitTestResultPrinter::OnTestPartResult( void PrettyUnitTestResultPrinter::OnTestPartResult(
const TestPartResult& result) { const TestPartResult& result) {
@ -3705,6 +3713,7 @@ class BriefUnitTestResultPrinter : public TestEventListener {
#endif // OnTestCaseStart #endif // OnTestCaseStart
void OnTestStart(const TestInfo& /*test_info*/) override {} void OnTestStart(const TestInfo& /*test_info*/) override {}
void OnTestDisabled(const TestInfo& /*test_info*/) override {}
void OnTestPartResult(const TestPartResult& result) override; void OnTestPartResult(const TestPartResult& result) override;
void OnTestEnd(const TestInfo& test_info) override; void OnTestEnd(const TestInfo& test_info) override;
@ -3817,6 +3826,7 @@ class TestEventRepeater : public TestEventListener {
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
void OnTestSuiteStart(const TestSuite& parameter) override; void OnTestSuiteStart(const TestSuite& parameter) override;
void OnTestStart(const TestInfo& test_info) override; void OnTestStart(const TestInfo& test_info) override;
void OnTestDisabled(const TestInfo& test_info) override;
void OnTestPartResult(const TestPartResult& result) override; void OnTestPartResult(const TestPartResult& result) override;
void OnTestEnd(const TestInfo& test_info) override; void OnTestEnd(const TestInfo& test_info) override;
// Legacy API is deprecated but still available // Legacy API is deprecated but still available
@ -3887,6 +3897,7 @@ GTEST_REPEATER_METHOD_(OnTestCaseStart, TestSuite)
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_ #endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite) GTEST_REPEATER_METHOD_(OnTestSuiteStart, TestSuite)
GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
GTEST_REPEATER_METHOD_(OnTestDisabled, TestInfo)
GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)

View File

@ -36,8 +36,10 @@
# include <time.h> # include <time.h>
#endif // GTEST_OS_MAC #endif // GTEST_OS_MAC
#include <chrono> // NOLINT
#include <list> #include <list>
#include <memory> #include <memory>
#include <thread> // NOLINT
#include <utility> // For std::pair and std::make_pair. #include <utility> // For std::pair and std::make_pair.
#include <vector> #include <vector>
@ -333,7 +335,7 @@ TEST(GetThreadCountTest, ReturnsCorrectValue) {
break; break;
} }
SleepMilliseconds(100); std::this_thread::sleep_for(std::chrono::milliseconds(100));
} }
// Retry if an arbitrary other thread was created or destroyed. // Retry if an arbitrary other thread was created or destroyed.
@ -1050,7 +1052,7 @@ class AtomicCounterWithMutex {
int temp = value_; int temp = value_;
{ {
// We need to put up a memory barrier to prevent reads and writes to // 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. // from other threads.
#if GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD
// On POSIX, locking a mutex puts up a memory barrier. We cannot use // 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)); pthread_mutex_init(&memory_barrier_mutex, nullptr));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex)); 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_unlock(&memory_barrier_mutex));
GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&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. // On Windows, performing an interlocked access puts up a memory barrier.
volatile LONG dummy = 0; volatile LONG dummy = 0;
::InterlockedIncrement(&dummy); ::InterlockedIncrement(&dummy);
SleepMilliseconds(static_cast<int>(random_.Generate(30))); std::this_thread::sleep_for(
std::chrono::milliseconds(random_.Generate(30)));
::InterlockedIncrement(&dummy); ::InterlockedIncrement(&dummy);
#else #else
# error "Memory barrier not implemented on this platform." # error "Memory barrier not implemented on this platform."

View File

@ -32,6 +32,7 @@
# pylint: disable-msg=C6204 # pylint: disable-msg=C6204
import os import os
import subprocess
import sys import sys
IS_WINDOWS = os.name == 'nt' IS_WINDOWS = os.name == 'nt'
@ -42,13 +43,6 @@ import atexit
import shutil import shutil
import tempfile import tempfile
import unittest as _test_module import unittest as _test_module
try:
import subprocess
_SUBPROCESS_MODULE_AVAILABLE = True
except:
import popen2
_SUBPROCESS_MODULE_AVAILABLE = False
# pylint: enable-msg=C6204 # pylint: enable-msg=C6204
GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT' GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT'
@ -224,69 +218,18 @@ class Subprocess:
combined in a string. combined in a string.
""" """
# The subprocess module is the preferable way of running programs if capture_stderr:
# since it is available and behaves consistently on all platforms, stderr = subprocess.STDOUT
# 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
else: else:
old_dir = os.getcwd() stderr = subprocess.PIPE
def _ReplaceEnvDict(dest, src): p = subprocess.Popen(command,
# Changes made by os.environ.clear are not inheritable by child stdout=subprocess.PIPE, stderr=stderr,
# processes until Python 2.6. To produce inheritable changes we have cwd=working_dir, universal_newlines=True, env=env)
# to delete environment items with the del statement. # communicate returns a tuple with the file object for the child's
for key in dest.keys(): # output.
del dest[key] self.output = p.communicate()[0]
dest.update(src) self._return_code = p.returncode
# 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)
if bool(self._return_code & 0x80000000): if bool(self._return_code & 0x80000000):
self.terminated_by_signal = True self.terminated_by_signal = True