diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/CMakeLists.txt | 7 | ||||
-rw-r--r-- | tests/clientapitest.cpp | 20 | ||||
-rw-r--r-- | tests/dummyresourcetest.cpp | 9 | ||||
-rw-r--r-- | tests/entitystoretest.cpp | 89 | ||||
-rw-r--r-- | tests/genericfacadetest.cpp | 154 | ||||
-rw-r--r-- | tests/genericresourcebenchmark.cpp | 209 | ||||
-rw-r--r-- | tests/genericresourcetest.cpp | 85 | ||||
-rw-r--r-- | tests/hawd/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/hawd/state.cpp | 2 | ||||
-rw-r--r-- | tests/interresourcemovetest.cpp | 37 | ||||
-rw-r--r-- | tests/mailquerybenchmark.cpp | 69 | ||||
-rw-r--r-- | tests/mailsynctest.cpp | 37 | ||||
-rw-r--r-- | tests/mailsynctest.h | 2 | ||||
-rw-r--r-- | tests/modelinteractivitytest.cpp | 6 | ||||
-rw-r--r-- | tests/notificationtest.cpp | 132 | ||||
-rw-r--r-- | tests/querytest.cpp | 65 |
16 files changed, 420 insertions, 506 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a69fcb3..c77a736 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt | |||
@@ -21,10 +21,8 @@ include(SinkTest) | |||
21 | manual_tests ( | 21 | manual_tests ( |
22 | storagebenchmark | 22 | storagebenchmark |
23 | dummyresourcebenchmark | 23 | dummyresourcebenchmark |
24 | # genericresourcebenchmark | ||
25 | mailquerybenchmark | 24 | mailquerybenchmark |
26 | pipelinebenchmark | 25 | pipelinebenchmark |
27 | # genericfacadebenchmark | ||
28 | ) | 26 | ) |
29 | 27 | ||
30 | auto_tests ( | 28 | auto_tests ( |
@@ -35,8 +33,6 @@ auto_tests ( | |||
35 | domainadaptortest | 33 | domainadaptortest |
36 | messagequeuetest | 34 | messagequeuetest |
37 | indextest | 35 | indextest |
38 | # genericresourcetest | ||
39 | # genericfacadetest | ||
40 | resourcecommunicationtest | 36 | resourcecommunicationtest |
41 | pipelinetest | 37 | pipelinetest |
42 | querytest | 38 | querytest |
@@ -48,6 +44,8 @@ auto_tests ( | |||
48 | testaccounttest | 44 | testaccounttest |
49 | dummyresourcemailtest | 45 | dummyresourcemailtest |
50 | interresourcemovetest | 46 | interresourcemovetest |
47 | notificationtest | ||
48 | entitystoretest | ||
51 | ) | 49 | ) |
52 | generate_flatbuffers(dummyresourcetest calendar) | 50 | generate_flatbuffers(dummyresourcetest calendar) |
53 | target_link_libraries(dummyresourcetest sink_resource_dummy) | 51 | target_link_libraries(dummyresourcetest sink_resource_dummy) |
@@ -56,3 +54,4 @@ target_link_libraries(dummyresourcewritebenchmark sink_resource_dummy) | |||
56 | target_link_libraries(querytest sink_resource_dummy) | 54 | target_link_libraries(querytest sink_resource_dummy) |
57 | target_link_libraries(modelinteractivitytest sink_resource_dummy) | 55 | target_link_libraries(modelinteractivitytest sink_resource_dummy) |
58 | target_link_libraries(inspectiontest sink_resource_dummy) | 56 | target_link_libraries(inspectiontest sink_resource_dummy) |
57 | target_link_libraries(notificationtest sink_resource_dummy) | ||
diff --git a/tests/clientapitest.cpp b/tests/clientapitest.cpp index da52afb..3955ebd 100644 --- a/tests/clientapitest.cpp +++ b/tests/clientapitest.cpp | |||
@@ -12,6 +12,12 @@ | |||
12 | #include "asyncutils.h" | 12 | #include "asyncutils.h" |
13 | 13 | ||
14 | template <typename T> | 14 | template <typename T> |
15 | struct Result { | ||
16 | QSharedPointer<T> parent; | ||
17 | bool fetchedAll; | ||
18 | }; | ||
19 | |||
20 | template <typename T> | ||
15 | class TestDummyResourceFacade : public Sink::StoreFacade<T> | 21 | class TestDummyResourceFacade : public Sink::StoreFacade<T> |
16 | { | 22 | { |
17 | public: | 23 | public: |
@@ -68,7 +74,7 @@ public: | |||
68 | auto emitter = resultProvider->emitter(); | 74 | auto emitter = resultProvider->emitter(); |
69 | 75 | ||
70 | resultProvider->setFetcher([query, resultProvider, this, ctx](const typename T::Ptr &parent) { | 76 | resultProvider->setFetcher([query, resultProvider, this, ctx](const typename T::Ptr &parent) { |
71 | async::run<int>([=] { | 77 | async::run<Result<T>>([=] { |
72 | if (parent) { | 78 | if (parent) { |
73 | SinkTraceCtx(ctx) << "Running the fetcher " << parent->identifier(); | 79 | SinkTraceCtx(ctx) << "Running the fetcher " << parent->identifier(); |
74 | } else { | 80 | } else { |
@@ -90,14 +96,16 @@ public: | |||
90 | SinkTraceCtx(ctx) << "Aborting early after " << count << "results."; | 96 | SinkTraceCtx(ctx) << "Aborting early after " << count << "results."; |
91 | offset = i + 1; | 97 | offset = i + 1; |
92 | bool fetchedAll = (i + 1 >= results.size()); | 98 | bool fetchedAll = (i + 1 >= results.size()); |
93 | resultProvider->initialResultSetComplete(parent, fetchedAll); | 99 | return Result<T>{parent, fetchedAll}; |
94 | return 0; | ||
95 | } | 100 | } |
96 | } | 101 | } |
97 | } | 102 | } |
98 | resultProvider->initialResultSetComplete(parent, true); | 103 | return Result<T>{parent, true}; |
99 | return 0; | 104 | }, runAsync) |
100 | }, runAsync).exec(); | 105 | .then([=] (const Result<T> &r) { |
106 | resultProvider->initialResultSetComplete(r.parent, r.fetchedAll); | ||
107 | }) | ||
108 | .exec(); | ||
101 | }); | 109 | }); |
102 | auto job = KAsync::start([query, resultProvider]() {}); | 110 | auto job = KAsync::start([query, resultProvider]() {}); |
103 | mResultProvider = resultProvider.data(); | 111 | mResultProvider = resultProvider.data(); |
diff --git a/tests/dummyresourcetest.cpp b/tests/dummyresourcetest.cpp index eea63c0..17df160 100644 --- a/tests/dummyresourcetest.cpp +++ b/tests/dummyresourcetest.cpp | |||
@@ -136,12 +136,7 @@ private slots: | |||
136 | void testResourceSync() | 136 | void testResourceSync() |
137 | { | 137 | { |
138 | ::DummyResource resource(getContext()); | 138 | ::DummyResource resource(getContext()); |
139 | auto job = resource.synchronizeWithSource(Sink::QueryBase()); | 139 | VERIFYEXEC(resource.synchronizeWithSource(Sink::QueryBase())); |
140 | // TODO pass in optional timeout? | ||
141 | auto future = job.exec(); | ||
142 | future.waitForFinished(); | ||
143 | QVERIFY(!future.errorCode()); | ||
144 | QVERIFY(future.isFinished()); | ||
145 | QVERIFY(!resource.error()); | 140 | QVERIFY(!resource.error()); |
146 | auto processAllMessagesFuture = resource.processAllMessages().exec(); | 141 | auto processAllMessagesFuture = resource.processAllMessages().exec(); |
147 | processAllMessagesFuture.waitForFinished(); | 142 | processAllMessagesFuture.waitForFinished(); |
@@ -152,7 +147,7 @@ private slots: | |||
152 | const auto query = Query().resourceFilter("sink.dummy.instance1"); | 147 | const auto query = Query().resourceFilter("sink.dummy.instance1"); |
153 | 148 | ||
154 | // Ensure all local data is processed | 149 | // Ensure all local data is processed |
155 | Sink::Store::synchronize(query).exec().waitForFinished(); | 150 | VERIFYEXEC(Sink::Store::synchronize(query)); |
156 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1")); | 151 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1")); |
157 | 152 | ||
158 | auto model = Sink::Store::loadModel<Event>(query); | 153 | auto model = Sink::Store::loadModel<Event>(query); |
diff --git a/tests/entitystoretest.cpp b/tests/entitystoretest.cpp new file mode 100644 index 0000000..90575a5 --- /dev/null +++ b/tests/entitystoretest.cpp | |||
@@ -0,0 +1,89 @@ | |||
1 | #include <QtTest> | ||
2 | |||
3 | #include <QDebug> | ||
4 | #include <QString> | ||
5 | |||
6 | #include "common/storage/entitystore.h" | ||
7 | #include "common/adaptorfactoryregistry.h" | ||
8 | #include "common/definitions.h" | ||
9 | #include "testimplementations.h" | ||
10 | |||
11 | class EntityStoreTest : public QObject | ||
12 | { | ||
13 | Q_OBJECT | ||
14 | private: | ||
15 | QString resourceInstanceIdentifier{"resourceId"}; | ||
16 | |||
17 | private slots: | ||
18 | void initTestCase() | ||
19 | { | ||
20 | Sink::AdaptorFactoryRegistry::instance().registerFactory<Sink::ApplicationDomain::Mail, TestMailAdaptorFactory>("test"); | ||
21 | } | ||
22 | |||
23 | void cleanup() | ||
24 | { | ||
25 | Sink::Storage::DataStore storage(Sink::storageLocation(), resourceInstanceIdentifier); | ||
26 | storage.removeFromDisk(); | ||
27 | } | ||
28 | |||
29 | void testCleanup() | ||
30 | { | ||
31 | } | ||
32 | |||
33 | void readAll() | ||
34 | { | ||
35 | using namespace Sink; | ||
36 | ResourceContext resourceContext{resourceInstanceIdentifier.toUtf8(), "dummy", AdaptorFactoryRegistry::instance().getFactories("test")}; | ||
37 | Storage::EntityStore store(resourceContext, {}); | ||
38 | |||
39 | auto mail = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Mail>("res1"); | ||
40 | mail.setExtractedMessageId("messageid"); | ||
41 | mail.setExtractedSubject("boo"); | ||
42 | |||
43 | auto mail2 = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Mail>("res1"); | ||
44 | mail2.setExtractedMessageId("messageid2"); | ||
45 | mail2.setExtractedSubject("foo"); | ||
46 | |||
47 | auto mail3 = ApplicationDomain::ApplicationDomainType::createEntity<ApplicationDomain::Mail>("res1"); | ||
48 | mail3.setExtractedMessageId("messageid2"); | ||
49 | mail3.setExtractedSubject("foo"); | ||
50 | |||
51 | store.startTransaction(Storage::DataStore::ReadWrite); | ||
52 | store.add("mail", mail, false); | ||
53 | store.add("mail", mail2, false); | ||
54 | store.add("mail", mail3, false); | ||
55 | |||
56 | mail.setExtractedSubject("foo"); | ||
57 | |||
58 | store.modify("mail", mail, QByteArrayList{}, false); | ||
59 | store.remove("mail", mail3, false); | ||
60 | store.commitTransaction(); | ||
61 | |||
62 | store.startTransaction(Storage::DataStore::ReadOnly); | ||
63 | { | ||
64 | //We get every uid once | ||
65 | QList<QByteArray> uids; | ||
66 | store.readAllUids("mail", [&] (const QByteArray &uid) { | ||
67 | uids << uid; | ||
68 | }); | ||
69 | QCOMPARE(uids.size(), 2); | ||
70 | } | ||
71 | |||
72 | { | ||
73 | //We get the latest version of every entity once | ||
74 | QList<QByteArray> uids; | ||
75 | store.readAll("mail", [&] (const ApplicationDomain::ApplicationDomainType &entity) { | ||
76 | //The first revision should be superseeded by the modification | ||
77 | QCOMPARE(entity.getProperty(ApplicationDomain::Mail::Subject::name).toString(), QString::fromLatin1("foo")); | ||
78 | uids << entity.identifier(); | ||
79 | }); | ||
80 | QCOMPARE(uids.size(), 2); | ||
81 | } | ||
82 | |||
83 | store.abortTransaction(); | ||
84 | |||
85 | } | ||
86 | }; | ||
87 | |||
88 | QTEST_MAIN(EntityStoreTest) | ||
89 | #include "entitystoretest.moc" | ||
diff --git a/tests/genericfacadetest.cpp b/tests/genericfacadetest.cpp deleted file mode 100644 index 0267dac..0000000 --- a/tests/genericfacadetest.cpp +++ /dev/null | |||
@@ -1,154 +0,0 @@ | |||
1 | #include <QtTest> | ||
2 | |||
3 | #include <QString> | ||
4 | |||
5 | #include "testimplementations.h" | ||
6 | |||
7 | #include <common/facade.h> | ||
8 | #include <common/domainadaptor.h> | ||
9 | #include <common/resultprovider.h> | ||
10 | #include <common/synclistresult.h> | ||
11 | #include <common/test.h> | ||
12 | |||
13 | // Replace with something different | ||
14 | #include "event_generated.h" | ||
15 | |||
16 | |||
17 | /** | ||
18 | * Test for the generic facade implementation. | ||
19 | * | ||
20 | * This test doesn't use the actual storage and thus only tests the update logic of the facade. | ||
21 | * //FIXME this now uses the actual storage | ||
22 | */ | ||
23 | class GenericFacadeTest : public QObject | ||
24 | { | ||
25 | Q_OBJECT | ||
26 | private slots: | ||
27 | void initTestCase() | ||
28 | { | ||
29 | Sink::Test::initTest(); | ||
30 | } | ||
31 | |||
32 | void testLoad() | ||
33 | { | ||
34 | Sink::Query query; | ||
35 | query.liveQuery = false; | ||
36 | |||
37 | auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr>>::create(); | ||
38 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); | ||
39 | // storage->mResults << Sink::ApplicationDomain::Event::Ptr::create(); | ||
40 | TestResourceFacade facade("identifier", resourceAccess); | ||
41 | |||
42 | async::SyncListResult<Sink::ApplicationDomain::Event::Ptr> result(resultSet->emitter()); | ||
43 | |||
44 | facade.load(query, *resultSet).exec().waitForFinished(); | ||
45 | resultSet->initialResultSetComplete(); | ||
46 | |||
47 | // We have to wait for the events that deliver the results to be processed by the eventloop | ||
48 | result.exec(); | ||
49 | |||
50 | QCOMPARE(result.size(), 1); | ||
51 | } | ||
52 | |||
53 | void testLiveQuery() | ||
54 | { | ||
55 | Sink::Query query; | ||
56 | query.liveQuery = true; | ||
57 | |||
58 | auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr>>::create(); | ||
59 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); | ||
60 | // storage->mResults << Sink::ApplicationDomain::Event::Ptr::create(); | ||
61 | TestResourceFacade facade("identifier", resourceAccess); | ||
62 | |||
63 | async::SyncListResult<Sink::ApplicationDomain::Event::Ptr> result(resultSet->emitter()); | ||
64 | |||
65 | facade.load(query, *resultSet).exec().waitForFinished(); | ||
66 | resultSet->initialResultSetComplete(); | ||
67 | |||
68 | result.exec(); | ||
69 | QCOMPARE(result.size(), 1); | ||
70 | |||
71 | // Enter a second result | ||
72 | // storage->mResults.clear(); | ||
73 | // storage->mResults << QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::BufferAdaptor>()); | ||
74 | // storage->mLatestRevision = 2; | ||
75 | resourceAccess->emit revisionChanged(2); | ||
76 | |||
77 | // Hack to get event loop in synclistresult to abort again | ||
78 | resultSet->initialResultSetComplete(); | ||
79 | result.exec(); | ||
80 | |||
81 | QCOMPARE(result.size(), 2); | ||
82 | } | ||
83 | |||
84 | void testLiveQueryModify() | ||
85 | { | ||
86 | Sink::Query query; | ||
87 | query.liveQuery = true; | ||
88 | |||
89 | auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr>>::create(); | ||
90 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); | ||
91 | auto entity = QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); | ||
92 | entity->setProperty("test", "test1"); | ||
93 | // storage->mResults << entity; | ||
94 | TestResourceFacade facade("identifier", resourceAccess); | ||
95 | |||
96 | async::SyncListResult<Sink::ApplicationDomain::Event::Ptr> result(resultSet->emitter()); | ||
97 | |||
98 | facade.load(query, *resultSet).exec().waitForFinished(); | ||
99 | resultSet->initialResultSetComplete(); | ||
100 | |||
101 | result.exec(); | ||
102 | QCOMPARE(result.size(), 1); | ||
103 | |||
104 | // Modify the entity again | ||
105 | // storage->mResults.clear(); | ||
106 | entity = QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create()); | ||
107 | entity->setProperty("test", "test2"); | ||
108 | // storage->mModifications << entity; | ||
109 | // storage->mLatestRevision = 2; | ||
110 | resourceAccess->emit revisionChanged(2); | ||
111 | |||
112 | // Hack to get event loop in synclistresult to abort again | ||
113 | resultSet->initialResultSetComplete(); | ||
114 | result.exec(); | ||
115 | |||
116 | QCOMPARE(result.size(), 1); | ||
117 | QCOMPARE(result.first()->getProperty("test").toByteArray(), QByteArray("test2")); | ||
118 | } | ||
119 | |||
120 | void testLiveQueryRemove() | ||
121 | { | ||
122 | Sink::Query query; | ||
123 | query.liveQuery = true; | ||
124 | |||
125 | auto resultSet = QSharedPointer<Sink::ResultProvider<Sink::ApplicationDomain::Event::Ptr>>::create(); | ||
126 | auto resourceAccess = QSharedPointer<TestResourceAccess>::create(); | ||
127 | auto entity = QSharedPointer<Sink::ApplicationDomain::Event>::create("resource", "id2", 0, QSharedPointer<Sink::ApplicationDomain::BufferAdaptor>()); | ||
128 | // storage->mResults << entity; | ||
129 | TestResourceFacade facade("identifier", resourceAccess); | ||
130 | |||
131 | async::SyncListResult<Sink::ApplicationDomain::Event::Ptr> result(resultSet->emitter()); | ||
132 | |||
133 | facade.load(query, *resultSet).exec().waitForFinished(); | ||
134 | resultSet->initialResultSetComplete(); | ||
135 | |||
136 | result.exec(); | ||
137 | QCOMPARE(result.size(), 1); | ||
138 | |||
139 | // Remove the entity again | ||
140 | // storage->mResults.clear(); | ||
141 | // storage->mRemovals << entity; | ||
142 | // storage->mLatestRevision = 2; | ||
143 | resourceAccess->emit revisionChanged(2); | ||
144 | |||
145 | // Hack to get event loop in synclistresult to abort again | ||
146 | resultSet->initialResultSetComplete(); | ||
147 | result.exec(); | ||
148 | |||
149 | QCOMPARE(result.size(), 0); | ||
150 | } | ||
151 | }; | ||
152 | |||
153 | QTEST_MAIN(GenericFacadeTest) | ||
154 | #include "genericfacadetest.moc" | ||
diff --git a/tests/genericresourcebenchmark.cpp b/tests/genericresourcebenchmark.cpp deleted file mode 100644 index 2315d0b..0000000 --- a/tests/genericresourcebenchmark.cpp +++ /dev/null | |||
@@ -1,209 +0,0 @@ | |||
1 | #include <QtTest> | ||
2 | |||
3 | #include <QString> | ||
4 | |||
5 | #include "testimplementations.h" | ||
6 | |||
7 | #include "event_generated.h" | ||
8 | #include "createentity_generated.h" | ||
9 | #include "commands.h" | ||
10 | #include "entitybuffer.h" | ||
11 | #include "pipeline.h" | ||
12 | #include "genericresource.h" | ||
13 | #include "definitions.h" | ||
14 | #include "domainadaptor.h" | ||
15 | #include "index.h" | ||
16 | |||
17 | #include "hawd/dataset.h" | ||
18 | #include "hawd/formatter.h" | ||
19 | |||
20 | |||
21 | static void removeFromDisk(const QString &name) | ||
22 | { | ||
23 | Sink::Storage store(Sink::storageLocation(), name, Sink::Storage::ReadWrite); | ||
24 | store.removeFromDisk(); | ||
25 | } | ||
26 | |||
27 | static QByteArray createEntityBuffer() | ||
28 | { | ||
29 | flatbuffers::FlatBufferBuilder eventFbb; | ||
30 | eventFbb.Clear(); | ||
31 | { | ||
32 | auto summary = eventFbb.CreateString("summary"); | ||
33 | Sink::ApplicationDomain::Buffer::EventBuilder eventBuilder(eventFbb); | ||
34 | eventBuilder.add_summary(summary); | ||
35 | auto eventLocation = eventBuilder.Finish(); | ||
36 | Sink::ApplicationDomain::Buffer::FinishEventBuffer(eventFbb, eventLocation); | ||
37 | } | ||
38 | |||
39 | flatbuffers::FlatBufferBuilder localFbb; | ||
40 | { | ||
41 | auto uid = localFbb.CreateString("testuid"); | ||
42 | auto localBuilder = Sink::ApplicationDomain::Buffer::EventBuilder(localFbb); | ||
43 | localBuilder.add_uid(uid); | ||
44 | auto location = localBuilder.Finish(); | ||
45 | Sink::ApplicationDomain::Buffer::FinishEventBuffer(localFbb, location); | ||
46 | } | ||
47 | |||
48 | flatbuffers::FlatBufferBuilder entityFbb; | ||
49 | Sink::EntityBuffer::assembleEntityBuffer(entityFbb, 0, 0, eventFbb.GetBufferPointer(), eventFbb.GetSize(), localFbb.GetBufferPointer(), localFbb.GetSize()); | ||
50 | |||
51 | flatbuffers::FlatBufferBuilder fbb; | ||
52 | auto type = fbb.CreateString(Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Event>().toStdString().data()); | ||
53 | auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize()); | ||
54 | Sink::Commands::CreateEntityBuilder builder(fbb); | ||
55 | builder.add_domainType(type); | ||
56 | builder.add_delta(delta); | ||
57 | auto location = builder.Finish(); | ||
58 | Sink::Commands::FinishCreateEntityBuffer(fbb, location); | ||
59 | |||
60 | return QByteArray(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize()); | ||
61 | } | ||
62 | |||
63 | class IndexUpdater : public Sink::Preprocessor | ||
64 | { | ||
65 | public: | ||
66 | void newEntity(const QByteArray &uid, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &newEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE | ||
67 | { | ||
68 | for (int i = 0; i < 10; i++) { | ||
69 | Index ridIndex(QString("index.index%1").arg(i).toLatin1(), transaction); | ||
70 | ridIndex.add("foo", uid); | ||
71 | } | ||
72 | } | ||
73 | |||
74 | void modifiedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, const Sink::ApplicationDomain::BufferAdaptor &newEntity, | ||
75 | Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE | ||
76 | { | ||
77 | } | ||
78 | |||
79 | void deletedEntity(const QByteArray &key, qint64 revision, const Sink::ApplicationDomain::BufferAdaptor &oldEntity, Sink::Storage::Transaction &transaction) Q_DECL_OVERRIDE | ||
80 | { | ||
81 | } | ||
82 | }; | ||
83 | |||
84 | /** | ||
85 | * Benchmark write performance of generic resource implementation including queues and pipeline. | ||
86 | */ | ||
87 | class GenericResourceBenchmark : public QObject | ||
88 | { | ||
89 | Q_OBJECT | ||
90 | private slots: | ||
91 | |||
92 | void init() | ||
93 | { | ||
94 | Sink::Log::setDebugOutputLevel(Sink::Log::Warning); | ||
95 | } | ||
96 | |||
97 | void initTestCase() | ||
98 | { | ||
99 | removeFromDisk("sink.test.instance1"); | ||
100 | removeFromDisk("sink.test.instance1.userqueue"); | ||
101 | removeFromDisk("sink.test.instance1.synchronizerqueue"); | ||
102 | } | ||
103 | |||
104 | |||
105 | void testWriteInProcess() | ||
106 | { | ||
107 | int num = 10000; | ||
108 | |||
109 | auto pipeline = QSharedPointer<Sink::Pipeline>::create("sink.test.instance1"); | ||
110 | TestResource resource("sink.test.instance1", pipeline); | ||
111 | |||
112 | auto command = createEntityBuffer(); | ||
113 | |||
114 | QTime time; | ||
115 | time.start(); | ||
116 | |||
117 | for (int i = 0; i < num; i++) { | ||
118 | resource.processCommand(Sink::Commands::CreateEntityCommand, command); | ||
119 | } | ||
120 | auto appendTime = time.elapsed(); | ||
121 | |||
122 | // Wait until all messages have been processed | ||
123 | resource.processAllMessages().exec().waitForFinished(); | ||
124 | |||
125 | auto allProcessedTime = time.elapsed(); | ||
126 | |||
127 | // Print memory layout, RSS is what is in memory | ||
128 | // std::system("exec pmap -x \"$PPID\""); | ||
129 | |||
130 | HAWD::Dataset dataset("generic_write_in_process", m_hawdState); | ||
131 | HAWD::Dataset::Row row = dataset.row(); | ||
132 | |||
133 | row.setValue("rows", num); | ||
134 | row.setValue("append", (qreal)num / appendTime); | ||
135 | row.setValue("total", (qreal)num / allProcessedTime); | ||
136 | dataset.insertRow(row); | ||
137 | HAWD::Formatter::print(dataset); | ||
138 | } | ||
139 | |||
140 | void testWriteInProcessWithIndex() | ||
141 | { | ||
142 | int num = 50000; | ||
143 | |||
144 | auto pipeline = QSharedPointer<Sink::Pipeline>::create("sink.test.instance1"); | ||
145 | |||
146 | auto eventFactory = QSharedPointer<TestEventAdaptorFactory>::create(); | ||
147 | const QByteArray resourceIdentifier = "sink.test.instance1"; | ||
148 | auto indexer = QSharedPointer<IndexUpdater>::create(); | ||
149 | |||
150 | pipeline->setPreprocessors("event", QVector<Sink::Preprocessor *>() << indexer.data()); | ||
151 | pipeline->setAdaptorFactory("event", eventFactory); | ||
152 | |||
153 | TestResource resource("sink.test.instance1", pipeline); | ||
154 | |||
155 | auto command = createEntityBuffer(); | ||
156 | |||
157 | QTime time; | ||
158 | time.start(); | ||
159 | |||
160 | for (int i = 0; i < num; i++) { | ||
161 | resource.processCommand(Sink::Commands::CreateEntityCommand, command); | ||
162 | } | ||
163 | auto appendTime = time.elapsed(); | ||
164 | |||
165 | // Wait until all messages have been processed | ||
166 | resource.processAllMessages().exec().waitForFinished(); | ||
167 | |||
168 | auto allProcessedTime = time.elapsed(); | ||
169 | |||
170 | // Print memory layout, RSS is what is in memory | ||
171 | // std::system("exec pmap -x \"$PPID\""); | ||
172 | |||
173 | HAWD::Dataset dataset("generic_write_in_process_with_indexes", m_hawdState); | ||
174 | HAWD::Dataset::Row row = dataset.row(); | ||
175 | |||
176 | row.setValue("rows", num); | ||
177 | row.setValue("append", (qreal)num / appendTime); | ||
178 | row.setValue("total", (qreal)num / allProcessedTime); | ||
179 | dataset.insertRow(row); | ||
180 | HAWD::Formatter::print(dataset); | ||
181 | } | ||
182 | |||
183 | void testCreateCommand() | ||
184 | { | ||
185 | Sink::ApplicationDomain::Event event; | ||
186 | |||
187 | QBENCHMARK { | ||
188 | auto mFactory = new TestEventAdaptorFactory; | ||
189 | static flatbuffers::FlatBufferBuilder entityFbb; | ||
190 | entityFbb.Clear(); | ||
191 | mFactory->createBuffer(event, entityFbb); | ||
192 | |||
193 | static flatbuffers::FlatBufferBuilder fbb; | ||
194 | fbb.Clear(); | ||
195 | // This is the resource buffer type and not the domain type | ||
196 | auto type = fbb.CreateString("event"); | ||
197 | // auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize()); | ||
198 | auto delta = Sink::EntityBuffer::appendAsVector(fbb, entityFbb.GetBufferPointer(), entityFbb.GetSize()); | ||
199 | auto location = Sink::Commands::CreateCreateEntity(fbb, type, delta); | ||
200 | Sink::Commands::FinishCreateEntityBuffer(fbb, location); | ||
201 | } | ||
202 | } | ||
203 | |||
204 | private: | ||
205 | HAWD::State m_hawdState; | ||
206 | }; | ||
207 | |||
208 | QTEST_MAIN(GenericResourceBenchmark) | ||
209 | #include "genericresourcebenchmark.moc" | ||
diff --git a/tests/genericresourcetest.cpp b/tests/genericresourcetest.cpp deleted file mode 100644 index 77a901d..0000000 --- a/tests/genericresourcetest.cpp +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | #include <QtTest> | ||
2 | |||
3 | #include <QString> | ||
4 | |||
5 | #include "testimplementations.h" | ||
6 | |||
7 | #include "event_generated.h" | ||
8 | #include "entity_generated.h" | ||
9 | #include "metadata_generated.h" | ||
10 | #include "createentity_generated.h" | ||
11 | #include "commands.h" | ||
12 | #include "entitybuffer.h" | ||
13 | #include "pipeline.h" | ||
14 | #include "genericresource.h" | ||
15 | #include "definitions.h" | ||
16 | |||
17 | /** | ||
18 | * Test of the generic resource implementation. | ||
19 | * | ||
20 | * This test relies on a working pipeline implementation, and writes to storage. | ||
21 | */ | ||
22 | class GenericResourceTest : public QObject | ||
23 | { | ||
24 | Q_OBJECT | ||
25 | private slots: | ||
26 | |||
27 | void init() | ||
28 | { | ||
29 | Sink::GenericResource::removeFromDisk("sink.test.instance1"); | ||
30 | } | ||
31 | |||
32 | /// Ensure the resource can process messages | ||
33 | void testProcessCommand() | ||
34 | { | ||
35 | flatbuffers::FlatBufferBuilder eventFbb; | ||
36 | eventFbb.Clear(); | ||
37 | { | ||
38 | auto summary = eventFbb.CreateString("summary"); | ||
39 | Sink::ApplicationDomain::Buffer::EventBuilder eventBuilder(eventFbb); | ||
40 | eventBuilder.add_summary(summary); | ||
41 | auto eventLocation = eventBuilder.Finish(); | ||
42 | Sink::ApplicationDomain::Buffer::FinishEventBuffer(eventFbb, eventLocation); | ||
43 | } | ||
44 | |||
45 | flatbuffers::FlatBufferBuilder localFbb; | ||
46 | { | ||
47 | auto uid = localFbb.CreateString("testuid"); | ||
48 | auto localBuilder = Sink::ApplicationDomain::Buffer::EventBuilder(localFbb); | ||
49 | localBuilder.add_uid(uid); | ||
50 | auto location = localBuilder.Finish(); | ||
51 | Sink::ApplicationDomain::Buffer::FinishEventBuffer(localFbb, location); | ||
52 | } | ||
53 | |||
54 | flatbuffers::FlatBufferBuilder entityFbb; | ||
55 | Sink::EntityBuffer::assembleEntityBuffer(entityFbb, 0, 0, eventFbb.GetBufferPointer(), eventFbb.GetSize(), localFbb.GetBufferPointer(), localFbb.GetSize()); | ||
56 | |||
57 | flatbuffers::FlatBufferBuilder fbb; | ||
58 | auto type = fbb.CreateString(Sink::ApplicationDomain::getTypeName<Sink::ApplicationDomain::Event>().toStdString().data()); | ||
59 | auto delta = fbb.CreateVector<uint8_t>(entityFbb.GetBufferPointer(), entityFbb.GetSize()); | ||
60 | Sink::Commands::CreateEntityBuilder builder(fbb); | ||
61 | builder.add_domainType(type); | ||
62 | builder.add_delta(delta); | ||
63 | auto location = builder.Finish(); | ||
64 | Sink::Commands::FinishCreateEntityBuffer(fbb, location); | ||
65 | |||
66 | const QByteArray command(reinterpret_cast<const char *>(fbb.GetBufferPointer()), fbb.GetSize()); | ||
67 | { | ||
68 | flatbuffers::Verifier verifyer(reinterpret_cast<const uint8_t *>(command.data()), command.size()); | ||
69 | QVERIFY(Sink::Commands::VerifyCreateEntityBuffer(verifyer)); | ||
70 | } | ||
71 | |||
72 | // Actual test | ||
73 | auto pipeline = QSharedPointer<Sink::Pipeline>::create("sink.test.instance1"); | ||
74 | QSignalSpy revisionSpy(pipeline.data(), SIGNAL(revisionUpdated(qint64))); | ||
75 | QVERIFY(revisionSpy.isValid()); | ||
76 | TestResource resource("sink.test.instance1", pipeline); | ||
77 | resource.processCommand(Sink::Commands::CreateEntityCommand, command); | ||
78 | resource.processCommand(Sink::Commands::CreateEntityCommand, command); | ||
79 | resource.processAllMessages().exec().waitForFinished(); | ||
80 | QCOMPARE(revisionSpy.last().at(0).toInt(), 2); | ||
81 | } | ||
82 | }; | ||
83 | |||
84 | QTEST_MAIN(GenericResourceTest) | ||
85 | #include "genericresourcetest.moc" | ||
diff --git a/tests/hawd/CMakeLists.txt b/tests/hawd/CMakeLists.txt index b3de83e..6ae5f13 100644 --- a/tests/hawd/CMakeLists.txt +++ b/tests/hawd/CMakeLists.txt | |||
@@ -1,6 +1,7 @@ | |||
1 | project(hawd) | 1 | project(hawd) |
2 | 2 | ||
3 | find_package(Libgit2) | 3 | #We require git_buf_free function |
4 | find_package(Libgit2 0.20.0) | ||
4 | 5 | ||
5 | if (LIBGIT2_FOUND) | 6 | if (LIBGIT2_FOUND) |
6 | add_definitions(-DHAVE_LIBGIT2) | 7 | add_definitions(-DHAVE_LIBGIT2) |
diff --git a/tests/hawd/state.cpp b/tests/hawd/state.cpp index dbfe019..dfeef41 100644 --- a/tests/hawd/state.cpp +++ b/tests/hawd/state.cpp | |||
@@ -116,6 +116,7 @@ const char *State::commitHash() const | |||
116 | void State::findGitHash() | 116 | void State::findGitHash() |
117 | { | 117 | { |
118 | #ifdef HAVE_LIBGIT2 | 118 | #ifdef HAVE_LIBGIT2 |
119 | git_libgit2_init(); | ||
119 | git_buf root = {0}; | 120 | git_buf root = {0}; |
120 | int error = git_repository_discover(&root, projectPath().toStdString().data(), 0, NULL); | 121 | int error = git_repository_discover(&root, projectPath().toStdString().data(), 0, NULL); |
121 | if (!error) { | 122 | if (!error) { |
@@ -133,6 +134,7 @@ void State::findGitHash() | |||
133 | git_repository_free(repo); | 134 | git_repository_free(repo); |
134 | } | 135 | } |
135 | git_buf_free(&root); | 136 | git_buf_free(&root); |
137 | git_libgit2_shutdown(); | ||
136 | #endif | 138 | #endif |
137 | } | 139 | } |
138 | 140 | ||
diff --git a/tests/interresourcemovetest.cpp b/tests/interresourcemovetest.cpp index 7561c5b..3ac6ad4 100644 --- a/tests/interresourcemovetest.cpp +++ b/tests/interresourcemovetest.cpp | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "log.h" | 28 | #include "log.h" |
29 | #include "test.h" | 29 | #include "test.h" |
30 | #include "testutils.h" | 30 | #include "testutils.h" |
31 | #include <KMime/Message> | ||
31 | 32 | ||
32 | using namespace Sink; | 33 | using namespace Sink; |
33 | using namespace Sink::ApplicationDomain; | 34 | using namespace Sink::ApplicationDomain; |
@@ -41,6 +42,15 @@ class InterResourceMoveTest : public QObject | |||
41 | { | 42 | { |
42 | Q_OBJECT | 43 | Q_OBJECT |
43 | 44 | ||
45 | QByteArray message(const QByteArray &uid, const QString &subject) | ||
46 | { | ||
47 | KMime::Message m; | ||
48 | m.subject(true)->fromUnicodeString(subject, "utf8"); | ||
49 | m.messageID(true)->setIdentifier(uid); | ||
50 | m.assemble(); | ||
51 | return m.encodedContent(); | ||
52 | } | ||
53 | |||
44 | private slots: | 54 | private slots: |
45 | void initTestCase() | 55 | void initTestCase() |
46 | { | 56 | { |
@@ -65,24 +75,25 @@ private slots: | |||
65 | 75 | ||
66 | void testMove() | 76 | void testMove() |
67 | { | 77 | { |
68 | Event event("instance1"); | 78 | QByteArray testuid = "testuid@test.test"; |
69 | event.setProperty("uid", "testuid"); | 79 | QString subject = "summaryValue"; |
70 | QCOMPARE(event.getProperty("uid").toByteArray(), QByteArray("testuid")); | 80 | auto mimeMessage = message(testuid, subject); |
71 | event.setProperty("summary", "summaryValue"); | ||
72 | VERIFYEXEC(Sink::Store::create<Event>(event)); | ||
73 | 81 | ||
82 | Mail mail("instance1"); | ||
83 | mail.setMimeMessage(mimeMessage); | ||
84 | VERIFYEXEC(Sink::Store::create<Mail>(mail)); | ||
74 | 85 | ||
75 | Event createdEvent; | 86 | Mail createdmail; |
76 | // Ensure all local data is processed | 87 | // Ensure all local data is processed |
77 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "instance1")); | 88 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "instance1")); |
78 | { | 89 | { |
79 | auto query = Query().resourceFilter("instance1") ; | 90 | auto query = Query().resourceFilter("instance1") ; |
80 | auto list = Sink::Store::read<Event>(query.filter<Event::Uid>("testuid")); | 91 | auto list = Sink::Store::read<Mail>(query.filter<Mail::MessageId>(testuid)); |
81 | QCOMPARE(list.size(), 1); | 92 | QCOMPARE(list.size(), 1); |
82 | createdEvent = list.first(); | 93 | createdmail = list.first(); |
83 | } | 94 | } |
84 | 95 | ||
85 | VERIFYEXEC(Sink::Store::move<Event>(createdEvent, "instance2")); | 96 | VERIFYEXEC(Sink::Store::move<Mail>(createdmail, "instance2")); |
86 | 97 | ||
87 | //FIXME we can't guarantee that that the create command arrives at instance2 before the flush command, so we'll just wait for a little bit. | 98 | //FIXME we can't guarantee that that the create command arrives at instance2 before the flush command, so we'll just wait for a little bit. |
88 | QTest::qWait(1000); | 99 | QTest::qWait(1000); |
@@ -92,14 +103,18 @@ private slots: | |||
92 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "instance2")); | 103 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "instance2")); |
93 | { | 104 | { |
94 | auto query = Query().resourceFilter("instance2") ; | 105 | auto query = Query().resourceFilter("instance2") ; |
95 | auto list = Sink::Store::read<Event>(query.filter<Event::Uid>("testuid")); | 106 | auto list = Sink::Store::read<Mail>(query.filter<Mail::MessageId>(testuid)); |
96 | QCOMPARE(list.size(), 1); | 107 | QCOMPARE(list.size(), 1); |
108 | const auto mail = list.first(); | ||
109 | QVERIFY(!mail.getMimeMessagePath().isEmpty()); | ||
110 | QCOMPARE(mail.getSubject(), subject); | ||
111 | QCOMPARE(mail.getMimeMessage(), mimeMessage); | ||
97 | } | 112 | } |
98 | 113 | ||
99 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "instance1")); | 114 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "instance1")); |
100 | { | 115 | { |
101 | auto query = Query().resourceFilter("instance1") ; | 116 | auto query = Query().resourceFilter("instance1") ; |
102 | auto list = Sink::Store::read<Event>(query.filter<Event::Uid>("testuid")); | 117 | auto list = Sink::Store::read<Mail>(query.filter<Mail::MessageId>(testuid)); |
103 | QCOMPARE(list.size(), 0); | 118 | QCOMPARE(list.size(), 0); |
104 | } | 119 | } |
105 | } | 120 | } |
diff --git a/tests/mailquerybenchmark.cpp b/tests/mailquerybenchmark.cpp index d68151a..b15c8d6 100644 --- a/tests/mailquerybenchmark.cpp +++ b/tests/mailquerybenchmark.cpp | |||
@@ -23,16 +23,10 @@ | |||
23 | 23 | ||
24 | #include "testimplementations.h" | 24 | #include "testimplementations.h" |
25 | 25 | ||
26 | #include <common/facade.h> | ||
27 | #include <common/domainadaptor.h> | ||
28 | #include <common/resultprovider.h> | 26 | #include <common/resultprovider.h> |
29 | #include <common/synclistresult.h> | ||
30 | #include <common/definitions.h> | 27 | #include <common/definitions.h> |
31 | #include <common/query.h> | 28 | #include <common/query.h> |
32 | #include <common/store.h> | 29 | #include <common/storage/entitystore.h> |
33 | #include <common/pipeline.h> | ||
34 | #include <common/index.h> | ||
35 | #include <common/adaptorfactoryregistry.h> | ||
36 | 30 | ||
37 | #include "hawd/dataset.h" | 31 | #include "hawd/dataset.h" |
38 | #include "hawd/formatter.h" | 32 | #include "hawd/formatter.h" |
@@ -57,30 +51,34 @@ class MailQueryBenchmark : public QObject | |||
57 | QByteArray resourceIdentifier; | 51 | QByteArray resourceIdentifier; |
58 | HAWD::State mHawdState; | 52 | HAWD::State mHawdState; |
59 | 53 | ||
60 | void populateDatabase(int count) | 54 | void populateDatabase(int count, int folderSpreadFactor = 0) |
61 | { | 55 | { |
62 | TestResource::removeFromDisk(resourceIdentifier); | 56 | TestResource::removeFromDisk(resourceIdentifier); |
63 | 57 | ||
64 | auto pipeline = QSharedPointer<Sink::Pipeline>::create(Sink::ResourceContext{resourceIdentifier, "test"}, "test"); | 58 | Sink::ResourceContext resourceContext{resourceIdentifier, "test", {{"mail", QSharedPointer<TestMailAdaptorFactory>::create()}}}; |
59 | Sink::Storage::EntityStore entityStore{resourceContext, {}}; | ||
60 | entityStore.startTransaction(Sink::Storage::DataStore::ReadWrite); | ||
65 | 61 | ||
66 | auto domainTypeAdaptorFactory = QSharedPointer<TestMailAdaptorFactory>::create(); | ||
67 | |||
68 | pipeline->startTransaction(); | ||
69 | const auto date = QDateTime::currentDateTimeUtc(); | 62 | const auto date = QDateTime::currentDateTimeUtc(); |
70 | for (int i = 0; i < count; i++) { | 63 | for (int i = 0; i < count; i++) { |
71 | auto domainObject = Mail::Ptr::create(); | 64 | auto domainObject = Mail::createEntity<Mail>(resourceIdentifier); |
72 | domainObject->setExtractedMessageId("uid"); | 65 | domainObject.setExtractedMessageId("uid"); |
73 | domainObject->setExtractedSubject(QString("subject%1").arg(i)); | 66 | domainObject.setExtractedParentMessageId("parentuid"); |
74 | domainObject->setExtractedDate(date.addSecs(count)); | 67 | domainObject.setExtractedSubject(QString("subject%1").arg(i)); |
75 | domainObject->setFolder("folder1"); | 68 | domainObject.setExtractedDate(date.addSecs(count)); |
76 | // domainObject->setAttachment(attachment); | 69 | if (folderSpreadFactor == 0) { |
77 | const auto command = createCommand<Mail>(*domainObject, *domainTypeAdaptorFactory); | 70 | domainObject.setFolder("folder1"); |
78 | pipeline->newEntity(command.data(), command.size()); | 71 | } else { |
72 | domainObject.setFolder(QByteArray("folder") + QByteArray::number(i - (i % folderSpreadFactor))); | ||
73 | } | ||
74 | |||
75 | entityStore.add("mail", domainObject, false); | ||
79 | } | 76 | } |
80 | pipeline->commit(); | 77 | |
78 | entityStore.commitTransaction(); | ||
81 | } | 79 | } |
82 | 80 | ||
83 | void testLoad(const Sink::Query &query, int count) | 81 | void testLoad(const Sink::Query &query, int count, int expectedSize) |
84 | { | 82 | { |
85 | const auto startingRss = getCurrentRSS(); | 83 | const auto startingRss = getCurrentRSS(); |
86 | 84 | ||
@@ -88,7 +86,10 @@ class MailQueryBenchmark : public QObject | |||
88 | QTime time; | 86 | QTime time; |
89 | time.start(); | 87 | time.start(); |
90 | auto resultSet = QSharedPointer<Sink::ResultProvider<Mail::Ptr>>::create(); | 88 | auto resultSet = QSharedPointer<Sink::ResultProvider<Mail::Ptr>>::create(); |
91 | Sink::ResourceContext context{resourceIdentifier, "test"}; | 89 | |
90 | //FIXME why do we need this here? | ||
91 | auto domainTypeAdaptorFactory = QSharedPointer<TestMailAdaptorFactory>::create(); | ||
92 | Sink::ResourceContext context{resourceIdentifier, "test", {{"mail", domainTypeAdaptorFactory}}}; | ||
92 | context.mResourceAccess = QSharedPointer<TestResourceAccess>::create(); | 93 | context.mResourceAccess = QSharedPointer<TestResourceAccess>::create(); |
93 | TestMailResourceFacade facade(context); | 94 | TestMailResourceFacade facade(context); |
94 | 95 | ||
@@ -101,7 +102,7 @@ class MailQueryBenchmark : public QObject | |||
101 | emitter->onInitialResultSetComplete([&done](const Mail::Ptr &mail, bool) { done = true; }); | 102 | emitter->onInitialResultSetComplete([&done](const Mail::Ptr &mail, bool) { done = true; }); |
102 | emitter->fetch(Mail::Ptr()); | 103 | emitter->fetch(Mail::Ptr()); |
103 | QTRY_VERIFY(done); | 104 | QTRY_VERIFY(done); |
104 | QCOMPARE(list.size(), query.limit()); | 105 | QCOMPARE(list.size(), expectedSize); |
105 | 106 | ||
106 | const auto elapsed = time.elapsed(); | 107 | const auto elapsed = time.elapsed(); |
107 | 108 | ||
@@ -145,7 +146,6 @@ private slots: | |||
145 | void init() | 146 | void init() |
146 | { | 147 | { |
147 | resourceIdentifier = "sink.test.instance1"; | 148 | resourceIdentifier = "sink.test.instance1"; |
148 | Sink::AdaptorFactoryRegistry::instance().registerFactory<Mail, TestMailAdaptorFactory>("test"); | ||
149 | } | 149 | } |
150 | 150 | ||
151 | void test50k() | 151 | void test50k() |
@@ -159,7 +159,24 @@ private slots: | |||
159 | query.limit(1000); | 159 | query.limit(1000); |
160 | 160 | ||
161 | populateDatabase(50000); | 161 | populateDatabase(50000); |
162 | testLoad(query, 50000); | 162 | testLoad(query, 50000, query.limit()); |
163 | } | ||
164 | |||
165 | void test50kThreadleader() | ||
166 | { | ||
167 | Sink::Query query; | ||
168 | query.request<Mail::MessageId>() | ||
169 | .request<Mail::Subject>() | ||
170 | .request<Mail::Date>(); | ||
171 | // query.filter<ApplicationDomain::Mail::Trash>(false); | ||
172 | query.reduce<ApplicationDomain::Mail::Folder>(Query::Reduce::Selector::max<ApplicationDomain::Mail::Date>()); | ||
173 | query.limit(1000); | ||
174 | |||
175 | int mailsPerFolder = 10; | ||
176 | |||
177 | int count = 50000; | ||
178 | populateDatabase(count, mailsPerFolder); | ||
179 | testLoad(query, count, query.limit()); | ||
163 | } | 180 | } |
164 | }; | 181 | }; |
165 | 182 | ||
diff --git a/tests/mailsynctest.cpp b/tests/mailsynctest.cpp index 3e5a928..c8ba9f1 100644 --- a/tests/mailsynctest.cpp +++ b/tests/mailsynctest.cpp | |||
@@ -411,6 +411,43 @@ void MailSyncTest::testSyncSingleFolder() | |||
411 | 411 | ||
412 | } | 412 | } |
413 | 413 | ||
414 | void MailSyncTest::testSyncSingleMail() | ||
415 | { | ||
416 | VERIFYEXEC(Store::synchronize(Sink::SyncScope{}.resourceFilter(mResourceInstanceIdentifier))); | ||
417 | VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); | ||
418 | |||
419 | Mail::Ptr mail; | ||
420 | { | ||
421 | auto job = Store::fetchAll<Mail>(Sink::Query{}.resourceFilter(mResourceInstanceIdentifier)).template then([&](const QList<Mail::Ptr> &mails) { | ||
422 | QVERIFY(mails.size() >= 1); | ||
423 | mail = mails.first(); | ||
424 | }); | ||
425 | VERIFYEXEC(job); | ||
426 | } | ||
427 | |||
428 | auto syncScope = Sink::SyncScope{ApplicationDomain::getTypeName<Mail>()}; | ||
429 | syncScope.resourceFilter(mResourceInstanceIdentifier); | ||
430 | syncScope.filter(mail->identifier()); | ||
431 | |||
432 | // Ensure all local data is processed | ||
433 | VERIFYEXEC(Store::synchronize(syncScope)); | ||
434 | VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); | ||
435 | } | ||
436 | |||
437 | void MailSyncTest::testSyncSingleMailWithBogusId() | ||
438 | { | ||
439 | VERIFYEXEC(Store::synchronize(Sink::SyncScope{}.resourceFilter(mResourceInstanceIdentifier))); | ||
440 | VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); | ||
441 | |||
442 | auto syncScope = Sink::SyncScope{ApplicationDomain::getTypeName<Mail>()}; | ||
443 | syncScope.resourceFilter(mResourceInstanceIdentifier); | ||
444 | syncScope.filter("WTFisThisEven?"); | ||
445 | |||
446 | // Ensure all local data is processed | ||
447 | VERIFYEXEC(Store::synchronize(syncScope)); | ||
448 | VERIFYEXEC(ResourceControl::flushMessageQueue(mResourceInstanceIdentifier)); | ||
449 | } | ||
450 | |||
414 | void MailSyncTest::testFailingSync() | 451 | void MailSyncTest::testFailingSync() |
415 | { | 452 | { |
416 | auto resource = createFaultyResource(); | 453 | auto resource = createFaultyResource(); |
diff --git a/tests/mailsynctest.h b/tests/mailsynctest.h index 8ad3bb3..0decf00 100644 --- a/tests/mailsynctest.h +++ b/tests/mailsynctest.h | |||
@@ -70,6 +70,8 @@ private slots: | |||
70 | void testFlagChange(); | 70 | void testFlagChange(); |
71 | 71 | ||
72 | void testSyncSingleFolder(); | 72 | void testSyncSingleFolder(); |
73 | void testSyncSingleMail(); | ||
74 | void testSyncSingleMailWithBogusId(); | ||
73 | 75 | ||
74 | void testFailingSync(); | 76 | void testFailingSync(); |
75 | }; | 77 | }; |
diff --git a/tests/modelinteractivitytest.cpp b/tests/modelinteractivitytest.cpp index 5231c1a..caa9ca2 100644 --- a/tests/modelinteractivitytest.cpp +++ b/tests/modelinteractivitytest.cpp | |||
@@ -70,9 +70,9 @@ private slots: | |||
70 | { | 70 | { |
71 | // Setup | 71 | // Setup |
72 | { | 72 | { |
73 | Sink::ApplicationDomain::Mail mail("sink.dummy.instance1"); | 73 | Sink::ApplicationDomain::Event event("sink.dummy.instance1"); |
74 | for (int i = 0; i < 1000; i++) { | 74 | for (int i = 0; i < 1000; i++) { |
75 | Sink::Store::create<Sink::ApplicationDomain::Mail>(mail).exec().waitForFinished(); | 75 | Sink::Store::create<Sink::ApplicationDomain::Event>(event).exec().waitForFinished(); |
76 | } | 76 | } |
77 | } | 77 | } |
78 | 78 | ||
@@ -85,7 +85,7 @@ private slots: | |||
85 | // Test | 85 | // Test |
86 | QTime time; | 86 | QTime time; |
87 | time.start(); | 87 | time.start(); |
88 | auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); | 88 | auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Event>(query); |
89 | blockingTime += time.elapsed(); | 89 | blockingTime += time.elapsed(); |
90 | QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); | 90 | QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); |
91 | // Never block longer than 10 ms | 91 | // Never block longer than 10 ms |
diff --git a/tests/notificationtest.cpp b/tests/notificationtest.cpp new file mode 100644 index 0000000..a34d325 --- /dev/null +++ b/tests/notificationtest.cpp | |||
@@ -0,0 +1,132 @@ | |||
1 | #include <QtTest> | ||
2 | |||
3 | #include <QString> | ||
4 | #include <QSignalSpy> | ||
5 | |||
6 | #include "store.h" | ||
7 | #include "resourceconfig.h" | ||
8 | #include "resourcecontrol.h" | ||
9 | #include "modelresult.h" | ||
10 | #include "log.h" | ||
11 | #include "test.h" | ||
12 | #include "testutils.h" | ||
13 | #include "notifier.h" | ||
14 | #include "notification.h" | ||
15 | |||
16 | using namespace Sink; | ||
17 | using namespace Sink::ApplicationDomain; | ||
18 | |||
19 | /** | ||
20 | * Test of complete system using the dummy resource. | ||
21 | * | ||
22 | * This test requires the dummy resource installed. | ||
23 | */ | ||
24 | class NotificationTest : public QObject | ||
25 | { | ||
26 | Q_OBJECT | ||
27 | |||
28 | private slots: | ||
29 | void initTestCase() | ||
30 | { | ||
31 | Sink::Test::initTest(); | ||
32 | ResourceConfig::addResource("sink.dummy.instance1", "sink.dummy"); | ||
33 | } | ||
34 | |||
35 | void cleanup() | ||
36 | { | ||
37 | VERIFYEXEC(Sink::Store::removeDataFromDisk("sink.dummy.instance1")); | ||
38 | } | ||
39 | |||
40 | void testSyncNotifications() | ||
41 | { | ||
42 | auto query = Query().resourceFilter("sink.dummy.instance1"); | ||
43 | query.setType<ApplicationDomain::Mail>(); | ||
44 | query.filter("id1"); | ||
45 | query.filter("id2"); | ||
46 | |||
47 | QList<Sink::Notification> statusNotifications; | ||
48 | QList<Sink::Notification> infoNotifications; | ||
49 | Sink::Notifier notifier("sink.dummy.instance1"); | ||
50 | notifier.registerHandler([&] (const Sink::Notification &n){ | ||
51 | SinkLogCtx(Sink::Log::Context{"dummyresourcetest"}) << "Received notification " << n; | ||
52 | if (n.type == Notification::Status) { | ||
53 | if (n.id == "changereplay") { | ||
54 | //We filter all changereplay notifications. | ||
55 | //Not the best way but otherwise the test becomes unstable and we currently | ||
56 | //only have the id to detect changereplay notifications. | ||
57 | return; | ||
58 | } | ||
59 | statusNotifications << n; | ||
60 | } | ||
61 | if (n.type == Notification::Info) { | ||
62 | infoNotifications << n; | ||
63 | } | ||
64 | }); | ||
65 | |||
66 | // Ensure all local data is processed | ||
67 | VERIFYEXEC(Sink::Store::synchronize(query)); | ||
68 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1")); | ||
69 | |||
70 | QVERIFY(statusNotifications.size() <= 3); | ||
71 | QTRY_COMPARE(statusNotifications.size(), 3); | ||
72 | //Sync | ||
73 | QCOMPARE(statusNotifications.at(0).code, static_cast<int>(ApplicationDomain::Status::ConnectedStatus)); | ||
74 | QCOMPARE(statusNotifications.at(1).code, static_cast<int>(ApplicationDomain::Status::BusyStatus)); | ||
75 | QCOMPARE(statusNotifications.at(2).code, static_cast<int>(ApplicationDomain::Status::ConnectedStatus)); | ||
76 | //Changereplay | ||
77 | // It can happen that we get a changereplay notification pair first and then a second one at the end, | ||
78 | // we therefore currently filter all changereplay notifications (see above). | ||
79 | // QCOMPARE(statusNotifications.at(3).code, static_cast<int>(Sink::ApplicationDomain::Status::BusyStatus)); | ||
80 | // QCOMPARE(statusNotifications.at(4).code, static_cast<int>(Sink::ApplicationDomain::Status::ConnectedStatus)); | ||
81 | |||
82 | QTRY_COMPARE(infoNotifications.size(), 2); | ||
83 | QCOMPARE(infoNotifications.at(0).code, static_cast<int>(ApplicationDomain::SyncStatus::SyncInProgress)); | ||
84 | QCOMPARE(infoNotifications.at(0).entities, QList<QByteArray>{} << "id1" << "id2"); | ||
85 | QCOMPARE(infoNotifications.at(1).code, static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess)); | ||
86 | QCOMPARE(infoNotifications.at(1).entities, QList<QByteArray>{} << "id1" << "id2"); | ||
87 | |||
88 | QCOMPARE(infoNotifications.at(1).code, static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess)); | ||
89 | } | ||
90 | |||
91 | void testModelNotifications() | ||
92 | { | ||
93 | auto query = Query().resourceFilter("sink.dummy.instance1"); | ||
94 | query.setType<ApplicationDomain::Mail>(); | ||
95 | query.setFlags(Query::LiveQuery | Query::UpdateStatus); | ||
96 | |||
97 | VERIFYEXEC(Sink::Store::synchronize(query)); | ||
98 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1")); | ||
99 | |||
100 | auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Mail>(query); | ||
101 | QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); | ||
102 | QVERIFY(model->rowCount() >= 1); | ||
103 | |||
104 | QSignalSpy changedSpy(model.data(), &QAbstractItemModel::dataChanged); | ||
105 | auto mail = model->index(0, 0, QModelIndex()).data(Sink::Store::DomainObjectRole).value<Mail::Ptr>(); | ||
106 | auto newQuery = query; | ||
107 | newQuery.filter(mail->identifier()); | ||
108 | |||
109 | QList<int> status; | ||
110 | QObject::connect(model.data(), &QAbstractItemModel::dataChanged, [&] (const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles) { | ||
111 | QVERIFY(begin.row() == end.row()); | ||
112 | if (begin.row() == 0) { | ||
113 | status << model->data(begin, Store::StatusRole).value<int>(); | ||
114 | // qWarning() << "New status: " << status.last() << roles; | ||
115 | } | ||
116 | }); | ||
117 | |||
118 | //This will trigger a modification of all previous items as well. | ||
119 | VERIFYEXEC(Sink::Store::synchronize(newQuery)); | ||
120 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue(QByteArrayList() << "sink.dummy.instance1")); | ||
121 | |||
122 | QCOMPARE(status.size(), 3); | ||
123 | //Sync progress of item | ||
124 | QCOMPARE(status.at(0), static_cast<int>(ApplicationDomain::SyncStatus::SyncInProgress)); | ||
125 | QCOMPARE(status.at(1), static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess)); | ||
126 | //Modification triggered during sync | ||
127 | QCOMPARE(status.at(2), static_cast<int>(ApplicationDomain::SyncStatus::SyncSuccess)); | ||
128 | } | ||
129 | }; | ||
130 | |||
131 | QTEST_MAIN(NotificationTest) | ||
132 | #include "notificationtest.moc" | ||
diff --git a/tests/querytest.cpp b/tests/querytest.cpp index bd3b927..f639d94 100644 --- a/tests/querytest.cpp +++ b/tests/querytest.cpp | |||
@@ -1042,6 +1042,71 @@ private slots: | |||
1042 | QCOMPARE(layoutChangedSpy.size(), 0); | 1042 | QCOMPARE(layoutChangedSpy.size(), 0); |
1043 | QCOMPARE(resetSpy.size(), 0); | 1043 | QCOMPARE(resetSpy.size(), 0); |
1044 | } | 1044 | } |
1045 | |||
1046 | /* | ||
1047 | * Ensure that we handle the situation properly if the thread-leader doesn't match a property filter. | ||
1048 | */ | ||
1049 | void testFilteredThreadLeader() | ||
1050 | { | ||
1051 | // Setup | ||
1052 | auto folder1 = Folder::createEntity<Folder>("sink.dummy.instance1"); | ||
1053 | VERIFYEXEC(Sink::Store::create<Folder>(folder1)); | ||
1054 | |||
1055 | auto folder2 = Folder::createEntity<Folder>("sink.dummy.instance1"); | ||
1056 | VERIFYEXEC(Sink::Store::create<Folder>(folder2)); | ||
1057 | |||
1058 | QDateTime earlier{QDate{2017, 2, 3}, QTime{9, 0, 0}}; | ||
1059 | QDateTime now{QDate{2017, 2, 3}, QTime{10, 0, 0}}; | ||
1060 | QDateTime later{QDate{2017, 2, 3}, QTime{11, 0, 0}}; | ||
1061 | |||
1062 | { | ||
1063 | auto mail1 = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
1064 | mail1.setExtractedMessageId("mail1"); | ||
1065 | mail1.setFolder(folder1); | ||
1066 | mail1.setExtractedDate(now); | ||
1067 | mail1.setImportant(false); | ||
1068 | VERIFYEXEC(Sink::Store::create(mail1)); | ||
1069 | } | ||
1070 | { | ||
1071 | auto mail2 = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
1072 | mail2.setExtractedMessageId("mail2"); | ||
1073 | mail2.setFolder(folder1); | ||
1074 | mail2.setExtractedDate(earlier); | ||
1075 | mail2.setImportant(false); | ||
1076 | VERIFYEXEC(Sink::Store::create(mail2)); | ||
1077 | } | ||
1078 | { | ||
1079 | auto mail3 = Mail::createEntity<Mail>("sink.dummy.instance1"); | ||
1080 | mail3.setExtractedMessageId("mail3"); | ||
1081 | mail3.setFolder(folder1); | ||
1082 | mail3.setExtractedDate(later); | ||
1083 | mail3.setImportant(true); | ||
1084 | VERIFYEXEC(Sink::Store::create(mail3)); | ||
1085 | } | ||
1086 | |||
1087 | // Ensure all local data is processed | ||
1088 | VERIFYEXEC(Sink::ResourceControl::flushMessageQueue("sink.dummy.instance1")); | ||
1089 | |||
1090 | Query query; | ||
1091 | query.setId("testLivequeryThreadleaderChange"); | ||
1092 | query.setFlags(Query::LiveQuery); | ||
1093 | query.reduce<Mail::Folder>(Query::Reduce::Selector::max<Mail::Date>()).count("count").collect<Mail::Folder>("folders"); | ||
1094 | query.sort<Mail::Date>(); | ||
1095 | query.request<Mail::MessageId>(); | ||
1096 | query.filter<Mail::Important>(false); | ||
1097 | |||
1098 | auto model = Sink::Store::loadModel<Mail>(query); | ||
1099 | QTRY_VERIFY(model->data(QModelIndex(), Sink::Store::ChildrenFetchedRole).toBool()); | ||
1100 | |||
1101 | QCOMPARE(model->rowCount(), 1); | ||
1102 | |||
1103 | { | ||
1104 | auto mail = model->data(model->index(0, 0, QModelIndex{}), Sink::Store::DomainObjectRole).value<Mail::Ptr>(); | ||
1105 | QCOMPARE(mail->getMessageId(), QByteArray{"mail1"}); | ||
1106 | QCOMPARE(mail->getProperty("count").toInt(), 2); | ||
1107 | QCOMPARE(mail->getProperty("folders").toList().size(), 2); | ||
1108 | } | ||
1109 | } | ||
1045 | }; | 1110 | }; |
1046 | 1111 | ||
1047 | QTEST_MAIN(QueryTest) | 1112 | QTEST_MAIN(QueryTest) |