1/*
2 * SPDX-FileCopyrightText: 2014-2015 David Rosca <nowrep@gmail.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6
7#include "adaptertest.h"
8#include "autotests.h"
9#include "device.h"
10#include "initmanagerjob.h"
11#include "pendingcall.h"
12
13#include <QSignalSpy>
14#include <QTest>
15
16namespace BluezQt
17{
18extern void bluezqt_initFakeBluezTestRun();
19}
20
21using namespace BluezQt;
22
23AdapterTest::AdapterTest()
24 : m_manager(nullptr)
25{
26 Autotests::registerMetatypes();
27}
28
29void AdapterTest::initTestCase()
30{
31 QDBusConnection connection = QDBusConnection::sessionBus();
32 QString service = QStringLiteral("org.kde.bluezqt.fakebluez");
33
34 bluezqt_initFakeBluezTestRun();
35
36 FakeBluez::start();
37 FakeBluez::runTest(QStringLiteral("bluez-standard"));
38
39 // Create adapters
40 QDBusObjectPath adapter1path = QDBusObjectPath(QStringLiteral("/org/bluez/hci0"));
41 QVariantMap adapterProps;
42 adapterProps[QStringLiteral("Path")] = QVariant::fromValue(adapter1path);
43 adapterProps[QStringLiteral("Address")] = QStringLiteral("1C:E5:C3:BC:94:7E");
44 adapterProps[QStringLiteral("Name")] = QStringLiteral("TestAdapter");
45 adapterProps[QStringLiteral("Alias")] = QStringLiteral("TestAlias");
46 adapterProps[QStringLiteral("Class")] = QVariant::fromValue(quint32(101));
47 adapterProps[QStringLiteral("Powered")] = false;
48 adapterProps[QStringLiteral("Discoverable")] = false;
49 adapterProps[QStringLiteral("Pairable")] = false;
50 adapterProps[QStringLiteral("PairableTimeout")] = QVariant::fromValue(quint32(0));
51 adapterProps[QStringLiteral("DiscoverableTimeout")] = QVariant::fromValue(quint32(0));
52 adapterProps[QStringLiteral("Discovering")] = false;
53 adapterProps[QStringLiteral("UUIDs")] = QStringList(QStringLiteral("00001200-0000-1000-8000-00805f9b34fb"));
54 adapterProps[QStringLiteral("Modalias")] = QStringLiteral("usb:v2D6Bp1236d0215");
55 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-adapter"), adapterProps);
56
57 QDBusObjectPath adapter2path = QDBusObjectPath(QStringLiteral("/org/bluez/hci1"));
58 adapterProps[QStringLiteral("Path")] = QVariant::fromValue(adapter2path);
59 adapterProps[QStringLiteral("Address")] = QStringLiteral("2E:3A:C3:BC:85:7C");
60 adapterProps[QStringLiteral("Name")] = QStringLiteral("TestAdapter2");
61 adapterProps[QStringLiteral("Alias")] = QStringLiteral("TestAlias2");
62 adapterProps[QStringLiteral("Class")] = QVariant::fromValue(quint32(201));
63 adapterProps[QStringLiteral("Powered")] = true;
64 adapterProps[QStringLiteral("Discoverable")] = true;
65 adapterProps[QStringLiteral("Pairable")] = true;
66 adapterProps[QStringLiteral("PairableTimeout")] = QVariant::fromValue(quint32(150));
67 adapterProps[QStringLiteral("DiscoverableTimeout")] = QVariant::fromValue(quint32(120));
68 adapterProps[QStringLiteral("Discovering")] = false;
69 adapterProps[QStringLiteral("UUIDs")] = QStringList(QStringLiteral("0000110c-0000-1000-8000-00805f9b34fb"));
70 adapterProps[QStringLiteral("Modalias")] = QStringLiteral("usb:v1D3Bp1134d0214");
71 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-adapter"), adapterProps);
72
73 // Create devices
74 QVariantMap deviceProps;
75 deviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci0/dev_40_79_6A_0C_39_75"));
76 deviceProps[QStringLiteral("Adapter")] = QVariant::fromValue(adapter1path);
77 deviceProps[QStringLiteral("Address")] = QStringLiteral("40:79:6A:0C:39:75");
78 deviceProps[QStringLiteral("Name")] = QStringLiteral("TestDevice");
79 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-device"), deviceProps);
80
81 deviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci1/dev_50_79_6A_0C_39_75"));
82 deviceProps[QStringLiteral("Adapter")] = QVariant::fromValue(adapter2path);
83 deviceProps[QStringLiteral("Address")] = QStringLiteral("50:79:6A:0C:39:75");
84 deviceProps[QStringLiteral("Name")] = QStringLiteral("TestDevice2");
85 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-device"), deviceProps);
86
87 m_manager = new Manager();
88 InitManagerJob *initJob = m_manager->init();
89 initJob->exec();
90 QVERIFY(!initJob->error());
91
92 for (AdapterPtr adapter : m_manager->adapters()) {
93 QVERIFY(!adapter->ubi().isEmpty());
94
95 AdapterUnit u;
96 u.adapter = adapter;
97 u.dbusAdapter = new org::bluez::Adapter1(service, adapter->ubi(), connection, this);
98 u.dbusProperties = new org::freedesktop::DBus::Properties(service, adapter->ubi(), connection, this);
99 m_units.append(u);
100 }
101
102 QCOMPARE(m_manager->adapters().count(), 2);
103}
104
105void AdapterTest::cleanupTestCase()
106{
107 for (const AdapterUnit &unit : m_units) {
108 delete unit.dbusAdapter;
109 delete unit.dbusProperties;
110 }
111
112 delete m_manager;
113
114 FakeBluez::stop();
115}
116
117static void compareUuids(const QStringList &actual, const QStringList &expected)
118{
119 QCOMPARE(actual.size(), expected.size());
120
121 for (int i = 0; i < actual.size(); ++i) {
122 QCOMPARE(actual.at(i).toUpper(), expected.at(i).toUpper());
123 }
124}
125
126void AdapterTest::getPropertiesTest()
127{
128 for (const AdapterUnit &unit : m_units) {
129 QCOMPARE(unit.adapter->ubi(), unit.dbusAdapter->path());
130 QCOMPARE(unit.adapter->address(), unit.dbusAdapter->address());
131 QCOMPARE(unit.adapter->name(), unit.dbusAdapter->alias());
132 QCOMPARE(unit.adapter->systemName(), unit.dbusAdapter->name());
133 QCOMPARE(unit.adapter->adapterClass(), unit.dbusAdapter->adapterClass());
134 QCOMPARE(unit.adapter->isPowered(), unit.dbusAdapter->powered());
135 QCOMPARE(unit.adapter->isDiscoverable(), unit.dbusAdapter->discoverable());
136 QCOMPARE(unit.adapter->discoverableTimeout(), unit.dbusAdapter->discoverableTimeout());
137 QCOMPARE(unit.adapter->isPairable(), unit.dbusAdapter->pairable());
138 QCOMPARE(unit.adapter->pairableTimeout(), unit.dbusAdapter->pairableTimeout());
139 QCOMPARE(unit.adapter->isDiscovering(), unit.dbusAdapter->discovering());
140 QCOMPARE(unit.adapter->modalias(), unit.dbusAdapter->modalias());
141
142 compareUuids(unit.adapter->uuids(), unit.dbusAdapter->uUIDs());
143 }
144}
145
146void AdapterTest::setAliasTest()
147{
148 for (const AdapterUnit &unit : m_units) {
149 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(nameChanged(QString)));
150 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
151
152 QString value = unit.adapter->name() + QLatin1String("_tst_alias");
153
154 unit.adapter->setName(value);
155 QTRY_COMPARE(adapterSpy.count(), 1);
156
157 QList<QVariant> adapterArguments = adapterSpy.takeFirst();
158 QCOMPARE(adapterArguments.at(0).toString(), value);
159 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Alias"), value);
160
161 QCOMPARE(unit.adapter->name(), value);
162 QCOMPARE(unit.dbusAdapter->alias(), value);
163 }
164}
165
166void AdapterTest::setPoweredTest()
167{
168 for (const AdapterUnit &unit : m_units) {
169 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(poweredChanged(bool)));
170 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
171
172 bool value = !unit.adapter->isPowered();
173
174 unit.adapter->setPowered(value);
175 QTRY_COMPARE(adapterSpy.count(), 1);
176
177 QVERIFY(dbusSpy.count() >= 1);
178 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Powered"), value);
179
180 QList<QVariant> adapterArguments = adapterSpy.takeFirst();
181 QCOMPARE(adapterArguments.at(0).toBool(), value);
182
183 QCOMPARE(unit.adapter->isPowered(), value);
184 QCOMPARE(unit.dbusAdapter->powered(), value);
185 }
186}
187
188void AdapterTest::setDiscoverableTest()
189{
190 // Discoverable cannot be changed when Adapter is off
191
192 for (const AdapterUnit &unit : m_units) {
193 unit.adapter->setPowered(true)->waitForFinished();
194
195 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(discoverableChanged(bool)));
196 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
197
198 bool value = !unit.adapter->isDiscoverable();
199
200 unit.adapter->setDiscoverable(value);
201 QTRY_COMPARE(adapterSpy.count(), 1);
202
203 QList<QVariant> adapterArguments = adapterSpy.takeFirst();
204 QCOMPARE(adapterArguments.at(0).toBool(), value);
205 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Discoverable"), value);
206
207 QCOMPARE(unit.adapter->isDiscoverable(), value);
208 QCOMPARE(unit.dbusAdapter->discoverable(), value);
209 }
210}
211
212void AdapterTest::setDiscoverableTimeoutTest()
213{
214 for (const AdapterUnit &unit : m_units) {
215 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(discoverableTimeoutChanged(quint32)));
216 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
217
218 quint32 value = unit.adapter->discoverableTimeout() + 1;
219
220 unit.adapter->setDiscoverableTimeout(value);
221 QTRY_COMPARE(adapterSpy.count(), 1);
222
223 QVERIFY(dbusSpy.count() >= 1);
224 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("DiscoverableTimeout"), value);
225
226 QList<QVariant> adapterArguments = adapterSpy.takeFirst();
227 QCOMPARE(adapterArguments.at(0).toUInt(), value);
228
229 QCOMPARE(unit.adapter->discoverableTimeout(), value);
230 QCOMPARE(unit.dbusAdapter->discoverableTimeout(), value);
231 }
232}
233
234void AdapterTest::setPairableTest()
235{
236 for (const AdapterUnit &unit : m_units) {
237 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(pairableChanged(bool)));
238 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
239
240 bool value = !unit.adapter->isPairable();
241
242 unit.adapter->setPairable(value);
243 QTRY_COMPARE(adapterSpy.count(), 1);
244
245 QList<QVariant> adapterArguments = adapterSpy.takeFirst();
246 QCOMPARE(adapterArguments.at(0).toBool(), value);
247 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Pairable"), value);
248
249 QCOMPARE(unit.adapter->isPairable(), value);
250 QCOMPARE(unit.dbusAdapter->pairable(), value);
251 }
252}
253
254void AdapterTest::setPairableTimeoutTest()
255{
256 for (const AdapterUnit &unit : m_units) {
257 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(pairableTimeoutChanged(quint32)));
258 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
259
260 quint32 value = unit.adapter->pairableTimeout() + 1;
261
262 unit.adapter->setPairableTimeout(value);
263 QTRY_COMPARE(adapterSpy.count(), 1);
264
265 QVERIFY(dbusSpy.count() >= 1);
266 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("PairableTimeout"), value);
267
268 QList<QVariant> adapterArguments = adapterSpy.takeFirst();
269 QCOMPARE(adapterArguments.at(0).toUInt(), value);
270
271 QCOMPARE(unit.adapter->pairableTimeout(), value);
272 QCOMPARE(unit.dbusAdapter->pairableTimeout(), value);
273 }
274}
275
276void AdapterTest::discoveryTest()
277{
278 // Discovery needs Adapter powered on
279
280 for (const AdapterUnit &unit : m_units) {
281 // Make sure the Adapter is powered on and not discovering
282 unit.adapter->setPowered(true)->waitForFinished();
283 if (unit.adapter->isDiscovering()) {
284 unit.adapter->stopDiscovery()->waitForFinished();
285 }
286
287 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(discoveringChanged(bool)));
288 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
289
290 // Start Discovery
291 unit.adapter->startDiscovery();
292 QTRY_COMPARE(adapterSpy.count(), 1);
293
294 QVERIFY(dbusSpy.count() >= 1);
295 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Discovering"), true);
296
297 QList<QVariant> adapterArguments = adapterSpy.takeFirst();
298 QCOMPARE(adapterArguments.at(0).toBool(), true);
299
300 QCOMPARE(unit.adapter->isDiscovering(), true);
301 QCOMPARE(unit.dbusAdapter->discovering(), true);
302
303 adapterSpy.clear();
304 dbusSpy.clear();
305
306 // Stop Discovery
307 unit.adapter->stopDiscovery();
308 QTRY_COMPARE(adapterSpy.count(), 1);
309
310 QVERIFY(dbusSpy.count() >= 1);
311 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Discovering"), false);
312
313 adapterArguments = adapterSpy.takeFirst();
314 QCOMPARE(adapterArguments.at(0).toBool(), false);
315
316 QCOMPARE(unit.adapter->isDiscovering(), false);
317 QCOMPARE(unit.dbusAdapter->discovering(), false);
318 }
319}
320
321void AdapterTest::removeDeviceTest()
322{
323 for (const AdapterUnit &unit : m_units) {
324 while (!unit.adapter->devices().isEmpty()) {
325 DevicePtr device = unit.adapter->devices().first();
326
327 QSignalSpy managerSpy(m_manager, SIGNAL(deviceRemoved(DevicePtr)));
328 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(deviceRemoved(DevicePtr)));
329 QSignalSpy deviceSpy(device.data(), SIGNAL(deviceRemoved(DevicePtr)));
330
331 unit.adapter->removeDevice(device);
332
333 QTRY_COMPARE(managerSpy.count(), 1);
334 QTRY_COMPARE(adapterSpy.count(), 1);
335 QTRY_COMPARE(deviceSpy.count(), 1);
336
337 QCOMPARE(managerSpy.at(0).at(0).value<DevicePtr>(), device);
338 QCOMPARE(adapterSpy.at(0).at(0).value<DevicePtr>(), device);
339 QCOMPARE(deviceSpy.at(0).at(0).value<DevicePtr>(), device);
340 }
341 }
342}
343
344static bool isFilterValid(const QStringList &filters, const QVariantMap &filter)
345{
346 auto i = filter.constBegin();
347 while (i != filter.constEnd()) {
348 if (!filters.contains(i.key())) {
349 return false;
350 }
351 i++;
352 }
353 return true;
354}
355
356void AdapterTest::discoveryFilterTest_data() {
357 QTest::addColumn<QVariantMap>("filter");
358 QTest::addColumn<bool>("isValid");
359 QTest::addColumn<bool>("shouldBeDiscoverable");
360
361
362 QTest::newRow("valid-non-discoverable") << QVariantMap({
363 { QStringLiteral("UUIDs"), QStringList() },
364 { QStringLiteral("RSSI"), QVariant::fromValue(qint16(-100)) },
365 { QStringLiteral("Transport"), QStringLiteral("auto") },
366 { QStringLiteral("DuplicateData"), true },
367 { QStringLiteral("Discoverable"), false },
368 { QStringLiteral("Pattern"), QLatin1String("")}
369 }) << true << false;
370
371 QTest::newRow("valid-discoverable") << QVariantMap({
372 { QStringLiteral("UUIDs"), QStringList() },
373 { QStringLiteral("RSSI"), QVariant::fromValue(qint16(-100)) },
374 { QStringLiteral("Transport"), QStringLiteral("auto") },
375 { QStringLiteral("DuplicateData"), true },
376 { QStringLiteral("Discoverable"), true },
377 { QStringLiteral("Pattern"), QLatin1String("")}
378 }) << true << true;
379
380 QTest::newRow("invalid") << QVariantMap({
381 { QStringLiteral("SomeKey"), QStringList() }
382 }) << false << false;
383}
384
385void AdapterTest::discoveryFilterTest()
386{
387 QFETCH(QVariantMap, filter);
388 QFETCH(bool, isValid);
389 QFETCH(bool, shouldBeDiscoverable);
390
391 for (const AdapterUnit &unit : m_units) {
392
393 // Get available discovery filters
394 PendingCall* p = unit.adapter->getDiscoveryFilters(); p->waitForFinished();
395 Q_ASSERT(p->isFinished());
396 QCOMPARE(p->error(), PendingCall::NoError);
397 const QStringList filters = p->value().toStringList();
398
399 // Verify filter
400 QCOMPARE(isFilterValid(filters, filter), isValid);
401
402 // Make sure adapter is powered and not discoverable
403 unit.adapter->setPowered(true)->waitForFinished();
404 unit.adapter->setDiscoverable(false);
405 QTRY_COMPARE(unit.adapter->isDiscoverable(), false);
406 QTRY_COMPARE(unit.dbusAdapter->discoverable(), false);
407
408 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(discoverableChanged(bool)));
409 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
410
411 // Set discovery filter
412 unit.adapter->setDiscoveryFilter(filter);
413
414 if (shouldBeDiscoverable) {
415 // Check if adapter became discoverable
416 QTRY_COMPARE(adapterSpy.count(), 1);
417
418 const QList<QVariant> adapterArguments = adapterSpy.takeFirst();
419 QCOMPARE(adapterArguments.at(0).toBool(), true);
420 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Discoverable"), true);
421
422 QCOMPARE(unit.adapter->isDiscoverable(), true);
423 QCOMPARE(unit.dbusAdapter->discoverable(), true);
424 }
425 }
426}
427
428void AdapterTest::adapterRemovedTest()
429{
430 for (const AdapterUnit &unit : m_units) {
431 QSignalSpy managerSpy(m_manager, SIGNAL(adapterRemoved(AdapterPtr)));
432 QSignalSpy adapterSpy(unit.adapter.data(), SIGNAL(adapterRemoved(AdapterPtr)));
433
434 QVariantMap properties;
435 properties[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(unit.adapter->ubi()));
436 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("remove-adapter"), properties);
437
438 QTRY_COMPARE(managerSpy.count(), 1);
439 QTRY_COMPARE(adapterSpy.count(), 1);
440
441 QCOMPARE(managerSpy.at(0).at(0).value<AdapterPtr>(), unit.adapter);
442 QCOMPARE(adapterSpy.at(0).at(0).value<AdapterPtr>(), unit.adapter);
443 }
444}
445
446QTEST_MAIN(AdapterTest)
447
448#include "moc_adaptertest.cpp"
449

source code of bluez-qt/autotests/adaptertest.cpp