File indexing completed on 2024-05-19 15:45:21
0001 // SPDX-FileCopyrightText: 2022 Gleb Popov <arrowd@FreeBSD.org> 0002 // SPDX-License-Identifier: BSD-3-Clause 0003 0004 #include "test_craftruntime.h" 0005 0006 #include <QFile> 0007 #include <QProcess> 0008 #include <QStandardPaths> 0009 #include <QTest> 0010 0011 #include <KIO/CopyJob> 0012 #include <KProcess> 0013 0014 #include <tests/testcore.h> 0015 #include <tests/testhelpers.h> 0016 0017 #include "../craftruntime.h" 0018 0019 using namespace KDevelop; 0020 0021 QTEST_MAIN(CraftRuntimeTest) 0022 0023 class TempDirWrapper 0024 { 0025 public: 0026 TempDirWrapper() = default; 0027 TempDirWrapper(const QString& craftRoot, const QString& pythonExecutable) 0028 : m_tempCraftRoot(new QTemporaryDir()) 0029 { 0030 QVERIFY(m_tempCraftRoot->isValid()); 0031 copyCraftRoot(craftRoot); 0032 m_runtime = std::make_shared<CraftRuntime>(m_tempCraftRoot->path(), pythonExecutable); 0033 } 0034 0035 QString path() const 0036 { 0037 QVERIFY_RETURN(m_tempCraftRoot, QString()); 0038 return m_tempCraftRoot->path(); 0039 } 0040 0041 CraftRuntime* operator->() const 0042 { 0043 QVERIFY_RETURN(m_runtime, nullptr); 0044 return m_runtime.get(); 0045 } 0046 0047 private: 0048 void copyCraftRoot(const QString& oldRoot) const 0049 { 0050 const QLatin1String craftSettingsRelativePath("/etc/CraftSettings.ini"); 0051 const QDir dest(m_tempCraftRoot->path()); 0052 0053 auto* job = KIO::copy(QUrl::fromLocalFile(oldRoot + QLatin1String("/craft")), QUrl::fromLocalFile(dest.path())); 0054 QVERIFY(job->exec()); 0055 0056 QVERIFY(dest.mkpath(QLatin1String("bin"))); 0057 QVERIFY(dest.mkpath(QLatin1String("etc"))); 0058 0059 QVERIFY(QFile::copy(oldRoot + craftSettingsRelativePath, dest.path() + craftSettingsRelativePath)); 0060 } 0061 std::shared_ptr<CraftRuntime> m_runtime; 0062 std::shared_ptr<QTemporaryDir> m_tempCraftRoot; 0063 }; 0064 0065 Q_DECLARE_METATYPE(TempDirWrapper) 0066 0067 // When this test itself is ran under a Craft root, its environment gets in the way 0068 static void breakoutFromCraftRoot() 0069 { 0070 auto craftRoot = qgetenv("KDEROOT"); 0071 if (craftRoot.isEmpty()) 0072 return; 0073 0074 auto paths = qgetenv("PATH").split(':'); 0075 std::remove_if(paths.begin(), paths.end(), [craftRoot](const QByteArray& path) { 0076 return path.startsWith(craftRoot); 0077 }); 0078 qputenv("PATH", paths.join(':')); 0079 0080 qunsetenv("KDEROOT"); 0081 qunsetenv("craftRoot"); 0082 } 0083 0084 void CraftRuntimeTest::initTestCase_data() 0085 { 0086 breakoutFromCraftRoot(); 0087 0088 const QString pythonExecutable = CraftRuntime::findPython(); 0089 if (pythonExecutable.isEmpty()) 0090 QSKIP("No python found, skipping kdevcraft tests."); 0091 0092 QTest::addColumn<TempDirWrapper>("runtimeInstance"); 0093 0094 QTest::newRow("Mock") << TempDirWrapper(QStringLiteral(CRAFT_ROOT_MOCK), pythonExecutable); 0095 0096 auto craftRoot = CraftRuntime::findCraftRoot(Path(QStringLiteral("."))); 0097 if (!craftRoot.isEmpty()) 0098 QTest::newRow("Real") << TempDirWrapper(craftRoot, pythonExecutable); 0099 } 0100 0101 void CraftRuntimeTest::testFindCraftRoot() 0102 { 0103 QFETCH_GLOBAL(TempDirWrapper, runtimeInstance); 0104 QCOMPARE(CraftRuntime::findCraftRoot(Path(runtimeInstance.path())), runtimeInstance.path()); 0105 QCOMPARE(CraftRuntime::findCraftRoot(Path(runtimeInstance.path()).cd(QStringLiteral("bin"))), 0106 runtimeInstance.path()); 0107 } 0108 0109 void CraftRuntimeTest::testGetenv() 0110 { 0111 QFETCH_GLOBAL(TempDirWrapper, runtimeInstance); 0112 0113 QVERIFY(!runtimeInstance->getenv("KDEROOT").isEmpty()); 0114 0115 QDir craftDir1 = QDir(QString::fromLocal8Bit(runtimeInstance->getenv("KDEROOT"))); 0116 QDir craftDir2 = QDir(runtimeInstance.path()); 0117 QCOMPARE(craftDir1.canonicalPath(), craftDir2.canonicalPath()); 0118 0119 QString pythonpathValue = QString::fromLocal8Bit(runtimeInstance->getenv("PYTHONPATH")); 0120 QVERIFY(!pythonpathValue.isEmpty()); 0121 QDir craftPythonPathDir = QDir(pythonpathValue); 0122 0123 QVERIFY(craftPythonPathDir.path().startsWith(craftDir1.path())); 0124 } 0125 0126 void CraftRuntimeTest::testStartProcess() 0127 { 0128 QFETCH_GLOBAL(TempDirWrapper, runtimeInstance); 0129 0130 QString envPath = QStandardPaths::findExecutable(QStringLiteral("env")); 0131 if (envPath.isEmpty()) 0132 QSKIP("Skipping startProcess() test, no \"env\" executable found"); 0133 0134 QString envUnderCraftPath = runtimeInstance.path() + QStringLiteral("/bin/env"); 0135 QVERIFY(QFile::copy(envPath, envUnderCraftPath)); 0136 0137 QProcess p; 0138 p.setProgram(QStringLiteral("env")); 0139 runtimeInstance->startProcess(&p); 0140 0141 // test that CraftRuntime::startProcess prefers programs under Craft root 0142 QCOMPARE(QDir(p.program()).canonicalPath(), QDir(envUnderCraftPath).canonicalPath()); 0143 0144 p.waitForFinished(); 0145 QVERIFY(QFile::remove(envUnderCraftPath)); 0146 } 0147 0148 void CraftRuntimeTest::testStartProcessEnv() 0149 { 0150 QFETCH_GLOBAL(TempDirWrapper, runtimeInstance); 0151 0152 QString printenvPath = QStandardPaths::findExecutable(QStringLiteral("printenv")); 0153 if (printenvPath.isEmpty()) 0154 QSKIP("Skipping startProcess() test, no \"printenv\" executable found"); 0155 0156 QString printenvUnderCraftPath = runtimeInstance.path() + QStringLiteral("/bin/printenv"); 0157 QVERIFY(QFile::copy(printenvPath, printenvUnderCraftPath)); 0158 0159 KProcess p; 0160 p.setProgram(QStringLiteral("printenv"), QStringList{QStringLiteral("PYTHONPATH")}); 0161 p.setOutputChannelMode(KProcess::OnlyStdoutChannel); 0162 runtimeInstance->startProcess(&p); 0163 p.waitForFinished(); 0164 0165 QVERIFY(p.readAllStandardOutput().contains("site-packages")); 0166 } 0167 0168 #include "moc_test_craftruntime.cpp"