File indexing completed on 2024-04-21 03:54:47
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::stat(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 connect(fileJob, &KIO::FileJob::fileClosed, this, &JobRemoteTest::slotFileJobClose); 0187 0188 m_result = -1; 0189 m_closeSignalCalled = false; 0190 0191 enterLoop(); 0192 QEXPECT_FAIL("", "Needs fixing in kio_file", Abort); 0193 QVERIFY(m_result == 0); // no error 0194 0195 KIO::StoredTransferJob *getJob = KIO::storedGet(u, KIO::NoReload, KIO::HideProgressInfo); 0196 getJob->setUiDelegate(nullptr); 0197 connect(getJob, &KJob::result, this, &JobRemoteTest::slotGetResult); 0198 enterLoop(); 0199 QCOMPARE(m_result, 0); // no error 0200 QVERIFY(m_closeSignalCalled); // close signal called. 0201 qDebug() << "m_data: " << m_data; 0202 QCOMPARE(m_data, QByteArray("test....test....test....test....test....test....end")); 0203 } 0204 0205 void JobRemoteTest::slotFileJobData(KIO::Job *job, const QByteArray &data) 0206 { 0207 Q_UNUSED(job); 0208 Q_UNUSED(data); 0209 } 0210 0211 void JobRemoteTest::slotFileJobRedirection(KIO::Job *job, const QUrl &url) 0212 { 0213 Q_UNUSED(job); 0214 Q_UNUSED(url); 0215 } 0216 0217 void JobRemoteTest::slotFileJobMimetype(KIO::Job *job, const QString &type) 0218 { 0219 Q_UNUSED(job); 0220 Q_UNUSED(type); 0221 } 0222 0223 void JobRemoteTest::slotFileJobOpen(KIO::Job *job) 0224 { 0225 Q_UNUSED(job); 0226 fileJob->seek(0); 0227 } 0228 0229 void JobRemoteTest::slotFileJobWritten(KIO::Job *job, KIO::filesize_t written) 0230 { 0231 Q_UNUSED(job); 0232 Q_UNUSED(written); 0233 if (m_rwCount > 5) { 0234 fileJob->close(); 0235 } else { 0236 fileJob->seek(m_rwCount * 8); 0237 m_rwCount++; 0238 } 0239 } 0240 0241 void JobRemoteTest::slotFileJobPosition(KIO::Job *job, KIO::filesize_t offset) 0242 { 0243 Q_UNUSED(job); 0244 Q_UNUSED(offset); 0245 const QByteArray data("test....end"); 0246 fileJob->write(data); 0247 } 0248 0249 void JobRemoteTest::slotFileJobClose(KIO::Job *job) 0250 { 0251 Q_UNUSED(job); 0252 m_closeSignalCalled = true; 0253 qDebug() << "+++++++++ filejob closed"; 0254 } 0255 0256 //// 0257 0258 void JobRemoteTest::openFileReading() 0259 { 0260 QUrl u(remoteTmpUrl()); 0261 u.setPath(u.path() + "openFileReading"); 0262 0263 const QByteArray putData("test1test2test3test4test5"); 0264 0265 KIO::StoredTransferJob *putJob = KIO::storedPut(putData, u, 0600, KIO::Overwrite | KIO::HideProgressInfo); 0266 0267 quint64 secsSinceEpoch = QDateTime::currentSecsSinceEpoch(); // Use second granularity, supported on all filesystems 0268 QDateTime mtime = QDateTime::fromSecsSinceEpoch(secsSinceEpoch - 30); // 30 seconds ago 0269 putJob->setModificationTime(mtime); 0270 putJob->setUiDelegate(nullptr); 0271 connect(putJob, &KJob::result, this, &JobRemoteTest::slotResult); 0272 m_result = -1; 0273 enterLoop(); 0274 QVERIFY(m_result == 0); // no error 0275 0276 m_rwCount = 4; 0277 m_data = QByteArray(); 0278 0279 fileJob = KIO::open(u, QIODevice::ReadOnly); 0280 0281 fileJob->setUiDelegate(nullptr); 0282 connect(fileJob, &KJob::result, this, &JobRemoteTest::slotResult); 0283 connect(fileJob, &KIO::FileJob::data, this, &JobRemoteTest::slotFileJob2Data); 0284 connect(fileJob, &KIO::FileJob::open, this, &JobRemoteTest::slotFileJob2Open); 0285 connect(fileJob, &KIO::FileJob::written, this, &JobRemoteTest::slotFileJob2Written); 0286 connect(fileJob, &KIO::FileJob::position, this, &JobRemoteTest::slotFileJob2Position); 0287 0288 // Can reuse this slot (same for all tests). 0289 connect(fileJob, &KIO::FileJob::fileClosed, this, &JobRemoteTest::slotFileJobClose); 0290 0291 m_result = -1; 0292 m_closeSignalCalled = false; 0293 0294 enterLoop(); 0295 QVERIFY(m_result == 0); // no error 0296 QVERIFY(m_closeSignalCalled); // close signal called. 0297 qDebug() << "resulting m_data: " << QString(m_data); 0298 QCOMPARE(m_data, QByteArray("test5test4test3test2test1")); 0299 } 0300 0301 void JobRemoteTest::slotFileJob2Data(KIO::Job *job, const QByteArray &data) 0302 { 0303 Q_UNUSED(job); 0304 qDebug() << "m_rwCount = " << m_rwCount << " data: " << data; 0305 m_data.append(data); 0306 0307 if (m_rwCount < 0) { 0308 fileJob->close(); 0309 } else { 0310 fileJob->seek(m_rwCount-- * 5); 0311 } 0312 } 0313 0314 void JobRemoteTest::slotFileJob2Redirection(KIO::Job *job, const QUrl &url) 0315 { 0316 Q_UNUSED(job); 0317 Q_UNUSED(url); 0318 } 0319 0320 void JobRemoteTest::slotFileJob2Mimetype(KIO::Job *job, const QString &type) 0321 { 0322 Q_UNUSED(job); 0323 qDebug() << "MIME type: " << type; 0324 } 0325 0326 void JobRemoteTest::slotFileJob2Open(KIO::Job *job) 0327 { 0328 Q_UNUSED(job); 0329 fileJob->seek(m_rwCount-- * 5); 0330 } 0331 0332 void JobRemoteTest::slotFileJob2Written(KIO::Job *job, KIO::filesize_t written) 0333 { 0334 Q_UNUSED(job); 0335 Q_UNUSED(written); 0336 } 0337 0338 void JobRemoteTest::slotFileJob2Position(KIO::Job *job, KIO::filesize_t offset) 0339 { 0340 Q_UNUSED(job); 0341 qDebug() << "position : " << offset << " -> read (5)"; 0342 fileJob->read(5); 0343 } 0344 0345 //// 0346 0347 void JobRemoteTest::slotMimetype(KIO::Job *job, const QString &type) 0348 { 0349 QVERIFY(job != nullptr); 0350 m_mimetype = type; 0351 } 0352 0353 void JobRemoteTest::openFileRead0Bytes() 0354 { 0355 QUrl u(remoteTmpUrl()); 0356 u.setPath(u.path() + "openFileReading"); 0357 0358 const QByteArray putData("Doesn't matter"); 0359 0360 KIO::StoredTransferJob *putJob = KIO::storedPut(putData, u, 0600, KIO::Overwrite | KIO::HideProgressInfo); 0361 0362 quint64 secsSinceEpoch = QDateTime::currentSecsSinceEpoch(); // Use second granularity, supported on all filesystems 0363 QDateTime mtime = QDateTime::fromSecsSinceEpoch(secsSinceEpoch - 30); // 30 seconds ago 0364 putJob->setModificationTime(mtime); 0365 putJob->setUiDelegate(nullptr); 0366 connect(putJob, &KJob::result, this, &JobRemoteTest::slotResult); 0367 m_result = -1; 0368 enterLoop(); 0369 QVERIFY(m_result == 0); // no error 0370 0371 m_data = QByteArray(); 0372 0373 fileJob = KIO::open(u, QIODevice::ReadOnly); 0374 0375 fileJob->setUiDelegate(nullptr); 0376 connect(fileJob, &KJob::result, this, &JobRemoteTest::slotResult); 0377 connect(fileJob, &KIO::FileJob::data, this, &JobRemoteTest::slotFileJob3Data); 0378 connect(fileJob, &KIO::FileJob::open, this, &JobRemoteTest::slotFileJob3Open); 0379 // Can reuse this slot (it's a noop). 0380 connect(fileJob, &KIO::FileJob::written, this, &JobRemoteTest::slotFileJob2Written); 0381 connect(fileJob, &KIO::FileJob::position, this, &JobRemoteTest::slotFileJob3Position); 0382 0383 // Can reuse this as well. 0384 connect(fileJob, &KIO::FileJob::fileClosed, this, &JobRemoteTest::slotFileJobClose); 0385 0386 m_result = -1; 0387 m_closeSignalCalled = false; 0388 0389 enterLoop(); 0390 // Previously reading 0 bytes would cause both data() and error() being emitted... 0391 QVERIFY(m_result == 0); // no error 0392 QVERIFY(m_closeSignalCalled); // close signal called. 0393 } 0394 0395 void JobRemoteTest::slotFileJob3Open(KIO::Job *job) 0396 { 0397 Q_UNUSED(job); 0398 fileJob->seek(0); 0399 } 0400 0401 void JobRemoteTest::slotFileJob3Position(KIO::Job *job, KIO::filesize_t offset) 0402 { 0403 Q_UNUSED(job); 0404 qDebug() << "position : " << offset << " -> read (0)"; 0405 fileJob->read(0); 0406 } 0407 0408 void JobRemoteTest::slotFileJob3Data(KIO::Job *job, const QByteArray &data) 0409 { 0410 Q_UNUSED(job); 0411 QVERIFY(data.isEmpty()); 0412 fileJob->close(); 0413 } 0414 0415 void JobRemoteTest::openFileTruncating() 0416 { 0417 QUrl u(remoteTmpUrl()); 0418 u.setPath(u.path() + "openFileTruncating"); 0419 0420 const QByteArray putData("test1"); 0421 0422 KIO::StoredTransferJob *putJob = KIO::storedPut(putData, u, 0600, KIO::Overwrite | KIO::HideProgressInfo); 0423 0424 quint64 secsSinceEpoch = QDateTime::currentSecsSinceEpoch(); // Use second granularity, supported on all filesystems 0425 QDateTime mtime = QDateTime::fromSecsSinceEpoch(secsSinceEpoch - 30); // 30 seconds ago 0426 putJob->setModificationTime(mtime); 0427 putJob->setUiDelegate(nullptr); 0428 connect(putJob, &KJob::result, this, &JobRemoteTest::slotResult); 0429 m_result = -1; 0430 enterLoop(); 0431 QVERIFY(m_result == 0); // no error 0432 0433 m_truncatedFile.setFileName(u.toLocalFile()); 0434 QVERIFY(m_truncatedFile.exists()); 0435 QVERIFY(m_truncatedFile.open(QIODevice::ReadOnly)); 0436 fileJob = KIO::open(u, QIODevice::ReadWrite); 0437 0438 fileJob->setUiDelegate(nullptr); 0439 connect(fileJob, &KJob::result, this, &JobRemoteTest::slotResult); 0440 connect(fileJob, &KIO::FileJob::open, this, &JobRemoteTest::slotFileJob4Open); 0441 connect(fileJob, &KIO::FileJob::truncated, this, &JobRemoteTest::slotFileJob4Truncated); 0442 0443 // Can reuse this slot (same for all tests). 0444 connect(fileJob, &KIO::FileJob::fileClosed, this, &JobRemoteTest::slotFileJobClose); 0445 0446 m_result = -1; 0447 m_closeSignalCalled = false; 0448 0449 enterLoop(); 0450 QVERIFY(m_result == 0); // no error 0451 QVERIFY(m_closeSignalCalled); // close signal called. 0452 } 0453 0454 void JobRemoteTest::slotFileJob4Open(KIO::Job *job) 0455 { 0456 Q_UNUSED(job); 0457 fileJob->truncate(10); 0458 qDebug() << "Truncating file to 10"; 0459 } 0460 0461 void JobRemoteTest::slotFileJob4Truncated(KIO::Job *job, KIO::filesize_t length) 0462 { 0463 Q_UNUSED(job); 0464 if (length == 10) { 0465 m_truncatedFile.seek(0); 0466 QCOMPARE(m_truncatedFile.readAll(), QByteArray("test1\x00\x00\x00\x00\x00", 10)); 0467 fileJob->truncate(4); 0468 qDebug() << "Truncating file to 4"; 0469 } else if (length == 4) { 0470 m_truncatedFile.seek(0); 0471 QCOMPARE(m_truncatedFile.readAll(), QByteArray("test")); 0472 fileJob->truncate(0); 0473 qDebug() << "Truncating file to 0"; 0474 } else { 0475 m_truncatedFile.seek(0); 0476 QCOMPARE(m_truncatedFile.readAll(), QByteArray()); 0477 fileJob->close(); 0478 qDebug() << "Truncating file finished"; 0479 } 0480 } 0481 0482 #include "moc_jobremotetest.cpp"