diff --git a/panels/notification/server/notifyserverapplet.cpp b/panels/notification/server/notifyserverapplet.cpp index b4de43dfc..ae678101f 100644 --- a/panels/notification/server/notifyserverapplet.cpp +++ b/panels/notification/server/notifyserverapplet.cpp @@ -25,13 +25,22 @@ NotifyServerApplet::NotifyServerApplet(QObject *parent) NotifyServerApplet::~NotifyServerApplet() { qDebug(notifyLog) << "Exit notification server."; - if (m_manager) { - m_manager->deleteLater(); - } if (m_worker) { + if (m_manager) { + // Schedule manager deletion while the worker event loop is still able to process it. + connect(m_worker, &QThread::finished, m_manager, &QObject::deleteLater, Qt::UniqueConnection); + } m_worker->exit(); m_worker->wait(); - m_worker->deleteLater(); + delete m_worker; + m_worker = nullptr; + m_manager = nullptr; + return; + } + + if (m_manager) { + delete m_manager; + m_manager = nullptr; } } diff --git a/tests/panels/notification/server/notifyserverapplet_test.cpp b/tests/panels/notification/server/notifyserverapplet_test.cpp index 9a0463167..11cd91195 100644 --- a/tests/panels/notification/server/notifyserverapplet_test.cpp +++ b/tests/panels/notification/server/notifyserverapplet_test.cpp @@ -5,12 +5,17 @@ #include #include +#include #include +#include +#include #include #include #include +#define private public #include "notifyserverapplet.h" +#undef private #include "notificationmanager.h" using namespace notification; @@ -18,6 +23,22 @@ using ::testing::_; using ::testing::Return; using ::testing::Invoke; +class TrackableNotificationManager : public NotificationManager { + Q_OBJECT +public: + explicit TrackableNotificationManager(QObject *parent = nullptr) + : NotificationManager(parent) {} + + ~TrackableNotificationManager() override + { + ++destroyedCount; + } + + static std::atomic_int destroyedCount; +}; + +std::atomic_int TrackableNotificationManager::destroyedCount = 0; + // Mock class for NotificationManager class MockNotificationManager : public NotificationManager { Q_OBJECT @@ -72,6 +93,59 @@ TEST_F(NotifyServerAppletTest, DestructorTest) { EXPECT_NO_THROW(delete testApplet); } +// Test destructor when only manager exists (no worker thread) +TEST_F(NotifyServerAppletTest, DestructorWithManagerOnlyTest) { + TrackableNotificationManager::destroyedCount = 0; + + auto *testApplet = new NotifyServerApplet(); + auto *manager = new TrackableNotificationManager(); + QPointer managerGuard(manager); + + testApplet->m_manager = manager; + // m_worker remains nullptr + + delete testApplet; + + EXPECT_TRUE(managerGuard.isNull()); + EXPECT_EQ(TrackableNotificationManager::destroyedCount.load(), 1); +} + +// Test destructor when worker exists but manager is null +TEST_F(NotifyServerAppletTest, DestructorWithWorkerOnlyTest) { + auto *testApplet = new NotifyServerApplet(); + auto *worker = new QThread(); + + testApplet->m_worker = worker; + testApplet->m_manager = nullptr; + + worker->start(); + QTRY_VERIFY_WITH_TIMEOUT(worker->isRunning(), 1000); + + EXPECT_NO_THROW(delete testApplet); +} + +TEST_F(NotifyServerAppletTest, DestructorDeletesManagerAfterWorkerThreadExit) { + TrackableNotificationManager::destroyedCount = 0; + + auto *testApplet = new NotifyServerApplet(); + auto *worker = new QThread(); + auto *manager = new TrackableNotificationManager(); + QPointer managerGuard(manager); + + testApplet->m_manager = manager; + testApplet->m_worker = worker; + + manager->moveToThread(worker); + worker->start(); + + QTRY_VERIFY_WITH_TIMEOUT(worker->isRunning(), 1000); + + delete testApplet; + + EXPECT_TRUE(managerGuard.isNull()); + EXPECT_EQ(TrackableNotificationManager::destroyedCount.load(), 1); +} + // Test memory leak detection for destructor with initialized applet TEST_F(NotifyServerAppletTest, DestructorMemoryLeakTest) { // This test verifies that all resources are properly cleaned up