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"