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

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