File indexing completed on 2024-04-21 15:02:37

0001 /*
0002     SPDX-FileCopyrightText: 2007 Bertjan Broeksema <b.broeksema@kdemail.net>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "plasmoidpackagetest.h"
0008 #include "../src/kpackage/config-package.h"
0009 #include "../src/kpackage/private/versionparser.cpp"
0010 
0011 #include <KJob>
0012 #include <QDir>
0013 #include <QFile>
0014 #include <QSignalSpy>
0015 #include <QStandardPaths>
0016 #include <kzip.h>
0017 
0018 #include <QDebug>
0019 #include <QJsonDocument>
0020 #include <QJsonObject>
0021 
0022 #include "packageloader.h"
0023 #include "packagestructures/plasmoidstructure.h"
0024 #include "private/utils.h"
0025 
0026 void PlasmoidPackageTest::initTestCase()
0027 {
0028     QStandardPaths::setTestModeEnabled(true);
0029 }
0030 
0031 void PlasmoidPackageTest::init()
0032 {
0033     qDebug() << "PlasmoidPackage::init()";
0034     m_package = QStringLiteral("Package");
0035     m_packageRoot = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/packageRoot";
0036     m_defaultPackage = KPackage::Package(new KPackage::PlasmoidPackage);
0037     cleanup(); // to prevent previous runs from interfering with this one
0038 }
0039 
0040 void PlasmoidPackageTest::cleanup()
0041 {
0042     qDebug() << "cleaning up";
0043     // Clean things up.
0044     QDir(m_packageRoot).removeRecursively();
0045 }
0046 
0047 void PlasmoidPackageTest::createTestPackage(const QString &packageName, const QString &version)
0048 {
0049     qDebug() << "Create test package" << m_packageRoot;
0050     QDir pRoot(m_packageRoot);
0051     // Create the root and package dir.
0052     if (!pRoot.exists()) {
0053         QVERIFY(QDir().mkpath(m_packageRoot));
0054     }
0055 
0056     // Create the package dir
0057     QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName));
0058     qDebug() << "Created" << (m_packageRoot + "/" + packageName);
0059 
0060     // Create the metadata.json file
0061     QFile file(m_packageRoot + "/" + packageName + "/metadata.json");
0062 
0063     QVERIFY(file.open(QIODevice::WriteOnly));
0064 
0065     QJsonObject kplugin;
0066     kplugin.insert(QLatin1String("Id"), packageName);
0067     kplugin.insert(QLatin1String("Name"), packageName);
0068     kplugin.insert(QLatin1String("Version"), version);
0069     QJsonObject root{{QLatin1String("KPlugin"), kplugin}};
0070 
0071     QTextStream out(&file);
0072     file.write(QJsonDocument(root).toJson());
0073     file.flush();
0074     file.close();
0075 
0076     qDebug() << "OUT: " << packageName;
0077 
0078     // Create the ui dir.
0079     QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName + "/contents/ui"));
0080 
0081     // Create the main file.
0082     file.setFileName(m_packageRoot + "/" + packageName + "/contents/ui/main.qml");
0083     QVERIFY(file.open(QIODevice::WriteOnly));
0084 
0085     out << "THIS IS A PLASMOID SCRIPT.....";
0086     file.flush();
0087     file.close();
0088 
0089     qDebug() << "THIS IS A PLASMOID SCRIPT THING";
0090     // Now we have a minimal plasmoid package which is valid. Let's add some
0091     // files to it for test purposes.
0092 
0093     // Create the images dir.
0094     QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName + "/contents/images"));
0095     file.setFileName(m_packageRoot + "/" + packageName + "/contents/images/image-1.svg");
0096 
0097     QVERIFY(file.open(QIODevice::WriteOnly));
0098 
0099     out << "<svg>This is a test image</svg>";
0100     file.flush();
0101     file.close();
0102 
0103     file.setFileName(m_packageRoot + "/" + packageName + "/contents/images/image-2.svg");
0104 
0105     QVERIFY(file.open(QIODevice::WriteOnly));
0106 
0107     out.setDevice(&file);
0108     out << "<svg>This is another test image</svg>";
0109     file.flush();
0110     file.close();
0111 
0112     // Create the scripts dir.
0113     QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName + "/contents/code"));
0114 
0115     // Create 2 js files
0116     file.setFileName(m_packageRoot + "/" + packageName + "/contents/code/script.js");
0117     QVERIFY(file.open(QIODevice::WriteOnly));
0118 
0119     out << "THIS IS A SCRIPT.....";
0120     file.flush();
0121     file.close();
0122 }
0123 
0124 void PlasmoidPackageTest::isValid()
0125 {
0126     KPackage::Package *p = new KPackage::Package(m_defaultPackage);
0127     p->setPath(m_packageRoot + '/' + m_package);
0128 #ifndef NDEBUG
0129     qDebug() << "package path is" << p->path();
0130 #endif
0131 
0132     // A PlasmoidPackage is valid when:
0133     // - The package root exists.
0134     // - The package root consists an file named "ui/main.qml"
0135     QVERIFY(!p->isValid());
0136 
0137     // Create the root and package dir.
0138     QVERIFY(QDir().mkpath(m_packageRoot));
0139     QVERIFY(QDir().mkpath(m_packageRoot + "/" + m_package));
0140 
0141     // Should still be invalid.
0142     delete p;
0143     p = new KPackage::Package(m_defaultPackage);
0144     p->setPath(m_packageRoot + '/' + m_package);
0145     QVERIFY(!p->isValid());
0146 
0147     // Create the metadata.json file.
0148     QFile file(m_packageRoot + "/" + m_package + "/metadata.json");
0149     QVERIFY(file.open(QIODevice::WriteOnly));
0150 
0151     QTextStream out(&file);
0152     out << "[Desktop Entry]\n";
0153     out << "Name=test\n";
0154     out << "Description=Just a test desktop file";
0155     file.flush();
0156     file.close();
0157 
0158     // Create the ui dir.
0159     QVERIFY(QDir().mkpath(m_packageRoot + "/" + m_package + "/contents/ui"));
0160 
0161     // No main file yet so should still be invalid.
0162     delete p;
0163     p = new KPackage::Package(m_defaultPackage);
0164     p->setPath(m_packageRoot + '/' + m_package);
0165     QVERIFY(!p->isValid());
0166 
0167     // Create the main file.
0168     file.setFileName(m_packageRoot + "/" + m_package + "/contents/ui/main.qml");
0169     QVERIFY(file.open(QIODevice::WriteOnly));
0170 
0171     out.setDevice(&file);
0172     out << "THIS IS A PLASMOID SCRIPT.....\n";
0173     file.flush();
0174     file.close();
0175 
0176     file.setPermissions(QFile::ReadUser | QFile::WriteUser);
0177     // Main file exists so should be valid now.
0178     delete p;
0179     p = new KPackage::Package(m_defaultPackage);
0180     p->setPath(m_packageRoot + '/' + m_package);
0181     QVERIFY(p->isValid());
0182 #if KPACKAGE_ENABLE_DEPRECATED_SINCE(5, 21)
0183     QCOMPARE(p->contentsHash(), QStringLiteral("a41160c6a763ea505c95bee12a7fc87952a61cf1"));
0184 #endif
0185     QCOMPARE(p->cryptographicHash(QCryptographicHash::Sha1), QByteArrayLiteral("a41160c6a763ea505c95bee12a7fc87952a61cf1"));
0186     delete p;
0187 }
0188 
0189 void PlasmoidPackageTest::filePath()
0190 {
0191     return;
0192     // Package::filePath() returns
0193     // - {package_root}/{package_name}/path/to/file if the file exists
0194     // - QString() otherwise.
0195     KPackage::Package *p = new KPackage::Package(m_defaultPackage);
0196     p->setPath(m_packageRoot + '/' + m_package);
0197 
0198     QCOMPARE(p->filePath("scripts", QStringLiteral("main")), QString());
0199 
0200     QVERIFY(QDir().mkpath(m_packageRoot + "/" + m_package + "/contents/ui/main.qml"));
0201     QFile file(m_packageRoot + "/" + m_package + "/contents/ui/main.qml");
0202     QVERIFY(file.open(QIODevice::WriteOnly));
0203 
0204     QTextStream out(&file);
0205     out << "THIS IS A PLASMOID SCRIPT.....";
0206     file.flush();
0207     file.close();
0208 
0209     // The package is valid by now so a path for code/main should get returned.
0210     delete p;
0211     p = new KPackage::Package(m_defaultPackage);
0212     p->setPath(m_packageRoot + '/' + m_package);
0213 
0214     const QString path = QFileInfo(m_packageRoot + "/" + m_package + "/contents/ui/main.qml").canonicalFilePath();
0215 
0216     // Two ways to get the same info.
0217     // 1. Give the file type which refers to a class of files (a directory) in
0218     //    the package structure and the file name.
0219     // 2. Give the file type which refers to a file in the package structure.
0220     //
0221     // NOTE: scripts, main and mainscript are defined in packages.cpp and are
0222     //       specific for a PlasmoidPackage.
0223     QCOMPARE(p->filePath("scripts", QStringLiteral("main")), path);
0224     QCOMPARE(p->filePath("mainscript"), path);
0225     delete p;
0226 }
0227 
0228 void PlasmoidPackageTest::entryList()
0229 {
0230     // Create a package named @p packageName which is valid and has some images.
0231     createTestPackage(m_package, QStringLiteral("1.1"));
0232 
0233     // Create a package object and verify that it is valid.
0234     KPackage::Package *p = new KPackage::Package(m_defaultPackage);
0235     p->setPath(m_packageRoot + '/' + m_package);
0236     QVERIFY(p->isValid());
0237 
0238     // Now we have a valid package that should contain the following files in
0239     // given filetypes:
0240     // fileTye - Files
0241     // scripts - {"script.js"}
0242     // images - {"image-1.svg", "image-2.svg"}
0243     QStringList files = p->entryList("scripts");
0244     QCOMPARE(files.size(), 1);
0245     QVERIFY(files.contains(QStringLiteral("script.js")));
0246 
0247     files = p->entryList("images");
0248     QCOMPARE(files.size(), 2);
0249     QVERIFY(files.contains(QStringLiteral("image-1.svg")));
0250     QVERIFY(files.contains(QStringLiteral("image-2.svg")));
0251     delete p;
0252 }
0253 
0254 void PlasmoidPackageTest::createAndInstallPackage()
0255 {
0256     qDebug() << "                   ";
0257     qDebug() << "   CreateAndInstall ";
0258     createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.1"));
0259     const QString packagePath = m_packageRoot + '/' + "testpackage.plasmoid";
0260 
0261     KZip creator(packagePath);
0262     QVERIFY(creator.open(QIODevice::WriteOnly));
0263     creator.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
0264     creator.close();
0265     QDir rootDir(m_packageRoot + "/plasmoid_to_package");
0266     rootDir.removeRecursively();
0267 
0268     QVERIFY2(QFile::exists(packagePath), qPrintable(packagePath));
0269 
0270     KZip package(packagePath);
0271     QVERIFY(package.open(QIODevice::ReadOnly));
0272     const KArchiveDirectory *dir = package.directory();
0273     QVERIFY(dir); //
0274     QVERIFY(dir->entry(QStringLiteral("metadata.json")));
0275     const KArchiveEntry *contentsEntry = dir->entry(QStringLiteral("contents"));
0276     QVERIFY(contentsEntry);
0277     QVERIFY(contentsEntry->isDirectory());
0278     const KArchiveDirectory *contents = static_cast<const KArchiveDirectory *>(contentsEntry);
0279     QVERIFY(contents->entry(QStringLiteral("ui")));
0280     QVERIFY(contents->entry(QStringLiteral("images")));
0281 
0282     m_defaultPackageStructure = new KPackage::PackageStructure(this);
0283     KPackage::Package *p = new KPackage::Package(m_defaultPackageStructure);
0284     qDebug() << "Installing " << packagePath;
0285     // const QString packageRoot = "plasma/plasmoids/";
0286     // const QString servicePrefix = "plasma-applet-";
0287     KJob *job = p->install(packagePath, m_packageRoot);
0288     // clang-format off
0289     connect(job, SIGNAL(finished(KJob*)), SLOT(packageInstalled(KJob*)));
0290     QSignalSpy spy(job, SIGNAL(finished(KJob*)));
0291     // clang-format on
0292     QVERIFY(spy.wait(1000));
0293 
0294     // is the package instance usable (ie proper path) after the install job has been completed?
0295     QCOMPARE(p->path(), QString(QDir(m_packageRoot % "/plasmoid_to_package").canonicalPath() + QLatin1Char('/')));
0296     cleanupPackage(QStringLiteral("plasmoid_to_package"));
0297 
0298     // QVERIFY(p->isValid());
0299     delete p;
0300 }
0301 
0302 void PlasmoidPackageTest::noCrashOnAsyncInstall()
0303 {
0304     createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.1"));
0305     const QString packagePath = m_packageRoot + '/' + "testpackage.plasmoid";
0306 
0307     KZip creator(packagePath);
0308     QVERIFY(creator.open(QIODevice::WriteOnly));
0309     creator.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
0310     creator.close();
0311     QDir rootDir(m_packageRoot + "/plasmoid_to_package");
0312     rootDir.removeRecursively();
0313 
0314     KJob *job;
0315     // scope the package so it will get deleted before the install operation finishes
0316     // package is explicitlyshared internally and designed to be used on the stack
0317     // see #370718
0318     {
0319         KPackage::Package package(new KPackage::PackageStructure(this));
0320         job = package.install(packagePath, m_packageRoot);
0321     }
0322     // clang-format off
0323     connect(job, SIGNAL(finished(KJob*)), SLOT(packageInstalled(KJob*)));
0324     QSignalSpy spy(job, SIGNAL(finished(KJob*)));
0325     // clang-format on
0326     QVERIFY(spy.wait(1000));
0327 
0328     cleanupPackage(QStringLiteral("plasmoid_to_package"));
0329 }
0330 
0331 void PlasmoidPackageTest::createAndUpdatePackage()
0332 {
0333     // does the version number parsing work?
0334     QVERIFY(KPackage::isVersionNewer(QStringLiteral("1.1"), QStringLiteral("1.1.1")));
0335     QVERIFY(!KPackage::isVersionNewer(QStringLiteral("1.1.1"), QStringLiteral("1.1")));
0336     QVERIFY(KPackage::isVersionNewer(QStringLiteral("1.1.1"), QStringLiteral("1.1.2")));
0337     QVERIFY(KPackage::isVersionNewer(QStringLiteral("1.1.2"), QStringLiteral("2.1")));
0338     QVERIFY(KPackage::isVersionNewer(QStringLiteral("0.1.2"), QStringLiteral("2")));
0339     QVERIFY(!KPackage::isVersionNewer(QStringLiteral("1"), QStringLiteral("0.1.2")));
0340 
0341     qDebug() << "                   ";
0342     qDebug() << "   CreateAndUpdate ";
0343     createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.1"));
0344     const QString packagePath = m_packageRoot + '/' + "testpackage.plasmoid";
0345 
0346     KZip creator(packagePath);
0347     QVERIFY(creator.open(QIODevice::WriteOnly));
0348     creator.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
0349     creator.close();
0350     QDir rootDir(m_packageRoot + "/plasmoid_to_package");
0351     rootDir.removeRecursively();
0352 
0353     QVERIFY(QFile::exists(packagePath));
0354 
0355     KZip package(packagePath);
0356     QVERIFY(package.open(QIODevice::ReadOnly));
0357     const KArchiveDirectory *dir = package.directory();
0358     QVERIFY(dir); //
0359     QVERIFY(dir->entry(QStringLiteral("metadata.json")));
0360     const KArchiveEntry *contentsEntry = dir->entry(QStringLiteral("contents"));
0361     QVERIFY(contentsEntry);
0362     QVERIFY(contentsEntry->isDirectory());
0363     const KArchiveDirectory *contents = static_cast<const KArchiveDirectory *>(contentsEntry);
0364     QVERIFY(contents->entry(QStringLiteral("ui")));
0365     QVERIFY(contents->entry(QStringLiteral("images")));
0366 
0367     m_defaultPackageStructure = new KPackage::PackageStructure(this);
0368     KPackage::Package *p = new KPackage::Package(m_defaultPackageStructure);
0369     qDebug() << "Installing " << packagePath;
0370     // const QString packageRoot = "plasma/plasmoids/";
0371     // const QString servicePrefix = "plasma-applet-";
0372 
0373     // clang-format off
0374     KJob *job = p->update(packagePath, m_packageRoot);
0375     connect(job, SIGNAL(finished(KJob*)), SLOT(packageInstalled(KJob*)));
0376     QSignalSpy spy(job, SIGNAL(finished(KJob*)));
0377     QVERIFY(spy.wait(1000));
0378 
0379     // same version, should fail
0380     job = p->update(packagePath, m_packageRoot);
0381     QSignalSpy spyFail(job, SIGNAL(finished(KJob*)));
0382     QVERIFY(spyFail.wait(1000));
0383     QVERIFY(job->error() == KPackage::Package::JobError::NewerVersionAlreadyInstalledError);
0384     qDebug()<<job->errorText();
0385 
0386 
0387     // create a new package with higher version
0388     createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.2"));
0389 
0390     KZip creator2(packagePath);
0391     QVERIFY(creator2.open(QIODevice::WriteOnly));
0392     creator2.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
0393     creator2.close();
0394     QDir rootDir2(m_packageRoot + "/plasmoid_to_package");
0395     rootDir2.removeRecursively();
0396 
0397 
0398     KJob *job2 = p->update(packagePath, m_packageRoot);
0399     connect(job2, SIGNAL(finished(KJob*)), SLOT(packageInstalled(KJob*)));
0400     QSignalSpy spy2(job2, SIGNAL(finished(KJob*)));
0401     QVERIFY(spy2.wait(1000));
0402     // clang-format on
0403 
0404     cleanupPackage(QStringLiteral("plasmoid_to_package"));
0405 
0406     // QVERIFY(p->isValid());
0407     delete p;
0408 }
0409 
0410 void PlasmoidPackageTest::uncompressPackageWithSubFolder()
0411 {
0412     KPackage::PackageStructure *structure = new KPackage::PackageStructure;
0413     KPackage::Package package(structure);
0414     package.setPath(QFINDTESTDATA("data/customcontent.tar.gz"));
0415 
0416     // if metadata is correctly found, servicetypes should be ("SimpleContent", "CustomContent")
0417     QCOMPARE(readKPackageTypes(package.metadata()), QStringList({"SimpleContent", "CustomContent"}));
0418 }
0419 
0420 void PlasmoidPackageTest::cleanupPackage(const QString &packageName)
0421 {
0422     KPackage::Package *p = new KPackage::Package(m_defaultPackageStructure);
0423     KJob *jj = p->uninstall(packageName, m_packageRoot);
0424     connect(jj, SIGNAL(finished(KJob *)), SLOT(packageUninstalled(KJob *)));
0425 
0426     QSignalSpy spy(jj, &KJob::finished);
0427     QVERIFY(spy.wait(1000));
0428 }
0429 
0430 void PlasmoidPackageTest::packageInstalled(KJob *j)
0431 {
0432     QVERIFY2(j->error() == KJob::NoError, qPrintable(j->errorText()));
0433 }
0434 
0435 void PlasmoidPackageTest::packageUninstalled(KJob *j)
0436 {
0437     QVERIFY2(j->error() == KJob::NoError, qPrintable(j->errorText()));
0438 }
0439 
0440 QTEST_MAIN(PlasmoidPackageTest)
0441 
0442 #include "moc_plasmoidpackagetest.cpp"