QtcProcess: Add a test for various quit methods

The quitBlockingProcess() test examines different types
of process quitting and illustrates differences in
behavior.

Change-Id: I9209f00576e03eef66fbdf5665351138ed437ac9
Reviewed-by: hjk <hjk@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Jarek Kobus
2022-06-03 11:12:29 +02:00
parent b4b779d641
commit f051ed3076
3 changed files with 96 additions and 9 deletions

View File

@@ -180,7 +180,7 @@ int ProcessTestApp::ChannelForwarding::main()
return 0; return 0;
} }
int ProcessTestApp::KillBlockingProcess::main() int ProcessTestApp::BlockingProcess::main()
{ {
std::cout << "Blocking process successfully executed." << std::endl; std::cout << "Blocking process successfully executed." << std::endl;
const BlockType blockType = BlockType(qEnvironmentVariableIntValue(envVar())); const BlockType blockType = BlockType(qEnvironmentVariableIntValue(envVar()));
@@ -261,7 +261,8 @@ int ProcessTestApp::RecursiveBlockingProcess::main()
if (currentDepth == 1) { if (currentDepth == 1) {
std::cout << s_leafProcessStarted << std::flush; std::cout << s_leafProcessStarted << std::flush;
while (true) { while (true) {
QThread::sleep(1); // TODO: make it configurable so that we could test the reaper timeout
QThread::msleep(100);
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
if (s_terminate.load()) { if (s_terminate.load()) {
std::cout << s_leafProcessTerminated << std::flush; std::cout << s_leafProcessTerminated << std::flush;

View File

@@ -71,7 +71,7 @@ public:
SUB_PROCESS(LineCallback); SUB_PROCESS(LineCallback);
SUB_PROCESS(StandardOutputAndErrorWriter); SUB_PROCESS(StandardOutputAndErrorWriter);
SUB_PROCESS(ChannelForwarding); SUB_PROCESS(ChannelForwarding);
SUB_PROCESS(KillBlockingProcess); SUB_PROCESS(BlockingProcess);
SUB_PROCESS(EmitOneErrorOnCrash); SUB_PROCESS(EmitOneErrorOnCrash);
SUB_PROCESS(CrashAfterOneSecond); SUB_PROCESS(CrashAfterOneSecond);
SUB_PROCESS(RecursiveCrashingProcess); SUB_PROCESS(RecursiveCrashingProcess);

View File

@@ -106,6 +106,9 @@ private:
QHash<QString, QString> m_map; QHash<QString, QString> m_map;
}; };
static constexpr char s_skipTerminateOnWindows[] =
"Windows implementation of this test is lacking handling of WM_CLOSE message.";
class tst_QtcProcess : public QObject class tst_QtcProcess : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -138,13 +141,15 @@ private slots:
void channelForwarding(); void channelForwarding();
void mergedChannels_data(); void mergedChannels_data();
void mergedChannels(); void mergedChannels();
void killBlockingProcess_data(); void destroyBlockingProcess_data();
void killBlockingProcess(); void destroyBlockingProcess();
void flushFinishedWhileWaitingForReadyRead(); void flushFinishedWhileWaitingForReadyRead();
void emitOneErrorOnCrash(); void emitOneErrorOnCrash();
void crashAfterOneSecond(); void crashAfterOneSecond();
void recursiveCrashingProcess(); void recursiveCrashingProcess();
void recursiveBlockingProcess(); void recursiveBlockingProcess();
void quitBlockingProcess_data();
void quitBlockingProcess();
void cleanupTestCase(); void cleanupTestCase();
@@ -1124,7 +1129,7 @@ void tst_QtcProcess::mergedChannels()
QCOMPARE(error.contains(QByteArray(s_errorData)), errorOnError); QCOMPARE(error.contains(QByteArray(s_errorData)), errorOnError);
} }
void tst_QtcProcess::killBlockingProcess_data() void tst_QtcProcess::destroyBlockingProcess_data()
{ {
QTest::addColumn<BlockType>("blockType"); QTest::addColumn<BlockType>("blockType");
@@ -1134,11 +1139,11 @@ void tst_QtcProcess::killBlockingProcess_data()
QTest::newRow("EventLoop") << BlockType::EventLoop; QTest::newRow("EventLoop") << BlockType::EventLoop;
} }
void tst_QtcProcess::killBlockingProcess() void tst_QtcProcess::destroyBlockingProcess()
{ {
QFETCH(BlockType, blockType); QFETCH(BlockType, blockType);
SubProcessConfig subConfig(ProcessTestApp::KillBlockingProcess::envVar(), SubProcessConfig subConfig(ProcessTestApp::BlockingProcess::envVar(),
QString::number(int(blockType))); QString::number(int(blockType)));
QtcProcess process; QtcProcess process;
@@ -1239,7 +1244,7 @@ static int runningTestProcessCount()
void tst_QtcProcess::recursiveBlockingProcess() void tst_QtcProcess::recursiveBlockingProcess()
{ {
if (HostOsInfo::isWindowsHost()) if (HostOsInfo::isWindowsHost())
QSKIP("Windows implementation of this test is lacking handling of WM_CLOSE message."); QSKIP(s_skipTerminateOnWindows);
Singleton::deleteAll(); Singleton::deleteAll();
QCOMPARE(runningTestProcessCount(), 0); QCOMPARE(runningTestProcessCount(), 0);
@@ -1266,6 +1271,87 @@ void tst_QtcProcess::recursiveBlockingProcess()
QCOMPARE(runningTestProcessCount(), 0); QCOMPARE(runningTestProcessCount(), 0);
} }
enum class QuitType {
Terminate,
Kill,
Stop,
Close
};
Q_DECLARE_METATYPE(QuitType)
void tst_QtcProcess::quitBlockingProcess_data()
{
QTest::addColumn<QuitType>("quitType");
QTest::addColumn<bool>("doneExpected");
QTest::addColumn<bool>("gracefulQuit");
QTest::newRow("Terminate") << QuitType::Terminate << true << true;
QTest::newRow("Kill") << QuitType::Kill << true << false;
QTest::newRow("Stop") << QuitType::Stop << true << true;
QTest::newRow("Close") << QuitType::Close << false << true;
}
void tst_QtcProcess::quitBlockingProcess()
{
QFETCH(QuitType, quitType);
QFETCH(bool, doneExpected);
QFETCH(bool, gracefulQuit);
if (HostOsInfo::isWindowsHost() && quitType == QuitType::Terminate)
QSKIP(s_skipTerminateOnWindows);
const int recursionDepth = 1;
SubProcessConfig subConfig(ProcessTestApp::RecursiveBlockingProcess::envVar(),
QString::number(recursionDepth));
QtcProcess process;
subConfig.setupSubProcess(&process);
bool done = false;
connect(&process, &QtcProcess::done, this, [&done] { done = true; });
process.start();
QVERIFY(process.waitForStarted());
QVERIFY(!done);
QVERIFY(process.isRunning());
QVERIFY(process.waitForReadyRead(1000));
QCOMPARE(process.readAllStandardOutput(), s_leafProcessStarted);
switch (quitType) {
case QuitType::Terminate: process.terminate(); break;
case QuitType::Kill: process.kill(); break;
case QuitType::Stop: process.stop(); break;
case QuitType::Close: process.close(); break;
}
QVERIFY(!done);
if (doneExpected) {
QVERIFY(process.isRunning());
QVERIFY(process.waitForFinished());
QVERIFY(!process.isRunning());
QVERIFY(done);
if (gracefulQuit) {
if (HostOsInfo::isWindowsHost())
QSKIP(s_skipTerminateOnWindows);
QCOMPARE(process.readAllStandardOutput(), s_leafProcessTerminated);
QCOMPARE(process.exitStatus(), QProcess::NormalExit);
QCOMPARE(process.exitCode(), s_crashCode);
} else {
QCOMPARE(process.readAllStandardOutput(), QByteArray());
QCOMPARE(process.exitStatus(), QProcess::CrashExit);
QVERIFY(process.exitCode() != s_crashCode);
}
} else {
QVERIFY(!process.isRunning());
}
}
QTEST_MAIN(tst_QtcProcess) QTEST_MAIN(tst_QtcProcess)
#include "tst_qtcprocess.moc" #include "tst_qtcprocess.moc"