File indexing completed on 2025-04-27 13:09:20
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"