QtBase  v6.3.1
tst_qdbuspendingcall.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22 ** included in the packaging of this file. Please review the following
23 ** information to ensure the GNU General Public License requirements will
24 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25 **
26 ** $QT_END_LICENSE$
27 **
28 ****************************************************************************/
29 
30 #include <QTest>
31 #include <QTestEventLoop>
32 #include <QObject>
33 #include <QVariant>
34 #include <QList>
35 #include <QThread>
36 #include <QDBusAbstractAdaptor>
37 #include <QDBusMessage>
38 #include <QDBusConnection>
39 #include <QDBusPendingCallWatcher>
40 #include <QDBusInterface>
41 
42 #define TEST_INTERFACE_NAME "org.qtproject.QtDBus.MyObject"
43 
44 class MyObject : public QDBusAbstractAdaptor
45 {
46  Q_OBJECT
47  Q_CLASSINFO("D-Bus Interface", "org.qtproject.QtDBus.MyObject")
48 
49 public:
52  {}
53 
54 public slots:
56  { return QStringList() << QString::fromLatin1("foo"); }
57 
58  void returnError(const QDBusMessage &msg) const
59  {
60  msg.setDelayedReply(true);
61  QDBusConnection::sessionBus().send(msg.createErrorReply("dbuspendingcall_error", ""));
62  }
63 };
64 
66 {
67  Q_OBJECT
68 
69 public:
71 
72 public Q_SLOTS:
73  void callback(const QStringList &list);
74  void errorCallback(const QDBusError &error);
76  void makeCall();
77 
78 private Q_SLOTS:
79  void initTestCase();
80  void waitForFinished();
81  void waitForFinished_error();
82  void watcher();
83  void watcher_error();
84  void watcher_waitForFinished();
85  void watcher_waitForFinished_threaded();
86  void watcher_waitForFinished_alreadyFinished();
87  void watcher_waitForFinished_alreadyFinished_eventLoop();
88  void watcher_waitForFinished_error();
89  void callInsideWaitForFinished();
90 
91  void callWithCallback_localLoop();
92  void callWithCallback_localLoop_errorReply();
93 
94 private:
95  QDBusPendingCall sendMessage();
96  QDBusPendingCall sendError();
97 
98  QDBusConnection conn;
99 
100  enum { CallbackCalled, ErrorCallbackCalled, FinishCalled, MakeCallCalled };
101  int slotCalled;
102  int callCount;
103  QStringList callbackArgument;
104  QDBusError errorArgument;
105  QDBusPendingCallWatcher *watchArgument;
106  MyObject *obj;
107 };
108 
110  : conn(QDBusConnection::sessionBus())
111  , obj(new MyObject(this))
112 {
113 }
114 
116 {
117  slotCalled = FinishCalled;
118  ++callCount;
119  watchArgument = call;
120  if (QThread::currentThread() == thread())
122 }
123 
125 {
126  slotCalled = CallbackCalled;
127  ++callCount;
128  callbackArgument = list;
130 }
131 
133 {
134  slotCalled = ErrorCallbackCalled;
135  ++callCount;
136  errorArgument = error;
138 }
139 
141 {
142  // make an external call to D-Bus to make sure we haven't left any locks
143  slotCalled = MakeCallCalled;
144  ++callCount;
145 
146  sendMessage().waitForFinished();
147 }
148 
149 void tst_QDBusPendingCall::initTestCase()
150 {
151  QVERIFY(conn.isConnected());
152  QVERIFY(conn.registerObject("/", this));
153 }
154 
155 QDBusPendingCall tst_QDBusPendingCall::sendMessage()
156 {
157  QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
158  "/",
159  "org.freedesktop.DBus",
160  "ListNames");
161  return conn.asyncCall(msg);
162 }
163 
164 QDBusPendingCall tst_QDBusPendingCall::sendError()
165 {
166  QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus",
167  "/",
168  "org.freedesktop.DBus",
169  "ThisNameWontExist");
170  return conn.asyncCall(msg);
171 }
172 
173 void tst_QDBusPendingCall::waitForFinished()
174 {
175  QDBusPendingCall ac = sendMessage();
176  ac.waitForFinished();
177  QVERIFY(ac.isFinished());
178  QVERIFY(!ac.isError());
179 
180  const QDBusMessage reply = ac.reply();
182  QCOMPARE(reply.signature(), QString("as"));
183 
184  const QVariantList args = ac.reply().arguments();
185  QCOMPARE(args.count(), 1);
186 
187  const QVariant &arg = args.at(0);
188  QCOMPARE(arg.userType(), QMetaType::QStringList);
189  QVERIFY(arg.toStringList().contains(conn.baseService()));
190 }
191 
192 void tst_QDBusPendingCall::waitForFinished_error()
193 {
194  QDBusPendingCall ac = sendError();
195  ac.waitForFinished();
196  QVERIFY(ac.isFinished());
197  QVERIFY(ac.isError());
198 
199  QDBusError error = ac.error();
200  QVERIFY(error.isValid());
201  QCOMPARE(error.name(), QString("org.freedesktop.DBus.Error.UnknownMethod"));
203 }
204 
205 void tst_QDBusPendingCall::callWithCallback_localLoop()
206 {
207  // Verify that a callback actually gets called when the call is dispatched locally.
208  QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
210  QVERIFY(iface.isValid());
211 
212  QVERIFY(iface.callWithCallback("returnFoo", QVariantList(), this, SLOT(callback(QStringList))));
213 
214  // May be called synchronously or asynchronously...
215  if (callbackArgument != (QStringList() << QString::fromLatin1("foo"))) {
218  }
219 
220  QCOMPARE(callbackArgument, QStringList() << QString::fromLatin1("foo"));
221 }
222 
223 void tst_QDBusPendingCall::callWithCallback_localLoop_errorReply()
224 {
225  // Verify that an error callback actually gets called when the call is
226  // dispatched locally and the called method returns an error
227 
228  QDBusInterface iface(QDBusConnection::sessionBus().baseService(), QLatin1String("/"),
230  QVERIFY(iface.isValid());
231 
232  callbackArgument.clear();
233 
234  QVERIFY(iface.callWithCallback("returnError", QVariantList(), this,
236 
237  // May be called synchronously or asynchronously...
238  if (errorArgument.name() != "dbuspendingcall_error") {
241  }
242 
243  QCOMPARE(errorArgument.name(), QString::fromLatin1("dbuspendingcall_error"));
244  QVERIFY(callbackArgument.isEmpty());
245 }
246 
247 void tst_QDBusPendingCall::watcher()
248 {
249  QDBusPendingCall ac = sendMessage();
250  callCount = 0;
251  watchArgument = 0;
252 
256 
259 
260  QVERIFY(ac.isFinished());
261  QVERIFY(!ac.isError());
262 
263  QCOMPARE(callCount, 1);
264  QCOMPARE(slotCalled, (int)FinishCalled);
265  QCOMPARE(watchArgument, &watch);
266  QVERIFY(!watch.isError());
267 
268  const QVariantList args2 = ac.reply().arguments();
269  QVERIFY(!args2.isEmpty());
270  QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
271 }
272 
273 void tst_QDBusPendingCall::watcher_error()
274 {
275  QDBusPendingCall ac = sendError();
276  callCount = 0;
277  watchArgument = 0;
278 
282 
285 
286  QVERIFY(ac.isFinished());
287  QVERIFY(ac.isError());
288 
289  QCOMPARE(callCount, 1);
290  QCOMPARE(slotCalled, (int)FinishCalled);
291  QCOMPARE(watchArgument, &watch);
292 
293  QVERIFY(watch.isError());
294  QVERIFY(watch.error().isValid());
295 }
296 
297 void tst_QDBusPendingCall::watcher_waitForFinished()
298 {
299  QDBusPendingCall ac = sendMessage();
300  callCount = 0;
301  watchArgument = 0;
302 
306 
307  watch.waitForFinished();
308 
309  QVERIFY(ac.isFinished());
310  QVERIFY(!ac.isError());
311 
312  QCOMPARE(callCount, 1);
313  QCOMPARE(slotCalled, (int)FinishCalled);
314  QCOMPARE(watchArgument, &watch);
315  QVERIFY(!watch.isError());
316 
317  const QVariantList args2 = ac.reply().arguments();
318  QVERIFY(!args2.isEmpty());
319  QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
320 }
321 
322 void tst_QDBusPendingCall::watcher_waitForFinished_threaded()
323 {
324  callCount = 0;
325  watchArgument = 0;
326  slotCalled = 0;
327 
328  class WorkerThread: public QThread {
329  public:
331  WorkerThread(tst_QDBusPendingCall *tst) : tst(tst) {}
332  void run() override
333  {
334  QDBusPendingCall ac = tst->sendMessage();
335 // QVERIFY(!ac.isFinished());
336 // QVERIFY(!ac.isError());
337 // QCOMPARE(ac.reply().type(), QDBusMessage::InvalidMessage);
338 
342 
343  QTest::qSleep(100); // don't process events in this thread
344 
345 // QVERIFY(!ac.isFinished());
346 // QVERIFY(!ac.isError());
347 // QCOMPARE(ac.reply().type(), QDBusMessage::InvalidMessage);
348  QCOMPARE(tst->callCount, 0);
349  QCOMPARE(tst->slotCalled, 0);
350 
351  watch.waitForFinished();
352  QVERIFY(ac.isFinished());
353  QVERIFY(!ac.isError());
354 
355  QCOMPARE(tst->callCount, 1);
356  QCOMPARE(tst->slotCalled, (int)FinishCalled);
357  QCOMPARE(tst->watchArgument, &watch);
358  QVERIFY(!watch.isError());
359 
360  const QVariantList args2 = ac.reply().arguments();
361  QVERIFY(!args2.isEmpty());
362  QVERIFY(args2.at(0).toStringList().contains(tst->conn.baseService()));
363  }
364  } thread(this);
366  thread.start();
368  QVERIFY(thread.wait(3000));
370 }
371 
372 void tst_QDBusPendingCall::watcher_waitForFinished_alreadyFinished()
373 {
374  QDBusPendingCall ac = sendMessage();
375  ac.waitForFinished();
376  QVERIFY(ac.isFinished());
377  QVERIFY(!ac.isError());
378 
379  callCount = 0;
380  watchArgument = 0;
381 
382  // create a watcher on an already-finished reply
386 
387  watch.waitForFinished();
388 
389  QVERIFY(ac.isFinished());
390  QVERIFY(!ac.isError());
391 
392  QCOMPARE(callCount, 1);
393  QCOMPARE(slotCalled, (int)FinishCalled);
394  QCOMPARE(watchArgument, &watch);
395  QVERIFY(!watch.isError());
396 
397  const QVariantList args2 = ac.reply().arguments();
398  QVERIFY(!args2.isEmpty());
399  QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
400 }
401 
402 void tst_QDBusPendingCall::watcher_waitForFinished_alreadyFinished_eventLoop()
403 {
404  QDBusPendingCall ac = sendMessage();
405  ac.waitForFinished();
406  QVERIFY(ac.isFinished());
407  QVERIFY(!ac.isError());
408 
409  callCount = 0;
410  watchArgument = 0;
411 
412  // create a watcher on an already-finished reply
417  &QTestEventLoop::instance(), SLOT(exitLoop()));
418 
421 
422  QVERIFY(ac.isFinished());
423  QVERIFY(!ac.isError());
424 
425  QCOMPARE(callCount, 1);
426  QCOMPARE(slotCalled, (int)FinishCalled);
427  QCOMPARE(watchArgument, &watch);
428  QVERIFY(!watch.isError());
429 
430  const QVariantList args2 = ac.reply().arguments();
431  QVERIFY(!args2.isEmpty());
432  QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
433 }
434 
435 void tst_QDBusPendingCall::watcher_waitForFinished_error()
436 {
437  QDBusPendingCall ac = sendError();
438  callCount = 0;
439  watchArgument = 0;
440 
444 
445  watch.waitForFinished();
446 
447  QVERIFY(ac.isFinished());
448  QVERIFY(ac.isError());
449 
450  QCOMPARE(callCount, 1);
451  QCOMPARE(slotCalled, (int)FinishCalled);
452  QCOMPARE(watchArgument, &watch);
453 
454  QVERIFY(watch.isError());
455  QVERIFY(watch.error().isValid());
456 }
457 
458 void tst_QDBusPendingCall::callInsideWaitForFinished()
459 {
460  QDBusPendingCall ac = sendMessage();
462 
463  callCount = 0;
464 
466  SLOT(makeCall()));
467 
468  watch.waitForFinished();
469 
470  QCOMPARE(callCount, 1);
471  QCOMPARE(slotCalled, (int)MakeCallCalled);
472  QVERIFY(!watch.isError());
473 
474  const QVariantList args2 = ac.reply().arguments();
475  QVERIFY(!args2.isEmpty());
476  QVERIFY(args2.at(0).toStringList().contains(conn.baseService()));
477 }
478 
480 #include "tst_qdbuspendingcall.moc"
const char msg[]
Definition: arch.cpp:46
FT_Error error
Definition: cffdrivr.c:657
[0]
Definition: myobject.h:58
MyObject(QObject *parent=0)
void returnError(const QDBusMessage &msg) const
QStringList returnFoo() const
The QDBusAbstractAdaptor class is the base class of D-Bus adaptor classes.
The QDBusConnection class represents a connection to the D-Bus bus daemon.
bool send(const QDBusMessage &message) const
bool isConnected() const
static QDBusConnection sessionBus()
QString baseService() const
QDBusPendingCall asyncCall(const QDBusMessage &message, int timeout=-1) const
bool registerObject(const QString &path, QObject *object, RegisterOptions options=ExportAdaptors)
The QDBusError class represents an error received from the D-Bus bus or from remote applications foun...
Definition: qdbuserror.h:57
@ UnknownMethod
Definition: qdbuserror.h:77
QString name() const
Definition: qdbuserror.cpp:307
The QDBusInterface class is a proxy for interfaces on remote objects.
The QDBusMessage class represents one message sent or received over the D-Bus bus.
Definition: qdbusmessage.h:58
QList< QVariant > arguments() const
static QDBusMessage createMethodCall(const QString &destination, const QString &path, const QString &interface, const QString &method)
The QDBusPendingCall class refers to one pending asynchronous call.
bool isFinished() const
QDBusError error() const
QDBusMessage reply() const
The QDBusPendingCallWatcher class provides a convenient way for waiting for asynchronous replies.
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
bool isEmpty() const noexcept
Definition: qlist.h:418
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
QObject * parent() const
Definition: qobject.h:409
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Definition: qobject.cpp:2772
QThread * thread() const
Definition: qobject.cpp:1527
The QString class provides a Unicode character string.
Definition: qstring.h:388
static QString fromLatin1(QByteArrayView ba)
Definition: qstring.cpp:5488
The QStringList class provides a list of strings.
void enterLoop(int secs)
static QTestEventLoop & instance()
void start(Priority=InheritPriority)
Definition: qthread.cpp:836
static QThread * currentThread()
Definition: qthread.cpp:879
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
Definition: qthread.cpp:863
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
QStringList toStringList() const
Definition: qvariant.cpp:1396
void errorCallback(const QDBusError &error)
void finished(QDBusPendingCallWatcher *call)
void callback(const QStringList &list)
#define this
Definition: dialogs.cpp:56
QCOMPARE(spy.count(), 1)
Q_CORE_EXPORT void qSleep(int ms)
@ DirectConnection
Definition: qnamespace.h:1306
QList< QString > QStringList
Definition: qcontainerfwd.h:64
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch * watch
#define SLOT(a)
Definition: qobjectdefs.h:87
#define SIGNAL(a)
Definition: qobjectdefs.h:88
GLbitfield GLuint64 timeout
[4]
GLhandleARB obj
[2]
Definition: qopenglext.h:4164
SSL_CTX int(*) void arg)
#define QTEST_MAIN(TestObject)
Definition: qtest.h:664
#define QVERIFY(statement)
Definition: qtestcase.h:64
#define Q_OBJECT
Definition: qtmetamacros.h:158
#define Q_CLASSINFO(name, value)
Definition: qtmetamacros.h:88
#define Q_SLOTS
Definition: qtmetamacros.h:80
#define slots
Definition: qtmetamacros.h:76
QNetworkReply * reply
QStringList list
[0]
bool run(const QString &name, QString *errorMessage)
#define TEST_INTERFACE_NAME