diff options
Diffstat (limited to 'tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp')
-rw-r--r-- | tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp b/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp new file mode 100644 index 00000000..12d0db17 --- /dev/null +++ b/tests/auto/qlowenergycontroller-gattserver/test/tst_qlowenergycontroller-gattserver.cpp @@ -0,0 +1,362 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtBluetooth module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtBluetooth/qbluetoothaddress.h> +#include <QtBluetooth/qbluetoothdevicediscoveryagent.h> +#include <QtBluetooth/qbluetoothdeviceinfo.h> +#include <QtBluetooth/qlowenergyadvertisingdata.h> +#include <QtBluetooth/qlowenergyadvertisingparameters.h> +#include <QtBluetooth/qlowenergycontroller.h> +#include <QtBluetooth/qlowenergycharacteristicdata.h> +#include <QtBluetooth/qlowenergydescriptordata.h> +#include <QtBluetooth/qlowenergyservicedata.h> +#include <QtCore/qscopedpointer.h> +#include <QtTest/qsignalspy.h> +#include <QtTest/QtTest> + +#include <algorithm> + +class TestQLowEnergyControllerGattServer : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + + // Static, local stuff goes here. + void advertisingParameters(); + void advertisingData(); + void controllerType(); + void serviceData(); + + // Interaction with actual GATT server goes here. Order is relevant. + void advertisedData(); + void initialServices(); + +private: + QBluetoothAddress m_serverAddress; + QBluetoothDeviceInfo m_serverInfo; + QScopedPointer<QLowEnergyController> m_leController; +}; + + +void TestQLowEnergyControllerGattServer::initTestCase() +{ + const QString serverAddress = qgetenv("QT_BT_GATTSERVER_TEST_ADDRESS"); + if (serverAddress.isEmpty()) + return; + m_serverAddress = QBluetoothAddress(serverAddress); + QVERIFY(!m_serverAddress.isNull()); +} + +void TestQLowEnergyControllerGattServer::advertisingParameters() +{ + QLowEnergyAdvertisingParameters params; + QCOMPARE(params, QLowEnergyAdvertisingParameters()); + QCOMPARE(params.filterPolicy(), QLowEnergyAdvertisingParameters::IgnoreWhiteList); + QCOMPARE(params.minimumInterval(), 1280); + QCOMPARE(params.maximumInterval(), 1280); + QCOMPARE(params.mode(), QLowEnergyAdvertisingParameters::AdvInd); + QVERIFY(params.whiteList().isEmpty()); + + params.setInterval(100, 200); + QCOMPARE(params.minimumInterval(), 100); + QCOMPARE(params.maximumInterval(), 200); + params.setInterval(200, 100); + QCOMPARE(params.minimumInterval(), 200); + QCOMPARE(params.maximumInterval(), 200); + + params.setMode(QLowEnergyAdvertisingParameters::AdvScanInd); + QCOMPARE(params.mode(), QLowEnergyAdvertisingParameters::AdvScanInd); + + const auto whiteList = QList<QLowEnergyAdvertisingParameters::AddressInfo>() + << QLowEnergyAdvertisingParameters::AddressInfo(QBluetoothAddress(), + QLowEnergyController::PublicAddress); + params.setWhiteList(whiteList, QLowEnergyAdvertisingParameters::UseWhiteListForConnecting); + QCOMPARE(params.whiteList(), whiteList); + QCOMPARE(params.filterPolicy(), QLowEnergyAdvertisingParameters::UseWhiteListForConnecting); + QVERIFY(params != QLowEnergyAdvertisingParameters()); +} + +void TestQLowEnergyControllerGattServer::advertisingData() +{ + QLowEnergyAdvertisingData data; + QCOMPARE(data, QLowEnergyAdvertisingData()); + QCOMPARE(data.discoverability(), QLowEnergyAdvertisingData::DiscoverabilityNone); + QCOMPARE(data.includePowerLevel(), false); + QCOMPARE(data.localName(), QString()); + QCOMPARE(data.manufacturerData(), QByteArray()); + QCOMPARE(data.manufacturerId(), QLowEnergyAdvertisingData::invalidManufacturerId()); + QVERIFY(data.services().isEmpty()); + + data.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityLimited); + QCOMPARE(data.discoverability(), QLowEnergyAdvertisingData::DiscoverabilityLimited); + + data.setIncludePowerLevel(true); + QCOMPARE(data.includePowerLevel(), true); + + data.setLocalName("A device name"); + QCOMPARE(data.localName(), QString("A device name")); + + data.setManufacturerData(0xfffd, "some data"); + QCOMPARE(data.manufacturerId(), quint16(0xfffd)); + QCOMPARE(data.manufacturerData(), QByteArray("some data")); + + const auto services = QList<QBluetoothUuid>() << QBluetoothUuid::CurrentTimeService + << QBluetoothUuid::DeviceInformation; + data.setServices(services); + QCOMPARE(data.services(), services); + + QByteArray rawData(7, 'x'); + data.setRawData(rawData); + QCOMPARE(data.rawData(), rawData); + + QVERIFY(data != QLowEnergyAdvertisingData()); +} + +void TestQLowEnergyControllerGattServer::advertisedData() +{ + if (m_serverAddress.isNull()) + QSKIP("No server address provided"); + QBluetoothDeviceDiscoveryAgent discoveryAgent; + discoveryAgent.start(); + QSignalSpy spy(&discoveryAgent, SIGNAL(finished())); + QVERIFY(spy.wait(30000)); + const QList<QBluetoothDeviceInfo> devices = discoveryAgent.discoveredDevices(); + const auto it = std::find_if(devices.constBegin(), devices.constEnd(), + [this](const QBluetoothDeviceInfo &device) { return device.address() == m_serverAddress; }); + QVERIFY(it != devices.constEnd()); + m_serverInfo = *it; + + // BlueZ seems to interfere with the advertising in some way, so that in addition to the name + // we set, the host name of the machine is also sent. Therefore we cannot guarantee that "our" + // name is seen on the scanning machine. + // QCOMPARE(m_serverInfo.name(), QString("Qt GATT server")); + + QCOMPARE(m_serverInfo.serviceUuids().count(), 3); + QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid::GenericAccess)); + QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid::RunningSpeedAndCadence)); + QVERIFY(m_serverInfo.serviceUuids().contains(QBluetoothUuid(quint16(0x2000)))); +} + +void TestQLowEnergyControllerGattServer::initialServices() +{ + if (m_serverAddress.isNull()) + QSKIP("No server address provided"); + m_leController.reset(QLowEnergyController::createCentral(m_serverInfo)); + QVERIFY(!m_leController.isNull()); + m_leController->connectToDevice(); + QScopedPointer<QSignalSpy> spy(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)); + const QList<QBluetoothUuid> serviceUuids = m_leController->services(); + QCOMPARE(serviceUuids.count(), 3); + QVERIFY(serviceUuids.contains(QBluetoothUuid::GenericAccess)); + QVERIFY(serviceUuids.contains(QBluetoothUuid::RunningSpeedAndCadence)); + QVERIFY(serviceUuids.contains(QBluetoothUuid(quint16(0x2000)))); + + const QScopedPointer<QLowEnergyService> genericAccessService( + m_leController->createServiceObject(QBluetoothUuid::GenericAccess)); + QVERIFY(!genericAccessService.isNull()); + genericAccessService->discoverDetails(); + while (genericAccessService->state() != QLowEnergyService::ServiceDiscovered) { + spy.reset(new QSignalSpy(genericAccessService.data(), &QLowEnergyService::stateChanged)); + QVERIFY(spy->wait(3000)); + } + QCOMPARE(genericAccessService->includedServices().count(), 1); + QCOMPARE(genericAccessService->includedServices().first(), + QBluetoothUuid(QBluetoothUuid::RunningSpeedAndCadence)); + QCOMPARE(genericAccessService->characteristics().count(), 2); + const QLowEnergyCharacteristic deviceNameChar + = genericAccessService->characteristic(QBluetoothUuid::DeviceName); + QVERIFY(deviceNameChar.isValid()); + QCOMPARE(deviceNameChar.descriptors().count(), 0); + QCOMPARE(deviceNameChar.properties(), + QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::Write); + QCOMPARE(deviceNameChar.value().constData(), "Qt GATT server"); + const QLowEnergyCharacteristic appearanceChar + = genericAccessService->characteristic(QBluetoothUuid::Appearance); + QVERIFY(appearanceChar.isValid()); + QCOMPARE(appearanceChar.descriptors().count(), 0); + QCOMPARE(appearanceChar.properties(), QLowEnergyCharacteristic::Read); + QByteArray appearanceValue(2, 0); + appearanceValue[0] = -1; + QCOMPARE(appearanceChar.value(), appearanceValue); + + const QScopedPointer<QLowEnergyService> runningSpeedService( + m_leController->createServiceObject(QBluetoothUuid::RunningSpeedAndCadence)); + QVERIFY(!runningSpeedService.isNull()); + runningSpeedService->discoverDetails(); + while (runningSpeedService->state() != QLowEnergyService::ServiceDiscovered) { + spy.reset(new QSignalSpy(runningSpeedService.data(), &QLowEnergyService::stateChanged)); + QVERIFY(spy->wait(3000)); + } + QCOMPARE(runningSpeedService->includedServices().count(), 0); + QCOMPARE(runningSpeedService->characteristics().count(), 2); + QLowEnergyCharacteristic measurementChar + = runningSpeedService->characteristic(QBluetoothUuid::RSCMeasurement); + QVERIFY(measurementChar.isValid()); + QCOMPARE(measurementChar.descriptors().count(), 1); + const QLowEnergyDescriptor clientConfigDesc + = measurementChar.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); + QVERIFY(clientConfigDesc.isValid()); + QCOMPARE(clientConfigDesc.value(), QByteArray(1, 0)); + QCOMPARE(measurementChar.properties(), QLowEnergyCharacteristic::Notify); + QCOMPARE(measurementChar.value(), QByteArray()); // Empty because Read property not set + QLowEnergyCharacteristic featureChar + = runningSpeedService->characteristic(QBluetoothUuid::RSCFeature); + QVERIFY(featureChar.isValid()); + QCOMPARE(featureChar.descriptors().count(), 0); + QCOMPARE(featureChar.properties(), QLowEnergyCharacteristic::Read); + QByteArray featureValue = QByteArray(2, 0); + featureValue[0] = 1 << 2; + QCOMPARE(featureChar.value(), featureValue); + + const 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)); + } + QCOMPARE(customService->includedServices().count(), 0); + QCOMPARE(customService->characteristics().count(), 1); + QLowEnergyCharacteristic customChar + = customService->characteristic(QBluetoothUuid(quint16(0x5000))); + QVERIFY(customChar.isValid()); + QCOMPARE(customChar.descriptors().count(), 0); + QCOMPARE(customChar.value(), QByteArray(1024, 'x')); +} + +void TestQLowEnergyControllerGattServer::controllerType() +{ + const QScopedPointer<QLowEnergyController> controller(QLowEnergyController::createPeripheral()); + QVERIFY(!controller.isNull()); + QCOMPARE(controller->role(), QLowEnergyController::PeripheralRole); +} + +void TestQLowEnergyControllerGattServer::serviceData() +{ + QLowEnergyDescriptorData descData; + QVERIFY(!descData.isValid()); + + descData.setUuid(QBluetoothUuid::ValidRange); + QCOMPARE(descData.uuid(), QBluetoothUuid(QBluetoothUuid::ValidRange)); + QVERIFY(descData.isValid()); + QVERIFY(descData != QLowEnergyDescriptorData()); + + descData.setValue("xyz"); + QCOMPARE(descData.value().constData(), "xyz"); + + QLowEnergyDescriptorData descData2(QBluetoothUuid::ReportReference, "abc"); + QVERIFY(descData2 != QLowEnergyDescriptorData()); + QVERIFY(descData2.isValid()); + QCOMPARE(descData2.uuid(), QBluetoothUuid(QBluetoothUuid::ReportReference)); + QCOMPARE(descData2.value().constData(), "abc"); + + QLowEnergyCharacteristicData charData; + QVERIFY(!charData.isValid()); + + charData.setUuid(QBluetoothUuid::BatteryLevel); + QVERIFY(charData != QLowEnergyCharacteristicData()); + QCOMPARE(charData.uuid(), QBluetoothUuid(QBluetoothUuid::BatteryLevel)); + QVERIFY(charData.isValid()); + + charData.setValue("value"); + QCOMPARE(charData.value().constData(), "value"); + + const QLowEnergyCharacteristic::PropertyTypes props + = QLowEnergyCharacteristic::Read | QLowEnergyCharacteristic::WriteSigned; + charData.setProperties(props); + QCOMPARE(charData.properties(), props); + + charData.setDescriptors(QList<QLowEnergyDescriptorData>() << descData << descData2); + QLowEnergyDescriptorData descData3(QBluetoothUuid::ExternalReportReference, "someval"); + charData.addDescriptor(descData3); + charData.addDescriptor(QLowEnergyDescriptorData()); // Invalid. + QCOMPARE(charData.descriptors(), + QList<QLowEnergyDescriptorData>() << descData << descData2 << descData3); + + QLowEnergyServiceData secondaryData; + QVERIFY(!secondaryData.isValid()); + + secondaryData.setUuid(QBluetoothUuid::SerialPort); + QCOMPARE(secondaryData.uuid(), QBluetoothUuid(QBluetoothUuid::SerialPort)); + QVERIFY(secondaryData.isValid()); + QVERIFY(secondaryData != QLowEnergyServiceData()); + + secondaryData.setType(QLowEnergyServiceData::ServiceTypeSecondary); + QCOMPARE(secondaryData.type(), QLowEnergyServiceData::ServiceTypeSecondary); + + secondaryData.setCharacteristics(QList<QLowEnergyCharacteristicData>() + << charData << QLowEnergyCharacteristicData()); + QCOMPARE(secondaryData.characteristics(), QList<QLowEnergyCharacteristicData>() << charData); + +#ifdef Q_OS_DARWIN + QSKIP("GATT server functionality not implemented for Apple platforms"); +#endif + const QScopedPointer<QLowEnergyController> controller(QLowEnergyController::createPeripheral()); + QVERIFY(!controller->addService(QLowEnergyServiceData())); + const QScopedPointer<QLowEnergyService> secondaryService(controller->addService(secondaryData)); + QVERIFY(!secondaryService.isNull()); + QCOMPARE(secondaryService->serviceUuid(), secondaryData.uuid()); + const QList<QLowEnergyCharacteristic> characteristics = secondaryService->characteristics(); + QCOMPARE(characteristics.count(), 1); + QCOMPARE(characteristics.first().uuid(), charData.uuid()); + const QList<QLowEnergyDescriptor> descriptors = characteristics.first().descriptors(); + QCOMPARE(descriptors.count(), 3); + const auto inUuids = QSet<QBluetoothUuid>() << descData.uuid() << descData2.uuid() + << descData3.uuid(); + QSet<QBluetoothUuid> outUuids; + foreach (const QLowEnergyDescriptor &desc, descriptors) + outUuids << desc.uuid(); + QCOMPARE(inUuids, outUuids); + + QLowEnergyServiceData primaryData; + primaryData.setUuid(QBluetoothUuid::Headset); + primaryData.addIncludedService(secondaryService.data()); + const QScopedPointer<QLowEnergyService> primaryService(controller->addService(primaryData)); + QVERIFY(!primaryService.isNull()); + QCOMPARE(primaryService->characteristics().count(), 0); + const QList<QBluetoothUuid> includedServices = primaryService->includedServices(); + QCOMPARE(includedServices.count(), 1); + QCOMPARE(includedServices.first(), secondaryService->serviceUuid()); +} + +QTEST_MAIN(TestQLowEnergyControllerGattServer) + +#include "tst_qlowenergycontroller-gattserver.moc" |