File indexing completed on 2024-04-28 04:44:20

0001 /*
0002    SPDX-FileCopyrightText: 2015 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
0003 
0004    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include "upnpssdpengine.h"
0008 
0009 #include "upnpdiscoveryresult.h"
0010 
0011 #include <QtCore/QDebug>
0012 #include <QtCore/QScopedPointer>
0013 #include <QtCore/QStringList>
0014 
0015 #include <QtNetwork/QUdpSocket>
0016 
0017 #include <QtTest/QtTest>
0018 #include <utility>
0019 
0020 
0021 #include <sys/socket.h>
0022 #include <sys/types.h>
0023 
0024 class MockSsdpClient : public QObject
0025 {
0026 
0027     Q_OBJECT
0028 
0029 public:
0030     explicit MockSsdpClient(quint16 aPortNumber, QByteArray aExpectedQuery, QStringList aAnswerData,
0031         bool aAutoRefresh, int aRefreshPeriod = 1000,
0032         QStringList aAnnounceData = {},
0033         QObject *parent = nullptr)
0034         : QObject(parent)
0035         , mPortNumber(aPortNumber)
0036         , mClientSocket()
0037         , mAnswerData(std::move(aAnswerData))
0038         , mExpectedQuery(std::move(aExpectedQuery))
0039         , mHttpClientSocket()
0040         , mAutoRefresh(aAutoRefresh)
0041         , mRefreshPeriod(aRefreshPeriod)
0042         , mAnnounceData(std::move(aAnnounceData))
0043         , mAutoRefreshTimer()
0044         , mSender()
0045         , mSenderPort(12345)
0046     {
0047         connect(&mAutoRefreshTimer, &QTimer::timeout, this, &MockSsdpClient::refreshAnnounce);
0048 
0049         if (mAutoRefresh) {
0050             mAutoRefreshTimer.setSingleShot(false);
0051             mAutoRefreshTimer.start(mRefreshPeriod * 1000);
0052         }
0053     }
0054 
0055     void listen()
0056     {
0057         connect(&mClientSocket, &QUdpSocket::readyRead, this, &MockSsdpClient::dataReceived);
0058 
0059         mClientSocket.bind(QHostAddress::AnyIPv4, mPortNumber, QAbstractSocket::ShareAddress | QAbstractSocket::ReuseAddressHint);
0060         mClientSocket.joinMulticastGroup(QHostAddress(QStringLiteral("239.255.255.250")));
0061         mClientSocket.setSocketOption(QAbstractSocket::MulticastLoopbackOption, 1);
0062         mClientSocket.setSocketOption(QAbstractSocket::MulticastTtlOption, 4);
0063 
0064         connect(&mHttpClientSocket, &QUdpSocket::readyRead, this, &MockSsdpClient::httpDataReceived);
0065 
0066         mHttpClientSocket.bind(QHostAddress::AnyIPv4, 8200);
0067 
0068         auto result = mAnnounceSocket.bind(QHostAddress(QStringLiteral("239.255.255.250")), 1900, QAbstractSocket::ShareAddress);
0069         //qDebug() << "bind" << QHostAddress::AnyIPv4 << (result ? "true" : "false");
0070         result = mAnnounceSocket.joinMulticastGroup(QHostAddress(QStringLiteral("239.255.255.250")));
0071         qDebug() << "joinMulticastGroup" << (result ? "true" : "false") << mAnnounceSocket.errorString();
0072 
0073         mAnnounceSocket.setSocketOption(QAbstractSocket::MulticastLoopbackOption, { 1 });
0074         mAnnounceSocket.setSocketOption(QAbstractSocket::MulticastTtlOption, { 4 });
0075     }
0076 
0077 public Q_SLOTS:
0078 
0079     void dataReceived()
0080     {
0081         while (mClientSocket.hasPendingDatagrams()) {
0082             QByteArray datagram;
0083             datagram.resize(mClientSocket.pendingDatagramSize());
0084 
0085             mClientSocket.readDatagram(datagram.data(), datagram.size(),
0086                 &mSender, &mSenderPort);
0087 
0088             QVERIFY(mExpectedQuery.isEmpty() || datagram == mExpectedQuery);
0089 
0090             QTest::qSleep(1700);
0091 
0092             for (auto &answer : mAnswerData) {
0093                 mClientSocket.writeDatagram(answer.toLatin1(), mSender, mSenderPort);
0094             }
0095         }
0096         mClientSocket.close();
0097     }
0098 
0099     void httpDataReceived()
0100     {
0101         while (mClientSocket.hasPendingDatagrams()) {
0102             QByteArray datagram;
0103             datagram.resize(mClientSocket.pendingDatagramSize());
0104             QHostAddress sender;
0105             quint16 senderPort;
0106 
0107             mClientSocket.readDatagram(datagram.data(), datagram.size(),
0108                 &sender, &senderPort);
0109 
0110             qDebug() << "httpDataReceived" << datagram;
0111         }
0112     }
0113 
0114     void refreshAnnounce()
0115     {
0116         qDebug() << "refreshAnnounce";
0117         for (auto &announcement : mAnnounceData) {
0118             mAnnounceSocket.writeDatagram(announcement.toLatin1(), QHostAddress(QStringLiteral("239.255.255.250")), mPortNumber);
0119         }
0120     }
0121 
0122 private:
0123     quint16 mPortNumber;
0124 
0125     QUdpSocket mClientSocket;
0126 
0127     QUdpSocket mAnnounceSocket;
0128 
0129     QStringList mAnswerData;
0130 
0131     QByteArray mExpectedQuery;
0132 
0133     QUdpSocket mHttpClientSocket;
0134 
0135     bool mAutoRefresh;
0136 
0137     int mRefreshPeriod;
0138 
0139     QStringList mAnnounceData;
0140 
0141     QTimer mAutoRefreshTimer;
0142 
0143     QHostAddress mSender;
0144 
0145     quint16 mSenderPort;
0146 };
0147 
0148 class SsdpTests : public QObject
0149 {
0150     Q_OBJECT
0151 
0152 public:
0153     SsdpTests(QObject *parent = nullptr)
0154         : QObject(parent)
0155     {
0156     }
0157 
0158 private Q_SLOTS:
0159 
0160     void initTestCase()
0161     {
0162         qRegisterMetaType<UpnpSearchQuery>("UpnpSearchQuery");
0163     }
0164 
0165     void searchAll_data()
0166     {
0167         QTest::addColumn<UpnpSsdpEngine::SEARCH_TYPE>("searchType");
0168         QTest::addColumn<QString>("searchCriteria");
0169         QTest::addColumn<QByteArray>("ssdpRequest");
0170         QTest::addColumn<QStringList>("ssdpAnswers");
0171         QTest::addColumn<QList<UpnpDiscoveryResult>>("results");
0172 
0173         QTest::newRow("all devices") << UpnpSsdpEngine::AllDevices
0174                                      << QString()
0175                                      << QByteArray("M-SEARCH * HTTP/1.1\r\n"
0176                                                    "HOST: 239.255.255.250:11900\r\n"
0177                                                    "MAN: \"ssdp:discover\"\r\n"
0178                                                    "MX: 2\r\n"
0179                                                    "ST: ssdp:all\r\n\r\n")
0180                                      << QStringList({ QStringLiteral("HTTP/1.1 200 OK\r\n"
0181                                                                      "CACHE-CONTROL: max-age=1800\r\n"
0182                                                                      "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0183                                                                      "ST: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e\r\n"
0184                                                                      "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e\r\n"
0185                                                                      "EXT:\r\n"
0186                                                                      "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0187                                                                      "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0188                                                                      "Content-Length: 0\r\n\r\n"),
0189                                             QStringLiteral("HTTP/1.1 200 OK\r\n"
0190                                                            "CACHE-CONTROL: max-age=1800\r\n"
0191                                                            "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0192                                                            "ST: upnp:rootdevice\r\n"
0193                                                            "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice\r\n"
0194                                                            "EXT:\r\n"
0195                                                            "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0196                                                            "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0197                                                            "Content-Length: 0\r\n\r\n"),
0198                                             QStringLiteral("HTTP/1.1 200 OK\r\n"
0199                                                            "CACHE-CONTROL: max-age=1800\r\n"
0200                                                            "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0201                                                            "ST: urn:schemas-upnp-org:device:MediaServer:1\r\n"
0202                                                            "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:device:MediaServer:1\r\n"
0203                                                            "EXT:\r\n"
0204                                                            "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0205                                                            "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0206                                                            "Content-Length: 0\r\n\r\n"),
0207                                             QStringLiteral("HTTP/1.1 200 OK\r\n"
0208                                                            "CACHE-CONTROL: max-age=1800\r\n"
0209                                                            "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0210                                                            "ST: urn:schemas-upnp-org:service:ContentDirectory:1\r\n"
0211                                                            "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:service:ContentDirectory:1\r\n"
0212                                                            "EXT:\r\n"
0213                                                            "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0214                                                            "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0215                                                            "Content-Length: 0\r\n\r\n"),
0216                                             QStringLiteral("HTTP/1.1 200 OK\r\n"
0217                                                            "CACHE-CONTROL: max-age=1800\r\n"
0218                                                            "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0219                                                            "ST: urn:schemas-upnp-org:service:ConnectionManager:1\r\n"
0220                                                            "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:service:ConnectionManager:1\r\n"
0221                                                            "EXT:\r\n"
0222                                                            "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0223                                                            "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0224                                                            "Content-Length: 0\r\n\r\n") })
0225                                      << QList<UpnpDiscoveryResult>({ UpnpDiscoveryResult(QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e"),
0226                                                                          QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e"),
0227                                                                          QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0228                                                                          UpnpSsdpEngine::NotificationSubType::Invalid,
0229                                                                          QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0230                                                                          1800),
0231                                             UpnpDiscoveryResult(QStringLiteral("upnp:rootdevice"),
0232                                                 QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice"),
0233                                                 QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0234                                                 UpnpSsdpEngine::NotificationSubType::Invalid,
0235                                                 QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0236                                                 1800),
0237                                             UpnpDiscoveryResult(QStringLiteral("urn:schemas-upnp-org:device:MediaServer:1"),
0238                                                 QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:device:MediaServer:1"),
0239                                                 QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0240                                                 UpnpSsdpEngine::NotificationSubType::Invalid,
0241                                                 QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0242                                                 1800),
0243                                             UpnpDiscoveryResult(QStringLiteral("urn:schemas-upnp-org:service:ContentDirectory:1"),
0244                                                 QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:service:ContentDirectory:1"),
0245                                                 QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0246                                                 UpnpSsdpEngine::NotificationSubType::Invalid,
0247                                                 QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0248                                                 1800),
0249                                             UpnpDiscoveryResult(QStringLiteral("urn:schemas-upnp-org:service:ConnectionManager:1"),
0250                                                 QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:service:ConnectionManager:1"),
0251                                                 QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0252                                                 UpnpSsdpEngine::NotificationSubType::Invalid,
0253                                                 QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0254                                                 1800) });
0255 
0256         QTest::newRow("root device") << UpnpSsdpEngine::RootDevices
0257                                      << QString()
0258                                      << QByteArray("M-SEARCH * HTTP/1.1\r\n"
0259                                                    "HOST: 239.255.255.250:11900\r\n"
0260                                                    "MAN: \"ssdp:discover\"\r\n"
0261                                                    "MX: 2\r\n"
0262                                                    "ST: upnp:rootdevice\r\n\r\n")
0263                                      << QStringList({ QStringLiteral("HTTP/1.1 200 OK\r\n"
0264                                                                      "CACHE-CONTROL: max-age=1800\r\n"
0265                                                                      "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0266                                                                      "ST: upnp:rootdevice\r\n"
0267                                                                      "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice\r\n"
0268                                                                      "EXT:\r\n"
0269                                                                      "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0270                                                                      "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0271                                                                      "Content-Length: 0\r\n\r\n") })
0272                                      << QList<UpnpDiscoveryResult>({ UpnpDiscoveryResult(QStringLiteral("upnp:rootdevice"),
0273                                             QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice"),
0274                                             QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0275                                             UpnpSsdpEngine::NotificationSubType::Invalid,
0276                                             QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0277                                             1800) });
0278 
0279         QTest::newRow("device by uuid") << UpnpSsdpEngine::DeviceByUUID
0280                                         << QStringLiteral("4d696e69-444c-164e-9d41-ecf4bb9c317e")
0281                                         << QByteArray("M-SEARCH * HTTP/1.1\r\n"
0282                                                       "HOST: 239.255.255.250:11900\r\n"
0283                                                       "MAN: \"ssdp:discover\"\r\n"
0284                                                       "MX: 2\r\n"
0285                                                       "ST: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e\r\n\r\n")
0286                                         << QStringList({
0287                                                QStringLiteral("HTTP/1.1 200 OK\r\n"
0288                                                               "CACHE-CONTROL: max-age=1800\r\n"
0289                                                               "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0290                                                               "ST: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e\r\n"
0291                                                               "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e\r\n"
0292                                                               "EXT:\r\n"
0293                                                               "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0294                                                               "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0295                                                               "Content-Length: 0\r\n\r\n"),
0296                                            })
0297                                         << QList<UpnpDiscoveryResult>({
0298                                                UpnpDiscoveryResult(QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e"),
0299                                                    QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e"),
0300                                                    QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0301                                                    UpnpSsdpEngine::NotificationSubType::Invalid,
0302                                                    QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0303                                                    1800),
0304                                            });
0305 
0306         QTest::newRow("device by type") << UpnpSsdpEngine::DeviceByType
0307                                         << QStringLiteral("schemas-upnp-org:device:MediaServer:1")
0308                                         << QByteArray("M-SEARCH * HTTP/1.1\r\n"
0309                                                       "HOST: 239.255.255.250:11900\r\n"
0310                                                       "MAN: \"ssdp:discover\"\r\n"
0311                                                       "MX: 2\r\n"
0312                                                       "ST: urn:schemas-upnp-org:device:MediaServer:1\r\n\r\n")
0313                                         << QStringList({
0314                                                QStringLiteral("HTTP/1.1 200 OK\r\n"
0315                                                               "CACHE-CONTROL: max-age=1800\r\n"
0316                                                               "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0317                                                               "ST: urn:schemas-upnp-org:device:MediaServer:1\r\n"
0318                                                               "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:device:MediaServer:1\r\n"
0319                                                               "EXT:\r\n"
0320                                                               "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0321                                                               "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0322                                                               "Content-Length: 0\r\n\r\n"),
0323                                            })
0324                                         << QList<UpnpDiscoveryResult>({
0325                                                UpnpDiscoveryResult(QStringLiteral("urn:schemas-upnp-org:device:MediaServer:1"),
0326                                                    QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:device:MediaServer:1"),
0327                                                    QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0328                                                    UpnpSsdpEngine::NotificationSubType::Invalid,
0329                                                    QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0330                                                    1800),
0331                                            });
0332 
0333         QTest::newRow("service by type") << UpnpSsdpEngine::ServiceByType
0334                                          << QStringLiteral("schemas-upnp-org:service:ConnectionManager:1")
0335                                          << QByteArray("M-SEARCH * HTTP/1.1\r\n"
0336                                                        "HOST: 239.255.255.250:11900\r\n"
0337                                                        "MAN: \"ssdp:discover\"\r\n"
0338                                                        "MX: 2\r\n"
0339                                                        "ST: urn:schemas-upnp-org:service:ConnectionManager:1\r\n\r\n")
0340                                          << QStringList({ QStringLiteral("HTTP/1.1 200 OK\r\n"
0341                                                                          "CACHE-CONTROL: max-age=1800\r\n"
0342                                                                          "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0343                                                                          "ST: urn:schemas-upnp-org:service:ConnectionManager:1\r\n"
0344                                                                          "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:service:ConnectionManager:1\r\n"
0345                                                                          "EXT:\r\n"
0346                                                                          "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0347                                                                          "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0348                                                                          "Content-Length: 0\r\n\r\n") })
0349                                          << QList<UpnpDiscoveryResult>({
0350                                                 UpnpDiscoveryResult(QStringLiteral("urn:schemas-upnp-org:service:ConnectionManager:1"),
0351                                                     QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::urn:schemas-upnp-org:service:ConnectionManager:1"),
0352                                                     QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0353                                                     UpnpSsdpEngine::NotificationSubType::Invalid,
0354                                                     QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0355                                                     1800),
0356                                             });
0357     }
0358 
0359     void searchAll()
0360     {
0361         QFETCH(UpnpSsdpEngine::SEARCH_TYPE, searchType);
0362         QFETCH(QString, searchCriteria);
0363         QFETCH(QByteArray, ssdpRequest);
0364         QFETCH(QStringList, ssdpAnswers);
0365         QFETCH(QList<UpnpDiscoveryResult>, results);
0366 
0367         QScopedPointer<MockSsdpClient> newClient(new MockSsdpClient(11900, ssdpRequest, ssdpAnswers, false));
0368         newClient->listen();
0369 
0370         UpnpSsdpEngine newEngine;
0371         newEngine.setPort(11900);
0372         newEngine.initialize();
0373 
0374         QSignalSpy newServiceSignal(&newEngine, &UpnpSsdpEngine::newService);
0375 
0376         newEngine.searchUpnp(searchType, searchCriteria, 2);
0377 
0378         newServiceSignal.wait(20000);
0379 
0380         QCOMPARE(newServiceSignal.size(), results.size());
0381 
0382         for (int i = 0; i < results.size(); ++i) {
0383             auto firstService = newServiceSignal[i][0].value<UpnpDiscoveryResult>();
0384             QCOMPARE(firstService.announceDate(), results[i].announceDate());
0385             QCOMPARE(firstService.cacheDuration(), results[i].cacheDuration());
0386             QCOMPARE(firstService.location(), results[i].location());
0387             QCOMPARE(firstService.nt(), results[i].nt());
0388             QCOMPARE(firstService.nts(), results[i].nts());
0389             QCOMPARE(firstService.usn(), results[i].usn());
0390         }
0391     }
0392 
0393     void searchDeviceWaitTimeout_data()
0394     {
0395         QTest::addColumn<UpnpSsdpEngine::SEARCH_TYPE>("searchType");
0396         QTest::addColumn<QString>("searchCriteria");
0397         QTest::addColumn<QByteArray>("ssdpRequest");
0398         QTest::addColumn<QStringList>("ssdpAnswers");
0399         QTest::addColumn<QList<UpnpDiscoveryResult>>("results");
0400 
0401         QTest::newRow("root device") << UpnpSsdpEngine::RootDevices
0402                                      << QString()
0403                                      << QByteArray("M-SEARCH * HTTP/1.1\r\n"
0404                                                    "HOST: 239.255.255.250:11900\r\n"
0405                                                    "MAN: \"ssdp:discover\"\r\n"
0406                                                    "MX: 2\r\n"
0407                                                    "ST: upnp:rootdevice\r\n\r\n")
0408                                      << QStringList({ QStringLiteral("HTTP/1.1 200 OK\r\n"
0409                                                                      "CACHE-CONTROL: max-age=3\r\n"
0410                                                                      "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0411                                                                      "ST: upnp:rootdevice\r\n"
0412                                                                      "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice\r\n"
0413                                                                      "EXT:\r\n"
0414                                                                      "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0415                                                                      "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0416                                                                      "Content-Length: 0\r\n\r\n") })
0417                                      << QList<UpnpDiscoveryResult>({ UpnpDiscoveryResult(QStringLiteral("upnp:rootdevice"),
0418                                             QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice"),
0419                                             QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0420                                             UpnpSsdpEngine::NotificationSubType::Invalid,
0421                                             QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0422                                             3) });
0423     }
0424 
0425     void searchDeviceWaitTimeout()
0426     {
0427         QFETCH(UpnpSsdpEngine::SEARCH_TYPE, searchType);
0428         QFETCH(QString, searchCriteria);
0429         QFETCH(QByteArray, ssdpRequest);
0430         QFETCH(QStringList, ssdpAnswers);
0431         QFETCH(QList<UpnpDiscoveryResult>, results);
0432 
0433         QScopedPointer<MockSsdpClient> newClient(new MockSsdpClient(11900, ssdpRequest, ssdpAnswers, false));
0434         newClient->listen();
0435 
0436         QScopedPointer<UpnpSsdpEngine> newEngine(new UpnpSsdpEngine);
0437         newEngine->setPort(11900);
0438         newEngine->initialize();
0439 
0440         QSignalSpy newServiceSignal(newEngine.data(), &UpnpSsdpEngine::newService);
0441         QSignalSpy removedServiceSignal(newEngine.data(), &UpnpSsdpEngine::removedService);
0442 
0443         newEngine->searchUpnp(searchType, searchCriteria, 2);
0444 
0445         newServiceSignal.wait(20000);
0446 
0447         QCOMPARE(newServiceSignal.size(), results.size());
0448 
0449         for (int i = 0; i < results.size(); ++i) {
0450             auto firstService = newServiceSignal[i][0].value<UpnpDiscoveryResult>();
0451             QCOMPARE(firstService.announceDate(), results[i].announceDate());
0452             QCOMPARE(firstService.cacheDuration(), results[i].cacheDuration());
0453             QCOMPARE(firstService.location(), results[i].location());
0454             QCOMPARE(firstService.nt(), results[i].nt());
0455             QCOMPARE(firstService.nts(), results[i].nts());
0456             QCOMPARE(firstService.usn(), results[i].usn());
0457         }
0458 
0459         removedServiceSignal.wait();
0460 
0461         QVERIFY(removedServiceSignal.count() > 0);
0462     }
0463 
0464     void searchDeviceWaitRefreshBeforeTimeout_data()
0465     {
0466         QTest::addColumn<UpnpSsdpEngine::SEARCH_TYPE>("searchType");
0467         QTest::addColumn<QString>("searchCriteria");
0468         QTest::addColumn<QByteArray>("ssdpRequest");
0469         QTest::addColumn<QStringList>("ssdpAnswers");
0470         QTest::addColumn<QList<UpnpDiscoveryResult>>("results");
0471         QTest::addColumn<bool>("needAutoRefresh");
0472         QTest::addColumn<int>("refreshPeriod");
0473         QTest::addColumn<QStringList>("refreshMessages");
0474 
0475         QTest::newRow("root device with refresh") << UpnpSsdpEngine::RootDevices
0476                                                   << QString()
0477                                                   << QByteArray("M-SEARCH * HTTP/1.1\r\n"
0478                                                                 "HOST: 239.255.255.250:11900\r\n"
0479                                                                 "MAN: \"ssdp:discover\"\r\n"
0480                                                                 "MX: 2\r\n"
0481                                                                 "ST: upnp:rootdevice\r\n\r\n")
0482                                                   << QStringList({ QStringLiteral("HTTP/1.1 200 OK\r\n"
0483                                                                                   "CACHE-CONTROL: max-age=4\r\n"
0484                                                                                   "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0485                                                                                   "ST: upnp:rootdevice\r\n"
0486                                                                                   "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice\r\n"
0487                                                                                   "EXT:\r\n"
0488                                                                                   "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0489                                                                                   "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0490                                                                                   "Content-Length: 0\r\n\r\n") })
0491                                                   << QList<UpnpDiscoveryResult>({ UpnpDiscoveryResult(QStringLiteral("upnp:rootdevice"),
0492                                                          QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice"),
0493                                                          QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0494                                                          UpnpSsdpEngine::NotificationSubType::Invalid,
0495                                                          QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0496                                                          4) })
0497                                                   << true
0498                                                   << 3
0499                                                   << QStringList({ QStringLiteral("NOTIFY * HTTP/1.1 200 OK\r\n"
0500                                                                                   "CACHE-CONTROL: max-age=4\r\n"
0501                                                                                   "HOST: 239.255.255.250:1900\r\n"
0502                                                                                   "NT: upnp:rootdevice\r\n"
0503                                                                                   "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice\r\n"
0504                                                                                   "NTS: ssdp:alive\r\n"
0505                                                                                   "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0506                                                                                   "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0507                                                                                   "Content-Length: 0\r\n\r\n") });
0508 
0509         QTest::newRow("root device without refresh") << UpnpSsdpEngine::RootDevices
0510                                                      << QString()
0511                                                      << QByteArray("M-SEARCH * HTTP/1.1\r\n"
0512                                                                    "HOST: 239.255.255.250:11900\r\n"
0513                                                                    "MAN: \"ssdp:discover\"\r\n"
0514                                                                    "MX: 2\r\n"
0515                                                                    "ST: upnp:rootdevice\r\n\r\n")
0516                                                      << QStringList({ QStringLiteral("HTTP/1.1 200 OK\r\n"
0517                                                                                      "CACHE-CONTROL: max-age=4\r\n"
0518                                                                                      "DATE: mar., 27 oct. 2015 21:03:35 G\x7F\r\n"
0519                                                                                      "ST: upnp:rootdevice\r\n"
0520                                                                                      "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice\r\n"
0521                                                                                      "EXT:\r\n"
0522                                                                                      "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0523                                                                                      "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0524                                                                                      "Content-Length: 0\r\n\r\n") })
0525                                                      << QList<UpnpDiscoveryResult>({ UpnpDiscoveryResult(QStringLiteral("upnp:rootdevice"),
0526                                                             QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice"),
0527                                                             QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0528                                                             UpnpSsdpEngine::NotificationSubType::Invalid,
0529                                                             QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0530                                                             4) })
0531                                                      << false
0532                                                      << 3
0533                                                      << QStringList({});
0534     }
0535 
0536     void searchDeviceWaitRefreshBeforeTimeout()
0537     {
0538         QFETCH(UpnpSsdpEngine::SEARCH_TYPE, searchType);
0539         QFETCH(QString, searchCriteria);
0540         QFETCH(QByteArray, ssdpRequest);
0541         QFETCH(QStringList, ssdpAnswers);
0542         QFETCH(QList<UpnpDiscoveryResult>, results);
0543         QFETCH(bool, needAutoRefresh);
0544         QFETCH(int, refreshPeriod);
0545         QFETCH(QStringList, refreshMessages);
0546 
0547         MockSsdpClient newClient(11900, ssdpRequest, ssdpAnswers, needAutoRefresh, refreshPeriod, refreshMessages);
0548         newClient.listen();
0549 
0550         UpnpSsdpEngine newEngine;
0551         newEngine.setPort(11900);
0552         newEngine.initialize();
0553 
0554         QSignalSpy newServiceSignal(&newEngine, &UpnpSsdpEngine::newService);
0555         QSignalSpy removedServiceSignal(&newEngine, &UpnpSsdpEngine::removedService);
0556 
0557         newEngine.searchUpnp(searchType, searchCriteria, 2);
0558 
0559         newServiceSignal.wait(20000);
0560 
0561         QCOMPARE(newServiceSignal.size(), results.size());
0562 
0563         for (int i = 0; i < results.size(); ++i) {
0564             auto firstService = newServiceSignal[i][0].value<UpnpDiscoveryResult>();
0565             QCOMPARE(firstService.announceDate(), results[i].announceDate());
0566             QCOMPARE(firstService.cacheDuration(), results[i].cacheDuration());
0567             QCOMPARE(firstService.location(), results[i].location());
0568             QCOMPARE(firstService.nt(), results[i].nt());
0569             QCOMPARE(firstService.nts(), results[i].nts());
0570             QCOMPARE(firstService.usn(), results[i].usn());
0571         }
0572 
0573         removedServiceSignal.wait(10000);
0574 
0575         if (needAutoRefresh) {
0576             QCOMPARE(removedServiceSignal.count(), 0);
0577         } else {
0578             QVERIFY(removedServiceSignal.count() > 0);
0579         }
0580     }
0581 
0582     void listenNotify_data()
0583     {
0584         QTest::addColumn<QList<UpnpDiscoveryResult>>("results");
0585         QTest::addColumn<int>("refreshPeriod");
0586         QTest::addColumn<QStringList>("refreshMessages");
0587 
0588         QTest::newRow("root device with notify")
0589             << QList<UpnpDiscoveryResult>({ UpnpDiscoveryResult(QStringLiteral("upnp:rootdevice"),
0590                    QStringLiteral("uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice"),
0591                    QStringLiteral("http://127.0.0.1:8200/rootDesc.xml"),
0592                    UpnpSsdpEngine::NotificationSubType::Alive,
0593                    QStringLiteral("mar., 27 oct. 2015 21:03:35 G\x7F"),
0594                    4) })
0595             << 3
0596             << QStringList({ QStringLiteral("NOTIFY * HTTP/1.1 200 OK\r\n"
0597                                             "CACHE-CONTROL: max-age=4\r\n"
0598                                             "HOST: 239.255.255.250:1900\r\n"
0599                                             "NT: upnp:rootdevice\r\n"
0600                                             "USN: uuid:4d696e69-444c-164e-9d41-ecf4bb9c317e::upnp:rootdevice\r\n"
0601                                             "NTS: ssdp:alive\r\n"
0602                                             "SERVER: Debian DLNADOC/1.50 UPnP/1.0 MiniDLNA/1.1.4\r\n"
0603                                             "LOCATION: http://127.0.0.1:8200/rootDesc.xml\r\n"
0604                                             "Content-Length: 0\r\n\r\n") });
0605     }
0606 
0607     void listenNotify()
0608     {
0609         QFETCH(QList<UpnpDiscoveryResult>, results);
0610         QFETCH(int, refreshPeriod);
0611         QFETCH(QStringList, refreshMessages);
0612 
0613         QScopedPointer<MockSsdpClient> newClient(new MockSsdpClient(11900, QByteArray(), QStringList({}), true, refreshPeriod, refreshMessages));
0614         newClient->listen();
0615 
0616         QScopedPointer<UpnpSsdpEngine> newEngine(new UpnpSsdpEngine);
0617         newEngine->setPort(11900);
0618         newEngine->initialize();
0619 
0620         QSignalSpy newServiceSignal(newEngine.data(), &UpnpSsdpEngine::newService);
0621         QSignalSpy removedServiceSignal(newEngine.data(), &UpnpSsdpEngine::removedService);
0622 
0623         newServiceSignal.wait();
0624 
0625         QVERIFY(newServiceSignal.size() == results.size());
0626 
0627         for (int i = 0; i < results.size(); ++i) {
0628             auto firstService = newServiceSignal[i][0].value<UpnpDiscoveryResult>();
0629             QVERIFY(firstService.cacheDuration() == results[i].cacheDuration());
0630             QVERIFY(firstService.location() == results[i].location());
0631             QVERIFY(firstService.nt() == results[i].nt());
0632             QVERIFY(firstService.nts() == results[i].nts());
0633             QVERIFY(firstService.usn() == results[i].usn());
0634         }
0635 
0636         removedServiceSignal.wait(10000);
0637 
0638         QCOMPARE(removedServiceSignal.count(), 0);
0639     }
0640 };
0641 
0642 QTEST_MAIN(SsdpTests)
0643 
0644 #include "ssdptests.moc"