summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2017-01-31 17:32:45 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2017-01-31 19:38:57 +0100
commit546d86aae7cd0b9766f3a0ea73f3777334d55814 (patch)
tree58667b891038926e732e1b6fd9b50a8433bf465b
parent871a048580d5a464fb697713a5e0e2c52dee5208 (diff)
downloadsink-546d86aae7cd0b9766f3a0ea73f3777334d55814.tar.gz
sink-546d86aae7cd0b9766f3a0ea73f3777334d55814.zip
A model stress test to try to crash the result emitter when used with
threads.
-rw-r--r--common/asyncutils.h26
-rw-r--r--tests/clientapitest.cpp59
2 files changed, 58 insertions, 27 deletions
diff --git a/common/asyncutils.h b/common/asyncutils.h
index 2cf010e..6cbcee8 100644
--- a/common/asyncutils.h
+++ b/common/asyncutils.h
@@ -25,17 +25,23 @@
25 25
26namespace async { 26namespace async {
27template <typename T> 27template <typename T>
28KAsync::Job<T> run(const std::function<T()> &f) 28KAsync::Job<T> run(const std::function<T()> &f, bool runAsync = true)
29{ 29{
30 return KAsync::start<T>([f](KAsync::Future<T> &future) { 30 if (runAsync) {
31 auto result = QtConcurrent::run(f); 31 return KAsync::start<T>([f](KAsync::Future<T> &future) {
32 auto watcher = new QFutureWatcher<T>; 32 auto result = QtConcurrent::run(f);
33 watcher->setFuture(result); 33 auto watcher = new QFutureWatcher<T>;
34 QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, [&future, watcher]() { 34 watcher->setFuture(result);
35 future.setValue(watcher->future().result()); 35 QObject::connect(watcher, &QFutureWatcher<T>::finished, watcher, [&future, watcher]() {
36 delete watcher; 36 future.setValue(watcher->future().result());
37 future.setFinished(); 37 delete watcher;
38 future.setFinished();
39 });
38 }); 40 });
39 }); 41 } else {
42 return KAsync::syncStart<T>([f]() {
43 return f();
44 });
45 }
40} 46}
41} 47}
diff --git a/tests/clientapitest.cpp b/tests/clientapitest.cpp
index 159789f..55fdcfc 100644
--- a/tests/clientapitest.cpp
+++ b/tests/clientapitest.cpp
@@ -9,6 +9,7 @@
9#include "resultprovider.h" 9#include "resultprovider.h"
10#include "facadefactory.h" 10#include "facadefactory.h"
11#include "test.h" 11#include "test.h"
12#include "asyncutils.h"
12 13
13template <typename T> 14template <typename T>
14class TestDummyResourceFacade : public Sink::StoreFacade<T> 15class TestDummyResourceFacade : public Sink::StoreFacade<T>
@@ -53,38 +54,41 @@ public:
53 }; 54 };
54 QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename T::Ptr>::Ptr> load(const Sink::Query &query, const Sink::Log::Context &ctx) Q_DECL_OVERRIDE 55 QPair<KAsync::Job<void>, typename Sink::ResultEmitter<typename T::Ptr>::Ptr> load(const Sink::Query &query, const Sink::Log::Context &ctx) Q_DECL_OVERRIDE
55 { 56 {
56 auto resultProvider = new Sink::ResultProvider<typename T::Ptr>(); 57 auto resultProvider = QSharedPointer<Sink::ResultProvider<typename T::Ptr>>::create();
57 resultProvider->onDone([resultProvider,ctx]() { 58 resultProvider->onDone([resultProvider,ctx]() {
58 SinkTraceCtx(ctx) << "Result provider is done"; 59 SinkTraceCtx(ctx) << "Result provider is done";
59 delete resultProvider;
60 }); 60 });
61 // We have to do it this way, otherwise we're not setting the fetcher right 61 // We have to do it this way, otherwise we're not setting the fetcher right
62 auto emitter = resultProvider->emitter(); 62 auto emitter = resultProvider->emitter();
63 63
64 resultProvider->setFetcher([query, resultProvider, this, ctx](const typename T::Ptr &parent) { 64 resultProvider->setFetcher([query, resultProvider, this, ctx](const typename T::Ptr &parent) {
65 if (parent) { 65 async::run<int>([=] {
66 SinkTraceCtx(ctx) << "Running the fetcher " << parent->identifier(); 66 if (parent) {
67 } else { 67 SinkTraceCtx(ctx) << "Running the fetcher " << parent->identifier();
68 SinkTraceCtx(ctx) << "Running the fetcher."; 68 } else {
69 } 69 SinkTraceCtx(ctx) << "Running the fetcher.";
70 SinkTraceCtx(ctx) << "-------------------------.";
71 for (const auto &res : results) {
72 SinkTraceCtx(ctx) << "Parent filter " << query.getFilter("parent").value.toByteArray() << res->identifier() << res->getProperty("parent").toByteArray();
73 auto parentProperty = res->getProperty("parent").toByteArray();
74 if ((!parent && parentProperty.isEmpty()) || (parent && parentProperty == parent->identifier()) || query.parentProperty().isEmpty()) {
75 SinkTraceCtx(ctx) << "Found a hit" << res->identifier();
76 resultProvider->add(res);
77 } 70 }
78 } 71 SinkTraceCtx(ctx) << "-------------------------.";
79 resultProvider->initialResultSetComplete(parent, true); 72 for (const auto &res : results) {
73 // SinkTraceCtx(ctx) << "Parent filter " << query.getFilter("parent").value.toByteArray() << res->identifier() << res->getProperty("parent").toByteArray();
74 auto parentProperty = res->getProperty("parent").toByteArray();
75 if ((!parent && parentProperty.isEmpty()) || (parent && parentProperty == parent->identifier()) || query.parentProperty().isEmpty()) {
76 // SinkTraceCtx(ctx) << "Found a hit" << res->identifier();
77 resultProvider->add(res);
78 }
79 }
80 resultProvider->initialResultSetComplete(parent, true);
81 return 0;
82 }, runAsync).exec();
80 }); 83 });
81 auto job = KAsync::syncStart<void>([query, resultProvider]() {}); 84 auto job = KAsync::syncStart<void>([query, resultProvider]() {});
82 mResultProvider = resultProvider; 85 mResultProvider = resultProvider.data();
83 return qMakePair(job, emitter); 86 return qMakePair(job, emitter);
84 } 87 }
85 88
86 QList<typename T::Ptr> results; 89 QList<typename T::Ptr> results;
87 Sink::ResultProviderInterface<typename T::Ptr> *mResultProvider; 90 Sink::ResultProviderInterface<typename T::Ptr> *mResultProvider;
91 bool runAsync = false;
88}; 92};
89 93
90 94
@@ -280,6 +284,27 @@ private slots:
280 QVERIFY(!result.errorCode()); 284 QVERIFY(!result.errorCode());
281 QVERIFY(gotValue); 285 QVERIFY(gotValue);
282 } 286 }
287
288 void testModelStress()
289 {
290 auto facade = TestDummyResourceFacade<Sink::ApplicationDomain::Folder>::registerFacade();
291 facade->runAsync = true;
292 for (int i = 0; i < 100; i++) {
293 facade->results << QSharedPointer<Sink::ApplicationDomain::Folder>::create("resource", "id" + QByteArray::number(i), 0, QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create());
294 }
295 ResourceConfig::addResource("dummyresource.instance1", "dummyresource");
296
297 Sink::Query query;
298 query.resourceFilter("dummyresource.instance1");
299
300 for (int i = 0; i < 100; i++) {
301 auto model = Sink::Store::loadModel<Sink::ApplicationDomain::Folder>(query);
302 model->fetchMore(QModelIndex());
303 QTest::qWait(1);
304 }
305 QTest::qWait(100);
306 }
307
283}; 308};
284 309
285QTEST_MAIN(ClientAPITest) 310QTEST_MAIN(ClientAPITest)