1/*
2 * SPDX-FileCopyrightText: 2021 Ivan Podkurkov <podkiva2@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 "gattcharacteristicremotetest.h"
8
9#include "adapter.h"
10#include "autotests.h"
11#include "device.h"
12#include "initmanagerjob.h"
13#include "pendingcall.h"
14
15#include <QSignalSpy>
16#include <QTest>
17#include <QDebug>
18
19namespace BluezQt
20{
21extern void bluezqt_initFakeBluezTestRun();
22}
23
24using namespace BluezQt;
25
26GattCharacteristicRemoteTest::GattCharacteristicRemoteTest()
27 : m_manager(nullptr)
28{
29 Autotests::registerMetatypes();
30}
31
32void GattCharacteristicRemoteTest::initTestCase()
33{
34 QDBusConnection connection = QDBusConnection::sessionBus();
35 QString service = QStringLiteral("org.kde.bluezqt.fakebluez");
36
37 bluezqt_initFakeBluezTestRun();
38
39 FakeBluez::start();
40 FakeBluez::runTest(QStringLiteral("bluez-standard"));
41
42 // Create adapters
43 QDBusObjectPath adapter1 = QDBusObjectPath(QStringLiteral("/org/bluez/hci0"));
44 QVariantMap adapterProps;
45 adapterProps[QStringLiteral("Path")] = QVariant::fromValue(adapter1);
46 adapterProps[QStringLiteral("Address")] = QStringLiteral("1C:E5:C3:BC:94:7E");
47 adapterProps[QStringLiteral("Name")] = QStringLiteral("TestAdapter");
48 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-adapter"), adapterProps);
49
50 QDBusObjectPath adapter2 = QDBusObjectPath(QStringLiteral("/org/bluez/hci1"));
51 adapterProps[QStringLiteral("Path")] = QVariant::fromValue(adapter2);
52 adapterProps[QStringLiteral("Address")] = QStringLiteral("2E:3A:C3:BC:85:7C");
53 adapterProps[QStringLiteral("Name")] = QStringLiteral("TestAdapter2");
54 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-adapter"), adapterProps);
55
56 // Create devices
57 QVariantMap deviceProps;
58 deviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci0/dev_40_79_6A_0C_39_75"));
59 deviceProps[QStringLiteral("Adapter")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci0"));
60 deviceProps[QStringLiteral("Address")] = QStringLiteral("40:79:6A:0C:39:75");
61 deviceProps[QStringLiteral("Name")] = QStringLiteral("TestDevice");
62 deviceProps[QStringLiteral("Alias")] = QStringLiteral("TestAlias");
63 deviceProps[QStringLiteral("Icon")] = QStringLiteral("phone");
64 deviceProps[QStringLiteral("Class")] = QVariant::fromValue(quint32(101));
65 deviceProps[QStringLiteral("Appearance")] = QVariant::fromValue(quint16(25));
66 deviceProps[QStringLiteral("UUIDs")] = QStringList();
67 deviceProps[QStringLiteral("Paired")] = false;
68 deviceProps[QStringLiteral("Connected")] = false;
69 deviceProps[QStringLiteral("Trusted")] = false;
70 deviceProps[QStringLiteral("Blocked")] = false;
71 deviceProps[QStringLiteral("LegacyPairing")] = false;
72 deviceProps[QStringLiteral("RSSI")] = QVariant::fromValue(qint16(20));
73 deviceProps[QStringLiteral("Modalias")] = QStringLiteral("bluetooth:v001Dp1200d1236");
74 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-device"), deviceProps);
75
76 deviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci1/dev_50_79_6A_0C_39_75"));
77 deviceProps[QStringLiteral("Adapter")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci1"));
78 deviceProps[QStringLiteral("Address")] = QStringLiteral("50:79:6A:0C:39:75");
79 deviceProps[QStringLiteral("Name")] = QStringLiteral("TestDevice2");
80 deviceProps[QStringLiteral("Alias")] = QStringLiteral("TestAlias2");
81 deviceProps[QStringLiteral("Icon")] = QStringLiteral("joypad");
82 deviceProps[QStringLiteral("Class")] = QVariant::fromValue(quint32(201));
83 deviceProps[QStringLiteral("Appearance")] = QVariant::fromValue(quint16(32));
84 deviceProps[QStringLiteral("UUIDs")] = QStringList();
85 deviceProps[QStringLiteral("Paired")] = true;
86 deviceProps[QStringLiteral("Connected")] = false;
87 deviceProps[QStringLiteral("Trusted")] = true;
88 deviceProps[QStringLiteral("Blocked")] = false;
89 deviceProps[QStringLiteral("LegacyPairing")] = false;
90 deviceProps[QStringLiteral("RSSI")] = QVariant::fromValue(qint16(-15));
91 deviceProps[QStringLiteral("Modalias")] = QStringLiteral("bluetooth:v001Dp1100d1236");
92 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-device"), deviceProps);
93
94 // Create services
95 QVariantMap serviceProps;
96 serviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci0/dev_40_79_6A_0C_39_75/service0"));
97 serviceProps[QStringLiteral("UUID")] = QStringLiteral("04FA28C0-2D0C-11EC-8D3D-0242AC130003");
98 serviceProps[QStringLiteral("Primary")] = true;
99 serviceProps[QStringLiteral("Device")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci0/dev_40_79_6A_0C_39_75"));
100 serviceProps[QStringLiteral("Includes")] = QVariant::fromValue(QList<QDBusObjectPath>());
101 serviceProps[QStringLiteral("Handle")] = QVariant::fromValue(qint16(1));
102 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-gatt-service"), serviceProps);
103
104 serviceProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci1/dev_50_79_6A_0C_39_75/service0"));
105 serviceProps[QStringLiteral("UUID")] = QStringLiteral("0663A394-9A76-4361-9DE6-82577B82AC9A");
106 serviceProps[QStringLiteral("Primary")] = true;
107 serviceProps[QStringLiteral("Device")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci1/dev_50_79_6A_0C_39_75"));
108 serviceProps[QStringLiteral("Includes")] = QVariant::fromValue(QList<QDBusObjectPath>());
109 serviceProps[QStringLiteral("Handle")] = QVariant::fromValue(qint16(2));
110 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-gatt-service"), serviceProps);
111
112 // Create characteristics
113 QVariantMap charProps;
114 charProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci0/dev_40_79_6A_0C_39_75/service0/char0"));
115 charProps[QStringLiteral("UUID")] = QStringLiteral("04FA28C0-2D0C-11EC-8D3D-0242AC130004");
116 charProps[QStringLiteral("Service")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci0/dev_40_79_6A_0C_39_75/service0"));
117 charProps[QStringLiteral("Value")] = QVariant::fromValue(QByteArray());
118 charProps[QStringLiteral("Notifying")] = false;
119 charProps[QStringLiteral("Flags")] = QStringList({QStringLiteral("read"), QStringLiteral("write")});
120 charProps[QStringLiteral("Handle")] = QVariant::fromValue(qint16(3));
121 charProps[QStringLiteral("MTU")] = QVariant::fromValue(qint16(512));
122 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-gatt-characteristic"), charProps);
123
124 charProps[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci1/dev_50_79_6A_0C_39_75/service0/char0"));
125 charProps[QStringLiteral("UUID")] = QStringLiteral("0663A394-9A76-4361-9DE6-82577B82AC9B");
126 charProps[QStringLiteral("Service")] = QVariant::fromValue(QDBusObjectPath("/org/bluez/hci1/dev_50_79_6A_0C_39_75/service0"));
127 charProps[QStringLiteral("Value")] = QVariant::fromValue(QByteArray());
128 charProps[QStringLiteral("Notifying")] = false;
129 charProps[QStringLiteral("Flags")] = QStringList({QStringLiteral("read"), QStringLiteral("write")});
130 charProps[QStringLiteral("Handle")] = QVariant::fromValue(qint16(4));
131 charProps[QStringLiteral("MTU")] = QVariant::fromValue(qint16(512));
132 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("create-gatt-characteristic"), charProps);
133
134
135 m_manager = new Manager();
136 InitManagerJob *initJob = m_manager->init();
137 initJob->exec();
138 QVERIFY(!initJob->error());
139
140 for (const AdapterPtr &adapter : m_manager->adapters()) {
141 QVERIFY(!adapter->ubi().isEmpty());
142
143 for (const DevicePtr &device : adapter->devices()) {
144 QVERIFY(!device->ubi().isEmpty());
145
146 for (const GattServiceRemotePtr &gattService : device->gattServices()) {
147 QVERIFY(!gattService->ubi().isEmpty());
148
149 for (const GattCharacteristicRemotePtr &gattCharacteristic : gattService->characteristics()) {
150 QVERIFY(!gattCharacteristic->ubi().isEmpty());
151
152 GattCharacteristicRemoteUnit u;
153 u.characteristic = gattCharacteristic;
154 u.dbusCharacteristic = new org::bluez::GattCharacteristic1(service, gattCharacteristic->ubi(), connection, this);
155 u.dbusProperties = new org::freedesktop::DBus::Properties(service, gattCharacteristic->ubi(), connection, this);
156 m_units.append(u);
157 }
158
159 QCOMPARE(gattService->characteristics().count(), 1);
160 }
161
162 QCOMPARE(device->gattServices().count(), 1);
163 }
164 }
165
166 QCOMPARE(m_manager->adapters().count(), 2);
167 QCOMPARE(m_manager->devices().count(), 2);
168}
169
170void GattCharacteristicRemoteTest::cleanupTestCase()
171{
172 for (const GattCharacteristicRemoteUnit &unit : std::as_const(m_units)) {
173 delete unit.dbusCharacteristic;
174 delete unit.dbusProperties;
175 }
176
177 delete m_manager;
178
179 FakeBluez::stop();
180}
181
182void GattCharacteristicRemoteTest::getPropertiesTest()
183{
184 for (const GattCharacteristicRemoteUnit &unit : std::as_const(m_units)) {
185 QCOMPARE(unit.characteristic->ubi(), unit.dbusCharacteristic->path());
186 QCOMPARE(unit.characteristic->uuid(), unit.dbusCharacteristic->uUID());
187 QCOMPARE(unit.characteristic->service()->ubi(), unit.dbusCharacteristic->service().path());
188 QCOMPARE(unit.characteristic->value(), unit.dbusCharacteristic->value());
189 QCOMPARE(unit.characteristic->isNotifying(), unit.dbusCharacteristic->notifying());
190 QCOMPARE(unit.characteristic->flags(), unit.dbusCharacteristic->flags());
191 QCOMPARE(unit.characteristic->handle(), unit.dbusCharacteristic->handle());
192 QCOMPARE(unit.characteristic->MTU(), unit.dbusCharacteristic->mTU());
193 }
194}
195
196void GattCharacteristicRemoteTest::setHandleTest()
197{
198 for (const GattCharacteristicRemoteUnit &unit : std::as_const(m_units)) {
199 QSignalSpy characteristicSpy(unit.characteristic.data(), SIGNAL(handleChanged(quint16)));
200 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
201
202 quint16 value = unit.characteristic->handle() + 3;
203
204 unit.characteristic->setHandle(value);
205 QTRY_COMPARE(characteristicSpy.count(), 1);
206
207 QList<QVariant> arguments = characteristicSpy.takeFirst();
208 QCOMPARE(arguments.at(0).toUInt(), value);
209 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Handle"), value);
210
211 QCOMPARE(unit.characteristic->handle(), value);
212 QCOMPARE(unit.dbusCharacteristic->handle(), value);
213 }
214}
215
216void GattCharacteristicRemoteTest::readValueTest()
217{
218 for (const GattCharacteristicRemoteUnit &unit : std::as_const(m_units)) {
219 QSignalSpy characteristicSpy(unit.characteristic.data(), SIGNAL(valueChanged(const QByteArray)));
220 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
221
222
223 // Test initial value
224 QByteArray value = QByteArray();
225 QCOMPARE(unit.characteristic->value(), value);
226 QCOMPARE(unit.dbusCharacteristic->value(), value);
227
228
229 // Test read
230 value = QByteArray("TEST");
231 unit.characteristic->readValue({});
232 QTRY_COMPARE(characteristicSpy.count(), 1);
233
234 QList<QVariant> arguments = characteristicSpy.takeFirst();
235 QCOMPARE(arguments.at(0).value<QByteArray>(), value);
236 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Value"), value);
237
238 QCOMPARE(unit.characteristic->value(), value);
239 QCOMPARE(unit.dbusCharacteristic->value(), value);
240 }
241}
242
243void GattCharacteristicRemoteTest::writeValueTest()
244{
245 for (const GattCharacteristicRemoteUnit &unit : std::as_const(m_units)) {
246 QSignalSpy characteristicSpy(unit.characteristic.data(), SIGNAL(valueChanged(const QByteArray)));
247 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
248
249 // Test write
250 QByteArray value = QByteArray("WRITE");
251 unit.characteristic->writeValue(value, {});
252 QTRY_COMPARE(characteristicSpy.count(), 1);
253
254 QList<QVariant> arguments = characteristicSpy.takeFirst();
255 QCOMPARE(arguments.at(0).value<QByteArray>(), value);
256 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Value"), value);
257
258 QCOMPARE(unit.characteristic->value(), value);
259 QCOMPARE(unit.dbusCharacteristic->value(), value);
260 }
261}
262
263void GattCharacteristicRemoteTest::startNotifyTest()
264{
265 for (const GattCharacteristicRemoteUnit &unit : std::as_const(m_units)) {
266 QSignalSpy characteristicSpy(unit.characteristic.data(), SIGNAL(notifyingChanged(bool)));
267 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
268
269
270 // Test initial value
271 bool value = false;
272 QCOMPARE(unit.characteristic->isNotifying(), value);
273 QCOMPARE(unit.dbusCharacteristic->notifying(), value);
274
275
276 // Test start notifying
277 value = true;
278 unit.characteristic->startNotify();
279 QTRY_COMPARE(characteristicSpy.count(), 1);
280
281 QList<QVariant> arguments = characteristicSpy.takeFirst();
282 QCOMPARE(arguments.at(0).value<bool>(), value);
283 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Notifying"), value);
284
285 QCOMPARE(unit.characteristic->isNotifying(), value);
286 QCOMPARE(unit.dbusCharacteristic->notifying(), value);
287 }
288}
289
290void GattCharacteristicRemoteTest::stopNotifyTest()
291{
292 for (const GattCharacteristicRemoteUnit &unit : std::as_const(m_units)) {
293 QSignalSpy characteristicSpy(unit.characteristic.data(), SIGNAL(notifyingChanged(bool)));
294 QSignalSpy dbusSpy(unit.dbusProperties, SIGNAL(PropertiesChanged(QString, QVariantMap, QStringList)));
295
296
297 // Test initial value
298 bool value = true;
299 QCOMPARE(unit.characteristic->isNotifying(), value);
300 QCOMPARE(unit.dbusCharacteristic->notifying(), value);
301
302
303 // Test start notifying
304 value = false;
305 unit.characteristic->stopNotify();
306 QTRY_COMPARE(characteristicSpy.count(), 1);
307
308 QList<QVariant> arguments = characteristicSpy.takeFirst();
309 QCOMPARE(arguments.at(0).value<bool>(), value);
310 Autotests::verifyPropertiesChangedSignal(dbusSpy, QStringLiteral("Notifying"), value);
311
312 QCOMPARE(unit.characteristic->isNotifying(), value);
313 QCOMPARE(unit.dbusCharacteristic->notifying(), value);
314 }
315}
316
317void GattCharacteristicRemoteTest::characteristicRemovedTest()
318{
319 for (const GattCharacteristicRemoteUnit &unit : std::as_const(m_units)) {
320 QSignalSpy serviceSpy(unit.characteristic->service().data(), SIGNAL(gattCharacteristicRemoved(GattCharacteristicRemotePtr)));
321
322 QVariantMap properties;
323 properties[QStringLiteral("Path")] = QVariant::fromValue(QDBusObjectPath(unit.characteristic->ubi()));
324 FakeBluez::runAction(QStringLiteral("devicemanager"), QStringLiteral("remove-gatt-characteristic"), properties);
325
326 QTRY_COMPARE(serviceSpy.count(), 1);
327
328 QCOMPARE(serviceSpy.at(0).at(0).value<GattCharacteristicRemotePtr>(), unit.characteristic);
329 }
330}
331
332QTEST_MAIN(GattCharacteristicRemoteTest)
333
334#include "moc_gattcharacteristicremotetest.cpp"
335

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