summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt7
-rw-r--r--tests/clientapitest.cpp20
-rw-r--r--tests/dummyresourcetest.cpp9
-rw-r--r--tests/entitystoretest.cpp89
-rw-r--r--tests/genericfacadetest.cpp154
-rw-r--r--tests/genericresourcebenchmark.cpp209
-rw-r--r--tests/genericresourcetest.cpp85
-rw-r--r--tests/hawd/CMakeLists.txt3
-rw-r--r--tests/hawd/state.cpp2
-rw-r--r--tests/interresourcemovetest.cpp37
-rw-r--r--tests/mailquerybenchmark.cpp69
-rw-r--r--tests/mailsynctest.cpp37
-rw-r--r--tests/mailsynctest.h2
-rw-r--r--tests/modelinteractivitytest.cpp6
-rw-r--r--tests/notificationtest.cpp132
-rw-r--r--tests/querytest.cpp65
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)
21manual_tests ( 21manual_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
30auto_tests ( 28auto_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)
52generate_flatbuffers(dummyresourcetest calendar) 50generate_flatbuffers(dummyresourcetest calendar)
53target_link_libraries(dummyresourcetest sink_resource_dummy) 51target_link_libraries(dummyresourcetest sink_resource_dummy)
@@ -56,3 +54,4 @@ target_link_libraries(dummyresourcewritebenchmark sink_resource_dummy)
56target_link_libraries(querytest sink_resource_dummy) 54target_link_libraries(querytest sink_resource_dummy)
57target_link_libraries(modelinteractivitytest sink_resource_dummy) 55target_link_libraries(modelinteractivitytest sink_resource_dummy)
58target_link_libraries(inspectiontest sink_resource_dummy) 56target_link_libraries(inspectiontest sink_resource_dummy)
57target_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
14template <typename T> 14template <typename T>
15struct Result {
16 QSharedPointer<T> parent;
17 bool fetchedAll;
18};
19
20template <typename T>
15class TestDummyResourceFacade : public Sink::StoreFacade<T> 21class TestDummyResourceFacade : public Sink::StoreFacade<T>
16{ 22{
17public: 23public:
@@ -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
11class EntityStoreTest : public QObject
12{
13 Q_OBJECT
14private:
15 QString resourceInstanceIdentifier{"resourceId"};
16
17private 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
88QTEST_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 */
23class GenericFacadeTest : public QObject
24{
25 Q_OBJECT
26private 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
153QTEST_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
21static void removeFromDisk(const QString &name)
22{
23 Sink::Storage store(Sink::storageLocation(), name, Sink::Storage::ReadWrite);
24 store.removeFromDisk();
25}
26
27static 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
63class IndexUpdater : public Sink::Preprocessor
64{
65public:
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 */
87class GenericResourceBenchmark : public QObject
88{
89 Q_OBJECT
90private 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
204private:
205 HAWD::State m_hawdState;
206};
207
208QTEST_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 */
22class GenericResourceTest : public QObject
23{
24 Q_OBJECT
25private 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
84QTEST_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 @@
1project(hawd) 1project(hawd)
2 2
3find_package(Libgit2) 3#We require git_buf_free function
4find_package(Libgit2 0.20.0)
4 5
5if (LIBGIT2_FOUND) 6if (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
116void State::findGitHash() 116void 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
32using namespace Sink; 33using namespace Sink;
33using namespace Sink::ApplicationDomain; 34using 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
44private slots: 54private 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
414void 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
437void 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
414void MailSyncTest::testFailingSync() 451void 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
16using namespace Sink;
17using namespace Sink::ApplicationDomain;
18
19/**
20 * Test of complete system using the dummy resource.
21 *
22 * This test requires the dummy resource installed.
23 */
24class NotificationTest : public QObject
25{
26 Q_OBJECT
27
28private 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
131QTEST_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
1047QTEST_MAIN(QueryTest) 1112QTEST_MAIN(QueryTest)