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.
|
// header file.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.,
|
// 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
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
// Definition of the SQLExecutor class.
|
// Definition of the SQLExecutor class.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.,
|
// 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
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// Definition of the AsyncNotificationCenter class.
|
// Definition of the AsyncNotificationCenter class.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||||
// Aleph ONE Software Engineering d.o.o.,
|
// Aleph ONE Software Engineering LLC,
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "Poco/Thread.h"
|
#include "Poco/Thread.h"
|
||||||
#include "Poco/RunnableAdapter.h"
|
#include "Poco/RunnableAdapter.h"
|
||||||
#include "Poco/NotificationQueue.h"
|
#include "Poco/NotificationQueue.h"
|
||||||
|
#include "Poco/AsyncObserver.h"
|
||||||
|
|
||||||
#if (POCO_HAVE_CPP20_COMPILER)
|
#if (POCO_HAVE_CPP20_COMPILER)
|
||||||
#if !(POCO_HAVE_JTHREAD)
|
#if !(POCO_HAVE_JTHREAD)
|
||||||
@@ -80,8 +81,11 @@ public:
|
|||||||
|
|
||||||
#if (POCO_HAVE_JTHREAD)
|
#if (POCO_HAVE_JTHREAD)
|
||||||
|
|
||||||
AsyncNotificationCenter(AsyncMode mode = AsyncMode::ENQUEUE, std::size_t workersCount = AsyncNotificationCenter::DEFAULT_WORKERS_COUNT);
|
explicit AsyncNotificationCenter(AsyncMode mode = AsyncMode::ENQUEUE);
|
||||||
/// Creates the AsyncNotificationCenter and starts the notifying thread and workers.
|
/// 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
|
#else
|
||||||
|
|
||||||
AsyncNotificationCenter();
|
AsyncNotificationCenter();
|
||||||
@@ -109,6 +113,33 @@ public:
|
|||||||
/// This method blocks until the notification is processed by
|
/// This method blocks until the notification is processed by
|
||||||
/// all observers. Returns results from all observers that accepted the notification.
|
/// 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:
|
protected:
|
||||||
|
|
||||||
void notifyObservers(Notification::Ptr& pNotification) override;
|
void notifyObservers(Notification::Ptr& pNotification) override;
|
||||||
@@ -120,11 +151,6 @@ private:
|
|||||||
|
|
||||||
using Adapter = RunnableAdapter<AsyncNotificationCenter>;
|
using Adapter = RunnableAdapter<AsyncNotificationCenter>;
|
||||||
|
|
||||||
class ShutdownNotification: public Notification
|
|
||||||
/// Internal notification used to signal the dequeue loop to stop.
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
const AsyncMode _mode { AsyncMode::ENQUEUE };
|
const AsyncMode _mode { AsyncMode::ENQUEUE };
|
||||||
|
|
||||||
// Async enqueue for notifications
|
// Async enqueue for notifications
|
||||||
@@ -146,11 +172,7 @@ private:
|
|||||||
void dispatchNotifications(std::stop_token& stopToken, int workerId);
|
void dispatchNotifications(std::stop_token& stopToken, int workerId);
|
||||||
/// Dispatching function executed by each worker thread.
|
/// Dispatching function executed by each worker thread.
|
||||||
|
|
||||||
constexpr static std::size_t DEFAULT_WORKERS_COUNT { 5 };
|
const std::size_t _workersCount { defaultWorkersCount() };
|
||||||
/// 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 };
|
|
||||||
/// Number of worker threads to process notifications.
|
/// Number of worker threads to process notifications.
|
||||||
/// This can be configured to a different value if needed.
|
/// This can be configured to a different value if needed.
|
||||||
|
|
||||||
@@ -178,8 +200,6 @@ private:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace Poco
|
} // namespace Poco
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// Definition of the AsyncObserver class template.
|
// Definition of the AsyncObserver class template.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||||
// Aleph ONE Software Engineering d.o.o.,
|
// Aleph ONE Software Engineering LLC,
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
#include "Poco/Notification.h"
|
#include "Poco/Notification.h"
|
||||||
#include "Poco/Mutex.h"
|
#include "Poco/Mutex.h"
|
||||||
#include "Poco/SharedPtr.h"
|
#include "Poco/SharedPtr.h"
|
||||||
|
#include "Poco/Observer.h"
|
||||||
|
#include "Poco/NObserver.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
@@ -97,6 +99,43 @@ public:
|
|||||||
void removeObserver(const AbstractObserver& observer);
|
void removeObserver(const AbstractObserver& observer);
|
||||||
/// Unregisters an observer with the NotificationCenter.
|
/// 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;
|
bool hasObserver(const AbstractObserver& observer) const;
|
||||||
/// Returns true if the observer is registered with this NotificationCenter.
|
/// Returns true if the observer is registered with this NotificationCenter.
|
||||||
|
|
||||||
@@ -148,8 +187,6 @@ private:
|
|||||||
ObserverList _observers;
|
ObserverList _observers;
|
||||||
mutable Mutex _mutex;
|
mutable Mutex _mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace Poco
|
} // namespace Poco
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// Definition of the PIDFile class.
|
// Definition of the PIDFile class.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||||
// Aleph ONE Software Engineering d.o.o.,
|
// Aleph ONE Software Engineering LLC,
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// Definition of the ProcessRunner class.
|
// Definition of the ProcessRunner class.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||||
// Aleph ONE Software Engineering d.o.o.,
|
// Aleph ONE Software Engineering LLC,
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
// Module: AsyncNotificationCenter
|
// Module: AsyncNotificationCenter
|
||||||
//
|
//
|
||||||
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
|
||||||
// Aleph ONE Software Engineering d.o.o.,
|
// Aleph ONE Software Engineering LLC,
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
@@ -26,6 +26,17 @@ namespace Poco {
|
|||||||
|
|
||||||
#if (POCO_HAVE_JTHREAD)
|
#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) :
|
AsyncNotificationCenter::AsyncNotificationCenter(AsyncMode mode, std::size_t workersCount) :
|
||||||
_mode(mode),
|
_mode(mode),
|
||||||
_ra(*this, &AsyncNotificationCenter::dequeue),
|
_ra(*this, &AsyncNotificationCenter::dequeue),
|
||||||
@@ -46,7 +57,7 @@ AsyncNotificationCenter::AsyncNotificationCenter() :
|
|||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // POCO_HAVE_JTHREAD
|
||||||
|
|
||||||
AsyncNotificationCenter::~AsyncNotificationCenter()
|
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)
|
void AsyncNotificationCenter::postNotification(Notification::Ptr pNotification)
|
||||||
{
|
{
|
||||||
#if (POCO_HAVE_JTHREAD)
|
#if (POCO_HAVE_JTHREAD)
|
||||||
@@ -108,8 +133,6 @@ void AsyncNotificationCenter::notifyObservers(Notification::Ptr& pNotification)
|
|||||||
|
|
||||||
if (_mode == AsyncMode::NOTIFY || _mode == AsyncMode::BOTH)
|
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);
|
std::unique_lock<std::mutex> lock(_listsMutex);
|
||||||
auto observers = observersToNotify(pNotification);
|
auto observers = observersToNotify(pNotification);
|
||||||
if (observers.empty())
|
if (observers.empty())
|
||||||
@@ -121,15 +144,12 @@ void AsyncNotificationCenter::notifyObservers(Notification::Ptr& pNotification)
|
|||||||
}
|
}
|
||||||
_listsEmpty = false;
|
_listsEmpty = false;
|
||||||
_listsEmptyCondition.notify_all();
|
_listsEmptyCondition.notify_all();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
#endif // POCO_HAVE_JTHREAD
|
||||||
// Notification is synchronous
|
|
||||||
NotificationCenter::notifyObservers(pNotification);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
NotificationCenter::notifyObservers(pNotification);
|
NotificationCenter::notifyObservers(pNotification);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -180,7 +200,6 @@ void AsyncNotificationCenter::stop()
|
|||||||
{
|
{
|
||||||
if (_enqueueThreadStarted.exchange(false))
|
if (_enqueueThreadStarted.exchange(false))
|
||||||
{
|
{
|
||||||
_nq.enqueueUrgentNotification(new ShutdownNotification);
|
|
||||||
_nq.wakeUpAll();
|
_nq.wakeUpAll();
|
||||||
while (!_enqueueThreadDone) Thread::sleep(100);
|
while (!_enqueueThreadDone) Thread::sleep(100);
|
||||||
_enqueueThread.join();
|
_enqueueThread.join();
|
||||||
@@ -196,9 +215,6 @@ void AsyncNotificationCenter::stop()
|
|||||||
{
|
{
|
||||||
if (t.joinable()) t.join();
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,11 +224,8 @@ void AsyncNotificationCenter::dequeue()
|
|||||||
Notification::Ptr pNf;
|
Notification::Ptr pNf;
|
||||||
_enqueueThreadStarted = true;
|
_enqueueThreadStarted = true;
|
||||||
_enqueueThreadDone = false;
|
_enqueueThreadDone = false;
|
||||||
while (true)
|
while ((pNf = _nq.waitDequeueNotification()))
|
||||||
{
|
{
|
||||||
pNf = _nq.waitDequeueNotification();
|
|
||||||
if (!pNf) break;
|
|
||||||
if (pNf.cast<ShutdownNotification>()) break;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
notifyObservers(pNf);
|
notifyObservers(pNf);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
// Module: PIDFile
|
// Module: PIDFile
|
||||||
//
|
//
|
||||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||||
// Aleph ONE Software Engineering d.o.o.,
|
// Aleph ONE Software Engineering LLC,
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
// Module: ProcessRunner
|
// Module: ProcessRunner
|
||||||
//
|
//
|
||||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||||
// Aleph ONE Software Engineering d.o.o.,
|
// Aleph ONE Software Engineering LLC,
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ objects = ActiveMethodTest ActivityTest ActiveDispatcherTest \
|
|||||||
ListMapTest LoggingFactoryTest LoggingRegistryTest LoggingTestSuite LogStreamTest \
|
ListMapTest LoggingFactoryTest LoggingRegistryTest LoggingTestSuite LogStreamTest \
|
||||||
NamedEventTest NamedMutexTest ProcessesTestSuite ProcessTest \
|
NamedEventTest NamedMutexTest ProcessesTestSuite ProcessTest \
|
||||||
MemoryPoolTest MD4EngineTest MD5EngineTest ManifestTest \
|
MemoryPoolTest MD4EngineTest MD5EngineTest ManifestTest \
|
||||||
NDCTest NotificationCenterTest NotificationQueueTest \
|
NDCTest NotificationCenterTest AsyncNotificationCenterTest NotificationQueueTest \
|
||||||
PriorityNotificationQueueTest TimedNotificationQueueTest \
|
PriorityNotificationQueueTest TimedNotificationQueueTest \
|
||||||
NotificationsTestSuite NullStreamTest NumberFormatterTest \
|
NotificationsTestSuite NullStreamTest NumberFormatterTest \
|
||||||
NumberParserTest PathTest PatternFormatterTest JSONFormatterTest PBKDF2EngineTest ProcessRunnerTest \
|
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 "NotificationCenterTest.h"
|
||||||
#include "CppUnit/TestCaller.h"
|
#include "CppUnit/TestCaller.h"
|
||||||
#include "CppUnit/TestCase.h"
|
|
||||||
#include "CppUnit/TestSuite.h"
|
#include "CppUnit/TestSuite.h"
|
||||||
#include "Poco/Notification.h"
|
|
||||||
#include "Poco/NotificationCenter.h"
|
#include "Poco/NotificationCenter.h"
|
||||||
#include "Poco/AsyncNotificationCenter.h"
|
#include "Poco/Observer.h"
|
||||||
#include "Poco/NObserver.h"
|
#include "Poco/NObserver.h"
|
||||||
#include "Poco/AsyncObserver.h"
|
|
||||||
#include "Poco/AutoPtr.h"
|
#include "Poco/AutoPtr.h"
|
||||||
|
|
||||||
|
|
||||||
using Poco::NotificationCenter;
|
using Poco::NotificationCenter;
|
||||||
using Poco::AsyncNotificationCenter;
|
using Poco::Observer;
|
||||||
using Poco::NObserver;
|
using Poco::NObserver;
|
||||||
using Poco::AsyncObserver;
|
|
||||||
using Poco::Notification;
|
using Poco::Notification;
|
||||||
using Poco::AutoPtr;
|
using Poco::AutoPtr;
|
||||||
|
|
||||||
|
|
||||||
class TestNotification: public Notification
|
class TestNotification: public Notification
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestNotification() = default;
|
TestNotification()
|
||||||
|
|
||||||
TestNotification(const std::string& name, int n = 0):
|
|
||||||
Notification(name), num(n)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
int num {0};
|
TestNotification(const std::string& name):
|
||||||
|
Notification(name)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
NotificationCenterTest::NotificationCenterTest(const std::string& 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()
|
void NotificationCenterTest::testNotificationCenter1()
|
||||||
@@ -59,7 +59,7 @@ void NotificationCenterTest::testNotificationCenter1()
|
|||||||
void NotificationCenterTest::testNotificationCenter2()
|
void NotificationCenterTest::testNotificationCenter2()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
NObserver<NotificationCenterTest, Notification> o(*this, &NotificationCenterTest::handle1);
|
Observer<NotificationCenterTest, Notification> o(*this, &NotificationCenterTest::handle1);
|
||||||
nc.addObserver(o);
|
nc.addObserver(o);
|
||||||
assertTrue (nc.hasObserver(o));
|
assertTrue (nc.hasObserver(o));
|
||||||
assertTrue (nc.hasObservers());
|
assertTrue (nc.hasObservers());
|
||||||
@@ -67,7 +67,7 @@ void NotificationCenterTest::testNotificationCenter2()
|
|||||||
nc.postNotification(new Notification);
|
nc.postNotification(new Notification);
|
||||||
assertTrue (_set.size() == 1);
|
assertTrue (_set.size() == 1);
|
||||||
assertTrue (_set.find("handle1") != _set.end());
|
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.hasObserver(o));
|
||||||
assertTrue (!nc.hasObservers());
|
assertTrue (!nc.hasObservers());
|
||||||
assertTrue (nc.countObservers() == 0);
|
assertTrue (nc.countObservers() == 0);
|
||||||
@@ -77,8 +77,8 @@ void NotificationCenterTest::testNotificationCenter2()
|
|||||||
void NotificationCenterTest::testNotificationCenter3()
|
void NotificationCenterTest::testNotificationCenter3()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
NObserver<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||||
NObserver<NotificationCenterTest, Notification> o2(*this, &NotificationCenterTest::handle2);
|
Observer<NotificationCenterTest, Notification> o2(*this, &NotificationCenterTest::handle2);
|
||||||
nc.addObserver(o1);
|
nc.addObserver(o1);
|
||||||
assertTrue (nc.hasObserver(o1));
|
assertTrue (nc.hasObserver(o1));
|
||||||
nc.addObserver(o2);
|
nc.addObserver(o2);
|
||||||
@@ -89,9 +89,9 @@ void NotificationCenterTest::testNotificationCenter3()
|
|||||||
assertTrue (_set.size() == 2);
|
assertTrue (_set.size() == 2);
|
||||||
assertTrue (_set.find("handle1") != _set.end());
|
assertTrue (_set.find("handle1") != _set.end());
|
||||||
assertTrue (_set.find("handle2") != _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));
|
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.hasObserver(o2));
|
||||||
assertTrue (!nc.hasObservers());
|
assertTrue (!nc.hasObservers());
|
||||||
assertTrue (nc.countObservers() == 0);
|
assertTrue (nc.countObservers() == 0);
|
||||||
@@ -101,8 +101,8 @@ void NotificationCenterTest::testNotificationCenter3()
|
|||||||
void NotificationCenterTest::testNotificationCenter4()
|
void NotificationCenterTest::testNotificationCenter4()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
NObserver<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
Observer<NotificationCenterTest, Notification> o1(*this, &NotificationCenterTest::handle1);
|
||||||
NObserver<NotificationCenterTest, Notification> o2(*this, &NotificationCenterTest::handle2);
|
Observer<NotificationCenterTest, Notification> o2(*this, &NotificationCenterTest::handle2);
|
||||||
nc.addObserver(o1);
|
nc.addObserver(o1);
|
||||||
assertTrue (nc.hasObserver(o1));
|
assertTrue (nc.hasObserver(o1));
|
||||||
nc.addObserver(o2);
|
nc.addObserver(o2);
|
||||||
@@ -111,20 +111,20 @@ void NotificationCenterTest::testNotificationCenter4()
|
|||||||
assertTrue (_set.size() == 2);
|
assertTrue (_set.size() == 2);
|
||||||
assertTrue (_set.find("handle1") != _set.end());
|
assertTrue (_set.find("handle1") != _set.end());
|
||||||
assertTrue (_set.find("handle2") != _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));
|
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.hasObserver(o2));
|
||||||
_set.clear();
|
_set.clear();
|
||||||
nc.postNotification(new Notification);
|
nc.postNotification(new Notification);
|
||||||
assertTrue (_set.empty());
|
assertTrue (_set.empty());
|
||||||
NObserver<NotificationCenterTest, Notification> o3(*this, &NotificationCenterTest::handle3);
|
Observer<NotificationCenterTest, Notification> o3(*this, &NotificationCenterTest::handle3);
|
||||||
nc.addObserver(o3);
|
nc.addObserver(o3);
|
||||||
assertTrue (nc.hasObserver(o3));
|
assertTrue (nc.hasObserver(o3));
|
||||||
nc.postNotification(new Notification);
|
nc.postNotification(new Notification);
|
||||||
assertTrue (_set.size() == 1);
|
assertTrue (_set.size() == 1);
|
||||||
assertTrue (_set.find("handle3") != _set.end());
|
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));
|
assertTrue (!nc.hasObserver(o3));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +132,8 @@ void NotificationCenterTest::testNotificationCenter4()
|
|||||||
void NotificationCenterTest::testNotificationCenter5()
|
void NotificationCenterTest::testNotificationCenter5()
|
||||||
{
|
{
|
||||||
NotificationCenter nc;
|
NotificationCenter nc;
|
||||||
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||||
nc.addObserver(NObserver<NotificationCenterTest, TestNotification>(*this, &NotificationCenterTest::handleTest));
|
nc.addObserver(Observer<NotificationCenterTest, TestNotification>(*this, &NotificationCenterTest::handleTest));
|
||||||
nc.postNotification(new Notification);
|
nc.postNotification(new Notification);
|
||||||
assertTrue (_set.size() == 1);
|
assertTrue (_set.size() == 1);
|
||||||
assertTrue (_set.find("handle1") != _set.end());
|
assertTrue (_set.find("handle1") != _set.end());
|
||||||
@@ -142,8 +142,8 @@ void NotificationCenterTest::testNotificationCenter5()
|
|||||||
assertTrue (_set.size() == 2);
|
assertTrue (_set.size() == 2);
|
||||||
assertTrue (_set.find("handle1") != _set.end());
|
assertTrue (_set.find("handle1") != _set.end());
|
||||||
assertTrue (_set.find("handleTest") != _set.end());
|
assertTrue (_set.find("handleTest") != _set.end());
|
||||||
nc.removeObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
nc.removeObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||||
nc.removeObserver(NObserver<NotificationCenterTest, TestNotification>(*this, &NotificationCenterTest::handleTest));
|
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()
|
void NotificationCenterTest::testDefaultNotificationCenter()
|
||||||
{
|
{
|
||||||
NotificationCenter& nc = NotificationCenter::defaultCenter();
|
NotificationCenter& nc = NotificationCenter::defaultCenter();
|
||||||
nc.addObserver(NObserver<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
nc.addObserver(Observer<NotificationCenterTest, Notification>(*this, &NotificationCenterTest::handle1));
|
||||||
nc.postNotification(new Notification);
|
nc.postNotification(new Notification);
|
||||||
assertTrue (_set.size() == 1);
|
assertTrue (_set.size() == 1);
|
||||||
assertTrue (_set.find("handle1") != _set.end());
|
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()
|
void NotificationCenterTest::handle1(Poco::Notification* pNf)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Poco::Mutex::ScopedLock l(_mutex);
|
Poco::Mutex::ScopedLock l(_mutex);
|
||||||
poco_check_ptr (pNf);
|
poco_check_ptr (pNf);
|
||||||
|
AutoPtr<Notification> nf = pNf;
|
||||||
_set.insert("handle1");
|
_set.insert("handle1");
|
||||||
_handle1Done = true;
|
_handle1Done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::handle2(const AutoPtr<Notification>& pNf)
|
void NotificationCenterTest::handle2(Poco::Notification* pNf)
|
||||||
{
|
{
|
||||||
poco_check_ptr (pNf);
|
poco_check_ptr (pNf);
|
||||||
|
AutoPtr<Notification> nf = pNf;
|
||||||
_set.insert("handle2");
|
_set.insert("handle2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::handle3(const AutoPtr<Notification>& pNf)
|
void NotificationCenterTest::handle3(Poco::Notification* pNf)
|
||||||
{
|
{
|
||||||
poco_check_ptr (pNf);
|
poco_check_ptr (pNf);
|
||||||
|
AutoPtr<Notification> nf = pNf;
|
||||||
_set.insert("handle3");
|
_set.insert("handle3");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void NotificationCenterTest::handleTest(const AutoPtr<TestNotification>& pNf)
|
void NotificationCenterTest::handleTest(TestNotification* pNf)
|
||||||
{
|
{
|
||||||
poco_check_ptr (pNf);
|
poco_check_ptr (pNf);
|
||||||
|
AutoPtr<TestNotification> nf = pNf;
|
||||||
_set.insert("handleTest");
|
_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()
|
void NotificationCenterTest::setUp()
|
||||||
{
|
{
|
||||||
_set.clear();
|
_set.clear();
|
||||||
_handle1Done = false;
|
_handle1Done = false;
|
||||||
_handleAuto1Done = 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, testNotificationCenter4);
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter5);
|
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenter5);
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, testNotificationCenterAuto);
|
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, testDefaultNotificationCenter);
|
||||||
CppUnit_addTest(pSuite, NotificationCenterTest, testMixedObservers);
|
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class NotificationCenterTest: public CppUnit::TestCase
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NotificationCenterTest(const std::string& name);
|
NotificationCenterTest(const std::string& name);
|
||||||
~NotificationCenterTest() override;
|
~NotificationCenterTest();
|
||||||
|
|
||||||
void testNotificationCenter1();
|
void testNotificationCenter1();
|
||||||
void testNotificationCenter2();
|
void testNotificationCenter2();
|
||||||
@@ -37,43 +37,24 @@ public:
|
|||||||
void testNotificationCenter4();
|
void testNotificationCenter4();
|
||||||
void testNotificationCenter5();
|
void testNotificationCenter5();
|
||||||
void testNotificationCenterAuto();
|
void testNotificationCenterAuto();
|
||||||
void testAsyncObserver();
|
|
||||||
void testAsyncNotificationCenter();
|
|
||||||
void testAsyncNotificationCenter2();
|
|
||||||
void testAsyncNotificationCenterSyncNotify();
|
|
||||||
void testAsyncNotificationCenterAsyncNotify();
|
|
||||||
void testAsyncNotificationCenterAsyncBoth();
|
|
||||||
void testAsyncNotificationCenterAsyncNotifyStress();
|
|
||||||
void testAsyncNotificationCenterAsyncRemoveObserver();
|
|
||||||
void testDefaultNotificationCenter();
|
void testDefaultNotificationCenter();
|
||||||
void testMixedObservers();
|
|
||||||
|
|
||||||
void setUp() override;
|
void setUp();
|
||||||
void tearDown() override;
|
void tearDown();
|
||||||
|
|
||||||
static CppUnit::Test* suite();
|
static CppUnit::Test* suite();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void handle1(const Poco::AutoPtr<Poco::Notification>& pNf);
|
void handle1(Poco::Notification* pNf);
|
||||||
void handle2(const Poco::AutoPtr<Poco::Notification>& pNf);
|
void handle2(Poco::Notification* pNf);
|
||||||
void handle3(const Poco::AutoPtr<Poco::Notification>& pNf);
|
void handle3(Poco::Notification* pNf);
|
||||||
void handleTest(const Poco::AutoPtr<TestNotification>& pNf);
|
void handleTest(TestNotification* pNf);
|
||||||
void handleAuto(const Poco::AutoPtr<Poco::Notification>& 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:
|
private:
|
||||||
std::set<std::string> _set;
|
std::set<std::string> _set;
|
||||||
std::atomic<bool> _handle1Done {false};
|
std::atomic<bool> _handle1Done;
|
||||||
std::atomic<bool> _handleAuto1Done {false};
|
std::atomic<bool> _handleAuto1Done;
|
||||||
std::atomic<bool> _handleAsync1Done {false};
|
|
||||||
std::atomic<bool> _handleAsync2Done {false};
|
|
||||||
|
|
||||||
std::atomic<std::size_t> _handleAsync1Counter {0};
|
|
||||||
std::atomic<std::size_t> _handleAsync2Counter {0};
|
|
||||||
|
|
||||||
Poco::Mutex _mutex;
|
Poco::Mutex _mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "NotificationsTestSuite.h"
|
#include "NotificationsTestSuite.h"
|
||||||
#include "NotificationCenterTest.h"
|
#include "NotificationCenterTest.h"
|
||||||
|
#include "AsyncNotificationCenterTest.h"
|
||||||
#include "NotificationQueueTest.h"
|
#include "NotificationQueueTest.h"
|
||||||
#include "PriorityNotificationQueueTest.h"
|
#include "PriorityNotificationQueueTest.h"
|
||||||
#include "TimedNotificationQueueTest.h"
|
#include "TimedNotificationQueueTest.h"
|
||||||
@@ -20,6 +21,7 @@ CppUnit::Test* NotificationsTestSuite::suite()
|
|||||||
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NotificationsTestSuite");
|
CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("NotificationsTestSuite");
|
||||||
|
|
||||||
pSuite->addTest(NotificationCenterTest::suite());
|
pSuite->addTest(NotificationCenterTest::suite());
|
||||||
|
pSuite->addTest(AsyncNotificationCenterTest::suite());
|
||||||
pSuite->addTest(NotificationQueueTest::suite());
|
pSuite->addTest(NotificationQueueTest::suite());
|
||||||
pSuite->addTest(PriorityNotificationQueueTest::suite());
|
pSuite->addTest(PriorityNotificationQueueTest::suite());
|
||||||
pSuite->addTest(TimedNotificationQueueTest::suite());
|
pSuite->addTest(TimedNotificationQueueTest::suite());
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// ProcessRunnerTest.cpp
|
// ProcessRunnerTest.cpp
|
||||||
//
|
//
|
||||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||||
// Aleph ONE Software Engineering d.o.o.,
|
// Aleph ONE Software Engineering LLC,
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// Definition of the ProcessRunnerTest class.
|
// Definition of the ProcessRunnerTest class.
|
||||||
//
|
//
|
||||||
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
// Copyright (c) 2023, Applied Informatics Software Engineering GmbH.
|
||||||
// Aleph ONE Software Engineering d.o.o.,
|
// Aleph ONE Software Engineering LLC,
|
||||||
// and Contributors.
|
// and Contributors.
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: BSL-1.0
|
// SPDX-License-Identifier: BSL-1.0
|
||||||
@@ -26,7 +26,7 @@ class ProcessRunnerTest: public CppUnit::TestCase
|
|||||||
public:
|
public:
|
||||||
ProcessRunnerTest(const std::string& name);
|
ProcessRunnerTest(const std::string& name);
|
||||||
~ProcessRunnerTest();
|
~ProcessRunnerTest();
|
||||||
|
|
||||||
void testPIDFile();
|
void testPIDFile();
|
||||||
void testProcessRunner();
|
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