File indexing completed on 2024-05-12 05:26:27

0001 #include <QTest>
0002 
0003 #include <QString>
0004 #include <QSharedPointer>
0005 
0006 #include "store.h"
0007 #include "commands.h"
0008 #include "entitybuffer.h"
0009 #include "pipeline.h"
0010 #include "synchronizer.h"
0011 #include "commandprocessor.h"
0012 #include "definitions.h"
0013 #include "adaptorfactoryregistry.h"
0014 #include "datastorequery.h"
0015 #include "genericresource.h"
0016 #include "test.h"
0017 
0018 class TestSynchronizer: public Sink::Synchronizer {
0019 public:
0020     TestSynchronizer(const Sink::ResourceContext &context): Sink::Synchronizer(context)
0021     {
0022 
0023     }
0024 
0025     QMap<QByteArray, std::function<void()>> mSyncCallbacks;
0026 
0027     KAsync::Job<void> synchronizeWithSource(const Sink::QueryBase &query) override
0028     {
0029         return KAsync::start([this, query] {
0030             Q_ASSERT(mSyncCallbacks.contains(query.id()));
0031             mSyncCallbacks.value(query.id())();
0032         });
0033     }
0034 
0035     void createOrModify(const QByteArray &rid, Sink::ApplicationDomain::ApplicationDomainType &entity)
0036     {
0037         Sink::Synchronizer::createOrModify("calendar", rid, entity);
0038     }
0039 
0040     void scanForRemovals(const QSet<QByteArray> &set)
0041     {
0042         Sink::Synchronizer::scanForRemovals("calendar", [&](const QByteArray &remoteId) {
0043             return set.contains(remoteId);
0044         });
0045     }
0046 
0047     QByteArray resolveRemoteId(const QByteArray &remoteId) {
0048         return syncStore().resolveRemoteId("calendar", remoteId);
0049     }
0050 
0051     void synchronize(std::function<void()> callback, const QByteArray &id = {}, Synchronizer::SyncRequest::RequestOptions options = Synchronizer::SyncRequest::NoOptions) {
0052         mSyncCallbacks.insert(id, callback);
0053         Sink::Query query;
0054         query.setId(id);
0055         addToQueue(Synchronizer::SyncRequest{query, id, options});
0056         VERIFYEXEC(processSyncQueue());
0057     }
0058 };
0059 
0060 class SynchronizerTest : public QObject
0061 {
0062     Q_OBJECT
0063 
0064     QByteArray instanceIdentifier()
0065     {
0066         return "synchronizertest.instance1";
0067     }
0068 
0069     Sink::ResourceContext getContext()
0070     {
0071         return Sink::ResourceContext{instanceIdentifier(), "test", Sink::AdaptorFactoryRegistry::instance().getFactories("test")};
0072     }
0073 
0074     bool queryFor(const QByteArray &sinkId, const QByteArray &type, Sink::Storage::EntityStore &store) {
0075         bool foundInQuery = false;
0076         DataStoreQuery dataStoreQuery{{sinkId}, type, store};
0077         auto resultSet = dataStoreQuery.execute();
0078         resultSet.replaySet(0, 1, [&](const ResultSet::Result &r) {
0079             if (r.entity.identifier() == sinkId) {
0080                 foundInQuery = true;
0081             }
0082         });
0083         return foundInQuery;
0084     }
0085 
0086 private slots:
0087     void initTestCase()
0088     {
0089         Sink::Test::initTest();
0090         Sink::Storage::DataStore{Sink::Store::storageLocation(), instanceIdentifier(), Sink::Storage::DataStore::ReadWrite}.removeFromDisk();
0091         Sink::AdaptorFactoryRegistry::instance().registerFactory<Sink::ApplicationDomain::Calendar, DomainTypeAdaptorFactory<Sink::ApplicationDomain::Calendar>>("test");
0092     }
0093 
0094     void init()
0095     {
0096         Sink::GenericResource::removeFromDisk(instanceIdentifier());
0097     }
0098 
0099     /*
0100      * Ensure we can remove an recreate an entity.
0101      */
0102     void testTemporaryRemoval()
0103     {
0104         const auto context = getContext();
0105         Sink::Pipeline pipeline(context, instanceIdentifier());
0106         Sink::CommandProcessor processor(&pipeline, instanceIdentifier(), Sink::Log::Context{"processor"});
0107 
0108         auto synchronizer = QSharedPointer<TestSynchronizer>::create(context);
0109         processor.setSynchronizer(synchronizer);
0110 
0111         synchronizer->setSecret("secret");
0112 
0113         synchronizer->synchronize([&] {
0114             Sink::ApplicationDomain::Calendar calendar;
0115             calendar.setName("Name");
0116             synchronizer->createOrModify("1", calendar);
0117         });
0118 
0119         VERIFYEXEC(processor.processAllMessages());
0120 
0121         const auto sinkId = synchronizer->resolveRemoteId("1");
0122         QVERIFY(!sinkId.isEmpty());
0123 
0124         {
0125             Sink::Storage::EntityStore store(context, {"entitystore"});
0126             QVERIFY(store.contains("calendar", sinkId));
0127             QVERIFY(store.exists("calendar", sinkId));
0128             QVERIFY(queryFor(sinkId, "calendar", store));
0129         }
0130 
0131         //Remove the calendar
0132         synchronizer->synchronize([&] {
0133             synchronizer->scanForRemovals({});
0134         });
0135         //Process the removal
0136         VERIFYEXEC(processor.processAllMessages());
0137 
0138         //Ensure we replay the revision generated by the removal.
0139         //This is necessary to remove the rid mapping
0140         synchronizer->replayNextRevision().exec();
0141         {
0142             Sink::Storage::EntityStore store(context, {"entitystore"});
0143             QVERIFY(!store.exists("calendar", sinkId));
0144             QVERIFY(store.contains("calendar", sinkId));
0145             QVERIFY(!queryFor(sinkId, "calendar", store));
0146         }
0147 
0148         //Recreate the same calendar
0149         synchronizer->synchronize([&] {
0150             Sink::ApplicationDomain::Calendar calendar;
0151             calendar.setName("Name");
0152             synchronizer->createOrModify("1", calendar);
0153         });
0154         VERIFYEXEC(processor.processAllMessages());
0155 
0156         //Ensure we got a new sink id (if not we failed to remove the rid mapping from the previous instance).
0157         const auto newSinkId = synchronizer->resolveRemoteId("1");
0158         QVERIFY(!newSinkId.isEmpty());
0159         QVERIFY(newSinkId != sinkId);
0160 
0161         {
0162             Sink::Storage::EntityStore store(context, {"entitystore"});
0163             QVERIFY(store.contains("calendar", newSinkId));
0164             QVERIFY(store.exists("calendar", newSinkId));
0165 
0166             // store.readRevisions("calendar", newSinkId, 0, [] (const QByteArray &uid, qint64 revision, const Sink::EntityBuffer &buffer) {
0167             //     qWarning() << uid << revision << buffer.operation();
0168             // });
0169 
0170             QVERIFY(!queryFor(sinkId, "calendar", store));
0171             QVERIFY(queryFor(newSinkId, "calendar", store));
0172         }
0173     }
0174 
0175     /*
0176      * Ensure the flushed content is available during the next sync request
0177      */
0178     void testFlush()
0179     {
0180         const auto context = getContext();
0181         Sink::Pipeline pipeline(context, instanceIdentifier());
0182         Sink::CommandProcessor processor(&pipeline, instanceIdentifier(), Sink::Log::Context{"processor"});
0183 
0184         auto synchronizer = QSharedPointer<TestSynchronizer>::create(context);
0185         processor.setSynchronizer(synchronizer);
0186 
0187         synchronizer->setSecret("secret");
0188 
0189         QByteArray sinkId;
0190         synchronizer->synchronize([&] {
0191             Sink::ApplicationDomain::Calendar calendar;
0192             calendar.setName("Name");
0193             synchronizer->createOrModify("1", calendar);
0194             sinkId = synchronizer->resolveRemoteId("1");
0195         }, "1");
0196         QVERIFY(!sinkId.isEmpty());
0197 
0198         //With a flush the calendar should be available during the next sync
0199         synchronizer->synchronize([&] {
0200             Sink::Storage::EntityStore store(context, {"entitystore"});
0201             QVERIFY(store.contains("calendar", sinkId));
0202 
0203         }, "2", Sink::Synchronizer::SyncRequest::RequestFlush);
0204 
0205         VERIFYEXEC(processor.processAllMessages());
0206     }
0207 
0208 };
0209 
0210 QTEST_MAIN(SynchronizerTest)
0211 #include "synchronizertest.moc"