From 1c6c64df2058cb8f2a06fce1a4ffa5476a80b762 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 16 Oct 2018 17:38:12 +0200 Subject: [PATCH] SSH: Turn some manual tests into autotests Change-Id: Id098709ff74dfc31a26ef42d559ce35d0120c0c3 Reviewed-by: Ulf Hermann --- src/libs/ssh/sshconnection.h | 3 + src/libs/ssh/ssherrors.h | 4 + tests/auto/auto.pro | 1 + tests/auto/auto.qbs | 1 + tests/auto/ssh/ssh.pro | 5 + tests/auto/ssh/ssh.qbs | 7 + tests/auto/ssh/tst_ssh.cpp | 843 ++++++++++++++++++ .../ssh/errorhandling/errorhandling.pro | 4 - tests/manual/ssh/errorhandling/main.cpp | 206 ----- tests/manual/ssh/remoteprocess/main.cpp | 49 - .../ssh/remoteprocess/remoteprocess.pro | 5 - .../ssh/remoteprocess/remoteprocesstest.cpp | 366 -------- .../ssh/remoteprocess/remoteprocesstest.h | 76 -- tests/manual/ssh/sftp/argumentscollector.cpp | 171 ---- tests/manual/ssh/sftp/argumentscollector.h | 52 -- tests/manual/ssh/sftp/main.cpp | 49 - tests/manual/ssh/sftp/parameters.h | 34 - tests/manual/ssh/sftp/sftp.pro | 6 - tests/manual/ssh/sftp/sftptest.cpp | 631 ------------- tests/manual/ssh/sftp/sftptest.h | 102 --- .../argumentscollector.cpp | 0 .../argumentscollector.h | 0 tests/manual/ssh/shell/main.cpp | 2 +- tests/manual/ssh/shell/shell.pro | 4 +- tests/manual/ssh/ssh.pro | 2 +- .../manual/ssh/tunnel/argumentscollector.cpp | 172 ---- tests/manual/ssh/tunnel/argumentscollector.h | 51 -- tests/manual/ssh/tunnel/directtunnel.cpp | 164 ---- tests/manual/ssh/tunnel/directtunnel.h | 74 -- tests/manual/ssh/tunnel/forwardtunnel.cpp | 146 --- tests/manual/ssh/tunnel/forwardtunnel.h | 70 -- tests/manual/ssh/tunnel/main.cpp | 59 -- tests/manual/ssh/tunnel/tunnel.pro | 12 - 33 files changed, 868 insertions(+), 2503 deletions(-) create mode 100644 tests/auto/ssh/ssh.pro create mode 100644 tests/auto/ssh/ssh.qbs create mode 100644 tests/auto/ssh/tst_ssh.cpp delete mode 100644 tests/manual/ssh/errorhandling/errorhandling.pro delete mode 100644 tests/manual/ssh/errorhandling/main.cpp delete mode 100644 tests/manual/ssh/remoteprocess/main.cpp delete mode 100644 tests/manual/ssh/remoteprocess/remoteprocess.pro delete mode 100644 tests/manual/ssh/remoteprocess/remoteprocesstest.cpp delete mode 100644 tests/manual/ssh/remoteprocess/remoteprocesstest.h delete mode 100644 tests/manual/ssh/sftp/argumentscollector.cpp delete mode 100644 tests/manual/ssh/sftp/argumentscollector.h delete mode 100644 tests/manual/ssh/sftp/main.cpp delete mode 100644 tests/manual/ssh/sftp/parameters.h delete mode 100644 tests/manual/ssh/sftp/sftp.pro delete mode 100644 tests/manual/ssh/sftp/sftptest.cpp delete mode 100644 tests/manual/ssh/sftp/sftptest.h rename tests/manual/ssh/{remoteprocess => shell}/argumentscollector.cpp (100%) rename tests/manual/ssh/{remoteprocess => shell}/argumentscollector.h (100%) delete mode 100644 tests/manual/ssh/tunnel/argumentscollector.cpp delete mode 100644 tests/manual/ssh/tunnel/argumentscollector.h delete mode 100644 tests/manual/ssh/tunnel/directtunnel.cpp delete mode 100644 tests/manual/ssh/tunnel/directtunnel.h delete mode 100644 tests/manual/ssh/tunnel/forwardtunnel.cpp delete mode 100644 tests/manual/ssh/tunnel/forwardtunnel.h delete mode 100644 tests/manual/ssh/tunnel/main.cpp delete mode 100644 tests/manual/ssh/tunnel/tunnel.pro diff --git a/src/libs/ssh/sshconnection.h b/src/libs/ssh/sshconnection.h index 0fbbbcdf8a8..78f7692c61b 100644 --- a/src/libs/ssh/sshconnection.h +++ b/src/libs/ssh/sshconnection.h @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -152,3 +153,5 @@ private: }; } // namespace QSsh + +Q_DECLARE_METATYPE(QSsh::SshConnectionParameters::AuthenticationType) diff --git a/src/libs/ssh/ssherrors.h b/src/libs/ssh/ssherrors.h index caf89819f00..f8a9e2fd954 100644 --- a/src/libs/ssh/ssherrors.h +++ b/src/libs/ssh/ssherrors.h @@ -26,6 +26,8 @@ #pragma once #define SSHERRORS_P_H +#include + namespace QSsh { enum SshError { @@ -35,3 +37,5 @@ enum SshError { }; } // namespace QSsh + +Q_DECLARE_METATYPE(QSsh::SshError) diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 14affe9fae0..78e86348107 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -13,6 +13,7 @@ SUBDIRS += \ generichighlighter \ pointeralgorithm \ profilewriter \ + ssh \ treeviewfind \ toolchaincache \ qtcprocess \ diff --git a/tests/auto/auto.qbs b/tests/auto/auto.qbs index 35211154703..1b6c5a7b307 100644 --- a/tests/auto/auto.qbs +++ b/tests/auto/auto.qbs @@ -22,6 +22,7 @@ Project { "qtcprocess/qtcprocess.qbs", "runextensions/runextensions.qbs", "sdktool/sdktool.qbs", + "ssh/ssh.qbs", "toolchaincache/toolchaincache.qbs", "tracing/tracing.qbs", "treeviewfind/treeviewfind.qbs", diff --git a/tests/auto/ssh/ssh.pro b/tests/auto/ssh/ssh.pro new file mode 100644 index 00000000000..31469ad3ad1 --- /dev/null +++ b/tests/auto/ssh/ssh.pro @@ -0,0 +1,5 @@ +QT = core network +QTC_LIB_DEPENDS += ssh +include(../qttest.pri) + +SOURCES += tst_ssh.cpp diff --git a/tests/auto/ssh/ssh.qbs b/tests/auto/ssh/ssh.qbs new file mode 100644 index 00000000000..b580f054333 --- /dev/null +++ b/tests/auto/ssh/ssh.qbs @@ -0,0 +1,7 @@ +import qbs + +QtcAutotest { + name: "SSH autotest" + Depends { name: "QtcSsh" } + files: "tst_ssh.cpp" +} diff --git a/tests/auto/ssh/tst_ssh.cpp b/tests/auto/ssh/tst_ssh.cpp new file mode 100644 index 00000000000..b15e4110667 --- /dev/null +++ b/tests/auto/ssh/tst_ssh.cpp @@ -0,0 +1,843 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace QSsh; + +static QString getHostFromEnvironment() +{ + return QString::fromLocal8Bit(qgetenv("QTC_SSH_TEST_HOST")); +} + +enum class TestType { Normal, Tunnel }; +static const char *portVar(TestType testType) +{ + return testType == TestType::Normal ? "QTC_SSH_TEST_PORT" : "QTC_SSH_TEST_PORT_TUNNEL"; +} +static const char *userVar(TestType testType) +{ + return testType == TestType::Normal ? "QTC_SSH_TEST_USER" : "QTC_SSH_TEST_USER_TUNNEL"; +} +static const char *pwdVar(TestType testType) +{ + return testType == TestType::Normal ? "QTC_SSH_TEST_PASSWORD" : "QTC_SSH_TEST_PASSWORD_TUNNEL"; +} +static const char *keyFileVar(TestType testType) +{ + return testType == TestType::Normal ? "QTC_SSH_TEST_KEYFILE" : "QTC_SSH_TEST_KEYFILE_TUNNEL"; +} + +static bool canUseFallbackValue(TestType testType) +{ + return testType == TestType::Tunnel && getHostFromEnvironment() == "localhost"; +} + +static quint16 getPortFromEnvironment(TestType testType) +{ + const int port = qEnvironmentVariableIntValue(portVar(testType)); + if (port != 0) + return port; + if (canUseFallbackValue(testType)) + return getPortFromEnvironment(TestType::Normal); + return 22; +} + +static QString getUserFromEnvironment(TestType testType) +{ + const QString user = QString::fromLocal8Bit(qgetenv(userVar(testType))); + if (user.isEmpty() && canUseFallbackValue(testType)) + return getUserFromEnvironment(TestType::Normal); + return user; +} + +static QString getPasswordFromEnvironment(TestType testType) +{ + const QString pwd = QString::fromLocal8Bit(qgetenv(pwdVar(testType))); + if (pwd.isEmpty() && canUseFallbackValue(testType)) + return getPasswordFromEnvironment(TestType::Normal); + return pwd; +} + +static QString getKeyFileFromEnvironment(TestType testType) +{ + const QString keyFile = QString::fromLocal8Bit(qgetenv(keyFileVar(testType))); + if (keyFile.isEmpty() && canUseFallbackValue(testType)) + return getKeyFileFromEnvironment(TestType::Normal); + return keyFile; +} + +static SshConnectionParameters getParameters(TestType testType) +{ + SshConnectionParameters params; + params.setHost(testType == TestType::Tunnel ? QString("localhost") + : getHostFromEnvironment()); + params.setPort(getPortFromEnvironment(testType)); + params.setUserName(getUserFromEnvironment(testType)); + params.setPassword(getPasswordFromEnvironment(testType)); + params.timeout = 10; + params.privateKeyFile = getKeyFileFromEnvironment(testType); + params.authenticationType = !params.password().isEmpty() + ? SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods + : SshConnectionParameters::AuthenticationTypePublicKey; + return params; +} + +#define CHECK_PARAMS(params, testType) \ + do { \ + if (params.host().isEmpty()) { \ + Q_ASSERT(testType == TestType::Normal); \ + QSKIP("No hostname provided. Set QTC_SSH_TEST_HOST."); \ + } \ + if (params.userName().isEmpty()) \ + QSKIP(qPrintable(QString::fromLatin1("No user name provided. Set %1.") \ + .arg(userVar(testType)))); \ + if (params.password().isEmpty() && params.privateKeyFile.isEmpty()) \ + QSKIP(qPrintable(QString::fromLatin1("No authentication data provided. " \ + "Set %1 or %2.").arg(pwdVar(testType), keyFileVar(testType)))); \ + } while (false) + +class tst_Ssh : public QObject +{ + Q_OBJECT + +private slots: + void directTunnel(); + void errorHandling_data(); + void errorHandling(); + void forwardTunnel(); + void pristineConnectionObject(); + void remoteProcess_data(); + void remoteProcess(); + void remoteProcessChannels(); + void remoteProcessInput(); + void sftp(); + +private: + bool waitForConnection(SshConnection &connection); +}; + +void tst_Ssh::directTunnel() +{ + // Establish SSH connection + const SshConnectionParameters params = getParameters(TestType::Tunnel); + CHECK_PARAMS(params, TestType::Tunnel); + SshConnection connection(params); + QVERIFY(waitForConnection(connection)); + + // Set up the tunnel + QTcpServer targetServer; + QTcpSocket *targetSocket = nullptr; + bool tunnelInitialized = false; + QVERIFY2(targetServer.listen(QHostAddress::LocalHost), qPrintable(targetServer.errorString())); + const quint16 targetPort = targetServer.serverPort(); + const SshDirectTcpIpTunnel::Ptr tunnel + = connection.createDirectTunnel("localhost", 1024, "localhost", targetPort); + QEventLoop loop; + const auto connectionHandler = [&targetServer, &targetSocket, &loop, &tunnelInitialized] { + targetSocket = targetServer.nextPendingConnection(); + targetServer.close(); + if (tunnelInitialized) + loop.quit(); + }; + connect(&targetServer, &QTcpServer::newConnection, connectionHandler); + connect(tunnel.data(), &SshDirectTcpIpTunnel::error, &loop, &QEventLoop::quit); + connect(tunnel.data(), &SshDirectTcpIpTunnel::initialized, + [&tunnelInitialized, &targetSocket, &loop] { + tunnelInitialized = true; + if (targetSocket) + loop.quit(); + }); + QTimer timer; + QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + timer.setSingleShot(true); + timer.setInterval((params.timeout + 5) * 1000); + timer.start(); + QVERIFY(!tunnel->isOpen()); + tunnel->initialize(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(tunnel->isOpen()); + QVERIFY(targetSocket); + QVERIFY(tunnelInitialized); + + // Send data through the tunnel and check that it is received by the "remote" side + static const QByteArray testData("Urgsblubb?"); + QByteArray clientDataReceivedByServer; + connect(targetSocket, + static_cast(&QAbstractSocket::error), + &loop, &QEventLoop::quit); + const auto socketDataHandler = [targetSocket, &clientDataReceivedByServer, &loop] { + clientDataReceivedByServer += targetSocket->readAll(); + if (clientDataReceivedByServer == testData) + loop.quit(); + }; + connect(targetSocket, &QIODevice::readyRead, socketDataHandler); + timer.start(); + tunnel->write(testData); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(tunnel->isOpen()); + QVERIFY2(targetSocket->error() == QAbstractSocket::UnknownSocketError, + qPrintable(targetSocket->errorString())); + QCOMPARE(clientDataReceivedByServer, testData); + + // Send data back and check that it is received by the "local" side + QByteArray serverDataReceivedByClient; + connect(tunnel.data(), &QIODevice::readyRead, [tunnel, &serverDataReceivedByClient, &loop] { + serverDataReceivedByClient += tunnel->readAll(); + if (serverDataReceivedByClient == testData) + loop.quit(); + }); + timer.start(); + targetSocket->write(clientDataReceivedByServer); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(tunnel->isOpen()); + QVERIFY2(targetSocket->error() == QAbstractSocket::UnknownSocketError, + qPrintable(targetSocket->errorString())); + QCOMPARE(serverDataReceivedByClient, testData); + + // Close tunnel by closing the "remote" socket + connect(tunnel.data(), &QIODevice::aboutToClose, &loop, &QEventLoop::quit); + timer.start(); + targetSocket->close(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(!tunnel->isOpen()); + QVERIFY2(targetSocket->error() == QAbstractSocket::UnknownSocketError, + qPrintable(targetSocket->errorString())); +} + +using ErrorList = QList; +void tst_Ssh::errorHandling_data() +{ + QTest::addColumn("host"); + QTest::addColumn("port"); + QTest::addColumn("authType"); + QTest::addColumn("user"); + QTest::addColumn("password"); + QTest::addColumn("keyFile"); + QTest::addColumn("expectedErrors"); + + QTest::newRow("no host") + << QString("hgdfxgfhgxfhxgfchxgcf") << quint16(12345) + << SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods + << QString() << QString() << QString() << ErrorList{SshSocketError, SshTimeoutError}; + const QString theHost = getHostFromEnvironment(); + if (theHost.isEmpty()) + return; + const quint16 thePort = getPortFromEnvironment(TestType::Normal); + QTest::newRow("no user") + << theHost << thePort + << SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods + << QString("dumdidumpuffpuff") << QString("whatever") << QString() + << ErrorList{SshAuthenticationError}; + QTest::newRow("wrong password") + << theHost << thePort + << SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods + << QString("root") << QString("thiscantpossiblybeapasswordcanit") << QString() + << ErrorList{SshAuthenticationError}; + QTest::newRow("non-existing key file") + << theHost << thePort + << SshConnectionParameters::AuthenticationTypePublicKey + << QString("root") << QString() + << QString("somefilenamethatwedontexpecttocontainavalidkey") + << ErrorList{SshKeyFileError}; + + // TODO: Valid key file not known to the server +} + +void tst_Ssh::errorHandling() +{ + QFETCH(QString, host); + QFETCH(quint16, port); + QFETCH(SshConnectionParameters::AuthenticationType, authType); + QFETCH(QString, user); + QFETCH(QString, password); + QFETCH(QString, keyFile); + QFETCH(ErrorList, expectedErrors); + SshConnectionParameters params; + params.setHost(host); + params.setPort(port); + params.setUserName(user); + params.setPassword(password); + params.timeout = 10; + params.authenticationType = authType; + params.privateKeyFile = keyFile; + SshConnection connection(params); + QEventLoop loop; + bool disconnected = false; + QString dataReceived; + QObject::connect(&connection, &SshConnection::connected, &loop, &QEventLoop::quit); + QObject::connect(&connection, &SshConnection::error, &loop, &QEventLoop::quit); + QObject::connect(&connection, &SshConnection::disconnected, + [&disconnected] { disconnected = true; }); + QObject::connect(&connection, &SshConnection::dataAvailable, + [&dataReceived](const QString &data) { dataReceived = data; }); + QTimer timer; + QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + timer.setSingleShot(true); + timer.start((params.timeout + 5) * 1000); + connection.connectToHost(); + loop.exec(); + QVERIFY(timer.isActive()); + QCOMPARE(connection.state(), SshConnection::Unconnected); + QVERIFY2(expectedErrors.contains(connection.errorState()), + qPrintable(connection.errorString())); + QVERIFY(!disconnected); + QVERIFY2(dataReceived.isEmpty(), qPrintable(dataReceived)); +} + +void tst_Ssh::forwardTunnel() +{ + // Set up SSH connection + const SshConnectionParameters params = getParameters(TestType::Tunnel); + CHECK_PARAMS(params, TestType::Tunnel); + SshConnection connection(params); + QVERIFY(waitForConnection(connection)); + + // Find a free port on the "remote" side and listen on it + quint16 targetPort; + { + QTcpServer server; + QVERIFY2(server.listen(QHostAddress::LocalHost), qPrintable(server.errorString())); + targetPort = server.serverPort(); + } + SshTcpIpForwardServer::Ptr server = connection.createForwardServer(QLatin1String("localhost"), + targetPort); + QEventLoop loop; + QTimer timer; + connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + connect(server.data(), &SshTcpIpForwardServer::stateChanged, &loop, &QEventLoop::quit); + connect(server.data(), &SshTcpIpForwardServer::error, &loop, &QEventLoop::quit); + timer.setSingleShot(true); + timer.setInterval((params.timeout + 5) * 1000); + timer.start(); + QCOMPARE(server->state(), SshTcpIpForwardServer::Inactive); + server->initialize(); + QCOMPARE(server->state(), SshTcpIpForwardServer::Initializing); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(server->state() == SshTcpIpForwardServer::Listening); + + // Establish a tunnel + connect(server.data(), &QSsh::SshTcpIpForwardServer::newConnection, &loop, &QEventLoop::quit); + QTcpSocket targetSocket; + targetSocket.connectToHost("localhost", targetPort); + timer.start(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + const SshForwardedTcpIpTunnel::Ptr tunnel = server->nextPendingConnection(); + QVERIFY(!tunnel.isNull()); + QVERIFY(tunnel->isOpen()); + + // Send data through the socket and check that we receive it through the tunnel + static const QByteArray testData("Urgsblubb?"); + QByteArray dataReceivedOnTunnel; + QString tunnelError; + const auto tunnelErrorHandler = [&loop, &tunnelError](const QString &error) { + tunnelError = error; + loop.quit(); + }; + connect(tunnel.data(), &SshForwardedTcpIpTunnel::error, tunnelErrorHandler); + connect(tunnel.data(), &QIODevice::readyRead, [tunnel, &dataReceivedOnTunnel, &loop] { + dataReceivedOnTunnel += tunnel->readAll(); + if (dataReceivedOnTunnel == testData) + loop.quit(); + }); + timer.start(); + targetSocket.write(testData); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(tunnel->isOpen()); + QVERIFY2(tunnelError.isEmpty(), qPrintable(tunnelError)); + QCOMPARE(dataReceivedOnTunnel, testData); + + // Send data though the tunnel and check that we receive it on the socket + QByteArray dataReceivedOnSocket; + connect(&targetSocket, &QTcpSocket::readyRead, [&targetSocket, &dataReceivedOnSocket, &loop] { + dataReceivedOnSocket += targetSocket.readAll(); + if (dataReceivedOnSocket == testData) + loop.quit(); + }); + timer.start(); + tunnel->write(dataReceivedOnTunnel); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(tunnel->isOpen()); + QCOMPARE(dataReceivedOnSocket, testData); + QVERIFY2(tunnelError.isEmpty(), qPrintable(tunnelError)); + + // Close the tunnel via the socket + connect(tunnel.data(), &SshForwardedTcpIpTunnel::aboutToClose, &loop, &QEventLoop::quit); + timer.start(); + targetSocket.close(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(!tunnel->isOpen()); + QVERIFY2(tunnelError.isEmpty(), qPrintable(tunnelError)); + QCOMPARE(server->state(), SshTcpIpForwardServer::Listening); + + // Close the server + timer.start(); + server->close(); + QCOMPARE(server->state(), SshTcpIpForwardServer::Closing); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QCOMPARE(server->state(), SshTcpIpForwardServer::Inactive); +} + +void tst_Ssh::pristineConnectionObject() +{ + QSsh::SshConnection connection((SshConnectionParameters())); + QCOMPARE(connection.state(), SshConnection::Unconnected); + QVERIFY(connection.createRemoteProcess("").isNull()); + QVERIFY(connection.createSftpChannel().isNull()); +} + +void tst_Ssh::remoteProcess_data() +{ + QTest::addColumn("commandLine"); + QTest::addColumn("useTerminal"); + QTest::addColumn("isBlocking"); + QTest::addColumn("successExpected"); + QTest::addColumn("stdoutExpected"); + QTest::addColumn("stderrExpected"); + + QTest::newRow("normal command") + << QByteArray("ls -a /tmp") << false << false << true << true << false; + QTest::newRow("failing command") + << QByteArray("top -n 1") << false << false << false << false << true; + QTest::newRow("blocking command") + << QByteArray("/bin/sleep 100") << false << true << false << false << false; + QTest::newRow("terminal command") + << QByteArray("top -n 1") << true << false << true << true << false; +} + +void tst_Ssh::remoteProcess() +{ + const SshConnectionParameters params = getParameters(TestType::Normal); + CHECK_PARAMS(params, TestType::Normal); + + QFETCH(QByteArray, commandLine); + QFETCH(bool, useTerminal); + QFETCH(bool, isBlocking); + QFETCH(bool, successExpected); + QFETCH(bool, stdoutExpected); + QFETCH(bool, stderrExpected); + + QByteArray remoteStdout; + QByteArray remoteStderr; + SshRemoteProcessRunner runner; + QEventLoop loop; + connect(&runner, &SshRemoteProcessRunner::connectionError, &loop, &QEventLoop::quit); + connect(&runner, &SshRemoteProcessRunner::processStarted, &loop, &QEventLoop::quit); + connect(&runner, &SshRemoteProcessRunner::processClosed, &loop, &QEventLoop::quit); + connect(&runner, &SshRemoteProcessRunner::readyReadStandardOutput, + [&remoteStdout, &runner] { remoteStdout += runner.readAllStandardOutput(); }); + connect(&runner, &SshRemoteProcessRunner::readyReadStandardError, + [&remoteStderr, &runner] { remoteStderr += runner.readAllStandardError(); }); + if (useTerminal) + runner.runInTerminal(commandLine, SshPseudoTerminal(), params); + else + runner.run(commandLine, params); + QTimer timer; + QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + timer.setSingleShot(true); + timer.setInterval((params.timeout + 5) * 1000); + timer.start(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(runner.isProcessRunning()); // Event loop exit should have been triggered by started(). + QVERIFY2(remoteStdout.isEmpty(), remoteStdout.constData()); + QVERIFY2(remoteStderr.isEmpty(), remoteStderr.constData()); + + SshRemoteProcessRunner killer; + if (isBlocking) + killer.run("pkill -f -9 \"" + commandLine + '"', params); + + timer.start(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(!runner.isProcessRunning()); + if (isBlocking) { + // Some shells (e.g. mksh) do not report a crash exit. + if (runner.processExitStatus() == SshRemoteProcess::CrashExit) + QCOMPARE(runner.processExitSignal(), SshRemoteProcess::KillSignal); + else + QVERIFY(runner.processExitCode() != 0); + } else { + QCOMPARE(successExpected, runner.processExitCode() == 0); + } + QCOMPARE(stdoutExpected, !remoteStdout.isEmpty()); + QCOMPARE(stderrExpected, !remoteStderr.isEmpty()); +} + +void tst_Ssh::remoteProcessChannels() +{ + const SshConnectionParameters params = getParameters(TestType::Normal); + CHECK_PARAMS(params, TestType::Normal); + SshConnection connection(params); + QVERIFY(waitForConnection(connection)); + + static const QByteArray testString("ChannelTest"); + QByteArray remoteStdout; + QByteArray remoteStderr; + QByteArray remoteData; + SshRemoteProcess::Ptr echoProcess + = connection.createRemoteProcess("printf " + testString + " >&2"); + echoProcess->setReadChannel(QProcess::StandardError); + QEventLoop loop; + connect(echoProcess.data(), &SshRemoteProcess::closed, &loop, &QEventLoop::quit); + connect(echoProcess.data(), &QIODevice::readyRead, + [&remoteData, echoProcess] { remoteData += echoProcess->readAll(); }); + connect(echoProcess.data(), &SshRemoteProcess::readyReadStandardOutput, + [&remoteStdout, echoProcess] { remoteStdout += echoProcess->readAllStandardOutput(); }); + connect(echoProcess.data(), &SshRemoteProcess::readyReadStandardError, + [&remoteStderr, echoProcess] { remoteStderr = testString; }); + echoProcess->start(); + QTimer timer; + QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + timer.setSingleShot(true); + timer.setInterval((params.timeout + 5) * 1000); + timer.start(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(!echoProcess->isRunning()); + QCOMPARE(echoProcess->exitSignal(), SshRemoteProcess::NoSignal); + QCOMPARE(echoProcess->exitCode(), 0); + QVERIFY(remoteStdout.isEmpty()); + QCOMPARE(remoteData, testString); + QCOMPARE(remoteData, remoteStderr); +} + +void tst_Ssh::remoteProcessInput() +{ + const SshConnectionParameters params = getParameters(TestType::Normal); + CHECK_PARAMS(params, TestType::Normal); + SshConnection connection(params); + QVERIFY(waitForConnection(connection)); + + SshRemoteProcess::Ptr catProcess + = connection.createRemoteProcess(QString::fromLatin1("/bin/cat").toUtf8()); + QEventLoop loop; + connect(catProcess.data(), &SshRemoteProcess::started, &loop, &QEventLoop::quit); + connect(catProcess.data(), &SshRemoteProcess::closed, &loop, &QEventLoop::quit); + QTimer timer; + QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + timer.setSingleShot(true); + timer.setInterval((params.timeout + 5) * 1000); + timer.start(); + catProcess->start(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(catProcess->isRunning()); + + static QString testString = "x\r\n"; + connect(catProcess.data(), &QIODevice::readyRead, &loop, &QEventLoop::quit); + QTextStream stream(catProcess.data()); + stream << testString; + stream.flush(); + timer.start(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(catProcess->isRunning()); + + const QString data = QString::fromUtf8(catProcess->readAll()); + QCOMPARE(data, testString); + SshRemoteProcessRunner * const killer = new SshRemoteProcessRunner(this); + killer->run("pkill -9 cat", params); + timer.start(); + loop.exec(); + QVERIFY(!catProcess->isRunning()); + QVERIFY(catProcess->exitCode() != 0 + || catProcess->exitSignal() == SshRemoteProcess::KillSignal); +} + +void tst_Ssh::sftp() +{ + // Connect to server + const SshConnectionParameters params = getParameters(TestType::Normal); + CHECK_PARAMS(params, TestType::Normal); + SshConnection connection(params); + QVERIFY(waitForConnection(connection)); + + // Establish SFTP channel + SftpChannel::Ptr sftpChannel = connection.createSftpChannel(); + QList jobs; + bool invalidFinishedSignal = false; + QString jobError; + QEventLoop loop; + connect(sftpChannel.data(), &SftpChannel::initialized, &loop, &QEventLoop::quit); + connect(sftpChannel.data(), &SftpChannel::channelError, &loop, &QEventLoop::quit); + connect(sftpChannel.data(), &SftpChannel::closed, &loop, &QEventLoop::quit); + connect(sftpChannel.data(), &SftpChannel::finished, + [&loop, &jobs, &invalidFinishedSignal, &jobError](SftpJobId job, const QString &error) { + if (!jobs.removeOne(job)) { + invalidFinishedSignal = true; + loop.quit(); + return; + } + if (!error.isEmpty()) { + jobError = error; + loop.quit(); + return; + } + if (jobs.empty()) + loop.quit(); + }); + QTimer timer; + QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + timer.setSingleShot(true); + timer.setInterval((params.timeout + 5) * 1000); + timer.start(); + sftpChannel->initialize(); + loop.exec(); + QVERIFY(timer.isActive()); + timer.stop(); + QVERIFY(!invalidFinishedSignal); + QCOMPARE(sftpChannel->state(), SftpChannel::Initialized); + + // Create and upload 1000 small files and one big file + QTemporaryDir dirForFilesToUpload; + QTemporaryDir dirForFilesToDownload; + QVERIFY2(dirForFilesToUpload.isValid(), qPrintable(dirForFilesToUpload.errorString())); + QVERIFY2(dirForFilesToDownload.isValid(), qPrintable(dirForFilesToDownload.errorString())); + static const auto getRemoteFilePath = [](const QString &localFileName) { + return QString("/tmp/").append(localFileName).append(".upload"); + }; + const auto getDownloadFilePath = [&dirForFilesToDownload](const QString &localFileName) { + return QString(dirForFilesToDownload.path()).append('/').append(localFileName); + }; + std::srand(QDateTime::currentDateTime().toSecsSinceEpoch()); + for (int i = 0; i < 1000; ++i) { + const QString fileName = "sftptestfile" + QString::number(i + 1); + QFile file(dirForFilesToUpload.path() + '/' + fileName); + QVERIFY2(file.open(QIODevice::WriteOnly), qPrintable(file.errorString())); + int content[1024 / sizeof(int)]; + for (size_t j = 0; j < sizeof content / sizeof content[0]; ++j) + content[j] = qrand(); + file.write(reinterpret_cast(content), sizeof content); + file.close(); + QVERIFY2(file.error() == QFile::NoError, qPrintable(file.errorString())); + const QString remoteFilePath = getRemoteFilePath(fileName); + const SftpJobId uploadJob = sftpChannel->uploadFile(file.fileName(), remoteFilePath, + SftpOverwriteExisting); + QVERIFY(uploadJob != SftpInvalidJob); + jobs << uploadJob; + } + const QString bigFileName("sftpbigfile"); + QFile bigFile(dirForFilesToUpload.path() + '/' + bigFileName); + QVERIFY2(bigFile.open(QIODevice::WriteOnly), qPrintable(bigFile.errorString())); + const int bigFileSize = 100 * 1024 * 1024; + const int blockSize = 8192; + const int blockCount = bigFileSize / blockSize; + for (int block = 0; block < blockCount; ++block) { + int content[blockSize / sizeof(int)]; + for (size_t j = 0; j < sizeof content / sizeof content[0]; ++j) + content[j] = qrand(); + bigFile.write(reinterpret_cast(content), sizeof content); + } + bigFile.close(); + QVERIFY2(bigFile.error() == QFile::NoError, qPrintable(bigFile.errorString())); + const SftpJobId uploadJob = sftpChannel->uploadFile(bigFile.fileName(), + getRemoteFilePath(bigFileName), SftpOverwriteExisting); + QVERIFY(uploadJob != SftpInvalidJob); + jobs << uploadJob; + QCOMPARE(jobs.size(), 1001); + loop.exec(); + QVERIFY(!invalidFinishedSignal); + QVERIFY2(jobError.isEmpty(), qPrintable(jobError)); + QCOMPARE(sftpChannel->state(), SftpChannel::Initialized); + QVERIFY(jobs.empty()); + + // Download the uploaded files to a different location + const QStringList allUploadedFileNames + = QDir(dirForFilesToUpload.path()).entryList(QDir::Files); + QCOMPARE(allUploadedFileNames.size(), 1001); + for (const QString &fileName : allUploadedFileNames) { + const QString localFilePath = dirForFilesToUpload.path() + '/' + fileName; + const QString remoteFilePath = getRemoteFilePath(fileName); + const QString downloadFilePath = getDownloadFilePath(fileName); + const SftpJobId downloadJob = sftpChannel->downloadFile(remoteFilePath, downloadFilePath, + SftpOverwriteExisting); + QVERIFY(downloadJob != SftpInvalidJob); + jobs << downloadJob; + } + QCOMPARE(jobs.size(), 1001); + loop.exec(); + QVERIFY(!invalidFinishedSignal); + QVERIFY2(jobError.isEmpty(), qPrintable(jobError)); + QCOMPARE(sftpChannel->state(), SftpChannel::Initialized); + QVERIFY(jobs.empty()); + + // Compare contents of uploaded and downloaded files + for (const QString &fileName : allUploadedFileNames) { + QFile originalFile(dirForFilesToUpload.path() + '/' + fileName); + QVERIFY2(originalFile.open(QIODevice::ReadOnly), qPrintable(originalFile.errorString())); + QFile downloadedFile(dirForFilesToDownload.path() + '/' + fileName); + QVERIFY2(downloadedFile.open(QIODevice::ReadOnly), + qPrintable(downloadedFile.errorString())); + QVERIFY(originalFile.fileName() != downloadedFile.fileName()); + QCOMPARE(originalFile.size(), downloadedFile.size()); + qint64 bytesLeft = originalFile.size(); + while (bytesLeft > 0) { + const qint64 bytesToRead = qMin(bytesLeft, Q_INT64_C(1024 * 1024)); + const QByteArray origBlock = originalFile.read(bytesToRead); + const QByteArray copyBlock = downloadedFile.read(bytesToRead); + QCOMPARE(origBlock.size(), bytesToRead); + QCOMPARE(origBlock, copyBlock); + bytesLeft -= bytesToRead; + } + } + + // Remove the uploaded files on the remote system + for (const QString &fileName : allUploadedFileNames) { + const QString remoteFilePath = getRemoteFilePath(fileName); + const SftpJobId removeJob = sftpChannel->removeFile(remoteFilePath); + QVERIFY(removeJob != SftpInvalidJob); + jobs << removeJob; + } + loop.exec(); + QVERIFY(!invalidFinishedSignal); + QVERIFY2(jobError.isEmpty(), qPrintable(jobError)); + QCOMPARE(sftpChannel->state(), SftpChannel::Initialized); + QVERIFY(jobs.empty()); + + // Create a directory on the remote system + const QString remoteDirPath = "/tmp/sftptest-" + QDateTime::currentDateTime().toString(); + const SftpJobId mkdirJob = sftpChannel->createDirectory(remoteDirPath); + QVERIFY(mkdirJob != SftpInvalidJob); + jobs << mkdirJob; + loop.exec(); + QVERIFY(!invalidFinishedSignal); + QVERIFY2(jobError.isEmpty(), qPrintable(jobError)); + QCOMPARE(sftpChannel->state(), SftpChannel::Initialized); + QVERIFY(jobs.empty()); + + // Retrieve and check the attributes of the remote directory + QList remoteFileInfo; + const auto fileInfoHandler + = [&remoteFileInfo](SftpJobId, const QList &fileInfoList) { + remoteFileInfo << fileInfoList; + }; + connect(sftpChannel.data(), &SftpChannel::fileInfoAvailable, fileInfoHandler); + const SftpJobId statDirJob = sftpChannel->statFile(remoteDirPath); + QVERIFY(statDirJob != SftpInvalidJob); + jobs << statDirJob; + loop.exec(); + QVERIFY(!invalidFinishedSignal); + QVERIFY2(jobError.isEmpty(), qPrintable(jobError)); + QCOMPARE(sftpChannel->state(), SftpChannel::Initialized); + QVERIFY(jobs.empty()); + QCOMPARE(remoteFileInfo.size(), 1); + const SftpFileInfo remoteDirInfo = remoteFileInfo.takeFirst(); + QCOMPARE(remoteDirInfo.type, FileTypeDirectory); + QCOMPARE(remoteDirInfo.name, QFileInfo(remoteDirPath).fileName()); + + // Retrieve and check the contents of the remote directory + const SftpJobId lsDirJob = sftpChannel->listDirectory(remoteDirPath); + QVERIFY(lsDirJob != SftpInvalidJob); + jobs << lsDirJob; + loop.exec(); + QVERIFY(!invalidFinishedSignal); + QVERIFY2(jobError.isEmpty(), qPrintable(jobError)); + QCOMPARE(sftpChannel->state(), SftpChannel::Initialized); + QVERIFY(jobs.empty()); + QCOMPARE(remoteFileInfo.size(), 2); + for (const SftpFileInfo &fi : remoteFileInfo) { + QCOMPARE(fi.type, FileTypeDirectory); + QVERIFY2(fi.name == "." || fi.name == "..", qPrintable(fi.name)); + } + QVERIFY(remoteFileInfo.first().name != remoteFileInfo.last().name); + + // Remove the remote directory. + const SftpJobId rmDirJob = sftpChannel->removeDirectory(remoteDirPath); + QVERIFY(rmDirJob != SftpInvalidJob); + jobs << rmDirJob; + loop.exec(); + QVERIFY(!invalidFinishedSignal); + QVERIFY2(jobError.isEmpty(), qPrintable(jobError)); + QCOMPARE(sftpChannel->state(), SftpChannel::Initialized); + QVERIFY(jobs.empty()); + + // Closing down + sftpChannel->closeChannel(); + QCOMPARE(sftpChannel->state(), SftpChannel::Closing); + loop.exec(); + QVERIFY(!invalidFinishedSignal); + QVERIFY2(jobError.isEmpty(), qPrintable(jobError)); + QCOMPARE(sftpChannel->state(), SftpChannel::Closed); +} + +bool tst_Ssh::waitForConnection(SshConnection &connection) +{ + QEventLoop loop; + QObject::connect(&connection, &SshConnection::connected, &loop, &QEventLoop::quit); + QObject::connect(&connection, &SshConnection::error, &loop, &QEventLoop::quit); + connection.connectToHost(); + loop.exec(); + if (connection.errorState() != SshNoError) + qDebug() << connection.errorString(); + return connection.state() == SshConnection::Connected && connection.errorState() == SshNoError; +} + +QTEST_MAIN(tst_Ssh) + +#include diff --git a/tests/manual/ssh/errorhandling/errorhandling.pro b/tests/manual/ssh/errorhandling/errorhandling.pro deleted file mode 100644 index 1161d4642da..00000000000 --- a/tests/manual/ssh/errorhandling/errorhandling.pro +++ /dev/null @@ -1,4 +0,0 @@ -include(../ssh.pri) - -TARGET=errorhandling -SOURCES=main.cpp diff --git a/tests/manual/ssh/errorhandling/main.cpp b/tests/manual/ssh/errorhandling/main.cpp deleted file mode 100644 index 2140de5788e..00000000000 --- a/tests/manual/ssh/errorhandling/main.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -using namespace QSsh; - -class Test : public QObject { - Q_OBJECT -public: - Test() - { - m_timeoutTimer.setSingleShot(true); - m_connection = new SshConnection(SshConnectionParameters()); - if (m_connection->state() != SshConnection::Unconnected) { - qDebug("Error: Newly created SSH connection has state %d.", - m_connection->state()); - } - - if (m_connection->createRemoteProcess("")) - qDebug("Error: Unconnected SSH connection creates remote process."); - if (m_connection->createSftpChannel()) - qDebug("Error: Unconnected SSH connection creates SFTP channel."); - - SshConnectionParameters noHost; - noHost.setHost("hgdfxgfhgxfhxgfchxgcf"); - noHost.setPort(12345); - noHost.timeout = 10; - noHost.authenticationType - = SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods; - - SshConnectionParameters noUser; - noUser.setHost("localhost"); - noUser.setPort(22); - noUser.timeout = 30; - noUser.authenticationType - = SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods; - noUser.setUserName("dumdidumpuffpuff"); - noUser.setPassword("whatever"); - - SshConnectionParameters wrongPwd; - wrongPwd.setHost("localhost"); - wrongPwd.setPort(22); - wrongPwd.timeout = 30; - wrongPwd.authenticationType - = SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods; - wrongPwd.setUserName("root"); - noUser.setPassword("thiscantpossiblybeapasswordcanit"); - - SshConnectionParameters invalidKeyFile; - invalidKeyFile.setHost("localhost"); - invalidKeyFile.setPort(22); - invalidKeyFile.timeout = 30; - invalidKeyFile.authenticationType = SshConnectionParameters::AuthenticationTypePublicKey; - invalidKeyFile.setUserName("root"); - invalidKeyFile.privateKeyFile - = QLatin1String("somefilenamethatwedontexpecttocontainavalidkey"); - - // TODO: Create a valid key file and check for authentication error. - - m_testSet << TestItem("Behavior with non-existing host", - noHost, ErrorList() << SshSocketError); - m_testSet << TestItem("Behavior with non-existing user", noUser, - ErrorList() << SshSocketError << SshTimeoutError - << SshAuthenticationError); - m_testSet << TestItem("Behavior with wrong password", wrongPwd, - ErrorList() << SshSocketError << SshTimeoutError - << SshAuthenticationError); - m_testSet << TestItem("Behavior with invalid key file", invalidKeyFile, - ErrorList() << SshSocketError << SshTimeoutError - << SshKeyFileError); - - runNextTest(); - } - - ~Test() - { - delete m_connection; - } - -private: - void handleConnected() - { - qDebug("Error: Received unexpected connected() signal."); - QCoreApplication::exit(EXIT_FAILURE); - } - - void handleDisconnected() - { - qDebug("Error: Received unexpected disconnected() signal."); - QCoreApplication::exit(EXIT_FAILURE); - } - - void handleDataAvailable(const QString &msg) - { - qDebug("Error: Received unexpected dataAvailable() signal. " - "Message was: '%s'.", qPrintable(msg)); - QCoreApplication::exit(EXIT_FAILURE); - } - - void handleError(QSsh::SshError error) - { - if (m_testSet.isEmpty()) { - qDebug("Error: Received error %d, but no test was running.", error); - QCoreApplication::exit(EXIT_FAILURE); - } - - const TestItem testItem = m_testSet.takeFirst(); - if (testItem.allowedErrors.contains(error)) { - qDebug("Received error %d, as expected.", error); - if (m_testSet.isEmpty()) { - qDebug("All tests finished successfully."); - QCoreApplication::quit(); - } else { - runNextTest(); - } - } else { - qDebug("Received unexpected error %d.", error); - QCoreApplication::exit(EXIT_FAILURE); - } - } - - void handleTimeout() - { - if (m_testSet.isEmpty()) { - qDebug("Error: timeout, but no test was running."); - QCoreApplication::exit(EXIT_FAILURE); - } - const TestItem testItem = m_testSet.takeFirst(); - qDebug("Error: The following test timed out: %s", testItem.description); - } - - void runNextTest() - { - if (m_connection) { - disconnect(m_connection, 0, this, 0); - delete m_connection; - } - m_connection = new SshConnection(m_testSet.first().params); - connect(m_connection, &SshConnection::connected, this, &Test::handleConnected); - connect(m_connection, &SshConnection::disconnected, this, &Test::handleDisconnected); - connect(m_connection, &SshConnection::dataAvailable, this, &Test::handleDataAvailable); - connect(m_connection, &SshConnection::error, this, &Test::handleError); - const TestItem &nextItem = m_testSet.first(); - m_timeoutTimer.stop(); - m_timeoutTimer.setInterval(qMax(10000, nextItem.params.timeout * 1000)); - qDebug("Testing: %s", nextItem.description); - m_connection->connectToHost(); - } - - SshConnection *m_connection; - typedef QList ErrorList; - struct TestItem { - TestItem(const char *d, const SshConnectionParameters &p, - const ErrorList &e) : description(d), params(p), allowedErrors(e) {} - - const char *description; - SshConnectionParameters params; - ErrorList allowedErrors; - }; - QList m_testSet; - QTimer m_timeoutTimer; -}; - -int main(int argc, char *argv[]) -{ - QCoreApplication a(argc, argv); - Test t; - - return a.exec(); -} - - -#include "main.moc" diff --git a/tests/manual/ssh/remoteprocess/main.cpp b/tests/manual/ssh/remoteprocess/main.cpp deleted file mode 100644 index 02d5d8ea3d0..00000000000 --- a/tests/manual/ssh/remoteprocess/main.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "argumentscollector.h" -#include "remoteprocesstest.h" - -#include - -#include -#include -#include - -#include -#include - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - bool parseSuccess; - const QSsh::SshConnectionParameters ¶meters - = ArgumentsCollector(app.arguments()).collect(parseSuccess); - if (!parseSuccess) - return EXIT_FAILURE; - RemoteProcessTest remoteProcessTest(parameters); - remoteProcessTest.run(); - return app.exec(); -} diff --git a/tests/manual/ssh/remoteprocess/remoteprocess.pro b/tests/manual/ssh/remoteprocess/remoteprocess.pro deleted file mode 100644 index 11c31a0a36b..00000000000 --- a/tests/manual/ssh/remoteprocess/remoteprocess.pro +++ /dev/null @@ -1,5 +0,0 @@ -include(../ssh.pri) - -TARGET=remoteprocess -SOURCES=main.cpp remoteprocesstest.cpp argumentscollector.cpp -HEADERS=remoteprocesstest.h argumentscollector.h diff --git a/tests/manual/ssh/remoteprocess/remoteprocesstest.cpp b/tests/manual/ssh/remoteprocess/remoteprocesstest.cpp deleted file mode 100644 index 28540768b8c..00000000000 --- a/tests/manual/ssh/remoteprocess/remoteprocesstest.cpp +++ /dev/null @@ -1,366 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "remoteprocesstest.h" - -#include - -#include -#include -#include - -#include - -using namespace QSsh; - -const QByteArray StderrOutput("ChannelTest"); - -RemoteProcessTest::RemoteProcessTest(const SshConnectionParameters ¶ms) - : m_sshParams(params), - m_timeoutTimer(new QTimer(this)), - m_sshConnection(0), - m_remoteRunner(new SshRemoteProcessRunner(this)), - m_state(Inactive) -{ - m_timeoutTimer->setInterval(5000); - connect(m_timeoutTimer, &QTimer::timeout, this, &RemoteProcessTest::handleTimeout); -} - -RemoteProcessTest::~RemoteProcessTest() -{ - delete m_sshConnection; -} - -void RemoteProcessTest::run() -{ - connect(m_remoteRunner, &SshRemoteProcessRunner::connectionError, - this, &RemoteProcessTest::handleConnectionError); - connect(m_remoteRunner, &SshRemoteProcessRunner::processStarted, - this, &RemoteProcessTest::handleProcessStarted); - connect(m_remoteRunner, &SshRemoteProcessRunner::readyReadStandardOutput, - this, &RemoteProcessTest::handleProcessStdout); - connect(m_remoteRunner, &SshRemoteProcessRunner::readyReadStandardError, - this, &RemoteProcessTest::handleProcessStderr); - connect(m_remoteRunner, &SshRemoteProcessRunner::processClosed, - this, &RemoteProcessTest::handleProcessClosed); - - std::cout << "Testing successful remote process... " << std::flush; - m_state = TestingSuccess; - m_started = false; - m_timeoutTimer->start(); - m_remoteRunner->run("ls -a /tmp", m_sshParams); -} - -void RemoteProcessTest::handleConnectionError() -{ - const QString error = m_state == TestingIoDevice || m_state == TestingProcessChannels - ? m_sshConnection->errorString() : m_remoteRunner->lastConnectionErrorString(); - - std::cerr << "Error: Connection failure (" << qPrintable(error) << ")." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); -} - -void RemoteProcessTest::handleProcessStarted() -{ - if (m_started) { - std::cerr << "Error: Received started() signal again." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - } else { - m_started = true; - if (m_state == TestingCrash) { - SshRemoteProcessRunner * const killer = new SshRemoteProcessRunner(this); - killer->run("pkill -9 sleep", m_sshParams); - } else if (m_state == TestingIoDevice) { - connect(m_catProcess.data(), &QIODevice::readyRead, - this, &RemoteProcessTest::handleReadyRead); - m_textStream = new QTextStream(m_catProcess.data()); - *m_textStream << testString(); - m_textStream->flush(); - } - } -} - -void RemoteProcessTest::handleProcessStdout() -{ - if (!m_started) { - std::cerr << "Error: Remote output from non-started process." - << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - } else if (m_state != TestingSuccess && m_state != TestingTerminal) { - std::cerr << "Error: Got remote standard output in state " << m_state - << "." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - } else { - m_remoteStdout += m_remoteRunner->readAllStandardOutput(); - } -} - -void RemoteProcessTest::handleProcessStderr() -{ - if (!m_started) { - std::cerr << "Error: Remote error output from non-started process." - << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - } else if (m_state == TestingSuccess) { - std::cerr << "Error: Unexpected remote standard error output." - << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - } else { - m_remoteStderr += m_remoteRunner->readAllStandardError(); - } -} - -void RemoteProcessTest::handleProcessClosed(int exitStatus) -{ - switch (exitStatus) { - case SshRemoteProcess::NormalExit: - if (!m_started) { - std::cerr << "Error: Process exited without starting." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - switch (m_state) { - case TestingSuccess: { - const int exitCode = m_remoteRunner->processExitCode(); - if (exitCode != 0) { - std::cerr << "Error: exit code is " << exitCode - << ", expected zero." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - if (m_remoteStdout.isEmpty()) { - std::cerr << "Error: Command did not produce output." - << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - - std::cout << "Ok.\nTesting unsuccessful remote process... " << std::flush; - m_state = TestingFailure; - m_started = false; - m_timeoutTimer->start(); - m_remoteRunner->run("top -n 1", m_sshParams); // Does not succeed without terminal. - break; - } - case TestingFailure: { - const int exitCode = m_remoteRunner->processExitCode(); - if (exitCode == 0) { - std::cerr << "Error: exit code is zero, expected non-zero." - << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - if (m_remoteStderr.isEmpty()) { - std::cerr << "Error: Command did not produce error output." << std::flush; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - - std::cout << "Ok.\nTesting crashing remote process... " << std::flush; - m_state = TestingCrash; - m_started = false; - m_timeoutTimer->start(); - m_remoteRunner->run("/bin/sleep 100", m_sshParams); - break; - } - case TestingCrash: - if (m_remoteRunner->processExitCode() == 0) { - std::cerr << "Error: Successful exit from process that was " - "supposed to crash." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - } else { - // Some shells (e.g. mksh) don't report "killed", but just a non-zero exit code. - handleSuccessfulCrashTest(); - } - break; - case TestingTerminal: { - const int exitCode = m_remoteRunner->processExitCode(); - if (exitCode != 0) { - std::cerr << "Error: exit code is " << exitCode - << ", expected zero." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - if (m_remoteStdout.isEmpty()) { - std::cerr << "Error: Command did not produce output." - << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - std::cout << "Ok.\nTesting I/O device functionality... " << std::flush; - m_state = TestingIoDevice; - m_sshConnection = new SshConnection(m_sshParams); - connect(m_sshConnection, &SshConnection::connected, - this, &RemoteProcessTest::handleConnected); - connect(m_sshConnection, &SshConnection::error, - this, &RemoteProcessTest::handleConnectionError); - m_sshConnection->connectToHost(); - m_timeoutTimer->start(); - break; - } - case TestingIoDevice: - if (m_catProcess->exitCode() == 0) { - std::cerr << "Error: Successful exit from process that was supposed to crash." - << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - } else { - handleSuccessfulIoTest(); - } - break; - case TestingProcessChannels: - if (m_remoteStderr.isEmpty()) { - std::cerr << "Error: Did not receive readyReadStderr()." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - if (m_remoteData != StderrOutput) { - std::cerr << "Error: Expected output '" << StderrOutput.data() << "', received '" - << m_remoteData.data() << "'." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - std::cout << "Ok.\nAll tests succeeded." << std::endl; - QCoreApplication::quit(); - break; - case Inactive: - Q_ASSERT(false); - } - break; - case SshRemoteProcess::FailedToStart: - if (m_started) { - std::cerr << "Error: Got 'failed to start' signal for process " - "that has not started yet." << std::endl; - } else { - std::cerr << "Error: Process failed to start." << std::endl; - } - QCoreApplication::exit(EXIT_FAILURE); - break; - case SshRemoteProcess::CrashExit: - switch (m_state) { - case TestingCrash: - handleSuccessfulCrashTest(); - break; - case TestingIoDevice: - handleSuccessfulIoTest(); - break; - default: - std::cerr << "Error: Unexpected crash." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - } -} - -void RemoteProcessTest::handleTimeout() -{ - std::cerr << "Error: Timeout waiting for progress." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); -} - -void RemoteProcessTest::handleConnected() -{ - Q_ASSERT(m_state == TestingIoDevice); - - m_catProcess = m_sshConnection->createRemoteProcess(QString::fromLatin1("/bin/cat").toUtf8()); - connect(m_catProcess.data(), &SshRemoteProcess::started, - this, &RemoteProcessTest::handleProcessStarted); - connect(m_catProcess.data(), &SshRemoteProcess::closed, - this, &RemoteProcessTest::handleProcessClosed); - m_started = false; - m_timeoutTimer->start(); - m_catProcess->start(); -} - -QString RemoteProcessTest::testString() const -{ - return QLatin1String("x\r\n"); -} - -void RemoteProcessTest::handleReadyRead() -{ - switch (m_state) { - case TestingIoDevice: { - const QString &data = QString::fromUtf8(m_catProcess->readAll()); - if (data != testString()) { - std::cerr << "Testing of QIODevice functionality failed: Expected '" - << qPrintable(testString()) << "', got '" << qPrintable(data) << "'." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); - } - SshRemoteProcessRunner * const killer = new SshRemoteProcessRunner(this); - killer->run("pkill -9 cat", m_sshParams); - break; - } - case TestingProcessChannels: - m_remoteData += m_echoProcess->readAll(); - break; - default: - qFatal("%s: Unexpected state %d.", Q_FUNC_INFO, m_state); - } - -} - -void RemoteProcessTest::handleReadyReadStdout() -{ - Q_ASSERT(m_state == TestingProcessChannels); - - std::cerr << "Error: Received unexpected stdout data." << std::endl; - QCoreApplication::exit(EXIT_FAILURE); -} - -void RemoteProcessTest::handleReadyReadStderr() -{ - Q_ASSERT(m_state == TestingProcessChannels); - - m_remoteStderr = "dummy"; -} - -void RemoteProcessTest::handleSuccessfulCrashTest() -{ - std::cout << "Ok.\nTesting remote process with terminal... " << std::flush; - m_state = TestingTerminal; - m_started = false; - m_timeoutTimer->start(); - m_remoteRunner->runInTerminal("top -n 1", SshPseudoTerminal(), m_sshParams); -} - -void RemoteProcessTest::handleSuccessfulIoTest() -{ - std::cout << "Ok\nTesting process channels... " << std::flush; - m_state = TestingProcessChannels; - m_started = false; - m_remoteStderr.clear(); - m_echoProcess = m_sshConnection->createRemoteProcess("printf " + StderrOutput + " >&2"); - m_echoProcess->setReadChannel(QProcess::StandardError); - connect(m_echoProcess.data(), &SshRemoteProcess::started, - this, &RemoteProcessTest::handleProcessStarted); - connect(m_echoProcess.data(), &SshRemoteProcess::closed, - this, &RemoteProcessTest::handleProcessClosed); - connect(m_echoProcess.data(), &QIODevice::readyRead, - this, &RemoteProcessTest::handleReadyRead); - connect(m_echoProcess.data(), &SshRemoteProcess::readyReadStandardError, - this, &RemoteProcessTest::handleReadyReadStderr); - m_echoProcess->start(); - m_timeoutTimer->start(); -} diff --git a/tests/manual/ssh/remoteprocess/remoteprocesstest.h b/tests/manual/ssh/remoteprocess/remoteprocesstest.h deleted file mode 100644 index b3c8ebc3e3f..00000000000 --- a/tests/manual/ssh/remoteprocess/remoteprocesstest.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include - -#include - -QT_FORWARD_DECLARE_CLASS(QTextStream) -QT_FORWARD_DECLARE_CLASS(QTimer) - -class RemoteProcessTest : public QObject -{ - Q_OBJECT -public: - RemoteProcessTest(const QSsh::SshConnectionParameters ¶ms); - ~RemoteProcessTest(); - void run(); - -private: - enum State { - Inactive, TestingSuccess, TestingFailure, TestingCrash, TestingTerminal, TestingIoDevice, - TestingProcessChannels - }; - - void handleConnectionError(); - void handleProcessStarted(); - void handleProcessStdout(); - void handleProcessStderr(); - void handleProcessClosed(int exitStatus); - void handleTimeout(); - void handleReadyRead(); - void handleReadyReadStdout(); - void handleReadyReadStderr(); - void handleConnected(); - - QString testString() const; - void handleSuccessfulCrashTest(); - void handleSuccessfulIoTest(); - - const QSsh::SshConnectionParameters m_sshParams; - QTimer * const m_timeoutTimer; - QTextStream *m_textStream; - QSsh::SshRemoteProcess::Ptr m_catProcess; - QSsh::SshRemoteProcess::Ptr m_echoProcess; - QSsh::SshConnection *m_sshConnection; - QSsh::SshRemoteProcessRunner * const m_remoteRunner; - QByteArray m_remoteStdout; - QByteArray m_remoteStderr; - QByteArray m_remoteData; - State m_state; - bool m_started; -}; diff --git a/tests/manual/ssh/sftp/argumentscollector.cpp b/tests/manual/ssh/sftp/argumentscollector.cpp deleted file mode 100644 index be8cb743b06..00000000000 --- a/tests/manual/ssh/sftp/argumentscollector.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "argumentscollector.h" - -#include - -using namespace QSsh; - -using namespace std; - -ArgumentsCollector::ArgumentsCollector(const QStringList &args) - : m_arguments(args) -{ -} - -Parameters ArgumentsCollector::collect(bool &success) const -{ - Parameters parameters; - parameters.sshParams.options &= ~SshIgnoreDefaultProxy; - try { - bool authTypeGiven = false; - bool portGiven = false; - bool timeoutGiven = false; - bool smallFileCountGiven = false; - bool bigFileSizeGiven = false; - bool proxySettingGiven = false; - int pos; - int port = 22; - for (pos = 1; pos < m_arguments.count() - 1; ++pos) { - QString host; - QString user; - if (checkAndSetStringArg(pos, host, "-h") || checkAndSetStringArg(pos, user, "-u")) { - parameters.sshParams.setHost(host); - parameters.sshParams.setUserName(user); - continue; - } - if (checkAndSetIntArg(pos, port, portGiven, "-p") - || checkAndSetIntArg(pos, parameters.sshParams.timeout, timeoutGiven, "-t") - || checkAndSetIntArg(pos, parameters.smallFileCount, smallFileCountGiven, "-c") - || checkAndSetIntArg(pos, parameters.bigFileSize, bigFileSizeGiven, "-s")) - continue; - QString pass; - if (checkAndSetStringArg(pos, pass, "-pwd")) { - parameters.sshParams.setPassword(pass); - if (!parameters.sshParams.privateKeyFile.isEmpty()) - throw ArgumentErrorException(QLatin1String("-pwd and -k are mutually exclusive.")); - parameters.sshParams.authenticationType - = SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods; - authTypeGiven = true; - continue; - } - if (checkAndSetStringArg(pos, parameters.sshParams.privateKeyFile, "-k")) { - if (!parameters.sshParams.password().isEmpty()) - throw ArgumentErrorException(QLatin1String("-pwd and -k are mutually exclusive.")); - parameters.sshParams.authenticationType - = SshConnectionParameters::AuthenticationTypePublicKey; - authTypeGiven = true; - continue; - } - if (!checkForNoProxy(pos, parameters.sshParams.options, proxySettingGiven)) - throw ArgumentErrorException(QLatin1String("unknown option ") + m_arguments.at(pos)); - } - - Q_ASSERT(pos <= m_arguments.count()); - if (pos == m_arguments.count() - 1) { - if (!checkForNoProxy(pos, parameters.sshParams.options, proxySettingGiven)) - throw ArgumentErrorException(QLatin1String("unknown option ") + m_arguments.at(pos)); - } - - if (!authTypeGiven) - throw ArgumentErrorException(QLatin1String("No authentication argument given.")); - if (parameters.sshParams.host().isEmpty()) - throw ArgumentErrorException(QLatin1String("No host given.")); - if (parameters.sshParams.userName().isEmpty()) - throw ArgumentErrorException(QLatin1String("No user name given.")); - - parameters.sshParams.setPort(portGiven ? port : 22); - if (!timeoutGiven) - parameters.sshParams.timeout = 30; - if (!smallFileCountGiven) - parameters.smallFileCount = 1000; - if (!bigFileSizeGiven) - parameters.bigFileSize = 1024; - success = true; - } catch (ArgumentErrorException &ex) { - cerr << "Error: " << qPrintable(ex.error) << endl; - printUsage(); - success = false; - } - return parameters; -} - -void ArgumentsCollector::printUsage() const -{ - cerr << "Usage: " << qPrintable(m_arguments.first()) - << " -h -u " - << "-pwd | -k [ -p ] " - << "[ -t ] [ -c ] " - << "[ -s ] [ -no-proxy ]" << endl; -} - -bool ArgumentsCollector::checkAndSetStringArg(int &pos, QString &arg, const char *opt) const -{ - if (m_arguments.at(pos) == QLatin1String(opt)) { - if (!arg.isEmpty()) { - throw ArgumentErrorException(QLatin1String("option ") + QLatin1String(opt) - + QLatin1String(" was given twice.")); - } - arg = m_arguments.at(++pos); - if (arg.isEmpty() && QLatin1String(opt) != QLatin1String("-pwd")) - throw ArgumentErrorException(QLatin1String("empty argument not allowed here.")); - return true; - } - return false; -} - -bool ArgumentsCollector::checkAndSetIntArg(int &pos, int &val, - bool &alreadyGiven, const char *opt) const -{ - if (m_arguments.at(pos) == QLatin1String(opt)) { - if (alreadyGiven) { - throw ArgumentErrorException(QLatin1String("option ") + QLatin1String(opt) - + QLatin1String(" was given twice.")); - } - bool isNumber; - val = m_arguments.at(++pos).toInt(&isNumber); - if (!isNumber) { - throw ArgumentErrorException(QLatin1String("option ") + QLatin1String(opt) - + QLatin1String(" needs integer argument")); - } - alreadyGiven = true; - return true; - } - return false; -} - -bool ArgumentsCollector::checkForNoProxy(int &pos, SshConnectionOptions &options, - bool &alreadyGiven) const -{ - if (m_arguments.at(pos) == QLatin1String("-no-proxy")) { - if (alreadyGiven) - throw ArgumentErrorException(QLatin1String("proxy setting given twice.")); - options |= SshIgnoreDefaultProxy; - alreadyGiven = true; - return true; - } - return false; -} diff --git a/tests/manual/ssh/sftp/argumentscollector.h b/tests/manual/ssh/sftp/argumentscollector.h deleted file mode 100644 index 67b69a7f474..00000000000 --- a/tests/manual/ssh/sftp/argumentscollector.h +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "parameters.h" - -#include - -class ArgumentsCollector -{ -public: - ArgumentsCollector(const QStringList &args); - Parameters collect(bool &success) const; -private: - struct ArgumentErrorException - { - ArgumentErrorException(const QString &error) : error(error) {} - const QString error; - }; - - void printUsage() const; - bool checkAndSetStringArg(int &pos, QString &arg, const char *opt) const; - bool checkAndSetIntArg(int &pos, int &val, bool &alreadyGiven, - const char *opt) const; - bool checkForNoProxy(int &pos, QSsh::SshConnectionOptions &options, - bool &alreadyGiven) const; - - const QStringList m_arguments; -}; diff --git a/tests/manual/ssh/sftp/main.cpp b/tests/manual/ssh/sftp/main.cpp deleted file mode 100644 index 2eccedee32d..00000000000 --- a/tests/manual/ssh/sftp/main.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "argumentscollector.h" -#include "sftptest.h" - -#include -#include - -#include -#include -#include - -#include -#include - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - bool parseSuccess; - const Parameters parameters = ArgumentsCollector(app.arguments()).collect(parseSuccess); - if (!parseSuccess) - return EXIT_FAILURE; - SftpTest sftpTest(parameters); - sftpTest.run(); - return app.exec(); -} diff --git a/tests/manual/ssh/sftp/parameters.h b/tests/manual/ssh/sftp/parameters.h deleted file mode 100644 index d947fa9d7da..00000000000 --- a/tests/manual/ssh/sftp/parameters.h +++ /dev/null @@ -1,34 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include - -struct Parameters { - QSsh::SshConnectionParameters sshParams; - int smallFileCount; - int bigFileSize; -}; diff --git a/tests/manual/ssh/sftp/sftp.pro b/tests/manual/ssh/sftp/sftp.pro deleted file mode 100644 index abb26a865cb..00000000000 --- a/tests/manual/ssh/sftp/sftp.pro +++ /dev/null @@ -1,6 +0,0 @@ -include(../ssh.pri) - -TARGET = sftp -SOURCES = main.cpp sftptest.cpp argumentscollector.cpp -HEADERS = sftptest.h argumentscollector.h parameters.h - diff --git a/tests/manual/ssh/sftp/sftptest.cpp b/tests/manual/ssh/sftp/sftptest.cpp deleted file mode 100644 index 928c53f6e37..00000000000 --- a/tests/manual/ssh/sftp/sftptest.cpp +++ /dev/null @@ -1,631 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "sftptest.h" - -#include -#include -#include -#include -#include - -#include - -#include - -using namespace QSsh; - -SftpTest::SftpTest(const Parameters ¶ms) - : m_parameters(params), m_state(Inactive), m_error(false), m_connection(0), - m_bigFileUploadJob(SftpInvalidJob), - m_bigFileDownloadJob(SftpInvalidJob), - m_bigFileRemovalJob(SftpInvalidJob), - m_mkdirJob(SftpInvalidJob), - m_statDirJob(SftpInvalidJob), - m_lsDirJob(SftpInvalidJob), - m_rmDirJob(SftpInvalidJob) -{ -} - -SftpTest::~SftpTest() -{ - removeFiles(true); - delete m_connection; -} - -void SftpTest::run() -{ - m_connection = new SshConnection(m_parameters.sshParams); - connect(m_connection, &SshConnection::connected, this, &SftpTest::handleConnected); - connect(m_connection, &SshConnection::error, this, &SftpTest::handleError); - connect(m_connection, &SshConnection::disconnected, this, &SftpTest::handleDisconnected); - std::cout << "Connecting to host '" - << qPrintable(m_parameters.sshParams.host()) << "'..." << std::endl; - m_state = Connecting; - m_connection->connectToHost(); -} - -void SftpTest::handleConnected() -{ - if (m_state != Connecting) { - std::cerr << "Unexpected state " << m_state << " in function " - << Q_FUNC_INFO << "." << std::endl; - earlyDisconnectFromHost(); - } else { - std::cout << "Connected. Initializing SFTP channel..." << std::endl; - m_channel = m_connection->createSftpChannel(); - connect(m_channel.data(), &SftpChannel::initialized, - this, &SftpTest::handleChannelInitialized); - connect(m_channel.data(), &SftpChannel::channelError, - this, &SftpTest::handleChannelInitializationFailure); - connect(m_channel.data(), &SftpChannel::finished, - this, static_cast( - &SftpTest::handleJobFinished)); - connect(m_channel.data(), &SftpChannel::fileInfoAvailable, - this, &SftpTest::handleFileInfo); - connect(m_channel.data(), &SftpChannel::closed, - this, &SftpTest::handleChannelClosed); - m_state = InitializingChannel; - m_channel->initialize(); - } -} - -void SftpTest::handleDisconnected() -{ - if (m_state != Disconnecting) { - std::cerr << "Unexpected state " << m_state << " in function " - << Q_FUNC_INFO << std::endl; - m_error = true; - } else { - std::cout << "Connection closed." << std::endl; - } - std::cout << "Test finished. "; - if (m_error) - std::cout << "There were errors."; - else - std::cout << "No errors encountered."; - std::cout << std::endl; - QCoreApplication::exit(m_error ? EXIT_FAILURE : EXIT_SUCCESS); -} - -void SftpTest::handleError() -{ - std::cerr << "Encountered SSH error: " - << qPrintable(m_connection->errorString()) << "." << std::endl; - m_error = true; - m_state = Disconnecting; - QCoreApplication::exit(EXIT_FAILURE); -} - -void SftpTest::handleChannelInitialized() -{ - if (m_state != InitializingChannel) { - std::cerr << "Unexpected state " << m_state << "in function " - << Q_FUNC_INFO << "." << std::endl; - earlyDisconnectFromHost(); - return; - } - - std::cout << "Creating " << m_parameters.smallFileCount - << " files of 1 KB each ..." << std::endl; - std::srand(QDateTime::currentDateTime().toSecsSinceEpoch()); - for (int i = 0; i < m_parameters.smallFileCount; ++i) { - const QString fileName - = QLatin1String("sftptestfile") + QString::number(i + 1); - const FilePtr file(new QFile(QDir::tempPath() + QLatin1Char('/') - + fileName)); - bool success = true; - if (!file->open(QIODevice::WriteOnly | QIODevice::Truncate)) - success = false; - if (success) { - int content[1024/sizeof(int)]; - for (size_t j = 0; j < sizeof content / sizeof content[0]; ++j) - content[j] = qrand(); - file->write(reinterpret_cast(content), sizeof content); - file->close(); - } - success = success && file->error() == QFile::NoError; - if (!success) { - std::cerr << "Error creating local file " - << qPrintable(file->fileName()) << "." << std::endl; - earlyDisconnectFromHost(); - return; - } - m_localSmallFiles << file; - } - std::cout << "Files created. Now uploading..." << std::endl; - foreach (const FilePtr &file, m_localSmallFiles) { - const QString localFilePath = file->fileName(); - const QString remoteFp - = remoteFilePath(QFileInfo(localFilePath).fileName()); - const SftpJobId uploadJob = m_channel->uploadFile(file->fileName(), - remoteFp, SftpOverwriteExisting); - if (uploadJob == SftpInvalidJob) { - std::cerr << "Error uploading local file " - << qPrintable(localFilePath) << " to remote file " - << qPrintable(remoteFp) << "." << std::endl; - earlyDisconnectFromHost(); - return; - } - m_smallFilesUploadJobs.insert(uploadJob, remoteFp); - } - m_state = UploadingSmall; -} - -void SftpTest::handleChannelInitializationFailure(const QString &reason) -{ - std::cerr << "Could not initialize SFTP channel: " << qPrintable(reason) - << "." << std::endl; - earlyDisconnectFromHost(); -} - -void SftpTest::handleChannelClosed() -{ - if (m_state != ChannelClosing) { - std::cerr << "Unexpected state " << m_state << " in function " - << Q_FUNC_INFO << "." << std::endl; - } else { - std::cout << "SFTP channel closed. Now disconnecting..." << std::endl; - } - m_state = Disconnecting; - m_connection->disconnectFromHost(); -} - -void SftpTest::handleJobFinished(SftpJobId job, const QString &error) -{ - switch (m_state) { - case UploadingSmall: - if (!handleJobFinished(job, m_smallFilesUploadJobs, error, "uploading")) - return; - if (m_smallFilesUploadJobs.isEmpty()) { - std::cout << "Uploading finished, now downloading for comparison..." - << std::endl; - foreach (const FilePtr &file, m_localSmallFiles) { - const QString localFilePath = file->fileName(); - const QString remoteFp - = remoteFilePath(QFileInfo(localFilePath).fileName()); - const QString downloadFilePath = cmpFileName(localFilePath); - const SftpJobId downloadJob = m_channel->downloadFile(remoteFp, - downloadFilePath, SftpOverwriteExisting); - if (downloadJob == SftpInvalidJob) { - std::cerr << "Error downloading remote file " - << qPrintable(remoteFp) << " to local file " - << qPrintable(downloadFilePath) << "." << std::endl; - earlyDisconnectFromHost(); - return; - } - m_smallFilesDownloadJobs.insert(downloadJob, remoteFp); - } - m_state = DownloadingSmall; - } - break; - case DownloadingSmall: - if (!handleJobFinished(job, m_smallFilesDownloadJobs, error, "downloading")) - return; - if (m_smallFilesDownloadJobs.isEmpty()) { - std::cout << "Downloading finished, now comparing..." << std::endl; - foreach (const FilePtr &ptr, m_localSmallFiles) { - if (!ptr->open(QIODevice::ReadOnly)) { - std::cerr << "Error opening local file " - << qPrintable(ptr->fileName()) << "." << std::endl; - earlyDisconnectFromHost(); - return; - } - const QString downloadedFilePath = cmpFileName(ptr->fileName()); - QFile downloadedFile(downloadedFilePath); - if (!downloadedFile.open(QIODevice::ReadOnly)) { - std::cerr << "Error opening downloaded file " - << qPrintable(downloadedFilePath) << "." << std::endl; - earlyDisconnectFromHost(); - return; - } - if (!compareFiles(ptr.data(), &downloadedFile)) - return; - } - - std::cout << "Comparisons successful, now removing files..." - << std::endl; - QList remoteFilePaths; - foreach (const FilePtr &ptr, m_localSmallFiles) { - const QString downloadedFilePath = cmpFileName(ptr->fileName()); - remoteFilePaths - << remoteFilePath(QFileInfo(ptr->fileName()).fileName()); - if (!ptr->remove()) { - std::cerr << "Error: Failed to remove local file '" - << qPrintable(ptr->fileName()) << "'." << std::endl; - earlyDisconnectFromHost(); - } - if (!QFile::remove(downloadedFilePath)) { - std::cerr << "Error: Failed to remove downloaded file '" - << qPrintable(downloadedFilePath) << "'." << std::endl; - earlyDisconnectFromHost(); - } - } - m_localSmallFiles.clear(); - foreach (const QString &remoteFp, remoteFilePaths) { - m_smallFilesRemovalJobs.insert(m_channel->removeFile(remoteFp), - remoteFp); - } - m_state = RemovingSmall; - } - break; - case RemovingSmall: - if (!handleJobFinished(job, m_smallFilesRemovalJobs, error, "removing")) - return; - if (m_smallFilesRemovalJobs.isEmpty()) { - std::cout << "Small files successfully removed. " - << "Now creating big file..." << std::endl; - const QLatin1String bigFileName("sftpbigfile"); - m_localBigFile = FilePtr(new QFile(QDir::tempPath() - + QLatin1Char('/') + bigFileName)); - bool success = m_localBigFile->open(QIODevice::WriteOnly); - const int blockSize = 8192; - const quint64 blockCount - = static_cast(m_parameters.bigFileSize)*1024*1024/blockSize; - for (quint64 block = 0; block < blockCount; ++block) { - int content[blockSize/sizeof(int)]; - for (size_t j = 0; j < sizeof content / sizeof content[0]; ++j) - content[j] = qrand(); - m_localBigFile->write(reinterpret_cast(content), - sizeof content); - } - m_localBigFile->close(); - success = success && m_localBigFile->error() == QFile::NoError; - if (!success) { - std::cerr << "Error trying to create big file '" - << qPrintable(m_localBigFile->fileName()) << "'." - << std::endl; - earlyDisconnectFromHost(); - return; - } - - std::cout << "Big file created. Now uploading ..." << std::endl; - m_bigJobTimer.start(); - m_bigFileUploadJob - = m_channel->uploadFile(m_localBigFile->fileName(), - remoteFilePath(bigFileName), SftpOverwriteExisting); - if (m_bigFileUploadJob == SftpInvalidJob) { - std::cerr << "Error uploading file '" << bigFileName.latin1() - << "'." << std::endl; - earlyDisconnectFromHost(); - return; - } - m_state = UploadingBig; - } - break; - case UploadingBig: { - if (!handleBigJobFinished(job, m_bigFileUploadJob, error, "uploading")) - return; - const qint64 msecs = m_bigJobTimer.elapsed(); - std::cout << "Successfully uploaded big file. Took " << (msecs/1000) - << " seconds for " << m_parameters.bigFileSize << " MB." - << std::endl; - const QString localFilePath = m_localBigFile->fileName(); - const QString downloadedFilePath = cmpFileName(localFilePath); - const QString remoteFp - = remoteFilePath(QFileInfo(localFilePath).fileName()); - std::cout << "Now downloading big file for comparison..." << std::endl; - m_bigJobTimer.start(); - m_bigFileDownloadJob = m_channel->downloadFile(remoteFp, - downloadedFilePath, SftpOverwriteExisting); - if (m_bigFileDownloadJob == SftpInvalidJob) { - std::cerr << "Error downloading remote file '" - << qPrintable(remoteFp) << "' to local file '" - << qPrintable(downloadedFilePath) << "'." << std::endl; - earlyDisconnectFromHost(); - return; - } - m_state = DownloadingBig; - break; - } - case DownloadingBig: { - if (!handleBigJobFinished(job, m_bigFileDownloadJob, error, "downloading")) - return; - const qint64 msecs = m_bigJobTimer.elapsed(); - std::cout << "Successfully downloaded big file. Took " << (msecs/1000) - << " seconds for " << m_parameters.bigFileSize << " MB." - << std::endl; - std::cout << "Now comparing big files..." << std::endl; - QFile downloadedFile(cmpFileName(m_localBigFile->fileName())); - if (!downloadedFile.open(QIODevice::ReadOnly)) { - std::cerr << "Error opening downloaded file '" - << qPrintable(downloadedFile.fileName()) << "': " - << qPrintable(downloadedFile.errorString()) << "." << std::endl; - earlyDisconnectFromHost(); - return; - } - if (!m_localBigFile->open(QIODevice::ReadOnly)) { - std::cerr << "Error opening big file '" - << qPrintable(m_localBigFile->fileName()) << "': " - << qPrintable(m_localBigFile->errorString()) << "." - << std::endl; - earlyDisconnectFromHost(); - return; - } - if (!compareFiles(m_localBigFile.data(), &downloadedFile)) - return; - std::cout << "Comparison successful. Now removing big files..." - << std::endl; - if (!m_localBigFile->remove()) { - std::cerr << "Error: Could not remove file '" - << qPrintable(m_localBigFile->fileName()) << "'." << std::endl; - earlyDisconnectFromHost(); - return; - } - if (!downloadedFile.remove()) { - std::cerr << "Error: Could not remove file '" - << qPrintable(downloadedFile.fileName()) << "'." << std::endl; - earlyDisconnectFromHost(); - return; - } - const QString remoteFp - = remoteFilePath(QFileInfo(m_localBigFile->fileName()).fileName()); - m_bigFileRemovalJob = m_channel->removeFile(remoteFp); - m_state = RemovingBig; - break; - } - case RemovingBig: - if (!handleBigJobFinished(job, m_bigFileRemovalJob, error, "removing")) - return; - std::cout << "Big files successfully removed. " - << "Now creating remote directory..." << std::endl; - m_remoteDirPath = QLatin1String("/tmp/sftptest-") + QDateTime::currentDateTime().toString(); - m_mkdirJob = m_channel->createDirectory(m_remoteDirPath); - m_state = CreatingDir; - break; - case CreatingDir: - if (!handleJobFinished(job, m_mkdirJob, error, "creating remote directory")) - return; - std::cout << "Directory successfully created. Now checking directory attributes..." - << std::endl; - m_statDirJob = m_channel->statFile(m_remoteDirPath); - m_state = CheckingDirAttributes; - break; - case CheckingDirAttributes: { - if (!handleJobFinished(job, m_statDirJob, error, "checking directory attributes")) - return; - if (m_dirInfo.type != FileTypeDirectory) { - std::cerr << "Error: Newly created directory has file type " << m_dirInfo.type - << ", expected was " << FileTypeDirectory << "." << std::endl; - earlyDisconnectFromHost(); - return; - } - const QString fileName = QFileInfo(m_remoteDirPath).fileName(); - if (m_dirInfo.name != fileName) { - std::cerr << "Error: Remote directory reports file name '" - << qPrintable(m_dirInfo.name) << "', expected '" << qPrintable(fileName) << "'." - << std::endl; - earlyDisconnectFromHost(); - return; - } - std::cout << "Directory attributes ok. Now checking directory contents..." << std::endl; - m_lsDirJob = m_channel->listDirectory(m_remoteDirPath); - m_state = CheckingDirContents; - break; - } - case CheckingDirContents: - if (!handleJobFinished(job, m_lsDirJob, error, "checking directory contents")) - return; - if (m_dirContents.count() != 2) { - std::cerr << "Error: Remote directory has " << m_dirContents.count() - << " entries, expected 2." << std::endl; - earlyDisconnectFromHost(); - return; - } - foreach (const SftpFileInfo &fi, m_dirContents) { - if (fi.type != FileTypeDirectory) { - std::cerr << "Error: Remote directory has entry of type " << fi.type - << ", expected " << FileTypeDirectory << "." << std::endl; - earlyDisconnectFromHost(); - return; - } - if (fi.name != QLatin1String(".") && fi.name != QLatin1String("..")) { - std::cerr << "Error: Remote directory has entry '" << qPrintable(fi.name) - << "', expected '.' or '..'." << std::endl; - earlyDisconnectFromHost(); - return; - } - } - if (m_dirContents.first().name == m_dirContents.last().name) { - std::cerr << "Error: Remote directory has two entries of the same name." << std::endl; - earlyDisconnectFromHost(); - return; - } - std::cout << "Directory contents ok. Now removing directory..." << std::endl; - m_rmDirJob = m_channel->removeDirectory(m_remoteDirPath); - m_state = RemovingDir; - break; - case RemovingDir: - if (!handleJobFinished(job, m_rmDirJob, error, "removing directory")) - return; - std::cout << "Directory successfully removed. Now closing the SFTP channel..." << std::endl; - m_state = ChannelClosing; - m_channel->closeChannel(); - break; - case Disconnecting: - break; - default: - if (!m_error) { - std::cerr << "Unexpected state " << m_state << " in function " - << Q_FUNC_INFO << "." << std::endl; - earlyDisconnectFromHost(); - } - } -} - -void SftpTest::handleFileInfo(SftpJobId job, const QList &fileInfoList) -{ - switch (m_state) { - case CheckingDirAttributes: { - static int count = 0; - if (!checkJobId(job, m_statDirJob, "checking directory attributes")) - return; - if (++count > 1) { - std::cerr << "Error: More than one reply for directory attributes check." << std::endl; - earlyDisconnectFromHost(); - return; - } - m_dirInfo = fileInfoList.first(); - break; - } - case CheckingDirContents: - if (!checkJobId(job, m_lsDirJob, "checking directory contents")) - return; - m_dirContents << fileInfoList; - break; - default: - std::cerr << "Error: Unexpected file info in state " << m_state << "." << std::endl; - earlyDisconnectFromHost(); - } -} - -void SftpTest::removeFile(const FilePtr &file, bool remoteToo) -{ - if (!file) - return; - const QString localFilePath = file->fileName(); - file->remove(); - QFile::remove(cmpFileName(localFilePath)); - if (remoteToo && m_channel - && m_channel->state() == SftpChannel::Initialized) - m_channel->removeFile(remoteFilePath(QFileInfo(localFilePath).fileName())); -} - -QString SftpTest::cmpFileName(const QString &fileName) const -{ - return fileName + QLatin1String(".cmp"); -} - -QString SftpTest::remoteFilePath(const QString &localFileName) const -{ - return QLatin1String("/tmp/") + localFileName + QLatin1String(".upload"); -} - -void SftpTest::earlyDisconnectFromHost() -{ - m_error = true; - removeFiles(true); - if (m_channel) - disconnect(m_channel.data(), 0, this, 0); - m_state = Disconnecting; - m_connection->disconnectFromHost(); -} - -bool SftpTest::checkJobId(SftpJobId job, SftpJobId expectedJob, const char *activity) -{ - if (job != expectedJob) { - std::cerr << "Error " << activity << ": Expected job id " << expectedJob - << ", got job id " << job << '.' << std::endl; - earlyDisconnectFromHost(); - return false; - } - return true; -} - -void SftpTest::removeFiles(bool remoteToo) -{ - foreach (const FilePtr &file, m_localSmallFiles) - removeFile(file, remoteToo); - removeFile(m_localBigFile, remoteToo); -} - -bool SftpTest::handleJobFinished(SftpJobId job, JobMap &jobMap, - const QString &error, const char *activity) -{ - JobMap::Iterator it = jobMap.find(job); - if (it == jobMap.end()) { - std::cerr << "Error: Unknown job " << job << "finished." - << std::endl; - earlyDisconnectFromHost(); - return false; - } - if (!error.isEmpty()) { - std::cerr << "Error " << activity << " file " << qPrintable(it.value()) - << ": " << qPrintable(error) << "." << std::endl; - earlyDisconnectFromHost(); - return false; - } - jobMap.erase(it); - return true; -} - -bool SftpTest::handleJobFinished(SftpJobId job, SftpJobId expectedJob, const QString &error, - const char *activity) -{ - if (!checkJobId(job, expectedJob, activity)) - return false; - if (!error.isEmpty()) { - std::cerr << "Error " << activity << ": " << qPrintable(error) << "." << std::endl; - earlyDisconnectFromHost(); - return false; - } - return true; -} - -bool SftpTest::handleBigJobFinished(SftpJobId job, SftpJobId expectedJob, - const QString &error, const char *activity) -{ - if (job != expectedJob) { - std::cerr << "Error " << activity << " file '" - << qPrintable(m_localBigFile->fileName()) - << "': Expected job id " << expectedJob - << ", got job id " << job << '.' << std::endl; - earlyDisconnectFromHost(); - return false; - } - if (!error.isEmpty()) { - std::cerr << "Error " << activity << " file '" - << qPrintable(m_localBigFile->fileName()) << "': " - << qPrintable(error) << std::endl; - earlyDisconnectFromHost(); - return false; - } - return true; -} - -bool SftpTest::compareFiles(QFile *orig, QFile *copy) -{ - bool success = orig->size() == copy->size(); - qint64 bytesLeft = orig->size(); - orig->seek(0); - while (success && bytesLeft > 0) { - const qint64 bytesToRead = qMin(bytesLeft, Q_INT64_C(1024*1024)); - const QByteArray origBlock = orig->read(bytesToRead); - const QByteArray copyBlock = copy->read(bytesToRead); - if (origBlock.size() != bytesToRead || origBlock != copyBlock) - success = false; - bytesLeft -= bytesToRead; - } - orig->close(); - success = success && orig->error() == QFile::NoError - && copy->error() == QFile::NoError; - if (!success) { - std::cerr << "Error: Original file '" << qPrintable(orig->fileName()) - << "'' differs from downloaded file '" - << qPrintable(copy->fileName()) << "'." << std::endl; - earlyDisconnectFromHost(); - } - return success; -} diff --git a/tests/manual/ssh/sftp/sftptest.h b/tests/manual/ssh/sftp/sftptest.h deleted file mode 100644 index 97b13217eeb..00000000000 --- a/tests/manual/ssh/sftp/sftptest.h +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "parameters.h" - -#include -#include - -#include -#include -#include -#include -#include - -QT_FORWARD_DECLARE_CLASS(QFile); - -class SftpTest : public QObject -{ - Q_OBJECT -public: - SftpTest(const Parameters ¶ms); - ~SftpTest(); - void run(); - -private: - typedef QHash JobMap; - typedef QSharedPointer FilePtr; - enum State { - Inactive, Connecting, InitializingChannel, UploadingSmall, DownloadingSmall, - RemovingSmall, UploadingBig, DownloadingBig, RemovingBig, CreatingDir, - CheckingDirAttributes, CheckingDirContents, RemovingDir, ChannelClosing, Disconnecting - }; - - void handleConnected(); - void handleError(); - void handleDisconnected(); - void handleChannelInitialized(); - void handleChannelInitializationFailure(const QString &reason); - void handleJobFinished(QSsh::SftpJobId job, const QString &error); - void handleFileInfo(QSsh::SftpJobId job, const QList &fileInfoList); - void handleChannelClosed(); - - void removeFile(const FilePtr &filePtr, bool remoteToo); - void removeFiles(bool remoteToo); - QString cmpFileName(const QString &localFileName) const; - QString remoteFilePath(const QString &localFileName) const; - void earlyDisconnectFromHost(); - bool checkJobId(QSsh::SftpJobId job, QSsh::SftpJobId expectedJob, const char *activity); - bool handleJobFinished(QSsh::SftpJobId job, JobMap &jobMap, - const QString &error, const char *activity); - bool handleJobFinished(QSsh::SftpJobId job, QSsh::SftpJobId expectedJob, const QString &error, - const char *activity); - bool handleBigJobFinished(QSsh::SftpJobId job, QSsh::SftpJobId expectedJob, - const QString &error, const char *activity); - bool compareFiles(QFile *orig, QFile *copy); - - const Parameters m_parameters; - State m_state; - bool m_error; - QSsh::SshConnection *m_connection; - QSsh::SftpChannel::Ptr m_channel; - QList m_localSmallFiles; - JobMap m_smallFilesUploadJobs; - JobMap m_smallFilesDownloadJobs; - JobMap m_smallFilesRemovalJobs; - FilePtr m_localBigFile; - QSsh::SftpJobId m_bigFileUploadJob; - QSsh::SftpJobId m_bigFileDownloadJob; - QSsh::SftpJobId m_bigFileRemovalJob; - QSsh::SftpJobId m_mkdirJob; - QSsh::SftpJobId m_statDirJob; - QSsh::SftpJobId m_lsDirJob; - QSsh::SftpJobId m_rmDirJob; - QElapsedTimer m_bigJobTimer; - QString m_remoteDirPath; - QSsh::SftpFileInfo m_dirInfo; - QList m_dirContents; -}; diff --git a/tests/manual/ssh/remoteprocess/argumentscollector.cpp b/tests/manual/ssh/shell/argumentscollector.cpp similarity index 100% rename from tests/manual/ssh/remoteprocess/argumentscollector.cpp rename to tests/manual/ssh/shell/argumentscollector.cpp diff --git a/tests/manual/ssh/remoteprocess/argumentscollector.h b/tests/manual/ssh/shell/argumentscollector.h similarity index 100% rename from tests/manual/ssh/remoteprocess/argumentscollector.h rename to tests/manual/ssh/shell/argumentscollector.h diff --git a/tests/manual/ssh/shell/main.cpp b/tests/manual/ssh/shell/main.cpp index 894eac6898b..8890342d451 100644 --- a/tests/manual/ssh/shell/main.cpp +++ b/tests/manual/ssh/shell/main.cpp @@ -23,7 +23,7 @@ ** ****************************************************************************/ -#include "../remoteprocess/argumentscollector.h" +#include "argumentscollector.h" #include "shell.h" #include diff --git a/tests/manual/ssh/shell/shell.pro b/tests/manual/ssh/shell/shell.pro index ed3b0d987ea..f7d0b174f0e 100644 --- a/tests/manual/ssh/shell/shell.pro +++ b/tests/manual/ssh/shell/shell.pro @@ -2,5 +2,5 @@ include(../ssh.pri) QT += network TARGET=shell -SOURCES=main.cpp shell.cpp ../remoteprocess/argumentscollector.cpp -HEADERS=shell.h ../remoteprocess/argumentscollector.h +SOURCES=main.cpp shell.cpp argumentscollector.cpp +HEADERS=shell.h argumentscollector.h diff --git a/tests/manual/ssh/ssh.pro b/tests/manual/ssh/ssh.pro index fdfd7681328..1801bd1d9b0 100644 --- a/tests/manual/ssh/ssh.pro +++ b/tests/manual/ssh/ssh.pro @@ -5,4 +5,4 @@ #------------------------------------------------- TEMPLATE = subdirs -SUBDIRS = errorhandling sftp remoteprocess shell sftpfsmodel tunnel +SUBDIRS = shell sftpfsmodel diff --git a/tests/manual/ssh/tunnel/argumentscollector.cpp b/tests/manual/ssh/tunnel/argumentscollector.cpp deleted file mode 100644 index 15d73901d20..00000000000 --- a/tests/manual/ssh/tunnel/argumentscollector.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "argumentscollector.h" - -#include -#include - -#include - -using namespace QSsh; - -using namespace std; - -ArgumentsCollector::ArgumentsCollector(const QStringList &args) - : m_arguments(args) -{ -} - -SshConnectionParameters ArgumentsCollector::collect(bool &success) const -{ - SshConnectionParameters parameters; - parameters.options &= ~SshIgnoreDefaultProxy; - parameters.setHost("localhost"); - - try { - bool authTypeGiven = false; - bool portGiven = false; - bool timeoutGiven = false; - bool proxySettingGiven = false; - int pos; - int port = 22; - - for (pos = 1; pos < m_arguments.count() - 1; ++pos) { - QString user; - if (checkAndSetStringArg(pos, user, "-u")) { - parameters.setUserName(user); - continue; - } - if (checkAndSetIntArg(pos, port, portGiven, "-p") - || checkAndSetIntArg(pos, parameters.timeout, timeoutGiven, "-t")) - continue; - QString pass; - if (checkAndSetStringArg(pos, pass, "-pwd")) { - parameters.setPassword(pass); - if (!parameters.privateKeyFile.isEmpty()) - throw ArgumentErrorException(QLatin1String("-pwd and -k are mutually exclusive.")); - parameters.authenticationType - = SshConnectionParameters::AuthenticationTypeTryAllPasswordBasedMethods; - authTypeGiven = true; - continue; - } - if (checkAndSetStringArg(pos, parameters.privateKeyFile, "-k")) { - if (!parameters.password().isEmpty()) - throw ArgumentErrorException(QLatin1String("-pwd and -k are mutually exclusive.")); - parameters.authenticationType - = SshConnectionParameters::AuthenticationTypePublicKey; - authTypeGiven = true; - continue; - } - if (!checkForNoProxy(pos, parameters.options, proxySettingGiven)) - throw ArgumentErrorException(QLatin1String("unknown option ") + m_arguments.at(pos)); - } - - Q_ASSERT(pos <= m_arguments.count()); - if (pos == m_arguments.count() - 1) { - if (!checkForNoProxy(pos, parameters.options, proxySettingGiven)) - throw ArgumentErrorException(QLatin1String("unknown option ") + m_arguments.at(pos)); - } - - if (!authTypeGiven) { - parameters.authenticationType = SshConnectionParameters::AuthenticationTypePublicKey; - parameters.privateKeyFile = QDir::homePath() + QLatin1String("/.ssh/id_rsa"); - } - - if (parameters.userName().isEmpty()) - parameters.setUserName(QProcessEnvironment::systemEnvironment().value("USER")); - if (parameters.userName().isEmpty()) - throw ArgumentErrorException(QLatin1String("No user name given.")); - - if (parameters.host().isEmpty()) - throw ArgumentErrorException(QLatin1String("No host given.")); - - parameters.setPort(portGiven ? port : 22); - if (!timeoutGiven) - parameters.timeout = 30; - success = true; - } catch (ArgumentErrorException &ex) { - cerr << "Error: " << qPrintable(ex.error) << endl; - printUsage(); - success = false; - } - return parameters; -} - -void ArgumentsCollector::printUsage() const -{ - cerr << "Usage: " << qPrintable(m_arguments.first()) - << "[ -u ] " - << "[ -pwd | -k ] [ -p ] " - << "[ -t ] [ -no-proxy ]" << endl; -} - -bool ArgumentsCollector::checkAndSetStringArg(int &pos, QString &arg, const char *opt) const -{ - if (m_arguments.at(pos) == QLatin1String(opt)) { - if (!arg.isEmpty()) { - throw ArgumentErrorException(QLatin1String("option ") + QLatin1String(opt) - + QLatin1String(" was given twice.")); - } - arg = m_arguments.at(++pos); - if (arg.isEmpty() && QLatin1String(opt) != QLatin1String("-pwd")) - throw ArgumentErrorException(QLatin1String("empty argument not allowed here.")); - return true; - } - return false; -} - -bool ArgumentsCollector::checkAndSetIntArg(int &pos, int &val, - bool &alreadyGiven, const char *opt) const -{ - if (m_arguments.at(pos) == QLatin1String(opt)) { - if (alreadyGiven) { - throw ArgumentErrorException(QLatin1String("option ") + QLatin1String(opt) - + QLatin1String(" was given twice.")); - } - bool isNumber; - val = m_arguments.at(++pos).toInt(&isNumber); - if (!isNumber) { - throw ArgumentErrorException(QLatin1String("option ") + QLatin1String(opt) - + QLatin1String(" needs integer argument")); - } - alreadyGiven = true; - return true; - } - return false; -} - -bool ArgumentsCollector::checkForNoProxy(int &pos, SshConnectionOptions &options, - bool &alreadyGiven) const -{ - if (m_arguments.at(pos) == QLatin1String("-no-proxy")) { - if (alreadyGiven) - throw ArgumentErrorException(QLatin1String("proxy setting given twice.")); - options |= SshIgnoreDefaultProxy; - alreadyGiven = true; - return true; - } - return false; -} diff --git a/tests/manual/ssh/tunnel/argumentscollector.h b/tests/manual/ssh/tunnel/argumentscollector.h deleted file mode 100644 index 5f195cf1f07..00000000000 --- a/tests/manual/ssh/tunnel/argumentscollector.h +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include - -#include - -class ArgumentsCollector -{ -public: - ArgumentsCollector(const QStringList &args); - QSsh::SshConnectionParameters collect(bool &success) const; -private: - struct ArgumentErrorException - { - ArgumentErrorException(const QString &error) : error(error) {} - const QString error; - }; - - void printUsage() const; - bool checkAndSetStringArg(int &pos, QString &arg, const char *opt) const; - bool checkAndSetIntArg(int &pos, int &val, bool &alreadyGiven, - const char *opt) const; - bool checkForNoProxy(int &pos, QSsh::SshConnectionOptions &options, bool &alreadyGiven) const; - - const QStringList m_arguments; -}; diff --git a/tests/manual/ssh/tunnel/directtunnel.cpp b/tests/manual/ssh/tunnel/directtunnel.cpp deleted file mode 100644 index 54f4c3a3e5d..00000000000 --- a/tests/manual/ssh/tunnel/directtunnel.cpp +++ /dev/null @@ -1,164 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "directtunnel.h" - -#include -#include - -#include -#include -#include -#include - -#include -#include - -const QByteArray ServerDataPrefix("Received the following data: "); -const QByteArray TestData("Urgsblubb?"); - -using namespace QSsh; - -DirectTunnel::DirectTunnel(const SshConnectionParameters ¶meters, QObject *parent) - : QObject(parent), - m_connection(new SshConnection(parameters, this)), - m_targetServer(new QTcpServer(this)), - m_expectingChannelClose(false) -{ - connect(m_connection, &SshConnection::connected, this, &DirectTunnel::handleConnected); - connect(m_connection, &SshConnection::error, this, &DirectTunnel::handleConnectionError); -} - -DirectTunnel::~DirectTunnel() -{ -} - -void DirectTunnel::run() -{ - std::cout << "Connecting to SSH server..." << std::endl; - m_connection->connectToHost(); -} - -void DirectTunnel::handleConnectionError() -{ - std::cerr << "SSH connection error: " << qPrintable(m_connection->errorString()) << std::endl; - emit finished(EXIT_FAILURE); -} - -void DirectTunnel::handleConnected() -{ - std::cout << "Opening server side..." << std::endl; - if (!m_targetServer->listen(QHostAddress::LocalHost)) { - std::cerr << "Error opening port: " - << m_targetServer->errorString().toLocal8Bit().constData() << std::endl; - emit finished(EXIT_FAILURE); - return; - } - m_targetPort = m_targetServer->serverPort(); - connect(m_targetServer, &QTcpServer::newConnection, this, &DirectTunnel::handleNewConnection); - - m_tunnel = m_connection->createDirectTunnel(QLatin1String("localhost"), 1024, // made-up values - QLatin1String("localhost"), m_targetPort); - connect(m_tunnel.data(), &SshDirectTcpIpTunnel::initialized, - this, &DirectTunnel::handleInitialized); - connect(m_tunnel.data(), &SshDirectTcpIpTunnel::error, - this, &DirectTunnel::handleTunnelError); - connect(m_tunnel.data(), &QIODevice::readyRead, this, &DirectTunnel::handleServerData); - connect(m_tunnel.data(), &QIODevice::aboutToClose, this, &DirectTunnel::handleTunnelClosed); - - std::cout << "Initializing tunnel..." << std::endl; - m_tunnel->initialize(); -} - -void DirectTunnel::handleInitialized() -{ - std::cout << "Writing data into the tunnel..." << std::endl; - m_tunnel->write(TestData); - QTimer * const timeoutTimer = new QTimer(this); - connect(timeoutTimer, &QTimer::timeout, this, &DirectTunnel::handleTimeout); - timeoutTimer->start(10000); -} - -void DirectTunnel::handleServerData() -{ - m_dataReceivedFromServer += m_tunnel->readAll(); - if (m_dataReceivedFromServer == ServerDataPrefix + TestData) { - std::cout << "Data exchange successful. Closing server socket..." << std::endl; - m_expectingChannelClose = true; - m_targetSocket->close(); - } -} - -void DirectTunnel::handleTunnelError(const QString &reason) -{ - std::cerr << "Tunnel error: " << reason.toLocal8Bit().constData() << std::endl; - emit finished(EXIT_FAILURE); -} - -void DirectTunnel::handleTunnelClosed() -{ - if (m_expectingChannelClose) { - std::cout << "Successfully detected channel close." << std::endl; - std::cout << "Test finished successfully." << std::endl; - emit finished(EXIT_SUCCESS); - } else { - std::cerr << "Error: Remote host closed channel." << std::endl; - emit finished(EXIT_FAILURE); - } -} - -void DirectTunnel::handleNewConnection() -{ - m_targetSocket = m_targetServer->nextPendingConnection(); - m_targetServer->close(); - connect(m_targetSocket, - static_cast(&QAbstractSocket::error), - this, &DirectTunnel::handleSocketError); - connect(m_targetSocket, &QIODevice::readyRead, this, &DirectTunnel::handleClientData); - handleClientData(); -} - -void DirectTunnel::handleSocketError() -{ - std::cerr << "Socket error: " << m_targetSocket->errorString().toLocal8Bit().constData() - << std::endl; - emit finished(EXIT_FAILURE); -} - -void DirectTunnel::handleClientData() -{ - m_dataReceivedFromClient += m_targetSocket->readAll(); - if (m_dataReceivedFromClient == TestData) { - std::cout << "Client data successfully received by server, now sending data to client..." - << std::endl; - m_targetSocket->write(ServerDataPrefix + m_dataReceivedFromClient); - } -} - -void DirectTunnel::handleTimeout() -{ - std::cerr << "Error: Timeout waiting for test completion." << std::endl; - emit finished(EXIT_FAILURE); -} diff --git a/tests/manual/ssh/tunnel/directtunnel.h b/tests/manual/ssh/tunnel/directtunnel.h deleted file mode 100644 index b73fcd9d63b..00000000000 --- a/tests/manual/ssh/tunnel/directtunnel.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include -#include - -QT_BEGIN_NAMESPACE -class QTcpServer; -class QTcpSocket; -QT_END_NAMESPACE - -namespace QSsh { -class SshConnection; -class SshConnectionParameters; -class SshDirectTcpIpTunnel; -} - -class DirectTunnel : public QObject -{ - Q_OBJECT -public: - DirectTunnel(const QSsh::SshConnectionParameters ¶meters, QObject *parent = 0); - ~DirectTunnel(); - - void run(); - -signals: - void finished(int errorCode); - -private: - void handleConnected(); - void handleConnectionError(); - void handleServerData(); - void handleInitialized(); - void handleTunnelError(const QString &reason); - void handleTunnelClosed(); - void handleNewConnection(); - void handleSocketError(); - void handleClientData(); - void handleTimeout(); - - QSsh::SshConnection * const m_connection; - QSharedPointer m_tunnel; - QTcpServer * const m_targetServer; - QTcpSocket *m_targetSocket; - quint16 m_targetPort; - QByteArray m_dataReceivedFromServer; - QByteArray m_dataReceivedFromClient; - bool m_expectingChannelClose; -}; diff --git a/tests/manual/ssh/tunnel/forwardtunnel.cpp b/tests/manual/ssh/tunnel/forwardtunnel.cpp deleted file mode 100644 index e80dbad30bc..00000000000 --- a/tests/manual/ssh/tunnel/forwardtunnel.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "forwardtunnel.h" - -#include -#include - -#include -#include -#include - -#include - -const QByteArray ClientDataPrefix("Received the following data: "); -const QByteArray TestData("Urgsblubb?"); - -ForwardTunnel::ForwardTunnel(const QSsh::SshConnectionParameters ¶meters, QObject *parent) - : QObject(parent), - m_connection(new QSsh::SshConnection(parameters, this)), - m_targetSocket(0), - m_targetPort(0) -{ - connect(m_connection, &QSsh::SshConnection::connected, this, &ForwardTunnel::handleConnected); - connect(m_connection, &QSsh::SshConnection::error, this, &ForwardTunnel::handleConnectionError); -} - -void ForwardTunnel::run() -{ - std::cout << "Connecting to SSH server..." << std::endl; - m_connection->connectToHost(); -} - -void ForwardTunnel::handleConnected() -{ - { - QTcpServer server; - if (server.listen(QHostAddress::LocalHost)) { - m_targetPort = server.serverPort(); - } else { - std::cerr << "Error while searching for free port: " - << server.errorString().toLocal8Bit().constData() << std::endl; - emit finished(EXIT_FAILURE); - } - } - - std::cout << "Initializing tunnel..." << std::endl; - m_server = m_connection->createForwardServer(QLatin1String("localhost"), m_targetPort); - connect(m_server.data(), &QSsh::SshTcpIpForwardServer::newConnection, - this, &ForwardTunnel::handleNewConnection); - connect(m_server.data(), &QSsh::SshTcpIpForwardServer::stateChanged, - this, [this](QSsh::SshTcpIpForwardServer::State state) { - if (state == QSsh::SshTcpIpForwardServer::Listening) - handleInitialized(); - else if (state == QSsh::SshTcpIpForwardServer::Inactive) - handleServerClosed(); - }); - connect(m_server.data(), &QSsh::SshTcpIpForwardServer::error, - this, &ForwardTunnel::handleServerError); - - m_server->initialize(); -} - -void ForwardTunnel::handleConnectionError(QSsh::SshError error) -{ - std::cout << "SSH connection error: " << error << " " << qPrintable(m_connection->errorString()) - << std::endl; - emit finished(EXIT_FAILURE); -} - -void ForwardTunnel::handleInitialized() -{ - std::cout << "Forward tunnel initialized, connecting ..." << std::endl; - m_targetSocket = new QTcpSocket(this); - connect(m_targetSocket, &QTcpSocket::connected, this, [this](){ - m_targetSocket->write(ClientDataPrefix + TestData); - }); - - connect(m_targetSocket, &QTcpSocket::readyRead, this, [this](){ - m_dataReceivedFromServer += m_targetSocket->readAll(); - if (m_dataReceivedFromServer == ClientDataPrefix + TestData) { - std::cout << "Data exchange successful. Closing client socket..." << std::endl; - m_targetSocket->close(); - } - }); - m_targetSocket->connectToHost(QLatin1String("localhost"), m_targetPort); -} - -void ForwardTunnel::handleServerError(const QString &reason) -{ - std::cerr << "Tunnel error:" << reason.toUtf8().constData() << std::endl; - emit finished(EXIT_FAILURE); -} - -void ForwardTunnel::handleServerClosed() -{ - std::cout << "Forward tunnel closed" << std::endl; - emit finished(EXIT_SUCCESS); -} - -void ForwardTunnel::handleNewConnection() -{ - std::cout << "Connection established" << std::endl; - QSsh::SshForwardedTcpIpTunnel::Ptr tunnel = m_server->nextPendingConnection(); - - connect(tunnel.data(), &QIODevice::readyRead, this, [this, tunnel](){ - m_dataReceivedFromClient += tunnel->readAll(); - if (m_dataReceivedFromClient == ClientDataPrefix + TestData) { - std::cout << "Data received successful. Sending it back..." << std::endl; - tunnel->write(m_dataReceivedFromClient); - } - }); - - connect(tunnel.data(), &QIODevice::aboutToClose, this, [this](){ - std::cout << "Server Connection closed, closing tunnel" << std::endl; - m_server->close(); - }); -} - -void ForwardTunnel::handleSocketError() -{ - std::cerr << "Socket error" << std::endl; - emit finished(EXIT_FAILURE); -} diff --git a/tests/manual/ssh/tunnel/forwardtunnel.h b/tests/manual/ssh/tunnel/forwardtunnel.h deleted file mode 100644 index fd3bf35d40d..00000000000 --- a/tests/manual/ssh/tunnel/forwardtunnel.h +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "ssh/ssherrors.h" - -#include -#include - -QT_BEGIN_NAMESPACE -class QTcpSocket; -QT_END_NAMESPACE - -namespace QSsh { -class SshConnection; -class SshConnectionParameters; -class SshTcpIpForwardServer; -} - -class ForwardTunnel : public QObject -{ - Q_OBJECT -public: - ForwardTunnel(const QSsh::SshConnectionParameters ¶meters, - QObject *parent = 0); - void run(); - -signals: - void finished(int exitCode); - -private: - void handleConnected(); - void handleConnectionError(QSsh::SshError error); - void handleInitialized(); - void handleServerError(const QString &reason); - void handleServerClosed(); - void handleNewConnection(); - void handleSocketError(); - - QSsh::SshConnection * const m_connection; - QSharedPointer m_server; - QTcpSocket *m_targetSocket; - quint16 m_targetPort; - - QByteArray m_dataReceivedFromServer; - QByteArray m_dataReceivedFromClient; -}; diff --git a/tests/manual/ssh/tunnel/main.cpp b/tests/manual/ssh/tunnel/main.cpp deleted file mode 100644 index e9c20618453..00000000000 --- a/tests/manual/ssh/tunnel/main.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "../remoteprocess/argumentscollector.h" -#include "directtunnel.h" -#include "forwardtunnel.h" - -#include - -#include -#include -#include - -#include -#include - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - bool parseSuccess; - QSsh::SshConnectionParameters parameters - = ArgumentsCollector(app.arguments()).collect(parseSuccess); - parameters.setHost("127.0.0.1"); - if (!parseSuccess) - return EXIT_FAILURE; - - DirectTunnel direct(parameters); - - parameters.setHost("127.0.0.2"); - ForwardTunnel forward(parameters); - forward.run(); - - QObject::connect(&forward, &ForwardTunnel::finished, &direct, &DirectTunnel::run); - QObject::connect(&direct, &DirectTunnel::finished, &app, &QCoreApplication::exit); - - return app.exec(); -} diff --git a/tests/manual/ssh/tunnel/tunnel.pro b/tests/manual/ssh/tunnel/tunnel.pro deleted file mode 100644 index 3d36634f7c9..00000000000 --- a/tests/manual/ssh/tunnel/tunnel.pro +++ /dev/null @@ -1,12 +0,0 @@ -include(../ssh.pri) - -TARGET =tunnel -SOURCES = \ - main.cpp \ - argumentscollector.cpp \ - directtunnel.cpp \ - forwardtunnel.cpp -HEADERS = \ - argumentscollector.h \ - directtunnel.h \ - forwardtunnel.h