mirror of
https://github.com/google/googletest.git
synced 2025-12-21 11:04:54 +08:00
Merge branch 'google:master' into master
This commit is contained in:
commit
2eebf3732a
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -1123,6 +1123,9 @@ class TestEventListener {
|
||||
// Fired before the test starts.
|
||||
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.
|
||||
// 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.
|
||||
@ -1172,6 +1175,7 @@ class EmptyTestEventListener : public TestEventListener {
|
||||
#endif // GTEST_REMOVE_LEGACY_TEST_CASEAPI_
|
||||
|
||||
void OnTestStart(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 {}
|
||||
|
||||
@ -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;
|
||||
|
||||
// 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:
|
||||
AutoHandle event_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
|
||||
std::mutex mu_;
|
||||
std::condition_variable cv_;
|
||||
bool notified_;
|
||||
};
|
||||
# endif // GTEST_HAS_NOTIFICATION_
|
||||
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -2855,20 +2855,20 @@ void UnitTestImpl::RegisterParameterizedTests() {
|
||||
// Creates the test object, runs it, records its result, and then
|
||||
// deletes it.
|
||||
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.
|
||||
internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
|
||||
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.
|
||||
repeater->OnTestStart(*this);
|
||||
|
||||
result_.set_start_timestamp(internal::GetTimeInMillis());
|
||||
internal::Timer timer;
|
||||
|
||||
impl->os_stack_trace_getter()->UponLeavingGTest();
|
||||
|
||||
// Creates the test object.
|
||||
@ -3398,6 +3398,7 @@ class PrettyUnitTestResultPrinter : public TestEventListener {
|
||||
#endif // OnTestCaseStart
|
||||
|
||||
void OnTestStart(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,6 +3498,13 @@ void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
|
||||
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.
|
||||
void PrettyUnitTestResultPrinter::OnTestPartResult(
|
||||
const TestPartResult& result) {
|
||||
@ -3705,6 +3713,7 @@ class BriefUnitTestResultPrinter : public TestEventListener {
|
||||
#endif // OnTestCaseStart
|
||||
|
||||
void OnTestStart(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;
|
||||
@ -3817,6 +3826,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 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
|
||||
@ -3887,6 +3897,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_(OnTestDisabled, TestInfo)
|
||||
GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
|
||||
GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
|
||||
GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
|
||||
|
||||
@ -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."
|
||||
|
||||
@ -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()
|
||||
stderr = subprocess.PIPE
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user