Skip to content

Commit

Permalink
added missing tests for handling perf data files
Browse files Browse the repository at this point in the history
  • Loading branch information
GitMensch committed Nov 5, 2023
1 parent 89c3808 commit 69ad59b
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ build*/
elfutils.build.tar.bz2
rustc_demangle.build.tar.bz2
d-demangle.tar.gz
*.actual
*.actual*
*.orig
scripts/output
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
116 changes: 105 additions & 11 deletions tests/integrationtests/tst_perfparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <QTemporaryFile>
#include <QTest>
#include <QTextStream>
#include <qdebug.h>

#include "data.h"
#include "perfparser.h"
Expand Down Expand Up @@ -172,6 +173,99 @@ private slots:
m_capabilities = host.perfCapabilities();
}

void testFileErrorHandling()
{
PerfParser parser(this);
QSignalSpy parsingFailedSpy(&parser, &PerfParser::parsingFailed);
QString message;

const auto notThereFile = QStringLiteral("not_here");
parser.initParserArgs(notThereFile);

QCOMPARE(parsingFailedSpy.count(), 1);
message = qvariant_cast<QString>(parsingFailedSpy.takeFirst().at(0));
QVERIFY(message.contains(notThereFile));
QVERIFY(message.contains(QLatin1String("does not exist")));

const auto parentDirs = QStringLiteral("../..");
parser.initParserArgs(parentDirs);
// note: initializing parser args reset the attached spy counter
QCOMPARE(parsingFailedSpy.count(), 1);
message = qvariant_cast<QString>(parsingFailedSpy.takeFirst().at(0));
QVERIFY(message.contains(parentDirs));
QVERIFY(message.contains(QLatin1String("is not a file")));

const auto noRead = QStringLiteral("no_r_possible");
const auto shell = QStandardPaths::findExecutable(QStringLiteral("bash"));
if (!shell.isEmpty()) {
QProcess::execute(
shell, {QLatin1String("-c"), QStringLiteral("rm -rf %1 && touch %1 && chmod a-r %1").arg(noRead)});
parser.initParserArgs(noRead);

QCOMPARE(parsingFailedSpy.count(), 1);
message = qvariant_cast<QString>(parsingFailedSpy.takeFirst().at(0));
QVERIFY(message.contains(noRead));
QVERIFY(message.contains(QLatin1String("not readable")));
}
}

void testFileContent()
{
Settings::instance()->setAppPath(
QFileInfo(QStandardPaths::findExecutable(QStringLiteral("true"))).dir().path());
Settings::instance()->setExtraLibPaths(QFINDTESTDATA("file_content"));
PerfParser parser(this);
QSignalSpy parsingFailedSpy(&parser, &PerfParser::parsingFailed);
QSignalSpy parsingFinishedSpy(&parser, &PerfParser::parsingFinished);
QString message;

// check pre-exported perfparser
const auto perfData = QFINDTESTDATA("file_content/true.perfparser");
QVERIFY(!perfData.isEmpty() && QFile::exists(perfData));
parser.startParseFile(perfData);
QVERIFY(parsingFinishedSpy.wait(2000));
QCOMPARE(parsingFailedSpy.count(), 0);
QCOMPARE(parsingFinishedSpy.count(), 1);

// check for invalid data -> expected error
const auto noPerf = QFINDTESTDATA("tst_perfparser.cpp");
QVERIFY(!noPerf.isEmpty() && QFile::exists(noPerf));
parser.startParseFile(noPerf);
QVERIFY(parsingFailedSpy.wait(1000));
QCOMPARE(parsingFailedSpy.count(), 1);
message = qvariant_cast<QString>(parsingFailedSpy.takeFirst().at(0));
QVERIFY(message.contains(QLatin1String("invalid perf data file")));

// check for PERFv1 -> expected error
const auto perf1 = QFINDTESTDATA("file_content/perf.data.true.v1");
QVERIFY(!perf1.isEmpty() && QFile::exists(perf1));
parser.startParseFile(perf1);
QVERIFY(parsingFailedSpy.wait(1000));
QCOMPARE(parsingFailedSpy.count(), 1);
message = qvariant_cast<QString>(parsingFailedSpy.takeFirst().at(0));
QVERIFY(message.contains(QLatin1String("invalid perf data file")));

// check for PERFv2
const auto perf2 = QFINDTESTDATA("file_content/perf.data.true.v2");
QVERIFY(!perf2.isEmpty() && QFile::exists(perf2));
parser.startParseFile(perf2);
QVERIFY(parsingFinishedSpy.wait(
8000)); // FIXME: this waittime and the one below must be so high as unavailable elf files are checked
// again and again via PerfSymbolTable::registerElf, as seen in the output
QCOMPARE(parsingFailedSpy.count(), 0);
QCOMPARE(parsingFinishedSpy.count(), 2);

#if KFArchive_FOUND
// check for PERFv2, gzipped
const auto perf2gz = QFINDTESTDATA("file_content/perf.data.true.v2.gz");
QVERIFY(!perf2gz.isEmpty() && QFile::exists(perf2gz));
parser.startParseFile(perf2gz);
QVERIFY(parsingFinishedSpy.wait(9000));
QCOMPARE(parsingFailedSpy.count(), 0);
QCOMPARE(parsingFinishedSpy.count(), 3);
#endif
}

void init()
{
m_bottomUpData = {};
Expand Down Expand Up @@ -743,8 +837,8 @@ private slots:

VERIFY_OR_THROW(recordingFinishedSpy.wait(10000));

COMPARE_OR_THROW(recordingFailedSpy.count(), 0);
COMPARE_OR_THROW(recordingFinishedSpy.count(), 1);
QCOMPARE(recordingFailedSpy.count(), 0);
QCOMPARE(recordingFinishedSpy.count(), 1);
COMPARE_OR_THROW(QFileInfo::exists(fileName), true);

m_perfCommand = perf.perfCommand();
Expand Down Expand Up @@ -790,25 +884,25 @@ private slots:

parser.startParseFile(fileName);

VERIFY_OR_THROW(parsingFinishedSpy.wait(6000));
QVERIFY(parsingFinishedSpy.wait(6000));

// Verify that the test passed
COMPARE_OR_THROW(parsingFailedSpy.count(), 0);
COMPARE_OR_THROW(parsingFinishedSpy.count(), 1);
QCOMPARE(parsingFailedSpy.count(), 0);
QCOMPARE(parsingFinishedSpy.count(), 1);

// Verify the summary data isn't empty
COMPARE_OR_THROW(summaryDataSpy.count(), 1);
QCOMPARE(summaryDataSpy.count(), 1);
QList<QVariant> summaryDataArgs = summaryDataSpy.takeFirst();
m_summaryData = qvariant_cast<Data::Summary>(summaryDataArgs.at(0));
COMPARE_OR_THROW(m_perfCommand, m_summaryData.command);
QCOMPARE(m_perfCommand, m_summaryData.command);
VERIFY_OR_THROW(m_summaryData.sampleCount > 0);
VERIFY_OR_THROW(m_summaryData.applicationTime.delta() > 0);
VERIFY_OR_THROW(m_summaryData.cpusAvailable > 0);
COMPARE_OR_THROW(m_summaryData.processCount, quint32(1)); // for now we always have a single process
QCOMPARE(m_summaryData.processCount, quint32(1)); // for now we always have a single process
VERIFY_OR_THROW(m_summaryData.threadCount > 0); // and at least one thread
COMPARE_OR_THROW(m_summaryData.cpuArchitecture, m_cpuArchitecture);
COMPARE_OR_THROW(m_summaryData.linuxKernelVersion, m_linuxKernelVersion);
COMPARE_OR_THROW(m_summaryData.hostName, m_machineHostName);
QCOMPARE(m_summaryData.cpuArchitecture, m_cpuArchitecture);
QCOMPARE(m_summaryData.linuxKernelVersion, m_linuxKernelVersion);
QCOMPARE(m_summaryData.hostName, m_machineHostName);

if (checkFrequency) {
// Verify the sample frequency is acceptable, greater than 500Hz
Expand Down

0 comments on commit 69ad59b

Please sign in to comment.