File indexing completed on 2024-04-21 14:59:36

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2004-2006 David Faure <faure@kde.org>
0004     SPDX-FileCopyrightText: 2008 Norbert Frese <nf2@scheinwelt.at>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "jobremotetest.h"
0010 
0011 #include <QDebug>
0012 #include <QDir>
0013 #include <QEventLoop>
0014 #include <QStandardPaths>
0015 #include <QTest>
0016 #include <QUrl>
0017 
0018 #include <KLocalizedString>
0019 
0020 #include <kio/copyjob.h>
0021 #include <kio/deletejob.h>
0022 #include <kio/directorysizejob.h>
0023 #include <kio/filejob.h>
0024 #include <kio/mkdirjob.h>
0025 #include <kio/statjob.h>
0026 #include <kio/storedtransferjob.h>
0027 #include <kprotocolinfo.h>
0028 // #include "kiotesthelper.h" // createTestFile etc.
0029 
0030 QTEST_MAIN(JobRemoteTest)
0031 
0032 QDateTime s_referenceTimeStamp;
0033 
0034 // The code comes partly from jobtest.cpp
0035 
0036 static QUrl remoteTmpUrl()
0037 {
0038     QString customDir(qgetenv("KIO_JOBREMOTETEST_REMOTETMP"));
0039     if (customDir.isEmpty()) {
0040         return QUrl::fromLocalFile(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + '/');
0041     } else {
0042         // Could be a path or a URL
0043         return QUrl::fromUserInput(customDir + '/');
0044     }
0045 }
0046 
0047 static QString localTmpDir()
0048 {
0049 #ifdef Q_OS_WIN
0050     return QDir::tempPath() + "/jobremotetest/";
0051 #else
0052     // This one needs to be on another partition
0053     return QStringLiteral("/tmp/jobremotetest/");
0054 #endif
0055 }
0056 
0057 static bool myExists(const QUrl &url)
0058 {
0059     KIO::Job *job = KIO::statDetails(url, KIO::StatJob::DestinationSide, KIO::StatBasic, KIO::HideProgressInfo);
0060     job->setUiDelegate(nullptr);
0061     return job->exec();
0062 }
0063 
0064 static bool myMkdir(const QUrl &url)
0065 {
0066     KIO::Job *job = KIO::mkdir(url, -1);
0067     job->setUiDelegate(nullptr);
0068     return job->exec();
0069 }
0070 
0071 void JobRemoteTest::initTestCase()
0072 {
0073     QStandardPaths::setTestModeEnabled(true);
0074 
0075     s_referenceTimeStamp = QDateTime::currentDateTime().addSecs(-30); // 30 seconds ago
0076 
0077     // Start with a clean base dir
0078     cleanupTestCase();
0079     QUrl url = remoteTmpUrl();
0080     if (!myExists(url)) {
0081         const bool ok = url.isLocalFile() ? QDir().mkpath(url.toLocalFile()) : myMkdir(url);
0082         if (!ok) {
0083             qFatal("couldn't create %s", qPrintable(url.toString()));
0084         }
0085     }
0086     const bool ok = QDir().mkpath(localTmpDir());
0087     if (!ok) {
0088         qFatal("couldn't create %s", qPrintable(localTmpDir()));
0089     }
0090 }
0091 
0092 static void delDir(const QUrl &pathOrUrl)
0093 {
0094     KIO::Job *job = KIO::del(pathOrUrl, KIO::HideProgressInfo);
0095     job->setUiDelegate(nullptr);
0096     job->exec();
0097 }
0098 
0099 void JobRemoteTest::cleanupTestCase()
0100 {
0101     delDir(remoteTmpUrl());
0102     delDir(QUrl::fromLocalFile(localTmpDir()));
0103 }
0104 
0105 void JobRemoteTest::enterLoop()
0106 {
0107     QEventLoop eventLoop;
0108     connect(this, &JobRemoteTest::exitLoop, &eventLoop, &QEventLoop::quit);
0109     eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
0110 }
0111 
0112 /////
0113 
0114 void JobRemoteTest::putAndGet()
0115 {
0116     QUrl u(remoteTmpUrl());
0117     u.setPath(u.path() + "putAndGetFile");
0118     KIO::TransferJob *job = KIO::put(u, 0600, KIO::Overwrite | KIO::HideProgressInfo);
0119     quint64 secsSinceEpoch = QDateTime::currentSecsSinceEpoch(); // Use second granularity, supported on all filesystems
0120     QDateTime mtime = QDateTime::fromSecsSinceEpoch(secsSinceEpoch - 30); // 30 seconds ago
0121     job->setModificationTime(mtime);
0122     job->setUiDelegate(nullptr);
0123     connect(job, &KJob::result, this, &JobRemoteTest::slotResult);
0124     connect(job, &KIO::TransferJob::dataReq, this, &JobRemoteTest::slotDataReq);
0125     m_result = -1;
0126     m_dataReqCount = 0;
0127     enterLoop();
0128     QVERIFY(m_result == 0); // no error
0129 
0130     m_result = -1;
0131 
0132     KIO::StoredTransferJob *getJob = KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo);
0133     getJob->setUiDelegate(nullptr);
0134     connect(getJob, &KJob::result, this, &JobRemoteTest::slotGetResult);
0135     enterLoop();
0136     QCOMPARE(m_result, 0); // no error
0137     QCOMPARE(m_data, QByteArray("This is a test for KIO::put()\n"));
0138     // QCOMPARE( m_data.size(), 11 );
0139 }
0140 
0141 void JobRemoteTest::slotGetResult(KJob *job)
0142 {
0143     m_result = job->error();
0144     m_data = static_cast<KIO::StoredTransferJob *>(job)->data();
0145     Q_EMIT exitLoop();
0146 }
0147 
0148 void JobRemoteTest::slotDataReq(KIO::Job *, QByteArray &data)
0149 {
0150     // Really not the way you'd write a slotDataReq usually :)
0151     switch (m_dataReqCount++) {
0152     case 0:
0153         data = "This is a test for ";
0154         break;
0155     case 1:
0156         data = "KIO::put()\n";
0157         break;
0158     case 2:
0159         data = QByteArray();
0160         break;
0161     }
0162 }
0163 
0164 void JobRemoteTest::slotResult(KJob *job)
0165 {
0166     m_result = job->error();
0167     Q_EMIT exitLoop();
0168 }
0169 
0170 ////
0171 
0172 void JobRemoteTest::openFileWriting()
0173 {
0174     m_rwCount = 0;
0175 
0176     QUrl u(remoteTmpUrl());
0177     u.setPath(u.path() + "openFileWriting");
0178     fileJob = KIO::open(u, QIODevice::WriteOnly);
0179 
0180     fileJob->setUiDelegate(nullptr);
0181     connect(fileJob, &KJob::result, this, &JobRemoteTest::slotResult);
0182     connect(fileJob, &KIO::FileJob::data, this, &JobRemoteTest::slotFileJobData);
0183     connect(fileJob, &KIO::FileJob::open, this, &JobRemoteTest::slotFileJobOpen);
0184     connect(fileJob, &KIO::FileJob::written, this, &JobRemoteTest::slotFileJobWritten);
0185     connect(fileJob, &KIO::FileJob::position, this, &JobRemoteTest::slotFileJobPosition);
0186 
0187 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 79)
0188     connect(fileJob, qOverload<KIO::Job *>(&KIO::FileJob::close), this, &JobRemoteTest::slotFileJobClose);
0189 #else
0190     connect(fileJob, &KIO::FileJob::fileClosed, this, &JobRemoteTest::slotFileJobClose);
0191 #endif
0192 
0193     m_result = -1;
0194     m_closeSignalCalled = false;
0195 
0196     enterLoop();
0197     QEXPECT_FAIL("", "Needs fixing in kio_file", Abort);
0198     QVERIFY(m_result == 0); // no error
0199 
0200     KIO::StoredTransferJob *getJob = KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo);
0201     getJob->setUiDelegate(nullptr);
0202     connect(getJob, &KJob::result, this, &JobRemoteTest::slotGetResult);
0203     enterLoop();
0204     QCOMPARE(m_result, 0); // no error
0205     QVERIFY(m_closeSignalCalled); // close signal called.
0206     qDebug() << "m_data: " << m_data;
0207     QCOMPARE(m_data, QByteArray("test....test....test....test....test....test....end"));
0208 }
0209 
0210 void JobRemoteTest::slotFileJobData(KIO::Job *job, const QByteArray &data)
0211 {
0212     Q_UNUSED(job);
0213     Q_UNUSED(data);
0214 }
0215 
0216 void JobRemoteTest::slotFileJobRedirection(KIO::Job *job, const QUrl &url)
0217 {
0218     Q_UNUSED(job);
0219     Q_UNUSED(url);
0220 }
0221 
0222 void JobRemoteTest::slotFileJobMimetype(KIO::Job *job, const QString &type)
0223 {
0224     Q_UNUSED(job);
0225     Q_UNUSED(type);
0226 }
0227 
0228 void JobRemoteTest::slotFileJobOpen(KIO::Job *job)
0229 {
0230     Q_UNUSED(job);
0231     fileJob->seek(0);
0232 }
0233 
0234 void JobRemoteTest::slotFileJobWritten(KIO::Job *job, KIO::filesize_t written)
0235 {
0236     Q_UNUSED(job);
0237     Q_UNUSED(written);
0238     if (m_rwCount > 5) {
0239         fileJob->close();
0240     } else {
0241         fileJob->seek(m_rwCount * 8);
0242         m_rwCount++;
0243     }
0244 }
0245 
0246 void JobRemoteTest::slotFileJobPosition(KIO::Job *job, KIO::filesize_t offset)
0247 {
0248     Q_UNUSED(job);
0249     Q_UNUSED(offset);
0250     const QByteArray data("test....end");
0251     fileJob->write(data);
0252 }
0253 
0254 void JobRemoteTest::slotFileJobClose(KIO::Job *job)
0255 {
0256     Q_UNUSED(job);
0257     m_closeSignalCalled = true;
0258     qDebug() << "+++++++++ filejob closed";
0259 }
0260 
0261 ////
0262 
0263 void JobRemoteTest::openFileReading()
0264 {
0265     QUrl u(remoteTmpUrl());
0266     u.setPath(u.path() + "openFileReading");
0267 
0268     const QByteArray putData("test1test2test3test4test5");
0269 
0270     KIO::StoredTransferJob *putJob = KIO::storedPut(putData, u, 0600, KIO::Overwrite | KIO::HideProgressInfo);
0271 
0272     quint64 secsSinceEpoch = QDateTime::currentSecsSinceEpoch(); // Use second granularity, supported on all filesystems
0273     QDateTime mtime = QDateTime::fromSecsSinceEpoch(secsSinceEpoch - 30); // 30 seconds ago
0274     putJob->setModificationTime(mtime);
0275     putJob->setUiDelegate(nullptr);
0276     connect(putJob, &KJob::result, this, &JobRemoteTest::slotResult);
0277     m_result = -1;
0278     enterLoop();
0279     QVERIFY(m_result == 0); // no error
0280 
0281     m_rwCount = 4;
0282     m_data = QByteArray();
0283 
0284     fileJob = KIO::open(u, QIODevice::ReadOnly);
0285 
0286     fileJob->setUiDelegate(nullptr);
0287     connect(fileJob, &KJob::result, this, &JobRemoteTest::slotResult);
0288     connect(fileJob, &KIO::FileJob::data, this, &JobRemoteTest::slotFileJob2Data);
0289     connect(fileJob, &KIO::FileJob::open, this, &JobRemoteTest::slotFileJob2Open);
0290     connect(fileJob, &KIO::FileJob::written, this, &JobRemoteTest::slotFileJob2Written);
0291     connect(fileJob, &KIO::FileJob::position, this, &JobRemoteTest::slotFileJob2Position);
0292 
0293     // Can reuse this slot (same for all tests).
0294 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 79)
0295     connect(fileJob, qOverload<KIO::Job *>(&KIO::FileJob::close), this, &JobRemoteTest::slotFileJobClose);
0296 #else
0297     connect(fileJob, &KIO::FileJob::fileClosed, this, &JobRemoteTest::slotFileJobClose);
0298 #endif
0299 
0300     m_result = -1;
0301     m_closeSignalCalled = false;
0302 
0303     enterLoop();
0304     QVERIFY(m_result == 0); // no error
0305     QVERIFY(m_closeSignalCalled); // close signal called.
0306     qDebug() << "resulting m_data: " << QString(m_data);
0307     QCOMPARE(m_data, QByteArray("test5test4test3test2test1"));
0308 }
0309 
0310 void JobRemoteTest::slotFileJob2Data(KIO::Job *job, const QByteArray &data)
0311 {
0312     Q_UNUSED(job);
0313     qDebug() << "m_rwCount = " << m_rwCount << " data: " << data;
0314     m_data.append(data);
0315 
0316     if (m_rwCount < 0) {
0317         fileJob->close();
0318     } else {
0319         fileJob->seek(m_rwCount-- * 5);
0320     }
0321 }
0322 
0323 void JobRemoteTest::slotFileJob2Redirection(KIO::Job *job, const QUrl &url)
0324 {
0325     Q_UNUSED(job);
0326     Q_UNUSED(url);
0327 }
0328 
0329 void JobRemoteTest::slotFileJob2Mimetype(KIO::Job *job, const QString &type)
0330 {
0331     Q_UNUSED(job);
0332     qDebug() << "MIME type: " << type;
0333 }
0334 
0335 void JobRemoteTest::slotFileJob2Open(KIO::Job *job)
0336 {
0337     Q_UNUSED(job);
0338     fileJob->seek(m_rwCount-- * 5);
0339 }
0340 
0341 void JobRemoteTest::slotFileJob2Written(KIO::Job *job, KIO::filesize_t written)
0342 {
0343     Q_UNUSED(job);
0344     Q_UNUSED(written);
0345 }
0346 
0347 void JobRemoteTest::slotFileJob2Position(KIO::Job *job, KIO::filesize_t offset)
0348 {
0349     Q_UNUSED(job);
0350     qDebug() << "position : " << offset << " -> read (5)";
0351     fileJob->read(5);
0352 }
0353 
0354 ////
0355 
0356 void JobRemoteTest::slotMimetype(KIO::Job *job, const QString &type)
0357 {
0358     QVERIFY(job != nullptr);
0359     m_mimetype = type;
0360 }
0361 
0362 void JobRemoteTest::openFileRead0Bytes()
0363 {
0364     QUrl u(remoteTmpUrl());
0365     u.setPath(u.path() + "openFileReading");
0366 
0367     const QByteArray putData("Doesn't matter");
0368 
0369     KIO::StoredTransferJob *putJob = KIO::storedPut(putData, u, 0600, KIO::Overwrite | KIO::HideProgressInfo);
0370 
0371     quint64 secsSinceEpoch = QDateTime::currentSecsSinceEpoch(); // Use second granularity, supported on all filesystems
0372     QDateTime mtime = QDateTime::fromSecsSinceEpoch(secsSinceEpoch - 30); // 30 seconds ago
0373     putJob->setModificationTime(mtime);
0374     putJob->setUiDelegate(nullptr);
0375     connect(putJob, &KJob::result, this, &JobRemoteTest::slotResult);
0376     m_result = -1;
0377     enterLoop();
0378     QVERIFY(m_result == 0); // no error
0379 
0380     m_data = QByteArray();
0381 
0382     fileJob = KIO::open(u, QIODevice::ReadOnly);
0383 
0384     fileJob->setUiDelegate(nullptr);
0385     connect(fileJob, &KJob::result, this, &JobRemoteTest::slotResult);
0386     connect(fileJob, &KIO::FileJob::data, this, &JobRemoteTest::slotFileJob3Data);
0387     connect(fileJob, &KIO::FileJob::open, this, &JobRemoteTest::slotFileJob3Open);
0388     // Can reuse this slot (it's a noop).
0389     connect(fileJob, &KIO::FileJob::written, this, &JobRemoteTest::slotFileJob2Written);
0390     connect(fileJob, &KIO::FileJob::position, this, &JobRemoteTest::slotFileJob3Position);
0391 
0392     // Can reuse this as well.
0393 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 79)
0394     connect(fileJob, qOverload<KIO::Job *>(&KIO::FileJob::close), this, &JobRemoteTest::slotFileJobClose);
0395 #else
0396     connect(fileJob, &KIO::FileJob::fileClosed, this, &JobRemoteTest::slotFileJobClose);
0397 #endif
0398 
0399     m_result = -1;
0400     m_closeSignalCalled = false;
0401 
0402     enterLoop();
0403     // Previously reading 0 bytes would cause both data() and error() being emitted...
0404     QVERIFY(m_result == 0); // no error
0405     QVERIFY(m_closeSignalCalled); // close signal called.
0406 }
0407 
0408 void JobRemoteTest::slotFileJob3Open(KIO::Job *job)
0409 {
0410     Q_UNUSED(job);
0411     fileJob->seek(0);
0412 }
0413 
0414 void JobRemoteTest::slotFileJob3Position(KIO::Job *job, KIO::filesize_t offset)
0415 {
0416     Q_UNUSED(job);
0417     qDebug() << "position : " << offset << " -> read (0)";
0418     fileJob->read(0);
0419 }
0420 
0421 void JobRemoteTest::slotFileJob3Data(KIO::Job *job, const QByteArray &data)
0422 {
0423     Q_UNUSED(job);
0424     QVERIFY(data.isEmpty());
0425     fileJob->close();
0426 }
0427 
0428 void JobRemoteTest::openFileTruncating()
0429 {
0430     QUrl u(remoteTmpUrl());
0431     u.setPath(u.path() + "openFileTruncating");
0432 
0433     const QByteArray putData("test1");
0434 
0435     KIO::StoredTransferJob *putJob = KIO::storedPut(putData, u, 0600, KIO::Overwrite | KIO::HideProgressInfo);
0436 
0437     quint64 secsSinceEpoch = QDateTime::currentSecsSinceEpoch(); // Use second granularity, supported on all filesystems
0438     QDateTime mtime = QDateTime::fromSecsSinceEpoch(secsSinceEpoch - 30); // 30 seconds ago
0439     putJob->setModificationTime(mtime);
0440     putJob->setUiDelegate(nullptr);
0441     connect(putJob, &KJob::result, this, &JobRemoteTest::slotResult);
0442     m_result = -1;
0443     enterLoop();
0444     QVERIFY(m_result == 0); // no error
0445 
0446     m_truncatedFile.setFileName(u.toLocalFile());
0447     QVERIFY(m_truncatedFile.exists());
0448     QVERIFY(m_truncatedFile.open(QIODevice::ReadOnly));
0449     fileJob = KIO::open(u, QIODevice::ReadWrite);
0450 
0451     fileJob->setUiDelegate(nullptr);
0452     connect(fileJob, &KJob::result, this, &JobRemoteTest::slotResult);
0453     connect(fileJob, &KIO::FileJob::open, this, &JobRemoteTest::slotFileJob4Open);
0454     connect(fileJob, &KIO::FileJob::truncated, this, &JobRemoteTest::slotFileJob4Truncated);
0455 
0456     // Can reuse this slot (same for all tests).
0457 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 79)
0458     connect(fileJob, qOverload<KIO::Job *>(&KIO::FileJob::close), this, &JobRemoteTest::slotFileJobClose);
0459 #else
0460     connect(fileJob, &KIO::FileJob::fileClosed, this, &JobRemoteTest::slotFileJobClose);
0461 #endif
0462 
0463     m_result = -1;
0464     m_closeSignalCalled = false;
0465 
0466     enterLoop();
0467     QVERIFY(m_result == 0); // no error
0468     QVERIFY(m_closeSignalCalled); // close signal called.
0469 }
0470 
0471 void JobRemoteTest::slotFileJob4Open(KIO::Job *job)
0472 {
0473     Q_UNUSED(job);
0474     fileJob->truncate(10);
0475     qDebug() << "Truncating file to 10";
0476 }
0477 
0478 void JobRemoteTest::slotFileJob4Truncated(KIO::Job *job, KIO::filesize_t length)
0479 {
0480     Q_UNUSED(job);
0481     if (length == 10) {
0482         m_truncatedFile.seek(0);
0483         QCOMPARE(m_truncatedFile.readAll(), QByteArray("test1\x00\x00\x00\x00\x00", 10));
0484         fileJob->truncate(4);
0485         qDebug() << "Truncating file to 4";
0486     } else if (length == 4) {
0487         m_truncatedFile.seek(0);
0488         QCOMPARE(m_truncatedFile.readAll(), QByteArray("test"));
0489         fileJob->truncate(0);
0490         qDebug() << "Truncating file to 0";
0491     } else {
0492         m_truncatedFile.seek(0);
0493         QCOMPARE(m_truncatedFile.readAll(), QByteArray());
0494         fileJob->close();
0495         qDebug() << "Truncating file finished";
0496     }
0497 }
0498 
0499 #include "moc_jobremotetest.cpp"