diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp | 72 | ||||
-rw-r--r-- | tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp | 115 |
2 files changed, 176 insertions, 11 deletions
diff --git a/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp b/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp index b1fc7256..97adf9db 100644 --- a/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp +++ b/tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp @@ -48,6 +48,9 @@ static QByteArray deviceName() { return "Qt GATT server"; } static QScopedPointer<QLowEnergyController> leController; typedef QSharedPointer<QLowEnergyService> ServicePtr; static QHash<QBluetoothUuid, ServicePtr> services; +static int descriptorWriteCount = 0; +static int disconnectCount = 0; +static QBluetoothAddress remoteDevice; void addService(const QLowEnergyServiceData &serviceData) { @@ -64,7 +67,7 @@ void addRunningSpeedService() QLowEnergyDescriptorData desc; desc.setUuid(QBluetoothUuid::ClientCharacteristicConfiguration); - desc.setValue(QByteArray(1, 0)); // Default: No indication, no notification. + desc.setValue(QByteArray(2, 0)); // Default: No indication, no notification. QLowEnergyCharacteristicData charData; charData.setUuid(QBluetoothUuid::RSCMeasurement); charData.addDescriptor(desc); @@ -111,7 +114,7 @@ void addGenericAccessService() void addCustomService() { QLowEnergyServiceData serviceData; - serviceData.setUuid(QBluetoothUuid(quint16(0x2000))); // Made up. + serviceData.setUuid(QBluetoothUuid(quint16(0x2000))); serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary); QLowEnergyCharacteristicData charData; @@ -120,12 +123,24 @@ void addCustomService() charData.setValue(QByteArray(1024, 'x')); // Long value to test "Read Blob". serviceData.addCharacteristic(charData); - charData.setUuid(QBluetoothUuid(quint16(0x5001))); // Made up. + charData.setUuid(QBluetoothUuid(quint16(0x5001))); charData.setProperties(QLowEnergyCharacteristic::Read); charData.setReadConstraints(QBluetooth::AttAuthorizationRequired); // To test read failure. serviceData.addCharacteristic(charData); charData.setValue("something"); + charData.setUuid(QBluetoothUuid(quint16(0x5002))); + charData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Indicate); + charData.setReadConstraints(QBluetooth::AttAccessConstraints()); + const QLowEnergyDescriptorData desc(QBluetoothUuid::ClientCharacteristicConfiguration, + QByteArray(2, 0)); + charData.addDescriptor(desc); + serviceData.addCharacteristic(charData); + + charData.setUuid(QBluetoothUuid(quint16(0x5003))); + charData.setProperties(QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Notify); + serviceData.addCharacteristic(charData); + addService(serviceData); } @@ -150,8 +165,55 @@ int main(int argc, char *argv[]) addCustomService(); startAdvertising(); - // TODO: Change characteristics, client checks that it gets indication/notification - // TODO: Where to test that we get the characteristicChanged signal for characteristics that the client writes? + const ServicePtr customService = services.value(QBluetoothUuid(quint16(0x2000))); + Q_ASSERT(customService); + + const auto stateChangedHandler = [customService]() { + switch (leController->state()) { + case QLowEnergyController::ConnectedState: + remoteDevice = leController->remoteAddress(); + break; + case QLowEnergyController::UnconnectedState: { + if (++disconnectCount == 2) { + qApp->quit(); + break; + } + Q_ASSERT(disconnectCount == 1); + const QLowEnergyCharacteristic indicatableChar + = customService->characteristic(QBluetoothUuid(quint16(0x5002))); + Q_ASSERT(indicatableChar.isValid()); + customService->writeCharacteristic(indicatableChar, "indicated2"); + Q_ASSERT(indicatableChar.value() == "indicated2"); + const QLowEnergyCharacteristic notifiableChar + = customService->characteristic(QBluetoothUuid(quint16(0x5003))); + Q_ASSERT(notifiableChar.isValid()); + customService->writeCharacteristic(notifiableChar, "notified2"); + Q_ASSERT(notifiableChar.value() == "notified2"); + startAdvertising(); + break; + } + default: + break; + } + }; + + QObject::connect(leController.data(), &QLowEnergyController::stateChanged, stateChangedHandler); + const auto descriptorWriteHandler = [customService]() { + if (++descriptorWriteCount != 2) + return; + const QLowEnergyCharacteristic indicatableChar + = customService->characteristic(QBluetoothUuid(quint16(0x5002))); + Q_ASSERT(indicatableChar.isValid()); + customService->writeCharacteristic(indicatableChar, "indicated"); + Q_ASSERT(indicatableChar.value() == "indicated"); + const QLowEnergyCharacteristic notifiableChar + = customService->characteristic(QBluetoothUuid(quint16(0x5003))); + Q_ASSERT(notifiableChar.isValid()); + customService->writeCharacteristic(notifiableChar, "notified"); + Q_ASSERT(notifiableChar.value() == "notified"); + }; + QObject::connect(customService.data(), &QLowEnergyService::descriptorWritten, + descriptorWriteHandler); return app.exec(); } diff --git a/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp b/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp index 25098273..c1701217 100644 --- a/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp +++ b/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp @@ -34,6 +34,7 @@ #include <QtBluetooth/qbluetoothaddress.h> #include <QtBluetooth/qbluetoothdevicediscoveryagent.h> #include <QtBluetooth/qbluetoothdeviceinfo.h> +#include <QtBluetooth/qbluetoothlocaldevice.h> #include <QtBluetooth/qlowenergyadvertisingdata.h> #include <QtBluetooth/qlowenergyadvertisingparameters.h> #include <QtBluetooth/qlowenergycontroller.h> @@ -63,7 +64,7 @@ private slots: // Interaction with actual GATT server goes here. Order is relevant. void advertisedData(); - void initialServices(); + void serverCommunication(); private: QBluetoothAddress m_serverAddress; @@ -171,8 +172,15 @@ void TestQLowEnergyControllerGattServer::advertisedData() QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid(quint16(0x2000)))); } -void TestQLowEnergyControllerGattServer::initialServices() +// TODO: Why on earth is this not in the library??? +Q_DECLARE_METATYPE(QLowEnergyCharacteristic) +Q_DECLARE_METATYPE(QLowEnergyDescriptor) + +void TestQLowEnergyControllerGattServer::serverCommunication() { + qRegisterMetaType<QLowEnergyCharacteristic>(); + qRegisterMetaType<QLowEnergyDescriptor>(); + if (m_serverAddress.isNull()) QSKIP("No server address provided"); m_leController.reset(QLowEnergyController::createCentral(m_serverInfo)); @@ -235,7 +243,7 @@ void TestQLowEnergyControllerGattServer::initialServices() const QLowEnergyDescriptor clientConfigDesc = measurementChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); QVERIFY(clientConfigDesc.isValid()); - QCOMPARE(clientConfigDesc.value(), QByteArray(1, 0)); + QCOMPARE(clientConfigDesc.value(), QByteArray(2, 0)); QCOMPARE(measurementChar.properties(), QLowEnergyCharacteristic::Notify); QCOMPARE(measurementChar.value(), QByteArray()); // Empty because Read property not set QLowEnergyCharacteristic featureChar @@ -247,16 +255,16 @@ void TestQLowEnergyControllerGattServer::initialServices() featureValue[0] = 1 << 2; QCOMPARE(featureChar.value(), featureValue); - const QScopedPointer<QLowEnergyService> customService( + QScopedPointer<QLowEnergyService> customService( m_leController->createServiceObject(QBluetoothUuid(quint16(0x2000)))); QVERIFY(!customService.isNull()); customService->discoverDetails(); while (customService->state() != QLowEnergyService::ServiceDiscovered) { spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::stateChanged)); - QVERIFY(spy->wait(3000)); + QVERIFY(spy->wait(5000)); } QCOMPARE(customService->includedServices().count(), 0); - QCOMPARE(customService->characteristics().count(), 2); + QCOMPARE(customService->characteristics().count(), 4); QLowEnergyCharacteristic customChar = customService->characteristic(QBluetoothUuid(quint16(0x5000))); QVERIFY(customChar.isValid()); @@ -269,11 +277,99 @@ void TestQLowEnergyControllerGattServer::initialServices() QCOMPARE(customChar2.descriptors().count(), 0); QCOMPARE(customChar2.value(), QByteArray()); // Was not readable due to authorization requirement. + QLowEnergyCharacteristic customChar3 + = customService->characteristic(QBluetoothUuid(quint16(0x5002))); + QVERIFY(customChar3.isValid()); + QCOMPARE(customChar3.properties(), + QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Indicate); + QCOMPARE(customChar3.descriptors().count(), 1); + QLowEnergyDescriptor cc3ClientConfig + = customChar3.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + QVERIFY(cc3ClientConfig.isValid()); + + QLowEnergyCharacteristic customChar4 + = customService->characteristic(QBluetoothUuid(quint16(0x5003))); + QVERIFY(customChar4.isValid()); + QCOMPARE(customChar4.properties(), + QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Notify); + QCOMPARE(customChar4.descriptors().count(), 1); + QLowEnergyDescriptor cc4ClientConfig + = customChar4.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + QVERIFY(cc4ClientConfig.isValid()); + customService->writeCharacteristic(customChar, "whatever"); spy.reset(new QSignalSpy(customService.data(), static_cast<void (QLowEnergyService::*) (QLowEnergyService::ServiceError)>(&QLowEnergyService::error))); QVERIFY(spy->wait(3000)); QCOMPARE(customService->error(), QLowEnergyService::CharacteristicWriteError); + + QByteArray indicateValue(2, 0); + indicateValue[0] = 2; + customService->writeDescriptor(cc3ClientConfig, indicateValue); + spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::descriptorWritten)); + QVERIFY(spy->wait(3000)); + + QByteArray notifyValue(2, 0); + notifyValue[0] = 1; + customService->writeDescriptor(cc4ClientConfig, notifyValue); + spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::descriptorWritten)); + QVERIFY(spy->wait(3000)); + + // Server now changes the characteristic values. + + spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::characteristicChanged)); + QVERIFY(spy->wait(3000)); + if (spy->count() == 1) + QVERIFY(spy->wait(3000)); + QCOMPARE(customChar3.value().constData(), "indicated"); + QCOMPARE(customChar4.value().constData(), "notified"); + + const bool isBonded = QBluetoothLocalDevice().pairingStatus(m_serverAddress) + != QBluetoothLocalDevice::Unpaired; + m_leController->disconnectFromDevice(); + + if (m_leController->state() != QLowEnergyController::UnconnectedState) { + spy.reset(new QSignalSpy(m_leController.data(), &QLowEnergyController::stateChanged)); + QVERIFY(spy->wait(3000)); + } + QCOMPARE(m_leController->state(), QLowEnergyController::UnconnectedState); + + // Server now changes the characteristic values again while we're offline. + // Note: We cannot test indications and notifications for this case, as the client does + // not cache the old information and thus does not yet know the characteristics + // at the time the notification/indication is received. + + QTest::qWait(3000); + m_leController->connectToDevice(); + spy.reset(new QSignalSpy(m_leController.data(), &QLowEnergyController::connected)); + QVERIFY(spy->wait(30000)); + m_leController->discoverServices(); + spy.reset(new QSignalSpy(m_leController.data(), &QLowEnergyController::discoveryFinished)); + QVERIFY(spy->wait(30000)); + customService.reset(m_leController->createServiceObject(QBluetoothUuid(quint16(0x2000)))); + QVERIFY(!customService.isNull()); + customService->discoverDetails(); + while (customService->state() != QLowEnergyService::ServiceDiscovered) { + spy.reset(new QSignalSpy(customService.data(), &QLowEnergyService::stateChanged)); + QVERIFY(spy->wait(5000)); + } + customChar3 = customService->characteristic(QBluetoothUuid(quint16(0x5002))); + QVERIFY(customChar3.isValid()); + QCOMPARE(customChar3.value().constData(), "indicated2"); + customChar4 = customService->characteristic(QBluetoothUuid(quint16(0x5003))); + QVERIFY(customChar4.isValid()); + QCOMPARE(customChar4.value().constData(), "notified2"); + cc3ClientConfig = customChar3.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + QVERIFY(cc3ClientConfig.isValid()); + cc4ClientConfig = customChar4.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + QVERIFY(cc4ClientConfig.isValid()); + if (isBonded) { + QCOMPARE(cc3ClientConfig.value(), indicateValue); + QCOMPARE(cc4ClientConfig.value(), notifyValue); + } else { + QCOMPARE(cc3ClientConfig.value(), QByteArray(2, 0)); + QCOMPARE(cc4ClientConfig.value(), QByteArray(2, 0)); + } } void TestQLowEnergyControllerGattServer::controllerType() @@ -320,6 +416,13 @@ void TestQLowEnergyControllerGattServer::serviceData() charData.setValue("value"); QCOMPARE(charData.value().constData(), "value"); + charData.setValueLength(4, 7); + QCOMPARE(charData.minimumValueLength(), 4); + QCOMPARE(charData.maximumValueLength(), 7); + charData.setValueLength(5, 2); + QCOMPARE(charData.minimumValueLength(), 5); + QCOMPARE(charData.maximumValueLength(), 5); + const QLowEnergyCharacteristic::PropertyTypes props = QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::WriteSigned; charData.setProperties(props); |