mirror of
https://github.com/pocoproject/poco.git
synced 2025-12-12 21:14:57 +01:00
* feat(AsyncNotificationCenter): Auto-configure number of workers #5060 add/removeObserver utility functions move AsyncNotificationCenter tests into a separate file tests * chore: update copyrighht
This commit is contained in:
committed by
GitHub
parent
1284103b98
commit
c775d5f3b7
@@ -10,7 +10,8 @@
|
||||
// header file.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.,
|
||||
// Aleph ONE Software Engineering d.o.o., and Contributors.
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
// Definition of the SQLExecutor class.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.,
|
||||
// Aleph ONE Software Engineering d.o.o., and Contributors.
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// Definition of the AsyncNotificationCenter class.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Poco/Thread.h"
|
||||
#include "Poco/RunnableAdapter.h"
|
||||
#include "Poco/NotificationQueue.h"
|
||||
#include "Poco/AsyncObserver.h"
|
||||
|
||||
#if (POCO_HAVE_CPP20_COMPILER)
|
||||
#if !(POCO_HAVE_JTHREAD)
|
||||
@@ -80,8 +81,11 @@ public:
|
||||
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
|
||||
AsyncNotificationCenter(AsyncMode mode = AsyncMode::ENQUEUE, std::size_t workersCount = AsyncNotificationCenter::DEFAULT_WORKERS_COUNT);
|
||||
/// Creates the AsyncNotificationCenter and starts the notifying thread and workers.
|
||||
explicit AsyncNotificationCenter(AsyncMode mode = AsyncMode::ENQUEUE);
|
||||
/// Creates the AsyncNotificationCenter with default worker count and starts the notifying thread and workers.
|
||||
|
||||
AsyncNotificationCenter(AsyncMode mode, std::size_t workersCount);
|
||||
/// Creates the AsyncNotificationCenter with explicit worker count and starts the notifying thread and workers.
|
||||
#else
|
||||
|
||||
AsyncNotificationCenter();
|
||||
@@ -109,6 +113,33 @@ public:
|
||||
/// This method blocks until the notification is processed by
|
||||
/// all observers. Returns results from all observers that accepted the notification.
|
||||
|
||||
template <class C, class N>
|
||||
void addAsyncObserver(C& object, void (C::*method)(const AutoPtr<N>&), bool (C::*matcher)(const std::string&) const = nullptr)
|
||||
/// Convenience method for registering an AsyncObserver.
|
||||
/// Creates an AsyncObserver<C, N> with optional matcher and registers it.
|
||||
/// Usage:
|
||||
/// asyncNotificationCenter.addAsyncObserver(*this, &MyClass::handleNotification);
|
||||
/// asyncNotificationCenter.addAsyncObserver(*this, &MyClass::handleNotification, &MyClass::matchNotification);
|
||||
{
|
||||
addObserver(AsyncObserver<C, N>(object, method, matcher));
|
||||
}
|
||||
|
||||
template <class C, class N>
|
||||
void removeAsyncObserver(C& object, void (C::*method)(const AutoPtr<N>&), bool (C::*matcher)(const std::string&) const = nullptr)
|
||||
/// Convenience method for unregistering an AsyncObserver.
|
||||
/// Removes the AsyncObserver<C, N> with the given callback and matcher.
|
||||
{
|
||||
removeObserver(AsyncObserver<C, N>(object, method, matcher));
|
||||
}
|
||||
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
|
||||
static std::size_t defaultWorkersCount();
|
||||
/// Returns the default number of worker threads based on hardware capabilities.
|
||||
/// Scales from 2 (embedded) to 6 (server) based on available CPU cores.
|
||||
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
void notifyObservers(Notification::Ptr& pNotification) override;
|
||||
@@ -120,11 +151,6 @@ private:
|
||||
|
||||
using Adapter = RunnableAdapter<AsyncNotificationCenter>;
|
||||
|
||||
class ShutdownNotification: public Notification
|
||||
/// Internal notification used to signal the dequeue loop to stop.
|
||||
{
|
||||
};
|
||||
|
||||
const AsyncMode _mode { AsyncMode::ENQUEUE };
|
||||
|
||||
// Async enqueue for notifications
|
||||
@@ -146,11 +172,7 @@ private:
|
||||
void dispatchNotifications(std::stop_token& stopToken, int workerId);
|
||||
/// Dispatching function executed by each worker thread.
|
||||
|
||||
constexpr static std::size_t DEFAULT_WORKERS_COUNT { 5 };
|
||||
/// Default number of worker threads to process notifications.
|
||||
/// This can be configured to a different value if needed.
|
||||
|
||||
const std::size_t _workersCount { DEFAULT_WORKERS_COUNT };
|
||||
const std::size_t _workersCount { defaultWorkersCount() };
|
||||
/// Number of worker threads to process notifications.
|
||||
/// This can be configured to a different value if needed.
|
||||
|
||||
@@ -178,8 +200,6 @@ private:
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// Definition of the AsyncObserver class template.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "Poco/Notification.h"
|
||||
#include "Poco/Mutex.h"
|
||||
#include "Poco/SharedPtr.h"
|
||||
#include "Poco/Observer.h"
|
||||
#include "Poco/NObserver.h"
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
|
||||
@@ -97,6 +99,43 @@ public:
|
||||
void removeObserver(const AbstractObserver& observer);
|
||||
/// Unregisters an observer with the NotificationCenter.
|
||||
|
||||
template <class C, class N>
|
||||
void addObserver(C& object, void (C::*method)(N*))
|
||||
/// Convenience method for registering an Observer.
|
||||
/// Creates an Observer<C, N> and registers it.
|
||||
/// Usage:
|
||||
/// notificationCenter.addObserver(*this, &MyClass::handleNotification);
|
||||
{
|
||||
addObserver(Observer<C, N>(object, method));
|
||||
}
|
||||
|
||||
template <class C, class N>
|
||||
void removeObserver(C& object, void (C::*method)(N*))
|
||||
/// Convenience method for unregistering an Observer.
|
||||
/// Removes the Observer<C, N> with the given callback.
|
||||
{
|
||||
removeObserver(Observer<C, N>(object, method));
|
||||
}
|
||||
|
||||
template <class C, class N>
|
||||
void addNObserver(C& object, void (C::*method)(const AutoPtr<N>&), bool (C::*matcher)(const std::string&) const = nullptr)
|
||||
/// Convenience method for registering an NObserver.
|
||||
/// Creates an NObserver<C, N> with optional matcher and registers it.
|
||||
/// Usage:
|
||||
/// notificationCenter.addNObserver(*this, &MyClass::handleNotification);
|
||||
/// notificationCenter.addNObserver(*this, &MyClass::handleNotification, &MyClass::matchNotification);
|
||||
{
|
||||
addObserver(NObserver<C, N>(object, method, matcher));
|
||||
}
|
||||
|
||||
template <class C, class N>
|
||||
void removeNObserver(C& object, void (C::*method)(const AutoPtr<N>&), bool (C::*matcher)(const std::string&) const = nullptr)
|
||||
/// Convenience method for unregistering an NObserver.
|
||||
/// Removes the NObserver<C, N> with the given callback and matcher.
|
||||
{
|
||||
removeObserver(NObserver<C, N>(object, method, matcher));
|
||||
}
|
||||
|
||||
bool hasObserver(const AbstractObserver& observer) const;
|
||||
/// Returns true if the observer is registered with this NotificationCenter.
|
||||
|
||||
@@ -148,8 +187,6 @@ private:
|
||||
ObserverList _observers;
|
||||
mutable Mutex _mutex;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// Definition of the PIDFile class.
|
||||
//
|
||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// Definition of the ProcessRunner class.
|
||||
//
|
||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Module: AsyncNotificationCenter
|
||||
//
|
||||
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
@@ -26,6 +26,17 @@ namespace Poco {
|
||||
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
|
||||
AsyncNotificationCenter::AsyncNotificationCenter(AsyncMode mode) :
|
||||
_mode(mode),
|
||||
_ra(*this, &AsyncNotificationCenter::dequeue),
|
||||
_enqueueThreadStarted(false),
|
||||
_enqueueThreadDone(false),
|
||||
_workersCount(defaultWorkersCount())
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
|
||||
AsyncNotificationCenter::AsyncNotificationCenter(AsyncMode mode, std::size_t workersCount) :
|
||||
_mode(mode),
|
||||
_ra(*this, &AsyncNotificationCenter::dequeue),
|
||||
@@ -46,7 +57,7 @@ AsyncNotificationCenter::AsyncNotificationCenter() :
|
||||
start();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // POCO_HAVE_JTHREAD
|
||||
|
||||
AsyncNotificationCenter::~AsyncNotificationCenter()
|
||||
{
|
||||
@@ -54,6 +65,20 @@ AsyncNotificationCenter::~AsyncNotificationCenter()
|
||||
}
|
||||
|
||||
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
|
||||
std::size_t AsyncNotificationCenter::defaultWorkersCount()
|
||||
{
|
||||
unsigned int cores = std::thread::hardware_concurrency();
|
||||
if (cores <= 2) return 2;
|
||||
else if (cores <= 4) return 3;
|
||||
else if (cores <= 8) return 4;
|
||||
else return 6;
|
||||
}
|
||||
|
||||
#endif // POCO_HAVE_JTHREAD
|
||||
|
||||
|
||||
void AsyncNotificationCenter::postNotification(Notification::Ptr pNotification)
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
@@ -108,8 +133,6 @@ void AsyncNotificationCenter::notifyObservers(Notification::Ptr& pNotification)
|
||||
|
||||
if (_mode == AsyncMode::NOTIFY || _mode == AsyncMode::BOTH)
|
||||
{
|
||||
// Notification is asynchronous, add it to the lists
|
||||
// for appropriate observers.
|
||||
std::unique_lock<std::mutex> lock(_listsMutex);
|
||||
auto observers = observersToNotify(pNotification);
|
||||
if (observers.empty())
|
||||
@@ -121,15 +144,12 @@ void AsyncNotificationCenter::notifyObservers(Notification::Ptr& pNotification)
|
||||
}
|
||||
_listsEmpty = false;
|
||||
_listsEmptyCondition.notify_all();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Notification is synchronous
|
||||
NotificationCenter::notifyObservers(pNotification);
|
||||
}
|
||||
#else
|
||||
|
||||
#endif // POCO_HAVE_JTHREAD
|
||||
|
||||
NotificationCenter::notifyObservers(pNotification);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +200,6 @@ void AsyncNotificationCenter::stop()
|
||||
{
|
||||
if (_enqueueThreadStarted.exchange(false))
|
||||
{
|
||||
_nq.enqueueUrgentNotification(new ShutdownNotification);
|
||||
_nq.wakeUpAll();
|
||||
while (!_enqueueThreadDone) Thread::sleep(100);
|
||||
_enqueueThread.join();
|
||||
@@ -196,9 +215,6 @@ void AsyncNotificationCenter::stop()
|
||||
{
|
||||
if (t.joinable()) t.join();
|
||||
}
|
||||
|
||||
// TODO: Should the observer lists be cleared here or
|
||||
// shall the workers send all of them to observers and then finish?
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -208,11 +224,8 @@ void AsyncNotificationCenter::dequeue()
|
||||
Notification::Ptr pNf;
|
||||
_enqueueThreadStarted = true;
|
||||
_enqueueThreadDone = false;
|
||||
while (true)
|
||||
while ((pNf = _nq.waitDequeueNotification()))
|
||||
{
|
||||
pNf = _nq.waitDequeueNotification();
|
||||
if (!pNf) break;
|
||||
if (pNf.cast<ShutdownNotification>()) break;
|
||||
try
|
||||
{
|
||||
notifyObservers(pNf);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Module: PIDFile
|
||||
//
|
||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// Module: ProcessRunner
|
||||
//
|
||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
@@ -17,7 +17,7 @@ objects = ActiveMethodTest ActivityTest ActiveDispatcherTest \
|
||||
ListMapTest LoggingFactoryTest LoggingRegistryTest LoggingTestSuite LogStreamTest \
|
||||
NamedEventTest NamedMutexTest ProcessesTestSuite ProcessTest \
|
||||
MemoryPoolTest MD4EngineTest MD5EngineTest ManifestTest \
|
||||
NDCTest NotificationCenterTest NotificationQueueTest \
|
||||
NDCTest NotificationCenterTest AsyncNotificationCenterTest NotificationQueueTest \
|
||||
PriorityNotificationQueueTest TimedNotificationQueueTest \
|
||||
NotificationsTestSuite NullStreamTest NumberFormatterTest \
|
||||
NumberParserTest PathTest PatternFormatterTest JSONFormatterTest PBKDF2EngineTest ProcessRunnerTest \
|
||||
|
||||
759
Foundation/testsuite/src/AsyncNotificationCenterTest.cpp
Normal file
759
Foundation/testsuite/src/AsyncNotificationCenterTest.cpp
Normal file
@@ -0,0 +1,759 @@
|
||||
//
|
||||
// AsyncNotificationCenterTest.cpp
|
||||
//
|
||||
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "AsyncNotificationCenterTest.h"
|
||||
#include "CppUnit/TestCaller.h"
|
||||
#include "CppUnit/TestSuite.h"
|
||||
#include "Poco/NotificationCenter.h"
|
||||
#include "Poco/AsyncNotificationCenter.h"
|
||||
#include "Poco/Observer.h"
|
||||
#include "Poco/NObserver.h"
|
||||
#include "Poco/AsyncObserver.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include <thread>
|
||||
|
||||
|
||||
using Poco::NotificationCenter;
|
||||
using Poco::AsyncNotificationCenter;
|
||||
using Poco::Observer;
|
||||
using Poco::NObserver;
|
||||
using Poco::AsyncObserver;
|
||||
using Poco::Notification;
|
||||
using Poco::AutoPtr;
|
||||
using AsyncMode = AsyncNotificationCenter::AsyncMode;
|
||||
|
||||
|
||||
class TestNotification: public Notification
|
||||
{
|
||||
public:
|
||||
TestNotification()
|
||||
{}
|
||||
|
||||
TestNotification(const std::string& name):
|
||||
Notification(name)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
// Custom observer that supports synchronous dispatch
|
||||
template <class C, class N>
|
||||
class SyncNObserver: public Poco::AbstractObserver
|
||||
{
|
||||
public:
|
||||
using NotificationPtr = Poco::AutoPtr<N>;
|
||||
using Callback = Poco::NotificationResult (C::*)(const NotificationPtr&);
|
||||
|
||||
SyncNObserver(C& object, Callback method):
|
||||
_pObject(&object),
|
||||
_callback(method)
|
||||
{
|
||||
}
|
||||
|
||||
SyncNObserver(const SyncNObserver& observer):
|
||||
Poco::AbstractObserver(observer),
|
||||
_pObject(observer._pObject),
|
||||
_callback(observer._callback)
|
||||
{
|
||||
}
|
||||
|
||||
~SyncNObserver()
|
||||
{
|
||||
}
|
||||
|
||||
SyncNObserver& operator = (const SyncNObserver& observer)
|
||||
{
|
||||
if (&observer != this)
|
||||
{
|
||||
_pObject = observer._pObject;
|
||||
_callback = observer._callback;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void notify(Poco::Notification* pNf) const override
|
||||
{
|
||||
// Async notification (not used for sync dispatch)
|
||||
Poco::AutoPtr<Poco::Notification> nf(pNf, true);
|
||||
}
|
||||
|
||||
Poco::NotificationResult notifySync(Poco::Notification* pNf) const override
|
||||
{
|
||||
NotificationPtr ptr(static_cast<N*>(pNf), true);
|
||||
return (_pObject->*_callback)(ptr);
|
||||
}
|
||||
|
||||
bool acceptsSync() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool equals(const Poco::AbstractObserver& abstractObserver) const override
|
||||
{
|
||||
const SyncNObserver* pObs = dynamic_cast<const SyncNObserver*>(&abstractObserver);
|
||||
return pObs && pObs->_pObject == _pObject && pObs->_callback == _callback;
|
||||
}
|
||||
|
||||
bool accepts(Poco::Notification* pNf, const char* /*pName*/) const override
|
||||
{
|
||||
return dynamic_cast<N*>(pNf) != nullptr;
|
||||
}
|
||||
|
||||
bool accepts(const Poco::Notification::Ptr& pNf) const override
|
||||
{
|
||||
return pNf.template cast<N>() != nullptr;
|
||||
}
|
||||
|
||||
Poco::AbstractObserver* clone() const override
|
||||
{
|
||||
return new SyncNObserver(*this);
|
||||
}
|
||||
|
||||
void disable() override
|
||||
{
|
||||
_pObject = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
C* _pObject;
|
||||
Callback _callback;
|
||||
};
|
||||
|
||||
|
||||
AsyncNotificationCenterTest::AsyncNotificationCenterTest(const std::string& name):
|
||||
CppUnit::TestCase(name),
|
||||
_handle1Done(false),
|
||||
_handleAuto1Done(false),
|
||||
_handleAsync1Done(false),
|
||||
_handleAsync2Done(false),
|
||||
_notificationCount(0),
|
||||
_syncCallCount(0),
|
||||
_threadSafeCount(0),
|
||||
_exceptionCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AsyncNotificationCenterTest::~AsyncNotificationCenterTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testAsyncObserver()
|
||||
{
|
||||
using AObserver = AsyncObserver<AsyncNotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
NotificationCenter nc;
|
||||
|
||||
nc.addObserver(AObserver(*this, &AsyncNotificationCenterTest::handleAsync1, &AsyncNotificationCenterTest::matchAsync));
|
||||
nc.addObserver(AObserver(*this, &AsyncNotificationCenterTest::handleAsync2, &AsyncNotificationCenterTest::matchAsync));
|
||||
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
nc.postNotification(new TestNotification("anotherNotification"));
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeObserver(AObserver(*this, &AsyncNotificationCenterTest::handleAsync1, &AsyncNotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(AObserver(*this, &AsyncNotificationCenterTest::handleAsync2, &AsyncNotificationCenterTest::matchAsync));
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertEqual(2u, _set.size());
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testAsyncNotificationCenter()
|
||||
{
|
||||
AsyncNotificationCenter nc;
|
||||
|
||||
nc.addAsyncObserver(*this, &AsyncNotificationCenterTest::handleAsync1, &AsyncNotificationCenterTest::matchAsync);
|
||||
nc.addAsyncObserver(*this, &AsyncNotificationCenterTest::handleAsync2, &AsyncNotificationCenterTest::matchAsync);
|
||||
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
nc.postNotification(new TestNotification("anotherNotification"));
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeAsyncObserver(*this, &AsyncNotificationCenterTest::handleAsync1, &AsyncNotificationCenterTest::matchAsync);
|
||||
nc.removeAsyncObserver(*this, &AsyncNotificationCenterTest::handleAsync2, &AsyncNotificationCenterTest::matchAsync);
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertEqual(2u, _set.size());
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testAsyncNotificationCenterModes()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
// Test ENQUEUE mode (default)
|
||||
{
|
||||
AsyncNotificationCenter nc(AsyncMode::ENQUEUE);
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
nc.postNotification(new Notification);
|
||||
while (!_handleAuto1Done)
|
||||
Poco::Thread::sleep(100);
|
||||
assertTrue(_set.find("handleAuto") != _set.end());
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
}
|
||||
|
||||
_set.clear();
|
||||
_handleAuto1Done = false;
|
||||
|
||||
// Test NOTIFY mode
|
||||
{
|
||||
AsyncNotificationCenter nc(AsyncMode::NOTIFY);
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
nc.postNotification(new Notification);
|
||||
while (!_handleAuto1Done)
|
||||
Poco::Thread::sleep(100);
|
||||
assertTrue(_set.find("handleAuto") != _set.end());
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
}
|
||||
|
||||
_set.clear();
|
||||
_handleAuto1Done = false;
|
||||
|
||||
// Test BOTH mode
|
||||
{
|
||||
AsyncNotificationCenter nc(AsyncMode::BOTH);
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
nc.postNotification(new Notification);
|
||||
while (!_handleAuto1Done)
|
||||
Poco::Thread::sleep(100);
|
||||
assertTrue(_set.find("handleAuto") != _set.end());
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testAsyncNotificationCenterWorkerCount()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
workerCount(AsyncMode::ENQUEUE);
|
||||
resetState();
|
||||
workerCount(AsyncMode::NOTIFY);
|
||||
resetState();
|
||||
workerCount(AsyncMode::BOTH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testAsyncNotificationCenterDefaultWorkers()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
// Test default worker count calculation
|
||||
std::size_t workers = AsyncNotificationCenter::defaultWorkersCount();
|
||||
unsigned int cores = std::thread::hardware_concurrency();
|
||||
|
||||
if (cores <= 2)
|
||||
assertEqual(2u, workers);
|
||||
else if (cores <= 4)
|
||||
assertEqual(3u, workers);
|
||||
else if (cores <= 8)
|
||||
assertEqual(4u, workers);
|
||||
else
|
||||
assertEqual(6u, workers);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testAsyncNotificationCenterBacklog()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
backlog(AsyncMode::ENQUEUE);
|
||||
resetState();
|
||||
backlog(AsyncMode::NOTIFY);
|
||||
resetState();
|
||||
backlog(AsyncMode::BOTH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testAsyncNotificationCenterParallelDispatch()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
parallelDispatch(AsyncMode::ENQUEUE);
|
||||
resetState();
|
||||
parallelDispatch(AsyncMode::NOTIFY);
|
||||
resetState();
|
||||
parallelDispatch(AsyncMode::BOTH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testMixedObservers()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
mixedObservers(AsyncMode::ENQUEUE);
|
||||
resetState();
|
||||
mixedObservers(AsyncMode::NOTIFY);
|
||||
resetState();
|
||||
mixedObservers(AsyncMode::BOTH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testSynchronousDispatch()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
synchronousDispatch(AsyncMode::ENQUEUE);
|
||||
resetState();
|
||||
synchronousDispatch(AsyncMode::NOTIFY);
|
||||
resetState();
|
||||
synchronousDispatch(AsyncMode::BOTH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testErrorHandling()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
// Test that exceptions from observers are caught and don't crash the system
|
||||
AsyncNotificationCenter nc(AsyncMode::ENQUEUE);
|
||||
|
||||
// Register an observer that throws
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleThrow);
|
||||
|
||||
// Register a normal observer that should still be called
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
|
||||
// Post notification - exception should be caught by ErrorHandler
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
// Give time for async processing
|
||||
Poco::Thread::sleep(200);
|
||||
|
||||
// The throwing observer should have been called
|
||||
assertTrue(_exceptionCount > 0);
|
||||
|
||||
// The normal observer should also have been called (error handling shouldn't stop dispatch)
|
||||
// Note: This depends on ErrorHandler implementation - it may or may not continue
|
||||
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleThrow);
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testThreadSafety()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
// Test concurrent postNotification calls from multiple threads
|
||||
AsyncNotificationCenter nc(AsyncMode::NOTIFY, 4);
|
||||
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleThreadSafe);
|
||||
|
||||
const int numThreads = 8;
|
||||
const int notificationsPerThread = 100;
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
// Launch multiple threads posting notifications concurrently
|
||||
for (int i = 0; i < numThreads; ++i)
|
||||
{
|
||||
threads.emplace_back([&nc, notificationsPerThread]() {
|
||||
for (int j = 0; j < notificationsPerThread; ++j)
|
||||
{
|
||||
nc.postNotification(new Notification);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Wait for all threads to finish posting
|
||||
for (auto& t : threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
// Wait for all notifications to be processed
|
||||
int timeout = 0;
|
||||
int expected = numThreads * notificationsPerThread;
|
||||
while (_threadSafeCount < expected && timeout < 200)
|
||||
{
|
||||
Poco::Thread::sleep(50);
|
||||
++timeout;
|
||||
}
|
||||
|
||||
// Verify all notifications were received
|
||||
assertEqual(expected, _threadSafeCount.load());
|
||||
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleThreadSafe);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testObserverLifecycle()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
// Test removing observer while notifications are being dispatched
|
||||
AsyncNotificationCenter nc(AsyncMode::NOTIFY, 2);
|
||||
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
|
||||
// Post many notifications
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
nc.postNotification(new Notification);
|
||||
}
|
||||
|
||||
// Give a tiny bit of time for processing to start
|
||||
Poco::Thread::sleep(10);
|
||||
|
||||
// Remove observer while notifications might still be in queue
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
|
||||
// Wait a bit for cleanup
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
// Test passes if:
|
||||
// 1. We didn't crash
|
||||
// 2. Count is in valid range (some might have been processed before removal)
|
||||
int finalCount = _notificationCount;
|
||||
assertTrue(finalCount >= 0 && finalCount <= 100);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testCleanupDestruction()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
const int testCount = 50;
|
||||
|
||||
// Test 1: NOTIFY mode - workers stop immediately, may not process all notifications
|
||||
{
|
||||
_notificationCount = 0;
|
||||
AsyncNotificationCenter nc(AsyncMode::NOTIFY, 2);
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
|
||||
for (int i = 0; i < testCount; ++i)
|
||||
{
|
||||
nc.postNotification(new Notification);
|
||||
}
|
||||
|
||||
Poco::Thread::sleep(5);
|
||||
// Destructor should complete quickly, possibly without processing all notifications
|
||||
}
|
||||
int notifyProcessed = _notificationCount.load();
|
||||
|
||||
// Test 2: ENQUEUE mode - must process all queued notifications before destructor completes
|
||||
int startCount = _notificationCount.load();
|
||||
{
|
||||
AsyncNotificationCenter nc(AsyncMode::ENQUEUE);
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
|
||||
for (int i = 0; i < testCount; ++i)
|
||||
{
|
||||
nc.postNotification(new Notification);
|
||||
}
|
||||
|
||||
// Give a moment for enqueue thread to start processing
|
||||
Poco::Thread::sleep(10);
|
||||
|
||||
// Destructor MUST process all remaining notifications in ENQUEUE mode
|
||||
}
|
||||
|
||||
// Verify ENQUEUE processed all notifications
|
||||
int enqueueProcessed = _notificationCount.load() - startCount;
|
||||
assertEqual(testCount, enqueueProcessed);
|
||||
|
||||
// NOTIFY may have processed fewer (workers stop immediately when destructor runs)
|
||||
assertTrue(notifyProcessed >= 0 && notifyProcessed <= testCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::testEdgeCases()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
// Test 1: Post to empty observer list
|
||||
{
|
||||
AsyncNotificationCenter nc(AsyncMode::NOTIFY);
|
||||
nc.postNotification(new Notification);
|
||||
Poco::Thread::sleep(50);
|
||||
// Should not crash
|
||||
}
|
||||
|
||||
// Test 2: Stress test with many notifications
|
||||
{
|
||||
AsyncNotificationCenter nc(AsyncMode::BOTH, 4);
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
|
||||
const int stressCount = 1000;
|
||||
for (int i = 0; i < stressCount; ++i)
|
||||
{
|
||||
nc.postNotification(new Notification);
|
||||
}
|
||||
|
||||
// Wait for all to process (max 10 seconds)
|
||||
int timeout = 0;
|
||||
while (_notificationCount < stressCount && timeout < 100)
|
||||
{
|
||||
Poco::Thread::sleep(100);
|
||||
++timeout;
|
||||
}
|
||||
|
||||
// Verify we got most/all notifications
|
||||
int received = _notificationCount.load();
|
||||
assertTrue(received >= stressCount * 0.9); // Allow 10% loss for timing issues
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
}
|
||||
|
||||
// Test 3: Observer registering other observers during notification
|
||||
// This is complex and can lead to undefined behavior, so we skip it
|
||||
// as it's not a supported use case
|
||||
|
||||
assertTrue(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
|
||||
void AsyncNotificationCenterTest::workerCount(AsyncMode mode)
|
||||
{
|
||||
AsyncNotificationCenter nc(mode, 8);
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
nc.postNotification(new Notification);
|
||||
while (!_handleAuto1Done)
|
||||
Poco::Thread::sleep(100);
|
||||
assertTrue(_set.find("handleAuto") != _set.end());
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::backlog(AsyncMode mode)
|
||||
{
|
||||
AsyncNotificationCenter nc(mode);
|
||||
|
||||
// Post notifications without observers (they'll queue up)
|
||||
nc.postNotification(new Notification);
|
||||
nc.postNotification(new Notification);
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
// Give time to process
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
// Backlog should be drained (or nearly drained)
|
||||
int backlog = nc.backlog();
|
||||
assertTrue(backlog >= 0);
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::parallelDispatch(AsyncMode mode)
|
||||
{
|
||||
AsyncNotificationCenter nc(mode, 4);
|
||||
|
||||
_notificationCount = 0;
|
||||
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
|
||||
// Post multiple notifications
|
||||
const int numNotifications = 10;
|
||||
for (int i = 0; i < numNotifications; ++i)
|
||||
{
|
||||
nc.postNotification(new Notification);
|
||||
}
|
||||
|
||||
// Wait for all to be processed
|
||||
int timeout = 0;
|
||||
while (_notificationCount < numNotifications && timeout < 100)
|
||||
{
|
||||
Poco::Thread::sleep(50);
|
||||
++timeout;
|
||||
}
|
||||
|
||||
assertEqual(numNotifications, _notificationCount.load());
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::mixedObservers(AsyncMode mode)
|
||||
{
|
||||
AsyncNotificationCenter nc(mode);
|
||||
|
||||
nc.addObserver<AsyncNotificationCenterTest, Notification>(*this, &AsyncNotificationCenterTest::handle1);
|
||||
nc.addNObserver<AsyncNotificationCenterTest, Notification>(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
nc.addAsyncObserver<AsyncNotificationCenterTest, TestNotification>(*this, &AsyncNotificationCenterTest::handleAsync1, &AsyncNotificationCenterTest::matchAsync);
|
||||
|
||||
nc.postNotification(new Notification);
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
|
||||
while (!_handle1Done || !_handleAuto1Done || !_handleAsync1Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeAsyncObserver<AsyncNotificationCenterTest, TestNotification>(*this, &AsyncNotificationCenterTest::handleAsync1, &AsyncNotificationCenterTest::matchAsync);
|
||||
nc.removeNObserver<AsyncNotificationCenterTest, Notification>(*this, &AsyncNotificationCenterTest::handleAuto);
|
||||
nc.removeObserver<AsyncNotificationCenterTest, Notification>(*this, &AsyncNotificationCenterTest::handle1);
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertEqual(3u, _set.size());
|
||||
assertTrue (_set.find("handle1") != _set.end());
|
||||
assertTrue (_set.find("handleAuto") != _set.end());
|
||||
assertTrue (_set.find("handleAsync1") != _set.end());
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::synchronousDispatch(AsyncMode mode)
|
||||
{
|
||||
AsyncNotificationCenter nc(mode);
|
||||
|
||||
// Register sync observers using custom SyncNObserver
|
||||
using SyncObs = SyncNObserver<AsyncNotificationCenterTest, Notification>;
|
||||
nc.addObserver(SyncObs(*this, &AsyncNotificationCenterTest::handleSync));
|
||||
|
||||
// Also register a regular NObserver (should not be called by synchronousDispatch)
|
||||
nc.addNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
|
||||
// Call synchronousDispatch - should only call sync observers
|
||||
auto results = nc.synchronousDispatch(new Notification);
|
||||
|
||||
// Verify that handleSync was called (returns result)
|
||||
assertEqual(1u, results.size());
|
||||
assertTrue(results[0].first == "result");
|
||||
assertEqual(1, Poco::AnyCast<int>(results[0].second));
|
||||
assertEqual(1, _syncCallCount.load());
|
||||
|
||||
// Verify that handleCount was NOT called by synchronousDispatch
|
||||
assertEqual(0, _notificationCount.load());
|
||||
|
||||
// Test with no sync observers - should return empty vector
|
||||
nc.removeObserver(SyncObs(*this, &AsyncNotificationCenterTest::handleSync));
|
||||
results = nc.synchronousDispatch(new Notification);
|
||||
assertEqual(0u, results.size());
|
||||
|
||||
nc.removeNObserver(*this, &AsyncNotificationCenterTest::handleCount);
|
||||
}
|
||||
|
||||
#endif // POCO_HAVE_JTHREAD
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::handle1(Poco::Notification* pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
poco_check_ptr (pNf);
|
||||
AutoPtr<Notification> nf = pNf;
|
||||
_set.insert("handle1");
|
||||
_handle1Done = true;
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::handleAuto(const AutoPtr<Notification>& pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
_set.insert("handleAuto");
|
||||
_handleAuto1Done = true;
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::handleAsync1(const AutoPtr<TestNotification>& pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
_set.insert("handleAsync1");
|
||||
_handleAsync1Done = true;
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::handleAsync2(const AutoPtr<TestNotification>& pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
_set.insert("handleAsync2");
|
||||
_handleAsync2Done = true;
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::handleCount(const AutoPtr<Notification>& pNf)
|
||||
{
|
||||
++_notificationCount;
|
||||
}
|
||||
|
||||
|
||||
Poco::NotificationResult AsyncNotificationCenterTest::handleSync(const AutoPtr<Notification>& pNf)
|
||||
{
|
||||
int callNum = ++_syncCallCount;
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
_set.insert("handleSync");
|
||||
return {"result", callNum};
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::handleThrow(const AutoPtr<Notification>& pNf)
|
||||
{
|
||||
++_exceptionCount;
|
||||
throw Poco::RuntimeException("Test exception from observer");
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::handleThreadSafe(const AutoPtr<Notification>& pNf)
|
||||
{
|
||||
++_threadSafeCount;
|
||||
// Simulate some processing time
|
||||
Poco::Thread::sleep(1);
|
||||
}
|
||||
|
||||
|
||||
bool AsyncNotificationCenterTest::matchAsync(const std::string& name) const
|
||||
{
|
||||
return name.find("asyncNotification") == 0;
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::resetState()
|
||||
{
|
||||
_set.clear();
|
||||
_notificationCount = 0;
|
||||
_syncCallCount = 0;
|
||||
_threadSafeCount = 0;
|
||||
_exceptionCount = 0;
|
||||
_handle1Done = false;
|
||||
_handleAuto1Done = false;
|
||||
_handleAsync1Done = false;
|
||||
_handleAsync2Done = false;
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::setUp()
|
||||
{
|
||||
resetState();
|
||||
}
|
||||
|
||||
|
||||
void AsyncNotificationCenterTest::tearDown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
CppUnit::Test* AsyncNotificationCenterTest::suite()
|
||||
{
|
||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("AsyncNotificationCenterTest");
|
||||
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testAsyncObserver);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testAsyncNotificationCenter);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testAsyncNotificationCenterModes);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testAsyncNotificationCenterWorkerCount);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testAsyncNotificationCenterDefaultWorkers);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testAsyncNotificationCenterBacklog);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testAsyncNotificationCenterParallelDispatch);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testMixedObservers);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testSynchronousDispatch);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testErrorHandling);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testThreadSafety);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testObserverLifecycle);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testCleanupDestruction);
|
||||
CppUnit_addTest(pSuite, AsyncNotificationCenterTest, testEdgeCases);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
119
Foundation/testsuite/src/AsyncNotificationCenterTest.h
Normal file
119
Foundation/testsuite/src/AsyncNotificationCenterTest.h
Normal file
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// AsyncNotificationCenterTest.h
|
||||
//
|
||||
// Definition of the AsyncNotificationCenterTest class.
|
||||
//
|
||||
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef AsyncNotificationCenterTest_INCLUDED
|
||||
#define AsyncNotificationCenterTest_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Foundation.h"
|
||||
#include "CppUnit/TestCase.h"
|
||||
#include "Poco/Notification.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/Mutex.h"
|
||||
#include "Poco/AsyncNotificationCenter.h"
|
||||
#include <set>
|
||||
|
||||
|
||||
class TestNotification;
|
||||
|
||||
|
||||
class AsyncNotificationCenterTest: public CppUnit::TestCase
|
||||
{
|
||||
public:
|
||||
AsyncNotificationCenterTest(const std::string& name);
|
||||
~AsyncNotificationCenterTest();
|
||||
|
||||
void testAsyncObserver();
|
||||
/// Tests AsyncObserver with NotificationCenter (async dispatch in observer's own thread)
|
||||
|
||||
void testAsyncNotificationCenter();
|
||||
/// Tests AsyncObserver with AsyncNotificationCenter (async dispatch in NC's worker pool)
|
||||
|
||||
void testAsyncNotificationCenterModes();
|
||||
/// Tests AsyncNotificationCenter modes: ENQUEUE, NOTIFY, and BOTH
|
||||
|
||||
void testAsyncNotificationCenterWorkerCount();
|
||||
/// Tests AsyncNotificationCenter with custom worker thread count
|
||||
|
||||
void testAsyncNotificationCenterDefaultWorkers();
|
||||
/// Tests that default worker count scales with CPU cores (2-6 workers)
|
||||
|
||||
void testAsyncNotificationCenterBacklog();
|
||||
/// Tests backlog() method returns queued notification count
|
||||
|
||||
void testAsyncNotificationCenterParallelDispatch();
|
||||
/// Tests that multiple workers dispatch notifications in parallel
|
||||
|
||||
void testMixedObservers();
|
||||
/// Tests mixing Observer, NObserver, and AsyncObserver in same NotificationCenter
|
||||
|
||||
void testSynchronousDispatch();
|
||||
/// Tests synchronousDispatch() method that returns results from sync observers
|
||||
|
||||
void testErrorHandling();
|
||||
/// Tests that exceptions thrown by observers are handled gracefully
|
||||
|
||||
void testThreadSafety();
|
||||
/// Tests concurrent postNotification() calls from multiple threads
|
||||
|
||||
void testObserverLifecycle();
|
||||
/// Tests removing observers while notifications are being dispatched
|
||||
|
||||
void testCleanupDestruction();
|
||||
/// Tests stopping AsyncNotificationCenter while notifications are queued/processing
|
||||
|
||||
void testEdgeCases();
|
||||
/// Tests edge cases: empty observer list, stress testing, dynamic observer registration
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
static CppUnit::Test* suite();
|
||||
|
||||
protected:
|
||||
void handle1(Poco::Notification* pNf);
|
||||
void handleAsync1(const Poco::AutoPtr<TestNotification>& pNf);
|
||||
void handleAsync2(const Poco::AutoPtr<TestNotification>& pNf);
|
||||
void handleAuto(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
void handleCount(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
Poco::NotificationResult handleSync(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
void handleThrow(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
void handleThreadSafe(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
bool matchAsync(const std::string& name) const;
|
||||
|
||||
void resetState();
|
||||
/// Resets test state between sub-tests. Not to be confused with setUp() which is called by the framework.
|
||||
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
void workerCount(Poco::AsyncNotificationCenter::AsyncMode mode);
|
||||
void backlog(Poco::AsyncNotificationCenter::AsyncMode mode);
|
||||
void parallelDispatch(Poco::AsyncNotificationCenter::AsyncMode mode);
|
||||
void mixedObservers(Poco::AsyncNotificationCenter::AsyncMode mode);
|
||||
void synchronousDispatch(Poco::AsyncNotificationCenter::AsyncMode mode);
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::set<std::string> _set;
|
||||
std::atomic<bool> _handle1Done;
|
||||
std::atomic<bool> _handleAuto1Done;
|
||||
std::atomic<bool> _handleAsync1Done;
|
||||
std::atomic<bool> _handleAsync2Done;
|
||||
std::atomic<int> _notificationCount;
|
||||
std::atomic<int> _syncCallCount;
|
||||
std::atomic<int> _threadSafeCount;
|
||||
std::atomic<int> _exceptionCount;
|
||||
Poco::Mutex _mutex;
|
||||
};
|
||||
|
||||
|
||||
#endif // AsyncNotificationCenterTest_INCLUDED
|
||||
@@ -10,43 +10,43 @@
|
||||
|
||||
#include "NotificationCenterTest.h"
|
||||
#include "CppUnit/TestCaller.h"
|
||||
#include "CppUnit/TestCase.h"
|
||||
#include "CppUnit/TestSuite.h"
|
||||
#include "Poco/Notification.h"
|
||||
#include "Poco/NotificationCenter.h"
|
||||
#include "Poco/AsyncNotificationCenter.h"
|
||||
#include "Poco/Observer.h"
|
||||
#include "Poco/NObserver.h"
|
||||
#include "Poco/AsyncObserver.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
|
||||
|
||||
using Poco::NotificationCenter;
|
||||
using Poco::AsyncNotificationCenter;
|
||||
using Poco::Observer;
|
||||
using Poco::NObserver;
|
||||
using Poco::AsyncObserver;
|
||||
using Poco::Notification;
|
||||
using Poco::AutoPtr;
|
||||
|
||||
|
||||
class TestNotification: public Notification
|
||||
{
|
||||
public:
|
||||
TestNotification() = default;
|
||||
|
||||
TestNotification(const std::string& name, int n = 0):
|
||||
Notification(name), num(n)
|
||||
TestNotification()
|
||||
{}
|
||||
|
||||
int num {0};
|
||||
TestNotification(const std::string& name):
|
||||
Notification(name)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
NotificationCenterTest::NotificationCenterTest(const std::string& name):
|
||||
CppUnit::TestCase(name)
|
||||
CppUnit::TestCase(name),
|
||||
_handle1Done(false),
|
||||
_handleAuto1Done(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NotificationCenterTest::~NotificationCenterTest() = default;
|
||||
NotificationCenterTest::~NotificationCenterTest()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testNotificationCenter1()
|
||||
@@ -59,7 +59,7 @@ void NotificationCenterTest::testNotificationCenter1()
|
||||
void NotificationCenterTest::testNotificationCenter2()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
NObserver<NotificationCenterTest, Notification> o(*this, &NotificationCenterTest::handle1);
|
||||
Observer<NotificationCenterTest, Notification> o(*this, &NotificationCenterTest::handle1);
|
||||
nc.addObserver(o);
|
||||
assertTrue (nc.hasObserver(o));
|
||||
assertTrue (nc.hasObservers());
|
||||
@@ -67,7 +67,7 @@ void NotificationCenterTest::testNotificationCenter2()
|
||||
nc.postNotification(new Notification);
|
||||
assertTrue (_set.size() == 1);
|
||||
assertTrue (_set.find("handle1") != _set.end());
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
assertTrue (!nc.hasObserver(o));
|
||||
assertTrue (!nc.hasObservers());
|
||||
assertTrue (nc.countObservers() == 0);
|
||||
@@ -77,8 +77,8 @@ void NotificationCenterTest::testNotificationCenter2()
|
||||
void NotificationCenterTest::testNotificationCenter3()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
NObserver<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||
NObserver<NotificationCenterTest, Notification> o2(*this, &NotificationCenterTest::handle2);
|
||||
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||
Observer<NotificationCenterTest, Notification> o2(*this, &NotificationCenterTest::handle2);
|
||||
nc.addObserver(o1);
|
||||
assertTrue (nc.hasObserver(o1));
|
||||
nc.addObserver(o2);
|
||||
@@ -89,9 +89,9 @@ void NotificationCenterTest::testNotificationCenter3()
|
||||
assertTrue (_set.size() == 2);
|
||||
assertTrue (_set.find("handle1") != _set.end());
|
||||
assertTrue (_set.find("handle2") != _set.end());
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
assertTrue (!nc.hasObserver(o1));
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle2));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle2));
|
||||
assertTrue (!nc.hasObserver(o2));
|
||||
assertTrue (!nc.hasObservers());
|
||||
assertTrue (nc.countObservers() == 0);
|
||||
@@ -101,8 +101,8 @@ void NotificationCenterTest::testNotificationCenter3()
|
||||
void NotificationCenterTest::testNotificationCenter4()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
NObserver<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||
NObserver<NotificationCenterTest, Notification> o2(*this, &NotificationCenterTest::handle2);
|
||||
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||
Observer<NotificationCenterTest, Notification> o2(*this, &NotificationCenterTest::handle2);
|
||||
nc.addObserver(o1);
|
||||
assertTrue (nc.hasObserver(o1));
|
||||
nc.addObserver(o2);
|
||||
@@ -111,20 +111,20 @@ void NotificationCenterTest::testNotificationCenter4()
|
||||
assertTrue (_set.size() == 2);
|
||||
assertTrue (_set.find("handle1") != _set.end());
|
||||
assertTrue (_set.find("handle2") != _set.end());
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
assertTrue (!nc.hasObserver(o1));
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle2));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle2));
|
||||
assertTrue (!nc.hasObserver(o2));
|
||||
_set.clear();
|
||||
nc.postNotification(new Notification);
|
||||
assertTrue (_set.empty());
|
||||
NObserver<NotificationCenterTest, Notification> o3(*this, &NotificationCenterTest::handle3);
|
||||
Observer<NotificationCenterTest, Notification> o3(*this, &NotificationCenterTest::handle3);
|
||||
nc.addObserver(o3);
|
||||
assertTrue (nc.hasObserver(o3));
|
||||
nc.postNotification(new Notification);
|
||||
assertTrue (_set.size() == 1);
|
||||
assertTrue (_set.find("handle3") != _set.end());
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle3));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle3));
|
||||
assertTrue (!nc.hasObserver(o3));
|
||||
}
|
||||
|
||||
@@ -132,8 +132,8 @@ void NotificationCenterTest::testNotificationCenter4()
|
||||
void NotificationCenterTest::testNotificationCenter5()
|
||||
{
|
||||
NotificationCenter nc;
|
||||
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.addObserver(NObserver<NotificationCenterTest, TestNotification>(*this, &NotificationCenterTest::handleTest));
|
||||
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.addObserver(Observer<NotificationCenterTest, TestNotification>(*this, &NotificationCenterTest::handleTest));
|
||||
nc.postNotification(new Notification);
|
||||
assertTrue (_set.size() == 1);
|
||||
assertTrue (_set.find("handle1") != _set.end());
|
||||
@@ -142,8 +142,8 @@ void NotificationCenterTest::testNotificationCenter5()
|
||||
assertTrue (_set.size() == 2);
|
||||
assertTrue (_set.find("handle1") != _set.end());
|
||||
assertTrue (_set.find("handleTest") != _set.end());
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, TestNotification>(*this, &NotificationCenterTest::handleTest));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, TestNotification>(*this, &NotificationCenterTest::handleTest));
|
||||
}
|
||||
|
||||
|
||||
@@ -158,309 +158,47 @@ void NotificationCenterTest::testNotificationCenterAuto()
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testAsyncObserver()
|
||||
{
|
||||
using ObserverT = AsyncObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
NotificationCenter nc;
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
nc.postNotification(new TestNotification("anotherNotification"));
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 2);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testAsyncNotificationCenter()
|
||||
{
|
||||
using ObserverT = NObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc;
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
nc.postNotification(new TestNotification("anotherNotification"));
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 2);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testAsyncNotificationCenter2()
|
||||
{
|
||||
using ObserverT = NObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc;
|
||||
|
||||
const auto matchAsync = [](const std::string& s) -> bool
|
||||
{
|
||||
return s.find("asyncNotification") == 0;
|
||||
};
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, matchAsync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, matchAsync));
|
||||
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
nc.postNotification(new TestNotification("anotherNotification"));
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 2);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
}
|
||||
|
||||
void NotificationCenterTest::testAsyncNotificationCenterSyncNotify()
|
||||
{
|
||||
using ObserverT = NObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc;
|
||||
|
||||
const auto matchAsync = [](const std::string& s) -> bool
|
||||
{
|
||||
return s.find("asyncNotification") == 0;
|
||||
};
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, matchAsync, &NotificationCenterTest::handleSync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, matchAsync));
|
||||
|
||||
const auto res = nc.synchronousDispatch(new TestNotification("asyncNotification"));
|
||||
assertFalse(res.empty());
|
||||
assertEquals(res.size(), 1);
|
||||
assertEquals(res[0].first, "handleAsync1");
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 1);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_handleAsync1Counter == 1);
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testAsyncNotificationCenterAsyncNotify()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
|
||||
using ObserverT = NObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc(AsyncNotificationCenter::AsyncMode::NOTIFY);
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
nc.postNotification(new TestNotification("anotherNotification"));
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 2);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testAsyncNotificationCenterAsyncBoth()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
|
||||
using ObserverT = NObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc(AsyncNotificationCenter::AsyncMode::BOTH);
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
nc.postNotification(new TestNotification("anotherNotification"));
|
||||
nc.postNotification(new Notification);
|
||||
|
||||
while (!_handleAsync1Done || !_handleAsync2Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 2);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testAsyncNotificationCenterAsyncNotifyStress()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
|
||||
using ObserverT = NObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc(AsyncNotificationCenter::AsyncMode::NOTIFY);
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
for (int i {0}; i < 1000; ++i)
|
||||
{
|
||||
nc.postNotification(new TestNotification("asyncNotification", i));
|
||||
nc.postNotification(new TestNotification("anotherNotification", i));
|
||||
nc.postNotification(new Notification);
|
||||
}
|
||||
|
||||
// Give enough time for the notifications to be delivered
|
||||
Poco::Thread::sleep(2000);
|
||||
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 2);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
|
||||
assertTrue(_handleAsync1Counter == 1000ul);
|
||||
assertTrue(_handleAsync2Counter == 1000ul);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testAsyncNotificationCenterAsyncRemoveObserver()
|
||||
{
|
||||
#if (POCO_HAVE_JTHREAD)
|
||||
|
||||
using ObserverT = NObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc(AsyncNotificationCenter::AsyncMode::NOTIFY);
|
||||
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.addObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
|
||||
for (int i {0}; i < 1000; ++i)
|
||||
{
|
||||
nc.postNotification(new TestNotification("asyncNotification", i));
|
||||
nc.postNotification(new TestNotification("anotherNotification", i));
|
||||
|
||||
if (i == 100)
|
||||
{
|
||||
while (!_handleAsync2Done)
|
||||
Poco::Thread::sleep(50);
|
||||
// Remove one observer while notifications are still being posted
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync2, &NotificationCenterTest::matchAsync));
|
||||
}
|
||||
}
|
||||
|
||||
// Give enough time for the notifications to be delivered
|
||||
Poco::Thread::sleep(2000);
|
||||
|
||||
nc.removeObserver(ObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue(_set.size() == 2);
|
||||
assertTrue(_set.find("handleAsync1") != _set.end());
|
||||
assertTrue(_set.find("handleAsync2") != _set.end());
|
||||
|
||||
assertTrue(_handleAsync1Counter == 1000ul);
|
||||
assertTrue(_handleAsync2Counter < 1000ul);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testDefaultNotificationCenter()
|
||||
{
|
||||
NotificationCenter& nc = NotificationCenter::defaultCenter();
|
||||
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.postNotification(new Notification);
|
||||
assertTrue (_set.size() == 1);
|
||||
assertTrue (_set.find("handle1") != _set.end());
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::testMixedObservers()
|
||||
{
|
||||
using AObserverT = AsyncObserver<NotificationCenterTest, TestNotification>::Type;
|
||||
|
||||
AsyncNotificationCenter nc;
|
||||
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handleAuto));
|
||||
nc.addObserver(AObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.postNotification(new Notification);
|
||||
nc.postNotification(new TestNotification("asyncNotification"));
|
||||
|
||||
while (!_handle1Done || !_handleAuto1Done || !_handleAsync1Done)
|
||||
Poco::Thread::sleep(100);
|
||||
|
||||
nc.removeObserver(AObserverT(*this, &NotificationCenterTest::handleAsync1, &NotificationCenterTest::matchAsync));
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handleAuto));
|
||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
assertTrue (_set.size() == 3);
|
||||
assertTrue (_set.find("handle1") != _set.end());
|
||||
assertTrue (_set.find("handleAuto") != _set.end());
|
||||
assertTrue (_set.find("handleAsync1") != _set.end());
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::handle1(const AutoPtr<Notification>& pNf)
|
||||
void NotificationCenterTest::handle1(Poco::Notification* pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
poco_check_ptr (pNf);
|
||||
AutoPtr<Notification> nf = pNf;
|
||||
_set.insert("handle1");
|
||||
_handle1Done = true;
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::handle2(const AutoPtr<Notification>& pNf)
|
||||
void NotificationCenterTest::handle2(Poco::Notification* pNf)
|
||||
{
|
||||
poco_check_ptr (pNf);
|
||||
AutoPtr<Notification> nf = pNf;
|
||||
_set.insert("handle2");
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::handle3(const AutoPtr<Notification>& pNf)
|
||||
void NotificationCenterTest::handle3(Poco::Notification* pNf)
|
||||
{
|
||||
poco_check_ptr (pNf);
|
||||
AutoPtr<Notification> nf = pNf;
|
||||
_set.insert("handle3");
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::handleTest(const AutoPtr<TestNotification>& pNf)
|
||||
void NotificationCenterTest::handleTest(TestNotification* pNf)
|
||||
{
|
||||
poco_check_ptr (pNf);
|
||||
AutoPtr<TestNotification> nf = pNf;
|
||||
_set.insert("handleTest");
|
||||
}
|
||||
|
||||
@@ -473,48 +211,11 @@ void NotificationCenterTest::handleAuto(const AutoPtr<Notification>& pNf)
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::handleAsync1(const AutoPtr<TestNotification>& pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
_set.insert("handleAsync1");
|
||||
_handleAsync1Done = true;
|
||||
_handleAsync1Counter++;
|
||||
}
|
||||
|
||||
Poco::NotificationResult NotificationCenterTest::handleSync(const AutoPtr<TestNotification>& pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
|
||||
_set.insert("handleAsync1");
|
||||
return std::make_pair("handleAsync1", Poco::Any(++_handleAsync1Counter));
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::handleAsync2(const AutoPtr<TestNotification>& pNf)
|
||||
{
|
||||
Poco::Mutex::ScopedLock l(_mutex);
|
||||
_set.insert("handleAsync2");
|
||||
_handleAsync2Done = true;
|
||||
_handleAsync2Counter++;
|
||||
}
|
||||
|
||||
|
||||
bool NotificationCenterTest::matchAsync(const std::string& name) const
|
||||
{
|
||||
return name.find("asyncNotification") == 0;
|
||||
}
|
||||
|
||||
|
||||
void NotificationCenterTest::setUp()
|
||||
{
|
||||
_set.clear();
|
||||
_handle1Done = false;
|
||||
_handleAuto1Done = false;
|
||||
_handleAsync1Done = false;
|
||||
_handleAsync2Done = false;
|
||||
|
||||
_handleAsync1Counter = 0;
|
||||
_handleAsync2Counter = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -533,16 +234,7 @@ CppUnit::Test* NotificationCenterTest::suite()
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter4);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter5);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenterAuto);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncObserver);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncNotificationCenter);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncNotificationCenter2);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncNotificationCenterSyncNotify);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncNotificationCenterAsyncNotify);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncNotificationCenterAsyncBoth);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncNotificationCenterAsyncNotifyStress);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testAsyncNotificationCenterAsyncRemoveObserver);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testDefaultNotificationCenter);
|
||||
CppUnit_addTest(pSuite, NotificationCenterTest, testMixedObservers);
|
||||
|
||||
return pSuite;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ class NotificationCenterTest: public CppUnit::TestCase
|
||||
{
|
||||
public:
|
||||
NotificationCenterTest(const std::string& name);
|
||||
~NotificationCenterTest() override;
|
||||
~NotificationCenterTest();
|
||||
|
||||
void testNotificationCenter1();
|
||||
void testNotificationCenter2();
|
||||
@@ -37,43 +37,24 @@ public:
|
||||
void testNotificationCenter4();
|
||||
void testNotificationCenter5();
|
||||
void testNotificationCenterAuto();
|
||||
void testAsyncObserver();
|
||||
void testAsyncNotificationCenter();
|
||||
void testAsyncNotificationCenter2();
|
||||
void testAsyncNotificationCenterSyncNotify();
|
||||
void testAsyncNotificationCenterAsyncNotify();
|
||||
void testAsyncNotificationCenterAsyncBoth();
|
||||
void testAsyncNotificationCenterAsyncNotifyStress();
|
||||
void testAsyncNotificationCenterAsyncRemoveObserver();
|
||||
void testDefaultNotificationCenter();
|
||||
void testMixedObservers();
|
||||
|
||||
void setUp() override;
|
||||
void tearDown() override;
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
static CppUnit::Test* suite();
|
||||
|
||||
protected:
|
||||
void handle1(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
void handle2(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
void handle3(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
void handleTest(const Poco::AutoPtr<TestNotification>& pNf);
|
||||
void handle1(Poco::Notification* pNf);
|
||||
void handle2(Poco::Notification* pNf);
|
||||
void handle3(Poco::Notification* pNf);
|
||||
void handleTest(TestNotification* pNf);
|
||||
void handleAuto(const Poco::AutoPtr<Poco::Notification>& pNf);
|
||||
void handleAsync1(const Poco::AutoPtr<TestNotification>& pNf);
|
||||
void handleAsync2(const Poco::AutoPtr<TestNotification>& pNf);
|
||||
Poco::NotificationResult handleSync(const Poco::AutoPtr<TestNotification>& pNf);
|
||||
bool matchAsync(const std::string& name) const;
|
||||
|
||||
private:
|
||||
std::set<std::string> _set;
|
||||
std::atomic<bool> _handle1Done {false};
|
||||
std::atomic<bool> _handleAuto1Done {false};
|
||||
std::atomic<bool> _handleAsync1Done {false};
|
||||
std::atomic<bool> _handleAsync2Done {false};
|
||||
|
||||
std::atomic<std::size_t> _handleAsync1Counter {0};
|
||||
std::atomic<std::size_t> _handleAsync2Counter {0};
|
||||
|
||||
std::atomic<bool> _handle1Done;
|
||||
std::atomic<bool> _handleAuto1Done;
|
||||
Poco::Mutex _mutex;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "NotificationsTestSuite.h"
|
||||
#include "NotificationCenterTest.h"
|
||||
#include "AsyncNotificationCenterTest.h"
|
||||
#include "NotificationQueueTest.h"
|
||||
#include "PriorityNotificationQueueTest.h"
|
||||
#include "TimedNotificationQueueTest.h"
|
||||
@@ -20,6 +21,7 @@ CppUnit::Test* NotificationsTestSuite::suite()
|
||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NotificationsTestSuite");
|
||||
|
||||
pSuite->addTest(NotificationCenterTest::suite());
|
||||
pSuite->addTest(AsyncNotificationCenterTest::suite());
|
||||
pSuite->addTest(NotificationQueueTest::suite());
|
||||
pSuite->addTest(PriorityNotificationQueueTest::suite());
|
||||
pSuite->addTest(TimedNotificationQueueTest::suite());
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// ProcessRunnerTest.cpp
|
||||
//
|
||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Definition of the ProcessRunnerTest class.
|
||||
//
|
||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||
// Aleph ONE Software Engineering d.o.o.,
|
||||
// Aleph ONE Software Engineering LLC,
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
@@ -26,7 +26,7 @@ class ProcessRunnerTest: public CppUnit::TestCase
|
||||
public:
|
||||
ProcessRunnerTest(const std::string& name);
|
||||
~ProcessRunnerTest();
|
||||
|
||||
|
||||
void testPIDFile();
|
||||
void testProcessRunner();
|
||||
|
||||
|
||||
0
poco_env.bash
Normal file → Executable file
0
poco_env.bash
Normal file → Executable file
Reference in New Issue
Block a user