diff options
author | Marcus Tillmanns <marcus.tillmanns@qt.io> | 2022-06-28 09:26:06 +0200 |
---|---|---|
committer | Marcus Tillmanns <marcus.tillmanns@qt.io> | 2022-06-29 07:28:46 +0000 |
commit | 39580871241c77303c43204da8bd1c666a2140e0 (patch) | |
tree | 68f3e2d4c96144750a928cc9b704a0738718d486 /tests | |
parent | 8130d895c820bff633884536c4955751a2b107f4 (diff) | |
download | qt-creator-39580871241c77303c43204da8bd1c666a2140e0.tar.gz |
deviceshell: fix hang on multithreaded access
When outputting a commands stdout / stderr / exitcode,
the shell was free to interlace different outputs.
This could trip the parsing of the output, leading
to the shell missing the exit code of a command.
When that happened, the caller might wait indefinitely
for a result that would never come.
To workaround, the shell script now writes each command output
to a temporary file first, which is then written to stdout
by a single subshell, that way guaranteeing that the output
of multiple commands will not interleave
Change-Id: I9d8e7e788f5922c612ff533e5ba063f61a22aa8c
Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/utils/deviceshell/tst_deviceshell.cpp | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/tests/auto/utils/deviceshell/tst_deviceshell.cpp b/tests/auto/utils/deviceshell/tst_deviceshell.cpp index 983c2d35ce..2c209b94a1 100644 --- a/tests/auto/utils/deviceshell/tst_deviceshell.cpp +++ b/tests/auto/utils/deviceshell/tst_deviceshell.cpp @@ -29,6 +29,7 @@ #include <utils/environment.h> #include <utils/hostosinfo.h> #include <utils/launcherinterface.h> +#include <utils/mapreduce.h> #include <utils/qtcprocess.h> #include <utils/runextensions.h> #include <utils/temporarydirectory.h> @@ -287,6 +288,63 @@ private slots: const DeviceShell::RunResult result2 = shell.outputForRunInShell( {"cat", {"/tmp/i-do-not-exist.none"}}); QVERIFY(!result2.stdErr.isEmpty()); + QVERIFY(result2.exitCode != 0); + } + + void testNoCommand_data() + { + QTest::addColumn<CommandLine>("cmdLine"); + for (const auto &cmdLine : m_availableShells) { + QTest::newRow(cmdLine.executable().baseName().toUtf8()) << cmdLine; + } + } + + void testNoCommand() + { + QFETCH(CommandLine, cmdLine); + + if (cmdLine.executable().toString().contains("docker") && !m_dockerSetupCheckOk) { + QSKIP("Docker was found, but does not seem to be set up correctly, skipping."); + } + + TestShell shell(cmdLine); + QCOMPARE(shell.state(), DeviceShell::State::Succeeded); + + const DeviceShell::RunResult result = shell.outputForRunInShell({}, {}); + + QVERIFY(result.exitCode == 255); + } + + void testMultiThreadedFind_data() + { + QTest::addColumn<CommandLine>("cmdLine"); + for (const auto &cmdLine : m_availableShells) { + QTest::newRow(cmdLine.executable().baseName().toUtf8()) << cmdLine; + } + } + + void testMultiThreadedFind() + { + QFETCH(CommandLine, cmdLine); + + if (cmdLine.executable().toString().contains("docker") && !m_dockerSetupCheckOk) { + QSKIP("Docker was found, but does not seem to be set up correctly, skipping."); + } + + TestShell shell(cmdLine); + QCOMPARE(shell.state(), DeviceShell::State::Succeeded); + + QList<int> runs{1,2,3,4,5,6,7,8,9}; + + QList<QByteArray> results = Utils::mapped<QList>(runs, [&shell](const int i) -> QByteArray{ + QElapsedTimer t; + t.start(); + DeviceShell::RunResult result = shell.outputForRunInShell({"find", {"/usr", "-maxdepth", "4"}}); + qDebug() << i << "took" << t.elapsed() << "ms"; + return result.stdOut; + }); + + QVERIFY (!Utils::anyOf(results, [&results](const QByteArray r){ return r != results[0]; })); } }; |