summaryrefslogtreecommitdiff
path: root/src/mongo/unittest
diff options
context:
space:
mode:
authorGabriel Russell <gabriel.russell@mongodb.com>2020-03-02 17:48:47 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-04-14 17:02:16 +0000
commitcdf9ea3b479bbffc1de900884ee10e29e7349bd2 (patch)
tree0da63f8345d2d0dc7e79b407da1726486fddbecb /src/mongo/unittest
parent298652908ebcc41ba28b1d68a3c6a90486ccce98 (diff)
downloadmongo-cdf9ea3b479bbffc1de900884ee10e29e7349bd2.tar.gz
SERVER-46568 removing the unittestOutput domain
Diffstat (limited to 'src/mongo/unittest')
-rw-r--r--src/mongo/unittest/SConscript1
-rw-r--r--src/mongo/unittest/death_test.cpp119
-rw-r--r--src/mongo/unittest/death_test.h18
-rw-r--r--src/mongo/unittest/unittest.cpp81
-rw-r--r--src/mongo/unittest/unittest.h12
-rw-r--r--src/mongo/unittest/unittest_test.cpp5
6 files changed, 123 insertions, 113 deletions
diff --git a/src/mongo/unittest/SConscript b/src/mongo/unittest/SConscript
index d472bd49bcc..f7691b0c5cd 100644
--- a/src/mongo/unittest/SConscript
+++ b/src/mongo/unittest/SConscript
@@ -21,6 +21,7 @@ env.Library(
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/db/server_options_core',
'$BUILD_DIR/mongo/util/options_parser/options_parser',
+ '$BUILD_DIR/mongo/util/debugger',
],
)
diff --git a/src/mongo/unittest/death_test.cpp b/src/mongo/unittest/death_test.cpp
index 31add6149ac..b33900aff90 100644
--- a/src/mongo/unittest/death_test.cpp
+++ b/src/mongo/unittest/death_test.cpp
@@ -30,6 +30,10 @@
#include "mongo/platform/basic.h"
+#include <fmt/format.h>
+#include <stdio.h>
+
+#include "mongo/bson/json.h"
#include "mongo/unittest/death_test.h"
#ifndef _WIN32
@@ -47,23 +51,36 @@
#include "mongo/logv2/log.h"
#include "mongo/util/assert_util.h"
+#include "mongo/util/debugger.h"
#include "mongo/util/quick_exit.h"
-#define checkSyscall(EXPR) \
- do { \
- if (-1 == (EXPR)) { \
- const int err = errno; \
- LOGV2_ERROR(24138, \
- "{expr} failed: {errno}", \
- "expr"_attr = #EXPR, \
- "errno"_attr = errnoWithDescription(err)); \
- invariantFailed("-1 != (" #EXPR ")", __FILE__, __LINE__); \
- } \
- } while (false)
-
namespace mongo {
namespace unittest {
+class DeathTestSyscallException : public std::runtime_error {
+public:
+ using std::runtime_error::runtime_error;
+};
+
+#define logAndThrowWithErrno(expr) logAndThrowWithErrnoAt(expr, __FILE__, __LINE__, errno)
+
+void logAndThrowWithErrnoAt(const StringData expr,
+ const StringData file,
+ const unsigned line,
+ const int err) {
+ using namespace fmt::literals;
+ LOGV2_ERROR(24138,
+ "{expr} failed: {error} @{file}:{line}",
+ "expression failed",
+ "expr"_attr = expr,
+ "error"_attr = errnoWithDescription(err),
+ "file"_attr = file,
+ "line"_attr = line);
+ breakpoint();
+ throw DeathTestSyscallException(
+ "{} failed: {} @{}:{}"_format(expr, errnoWithDescription(err), file, line));
+}
+
void DeathTestBase::_doTest() {
#if defined(_WIN32)
LOGV2(24133, "Skipping death test on Windows");
@@ -73,23 +90,47 @@ void DeathTestBase::_doTest() {
return;
#else
int pipes[2];
- checkSyscall(pipe(pipes));
+ if (pipe(pipes) == -1)
+ logAndThrowWithErrno("pipe()");
pid_t child;
- checkSyscall(child = fork());
+ if ((child = fork()) == -1)
+ logAndThrowWithErrno("fork()");
if (child) {
- checkSyscall(close(pipes[1]));
- char buf[1000];
+ if (close(pipes[1]) == -1)
+ logAndThrowWithErrno("close(pipe[1])");
std::ostringstream os;
+ FILE* pf = 0;
+ if ((pf = fdopen(pipes[0], "r")) == NULL)
+ logAndThrowWithErrno("fdopen(pipe[0], \"r\")");
+ auto pfGuard = makeGuard([&] {
+ if (fclose(pf) != 0)
+ logAndThrowWithErrno("fclose(pf)");
+ });
+ char* lineBuf = nullptr;
+ size_t lineBufSize = 0;
+ auto lineBufGuard = makeGuard([&] { free(lineBuf); });
ssize_t bytesRead;
- LOGV2(24135, "========== Beginning of interleaved output of death test ==========");
- while (0 < (bytesRead = read(pipes[0], buf, sizeof(buf)))) {
- std::cout.write(buf, bytesRead);
- invariant(std::cout);
- os.write(buf, bytesRead);
+ while ((bytesRead = getline(&lineBuf, &lineBufSize, pf)) != -1) {
+ StringData line(lineBuf, bytesRead);
+ if (line.empty())
+ continue;
+ if (line[line.size() - 1] == '\n')
+ line = line.substr(0, line.size() - 1);
+ if (line.empty())
+ continue;
+ int parsedLen;
+ auto parsedChildLog = fromjson(lineBuf, &parsedLen);
+ if (static_cast<size_t>(parsedLen) == line.size()) {
+ LOGV2(20165, "child", "json"_attr = parsedChildLog);
+ } else {
+ LOGV2(20169, "child", "text"_attr = line);
+ }
+ os.write(lineBuf, bytesRead);
invariant(os);
}
- LOGV2(24136, "========== End of interleaved output of death test ==========");
- checkSyscall(bytesRead);
+ if (!feof(pf))
+ logAndThrowWithErrno("getline(&buf, &bufSize, pf)");
+
pid_t pid;
int stat;
while (child != (pid = waitpid(child, &stat, 0))) {
@@ -99,20 +140,17 @@ void DeathTestBase::_doTest() {
case EINTR:
continue;
default:
- LOGV2_FATAL(
- 24139,
- "Unrecoverable error while waiting for {child}: {errnoWithDescription_err}",
- "child"_attr = child,
- "errnoWithDescription_err"_attr = errnoWithDescription(err));
- MONGO_UNREACHABLE;
+ logAndThrowWithErrno("waitpid(child, &stat, 0)");
}
}
if (WIFSIGNALED(stat) || (WIFEXITED(stat) && WEXITSTATUS(stat) != 0)) {
// Exited with a signal or non-zero code. Validate the expected message.
if (_isRegex()) {
- ASSERT_STRING_SEARCH_REGEX(os.str(), _doGetPattern());
+ ASSERT_STRING_SEARCH_REGEX(os.str(), _doGetPattern())
+ << " @" << _getFile() << ":" << _getLine();
} else {
- ASSERT_STRING_CONTAINS(os.str(), _doGetPattern());
+ ASSERT_STRING_CONTAINS(os.str(), _doGetPattern())
+ << " @" << _getFile() << ":" << _getLine();
}
return;
} else {
@@ -122,18 +160,23 @@ void DeathTestBase::_doTest() {
}
// This code only executes in the child process.
- checkSyscall(close(pipes[0]));
- checkSyscall(dup2(pipes[1], 1));
- checkSyscall(dup2(1, 2));
+ if (close(pipes[0]) == -1)
+ logAndThrowWithErrno("close(pipes[0])");
+ if (dup2(pipes[1], 1) == -1)
+ logAndThrowWithErrno("dup2(pipes[1], 1)");
+ if (dup2(1, 2) == -1)
+ logAndThrowWithErrno("dup2(1, 2)");
- // We disable the creation of core dump files in the child process since the child process is
- // expected to exit uncleanly. This avoids unnecessarily creating core dump files when the child
- // process calls std::abort() or std::terminate().
+ // We disable the creation of core dump files in the child process since the child process
+ // is expected to exit uncleanly. This avoids unnecessarily creating core dump files when
+ // the child process calls std::abort() or std::terminate().
const struct rlimit kNoCoreDump { 0U, 0U };
- checkSyscall(setrlimit(RLIMIT_CORE, &kNoCoreDump));
+ if (setrlimit(RLIMIT_CORE, &kNoCoreDump) == -1)
+ logAndThrowWithErrno("setrlimit(RLIMIT_CORE, &kNoCoreDump)");
try {
auto test = _doMakeTest();
+ LOGV2(23515, "Running DeathTest in child");
test->run();
LOGV2(20166, "Death test failed to die");
} catch (const TestAssertionFailureException& tafe) {
diff --git a/src/mongo/unittest/death_test.h b/src/mongo/unittest/death_test.h
index 599f3da2faa..f93f66c485f 100644
--- a/src/mongo/unittest/death_test.h
+++ b/src/mongo/unittest/death_test.h
@@ -96,6 +96,14 @@
return IS_REGEX; \
} \
\
+ static int getLine() { \
+ return __LINE__; \
+ } \
+ \
+ static std::string getFile() { \
+ return __FILE__; \
+ } \
+ \
private: \
void _doTest() override; \
static inline const RegistrationAgent<::mongo::unittest::DeathTest<TEST_TYPE>> _agent{ \
@@ -118,6 +126,8 @@ private:
virtual std::unique_ptr<Test> _doMakeTest() = 0;
virtual std::string _doGetPattern() = 0;
virtual bool _isRegex() = 0;
+ virtual int _getLine() = 0;
+ virtual std::string _getFile() = 0;
};
template <typename T>
@@ -136,6 +146,14 @@ private:
return T::isRegex();
}
+ int _getLine() override {
+ return T::getLine();
+ }
+
+ std::string _getFile() override {
+ return T::getFile();
+ }
+
std::unique_ptr<Test> _doMakeTest() override {
return _makeTest();
}
diff --git a/src/mongo/unittest/unittest.cpp b/src/mongo/unittest/unittest.cpp
index 2d0a1863cb5..608e97c1ad8 100644
--- a/src/mongo/unittest/unittest.cpp
+++ b/src/mongo/unittest/unittest.cpp
@@ -27,8 +27,7 @@
* it in the license file.
*/
-#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
-#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kDefault
#include "mongo/platform/basic.h"
@@ -42,14 +41,15 @@
#include <map>
#include <memory>
-#include "mongo/base/checked_cast.h"
-#include "mongo/base/init.h"
-#include "mongo/db/server_options.h"
#include "mongo/logger/console_appender.h"
#include "mongo/logger/log_manager.h"
#include "mongo/logger/logger.h"
#include "mongo/logger/message_event_utf8_encoder.h"
#include "mongo/logger/message_log_domain.h"
+
+#include "mongo/base/checked_cast.h"
+#include "mongo/base/init.h"
+#include "mongo/db/server_options.h"
#include "mongo/logv2/bson_formatter.h"
#include "mongo/logv2/component_settings_filter.h"
#include "mongo/logv2/log.h"
@@ -61,7 +61,6 @@
#include "mongo/logv2/plain_formatter.h"
#include "mongo/platform/mutex.h"
#include "mongo/util/assert_util.h"
-#include "mongo/util/log.h"
#include "mongo/util/stacktrace.h"
#include "mongo/util/timer.h"
@@ -73,11 +72,6 @@ bool stringContains(const std::string& haystack, const std::string& needle) {
return haystack.find(needle) != std::string::npos;
}
-logger::MessageLogDomain* unittestOutput() {
- static const auto p = logger::globalLogManager()->getNamedDomain("unittest");
- return p;
-}
-
/** Each map key is owned by its corresponding Suite object. */
auto& suitesMap() {
static std::map<StringData, std::shared_ptr<Suite>> m;
@@ -86,28 +80,6 @@ auto& suitesMap() {
} // namespace
-logger::LogstreamBuilderDeprecated log() {
- return LogstreamBuilderDeprecated(
- unittestOutput(), getThreadName(), logger::LogSeverity::Log());
-}
-
-logger::LogstreamBuilderDeprecated warning() {
- return LogstreamBuilderDeprecated(
- unittestOutput(), getThreadName(), logger::LogSeverity::Warning());
-}
-
-void setupTestLogger() {
- unittestOutput()->attachAppender(
- std::make_unique<logger::ConsoleAppender<logger::MessageLogDomain::Event>>(
- std::make_unique<logger::MessageEventDetailsEncoder>()));
-}
-
-MONGO_INITIALIZER_WITH_PREREQUISITES(UnitTestOutput, ("GlobalLogManager", "default"))
-(InitializerContext*) {
- setupTestLogger();
- return Status::OK();
-}
-
class Result {
public:
struct FailStatus {
@@ -235,8 +207,6 @@ private:
// Captured BSON
std::vector<std::string> _capturedBSONLogMessages;
- logger::MessageLogDomain::AppenderHandle _captureAppenderHandle;
- std::unique_ptr<logger::MessageLogDomain::EventAppender> _captureAppender;
// Capture Sink for Plain Text
boost::shared_ptr<boost::log::sinks::synchronous_sink<logv2::LogCaptureBackend>> _captureSink;
@@ -315,43 +285,28 @@ void CaptureLogs::startCapturingLogMessages() {
_capturedLogMessages.clear();
_capturedBSONLogMessages.clear();
- if (logV2Enabled()) {
- if (!_captureSink) {
- _captureSink = logv2::LogCaptureBackend::create(_capturedLogMessages);
- _captureSink->set_filter(
- logv2::AllLogsFilter(logv2::LogManager::global().getGlobalDomain()));
- _captureSink->set_formatter(logv2::PlainFormatter());
+ if (!_captureSink) {
+ _captureSink = logv2::LogCaptureBackend::create(_capturedLogMessages);
+ _captureSink->set_filter(
+ logv2::AllLogsFilter(logv2::LogManager::global().getGlobalDomain()));
+ _captureSink->set_formatter(logv2::PlainFormatter());
- _captureBSONSink = logv2::LogCaptureBackend::create(_capturedBSONLogMessages);
+ _captureBSONSink = logv2::LogCaptureBackend::create(_capturedBSONLogMessages);
- _captureBSONSink->set_filter(
- logv2::AllLogsFilter(logv2::LogManager::global().getGlobalDomain()));
- _captureBSONSink->set_formatter(logv2::BSONFormatter());
- }
- boost::log::core::get()->add_sink(_captureSink);
- boost::log::core::get()->add_sink(_captureBSONSink);
- } else {
- if (!_captureAppender) {
- _captureAppender = std::make_unique<StringVectorAppender>(&_capturedLogMessages);
- }
- checked_cast<StringVectorAppender*>(_captureAppender.get())->enable();
- _captureAppenderHandle =
- logger::globalLogDomain()->attachAppender(std::move(_captureAppender));
+ _captureBSONSink->set_filter(
+ logv2::AllLogsFilter(logv2::LogManager::global().getGlobalDomain()));
+ _captureBSONSink->set_formatter(logv2::BSONFormatter());
}
+ boost::log::core::get()->add_sink(_captureSink);
+ boost::log::core::get()->add_sink(_captureBSONSink);
_isCapturingLogMessages = true;
}
void CaptureLogs::stopCapturingLogMessages() {
invariant(_isCapturingLogMessages);
- if (logV2Enabled()) {
- boost::log::core::get()->remove_sink(_captureSink);
- boost::log::core::get()->remove_sink(_captureBSONSink);
- } else {
- invariant(!_captureAppender);
- _captureAppender = logger::globalLogDomain()->detachAppender(_captureAppenderHandle);
- checked_cast<StringVectorAppender*>(_captureAppender.get())->disable();
- }
+ boost::log::core::get()->remove_sink(_captureSink);
+ boost::log::core::get()->remove_sink(_captureBSONSink);
_isCapturingLogMessages = false;
}
diff --git a/src/mongo/unittest/unittest.h b/src/mongo/unittest/unittest.h
index 8fa5869dc29..b2ffab38891 100644
--- a/src/mongo/unittest/unittest.h
+++ b/src/mongo/unittest/unittest.h
@@ -51,6 +51,7 @@
#include "mongo/base/string_data.h"
#include "mongo/logger/logstream_builder.h"
#include "mongo/logger/message_log_domain.h"
+#include "mongo/logv2/log_detail.h"
#include "mongo/unittest/bson_test_util.h"
#include "mongo/unittest/unittest_helpers.h"
#include "mongo/util/assert_util.h"
@@ -347,15 +348,6 @@ namespace mongo::unittest {
class Result;
-void setupTestLogger();
-
-/**
- * Gets a LogstreamBuilder for logging to the unittest log domain, which may have
- * different target from the global log domain.
- */
-logger::LogstreamBuilderDeprecated log();
-logger::LogstreamBuilderDeprecated warning();
-
/**
* Representation of a collection of tests.
*
@@ -489,9 +481,7 @@ struct OldStyleSuiteInitializer {
}
void init(OldStyleSuiteSpecification& suiteSpec) const {
- log() << "\t about to setupTests" << std::endl;
suiteSpec.setupTests();
- log() << "\t done setupTests" << std::endl;
auto& suite = Suite::getSuite(suiteSpec.name());
for (auto&& t : suiteSpec.tests()) {
suite.add(t.name, "", t.fn);
diff --git a/src/mongo/unittest/unittest_test.cpp b/src/mongo/unittest/unittest_test.cpp
index 1689e5e3ebb..9d325b300f5 100644
--- a/src/mongo/unittest/unittest_test.cpp
+++ b/src/mongo/unittest/unittest_test.cpp
@@ -31,6 +31,8 @@
* Unit tests of the unittest framework itself.
*/
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kDefault
+
#include "mongo/platform/basic.h"
#include <functional>
@@ -38,6 +40,7 @@
#include <string>
#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/logv2/log.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/assert_util.h"
@@ -270,7 +273,7 @@ class DeathTestSelfTestFixture : public ::mongo::unittest::Test {
public:
void setUp() override {}
void tearDown() override {
- mongo::unittest::log() << "Died in tear-down";
+ LOGV2(24148, "Died in tear-down");
invariant(false);
}
};