mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 23:09:44 -04:00
test: make it possible for DebugLogHelper to wait for messages
Extend `DebugLogHelper::~DebugLogHelper()` to be able to optionally wait for messages, possibly logged from another thread, to arrive before performing the final check.
This commit is contained in:
parent
e34b41b6a9
commit
e7f9d8c9f0
3 changed files with 47 additions and 6 deletions
|
@ -12,13 +12,18 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
DebugLogHelper::DebugLogHelper(std::string message, MatchFn match)
|
DebugLogHelper::DebugLogHelper(std::string message, MatchFn match, std::optional<std::chrono::milliseconds> timeout)
|
||||||
: m_message{std::move(message)}, m_match(std::move(match))
|
: m_message{std::move(message)}, m_timeout{timeout}, m_match(std::move(match))
|
||||||
{
|
{
|
||||||
m_print_connection = LogInstance().PushBackCallback(
|
m_print_connection = LogInstance().PushBackCallback(
|
||||||
[this](const std::string& s) {
|
[this](const std::string& s) {
|
||||||
if (m_found) return;
|
StdLockGuard lock{m_mutex};
|
||||||
m_found = s.find(m_message) != std::string::npos && m_match(&s);
|
if (!m_found) {
|
||||||
|
if (s.find(m_message) != std::string::npos && m_match(&s)) {
|
||||||
|
m_found = true;
|
||||||
|
m_cv.notify_all();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
noui_test_redirect();
|
noui_test_redirect();
|
||||||
m_receiving_log = true;
|
m_receiving_log = true;
|
||||||
|
@ -26,6 +31,12 @@ DebugLogHelper::DebugLogHelper(std::string message, MatchFn match)
|
||||||
|
|
||||||
DebugLogHelper::~DebugLogHelper()
|
DebugLogHelper::~DebugLogHelper()
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
StdUniqueLock lock{m_mutex};
|
||||||
|
if (m_timeout.has_value()) {
|
||||||
|
m_cv.wait_for(lock, m_timeout.value(), [this]() EXCLUSIVE_LOCKS_REQUIRED(m_mutex) { return m_found; });
|
||||||
|
}
|
||||||
|
}
|
||||||
StopReceivingLog();
|
StopReceivingLog();
|
||||||
if (!m_found && m_match(nullptr)) {
|
if (!m_found && m_match(nullptr)) {
|
||||||
std::cerr << "Fatal error: expected message not found in the debug log: " << m_message << "\n";
|
std::cerr << "Fatal error: expected message not found in the debug log: " << m_message << "\n";
|
||||||
|
|
|
@ -5,10 +5,14 @@
|
||||||
#ifndef BITCOIN_TEST_UTIL_LOGGING_H
|
#ifndef BITCOIN_TEST_UTIL_LOGGING_H
|
||||||
#define BITCOIN_TEST_UTIL_LOGGING_H
|
#define BITCOIN_TEST_UTIL_LOGGING_H
|
||||||
|
|
||||||
|
#include <sync.h>
|
||||||
#include <util/macros.h>
|
#include <util/macros.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class DebugLogHelper
|
class DebugLogHelper
|
||||||
|
@ -16,13 +20,27 @@ class DebugLogHelper
|
||||||
public:
|
public:
|
||||||
using MatchFn = std::function<bool(const std::string* line)>;
|
using MatchFn = std::function<bool(const std::string* line)>;
|
||||||
|
|
||||||
explicit DebugLogHelper(std::string message, MatchFn match = [](const std::string*){ return true; });
|
static bool MatchFnDefault(const std::string*)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit DebugLogHelper(
|
||||||
|
std::string message,
|
||||||
|
MatchFn match = MatchFnDefault,
|
||||||
|
std::optional<std::chrono::milliseconds> timeout = std::nullopt);
|
||||||
|
|
||||||
~DebugLogHelper();
|
~DebugLogHelper();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string m_message;
|
const std::string m_message;
|
||||||
bool m_found{false};
|
const std::optional<std::chrono::milliseconds> m_timeout;
|
||||||
|
// Mutex + LOCK() is not usable here because LOCK() may print to the log
|
||||||
|
// itself (see DEBUG_LOCKCONTENTION) causing a deadlock between this mutex
|
||||||
|
// and BCLog::Logger::m_cs which is acquired when logging a message.
|
||||||
|
StdMutex m_mutex;
|
||||||
|
std::condition_variable_any m_cv;
|
||||||
|
bool m_found GUARDED_BY(m_mutex){false};
|
||||||
std::list<std::function<void(const std::string&)>>::iterator m_print_connection;
|
std::list<std::function<void(const std::string&)>>::iterator m_print_connection;
|
||||||
|
|
||||||
//! Custom match checking function.
|
//! Custom match checking function.
|
||||||
|
@ -42,4 +60,7 @@ private:
|
||||||
|
|
||||||
#define ASSERT_DEBUG_LOG(message) DebugLogHelper UNIQUE_NAME(debugloghelper)(message)
|
#define ASSERT_DEBUG_LOG(message) DebugLogHelper UNIQUE_NAME(debugloghelper)(message)
|
||||||
|
|
||||||
|
#define ASSERT_DEBUG_LOG_WAIT(message, timeout) \
|
||||||
|
DebugLogHelper UNIQUE_NAME(debugloghelper)(message, DebugLogHelper::MatchFnDefault, timeout)
|
||||||
|
|
||||||
#endif // BITCOIN_TEST_UTIL_LOGGING_H
|
#endif // BITCOIN_TEST_UTIL_LOGGING_H
|
||||||
|
|
|
@ -74,4 +74,13 @@ public:
|
||||||
~StdLockGuard() UNLOCK_FUNCTION() = default;
|
~StdLockGuard() UNLOCK_FUNCTION() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// StdUniqueLock provides an annotated version of std::unique_lock for us,
|
||||||
|
// and should only be used when sync.h Mutex/LOCK/etc are not usable.
|
||||||
|
class SCOPED_LOCKABLE StdUniqueLock : public std::unique_lock<StdMutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit StdUniqueLock(StdMutex& cs) EXCLUSIVE_LOCK_FUNCTION(cs) : std::unique_lock<StdMutex>(cs) {}
|
||||||
|
~StdUniqueLock() UNLOCK_FUNCTION() = default;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_THREADSAFETY_H
|
#endif // BITCOIN_THREADSAFETY_H
|
||||||
|
|
Loading…
Add table
Reference in a new issue