1 #include <QtCore/QDebug>
2 #include <QtCore/QTimer>
3 
4 #include <QtDBus/QtDBus>
5 
6 #include <QtTest/QtTest>
7 
8 #define TP_QT_ENABLE_LOWLEVEL_API
9 
10 #include <TelepathyQt/ChannelFactory>
11 #include <TelepathyQt/Connection>
12 #include <TelepathyQt/ConnectionLowlevel>
13 #include <TelepathyQt/ContactFactory>
14 #include <TelepathyQt/PendingChannel>
15 #include <TelepathyQt/PendingReady>
16 #include <TelepathyQt/Debug>
17 
18 #include <telepathy-glib/dbus.h>
19 #include <telepathy-glib/debug.h>
20 
21 #include <tests/lib/glib/contacts-conn.h>
22 #include <tests/lib/test.h>
23 
24 using namespace Tp;
25 
26 class TestConnBasics : public Test
27 {
28     Q_OBJECT
29 
30 public:
TestConnBasics(QObject * parent=0)31     TestConnBasics(QObject *parent = 0)
32         : Test(parent), mConnService(0)
33     { }
34 
35 protected Q_SLOTS:
36     void expectConnReady(Tp::ConnectionStatus);
37     void expectConnInvalidated();
38     void expectPresenceAvailable(const Tp::SimplePresence &);
39     void onRequestConnectFinished(Tp::PendingOperation *);
40 
41 private Q_SLOTS:
42     void initTestCase();
43     void init();
44 
45     void testBasics();
46     void testSimplePresence();
47 
48     void cleanup();
49     void cleanupTestCase();
50 
51 private:
52     QString mConnName, mConnPath;
53     TpTestsContactsConnection *mConnService;
54     ConnectionPtr mConn;
55     QList<ConnectionStatus> mStatuses;
56 };
57 
expectConnReady(Tp::ConnectionStatus newStatus)58 void TestConnBasics::expectConnReady(Tp::ConnectionStatus newStatus)
59 {
60     qDebug() << "connection changed to status" << newStatus;
61     switch (newStatus) {
62     case ConnectionStatusDisconnected:
63         qWarning() << "Disconnected";
64         break;
65     case ConnectionStatusConnecting:
66         QCOMPARE(mConn->isReady(Connection::FeatureConnected), false);
67         mStatuses << newStatus;
68         qDebug() << "Connecting";
69         break;
70     case ConnectionStatusConnected:
71         QCOMPARE(mConn->isReady(Connection::FeatureConnected), true);
72         mStatuses << newStatus;
73         qDebug() << "Connected";
74         break;
75     default:
76         qWarning().nospace() << "What sort of status is "
77             << newStatus << "?!";
78         break;
79     }
80 }
81 
expectConnInvalidated()82 void TestConnBasics::expectConnInvalidated()
83 {
84     qDebug() << "conn invalidated";
85 
86     mLoop->exit(0);
87 }
88 
expectPresenceAvailable(const Tp::SimplePresence & presence)89 void TestConnBasics::expectPresenceAvailable(const Tp::SimplePresence &presence)
90 {
91     if (presence.type == Tp::ConnectionPresenceTypeAvailable) {
92         mLoop->exit(0);
93         return;
94     }
95     mLoop->exit(1);
96 }
97 
onRequestConnectFinished(Tp::PendingOperation * op)98 void TestConnBasics::onRequestConnectFinished(Tp::PendingOperation *op)
99 {
100     QCOMPARE(mConn->status(), ConnectionStatusConnected);
101     QVERIFY(mStatuses.contains(ConnectionStatusConnected));
102     mLoop->exit(0);
103 }
104 
initTestCase()105 void TestConnBasics::initTestCase()
106 {
107     initTestCaseImpl();
108 
109     g_type_init();
110     g_set_prgname("conn-basics");
111     tp_debug_set_flags("all");
112     dbus_g_bus_get(DBUS_BUS_STARTER, 0);
113 }
114 
init()115 void TestConnBasics::init()
116 {
117     initImpl();
118 
119     gchar *name;
120     gchar *connPath;
121     GError *error = 0;
122 
123     mConnService = TP_TESTS_CONTACTS_CONNECTION(g_object_new(
124             TP_TESTS_TYPE_CONTACTS_CONNECTION,
125             "account", "me@example.com",
126             "protocol", "contacts",
127             NULL));
128     QVERIFY(mConnService != 0);
129     QVERIFY(tp_base_connection_register(TP_BASE_CONNECTION(mConnService),
130                 "contacts", &name, &connPath, &error));
131     QVERIFY(error == 0);
132 
133     QVERIFY(name != 0);
134     QVERIFY(connPath != 0);
135 
136     mConnName = QLatin1String(name);
137     mConnPath = QLatin1String(connPath);
138 
139     g_free(name);
140     g_free(connPath);
141 
142     mConn = Connection::create(mConnName, mConnPath,
143             ChannelFactory::create(QDBusConnection::sessionBus()),
144             ContactFactory::create());
145     QCOMPARE(mConn->isReady(), false);
146 
147     QVERIFY(connect(mConn.data(),
148                     SIGNAL(statusChanged(Tp::ConnectionStatus)),
149                     SLOT(expectConnReady(Tp::ConnectionStatus))));
150 
151     qDebug() << "waiting connection to become connected";
152     PendingOperation *pr = mConn->becomeReady(Connection::FeatureConnected);
153     QVERIFY(connect(pr,
154                     SIGNAL(finished(Tp::PendingOperation*)),
155                     SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
156 
157     PendingOperation *pc = mConn->lowlevel()->requestConnect();
158     QVERIFY(connect(pc,
159                     SIGNAL(finished(Tp::PendingOperation*)),
160                     SLOT(onRequestConnectFinished(Tp::PendingOperation*))));
161     QCOMPARE(mLoop->exec(), 0);
162     QCOMPARE(pr->isFinished(), true);
163     QCOMPARE(mLoop->exec(), 0);
164     QCOMPARE(pc->isFinished(), true);
165     QCOMPARE(mConn->isReady(Connection::FeatureConnected), true);
166     qDebug() << "connection is now ready";
167 
168     QVERIFY(disconnect(mConn.data(),
169                        SIGNAL(statusChanged(Tp::ConnectionStatus)),
170                        this,
171                        SLOT(expectConnReady(Tp::ConnectionStatus))));
172 }
173 
testBasics()174 void TestConnBasics::testBasics()
175 {
176     QCOMPARE(static_cast<uint>(mConn->statusReason()),
177             static_cast<uint>(ConnectionStatusReasonRequested));
178 }
179 
testSimplePresence()180 void TestConnBasics::testSimplePresence()
181 {
182     qDebug() << "Making SimplePresence ready";
183 
184     Features features = Features() << Connection::FeatureSimplePresence;
185     QCOMPARE(mConn->isReady(features), false);
186     QVERIFY(connect(mConn->becomeReady(features),
187                     SIGNAL(finished(Tp::PendingOperation*)),
188                     SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
189     QCOMPARE(mLoop->exec(), 0);
190     QCOMPARE(mConn->isReady(features), true);
191 
192     qDebug() << "SimplePresence ready";
193     qDebug() << "mConn->status:" << mConn->status();
194 
195     const QStringList canSetNames = QStringList()
196         << QLatin1String("available")
197         << QLatin1String("busy")
198         << QLatin1String("away");
199 
200     const QStringList cantSetNames = QStringList()
201         << QLatin1String("offline")
202         << QLatin1String("unknown")
203         << QLatin1String("error");
204 
205     const QStringList expectedNames = canSetNames + cantSetNames;
206 
207     const ConnectionPresenceType expectedTypes[] = {
208         ConnectionPresenceTypeAvailable,
209         ConnectionPresenceTypeBusy,
210         ConnectionPresenceTypeAway,
211         ConnectionPresenceTypeOffline,
212         ConnectionPresenceTypeUnknown,
213         ConnectionPresenceTypeError
214     };
215 
216     SimpleStatusSpecMap statuses = mConn->lowlevel()->allowedPresenceStatuses();
217     Q_FOREACH (QString name, statuses.keys()) {
218         QVERIFY(expectedNames.contains(name));
219 
220         if (canSetNames.contains(name)) {
221             QVERIFY(statuses[name].maySetOnSelf);
222             QVERIFY(statuses[name].canHaveMessage);
223         } else {
224             QVERIFY(cantSetNames.contains(name));
225             QVERIFY(!statuses[name].maySetOnSelf);
226             QVERIFY(!statuses[name].canHaveMessage);
227         }
228 
229         QCOMPARE(statuses[name].type,
230                  static_cast<uint>(expectedTypes[expectedNames.indexOf(name)]));
231     }
232 
233     QCOMPARE(mConn->lowlevel()->maxPresenceStatusMessageLength(), (uint) 512);
234 }
235 
cleanup()236 void TestConnBasics::cleanup()
237 {
238     if (mConn) {
239         QVERIFY(mConn->isValid());
240 
241         GHashTable *details = tp_asv_new(
242                 "debug-message", G_TYPE_STRING, "woo i'm going doooooown",
243                 "x-tpqt-test-rgba-herring-color", G_TYPE_UINT, 0xff0000ffU,
244                 NULL
245                 );
246 
247         // Disconnect and wait for invalidation
248         tp_base_connection_disconnect_with_dbus_error(TP_BASE_CONNECTION(mConnService),
249                 TP_QT_ERROR_CANCELLED.latin1(),
250                 details,
251                 TP_CONNECTION_STATUS_REASON_REQUESTED);
252 
253         g_hash_table_destroy(details);
254 
255         QVERIFY(connect(mConn.data(),
256                     SIGNAL(invalidated(Tp::DBusProxy *,
257                             const QString &, const QString &)),
258                     SLOT(expectConnInvalidated())));
259         QCOMPARE(mLoop->exec(), 0);
260         QVERIFY(!mConn->isValid());
261 
262         // Check that we got the connection error details
263         QCOMPARE(static_cast<uint>(mConn->statusReason()),
264                  static_cast<uint>(ConnectionStatusReasonRequested));
265 
266         QVERIFY(mConn->errorDetails().isValid());
267 
268         QVERIFY(mConn->errorDetails().hasDebugMessage());
269         QCOMPARE(mConn->errorDetails().debugMessage(), QLatin1String("woo i'm going doooooown"));
270 
271 #if 0
272         // Not yet there
273         QVERIFY(!mConn->errorDetails().hasExpectedHostname());
274         QVERIFY(!mConn->errorDetails().hasCertificateHostname());
275 #endif
276 
277         QVERIFY(mConn->errorDetails().allDetails().contains(
278                     QLatin1String("x-tpqt-test-rgba-herring-color")));
279         QCOMPARE(qdbus_cast<uint>(mConn->errorDetails().allDetails().value(
280                         QLatin1String("x-tpqt-test-rgba-herring-color"))),
281                 0xff0000ffU);
282 
283         processDBusQueue(mConn.data());
284 
285         mConn.reset();
286     }
287 
288     if (mConnService != 0) {
289         g_object_unref(mConnService);
290         mConnService = 0;
291     }
292 
293     cleanupImpl();
294 }
295 
cleanupTestCase()296 void TestConnBasics::cleanupTestCase()
297 {
298     cleanupTestCaseImpl();
299 }
300 
301 QTEST_MAIN(TestConnBasics)
302 #include "_gen/conn-basics.cpp.moc.hpp"
303