|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include <qvaluespacesubscriber.h> |
|
43 #include <qvaluespacemanager_p.h> |
|
44 #include <qvaluespacepublisher.h> |
|
45 |
|
46 #include <QThread> |
|
47 #include <QVector> |
|
48 |
|
49 #include <QTest> |
|
50 #include <QDebug> |
|
51 #include <QSignalSpy> |
|
52 #include <QFile> |
|
53 |
|
54 #ifdef Q_OS_WIN |
|
55 #define _WIN32_WINNT 0x0500 |
|
56 #include <windows.h> |
|
57 #endif |
|
58 |
|
59 #include <QProcess> |
|
60 |
|
61 #define QTRY_COMPARE(a,e) \ |
|
62 for (int _i = 0; _i < 5000; _i += 100) { \ |
|
63 if ((a) == (e)) break; \ |
|
64 QTest::qWait(100); \ |
|
65 } \ |
|
66 QCOMPARE(a, e) |
|
67 |
|
68 #define QTRY_VERIFY(a) \ |
|
69 for (int _i = 0; _i < 5000; _i += 100) { \ |
|
70 if (a) break; \ |
|
71 QTest::qWait(100); \ |
|
72 } \ |
|
73 QVERIFY(a) |
|
74 |
|
75 QTM_USE_NAMESPACE |
|
76 class ChangeListener : public QObject |
|
77 { |
|
78 Q_OBJECT |
|
79 Q_SIGNALS: |
|
80 void interestChanged(const QString&, bool); |
|
81 }; |
|
82 |
|
83 class tst_QValueSpacePublisher: public QObject |
|
84 { |
|
85 Q_OBJECT |
|
86 |
|
87 private slots: |
|
88 void initTestCase(); |
|
89 void cleanupTestCase(); |
|
90 |
|
91 void testConstructor_data(); |
|
92 void testConstructor(); |
|
93 void testFilterConstructor_data(); |
|
94 void testFilterConstructor(); |
|
95 void testBaseConstructor(); |
|
96 |
|
97 void testSetValue_data(); |
|
98 void testSetValue(); |
|
99 |
|
100 void testSignals_data(); |
|
101 void testSignals(); |
|
102 |
|
103 void valuePermanence_data(); |
|
104 void valuePermanence(); |
|
105 |
|
106 void threads_data(); |
|
107 void threads(); |
|
108 |
|
109 private: |
|
110 int variantMetaTypeId; |
|
111 }; |
|
112 |
|
113 Q_DECLARE_METATYPE(QAbstractValueSpaceLayer *) |
|
114 Q_DECLARE_METATYPE(QUuid) |
|
115 Q_DECLARE_METATYPE(QVariant) |
|
116 Q_DECLARE_METATYPE(QValueSpace::LayerOptions) |
|
117 |
|
118 void tst_QValueSpacePublisher::initTestCase() |
|
119 { |
|
120 variantMetaTypeId = qRegisterMetaType<QVariant>("QVariant"); |
|
121 |
|
122 #ifdef Q_OS_WIN |
|
123 HKEY key; |
|
124 long result = RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\Nokia", |
|
125 0, KEY_ALL_ACCESS, &key); |
|
126 if (result == ERROR_SUCCESS) { |
|
127 result = RegDeleteKey(key, L"QtMobility\\volatileContext"); |
|
128 result = RegDeleteKey(key, L"QtMobility\\nonVolatileContext"); |
|
129 result = RegDeleteKey(key, L"QtMobility"); |
|
130 |
|
131 RegCloseKey(key); |
|
132 } |
|
133 #endif |
|
134 |
|
135 #ifdef Q_OS_UNIX |
|
136 QFile::remove("/tmp/qt-0/valuespace_shmlayer"); |
|
137 #endif |
|
138 |
|
139 QValueSpace::initValueSpaceServer(); |
|
140 |
|
141 if (QValueSpace::availableLayers().contains(QVALUESPACE_GCONF_LAYER)) { |
|
142 QCOMPARE(QProcess::execute("gconftool-2 -u /value"), 0); |
|
143 QCOMPARE(QProcess::execute("gconftool-2 -u /testConstructor/value"), 0); |
|
144 QCOMPARE(QProcess::execute("gconftool-2 -u /testConstructor/subpath/value"), 0); |
|
145 } |
|
146 |
|
147 } |
|
148 |
|
149 void tst_QValueSpacePublisher::cleanupTestCase() |
|
150 { |
|
151 } |
|
152 |
|
153 #define ADD(layer, id, path, canonical, valid) do {\ |
|
154 const QString layerName(layer ? layer->name() : 0); \ |
|
155 QTest::newRow((layerName + ' ' + path + " const QString &").toLocal8Bit().constData()) \ |
|
156 << layer << id << path << canonical << valid; \ |
|
157 } while (false) |
|
158 |
|
159 void tst_QValueSpacePublisher::testConstructor_data() |
|
160 { |
|
161 QTest::addColumn<QAbstractValueSpaceLayer *>("layer"); |
|
162 QTest::addColumn<QUuid>("uuid"); |
|
163 |
|
164 QTest::addColumn<QString>("path"); |
|
165 QTest::addColumn<QString>("canonical"); |
|
166 QTest::addColumn<bool>("connected"); |
|
167 |
|
168 QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers(); |
|
169 |
|
170 // add all known layers |
|
171 for (int i = 0; i < layers.count(); ++i) { |
|
172 QAbstractValueSpaceLayer *layer = layers.at(i); |
|
173 |
|
174 ADD(layer, layer->id(), QString(""), QString("/"), true); |
|
175 ADD(layer, layer->id(), QString("/"), QString("/"), true); |
|
176 ADD(layer, layer->id(), QString("//"), QString("/"), true); |
|
177 ADD(layer, layer->id(), QString("/testConstructor"), QString("/testConstructor"), true); |
|
178 ADD(layer, layer->id(), QString("/testConstructor/"), QString("/testConstructor"), true); |
|
179 ADD(layer, layer->id(), QString("testConstructor"), QString("/testConstructor"), true); |
|
180 ADD(layer, layer->id(), QString("/testConstructor/subpath"),\ |
|
181 QString("/testConstructor/subpath"), true); |
|
182 } |
|
183 |
|
184 // unknown uuid |
|
185 ADD(reinterpret_cast<QAbstractValueSpaceLayer *>(0), |
|
186 QUuid("{9fa51477-7730-48e0-aee1-3eeb5f0c0c5b}"), QString(), QString("/"), false); |
|
187 } |
|
188 |
|
189 #undef ADD |
|
190 |
|
191 void tst_QValueSpacePublisher::testConstructor() |
|
192 { |
|
193 QFETCH(QAbstractValueSpaceLayer *, layer); |
|
194 QFETCH(QUuid, uuid); |
|
195 |
|
196 QFETCH(QString, path); |
|
197 QFETCH(QString, canonical); |
|
198 QFETCH(bool, connected); |
|
199 |
|
200 QValueSpacePublisher *publisher = new QValueSpacePublisher(uuid, path); |
|
201 |
|
202 QCOMPARE(publisher->path(), canonical); |
|
203 QCOMPARE(publisher->isConnected(), connected); |
|
204 |
|
205 if (layer) { |
|
206 QAbstractValueSpaceLayer::Handle handle = |
|
207 layer->item(QAbstractValueSpaceLayer::InvalidHandle, canonical.toUtf8()); |
|
208 |
|
209 QVariant data; |
|
210 QVERIFY(!layer->value(handle, "/value", &data)); |
|
211 |
|
212 layer->removeHandle(handle); |
|
213 } |
|
214 |
|
215 publisher->setValue(QString("value"), 100); |
|
216 publisher->sync(); |
|
217 |
|
218 if (layer) { |
|
219 QAbstractValueSpaceLayer::Handle handle = |
|
220 layer->item(QAbstractValueSpaceLayer::InvalidHandle, canonical.toUtf8()); |
|
221 |
|
222 QVariant data; |
|
223 QVERIFY(layer->value(handle, "/value", &data)); |
|
224 QCOMPARE(data.toInt(), 100); |
|
225 |
|
226 layer->removeHandle(handle); |
|
227 } |
|
228 |
|
229 publisher->resetValue(QString("value")); |
|
230 publisher->sync(); |
|
231 |
|
232 if (layer) { |
|
233 QAbstractValueSpaceLayer::Handle handle = |
|
234 layer->item(QAbstractValueSpaceLayer::InvalidHandle, canonical.toUtf8()); |
|
235 |
|
236 QVariant data; |
|
237 QVERIFY(!layer->value(handle, "/value", &data)); |
|
238 |
|
239 layer->removeHandle(handle); |
|
240 } |
|
241 |
|
242 delete publisher; |
|
243 |
|
244 if (layer && layer->layerOptions() & QValueSpace::PermanentLayer) { |
|
245 QValueSpacePublisher root(uuid, "/"); |
|
246 while (!canonical.isEmpty()) { |
|
247 root.resetValue(canonical.mid(1)); |
|
248 canonical.truncate(canonical.lastIndexOf('/')); |
|
249 } |
|
250 root.sync(); |
|
251 } |
|
252 } |
|
253 |
|
254 #define ADD(opt, valid) do {\ |
|
255 QTest::newRow(QString::number(opt).append(" const QString &").toLocal8Bit().constData()) \ |
|
256 << (QValueSpace::UnspecifiedLayer | opt) << valid; \ |
|
257 } while (false) |
|
258 |
|
259 void tst_QValueSpacePublisher::testFilterConstructor_data() |
|
260 { |
|
261 QTest::addColumn<QValueSpace::LayerOptions>("options"); |
|
262 QTest::addColumn<bool>("connected"); |
|
263 |
|
264 QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers(); |
|
265 |
|
266 for (int i = 0; i < layers.count(); ++i) { |
|
267 QAbstractValueSpaceLayer *layer = layers.at(i); |
|
268 |
|
269 ADD(layer->layerOptions(), true); |
|
270 } |
|
271 |
|
272 ADD(QValueSpace::PermanentLayer | QValueSpace::TransientLayer, |
|
273 false); |
|
274 ADD(QValueSpace::WritableLayer | QValueSpace::ReadOnlyLayer, |
|
275 false); |
|
276 } |
|
277 |
|
278 void tst_QValueSpacePublisher::testFilterConstructor() |
|
279 { |
|
280 QFETCH(QValueSpace::LayerOptions, options); |
|
281 QFETCH(bool, connected); |
|
282 |
|
283 QValueSpacePublisher *publisher = new QValueSpacePublisher(options, QString("/")); |
|
284 |
|
285 QCOMPARE(publisher->isConnected(), connected); |
|
286 } |
|
287 |
|
288 void tst_QValueSpacePublisher::testBaseConstructor() |
|
289 { |
|
290 { |
|
291 QValueSpacePublisher publisher("/"); |
|
292 QVERIFY(publisher.isConnected()); |
|
293 } |
|
294 |
|
295 { |
|
296 QValueSpacePublisher publisher(QString("/")); |
|
297 QVERIFY(publisher.isConnected()); |
|
298 } |
|
299 } |
|
300 |
|
301 void tst_QValueSpacePublisher::testSetValue_data() |
|
302 { |
|
303 QTest::addColumn<QAbstractValueSpaceLayer *>("layer"); |
|
304 |
|
305 QTest::addColumn<QString>("value"); |
|
306 |
|
307 QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers(); |
|
308 |
|
309 for (int i = 0; i < layers.count(); ++i) { |
|
310 QAbstractValueSpaceLayer *layer = layers.at(i); |
|
311 |
|
312 QTest::newRow("empty") << layer << QString::fromLatin1("/"); |
|
313 } |
|
314 } |
|
315 |
|
316 void tst_QValueSpacePublisher::testSetValue() |
|
317 { |
|
318 QFETCH(QAbstractValueSpaceLayer *, layer); |
|
319 QFETCH(QString, value); |
|
320 |
|
321 QValueSpaceSubscriber subscriber(layer->id(), QLatin1String("/testSetValue")); |
|
322 QVERIFY(subscriber.subPaths().isEmpty()); |
|
323 |
|
324 QValueSpacePublisher publisher(layer->id(), QLatin1String("/testSetValue")); |
|
325 |
|
326 publisher.setValue(QLatin1String(""), QLatin1String("default data")); |
|
327 publisher.sync(); |
|
328 QVERIFY(subscriber.subPaths().isEmpty()); |
|
329 QCOMPARE(subscriber.value(QLatin1String("")).toString(), QLatin1String("default data")); |
|
330 |
|
331 publisher.setValue(QLatin1String("key"), QLatin1String("key data")); |
|
332 publisher.sync(); |
|
333 QCOMPARE(subscriber.subPaths().count(), 1); |
|
334 QCOMPARE(subscriber.subPaths().first(), QLatin1String("key")); |
|
335 QCOMPARE(subscriber.value(QLatin1String("key")).toString(), QLatin1String("key data")); |
|
336 |
|
337 publisher.resetValue(QLatin1String("key")); |
|
338 publisher.resetValue(QLatin1String("")); |
|
339 publisher.sync(); |
|
340 |
|
341 QVERIFY(!subscriber.value(QLatin1String("")).isValid()); |
|
342 QVERIFY(!subscriber.value(QLatin1String("key")).isValid()); |
|
343 } |
|
344 |
|
345 |
|
346 void tst_QValueSpacePublisher::testSignals_data() |
|
347 { |
|
348 QTest::addColumn<QAbstractValueSpaceLayer *>("layer"); |
|
349 |
|
350 QTest::addColumn<QString>("publisherPath"); |
|
351 QTest::addColumn<QString>("subscriberPath"); |
|
352 QTest::addColumn<QString>("attribute"); |
|
353 |
|
354 QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers(); |
|
355 |
|
356 bool foundSupported = false; |
|
357 |
|
358 for (int i = 0; i < layers.count(); ++i) { |
|
359 QAbstractValueSpaceLayer *layer = layers.at(i); |
|
360 |
|
361 if (!layer->supportsInterestNotification()) |
|
362 continue; |
|
363 |
|
364 foundSupported = true; |
|
365 |
|
366 QTest::newRow("/ /") |
|
367 << layer |
|
368 << QString("/") |
|
369 << QString("/") |
|
370 << QString(); |
|
371 |
|
372 QTest::newRow("/ /testSignals") |
|
373 << layer |
|
374 << QString("/") |
|
375 << QString("/testSignals") |
|
376 << QString("testSignals"); |
|
377 |
|
378 QTest::newRow("/testSignals /testSignals") |
|
379 << layer |
|
380 << QString("/testSignals") |
|
381 << QString("/testSignals") |
|
382 << QString(); |
|
383 } |
|
384 |
|
385 if (!foundSupported) |
|
386 QSKIP("No layer supporting interest notifications found.", SkipAll); |
|
387 } |
|
388 |
|
389 void tst_QValueSpacePublisher::testSignals() |
|
390 { |
|
391 QFETCH(QAbstractValueSpaceLayer *, layer); |
|
392 |
|
393 QFETCH(QString, publisherPath); |
|
394 QFETCH(QString, subscriberPath); |
|
395 QFETCH(QString, attribute); |
|
396 |
|
397 QValueSpacePublisher *publisher = new QValueSpacePublisher(layer->id(), publisherPath); |
|
398 |
|
399 ChangeListener listener; |
|
400 connect(publisher, SIGNAL(interestChanged(QString,bool)), |
|
401 &listener, SIGNAL(interestChanged(QString,bool))); |
|
402 |
|
403 QSignalSpy interestChangedSpy(&listener, SIGNAL(interestChanged(QString,bool))); |
|
404 |
|
405 QValueSpaceSubscriber *subscriber = new QValueSpaceSubscriber(layer->id(), subscriberPath); |
|
406 |
|
407 QTRY_COMPARE(interestChangedSpy.count(), 1); |
|
408 |
|
409 QList<QVariant> arguments = interestChangedSpy.takeFirst(); |
|
410 QCOMPARE(arguments.count(), 2); |
|
411 QCOMPARE(arguments.at(0).type(), QVariant::String); |
|
412 QCOMPARE(arguments.at(0).toString(), attribute); |
|
413 QCOMPARE(arguments.at(1).type(), QVariant::Bool); |
|
414 QVERIFY(arguments.at(1).toBool()); |
|
415 |
|
416 delete subscriber; |
|
417 |
|
418 QTRY_COMPARE(interestChangedSpy.count(), 1); |
|
419 |
|
420 arguments = interestChangedSpy.takeFirst(); |
|
421 QCOMPARE(arguments.count(), 2); |
|
422 QCOMPARE(arguments.at(0).type(), QVariant::String); |
|
423 QCOMPARE(arguments.at(0).toString(), attribute); |
|
424 QCOMPARE(arguments.at(1).type(), QVariant::Bool); |
|
425 QVERIFY(!arguments.at(1).toBool()); |
|
426 |
|
427 delete publisher; |
|
428 } |
|
429 |
|
430 void tst_QValueSpacePublisher::valuePermanence_data() |
|
431 { |
|
432 QTest::addColumn<QAbstractValueSpaceLayer *>("layer"); |
|
433 |
|
434 QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers(); |
|
435 |
|
436 // add all known layers |
|
437 for (int i = 0; i < layers.count(); ++i) { |
|
438 QAbstractValueSpaceLayer *layer = layers.at(i); |
|
439 |
|
440 QTest::newRow(layer->name().toLocal8Bit().constData()) << layer; |
|
441 } |
|
442 } |
|
443 |
|
444 void tst_QValueSpacePublisher::valuePermanence() |
|
445 { |
|
446 QFETCH(QAbstractValueSpaceLayer *, layer); |
|
447 |
|
448 QValueSpacePublisher *publisher = new QValueSpacePublisher(layer->id(), "/valuePermanence"); |
|
449 |
|
450 publisher->setValue("value", 10); |
|
451 |
|
452 QValueSpaceSubscriber subscriber("/valuePermanence"); |
|
453 QCOMPARE(subscriber.value("value", 0).toInt(), 10); |
|
454 |
|
455 delete publisher; |
|
456 |
|
457 if (layer->layerOptions() & QValueSpace::PermanentLayer) { |
|
458 // Permanent layer, check that value is still available after publisher is deleted. |
|
459 QCOMPARE(subscriber.value("value", 0).toInt(), 10); |
|
460 |
|
461 publisher = new QValueSpacePublisher(layer->id(), "/valuePermanence"); |
|
462 |
|
463 publisher->resetValue("value"); |
|
464 |
|
465 QCOMPARE(subscriber.value("value", 0).toInt(), 0); |
|
466 |
|
467 publisher->resetValue(QString()); |
|
468 |
|
469 delete publisher; |
|
470 } else { |
|
471 // Non-permanent layer, check that value is not available after publisher is deleted. |
|
472 QCOMPARE(subscriber.value("value", 0).toInt(), 0); |
|
473 } |
|
474 } |
|
475 |
|
476 class WriteThread : public QThread |
|
477 { |
|
478 Q_OBJECT |
|
479 |
|
480 public: |
|
481 WriteThread(const QString &path, const QUuid &uuid, unsigned int count); |
|
482 ~WriteThread(); |
|
483 |
|
484 void runSequential() { run(); } |
|
485 |
|
486 protected: |
|
487 void run(); |
|
488 |
|
489 private: |
|
490 QString path; |
|
491 unsigned int count; |
|
492 QValueSpacePublisher *publisher; |
|
493 }; |
|
494 |
|
495 WriteThread::WriteThread(const QString &path, const QUuid &uuid, unsigned int count) |
|
496 : path(path), count(count) |
|
497 { |
|
498 publisher = new QValueSpacePublisher(uuid, path, this); |
|
499 } |
|
500 |
|
501 WriteThread::~WriteThread() |
|
502 { |
|
503 #ifdef Q_OS_SYMBIAN |
|
504 //Cleanup published values since the SymbianSettingLayer is permanent |
|
505 const QString key("key%1"); |
|
506 for (unsigned int i = 0; i < count; ++i) |
|
507 publisher->resetValue(key.arg(i)); |
|
508 |
|
509 publisher->sync(); |
|
510 #endif |
|
511 } |
|
512 |
|
513 void WriteThread::run() |
|
514 { |
|
515 const QString key("key%1"); |
|
516 const QString value("value%1"); |
|
517 |
|
518 for (unsigned int i = 0; i < count; ++i) |
|
519 publisher->setValue(key.arg(i), value.arg(i)); |
|
520 |
|
521 publisher->sync(); |
|
522 } |
|
523 |
|
524 void tst_QValueSpacePublisher::threads_data() |
|
525 { |
|
526 QTest::addColumn<QUuid>("uuid"); |
|
527 |
|
528 QTest::addColumn<unsigned int>("threads"); |
|
529 QTest::addColumn<unsigned int>("count"); |
|
530 QTest::addColumn<bool>("sequential"); |
|
531 |
|
532 QList<QAbstractValueSpaceLayer *> layers = QValueSpaceManager::instance()->getLayers(); |
|
533 |
|
534 int foundLayers = 0; |
|
535 for (int i = 0; i < layers.count(); ++i) { |
|
536 QAbstractValueSpaceLayer *layer = layers.at(i); |
|
537 |
|
538 if (layer->id() == QVALUESPACE_NONVOLATILEREGISTRY_LAYER) |
|
539 continue; |
|
540 |
|
541 //GConfLayer can't provide thread-safety because it eventually depends on |
|
542 //DBus which isn't fully thread-safe |
|
543 if (layer->id() == QVALUESPACE_GCONF_LAYER) |
|
544 continue; |
|
545 |
|
546 #ifdef Q_OS_WINCE |
|
547 // Limit number of items on Windows CE to prevent out of disk space errors. |
|
548 if (layer->id() == QVALUESPACE_VOLATILEREGISTRY_LAYER) { |
|
549 QTest::newRow("1 thread, 10 items, sequential") |
|
550 << layer->id() << uint(1) << uint(10) << true; |
|
551 QTest::newRow("1 thread, 3000 items, sequential") |
|
552 << layer->id() << uint(1) << uint(3000) << true; |
|
553 QTest::newRow("2 threads, 10 items, sequential") |
|
554 << layer->id() << uint(2) << uint(10) << true; |
|
555 QTest::newRow("2 threads, 1500 items, sequential") |
|
556 << layer->id() << uint(2) << uint(1500) << true; |
|
557 QTest::newRow("4 threads, 750 items, sequential") |
|
558 << layer->id() << uint(4) << uint(750) << true; |
|
559 QTest::newRow("10 threads, 300 items, sequential") |
|
560 << layer->id() << uint(10) << uint(300) << true; |
|
561 |
|
562 QTest::newRow("1 thread, 10 items") |
|
563 << layer->id() << uint(1) << uint(10) << false; |
|
564 QTest::newRow("1 thread, 3000 items") |
|
565 << layer->id() << uint(1) << uint(3000) << false; |
|
566 QTest::newRow("2 threads, 10 items") |
|
567 << layer->id() << uint(2) << uint(10) << false; |
|
568 QTest::newRow("2 threads, 1500 items") |
|
569 << layer->id() << uint(2) << uint(1500) << false; |
|
570 QTest::newRow("4 threads, 750 items") |
|
571 << layer->id() << uint(4) << uint(750) << false; |
|
572 QTest::newRow("10 threads, 300 items") |
|
573 << layer->id() << uint(10) << uint(300) << false; |
|
574 } else |
|
575 #endif |
|
576 |
|
577 // The Shared Memory layer can hold a maximum of 8191 nodes. |
|
578 if (layer->id() == QVALUESPACE_SHAREDMEMORY_LAYER) { |
|
579 QTest::newRow("1 thread, 10 items, sequential") |
|
580 << layer->id() << uint(1) << uint(10) << true; |
|
581 QTest::newRow("1 thread, 8000 items, sequential") |
|
582 << layer->id() << uint(1) << uint(8000) << true; |
|
583 QTest::newRow("2 threads, 10 items, sequential") |
|
584 << layer->id() << uint(2) << uint(10) << true; |
|
585 QTest::newRow("2 threads, 4000 items, sequential") |
|
586 << layer->id() << uint(2) << uint(4000) << true; |
|
587 QTest::newRow("4 threads, 2000 items, sequential") |
|
588 << layer->id() << uint(4) << uint(2000) << true; |
|
589 QTest::newRow("10 threads, 800 items, sequential") |
|
590 << layer->id() << uint(10) << uint(800) << true; |
|
591 QTest::newRow("100 threads, 80 items, sequential") |
|
592 << layer->id() << uint(100) << uint(80) << true; |
|
593 |
|
594 QTest::newRow("1 thread, 10 items") |
|
595 << layer->id() << uint(1) << uint(10) << false; |
|
596 QTest::newRow("1 thread, 8000 items") |
|
597 << layer->id() << uint(1) << uint(8000) << false; |
|
598 QTest::newRow("2 threads, 10 items") |
|
599 << layer->id() << uint(2) << uint(10) << false; |
|
600 QTest::newRow("2 threads, 4000 items") |
|
601 << layer->id() << uint(2) << uint(4000) << false; |
|
602 QTest::newRow("4 threads, 2000 items") |
|
603 << layer->id() << uint(4) << uint(2000) << false; |
|
604 QTest::newRow("10 threads, 800 items") |
|
605 << layer->id() << uint(10) << uint(800) << false; |
|
606 QTest::newRow("100 threads, 80 items") |
|
607 << layer->id() << uint(100) << uint(80) << false; |
|
608 } else if (layer->id() == QVALUESPACE_SYMBIAN_SETTINGS_LAYER) { |
|
609 QTest::newRow("1 thread, 10 items, sequential") |
|
610 << layer->id() << uint(1) << uint(10) << true; |
|
611 QTest::newRow("2 threads, 10 items, sequential") |
|
612 << layer->id() << uint(2) << uint(10) << true; |
|
613 } else { |
|
614 // Assume no limits on all other layers. |
|
615 QTest::newRow("1 thread, 10 items, sequential") |
|
616 << layer->id() << uint(1) << uint(10) << true; |
|
617 QTest::newRow("1 thread, 10000 items, sequential") |
|
618 << layer->id() << uint(1) << uint(10000) << true; |
|
619 QTest::newRow("2 threads, 10 items, sequential") |
|
620 << layer->id() << uint(2) << uint(10) << true; |
|
621 QTest::newRow("2 threads, 5000 items, sequential") |
|
622 << layer->id() << uint(2) << uint(5000) << true; |
|
623 QTest::newRow("100 threads, 100 items, sequential") |
|
624 << layer->id() << uint(100) << uint(100) << true; |
|
625 |
|
626 QTest::newRow("1 thread, 10 items") |
|
627 << layer->id() << uint(1) << uint(10) << false; |
|
628 QTest::newRow("1 thread, 10000 items") |
|
629 << layer->id() << uint(1) << uint(10000) << false; |
|
630 QTest::newRow("2 threads, 10 items") |
|
631 << layer->id() << uint(2) << uint(10) << false; |
|
632 QTest::newRow("2 threads, 5000 items") |
|
633 << layer->id() << uint(2) << uint(5000) << false; |
|
634 QTest::newRow("100 threads, 100 items") |
|
635 << layer->id() << uint(100) << uint(100) << false; |
|
636 } |
|
637 foundLayers++; |
|
638 } |
|
639 |
|
640 if (foundLayers == 0) |
|
641 QSKIP("No layers providing thread-safety found", SkipAll); |
|
642 } |
|
643 |
|
644 void tst_QValueSpacePublisher::threads() |
|
645 { |
|
646 QFETCH(QUuid, uuid); |
|
647 QFETCH(unsigned int, threads); |
|
648 QFETCH(unsigned int, count); |
|
649 QFETCH(bool, sequential); |
|
650 |
|
651 if (QValueSpace::availableLayers().contains(QVALUESPACE_GCONF_LAYER)) { |
|
652 QCOMPARE(QProcess::execute("gconftool-2 --recursive-unset /threads"), 0); |
|
653 } |
|
654 QStringList expectedPaths; |
|
655 for (unsigned int i = 0; i < threads; ++i) |
|
656 expectedPaths.append(QString("thread%1").arg(i)); |
|
657 |
|
658 QHash<QString, QString> expectedValues; |
|
659 for (unsigned int i = 0; i < count; ++i) |
|
660 expectedValues.insert(QString("key%1").arg(i), QString("value%1").arg(i)); |
|
661 |
|
662 QValueSpaceSubscriber *subscriber = new QValueSpaceSubscriber(uuid, "/threads"); |
|
663 |
|
664 QVERIFY(subscriber->subPaths().isEmpty()); |
|
665 |
|
666 QVector<WriteThread *> writeThreads(threads); |
|
667 |
|
668 // Create and start writer threads. |
|
669 for (unsigned int i = 0; i < threads; ++i) { |
|
670 writeThreads[i] = |
|
671 new WriteThread(QString("/threads/%1").arg(expectedPaths.at(i)), uuid, count); |
|
672 |
|
673 if (sequential) |
|
674 writeThreads[i]->runSequential(); |
|
675 else |
|
676 writeThreads[i]->start(); |
|
677 } |
|
678 |
|
679 if (!sequential) { |
|
680 // Wait for writer threads to finish. |
|
681 for (unsigned int i = 0; i < threads; ++i) |
|
682 writeThreads[i]->wait(); |
|
683 } |
|
684 |
|
685 qDebug() << "Published" << count << "items in" << threads |
|
686 << "theads, totaling" << (threads * count); |
|
687 |
|
688 // Verify Value Space |
|
689 QStringList subPaths = subscriber->subPaths(); |
|
690 if (subPaths.toSet() != expectedPaths.toSet()) { |
|
691 qDebug() << "Expected Paths:" << expectedPaths; |
|
692 qDebug() << "Actual Paths:" << subPaths; |
|
693 } |
|
694 QVERIFY(subPaths.toSet() == expectedPaths.toSet()); |
|
695 |
|
696 while (!subPaths.isEmpty()) { |
|
697 QValueSpaceSubscriber threadItem; |
|
698 threadItem.setPath(subscriber); |
|
699 threadItem.cd(subPaths.takeFirst()); |
|
700 |
|
701 QStringList keys = threadItem.subPaths(); |
|
702 |
|
703 if (keys.toSet() != expectedValues.keys().toSet()) { |
|
704 qDebug() << "Expected value keys:" << expectedValues.keys(); |
|
705 qDebug() << "Actual value keys:" << keys; |
|
706 } |
|
707 QVERIFY(keys.toSet() == expectedValues.keys().toSet()); |
|
708 |
|
709 while (!keys.isEmpty()) { |
|
710 const QString key = keys.takeFirst(); |
|
711 QCOMPARE(threadItem.value(key).toString(), expectedValues.value(key)); |
|
712 } |
|
713 } |
|
714 |
|
715 delete subscriber; |
|
716 |
|
717 // Delete writer threads. |
|
718 for (unsigned int i = 0; i < threads; ++i) |
|
719 delete writeThreads[i]; |
|
720 } |
|
721 |
|
722 QTEST_MAIN(tst_QValueSpacePublisher) |
|
723 #include "tst_qvaluespacepublisher.moc" |