diff options
Diffstat (limited to 'tests/arthur')
-rw-r--r-- | tests/arthur/baselineserver/src/baselineserver.cpp | 174 | ||||
-rw-r--r-- | tests/arthur/baselineserver/src/baselineserver.h | 11 | ||||
-rw-r--r-- | tests/arthur/baselineserver/src/htmlpage.cpp | 44 | ||||
-rw-r--r-- | tests/arthur/baselineserver/src/htmlpage.h | 4 | ||||
-rw-r--r-- | tests/arthur/common/baselineprotocol.cpp | 51 | ||||
-rw-r--r-- | tests/arthur/common/baselineprotocol.h | 8 |
6 files changed, 160 insertions, 132 deletions
diff --git a/tests/arthur/baselineserver/src/baselineserver.cpp b/tests/arthur/baselineserver/src/baselineserver.cpp index 03d6499..7679f13 100644 --- a/tests/arthur/baselineserver/src/baselineserver.cpp +++ b/tests/arthur/baselineserver/src/baselineserver.cpp @@ -38,6 +38,10 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + +#define QT_USE_FAST_CONCATENATION +#define QT_USE_FAST_OPERATOR_PLUS + #include "baselineserver.h" #include <QBuffer> #include <QFile> @@ -50,6 +54,7 @@ QString BaselineServer::storage; + BaselineServer::BaselineServer(QObject *parent) : QTcpServer(parent) { @@ -63,11 +68,9 @@ BaselineServer::BaselineServer(QObject *parent) QString BaselineServer::storagePath() { if (storage.isEmpty()) { - QByteArray envDir = qgetenv("QT_LANCELOT_DIR"); - if (!envDir.isEmpty()) - storage = QLS(envDir.append('/')); - else - storage = QLS("/var/www/"); + storage = QLS(qgetenv("QT_LANCELOT_DIR")); + if (storage.isEmpty()) + storage = QLS("/var/www"); } return storage; } @@ -147,7 +150,6 @@ void BaselineHandler::receiveRequest() proto.socket.disconnectFromHost(); return; } - connectionEstablished = true; QString logMsg; foreach (QString key, plat.keys()) { if (key != PI_HostName && key != PI_HostAddress) @@ -155,6 +157,21 @@ void BaselineHandler::receiveRequest() } qDebug() << runId << logtime() << "Connection established with" << plat.value(PI_HostName) << "[" << qPrintable(plat.value(PI_HostAddress)) << "]" << logMsg; + + // Filter on branch + QString branch = plat.value(PI_PulseGitBranch); + if (branch.isEmpty()) { + // Not run by Pulse, i.e. ad hoc run: Ok. + } + else if (branch != QLS("master-integration") || !plat.value(PI_GitCommit).contains(QLS("Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into master-integration"))) { + qDebug() << runId << logtime() << "Did not pass branch/staging repo filter, disconnecting."; + proto.sendBlock(BaselineProtocol::Abort, QByteArray("This branch/staging repo is not assigned to be tested.")); + proto.socket.disconnectFromHost(); + return; + } + + proto.sendBlock(BaselineProtocol::Ack, QByteArray()); + connectionEstablished = true; return; } @@ -206,9 +223,9 @@ void BaselineHandler::provideBaselineChecksums(const QByteArray &itemListBlock) } // Find and mark blacklisted items + QString context = pathForItem(itemList.at(0), true, false).section(QLC('/'), 0, -2); if (itemList.count() > 0) { - QString prefix = pathForItem(itemList.at(0), true).section(QLC('/'), 0, -2); - QFile file(prefix + QLS("/.blacklist")); + QFile file(BaselineServer::storagePath() + QLC('/') + context + QLS("/BLACKLIST")); if (file.open(QIODevice::ReadOnly)) { QTextStream in(&file); do { @@ -227,7 +244,7 @@ void BaselineHandler::provideBaselineChecksums(const QByteArray &itemListBlock) QDataStream ods(&block, QIODevice::WriteOnly); ods << itemList; proto.sendBlock(BaselineProtocol::Ack, block); - report.start(BaselineServer::storagePath(), runId, plat, proto.socket.peerAddress().toString(), itemList); + report.start(BaselineServer::storagePath(), runId, plat, context, itemList); } @@ -278,34 +295,37 @@ void BaselineHandler::receiveDisconnect() } -QString BaselineHandler::itemSubPath(const QString &engine, const QString &format, bool isBaseline) +void BaselineHandler::mapPlatformInfo() { - if (isBaseline) - return QString(QLS("baselines_%1_%2/")).arg(engine, format); - else - return QString(QLS("mismatches_%1_%2/")).arg(engine, format); + mapped = plat; + + // Map hostname + QString host = plat.value(PI_HostName).section(QLC('.'), 0, 0); // Filter away domain, if any + if (host.isEmpty() || host == QLS("localhost")) { + host = plat.value(PI_HostAddress); + } else { + // remove index postfix typical of vm hostnames + host.remove(QRegExp(QLS("\\d+$"))); + if (host.endsWith(QLC('-'))) + host.chop(1); + } + if (host.isEmpty()) + host = QLS("unknownhost"); + mapped.insert(PI_HostName, host); + + // Map qmakespec + QString mkspec = plat.value(PI_QMakeSpec); + mapped.insert(PI_QMakeSpec, mkspec.replace(QLC('/'), QLC('_'))); + + // Map Qt version + QString ver = plat.value(PI_QtVersion); + mapped.insert(PI_QtVersion, ver.prepend(QLS("Qt-"))); //### TBD: remove patch version } QString BaselineHandler::pathForItem(const ImageItem &item, bool isBaseline, bool absolute) { - if (pathForRun.isNull()) { - QString host = plat.value(PI_HostName).section(QLC('.'), 0, 0); // Filter away domain, if any - if (host.isEmpty() || host == QLS("localhost")) { - host = proto.socket.peerAddress().toString(); - if (host.isEmpty()) - host = QLS("Unknown"); - } else { - host.replace(QRegExp(QLS("^(bq|oslo?)-(.*)$")), QLS("\\2")); - host.replace(QRegExp(QLS("^(.*)-\\d+$")), QLS("vm-\\1")); - } - pathForRun = host + QLC('/'); - } - - QString storePath = pathForRun; - if (isBaseline) - storePath += itemSubPath(item.engineAsString(), item.formatAsString(), isBaseline); - else - storePath += itemSubPath(item.engineAsString(), item.formatAsString(), isBaseline) + runId + QLC('/'); + if (mapped.isEmpty()) + mapPlatformInfo(); QString itemName = item.scriptName; if (itemName.contains(QLC('.'))) @@ -313,15 +333,26 @@ QString BaselineHandler::pathForItem(const ImageItem &item, bool isBaseline, boo itemName.append(QLC('_')); itemName.append(QString::number(item.scriptChecksum, 16).rightJustified(4, QLC('0'))); + QStringList path; if (absolute) - storePath.prepend(BaselineServer::storagePath()); - return storePath + itemName + QLC('.'); + path += BaselineServer::storagePath(); + path += QLS(isBaseline ? "baselines" : "mismatches"); + path += item.engineAsString() + QLC('_') + item.formatAsString(); + path += mapped.value(PI_QtVersion); + path += mapped.value(PI_QMakeSpec); + path += mapped.value(PI_HostName); + if (!isBaseline) + path += runId; + path += itemName + QLC('.'); + + return path.join(QLS("/")); } QString BaselineHandler::updateAllBaselines(const QString &host, const QString &id, const QString &engine, const QString &format) { +#if 0 QString basePath(BaselineServer::storagePath()); QString srcDir(basePath + host + QLC('/') + itemSubPath(engine, format, false) + id); QString dstDir(basePath + host + QLC('/') + itemSubPath(engine, format)); @@ -352,12 +383,15 @@ QString BaselineHandler::updateAllBaselines(const QString &host, const QString & "Command output: <pre>%2</pre>").arg(proc.errorString(), proc.readAll().constData()); return res; +#else + return QString(); +#endif } QString BaselineHandler::updateSingleBaseline(const QString &oldBaseline, const QString &newBaseline) { QString res; - QString basePath(BaselineServer::storagePath()); + QString basePath(BaselineServer::storagePath() + QLC('/')); QString srcBase(basePath + newBaseline.left(newBaseline.length() - 3)); QString dstDir(basePath + oldBaseline.left(oldBaseline.lastIndexOf(QLC('/')))); @@ -374,53 +408,29 @@ QString BaselineHandler::updateSingleBaseline(const QString &oldBaseline, const return res; } -QString BaselineHandler::blacklistTest(const QString &scriptName, const QString &host, const QString &engine, - const QString &format) +QString BaselineHandler::blacklistTest(const QString &context, const QString &itemId, bool removeFromBlacklist) { - QString configFile(BaselineServer::storagePath() + host + QLC('/') - + itemSubPath(engine, format) + QLS(".blacklist")); - QFile file(configFile); - if (file.open(QIODevice::Append)) { - QTextStream out(&file); - out << scriptName << endl; - return QLS("Blacklisted ") + scriptName; + QFile file(BaselineServer::storagePath() + QLC('/') + context + QLS("/BLACKLIST")); + QStringList blackList; + if (file.open(QIODevice::ReadWrite)) { + while (!file.atEnd()) + blackList.append(file.readLine().trimmed()); + + if (removeFromBlacklist) + blackList.removeAll(itemId); + else if (!blackList.contains(itemId)) + blackList.append(itemId); + + file.resize(0); + foreach (QString id, blackList) + file.write(id.toLatin1() + '\n'); + file.close(); + return QLS(removeFromBlacklist ? "Whitelisted " : "Blacklisted ") + itemId + QLS(" in context ") + context; } else { - return QLS("Unable to update blacklisted tests."); + return QLS("Unable to update blacklisted tests, failed to open ") + file.fileName(); } } -QString BaselineHandler::whitelistTest(const QString &scriptName, const QString &host, const QString &engine, - const QString &format) -{ - QString configFile(BaselineServer::storagePath() + host + QLC('/') - + itemSubPath(engine, format) + QLS(".blacklist")); - QFile file(configFile); - QStringList tests; - if (file.open(QIODevice::ReadOnly)) { - QTextStream in(&file); - do { - tests << in.readLine(); - } while (!in.atEnd()); - if (tests.count() != 0) { - QMutableStringListIterator it(tests); - while (it.hasNext()) { - it.next(); - if (it.value() == scriptName) - it.remove(); - } - } - file.close(); - if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - QTextStream out(&file); - for (int i=0; i<tests.count(); ++i) - out << tests.at(i); - return QLS("Whitelisted ") + scriptName; - } else { - QLS("Unable to whitelist ") + scriptName + QLS(". Unable to truncate blacklist file."); - } - } - return QLS("Unable to whitelist ") + scriptName + QLS(". Unable to open blacklist file."); -} void BaselineHandler::testPathMapping() { @@ -433,6 +443,9 @@ void BaselineHandler::testPathMapping() << QLS("osl-mac-master-6.test.qt.nokia.com") << QLS("sv-xp-vs-010") << QLS("sv-xp-vs-011") + << QLS("sv-solaris-sparc-008") + << QLS("macbuilder-02.test.troll.no") + << QLS("bqvm1164") << QLS("chimera") << QLS("localhost"); @@ -445,11 +458,12 @@ void BaselineHandler::testPathMapping() plat.insert(PI_QtVersion, QLS("4.8.0")); plat.insert(PI_BuildKey, QLS("(nobuildkey)")); + plat.insert(PI_QMakeSpec, "linux-g++"); foreach(const QString& host, hosts) { - pathForRun = QString(); + mapped.clear(); plat.insert(PI_HostName, host); - qDebug() << "Baseline from" << host << "->" << pathForItem(item, true).remove(BaselineServer::storagePath()); - qDebug() << "Mismatch from" << host << "->" << pathForItem(item, false).remove(BaselineServer::storagePath()); + qDebug() << "Baseline from" << host << "->" << pathForItem(item, true); + qDebug() << "Mismatch from" << host << "->" << pathForItem(item, false); } } diff --git a/tests/arthur/baselineserver/src/baselineserver.h b/tests/arthur/baselineserver/src/baselineserver.h index e311527..d49aedb 100644 --- a/tests/arthur/baselineserver/src/baselineserver.h +++ b/tests/arthur/baselineserver/src/baselineserver.h @@ -103,10 +103,7 @@ public: static QString updateAllBaselines(const QString &host, const QString &id, const QString &engine, const QString &format); static QString updateSingleBaseline(const QString &oldBaseline, const QString &newBaseline); - static QString blacklistTest(const QString &scriptName, const QString &host, - const QString &engine, const QString &format); - static QString whitelistTest(const QString &scriptName, const QString &host, - const QString &engine, const QString &format); + static QString blacklistTest(const QString &context, const QString &itemId, bool removeFromBlacklist = false); private slots: void receiveRequest(); @@ -115,18 +112,16 @@ private slots: private: void provideBaselineChecksums(const QByteArray &itemListBlock); void storeImage(const QByteArray &itemBlock, bool isBaseline); + void mapPlatformInfo(); QString pathForItem(const ImageItem &item, bool isBaseline = true, bool absolute = true); const char *logtime(); QString computeMismatchScore(const QImage& baseline, const QImage& rendered); - QString engineForItem(const ImageItem &item); - - static QString itemSubPath(const QString &engine, const QString &format, bool isBaseline = true); BaselineProtocol proto; PlatformInfo plat; + PlatformInfo mapped; bool connectionEstablished; QString runId; - QString pathForRun; HTMLPage report; }; diff --git a/tests/arthur/baselineserver/src/htmlpage.cpp b/tests/arthur/baselineserver/src/htmlpage.cpp index ad7f8b7..f75da88 100644 --- a/tests/arthur/baselineserver/src/htmlpage.cpp +++ b/tests/arthur/baselineserver/src/htmlpage.cpp @@ -60,14 +60,14 @@ QString HTMLPage::filePath() return path; } -void HTMLPage::start(const QString &storagepath, const QString &runId, const PlatformInfo pinfo, const QString &hostAddress, const ImageItemList &itemList) +void HTMLPage::start(const QString &storagepath, const QString &runId, const PlatformInfo pinfo, const QString &context, const ImageItemList &itemList) { end(); id = runId; plat = pinfo; - address = hostAddress; - root = storagepath; + ctx = context; + root = storagepath + QLC('/'); imageItems = itemList; QString dir = root + QLS("reports/"); QDir cwd; @@ -132,16 +132,13 @@ void HTMLPage::addItem(const QString &baseline, const QString &rendered, const I QStringList images = QStringList() << baseline << rendered << compared; foreach(const QString& img, images) out << "<td><a href=\"/" << img << "\"><img src=\"/" << img << "\" width=240 height=240></a></td>\n"; - out << "<td><a href=\"/cgi-bin/server.cgi?cmd=updateSingleBaseline&oldBaseline=" << baseline - << "&newBaseline=" << rendered << "&url=" << pageUrl << "\">Update baseline</a><br>" -#if 0 - "<a href=\"/cgi-bin/server.cgi?cmd=blacklist&scriptName=" << item.scriptName - << "&host=" << plat.hostName << "&engine=" << item.engineAsString() - << "&format=" << item.formatAsString() - << "&url=" << pageUrl << "\">Blacklist test</a>" -#endif + + out << "<td><p><a href=\"/cgi-bin/server.cgi?cmd=updateSingleBaseline&oldBaseline=" << baseline + << "&newBaseline=" << rendered << "&url=" << pageUrl << "\">Replace baseline with rendered</a></p>" + << "<p><a href=\"/cgi-bin/server.cgi?cmd=blacklist&context=" << ctx + << "&itemId=" << item.scriptName << "&url=" << pageUrl << "\">Blacklist this item</a></p>" << "</td>\n"; - out << "</tr>\n\n"; + out << "</tr>\n\n"; QMutableVectorIterator<ImageItem> it(imageItems); while (it.hasNext()) { @@ -162,13 +159,10 @@ void HTMLPage::end() for (int i=0; i<imageItems.count(); ++i) { out << "<tr><td>" << imageItems.at(i).scriptName << "</td><td>N/A</td><td>N/A</td><td>N/A</td><td>"; if (imageItems.at(i).status == ImageItem::IgnoreItem) { - out << "<span style=\"background-color:yellow\">Blacklisted</span><br>" - "<a href=\"/cgi-bin/server.cgi?cmd=whitelist&scriptName=" - << imageItems.at(i).scriptName << "&host=" << plat.value(PI_HostName) - << "&engine=" << imageItems.at(i).engineAsString() - << "&format=" << imageItems.at(i).formatAsString() - << "&url=" << pageUrl - << "\">Whitelist test</a>"; + out << "<span style=\"background-color:yellow\">Blacklisted</span> " + << "<a href=\"/cgi-bin/server.cgi?cmd=whitelist&context=" << ctx + << "&itemId=" << imageItems.at(i).scriptName << "&url=" << pageUrl + << "\">Whitelist item</a>"; } else { out << "<span style=\"color:green\">Test passed</span>"; } @@ -220,16 +214,12 @@ void HTMLPage::handleCGIQuery(const QString &query) cgiUrl.queryItemValue(QLS("format"))); } else if (command == QLS("blacklist")) { // blacklist a test - s << BaselineHandler::blacklistTest(cgiUrl.queryItemValue(QLS("scriptName")), - cgiUrl.queryItemValue(QLS("host")), - cgiUrl.queryItemValue(QLS("engine")), - cgiUrl.queryItemValue(QLS("format"))); + s << BaselineHandler::blacklistTest(cgiUrl.queryItemValue(QLS("context")), + cgiUrl.queryItemValue(QLS("itemId"))); } else if (command == QLS("whitelist")) { // whitelist a test - s << BaselineHandler::whitelistTest(cgiUrl.queryItemValue(QLS("scriptName")), - cgiUrl.queryItemValue(QLS("host")), - cgiUrl.queryItemValue(QLS("engine")), - cgiUrl.queryItemValue(QLS("format"))); + s << BaselineHandler::blacklistTest(cgiUrl.queryItemValue(QLS("context")), + cgiUrl.queryItemValue(QLS("itemId")), true); } else { s << "Unknown query:<br>" << query << "<br>"; } diff --git a/tests/arthur/baselineserver/src/htmlpage.h b/tests/arthur/baselineserver/src/htmlpage.h index bef6b55..fa4d1ed 100644 --- a/tests/arthur/baselineserver/src/htmlpage.h +++ b/tests/arthur/baselineserver/src/htmlpage.h @@ -51,7 +51,7 @@ public: HTMLPage(); ~HTMLPage(); - void start(const QString &storagePath, const QString &runId, const PlatformInfo pinfo, const QString &hostAddress, const ImageItemList &itemList); + void start(const QString &storagePath, const QString &runId, const PlatformInfo pinfo, const QString &context, const ImageItemList &itemList); void addItem(const QString &baseline, const QString &rendered, const ImageItem &item); void end(); QString filePath(); @@ -69,7 +69,7 @@ private: QTextStream out; QString id; PlatformInfo plat; - QString address; + QString ctx; ImageItemList imageItems; bool headerWritten; }; diff --git a/tests/arthur/common/baselineprotocol.cpp b/tests/arthur/common/baselineprotocol.cpp index 2a41104..6d26e9a 100644 --- a/tests/arthur/common/baselineprotocol.cpp +++ b/tests/arthur/common/baselineprotocol.cpp @@ -47,11 +47,28 @@ #include <QProcess> #include <QFileInfo> #include <QDir> +#include <QTime> #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(bool useLocal) : QMap<QString, QString>() { @@ -141,12 +158,6 @@ quint64 ImageItem::computeChecksum(const QImage &image) p += bpl; } } - if (img.format() == QImage::Format_RGB32) { // Thank you, Haavard - quint32 *p = (quint32 *)img.bits(); - const quint32 *end = p + (img.byteCount()/4); - while (p<end) - *p++ &= RGB_MASK; - } quint32 h1 = 0xfeedbacc; quint32 h2 = 0x21604894; @@ -221,7 +232,7 @@ BaselineProtocol::~BaselineProtocol() } -bool BaselineProtocol::connect() +bool BaselineProtocol::connect(bool *dryrun) { errMsg.clear(); QByteArray serverName(qgetenv("QT_LANCELOT_SERVER")); @@ -230,8 +241,11 @@ bool BaselineProtocol::connect() socket.connectToHost(serverName, ServerPort); if (!socket.waitForConnected(Timeout)) { - errMsg += QLS("TCP connectToHost failed. Host:") + serverName + QLS(" port:") + QString::number(ServerPort); - return false; + sysSleep(Timeout); // Wait a bit and try again, the server might just be restarting + if (!socket.waitForConnected(Timeout)) { + errMsg += QLS("TCP connectToHost failed. Host:") + serverName + QLS(" port:") + QString::number(ServerPort); + return false; + } } PlatformInfo pi(true); @@ -243,12 +257,25 @@ bool BaselineProtocol::connect() return false; } - Command cmd = Ack; - if (!receiveBlock(&cmd, &block) || cmd != Ack) { + Command cmd = UnknownError; + if (!receiveBlock(&cmd, &block)) { errMsg += QLS("Failed to get response from server."); return false; } + if (cmd == Abort) { + errMsg += QLS("Server aborted 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; } @@ -268,8 +295,6 @@ bool BaselineProtocol::acceptConnection(PlatformInfo *pi) pi->insert(PI_HostAddress, socket.peerAddress().toString()); } - if (!sendBlock(Ack, QByteArray())) - return false; return true; } diff --git a/tests/arthur/common/baselineprotocol.h b/tests/arthur/common/baselineprotocol.h index 162a19f..9f59454 100644 --- a/tests/arthur/common/baselineprotocol.h +++ b/tests/arthur/common/baselineprotocol.h @@ -123,7 +123,7 @@ public: enum Constant { ProtocolVersion = 2, ServerPort = 54129, - Timeout = 10000 + Timeout = 5000 }; enum Command { @@ -135,10 +135,12 @@ public: AcceptMismatch = 5, // Responses Ack = 128, + Abort = 129, + DoDryRun = 130 }; // For client: - bool connect(); + bool connect(bool *dryrun = 0); bool requestBaselineChecksums(ImageItemList *itemList); bool submitNewBaseline(const ImageItem &item, QByteArray *serverMsg); bool submitMismatch(const ImageItem &item, QByteArray *serverMsg); @@ -153,6 +155,8 @@ private: bool sendBlock(Command cmd, const QByteArray &block); bool receiveBlock(Command *cmd, QByteArray *block); + void sysSleep(int ms); + QString errMsg; QTcpSocket socket; |