cf12defd28
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
222 lines
7.7 KiB
C++
222 lines
7.7 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2019 Harald Sitter <sitter@kde.org>
|
|
|
|
SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
|
*/
|
|
|
|
#include <kio/copyjob.h>
|
|
#include <kio/storedtransferjob.h>
|
|
|
|
#include <QBuffer>
|
|
#include <QProcess>
|
|
#include <QStandardPaths>
|
|
#include <QTest>
|
|
|
|
class FTPTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
QUrl url(const QString &path) const
|
|
{
|
|
Q_ASSERT(path.startsWith(QChar('/')));
|
|
QUrl newUrl = m_url;
|
|
newUrl.setPath(path);
|
|
return newUrl;
|
|
}
|
|
|
|
QTemporaryDir m_remoteDir;
|
|
QProcess m_daemonProc;
|
|
QUrl m_url = QUrl("ftp://localhost");
|
|
|
|
private Q_SLOTS:
|
|
static void runDaemon(QProcess &proc, QUrl &url, const QTemporaryDir &remoteDir)
|
|
{
|
|
QVERIFY(remoteDir.isValid());
|
|
proc.setProgram(RubyExe_EXECUTABLE);
|
|
proc.setArguments({QFINDTESTDATA("ftpd"), QStringLiteral("0"), remoteDir.path()});
|
|
proc.setProcessChannelMode(QProcess::ForwardedOutputChannel);
|
|
qDebug() << proc.arguments();
|
|
proc.start();
|
|
QVERIFY(proc.waitForStarted());
|
|
QCOMPARE(proc.state(), QProcess::Running);
|
|
// Wait for the daemon to print its port. That tells us both where it's listening
|
|
// and also that it is ready to move ahead with testing.
|
|
QVERIFY(QTest::qWaitFor(
|
|
[&]() -> bool {
|
|
const QString err = proc.readAllStandardError();
|
|
if (!err.isEmpty()) {
|
|
qDebug() << "STDERR:" << err;
|
|
}
|
|
if (!err.startsWith("port = ")) {
|
|
return false;
|
|
}
|
|
bool ok = false;
|
|
const int port = err.split(" = ").at(1).toInt(&ok);
|
|
url.setPort(port);
|
|
return ok;
|
|
},
|
|
8000));
|
|
}
|
|
|
|
void initTestCase()
|
|
{
|
|
// Force the ftp worker from our bindir as first choice. This specifically
|
|
// works around the fact that the kioworker executable would load the worker from the system
|
|
// as first choice instead of the one from the build dir.
|
|
qputenv("QT_PLUGIN_PATH", QCoreApplication::applicationDirPath().toUtf8());
|
|
|
|
// Run ftpd to talk to.
|
|
runDaemon(m_daemonProc, m_url, m_remoteDir);
|
|
// Once it's started we can simply forward the output. Possibly should do the
|
|
// same for stdout so it has a prefix.
|
|
connect(&m_daemonProc, &QProcess::readyReadStandardError, this, [this] {
|
|
qDebug() << "ftpd STDERR:" << m_daemonProc.readAllStandardError();
|
|
});
|
|
|
|
QStandardPaths::setTestModeEnabled(true);
|
|
}
|
|
|
|
void cleanupTestCase()
|
|
{
|
|
m_daemonProc.terminate();
|
|
m_daemonProc.kill();
|
|
m_daemonProc.waitForFinished();
|
|
}
|
|
|
|
void init()
|
|
{
|
|
QCOMPARE(m_daemonProc.state(), QProcess::Running);
|
|
}
|
|
|
|
void testGet()
|
|
{
|
|
const QString path("/testGet");
|
|
const auto url = this->url(path);
|
|
const QString remotePath = m_remoteDir.path() + path;
|
|
|
|
QByteArray data("testBasicGet");
|
|
QFile file(remotePath);
|
|
QVERIFY(file.open(QFile::WriteOnly));
|
|
file.write(data);
|
|
file.close();
|
|
|
|
auto job = KIO::storedGet(url);
|
|
job->setUiDelegate(nullptr);
|
|
QVERIFY2(job->exec(), qUtf8Printable(job->errorString()));
|
|
QCOMPARE(job->data(), data);
|
|
}
|
|
|
|
void testCopy()
|
|
{
|
|
const QString path("/testCopy");
|
|
const auto url = this->url(path);
|
|
const QString remotePath = m_remoteDir.path() + path;
|
|
const QString partPath = remotePath + ".part";
|
|
|
|
QFile::remove(remotePath);
|
|
QFile::remove(partPath);
|
|
|
|
auto job = KIO::copy({QUrl::fromLocalFile(QFINDTESTDATA("ftp/testCopy1"))}, url, KIO::DefaultFlags);
|
|
job->setUiDelegate(nullptr);
|
|
QVERIFY2(job->exec(), qUtf8Printable(job->errorString()));
|
|
QCOMPARE(job->error(), 0);
|
|
QFile file(remotePath);
|
|
QVERIFY(file.exists());
|
|
QVERIFY(file.open(QFile::ReadOnly));
|
|
QCOMPARE(file.readAll(), QByteArray("part1\n"));
|
|
}
|
|
|
|
void testCopyResume()
|
|
{
|
|
const QString path("/testCopy");
|
|
const auto url = this->url(path);
|
|
const QString remotePath = m_remoteDir.path() + path;
|
|
const QString partPath = remotePath + ".part";
|
|
|
|
QFile::remove(remotePath);
|
|
QFile::remove(partPath);
|
|
QVERIFY(QFile::copy(QFINDTESTDATA("ftp/testCopy1"), partPath));
|
|
|
|
auto job = KIO::copy({QUrl::fromLocalFile(QFINDTESTDATA("ftp/testCopy2"))}, url, KIO::Resume);
|
|
job->setUiDelegate(nullptr);
|
|
QVERIFY2(job->exec(), qUtf8Printable(job->errorString()));
|
|
QCOMPARE(job->error(), 0);
|
|
QFile file(remotePath);
|
|
QVERIFY(file.exists());
|
|
QVERIFY(file.open(QFile::ReadOnly));
|
|
QCOMPARE(file.readAll(), QByteArray("part1\npart2\n"));
|
|
}
|
|
|
|
void testCopyInaccessible()
|
|
{
|
|
const QString inaccessiblePath("/testCopy.__inaccessiblePath__");
|
|
auto inaccessibleUrl = this->url(inaccessiblePath);
|
|
|
|
auto job = KIO::copy({QUrl::fromLocalFile(QFINDTESTDATA("ftp/testCopy1"))}, inaccessibleUrl, KIO::Resume);
|
|
job->setUiDelegate(nullptr);
|
|
QVERIFY(!job->exec());
|
|
QCOMPARE(job->error(), KIO::ERR_WRITE_ACCESS_DENIED);
|
|
QFile file(inaccessiblePath);
|
|
QVERIFY(!file.exists());
|
|
}
|
|
|
|
void testCopyBadResume()
|
|
{
|
|
const QString inaccessiblePath("/testCopy.__badResume__");
|
|
auto inaccessibleUrl = this->url(inaccessiblePath);
|
|
inaccessibleUrl.setUserInfo("user");
|
|
inaccessibleUrl.setPassword("password");
|
|
const QString remoteInaccessiblePath = m_remoteDir.path() + inaccessiblePath;
|
|
QVERIFY(QFile::copy(QFINDTESTDATA("ftp/testCopy1"), remoteInaccessiblePath + ".part"));
|
|
|
|
auto job = KIO::copy({QUrl::fromLocalFile(QFINDTESTDATA("ftp/testCopy2"))}, inaccessibleUrl, KIO::Resume);
|
|
job->setUiDelegate(nullptr);
|
|
QVERIFY(!job->exec());
|
|
QCOMPARE(job->error(), KIO::ERR_WRITE_ACCESS_DENIED);
|
|
QFile file(inaccessiblePath);
|
|
QVERIFY(!file.exists());
|
|
}
|
|
|
|
void testOverwriteCopy()
|
|
{
|
|
const QString path("/testOverwriteCopy");
|
|
const auto url = this->url(path);
|
|
|
|
qDebug() << (m_remoteDir.path() + path);
|
|
QVERIFY(QFile::copy(QFINDTESTDATA("ftp/testOverwriteCopy1"), m_remoteDir.path() + path));
|
|
|
|
// File already exists, we expect it to be overwritten.
|
|
auto job = KIO::copy({QUrl::fromLocalFile(QFINDTESTDATA("ftp/testOverwriteCopy2"))}, url, KIO::Overwrite);
|
|
job->setUiDelegate(nullptr);
|
|
QVERIFY2(job->exec(), qUtf8Printable(job->errorString()));
|
|
QCOMPARE(job->error(), 0);
|
|
QFile file(m_remoteDir.path() + path);
|
|
QVERIFY(file.exists());
|
|
QVERIFY(file.open(QFile::ReadOnly));
|
|
QCOMPARE(file.readAll(), QByteArray("testOverwriteCopy2\n"));
|
|
}
|
|
|
|
void testOverwriteCopyWithoutFlag()
|
|
{
|
|
const QString path("/testOverwriteCopyWithoutFlag");
|
|
const auto url = this->url(path);
|
|
|
|
qDebug() << (m_remoteDir.path() + path);
|
|
QVERIFY(QFile::copy(QFINDTESTDATA("ftp/testOverwriteCopy1"), m_remoteDir.path() + path));
|
|
|
|
// Without overwrite flag.
|
|
// https://bugs.kde.org/show_bug.cgi?id=409954
|
|
auto job = KIO::copy({QUrl::fromLocalFile(QFINDTESTDATA("ftp/testOverwriteCopy2"))}, url, KIO::DefaultFlags);
|
|
job->setUiDelegate(nullptr);
|
|
QVERIFY2(!job->exec(), qUtf8Printable(job->errorString()));
|
|
QCOMPARE(job->error(), KIO::ERR_FILE_ALREADY_EXIST);
|
|
QFile file(m_remoteDir.path() + path);
|
|
QVERIFY(file.exists());
|
|
QVERIFY(file.open(QFile::ReadOnly));
|
|
QCOMPARE(file.readAll(), QByteArray("testOverwriteCopy1\n")); // not 2!
|
|
}
|
|
};
|
|
|
|
QTEST_MAIN(FTPTest)
|
|
#include "ftptest.moc"
|