mirror of
https://github.com/overte-org/overte.git
synced 2025-04-16 05:48:39 +02:00
Can write an HTML file created from zipped results
This commit is contained in:
parent
ed94ffa384
commit
d79d092dc8
3 changed files with 271 additions and 15 deletions
216
tools/auto-tester/src/AWSInterface.cpp
Normal file
216
tools/auto-tester/src/AWSInterface.cpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
//
|
||||
// AWSInterface.cpp
|
||||
//
|
||||
// Created by Nissim Hadar on 3 Oct 2018.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "AWSInterface.h"
|
||||
|
||||
#include <QDirIterator>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <quazip5/quazip.h>
|
||||
#include <quazip5/JlCompress.h>
|
||||
|
||||
AWSInterface::AWSInterface(QObject* parent) :
|
||||
QObject(parent) {
|
||||
}
|
||||
|
||||
void AWSInterface::createWebPageFromResults(const QString& testResults, const QString& tempDirectory) {
|
||||
// Extract test failures from zipped folder
|
||||
_tempDirectory = tempDirectory;
|
||||
|
||||
QDir dir = _tempDirectory;
|
||||
dir.mkdir(_tempDirectory);
|
||||
JlCompress::extractDir(testResults, _tempDirectory);
|
||||
|
||||
createHTMLFile(testResults, tempDirectory);
|
||||
}
|
||||
|
||||
void AWSInterface::createHTMLFile(const QString& testResults, const QString& tempDirectory) {
|
||||
// For file named `D:/tt/snapshots/TestResults--2018-10-03_15-35-28(9433)[DESKTOP-PMKNLSQ].zip`
|
||||
// - the HTML will be named `TestResults--2018-10-03_15-35-28(9433)[DESKTOP-PMKNLSQ]`
|
||||
QString resultsPath = tempDirectory + "/" + resultsFolder + "/";
|
||||
QDir().mkdir(resultsPath);
|
||||
QStringList tokens = testResults.split('/');
|
||||
QString htmlFilename = resultsPath + tokens[tokens.length() - 1].split('.')[0] + ".html";
|
||||
|
||||
QFile file(htmlFilename);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
|
||||
"Could not create '" + htmlFilename + "'");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
QTextStream stream(&file);
|
||||
|
||||
startHTMLpage(stream);
|
||||
writeHead(stream);
|
||||
writeBody(testResults, stream);
|
||||
finishHTMLpage(stream);
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void AWSInterface::startHTMLpage(QTextStream& stream) {
|
||||
stream << "<!DOCTYPE html>\n";
|
||||
stream << "<html>\n";
|
||||
}
|
||||
|
||||
void AWSInterface::writeHead(QTextStream& stream) {
|
||||
stream << "\t" << "<head>\n";
|
||||
stream << "\t" << "\t" << "<style>\n";
|
||||
stream << "\t" << "\t" << "\t" << "table, th, td {\n";
|
||||
stream << "\t" << "\t" << "\t" << "\t" << "border: 1px solid blue;\n";
|
||||
stream << "\t" << "\t" << "\t" << "}\n";
|
||||
stream << "\t" << "\t" << "</style>\n";
|
||||
stream << "\t" << "</head>\n";
|
||||
}
|
||||
|
||||
void AWSInterface::writeBody(const QString& testResults, QTextStream& stream) {
|
||||
stream << "\t" << "<body>\n";
|
||||
writeTitle(testResults, stream);
|
||||
writeTable(stream);
|
||||
stream << "\t" << "</body>\n";
|
||||
}
|
||||
|
||||
void AWSInterface::finishHTMLpage(QTextStream& stream) {
|
||||
stream << "</html>\n";
|
||||
}
|
||||
|
||||
void AWSInterface::writeTitle(const QString& testResults, QTextStream& stream) {
|
||||
// Separate relevant components from the results name
|
||||
// The expected format is as follows: `D:/tt/snapshots/TestResults--2018-10-04_11-09-41(PR14128)[DESKTOP-PMKNLSQ].zip`
|
||||
QStringList tokens = testResults.split('/');
|
||||
|
||||
// date_buildorPR_hostName will be 2018-10-03_15-35-28(9433)[DESKTOP-PMKNLSQ]
|
||||
QString date_buildorPR_hostName = tokens[tokens.length() - 1].split("--")[1].split(".")[0];
|
||||
|
||||
QString buildorPR = date_buildorPR_hostName.split('(')[1].split(')')[0];
|
||||
QString hostName = date_buildorPR_hostName.split('[')[1].split(']')[0];
|
||||
|
||||
QStringList dateList = date_buildorPR_hostName.split('(')[0].split('_')[0].split('-');
|
||||
QString year = dateList[0];
|
||||
QString month = dateList[1];
|
||||
QString day = dateList[2];
|
||||
|
||||
QStringList timeList = date_buildorPR_hostName.split('(')[0].split('_')[1].split('-');
|
||||
QString hour = timeList[0];
|
||||
QString minute = timeList[1];
|
||||
QString second = timeList[2];
|
||||
|
||||
const QString months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
|
||||
|
||||
stream << "\t" << "\t" << "<h1>Failures for ";
|
||||
stream << months[month.toInt() - 1] << " " << day << ", " << year << ", ";
|
||||
stream << hour << ":" << minute << ":" << second << ", ";
|
||||
|
||||
if (buildorPR.left(2) == "PR") {
|
||||
stream << "PR " << buildorPR.right(buildorPR.length() - 2) << ", ";
|
||||
} else {
|
||||
stream << "build " << buildorPR << ", ";
|
||||
}
|
||||
|
||||
stream << "run on " << hostName << "</h1>\n";
|
||||
}
|
||||
|
||||
void AWSInterface::writeTable(QTextStream& stream) {
|
||||
QString previousTestName{ "" };
|
||||
|
||||
// Loop over all entries in directory. This is done in stages, as the names are not in the order of the tests
|
||||
// The first stage reads the directory names into a list
|
||||
// The second stage renames the tests by removing everything up to "--tests."
|
||||
// The third stage renames the directories
|
||||
// The fourth and lasts stage creates the HTML entries
|
||||
|
||||
QStringList originalNames;
|
||||
QDirIterator it1(_tempDirectory.toStdString().c_str());
|
||||
while (it1.hasNext()) {
|
||||
QString nextDirectory = it1.next();
|
||||
|
||||
// Skip `.` and `..` directories
|
||||
if (nextDirectory.right(1) == ".") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only process failure folders
|
||||
if (!nextDirectory.contains("--tests.")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
originalNames.append(nextDirectory);
|
||||
}
|
||||
|
||||
QStringList newNames;
|
||||
for (int i = 0; i < originalNames.length(); ++i) {
|
||||
newNames.append(originalNames[i].split("--tests.")[1]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < newNames.length(); ++i) {
|
||||
QDir dir(originalNames[i]);
|
||||
dir.rename(originalNames[i], _tempDirectory + "/" + resultsFolder + "/" + newNames[i]);
|
||||
}
|
||||
|
||||
QDirIterator it2((_tempDirectory + "/" + resultsFolder).toStdString().c_str());
|
||||
while (it2.hasNext()) {
|
||||
QString nextDirectory = it2.next();
|
||||
|
||||
// Skip `.` and `..` directories, as well as the HTML directory
|
||||
if (nextDirectory.right(1) == "." || nextDirectory.contains(QString("/") + resultsFolder + "/TestResults--")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int splitIndex = nextDirectory.lastIndexOf(".");
|
||||
QString testName = nextDirectory.left(splitIndex).replace(".", " / ");
|
||||
QString testNumber = nextDirectory.right(nextDirectory.length() - (splitIndex + 1));
|
||||
|
||||
// The failures are ordered lexicographically, so we know that we can rely on the testName changing to create a new table
|
||||
if (testName != previousTestName) {
|
||||
if (!previousTestName.isEmpty()) {
|
||||
closeTable(stream);
|
||||
}
|
||||
|
||||
previousTestName = testName;
|
||||
|
||||
stream << "\t\t<h2>" << testName << "</h2>\n";
|
||||
|
||||
openTable(stream);
|
||||
}
|
||||
|
||||
createEntry(testNumber.toInt(), nextDirectory, stream);
|
||||
}
|
||||
|
||||
closeTable(stream);
|
||||
}
|
||||
|
||||
void AWSInterface::openTable(QTextStream& stream) {
|
||||
stream << "\t\t<table>\n";
|
||||
stream << "\t\t\t<tr>\n";
|
||||
stream << "\t\t\t\t<th><h1>Test</h1></th>\n";
|
||||
stream << "\t\t\t\t<th><h1>Actual Image</h1></th>\n";
|
||||
stream << "\t\t\t\t<th><h1>Expected Image</h1></th>\n";
|
||||
stream << "\t\t\t\t<th><h1>Difference Image</h1></th>\n";
|
||||
stream << "\t\t\t</tr>\n";
|
||||
}
|
||||
|
||||
void AWSInterface::closeTable(QTextStream& stream) {
|
||||
stream << "\t\t</table>\n";
|
||||
}
|
||||
|
||||
void AWSInterface::createEntry(int index, const QString& testFailure, QTextStream& stream) {
|
||||
stream << "\t\t\t<tr>\n";
|
||||
stream << "\t\t\t\t\<td><h1>" << QString::number(index) << "</h1></td>\n";
|
||||
|
||||
// For a test named `D:/t/fgadhcUDHSFaidsfh3478JJJFSDFIUSOEIrf/Failure_1--tests.engine.interaction.pick.collision.many.00000`
|
||||
// we need `Failure_1--tests.engine.interaction.pick.collision.many.00000`
|
||||
QStringList failureNameComponents = testFailure.split('/');
|
||||
QString failureName = failureNameComponents[failureNameComponents.length() - 1];
|
||||
|
||||
stream << "\t\t\t\t<td><img src=\"" << failureName << "/Actual Image.png\" width = \"576\" height = \"324\" ></td>\n";
|
||||
stream << "\t\t\t\t<td><img src=\"" << failureName << "/Expected Image.png\" width = \"576\" height = \"324\" ></td>\n";
|
||||
stream << "\t\t\t\t<td><img src=\"" << failureName << "/Difference Image.png\" width = \"576\" height = \"324\" ></td>\n";
|
||||
stream << "\t\t\t</tr>\n";
|
||||
}
|
44
tools/auto-tester/src/AWSInterface.h
Normal file
44
tools/auto-tester/src/AWSInterface.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// AWSInterface.h
|
||||
//
|
||||
// Created by Nissim Hadar on 3 Oct 2018.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_AWSInterface_h
|
||||
#define hifi_AWSInterface_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QTextStream>
|
||||
|
||||
class AWSInterface : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AWSInterface(QObject* parent = 0);
|
||||
|
||||
void createWebPageFromResults(const QString& testResults, const QString& tempDirectory);
|
||||
|
||||
void createHTMLFile(const QString& testResults, const QString& tempDirectory);
|
||||
|
||||
void startHTMLpage(QTextStream& stream);
|
||||
void writeHead(QTextStream& stream);
|
||||
void writeBody(const QString& testResults, QTextStream& stream);
|
||||
void finishHTMLpage(QTextStream& stream);
|
||||
|
||||
void writeTitle(const QString& testResults, QTextStream& stream);
|
||||
void writeTable(QTextStream& stream);
|
||||
void openTable(QTextStream& stream);
|
||||
void closeTable(QTextStream& stream);
|
||||
|
||||
void createEntry(int index, const QString& testFailure, QTextStream& stream);
|
||||
|
||||
private:
|
||||
QString _tempDirectory;
|
||||
|
||||
const QString resultsFolder{ "HTML" };
|
||||
};
|
||||
|
||||
#endif // hifi_AWSInterface_h
|
|
@ -110,6 +110,8 @@ void TestRunner::run() {
|
|||
saveExistingHighFidelityAppDataFolder();
|
||||
|
||||
// Download the latest High Fidelity build XML.
|
||||
// Note that this is not needed for PR builds (or whenever `Run Latest` is unchecked)
|
||||
// It is still downloaded, to simplify the flow
|
||||
QStringList urls;
|
||||
QStringList filenames;
|
||||
|
||||
|
@ -129,12 +131,12 @@ void TestRunner::downloadComplete() {
|
|||
// Download of Build XML has completed
|
||||
buildXMLDownloaded = true;
|
||||
|
||||
parseBuildInformation();
|
||||
|
||||
// Download the High Fidelity installer
|
||||
QStringList urls;
|
||||
QStringList filenames;
|
||||
if (_runLatest->isChecked()) {
|
||||
parseBuildInformation();
|
||||
|
||||
_installerFilename = INSTALLER_FILENAME_LATEST;
|
||||
|
||||
urls << _buildInformation.url;
|
||||
|
@ -392,18 +394,16 @@ void TestRunner::automaticTestRunEvaluationComplete(QString zippedFolder, int nu
|
|||
}
|
||||
|
||||
void TestRunner::addBuildNumberAndHostnameToResults(QString zippedFolderName) {
|
||||
QString augmentedFilename;
|
||||
if (!_runLatest->isChecked()) {
|
||||
QStringList filenameParts = zippedFolderName.split(".");
|
||||
QString augmentedFilename = filenameParts[0] + "(" + getPRNumberFromURL(_url->toPlainText()) + ")." + filenameParts[1];
|
||||
QFile::rename(zippedFolderName, augmentedFilename);
|
||||
|
||||
return;
|
||||
augmentedFilename =
|
||||
filenameParts[0] + "(" + getPRNumberFromURL(_url->toPlainText()) + ")[" + QHostInfo::localHostName() + "]." + filenameParts[1];
|
||||
} else {
|
||||
QStringList filenameParts = zippedFolderName.split(".");
|
||||
augmentedFilename =
|
||||
filenameParts[0] + "(" + _buildInformation.build + ")[" + QHostInfo::localHostName() + "]." + filenameParts[1];
|
||||
}
|
||||
|
||||
QStringList filenameParts = zippedFolderName.split(".");
|
||||
QString augmentedFilename =
|
||||
filenameParts[0] + "(" + _buildInformation.build + ")[" + QHostInfo::localHostName() + "]." + filenameParts[1];
|
||||
|
||||
QFile::rename(zippedFolderName, augmentedFilename);
|
||||
}
|
||||
|
||||
|
@ -504,10 +504,6 @@ QString TestRunner::getInstallerNameFromURL(const QString& url) {
|
|||
// An example URL: https://deployment.highfidelity.com/jobs/pr-build/label%3Dwindows/13023/HighFidelity-Beta-Interface-PR14006-be76c43.exe
|
||||
try {
|
||||
QStringList urlParts = url.split("/");
|
||||
int rr = urlParts.size();
|
||||
if (urlParts.size() != 8) {
|
||||
throw "URL not in expected format, should look like `https://deployment.highfidelity.com/jobs/pr-build/label%3Dwindows/13023/HighFidelity-Beta-Interface-PR14006-be76c43.exe`";
|
||||
}
|
||||
return urlParts[urlParts.size() - 1];
|
||||
} catch (QString errorMessage) {
|
||||
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), errorMessage);
|
||||
|
|
Loading…
Reference in a new issue