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 | |
20 | namespace BluezQt |
21 | { |
22 | extern void bluezqt_initFakeBluezTestRun(); |
23 | } |
24 | |
25 | using namespace BluezQt; |
26 | |
27 | GattDescriptorRemoteTest::GattDescriptorRemoteTest() |
28 | : m_manager(nullptr) |
29 | { |
30 | Autotests::registerMetatypes(); |
31 | qRegisterMetaType<BluezQt::GattDescriptorRemotePtr>("GattDescriptorRemotePtr" ); |
32 | } |
33 | |
34 | void 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 | |
196 | void 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 | |
208 | void 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 | |
220 | void 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 | |
240 | void 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 | |
267 | void 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 | |
287 | void 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 | |
302 | QTEST_MAIN(GattDescriptorRemoteTest) |
303 | |
304 | #include "moc_gattdescriptorremotetest.cpp" |
305 | |