1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtBluetooth module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QtTest/QtTest> |
30 | |
31 | #include <QDebug> |
32 | #include <QMap> |
33 | #include <QTextStream> |
34 | |
35 | #include <qbluetoothtransferrequest.h> |
36 | #include <qbluetoothtransfermanager.h> |
37 | #include <qbluetoothtransferreply.h> |
38 | #include <qbluetoothaddress.h> |
39 | #include <qbluetoothlocaldevice.h> |
40 | |
41 | #include <qbluetoothdeviceinfo.h> |
42 | #include <qbluetoothserviceinfo.h> |
43 | #include <qbluetoothservicediscoveryagent.h> |
44 | |
45 | /* |
46 | * Some tests require a Bluetooth device within the vincinity of the test |
47 | * machine executing this test. The tests require manual interaction |
48 | * as pairing and file transfer requests must be accepted. |
49 | * The remote device's address must be passed |
50 | * via the BT_TEST_DEVICE env variable. The remote device must be |
51 | * discoverable and the object push service must be accessible. Any |
52 | **/ |
53 | |
54 | QT_USE_NAMESPACE |
55 | |
56 | typedef QMap<QBluetoothTransferRequest::Attribute,QVariant> tst_QBluetoothTransferManager_QParameterMap; |
57 | Q_DECLARE_METATYPE(tst_QBluetoothTransferManager_QParameterMap) |
58 | |
59 | static const int MaxConnectTime = 60 * 1000; // 1 minute in ms |
60 | |
61 | class tst_QBluetoothTransferManager : public QObject |
62 | { |
63 | Q_OBJECT |
64 | |
65 | public: |
66 | tst_QBluetoothTransferManager(); |
67 | ~tst_QBluetoothTransferManager(); |
68 | |
69 | private slots: |
70 | void initTestCase(); |
71 | |
72 | void tst_construction(); |
73 | |
74 | void tst_request_data(); |
75 | void tst_request(); |
76 | |
77 | void tst_sendFile_data(); |
78 | void tst_sendFile(); |
79 | |
80 | void tst_sendBuffer_data(); |
81 | void tst_sendBuffer(); |
82 | |
83 | void tst_sendNullPointer(); |
84 | private: |
85 | QBluetoothAddress remoteAddress; |
86 | }; |
87 | |
88 | tst_QBluetoothTransferManager::tst_QBluetoothTransferManager() |
89 | { |
90 | } |
91 | |
92 | tst_QBluetoothTransferManager::~tst_QBluetoothTransferManager() |
93 | { |
94 | } |
95 | |
96 | void tst_QBluetoothTransferManager::initTestCase() |
97 | { |
98 | const QString remote = qgetenv(varName: "BT_TEST_DEVICE" ); |
99 | if (!remote.isEmpty()) { |
100 | remoteAddress = QBluetoothAddress(remote); |
101 | QVERIFY(!remoteAddress.isNull()); |
102 | qWarning() << "Using remote device " << remote << " for testing. Ensure that the device is discoverable for pairing requests" ; |
103 | } else { |
104 | qWarning() << "Not using any remote device for testing. Set BT_TEST_DEVICE env to run manual tests involving a remote device" ; |
105 | QSKIP("Remote upload test not possible. Set BT_TEST_DEVICE" ); |
106 | } |
107 | |
108 | if (!QBluetoothLocalDevice::allDevices().count()) |
109 | QSKIP("Skipping test due to missing Bluetooth device" ); |
110 | |
111 | // start Bluetooth if not started |
112 | QBluetoothLocalDevice *device = new QBluetoothLocalDevice(); |
113 | device->powerOn(); |
114 | delete device; |
115 | } |
116 | |
117 | void tst_QBluetoothTransferManager::tst_construction() |
118 | { |
119 | QBluetoothTransferManager *manager = new QBluetoothTransferManager(); |
120 | |
121 | QVERIFY(manager); |
122 | delete manager; |
123 | } |
124 | |
125 | void tst_QBluetoothTransferManager::tst_request_data() |
126 | { |
127 | QTest::addColumn<QBluetoothAddress>(name: "address" ); |
128 | QTest::addColumn<QMap<QBluetoothTransferRequest::Attribute, QVariant> >(name: "parameters" ); |
129 | |
130 | QMap<QBluetoothTransferRequest::Attribute, QVariant> inparameters; |
131 | inparameters.insert(akey: QBluetoothTransferRequest::DescriptionAttribute, avalue: "Description" ); |
132 | inparameters.insert(akey: QBluetoothTransferRequest::LengthAttribute, avalue: QVariant(1024)); |
133 | inparameters.insert(akey: QBluetoothTransferRequest::TypeAttribute, avalue: "OPP" ); |
134 | inparameters.insert(akey: QBluetoothTransferRequest::NameAttribute, avalue: "name" ); |
135 | inparameters.insert(akey: QBluetoothTransferRequest::TimeAttribute, avalue: QDateTime::currentDateTime()); |
136 | |
137 | QTest::newRow(dataTag: "TESTDATA" ) << QBluetoothAddress("00:11:22:33:44:55:66" ) << inparameters; |
138 | } |
139 | |
140 | void tst_QBluetoothTransferManager::tst_request() |
141 | { |
142 | QFETCH(QBluetoothAddress, address); |
143 | QFETCH(tst_QBluetoothTransferManager_QParameterMap, parameters); |
144 | |
145 | QBluetoothTransferRequest transferRequest(address); |
146 | const QList<QBluetoothTransferRequest::Attribute> attributes = parameters.keys(); |
147 | for (QBluetoothTransferRequest::Attribute key : attributes) |
148 | QCOMPARE(transferRequest.attribute(key), QVariant()); |
149 | |
150 | for (QBluetoothTransferRequest::Attribute key : attributes) |
151 | transferRequest.setAttribute(code: (QBluetoothTransferRequest::Attribute)key, value: parameters[key]); |
152 | |
153 | QCOMPARE(transferRequest.address(), address); |
154 | for (QBluetoothTransferRequest::Attribute key : attributes) |
155 | QCOMPARE(transferRequest.attribute(key), parameters[key]); |
156 | |
157 | //test copy constructor |
158 | QBluetoothTransferRequest constructorCopy = transferRequest; |
159 | QVERIFY(constructorCopy == transferRequest); |
160 | QVERIFY(!(constructorCopy != transferRequest)); |
161 | QCOMPARE(constructorCopy.address(), address); |
162 | for (QBluetoothTransferRequest::Attribute key : attributes) |
163 | QCOMPARE(constructorCopy.attribute(key), parameters[key]); |
164 | |
165 | //test assignment operator |
166 | QBluetoothTransferRequest request; |
167 | QVERIFY(request.address().isNull()); |
168 | for (QBluetoothTransferRequest::Attribute key : attributes) |
169 | QCOMPARE(request.attribute(key), QVariant()); |
170 | request = transferRequest; |
171 | QCOMPARE(request.address(), address); |
172 | for (QBluetoothTransferRequest::Attribute key : attributes) |
173 | QCOMPARE(request.attribute(key), parameters[key]); |
174 | |
175 | //test that it's a true and independent copy |
176 | constructorCopy.setAttribute(code: QBluetoothTransferRequest::DescriptionAttribute, value: "newDescription" ); |
177 | request.setAttribute(code: QBluetoothTransferRequest::TypeAttribute, value: "FTP" ); |
178 | |
179 | QCOMPARE(constructorCopy.attribute(QBluetoothTransferRequest::DescriptionAttribute).toString(),QString("newDescription" )); |
180 | QCOMPARE(request.attribute(QBluetoothTransferRequest::DescriptionAttribute).toString(),QString("Description" )); |
181 | QCOMPARE(transferRequest.attribute(QBluetoothTransferRequest::DescriptionAttribute).toString(),QString("Description" )); |
182 | |
183 | QCOMPARE(constructorCopy.attribute(QBluetoothTransferRequest::TypeAttribute).toString(),QString("OPP" )); |
184 | QCOMPARE(request.attribute(QBluetoothTransferRequest::TypeAttribute).toString(),QString("FTP" )); |
185 | QCOMPARE(transferRequest.attribute(QBluetoothTransferRequest::TypeAttribute).toString(),QString("OPP" )); |
186 | } |
187 | |
188 | void tst_QBluetoothTransferManager::tst_sendFile_data() |
189 | { |
190 | QTest::addColumn<QBluetoothAddress>(name: "deviceAddress" ); |
191 | QTest::addColumn<bool>(name: "expectSuccess" ); |
192 | QTest::addColumn<bool>(name: "isInvalidFile" ); |
193 | |
194 | QTest::newRow(dataTag: "Push to remote test device" ) << remoteAddress << true << false; |
195 | QTest::newRow(dataTag: "Push of non-existing file" ) << remoteAddress << false << true; |
196 | QTest::newRow(dataTag: "Push to invalid address" ) << QBluetoothAddress() << false << false; |
197 | QTest::newRow(dataTag: "Push to non-existend device" ) << QBluetoothAddress("11:22:33:44:55:66" ) << false << false; |
198 | |
199 | } |
200 | |
201 | void tst_QBluetoothTransferManager::tst_sendFile() |
202 | { |
203 | QFETCH(QBluetoothAddress, deviceAddress); |
204 | QFETCH(bool, expectSuccess); |
205 | QFETCH(bool, isInvalidFile); |
206 | |
207 | QBluetoothLocalDevice dev; |
208 | if (expectSuccess) { |
209 | dev.requestPairing(address: deviceAddress, pairing: QBluetoothLocalDevice::Paired); |
210 | QTest::qWait(ms: 5000); |
211 | QCOMPARE(dev.pairingStatus(deviceAddress), QBluetoothLocalDevice::Paired); |
212 | } |
213 | |
214 | QBluetoothTransferRequest request(deviceAddress); |
215 | QCOMPARE(request.address(), deviceAddress); |
216 | |
217 | QBluetoothTransferManager manager; |
218 | QString fileHandle; |
219 | if (!isInvalidFile) { |
220 | fileHandle = QFINDTESTDATA("testfile.txt" ); |
221 | QVERIFY(!fileHandle.isEmpty()); |
222 | } else { |
223 | fileHandle = ("arbitraryFileName.txt" ); //file doesn't exist |
224 | } |
225 | QFile f(fileHandle); |
226 | QCOMPARE(f.exists(), !isInvalidFile); |
227 | |
228 | |
229 | qDebug() << "Transferring file to " << deviceAddress.toString(); |
230 | if (expectSuccess) |
231 | qDebug() << "Please accept Object push request on remote device" ; |
232 | QBluetoothTransferReply* reply = manager.put(request, data: &f); |
233 | QSignalSpy finishedSpy(reply, SIGNAL(finished(QBluetoothTransferReply*))); |
234 | QSignalSpy progressSpy(reply, SIGNAL(transferProgress(qint64,qint64))); |
235 | QSignalSpy errorSpy(reply, SIGNAL(error(QBluetoothTransferReply::TransferError))); |
236 | |
237 | QCOMPARE(reply->request(), request); |
238 | QVERIFY(reply->manager() == &manager); |
239 | QVERIFY(!reply->isFinished()); |
240 | QVERIFY(reply->isRunning()); |
241 | |
242 | const int maxWaitTime = 20 * 1000; //20s |
243 | for (int time = 0; |
244 | time<maxWaitTime && (finishedSpy.count()==0); |
245 | time+=1000) { |
246 | QTest::qWait(ms: 1000); //if interval |
247 | } |
248 | |
249 | QVERIFY(finishedSpy.count()>0); |
250 | if (expectSuccess) { |
251 | QVERIFY(progressSpy.count()>0); |
252 | QCOMPARE(reply->error(), QBluetoothTransferReply::NoError); |
253 | QCOMPARE(reply->errorString(), QString()); |
254 | QVERIFY(errorSpy.isEmpty()); |
255 | } else { |
256 | QVERIFY(progressSpy.count() == 0); |
257 | if (isInvalidFile) |
258 | QVERIFY(reply->error() == QBluetoothTransferReply::FileNotFoundError); |
259 | else |
260 | QVERIFY(reply->error() != QBluetoothTransferReply::NoError); |
261 | QVERIFY(!reply->errorString().isEmpty()); |
262 | QCOMPARE(errorSpy.count(), 1); |
263 | } |
264 | |
265 | QVERIFY(reply->isFinished()); |
266 | QVERIFY(!reply->isRunning()); |
267 | } |
268 | |
269 | void tst_QBluetoothTransferManager::tst_sendBuffer_data() |
270 | { |
271 | |
272 | QTest::addColumn<QBluetoothAddress>(name: "deviceAddress" ); |
273 | QTest::addColumn<bool>(name: "expectSuccess" ); |
274 | QTest::addColumn<QByteArray>(name: "data" ); |
275 | |
276 | QTest::newRow(dataTag: "Push to remote test device" ) << remoteAddress << true << |
277 | QByteArray("This is a very long byte array which we are going to access via a QBuffer" ); ; |
278 | QTest::newRow(dataTag: "Push to invalid address" ) << QBluetoothAddress() << false << QByteArray("test" ); |
279 | QTest::newRow(dataTag: "Push to non-existend device" ) << QBluetoothAddress("11:22:33:44:55:66" ) << false << QByteArray("test" ); |
280 | } |
281 | |
282 | |
283 | |
284 | void tst_QBluetoothTransferManager::tst_sendBuffer() |
285 | { |
286 | QFETCH(QBluetoothAddress, deviceAddress); |
287 | QFETCH(bool, expectSuccess); |
288 | QFETCH(QByteArray, data); |
289 | |
290 | QBuffer buffer; |
291 | buffer.setData(data); |
292 | buffer.open(openMode: QIODevice::ReadOnly); |
293 | buffer.seek(off: 0); |
294 | |
295 | QBluetoothLocalDevice dev; |
296 | if (expectSuccess) { |
297 | dev.requestPairing(address: deviceAddress, pairing: QBluetoothLocalDevice::Paired); |
298 | QTest::qWait(ms: 2000); |
299 | QCOMPARE(dev.pairingStatus(deviceAddress), QBluetoothLocalDevice::Paired); |
300 | } |
301 | |
302 | QBluetoothTransferRequest request(deviceAddress); |
303 | QCOMPARE(request.address(), deviceAddress); |
304 | |
305 | QBluetoothTransferManager manager; |
306 | |
307 | qDebug() << "Transferring test buffer to " << deviceAddress.toString(); |
308 | if (expectSuccess) |
309 | qDebug() << "Please accept Object push request on remote device" ; |
310 | QBluetoothTransferReply* reply = manager.put(request, data: &buffer); |
311 | QSignalSpy finishedSpy(reply, SIGNAL(finished(QBluetoothTransferReply*))); |
312 | QSignalSpy progressSpy(reply, SIGNAL(transferProgress(qint64,qint64))); |
313 | QSignalSpy errorSpy(reply, SIGNAL(error(QBluetoothTransferReply::TransferError))); |
314 | |
315 | QCOMPARE(reply->request(), request); |
316 | QVERIFY(reply->manager() == &manager); |
317 | QVERIFY(!reply->isFinished()); |
318 | QVERIFY(reply->isRunning()); |
319 | |
320 | const int maxWaitTime = 20 * 1000; //20s |
321 | for (int time = 0; |
322 | time<maxWaitTime && (finishedSpy.count()==0); |
323 | time+=10000) { |
324 | QTest::qWait(ms: 10000); //if interval |
325 | } |
326 | |
327 | QVERIFY(finishedSpy.count()>0); |
328 | if (expectSuccess) { |
329 | QVERIFY(progressSpy.count()>0); |
330 | QVERIFY(errorSpy.isEmpty()); |
331 | QCOMPARE(reply->error(), QBluetoothTransferReply::NoError); |
332 | QCOMPARE(reply->errorString(), QString()); |
333 | } else { |
334 | QVERIFY(progressSpy.count() == 0); |
335 | QVERIFY(reply->error() != QBluetoothTransferReply::NoError); |
336 | QVERIFY(!reply->errorString().isEmpty()); |
337 | QCOMPARE(errorSpy.count(), 1); |
338 | } |
339 | |
340 | QVERIFY(reply->isFinished()); |
341 | QVERIFY(!reply->isRunning()); |
342 | } |
343 | |
344 | void tst_QBluetoothTransferManager::tst_sendNullPointer() |
345 | { |
346 | QBluetoothTransferRequest request(remoteAddress); |
347 | QBluetoothTransferManager manager; |
348 | QBluetoothTransferReply *reply = manager.put(request, data: 0); |
349 | |
350 | QVERIFY(reply); |
351 | QCOMPARE(reply->isFinished(), true); |
352 | QCOMPARE(reply->isRunning(), false); |
353 | QCOMPARE(reply->manager(), &manager); |
354 | QCOMPARE(reply->request(), request); |
355 | QCOMPARE(reply->error(), QBluetoothTransferReply::FileNotFoundError); |
356 | } |
357 | |
358 | QTEST_MAIN(tst_QBluetoothTransferManager) |
359 | |
360 | #include "tst_qbluetoothtransfermanager.moc" |
361 | |