summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/server/qlowenergycontroller-gattserver.cpp72
-rw-r--r--tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp115
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);