diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 05cc44c..7193e68 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,109 @@ -# Copyright (C) 2022 The Qt Company Ltd. +# Copyright (C) 2025 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause +# This function adds the test 12 times if run on a computer where the +# mosquitto broker has been provisioned by running the corresponding +# script located qt6/coin/provisioning/*/*mosquitto* +# +# The script adds the file /etc/mosquitto/conf.d/mqtt.conf on unix-like +# systems, and the file C:\\Program Files\\mosquitto\\conf.d\\mqtt.conf +# on windows like systems. So this is what we test for. +# +# If we are on a provisioned system as detected by the two files above +# we define these variables which the test use +# MQTT_TEST_TYPE= selection from; 3, 4, 5 +# 3 -> Vers 3.1 +# 4 -> Vers 3.1.1 +# 5 -> Vers 5.0 +# MQTT_TEST_PROTOCOL= selection from; Tcp,Ssl,Ws,Wss +# MQTT_TEST_BROKER="localhost" +# +# If neither of these files are present, we use the existing +# design which is to run for tcp,3.1.1 by default. +# In this case set the environment variable MQTT_TEST_BROKER +# to localhost +# +# Finally, we allow the test to override for individual test +# cases, if wanted. This is mostly used for MQTT_TEST_TYPE +# +function(qtmqtt_add_test) + + set(options) + set(oneValueArgs TARGET) + set(multiValueArgs SOURCES DEFINES INCLUDE_DIRECTORIES LIBRARIES) + + cmake_parse_arguments( + arg_mqtt + "${options}" + "${oneValueArgs}" + "${multiValueArgs}" + ${ARGN} + ) + + set(TYPES) + set(PROTOCOLS) + + if((EXISTS "/etc/mosquitto/conf.d/mqtt.conf") OR + (EXISTS "C:\\Program Files\\mosquitto\\conf.d\\mqtt.conf")) + if(WASM) + if(TARGET Qt::WebSockets) + set(TYPES Ws Wss) + set(PROTOCOLS 3 4 5) + endif() + elseif(QT_FEATURE_ssl) + if(TARGET Qt::WebSockets) + set(TYPES Tcp Ssl Ws Wss) + else() + set(TYPES Tcp Ssl) + endif() + set(PROTOCOLS 3 4 5) + else() + if(TARGET Qt::WebSockets) + set(TYPES Tcp Ws) + else() + set(TYPES Tcp) + endif() + set(PROTOCOLS 3 4 5) + endif() + elseif(NOT WASM) + set(TYPES Tcp) + set(PROTOCOLS 4) + endif() + + foreach(TYPE ${TYPES}) + foreach(PROTOCOL ${PROTOCOLS}) + set(EXTRA_DEFINES) + set(EXTRA_LIBS) + if(EXISTS "/etc/mosquitto/conf.d/mqtt.conf" OR + EXISTS "C:\\Program Files\\mosquitto\\conf.d\\mqtt.conf") + set(EXTRA_DEFINES MQTT_TEST_TYPE="${TYPE}" MQTT_TEST_PROTOCOL=${PROTOCOL} MQTT_TEST_BROKER="localhost") + endif() + + if(TARGET Qt::WebSockets) + set(EXTRA_DEFINES ${EXTRA_DEFINES} QT_MQTT_WITH_WEBSOCKETS) + set(EXTRA_LIBS Qt::WebSockets) + endif() + + qt_internal_add_test( + ${arg_mqtt_TARGET}_${TYPE}_${PROTOCOL} + SOURCES + ${arg_mqtt_SOURCES} + DEFINES + ${arg_mqtt_DEFINES} ${EXTRA_DEFINES} + INCLUDE_DIRECTORIES + ${arg_mqtt_INCLUDE_DIRECTORIES} + LIBRARIES + ${arg_mqtt_LIBRARIES} ${EXTRA_LIBS} + TESTDATA + "../../certificate/cert.crt" + "../../certificate/cert.key" + BUILTIN_TESTDATA + ) + + endforeach() + endforeach() +endfunction() + if(QT_BUILD_STANDALONE_TESTS) # Add qt_find_package calls for extra dependencies that need to be found when building # the standalone tests here. diff --git a/tests/auto/conformance/CMakeLists.txt b/tests/auto/conformance/CMakeLists.txt index e4dbadd..2b351bc 100644 --- a/tests/auto/conformance/CMakeLists.txt +++ b/tests/auto/conformance/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_conformance Test: ##################################################################### -qt_internal_add_test(tst_conformance +qtmqtt_add_test( + TARGET + tst_conformance SOURCES ../../common/broker_connection.h tst_conformance.cpp diff --git a/tests/auto/conformance/tst_conformance.cpp b/tests/auto/conformance/tst_conformance.cpp index 96a4018..7e1e55e 100644 --- a/tests/auto/conformance/tst_conformance.cpp +++ b/tests/auto/conformance/tst_conformance.cpp @@ -42,7 +42,7 @@ private Q_SLOTS: private: QProcess m_brokerProcess; QString m_testBroker; - quint16 m_port{1883}; + quint16 m_port{0}; }; Tst_MqttConformance::Tst_MqttConformance() diff --git a/tests/auto/qmqttclient/CMakeLists.txt b/tests/auto/qmqttclient/CMakeLists.txt index d3db01f..f97ac2b 100644 --- a/tests/auto/qmqttclient/CMakeLists.txt +++ b/tests/auto/qmqttclient/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_qmqttclient Test: ##################################################################### -qt_internal_add_test(tst_qmqttclient +qtmqtt_add_test( + TARGET + tst_qmqttclient SOURCES ../../common/broker_connection.h tst_qmqttclient.cpp diff --git a/tests/auto/qmqttclient/tst_qmqttclient.cpp b/tests/auto/qmqttclient/tst_qmqttclient.cpp index 4ae3a16..2656bec 100644 --- a/tests/auto/qmqttclient/tst_qmqttclient.cpp +++ b/tests/auto/qmqttclient/tst_qmqttclient.cpp @@ -51,10 +51,11 @@ private Q_SLOTS: void subscriptionIdsOverlap(); void keepAlive_data(); void keepAlive(); + void reconnect(); private: QProcess m_brokerProcess; QString m_testBroker; - quint16 m_port{1883}; + quint16 m_port{0}; }; Tst_QMqttClient::Tst_QMqttClient() @@ -185,7 +186,7 @@ void Tst_QMqttClient::sendReceive() QSKIP("The MQTT 5 test broker does not support huge packages.", SkipOnce); publisher.publish(testTopic, data, 1); - QTRY_VERIFY2(received, "Subscriber did not receive message"); + QTRY_VERIFY2_WITH_TIMEOUT(received, "Subscriber did not receive message", std::chrono::seconds(180)); QVERIFY2(verified, "Subscriber received different message"); } @@ -270,6 +271,9 @@ void Tst_QMqttClient::willMessage() client1.connectToHost(); QTRY_COMPARE(client1.state(), QMqttClient::Connected); + if (!client1.isTcp()) + QSKIP("This test is only for tcp"); + auto client1Sub = client1.subscribe(willTopic, 1); connect(client1Sub, &QMqttSubscription::messageReceived, [=](QMqttMessage message) { Q_UNUSED(message); @@ -282,7 +286,7 @@ void Tst_QMqttClient::willMessage() // Client B connects (via TcpSocket) QTcpSocket sock; - sock.connectToHost(m_testBroker, m_port); + sock.connectToHost(client1.hostname(), client1.port()); QVERIFY(sock.waitForConnected()); for (int i = 1; i > 0; --i) { @@ -507,6 +511,9 @@ void Tst_QMqttClient::reconnect_QTBUG65726() client.setHostname(QLatin1String("localhost")); client.setPort(5726); + if (!client.isTcp()) + QSKIP("This test is only for tcp"); + server.version = client.protocolVersion(); client.connectToHost(); @@ -569,6 +576,9 @@ void Tst_QMqttClient::staticProperties_QTBUG_67176() client.setHostname(m_testBroker); client.setPort(m_port); + auto clientVersion = client.protocolVersion(); + const QString hostname = client.hostname(); + const int port = client.port(); const QString clientId = client.clientId(); const quint16 keepAlive = client.keepAlive(); const bool clean = client.cleanSession(); @@ -580,16 +590,16 @@ void Tst_QMqttClient::staticProperties_QTBUG_67176() QCOMPARE(client.clientId(), clientId); client.setHostname(QLatin1String("some.domain.foo")); - QCOMPARE(client.hostname(), m_testBroker); + QCOMPARE(client.hostname(), hostname); client.setPort(1234); - QCOMPARE(client.port(), m_port); + QCOMPARE(client.port(), port); client.setKeepAlive(keepAlive + 10); QCOMPARE(client.keepAlive(), keepAlive); client.setProtocolVersion(QMqttClient::MQTT_3_1); - QCOMPARE(client.protocolVersion(), mqttVersion); + QCOMPARE(client.protocolVersion(), clientVersion); client.setUsername(QLatin1String("someUser")); QCOMPARE(client.username(), QLatin1String()); @@ -651,6 +661,7 @@ void Tst_QMqttClient::messageStatus() client.setPort(m_port); client.connectToHost(); + QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker."); const QString topic = QLatin1String("Qt/client/statusCheck"); @@ -881,6 +892,76 @@ void Tst_QMqttClient::keepAlive() QTRY_COMPARE(client.state(), QMqttClient::Disconnected); } +void Tst_QMqttClient::reconnect() +{ + VersionClient(QMqttClient::ProtocolVersion(0), client); + client.setHostname(m_testBroker); + client.setPort(m_port); + client.connectToHost(); + QTRY_COMPARE(client.state(), QMqttClient::Connected); + + client.disconnectFromHost(); + QTRY_COMPARE(client.state(), QMqttClient::Disconnected); + + /* The rest requires a mosquitto installation that runs + on multiple ports. + */ +#if defined(MQTT_TEST_BROKER) + client.setPort(client.port() + 1000); + client.connectToHost(); + QTRY_COMPARE(client.state(), QMqttClient::Connected); + + client.disconnectFromHost(); + QTRY_COMPARE(client.state(), QMqttClient::Disconnected); + + QMqttClient client2; + client2.setHostname(client.hostname()); + + for (int i = 0; i < 2; ++i) { +#if defined(QT_MQTT_WITH_WEBSOCKETS) + client2.setPort(9080); + client2.connectToHostWebSocket(); + QTRY_COMPARE(client2.state(), QMqttClient::Connected); + + client2.disconnectFromHost(); + QTRY_COMPARE(client2.state(), QMqttClient::Disconnected); +#endif + +#if defined(QT_MQTT_WITH_WEBSOCKETS) && !defined(QT_NO_SSL) + client2.setPort(9081); + QUrl url(QString(u"wss://") + client2.hostname() + QString(u":") + QString::number(client2.port())); + QWebSocketHandshakeOptions options; + options.setSubprotocols(QStringList{ QString::fromUtf8("mqttv3.1") }); + QWebSocket socket; + socket.setSslConfiguration(makeConfig(QString::fromUtf8(getenv("MQTT_TEST_BROKER_CERTIFICATE")))); + socket.open(url, options); + + client2.connectToHostWebSocketEncrypted(&socket); + QTRY_COMPARE(client2.state(), QMqttClient::Connected); + + client2.disconnectFromHost(); + QTRY_COMPARE(client2.state(), QMqttClient::Disconnected); +#endif + +#if !defined(QT_NO_SSL) + client2.setPort(9883); + client2.connectToHostEncrypted(makeConfig(QString::fromUtf8(getenv("MQTT_TEST_BROKER_CERTIFICATE")))); + QTRY_COMPARE(client2.state(), QMqttClient::Connected); + + client2.disconnectFromHost(); + QTRY_COMPARE(client2.state(), QMqttClient::Disconnected); +#endif + + client2.setPort(2883); + client2.connectToHost(); + QTRY_COMPARE(client2.state(), QMqttClient::Connected); + + client2.disconnectFromHost(); + QTRY_COMPARE(client2.state(), QMqttClient::Disconnected); + } +#endif +} + QTEST_MAIN(Tst_QMqttClient) #include "tst_qmqttclient.moc" diff --git a/tests/auto/qmqttconnectionproperties/CMakeLists.txt b/tests/auto/qmqttconnectionproperties/CMakeLists.txt index f177c59..0c8eade 100644 --- a/tests/auto/qmqttconnectionproperties/CMakeLists.txt +++ b/tests/auto/qmqttconnectionproperties/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_qmqttconnectionproperties Test: ##################################################################### -qt_internal_add_test(tst_qmqttconnectionproperties +qtmqtt_add_test( + TARGET + tst_qmqttconnectionproperties SOURCES ../../common/broker_connection.h tst_qmqttconnectionproperties.cpp diff --git a/tests/auto/qmqttconnectionproperties/tst_qmqttconnectionproperties.cpp b/tests/auto/qmqttconnectionproperties/tst_qmqttconnectionproperties.cpp index 33857ca..3cbef3b 100644 --- a/tests/auto/qmqttconnectionproperties/tst_qmqttconnectionproperties.cpp +++ b/tests/auto/qmqttconnectionproperties/tst_qmqttconnectionproperties.cpp @@ -31,7 +31,7 @@ private Q_SLOTS: private: QProcess m_brokerProcess; QString m_testBroker; - quint16 m_port{1883}; + quint16 m_port{0}; }; tst_QMqttConnectionProperties::tst_QMqttConnectionProperties() @@ -239,7 +239,7 @@ void tst_QMqttConnectionProperties::maximumTopicAlias() client.publish(topic, msgContent, 1); QTRY_VERIFY(publishSpy.size() == 1); - QVERIFY(transportSpy.size() == 1); + QTRY_VERIFY(transportSpy.size() == 1); const int dataSize = transportSpy.at(0).at(0).toInt(); if (publishTransportSize == 0) { publishTransportSize = dataSize; diff --git a/tests/auto/qmqttcontrolpacket/CMakeLists.txt b/tests/auto/qmqttcontrolpacket/CMakeLists.txt index 755803b..7b8cc1a 100644 --- a/tests/auto/qmqttcontrolpacket/CMakeLists.txt +++ b/tests/auto/qmqttcontrolpacket/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_qmqttcontrolpacket Test: ##################################################################### -qt_internal_add_test(tst_qmqttcontrolpacket +qtmqtt_add_test( + TARGET + tst_qmqttcontrolpacket SOURCES tst_qmqttcontrolpacket.cpp DEFINES diff --git a/tests/auto/qmqttlastwillproperties/CMakeLists.txt b/tests/auto/qmqttlastwillproperties/CMakeLists.txt index 610d298..3fb29b7 100644 --- a/tests/auto/qmqttlastwillproperties/CMakeLists.txt +++ b/tests/auto/qmqttlastwillproperties/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_qmqttlastwillproperties Test: ##################################################################### -qt_internal_add_test(tst_qmqttlastwillproperties +qtmqtt_add_test( + TARGET + tst_qmqttlastwillproperties SOURCES ../../common/broker_connection.h tst_qmqttlastwillproperties.cpp diff --git a/tests/auto/qmqttlastwillproperties/tst_qmqttlastwillproperties.cpp b/tests/auto/qmqttlastwillproperties/tst_qmqttlastwillproperties.cpp index 3c12d5d..4ed3e82 100644 --- a/tests/auto/qmqttlastwillproperties/tst_qmqttlastwillproperties.cpp +++ b/tests/auto/qmqttlastwillproperties/tst_qmqttlastwillproperties.cpp @@ -27,7 +27,7 @@ private Q_SLOTS: private: QProcess m_brokerProcess; QString m_testBroker; - quint16 m_port{1883}; + quint16 m_port{0}; }; tst_QMqttLastWillProperties::tst_QMqttLastWillProperties() diff --git a/tests/auto/qmqttpublishproperties/CMakeLists.txt b/tests/auto/qmqttpublishproperties/CMakeLists.txt index 3ee0f0f..3613238 100644 --- a/tests/auto/qmqttpublishproperties/CMakeLists.txt +++ b/tests/auto/qmqttpublishproperties/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_qmqttpublishproperties Test: ##################################################################### -qt_internal_add_test(tst_qmqttpublishproperties +qtmqtt_add_test( + TARGET + tst_qmqttpublishproperties SOURCES ../../common/broker_connection.h tst_qmqttpublishproperties.cpp diff --git a/tests/auto/qmqttpublishproperties/tst_qmqttpublishproperties.cpp b/tests/auto/qmqttpublishproperties/tst_qmqttpublishproperties.cpp index aa9ce54..c6527d3 100644 --- a/tests/auto/qmqttpublishproperties/tst_qmqttpublishproperties.cpp +++ b/tests/auto/qmqttpublishproperties/tst_qmqttpublishproperties.cpp @@ -26,7 +26,7 @@ private Q_SLOTS: private: QProcess m_brokerProcess; QString m_testBroker; - quint16 m_port{1883}; + quint16 m_port{0}; }; tst_QMqttPublishProperties::tst_QMqttPublishProperties() diff --git a/tests/auto/qmqttsubscription/CMakeLists.txt b/tests/auto/qmqttsubscription/CMakeLists.txt index 4966d97..278ddae 100644 --- a/tests/auto/qmqttsubscription/CMakeLists.txt +++ b/tests/auto/qmqttsubscription/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_qmqttsubscription Test: ##################################################################### -qt_internal_add_test(tst_qmqttsubscription +qtmqtt_add_test( + TARGET + tst_qmqttsubscription SOURCES ../../common/broker_connection.h tst_qmqttsubscription.cpp diff --git a/tests/auto/qmqttsubscription/tst_qmqttsubscription.cpp b/tests/auto/qmqttsubscription/tst_qmqttsubscription.cpp index 68bff51..d13a22d 100644 --- a/tests/auto/qmqttsubscription/tst_qmqttsubscription.cpp +++ b/tests/auto/qmqttsubscription/tst_qmqttsubscription.cpp @@ -36,7 +36,7 @@ private: void createAndSubscribe(Client *c, QMqttSubscription **sub, const QString &topic); QProcess m_brokerProcess; QString m_testBroker; - quint16 m_port{1883}; + quint16 m_port{0}; }; Tst_QMqttSubscription::Tst_QMqttSubscription() @@ -149,6 +149,9 @@ void Tst_QMqttSubscription::reconnect() client.connectToHost(); QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker."); + if (!client.isTcp() && !client.isSsl()) + QSKIP("This test only runs for tcp and ssl"); + // - Subscribe to topic A const QString subscription("Qt/subscription/topics/resub"); auto sub = client.subscribe(subscription, 1); @@ -384,6 +387,8 @@ void Tst_QMqttSubscription::noLocal() client.setPort(m_port); client.connectToHost(); + const auto clientVersion = client.protocolVersion(); + QTRY_VERIFY2(client.state() == QMqttClient::Connected, "Could not connect to broker."); QMqttSubscriptionProperties subProps; @@ -400,7 +405,7 @@ void Tst_QMqttSubscription::noLocal() client.publish(topic, "content", 1); QTRY_VERIFY(publishSpy.size() == 1); - if (version == QMqttClient::MQTT_3_1_1 || !non) { // 3.1.1 does not know NoLocal and sends to subscription + if (clientVersion == QMqttClient::MQTT_3_1_1 || !non) { // 3.1.1 does not know NoLocal and sends to subscription QTRY_VERIFY(receivalSpy.size() == 1); } else { QTest::qWait(3000); @@ -483,8 +488,8 @@ void Tst_QMqttSubscription::qtbug_104478() client.publish(topic, "Wildcard checks", 1); QTRY_VERIFY2(pubSpy.size() == 1, "Could not publish message."); - QTRY_VERIFY2(singleSpy.count() == 1, "Did not receive message"); - QTRY_VERIFY2(mixedSpy.count() == 1, "Did not receive message"); + QTRY_VERIFY2(singleSpy.count() >= 1, "Did not receive message"); + QTRY_VERIFY2(mixedSpy.count() >= 1, "Did not receive message"); client.disconnectFromHost(); QTRY_VERIFY2(client.state() == QMqttClient::Disconnected, "Could not disconnect from broker."); diff --git a/tests/auto/qmqttsubscriptionproperties/CMakeLists.txt b/tests/auto/qmqttsubscriptionproperties/CMakeLists.txt index 2ee2a36..a173b22 100644 --- a/tests/auto/qmqttsubscriptionproperties/CMakeLists.txt +++ b/tests/auto/qmqttsubscriptionproperties/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_qmqttsubscriptionproperties Test: ##################################################################### -qt_internal_add_test(tst_qmqttsubscriptionproperties +qtmqtt_add_test( + TARGET + tst_qmqttsubscriptionproperties SOURCES ../../common/broker_connection.h tst_qmqttsubscriptionproperties.cpp diff --git a/tests/auto/qmqttsubscriptionproperties/tst_qmqttsubscriptionproperties.cpp b/tests/auto/qmqttsubscriptionproperties/tst_qmqttsubscriptionproperties.cpp index 5443a9c..1b4195f 100644 --- a/tests/auto/qmqttsubscriptionproperties/tst_qmqttsubscriptionproperties.cpp +++ b/tests/auto/qmqttsubscriptionproperties/tst_qmqttsubscriptionproperties.cpp @@ -26,7 +26,7 @@ private Q_SLOTS: private: QProcess m_brokerProcess; QString m_testBroker; - quint16 m_port{1883}; + quint16 m_port{0}; }; tst_QMqttSubscriptionProperties::tst_QMqttSubscriptionProperties() diff --git a/tests/auto/qmqtttopicfilter/CMakeLists.txt b/tests/auto/qmqtttopicfilter/CMakeLists.txt index ee1a19b..fadcdc3 100644 --- a/tests/auto/qmqtttopicfilter/CMakeLists.txt +++ b/tests/auto/qmqtttopicfilter/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_qmqtttopicfilter Test: ##################################################################### -qt_internal_add_test(tst_qmqtttopicfilter +qtmqtt_add_test( + TARGET + tst_qmqtttopicfilter SOURCES tst_qmqtttopicfilter.cpp DEFINES diff --git a/tests/auto/qmqtttopicname/CMakeLists.txt b/tests/auto/qmqtttopicname/CMakeLists.txt index 142d3aa..59b2c8d 100644 --- a/tests/auto/qmqtttopicname/CMakeLists.txt +++ b/tests/auto/qmqtttopicname/CMakeLists.txt @@ -5,7 +5,9 @@ ## tst_qmqtttopicname Test: ##################################################################### -qt_internal_add_test(tst_qmqtttopicname +qtmqtt_add_test( + TARGET + tst_qmqtttopicname SOURCES tst_qmqtttopicname.cpp DEFINES diff --git a/tests/benchmarks/qmqttclient/tst_qmqttclient.cpp b/tests/benchmarks/qmqttclient/tst_qmqttclient.cpp index f0d938c..47e04f1 100644 --- a/tests/benchmarks/qmqttclient/tst_qmqttclient.cpp +++ b/tests/benchmarks/qmqttclient/tst_qmqttclient.cpp @@ -25,7 +25,7 @@ private Q_SLOTS: private: QProcess m_brokerProcess; QString m_testBroker; - quint16 m_port{1883}; + quint16 m_port{0}; }; Tst_QMqttClient::Tst_QMqttClient() @@ -54,8 +54,8 @@ void Tst_QMqttClient::stressTest_data() void Tst_QMqttClient::stressTest() { QFETCH(int, qos); - VersionClient(QMqttClient::MQTT_3_1_1, subscriber); - VersionClient(QMqttClient::MQTT_3_1_1, publisher); + VersionClient(0, subscriber); + VersionClient(0, publisher); subscriber.setHostname(m_testBroker); subscriber.setPort(m_port); @@ -109,7 +109,7 @@ void Tst_QMqttClient::stressTest2() QSet msgIds; msgIds.reserve(msgCount); - VersionClient(QMqttClient::MQTT_3_1_1, publisher); + VersionClient(0, publisher); publisher.setHostname(m_testBroker); publisher.setPort(m_port); diff --git a/tests/certificate/cert.crt b/tests/certificate/cert.crt new file mode 100644 index 0000000..01a2fcd --- /dev/null +++ b/tests/certificate/cert.crt @@ -0,0 +1,27 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +-----BEGIN CERTIFICATE----- +MIID6zCCAtOgAwIBAgIUbbY+pKEPOOytRZ3RujmmdriEAKcwDQYJKoZIhvcNAQEL +BQAwgYMxCzAJBgNVBAYTAk5PMQ0wCwYDVQQIDARPc2xvMQ0wCwYDVQQHDARPc2xv +MQswCQYDVQQKDAJRdDELMAkGA1UECwwCUXQxEjAQBgNVBAMMCWxvY2FsaG9zdDEo +MCYGCSqGSIb3DQEJARYZZXZlbi5vc2Nhci5hbmRlcnNlbkBxdC5pbzAgFw0yNDEw +MzExMTMyNDdaGA8yMTI0MTAwNzExMzI0N1owgYMxCzAJBgNVBAYTAk5PMQ0wCwYD +VQQIDARPc2xvMQ0wCwYDVQQHDARPc2xvMQswCQYDVQQKDAJRdDELMAkGA1UECwwC +UXQxEjAQBgNVBAMMCWxvY2FsaG9zdDEoMCYGCSqGSIb3DQEJARYZZXZlbi5vc2Nh +ci5hbmRlcnNlbkBxdC5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJzWmpWU9f/baRi/Fhn362W488HzC2/MUdbTZGIQUqt1TwTLyYMEqkr6WMy/NdYL +8X5oXW0uz8LttbFp98wJTkNirYBMxowxwWWePnqbK0iKaZTBvBzUh0vWvmtFzHUW +E93K1NtKyL76Zj/EZv0I0CpkWMobpzEW/zquPj83Wxki0xp2rr/HHynqFv8KFMoJ +pR1A6uWtly12V1aQyXZIyMoIUPgDPmsHtNZKBCcz7IsAYHjjfvEIJ+r4lOOsgTXj +cdMU+0hHfyNCy1/6xmBwnchSqDZf3bTyFRu6GK+zzFKBSyt4MB7zQ2P29qYwoNJO +buJkPRfqiQJJRLkwyu59TB0CAwEAAaNTMFEwHQYDVR0OBBYEFGGxHowwihBbJlM5 +2wzicQa2sCfwMB8GA1UdIwQYMBaAFGGxHowwihBbJlM52wzicQa2sCfwMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBACf4lUaBpw65tOZk32EpMD0D +M0ilx1AwfUqliKdhVvkFJ6jN5h17YhVjFoGtSzE7ry5Rg5J07tUK5Xkjcfk39UWV +RofVnRhrtiticXs0eXQkDXqao0aMjUjsWiokr4/cTNT5R3h9jmjzyjA6pWf2oSjT +GTzZAHdcuBTUfvPy/Ff4M5AVNsI6geUqrUd6XzFwQsDWTT86sdWQIC8j+FMghhss +9XRNOmhWtWGSRbP0HqlWOz5hFRPP/faI/FGTknzkkVYoWaB1CR+ThFK9jYi0FnFL +2fIcJPt+6g6d01Ws5cb9HpL9joUloCjsZ+w6PXYNVyHTaG3Lg5o4nT1Oizvrq1k= +-----END CERTIFICATE----- + diff --git a/tests/certificate/cert.key b/tests/certificate/cert.key new file mode 100644 index 0000000..ab63489 --- /dev/null +++ b/tests/certificate/cert.key @@ -0,0 +1,32 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCc1pqVlPX/22kY +vxYZ9+tluPPB8wtvzFHW02RiEFKrdU8Ey8mDBKpK+ljMvzXWC/F+aF1tLs/C7bWx +affMCU5DYq2ATMaMMcFlnj56mytIimmUwbwc1IdL1r5rRcx1FhPdytTbSsi++mY/ +xGb9CNAqZFjKG6cxFv86rj4/N1sZItMadq6/xx8p6hb/ChTKCaUdQOrlrZctdldW +kMl2SMjKCFD4Az5rB7TWSgQnM+yLAGB4437xCCfq+JTjrIE143HTFPtIR38jQstf ++sZgcJ3IUqg2X9208hUbuhivs8xSgUsreDAe80Nj9vamMKDSTm7iZD0X6okCSUS5 +MMrufUwdAgMBAAECggEAKs2u9q/my2M4NZbBE2lEB0kIzZ/lOSfMFhMvTEwkI8Mq +Q6bSYj19tGTKo2Zz7OzphZQ6GzgxX4O8mKTRChBoGZ/uths9/Lj/jRo49wEuOOf9 +lKmjC0M9gYckBObRvArAdUGMAiVQ0D5KdZDGgrxLA6bLTK1rXcxm777qIhqbdCpN +i9RwW9wp9rMV53J8mmWWUDVpfbIKHAmp50JknXj07onPEqN6IKdZY7sYACfYiz/8 +l31rKfR/P5j/aRBOFwBnq7Z3JGfOEQPmE8bxQ2Vt3ZXPK2ekreDx4j2Tz+gSZmF3 +Ee8DonQtA1DTOlhMyb6FhJrEFmDr38jGQqDK4qV8iQKBgQDLoOSYzX0xcyK2dPMD +woPGcKymI+XYx0Q6cVZo1GttNarhBN0w0ms9a4SYoTMhAI9tzjJw/sU5t9kLan6n +m11PqQVK+Vbh1v2YICJW89LcOFYwyO6IAiMN1LUdy8las4GwcXRwBWWnXAnE+YJK +AiXcmB1ZX3j8pgStCF9VApC50wKBgQDFLP87pGtWW3nvkxoDpgVb1CwpO1T1EsFF +Yzv7eIkFQGUkqF7OlslhMCOERE8pj4dr4CoTIvVsYW+lYfBnFPpQ0pQ+BZ2meZ0u +GfWBDYpNGTGrxEDBc923glb2oegQQirHpiWtlinp5nciOn/rqpUwJR3b46drFlNy +26CTKA+8TwKBgQDKv8qdMo2i/QblMRD+/2CB55KgYkHrVI1ku5DUFB1awgMAxf0P +LZRFtZZy+p6UD6DALn0e8S2jSKE9sq2laRbByINSoW2WtKAQJn7KoT+kshtvu8F1 +fts0XERyBITaYL2S14SePWF4ADZiACVwVy8ns/YVFPC8bvlc6Gczl7hOrQKBgQCP +BUmJSIT3GdlDlq7q8JS4fBkgO0IvldAM9aL/j/nLjl8PDPXf4e3mihVpDmdhXRO8 +gtfiE5xzZeWmz3iiPMworeYLauVkaJhDZV73ogusStcFoY/bAqFTR76unNgIWwZO +1MxFskNqvtmxQT+igJRAXNvgsKuyeHpFONurggaP7wKBgCj25sAxVcOuOcANQGcO +wCNvt1pHDJengrzaKooCJqm5YxNhrcKlJsdQcQ1Mu+KyhcMY/WF/0UaJZytlHMWf +aDlF7zKqhQFqFY7nk/C7+fED7Kg3XJR54qtweVNzD6k4yTeSsvBeTd2aaepzZvJI +IOQ3RPVQNsdgjn3VTGs/rmrR +-----END PRIVATE KEY----- + diff --git a/tests/common/broker_connection.h b/tests/common/broker_connection.h index a28f13c..1d6d9f6 100644 --- a/tests/common/broker_connection.h +++ b/tests/common/broker_connection.h @@ -8,8 +8,16 @@ #include #include +#ifdef QT_MQTT_WITH_WEBSOCKETS +#include +#include +#endif + QString invokeOrInitializeBroker(QProcess *gBrokerProcess) { +#if defined(MQTT_TEST_BROKER) + return QString::fromLatin1(MQTT_TEST_BROKER); +#endif const QString broker = qgetenv("MQTT_TEST_BROKER"); if (broker.size()) { qDebug("Overwriting default test broker"); @@ -65,13 +73,256 @@ QString invokeOrInitializeBroker(QProcess *gBrokerProcess) return QString(); } +#if !defined(QT_NO_SSL) +QSslConfiguration makeConfig(QString certificateFile) +{ + if (certificateFile.isEmpty()) + certificateFile=QString(u":/certificate/cert.crt"); + + QSslConfiguration config; + QFile file(certificateFile); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << " Could not open certificate file " << certificateFile; + } else { + const auto bytes = file.readAll(); + const QSslCertificate certificate(bytes); + + config.addCaCertificate(certificate); + } + return config; +} +#endif /* !QT_NO_SSL */ + +int getBrokerPort(int defaultPort) +{ + if (getenv("MQTT_TEST_BROKER_PORT")) + return atoi(getenv("MQTT_TEST_BROKER_PORT")); + +#if defined (MQTT_TEST_PROTOCOL) + return defaultPort; +#else + return defaultPort - 1000; /* evaluates to 1883 for the old system */ +#endif +} + +QMqttClient::ProtocolVersion getProtocolVersion(int version) +{ +#if defined (MQTT_TEST_PROTOCOL) + if (version == 0) + version=MQTT_TEST_PROTOCOL; +#else + if ((version == 0) && getenv("MQTT_TEST_PROTOCOL_VERSION")) { + switch (atoi(getenv("MQTT_TEST_PROTOCOL_VERSION"))) { + case 3: version = QMqttClient::MQTT_3_1; break; + case 4: version = QMqttClient::MQTT_3_1_1; break; + case 5: version = QMqttClient::MQTT_5_0; break; + } + } + if (version == 0) + version = QMqttClient::MQTT_5_0; +#endif + return (QMqttClient::ProtocolVersion)version; +} + +class MqTTTestClientBase : public QMqttClient +{ +public: + virtual bool isTcp() const { return false; } + virtual bool isSsl() const { return false; } + virtual bool isWs() const { return false; } + virtual bool isWss() const { return false; } +public: + virtual void setPort(quint16 port) = 0; + virtual void connectToHost() = 0; + + void setTransport(QIODevice *device, TransportType transport) + { + m_transportSet = true; + QMqttClient::setTransport(device, transport); + } + void disconnectFromHost() + { + m_transportSet = false; + QMqttClient::disconnectFromHost(); + } +protected: + bool m_transportSet = false; +}; + +class MqTTClientTcp : public MqTTTestClientBase +{ +public: + MqTTClientTcp() = default; + + virtual bool isTcp() const override { return true; } + void setPort(quint16 port) override + { + if (port == 0) + port = getBrokerPort(2883); + QMqttClient::setPort(port); + } + void connectToHost() override + { + QMqttClient::connectToHost(); + } +}; + +#ifdef QT_MQTT_WITH_WEBSOCKETS +class MqTTClientWs : public MqTTTestClientBase +{ +public: + MqTTClientWs() = default; + + virtual bool isWs() const override { return true; } + + void setPort(quint16 port) override + { + if (port == 0) + port = getBrokerPort(9080); + QMqttClient::setPort(port); + } + + void connectToHost() override + { + if (m_transportSet) + QMqttClient::connectToHost(); + else + QMqttClient::connectToHostWebSocket(); + } +}; +#endif + +#ifdef QT_MQTT_WITH_WEBSOCKETS +class MqTTClientWss : public MqTTTestClientBase +{ +public: + MqTTClientWss() + { +#ifndef QT_NO_SSL + const QString origin; + const QWebSocketProtocol::Version version = QWebSocketProtocol::VersionLatest; + socket = new QWebSocket(origin, version, this); +#endif + } + + virtual bool isWss() const override { return true; } + + void setPort(quint16 port) override + { + if (port == 0) + port = getBrokerPort(9081); + QMqttClient::setPort(port); + } + + void connectToHost() override + { + if (m_transportSet) + QMqttClient::connectToHost(); + else { +#ifndef QT_NO_SSL + QUrl url(QString(u"wss://") + QMqttClient::hostname() + QString(u":") + QString::number(QMqttClient::port())); + QWebSocketHandshakeOptions options; + options.setSubprotocols(QStringList{ QString::fromUtf8("mqttv3.1") }); + socket->setSslConfiguration(makeConfig(QString::fromUtf8(getenv("MQTT_TEST_BROKER_CERTIFICATE")))); + socket->open(url, options); +#endif + QMqttClient::connectToHostWebSocketEncrypted(socket); + } + } + +private: + QWebSocket *socket = nullptr; +}; +#endif + +#ifndef QT_NO_SSL +class MqTTClientSsl : public MqTTTestClientBase +{ +public: + MqTTClientSsl() = default; + + virtual bool isSsl() const override { return true; } + + void setPort(quint16 port) override + { + if (port == 0) + port = getBrokerPort(9883); + QMqttClient::setPort(port); + } + + void connectToHost() override + { + if (m_transportSet) + QMqttClient::connectToHost(); + else { + QMqttClient::connectToHostEncrypted(makeConfig(QString::fromUtf8(getenv("MQTT_TEST_BROKER_CERTIFICATE")))); + } + } +}; +#endif /* !QT_NO_SSL */ + Q_DECLARE_METATYPE(QMqttClient::ProtocolVersion) -#define VersionClient(MQTTVERSION, CLIENTNAME) QMqttClient CLIENTNAME; CLIENTNAME.setProtocolVersion(MQTTVERSION) + +#if !defined(QT_NO_SSL) && defined(QT_MQTT_WITH_WEBSOCKETS) +#define VersionClientBase(MQTTVERSION, CLIENTNAME, TestType) \ + std::shared_ptr p##CLIENTNAME; \ + if (TestType == QString(u"Tcp")) p##CLIENTNAME = std::make_shared(); \ + if (TestType == QString(u"Ws")) p##CLIENTNAME = std::make_shared(); \ + if (TestType == QString(u"Wss")) p##CLIENTNAME = std::make_shared(); \ + if (TestType == QString(u"Ssl")) p##CLIENTNAME = std::make_shared(); \ + if (!p##CLIENTNAME) p##CLIENTNAME = std::make_shared(); \ + MqTTTestClientBase &CLIENTNAME = *p##CLIENTNAME; \ + CLIENTNAME.setProtocolVersion(getProtocolVersion(MQTTVERSION)) +#endif + +#if defined(QT_NO_SSL) && defined(QT_MQTT_WITH_WEBSOCKETS) +#define VersionClientBase(MQTTVERSION, CLIENTNAME, TestType) \ + std::shared_ptr p##CLIENTNAME; \ + if (TestType == QString(u"Tcp")) p##CLIENTNAME = std::make_shared(); \ + if (TestType == QString(u"Ws")) p##CLIENTNAME = std::make_shared(); \ + if (TestType == QString(u"Wss")) p##CLIENTNAME = std::make_shared(); \ + if (!p##CLIENTNAME) p##CLIENTNAME = std::make_shared(); \ + MqTTTestClientBase &CLIENTNAME = *p##CLIENTNAME; \ + CLIENTNAME.setProtocolVersion(getProtocolVersion(MQTTVERSION)) +#endif + +#if !defined(QT_NO_SSL) && !defined(QT_MQTT_WITH_WEBSOCKETS) +#define VersionClientBase(MQTTVERSION, CLIENTNAME, TestType) \ + std::shared_ptr p##CLIENTNAME; \ + if (TestType == QString(u"Tcp")) p##CLIENTNAME = std::make_shared(); \ + if (TestType == QString(u"Ssl")) p##CLIENTNAME = std::make_shared(); \ + if (!p##CLIENTNAME) p##CLIENTNAME = std::make_shared(); \ + MqTTTestClientBase &CLIENTNAME = *p##CLIENTNAME; \ + CLIENTNAME.setProtocolVersion(getProtocolVersion(MQTTVERSION)) +#endif + +#if defined(QT_NO_SSL) && !defined(QT_MQTT_WITH_WEBSOCKETS) +#define VersionClientBase(MQTTVERSION, CLIENTNAME, TestType) \ + std::shared_ptr p##CLIENTNAME; \ + if (TestType == QString(u"Tcp")) p##CLIENTNAME = std::make_shared(); \ + if (!p##CLIENTNAME) p##CLIENTNAME = std::make_shared(); \ + MqTTTestClientBase &CLIENTNAME = *p##CLIENTNAME; \ + CLIENTNAME.setProtocolVersion(getProtocolVersion(MQTTVERSION)) +#endif + + +#if defined(MQTT_TEST_TYPE) +#define VersionClient(MQTTVERSION, CLIENTNAME) \ + VersionClientBase(MQTTVERSION, CLIENTNAME, MQTT_TEST_TYPE) +#else +#define VersionClient(MQTTVERSION, CLIENTNAME) \ + VersionClientBase(MQTTVERSION, CLIENTNAME, qgetenv("MQTT_TEST_BROKER_TYPE")) +#endif + #define DefaultVersionTestData(FUNCTION) \ void FUNCTION() \ { \ QTest::addColumn("mqttVersion"); \ - QTest::newRow("V3.1.1") << QMqttClient::MQTT_3_1_1; \ - QTest::newRow("V5.0.0") << QMqttClient::MQTT_5_0; \ + if (getenv("MQTT_TEST_PROTOCOL_VERSION"))\ + QTest::newRow("V0") << QMqttClient::ProtocolVersion(0); \ + else { \ + QTest::newRow("V3.1.1") << QMqttClient::MQTT_3_1_1; \ + QTest::newRow("V5.0.0") << QMqttClient::MQTT_5_0; \ + } \ }