diff options
Diffstat (limited to 'tests/baselineserver/shared/baselineprotocol.cpp')
-rw-r--r-- | tests/baselineserver/shared/baselineprotocol.cpp | 548 |
1 files changed, 0 insertions, 548 deletions
diff --git a/tests/baselineserver/shared/baselineprotocol.cpp b/tests/baselineserver/shared/baselineprotocol.cpp deleted file mode 100644 index c481bf7639..0000000000 --- a/tests/baselineserver/shared/baselineprotocol.cpp +++ /dev/null @@ -1,548 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** 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 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** 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 "baselineprotocol.h" -#include <QLibraryInfo> -#include <QImage> -#include <QBuffer> -#include <QHostInfo> -#include <QSysInfo> -#if QT_CONFIG(process) -# include <QProcess> -#endif -#include <QFileInfo> -#include <QDir> -#include <QTime> -#include <QPointer> -#include <QRegularExpression> - -const QString PI_Project(QLS("Project")); -const QString PI_TestCase(QLS("TestCase")); -const QString PI_HostName(QLS("HostName")); -const QString PI_HostAddress(QLS("HostAddress")); -const QString PI_OSName(QLS("OSName")); -const QString PI_OSVersion(QLS("OSVersion")); -const QString PI_QtVersion(QLS("QtVersion")); -const QString PI_QtBuildMode(QLS("QtBuildMode")); -const QString PI_GitCommit(QLS("GitCommit")); -const QString PI_QMakeSpec(QLS("QMakeSpec")); -const QString PI_PulseGitBranch(QLS("PulseGitBranch")); -const QString PI_PulseTestrBranch(QLS("PulseTestrBranch")); - -#ifndef QMAKESPEC -#define QMAKESPEC "Unknown" -#endif - -#if defined(Q_OS_WIN) -#include <QtCore/qt_windows.h> -#endif -#if defined(Q_OS_UNIX) -#include <time.h> -#endif -void BaselineProtocol::sysSleep(int ms) -{ -#if defined(Q_OS_WIN) - Sleep(DWORD(ms)); -#else - struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 }; - nanosleep(&ts, NULL); -#endif -} - -PlatformInfo::PlatformInfo() - : QMap<QString, QString>(), adHoc(true) -{ -} - -PlatformInfo PlatformInfo::localHostInfo() -{ - PlatformInfo pi; - pi.insert(PI_HostName, QHostInfo::localHostName()); - pi.insert(PI_QtVersion, QLS(qVersion())); - pi.insert(PI_QMakeSpec, QString(QLS(QMAKESPEC)).remove(QRegularExpression(QLS("^.*mkspecs/")))); -#if QT_VERSION >= 0x050000 - pi.insert(PI_QtBuildMode, QLibraryInfo::isDebugBuild() ? QLS("QtDebug") : QLS("QtRelease")); -#endif -#if defined(Q_OS_LINUX) && QT_CONFIG(process) - pi.insert(PI_OSName, QLS("Linux")); -#elif defined(Q_OS_WIN) - pi.insert(PI_OSName, QLS("Windows")); -#elif defined(Q_OS_DARWIN) - pi.insert(PI_OSName, QLS("Darwin")); -#else - pi.insert(PI_OSName, QLS("Other")); -#endif - pi.insert(PI_OSVersion, QSysInfo::kernelVersion()); - -#if QT_CONFIG(process) - QProcess git; - QString cmd; - QStringList args; -#if defined(Q_OS_WIN) - cmd = QLS("cmd.exe"); - args << QLS("/c") << QLS("git"); -#else - cmd = QLS("git"); -#endif - args << QLS("log") << QLS("--max-count=1") << QLS("--pretty=%H [%an] [%ad] %s"); - git.start(cmd, args); - git.waitForFinished(3000); - if (!git.exitCode()) - pi.insert(PI_GitCommit, QString::fromLocal8Bit(git.readAllStandardOutput().constData()).simplified()); - else - pi.insert(PI_GitCommit, QLS("Unknown")); - - QByteArray gb = qgetenv("PULSE_GIT_BRANCH"); - if (!gb.isEmpty()) { - pi.insert(PI_PulseGitBranch, QString::fromLatin1(gb)); - pi.setAdHocRun(false); - } - QByteArray tb = qgetenv("PULSE_TESTR_BRANCH"); - if (!tb.isEmpty()) { - pi.insert(PI_PulseTestrBranch, QString::fromLatin1(tb)); - pi.setAdHocRun(false); - } - if (!qgetenv("JENKINS_HOME").isEmpty()) { - pi.setAdHocRun(false); - gb = qgetenv("GIT_BRANCH"); - if (!gb.isEmpty()) { - // FIXME: the string "Pulse" should be eliminated, since that is not the used tool. - pi.insert(PI_PulseGitBranch, QString::fromLatin1(gb)); - } - } -#endif // QT_CONFIG(process) - - return pi; -} - - -PlatformInfo::PlatformInfo(const PlatformInfo &other) - : QMap<QString, QString>(other) -{ - orides = other.orides; - adHoc = other.adHoc; -} - - -PlatformInfo &PlatformInfo::operator=(const PlatformInfo &other) -{ - QMap<QString, QString>::operator=(other); - orides = other.orides; - adHoc = other.adHoc; - return *this; -} - - -void PlatformInfo::addOverride(const QString& key, const QString& value) -{ - orides.append(key); - orides.append(value); -} - - -QStringList PlatformInfo::overrides() const -{ - return orides; -} - - -void PlatformInfo::setAdHocRun(bool isAdHoc) -{ - adHoc = isAdHoc; -} - - -bool PlatformInfo::isAdHocRun() const -{ - return adHoc; -} - - -QDataStream & operator<< (QDataStream &stream, const PlatformInfo &pi) -{ - stream << static_cast<const QMap<QString, QString>&>(pi); - stream << pi.orides << pi.adHoc; - return stream; -} - - -QDataStream & operator>> (QDataStream &stream, PlatformInfo &pi) -{ - stream >> static_cast<QMap<QString, QString>&>(pi); - stream >> pi.orides >> pi.adHoc; - return stream; -} - - -ImageItem &ImageItem::operator=(const ImageItem &other) -{ - testFunction = other.testFunction; - itemName = other.itemName; - itemChecksum = other.itemChecksum; - status = other.status; - image = other.image; - imageChecksums = other.imageChecksums; - return *this; -} - -// Defined in lookup3.c: -void hashword2 ( -const quint32 *k, /* the key, an array of quint32 values */ -size_t length, /* the length of the key, in quint32s */ -quint32 *pc, /* IN: seed OUT: primary hash value */ -quint32 *pb); /* IN: more seed OUT: secondary hash value */ - -quint64 ImageItem::computeChecksum(const QImage &image) -{ - QImage img(image); - const qsizetype bpl = img.bytesPerLine(); - const int padBytes = bpl - (qsizetype(img.width()) * img.depth() / 8); - if (padBytes) { - uchar *p = img.bits() + bpl - padBytes; - const int h = img.height(); - for (int y = 0; y < h; ++y) { - memset(p, 0, padBytes); - p += bpl; - } - } - - quint32 h1 = 0xfeedbacc; - quint32 h2 = 0x21604894; - hashword2((const quint32 *)img.constBits(), img.sizeInBytes()/4, &h1, &h2); - return (quint64(h1) << 32) | h2; -} - -#if 0 -QString ImageItem::engineAsString() const -{ - switch (engine) { - case Raster: - return QLS("Raster"); - break; - case OpenGL: - return QLS("OpenGL"); - break; - default: - break; - } - return QLS("Unknown"); -} - -QString ImageItem::formatAsString() const -{ - static const int numFormats = 16; - static const char *formatNames[numFormats] = { - "Invalid", - "Mono", - "MonoLSB", - "Indexed8", - "RGB32", - "ARGB32", - "ARGB32-Premult", - "RGB16", - "ARGB8565-Premult", - "RGB666", - "ARGB6666-Premult", - "RGB555", - "ARGB8555-Premult", - "RGB888", - "RGB444", - "ARGB4444-Premult" - }; - if (renderFormat < 0 || renderFormat >= numFormats) - return QLS("UnknownFormat"); - return QLS(formatNames[renderFormat]); -} -#endif - -void ImageItem::writeImageToStream(QDataStream &out) const -{ - if (image.isNull() || image.format() == QImage::Format_Invalid) { - out << quint8(0); - return; - } - out << quint8('Q') << quint8(image.format()); - out << quint8(QSysInfo::ByteOrder) << quint8(0); // pad to multiple of 4 bytes - out << quint32(image.width()) << quint32(image.height()) << quint32(image.bytesPerLine()); - out << qCompress(reinterpret_cast<const uchar *>(image.constBits()), - int(image.sizeInBytes())); - //# can be followed by colormap for formats that use it -} - -void ImageItem::readImageFromStream(QDataStream &in) -{ - quint8 hdr, fmt, endian, pad; - quint32 width, height, bpl; - QByteArray data; - - in >> hdr; - if (hdr != 'Q') { - image = QImage(); - return; - } - in >> fmt >> endian >> pad; - if (!fmt || fmt >= QImage::NImageFormats) { - image = QImage(); - return; - } - if (endian != QSysInfo::ByteOrder) { - qWarning("ImageItem cannot read streamed image with different endianness"); - image = QImage(); - return; - } - in >> width >> height >> bpl; - in >> data; - data = qUncompress(data); - QImage res((const uchar *)data.constData(), width, height, bpl, QImage::Format(fmt)); - image = res.copy(); //# yuck, seems there is currently no way to avoid data copy -} - -QDataStream & operator<< (QDataStream &stream, const ImageItem &ii) -{ - stream << ii.testFunction << ii.itemName << ii.itemChecksum << quint8(ii.status) << ii.imageChecksums << ii.misc; - ii.writeImageToStream(stream); - return stream; -} - -QDataStream & operator>> (QDataStream &stream, ImageItem &ii) -{ - quint8 encStatus; - stream >> ii.testFunction >> ii.itemName >> ii.itemChecksum >> encStatus >> ii.imageChecksums >> ii.misc; - ii.status = ImageItem::ItemStatus(encStatus); - ii.readImageFromStream(stream); - return stream; -} - -BaselineProtocol::BaselineProtocol() -{ -} - -BaselineProtocol::~BaselineProtocol() -{ - disconnect(); -} - -bool BaselineProtocol::disconnect() -{ - socket.close(); - return (socket.state() == QTcpSocket::UnconnectedState) ? true : socket.waitForDisconnected(Timeout); -} - - -bool BaselineProtocol::connect(const QString &testCase, bool *dryrun, const PlatformInfo& clientInfo) -{ - errMsg.clear(); - QByteArray serverName(qgetenv("QT_LANCELOT_SERVER")); - if (serverName.isNull()) - serverName = "lancelot.test.qt-project.org"; - - socket.connectToHost(serverName, ServerPort); - if (!socket.waitForConnected(Timeout)) { - sysSleep(3000); // Wait a bit and try again, the server might just be restarting - if (!socket.waitForConnected(Timeout)) { - errMsg += QLS("TCP connectToHost failed. Host:") + QLS(serverName) + QLS(" port:") + QString::number(ServerPort); - return false; - } - } - - PlatformInfo pi = clientInfo.isEmpty() ? PlatformInfo::localHostInfo() : clientInfo; - pi.insert(PI_TestCase, testCase); - QByteArray block; - QDataStream ds(&block, QIODevice::ReadWrite); - ds << pi; - if (!sendBlock(AcceptPlatformInfo, block)) { - errMsg += QLS("Failed to send data to server."); - return false; - } - - Command cmd = UnknownError; - if (!receiveBlock(&cmd, &block)) { - errMsg.prepend(QLS("Failed to get response from server. ")); - return false; - } - - if (cmd == Abort) { - errMsg += QLS("Server rejected connection. Reason: ") + QString::fromLatin1(block); - return false; - } - - if (dryrun) - *dryrun = (cmd == DoDryRun); - - if (cmd != Ack && cmd != DoDryRun) { - errMsg += QLS("Unexpected response from server."); - return false; - } - - return true; -} - - -bool BaselineProtocol::acceptConnection(PlatformInfo *pi) -{ - errMsg.clear(); - - QByteArray block; - Command cmd = AcceptPlatformInfo; - if (!receiveBlock(&cmd, &block) || cmd != AcceptPlatformInfo) - return false; - - if (pi) { - QDataStream ds(block); - ds >> *pi; - pi->insert(PI_HostAddress, socket.peerAddress().toString()); - } - - return true; -} - - -bool BaselineProtocol::requestBaselineChecksums(const QString &testFunction, ImageItemList *itemList) -{ - errMsg.clear(); - if (!itemList) - return false; - - for(ImageItemList::iterator it = itemList->begin(); it != itemList->end(); it++) - it->testFunction = testFunction; - - QByteArray block; - QDataStream ds(&block, QIODevice::WriteOnly); - ds << *itemList; - if (!sendBlock(RequestBaselineChecksums, block)) - return false; - - Command cmd; - QByteArray rcvBlock; - if (!receiveBlock(&cmd, &rcvBlock) || cmd != BaselineProtocol::Ack) - return false; - QDataStream rds(&rcvBlock, QIODevice::ReadOnly); - rds >> *itemList; - return true; -} - - -bool BaselineProtocol::submitMatch(const ImageItem &item, QByteArray *serverMsg) -{ - Command cmd; - ImageItem smallItem = item; - smallItem.image = QImage(); // No need to waste bandwith sending image (identical to baseline) to server - return (sendItem(AcceptMatch, smallItem) && receiveBlock(&cmd, serverMsg) && cmd == Ack); -} - - -bool BaselineProtocol::submitNewBaseline(const ImageItem &item, QByteArray *serverMsg) -{ - Command cmd; - return (sendItem(AcceptNewBaseline, item) && receiveBlock(&cmd, serverMsg) && cmd == Ack); -} - - -bool BaselineProtocol::submitMismatch(const ImageItem &item, QByteArray *serverMsg, bool *fuzzyMatch) -{ - Command cmd; - if (sendItem(AcceptMismatch, item) && receiveBlock(&cmd, serverMsg) && (cmd == Ack || cmd == FuzzyMatch)) { - if (fuzzyMatch) - *fuzzyMatch = (cmd == FuzzyMatch); - return true; - } - return false; -} - - -bool BaselineProtocol::sendItem(Command cmd, const ImageItem &item) -{ - errMsg.clear(); - QBuffer buf; - buf.open(QIODevice::WriteOnly); - QDataStream ds(&buf); - ds << item; - if (!sendBlock(cmd, buf.data())) { - errMsg.prepend(QLS("Failed to submit image to server. ")); - return false; - } - return true; -} - - -bool BaselineProtocol::sendBlock(Command cmd, const QByteArray &block) -{ - QDataStream s(&socket); - // TBD: set qds version as a constant - s << quint16(ProtocolVersion) << quint16(cmd); - s.writeBytes(block.constData(), block.size()); - return true; -} - - -bool BaselineProtocol::receiveBlock(Command *cmd, QByteArray *block) -{ - while (socket.bytesAvailable() < int(2*sizeof(quint16) + sizeof(quint32))) { - if (!socket.waitForReadyRead(Timeout)) - return false; - } - QDataStream ds(&socket); - quint16 rcvProtocolVersion, rcvCmd; - ds >> rcvProtocolVersion >> rcvCmd; - if (rcvProtocolVersion != ProtocolVersion) { - errMsg = QLS("Baseline protocol version mismatch, received:") + QString::number(rcvProtocolVersion) - + QLS(" expected:") + QString::number(ProtocolVersion); - return false; - } - if (cmd) - *cmd = Command(rcvCmd); - - QByteArray uMsg; - quint32 remaining; - ds >> remaining; - uMsg.resize(remaining); - int got = 0; - char* uMsgBuf = uMsg.data(); - do { - got = ds.readRawData(uMsgBuf, remaining); - remaining -= got; - uMsgBuf += got; - } while (remaining && got >= 0 && socket.waitForReadyRead(Timeout)); - - if (got < 0) - return false; - - if (block) - *block = uMsg; - - return true; -} - - -QString BaselineProtocol::errorMessage() -{ - QString ret = errMsg; - if (socket.error() >= 0) - ret += QLS(" Socket state: ") + socket.errorString(); - return ret; -} - |