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 | |
19 | namespace BluezQt |
20 | { |
21 | extern void bluezqt_initFakeBluezTestRun(); |
22 | } |
23 | |
24 | using namespace BluezQt; |
25 | |
26 | GattCharacteristicRemoteTest::GattCharacteristicRemoteTest() |
27 | : m_manager(nullptr) |
28 | { |
29 | Autotests::registerMetatypes(); |
30 | } |
31 | |
32 | void 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 | |
170 | void 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 | |
182 | void 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 | |
196 | void 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 | |
216 | void 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 | |
243 | void 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 | |
263 | void 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 | |
290 | void 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 | |
317 | void 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 | |
332 | QTEST_MAIN(GattCharacteristicRemoteTest) |
333 | |
334 | #include "moc_gattcharacteristicremotetest.cpp" |
335 | |