Files
qt-creator/tests/manual/deviceshell/tst_deviceshell.cpp
Jarek Kobus a27a4fc473 Process: Get rid of process launcher implementation
Change-Id: Ief42af62f07fa19667a84b92a263c0330acc2262
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
Reviewed-by: hjk <hjk@qt.io>
2024-11-01 15:16:18 +00:00

201 lines
6.2 KiB
C++

// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <app/app_version.h>
#include <utils/deviceshell.h>
#include <utils/environment.h>
#include <utils/qtcprocess.h>
#include <utils/singleton.h>
#include <utils/temporarydirectory.h>
#include <QObject>
#include <QtConcurrent>
#include <QtTest>
using namespace Utils;
class TestShell : public DeviceShell
{
public:
TestShell() { start(); }
static CommandLine cmdLine() {
static CommandLine cmd;
if (cmd.isEmpty()) {
const FilePath dockerExecutable = Environment::systemEnvironment()
.searchInPath("docker", {"/usr/local/bin"});
const FilePath dashExecutable = Environment::systemEnvironment()
.searchInPath("dash", {"/usr/local/bin"});
const FilePath bashExecutable = Environment::systemEnvironment()
.searchInPath("bash", {"/usr/local/bin"});
const FilePath shExecutable = Environment::systemEnvironment()
.searchInPath("sh", {"/usr/local/bin"});
if (dockerExecutable.exists())
cmd = {dockerExecutable, {"run", "-i", "--rm","alpine"}};
else if (dashExecutable.exists())
cmd = CommandLine{dashExecutable};
else if (bashExecutable.exists())
cmd = CommandLine{bashExecutable};
else if (shExecutable.exists())
cmd = CommandLine{shExecutable};
if (cmd.isEmpty())
return cmd;
qDebug() << "Using shell cmd:" << cmd;
}
return cmd;
}
private:
void setupShellProcess(Process *shellProcess) override
{
shellProcess->setCommand(cmdLine());
}
};
class tst_DeviceShell : public QObject
{
Q_OBJECT
QList<QByteArray> testArrays(const int numArrays)
{
QRandomGenerator generator;
QList<QByteArray> result;
for (int i = 0; i < numArrays; i++) {
QByteArray data;
auto numLines = generator.bounded(1, 100);
for (int l = 0; l < numLines; l++) {
auto numChars = generator.bounded(10, 40);
for (int c = 0; c < numChars; c++) {
data += static_cast<char>(generator.bounded('a', 'z'));
}
data += '\n';
}
result.append(data);
}
return result;
}
void test(int numCalls, int maxNumThreads)
{
TestShell shell;
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
QThreadPool::globalInstance()->setMaxThreadCount(maxNumThreads);
const QList<QByteArray> testArray = testArrays(numCalls);
QElapsedTimer t;
t.start();
const auto cat = [&shell](const QByteArray &data) {
return shell.runInShell(CommandLine{"cat"}, data).stdOut;
};
const QList<QByteArray> results = QtConcurrent::blockingMapped(testArray, cat);
QCOMPARE(results, testArray);
qDebug() << "maxThreads:" << maxNumThreads << ", took:" << t.elapsed() / 1000.0
<< "seconds";
}
void testSleep(QList<int> testData, int maxNumThreads)
{
TestShell shell;
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
QThreadPool::globalInstance()->setMaxThreadCount(maxNumThreads);
QElapsedTimer t;
t.start();
const auto sleep = [&shell](int time) {
shell.runInShell({"sleep", {QString("%1").arg(time)}});
return 0;
};
const QList<int> results = QtConcurrent::blockingMapped(testData, sleep);
QCOMPARE(results, QList<int>(testData.size(), 0));
qDebug() << "maxThreads:" << maxNumThreads << ", took:" << t.elapsed() / 1000.0
<< "seconds";
}
private slots:
void initTestCase()
{
TemporaryDirectory::setMasterTemporaryDirectory(
QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX");
if (TestShell::cmdLine().isEmpty()) {
QSKIP("Skipping deviceshell tests, as no compatible shell could be found");
}
}
void cleanupTestCase() { Singleton::deleteAll(); }
void testEncoding_data()
{
QTest::addColumn<QString>("utf8string");
QTest::newRow("japanese") << QString::fromUtf8(
u8"\xe8\xac\x9d\xe3\x81\x8d\xe3\x82\x81\xe9\x80\x80\x31\x30\xe8\x89\xaf\xe3\x81\x9a\xe3"
u8"\x82\xa4\xe3\x81\xb5\xe3\x81\x8b\xe7\x89\x88\xe8\x84\xb3\xe3\x83\xa9\xe3\x83\xaf\xe6"
u8"\xad\xa2\xe9\x80\x9a\xe3\x83\xa8\xe3\x83\xb2\xe3\x82\xad\n");
QTest::newRow("german") << QString::fromUtf8(
u8"\x48\x61\x6c\x6c\xc3\xb6\x2c\x20\x77\x69\x65\x20\x67\xc3\xa4\x68\x74\x20\x65\x73\x20"
u8"\x64\xc3\xbc\x72\n");
}
void testEncoding()
{
QFETCH(QString, utf8string);
TestShell shell;
QCOMPARE(shell.state(), DeviceShell::State::Succeeded);
const RunResult r = shell.runInShell(CommandLine{"cat"}, utf8string.toUtf8());
const QString output = QString::fromUtf8(r.stdOut);
QCOMPARE(output, utf8string);
}
void testThreading_data()
{
QTest::addColumn<int>("numThreads");
QTest::addColumn<int>("numIterations");
QTest::newRow("multi-threaded") << 10 << 1000;
QTest::newRow("single-threaded") << 1 << 1000;
}
void testThreading()
{
QFETCH(int, numThreads);
QFETCH(int, numIterations);
test(numIterations, numThreads);
}
void testSleepMulti()
{
QList<int> testData{4, 7, 10, 3, 1, 10, 3, 3, 5, 4};
int full = std::accumulate(testData.begin(), testData.end(), 0);
qDebug() << "Testing sleep, full time is:" << full << "seconds";
QElapsedTimer t;
t.start();
testSleep(testData, 10);
const int multiThreadRunTime = t.restart();
testSleep(testData, 1);
const int singleThreadRunTime = t.elapsed();
QVERIFY(multiThreadRunTime < singleThreadRunTime);
}
};
QTEST_GUILESS_MAIN(tst_DeviceShell)
#include "tst_deviceshell.moc"