1 /*
2 SPDX-FileCopyrightText: 2007 Bertjan Broeksema <b.broeksema@kdemail.net>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "plasmoidpackagetest.h"
8 #include "../src/kpackage/config-package.h"
9 #include "../src/kpackage/private/versionparser.cpp"
10
11 #include <KJob>
12 #include <QDir>
13 #include <QFile>
14 #include <QSignalSpy>
15 #include <QStandardPaths>
16 #include <kzip.h>
17
18 #include <QDebug>
19
20 #include "packageloader.h"
21 #include "packagestructures/plasmoidstructure.h"
22
initTestCase()23 void PlasmoidPackageTest::initTestCase()
24 {
25 QStandardPaths::setTestModeEnabled(true);
26 }
27
init()28 void PlasmoidPackageTest::init()
29 {
30 qDebug() << "PlasmoidPackage::init()";
31 m_package = QStringLiteral("Package");
32 m_packageRoot = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/packageRoot";
33 m_defaultPackage = KPackage::Package(new KPackage::PlasmoidPackage);
34 cleanup(); // to prevent previous runs from interfering with this one
35 }
36
cleanup()37 void PlasmoidPackageTest::cleanup()
38 {
39 qDebug() << "cleaning up";
40 // Clean things up.
41 QDir(m_packageRoot).removeRecursively();
42 }
43
createTestPackage(const QString & packageName,const QString & version)44 void PlasmoidPackageTest::createTestPackage(const QString &packageName, const QString &version)
45 {
46 qDebug() << "Create test package" << m_packageRoot;
47 QDir pRoot(m_packageRoot);
48 // Create the root and package dir.
49 if (!pRoot.exists()) {
50 QVERIFY(QDir().mkpath(m_packageRoot));
51 }
52
53 // Create the package dir
54 QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName));
55 qDebug() << "Created" << (m_packageRoot + "/" + packageName);
56
57 // Create the metadata.desktop file
58 QFile file(m_packageRoot + "/" + packageName + "/metadata.desktop");
59
60 QVERIFY(file.open(QIODevice::WriteOnly));
61
62 QTextStream out(&file);
63 out << "[Desktop Entry]\n";
64 out << "Name=" << packageName << "\n";
65 out << "X-KDE-PluginInfo-Name=" << packageName << "\n";
66 out << "X-KDE-PluginInfo-Version=" << version << "\n";
67 file.flush();
68 file.close();
69
70 qDebug() << "OUT: " << packageName;
71
72 // Create the ui dir.
73 QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName + "/contents/ui"));
74
75 // Create the main file.
76 file.setFileName(m_packageRoot + "/" + packageName + "/contents/ui/main.qml");
77 QVERIFY(file.open(QIODevice::WriteOnly));
78
79 out << "THIS IS A PLASMOID SCRIPT.....";
80 file.flush();
81 file.close();
82
83 qDebug() << "THIS IS A PLASMOID SCRIPT THING";
84 // Now we have a minimal plasmoid package which is valid. Let's add some
85 // files to it for test purposes.
86
87 // Create the images dir.
88 QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName + "/contents/images"));
89 file.setFileName(m_packageRoot + "/" + packageName + "/contents/images/image-1.svg");
90
91 QVERIFY(file.open(QIODevice::WriteOnly));
92
93 out << "<svg>This is a test image</svg>";
94 file.flush();
95 file.close();
96
97 file.setFileName(m_packageRoot + "/" + packageName + "/contents/images/image-2.svg");
98
99 QVERIFY(file.open(QIODevice::WriteOnly));
100
101 out.setDevice(&file);
102 out << "<svg>This is another test image</svg>";
103 file.flush();
104 file.close();
105
106 // Create the scripts dir.
107 QVERIFY(QDir().mkpath(m_packageRoot + "/" + packageName + "/contents/code"));
108
109 // Create 2 js files
110 file.setFileName(m_packageRoot + "/" + packageName + "/contents/code/script.js");
111 QVERIFY(file.open(QIODevice::WriteOnly));
112
113 out << "THIS IS A SCRIPT.....";
114 file.flush();
115 file.close();
116 }
117
isValid()118 void PlasmoidPackageTest::isValid()
119 {
120 KPackage::Package *p = new KPackage::Package(m_defaultPackage);
121 p->setPath(m_packageRoot + '/' + m_package);
122 #ifndef NDEBUG
123 qDebug() << "package path is" << p->path();
124 #endif
125
126 // A PlasmoidPackage is valid when:
127 // - The package root exists.
128 // - The package root consists an file named "ui/main.qml"
129 QVERIFY(!p->isValid());
130
131 // Create the root and package dir.
132 QVERIFY(QDir().mkpath(m_packageRoot));
133 QVERIFY(QDir().mkpath(m_packageRoot + "/" + m_package));
134
135 // Should still be invalid.
136 delete p;
137 p = new KPackage::Package(m_defaultPackage);
138 p->setPath(m_packageRoot + '/' + m_package);
139 QVERIFY(!p->isValid());
140
141 // Create the metadata.desktop file.
142 QFile file(m_packageRoot + "/" + m_package + "/metadata.desktop");
143 QVERIFY(file.open(QIODevice::WriteOnly));
144
145 QTextStream out(&file);
146 out << "[Desktop Entry]\n";
147 out << "Name=test\n";
148 out << "Description=Just a test desktop file";
149 file.flush();
150 file.close();
151
152 // Create the ui dir.
153 QVERIFY(QDir().mkpath(m_packageRoot + "/" + m_package + "/contents/ui"));
154
155 // No main file yet so should still be invalid.
156 delete p;
157 p = new KPackage::Package(m_defaultPackage);
158 p->setPath(m_packageRoot + '/' + m_package);
159 QVERIFY(!p->isValid());
160
161 // Create the main file.
162 file.setFileName(m_packageRoot + "/" + m_package + "/contents/ui/main.qml");
163 QVERIFY(file.open(QIODevice::WriteOnly));
164
165 out.setDevice(&file);
166 out << "THIS IS A PLASMOID SCRIPT.....\n";
167 file.flush();
168 file.close();
169
170 file.setPermissions(QFile::ReadUser | QFile::WriteUser);
171 // Main file exists so should be valid now.
172 delete p;
173 p = new KPackage::Package(m_defaultPackage);
174 p->setPath(m_packageRoot + '/' + m_package);
175 QVERIFY(p->isValid());
176 #if KPACKAGE_ENABLE_DEPRECATED_SINCE(5, 21)
177 QCOMPARE(p->contentsHash(), QStringLiteral("a41160c6a763ea505c95bee12a7fc87952a61cf1"));
178 #endif
179 QCOMPARE(p->cryptographicHash(QCryptographicHash::Sha1), QByteArrayLiteral("a41160c6a763ea505c95bee12a7fc87952a61cf1"));
180 delete p;
181 }
182
filePath()183 void PlasmoidPackageTest::filePath()
184 {
185 return;
186 // Package::filePath() returns
187 // - {package_root}/{package_name}/path/to/file if the file exists
188 // - QString() otherwise.
189 KPackage::Package *p = new KPackage::Package(m_defaultPackage);
190 p->setPath(m_packageRoot + '/' + m_package);
191
192 QCOMPARE(p->filePath("scripts", QStringLiteral("main")), QString());
193
194 QVERIFY(QDir().mkpath(m_packageRoot + "/" + m_package + "/contents/ui/main.qml"));
195 QFile file(m_packageRoot + "/" + m_package + "/contents/ui/main.qml");
196 QVERIFY(file.open(QIODevice::WriteOnly));
197
198 QTextStream out(&file);
199 out << "THIS IS A PLASMOID SCRIPT.....";
200 file.flush();
201 file.close();
202
203 // The package is valid by now so a path for code/main should get returned.
204 delete p;
205 p = new KPackage::Package(m_defaultPackage);
206 p->setPath(m_packageRoot + '/' + m_package);
207
208 const QString path = QFileInfo(m_packageRoot + "/" + m_package + "/contents/ui/main.qml").canonicalFilePath();
209
210 // Two ways to get the same info.
211 // 1. Give the file type which refers to a class of files (a directory) in
212 // the package structure and the file name.
213 // 2. Give the file type which refers to a file in the package structure.
214 //
215 // NOTE: scripts, main and mainscript are defined in packages.cpp and are
216 // specific for a PlasmoidPackage.
217 QCOMPARE(p->filePath("scripts", QStringLiteral("main")), path);
218 QCOMPARE(p->filePath("mainscript"), path);
219 delete p;
220 }
221
entryList()222 void PlasmoidPackageTest::entryList()
223 {
224 // Create a package named @p packageName which is valid and has some images.
225 createTestPackage(m_package, QStringLiteral("1.1"));
226
227 // Create a package object and verify that it is valid.
228 KPackage::Package *p = new KPackage::Package(m_defaultPackage);
229 p->setPath(m_packageRoot + '/' + m_package);
230 QVERIFY(p->isValid());
231
232 // Now we have a valid package that should contain the following files in
233 // given filetypes:
234 // fileTye - Files
235 // scripts - {"script.js"}
236 // images - {"image-1.svg", "image-2.svg"}
237 QStringList files = p->entryList("scripts");
238 QCOMPARE(files.size(), 1);
239 QVERIFY(files.contains(QStringLiteral("script.js")));
240
241 files = p->entryList("images");
242 QCOMPARE(files.size(), 2);
243 QVERIFY(files.contains(QStringLiteral("image-1.svg")));
244 QVERIFY(files.contains(QStringLiteral("image-2.svg")));
245 delete p;
246 }
247
createAndInstallPackage()248 void PlasmoidPackageTest::createAndInstallPackage()
249 {
250 qDebug() << " ";
251 qDebug() << " CreateAndInstall ";
252 createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.1"));
253 const QString packagePath = m_packageRoot + '/' + "testpackage.plasmoid";
254
255 KZip creator(packagePath);
256 QVERIFY(creator.open(QIODevice::WriteOnly));
257 creator.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
258 creator.close();
259 QDir rootDir(m_packageRoot + "/plasmoid_to_package");
260 rootDir.removeRecursively();
261
262 QVERIFY2(QFile::exists(packagePath), qPrintable(packagePath));
263
264 KZip package(packagePath);
265 QVERIFY(package.open(QIODevice::ReadOnly));
266 const KArchiveDirectory *dir = package.directory();
267 QVERIFY(dir); //
268 QVERIFY(dir->entry(QStringLiteral("metadata.desktop")));
269 const KArchiveEntry *contentsEntry = dir->entry(QStringLiteral("contents"));
270 QVERIFY(contentsEntry);
271 QVERIFY(contentsEntry->isDirectory());
272 const KArchiveDirectory *contents = static_cast<const KArchiveDirectory *>(contentsEntry);
273 QVERIFY(contents->entry(QStringLiteral("ui")));
274 QVERIFY(contents->entry(QStringLiteral("images")));
275
276 m_defaultPackageStructure = new KPackage::PackageStructure(this);
277 KPackage::Package *p = new KPackage::Package(m_defaultPackageStructure);
278 qDebug() << "Installing " << packagePath;
279 // const QString packageRoot = "plasma/plasmoids/";
280 // const QString servicePrefix = "plasma-applet-";
281 KJob *job = p->install(packagePath, m_packageRoot);
282 // clang-format off
283 connect(job, SIGNAL(finished(KJob*)), SLOT(packageInstalled(KJob*)));
284 QSignalSpy spy(job, SIGNAL(finished(KJob*)));
285 // clang-format on
286 QVERIFY(spy.wait(1000));
287
288 // is the package instance usable (ie proper path) after the install job has been completed?
289 QCOMPARE(p->path(), QString(QDir(m_packageRoot % "/plasmoid_to_package").canonicalPath() + QLatin1Char('/')));
290 cleanupPackage(QStringLiteral("plasmoid_to_package"));
291
292 // QVERIFY(p->isValid());
293 delete p;
294 }
295
noCrashOnAsyncInstall()296 void PlasmoidPackageTest::noCrashOnAsyncInstall()
297 {
298 createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.1"));
299 const QString packagePath = m_packageRoot + '/' + "testpackage.plasmoid";
300
301 KZip creator(packagePath);
302 QVERIFY(creator.open(QIODevice::WriteOnly));
303 creator.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
304 creator.close();
305 QDir rootDir(m_packageRoot + "/plasmoid_to_package");
306 rootDir.removeRecursively();
307
308 KJob *job;
309 // scope the package so it will get deleted before the install operation finishes
310 // package is explicitlyshared internally and designed to be used on the stack
311 // see #370718
312 {
313 KPackage::Package package(new KPackage::PackageStructure(this));
314 job = package.install(packagePath, m_packageRoot);
315 }
316 // clang-format off
317 connect(job, SIGNAL(finished(KJob*)), SLOT(packageInstalled(KJob*)));
318 QSignalSpy spy(job, SIGNAL(finished(KJob*)));
319 // clang-format on
320 QVERIFY(spy.wait(1000));
321
322 cleanupPackage(QStringLiteral("plasmoid_to_package"));
323 }
324
createAndUpdatePackage()325 void PlasmoidPackageTest::createAndUpdatePackage()
326 {
327 // does the version number parsing work?
328 QVERIFY(KPackage::isVersionNewer(QStringLiteral("1.1"), QStringLiteral("1.1.1")));
329 QVERIFY(!KPackage::isVersionNewer(QStringLiteral("1.1.1"), QStringLiteral("1.1")));
330 QVERIFY(KPackage::isVersionNewer(QStringLiteral("1.1.1"), QStringLiteral("1.1.2")));
331 QVERIFY(KPackage::isVersionNewer(QStringLiteral("1.1.2"), QStringLiteral("2.1")));
332 QVERIFY(KPackage::isVersionNewer(QStringLiteral("0.1.2"), QStringLiteral("2")));
333 QVERIFY(!KPackage::isVersionNewer(QStringLiteral("1"), QStringLiteral("0.1.2")));
334
335 qDebug() << " ";
336 qDebug() << " CreateAndUpdate ";
337 createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.1"));
338 const QString packagePath = m_packageRoot + '/' + "testpackage.plasmoid";
339
340 KZip creator(packagePath);
341 QVERIFY(creator.open(QIODevice::WriteOnly));
342 creator.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
343 creator.close();
344 QDir rootDir(m_packageRoot + "/plasmoid_to_package");
345 rootDir.removeRecursively();
346
347 QVERIFY(QFile::exists(packagePath));
348
349 KZip package(packagePath);
350 QVERIFY(package.open(QIODevice::ReadOnly));
351 const KArchiveDirectory *dir = package.directory();
352 QVERIFY(dir); //
353 QVERIFY(dir->entry(QStringLiteral("metadata.desktop")));
354 const KArchiveEntry *contentsEntry = dir->entry(QStringLiteral("contents"));
355 QVERIFY(contentsEntry);
356 QVERIFY(contentsEntry->isDirectory());
357 const KArchiveDirectory *contents = static_cast<const KArchiveDirectory *>(contentsEntry);
358 QVERIFY(contents->entry(QStringLiteral("ui")));
359 QVERIFY(contents->entry(QStringLiteral("images")));
360
361 m_defaultPackageStructure = new KPackage::PackageStructure(this);
362 KPackage::Package *p = new KPackage::Package(m_defaultPackageStructure);
363 qDebug() << "Installing " << packagePath;
364 // const QString packageRoot = "plasma/plasmoids/";
365 // const QString servicePrefix = "plasma-applet-";
366
367 // clang-format off
368 KJob *job = p->update(packagePath, m_packageRoot);
369 connect(job, SIGNAL(finished(KJob*)), SLOT(packageInstalled(KJob*)));
370 QSignalSpy spy(job, SIGNAL(finished(KJob*)));
371 QVERIFY(spy.wait(1000));
372
373 // same version, should fail
374 job = p->update(packagePath, m_packageRoot);
375 QSignalSpy spyFail(job, SIGNAL(finished(KJob*)));
376 QVERIFY(spyFail.wait(1000));
377 QVERIFY(job->error() == KPackage::Package::JobError::NewerVersionAlreadyInstalledError);
378 qDebug()<<job->errorText();
379
380
381 // create a new package with higher version
382 createTestPackage(QStringLiteral("plasmoid_to_package"), QStringLiteral("1.2"));
383
384 KZip creator2(packagePath);
385 QVERIFY(creator2.open(QIODevice::WriteOnly));
386 creator2.addLocalDirectory(m_packageRoot + '/' + "plasmoid_to_package", QStringLiteral("."));
387 creator2.close();
388 QDir rootDir2(m_packageRoot + "/plasmoid_to_package");
389 rootDir2.removeRecursively();
390
391
392 KJob *job2 = p->update(packagePath, m_packageRoot);
393 connect(job2, SIGNAL(finished(KJob*)), SLOT(packageInstalled(KJob*)));
394 QSignalSpy spy2(job2, SIGNAL(finished(KJob*)));
395 QVERIFY(spy2.wait(1000));
396 // clang-format on
397
398 cleanupPackage(QStringLiteral("plasmoid_to_package"));
399
400 // QVERIFY(p->isValid());
401 delete p;
402 }
403
uncompressPackageWithSubFolder()404 void PlasmoidPackageTest::uncompressPackageWithSubFolder()
405 {
406 KPackage::PackageStructure *structure = new KPackage::PackageStructure;
407 KPackage::Package package(structure);
408 package.setPath(QFINDTESTDATA("data/customcontent.tar.gz"));
409
410 // if metadata is correctly found, servicetypes should be ("SimpleContent", "CustomContent")
411 QCOMPARE(package.metadata().serviceTypes(), QStringList({"SimpleContent", "CustomContent"}));
412 }
413
cleanupPackage(const QString & packageName)414 void PlasmoidPackageTest::cleanupPackage(const QString &packageName)
415 {
416 KPackage::Package *p = new KPackage::Package(m_defaultPackageStructure);
417 KJob *jj = p->uninstall(packageName, m_packageRoot);
418 connect(jj, SIGNAL(finished(KJob *)), SLOT(packageUninstalled(KJob *)));
419
420 QSignalSpy spy(jj, &KJob::finished);
421 QVERIFY(spy.wait(1000));
422 }
423
packageInstalled(KJob * j)424 void PlasmoidPackageTest::packageInstalled(KJob *j)
425 {
426 QVERIFY2(j->error() == KJob::NoError, qPrintable(j->errorText()));
427 }
428
packageUninstalled(KJob * j)429 void PlasmoidPackageTest::packageUninstalled(KJob *j)
430 {
431 QVERIFY2(j->error() == KJob::NoError, qPrintable(j->errorText()));
432 }
433
434 QTEST_MAIN(PlasmoidPackageTest)
435