File indexing completed on 2025-01-05 04:59:53

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org>
0003  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 
0007 #include <testlib/qtest_zanshin.h>
0008 
0009 #include "utils/mockobject.h"
0010 
0011 #include "testlib/akonadifakejobs.h"
0012 #include "testlib/akonadifakemonitor.h"
0013 
0014 #include "akonadi/akonadiprojectrepository.h"
0015 #include "akonadi/akonadiserializerinterface.h"
0016 #include "akonadi/akonadistorageinterface.h"
0017 
0018 using namespace mockitopp;
0019 
0020 Q_DECLARE_METATYPE(Testlib::AkonadiFakeItemFetchJob*)
0021 
0022 class AkonadiProjectRepositoryTest : public QObject
0023 {
0024     Q_OBJECT
0025 private slots:
0026     void shouldCreateProjectInDataSource()
0027     {
0028         // GIVEN
0029 
0030         // A project and its corresponding item already not existing in storage
0031         Akonadi::Item item;
0032         auto project = Domain::Project::Ptr::create();
0033 
0034         // A data source and its corresponding collection existing in storage
0035         Akonadi::Collection collection(42);
0036         auto source = Domain::DataSource::Ptr::create();
0037 
0038         // A mock create job
0039         auto itemCreateJob = new FakeJob(this);
0040 
0041         // Storage mock returning the create job
0042         Utils::MockObject<Akonadi::StorageInterface> storageMock;
0043         storageMock(&Akonadi::StorageInterface::createItem).when(item, collection)
0044                                                            .thenReturn(itemCreateJob);
0045 
0046         // Serializer mock
0047         Utils::MockObject<Akonadi::SerializerInterface> serializerMock;
0048         serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).thenReturn(item);
0049         serializerMock(&Akonadi::SerializerInterface::createCollectionFromDataSource).when(source).thenReturn(collection);
0050 
0051         // WHEN
0052         QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(),
0053                                                                                              serializerMock.getInstance()));
0054         repository->create(project, source)->exec();
0055 
0056         // THEN
0057         QVERIFY(storageMock(&Akonadi::StorageInterface::createItem).when(item, collection).exactly(1));
0058     }
0059 
0060     void shouldUpdateExistingProject()
0061     {
0062         // GIVEN
0063 
0064         // A project and its corresponding item already existing in storage
0065         Akonadi::Item item(42);
0066         Domain::Project::Ptr project(new Domain::Project);
0067 
0068         // A mock modify job
0069         auto itemModifyJob = new FakeJob(this);
0070 
0071         Utils::MockObject<Akonadi::StorageInterface> storageMock;
0072         Utils::MockObject<Akonadi::SerializerInterface> serializerMock;
0073         QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(),
0074                                                                                              serializerMock.getInstance()));
0075 
0076         // Storage mock returning the create job
0077         storageMock(&Akonadi::StorageInterface::updateItem).when(item, repository.get())
0078                                                            .thenReturn(itemModifyJob);
0079 
0080         // Serializer mock returning the item for the project
0081         serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).thenReturn(item);
0082 
0083         // WHEN
0084         repository->update(project)->exec();
0085 
0086         // THEN
0087         QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).exactly(1));
0088         QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(item, repository.get()).exactly(1));
0089     }
0090 
0091     void shouldRemoveExistingProject()
0092     {
0093         // GIVEN
0094 
0095         // A project and its corresponding item already existing in storage
0096         Akonadi::Item item(42);
0097         auto project = Domain::Project::Ptr::create();
0098 
0099         // A mock remove job
0100         auto itemRemoveJob = new FakeJob(this);
0101 
0102         Utils::MockObject<Akonadi::StorageInterface> storageMock;
0103         Utils::MockObject<Akonadi::SerializerInterface> serializerMock;
0104         QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(),
0105                                                                                              serializerMock.getInstance()));
0106 
0107         // Storage mock returning the create job
0108         storageMock(&Akonadi::StorageInterface::removeItem).when(item, repository.get())
0109                                                            .thenReturn(itemRemoveJob);
0110 
0111         // Serializer mock returning the item for the project
0112         serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(project).thenReturn(item);
0113 
0114         // WHEN
0115         repository->remove(project)->exec();
0116 
0117         // THEN
0118         QVERIFY(storageMock(&Akonadi::StorageInterface::removeItem).when(item, repository.get()).exactly(1));
0119     }
0120 
0121     void shouldAssociateATaskToAProject_data()
0122     {
0123         QTest::addColumn<Akonadi::Item>("childItem");
0124         QTest::addColumn<Akonadi::Item>("parentItem");
0125         QTest::addColumn<Domain::Task::Ptr>("child");
0126         QTest::addColumn<Domain::Project::Ptr>("parent");
0127         QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob1");
0128         QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob2");
0129         QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob3");
0130         QTest::addColumn<bool>("execJob");
0131         QTest::addColumn<bool>("execParentJob");
0132         QTest::addColumn<Akonadi::Item::List>("list");
0133 
0134         Akonadi::Collection col(40);
0135 
0136         Akonadi::Item childItem(42);
0137         childItem.setParentCollection(col);
0138         Domain::Task::Ptr childTask(new Domain::Task);
0139 
0140         Akonadi::Item parentItem(41);
0141         parentItem.setParentCollection(col);
0142         auto parent = Domain::Project::Ptr::create();
0143 
0144         auto itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this);
0145         itemFetchJob1->setItems(Akonadi::Item::List() << childItem);
0146         auto itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this);
0147         itemFetchJob2->setItems(Akonadi::Item::List() << parentItem);
0148         auto itemFetchJob3 = new Testlib::AkonadiFakeItemFetchJob(this);
0149 
0150         Akonadi::Item::List list;
0151 
0152         QTest::newRow("nominal case (task)") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << true << list;
0153 
0154         itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this);
0155         itemFetchJob1->setExpectedError(KJob::KilledJobError);
0156         QTest::newRow("child job error with empty list") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << false << false << list;
0157 
0158         itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this);
0159         itemFetchJob1->setExpectedError(KJob::KilledJobError);
0160         itemFetchJob1->setItems(Akonadi::Item::List() << childItem);
0161         QTest::newRow("child job error with item (task)") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << false << false << list;
0162 
0163         itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this);
0164         itemFetchJob1->setItems(Akonadi::Item::List() << childItem);
0165         itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this);
0166         itemFetchJob2->setExpectedError(KJob::KilledJobError);
0167         QTest::newRow("parent job error with empty list (task)") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << false << list;
0168 
0169         itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this);
0170         itemFetchJob1->setItems(Akonadi::Item::List() << childItem);
0171         itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this);
0172         itemFetchJob2->setExpectedError(KJob::KilledJobError);
0173         itemFetchJob2->setItems(Akonadi::Item::List() << parentItem);
0174         QTest::newRow("parent job error with item (task)") << childItem << parentItem << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << false << list;
0175 
0176         itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this);
0177         itemFetchJob1->setItems(Akonadi::Item::List() << childItem);
0178         itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this);
0179         Akonadi::Collection col2(39);
0180         Akonadi::Item parentItem2(41);
0181         parentItem2.setParentCollection(col2);
0182         itemFetchJob2->setItems(Akonadi::Item::List() << parentItem2);
0183         itemFetchJob3 = new Testlib::AkonadiFakeItemFetchJob(this);
0184         QTest::newRow("update and move item (task)") << childItem << parentItem2 << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << true << list;
0185 
0186         itemFetchJob1 = new Testlib::AkonadiFakeItemFetchJob(this);
0187         itemFetchJob1->setItems(Akonadi::Item::List() << childItem);
0188         itemFetchJob2 = new Testlib::AkonadiFakeItemFetchJob(this);
0189         itemFetchJob2->setItems(Akonadi::Item::List() << parentItem2);
0190         itemFetchJob3 = new Testlib::AkonadiFakeItemFetchJob(this);
0191         Akonadi::Item childItem2(43);
0192         Akonadi::Item::List list2;
0193         list2 << childItem2;
0194         itemFetchJob3->setItems(list2);
0195         QTest::newRow("update and move item and his child (task)") << childItem << parentItem2 << childTask << parent << itemFetchJob1 << itemFetchJob2 << itemFetchJob3 << true << true << list2;
0196     }
0197 
0198     void shouldAssociateATaskToAProject()
0199     {
0200         // GIVEN
0201         QFETCH(Akonadi::Item, childItem);
0202         QFETCH(Akonadi::Item, parentItem);
0203         QFETCH(Domain::Task::Ptr, child);
0204         QFETCH(Domain::Project::Ptr, parent);
0205         QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob1);
0206         QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob2);
0207         QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob3);
0208         QFETCH(bool, execJob);
0209         QFETCH(bool, execParentJob);
0210         QFETCH(Akonadi::Item::List, list);
0211 
0212         // A mock create job
0213         auto itemModifyJob = new FakeJob(this);
0214         auto transactionJob = new FakeJob(this);
0215         auto itemsMoveJob = new FakeJob(this);
0216 
0217         Akonadi::Item::List movedList;
0218         movedList << childItem << list;
0219 
0220         Utils::MockObject<Akonadi::StorageInterface> storageMock;
0221         Utils::MockObject<Akonadi::SerializerInterface> serializerMock;
0222         QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(),
0223                                                                                              serializerMock.getInstance()));
0224 
0225         // Storage mock returning the create job
0226         storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get())
0227                                                           .thenReturn(itemFetchJob1);
0228         storageMock(&Akonadi::StorageInterface::fetchItem).when(parentItem, repository.get())
0229                                                           .thenReturn(itemFetchJob2);
0230         if (parentItem.parentCollection().id() != childItem.parentCollection().id()) {
0231             storageMock(&Akonadi::StorageInterface::fetchItems).when(childItem.parentCollection(), repository.get())
0232                                                                .thenReturn(itemFetchJob3);
0233             storageMock(&Akonadi::StorageInterface::createTransaction).when(repository.get()).thenReturn(transactionJob);
0234             storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, transactionJob)
0235                                                                .thenReturn(itemModifyJob);
0236             storageMock(&Akonadi::StorageInterface::moveItems).when(movedList, parentItem.parentCollection(), transactionJob)
0237                                                               .thenReturn(itemsMoveJob);
0238         } else {
0239             storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get())
0240                                                                .thenReturn(itemModifyJob);
0241         }
0242 
0243         // Serializer mock returning the item for the task
0244         serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).thenReturn(childItem);
0245         serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(parent).thenReturn(parentItem);
0246         serializerMock(&Akonadi::SerializerInterface::updateItemProject).when(childItem, parent).thenReturn();
0247         if (execParentJob)
0248             serializerMock(&Akonadi::SerializerInterface::filterDescendantItems).when(list, childItem).thenReturn(list);
0249 
0250         // WHEN
0251         auto associateJob = repository->associate(parent, child);
0252         if (execJob)
0253             associateJob->exec();
0254 
0255         // THEN
0256         QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()).exactly(1));
0257         if (execJob) {
0258             QVERIFY(serializerMock(&Akonadi::SerializerInterface::updateItemProject).when(childItem, parent).exactly(1));
0259             QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromProject).when(parent).exactly(1));
0260             QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(parentItem, repository.get()).exactly(1));
0261             if (execParentJob) {
0262                 if (parentItem.parentCollection().id() != childItem.parentCollection().id()) {
0263                     QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItems).when(childItem.parentCollection(), repository.get()).exactly(1));
0264                     QVERIFY(storageMock(&Akonadi::StorageInterface::createTransaction).when(repository.get()).thenReturn(transactionJob).exactly(1));
0265                     QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, transactionJob).exactly(1));
0266                     QVERIFY(storageMock(&Akonadi::StorageInterface::moveItems).when(movedList, parentItem.parentCollection(), transactionJob).exactly(1));
0267                 } else {
0268                     QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()).exactly(1));
0269                 }
0270             }
0271         }
0272     }
0273 
0274     void shouldDissociateATaskFromItsProject_data()
0275     {
0276         QTest::addColumn<Domain::Task::Ptr>("child");
0277         QTest::addColumn<Akonadi::Item>("childItem");
0278         QTest::addColumn<Testlib::AkonadiFakeItemFetchJob*>("itemFetchJob");
0279         QTest::addColumn<bool>("fetchJobFailed");
0280 
0281         Domain::Task::Ptr taskChild(new Domain::Task);
0282         Akonadi::Item childItem(42);
0283 
0284         auto itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this);
0285         itemFetchJob->setItems(Akonadi::Item::List() << childItem);
0286         QTest::newRow("task nominal case") << taskChild << childItem << itemFetchJob << false;
0287 
0288         itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this);
0289         itemFetchJob->setExpectedError(KJob::KilledJobError);
0290         QTest::newRow("task job error with empty list") << taskChild << childItem << itemFetchJob << true;
0291 
0292         itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this);
0293         itemFetchJob->setExpectedError(KJob::KilledJobError);
0294         itemFetchJob->setItems(Akonadi::Item::List() << childItem);
0295         QTest::newRow("task job error with item") << taskChild << childItem << itemFetchJob << true;
0296     }
0297 
0298     void shouldDissociateATaskFromItsProject()
0299     {
0300         // GIVEN
0301         QFETCH(Domain::Task::Ptr, child);
0302         QFETCH(Akonadi::Item, childItem);
0303         QFETCH(Testlib::AkonadiFakeItemFetchJob*, itemFetchJob);
0304         QFETCH(bool, fetchJobFailed);
0305 
0306         auto itemModifyJob = new FakeJob(this);
0307 
0308         Utils::MockObject<Akonadi::StorageInterface> storageMock;
0309         Utils::MockObject<Akonadi::SerializerInterface> serializerMock;
0310         QScopedPointer<Akonadi::ProjectRepository> repository(new Akonadi::ProjectRepository(storageMock.getInstance(),
0311                                                                                              serializerMock.getInstance()));
0312 
0313         // Storage mock returning the delete job
0314         storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get())
0315                                                            .thenReturn(itemModifyJob);
0316         storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get())
0317                                                           .thenReturn(itemFetchJob);
0318 
0319         // Serializer mock returning the item for the task
0320         serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).thenReturn(childItem);
0321         serializerMock(&Akonadi::SerializerInterface::removeItemParent).when(childItem).thenReturn();
0322 
0323         // WHEN
0324         repository->dissociate(child)->exec();
0325 
0326         // THEN
0327         QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(child).exactly(1));
0328 
0329         QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(childItem, repository.get()).exactly(1));
0330         if (!fetchJobFailed) {
0331             QVERIFY(serializerMock(&Akonadi::SerializerInterface::removeItemParent).when(childItem).exactly(1));;
0332             QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(childItem, repository.get()).exactly(1));
0333         }
0334 
0335         // Give a chance to job to delete themselves
0336         // in case of an error (since they use deleteLater() internally)
0337         QTest::qWait(10);
0338     }
0339 };
0340 
0341 ZANSHIN_TEST_MAIN(AkonadiProjectRepositoryTest)
0342 
0343 #include "akonadiprojectrepositorytest.moc"