QDBusServiceWatcher namespace prefix support

This allows a user to efficiently watch for services with a common
domain prefix.

This is exposed in the API via a wildcard character in the service name.

For example creating a watcher on "org.mpris*" will match
"org.mpris.foo" "org.mpris.bar" and "org.mpris" itself. It will not
match org.mprisasdf.

Internally the argument match rules have been expanded from a single
QStringList to a struct containing args and arg0namespace. This was done
so that we can easily use argpath in match rules in the future.

Change-Id: I55882ab603cc6ba478e8c0ea9a6800f6e483a50c
Reviewed-by: Kai Uwe Broulik <kde@privat.broulik.de>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
David Edmundson 2018-04-06 01:27:32 +01:00 committed by David Faure
parent fc88dd52a4
commit d761c62783
4 changed files with 194 additions and 63 deletions

View File

@ -121,6 +121,15 @@ public:
QSocketNotifier *write; QSocketNotifier *write;
}; };
struct ArgMatchRules {
QStringList args;
QString arg0namespace;
bool operator==(const ArgMatchRules &other) const {
return args == other.args &&
arg0namespace == other.arg0namespace;
}
};
struct SignalHook struct SignalHook
{ {
inline SignalHook() : obj(0), midx(-1) { } inline SignalHook() : obj(0), midx(-1) { }
@ -128,7 +137,7 @@ public:
QObject* obj; QObject* obj;
int midx; int midx;
QVector<int> params; QVector<int> params;
QStringList argumentMatch; ArgMatchRules argumentMatch;
QByteArray matchRule; QByteArray matchRule;
}; };
@ -207,12 +216,19 @@ public:
QDBusMessage sendWithReplyLocal(const QDBusMessage &message); QDBusMessage sendWithReplyLocal(const QDBusMessage &message);
QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, QObject *receiver,
const char *returnMethod, const char *errorMethod,int timeout = -1); const char *returnMethod, const char *errorMethod,int timeout = -1);
bool connectSignal(const QString &service, const QString &path, const QString& interface, bool connectSignal(const QString &service, const QString &path, const QString& interface,
const QString &name, const QStringList &argumentMatch, const QString &signature, const QString &name, const QStringList &argumentMatch, const QString &signature,
QObject *receiver, const char *slot); QObject *receiver, const char *slot);
bool disconnectSignal(const QString &service, const QString &path, const QString& interface, bool disconnectSignal(const QString &service, const QString &path, const QString& interface,
const QString &name, const QStringList &argumentMatch, const QString &signature, const QString &name, const QStringList &argumentMatch, const QString &signature,
QObject *receiver, const char *slot); QObject *receiver, const char *slot);
bool connectSignal(const QString &service, const QString &path, const QString& interface,
const QString &name, const ArgMatchRules &argumentMatch, const QString &signature,
QObject *receiver, const char *slot);
bool disconnectSignal(const QString &service, const QString &path, const QString& interface,
const QString &name, const ArgMatchRules &argumentMatch, const QString &signature,
QObject *receiver, const char *slot);
void registerObject(const ObjectTreeNode *node); void registerObject(const ObjectTreeNode *node);
void unregisterObject(const QString &path, QDBusConnection::UnregisterMode mode); void unregisterObject(const QString &path, QDBusConnection::UnregisterMode mode);
void connectRelay(const QString &service, void connectRelay(const QString &service,
@ -332,7 +348,7 @@ public:
static bool prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key, static bool prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
const QString &service, const QString &service,
const QString &path, const QString &interface, const QString &name, const QString &path, const QString &interface, const QString &name,
const QStringList &argMatch, const ArgMatchRules &argMatch,
QObject *receiver, const char *signal, int minMIdx, QObject *receiver, const char *signal, int minMIdx,
bool buildSignature); bool buildSignature);
static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *); static DBusHandlerResult messageFilter(DBusConnection *, DBusMessage *, void *);

View File

@ -338,7 +338,7 @@ void QDBusConnectionPrivate::_q_newConnection(QDBusConnectionPrivate *newConnect
static QByteArray buildMatchRule(const QString &service, static QByteArray buildMatchRule(const QString &service,
const QString &objectPath, const QString &interface, const QString &objectPath, const QString &interface,
const QString &member, const QStringList &argMatch, const QString & /*signature*/) const QString &member, const QDBusConnectionPrivate::ArgMatchRules &argMatch, const QString & /*signature*/)
{ {
QString result = QLatin1String("type='signal',"); QString result = QLatin1String("type='signal',");
QString keyValue = QLatin1String("%1='%2',"); QString keyValue = QLatin1String("%1='%2',");
@ -353,11 +353,14 @@ static QByteArray buildMatchRule(const QString &service,
result += keyValue.arg(QLatin1String("member"), member); result += keyValue.arg(QLatin1String("member"), member);
// add the argument string-matching now // add the argument string-matching now
if (!argMatch.isEmpty()) { if (!argMatch.args.isEmpty()) {
keyValue = QLatin1String("arg%1='%2',"); keyValue = QLatin1String("arg%1='%2',");
for (int i = 0; i < argMatch.count(); ++i) for (int i = 0; i < argMatch.args.count(); ++i)
if (!argMatch.at(i).isNull()) if (!argMatch.args.at(i).isNull())
result += keyValue.arg(i).arg(argMatch.at(i)); result += keyValue.arg(i).arg(argMatch.args.at(i));
}
if (!argMatch.arg0namespace.isEmpty()) {
result += QStringLiteral("arg0namespace='%1',").arg(argMatch.arg0namespace);
} }
result.chop(1); // remove ending comma result.chop(1); // remove ending comma
@ -456,21 +459,26 @@ static QObject *findChildObject(const QDBusConnectionPrivate::ObjectTreeNode *ro
return 0; return 0;
} }
static QStringList matchArgsForService(const QString &service, QDBusServiceWatcher::WatchMode mode) static QDBusConnectionPrivate::ArgMatchRules matchArgsForService(const QString &service, QDBusServiceWatcher::WatchMode mode)
{ {
QStringList matchArgs; QDBusConnectionPrivate::ArgMatchRules matchArgs;
matchArgs << service; if (service.endsWith(QLatin1Char('*'))) {
matchArgs.arg0namespace = service.chopped(1);
matchArgs.args << QString();
}
else
matchArgs.args << service;
switch (mode) { switch (mode) {
case QDBusServiceWatcher::WatchForOwnerChange: case QDBusServiceWatcher::WatchForOwnerChange:
break; break;
case QDBusServiceWatcher::WatchForRegistration: case QDBusServiceWatcher::WatchForRegistration:
matchArgs << QString::fromLatin1("", 0); matchArgs.args << QString::fromLatin1("", 0);
break; break;
case QDBusServiceWatcher::WatchForUnregistration: case QDBusServiceWatcher::WatchForUnregistration:
matchArgs << QString() << QString::fromLatin1("", 0); matchArgs.args << QString() << QString::fromLatin1("", 0);
break; break;
} }
return matchArgs; return matchArgs;
@ -1310,7 +1318,7 @@ int QDBusConnectionPrivate::findSlot(QObject* obj, const QByteArray &normalizedN
bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key, bool QDBusConnectionPrivate::prepareHook(QDBusConnectionPrivate::SignalHook &hook, QString &key,
const QString &service, const QString &service,
const QString &path, const QString &interface, const QString &name, const QString &path, const QString &interface, const QString &name,
const QStringList &argMatch, const ArgMatchRules &argMatch,
QObject *receiver, const char *signal, int minMIdx, QObject *receiver, const char *signal, int minMIdx,
bool buildSignature) bool buildSignature)
{ {
@ -1620,14 +1628,14 @@ void QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage
continue; continue;
if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty()) if (hook.signature.isEmpty() && !hook.signature.isNull() && !msg.signature().isEmpty())
continue; continue;
if (!hook.argumentMatch.isEmpty()) { if (!hook.argumentMatch.args.isEmpty()) {
const QVariantList arguments = msg.arguments(); const QVariantList arguments = msg.arguments();
if (hook.argumentMatch.size() > arguments.size()) if (hook.argumentMatch.args.size() > arguments.size())
continue; continue;
bool matched = true; bool matched = true;
for (int i = 0; i < hook.argumentMatch.size(); ++i) { for (int i = 0; i < hook.argumentMatch.args.size(); ++i) {
const QString &param = hook.argumentMatch.at(i); const QString &param = hook.argumentMatch.args.at(i);
if (param.isNull()) if (param.isNull())
continue; // don't try to match against this continue; // don't try to match against this
if (param == arguments.at(i).toString()) if (param == arguments.at(i).toString())
@ -1638,7 +1646,15 @@ void QDBusConnectionPrivate::handleSignal(const QString &key, const QDBusMessage
if (!matched) if (!matched)
continue; continue;
} }
if (!hook.argumentMatch.arg0namespace.isEmpty()) {
const QVariantList arguments = msg.arguments();
if (arguments.size() < 1)
continue;
const QString param = arguments.at(0).toString();
if (param != hook.argumentMatch.arg0namespace
&& !param.startsWith(hook.argumentMatch.arg0namespace + QLatin1Char('.')))
continue;
}
activateSignal(hook, msg); activateSignal(hook, msg);
} }
} }
@ -2180,10 +2196,21 @@ void QDBusConnectionPrivate::sendInternal(QDBusPendingCallPrivate *pcall, void *
} }
} }
bool QDBusConnectionPrivate::connectSignal(const QString &service, bool QDBusConnectionPrivate::connectSignal(const QString &service,
const QString &path, const QString &interface, const QString &name, const QString &path, const QString &interface, const QString &name,
const QStringList &argumentMatch, const QString &signature, const QStringList &argumentMatch, const QString &signature,
QObject *receiver, const char *slot) QObject *receiver, const char *slot)
{
ArgMatchRules rules;
rules.args = argumentMatch;
return connectSignal(service, path, interface, name, rules, signature, receiver, slot);
}
bool QDBusConnectionPrivate::connectSignal(const QString &service,
const QString &path, const QString &interface, const QString &name,
const ArgMatchRules &argumentMatch, const QString &signature,
QObject *receiver, const char *slot)
{ {
// check the slot // check the slot
QDBusConnectionPrivate::SignalHook hook; QDBusConnectionPrivate::SignalHook hook;
@ -2241,9 +2268,11 @@ bool QDBusConnectionPrivate::addSignalHook(const QString &key, const SignalHook
WatchedServicesHash::mapped_type &data = watchedServices[hook.service]; WatchedServicesHash::mapped_type &data = watchedServices[hook.service];
if (++data.refcount == 1) { if (++data.refcount == 1) {
// we need to watch for this service changing // we need to watch for this service changing
ArgMatchRules rules;
rules.args << hook.service;
q_dbus_bus_add_match(connection, q_dbus_bus_add_match(connection,
buildMatchRule(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), buildMatchRule(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(),
QDBusUtil::nameOwnerChanged(), QStringList() << hook.service, QString()), QDBusUtil::nameOwnerChanged(), rules, QString()),
NULL); NULL);
data.owner = getNameOwnerNoCache(hook.service); data.owner = getNameOwnerNoCache(hook.service);
qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:" qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:"
@ -2255,9 +2284,19 @@ bool QDBusConnectionPrivate::addSignalHook(const QString &key, const SignalHook
return true; return true;
} }
bool QDBusConnectionPrivate::disconnectSignal(const QString &service,
const QString &path, const QString &interface, const QString &name,
const QStringList &argumentMatch, const QString &signature,
QObject *receiver, const char *slot)
{
ArgMatchRules rules;
rules.args = argumentMatch;
return disconnectSignal(service, path, interface, name, rules, signature, receiver, slot);
}
bool QDBusConnectionPrivate::disconnectSignal(const QString &service, bool QDBusConnectionPrivate::disconnectSignal(const QString &service,
const QString &path, const QString &interface, const QString &name, const QString &path, const QString &interface, const QString &name,
const QStringList &argumentMatch, const QString &signature, const ArgMatchRules &argumentMatch, const QString &signature,
QObject *receiver, const char *slot) QObject *receiver, const char *slot)
{ {
// check the slot // check the slot
@ -2288,7 +2327,7 @@ bool QDBusConnectionPrivate::removeSignalHook(const QString &key, const SignalHo
entry.signature == hook.signature && entry.signature == hook.signature &&
entry.obj == hook.obj && entry.obj == hook.obj &&
entry.midx == hook.midx && entry.midx == hook.midx &&
entry.argumentMatch == hook.argumentMatch) { entry.argumentMatch.args == hook.argumentMatch.args) {
// no need to compare the parameters if it's the same slot // no need to compare the parameters if it's the same slot
removeSignalHookNoLock(it); removeSignalHookNoLock(it);
return true; // it was there return true; // it was there
@ -2330,9 +2369,11 @@ QDBusConnectionPrivate::removeSignalHookNoLock(SignalHookHash::Iterator it)
if (sit != watchedServices.end()) { if (sit != watchedServices.end()) {
if (--sit.value().refcount == 0) { if (--sit.value().refcount == 0) {
watchedServices.erase(sit); watchedServices.erase(sit);
ArgMatchRules rules;
rules.args << hook.service;
q_dbus_bus_remove_match(connection, q_dbus_bus_remove_match(connection,
buildMatchRule(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), buildMatchRule(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(),
QDBusUtil::nameOwnerChanged(), QStringList() << hook.service, QString()), QDBusUtil::nameOwnerChanged(), rules, QString()),
NULL); NULL);
} }
} }
@ -2393,7 +2434,7 @@ void QDBusConnectionPrivate::connectRelay(const QString &service,
QByteArray sig; QByteArray sig;
sig.append(QSIGNAL_CODE + '0'); sig.append(QSIGNAL_CODE + '0');
sig.append(signal.methodSignature()); sig.append(signal.methodSignature());
if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, sig, if (!prepareHook(hook, key, service, path, interface, QString(), ArgMatchRules(), receiver, sig,
QDBusAbstractInterface::staticMetaObject.methodCount(), true)) QDBusAbstractInterface::staticMetaObject.methodCount(), true))
return; // don't connect return; // don't connect
@ -2414,7 +2455,7 @@ void QDBusConnectionPrivate::disconnectRelay(const QString &service,
QByteArray sig; QByteArray sig;
sig.append(QSIGNAL_CODE + '0'); sig.append(QSIGNAL_CODE + '0');
sig.append(signal.methodSignature()); sig.append(signal.methodSignature());
if (!prepareHook(hook, key, service, path, interface, QString(), QStringList(), receiver, sig, if (!prepareHook(hook, key, service, path, interface, QString(), ArgMatchRules(), receiver, sig,
QDBusAbstractInterface::staticMetaObject.methodCount(), true)) QDBusAbstractInterface::staticMetaObject.methodCount(), true))
return; // don't disconnect return; // don't disconnect
@ -2447,7 +2488,7 @@ bool QDBusConnectionPrivate::shouldWatchService(const QString &service)
*/ */
void QDBusConnectionPrivate::watchService(const QString &service, QDBusServiceWatcher::WatchMode mode, QObject *obj, const char *member) void QDBusConnectionPrivate::watchService(const QString &service, QDBusServiceWatcher::WatchMode mode, QObject *obj, const char *member)
{ {
QStringList matchArgs = matchArgsForService(service, mode); ArgMatchRules matchArgs = matchArgsForService(service, mode);
connectSignal(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), QDBusUtil::nameOwnerChanged(), connectSignal(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), QDBusUtil::nameOwnerChanged(),
matchArgs, QString(), obj, member); matchArgs, QString(), obj, member);
} }
@ -2462,7 +2503,7 @@ void QDBusConnectionPrivate::watchService(const QString &service, QDBusServiceWa
*/ */
void QDBusConnectionPrivate::unwatchService(const QString &service, QDBusServiceWatcher::WatchMode mode, QObject *obj, const char *member) void QDBusConnectionPrivate::unwatchService(const QString &service, QDBusServiceWatcher::WatchMode mode, QObject *obj, const char *member)
{ {
QStringList matchArgs = matchArgsForService(service, mode); ArgMatchRules matchArgs = matchArgsForService(service, mode);
disconnectSignal(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), QDBusUtil::nameOwnerChanged(), disconnectSignal(QDBusUtil::dbusService(), QString(), QDBusUtil::dbusInterface(), QDBusUtil::nameOwnerChanged(),
matchArgs, QString(), obj, member); matchArgs, QString(), obj, member);
} }

View File

@ -139,6 +139,17 @@ void QDBusServiceWatcherPrivate::removeService(const QString &service)
QDBusConnectionInterface::serviceOwnerChanged() signal because it allows QDBusConnectionInterface::serviceOwnerChanged() signal because it allows
one to receive only the signals for which the class is interested in. one to receive only the signals for which the class is interested in.
Ending a service name with the character '*' will match all service names
within the specified namespace.
For example "com.example.backend1*" will match
\list
\li com.example.backend1
\li com.example.backend1.foo
\li com.example.backend1.foo.bar
\endlist
Substrings in the same domain will not be matched, i.e "com.example.backend12".
\sa QDBusConnection \sa QDBusConnection
*/ */

View File

@ -34,22 +34,27 @@
class tst_QDBusServiceWatcher: public QObject class tst_QDBusServiceWatcher: public QObject
{ {
Q_OBJECT Q_OBJECT
QString serviceName;
int testCounter; int testCounter;
public: public:
tst_QDBusServiceWatcher(); tst_QDBusServiceWatcher();
private slots: private slots:
void initTestCase(); void initTestCase();
void init(); void watchForCreation_data();
void watchForCreation(); void watchForCreation();
void watchForDisappearance_data();
void watchForDisappearance(); void watchForDisappearance();
void watchForDisappearanceUniqueConnection(); void watchForDisappearanceUniqueConnection();
void watchForOwnerChange_data();
void watchForOwnerChange(); void watchForOwnerChange();
void modeChange_data();
void modeChange(); void modeChange();
void disconnectedConnection(); void disconnectedConnection();
void setConnection_data();
void setConnection(); void setConnection();
private:
QString generateServiceName();
}; };
tst_QDBusServiceWatcher::tst_QDBusServiceWatcher() tst_QDBusServiceWatcher::tst_QDBusServiceWatcher()
@ -63,18 +68,45 @@ void tst_QDBusServiceWatcher::initTestCase()
QVERIFY(con.isConnected()); QVERIFY(con.isConnected());
} }
void tst_QDBusServiceWatcher::init() QString tst_QDBusServiceWatcher::generateServiceName() {
return "com.example.TestService" + QString::number(testCounter++);
}
void tst_QDBusServiceWatcher::watchForCreation_data()
{ {
// change the service name from test to test QTest::addColumn<QString>("watchedName");
serviceName = "com.example.TestService" + QString::number(testCounter++); QTest::addColumn<QString>("registeredName");
//com.example.TestService5 matches com.example.TestService5
QString name = generateServiceName();
QTest::newRow("normal") << name << name;
//com.example* matches com.example.TestService5
name = generateServiceName();
QTest::newRow("wildcard") << "com.example*" << name;
//com.example.TestService5* matches com.example.TestService5
name = generateServiceName();
QTest::newRow("wildcard_exact") << name+"*" << name;
//com.example.TestService5* matches com.example.TestService5.Foo
name = generateServiceName();
QTest::newRow("wildcard_subdomain") << name+"*" << name + ".Foo";
//com.example.TestService5* matches com.example.TestService5.Foo.Bar
name = generateServiceName();
QTest::newRow("wildcard_subsubdomain") << name+"*" << name + ".Foo.Bar";
} }
void tst_QDBusServiceWatcher::watchForCreation() void tst_QDBusServiceWatcher::watchForCreation()
{ {
QFETCH(QString, watchedName);
QFETCH(QString, registeredName);
QDBusConnection con = QDBusConnection::sessionBus(); QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected()); QVERIFY(con.isConnected());
QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration); QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForRegistration);
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString))); QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString))); QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
@ -82,18 +114,18 @@ void tst_QDBusServiceWatcher::watchForCreation()
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop())); QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop()));
// register a name // register a name
QVERIFY(con.registerService(serviceName)); QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1); QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.count(), 1); QCOMPARE(spyR.count(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), serviceName); QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.count(), 0); QCOMPARE(spyU.count(), 0);
QCOMPARE(spyO.count(), 1); QCOMPARE(spyO.count(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), serviceName); QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QVERIFY(spyO.at(0).at(1).toString().isEmpty()); QVERIFY(spyO.at(0).at(1).toString().isEmpty());
QCOMPARE(spyO.at(0).at(2).toString(), con.baseService()); QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
@ -102,31 +134,39 @@ void tst_QDBusServiceWatcher::watchForCreation()
spyO.clear(); spyO.clear();
// unregister it: // unregister it:
con.unregisterService(serviceName); con.unregisterService(registeredName);
// and register again // and register again
QVERIFY(con.registerService(serviceName)); QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1); QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.count(), 1); QCOMPARE(spyR.count(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), serviceName); QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.count(), 0); QCOMPARE(spyU.count(), 0);
QCOMPARE(spyO.count(), 1); QCOMPARE(spyO.count(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), serviceName); QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QVERIFY(spyO.at(0).at(1).toString().isEmpty()); QVERIFY(spyO.at(0).at(1).toString().isEmpty());
QCOMPARE(spyO.at(0).at(2).toString(), con.baseService()); QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
} }
void tst_QDBusServiceWatcher::watchForDisappearance_data()
{
tst_QDBusServiceWatcher::watchForCreation_data();
}
void tst_QDBusServiceWatcher::watchForDisappearance() void tst_QDBusServiceWatcher::watchForDisappearance()
{ {
QFETCH(QString, watchedName);
QFETCH(QString, registeredName);
QDBusConnection con = QDBusConnection::sessionBus(); QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected()); QVERIFY(con.isConnected());
QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForUnregistration); QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForUnregistration);
watcher.setObjectName("watcher for disappearance"); watcher.setObjectName("watcher for disappearance");
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString))); QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
@ -135,10 +175,10 @@ void tst_QDBusServiceWatcher::watchForDisappearance()
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop())); QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop()));
// register a name // register a name
QVERIFY(con.registerService(serviceName)); QVERIFY(con.registerService(registeredName));
// unregister it: // unregister it:
con.unregisterService(serviceName); con.unregisterService(registeredName);
QTestEventLoop::instance().enterLoop(1); QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!QTestEventLoop::instance().timeout());
@ -146,10 +186,10 @@ void tst_QDBusServiceWatcher::watchForDisappearance()
QCOMPARE(spyR.count(), 0); QCOMPARE(spyR.count(), 0);
QCOMPARE(spyU.count(), 1); QCOMPARE(spyU.count(), 1);
QCOMPARE(spyU.at(0).at(0).toString(), serviceName); QCOMPARE(spyU.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.count(), 1); QCOMPARE(spyO.count(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), serviceName); QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.at(0).at(1).toString(), con.baseService()); QCOMPARE(spyO.at(0).at(1).toString(), con.baseService());
QVERIFY(spyO.at(0).at(2).toString().isEmpty()); QVERIFY(spyO.at(0).at(2).toString().isEmpty());
} }
@ -188,12 +228,20 @@ void tst_QDBusServiceWatcher::watchForDisappearanceUniqueConnection()
QVERIFY(spyO.at(0).at(2).toString().isEmpty()); QVERIFY(spyO.at(0).at(2).toString().isEmpty());
} }
void tst_QDBusServiceWatcher::watchForOwnerChange_data()
{
watchForCreation_data();
}
void tst_QDBusServiceWatcher::watchForOwnerChange() void tst_QDBusServiceWatcher::watchForOwnerChange()
{ {
QFETCH(QString, watchedName);
QFETCH(QString, registeredName);
QDBusConnection con = QDBusConnection::sessionBus(); QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected()); QVERIFY(con.isConnected());
QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForOwnerChange); QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForOwnerChange);
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString))); QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString))); QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
@ -201,18 +249,18 @@ void tst_QDBusServiceWatcher::watchForOwnerChange()
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop())); QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop()));
// register a name // register a name
QVERIFY(con.registerService(serviceName)); QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1); QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.count(), 1); QCOMPARE(spyR.count(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), serviceName); QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.count(), 0); QCOMPARE(spyU.count(), 0);
QCOMPARE(spyO.count(), 1); QCOMPARE(spyO.count(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), serviceName); QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QVERIFY(spyO.at(0).at(1).toString().isEmpty()); QVERIFY(spyO.at(0).at(1).toString().isEmpty());
QCOMPARE(spyO.at(0).at(2).toString(), con.baseService()); QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
@ -221,35 +269,43 @@ void tst_QDBusServiceWatcher::watchForOwnerChange()
spyO.clear(); spyO.clear();
// unregister it: // unregister it:
con.unregisterService(serviceName); con.unregisterService(registeredName);
// and register again // and register again
QVERIFY(con.registerService(serviceName)); QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1); QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.count(), 1); QCOMPARE(spyR.count(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), serviceName); QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.count(), 1); QCOMPARE(spyU.count(), 1);
QCOMPARE(spyU.at(0).at(0).toString(), serviceName); QCOMPARE(spyU.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.count(), 2); QCOMPARE(spyO.count(), 2);
QCOMPARE(spyO.at(0).at(0).toString(), serviceName); QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.at(0).at(1).toString(), con.baseService()); QCOMPARE(spyO.at(0).at(1).toString(), con.baseService());
QVERIFY(spyO.at(0).at(2).toString().isEmpty()); QVERIFY(spyO.at(0).at(2).toString().isEmpty());
QCOMPARE(spyO.at(1).at(0).toString(), serviceName); QCOMPARE(spyO.at(1).at(0).toString(), registeredName);
QVERIFY(spyO.at(1).at(1).toString().isEmpty()); QVERIFY(spyO.at(1).at(1).toString().isEmpty());
QCOMPARE(spyO.at(1).at(2).toString(), con.baseService()); QCOMPARE(spyO.at(1).at(2).toString(), con.baseService());
} }
void tst_QDBusServiceWatcher::modeChange_data()
{
watchForCreation_data();
}
void tst_QDBusServiceWatcher::modeChange() void tst_QDBusServiceWatcher::modeChange()
{ {
QFETCH(QString, watchedName);
QFETCH(QString, registeredName);
QDBusConnection con = QDBusConnection::sessionBus(); QDBusConnection con = QDBusConnection::sessionBus();
QVERIFY(con.isConnected()); QVERIFY(con.isConnected());
QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration); QDBusServiceWatcher watcher(watchedName, con, QDBusServiceWatcher::WatchForRegistration);
QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString))); QSignalSpy spyR(&watcher, SIGNAL(serviceRegistered(QString)));
QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString))); QSignalSpy spyU(&watcher, SIGNAL(serviceUnregistered(QString)));
@ -257,18 +313,18 @@ void tst_QDBusServiceWatcher::modeChange()
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop())); QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceRegistered(QString)), SLOT(exitLoop()));
// register a name // register a name
QVERIFY(con.registerService(serviceName)); QVERIFY(con.registerService(registeredName));
QTestEventLoop::instance().enterLoop(1); QTestEventLoop::instance().enterLoop(1);
QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(spyR.count(), 1); QCOMPARE(spyR.count(), 1);
QCOMPARE(spyR.at(0).at(0).toString(), serviceName); QCOMPARE(spyR.at(0).at(0).toString(), registeredName);
QCOMPARE(spyU.count(), 0); QCOMPARE(spyU.count(), 0);
QCOMPARE(spyO.count(), 1); QCOMPARE(spyO.count(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), serviceName); QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QVERIFY(spyO.at(0).at(1).toString().isEmpty()); QVERIFY(spyO.at(0).at(1).toString().isEmpty());
QCOMPARE(spyO.at(0).at(2).toString(), con.baseService()); QCOMPARE(spyO.at(0).at(2).toString(), con.baseService());
@ -279,7 +335,7 @@ void tst_QDBusServiceWatcher::modeChange()
watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration); watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
// unregister it: // unregister it:
con.unregisterService(serviceName); con.unregisterService(registeredName);
QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop())); QTestEventLoop::instance().connect(&watcher, SIGNAL(serviceUnregistered(QString)), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(1); QTestEventLoop::instance().enterLoop(1);
@ -288,10 +344,10 @@ void tst_QDBusServiceWatcher::modeChange()
QCOMPARE(spyR.count(), 0); QCOMPARE(spyR.count(), 0);
QCOMPARE(spyU.count(), 1); QCOMPARE(spyU.count(), 1);
QCOMPARE(spyU.at(0).at(0).toString(), serviceName); QCOMPARE(spyU.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.count(), 1); QCOMPARE(spyO.count(), 1);
QCOMPARE(spyO.at(0).at(0).toString(), serviceName); QCOMPARE(spyO.at(0).at(0).toString(), registeredName);
QCOMPARE(spyO.at(0).at(1).toString(), con.baseService()); QCOMPARE(spyO.at(0).at(1).toString(), con.baseService());
QVERIFY(spyO.at(0).at(2).toString().isEmpty()); QVERIFY(spyO.at(0).at(2).toString().isEmpty());
} }
@ -301,7 +357,7 @@ void tst_QDBusServiceWatcher::disconnectedConnection()
QDBusConnection con(""); QDBusConnection con("");
QVERIFY(!con.isConnected()); QVERIFY(!con.isConnected());
QDBusServiceWatcher watcher(serviceName, con, QDBusServiceWatcher::WatchForRegistration); QDBusServiceWatcher watcher(generateServiceName(), con, QDBusServiceWatcher::WatchForRegistration);
watcher.addWatchedService("com.example.somethingelse"); watcher.addWatchedService("com.example.somethingelse");
watcher.addWatchedService("org.freedesktop.DBus"); watcher.addWatchedService("org.freedesktop.DBus");
@ -311,8 +367,15 @@ void tst_QDBusServiceWatcher::disconnectedConnection()
watcher.setWatchedServices(QStringList()); watcher.setWatchedServices(QStringList());
} }
void tst_QDBusServiceWatcher::setConnection_data()
{
QTest::addColumn<QString>("serviceName");
QTest::newRow("normal") << generateServiceName();
}
void tst_QDBusServiceWatcher::setConnection() void tst_QDBusServiceWatcher::setConnection()
{ {
QFETCH(QString, serviceName);
// begin with a disconnected connection // begin with a disconnected connection
QDBusConnection con(""); QDBusConnection con("");
QVERIFY(!con.isConnected()); QVERIFY(!con.isConnected());