summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorAlex Blasche <alexander.blasche@digia.com>2014-06-27 13:57:09 +0200
committerAlex Blasche <alexander.blasche@digia.com>2014-07-02 16:17:12 +0200
commitc35020419edafae6e7d1f0489942909a611f729f (patch)
tree17e9b68b2fe693a8a62e15fe29630219fe353143 /tests
parentbdf895b5fffe8c79c2b1d60b7cad8f8b1ffa72b4 (diff)
Add more unit testing to verify robustness of L2CP communication
Verifies that multiple services can be discovered at the same time and confirms the correct behavior of the controller when reconnecting (old service objects become invalid but retain data and new service objects have same data and are valid). Change-Id: I7e5a809a050c6effaac9a9dc90024be8a5e8d418 Reviewed-by: Fabian Bumberger <fbumberger@rim.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp188
1 files changed, 185 insertions, 3 deletions
diff --git a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp
index 39b1fbe0..1710abed 100644
--- a/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp
+++ b/tests/auto/qlowenergycontroller/tst_qlowenergycontroller.cpp
@@ -72,6 +72,7 @@ private slots:
void tst_verifyAllServices();
void tst_connect();
void tst_connectNew();
+ void tst_concurrentDiscovery();
void tst_defaultBehavior();
private:
@@ -751,8 +752,8 @@ void tst_QLowEnergyController::tst_connect()
void tst_QLowEnergyController::tst_connectNew()
{
QList<QBluetoothHostInfo> localAdapters = QBluetoothLocalDevice::allDevices();
- if (localAdapters.isEmpty())
- QSKIP("No local Bluetooth device found. Skipping test.");
+ if (localAdapters.isEmpty() || remoteDevice.isNull())
+ QSKIP("No local Bluetooth or remote BTLE device found. Skipping test.");
const QBluetoothAddress localAdapter = localAdapters.at(0).address();
QLowEnergyControllerNew control(remoteDevice);
@@ -824,6 +825,12 @@ void tst_QLowEnergyController::tst_connectNew()
QCOMPARE(service->state(), QLowEnergyService::DiscoveryRequired);
}
+ // unrelated uuids don't return valid service object
+ // invalid service uuid
+ QVERIFY(!control.createServiceObject(QBluetoothUuid()));
+ // some random uuid
+ QVERIFY(!control.createServiceObject(QBluetoothUuid(QBluetoothUuid::DeviceName)));
+
// initiate characteristic discovery
foreach (QLowEnergyService *service, savedReferences) {
qDebug() << "Discoverying" << service->serviceUuid();
@@ -840,6 +847,15 @@ void tst_QLowEnergyController::tst_connectNew()
verifyServiceProperties(service);
}
+
+ // ensure that related service objects share same state
+ foreach (QLowEnergyService* originalService, savedReferences) {
+ QLowEnergyService *newService = control.createServiceObject(
+ originalService->serviceUuid());
+ QVERIFY(newService);
+ QCOMPARE(newService->state(), QLowEnergyService::ServiceDiscovered);
+ delete newService;
+ }
}
// Finish off
@@ -852,12 +868,20 @@ void tst_QLowEnergyController::tst_connectNew()
QCOMPARE(disconnectedSpy.count(), 0);
} else {
QCOMPARE(disconnectedSpy.count(), 1);
-
// after disconnect all service references must be invalid
foreach (const QLowEnergyService *entry, savedReferences) {
const QBluetoothUuid &uuid = entry->serviceUuid();
QVERIFY2(entry->state() == QLowEnergyService::InvalidService,
uuid.toString().toLatin1());
+
+ //after disconnect all related characteristics and descriptors are invalid
+ QList<QLowEnergyCharacteristic> chars = entry->characteristics();
+ for (int i = 0; i < chars.count(); i++) {
+ QCOMPARE(chars.at(i).isValid(), false);
+ QList<QLowEnergyDescriptor> descriptors = chars[i].descriptors();
+ for (int j = 0; j < descriptors.count(); j++)
+ QCOMPARE(descriptors[j].isValid(), false);
+ }
}
}
@@ -865,6 +889,143 @@ void tst_QLowEnergyController::tst_connectNew()
savedReferences.clear();
}
+void tst_QLowEnergyController::tst_concurrentDiscovery()
+{
+ QList<QBluetoothHostInfo> localAdapters = QBluetoothLocalDevice::allDevices();
+ if (localAdapters.isEmpty() || remoteDevice.isNull())
+ QSKIP("No local Bluetooth or remote BTLE device found. Skipping test.");
+
+ // quick setup - more elaborate test is done by connectNew()
+ QLowEnergyControllerNew control(remoteDevice);
+ QCOMPARE(control.state(), QLowEnergyControllerNew::UnconnectedState);
+ QCOMPARE(control.error(), QLowEnergyControllerNew::NoError);
+
+ control.connectToDevice();
+ {
+ QTRY_IMPL(control.state() != QLowEnergyControllerNew::ConnectingState,
+ 30000);
+ }
+
+ if (control.state() == QLowEnergyControllerNew::ConnectingState
+ || control.error() != QLowEnergyControllerNew::NoError) {
+ // default BTLE backend forever hangs in ConnectingState
+ QSKIP("Cannot connect to remote device");
+ }
+
+ QCOMPARE(control.state(), QLowEnergyControllerNew::ConnectedState);
+
+ // 2. new controller to same device fails
+ {
+ QLowEnergyControllerNew control2(remoteDevice);
+ control2.connectToDevice();
+ {
+ QTRY_IMPL(control2.state() != QLowEnergyControllerNew::ConnectingState,
+ 30000);
+ }
+
+ QVERIFY(control2.error() != QLowEnergyControllerNew::NoError);
+ }
+
+ /* We are testing that we can run service discovery on the same device
+ * for multiple services at the same time.
+ * */
+
+ QSignalSpy discoveryFinishedSpy(&control, SIGNAL(discoveryFinished()));
+ control.discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 10000);
+
+ // pick MAX_SERVICES_SAME_TIME_ACCESS services
+ // and discover them at the same time
+#define MAX_SERVICES_SAME_TIME_ACCESS 3
+ QLowEnergyService *services[MAX_SERVICES_SAME_TIME_ACCESS];
+
+ QVERIFY(control.services().count() >= MAX_SERVICES_SAME_TIME_ACCESS);
+
+ QList<QBluetoothUuid> uuids = control.services();
+
+ // initialize services
+ for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
+ services[i] = control.createServiceObject(uuids.at(i));
+ QVERIFY(services[i]);
+ }
+
+ // start complete discovery
+ for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++)
+ services[i]->discoverDetails();
+
+ // wait until discovery done
+ for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
+ qWarning() << "Waiting for" << i << services[i]->serviceUuid();
+ QTRY_VERIFY_WITH_TIMEOUT(
+ services[i]->state() == QLowEnergyService::ServiceDiscovered,
+ 30000);
+ }
+
+ // verify discovered services
+ for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++)
+ verifyServiceProperties(services[i]);
+
+ control.disconnectFromDevice();
+ QTRY_VERIFY_WITH_TIMEOUT(control.state() == QLowEnergyControllerNew::UnconnectedState,
+ 30000);
+ discoveryFinishedSpy.clear();
+
+ // redo the discovery with same controller
+ QLowEnergyService *services_second[MAX_SERVICES_SAME_TIME_ACCESS];
+ control.connectToDevice();
+ {
+ QTRY_IMPL(control.state() != QLowEnergyControllerNew::ConnectingState,
+ 30000);
+ }
+
+ QCOMPARE(control.state(), QLowEnergyControllerNew::ConnectedState);
+ control.discoverServices();
+ QTRY_VERIFY_WITH_TIMEOUT(discoveryFinishedSpy.count() == 1, 10000);
+
+ // get all details
+ for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
+ services_second[i] = control.createServiceObject(uuids.at(i));
+ QVERIFY(services[i]);
+ services_second[i]->discoverDetails();
+ }
+
+ // wait until discovery done
+ for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
+ qWarning() << "Waiting for" << i << services_second[i]->serviceUuid();
+ QTRY_VERIFY_WITH_TIMEOUT(
+ services_second[i]->state() == QLowEnergyService::ServiceDiscovered,
+ 30000);
+ }
+
+ // verify discovered services (1st and 2nd round)
+ for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
+
+ verifyServiceProperties(services_second[i]);
+ //after disconnect all related characteristics and descriptors are invalid
+ const QList<QLowEnergyCharacteristic> chars = services[i]->characteristics();
+ for (int j = 0; j < chars.count(); j++) {
+ QCOMPARE(chars.at(j).isValid(), false);
+ const QList<QLowEnergyDescriptor> descriptors = chars[j].descriptors();
+ for (int k = 0; k < descriptors.count(); k++)
+ QCOMPARE(descriptors[k].isValid(), false);
+ }
+
+ QCOMPARE(services[i]->serviceUuid(), services_second[i]->serviceUuid());
+ QCOMPARE(services[i]->serviceName(), services_second[i]->serviceName());
+ QCOMPARE(services[i]->type(), services_second[i]->type());
+ QVERIFY(services[i]->state() == QLowEnergyService::InvalidService);
+ QVERIFY(services_second[i]->state() == QLowEnergyService::ServiceDiscovered);
+ }
+
+ // cleanup
+ for (int i = 0; i<MAX_SERVICES_SAME_TIME_ACCESS; i++) {
+ delete services[i];
+ delete services_second[i];
+ }
+
+ control.disconnectFromDevice();
+}
+
void tst_QLowEnergyController::verifyServiceProperties(
const QLowEnergyService *info)
{
@@ -1580,8 +1741,18 @@ void tst_QLowEnergyController::tst_defaultBehavior()
QCOMPARE(controlDefaultAdapter.error(), QLowEnergyControllerNew::NoError);
QVERIFY(controlDefaultAdapter.errorString().isEmpty());
QVERIFY(foundAddresses.contains(controlDefaultAdapter.localAddress()));
+
+ // unrelated uuids don't return valid service object
+ // invalid service uuid
+ QVERIFY(!controlDefaultAdapter.createServiceObject(
+ QBluetoothUuid()));
+ // some random uuid
+ QVERIFY(!controlDefaultAdapter.createServiceObject(
+ QBluetoothUuid(QBluetoothUuid::DeviceName)));
}
+ QCOMPARE(controlDefaultAdapter.services().count(), 0);
+
// Test explicit local adapter
if (!foundAddresses.isEmpty()) {
QLowEnergyControllerNew controlExplicitAdapter(randomAddress,
@@ -1590,7 +1761,18 @@ void tst_QLowEnergyController::tst_defaultBehavior()
QCOMPARE(controlExplicitAdapter.localAddress(), foundAddresses[0]);
QCOMPARE(controlExplicitAdapter.state(),
QLowEnergyControllerNew::UnconnectedState);
+ QCOMPARE(controlExplicitAdapter.services().count(), 0);
+
+ // unrelated uuids don't return valid service object
+ // invalid service uuid
+ QVERIFY(!controlExplicitAdapter.createServiceObject(
+ QBluetoothUuid()));
+ // some random uuid
+ QVERIFY(!controlExplicitAdapter.createServiceObject(
+ QBluetoothUuid(QBluetoothUuid::DeviceName)));
}
+
+
}
QTEST_MAIN(tst_QLowEnergyController)