1 /* 2 * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org> 3 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 4 */ 5 6 7 #include <testlib/qtest_zanshin.h> 8 9 #include "utils/mockobject.h" 10 11 #include "testlib/akonadifakejobs.h" 12 #include "testlib/akonadifakemonitor.h" 13 14 #include "akonadi/akonadiprojectrepository.h" 15 #include "akonadi/akonadiserializerinterface.h" 16 #include "akonadi/akonadistorageinterface.h" 17 18 using namespace mockitopp; 19 20 Q_DECLARE_METATYPE(Testlib::AkonadiFakeItemFetchJob*) 21 22 class AkonadiProjectRepositoryTest : public QObject 23 { 24 Q_OBJECT 25 private slots: shouldCreateProjectInDataSource()26 void shouldCreateProjectInDataSource() 27 { 28 // GIVEN 29 30 // A project and its corresponding item already not existing in storage 31 Akonadi::Item item; 32 auto project = Domain::Project::Ptr::create(); 33 34 // A data source and its corresponding collection existing in storage 35 Akonadi::Collection collection(42); 36 auto source = Domain::DataSource::Ptr::create(); 37 38 // A mock create job 39 auto itemCreateJob = new FakeJob(this); 40 41 // Storage mock returning the create job 42 Utils::MockObject<Akonadi::StorageInterface> storageMock; 43 storageMock(&Akonadi::StorageInterface::createItem).when(item, collection) 44 .thenReturn(itemCreateJob); 45 46 // Serializer mock 47 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 48 serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).thenReturn(item); 49 serializerMock(&Akonadi::SerializerInterface::createCollectionFromDataSource).when(source).thenReturn(collection); 50 51 // WHEN 52 QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(), 53 serializerMock.getInstance())); 54 repository->create(project, source)->exec(); 55 56 // THEN 57 QVERIFY(storageMock(&Akonadi::StorageInterface::createItem).when(item, collection).exactly(1)); 58 } 59 shouldUpdateExistingProject()60 void shouldUpdateExistingProject() 61 { 62 // GIVEN 63 64 // A project and its corresponding item already existing in storage 65 Akonadi::Item item(42); 66 Domain::Project::Ptr project(new Domain::Project); 67 68 // A mock modify job 69 auto itemModifyJob = new FakeJob(this); 70 71 Utils::MockObject<Akonadi::StorageInterface> storageMock; 72 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 73 QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(), 74 serializerMock.getInstance())); 75 76 // Storage mock returning the create job 77 storageMock(&Akonadi::StorageInterface::updateItem).when(item, repository.get()) 78 .thenReturn(itemModifyJob); 79 80 // Serializer mock returning the item for the project 81 serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).thenReturn(item); 82 83 // WHEN 84 repository->update(project)->exec(); 85 86 // THEN 87 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).exactly(1)); 88 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(item, repository.get()).exactly(1)); 89 } 90 shouldRemoveExistingProject()91 void shouldRemoveExistingProject() 92 { 93 // GIVEN 94 95 // A project and its corresponding item already existing in storage 96 Akonadi::Item item(42); 97 auto project = Domain::Project::Ptr::create(); 98 99 // A mock remove job 100 auto itemRemoveJob = new FakeJob(this); 101 102 Utils::MockObject<Akonadi::StorageInterface> storageMock; 103 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 104 QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(), 105 serializerMock.getInstance())); 106 107 // Storage mock returning the create job 108 storageMock(&Akonadi::StorageInterface::removeItem).when(item, repository.get()) 109 .thenReturn(itemRemoveJob); 110 111 // Serializer mock returning the item for the project 112 serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).thenReturn(item); 113 114 // WHEN 115 repository->remove(project)->exec(); 116 117 // THEN 118 QVERIFY(storageMock(&Akonadi::StorageInterface::removeItem).when(item, repository.get()).exactly(1)); 119 } 120 shouldAssociateATaskToAProject_data()121 void shouldAssociateATaskToAProject_data() 122 { 123 QTest::addColumn<Akonadi::Item>("childItem"); 124 QTest::addColumn<Akonadi::Item>("parentItem"); 125 QTest::addColumn<Domain::Task::Ptr>("child"); 126 QTest::addColumn<Domain::Project::Ptr>("parent"); 127 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob1"); 128 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob2"); 129 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob3"); 130 QTest::addColumn<bool>("execJob"); 131 QTest::addColumn<bool>("execParentJob"); 132 QTest::addColumn<Akonadi::Item::List>("list"); 133 134 Akonadi::Collection col(40); 135 136 Akonadi::Item childItem(42); 137 childItem.setParentCollection(col); 138 Domain::Task::Ptr childTask(new Domain::Task); 139 140 Akonadi::Item parentItem(41); 141 parentItem.setParentCollection(col); 142 auto parent = Domain::Project::Ptr::create(); 143 144 auto itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 145 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 146 auto itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 147 itemFetchJob2->setItems(Akonadi::Item::List() << parentItem); 148 auto itemFetchJob3 = new Testlib::AkonadiFakeItemFetchJob(this); 149 150 Akonadi::Item::List list; 151 152 QTest::newRow("nominal case (task)") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << true << list; 153 154 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 155 itemFetchJob1->setExpectedError(KJob::KilledJobError); 156 QTest::newRow("child job error with empty list") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << false << false << list; 157 158 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 159 itemFetchJob1->setExpectedError(KJob::KilledJobError); 160 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 161 QTest::newRow("child job error with item (task)") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << false << false << list; 162 163 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 164 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 165 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 166 itemFetchJob2->setExpectedError(KJob::KilledJobError); 167 QTest::newRow("parent job error with empty list (task)") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << false << list; 168 169 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 170 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 171 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 172 itemFetchJob2->setExpectedError(KJob::KilledJobError); 173 itemFetchJob2->setItems(Akonadi::Item::List() << parentItem); 174 QTest::newRow("parent job error with item (task)") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << false << list; 175 176 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 177 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 178 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 179 Akonadi::Collection col2(39); 180 Akonadi::Item parentItem2(41); 181 parentItem2.setParentCollection(col2); 182 itemFetchJob2->setItems(Akonadi::Item::List() << parentItem2); 183 itemFetchJob3 = new Testlib::AkonadiFakeItemFetchJob(this); 184 QTest::newRow("update and move item (task)") << childItem << parentItem2 << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << true << list; 185 186 itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this); 187 itemFetchJob1->setItems(Akonadi::Item::List() << childItem); 188 itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this); 189 itemFetchJob2->setItems(Akonadi::Item::List() << parentItem2); 190 itemFetchJob3 = new Testlib::AkonadiFakeItemFetchJob(this); 191 Akonadi::Item childItem2(43); 192 Akonadi::Item::List list2; 193 list2 << childItem2; 194 itemFetchJob3->setItems(list2); 195 QTest::newRow("update and move item and his child (task)") << childItem << parentItem2 << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << true << list2; 196 } 197 shouldAssociateATaskToAProject()198 void shouldAssociateATaskToAProject() 199 { 200 // GIVEN 201 QFETCH(Akonadi::Item, childItem); 202 QFETCH(Akonadi::Item, parentItem); 203 QFETCH(Domain::Task::Ptr, child); 204 QFETCH(Domain::Project::Ptr, parent); 205 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob1); 206 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob2); 207 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob3); 208 QFETCH(bool, execJob); 209 QFETCH(bool, execParentJob); 210 QFETCH(Akonadi::Item::List, list); 211 212 // A mock create job 213 auto itemModifyJob = new FakeJob(this); 214 auto transactionJob = new FakeJob(this); 215 auto itemsMoveJob = new FakeJob(this); 216 217 Akonadi::Item::List movedList; 218 movedList << childItem << list; 219 220 Utils::MockObject<Akonadi::StorageInterface> storageMock; 221 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 222 QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(), 223 serializerMock.getInstance())); 224 225 // Storage mock returning the create job 226 storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()) 227 .thenReturn(itemFetchJob1); 228 storageMock(&Akonadi::StorageInterface::fetchItem).when(parentItem, repository.get()) 229 .thenReturn(itemFetchJob2); 230 if (parentItem.parentCollection().id() != childItem.parentCollection().id()) { 231 storageMock(&Akonadi::StorageInterface::fetchItems).when(childItem.parentCollection(), repository.get()) 232 .thenReturn(itemFetchJob3); 233 storageMock(&Akonadi::StorageInterface::createTransaction).when(repository.get()).thenReturn(transactionJob); 234 storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, transactionJob) 235 .thenReturn(itemModifyJob); 236 storageMock(&Akonadi::StorageInterface::moveItems).when(movedList, parentItem.parentCollection(), transactionJob) 237 .thenReturn(itemsMoveJob); 238 } else { 239 storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()) 240 .thenReturn(itemModifyJob); 241 } 242 243 // Serializer mock returning the item for the task 244 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).thenReturn(childItem); 245 serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(parent).thenReturn(parentItem); 246 serializerMock(&Akonadi::SerializerInterface::updateItemProject).when(childItem, parent).thenReturn(); 247 if (execParentJob) 248 serializerMock(&Akonadi::SerializerInterface::filterDescendantItems).when(list, childItem).thenReturn(list); 249 250 // WHEN 251 auto associateJob = repository->associate(parent, child); 252 if (execJob) 253 associateJob->exec(); 254 255 // THEN 256 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()).exactly(1)); 257 if (execJob) { 258 QVERIFY(serializerMock(&Akonadi::SerializerInterface::updateItemProject).when(childItem, parent).exactly(1)); 259 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(parent).exactly(1)); 260 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(parentItem, repository.get()).exactly(1)); 261 if (execParentJob) { 262 if (parentItem.parentCollection().id() != childItem.parentCollection().id()) { 263 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItems).when(childItem.parentCollection(), repository.get()).exactly(1)); 264 QVERIFY(storageMock(&Akonadi::StorageInterface::createTransaction).when(repository.get()).thenReturn(transactionJob).exactly(1)); 265 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, transactionJob).exactly(1)); 266 QVERIFY(storageMock(&Akonadi::StorageInterface::moveItems).when(movedList, parentItem.parentCollection(), transactionJob).exactly(1)); 267 } else { 268 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()).exactly(1)); 269 } 270 } 271 } 272 } 273 shouldDissociateATaskFromItsProject_data()274 void shouldDissociateATaskFromItsProject_data() 275 { 276 QTest::addColumn<Domain::Task::Ptr>("child"); 277 QTest::addColumn<Akonadi::Item>("childItem"); 278 QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob"); 279 QTest::addColumn<bool>("fetchJobFailed"); 280 281 Domain::Task::Ptr taskChild(new Domain::Task); 282 Akonadi::Item childItem(42); 283 284 auto itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this); 285 itemFetchJob->setItems(Akonadi::Item::List() << childItem); 286 QTest::newRow("task nominal case") << taskChild << childItem << itemFetchJob << false; 287 288 itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this); 289 itemFetchJob->setExpectedError(KJob::KilledJobError); 290 QTest::newRow("task job error with empty list") << taskChild << childItem << itemFetchJob << true; 291 292 itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this); 293 itemFetchJob->setExpectedError(KJob::KilledJobError); 294 itemFetchJob->setItems(Akonadi::Item::List() << childItem); 295 QTest::newRow("task job error with item") << taskChild << childItem << itemFetchJob << true; 296 } 297 shouldDissociateATaskFromItsProject()298 void shouldDissociateATaskFromItsProject() 299 { 300 // GIVEN 301 QFETCH(Domain::Task::Ptr, child); 302 QFETCH(Akonadi::Item, childItem); 303 QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob); 304 QFETCH(bool, fetchJobFailed); 305 306 auto itemModifyJob = new FakeJob(this); 307 308 Utils::MockObject<Akonadi::StorageInterface> storageMock; 309 Utils::MockObject<Akonadi::SerializerInterface> serializerMock; 310 QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(), 311 serializerMock.getInstance())); 312 313 // Storage mock returning the delete job 314 storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()) 315 .thenReturn(itemModifyJob); 316 storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()) 317 .thenReturn(itemFetchJob); 318 319 // Serializer mock returning the item for the task 320 serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).thenReturn(childItem); 321 serializerMock(&Akonadi::SerializerInterface::removeItemParent).when(childItem).thenReturn(); 322 323 // WHEN 324 repository->dissociate(child)->exec(); 325 326 // THEN 327 QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).exactly(1)); 328 329 QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()).exactly(1)); 330 if (!fetchJobFailed) { 331 QVERIFY(serializerMock(&Akonadi::SerializerInterface::removeItemParent).when(childItem).exactly(1));; 332 QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()).exactly(1)); 333 } 334 335 // Give a chance to job to delete themselves 336 // in case of an error (since they use deleteLater() internally) 337 QTest::qWait(10); 338 } 339 }; 340 341 ZANSHIN_TEST_MAIN(AkonadiProjectRepositoryTest) 342 343 #include "akonadiprojectrepositorytest.moc" 344