зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1825259 - Implement ScopedTestResultReporter to help print assertion failures in death test child processes. r=gbrown
Gtest checks (with ASSERT_* or EXPECT_* macros) in gtest death test child processes are usually ignored with no way of manually enabling them. This patch implements a helper class, ScopedTestResultReporter, that when it is the current test reporter will print TestPartResults to stderr. Stderr of a death test child process will get printed by the parent only if the testcase failed. A death test child can only signal to the parent to fail the testcase by means of the exit code (or the absence of exit). To help signal an unexpected exit code, ScopedTestResultReporter can be made to exit the process automatically as it goes out of scope, using different exit codes depending on the death test child's test status where 0=pass, 1=nonfatal failure, and 2=fatal failure. Note that when used like this, the death test parent process must be set up to expect an exit code of 0 from the death test child process, typically through `EXPECT_EXIT(DoTestThatExits(), testing::ExitedWithCode(0), "");`. When an `EXPECT_EXIT` check fails, gtest makes sure to print stderr from the child process with the unexpected exit code (which is where the test results passed through ScopedTestResultReporter were printed). Differential Revision: https://phabricator.services.mozilla.com/D175139
This commit is contained in:
Родитель
b7d19f4f6d
Коммит
6364d695b5
|
@ -1,5 +1,11 @@
|
|||
#include "MozHelpers.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "gtest/gtest-spi.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
namespace mozilla::gtest {
|
||||
|
||||
void DisableCrashReporter() {
|
||||
|
@ -10,4 +16,58 @@ void DisableCrashReporter() {
|
|||
}
|
||||
}
|
||||
|
||||
class ScopedTestResultReporterImpl
|
||||
: public ScopedTestResultReporter,
|
||||
public testing::ScopedFakeTestPartResultReporter {
|
||||
public:
|
||||
explicit ScopedTestResultReporterImpl(ExitMode aExitMode)
|
||||
: testing::ScopedFakeTestPartResultReporter(INTERCEPT_ALL_THREADS,
|
||||
nullptr),
|
||||
mExitMode(aExitMode) {}
|
||||
|
||||
~ScopedTestResultReporterImpl() {
|
||||
switch (mExitMode) {
|
||||
case ExitMode::ExitOnDtor:
|
||||
exit(ExitCode(Status()));
|
||||
case ExitMode::NoExit:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ReportTestPartResult(const testing::TestPartResult& aResult) override {
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (aResult.nonfatally_failed() &&
|
||||
mStatus < TestResultStatus::NonFatalFailure) {
|
||||
mStatus = TestResultStatus::NonFatalFailure;
|
||||
}
|
||||
|
||||
if (aResult.fatally_failed() &&
|
||||
mStatus < TestResultStatus::FatalFailure) {
|
||||
mStatus = TestResultStatus::FatalFailure;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << aResult;
|
||||
printf_stderr("%s\n", stream.str().c_str());
|
||||
}
|
||||
|
||||
TestResultStatus Status() const override {
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
private:
|
||||
const ExitMode mExitMode;
|
||||
|
||||
mutable Mutex mMutex{"ScopedTestResultReporterImpl::mMutex"};
|
||||
TestResultStatus mStatus MOZ_GUARDED_BY(mMutex) = TestResultStatus::Pass;
|
||||
};
|
||||
|
||||
UniquePtr<ScopedTestResultReporter> ScopedTestResultReporter::Create(
|
||||
ExitMode aExitMode) {
|
||||
return MakeUnique<ScopedTestResultReporterImpl>(aExitMode);
|
||||
}
|
||||
|
||||
} // namespace mozilla::gtest
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsICrashReporter.h"
|
||||
|
@ -63,6 +64,56 @@ namespace mozilla::gtest {
|
|||
|
||||
void DisableCrashReporter();
|
||||
|
||||
/**
|
||||
* Exit mode used for ScopedTestResultReporter.
|
||||
*/
|
||||
enum class ExitMode {
|
||||
// The user of the reporter handles exit.
|
||||
NoExit,
|
||||
// As the reporter goes out of scope, exit with ExitCode().
|
||||
ExitOnDtor,
|
||||
};
|
||||
|
||||
/**
|
||||
* Status used by ScopedTestResultReporter.
|
||||
*/
|
||||
enum class TestResultStatus : int {
|
||||
Pass = 0,
|
||||
NonFatalFailure = 1,
|
||||
FatalFailure = 2,
|
||||
};
|
||||
|
||||
inline int ExitCode(TestResultStatus aStatus) {
|
||||
return static_cast<int>(aStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper that reports test results to stderr in death test child
|
||||
* processes, since that is normally disabled by default (with no way of
|
||||
* enabling).
|
||||
*
|
||||
* Note that for this to work as intended the death test child has to, on
|
||||
* failure, exit with an exit code that is unexpected to the death test parent,
|
||||
* so the parent can mark the test case as failed.
|
||||
*
|
||||
* If the parent expects a graceful exit (code 0), ExitCode() can be used with
|
||||
* Status() to exit the child process.
|
||||
*
|
||||
* For simplicity the reporter can exit automatically as it goes out of scope,
|
||||
* when created with ExitMode::ExitOnDtor.
|
||||
*/
|
||||
class ScopedTestResultReporter {
|
||||
public:
|
||||
virtual ~ScopedTestResultReporter() = default;
|
||||
|
||||
/**
|
||||
* The aggregate status of all observed test results.
|
||||
*/
|
||||
virtual TestResultStatus Status() const = 0;
|
||||
|
||||
static UniquePtr<ScopedTestResultReporter> Create(ExitMode aExitMode);
|
||||
};
|
||||
|
||||
} // namespace mozilla::gtest
|
||||
|
||||
#endif // TESTING_GTEST_MOZILLA_HELPERS_H_
|
||||
|
|
Загрузка…
Ссылка в новой задаче