1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtSystems module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL21$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 or version 3 as published by the Free
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22** following information to ensure the GNU Lesser General Public License
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** As a special exception, The Qt Company gives you certain additional
27** rights. These rights are described in The Qt Company LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** $QT_END_LICENSE$
31**
32****************************************************************************/
33
34//TESTED_COMPONENT=src/serviceframework
35
36#include <qservicemanager.h>
37#include <private/qserviceinterfacedescriptor_p.h>
38#include "sampleservice/sampleserviceplugin.h"
39#include "../qsfwtestutil.h"
40
41#include <QtTest/QtTest>
42#include <QtCore>
43#include <QSettings>
44#include <QFileInfo>
45#include <QDir>
46#include <QPair>
47
48#define PRINT_ERR(a) qPrintable(QString("error = %1").arg(a.error()))
49
50typedef QList<QServiceInterfaceDescriptor> ServiceInterfaceDescriptorList;
51Q_DECLARE_METATYPE(QServiceFilter)
52Q_DECLARE_METATYPE(QServiceInterfaceDescriptor)
53Q_DECLARE_METATYPE(ServiceInterfaceDescriptorList)
54
55Q_DECLARE_METATYPE(QSet<QString>)
56Q_DECLARE_METATYPE(QList<QByteArray>)
57Q_DECLARE_METATYPE(QService::Scope)
58
59QT_BEGIN_NAMESPACE
60typedef QHash<QServiceInterfaceDescriptor::Attribute, QVariant> DescriptorAttributes;
61QT_END_NAMESPACE
62
63QT_USE_NAMESPACE
64static DescriptorAttributes defaultDescriptorAttributes()
65{
66 DescriptorAttributes props;
67 //props[QServiceInterfaceDescriptor::Capabilities] = QStringList();
68 props[QServiceInterfaceDescriptor::Location] = "";
69 props[QServiceInterfaceDescriptor::ServiceDescription] = "";
70 props[QServiceInterfaceDescriptor::InterfaceDescription] = "";
71 props[QServiceInterfaceDescriptor::ServiceType] = QService::Plugin;
72 return props;
73}
74static const DescriptorAttributes DEFAULT_DESCRIPTOR_PROPERTIES = defaultDescriptorAttributes();
75
76// Helper function for debugging. Useful e.g. for checking what is difference between
77// two descriptors (in addition to attributes printed below, the
78// QServiceInterfaceDescriptor::== operator also compares
79// attributes.
80/*static void printDescriptor (const QServiceInterfaceDescriptor &desc) {
81 qDebug("***QServiceInterfaceDescriptor printed:");
82 qDebug() << "***majorVersion:" << desc.majorVersion();
83 qDebug() << "***minorVersion:" << desc.minorVersion();
84 qDebug() << "***interfaceName:" << desc.interfaceName();
85 qDebug() << "***serviceName:" << desc.serviceName();
86 qDebug() << "***customAttributes:" << desc.customAttributes();
87 qDebug() << "***attributes:" << desc.attribute(QServiceInterfaceDescriptor::Capabilities) <<
88 desc.attribute(QServiceInterfaceDescriptor::Location) <<
89 desc.attribute(QServiceInterfaceDescriptor::ServiceDescription) <<
90 desc.attribute(QServiceInterfaceDescriptor::InterfaceDescription) <<
91 desc.attribute(QServiceInterfaceDescriptor::ServiceType);
92 qDebug() << "***isValid(): " << desc.isValid();
93 qDebug() << "***scope (user:0, system:1): " << desc.scope();
94}*/
95
96class ServicesListener : public QObject
97{
98 Q_OBJECT
99public slots:
100 void serviceAdded(const QString &name , QService::Scope scope) {
101 params.append(t: qMakePair(x: name, y: scope));
102 }
103 void serviceRemoved(const QString &name, QService::Scope scope) {
104 params.append(t: qMakePair(x: name, y: scope));
105 }
106public:
107 QList<QPair<QString, QService::Scope> > params;
108};
109
110
111class tst_QServiceManager: public QObject
112{
113 Q_OBJECT
114
115private:
116 inline QString xmlTestDataPath(const QString &xmlFileName) const
117 { return m_xmlDirectory + QLatin1Char('/') + xmlFileName; }
118
119 QByteArray createServiceXml(const QString &serviceName, const QByteArray &interfaceXml, const QString &path, const QString &description = QString()) const
120 {
121 QString xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
122 xml += "<service>\n";
123 xml += "<name>" + serviceName + "</name>\n";
124 xml += "<filepath>" + path + "</filepath>\n";
125 xml += "<description>" + description + "</description>\n";
126 xml += interfaceXml;
127 xml += "</service>\n";
128 return xml.toLatin1();
129 }
130
131 QByteArray createServiceXml(const QString &serviceName, const QList<QServiceInterfaceDescriptor> &descriptors) const
132 {
133 Q_ASSERT(descriptors.count() > 0);
134 return createServiceXml(serviceName, interfaceXml: createInterfaceXml(descriptors),
135 path: descriptors[0].attribute(which: QServiceInterfaceDescriptor::Location).toString(),
136 description: descriptors[0].attribute(which: QServiceInterfaceDescriptor::ServiceDescription).toString());
137 }
138
139 QByteArray createInterfaceXml(const QList<QServiceInterfaceDescriptor> &descriptors) const
140 {
141 QByteArray interfacesXml;
142 foreach (const QServiceInterfaceDescriptor &desc, descriptors) {
143 QString version = QString("%1.%2").arg(a: desc.majorVersion()).arg(a: desc.minorVersion());
144 interfacesXml += createInterfaceXml(name: desc.interfaceName(), version,
145 description: desc.attribute(which: QServiceInterfaceDescriptor::InterfaceDescription).toString());
146 }
147 return interfacesXml;
148 }
149
150 QByteArray createInterfaceXml(const QString &name, const QString &version = "1.0", const QString &description = QString()) const
151 {
152 QString xml = "<interface>\n";
153 xml += "<name>" + name + "</name>\n";
154 xml += "<version>" + version + "</version>\n";
155 xml += " <description>" + description + "</description>\n";
156 xml += "</interface>\n";
157 return xml.toLatin1();
158
159 }
160
161 QServiceInterfaceDescriptor createDescriptor(const QString &interfaceName, int major, int minor, const QString &serviceName, const DescriptorAttributes &attributes = DescriptorAttributes(), QService::Scope scope = QService::UserScope) const
162 {
163 QString version = QString("%1.%2").arg(a: major).arg(a: minor);
164
165 QServiceInterfaceDescriptorPrivate *priv = new QServiceInterfaceDescriptorPrivate;
166 priv->serviceName = serviceName;
167 priv->interfaceName = interfaceName;
168 priv->major = major;
169 priv->minor = minor;
170 priv->scope = scope;
171
172 priv->attributes = attributes;
173 foreach (QServiceInterfaceDescriptor::Attribute key, DEFAULT_DESCRIPTOR_PROPERTIES.keys()) {
174 if (!priv->attributes.contains(akey: key))
175 priv->attributes[key] = DEFAULT_DESCRIPTOR_PROPERTIES[key];
176 }
177
178 QServiceInterfaceDescriptor desc;
179 QServiceInterfaceDescriptorPrivate::setPrivate(descriptor: &desc, p: priv);
180 return desc;
181 }
182
183 void deleteTestDatabasesAndWaitUntilDone()
184 {
185 QSfwTestUtil::removeTempUserDb();
186 QSfwTestUtil::removeTempSystemDb();
187
188 QTRY_VERIFY(!QFile::exists(QSfwTestUtil::tempUserDbDir()));
189 QTRY_VERIFY(!QFile::exists(QSfwTestUtil::tempSystemDbDir()));
190 }
191
192private slots:
193 void initTestCase();
194 void cleanupTestCase();
195 void init();
196
197 void constructor();
198 void constructor_scope();
199 void constructor_scope_data();
200
201 void findServices();
202 void findServices_data();
203
204 void findServices_scope();
205 void findServices_scope_data();
206
207 void findInterfaces_filter();
208 void findInterfaces_filter_data();
209
210 void findInterfaces_scope();
211 void findInterfaces_scope_data();
212
213 void loadInterface_string();
214
215 void loadInterface_descriptor();
216 void loadInterface_descriptor_data();
217
218 void loadInterface_testLoadedObjectAttributes();
219
220 void loadLocalTypedInterface();
221
222 void addService();
223 void addService_data();
224
225 void addService_testInvalidServiceXml();
226 void addService_testPluginLoading();
227 void addService_testPluginLoading_data();
228 void addService_testInstallService();
229
230 void removeService();
231
232 void setInterfaceDefault_strings();
233 void setInterfaceDefault_strings_multipleInterfaces();
234
235 void setInterfaceDefault_descriptor();
236 void setInterfaceDefault_descriptor_data();
237
238 void interfaceDefault();
239
240 void serviceAdded();
241 void serviceAdded_data();
242
243 void serviceRemoved();
244 void serviceRemoved_data();
245
246private:
247 QString m_xmlDirectory;
248 QString m_pluginsDirectory;
249 QStringList m_validPluginNames;
250 QStringList m_validPluginPaths;
251};
252
253static const char *plugins[] =
254 {"tst_sfw_sampleserviceplugin", "tst_sfw_sampleserviceplugin2", "tst_sfw_testservice2plugin"};
255
256static const char *expectedPluginClassNames[] =
257 {"SampleServicePluginClass", 0, "TestService"};
258
259static inline QByteArray msgCannotLoadLibrary(const QString &name, const QString &error)
260{
261 QByteArray result = "Unable to load '";
262 result += name.toLocal8Bit();
263 result += "': ";
264 result += error.toLocal8Bit();
265 return result;
266}
267
268void tst_QServiceManager::initTestCase()
269{
270 qRegisterMetaType<QService::Scope>(typeName: "QService::Scope");
271
272 QSfwTestUtil::setupTempUserDb();
273 QSfwTestUtil::setupTempSystemDb();
274
275 m_xmlDirectory = QFINDTESTDATA("xml");
276 QVERIFY2(!m_xmlDirectory.isEmpty(), "Unable to locate XML test data");
277 m_pluginsDirectory = QFINDTESTDATA("plugins");
278 QVERIFY2(!m_pluginsDirectory.isEmpty(), "Unable to locate plugins");
279
280 // Example XML files specify plugins as 'plugins/foo', so, add parent directory.
281 const QFileInfo pluginsDirectory(m_pluginsDirectory);
282 QCoreApplication::addLibraryPath(pluginsDirectory.absolutePath());
283 QCoreApplication::addLibraryPath(pluginsDirectory.absoluteFilePath());
284
285 // Determine plugin and let QLibrary resolve the full path of the libraries
286 // '/path/foo' -> '/path/libfoo.so' or '/path/foo.dll'
287 const size_t pluginCount = sizeof(plugins) / sizeof(const char *);
288 for (size_t i = 0; i < pluginCount; ++i) {
289 const QString pluginName = QLatin1String(plugins[i]);
290 const QString pluginPathIn = m_pluginsDirectory + QLatin1Char('/') + pluginName;
291 QLibrary lib(pluginPathIn);
292 QVERIFY2(lib.load(), msgCannotLoadLibrary(pluginPathIn, lib.errorString()).constData());
293 lib.unload();
294 m_validPluginNames << pluginName;
295 m_validPluginPaths << lib.fileName();
296 }
297}
298
299void tst_QServiceManager::init()
300{
301 QSfwTestUtil::removeTempUserDb();
302 QSfwTestUtil::removeTempSystemDb();
303 QSettings settings("com.nokia.qt.serviceframework.tests", "SampleServicePlugin");
304 settings.setValue(key: "installed", value: false);
305}
306
307void tst_QServiceManager::cleanupTestCase()
308{
309 QSfwTestUtil::removeTempUserDb();
310 QSfwTestUtil::removeTempSystemDb();
311 //process deferred delete events
312 //QServiceManager::loadInterface makes use of deleteLater() when
313 //cleaning up service objects and their respective QPluginLoader
314 //we want to force the testcase to run the cleanup code
315 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
316 QCoreApplication::processEvents();
317}
318
319void tst_QServiceManager::constructor()
320{
321 QObject o;
322 QServiceManager mgr(&o);
323 QCOMPARE(mgr.scope(), QService::UserScope);
324 QCOMPARE(mgr.parent(), &o);
325}
326
327void tst_QServiceManager::constructor_scope()
328{
329 QFETCH(QService::Scope, scope);
330
331 QObject o;
332 QServiceManager mgr(scope, &o);
333 QCOMPARE(mgr.scope(), scope);
334 QCOMPARE(mgr.parent(), &o);
335}
336
337void tst_QServiceManager::constructor_scope_data()
338{
339 QTest::addColumn<QService::Scope>(name: "scope");
340
341 QTest::newRow(dataTag: "user") << QService::UserScope;
342 QTest::newRow(dataTag: "system") << QService::SystemScope;
343}
344
345void tst_QServiceManager::findServices()
346{
347 QFETCH(QList<QByteArray>, xmlBlocks);
348 QFETCH(QStringList, interfaceNames);
349 QFETCH(QSet<QString>, searchByInterfaceResult);
350 QFETCH(QSet<QString>, searchAllResult);
351
352 QServiceManager mgr;
353 QServiceFilter wildcardFilter;
354
355 // Check that nothing is found neither with default search or interface-search
356 QVERIFY(mgr.findServices().isEmpty());
357 foreach (const QString &serviceInterface, interfaceNames)
358 QVERIFY(mgr.findServices(serviceInterface).isEmpty());
359 QCOMPARE(mgr.findInterfaces(wildcardFilter).count(), 0);
360
361 // Add all services from the xmlBlocks list
362 foreach (const QByteArray &xml, xmlBlocks) {
363 QBuffer buffer;
364 buffer.setData(xml);
365 QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
366 }
367 // Check that all services are found with default search
368 QCOMPARE(mgr.findServices().toSet(), searchAllResult);
369 // Check that all services are found based on interface search
370 foreach (const QString &serviceInterface, interfaceNames)
371 QCOMPARE(mgr.findServices(serviceInterface).toSet(), searchByInterfaceResult);
372
373 // Check that nothing is found with empty interface
374 QCOMPARE(mgr.findServices("com.invalid.interface") , QStringList());
375}
376
377void tst_QServiceManager::findServices_data()
378{
379 QTest::addColumn< QList<QByteArray> >(name: "xmlBlocks");
380 QTest::addColumn<QStringList>(name: "interfaceNames");
381 QTest::addColumn< QSet<QString> >(name: "searchByInterfaceResult");
382 QTest::addColumn< QSet<QString> >(name: "searchAllResult");
383
384 QStringList interfaces;
385 interfaces << "com.nokia.qt.TestInterfaceA";
386 interfaces << "com.nokia.qt.TestInterfaceB";
387 QByteArray interfacesXml;
388 for (int i=0; i<interfaces.count(); i++)
389 interfacesXml += "\n" + createInterfaceXml(name: interfaces[i]);
390
391 QTest::newRow(dataTag: "one service")
392 << (QList<QByteArray>() << createServiceXml(serviceName: "SomeTestService", interfaceXml: interfacesXml, path: m_validPluginNames.first()))
393 << interfaces
394 << (QSet<QString>() << "SomeTestService")
395 << (QSet<QString>() << "SomeTestService");
396
397 QTest::newRow(dataTag: "multiple services with same interfaces")
398 << (QList<QByteArray>() << createServiceXml(serviceName: "SomeTestService", interfaceXml: interfacesXml, path: m_validPluginNames[0])
399 << createServiceXml(serviceName: "SomeSimilarTestService", interfaceXml: interfacesXml, path: m_validPluginNames[1]))
400 << interfaces
401 << (QSet<QString>() << "SomeTestService" << "SomeSimilarTestService")
402 << (QSet<QString>() << "SomeTestService" << "SomeSimilarTestService");
403
404 QStringList interfaces2;
405 interfaces2 << "com.nokia.qt.TestInterfaceY";
406 interfaces2 << "com.nokia.qt.TestInterfaceZ";
407 QByteArray interfacesXml2;
408 for (int i=0; i<interfaces2.count(); i++)
409 interfacesXml2 += "\n" + createInterfaceXml(name: interfaces2[i]);
410 QTest::newRow(dataTag: "multiple services with different interfaces")
411 << (QList<QByteArray>() << createServiceXml(serviceName: "SomeTestService", interfaceXml: interfacesXml, path: m_validPluginNames[0])
412 << createServiceXml(serviceName: "TestServiceWithOtherInterfaces", interfaceXml: interfacesXml2, path: m_validPluginNames[1]))
413 << interfaces2
414 << (QSet<QString>() << "TestServiceWithOtherInterfaces")
415 << (QSet<QString>() << "SomeTestService" << "TestServiceWithOtherInterfaces");
416}
417
418void tst_QServiceManager::findServices_scope()
419{
420 QFETCH(QService::Scope, scope_add);
421 QFETCH(QService::Scope, scope_find);
422 QFETCH(bool, expectFound);
423
424 QByteArray xml = createServiceXml(serviceName: "SomeTestService",
425 interfaceXml: createInterfaceXml(name: "com.nokia.qt.TestInterface"), path: m_validPluginNames[0]);
426 QBuffer buffer(&xml);
427
428 QServiceManager mgrUser(QService::UserScope);
429 QServiceManager mgrSystem(QService::SystemScope);
430
431 QServiceManager &mgrAdd = scope_add == QService::UserScope ? mgrUser : mgrSystem;
432 QServiceManager &mgrFind = scope_find == QService::UserScope ? mgrUser : mgrSystem;
433
434 QVERIFY2(mgrAdd.addService(&buffer), PRINT_ERR(mgrAdd));
435 QStringList result = mgrFind.findServices();
436 QCOMPARE(!result.isEmpty(), expectFound);
437}
438
439void tst_QServiceManager::findServices_scope_data()
440{
441 QTest::addColumn<QService::Scope>(name: "scope_add");
442 QTest::addColumn<QService::Scope>(name: "scope_find");
443 QTest::addColumn<bool>(name: "expectFound");
444
445 QTest::newRow(dataTag: "user scope")
446 << QService::UserScope << QService::UserScope << true;
447 QTest::newRow(dataTag: "system scope")
448 << QService::SystemScope << QService::SystemScope << true;
449
450 QTest::newRow(dataTag: "user scope - add, system scope - find")
451 << QService::UserScope << QService::SystemScope << false;
452 QTest::newRow(dataTag: "system scope - add, user scope - find")
453 << QService::SystemScope << QService::UserScope << true;
454}
455
456void tst_QServiceManager::findInterfaces_filter()
457{
458 QFETCH(QByteArray, xml);
459 QFETCH(QServiceFilter, filter);
460 QFETCH(QList<QServiceInterfaceDescriptor>, expectedInterfaces);
461
462 QServiceManager mgr;
463
464 QBuffer buffer(&xml);
465 QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
466
467 QList<QServiceInterfaceDescriptor> result = mgr.findInterfaces(filter);
468
469 qDebug() << "Wanted" << expectedInterfaces;
470
471 qDebug() << "Got" << result;
472
473 QCOMPARE(result.toSet(), expectedInterfaces.toSet());
474}
475
476void tst_QServiceManager::findInterfaces_filter_data()
477{
478 QTest::addColumn<QByteArray>(name: "xml");
479 QTest::addColumn<QServiceFilter>(name: "filter");
480 QTest::addColumn<ServiceInterfaceDescriptorList>(name: "expectedInterfaces");
481
482 QString serviceName = "SomeTestService";
483 DescriptorAttributes attributes;
484 attributes[QServiceInterfaceDescriptor::Location] = m_validPluginNames.first();
485 //attributes[QServiceInterfaceDescriptor::ServiceType] = QService::Plugin;
486
487 QList<QServiceInterfaceDescriptor> descriptors;
488 descriptors << createDescriptor(interfaceName: "com.nokia.qt.TestInterfaceA", major: 1, minor: 0, serviceName, attributes);
489 descriptors << createDescriptor(interfaceName: "com.nokia.qt.TestInterfaceB", major: 1, minor: 0, serviceName, attributes);
490 descriptors << createDescriptor(interfaceName: "com.nokia.qt.TestInterfaceB", major: 2, minor: 0, serviceName, attributes);
491 descriptors << createDescriptor(interfaceName: "com.nokia.qt.TestInterfaceB", major: 2, minor: 3, serviceName, attributes);
492
493 QByteArray serviceXml = createServiceXml(serviceName, descriptors);
494 QServiceFilter filter;
495
496 QTest::newRow(dataTag: "empty/wildcard filter")
497 << serviceXml
498 << QServiceFilter()
499 << descriptors;
500
501 filter = QServiceFilter();
502 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceA");
503 QTest::newRow(dataTag: "by interface name (A)")
504 << serviceXml
505 << filter
506 << descriptors.mid(pos: 0, alength: 1);
507
508 filter = QServiceFilter();
509 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB");
510 QTest::newRow(dataTag: "by interface name (B)")
511 << serviceXml
512 << filter
513 << descriptors.mid(pos: 1);
514
515 filter = QServiceFilter();
516 filter.setServiceName(serviceName);
517 QTest::newRow(dataTag: "by service name, should find all")
518 << serviceXml
519 << filter
520 << descriptors;
521
522 filter = QServiceFilter();
523 filter.setInterface(interfaceName: "com.invalid.interface");
524 QTest::newRow(dataTag: "by non-existing interface name")
525 << serviceXml
526 << filter
527 << ServiceInterfaceDescriptorList();
528
529 filter = QServiceFilter();
530 filter.setServiceName("InvalidServiceName");
531 QTest::newRow(dataTag: "by non-existing service name")
532 << serviceXml
533 << filter
534 << ServiceInterfaceDescriptorList();
535
536 //version lookup testing for existing interface
537 //valid from first version onwards
538 filter = QServiceFilter();
539 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "1.0");
540 QTest::newRow(dataTag: "by version name 1.0 DefaultMatch, should find all B interfaces")
541 << serviceXml
542 << filter
543 << descriptors.mid(pos: 1);
544
545 filter = QServiceFilter();
546 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "1.0", rule: QServiceFilter::MinimumVersionMatch);
547 QTest::newRow(dataTag: "by version name 1.0 MinimumMatch, should find all B interfaces")
548 << serviceXml
549 << filter
550 << descriptors.mid(pos: 1);
551
552 filter = QServiceFilter();
553 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "1.0", rule: QServiceFilter::ExactVersionMatch);
554 QTest::newRow(dataTag: "by version name 1.0 ExactMatch, find B 1.0 only")
555 << serviceXml
556 << filter
557 << descriptors.mid(pos: 1, alength: 1);
558
559 //valid with exact version match
560 filter = QServiceFilter();
561 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "2.0");
562 QTest::newRow(dataTag: "by version name 2.0 DefaultMatch, find B 2.0+")
563 << serviceXml
564 << filter
565 << descriptors.mid(pos: 2);
566
567 filter = QServiceFilter();
568 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "2.0", rule: QServiceFilter::MinimumVersionMatch);
569 QTest::newRow(dataTag: "by version name 2.0 MinimumMatch, find B 2.0+")
570 << serviceXml
571 << filter
572 << descriptors.mid(pos: 2);
573
574 filter = QServiceFilter();
575 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "2.0", rule: QServiceFilter::ExactVersionMatch);
576 QTest::newRow(dataTag: "by version name 2.0 ExactMatch, find B 2.0")
577 << serviceXml
578 << filter
579 << descriptors.mid(pos: 2, alength: 1);
580
581 //valid but not exact version match
582 filter = QServiceFilter();
583 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "1.9");
584 QTest::newRow(dataTag: "by version name 1.9 DefaultMatch, find B 1.9+")
585 << serviceXml
586 << filter
587 << descriptors.mid(pos: 2);
588
589 filter = QServiceFilter();
590 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "1.9", rule: QServiceFilter::MinimumVersionMatch);
591 QTest::newRow(dataTag: "by version name 1.9 MinimumMatch, find B 1.9+")
592 << serviceXml
593 << filter
594 << descriptors.mid(pos: 2);
595
596 filter = QServiceFilter();
597 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "1.9", rule: QServiceFilter::ExactVersionMatch);
598 QTest::newRow(dataTag: "by version name 1.9 ExactMatch")
599 << serviceXml
600 << filter
601 << ServiceInterfaceDescriptorList();
602
603 //version doesn't exist yet
604 filter = QServiceFilter();
605 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "3.9");
606 QTest::newRow(dataTag: "by version name 3.9 DefaultMatch")
607 << serviceXml
608 << filter
609 << ServiceInterfaceDescriptorList();
610
611 filter = QServiceFilter();
612 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "3.9", rule: QServiceFilter::MinimumVersionMatch);
613 QTest::newRow(dataTag: "by version name 3.9 MinimumMatch")
614 << serviceXml
615 << filter
616 << ServiceInterfaceDescriptorList();
617
618 filter = QServiceFilter();
619 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "3.9", rule: QServiceFilter::ExactVersionMatch);
620 QTest::newRow(dataTag: "by version name 3.9 ExactMatch")
621 << serviceXml
622 << filter
623 << ServiceInterfaceDescriptorList();
624
625 //invalid version tag 1 -> match anything
626 filter = QServiceFilter();
627 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "x3.9");
628 QTest::newRow(dataTag: "by version name x3.9 DefaultMatch")
629 << serviceXml<< filter
630 << descriptors;
631
632 filter = QServiceFilter();
633 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "x3.9", rule: QServiceFilter::MinimumVersionMatch);
634 QTest::newRow(dataTag: "by version name x3.9 MinimumMatch")
635 << serviceXml
636 << filter
637 << descriptors;
638
639 filter = QServiceFilter();
640 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "x3.9", rule: QServiceFilter::ExactVersionMatch);
641 QTest::newRow(dataTag: "by version name x3.9 ExactMatch")
642 << serviceXml
643 << filter
644 << descriptors;
645
646 //envalid/empty version tag
647 filter = QServiceFilter();
648 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "");
649 QTest::newRow(dataTag: "by empty version string DefaultMatch")
650 << serviceXml
651 << filter
652 << descriptors.mid(pos: 1);
653
654 filter = QServiceFilter();
655 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "", rule: QServiceFilter::MinimumVersionMatch);
656 QTest::newRow(dataTag: "by empty version string MinimumMatch")
657 << serviceXml
658 << filter
659 << descriptors.mid(pos: 1);
660
661 filter = QServiceFilter();
662 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "", rule: QServiceFilter::ExactVersionMatch); //what's the result of this?
663 QTest::newRow(dataTag: "by empty version string ExactMatch")
664 << serviceXml
665 << filter
666 << descriptors.mid(pos: 1);
667
668 //invalid version tag 2
669 filter = QServiceFilter();
670 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "abc");
671 QTest::newRow(dataTag: "by version name abc DefaultMatch")
672 << serviceXml<< filter
673 << descriptors;
674
675 filter = QServiceFilter();
676 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "abc", rule: QServiceFilter::MinimumVersionMatch);
677 QTest::newRow(dataTag: "by version name abc MinimumMatch")
678 << serviceXml<< filter
679 << descriptors;
680
681 filter = QServiceFilter();
682 filter.setInterface(interfaceName: "com.nokia.qt.TestInterfaceB", version: "abc", rule: QServiceFilter::ExactVersionMatch);
683 QTest::newRow(dataTag: "by version name abc ExactMatch")
684 << serviceXml
685 << filter
686 << descriptors;
687}
688
689void tst_QServiceManager::findInterfaces_scope()
690{
691 QFETCH(QService::Scope, scope_add);
692 QFETCH(QService::Scope, scope_find);
693 QFETCH(bool, expectFound);
694
695 QByteArray xml = createServiceXml(serviceName: "SomeTestService",
696 interfaceXml: createInterfaceXml(name: "com.nokia.qt.TestInterface"), path: m_validPluginNames[0]);
697 QBuffer buffer(&xml);
698
699 QServiceManager mgrUser(QService::UserScope);
700 QServiceManager mgrSystem(QService::SystemScope);
701
702 QServiceManager &mgrAdd = scope_add == QService::UserScope ? mgrUser : mgrSystem;
703 QServiceManager &mgrFind = scope_find == QService::UserScope ? mgrUser : mgrSystem;
704
705 QList<QServiceInterfaceDescriptor> result = mgrFind.findInterfaces(serviceName: QString());
706 QVERIFY(result.isEmpty());
707
708 QVERIFY2(mgrAdd.addService(&buffer), PRINT_ERR(mgrAdd));
709 result = mgrFind.findInterfaces(serviceName: "SomeTestService");
710 QCOMPARE(!result.isEmpty(), expectFound);
711
712 result = mgrFind.findInterfaces(serviceName: QString());
713 if (expectFound)
714 QVERIFY(result.count() == 1);
715 else
716 QVERIFY(result.isEmpty());
717
718 result = mgrFind.findInterfaces(serviceName: "NonExistingService");
719 QVERIFY(result.isEmpty());
720}
721
722void tst_QServiceManager::findInterfaces_scope_data()
723{
724 findServices_scope_data();
725}
726
727
728void tst_QServiceManager::loadInterface_string()
729{
730 // The sampleservice.xml and sampleservice2.xml services in
731 // tests/sampleserviceplugin and tests/sampleserviceplugin2 implement a
732 // common interface, "com.nokia.qt.TestInterfaceA". If both are
733 // registered, loadInterface(QString) should return the correct one
734 // depending on which is set as the default.
735
736 // Real servicenames and classnames
737 QString serviceA = "SampleService";
738 QString serviceAClassName = "SampleServicePluginClass";
739 QString serviceB = "SampleService2";
740 QString serviceBClassName = "SampleServicePluginClass2";
741
742 QObject *obj = 0;
743 QServiceManager mgr;
744 QString commonInterface = "com.nokia.qt.TestInterfaceA";
745
746 // Add first service. Adds the service described in
747 // c/Private/<uid3 of this executable>/plugins/xmldata/sampleservice.xml
748 QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice.xml")), PRINT_ERR(mgr));
749
750 obj = mgr.loadInterface(interfaceName: commonInterface);
751 QVERIFY(obj != 0);
752 QCOMPARE(QString(obj->metaObject()->className()), serviceAClassName);
753 delete obj;
754 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
755 QCoreApplication::processEvents();
756
757 // Add first service. Adds the service described in
758 // c/Private/<uid3 of this executable>/plugins/xmldata/sampleservice2.xml
759 QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice2.xml")), PRINT_ERR(mgr));
760
761 // if first service is set as default, it should be returned
762 QVERIFY(mgr.setInterfaceDefault(serviceA, commonInterface));
763 obj = mgr.loadInterface(interfaceName: commonInterface);
764 QVERIFY(obj != 0);
765 QCOMPARE(QString(obj->metaObject()->className()), serviceAClassName);
766 delete obj;
767 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
768 QCoreApplication::processEvents();
769
770 // if second service is set as default, it should be returned
771 QVERIFY(mgr.setInterfaceDefault(serviceB, commonInterface));
772 obj = mgr.loadInterface(interfaceName: commonInterface);
773 QVERIFY(obj != 0);
774 QCOMPARE(QString(obj->metaObject()->className()), serviceBClassName);
775 delete obj;
776 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
777 QCoreApplication::processEvents();
778}
779
780void tst_QServiceManager::loadInterface_descriptor()
781{
782 QFETCH(QServiceInterfaceDescriptor, descriptor);
783 QFETCH(QString, className);
784
785 QObject* obj;
786 {
787 QServiceManager mgr;
788 obj = mgr.loadInterface(descriptor);
789 QVERIFY(obj != 0);
790 QCOMPARE(QString::fromLatin1(obj->metaObject()->className()), className);
791 }
792
793 QVERIFY(obj != 0);
794
795 delete obj;
796 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
797 QCoreApplication::processEvents();
798}
799
800void tst_QServiceManager::loadInterface_descriptor_data()
801{
802 QTest::addColumn<QServiceInterfaceDescriptor>(name: "descriptor");
803 QTest::addColumn<QString>(name: "className");
804
805 for (int i = 0; i < m_validPluginNames.size(); ++i) {
806 if (const char *expectedClassName = expectedPluginClassNames[i]) {
807 QServiceInterfaceDescriptor descriptor;
808 QServiceInterfaceDescriptorPrivate *priv = new QServiceInterfaceDescriptorPrivate;
809 priv->interfaceName = "com.nokia.qt.TestInterfaceA"; // needed by service plugin implementation
810 priv->attributes[QServiceInterfaceDescriptor::Location] = m_validPluginPaths.at(i);
811 QServiceInterfaceDescriptorPrivate::setPrivate(descriptor: &descriptor, p: priv);
812 QTest::newRow(qPrintable(m_validPluginNames.at(i)))
813 << descriptor
814 << QString(QLatin1String(expectedClassName));
815 }
816 }
817}
818
819void tst_QServiceManager::loadInterface_testLoadedObjectAttributes()
820{
821 QServiceInterfaceDescriptor descriptor;
822 QServiceInterfaceDescriptorPrivate *priv = new QServiceInterfaceDescriptorPrivate;
823 priv->interfaceName = "com.nokia.qt.TestInterfaceA"; // needed by service plugin implementation
824 priv->attributes[QServiceInterfaceDescriptor::Location] = m_validPluginPaths.at(i: 2);
825
826 QServiceInterfaceDescriptorPrivate::setPrivate(descriptor: &descriptor, p: priv);
827
828 QServiceManager mgr;
829 QObject *obj = mgr.loadInterface(descriptor);
830 QVERIFY(obj != 0);
831
832 bool invokeOk = false;
833 QString name;
834
835 // check attributes
836 QMetaProperty nameProperty = obj->metaObject()->property(index: obj->metaObject()->indexOfProperty(name: "name"));
837 QVERIFY(nameProperty.isValid());
838 QVERIFY(nameProperty.write(obj, "A service name"));
839 QCOMPARE(nameProperty.read(obj), QVariant("A service name"));
840
841 // check signals
842 QVERIFY(obj->metaObject()->indexOfSignal("someSignal()") >= 0);
843 QSignalSpy spy(obj, SIGNAL(someSignal()));
844 invokeOk = QMetaObject::invokeMethod(obj, member: "someSignal");
845 QVERIFY(invokeOk);
846 QVERIFY(spy.count() == 1);
847
848 // check slots
849 invokeOk = QMetaObject::invokeMethod(obj, member: "callSlot");
850 QVERIFY(invokeOk);
851 invokeOk = QMetaObject::invokeMethod(obj, member: "callSlotAndSetName", Q_ARG(QString, "test string"));
852 QVERIFY(invokeOk);
853 invokeOk = QMetaObject::invokeMethod(obj, member: "callSlotAndReturnName", Q_RETURN_ARG(QString, name));
854 QVERIFY(invokeOk);
855 QCOMPARE(name, QString("test string"));
856
857 // check invokables
858 invokeOk = QMetaObject::invokeMethod(obj, member: "callInvokable");
859 QVERIFY(invokeOk);
860
861 // call method on a returned object
862 QObject *embeddedObj = 0;
863 int value = 0;
864 invokeOk = QMetaObject::invokeMethod(obj, member: "embeddedTestService", Q_RETURN_ARG(QObject*, embeddedObj));
865 QVERIFY(invokeOk);
866 invokeOk = QMetaObject::invokeMethod(obj: embeddedObj, member: "callWithInt", Q_RETURN_ARG(int, value), Q_ARG(int, 10));
867 QVERIFY(invokeOk);
868 QCOMPARE(value, 10);
869
870 // call a method that is not invokable via meta system
871 invokeOk = QMetaObject::invokeMethod(obj: embeddedObj, member: "callNormalMethod");
872 QVERIFY(!invokeOk);
873
874 delete obj;
875 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
876 QCoreApplication::processEvents();
877}
878
879void tst_QServiceManager::loadLocalTypedInterface()
880{
881 QServiceManager mgr;
882
883 QServiceInterfaceDescriptor descriptor;
884 QServiceInterfaceDescriptorPrivate *priv = new QServiceInterfaceDescriptorPrivate;
885 priv->interfaceName = "com.nokia.qt.TestInterfaceA"; // needed by service plugin implementation
886 priv->attributes[QServiceInterfaceDescriptor::Location] = m_validPluginPaths.at(i: 0);
887 QServiceInterfaceDescriptorPrivate::setPrivate(descriptor: &descriptor, p: priv);
888
889 //use manual descriptor -> avoid database involvement
890 SampleServicePluginClass *plugin = 0;
891 plugin = mgr.loadLocalTypedInterface<SampleServicePluginClass>(descriptor);
892
893 QVERIFY(plugin != 0);
894
895 delete plugin;
896 plugin = 0;
897 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
898 QCoreApplication::processEvents();
899
900 //use database descriptor
901 QFile file1(xmlTestDataPath(xmlFileName: "sampleservice.xml"));
902 QVERIFY2(file1.exists(), qPrintable(QString("%1: %2").arg(xmlTestDataPath("sampleservice.xml")).arg(file1.errorString()) ));
903 QVERIFY2(mgr.addService(&file1), PRINT_ERR(mgr));
904
905 QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceA"), QStringList("SampleService"));
906 QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceB"), QStringList("SampleService"));
907 QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceC"), QStringList("SampleService"));
908 QList<QServiceInterfaceDescriptor> ifaces = mgr.findInterfaces(serviceName: "SampleService");
909 QList<SampleServicePluginClass*> serviceObjects;
910 QVERIFY(ifaces.count() == 3);
911 for (int i = 0; i<ifaces.count(); i++) {
912 plugin = mgr.loadLocalTypedInterface<SampleServicePluginClass>(descriptor: ifaces.at(i));
913
914 if (ifaces.at(i).interfaceName() == "com.nokia.qt.TestInterfaceC") {
915 QVERIFY(plugin == 0);
916 } else {
917 QVERIFY(plugin != 0);
918 plugin->testSlotOne();
919 serviceObjects.append(t: plugin);
920 }
921 }
922
923 //test for a bug where two service instances from same plugin
924 //caused a crash when the first instance was deleted and
925 //the second instance called
926 QVERIFY(serviceObjects.count() == 2);
927 delete serviceObjects.takeFirst();
928 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
929 QCoreApplication::processEvents();
930
931 plugin = serviceObjects.takeFirst();
932 plugin->testSlotOne();
933 delete plugin;
934 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
935 QCoreApplication::processEvents();
936
937
938 //use default lookup
939 plugin = mgr.loadLocalTypedInterface<SampleServicePluginClass>(interfaceName: "com.nokia.qt.TestInterfaceA");
940 QVERIFY(plugin != 0);
941
942 delete plugin;
943 QCoreApplication::sendPostedEvents(receiver: 0, event_type: QEvent::DeferredDelete);
944 QCoreApplication::processEvents();
945 plugin = 0;
946
947 //use totally wrong but QObject based template class type
948 QFile *w = mgr.loadLocalTypedInterface<QFile>(interfaceName: "com.nokia.qt.TestInterfaceA");
949 QVERIFY(!w);
950
951 //use non QObject based template class type
952 //doesn't compile and should never compile
953 //QString* s = mgr.loadLocalTypedInterface<QString>("com.nokia.qt.TestInterfaceA", &context, &session);
954 //QVERIFY(!s);
955}
956
957#define TST_QSERVICEMANAGER_ADD_SERVICE(paramType, file) { \
958 if (paramType == "QString") \
959 QVERIFY2(mgr.addService(file->fileName()), PRINT_ERR(mgr)); \
960 else if (paramType == "QIODevice") \
961 QVERIFY2(mgr.addService(file), PRINT_ERR(mgr)); \
962 else \
963 QFAIL("tst_QServiceManager::addService(): Bad test parameter"); \
964}
965
966void tst_QServiceManager::addService()
967{
968 QFETCH(QString, paramType);
969
970 QServiceManager mgr;
971
972 QString commonInterface = "com.qt.serviceframework.tests.CommonInterface";
973 QByteArray xmlA = createServiceXml(serviceName: "ServiceA", interfaceXml: createInterfaceXml(name: commonInterface), path: m_validPluginNames[0]);
974 QByteArray xmlB = createServiceXml(serviceName: "ServiceB", interfaceXml: createInterfaceXml(name: commonInterface), path: m_validPluginNames[1]);
975
976 QTemporaryFile *tempFileA = new QTemporaryFile(this);
977 QVERIFY2(tempFileA->open(), "Can't open temp file A");
978 tempFileA->write(data: xmlA);
979 tempFileA->seek(offset: 0);
980 QTemporaryFile *tempFileB = new QTemporaryFile(this);
981 QVERIFY2(tempFileB->open(), "Can't open temp file B");
982 tempFileB->write(data: xmlB);
983 tempFileB->seek(offset: 0);
984
985 TST_QSERVICEMANAGER_ADD_SERVICE(paramType, tempFileA);
986 QCOMPARE(mgr.findServices(), QStringList("ServiceA"));
987
988 // the service should be automatically set as the default for its
989 // implemented interfaces since it was the first service added for them
990 QCOMPARE(mgr.interfaceDefault(commonInterface).serviceName(), QString("ServiceA"));
991 QCOMPARE(mgr.interfaceDefault(commonInterface).serviceName(), QString("ServiceA"));
992
993 // add second service
994 TST_QSERVICEMANAGER_ADD_SERVICE(paramType, tempFileB);
995 QStringList result = mgr.findServices();
996 QCOMPARE(result.count(), 2);
997 QVERIFY(result.contains("ServiceA"));
998 QVERIFY(result.contains("ServiceB"));
999
1000 // the default does not change once ServiceB is added
1001 QCOMPARE(mgr.interfaceDefault(commonInterface).serviceName(), QString("ServiceA"));
1002 QCOMPARE(mgr.interfaceDefault(commonInterface).serviceName(), QString("ServiceA"));
1003
1004 delete tempFileA;
1005 delete tempFileB;
1006}
1007
1008void tst_QServiceManager::addService_data()
1009{
1010 QTest::addColumn<QString>(name: "paramType");
1011
1012 QTest::newRow(dataTag: "string") << "QString";
1013 QTest::newRow(dataTag: "iodevice") << "QIODevice";
1014}
1015
1016void tst_QServiceManager::addService_testInvalidServiceXml()
1017{
1018 QBuffer buffer;
1019 QServiceManager mgr;
1020
1021 QVERIFY2(!mgr.addService(&buffer), PRINT_ERR(mgr));
1022
1023 // a service with no interfaces
1024 QString xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
1025 xml += "<service><name>SomeService</name><filepath>" + m_validPluginNames.first() + "</filepath>\n";
1026 xml += "</service>\n";
1027 buffer.close();
1028 buffer.setData(xml.toLatin1());
1029 QVERIFY(!mgr.addService(&buffer));
1030
1031 QVERIFY2(mgr.findServices().isEmpty(), PRINT_ERR(mgr));
1032}
1033
1034void tst_QServiceManager::addService_testPluginLoading()
1035{
1036 QFETCH(QString, pluginPath);
1037 QFETCH(bool, isAdded);
1038
1039 QServiceManager mgr;
1040
1041 QByteArray xml = createServiceXml(serviceName: "SomeService", interfaceXml: createInterfaceXml(name: "com.qt.serviceframework.Interface"), path: pluginPath);
1042 QBuffer buffer(&xml);
1043 QVERIFY2(mgr.addService(&buffer) == isAdded, PRINT_ERR(mgr));
1044
1045 // the service should not be added if the service plugin cannot be loaded
1046 if (!isAdded)
1047 QVERIFY(mgr.findServices().isEmpty());
1048}
1049
1050void tst_QServiceManager::addService_testPluginLoading_data()
1051{
1052 QTest::addColumn<QString>(name: "pluginPath");
1053 QTest::addColumn<bool>(name: "isAdded");
1054
1055 QTest::newRow(dataTag: "valid path") << m_validPluginNames.first() << true;
1056 QTest::newRow(dataTag: "invalid path") << "no_such_plugin" << false;
1057}
1058
1059void tst_QServiceManager::addService_testInstallService()
1060{
1061 QSettings settings("com.nokia.qt.serviceframework.tests", "SampleServicePlugin");
1062 QCOMPARE(settings.value("installed").toBool(), false);
1063
1064 QServiceManager mgr;
1065 QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice.xml")), PRINT_ERR(mgr));
1066 QCOMPARE(mgr.findServices(), QStringList("SampleService"));
1067
1068 // test installService() was called on the plugin
1069 QCOMPARE(settings.value("installed").toBool(), true);
1070}
1071
1072void tst_QServiceManager::removeService()
1073{
1074 QServiceManager mgr;
1075
1076 QVERIFY(!mgr.removeService("NonExistentService"));
1077
1078 QSettings settings("com.nokia.qt.serviceframework.tests", "SampleServicePlugin");
1079 QCOMPARE(settings.value("installed").toBool(), false);
1080
1081 qDebug() << "open" << xmlTestDataPath(xmlFileName: "sampleservice.xml");
1082 QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice.xml")), PRINT_ERR(mgr));
1083 QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceA"), QStringList("SampleService"));
1084 QCOMPARE(settings.value("installed").toBool(), true);
1085
1086 QVERIFY(mgr.removeService("SampleService"));
1087 QVERIFY(mgr.findServices().isEmpty());
1088 QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceA"), QStringList());
1089 QCOMPARE(settings.value("installed").toBool(), false);
1090
1091 // add it again, should still work
1092 QVERIFY2(mgr.addService(xmlTestDataPath("sampleservice.xml")), PRINT_ERR(mgr));
1093 QCOMPARE(mgr.findServices("com.nokia.qt.TestInterfaceA"), QStringList("SampleService"));
1094 QCOMPARE(settings.value("installed").toBool(), true);
1095}
1096
1097void tst_QServiceManager::setInterfaceDefault_strings()
1098{
1099 QServiceManager mgr;
1100 QString interfaceName = "com.nokia.qt.serviceframework.tests.AnInterface";
1101 DescriptorAttributes attributes;
1102 QServiceInterfaceDescriptor descriptor;
1103 QByteArray xml;
1104
1105 attributes[QServiceInterfaceDescriptor::Location] = m_validPluginNames[0];
1106 descriptor = createDescriptor(interfaceName, major: 1, minor: 0, serviceName: "ServiceA", attributes);
1107 xml = createServiceXml(serviceName: "ServiceA",
1108 interfaceXml: createInterfaceXml(descriptors: QList<QServiceInterfaceDescriptor>() << descriptor),
1109 path: attributes[QServiceInterfaceDescriptor::Location].toString());
1110 QBuffer buffer(&xml);
1111
1112 // fails if the specified interface hasn't been registered
1113 QCOMPARE(mgr.setInterfaceDefault("ServiceA", interfaceName), false);
1114
1115 // now it works
1116 QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
1117 QCOMPARE(mgr.setInterfaceDefault("ServiceA", interfaceName), true);
1118 QCOMPARE(mgr.interfaceDefault(interfaceName), descriptor);
1119
1120 // replace the default with another service
1121 attributes[QServiceInterfaceDescriptor::Location] = m_validPluginNames[1];
1122 descriptor = createDescriptor(interfaceName, major: 1, minor: 0, serviceName: "ServiceB", attributes);
1123 xml = createServiceXml(serviceName: "ServiceB",
1124 interfaceXml: createInterfaceXml(descriptors: QList<QServiceInterfaceDescriptor>() << descriptor),
1125 path: attributes[QServiceInterfaceDescriptor::Location].toString());
1126 buffer.close();
1127 buffer.setData(xml);
1128 QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
1129 QCOMPARE(mgr.setInterfaceDefault("ServiceB", interfaceName), true);
1130 QCOMPARE(mgr.interfaceDefault(interfaceName), descriptor);
1131
1132 // bad arguments
1133 QCOMPARE(mgr.setInterfaceDefault("", ""), false);
1134 QCOMPARE(mgr.setInterfaceDefault("blah", "blah"), false);
1135 QCOMPARE(mgr.setInterfaceDefault("SampleService", ""), false);
1136}
1137
1138void tst_QServiceManager::setInterfaceDefault_strings_multipleInterfaces()
1139{
1140 QServiceManager mgr;
1141 QString interfaceName = "com.nokia.qt.serviceframework.tests.AnInterface";
1142 DescriptorAttributes attributes;
1143 QServiceInterfaceDescriptor descriptor;
1144 QByteArray xml;
1145
1146 // if there are multiple interfaces, the default should be the latest version
1147 attributes[QServiceInterfaceDescriptor::Location] = m_validPluginNames[0];
1148 QList<QServiceInterfaceDescriptor> descriptorList;
1149 descriptorList << createDescriptor(interfaceName, major: 1, minor: 0, serviceName: "ServiceC", attributes)
1150 << createDescriptor(interfaceName, major: 1, minor: 8, serviceName: "ServiceC", attributes)
1151 << createDescriptor(interfaceName, major: 1, minor: 3, serviceName: "ServiceC", attributes);
1152 xml = createServiceXml(serviceName: "ServiceC", interfaceXml: createInterfaceXml(descriptors: descriptorList),
1153 path: attributes[QServiceInterfaceDescriptor::Location].toString());
1154 QBuffer buffer(&xml);
1155 QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
1156 QCOMPARE(mgr.setInterfaceDefault("ServiceC", interfaceName), true);
1157 QCOMPARE(mgr.interfaceDefault(interfaceName), descriptorList[1]);
1158}
1159
1160void tst_QServiceManager::setInterfaceDefault_descriptor()
1161{
1162 QFETCH(QService::Scope, scope_add);
1163 QFETCH(QService::Scope, scope_find);
1164 QFETCH(bool, expectFound);
1165
1166 QServiceManager mgr(scope_add);
1167 QServiceInterfaceDescriptor desc;
1168
1169 QString interfaceName = "com.nokia.qt.serviceframework.TestInterface";
1170 DescriptorAttributes attributes;
1171 attributes[QServiceInterfaceDescriptor::Location] = m_validPluginNames.first();
1172
1173 QCOMPARE(mgr.setInterfaceDefault(desc), false);
1174
1175 desc = createDescriptor(interfaceName, major: 1, minor: 0, serviceName: "SomeService", attributes,
1176 scope: scope_add);
1177
1178 // fails if the specified interface hasn't been registered
1179 QCOMPARE(mgr.setInterfaceDefault(desc), false);
1180
1181 // now it works
1182 QByteArray xml = createServiceXml(serviceName: "SomeService",
1183 interfaceXml: createInterfaceXml(descriptors: QList<QServiceInterfaceDescriptor>() << desc), path: m_validPluginNames.first());
1184 QBuffer buffer(&xml);
1185 QVERIFY2(mgr.addService(&buffer), PRINT_ERR(mgr));
1186 QCOMPARE(mgr.setInterfaceDefault(desc), true);
1187
1188 QCOMPARE(mgr.interfaceDefault(interfaceName), desc);
1189
1190 QServiceManager mgrWithOtherScope(scope_find);
1191 QCOMPARE(mgrWithOtherScope.interfaceDefault(interfaceName).isValid(), expectFound);
1192}
1193
1194void tst_QServiceManager::setInterfaceDefault_descriptor_data()
1195{
1196 QTest::addColumn<QService::Scope>(name: "scope_add");
1197 QTest::addColumn<QService::Scope>(name: "scope_find");
1198 QTest::addColumn<bool>(name: "expectFound");
1199
1200 QTest::newRow(dataTag: "user scope")
1201 << QService::UserScope << QService::UserScope << true;
1202 QTest::newRow(dataTag: "system scope")
1203 << QService::SystemScope << QService::SystemScope << true;
1204
1205 QTest::newRow(dataTag: "user scope - add, system scope - find")
1206 << QService::UserScope << QService::SystemScope << false;
1207 QTest::newRow(dataTag: "system scope - add, user scope - find")
1208 << QService::SystemScope << QService::UserScope << true;
1209}
1210
1211void tst_QServiceManager::interfaceDefault()
1212{
1213 QServiceManager mgr;
1214 QVERIFY(!mgr.interfaceDefault("").isValid());
1215}
1216
1217void tst_QServiceManager::serviceAdded()
1218{
1219 QFETCH(QByteArray, xml);
1220 QFETCH(QString, serviceName);
1221 QFETCH(QService::Scope, scope_modify);
1222 QFETCH(QService::Scope, scope_listen);
1223 QFETCH(bool, expectSignal);
1224
1225 QBuffer buffer;
1226 buffer.setData(xml);
1227 QServiceManager mgr_modify(scope_modify);
1228 QServiceManager mgr_listen(scope_listen);
1229
1230 // ensure mgr.connectNotify() is called
1231 ServicesListener *listener = new ServicesListener;
1232 connect(sender: &mgr_listen, SIGNAL(serviceAdded(QString,QService::Scope)),
1233 receiver: listener, SLOT(serviceAdded(QString,QService::Scope)));
1234
1235 QSignalSpy spyAdd(&mgr_listen, SIGNAL(serviceAdded(QString,QService::Scope)));
1236 QVERIFY2(mgr_modify.addService(&buffer), PRINT_ERR(mgr_modify));
1237
1238 if (!expectSignal) {
1239 QTest::qWait(ms: 2000);
1240 QCOMPARE(spyAdd.count(), 0);
1241 } else {
1242 QTRY_COMPARE(spyAdd.count(), 1);
1243 }
1244
1245 if (expectSignal) {
1246 QCOMPARE(spyAdd.at(0).at(0).toString(), serviceName);
1247 QCOMPARE( listener->params.at(0).second , scope_modify);
1248 }
1249 listener->params.clear();
1250
1251 // Pause between file changes so they are detected separately
1252 QTest::qWait(ms: 2000);
1253
1254 QSignalSpy spyRemove(&mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)));
1255 QVERIFY(mgr_modify.removeService(serviceName));
1256
1257 if (!expectSignal) {
1258 QTest::qWait(ms: 2000);
1259 QCOMPARE(spyRemove.count(), 0);
1260 } else {
1261 QTRY_COMPARE(spyRemove.count(), 1);
1262 }
1263
1264#if !defined (Q_OS_WIN)
1265 // on win, cannot delete the database while it is in use
1266 // try it again after deleting the database
1267 deleteTestDatabasesAndWaitUntilDone();
1268#else
1269 // Pause between file changes so they are detected separately
1270 QTest::qWait(2000);
1271#endif
1272
1273 spyAdd.clear();
1274 buffer.seek(off: 0);
1275 QVERIFY2(mgr_modify.addService(&buffer), PRINT_ERR(mgr_modify));
1276 if (!expectSignal) {
1277 QTest::qWait(ms: 2000);
1278 QCOMPARE(spyAdd.count(), 0);
1279 } else {
1280 QTRY_COMPARE(spyAdd.count(), 1);
1281 }
1282 if (expectSignal) {
1283 QCOMPARE(spyAdd.at(0).at(0).toString(), serviceName);
1284 QCOMPARE(listener->params.at(0).second, scope_modify);
1285 }
1286
1287 // ensure mgr.disconnectNotify() is called
1288 disconnect(sender: &mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)),
1289 receiver: listener, SLOT(serviceRemoved(QString,QService::Scope)));
1290
1291 delete listener;
1292}
1293
1294void tst_QServiceManager::serviceAdded_data()
1295{
1296 QTest::addColumn<QByteArray>(name: "xml");
1297 QTest::addColumn<QString>(name: "serviceName");
1298 QTest::addColumn<QService::Scope>(name: "scope_modify");
1299 QTest::addColumn<QService::Scope>(name: "scope_listen");
1300 QTest::addColumn<bool>(name: "expectSignal");
1301
1302 QFile file1(xmlTestDataPath(xmlFileName: "sampleservice.xml"));
1303 QVERIFY(file1.open(QIODevice::ReadOnly));
1304 QFile file2(xmlTestDataPath(xmlFileName: "testserviceplugin.xml"));
1305 QVERIFY(file2.open(QIODevice::ReadOnly));
1306
1307 QByteArray file1Data = file1.readAll();
1308
1309 QTest::newRow(dataTag: "SampleService, user scope") << file1Data << "SampleService"
1310 << QService::UserScope << QService::UserScope << true;
1311 QTest::newRow(dataTag: "TestService, user scope") << file2.readAll() << "TestService"
1312 << QService::UserScope << QService::UserScope << true;
1313
1314 QTest::newRow(dataTag: "system scope") << file1Data << "SampleService"
1315 << QService::SystemScope << QService::SystemScope << true;
1316 QTest::newRow(dataTag: "modify as user, listen in system") << file1Data << "SampleService"
1317 << QService::UserScope << QService::SystemScope << false;
1318 QTest::newRow(dataTag: "modify as system, listen in user") << file1Data << "SampleService"
1319 << QService::SystemScope << QService::UserScope << true;
1320}
1321
1322void tst_QServiceManager::serviceRemoved()
1323{
1324 QFETCH(QByteArray, xml);
1325 QFETCH(QString, serviceName);
1326 QFETCH(QService::Scope, scope_modify);
1327 QFETCH(QService::Scope, scope_listen);
1328 QFETCH(bool, expectSignal);
1329
1330 QBuffer buffer;
1331 buffer.setData(xml);
1332 QServiceManager mgr_modify(scope_modify);
1333 QServiceManager mgr_verify(scope_listen);
1334
1335 // ensure mgr.connectNotify() is called
1336 ServicesListener *listenerVerify = new ServicesListener;
1337 connect(sender: &mgr_verify, SIGNAL(serviceAdded(QString,QService::Scope)),
1338 receiver: listenerVerify, SLOT(serviceAdded(QString,QService::Scope)));
1339
1340 QSignalSpy spyAddMod(&mgr_verify, SIGNAL(serviceAdded(QString,QService::Scope)));
1341 QVERIFY2(mgr_modify.addService(&buffer), PRINT_ERR(mgr_modify));
1342
1343 if (!expectSignal) {
1344 QTest::qWait(ms: 2000);
1345 QCOMPARE(spyAddMod.count(), 0);
1346 } else {
1347 QTRY_COMPARE(spyAddMod.count(), 1);
1348 }
1349
1350 // Pause between file changes so they are detected separately
1351 QTest::qWait(ms: 2000);
1352
1353 QServiceManager mgr_listen(scope_listen);
1354 QSignalSpy spyAdd(&mgr_listen, SIGNAL(serviceAdded(QString,QService::Scope)));
1355
1356 // ensure mgr.connectNotify() is called
1357 ServicesListener *listener = new ServicesListener;
1358 connect(sender: &mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)),
1359 receiver: listener, SLOT(serviceRemoved(QString,QService::Scope)));
1360
1361 QSignalSpy spyRemove(&mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)));
1362 QVERIFY(mgr_modify.removeService(serviceName));
1363
1364 if (!expectSignal) {
1365 QTest::qWait(ms: 2000);
1366 QCOMPARE(spyRemove.count(), 0);
1367 } else {
1368 QTRY_COMPARE(spyRemove.count(), 1);
1369 }
1370 if (expectSignal) {
1371 QCOMPARE(spyRemove.at(0).at(0).toString(), serviceName);
1372 QCOMPARE(listener->params.at(0).second , scope_modify);
1373 }
1374 listener->params.clear();
1375
1376#if !defined (Q_OS_WIN)
1377 // on win, cannot delete the database while it is in use
1378 // try it again after deleting the database
1379 deleteTestDatabasesAndWaitUntilDone();
1380#else
1381 // Pause between file changes so they are detected separately
1382 QTest::qWait(2000);
1383#endif
1384 spyAdd.clear();
1385 buffer.seek(off: 0);
1386 QVERIFY2(mgr_modify.addService(&buffer), PRINT_ERR(mgr_modify));
1387 if (!expectSignal) {
1388 QTest::qWait(ms: 2000);
1389 QCOMPARE(spyAdd.count(), 0);
1390 } else {
1391 QTRY_COMPARE(spyAdd.count(), 1);
1392 }
1393
1394 spyRemove.clear();
1395
1396 // Pause between file changes so they are detected separately
1397 QTest::qWait(ms: 2000);
1398
1399 QVERIFY(mgr_modify.removeService(serviceName));
1400 if (!expectSignal) {
1401 QTest::qWait(ms: 2000);
1402 QCOMPARE(spyRemove.count(), 0);
1403 } else {
1404 QTRY_COMPARE(spyRemove.count(), 1);
1405 }
1406 if (expectSignal) {
1407 QCOMPARE(spyRemove.at(0).at(0).toString(), serviceName);
1408 QCOMPARE(listener->params.at(0).second , scope_modify);
1409 }
1410
1411 // ensure mgr.disconnectNotify() is called
1412 disconnect(sender: &mgr_listen, SIGNAL(serviceRemoved(QString,QService::Scope)),
1413 receiver: listener, SLOT(serviceRemoved(QString,QService::Scope)));
1414 disconnect(sender: &mgr_verify, SIGNAL(serviceRemoved(QString,QService::Scope)),
1415 receiver: listenerVerify, SLOT(serviceRemoved(QString,QService::Scope)));
1416
1417
1418 delete listener;
1419 delete listenerVerify;
1420}
1421
1422void tst_QServiceManager::serviceRemoved_data()
1423{
1424 serviceAdded_data();
1425}
1426
1427QTEST_MAIN(tst_QServiceManager)
1428
1429#include "tst_qservicemanager.moc"
1430

source code of qtsystems/tests/auto/serviceframework/qservicemanager/tst_qservicemanager.cpp