Revision control

Copy as Markdown

// Copyright (C) 2018 Witekio.
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtTest>
#include <QCoreApplication>
#include <QtCoap/qcoaprequest.h>
#include <private/qcoapinternalrequest_p.h>
#include <private/qcoaprequest_p.h>
class tst_QCoapInternalRequest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void requestToFrame_data();
void requestToFrame();
void parseUri_data();
void parseUri();
void urlOptions_data();
void urlOptions();
void invalidUrls_data();
void invalidUrls();
void isMulticast_data();
void isMulticast();
void parseBlockOption_data();
void parseBlockOption();
void createBlockOption_data();
void createBlockOption();
void initEmptyMessage_data();
void initEmptyMessage();
};
void tst_QCoapInternalRequest::requestToFrame_data()
{
QTest::addColumn<QUrl>("url");
QTest::addColumn<QtCoap::Method>("method");
QTest::addColumn<QCoapMessage::Type>("type");
QTest::addColumn<quint16>("messageId");
QTest::addColumn<QByteArray>("token");
QTest::addColumn<QString>("pduHeader");
QTest::addColumn<QString>("pduPayload");
QTest::newRow("request_with_option_and_payload")
<< QtCoap::Method::Get
<< QCoapRequest::Type::NonConfirmable
<< quint16(56400)
<< QByteArray::fromHex("4647f09b")
<< "5401dc504647f09bb474657374ff"
<< "Some payload";
QTest::newRow("request_domain")
<< QtCoap::Method::Get
<< QCoapRequest::Type::NonConfirmable
<< quint16(56400)
<< QByteArray::fromHex("4647f09b")
<< "5401dc504647f09b3a646f6d61696e2e636f6d8474657374ff"
<< "Some payload";
QTest::newRow("request_ipv6")
<< QtCoap::Method::Get
<< QCoapRequest::Type::NonConfirmable
<< quint16(56400)
<< QByteArray::fromHex("4647f09b")
<< "5401dc504647f09bb474657374ff"
<< "Some payload";
QTest::newRow("request_without_payload")
<< QtCoap::Method::Get
<< QCoapRequest::Type::NonConfirmable
<< quint16(56400)
<< QByteArray::fromHex("4647f09b")
<< "5401dc504647f09bb474657374"
<< "";
QTest::newRow("request_without_option")
<< QtCoap::Method::Put
<< QCoapRequest::Type::Confirmable
<< quint16(56400)
<< QByteArray::fromHex("4647f09b")
<< "4403dc504647f09bff"
<< "Some payload";
QTest::newRow("request_only")
<< QtCoap::Method::Get
<< QCoapRequest::Type::NonConfirmable
<< quint16(56400)
<< QByteArray::fromHex("4647f09b")
<< "5401dc504647f09b"
<< "";
QTest::newRow("request_with_multiple_options")
<< QtCoap::Method::Get
<< QCoapRequest::Type::NonConfirmable
<< quint16(56400)
<< QByteArray::fromHex("4647f09b")
<< "5401dc504647f09bb474657374036f7569"
<< "";
QTest::newRow("request_with_big_option_number")
<< QtCoap::Method::Get
<< QCoapRequest::Type::NonConfirmable
<< quint16(56400)
<< QByteArray::fromHex("4647f09b")
<< "5401dc504647f09bb474657374dd240d6162636465666768696a6b6c6d6e6f70"
"7172737475767778797aff"
<< "Some payload";
}
void tst_QCoapInternalRequest::requestToFrame()
{
QFETCH(QUrl, url);
QFETCH(QtCoap::Method, method);
QFETCH(QCoapMessage::Type, type);
QFETCH(quint16, messageId);
QFETCH(QByteArray, token);
QFETCH(QString, pduHeader);
QFETCH(QString, pduPayload);
QCoapRequest request = QCoapRequestPrivate::createRequest(QCoapRequest(url), method);
request.setType(type);
request.setPayload(pduPayload.toUtf8());
request.setMessageId(messageId);
request.setToken(token);
if (qstrcmp(QTest::currentDataTag(), "request_with_big_option_number") == 0)
request.addOption(QCoapOption::Size1, QByteArray("abcdefghijklmnopqrstuvwxyz"));
QByteArray pdu;
pdu.append(pduHeader.toUtf8());
if (!pduPayload.isEmpty())
pdu.append(pduPayload.toUtf8().toHex());
QCoapInternalRequest internalRequest(request);
QCOMPARE(internalRequest.toQByteArray().toHex(), pdu);
}
void tst_QCoapInternalRequest::parseUri_data()
{
qRegisterMetaType<QList<QCoapOption>>();
QTest::addColumn<QUrl>("uri");
QTest::addColumn<QUrl>("proxyUri");
QTest::addColumn<QList<QCoapOption>>("options");
QTest::newRow("port_path")
<< QUrl()
<< QList<QCoapOption>({
QCoapOption(QCoapOption::UriPort, 1234),
QCoapOption(QCoapOption::UriPath, QByteArray("test")),
QCoapOption(QCoapOption::UriPath, QByteArray("path1")) });
QTest::newRow("path_query")
<< QUrl()
<< QList<QCoapOption>({
QCoapOption(QCoapOption::UriPath, QByteArray("test")),
QCoapOption(QCoapOption::UriPath, QByteArray("path1")),
QCoapOption(QCoapOption::UriQuery, QByteArray("rd=25")),
QCoapOption(QCoapOption::UriQuery, QByteArray("nd=4")) });
QTest::newRow("host_path_query")
<< QUrl()
<< QList<QCoapOption>({
QCoapOption(QCoapOption::UriHost, QByteArray("aa.bb.cc.com")),
QCoapOption(QCoapOption::UriPath, QByteArray("test")),
QCoapOption(QCoapOption::UriPath, QByteArray("path1")),
QCoapOption(QCoapOption::UriQuery, QByteArray("rd=25")),
QCoapOption(QCoapOption::UriQuery, QByteArray("nd=4")) });
QTest::newRow("proxy_url")
<< QList<QCoapOption>({
QCoapOption(QCoapOption::ProxyUri,
}
void tst_QCoapInternalRequest::parseUri()
{
QFETCH(QUrl, uri);
QFETCH(QUrl, proxyUri);
QFETCH(QList<QCoapOption>, options);
QCoapRequest request(uri, QCoapMessage::Type::NonConfirmable, proxyUri);
QCoapInternalRequest internalRequest(request);
for (QCoapOption opt : options)
QVERIFY2(internalRequest.message()->options().contains(opt), "Missing option");
QCOMPARE(options.size(), internalRequest.message()->optionCount());
}
void tst_QCoapInternalRequest::urlOptions_data()
{
QTest::addColumn<QString>("url");
QTest::addColumn<QList<QCoapOption>>("options");
QList<QCoapOption> options = {
{ QCoapOption::UriHost, QByteArray("example.com") },
{ QCoapOption::UriPath, QByteArray("~sensors") },
{ QCoapOption::UriPath, QByteArray("temp.xml") }
};
QTest::newRow("url_with_default_port")
<< options;
QTest::newRow("url_percent_encoding_uppercase")
<< options;
QTest::newRow("url_with_no_port_uppercase")
<< options;
QTest::newRow("url_with_dot_segments")
<< options;
//! TODO Add more test URLs
}
void tst_QCoapInternalRequest::urlOptions()
{
QFETCH(QString, url);
QFETCH(QList<QCoapOption>, options);
const QCoapRequest request(QUrl{url});
const QCoapInternalRequest internalRequest(request);
auto requestOptions = internalRequest.message()->options();
for (const auto& option : options)
QVERIFY2(requestOptions.removeAll(option) > 0, "Missing option");
QVERIFY2(requestOptions.isEmpty(), "Fewer options were expected");
}
void tst_QCoapInternalRequest::invalidUrls_data()
{
QTest::addColumn<QString>("url");
QTest::newRow("url_with_non_ascii")
<< QString("coap://example.com:5683/~sensors/%1temp.xml").arg(QChar(0x00A3));
QTest::newRow("url_no_scheme")
<< "example.com:5683/~sensors/temp.xml";
QTest::newRow("url_wrong_scheme")
//! TODO Add more test URLs
}
void tst_QCoapInternalRequest::invalidUrls()
{
QFETCH(QString, url);
const QCoapRequest request(QUrl{url});
const QCoapInternalRequest internalRequest(request);
QVERIFY(!internalRequest.isValid());
QVERIFY(internalRequest.message()->options().empty());
}
void tst_QCoapInternalRequest::isMulticast_data()
{
QTest::addColumn<QString>("url");
QTest::addColumn<bool>("result");
QTest::newRow("ipv4_multicast") << QString("coap://224.0.1.187") << true;
QTest::newRow("ipv4_multicast_resource") << QString("coap://224.0.1.187/path") << true;
QTest::newRow("ipv6_multicast_link_local") << "coap://[ff02::fd]" << true;
QTest::newRow("ipv6_multicast_site_local") << "coap://[ff05::fd]" << true;
QTest::newRow("not_multicast") << QString("coap://127.0.0.1") << false;
}
void tst_QCoapInternalRequest::isMulticast()
{
QFETCH(QString, url);
QFETCH(bool, result);
const QCoapRequest request(QUrl{url});
const QCoapInternalRequest internalRequest(request);
QCOMPARE(internalRequest.isMulticast(), result);
}
void tst_QCoapInternalRequest::parseBlockOption_data()
{
QTest::addColumn<QByteArray>("value");
QTest::addColumn<uint>("blockNumber");
QTest::addColumn<bool>("hasNext");
QTest::addColumn<uint>("blockSize");
QTest::newRow("block_option_1byte_more_blocks") << QByteArray::fromHex("3B")
<< 3u
<< true
<< 128u;
QTest::newRow("block_option_1byte_no_more_blocks") << QByteArray::fromHex("93")
<< 9u
<< false
<< 128u;
QTest::newRow("block_option_2bytes_more_blocks") << QByteArray::fromHex("12A")
<< 18u
<< true
<< 64u;
QTest::newRow("block_option_2bytes_no_more_blocks") << QByteArray::fromHex("132")
<< 19u
<< false
<< 64u;
QTest::newRow("block_option_3bytes_more_blocks") << QByteArray::fromHex("3AB2A")
<< 15026u
<< true
<< 64u;
QTest::newRow("block_option_3bytes_no_more_blocks") << QByteArray::fromHex("3AB22")
<< 15026u
<< false
<< 64u;
}
void tst_QCoapInternalRequest::parseBlockOption()
{
QFETCH(QByteArray, value);
QFETCH(uint, blockNumber);
QFETCH(bool, hasNext);
QFETCH(uint, blockSize);
QCoapInternalRequest request;
request.addOption(QCoapOption::Block1, value);
QCOMPARE(request.currentBlockNumber(), blockNumber);
QCOMPARE(request.hasMoreBlocksToReceive(), hasNext);
QCOMPARE(request.blockSize(), blockSize);
}
void tst_QCoapInternalRequest::createBlockOption_data()
{
QTest::addColumn<QByteArray>("payload");
QTest::addColumn<uint>("blockNumber");
QTest::addColumn<uint>("blockSize");
QTest::addColumn<QCoapOption>("expectedOption");
QByteArray data;
for (uint i = 0; i < 1024; ++i)
data.append(0xF);
QByteArray largeData;
for (uint i = 0; i < 32; ++i)
largeData.append(data);
QTest::newRow("block1_option_1byte_more_blocks")
<< data
<< 3u
<< 64u
<< QCoapOption(QCoapOption::Block1, QByteArray::fromHex("3A"));
QTest::newRow("block1_option_1byte_no_more_blocks")
<< data
<< 8u
<< 128u
<< QCoapOption(QCoapOption::Block1, QByteArray::fromHex("83"));
QTest::newRow("block2_option_1byte")
<< data
<< 3u
<< 64u
<< QCoapOption(QCoapOption::Block2, QByteArray::fromHex("32"));
QTest::newRow("block1_option_2bytes_more_blocks")
<< data
<< 29u
<< 32u
<< QCoapOption(QCoapOption::Block1, QByteArray::fromHex("1D9"));
QTest::newRow("block1_option_2bytes_no_more_blocks")
<< data
<< 32u
<< 32u
<< QCoapOption(QCoapOption::Block1, QByteArray::fromHex("201"));
QTest::newRow("block2_option_2bytes")
<< data
<< 29u
<< 32u
<< QCoapOption(QCoapOption::Block2, QByteArray::fromHex("1D1"));
QTest::newRow("block1_option_3bytes_more_blocks")
<< largeData
<< 4096u
<< 4u
<< QCoapOption(QCoapOption::Block1, QByteArray::fromHex("10008"));
QTest::newRow("block1_option_3bytes_no_more_blocks")
<< largeData
<< 8192u
<< 4u
<< QCoapOption(QCoapOption::Block1, QByteArray::fromHex("20000"));
QTest::newRow("block2_option_3bytes")
<< largeData
<< 4096u
<< 4u
<< QCoapOption(QCoapOption::Block2, QByteArray::fromHex("10000"));
}
void tst_QCoapInternalRequest::createBlockOption()
{
QFETCH(QByteArray, payload);
QFETCH(uint, blockNumber);
QFETCH(uint, blockSize);
QFETCH(QCoapOption, expectedOption);
QCoapRequest request;
request.setPayload(payload);
QCoapInternalRequest internalRequest(request);
if (expectedOption.name() == QCoapOption::Block1)
internalRequest.setToSendBlock(blockNumber, blockSize);
else if (expectedOption.name() == QCoapOption::Block2)
internalRequest.setToRequestBlock(blockNumber, blockSize);
else
QFAIL("Incorrect option, the test expects Block1 or Block2 options.");
QCOMPARE(internalRequest.message()->options().size(), 1);
const auto option = internalRequest.message()->options().back();
QCOMPARE(option.name(), expectedOption.name());
QCOMPARE(option.opaqueValue(), expectedOption.opaqueValue());
}
void tst_QCoapInternalRequest::initEmptyMessage_data()
{
QTest::addColumn<QCoapMessage::Type>("type");
QTest::addColumn<QByteArray>("messageHeader");
QTest::newRow("acknowledge") << QCoapMessage::Type::Acknowledgment << QByteArray("6000002a");
QTest::newRow("reset") << QCoapMessage::Type::Reset << QByteArray("7000002a");
}
void tst_QCoapInternalRequest::initEmptyMessage()
{
QFETCH(QCoapMessage::Type, type);
QFETCH(QByteArray, messageHeader);
// Populate the request with random data
QCoapRequest request = QCoapRequestPrivate::createRequest(QCoapRequest("coap://test"),
QtCoap::Method::Get);
request.setVersion(1);
request.setType(QCoapMessage::Type::Confirmable);
request.setMessageId(111);
request.setToken("token");
request.addOption(QCoapOption::ProxyUri);
request.setPayload("payload");
QCoapInternalRequest emptyMessageRequest(request);
emptyMessageRequest.initEmptyMessage(42, type);
QCOMPARE(emptyMessageRequest.toQByteArray().toHex(), messageHeader);
}
QTEST_APPLESS_MAIN(tst_QCoapInternalRequest)
#include "tst_qcoapinternalrequest.moc"