File indexing completed on 2024-11-10 04:40:14
0001 /* 0002 SPDX-FileCopyrightText: 2011 Stephen Kelly <steveire@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "monitor.h" 0008 0009 #include "akonaditestfake_export.h" 0010 #include "fakeserverdata.h" 0011 #include "fakesession.h" 0012 #include "inspectablechangerecorder.h" 0013 #include "inspectablemonitor.h" 0014 #include <QSignalSpy> 0015 #include <QTest> 0016 0017 using namespace Akonadi; 0018 0019 class MonitorNotificationTest : public QObject 0020 { 0021 Q_OBJECT 0022 public: 0023 explicit MonitorNotificationTest(QObject *parent = nullptr) 0024 : QObject(parent) 0025 , m_sessionName("MonitorNotificationTest fake session") 0026 { 0027 m_fakeSession = new FakeSession(m_sessionName, FakeSession::EndJobsImmediately); 0028 m_fakeSession->setAsDefaultSession(); 0029 } 0030 0031 ~MonitorNotificationTest() override 0032 { 0033 delete m_fakeSession; 0034 } 0035 0036 private Q_SLOTS: 0037 void testSingleMessage(); 0038 void testFillPipeline(); 0039 void testMonitor(); 0040 0041 void testSingleMessage_data(); 0042 void testFillPipeline_data(); 0043 void testMonitor_data(); 0044 0045 private: 0046 template<typename MonitorImpl> 0047 void testSingleMessage_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache); 0048 template<typename MonitorImpl> 0049 void testFillPipeline_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache); 0050 template<typename MonitorImpl> 0051 void testMonitor_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache); 0052 0053 private: 0054 FakeSession *m_fakeSession = nullptr; 0055 QByteArray m_sessionName; 0056 }; 0057 0058 void MonitorNotificationTest::testSingleMessage_data() 0059 { 0060 QTest::addColumn<bool>("useChangeRecorder"); 0061 0062 QTest::newRow("useChangeRecorder") << true; 0063 QTest::newRow("useMonitor") << false; 0064 } 0065 0066 void MonitorNotificationTest::testSingleMessage() 0067 { 0068 QFETCH(bool, useChangeRecorder); 0069 0070 auto collectionCache = new FakeCollectionCache(m_fakeSession); 0071 FakeItemCache itemCache(m_fakeSession); 0072 auto depsFactory = new FakeMonitorDependenciesFactory(&itemCache, collectionCache); 0073 0074 if (!useChangeRecorder) { 0075 testSingleMessage_impl(new InspectableMonitor(depsFactory, this), collectionCache, &itemCache); 0076 } else { 0077 auto changeRecorder = new InspectableChangeRecorder(depsFactory, this); 0078 changeRecorder->setChangeRecordingEnabled(false); 0079 testSingleMessage_impl(changeRecorder, collectionCache, &itemCache); 0080 } 0081 } 0082 0083 template<typename MonitorImpl> 0084 void MonitorNotificationTest::testSingleMessage_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache) 0085 { 0086 Q_UNUSED(itemCache) 0087 0088 // Workaround for the QTimer::singleShot() in fake monitors to happen 0089 QTest::qWait(10); 0090 0091 monitor->setSession(m_fakeSession); 0092 monitor->fetchCollection(true); 0093 0094 Protocol::ChangeNotificationList list; 0095 0096 Collection parent(1); 0097 Collection added(2); 0098 0099 auto msg = Protocol::CollectionChangeNotificationPtr::create(); 0100 msg->setParentCollection(parent.id()); 0101 msg->setOperation(Protocol::CollectionChangeNotification::Add); 0102 msg->setCollection(Protocol::FetchCollectionsResponse(added.id())); 0103 // With notification payloads most requests by-pass the pipeline as the 0104 // notification already contains everything. To force pipelineing we set 0105 // the internal metadata (normally set by ChangeRecorder) 0106 msg->addMetadata("FETCH_COLLECTION"); 0107 0108 QHash<Collection::Id, Collection> data; 0109 data.insert(parent.id(), parent); 0110 data.insert(added.id(), added); 0111 0112 // Pending notifications remains empty because we don't fill the pipeline with one message. 0113 0114 QVERIFY(monitor->pipeline().isEmpty()); 0115 QVERIFY(monitor->pendingNotifications().isEmpty()); 0116 0117 monitor->notificationConnection()->emitNotify(msg); 0118 0119 QTRY_COMPARE(monitor->pipeline().size(), 1); 0120 QVERIFY(monitor->pendingNotifications().isEmpty()); 0121 0122 collectionCache->setData(data); 0123 collectionCache->emitDataAvailable(); 0124 0125 QVERIFY(monitor->pipeline().isEmpty()); 0126 QVERIFY(monitor->pendingNotifications().isEmpty()); 0127 } 0128 0129 void MonitorNotificationTest::testFillPipeline_data() 0130 { 0131 QTest::addColumn<bool>("useChangeRecorder"); 0132 0133 QTest::newRow("useChangeRecorder") << true; 0134 QTest::newRow("useMonitor") << false; 0135 } 0136 0137 void MonitorNotificationTest::testFillPipeline() 0138 { 0139 QFETCH(bool, useChangeRecorder); 0140 0141 auto collectionCache = new FakeCollectionCache(m_fakeSession); 0142 FakeItemCache itemCache(m_fakeSession); 0143 auto depsFactory = new FakeMonitorDependenciesFactory(&itemCache, collectionCache); 0144 0145 if (!useChangeRecorder) { 0146 testFillPipeline_impl(new InspectableMonitor(depsFactory, this), collectionCache, &itemCache); 0147 } else { 0148 auto changeRecorder = new InspectableChangeRecorder(depsFactory, this); 0149 changeRecorder->setChangeRecordingEnabled(false); 0150 testFillPipeline_impl(changeRecorder, collectionCache, &itemCache); 0151 } 0152 } 0153 0154 template<typename MonitorImpl> 0155 void MonitorNotificationTest::testFillPipeline_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache) 0156 { 0157 Q_UNUSED(itemCache) 0158 0159 monitor->setSession(m_fakeSession); 0160 monitor->fetchCollection(true); 0161 0162 Protocol::ChangeNotificationList list; 0163 QHash<Collection::Id, Collection> data; 0164 0165 int i = 1; 0166 while (i < 40) { 0167 Collection parent(i++); 0168 Collection added(i++); 0169 0170 auto msg = Protocol::CollectionChangeNotificationPtr::create(); 0171 msg->setParentCollection(parent.id()); 0172 msg->setOperation(Protocol::CollectionChangeNotification::Add); 0173 msg->setCollection(Protocol::FetchCollectionsResponse(added.id())); 0174 msg->addMetadata("FETCH_COLLECTION"); 0175 0176 data.insert(parent.id(), parent); 0177 data.insert(added.id(), added); 0178 0179 list << msg; 0180 } 0181 0182 QVERIFY(monitor->pipeline().isEmpty()); 0183 QVERIFY(monitor->pendingNotifications().isEmpty()); 0184 0185 for (const Protocol::ChangeNotificationPtr &ntf : std::as_const(list)) { 0186 monitor->notificationConnection()->emitNotify(ntf); 0187 } 0188 0189 QTRY_COMPARE(monitor->pipeline().size(), 5); 0190 QCOMPARE(monitor->pendingNotifications().size(), 15); 0191 0192 collectionCache->setData(data); 0193 collectionCache->emitDataAvailable(); 0194 0195 QVERIFY(monitor->pipeline().isEmpty()); 0196 QVERIFY(monitor->pendingNotifications().isEmpty()); 0197 } 0198 0199 void MonitorNotificationTest::testMonitor_data() 0200 { 0201 QTest::addColumn<bool>("useChangeRecorder"); 0202 0203 QTest::newRow("useChangeRecorder") << true; 0204 QTest::newRow("useMonitor") << false; 0205 } 0206 0207 void MonitorNotificationTest::testMonitor() 0208 { 0209 QFETCH(bool, useChangeRecorder); 0210 0211 auto collectionCache = new FakeCollectionCache(m_fakeSession); 0212 FakeItemCache itemCache(m_fakeSession); 0213 auto depsFactory = new FakeMonitorDependenciesFactory(&itemCache, collectionCache); 0214 0215 if (!useChangeRecorder) { 0216 testMonitor_impl(new InspectableMonitor(depsFactory, this), collectionCache, &itemCache); 0217 } else { 0218 auto changeRecorder = new InspectableChangeRecorder(depsFactory, this); 0219 changeRecorder->setChangeRecordingEnabled(false); 0220 testMonitor_impl(changeRecorder, collectionCache, &itemCache); 0221 } 0222 } 0223 0224 template<typename MonitorImpl> 0225 void MonitorNotificationTest::testMonitor_impl(MonitorImpl *monitor, FakeCollectionCache *collectionCache, FakeItemCache *itemCache) 0226 { 0227 Q_UNUSED(itemCache) 0228 0229 monitor->setSession(m_fakeSession); 0230 monitor->fetchCollection(true); 0231 0232 Protocol::ChangeNotificationList list; 0233 0234 Collection col2(2); 0235 col2.setParentCollection(Collection::root()); 0236 0237 collectionCache->insert(col2); 0238 0239 int i = 4; 0240 0241 while (i < 8) { 0242 Collection added(i++); 0243 0244 auto msg = Protocol::CollectionChangeNotificationPtr::create(); 0245 msg->setParentCollection(i % 2 ? 2 : added.id() - 1); 0246 msg->setOperation(Protocol::CollectionChangeNotification::Add); 0247 msg->setCollection(Protocol::FetchCollectionsResponse(added.id())); 0248 msg->addMetadata("FETCH_COLLECTION"); 0249 0250 list << msg; 0251 } 0252 0253 QVERIFY(monitor->pipeline().isEmpty()); 0254 QVERIFY(monitor->pendingNotifications().isEmpty()); 0255 0256 Collection col4(4); 0257 col4.setParentCollection(col2); 0258 Collection col6(6); 0259 col6.setParentCollection(col2); 0260 0261 collectionCache->insert(col4); 0262 collectionCache->insert(col6); 0263 0264 qRegisterMetaType<Akonadi::Collection>(); 0265 QSignalSpy collectionAddedSpy(monitor, SIGNAL(collectionAdded(Akonadi::Collection, Akonadi::Collection))); 0266 0267 collectionCache->emitDataAvailable(); 0268 0269 QTRY_VERIFY(monitor->pipeline().isEmpty()); 0270 QVERIFY(monitor->pendingNotifications().isEmpty()); 0271 0272 for (const Protocol::ChangeNotificationPtr &ntf : std::as_const(list)) { 0273 monitor->notificationConnection()->emitNotify(ntf); 0274 } 0275 0276 // Collection 6 is not notified, because Collection 5 has held up the pipeline 0277 QTRY_COMPARE(collectionAddedSpy.size(), 1); 0278 QCOMPARE((int)collectionAddedSpy.takeFirst().first().value<Akonadi::Collection>().id(), 4); 0279 QCOMPARE(monitor->pipeline().size(), 3); 0280 QCOMPARE(monitor->pendingNotifications().size(), 0); 0281 0282 Collection col7(7); 0283 col7.setParentCollection(col6); 0284 0285 collectionCache->insert(col7); 0286 collectionCache->emitDataAvailable(); 0287 0288 // Collection 5 is still holding the pipeline 0289 QCOMPARE(collectionAddedSpy.size(), 0); 0290 QCOMPARE(monitor->pipeline().size(), 3); 0291 QCOMPARE(monitor->pendingNotifications().size(), 0); 0292 0293 Collection col5(5); 0294 col5.setParentCollection(col4); 0295 0296 collectionCache->insert(col5); 0297 collectionCache->emitDataAvailable(); 0298 0299 // Collection 5 is in cache, pipeline is flushed 0300 QCOMPARE(collectionAddedSpy.size(), 3); 0301 QCOMPARE(monitor->pipeline().size(), 0); 0302 QCOMPARE(monitor->pendingNotifications().size(), 0); 0303 } 0304 0305 QTEST_MAIN(MonitorNotificationTest) 0306 #include "monitornotificationtest.moc"