File indexing completed on 2024-04-28 11:35:24
0001 /* 0002 SPDX-FileCopyrightText: 2008 Omat Holding B .V. <info@omat.nl> 0003 SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB , a KDAB Group company <info@kdab.com> 0004 SPDX-FileContributor: Kevin Ottens <kevin@kdab.com> 0005 SPDX-FileCopyrightText: 2017 Sandro Kanuà <knauss@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 // Own 0011 #include "fakeserver.h" 0012 0013 // Qt 0014 #include <QDebug> 0015 #include <QFile> 0016 #include <QTest> 0017 0018 FakeServer::FakeServer(int port, QObject *parent) 0019 : QObject(parent) 0020 , m_thread(new QThread) 0021 , m_port(port) 0022 { 0023 moveToThread(m_thread); 0024 } 0025 0026 FakeServer::~FakeServer() 0027 { 0028 QMetaObject::invokeMethod(this, &FakeServer::cleanup); 0029 m_thread->quit(); 0030 m_thread->wait(); 0031 delete m_thread; 0032 } 0033 0034 void FakeServer::startAndWait() 0035 { 0036 m_thread->start(); 0037 // this will block until the init code happens and the event queue starts 0038 QMetaObject::invokeMethod(this, &FakeServer::init, Qt::BlockingQueuedConnection); 0039 } 0040 0041 void FakeServer::dataAvailable() 0042 { 0043 QMutexLocker locker(&m_mutex); 0044 0045 QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender()); 0046 Q_ASSERT(socket != nullptr); 0047 0048 int scenarioNumber = -1; 0049 readClientPart(socket, &scenarioNumber); 0050 if (scenarioNumber >= 0) { 0051 Q_ASSERT(scenarioNumber < m_scenarios.count()); 0052 writeServerPart(socket, scenarioNumber); 0053 } 0054 } 0055 0056 void FakeServer::newConnection() 0057 { 0058 QMutexLocker locker(&m_mutex); 0059 0060 m_clientSockets << m_tcpServer->nextPendingConnection(); 0061 connect(m_clientSockets.last(), &QTcpSocket::readyRead, this, &FakeServer::dataAvailable); 0062 } 0063 0064 void FakeServer::init() 0065 { 0066 m_tcpServer = new QTcpServer(); 0067 0068 if (!m_tcpServer->listen(QHostAddress(QHostAddress::LocalHost), m_port)) { 0069 qFatal("Unable to start the server"); 0070 } 0071 0072 connect(m_tcpServer, &QTcpServer::newConnection, this, &FakeServer::newConnection); 0073 } 0074 0075 void FakeServer::cleanup() 0076 { 0077 qDeleteAll(m_clientSockets); 0078 delete m_tcpServer; 0079 } 0080 0081 void FakeServer::setScenario(const QList<QByteArray> &scenario) 0082 { 0083 QMutexLocker locker(&m_mutex); 0084 0085 m_scenarios.clear(); 0086 m_scenarios << scenario; 0087 } 0088 0089 void FakeServer::addScenario(const QList<QByteArray> &scenario) 0090 { 0091 QMutexLocker locker(&m_mutex); 0092 0093 m_scenarios << scenario; 0094 } 0095 0096 void FakeServer::addScenarioFromFile(const QString &fileName) 0097 { 0098 QFile file(fileName); 0099 file.open(QIODevice::ReadOnly | QIODevice::Text); 0100 0101 QList<QByteArray> scenario; 0102 0103 while (!file.atEnd()) { 0104 scenario << file.readLine().trimmed(); 0105 } 0106 0107 file.close(); 0108 0109 addScenario(scenario); 0110 } 0111 0112 bool FakeServer::isScenarioDone(int scenarioNumber) const 0113 { 0114 QMutexLocker locker(&m_mutex); 0115 0116 if (scenarioNumber < m_scenarios.size()) { 0117 return m_scenarios[scenarioNumber].isEmpty(); 0118 } else { 0119 return true; // Non existent hence empty, right? 0120 } 0121 } 0122 0123 bool FakeServer::isAllScenarioDone() const 0124 { 0125 QMutexLocker locker(&m_mutex); 0126 0127 for (const QList<QByteArray> &scenario : std::as_const(m_scenarios)) { 0128 if (!scenario.isEmpty()) { 0129 return false; 0130 } 0131 } 0132 0133 return true; 0134 } 0135 0136 void FakeServer::writeServerPart(QTcpSocket *clientSocket, int scenarioNumber) 0137 { 0138 QList<QByteArray> scenario = m_scenarios[scenarioNumber]; 0139 0140 while (!scenario.isEmpty() && scenario.first().startsWith("S: ")) { 0141 QByteArray rule = scenario.takeFirst(); 0142 0143 QByteArray payload = rule.mid(3); 0144 clientSocket->write(payload + "\r\n"); 0145 } 0146 0147 QByteArray data; 0148 0149 while (!scenario.isEmpty() && scenario.first().startsWith("D: ")) { 0150 QByteArray rule = scenario.takeFirst(); 0151 0152 QByteArray payload = rule.mid(3); 0153 data.append(payload + "\r\n"); 0154 } 0155 0156 clientSocket->write(QStringLiteral("Content-Length: %1\r\n\r\n").arg(data.length()).toLatin1()); 0157 clientSocket->write(data); 0158 0159 if (!scenario.isEmpty() && scenario.first().startsWith("X")) { 0160 scenario.takeFirst(); 0161 clientSocket->close(); 0162 } 0163 0164 if (!scenario.isEmpty()) { 0165 QVERIFY(scenario.first().startsWith("C: ")); 0166 } 0167 0168 m_scenarios[scenarioNumber] = scenario; 0169 } 0170 0171 void FakeServer::readClientPart(QTcpSocket *socket, int *scenarioNumber) 0172 { 0173 QByteArray line = socket->readLine(); 0174 qDebug() << "Read client request" << line; 0175 const auto it = std::find_if(m_scenarios.begin(), m_scenarios.end(), [&](const QList<QByteArray> &scenario) { 0176 return !scenario.isEmpty() && scenario.at(0).mid(3) + "\r\n" == line; 0177 }); 0178 if (it == m_scenarios.end()) { 0179 qWarning() << "No server response available for" << line; 0180 QFAIL("Unexpected request"); 0181 return; 0182 } 0183 QList<QByteArray> scenario = *it; 0184 QVector<QByteArray> header; 0185 0186 while (line != "\r\n") { 0187 header << line; 0188 if (socket->bytesAvailable() == 0 && !socket->waitForReadyRead()) { 0189 qDebug() << header; 0190 QFAIL("could not read all headers"); 0191 return; 0192 } 0193 line = socket->readLine(); 0194 } 0195 0196 while (!scenario.isEmpty() && scenario.first().startsWith("C: ")) { 0197 QByteArray expected = scenario.takeFirst().mid(3) + "\r\n"; 0198 0199 if (!header.contains(expected)) { 0200 qWarning() << expected << "not found in header. Here's what we got:"; 0201 qWarning() << header; 0202 QVERIFY(false); 0203 break; 0204 } 0205 } 0206 0207 if (!scenario.isEmpty()) { 0208 QVERIFY(scenario.first().startsWith("S: ")); 0209 } 0210 0211 *it = scenario; 0212 *scenarioNumber = std::distance(m_scenarios.begin(), it); 0213 QVERIFY(*scenarioNumber < m_scenarios.count()); 0214 } 0215 0216 int FakeServer::port() const 0217 { 0218 return m_port; 0219 } 0220 0221 #include "moc_fakeserver.cpp"