File indexing completed on 2025-01-12 12:29:22
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #include "commandlauncherjobtest.h" 0009 #include "commandlauncherjob.h" 0010 0011 #include "kiotesthelper.h" // createTestFile etc. 0012 0013 #include <QStandardPaths> 0014 #include <QTemporaryDir> 0015 #include <QTest> 0016 #include <kprocessrunner_p.h> 0017 0018 QTEST_GUILESS_MAIN(CommandLauncherJobTest) 0019 0020 void CommandLauncherJobTest::initTestCase() 0021 { 0022 QStandardPaths::setTestModeEnabled(true); 0023 } 0024 0025 static void createSrcFile(const QString path) 0026 { 0027 QFile srcFile(path); 0028 QVERIFY2(srcFile.open(QFile::WriteOnly), qPrintable(srcFile.errorString())); 0029 QVERIFY(srcFile.write("Hello world\n") > 0); 0030 } 0031 0032 void CommandLauncherJobTest::startProcessAsCommand_data() 0033 { 0034 QTest::addColumn<bool>("useExec"); 0035 0036 QTest::newRow("exec") << true; 0037 QTest::newRow("waitForStarted") << false; 0038 } 0039 0040 void CommandLauncherJobTest::startProcessAsCommand() 0041 { 0042 QFETCH(bool, useExec); 0043 0044 // Given a command 0045 QTemporaryDir tempDir; 0046 const QString srcDir = tempDir.path(); 0047 const QString srcFile = srcDir + "/srcfile"; 0048 createSrcFile(srcFile); 0049 QVERIFY(QFile::exists(srcFile)); 0050 0051 #ifdef Q_OS_WIN 0052 QString command = "copy.exe"; 0053 #else 0054 QString command = "cp"; 0055 #endif 0056 0057 command += QStringLiteral(" %1 destfile").arg(srcFile); 0058 0059 // When running a CommandLauncherJob 0060 KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(command, this); 0061 job->setWorkingDirectory(srcDir); 0062 if (useExec) { 0063 QVERIFY(job->exec()); 0064 } else { 0065 job->start(); 0066 QVERIFY(job->waitForStarted()); 0067 } 0068 const qint64 pid = job->pid(); 0069 0070 // Then the service should be executed (which copies the source file to "dest") 0071 QVERIFY(pid != 0); 0072 const QString dest = srcDir + "/destfile"; 0073 QTRY_VERIFY2(QFile::exists(dest), qPrintable(dest)); 0074 QVERIFY(QFile::remove(srcFile)); // cleanup 0075 QVERIFY(QFile::remove(dest)); 0076 0077 // Just to make sure 0078 QTRY_COMPARE(KProcessRunner::instanceCount(), 0); 0079 } 0080 0081 void CommandLauncherJobTest::startProcessWithArgs_data() 0082 { 0083 QTest::addColumn<QString>("srcName"); 0084 QTest::addColumn<QString>("destName"); 0085 0086 QTest::newRow("path without spaces") << QStringLiteral("srcfile") << QStringLiteral("destfile"); 0087 QTest::newRow("path with spaces") << QStringLiteral("Source File") << QStringLiteral("Destination File"); 0088 } 0089 0090 void CommandLauncherJobTest::startProcessWithArgs() 0091 { 0092 QFETCH(QString, srcName); 0093 QFETCH(QString, destName); 0094 0095 QTemporaryDir tempDir; 0096 const QString srcDir = tempDir.path(); 0097 const QString srcPath = srcDir + '/' + srcName; 0098 const QString destPath = srcDir + '/' + destName; 0099 0100 createSrcFile(srcPath); 0101 QVERIFY(QFileInfo::exists(srcPath)); 0102 0103 #ifdef Q_OS_WIN 0104 const QString executable = "copy.exe"; 0105 #else 0106 const QString executable = "cp"; 0107 #endif 0108 0109 auto *job = new KIO::CommandLauncherJob(executable, {srcPath, destName}, this); 0110 job->setWorkingDirectory(srcDir); 0111 0112 job->start(); 0113 QVERIFY(job->waitForStarted()); 0114 0115 const qint64 pid = job->pid(); 0116 0117 // Then the service should be executed (which copies the source file to "dest") 0118 QVERIFY(pid != 0); 0119 QTRY_VERIFY2(QFileInfo::exists(destPath), qPrintable(destPath)); 0120 QVERIFY(QFile::remove(srcPath)); 0121 QVERIFY(QFile::remove(destPath)); // cleanup 0122 0123 // Just to make sure 0124 QTRY_COMPARE(KProcessRunner::instanceCount(), 0); 0125 } 0126 0127 void CommandLauncherJobTest::startProcessWithSpacesInExecutablePath_data() 0128 { 0129 QTest::addColumn<QString>("srcName"); 0130 QTest::addColumn<QString>("destName"); 0131 0132 QTest::newRow("path without spaces") << QStringLiteral("srcfile") << QStringLiteral("destfile"); 0133 QTest::newRow("path with spaces") << QStringLiteral("Source File") << QStringLiteral("Destination File"); 0134 } 0135 0136 void CommandLauncherJobTest::startProcessWithSpacesInExecutablePath() 0137 { 0138 QFETCH(QString, srcName); 0139 QFETCH(QString, destName); 0140 0141 QTemporaryDir tempDir; 0142 0143 const QString srcDir = tempDir.filePath("folder with spaces"); 0144 QVERIFY(QDir().mkpath(srcDir)); 0145 0146 const QString srcPath = srcDir + '/' + srcName; 0147 const QString destPath = srcDir + '/' + destName; 0148 0149 createSrcFile(srcPath); 0150 QVERIFY(QFileInfo::exists(srcPath)); 0151 0152 // Copy the executable into the folder with spaces in its path 0153 #ifdef Q_OS_WIN 0154 const QString executableName = "copy"; // QStandardPaths appends extension as necessary 0155 #else 0156 const QString executableName = "cp"; 0157 #endif 0158 0159 const QString executablePath = QStandardPaths::findExecutable(executableName); 0160 QVERIFY(!executablePath.isEmpty()); 0161 QFileInfo fi(executablePath); 0162 // Needed since it could be .exe or .bat on Windows 0163 const QString executableFileName = fi.fileName(); 0164 0165 const QString executable = srcDir + '/' + executableFileName; 0166 QVERIFY(QFile::copy(executablePath, executable)); 0167 0168 auto *job = new KIO::CommandLauncherJob(executable, {srcPath, destName}, this); 0169 job->setWorkingDirectory(srcDir); 0170 0171 job->start(); 0172 QVERIFY(job->waitForStarted()); 0173 0174 const qint64 pid = job->pid(); 0175 0176 // Then the service should be executed (which copies the source file to "dest") 0177 QVERIFY(pid != 0); 0178 QTRY_VERIFY2(QFileInfo::exists(destPath), qPrintable(destPath)); 0179 0180 // cleanup 0181 QVERIFY(QFile::remove(destPath)); 0182 QVERIFY(QFile::remove(srcPath)); 0183 QVERIFY(QFile::remove(executable)); 0184 0185 // Just to make sure 0186 QTRY_COMPARE(KProcessRunner::instanceCount(), 0); 0187 } 0188 0189 void CommandLauncherJobTest::startProcessWithEnvironmentVariables() 0190 { 0191 // Given an env var and a command that uses it 0192 QProcessEnvironment env; 0193 env.insert("MYVAR", "myvalue"); 0194 #ifdef Q_OS_WIN 0195 const QString command = "echo myvar=%MYVAR% > destfile"; 0196 #else 0197 const QString command = "echo myvar=$MYVAR > destfile"; 0198 #endif 0199 QTemporaryDir tempDir; 0200 const QString srcDir = tempDir.path(); 0201 const QString srcFile = srcDir + "/srcfile"; 0202 createSrcFile(srcFile); 0203 0204 // When running a CommandLauncherJob 0205 KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(command, this); 0206 job->setWorkingDirectory(srcDir); 0207 job->setProcessEnvironment(env); 0208 QVERIFY(job->exec()); 0209 0210 // Then the env var was visible 0211 QFile destFile(srcDir + "/destfile"); 0212 QTRY_VERIFY(QFileInfo(destFile).size() > 0); 0213 QVERIFY(destFile.open(QIODevice::ReadOnly)); 0214 const QByteArray data = destFile.readAll().trimmed(); 0215 QCOMPARE(data, "myvar=myvalue"); 0216 } 0217 0218 void CommandLauncherJobTest::doesNotFailOnNonExistingExecutable() 0219 { 0220 // Given a command that uses an executable that doesn't exist 0221 const QString command = "does_not_exist foo bar"; 0222 0223 // When running a CommandLauncherJob 0224 KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(command, this); 0225 job->setExecutable("really_does_not_exist"); 0226 0227 // Then it doesn't actually fail. QProcess is starting /bin/sh, which works... 0228 QVERIFY(job->exec()); 0229 0230 // Wait for KProcessRunner to be deleted 0231 QTRY_COMPARE(KProcessRunner::instanceCount(), 0); 0232 } 0233 0234 void CommandLauncherJobTest::shouldDoNothingOnEmptyCommand() 0235 { 0236 // When running an empty command 0237 KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(QString(), this); 0238 0239 // THEN it should do nothing 0240 // at least not crash (old bug 186036) 0241 QVERIFY(job->exec()); 0242 0243 // Wait for KProcessRunner to be deleted 0244 QTRY_COMPARE(KProcessRunner::instanceCount(), 0); 0245 } 0246 0247 #include "moc_commandlauncherjobtest.cpp"