2018-08-24 04:42:50 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Copyright (C) 2017 Witekio.
|
|
|
|
** Copyright (C) 2018 The Qt Company Ltd.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
|
|
|
**
|
|
|
|
** This file is part of the QtCoap module.
|
|
|
|
**
|
|
|
|
** $QT_BEGIN_LICENSE:GPL$
|
|
|
|
** 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 https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
**
|
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 or (at your option) any later version
|
|
|
|
** approved by the KDE Free Qt Foundation. The licenses are as published by
|
|
|
|
** the Free Software Foundation and appearing in the file LICENSE.GPL3
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <QtTest>
|
|
|
|
#include <QCoreApplication>
|
|
|
|
|
|
|
|
#include <QtCoap/qcoapclient.h>
|
|
|
|
#include <QtCoap/qcoaprequest.h>
|
|
|
|
#include <QtCoap/qcoapreply.h>
|
|
|
|
#include <QtCoap/qcoapdiscoveryreply.h>
|
|
|
|
#include <QtCore/qbuffer.h>
|
|
|
|
#include <QtNetwork/qnetworkdatagram.h>
|
|
|
|
#include <private/qcoapclient_p.h>
|
2019-01-09 13:30:01 +00:00
|
|
|
#include <private/qcoapqudpconnection_p.h>
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
#include "../coapnetworksettings.h"
|
|
|
|
|
|
|
|
using namespace QtCoapNetworkSettings;
|
|
|
|
|
|
|
|
class tst_QCoapClient : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
private Q_SLOTS:
|
|
|
|
void incorrectUrls_data();
|
|
|
|
void incorrectUrls();
|
|
|
|
void methods_data();
|
|
|
|
void methods();
|
|
|
|
void separateMethod();
|
|
|
|
void socketError();
|
|
|
|
void timeout_data();
|
|
|
|
void timeout();
|
|
|
|
void abort();
|
|
|
|
void removeReply();
|
|
|
|
void setBlockSize_data();
|
|
|
|
void setBlockSize();
|
|
|
|
void requestWithQIODevice_data();
|
|
|
|
void requestWithQIODevice();
|
|
|
|
void multipleRequests();
|
|
|
|
void blockwiseReply_data();
|
|
|
|
void blockwiseReply();
|
|
|
|
void blockwiseRequest_data();
|
|
|
|
void blockwiseRequest();
|
|
|
|
void discover_data();
|
|
|
|
void discover();
|
|
|
|
void observe_data();
|
|
|
|
void observe();
|
2019-02-11 16:35:15 +00:00
|
|
|
void confirmableMulticast();
|
|
|
|
void multicast();
|
|
|
|
void multicast_blockwise();
|
2018-08-24 04:42:50 +00:00
|
|
|
};
|
|
|
|
|
2019-05-09 16:01:35 +00:00
|
|
|
#ifdef QT_BUILD_INTERNAL
|
|
|
|
|
2019-01-09 13:30:01 +00:00
|
|
|
class QCoapQUdpConnectionSocketTestsPrivate : public QCoapQUdpConnectionPrivate
|
2018-08-24 04:42:50 +00:00
|
|
|
{
|
|
|
|
bool bind() override
|
|
|
|
{
|
|
|
|
// Force a socket binding error
|
|
|
|
QUdpSocket anotherSocket;
|
|
|
|
anotherSocket.bind(QHostAddress::Any, 6080);
|
|
|
|
return socket()->bind(QHostAddress::Any, 6080);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-01-09 13:30:01 +00:00
|
|
|
class QCoapQUdpConnectionSocketTests : public QCoapQUdpConnection
|
2018-08-24 04:42:50 +00:00
|
|
|
{
|
|
|
|
public:
|
2019-01-09 13:30:01 +00:00
|
|
|
QCoapQUdpConnectionSocketTests() :
|
|
|
|
QCoapQUdpConnection(*new QCoapQUdpConnectionSocketTestsPrivate)
|
2018-08-24 04:42:50 +00:00
|
|
|
{
|
|
|
|
createSocket();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2019-01-09 13:30:01 +00:00
|
|
|
Q_DECLARE_PRIVATE(QCoapQUdpConnectionSocketTests)
|
2018-08-24 04:42:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class QCoapClientForSocketErrorTests : public QCoapClient
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
QCoapClientForSocketErrorTests() :
|
2019-01-09 13:30:01 +00:00
|
|
|
QCoapClient(new QCoapProtocol, new QCoapQUdpConnectionSocketTests)
|
2018-08-24 04:42:50 +00:00
|
|
|
{}
|
|
|
|
|
2019-01-09 13:30:01 +00:00
|
|
|
QCoapQUdpConnection *connection()
|
2018-08-24 04:42:50 +00:00
|
|
|
{
|
|
|
|
QCoapClientPrivate *privateClient = static_cast<QCoapClientPrivate *>(d_func());
|
2019-01-09 13:30:01 +00:00
|
|
|
return qobject_cast<QCoapQUdpConnection*>(privateClient->connection);
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class QCoapClientForTests : public QCoapClient
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
QCoapClientForTests() {}
|
2019-01-09 13:30:01 +00:00
|
|
|
QCoapClientForTests(QCoapProtocol *protocol, QCoapQUdpConnection *connection) :
|
2018-08-24 04:42:50 +00:00
|
|
|
QCoapClient(protocol, connection)
|
|
|
|
{}
|
|
|
|
|
|
|
|
QCoapProtocol *protocol()
|
|
|
|
{
|
|
|
|
QCoapClientPrivate *privateClient = static_cast<QCoapClientPrivate *>(d_func());
|
|
|
|
return privateClient->protocol;
|
|
|
|
}
|
2019-01-09 13:30:01 +00:00
|
|
|
QCoapQUdpConnection *connection()
|
2018-08-24 04:42:50 +00:00
|
|
|
{
|
|
|
|
QCoapClientPrivate *privateClient = static_cast<QCoapClientPrivate *>(d_func());
|
2019-01-09 13:30:01 +00:00
|
|
|
return qobject_cast<QCoapQUdpConnection*>(privateClient->connection);
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-02-11 16:35:15 +00:00
|
|
|
class QCoapConnectionMulticastTests : public QCoapConnection
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
~QCoapConnectionMulticastTests() override = default;
|
|
|
|
|
|
|
|
void bind(const QString &host, quint16 port) override
|
|
|
|
{
|
|
|
|
Q_UNUSED(host);
|
|
|
|
Q_UNUSED(port);
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeData(const QByteArray &data, const QString &host, quint16 port) override
|
|
|
|
{
|
|
|
|
Q_UNUSED(data);
|
|
|
|
Q_UNUSED(host);
|
|
|
|
Q_UNUSED(port);
|
|
|
|
// Do nothing
|
|
|
|
}
|
2019-04-01 16:13:57 +00:00
|
|
|
|
|
|
|
void close() override {}
|
2019-02-11 16:35:15 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class QCoapClientForMulticastTests : public QCoapClient
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
QCoapClientForMulticastTests() :
|
|
|
|
QCoapClient(new QCoapProtocol, new QCoapConnectionMulticastTests)
|
|
|
|
{}
|
|
|
|
|
|
|
|
QCoapConnection *connection()
|
|
|
|
{
|
|
|
|
QCoapClientPrivate *privateClient = static_cast<QCoapClientPrivate *>(d_func());
|
|
|
|
return privateClient->connection;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-05-09 16:01:35 +00:00
|
|
|
#endif
|
2019-02-11 16:35:15 +00:00
|
|
|
|
2018-08-24 04:42:50 +00:00
|
|
|
class Helper : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
Helper() {}
|
|
|
|
|
|
|
|
public slots:
|
|
|
|
void onError(QCoapReply *, QtCoap::Error error)
|
|
|
|
{
|
|
|
|
qWarning() << "Network error" << error << "occurred";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void tst_QCoapClient::incorrectUrls_data()
|
|
|
|
{
|
|
|
|
QWARN("Expect warnings here...");
|
|
|
|
QTest::addColumn<QUrl>("url");
|
|
|
|
|
|
|
|
QTest::newRow("get") << QUrl("wrong://10.20.30.40:5683/test");
|
|
|
|
QTest::newRow("post") << QUrl("wrong://10.20.30.40:5683/test");
|
|
|
|
QTest::newRow("put") << QUrl("wrong://10.20.30.40:5683/test");
|
|
|
|
QTest::newRow("delete") << QUrl("wrong://10.20.30.40:5683/test");
|
|
|
|
QTest::newRow("discover") << QUrl("wrong://10.20.30.40:5683/test");
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::incorrectUrls()
|
|
|
|
{
|
|
|
|
QFETCH(QUrl, url);
|
|
|
|
|
|
|
|
QCoapClient client;
|
|
|
|
QScopedPointer<QCoapReply> reply;
|
|
|
|
|
|
|
|
if (qstrcmp(QTest::currentDataTag(), "get") == 0)
|
|
|
|
reply.reset(client.get(url));
|
|
|
|
else if (qstrcmp(QTest::currentDataTag(), "post") == 0)
|
|
|
|
reply.reset(client.post(url));
|
|
|
|
else if (qstrcmp(QTest::currentDataTag(), "put") == 0)
|
|
|
|
reply.reset(client.put(url));
|
|
|
|
else if (qstrcmp(QTest::currentDataTag(), "delete") == 0)
|
|
|
|
reply.reset(client.deleteResource(url));
|
|
|
|
else if (qstrcmp(QTest::currentDataTag(), "discover") == 0)
|
|
|
|
reply.reset(client.discover(url));
|
|
|
|
else {
|
|
|
|
QString error = QLatin1Literal("Unrecognized method '") + QTest::currentDataTag() + "'";
|
|
|
|
QFAIL(qPrintable(error));
|
|
|
|
}
|
|
|
|
|
|
|
|
QVERIFY2(reply.isNull(), "Request did not fail as expected.");
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::methods_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<QUrl>("url");
|
|
|
|
QTest::addColumn<QtCoap::Method>("method");
|
|
|
|
|
2019-04-26 14:40:18 +00:00
|
|
|
QTest::newRow("get") << QUrl(testServerResource()) << QtCoap::Method::Get;
|
|
|
|
QTest::newRow("get_no_port") << QUrl("coap://" + testServerHost() + "/test")
|
|
|
|
<< QtCoap::Method::Get;
|
|
|
|
QTest::newRow("get_no_scheme_no_port") << QUrl(testServerHost() + "/test")
|
|
|
|
<< QtCoap::Method::Get;
|
|
|
|
QTest::newRow("post") << QUrl(testServerResource())
|
|
|
|
<< QtCoap::Method::Post;
|
|
|
|
QTest::newRow("post_no_scheme_no_port") << QUrl(testServerHost() + "/test")
|
|
|
|
<< QtCoap::Method::Post;
|
|
|
|
QTest::newRow("put") << QUrl(testServerResource())
|
|
|
|
<< QtCoap::Method::Put;
|
|
|
|
QTest::newRow("put_no_scheme_no_port") << QUrl(testServerHost() + "/test")
|
|
|
|
<< QtCoap::Method::Put;
|
|
|
|
QTest::newRow("delete") << QUrl(testServerResource())
|
|
|
|
<< QtCoap::Method::Delete;
|
|
|
|
QTest::newRow("delete_no_scheme_no_port") << QUrl(testServerHost() + "/test")
|
|
|
|
<< QtCoap::Method::Delete;
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::methods()
|
|
|
|
{
|
|
|
|
QFETCH(QUrl, url);
|
|
|
|
QFETCH(QtCoap::Method, method);
|
|
|
|
|
|
|
|
QCoapClient client;
|
|
|
|
QCoapRequest request(url);
|
|
|
|
|
|
|
|
QSignalSpy spyClientFinished(&client, SIGNAL(finished(QCoapReply *)));
|
|
|
|
|
|
|
|
QScopedPointer<QCoapReply> reply;
|
|
|
|
if (qstrncmp(QTest::currentDataTag(), "get", 3) == 0)
|
|
|
|
reply.reset(client.get(request));
|
|
|
|
else if (qstrncmp(QTest::currentDataTag(), "post", 4) == 0)
|
|
|
|
reply.reset(client.post(request));
|
|
|
|
else if (qstrncmp(QTest::currentDataTag(), "put", 3) == 0)
|
|
|
|
reply.reset(client.put(request));
|
|
|
|
else if (qstrncmp(QTest::currentDataTag(), "delete", 6) == 0)
|
|
|
|
reply.reset(client.deleteResource(request));
|
|
|
|
else {
|
|
|
|
QString error = QLatin1Literal("Unrecognized method '") + QTest::currentDataTag() + "'";
|
|
|
|
QFAIL(qPrintable(error));
|
|
|
|
}
|
|
|
|
|
|
|
|
QVERIFY2(!reply.isNull(), "Request failed unexpectedly");
|
2019-02-05 14:14:26 +00:00
|
|
|
QCOMPARE(reply->url(), QCoapRequest::adjustedUrl(url, false));
|
2018-08-24 04:42:50 +00:00
|
|
|
QSignalSpy spyReplyFinished(reply.data(), SIGNAL(finished(QCoapReply *)));
|
|
|
|
QTRY_COMPARE(spyReplyFinished.count(), 1);
|
|
|
|
QTRY_COMPARE(spyClientFinished.count(), 1);
|
|
|
|
|
|
|
|
QByteArray replyData;
|
|
|
|
if (!reply.isNull()) {
|
|
|
|
replyData = reply->readAll();
|
|
|
|
if (qstrncmp(QTest::currentDataTag(), "get", 3) == 0) {
|
|
|
|
QVERIFY(!replyData.isEmpty());
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(reply->responseCode(), QtCoap::ResponseCode::Content);
|
2018-08-24 04:42:50 +00:00
|
|
|
} else if (qstrncmp(QTest::currentDataTag(), "post", 4) == 0) {
|
|
|
|
QVERIFY(replyData.isEmpty());
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(reply->responseCode(), QtCoap::ResponseCode::Created);
|
2018-08-24 04:42:50 +00:00
|
|
|
} else if (qstrncmp(QTest::currentDataTag(), "put", 3) == 0) {
|
|
|
|
QVERIFY(replyData.isEmpty());
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(reply->responseCode(), QtCoap::ResponseCode::Changed);
|
2018-08-24 04:42:50 +00:00
|
|
|
} else if (qstrncmp(QTest::currentDataTag(), "delete", 6) == 0) {
|
|
|
|
QVERIFY(replyData.isEmpty());
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(reply->responseCode(), QtCoap::ResponseCode::Deleted);
|
2018-08-24 04:42:50 +00:00
|
|
|
} else {
|
|
|
|
QString error = QLatin1Literal("Unrecognized method '") + QTest::currentDataTag() + "'";
|
|
|
|
QFAIL(qPrintable(error));
|
|
|
|
}
|
|
|
|
}
|
2019-03-06 16:14:56 +00:00
|
|
|
QCOMPARE(reply->request().method(), method);
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::separateMethod()
|
|
|
|
{
|
|
|
|
QCoapClient client;
|
|
|
|
QScopedPointer<QCoapReply> reply(client.get(QUrl(testServerUrl() + "/separate")));
|
|
|
|
|
|
|
|
QVERIFY2(!reply.isNull(), "Request failed unexpectedly");
|
|
|
|
QSignalSpy spyReplyFinished(reply.data(), SIGNAL(finished(QCoapReply *)));
|
|
|
|
QTRY_COMPARE(spyReplyFinished.count(), 1);
|
|
|
|
|
|
|
|
QByteArray replyData = reply->readAll();
|
|
|
|
|
|
|
|
QVERIFY(!replyData.isEmpty());
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(reply->responseCode(), QtCoap::ResponseCode::Content);
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::removeReply()
|
|
|
|
{
|
|
|
|
QCoapClient client;
|
|
|
|
QCoapReply *reply = client.get(QUrl(testServerResource()));
|
|
|
|
QVERIFY2(reply != nullptr, "Request failed unexpectedly");
|
|
|
|
|
|
|
|
try {
|
|
|
|
reply->deleteLater();
|
|
|
|
|
|
|
|
QEventLoop eventLoop;
|
|
|
|
QTimer::singleShot(2000, &eventLoop, &QEventLoop::quit);
|
|
|
|
eventLoop.exec();
|
|
|
|
} catch (...) {
|
|
|
|
QFAIL("Exception occurred after destroying the QCoapReply");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::setBlockSize_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<int>("blockSizeSet");
|
|
|
|
QTest::addColumn<int>("blockSizeExpected");
|
|
|
|
|
|
|
|
QTest::newRow("valid_size_0") << 0 << 0;
|
|
|
|
QTest::newRow("valid_size_16") << 16 << 16;
|
|
|
|
QTest::newRow("valid_size_1024") << 1024 << 1024;
|
|
|
|
QTest::newRow("invalid_size_8") << 8 << 0;
|
|
|
|
QTest::newRow("invalid_size_350") << 350 << 0;
|
|
|
|
QTest::newRow("invalid_size_2048") << 2048 << 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::setBlockSize()
|
|
|
|
{
|
2019-05-09 16:01:35 +00:00
|
|
|
#ifdef QT_BUILD_INTERNAL
|
2018-08-24 04:42:50 +00:00
|
|
|
QFETCH(int, blockSizeSet);
|
|
|
|
QFETCH(int, blockSizeExpected);
|
|
|
|
|
|
|
|
QCoapClientForTests client;
|
|
|
|
client.setBlockSize(blockSizeSet);
|
|
|
|
|
|
|
|
QEventLoop eventLoop;
|
|
|
|
QTimer::singleShot(1000, &eventLoop, &QEventLoop::quit);
|
|
|
|
eventLoop.exec();
|
|
|
|
|
|
|
|
QCOMPARE(client.protocol()->blockSize(), blockSizeExpected);
|
2019-05-09 16:01:35 +00:00
|
|
|
#else
|
|
|
|
QSKIP("Not an internal build, skipping this test");
|
|
|
|
#endif
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::requestWithQIODevice_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<QUrl>("url");
|
|
|
|
|
|
|
|
QTest::newRow("post") << QUrl(testServerResource());
|
|
|
|
QTest::newRow("put") << QUrl(testServerResource());
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::requestWithQIODevice()
|
|
|
|
{
|
|
|
|
QFETCH(QUrl, url);
|
|
|
|
|
|
|
|
QCoapClient client;
|
|
|
|
QCoapRequest request(url);
|
|
|
|
|
|
|
|
QBuffer buffer;
|
|
|
|
buffer.open(QIODevice::ReadWrite);
|
|
|
|
buffer.write("Some data");
|
|
|
|
|
|
|
|
QScopedPointer<QCoapReply> reply;
|
|
|
|
if (qstrcmp(QTest::currentDataTag(), "post") == 0)
|
|
|
|
reply.reset(client.post(request, &buffer));
|
|
|
|
else
|
|
|
|
reply.reset(client.put(request, &buffer));
|
|
|
|
|
|
|
|
QVERIFY2(!reply.isNull(), "Request failed unexpectedly");
|
|
|
|
QSignalSpy spyReplyFinished(reply.data(), SIGNAL(finished(QCoapReply *)));
|
|
|
|
QTRY_COMPARE(spyReplyFinished.count(), 1);
|
|
|
|
|
|
|
|
QByteArray replyData = reply->readAll();
|
|
|
|
|
|
|
|
if (qstrcmp(QTest::currentDataTag(), "post") == 0) {
|
|
|
|
QVERIFY(replyData.isEmpty());
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(reply->responseCode(), QtCoap::ResponseCode::Created);
|
2018-08-24 04:42:50 +00:00
|
|
|
} else if (qstrcmp(QTest::currentDataTag(), "put") == 0) {
|
|
|
|
QVERIFY(replyData.isEmpty());
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(reply->responseCode(), QtCoap::ResponseCode::Changed);
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::multipleRequests()
|
|
|
|
{
|
|
|
|
QCoapClient client;
|
|
|
|
QUrl url = QUrl(testServerResource());
|
|
|
|
QSignalSpy spyClientFinished(&client, SIGNAL(finished(QCoapReply *)));
|
|
|
|
|
|
|
|
QScopedPointer<QCoapReply> replyGet1(client.get(url));
|
|
|
|
QScopedPointer<QCoapReply> replyGet2(client.get(url));
|
|
|
|
QScopedPointer<QCoapReply> replyGet3(client.get(url));
|
|
|
|
QScopedPointer<QCoapReply> replyGet4(client.get(url));
|
|
|
|
|
|
|
|
QVERIFY2(!replyGet1.isNull(), "Request failed unexpectedly");
|
|
|
|
QVERIFY2(!replyGet2.isNull(), "Request failed unexpectedly");
|
|
|
|
QVERIFY2(!replyGet3.isNull(), "Request failed unexpectedly");
|
|
|
|
QVERIFY2(!replyGet4.isNull(), "Request failed unexpectedly");
|
|
|
|
|
|
|
|
QSignalSpy spyReplyGet1Finished(replyGet1.data(), SIGNAL(finished(QCoapReply *)));
|
|
|
|
QSignalSpy spyReplyGet2Finished(replyGet2.data(), SIGNAL(finished(QCoapReply *)));
|
|
|
|
QSignalSpy spyReplyGet3Finished(replyGet3.data(), SIGNAL(finished(QCoapReply *)));
|
|
|
|
QSignalSpy spyReplyGet4Finished(replyGet4.data(), SIGNAL(finished(QCoapReply *)));
|
|
|
|
|
|
|
|
QTRY_COMPARE(spyReplyGet1Finished.count(), 1);
|
|
|
|
QTRY_COMPARE(spyReplyGet2Finished.count(), 1);
|
|
|
|
QTRY_COMPARE(spyReplyGet3Finished.count(), 1);
|
|
|
|
QTRY_COMPARE(spyReplyGet4Finished.count(), 1);
|
|
|
|
QTRY_COMPARE(spyClientFinished.count(), 4);
|
|
|
|
|
|
|
|
QByteArray replyData1 = replyGet1->readAll();
|
|
|
|
QByteArray replyData2 = replyGet2->readAll();
|
|
|
|
QByteArray replyData3 = replyGet3->readAll();
|
|
|
|
QByteArray replyData4 = replyGet4->readAll();
|
|
|
|
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(replyGet1->responseCode(), QtCoap::ResponseCode::Content);
|
|
|
|
QCOMPARE(replyGet2->responseCode(), QtCoap::ResponseCode::Content);
|
|
|
|
QCOMPARE(replyGet3->responseCode(), QtCoap::ResponseCode::Content);
|
|
|
|
QCOMPARE(replyGet4->responseCode(), QtCoap::ResponseCode::Content);
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
QVERIFY(replyData1 != replyData2);
|
|
|
|
QVERIFY(replyData1 != replyData3);
|
|
|
|
QVERIFY(replyData1 != replyData4);
|
|
|
|
QVERIFY(replyData2 != replyData3);
|
|
|
|
QVERIFY(replyData2 != replyData4);
|
|
|
|
QVERIFY(replyData3 != replyData4);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::socketError()
|
|
|
|
{
|
|
|
|
#ifdef QT_BUILD_INTERNAL
|
|
|
|
QCoapClientForSocketErrorTests client;
|
|
|
|
QUrl url = QUrl(testServerResource());
|
|
|
|
|
2019-01-09 13:30:01 +00:00
|
|
|
const auto connection = client.connection();
|
|
|
|
QVERIFY2(connection, "Failed to get coap connection!");
|
|
|
|
QUdpSocket *socket = connection->socket();
|
2018-08-24 04:42:50 +00:00
|
|
|
QVERIFY2(socket, "Socket not properly created with connection");
|
|
|
|
QSignalSpy spySocketError(socket, SIGNAL(error(QAbstractSocket::SocketError)));
|
|
|
|
QScopedPointer<QCoapReply> reply(client.get(url));
|
|
|
|
QSignalSpy spyClientError(&client, &QCoapClient::error);
|
|
|
|
|
|
|
|
QTRY_COMPARE_WITH_TIMEOUT(spySocketError.count(), 1, 10000);
|
|
|
|
QTRY_COMPARE_WITH_TIMEOUT(spyClientError.count(), 1, 1000);
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(qvariant_cast<QtCoap::Error>(spyClientError.first().at(1)),
|
2019-04-26 15:12:17 +00:00
|
|
|
QtCoap::Error::AddressInUse);
|
2018-08-24 04:42:50 +00:00
|
|
|
#else
|
|
|
|
QSKIP("Not an internal build, skipping this test");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
void tst_QCoapClient::timeout_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<int>("timeout");
|
|
|
|
QTest::addColumn<int>("maxRetransmit");
|
|
|
|
|
|
|
|
QTest::newRow("2000/0") << 2000 << 0;
|
|
|
|
QTest::newRow("2000/2") << 2000 << 2;
|
|
|
|
QTest::newRow("4000/0") << 4000 << 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::timeout()
|
|
|
|
{
|
2019-05-09 16:01:35 +00:00
|
|
|
#ifdef QT_BUILD_INTERNAL
|
2018-08-24 04:42:50 +00:00
|
|
|
QFETCH(int, timeout);
|
|
|
|
QFETCH(int, maxRetransmit);
|
|
|
|
|
|
|
|
QCoapClientForTests client;
|
|
|
|
// Trigger a network timeout
|
|
|
|
client.protocol()->setAckTimeout(timeout);
|
|
|
|
client.protocol()->setAckRandomFactor(1);
|
|
|
|
client.protocol()->setMaxRetransmit(maxRetransmit);
|
2018-12-14 12:33:25 +00:00
|
|
|
QUrl url = QUrl("coap://192.0.2.0:5683/"); // Need an url that returns nothing
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
QElapsedTimer timeoutTimer;
|
|
|
|
timeoutTimer.start();
|
2019-04-26 14:40:18 +00:00
|
|
|
QScopedPointer<QCoapReply> reply(
|
|
|
|
client.get(QCoapRequest(url, QCoapMessage::MessageType::Confirmable)));
|
2018-08-24 04:42:50 +00:00
|
|
|
QSignalSpy spyClientError(&client, &QCoapClient::error);
|
|
|
|
QSignalSpy spyReplyError(reply.data(), &QCoapReply::error);
|
|
|
|
QSignalSpy spyReplyAborted(reply.data(), &QCoapReply::aborted);
|
|
|
|
QSignalSpy spyReplyFinished(reply.data(), &QCoapReply::finished);
|
|
|
|
|
|
|
|
// Check timeout upper limit
|
|
|
|
int transmissions = maxRetransmit + 1;
|
|
|
|
|
|
|
|
// 10% Precision expected at least, plus timer precision
|
|
|
|
QTRY_COMPARE_WITH_TIMEOUT(spyReplyError.count(), 1, static_cast<int>(
|
|
|
|
1.1 * client.protocol()->maxTransmitWait() + 20 * transmissions));
|
|
|
|
|
|
|
|
// Check timeout lower limit
|
|
|
|
qint64 elapsedTime = timeoutTimer.elapsed();
|
|
|
|
QString errorMessage = QString("Timeout was triggered after %1ms, while expecting about %2ms")
|
|
|
|
.arg(QString::number(elapsedTime),
|
|
|
|
QString::number(client.protocol()->maxTransmitWait()));
|
|
|
|
|
|
|
|
// 10% Precision expected at least, minus timer precision
|
|
|
|
QVERIFY2(elapsedTime > 0.9 * client.protocol()->maxTransmitWait() - 20 * transmissions,
|
|
|
|
qPrintable(errorMessage));
|
|
|
|
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(qvariant_cast<QtCoap::Error>(spyReplyError.first().at(1)),
|
2019-04-26 15:12:17 +00:00
|
|
|
QtCoap::Error::TimeOut);
|
2018-08-24 04:42:50 +00:00
|
|
|
QCOMPARE(spyReplyFinished.count(), 1);
|
|
|
|
QCOMPARE(spyReplyAborted.count(), 0);
|
|
|
|
QCOMPARE(spyClientError.count(), 1);
|
2019-05-09 16:01:35 +00:00
|
|
|
#else
|
|
|
|
QSKIP("Not an internal build, skipping this test");
|
|
|
|
#endif
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::abort()
|
|
|
|
{
|
|
|
|
QCoapClient client;
|
|
|
|
QUrl url = QUrl(testServerUrl() + "/large");
|
|
|
|
|
|
|
|
QScopedPointer<QCoapReply> reply(client.get(url));
|
|
|
|
QSignalSpy spyReplyFinished(reply.data(), &QCoapReply::finished);
|
|
|
|
QSignalSpy spyReplyAborted(reply.data(), &QCoapReply::aborted);
|
|
|
|
QSignalSpy spyReplyError(reply.data(), &QCoapReply::error);
|
|
|
|
|
|
|
|
reply->abortRequest();
|
|
|
|
|
|
|
|
QEventLoop eventLoop;
|
|
|
|
QTimer::singleShot(1000, &eventLoop, &QEventLoop::quit);
|
|
|
|
eventLoop.exec();
|
|
|
|
|
|
|
|
QCOMPARE(spyReplyAborted.count(), 1);
|
|
|
|
QCOMPARE(spyReplyFinished.count(), 1);
|
|
|
|
QCOMPARE(spyReplyError.count(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::blockwiseReply_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<QUrl>("url");
|
|
|
|
QTest::addColumn<QCoapMessage::MessageType>("type");
|
|
|
|
QTest::addColumn<QByteArray>("replyData");
|
|
|
|
|
|
|
|
QByteArray data;
|
|
|
|
data.append("/-------------------------------------------------------------\\\n");
|
|
|
|
data.append("| RESOURCE BLOCK NO. 1 OF 5 |\n");
|
|
|
|
data.append("| [each line contains 64 bytes] |\n");
|
|
|
|
data.append("\\-------------------------------------------------------------/\n");
|
|
|
|
data.append("/-------------------------------------------------------------\\\n");
|
|
|
|
data.append("| RESOURCE BLOCK NO. 2 OF 5 |\n");
|
|
|
|
data.append("| [each line contains 64 bytes] |\n");
|
|
|
|
data.append("\\-------------------------------------------------------------/\n");
|
|
|
|
data.append("/-------------------------------------------------------------\\\n");
|
|
|
|
data.append("| RESOURCE BLOCK NO. 3 OF 5 |\n");
|
|
|
|
data.append("| [each line contains 64 bytes] |\n");
|
|
|
|
data.append("\\-------------------------------------------------------------/\n");
|
|
|
|
data.append("/-------------------------------------------------------------\\\n");
|
|
|
|
data.append("| RESOURCE BLOCK NO. 4 OF 5 |\n");
|
|
|
|
data.append("| [each line contains 64 bytes] |\n");
|
|
|
|
data.append("\\-------------------------------------------------------------/\n");
|
|
|
|
data.append("/-------------------------------------------------------------\\\n");
|
|
|
|
data.append("| RESOURCE BLOCK NO. 5 OF 5 |\n");
|
|
|
|
data.append("| [each line contains 64 bytes] |\n");
|
|
|
|
data.append("\\-------------------------------------------------------------/\n");
|
|
|
|
|
|
|
|
QTest::newRow("get_large")
|
|
|
|
<< QUrl(testServerUrl() + "/large")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable
|
2018-08-24 04:42:50 +00:00
|
|
|
<< data;
|
|
|
|
QTest::newRow("get_large_separate")
|
|
|
|
<< QUrl(testServerUrl() + "/large-separate")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable
|
2018-08-24 04:42:50 +00:00
|
|
|
<< data;
|
|
|
|
QTest::newRow("get_large_confirmable")
|
|
|
|
<< QUrl(testServerUrl() + "/large")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::Confirmable
|
2018-08-24 04:42:50 +00:00
|
|
|
<< data;
|
|
|
|
QTest::newRow("get_large_separate_confirmable")
|
|
|
|
<< QUrl(testServerUrl() + "/large-separate")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::Confirmable
|
2018-08-24 04:42:50 +00:00
|
|
|
<< data;
|
|
|
|
QTest::newRow("get_large_16bits")
|
|
|
|
<< QUrl(testServerUrl() + "/large")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable
|
2018-08-24 04:42:50 +00:00
|
|
|
<< data;
|
|
|
|
QTest::newRow("get_large_16bits_confirmable")
|
|
|
|
<< QUrl(testServerUrl() + "/large")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::Confirmable
|
2018-08-24 04:42:50 +00:00
|
|
|
<< data;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::blockwiseReply()
|
|
|
|
{
|
|
|
|
QFETCH(QUrl, url);
|
|
|
|
QFETCH(QCoapMessage::MessageType, type);
|
|
|
|
QFETCH(QByteArray, replyData);
|
|
|
|
|
|
|
|
QCoapClient client;
|
|
|
|
QCoapRequest request(url);
|
|
|
|
|
|
|
|
if (qstrncmp(QTest::currentDataTag(), "get_large_16bits", 16) == 0)
|
|
|
|
client.setBlockSize(16);
|
|
|
|
|
|
|
|
request.setType(type);
|
|
|
|
QScopedPointer<QCoapReply> reply(client.get(request));
|
|
|
|
QSignalSpy spyReplyFinished(reply.data(), &QCoapReply::finished);
|
|
|
|
QSignalSpy spyReplyError(reply.data(), &QCoapReply::error);
|
|
|
|
Helper helper;
|
|
|
|
connect(reply.data(), &QCoapReply::error, &helper, &Helper::onError);
|
|
|
|
|
|
|
|
QCOMPARE(spyReplyError.count(), 0);
|
|
|
|
QTRY_COMPARE_WITH_TIMEOUT(spyReplyFinished.count(), 1, 30000);
|
|
|
|
QCOMPARE(reply->readAll(), replyData);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::blockwiseRequest_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<QUrl>("url");
|
|
|
|
QTest::addColumn<QCoapMessage::MessageType>("type");
|
|
|
|
QTest::addColumn<QByteArray>("requestData");
|
|
|
|
QTest::addColumn<QtCoap::ResponseCode>("responseCode");
|
|
|
|
QTest::addColumn<QByteArray>("replyData");
|
|
|
|
|
|
|
|
QByteArray data;
|
|
|
|
const char alphabet[] = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
|
|
|
|
for (int i = 3; i-- > 0; )
|
|
|
|
data.append(alphabet);
|
|
|
|
|
|
|
|
QTest::newRow("large_post_empty_reply") << QUrl(testServerUrl() + "/query")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable
|
2018-08-24 04:42:50 +00:00
|
|
|
<< data
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QtCoap::ResponseCode::MethodNotAllowed
|
2018-08-24 04:42:50 +00:00
|
|
|
<< QByteArray();
|
|
|
|
QTest::newRow("large_post_large_reply") << QUrl(testServerUrl() + "/large-post")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable
|
2018-08-24 04:42:50 +00:00
|
|
|
<< data
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QtCoap::ResponseCode::Changed
|
2018-08-24 04:42:50 +00:00
|
|
|
<< data.toUpper();
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::blockwiseRequest()
|
|
|
|
{
|
|
|
|
QFETCH(QUrl, url);
|
|
|
|
QFETCH(QCoapMessage::MessageType, type);
|
|
|
|
QFETCH(QByteArray, requestData);
|
|
|
|
QFETCH(QtCoap::ResponseCode, responseCode);
|
|
|
|
QFETCH(QByteArray, replyData);
|
|
|
|
|
|
|
|
QCoapClient client;
|
|
|
|
client.setBlockSize(16);
|
|
|
|
|
|
|
|
QCoapRequest request(url);
|
|
|
|
request.setType(type);
|
|
|
|
request.addOption(QCoapOption::ContentFormat);
|
|
|
|
|
|
|
|
QScopedPointer<QCoapReply> reply(client.post(request, requestData));
|
|
|
|
QSignalSpy spyReplyFinished(reply.data(), SIGNAL(finished(QCoapReply *)));
|
|
|
|
|
|
|
|
QTRY_COMPARE_WITH_TIMEOUT(spyReplyFinished.count(), 1, 30000);
|
|
|
|
|
|
|
|
QByteArray dataReply = reply->readAll();
|
|
|
|
QCOMPARE(dataReply, replyData);
|
|
|
|
QCOMPARE(reply->responseCode(), responseCode);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::discover_data()
|
|
|
|
{
|
|
|
|
QTest::addColumn<QUrl>("url");
|
|
|
|
QTest::addColumn<int>("resourceNumber");
|
|
|
|
|
|
|
|
// Californium test server exposes 29 resources
|
|
|
|
QTest::newRow("discover") << QUrl(testServerUrl())
|
|
|
|
<< 29;
|
2019-02-05 14:14:26 +00:00
|
|
|
QTest::newRow("discover_no_scheme_no_port") << QUrl(testServerHost())
|
|
|
|
<< 29;
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::discover()
|
|
|
|
{
|
|
|
|
QFETCH(QUrl, url);
|
|
|
|
QFETCH(int, resourceNumber);
|
|
|
|
|
|
|
|
QCoapClient client;
|
|
|
|
|
|
|
|
QScopedPointer<QCoapDiscoveryReply> resourcesReply(client.discover(url)); // /.well-known/core
|
|
|
|
QSignalSpy spyReplyFinished(resourcesReply.data(), SIGNAL(finished(QCoapReply *)));
|
|
|
|
|
|
|
|
QTRY_COMPARE_WITH_TIMEOUT(spyReplyFinished.count(), 1, 30000);
|
|
|
|
|
2019-02-05 14:14:26 +00:00
|
|
|
const auto discoverUrl = QUrl(url.toString() + "/.well-known/core");
|
|
|
|
QCOMPARE(resourcesReply->url(), QCoapRequest::adjustedUrl(discoverUrl, false));
|
2018-08-24 04:42:50 +00:00
|
|
|
QCOMPARE(resourcesReply->resources().length(), resourceNumber);
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(resourcesReply->request().method(), QtCoap::Method::Get);
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
//! TODO Test discovery content too
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::observe_data()
|
|
|
|
{
|
|
|
|
QWARN("Observe tests may take some time, don't forget to raise Tests timeout in settings.");
|
|
|
|
QTest::addColumn<QUrl>("url");
|
|
|
|
QTest::addColumn<QCoapMessage::MessageType>("type");
|
|
|
|
|
|
|
|
QTest::newRow("observe")
|
|
|
|
<< QUrl(testServerUrl() + "/obs")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable;
|
2018-08-24 04:42:50 +00:00
|
|
|
|
2019-02-05 14:14:26 +00:00
|
|
|
QTest::newRow("observe_no_scheme_no_port")
|
|
|
|
<< QUrl(testServerHost() + "/obs")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable;
|
2019-02-05 14:14:26 +00:00
|
|
|
|
2018-08-24 04:42:50 +00:00
|
|
|
QTest::newRow("observe_confirmable")
|
|
|
|
<< QUrl(testServerUrl() + "/obs")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::Confirmable;
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
QTest::newRow("observe_receive")
|
|
|
|
<< QUrl(testServerUrl() + "/obs-non")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable;
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
QTest::newRow("observe_receive_confirmable")
|
|
|
|
<< QUrl(testServerUrl() + "/obs-non")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::Confirmable;
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
QTest::newRow("observe_large")
|
|
|
|
<< QUrl(testServerUrl() + "/obs-large")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable;
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
QTest::newRow("observe_large_confirmable")
|
|
|
|
<< QUrl(testServerUrl() + "/obs-large")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::Confirmable;
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
QTest::newRow("observe_pumping")
|
|
|
|
<< QUrl(testServerUrl() + "/obs-pumping")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::NonConfirmable;
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
QTest::newRow("observe_pumping_confirmable")
|
|
|
|
<< QUrl(testServerUrl() + "/obs-pumping")
|
2019-04-26 14:40:18 +00:00
|
|
|
<< QCoapMessage::MessageType::Confirmable;
|
2018-08-24 04:42:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::observe()
|
|
|
|
{
|
|
|
|
QFETCH(QUrl, url);
|
|
|
|
QFETCH(QCoapMessage::MessageType, type);
|
|
|
|
|
|
|
|
QCoapClient client;
|
|
|
|
QCoapRequest request(url);
|
|
|
|
|
|
|
|
request.setType(type);
|
|
|
|
QSharedPointer<QCoapReply> reply(client.observe(request),
|
|
|
|
&QObject::deleteLater);
|
|
|
|
QSignalSpy spyReplyNotified(reply.data(), &QCoapReply::notified);
|
|
|
|
QSignalSpy spyReplyFinished(reply.data(), &QCoapReply::finished);
|
|
|
|
|
|
|
|
QTRY_COMPARE_WITH_TIMEOUT(spyReplyNotified.count(), 3, 30000);
|
|
|
|
client.cancelObserve(reply.data());
|
2019-02-05 14:14:26 +00:00
|
|
|
QCOMPARE(reply->url(), QCoapRequest::adjustedUrl(url, false));
|
2019-04-26 14:40:18 +00:00
|
|
|
QCOMPARE(reply->request().method(), QtCoap::Method::Get);
|
2018-08-24 04:42:50 +00:00
|
|
|
|
|
|
|
QVERIFY2(!spyReplyNotified.wait(7000), "'Notify' signal received after cancelling observe");
|
|
|
|
QCOMPARE(spyReplyFinished.count(), 1);
|
|
|
|
|
|
|
|
for (QList<QVariant> receivedSignals : qAsConst(spyReplyNotified)) {
|
|
|
|
QRegularExpression regexp(QStringLiteral("..:..:.."));
|
|
|
|
QByteArray payload = receivedSignals.at(1).value<QCoapMessage>().payload();
|
|
|
|
QString error = QString("Invalid payload for 'notified' signal: %1").arg(QString(payload));
|
|
|
|
QVERIFY2(regexp.match(payload).hasMatch(), qPrintable(error));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-11 16:35:15 +00:00
|
|
|
void tst_QCoapClient::confirmableMulticast()
|
|
|
|
{
|
|
|
|
QCoapClient client;
|
2019-04-26 14:40:18 +00:00
|
|
|
const auto reply = client.get(QCoapRequest("224.0.1.187",
|
|
|
|
QCoapMessage::MessageType::Confirmable));
|
2019-02-11 16:35:15 +00:00
|
|
|
QVERIFY2(!reply, "Confirmable multicast request didn't fail as expected.");
|
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::multicast()
|
|
|
|
{
|
2019-05-09 16:01:35 +00:00
|
|
|
#ifdef QT_BUILD_INTERNAL
|
2019-02-11 16:35:15 +00:00
|
|
|
QCoapClientForMulticastTests client;
|
|
|
|
QCoapRequest request = QCoapRequest(QUrl("224.0.1.187"));
|
|
|
|
request.setToken("abc");
|
|
|
|
QCoapReply *reply = client.get(request);
|
|
|
|
QVERIFY(reply);
|
|
|
|
|
2019-03-06 16:59:05 +00:00
|
|
|
QHostAddress host0("10.20.30.40");
|
|
|
|
QHostAddress host1("10.20.30.41");
|
|
|
|
|
2019-02-11 16:35:15 +00:00
|
|
|
// Simulate sending unicast responses to the multicast request
|
2019-03-06 16:59:05 +00:00
|
|
|
emit client.connection()->readyRead("SE\xAD/abc\xC0\xFFReply0", host0);
|
|
|
|
emit client.connection()->readyRead("SE\xAD/abc\xC0\xFFReply1", host1);
|
2019-02-11 16:35:15 +00:00
|
|
|
|
|
|
|
QSignalSpy spyMulticastResponse(&client, &QCoapClient::responseToMulticastReceived);
|
|
|
|
QTRY_COMPARE(spyMulticastResponse.count(), 2);
|
|
|
|
|
2019-03-06 16:59:05 +00:00
|
|
|
QCoapMessage message0 = qvariant_cast<QCoapMessage>(spyMulticastResponse.at(0).at(1));
|
|
|
|
QCOMPARE(message0.payload(), "Reply0");
|
|
|
|
QHostAddress sender0 = qvariant_cast<QHostAddress>(spyMulticastResponse.at(0).at(2));
|
|
|
|
QCOMPARE(sender0, host0);
|
2019-02-11 16:35:15 +00:00
|
|
|
|
2019-03-06 16:59:05 +00:00
|
|
|
QCoapMessage message1 = qvariant_cast<QCoapMessage>(spyMulticastResponse.at(1).at(1));
|
|
|
|
QCOMPARE(message1.payload(), "Reply1");
|
|
|
|
QHostAddress sender1 = qvariant_cast<QHostAddress>(spyMulticastResponse.at(1).at(2));
|
|
|
|
QCOMPARE(sender1, host1);
|
2019-05-09 16:01:35 +00:00
|
|
|
#else
|
|
|
|
QSKIP("Not an internal build, skipping this test");
|
|
|
|
#endif
|
2019-02-11 16:35:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void tst_QCoapClient::multicast_blockwise()
|
|
|
|
{
|
2019-05-09 16:01:35 +00:00
|
|
|
#ifdef QT_BUILD_INTERNAL
|
2019-02-11 16:35:15 +00:00
|
|
|
QCoapClientForMulticastTests client;
|
|
|
|
QCoapRequest request = QCoapRequest(QUrl("224.0.1.187"));
|
|
|
|
request.setToken("abc");
|
|
|
|
QCoapReply *reply = client.get(request);
|
|
|
|
QVERIFY(reply);
|
|
|
|
|
2019-03-06 16:59:05 +00:00
|
|
|
QHostAddress host0("10.20.30.40");
|
|
|
|
QHostAddress host1("10.20.30.41");
|
2019-02-11 16:35:15 +00:00
|
|
|
|
|
|
|
// Simulate blockwise transfer responses coming from two different hosts
|
2019-03-06 16:59:05 +00:00
|
|
|
emit client.connection()->readyRead("SE#}abc\xC0\xB1\x1D\xFFReply1", host0);
|
|
|
|
emit client.connection()->readyRead("SE#}abc\xC0\xB1\x1D\xFFReply3", host1);
|
|
|
|
emit client.connection()->readyRead("SE#~abc\xC0\xB1%\xFFReply2", host0);
|
|
|
|
emit client.connection()->readyRead("SE#~abc\xC0\xB1%\xFFReply4", host1);
|
2019-02-11 16:35:15 +00:00
|
|
|
|
|
|
|
QSignalSpy spyMulticastResponse(&client, &QCoapClient::responseToMulticastReceived);
|
|
|
|
QTRY_COMPARE(spyMulticastResponse.count(), 2);
|
|
|
|
|
2019-03-06 16:59:05 +00:00
|
|
|
QCoapMessage message0 = qvariant_cast<QCoapMessage>(spyMulticastResponse.at(0).at(1));
|
|
|
|
QCOMPARE(message0.payload(), "Reply1Reply2");
|
|
|
|
QHostAddress sender0 = qvariant_cast<QHostAddress>(spyMulticastResponse.at(0).at(2));
|
|
|
|
QCOMPARE(sender0, host0);
|
2019-02-11 16:35:15 +00:00
|
|
|
|
2019-03-06 16:59:05 +00:00
|
|
|
QCoapMessage message1 = qvariant_cast<QCoapMessage>(spyMulticastResponse.at(1).at(1));
|
|
|
|
QCOMPARE(message1.payload(), "Reply3Reply4");
|
|
|
|
QHostAddress sender1 = qvariant_cast<QHostAddress>(spyMulticastResponse.at(1).at(2));
|
|
|
|
QCOMPARE(sender1, host1);
|
2019-05-09 16:01:35 +00:00
|
|
|
#else
|
|
|
|
QSKIP("Not an internal build, skipping this test");
|
|
|
|
#endif
|
2019-02-11 16:35:15 +00:00
|
|
|
}
|
|
|
|
|
2018-08-24 04:42:50 +00:00
|
|
|
QTEST_MAIN(tst_QCoapClient)
|
|
|
|
|
|
|
|
#include "tst_qcoapclient.moc"
|