1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 
43 #include <QtTest/QtTest>
44 
45 #include <qcoreapplication.h>
46 #include <qfile.h>
47 #include <qbuffer.h>
48 #include "qftp.h"
49 #include <qmap.h>
50 #include <time.h>
51 #include <stdlib.h>
52 #include <QNetworkProxy>
53 #include <QNetworkConfiguration>
54 #include <qnetworkconfigmanager.h>
55 #include <QNetworkSession>
56 #include <QtNetwork/private/qnetworksession_p.h>
57 
58 #include "../network-settings.h"
59 
60 //TESTED_CLASS=
61 //TESTED_FILES=
62 
63 #ifdef Q_OS_SYMBIAN
64 // In Symbian OS test data is located in applications private dir
65 // Application private dir is default serach path for files, so SRCDIR can be set to empty
66 #define SRCDIR ""
67 #endif
68 
69 #ifndef QT_NO_BEARERMANAGEMENT
70 Q_DECLARE_METATYPE(QNetworkConfiguration)
71 #endif
72 
73 class tst_QFtp : public QObject
74 {
75     Q_OBJECT
76 
77 public:
78     tst_QFtp();
79     virtual ~tst_QFtp();
80 
81 
82 public slots:
83     void initTestCase_data();
84     void initTestCase();
85     void cleanupTestCase();
86     void init();
87     void cleanup();
88 private slots:
89     void connectToHost_data();
90     void connectToHost();
91     void connectToUnresponsiveHost();
92     void login_data();
93     void login();
94     void close_data();
95     void close();
96 
97     void list_data();
98     void list();
99     void cd_data();
100     void cd();
101     void get_data();
102     void get();
103     void put_data();
104     void put();
105     void remove();
106     void mkdir_data();
107     void mkdir();
108     void mkdir2();
109     void rmdir();
110     void rename_data();
111     void rename();
112 
113     void commandSequence_data();
114     void commandSequence();
115 
116     void abort_data();
117     void abort();
118 
119     void bytesAvailable_data();
120     void bytesAvailable();
121 
122     void activeMode();
123 
124     void proxy_data();
125     void proxy();
126 
127     void binaryAscii();
128 
129     void doneSignal();
130     void queueMoreCommandsInDoneSlot();
131 
132     void qtbug7359Crash();
133 
134 protected slots:
135     void stateChanged( int );
136     void listInfo( const QUrlInfo & );
137     void readyRead();
138     void dataTransferProgress(qint64, qint64);
139 
140     void commandStarted( int );
141     void commandFinished( int, bool );
142     void done( bool );
143     void activeModeDone( bool );
144     void mkdir2Slot(int id, bool error);
145     void cdUpSlot(bool);
146 
147 private:
148     QFtp *newFtp();
149     void addCommand( QFtp::Command, int );
150     bool fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir = QString::null );
151     bool dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate );
152 
153     void renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile );
154     void renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete );
155 
156     QFtp *ftp;
157 #ifndef QT_NO_BEARERMANAGEMENT
158     QNetworkConfigurationManager *netConfMan;
159     QSharedPointer<QNetworkSession> networkSessionExplicit;
160     QSharedPointer<QNetworkSession> networkSessionImplicit;
161 #endif
162 
163     QList<int> ids; // helper to make sure that all expected signals are emitted
164     int current_id;
165 
166     int connectToHost_state;
167     int close_state;
168     int login_state;
169     int cur_state;
170     struct CommandResult
171     {
172         int id;
173         int success;
174     };
175     QMap< QFtp::Command, CommandResult > resultMap;
176     typedef QMap<QFtp::Command,CommandResult>::Iterator ResMapIt;
177 
178     int done_success;
179     int commandSequence_success;
180 
181     qlonglong bytesAvailable_finishedGet;
182     qlonglong bytesAvailable_finished;
183     qlonglong bytesAvailable_done;
184 
185     QList<QUrlInfo> listInfo_i;
186     QByteArray newData_ba;
187     qlonglong bytesTotal;
188     qlonglong bytesDone;
189 
190     bool inFileDirExistsFunction;
191 
192     QString uniqueExtension;
193 };
194 
195 //#define DUMP_SIGNALS
196 
197 const int bytesTotal_init = -10;
198 const int bytesDone_init = -10;
199 
tst_QFtp()200 tst_QFtp::tst_QFtp() :
201     ftp(0)
202 {
203 }
204 
~tst_QFtp()205 tst_QFtp::~tst_QFtp()
206 {
207 }
208 
initTestCase_data()209 void tst_QFtp::initTestCase_data()
210 {
211     QTest::addColumn<bool>("setProxy");
212     QTest::addColumn<int>("proxyType");
213     QTest::addColumn<bool>("setSession");
214 
215     QTest::newRow("WithoutProxy") << false << 0 << false;
216     QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy) << false;
217     //### doesn't work well yet.
218     //QTest::newRow("WithHttpProxy") << true << int(QNetworkProxy::HttpProxy);
219 
220 #ifndef QT_NO_BEARERMANAGEMENT
221     QTest::newRow("WithoutProxyWithSession") << false << 0 << true;
222     QTest::newRow("WithSocks5ProxyAndSession") << true << int(QNetworkProxy::Socks5Proxy) << true;
223 #endif
224 }
225 
initTestCase()226 void tst_QFtp::initTestCase()
227 {
228 #ifndef QT_NO_BEARERMANAGEMENT
229     netConfMan = new QNetworkConfigurationManager(this);
230     netConfMan->updateConfigurations();
231     connect(netConfMan, SIGNAL(updateCompleted()), &QTestEventLoop::instance(), SLOT(exitLoop()));
232     QTestEventLoop::instance().enterLoop(10);
233     QNetworkConfiguration networkConfiguration = netConfMan->defaultConfiguration();
234     if (networkConfiguration.isValid()) {
235         networkSessionImplicit = QSharedPointer<QNetworkSession>(new QNetworkSession(networkConfiguration));
236         if (!networkSessionImplicit->isOpen()) {
237             networkSessionImplicit->open();
238             QVERIFY(networkSessionImplicit->waitForOpened(30000));
239         }
240     } else {
241         QVERIFY(!(netConfMan->capabilities() & QNetworkConfigurationManager::NetworkSessionRequired));
242     }
243 #endif
244 }
245 
cleanupTestCase()246 void tst_QFtp::cleanupTestCase()
247 {
248 #ifndef QT_NO_BEARERMANAGEMENT
249     networkSessionExplicit.clear();
250     networkSessionImplicit.clear();
251 #endif
252 }
253 
init()254 void tst_QFtp::init()
255 {
256     QFETCH_GLOBAL(bool, setProxy);
257     QFETCH_GLOBAL(int, proxyType);
258     QFETCH_GLOBAL(bool, setSession);
259     if (setProxy) {
260         if (proxyType == QNetworkProxy::Socks5Proxy) {
261             QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080));
262         } else if (proxyType == QNetworkProxy::HttpProxy) {
263             QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128));
264         }
265     }
266 #ifndef QT_NO_BEARERMANAGEMENT
267     if (setSession) {
268         if (!networkSessionImplicit)
269             QSKIP("test requires a valid default network configuration", SkipSingle);
270         networkSessionExplicit = networkSessionImplicit;
271         if (!networkSessionExplicit->isOpen()) {
272             networkSessionExplicit->open();
273             QVERIFY(networkSessionExplicit->waitForOpened(30000));
274         }
275     } else {
276         networkSessionExplicit.clear();
277     }
278 #endif
279 
280     delete ftp;
281     ftp = 0;
282 
283     ids.clear();
284     current_id = 0;
285 
286     resultMap.clear();
287     connectToHost_state = -1;
288     close_state = -1;
289     login_state = -1;
290     cur_state = QFtp::Unconnected;
291 
292     listInfo_i.clear();
293     newData_ba = QByteArray();
294     bytesTotal = bytesTotal_init;
295     bytesDone = bytesDone_init;
296 
297     done_success = -1;
298     commandSequence_success = -1;
299 
300     bytesAvailable_finishedGet = 1234567890;
301     bytesAvailable_finished = 1234567890;
302     bytesAvailable_done = 1234567890;
303 
304     inFileDirExistsFunction = FALSE;
305 
306 #if !defined(Q_OS_WINCE)
307     srand(time(0));
308     uniqueExtension = QString("%1%2%3").arg((qulonglong)this).arg(rand()).arg((qulonglong)time(0));
309 #else
310     srand(0);
311     uniqueExtension = QString("%1%2%3").arg((qulonglong)this).arg(rand()).arg((qulonglong)(0));
312 #endif
313 }
314 
cleanup()315 void tst_QFtp::cleanup()
316 {
317     if (ftp) {
318         delete ftp;
319         ftp = 0;
320     }
321     QFETCH_GLOBAL(bool, setProxy);
322     if (setProxy) {
323         QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy);
324     }
325 
326     delete ftp;
327     ftp = 0;
328 #ifndef QT_NO_BEARERMANAGEMENT
329     networkSessionExplicit.clear();
330 #endif
331 }
332 
connectToHost_data()333 void tst_QFtp::connectToHost_data()
334 {
335     QTest::addColumn<QString>("host");
336     QTest::addColumn<uint>("port");
337     QTest::addColumn<int>("state");
338 
339     QTest::newRow( "ok01" ) << QtNetworkSettings::serverName() << (uint)21 << (int)QFtp::Connected;
340     QTest::newRow( "error01" ) << QtNetworkSettings::serverName() << (uint)2222 << (int)QFtp::Unconnected;
341     QTest::newRow( "error02" ) << QString("foo.bar") << (uint)21 << (int)QFtp::Unconnected;
342 }
343 
connectToHost()344 void tst_QFtp::connectToHost()
345 {
346     QFETCH( QString, host );
347     QFETCH( uint, port );
348 
349     ftp = newFtp();
350     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
351 
352     QTestEventLoop::instance().enterLoop( 61 );
353     delete ftp;
354     ftp = 0;
355     if ( QTestEventLoop::instance().timeout() )
356         QFAIL( "Network operation timed out" );
357 
358     QTEST( connectToHost_state, "state" );
359 
360     ResMapIt it = resultMap.find( QFtp::ConnectToHost );
361     QVERIFY( it != resultMap.end() );
362     QFETCH( int, state );
363     if ( state == QFtp::Connected ) {
364         QVERIFY( it.value().success == 1 );
365     } else {
366         QVERIFY( it.value().success == 0 );
367     }
368 }
369 
connectToUnresponsiveHost()370 void tst_QFtp::connectToUnresponsiveHost()
371 {
372     QFETCH_GLOBAL(bool, setProxy);
373     if (setProxy)
374         QSKIP( "This test takes too long if we test with proxies too", SkipSingle );
375 
376     QString host = "192.0.2.42"; // IP out of TEST-NET, should be unreachable
377     uint port = 21;
378 
379     ftp = newFtp();
380     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
381 
382     qDebug( "About to connect to host that won't reply (this test takes 60 seconds)" );
383     QTestEventLoop::instance().enterLoop( 61 );
384 #ifdef Q_OS_WIN
385     /* On Windows, we do not get a timeout, because Winsock is behaving in a strange way:
386     We issue two "WSAConnect()" calls, after the first, as a result we get WSAEWOULDBLOCK,
387     after the second, we get WSAEISCONN, which means that the socket is connected, which cannot be.
388     However, after some seconds we get a socket error saying that the remote host closed the connection,
389     which can neither be. For this test, that would actually enable us to finish before timout, but handling that case
390     (in void QFtpPI::error(QAbstractSocket::SocketError e)) breaks
391     a lot of other stuff in QFtp, so we just expect this test to fail on Windows.
392     */
393     QEXPECT_FAIL("", "timeout not working due to strange Windows socket behaviour (see source file of this test for explanation)", Abort);
394 #endif
395     QVERIFY2(! QTestEventLoop::instance().timeout(), "Network timeout longer than expected (should have been 60 seconds)");
396 
397     QVERIFY( ftp->state() == QFtp::Unconnected);
398     ResMapIt it = resultMap.find( QFtp::ConnectToHost );
399     QVERIFY( it != resultMap.end() );
400     QVERIFY( it.value().success == 0 );
401 
402     delete ftp;
403     ftp = 0;
404 }
405 
login_data()406 void tst_QFtp::login_data()
407 {
408     QTest::addColumn<QString>("host");
409     QTest::addColumn<uint>("port");
410     QTest::addColumn<QString>("user");
411     QTest::addColumn<QString>("password");
412     QTest::addColumn<int>("success");
413 
414     QTest::newRow( "ok01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << 1;
415     QTest::newRow( "ok02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString() << 1;
416     QTest::newRow( "ok03" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString("foo") << 1;
417     QTest::newRow( "ok04" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << 1;
418 
419     QTest::newRow( "error01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("foo") << QString() << 0;
420     QTest::newRow( "error02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("foo") << QString("bar") << 0;
421 }
422 
login()423 void tst_QFtp::login()
424 {
425     QFETCH( QString, host );
426     QFETCH( uint, port );
427     QFETCH( QString, user );
428     QFETCH( QString, password );
429 
430     ftp = newFtp();
431     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
432     addCommand( QFtp::Login, ftp->login( user, password ) );
433 
434     QTestEventLoop::instance().enterLoop( 30 );
435     delete ftp;
436     ftp = 0;
437     if ( QTestEventLoop::instance().timeout() )
438         QFAIL( "Network operation timed out" );
439 
440     ResMapIt it = resultMap.find( QFtp::Login );
441     QVERIFY( it != resultMap.end() );
442     QTEST( it.value().success, "success" );
443 
444     if ( it.value().success ) {
445         QVERIFY( login_state == QFtp::LoggedIn );
446     } else {
447         QVERIFY( login_state != QFtp::LoggedIn );
448     }
449 }
450 
close_data()451 void tst_QFtp::close_data()
452 {
453     QTest::addColumn<QString>("host");
454     QTest::addColumn<uint>("port");
455     QTest::addColumn<QString>("user");
456     QTest::addColumn<QString>("password");
457     QTest::addColumn<bool>("login");
458 
459     QTest::newRow( "login01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << (bool)TRUE;
460     QTest::newRow( "login02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString() << (bool)TRUE;
461     QTest::newRow( "login03" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftp") << QString("foo") << (bool)TRUE;
462     QTest::newRow( "login04" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest") << QString("password") << (bool)TRUE;
463 
464     QTest::newRow( "no-login01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("") << QString("") << (bool)FALSE;
465 }
466 
close()467 void tst_QFtp::close()
468 {
469     QFETCH( QString, host );
470     QFETCH( uint, port );
471     QFETCH( QString, user );
472     QFETCH( QString, password );
473     QFETCH( bool, login );
474 
475     ftp = newFtp();
476     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
477     if ( login )
478         addCommand( QFtp::Login, ftp->login( user, password ) );
479     addCommand( QFtp::Close, ftp->close() );
480 
481     QTestEventLoop::instance().enterLoop( 30 );
482     delete ftp;
483     ftp = 0;
484     if ( QTestEventLoop::instance().timeout() )
485         QFAIL( "Network operation timed out" );
486 
487     QCOMPARE( close_state, (int)QFtp::Unconnected );
488 
489     ResMapIt it = resultMap.find( QFtp::Close );
490     QVERIFY( it != resultMap.end() );
491     QVERIFY( it.value().success == 1 );
492 }
493 
list_data()494 void tst_QFtp::list_data()
495 {
496     QTest::addColumn<QString>("host");
497     QTest::addColumn<uint>("port");
498     QTest::addColumn<QString>("user");
499     QTest::addColumn<QString>("password");
500     QTest::addColumn<QString>("dir");
501     QTest::addColumn<int>("success");
502     QTest::addColumn<QStringList>("entryNames"); // ### we should rather use a QList<QUrlInfo> here
503 
504     QStringList flukeRoot;
505     flukeRoot << "pub";
506     flukeRoot << "qtest";
507     QStringList flukeQtest;
508     flukeQtest << "bigfile";
509     flukeQtest << "nonASCII";
510     flukeQtest << "rfc3252";
511     flukeQtest << "rfc3252.txt";
512     flukeQtest << "upload";
513 
514     QTest::newRow( "workDir01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString() << 1 << flukeRoot;
515     QTest::newRow( "workDir02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")     << QString() << 1 << flukeRoot;
516 
517     QTest::newRow( "relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest;
518     QTest::newRow( "relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")     << QString("qtest") << 1 << flukeQtest;
519 
520     QTest::newRow( "absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest;
521     QTest::newRow( "absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")     << QString("/var/ftp/qtest") << 1 << flukeQtest;
522 
523     QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo")  << 1 << QStringList();
524     QTest::newRow( "nonExist02" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/foo") << 1 << QStringList();
525     // ### The microsoft server does not seem to work properly at the moment --
526     // I am also not able to open a data connection with other, non-Qt FTP
527     // clients to it.
528     // QTest::newRow( "nonExist03" ) << "ftp.microsoft.com" << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList();
529 
530     QStringList susePub;
531     susePub << "README.mirror-policy" << "axp" << "i386" << "ia64" << "install" << "noarch" << "pubring.gpg-build.suse.de" << "update" << "x86_64";
532     QTest::newRow( "epsvNotSupported" ) << QString("ftp.funet.fi") << (uint)21 << QString::fromLatin1("ftp") << QString::fromLatin1("root@") << QString("/pub/Linux/suse/suse") << 1 << susePub;
533 }
534 
list()535 void tst_QFtp::list()
536 {
537     QFETCH( QString, host );
538     QFETCH( uint, port );
539     QFETCH( QString, user );
540     QFETCH( QString, password );
541     QFETCH( QString, dir );
542 
543     ftp = newFtp();
544     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
545     addCommand( QFtp::Login, ftp->login( user, password ) );
546     addCommand( QFtp::List, ftp->list( dir ) );
547     addCommand( QFtp::Close, ftp->close() );
548 
549     QTestEventLoop::instance().enterLoop( 30 );
550     delete ftp;
551     ftp = 0;
552     if ( QTestEventLoop::instance().timeout() )
553         QFAIL( "Network operation timed out" );
554 
555     ResMapIt it = resultMap.find( QFtp::List );
556     QVERIFY( it != resultMap.end() );
557     QTEST( it.value().success, "success" );
558     QFETCH( QStringList, entryNames );
559     QCOMPARE( listInfo_i.count(), entryNames.count() );
560     for ( uint i=0; i < (uint) entryNames.count(); i++ ) {
561         QCOMPARE( listInfo_i[i].name(), entryNames[i] );
562     }
563 }
564 
cd_data()565 void tst_QFtp::cd_data()
566 {
567     QTest::addColumn<QString>("host");
568     QTest::addColumn<uint>("port");
569     QTest::addColumn<QString>("user");
570     QTest::addColumn<QString>("password");
571     QTest::addColumn<QString>("dir");
572     QTest::addColumn<int>("success");
573     QTest::addColumn<QStringList>("entryNames"); // ### we should rather use a QList<QUrlInfo> here
574 
575     QStringList flukeRoot;
576     flukeRoot << "qtest";
577     QStringList flukeQtest;
578     flukeQtest << "bigfile";
579     flukeQtest << "nonASCII";
580     flukeQtest << "rfc3252";
581     flukeQtest << "rfc3252.txt";
582     flukeQtest << "upload";
583 
584     QTest::newRow( "relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest;
585     QTest::newRow( "relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")     << QString("qtest") << 1 << flukeQtest;
586 
587     QTest::newRow( "absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest;
588     QTest::newRow( "absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")     << QString("/var/ftp/qtest") << 1 << flukeQtest;
589 
590     QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo")  << 0 << QStringList();
591     QTest::newRow( "nonExist03" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList();
592 }
593 
cd()594 void tst_QFtp::cd()
595 {
596     QFETCH( QString, host );
597     QFETCH( uint, port );
598     QFETCH( QString, user );
599     QFETCH( QString, password );
600     QFETCH( QString, dir );
601 
602     ftp = newFtp();
603     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
604     addCommand( QFtp::Login, ftp->login( user, password ) );
605     addCommand( QFtp::Cd, ftp->cd( dir ) );
606     addCommand( QFtp::List, ftp->list() );
607     addCommand( QFtp::Close, ftp->close() );
608 
609     QTestEventLoop::instance().enterLoop( 30 );
610 
611     delete ftp;
612     ftp = 0;
613     if ( QTestEventLoop::instance().timeout() ) {
614         QFAIL( "Network operation timed out" );
615     }
616 
617     ResMapIt it = resultMap.find( QFtp::Cd );
618     QVERIFY( it != resultMap.end() );
619     QTEST( it.value().success, "success" );
620     QFETCH( QStringList, entryNames );
621     QCOMPARE( listInfo_i.count(), entryNames.count() );
622     for ( uint i=0; i < (uint) entryNames.count(); i++ ) {
623         QCOMPARE( listInfo_i[i].name(), entryNames[i] );
624     }
625 }
626 
get_data()627 void tst_QFtp::get_data()
628 {
629     QTest::addColumn<QString>("host");
630     QTest::addColumn<uint>("port");
631     QTest::addColumn<QString>("user");
632     QTest::addColumn<QString>("password");
633     QTest::addColumn<QString>("file");
634     QTest::addColumn<int>("success");
635     QTest::addColumn<QByteArray>("res");
636     QTest::addColumn<bool>("useIODevice");
637 
638     // ### move this into external testdata
639     QFile file( SRCDIR "rfc3252.txt" );
640     QVERIFY( file.open( QIODevice::ReadOnly ) );
641     QByteArray rfc3252 = file.readAll();
642 
643     // test the two get() overloads in one routine
644     for ( int i=0; i<2; i++ ) {
645         QTest::newRow( QString("relPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
646                 << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
647         QTest::newRow( QString("relPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")
648                 << "qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
649 
650         QTest::newRow( QString("absPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
651                 << "/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
652         QTest::newRow( QString("absPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")
653                 << "/var/ftp/qtest/rfc3252" << 1 << rfc3252 << (bool)(i==1);
654 
655         QTest::newRow( QString("nonExist01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
656                 << QString("foo")  << 0 << QByteArray() << (bool)(i==1);
657         QTest::newRow( QString("nonExist02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
658                 << QString("/foo") << 0 << QByteArray() << (bool)(i==1);
659     }
660 }
661 
get()662 void tst_QFtp::get()
663 {
664     // for the overload that takes a QIODevice
665     QByteArray buf_ba;
666     QBuffer buf( &buf_ba );
667 
668     QFETCH( QString, host );
669     QFETCH( uint, port );
670     QFETCH( QString, user );
671     QFETCH( QString, password );
672     QFETCH( QString, file );
673     QFETCH( bool, useIODevice );
674 
675     ftp = newFtp();
676     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
677     addCommand( QFtp::Login, ftp->login( user, password ) );
678     if ( useIODevice ) {
679         buf.open( QIODevice::WriteOnly );
680         addCommand( QFtp::Get, ftp->get( file, &buf ) );
681     } else {
682         addCommand( QFtp::Get, ftp->get( file ) );
683     }
684     addCommand( QFtp::Close, ftp->close() );
685 
686     QTestEventLoop::instance().enterLoop( 50 );
687     delete ftp;
688     ftp = 0;
689     if ( QTestEventLoop::instance().timeout() )
690         QFAIL( "Network operation timed out" );
691 
692     ResMapIt it = resultMap.find( QFtp::Get );
693     QVERIFY( it != resultMap.end() );
694     QTEST( it.value().success, "success" );
695     if ( useIODevice ) {
696         QTEST( buf_ba, "res" );
697     } else {
698         QTEST( newData_ba, "res" );
699     }
700     QVERIFY( bytesTotal != bytesTotal_init );
701     if ( bytesTotal != -1 ) {
702         QVERIFY( bytesDone == bytesTotal );
703     }
704     if ( useIODevice ) {
705         if ( bytesDone != bytesDone_init ) {
706             QVERIFY( (int)buf_ba.size() == bytesDone );
707         }
708     } else {
709         if ( bytesDone != bytesDone_init ) {
710             QVERIFY( (int)newData_ba.size() == bytesDone );
711         }
712     }
713 }
714 
put_data()715 void tst_QFtp::put_data()
716 {
717     QTest::addColumn<QString>("host");
718     QTest::addColumn<uint>("port");
719     QTest::addColumn<QString>("user");
720     QTest::addColumn<QString>("password");
721     QTest::addColumn<QString>("file");
722     QTest::addColumn<QByteArray>("fileData");
723     QTest::addColumn<bool>("useIODevice");
724     QTest::addColumn<int>("success");
725 
726     // ### move this into external testdata
727     QFile file( SRCDIR "rfc3252.txt" );
728     QVERIFY( file.open( QIODevice::ReadOnly ) );
729     QByteArray rfc3252 = file.readAll();
730 
731     QByteArray bigData( 10*1024*1024, 0 );
732     bigData.fill( 'A' );
733 
734     // test the two put() overloads in one routine
735     for ( int i=0; i<2; i++ ) {
736         QTest::newRow( QString("relPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
737                 << QString("qtest/upload/rel01_%1") << rfc3252
738                 << (bool)(i==1) << 1;
739         /*
740     QTest::newRow( QString("relPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")
741         << QString("qtest/upload/rel02_%1") << rfc3252
742         << (bool)(i==1) << 1;
743     QTest::newRow( QString("relPath03_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")
744         << QString("qtest/upload/rel03_%1") << QByteArray()
745         << (bool)(i==1) << 1;
746     QTest::newRow( QString("relPath04_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")
747         << QString("qtest/upload/rel04_%1") << bigData
748         << (bool)(i==1) << 1;
749 
750     QTest::newRow( QString("absPath01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
751         << QString("/qtest/upload/abs01_%1") << rfc3252
752         << (bool)(i==1) << 1;
753     QTest::newRow( QString("absPath02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")
754         << QString("/srv/ftp/qtest/upload/abs02_%1") << rfc3252
755         << (bool)(i==1) << 1;
756 
757     QTest::newRow( QString("nonExist01_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
758         << QString("foo")  << QByteArray()
759         << (bool)(i==1) << 0;
760     QTest::newRow( QString("nonExist02_%1").arg(i).toLatin1().constData() ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
761         << QString("/foo") << QByteArray()
762         << (bool)(i==1) << 0;
763 */
764     }
765 }
766 
put()767 void tst_QFtp::put()
768 {
769     QFETCH( QString, host );
770     QFETCH( uint, port );
771     QFETCH( QString, user );
772     QFETCH( QString, password );
773     QFETCH( QString, file );
774     QFETCH( QByteArray, fileData );
775     QFETCH( bool, useIODevice );
776 
777 #ifdef Q_OS_WIN
778     QFETCH_GLOBAL(bool, setProxy);
779     if (setProxy) {
780         QFETCH_GLOBAL(int, proxyType);
781         if (proxyType == QNetworkProxy::Socks5Proxy) {
782             QSKIP("With socks5 the put() test takes too long time on Windows.", SkipAll);
783         }
784     }
785 #endif
786 
787     const int timestep = 50;
788 
789     if(file.contains('%'))
790         file = file.arg(uniqueExtension);
791 
792     // for the overload that takes a QIODevice
793     QBuffer buf_fileData( &fileData );
794     buf_fileData.open( QIODevice::ReadOnly );
795 
796     ResMapIt it;
797     //////////////////////////////////////////////////////////////////
798     // upload the file
799     init();
800     ftp = newFtp();
801     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
802     addCommand( QFtp::Login, ftp->login( user, password ) );
803     if ( useIODevice )
804         addCommand( QFtp::Put, ftp->put( &buf_fileData, file ) );
805     else
806         addCommand( QFtp::Put, ftp->put( fileData, file ) );
807     addCommand( QFtp::Close, ftp->close() );
808 
809     for(int time = 0; time <= fileData.length() / 20000; time += timestep) {
810         QTestEventLoop::instance().enterLoop( timestep );
811         if(ftp->currentCommand() == QFtp::None)
812             break;
813     }
814     delete ftp;
815     ftp = 0;
816     if ( QTestEventLoop::instance().timeout() )
817         QFAIL( "Network operation timed out" );
818 
819     it = resultMap.find( QFtp::Put );
820     QVERIFY( it != resultMap.end() );
821     QTEST( it.value().success, "success" );
822     if ( !it.value().success ) {
823         QVERIFY( !fileExists( host, port, user, password, file ) );
824         return; // the following tests are only meaningful if the file could be put
825     }
826     QVERIFY( bytesTotal == (int)fileData.size() );
827     QVERIFY( bytesDone == bytesTotal );
828 
829     QVERIFY( fileExists( host, port, user, password, file ) );
830 
831     //////////////////////////////////////////////////////////////////
832     // fetch file to make sure that it is equal to the uploaded file
833     init();
834     ftp = newFtp();
835     QBuffer buf;
836     buf.open( QIODevice::WriteOnly );
837     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
838     addCommand( QFtp::Login, ftp->login( user, password ) );
839     addCommand( QFtp::Get, ftp->get( file, &buf ) );
840     addCommand( QFtp::Close, ftp->close() );
841 
842     for(int time = 0; time <= fileData.length() / 20000; time += timestep) {
843         QTestEventLoop::instance().enterLoop( timestep );
844         if(ftp->currentCommand() == QFtp::None)
845             break;
846     }
847     delete ftp;
848     ftp = 0;
849     if ( QTestEventLoop::instance().timeout() )
850         QFAIL( "Network operation timed out" );
851 
852     QVERIFY( done_success == 1 );
853     QTEST( buf.buffer(), "fileData" );
854 
855     //////////////////////////////////////////////////////////////////
856     // cleanup (i.e. remove the file) -- this also tests the remove command
857     init();
858     ftp = newFtp();
859     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
860     addCommand( QFtp::Login, ftp->login( user, password ) );
861     addCommand( QFtp::Remove, ftp->remove( file ) );
862     addCommand( QFtp::Close, ftp->close() );
863 
864     QTestEventLoop::instance().enterLoop( timestep );
865     delete ftp;
866     ftp = 0;
867     if ( QTestEventLoop::instance().timeout() )
868         QFAIL( "Network operation timed out" );
869 
870     it = resultMap.find( QFtp::Remove );
871     QVERIFY( it != resultMap.end() );
872     QCOMPARE( it.value().success, 1 );
873 
874     QVERIFY( !fileExists( host, port, user, password, file ) );
875 }
876 
remove()877 void tst_QFtp::remove()
878 {
879     DEPENDS_ON( "put" );
880 }
881 
mkdir_data()882 void tst_QFtp::mkdir_data()
883 {
884     QTest::addColumn<QString>("host");
885     QTest::addColumn<uint>("port");
886     QTest::addColumn<QString>("user");
887     QTest::addColumn<QString>("password");
888     QTest::addColumn<QString>("cdDir");
889     QTest::addColumn<QString>("dirToCreate");
890     QTest::addColumn<int>("success");
891 
892     QTest::newRow( "relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
893             << "qtest/upload" << QString("rel01_%1") << 1;
894     QTest::newRow( "relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")
895             << "qtest/upload" << QString("rel02_%1") << 1;
896     QTest::newRow( "relPath03" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")
897             << "qtest/upload" << QString("rel03_%1") << 1;
898 
899     QTest::newRow( "absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
900             << "." << QString("/qtest/upload/abs01_%1") << 1;
901     QTest::newRow( "absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")
902             << "." << QString("/var/ftp/qtest/upload/abs02_%1") << 1;
903 
904     //    QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo")  << 0;
905     QTest::newRow( "nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
906             << "." << QString("foo")  << 0;
907     QTest::newRow( "nonExist02" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString()
908             << "." << QString("/foo") << 0;
909 }
910 
mkdir()911 void tst_QFtp::mkdir()
912 {
913     QFETCH( QString, host );
914     QFETCH( uint, port );
915     QFETCH( QString, user );
916     QFETCH( QString, password );
917     QFETCH( QString, cdDir );
918     QFETCH( QString, dirToCreate );
919 
920     if(dirToCreate.contains('%'))
921         dirToCreate = dirToCreate.arg(uniqueExtension);
922 
923     //////////////////////////////////////////////////////////////////
924     // create the directory
925     init();
926     ftp = newFtp();
927     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
928     addCommand( QFtp::Login, ftp->login( user, password ) );
929     addCommand( QFtp::Cd, ftp->cd( cdDir ) );
930     addCommand( QFtp::Mkdir, ftp->mkdir( dirToCreate ) );
931     addCommand( QFtp::Close, ftp->close() );
932 
933     QTestEventLoop::instance().enterLoop( 30 );
934     delete ftp;
935     ftp = 0;
936     if ( QTestEventLoop::instance().timeout() )
937         QFAIL( "Network operation timed out" );
938 
939     ResMapIt it = resultMap.find( QFtp::Mkdir );
940     QVERIFY( it != resultMap.end() );
941     QTEST( it.value().success, "success" );
942     if ( !it.value().success ) {
943         QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) );
944         return; // the following tests are only meaningful if the dir could be created
945     }
946     QVERIFY( dirExists( host, port, user, password, cdDir, dirToCreate ) );
947 
948     //////////////////////////////////////////////////////////////////
949     // create the directory again (should always fail!)
950     init();
951     ftp = newFtp();
952     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
953     addCommand( QFtp::Login, ftp->login( user, password ) );
954     addCommand( QFtp::Cd, ftp->cd( cdDir ) );
955     addCommand( QFtp::Mkdir, ftp->mkdir( dirToCreate ) );
956     addCommand( QFtp::Close, ftp->close() );
957 
958     QTestEventLoop::instance().enterLoop( 30 );
959     delete ftp;
960     ftp = 0;
961     if ( QTestEventLoop::instance().timeout() )
962         QFAIL( "Network operation timed out" );
963 
964     it = resultMap.find( QFtp::Mkdir );
965     QVERIFY( it != resultMap.end() );
966     QCOMPARE( it.value().success, 0 );
967 
968     //////////////////////////////////////////////////////////////////
969     // remove the directory
970     init();
971     ftp = newFtp();
972     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
973     addCommand( QFtp::Login, ftp->login( user, password ) );
974     addCommand( QFtp::Cd, ftp->cd( cdDir ) );
975     addCommand( QFtp::Rmdir, ftp->rmdir( dirToCreate ) );
976     addCommand( QFtp::Close, ftp->close() );
977 
978     QTestEventLoop::instance().enterLoop( 30 );
979     delete ftp;
980     ftp = 0;
981     if ( QTestEventLoop::instance().timeout() )
982         QFAIL( "Network operation timed out" );
983 
984     it = resultMap.find( QFtp::Rmdir );
985     QVERIFY( it != resultMap.end() );
986     QCOMPARE( it.value().success, 1 );
987 
988     QVERIFY( !dirExists( host, port, user, password, cdDir, dirToCreate ) );
989 }
990 
mkdir2()991 void tst_QFtp::mkdir2()
992 {
993     ftp = new QFtp;
994     ftp->connectToHost(QtNetworkSettings::serverName());
995     ftp->login();
996     current_id = ftp->cd("kake/test");
997 
998     QEventLoop loop;
999     connect(ftp, SIGNAL(done(bool)), &loop, SLOT(quit()));
1000     connect(ftp, SIGNAL(commandFinished(int, bool)), this, SLOT(mkdir2Slot(int, bool)));
1001     QTimer::singleShot(5000, &loop, SLOT(quit()));
1002 
1003     QSignalSpy commandStartedSpy(ftp, SIGNAL(commandStarted(int)));
1004     QSignalSpy commandFinishedSpy(ftp, SIGNAL(commandFinished(int, bool)));
1005 
1006     loop.exec();
1007 
1008     QCOMPARE(commandStartedSpy.count(), 4); // connect, login, cd, mkdir
1009     QCOMPARE(commandFinishedSpy.count(), 4);
1010 
1011     for (int i = 0; i < 4; ++i)
1012         QCOMPARE(commandFinishedSpy.at(i).at(0), commandStartedSpy.at(i).at(0));
1013 
1014     QVERIFY(!commandFinishedSpy.at(0).at(1).toBool());
1015     QVERIFY(!commandFinishedSpy.at(1).at(1).toBool());
1016     QVERIFY(commandFinishedSpy.at(2).at(1).toBool());
1017     QVERIFY(commandFinishedSpy.at(3).at(1).toBool());
1018 
1019     delete ftp;
1020     ftp = 0;
1021 }
1022 
mkdir2Slot(int id,bool)1023 void tst_QFtp::mkdir2Slot(int id, bool)
1024 {
1025     if (id == current_id)
1026         ftp->mkdir("kake/test");
1027 }
1028 
rmdir()1029 void tst_QFtp::rmdir()
1030 {
1031     DEPENDS_ON( "mkdir" );
1032 }
1033 
rename_data()1034 void tst_QFtp::rename_data()
1035 {
1036     QTest::addColumn<QString>("host");
1037     QTest::addColumn<QString>("user");
1038     QTest::addColumn<QString>("password");
1039     QTest::addColumn<QString>("cdDir");
1040     QTest::addColumn<QString>("oldfile");
1041     QTest::addColumn<QString>("newfile");
1042     QTest::addColumn<QString>("createFile");
1043     QTest::addColumn<QString>("renamedFile");
1044     QTest::addColumn<int>("success");
1045 
1046     QTest::newRow("relPath01") << QtNetworkSettings::serverName() << QString() << QString()
1047             << "qtest/upload"
1048             << QString("rel_old01_%1") << QString("rel_new01_%1")
1049             << QString("qtest/upload/rel_old01_%1") << QString("qtest/upload/rel_new01_%1")
1050             << 1;
1051     QTest::newRow("relPath02") << QtNetworkSettings::serverName() << QString("ftptest")     << "password"
1052             << "qtest/upload"
1053             << QString("rel_old02_%1") << QString("rel_new02_%1")
1054             << QString("qtest/upload/rel_old02_%1") << QString("qtest/upload/rel_new02_%1")
1055             << 1;
1056     QTest::newRow("relPath03") << QtNetworkSettings::serverName() << QString("ftptest")     << "password"
1057             << "qtest/upload"
1058             << QString("rel_old03_%1")<< QString("rel_new03_%1")
1059             << QString("qtest/upload/rel_old03_%1") << QString("qtest/upload/rel_new03_%1")
1060             << 1;
1061 
1062     QTest::newRow("absPath01") << QtNetworkSettings::serverName() << QString() << QString()
1063             << QString()
1064             << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1")
1065             << QString("/qtest/upload/abs_old01_%1") << QString("/qtest/upload/abs_new01_%1")
1066             << 1;
1067     QTest::newRow("absPath02") << QtNetworkSettings::serverName() << QString("ftptest")     << "password"
1068             << QString()
1069             << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1")
1070             << QString("/var/ftp/qtest/upload/abs_old02_%1") << QString("/var/ftp/qtest/upload/abs_new02_%1")
1071             << 1;
1072 
1073     QTest::newRow("nonExist01") << QtNetworkSettings::serverName() << QString() << QString()
1074             << QString()
1075             << QString("foo") << "new_foo"
1076             << QString() << QString()
1077             << 0;
1078     QTest::newRow("nonExist02") << QtNetworkSettings::serverName() << QString() << QString()
1079             << QString()
1080             << QString("/foo") << QString("/new_foo")
1081             << QString() << QString()
1082             << 0;
1083 }
1084 
renameInit(const QString & host,const QString & user,const QString & password,const QString & createFile)1085 void tst_QFtp::renameInit( const QString &host, const QString &user, const QString &password, const QString &createFile )
1086 {
1087     if ( !createFile.isNull() ) {
1088         // upload the file
1089         init();
1090         ftp = newFtp();
1091         addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
1092         addCommand( QFtp::Login, ftp->login( user, password ) );
1093         addCommand( QFtp::Put, ftp->put( QByteArray(), createFile ) );
1094         addCommand( QFtp::Close, ftp->close() );
1095 
1096         QTestEventLoop::instance().enterLoop( 50 );
1097         delete ftp;
1098         ftp = 0;
1099         if ( QTestEventLoop::instance().timeout() )
1100             QFAIL( "Network operation timed out" );
1101 
1102         ResMapIt it = resultMap.find( QFtp::Put );
1103         QVERIFY( it != resultMap.end() );
1104         QVERIFY( it.value().success == 1 );
1105 
1106         QVERIFY( fileExists( host, 21, user, password, createFile ) );
1107     }
1108 }
1109 
renameCleanup(const QString & host,const QString & user,const QString & password,const QString & fileToDelete)1110 void tst_QFtp::renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete )
1111 {
1112     if ( !fileToDelete.isNull() ) {
1113         // cleanup (i.e. remove the file)
1114         init();
1115         ftp = newFtp();
1116         addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
1117         addCommand( QFtp::Login, ftp->login( user, password ) );
1118         addCommand( QFtp::Remove, ftp->remove( fileToDelete ) );
1119         addCommand( QFtp::Close, ftp->close() );
1120 
1121         QTestEventLoop::instance().enterLoop( 30 );
1122         delete ftp;
1123         ftp = 0;
1124         if ( QTestEventLoop::instance().timeout() )
1125             QFAIL( "Network operation timed out" );
1126 
1127         ResMapIt it = resultMap.find( QFtp::Remove );
1128         QVERIFY( it != resultMap.end() );
1129         QVERIFY( it.value().success == 1 );
1130 
1131         QVERIFY( !fileExists( host, 21, user, password, fileToDelete ) );
1132     }
1133 }
1134 
rename()1135 void tst_QFtp::rename()
1136 {
1137     QFETCH( QString, host );
1138     QFETCH( QString, user );
1139     QFETCH( QString, password );
1140     QFETCH( QString, cdDir );
1141     QFETCH( QString, oldfile );
1142     QFETCH( QString, newfile );
1143     QFETCH( QString, createFile );
1144     QFETCH( QString, renamedFile );
1145 
1146     if(oldfile.contains('%'))
1147         oldfile = oldfile.arg(uniqueExtension);
1148     if(newfile.contains('%'))
1149         newfile = newfile.arg(uniqueExtension);
1150     if(createFile.contains('%'))
1151         createFile = createFile.arg(uniqueExtension);
1152     if(renamedFile.contains('%'))
1153         renamedFile = renamedFile.arg(uniqueExtension);
1154 
1155     renameInit( host, user, password, createFile );
1156 
1157     init();
1158     ftp = newFtp();
1159     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
1160     addCommand( QFtp::Login, ftp->login( user, password ) );
1161     if ( !cdDir.isNull() )
1162         addCommand( QFtp::Cd, ftp->cd( cdDir ) );
1163     addCommand( QFtp::Rename, ftp->rename( oldfile, newfile ) );
1164     addCommand( QFtp::Close, ftp->close() );
1165 
1166     QTestEventLoop::instance().enterLoop( 30 );
1167     delete ftp;
1168     ftp = 0;
1169     if ( QTestEventLoop::instance().timeout() )
1170         QFAIL( "Network operation timed out" );
1171 
1172     ResMapIt it = resultMap.find( QFtp::Rename );
1173     QVERIFY( it != resultMap.end() );
1174     QTEST( it.value().success, "success" );
1175 
1176     if ( it.value().success ) {
1177         QVERIFY( !fileExists( host, 21, user, password, oldfile, cdDir ) );
1178         QVERIFY( fileExists( host, 21, user, password, newfile, cdDir ) );
1179         QVERIFY( fileExists( host, 21, user, password, renamedFile ) );
1180     } else {
1181         QVERIFY( !fileExists( host, 21, user, password, newfile, cdDir ) );
1182         QVERIFY( !fileExists( host, 21, user, password, renamedFile ) );
1183     }
1184 
1185     renameCleanup( host, user, password, renamedFile );
1186 }
1187 
1188 /*
1189   The commandSequence() test does not test any particular function. It rather
1190   tests a sequence of arbitrary commands specified in the test data.
1191 */
1192 class FtpCommand
1193 {
1194 public:
FtpCommand()1195     FtpCommand() :
1196             cmd(QFtp::None)
1197     { }
1198 
FtpCommand(QFtp::Command command)1199     FtpCommand( QFtp::Command command ) :
1200             cmd(command)
1201     { }
1202 
FtpCommand(QFtp::Command command,const QStringList & arguments)1203     FtpCommand( QFtp::Command command, const QStringList &arguments ) :
1204             cmd(command), args(arguments)
1205     { }
1206 
FtpCommand(const FtpCommand & c)1207     FtpCommand( const FtpCommand &c )
1208     { *this = c; }
1209 
operator =(const FtpCommand & c)1210     FtpCommand &operator=( const FtpCommand &c )
1211                          {
1212         this->cmd  = c.cmd;
1213         this->args = c.args;
1214         return *this;
1215     }
1216 
1217     QFtp::Command cmd;
1218     QStringList args;
1219 };
operator <<(QDataStream & s,const FtpCommand & command)1220 QDataStream &operator<<( QDataStream &s, const FtpCommand &command )
1221 {
1222     s << (int)command.cmd;
1223     s << command.args;
1224     return s;
1225 }
operator >>(QDataStream & s,FtpCommand & command)1226 QDataStream &operator>>( QDataStream &s, FtpCommand &command )
1227 {
1228     int tmp;
1229     s >> tmp;
1230     command.cmd = (QFtp::Command)tmp;
1231     s >> command.args;
1232     return s;
1233 }
Q_DECLARE_METATYPE(QList<FtpCommand>)1234 Q_DECLARE_METATYPE(QList<FtpCommand>)
1235 
1236 void tst_QFtp::commandSequence_data()
1237 {
1238     // some "constants"
1239     QStringList argConnectToHost01;
1240     argConnectToHost01 << QtNetworkSettings::serverName() << "21";
1241 
1242     QStringList argLogin01, argLogin02, argLogin03, argLogin04;
1243     argLogin01 << QString() << QString();
1244     argLogin02 << "ftp"         << QString();
1245     argLogin03 << "ftp"         << "foo";
1246     argLogin04 << QString("ftptest")     << "password";
1247 
1248     FtpCommand connectToHost01( QFtp::ConnectToHost, argConnectToHost01 );
1249     FtpCommand login01( QFtp::Login, argLogin01 );
1250     FtpCommand login02( QFtp::Login, argLogin01 );
1251     FtpCommand login03( QFtp::Login, argLogin01 );
1252     FtpCommand login04( QFtp::Login, argLogin01 );
1253     FtpCommand close01( QFtp::Close );
1254 
1255     QTest::addColumn<QList<FtpCommand> >("cmds");
1256     QTest::addColumn<int>("success");
1257 
1258     // success data
1259     {
1260         QList<FtpCommand> cmds;
1261         cmds << connectToHost01;
1262         QTest::newRow( "simple_ok01" ) << cmds << 1;
1263     }
1264     {
1265         QList<FtpCommand> cmds;
1266         cmds << connectToHost01;
1267         cmds << login01;
1268         QTest::newRow( "simple_ok02" ) << cmds << 1;
1269     }
1270     {
1271         QList<FtpCommand> cmds;
1272         cmds << connectToHost01;
1273         cmds << login01;
1274         cmds << close01;
1275         QTest::newRow( "simple_ok03" ) << cmds << 1;
1276     }
1277     {
1278         QList<FtpCommand> cmds;
1279         cmds << connectToHost01;
1280         cmds << close01;
1281         QTest::newRow( "simple_ok04" ) << cmds << 1;
1282     }
1283     {
1284         QList<FtpCommand> cmds;
1285         cmds << connectToHost01;
1286         cmds << login01;
1287         cmds << close01;
1288         cmds << connectToHost01;
1289         cmds << login02;
1290         cmds << close01;
1291         QTest::newRow( "connect_twice" ) << cmds << 1;
1292     }
1293 
1294     // error data
1295     {
1296         QList<FtpCommand> cmds;
1297         cmds << close01;
1298         QTest::newRow( "error01" ) << cmds << 0;
1299     }
1300     {
1301         QList<FtpCommand> cmds;
1302         cmds << login01;
1303         QTest::newRow( "error02" ) << cmds << 0;
1304     }
1305     {
1306         QList<FtpCommand> cmds;
1307         cmds << login01;
1308         cmds << close01;
1309         QTest::newRow( "error03" ) << cmds << 0;
1310     }
1311     {
1312         QList<FtpCommand> cmds;
1313         cmds << connectToHost01;
1314         cmds << login01;
1315         cmds << close01;
1316         cmds << login01;
1317         QTest::newRow( "error04" ) << cmds << 0;
1318     }
1319 }
1320 
commandSequence()1321 void tst_QFtp::commandSequence()
1322 {
1323     QFETCH( QList<FtpCommand>, cmds );
1324 
1325     ftp = newFtp();
1326     QList<FtpCommand>::iterator it;
1327     for ( it = cmds.begin(); it != cmds.end(); ++it ) {
1328         switch ( (*it).cmd ) {
1329         case QFtp::ConnectToHost:
1330             {
1331                 QVERIFY( (*it).args.count() == 2 );
1332                 uint port;
1333                 bool portOk;
1334                 port = (*it).args[1].toUInt( &portOk );
1335                 QVERIFY( portOk );
1336                 ids << ftp->connectToHost( (*it).args[0], port );
1337             }
1338             break;
1339         case QFtp::Login:
1340             QVERIFY( (*it).args.count() == 2 );
1341             ids << ftp->login( (*it).args[0], (*it).args[1] );
1342             break;
1343         case QFtp::Close:
1344             QVERIFY( (*it).args.count() == 0 );
1345             ids << ftp->close();
1346             break;
1347         default:
1348             QFAIL( "Error in test: unexpected enum value" );
1349             break;
1350         }
1351     }
1352 
1353     QTestEventLoop::instance().enterLoop( 30 );
1354     delete ftp;
1355     ftp = 0;
1356     if ( QTestEventLoop::instance().timeout() )
1357         QFAIL( "Network operation timed out" );
1358 
1359     QTEST( commandSequence_success, "success" );
1360 }
1361 
abort_data()1362 void tst_QFtp::abort_data()
1363 {
1364     QTest::addColumn<QString>("host");
1365     QTest::addColumn<uint>("port");
1366     QTest::addColumn<QString>("file");
1367     QTest::addColumn<QByteArray>("uploadData");
1368 
1369     QTest::newRow( "get_fluke01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/bigfile") << QByteArray();
1370     QTest::newRow( "get_fluke02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/rfc3252") << QByteArray();
1371 
1372     // Qt/CE and Symbian test environment has to less memory for this test
1373 #if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
1374     QByteArray bigData( 10*1024*1024, 0 );
1375 #else
1376     QByteArray bigData( 1*1024*1024, 0 );
1377 #endif
1378     bigData.fill( 'B' );
1379     QTest::newRow( "put_fluke01" ) << QtNetworkSettings::serverName() << (uint)21 << QString("qtest/upload/abort_put") << bigData;
1380 }
1381 
abort()1382 void tst_QFtp::abort()
1383 {
1384     // In case you wonder where the abort() actually happens, look into
1385     // tst_QFtp::dataTransferProgress
1386     //
1387     QFETCH( QString, host );
1388     QFETCH( uint, port );
1389     QFETCH( QString, file );
1390     QFETCH( QByteArray, uploadData );
1391 
1392     QFtp::Command cmd;
1393     if ( uploadData.size() == 0 )
1394         cmd = QFtp::Get;
1395     else
1396         cmd = QFtp::Put;
1397 
1398     ftp = newFtp();
1399     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
1400     addCommand( QFtp::Login, ftp->login() );
1401     if ( cmd == QFtp::Get )
1402         addCommand( cmd, ftp->get( file ) );
1403     else
1404         addCommand( cmd, ftp->put( uploadData, file ) );
1405     addCommand( QFtp::Close, ftp->close() );
1406 
1407     for(int time = 0; time <= uploadData.length() / 30000; time += 30) {
1408         QTestEventLoop::instance().enterLoop( 50 );
1409         if(ftp->currentCommand() == QFtp::None)
1410             break;
1411     }
1412     delete ftp;
1413     ftp = 0;
1414     if ( QTestEventLoop::instance().timeout() )
1415         QFAIL( "Network operation timed out" );
1416 
1417     ResMapIt it = resultMap.find( cmd );
1418     QVERIFY( it != resultMap.end() );
1419     // ### how to test the abort?
1420     if ( it.value().success ) {
1421         // The FTP server on fluke is sadly returning a success, even when
1422         // the operation was aborted. So we have to use some heuristics.
1423         if ( host == QtNetworkSettings::serverName() ) {
1424             if ( cmd == QFtp::Get ) {
1425                 QVERIFY(bytesDone <= bytesTotal);
1426             } else {
1427                 // put commands should always be aborted, since we use really
1428                 // big data
1429                 QVERIFY( bytesDone != bytesTotal );
1430             }
1431         } else {
1432             // this could be tested by verifying that no more progress signals are emitted
1433             QVERIFY(bytesDone <= bytesTotal);
1434         }
1435     } else {
1436         QVERIFY( bytesDone != bytesTotal );
1437     }
1438 
1439     if ( cmd == QFtp::Put ) {
1440         //////////////////////////////////////
1441         // cleanup (i.e. remove the file)
1442         init();
1443         ftp = newFtp();
1444         addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
1445         addCommand( QFtp::Login, ftp->login() );
1446         addCommand( QFtp::Remove, ftp->remove( file ) );
1447         addCommand( QFtp::Close, ftp->close() );
1448 
1449         QTestEventLoop::instance().enterLoop( 30 );
1450         delete ftp;
1451         ftp = 0;
1452         if ( QTestEventLoop::instance().timeout() )
1453             QFAIL( "Network operation timed out" );
1454 
1455         it = resultMap.find( QFtp::Remove );
1456         QVERIFY( it != resultMap.end() );
1457         QVERIFY( it.value().success == 1 );
1458     }
1459 }
1460 
bytesAvailable_data()1461 void tst_QFtp::bytesAvailable_data()
1462 {
1463     QTest::addColumn<QString>("host");
1464     QTest::addColumn<QString>("file");
1465     QTest::addColumn<int>("type");
1466     QTest::addColumn<qlonglong>("bytesAvailFinishedGet");
1467     QTest::addColumn<qlonglong>("bytesAvailFinished");
1468     QTest::addColumn<qlonglong>("bytesAvailDone");
1469 
1470     QTest::newRow( "fluke01" ) << QtNetworkSettings::serverName() << QString("qtest/bigfile") << 0 << (qlonglong)519240 << (qlonglong)519240 << (qlonglong)519240;
1471     QTest::newRow( "fluke02" ) << QtNetworkSettings::serverName() << QString("qtest/rfc3252") << 0 << (qlonglong)25962 << (qlonglong)25962 << (qlonglong)25962;
1472 
1473     QTest::newRow( "fluke03" ) << QtNetworkSettings::serverName() << QString("qtest/bigfile") << 1 << (qlonglong)519240 << (qlonglong)0 << (qlonglong)0;
1474     QTest::newRow( "fluke04" ) << QtNetworkSettings::serverName() << QString("qtest/rfc3252") << 1 << (qlonglong)25962 << (qlonglong)0 << (qlonglong)0;
1475 }
1476 
bytesAvailable()1477 void tst_QFtp::bytesAvailable()
1478 {
1479     QFETCH( QString, host );
1480     QFETCH( QString, file );
1481     QFETCH( int, type );
1482 
1483     ftp = newFtp();
1484     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host ) );
1485     addCommand( QFtp::Login, ftp->login() );
1486     addCommand( QFtp::Get, ftp->get( file ) );
1487     if ( type != 0 )
1488         addCommand( QFtp::Close, ftp->close() );
1489 
1490     QTestEventLoop::instance().enterLoop( 40 );
1491     if ( QTestEventLoop::instance().timeout() )
1492         QFAIL( "Network operation timed out" );
1493 
1494     ResMapIt it = resultMap.find( QFtp::Get );
1495     QVERIFY( it != resultMap.end() );
1496     QVERIFY( it.value().success );
1497 
1498     QFETCH(qlonglong, bytesAvailFinishedGet);
1499     QCOMPARE(bytesAvailable_finishedGet, bytesAvailFinishedGet);
1500 
1501     QFETCH(qlonglong, bytesAvailFinished);
1502     QCOMPARE(bytesAvailable_finished, bytesAvailFinished);
1503 
1504     QFETCH(qlonglong, bytesAvailDone);
1505     QCOMPARE(bytesAvailable_done, bytesAvailDone);
1506 
1507     ftp->readAll();
1508     QVERIFY( ftp->bytesAvailable() == 0 );
1509     delete ftp;
1510     ftp = 0;
1511 }
1512 
activeMode()1513 void tst_QFtp::activeMode()
1514 {
1515     QFile file("tst_QFtp_activeMode_inittab");
1516     file.open(QIODevice::ReadWrite);
1517     QFtp ftp;
1518     ftp.setTransferMode(QFtp::Active);
1519     ftp.connectToHost(QtNetworkSettings::serverName(), 21);
1520     ftp.login();
1521     ftp.list();
1522     ftp.get("/qtest/rfc3252.txt", &file);
1523     connect(&ftp, SIGNAL(done(bool)), SLOT(activeModeDone(bool)));
1524     QTestEventLoop::instance().enterLoop(900);
1525     QFile::remove("tst_QFtp_activeMode_inittab");
1526     QVERIFY(done_success == 1);
1527 
1528 }
1529 
activeModeDone(bool error)1530 void tst_QFtp::activeModeDone(bool error)
1531 {
1532     done_success = error ? -1 : 1;
1533     QTestEventLoop::instance().exitLoop();
1534 }
1535 
proxy_data()1536 void tst_QFtp::proxy_data()
1537 {
1538     QTest::addColumn<QString>("host");
1539     QTest::addColumn<uint>("port");
1540     QTest::addColumn<QString>("user");
1541     QTest::addColumn<QString>("password");
1542     QTest::addColumn<QString>("dir");
1543     QTest::addColumn<int>("success");
1544     QTest::addColumn<QStringList>("entryNames"); // ### we should rather use a QList<QUrlInfo> here
1545 
1546     QStringList flukeRoot;
1547     flukeRoot << "qtest";
1548     QStringList flukeQtest;
1549     flukeQtest << "bigfile";
1550     flukeQtest << "nonASCII";
1551     flukeQtest << "rfc3252";
1552     flukeQtest << "rfc3252.txt";
1553     flukeQtest << "upload";
1554 
1555     QTest::newRow( "proxy_relPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("qtest") << 1 << flukeQtest;
1556     QTest::newRow( "proxy_relPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")     << QString("qtest") << 1 << flukeQtest;
1557 
1558     QTest::newRow( "proxy_absPath01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/qtest") << 1 << flukeQtest;
1559     QTest::newRow( "proxy_absPath02" ) << QtNetworkSettings::serverName() << (uint)21 << QString("ftptest")     << QString("password")     << QString("/var/ftp/qtest") << 1 << flukeQtest;
1560 
1561     QTest::newRow( "proxy_nonExist01" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("foo")  << 0 << QStringList();
1562     QTest::newRow( "proxy_nonExist03" ) << QtNetworkSettings::serverName() << (uint)21 << QString() << QString() << QString("/foo") << 0 << QStringList();
1563 }
1564 
proxy()1565 void tst_QFtp::proxy()
1566 {
1567     QFETCH( QString, host );
1568     QFETCH( uint, port );
1569     QFETCH( QString, user );
1570     QFETCH( QString, password );
1571     QFETCH( QString, dir );
1572 
1573     ftp = newFtp();
1574     addCommand( QFtp::SetProxy, ftp->setProxy( QtNetworkSettings::serverName(), 2121 ) );
1575     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
1576     addCommand( QFtp::Login, ftp->login( user, password ) );
1577     addCommand( QFtp::Cd, ftp->cd( dir ) );
1578     addCommand( QFtp::List, ftp->list() );
1579 
1580     QTestEventLoop::instance().enterLoop( 50 );
1581 
1582     delete ftp;
1583     ftp = 0;
1584     if ( QTestEventLoop::instance().timeout() ) {
1585         QFAIL( "Network operation timed out" );
1586     }
1587 
1588     ResMapIt it = resultMap.find( QFtp::Cd );
1589     QVERIFY( it != resultMap.end() );
1590     QFETCH( int, success );
1591     QCOMPARE( it.value().success, success );
1592     QFETCH( QStringList, entryNames );
1593     QCOMPARE( listInfo_i.count(), entryNames.count() );
1594     for ( uint i=0; i < (uint) entryNames.count(); i++ ) {
1595         QCOMPARE( listInfo_i[i].name(), entryNames[i] );
1596     }
1597 }
1598 
binaryAscii()1599 void tst_QFtp::binaryAscii()
1600 {
1601     QString file = "asciifile%1.txt";
1602 
1603     if(file.contains('%'))
1604         file = file.arg(uniqueExtension);
1605 
1606     QByteArray putData = "a line of text\r\n";
1607 
1608     init();
1609     ftp = newFtp();
1610     addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::serverName(), 21));
1611     addCommand(QFtp::Login, ftp->login("ftptest", "password"));
1612     addCommand(QFtp::Cd, ftp->cd("qtest/upload"));
1613     addCommand(QFtp::Put, ftp->put(putData, file, QFtp::Ascii));
1614     addCommand(QFtp::Close, ftp->close());
1615 
1616     QTestEventLoop::instance().enterLoop( 30 );
1617     delete ftp;
1618     ftp = 0;
1619     if ( QTestEventLoop::instance().timeout() )
1620         QFAIL( "Network operation timed out" );
1621 
1622     ResMapIt it = resultMap.find(QFtp::Put);
1623     QVERIFY(it != resultMap.end());
1624     QVERIFY(it.value().success);
1625 
1626     QByteArray getData;
1627     QBuffer getBuf(&getData);
1628     getBuf.open(QBuffer::WriteOnly);
1629 
1630     init();
1631     ftp = newFtp();
1632     addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::serverName(), 21));
1633     addCommand(QFtp::Login, ftp->login("ftptest", "password"));
1634     addCommand(QFtp::Cd, ftp->cd("qtest/upload"));
1635     addCommand(QFtp::Get, ftp->get(file, &getBuf, QFtp::Binary));
1636     addCommand(QFtp::Close, ftp->close());
1637 
1638     QTestEventLoop::instance().enterLoop( 30 );
1639     delete ftp;
1640     ftp = 0;
1641     if ( QTestEventLoop::instance().timeout() )
1642         QFAIL( "Network operation timed out" );
1643 
1644     ResMapIt it2 = resultMap.find(QFtp::Get);
1645     QVERIFY(it2 != resultMap.end());
1646     QVERIFY(it2.value().success);
1647     // most modern ftp servers leave the file as it is by default
1648     // (and do not remove the windows line ending), the -1 below could be
1649     // deleted in the future
1650     QVERIFY(getData.size() == putData.size()-1);
1651     //////////////////////////////////////////////////////////////////
1652     // cleanup (i.e. remove the file) -- this also tests the remove command
1653     init();
1654     ftp = newFtp();
1655     addCommand(QFtp::ConnectToHost, ftp->connectToHost(QtNetworkSettings::serverName(), 21));
1656     addCommand(QFtp::Login, ftp->login("ftptest", "password"));
1657     addCommand(QFtp::Cd, ftp->cd("qtest/upload"));
1658     addCommand(QFtp::Remove, ftp->remove(file));
1659     addCommand(QFtp::Close, ftp->close());
1660 
1661     QTestEventLoop::instance().enterLoop( 30 );
1662     delete ftp;
1663     ftp = 0;
1664     if ( QTestEventLoop::instance().timeout() )
1665         QFAIL( "Network operation timed out" );
1666 
1667     it = resultMap.find( QFtp::Remove );
1668     QVERIFY( it != resultMap.end() );
1669     QCOMPARE( it.value().success, 1 );
1670 
1671     QVERIFY(!fileExists(QtNetworkSettings::serverName(), 21, "ftptest", "password", file));
1672 }
1673 
1674 
1675 // test QFtp::currentId() and QFtp::currentCommand()
1676 #define CURRENTCOMMAND_TEST \
1677 { \
1678   ResMapIt it; \
1679   for ( it = resultMap.begin(); it != resultMap.end(); ++it ) { \
1680                                                                 if ( it.value().id == ftp->currentId() ) { \
1681                                                                                                            QVERIFY( it.key() == ftp->currentCommand() ); \
1682                                                                                                        } \
1683 } \
1684 }
1685 
commandStarted(int id)1686 void tst_QFtp::commandStarted( int id )
1687 {
1688 #if defined( DUMP_SIGNALS )
1689     qDebug( "%d:commandStarted( %d )", ftp->currentId(), id );
1690 #endif
1691     // make sure that the commandStarted and commandFinished are nested correctly
1692     QVERIFY( current_id == 0 );
1693     current_id = id;
1694 
1695     QVERIFY( !ids.isEmpty() );
1696     QVERIFY( ids.first() == id );
1697     if ( ids.count() > 1 ) {
1698         QVERIFY( ftp->hasPendingCommands() );
1699     } else {
1700         QVERIFY( !ftp->hasPendingCommands() );
1701     }
1702 
1703     QVERIFY( ftp->currentId() == id );
1704     QVERIFY( cur_state == ftp->state() );
1705     CURRENTCOMMAND_TEST;
1706 
1707     QVERIFY( ftp->error() == QFtp::NoError );
1708 }
1709 
commandFinished(int id,bool error)1710 void tst_QFtp::commandFinished( int id, bool error )
1711 {
1712 #if defined( DUMP_SIGNALS )
1713     qDebug( "%d:commandFinished( %d, %d ) -- errorString: '%s'",
1714             ftp->currentId(), id, (int)error, ftp->errorString().toLatin1().constData() );
1715 #endif
1716     if ( ftp->currentCommand() == QFtp::Get ) {
1717         bytesAvailable_finishedGet = ftp->bytesAvailable();
1718     }
1719     bytesAvailable_finished = ftp->bytesAvailable();
1720 
1721     // make sure that the commandStarted and commandFinished are nested correctly
1722     QVERIFY( current_id == id );
1723     current_id = 0;
1724 
1725     QVERIFY( !ids.isEmpty() );
1726     QVERIFY( ids.first() == id );
1727     if ( !error && ids.count() > 1) {
1728         QVERIFY( ftp->hasPendingCommands() );
1729     } else {
1730         QVERIFY( !ftp->hasPendingCommands() );
1731     }
1732     if ( error ) {
1733         QVERIFY( ftp->error() != QFtp::NoError );
1734         ids.clear();
1735     } else {
1736         QVERIFY( ftp->error() == QFtp::NoError );
1737         ids.pop_front();
1738     }
1739 
1740     QVERIFY( ftp->currentId() == id );
1741     QVERIFY( cur_state == ftp->state() );
1742     CURRENTCOMMAND_TEST;
1743 
1744     if ( QTest::currentTestFunction() != QLatin1String("commandSequence") ) {
1745         ResMapIt it = resultMap.find( ftp->currentCommand() );
1746         QVERIFY( it != resultMap.end() );
1747         QVERIFY( it.value().success == -1 );
1748         if ( error )
1749             it.value().success = 0;
1750         else
1751             it.value().success = 1;
1752     }
1753 }
1754 
done(bool error)1755 void tst_QFtp::done( bool error )
1756 {
1757 #if defined( DUMP_SIGNALS )
1758     qDebug( "%d:done( %d )", ftp->currentId(), (int)error );
1759 #endif
1760     bytesAvailable_done = ftp->bytesAvailable();
1761 
1762     QVERIFY( ftp->currentId() == 0 );
1763     QVERIFY( current_id == 0 );
1764     QVERIFY( ids.isEmpty() );
1765     QVERIFY( cur_state == ftp->state() );
1766     QVERIFY( !ftp->hasPendingCommands() );
1767 
1768     if ( QTest::currentTestFunction() == QLatin1String("commandSequence") ) {
1769         QVERIFY( commandSequence_success == -1 );
1770         if ( error )
1771             commandSequence_success = 0;
1772         else
1773             commandSequence_success = 1;
1774     }
1775     QVERIFY( done_success == -1 );
1776     if ( error ) {
1777         QVERIFY( ftp->error() != QFtp::NoError );
1778         done_success = 0;
1779     } else {
1780         QVERIFY( ftp->error() == QFtp::NoError );
1781         done_success = 1;
1782     }
1783     QTestEventLoop::instance().exitLoop();
1784 }
1785 
stateChanged(int state)1786 void tst_QFtp::stateChanged( int state )
1787 {
1788 #if defined( DUMP_SIGNALS )
1789     qDebug( "%d:  stateChanged( %d )", ftp->currentId(), state );
1790 #endif
1791     QCOMPARE( ftp->currentId(), current_id );
1792     CURRENTCOMMAND_TEST;
1793 
1794     QVERIFY( state != cur_state );
1795     QCOMPARE( state, (int)ftp->state() );
1796     if ( state != QFtp::Unconnected ) {
1797         // make sure that the states are always emitted in the right order (for
1798         // this, we assume an ordering on the enum values, which they have at
1799         // the moment)
1800         QVERIFY( cur_state < state );
1801 
1802         // make sure that state changes are only emitted in response to certain
1803         // commands
1804         switch ( state ) {
1805         case QFtp::HostLookup:
1806         case QFtp::Connecting:
1807         case QFtp::Connected:
1808             QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::ConnectToHost );
1809             break;
1810         case QFtp::LoggedIn:
1811             QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Login );
1812             break;
1813         case QFtp::Closing:
1814             QCOMPARE( (int)ftp->currentCommand(), (int)QFtp::Close );
1815             break;
1816         default:
1817             QWARN( QString("Unexpected state '%1'").arg(state).toLatin1().constData() );
1818             break;
1819         }
1820     }
1821     cur_state = state;
1822 
1823     if ( QTest::currentTestFunction() == QLatin1String("connectToHost") ) {
1824         switch ( state ) {
1825         case QFtp::HostLookup:
1826         case QFtp::Connecting:
1827         case QFtp::LoggedIn:
1828         case QFtp::Closing:
1829             // ignore
1830             break;
1831         case QFtp::Connected:
1832         case QFtp::Unconnected:
1833             QVERIFY( connectToHost_state == -1 );
1834             connectToHost_state = state;
1835             break;
1836         default:
1837             QWARN( QString("Unknown state '%1'").arg(state).toLatin1().constData() );
1838             break;
1839         }
1840     } else if ( QTest::currentTestFunction() == QLatin1String("close") ) {
1841         ResMapIt it = resultMap.find( QFtp::Close );
1842         if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) {
1843             if ( state == QFtp::Closing ) {
1844                 QVERIFY( close_state == -1 );
1845                 close_state = state;
1846             } else if ( state == QFtp::Unconnected ) {
1847                 QVERIFY( close_state == QFtp::Closing );
1848                 close_state = state;
1849             }
1850         }
1851     } else if ( QTest::currentTestFunction() == QLatin1String("login") ) {
1852         ResMapIt it = resultMap.find( QFtp::Login );
1853         if ( it!=resultMap.end() && ftp->currentId()==it.value().id ) {
1854             if ( state == QFtp::LoggedIn ) {
1855                 QVERIFY( login_state == -1 );
1856                 login_state = state;
1857             }
1858         }
1859     }
1860 }
1861 
listInfo(const QUrlInfo & i)1862 void tst_QFtp::listInfo( const QUrlInfo &i )
1863 {
1864 #if defined( DUMP_SIGNALS )
1865     qDebug( "%d:  listInfo( %s )", ftp->currentId(), i.name().toLatin1().constData() );
1866 #endif
1867     QCOMPARE( ftp->currentId(), current_id );
1868     if ( ids.count() > 1 ) {
1869         QVERIFY( ftp->hasPendingCommands() );
1870     } else {
1871         QVERIFY( !ftp->hasPendingCommands() );
1872     }
1873     QVERIFY( cur_state == ftp->state() );
1874     CURRENTCOMMAND_TEST;
1875 
1876     if ( QTest::currentTestFunction()==QLatin1String("list") || QTest::currentTestFunction()==QLatin1String("cd") || QTest::currentTestFunction()==QLatin1String("proxy") || inFileDirExistsFunction ) {
1877         ResMapIt it = resultMap.find( QFtp::List );
1878         QVERIFY( it != resultMap.end() );
1879         QVERIFY( ftp->currentId() == it.value().id );
1880         listInfo_i << i;
1881     }
1882 }
1883 
readyRead()1884 void tst_QFtp::readyRead()
1885 {
1886 #if defined( DUMP_SIGNALS )
1887     qDebug( "%d:  readyRead(), bytesAvailable == %lu", ftp->currentId(), ftp->bytesAvailable() );
1888 #endif
1889     QCOMPARE( ftp->currentId(), current_id );
1890     if ( ids.count() > 1 ) {
1891         QVERIFY( ftp->hasPendingCommands() );
1892     } else {
1893         QVERIFY( !ftp->hasPendingCommands() );
1894     }
1895     QVERIFY( cur_state == ftp->state() );
1896     CURRENTCOMMAND_TEST;
1897 
1898     if ( QTest::currentTestFunction() != QLatin1String("bytesAvailable") ) {
1899         int oldSize = newData_ba.size();
1900         qlonglong bytesAvail = ftp->bytesAvailable();
1901         QByteArray ba = ftp->readAll();
1902         QVERIFY( ba.size() == (int) bytesAvail );
1903         newData_ba.resize( oldSize + ba.size() );
1904         memcpy( newData_ba.data()+oldSize, ba.data(), ba.size() );
1905 
1906         if ( bytesTotal != -1 ) {
1907             QVERIFY( (int)newData_ba.size() <= bytesTotal );
1908         }
1909         QVERIFY( (int)newData_ba.size() == bytesDone );
1910     }
1911 }
1912 
dataTransferProgress(qint64 done,qint64 total)1913 void tst_QFtp::dataTransferProgress( qint64 done, qint64 total )
1914 {
1915 #if defined( DUMP_SIGNALS )
1916     qDebug( "%d:  dataTransferProgress( %lli, %lli )", ftp->currentId(), done, total );
1917 #endif
1918     QCOMPARE( ftp->currentId(), current_id );
1919     if ( ids.count() > 1 ) {
1920         QVERIFY( ftp->hasPendingCommands() );
1921     } else {
1922         QVERIFY( !ftp->hasPendingCommands() );
1923     }
1924     QVERIFY( cur_state == ftp->state() );
1925     CURRENTCOMMAND_TEST;
1926 
1927     if ( bytesTotal == bytesTotal_init ) {
1928         bytesTotal = total;
1929     } else {
1930         QVERIFY( bytesTotal == total );
1931     }
1932 
1933     QVERIFY( bytesTotal != bytesTotal_init );
1934     QVERIFY( bytesDone <= done );
1935     bytesDone = done;
1936     if ( bytesTotal != -1 ) {
1937         QVERIFY( bytesDone <= bytesTotal );
1938     }
1939 
1940     if ( QTest::currentTestFunction() == QLatin1String("abort") ) {
1941         // ### it would be nice if we could specify in our testdata when to do
1942         // the abort
1943         if ( done >= total/100000 ) {
1944             if ( ids.count() != 1 ) {
1945                 // do abort only once
1946                 int tmpId = ids.first();
1947                 ids.clear();
1948                 ids << tmpId;
1949                 ftp->abort();
1950             }
1951         }
1952     }
1953 }
1954 
1955 
newFtp()1956 QFtp *tst_QFtp::newFtp()
1957 {
1958     QFtp *nFtp = new QFtp( this );
1959 #ifndef QT_NO_BEARERMANAGEMENT
1960     if (networkSessionExplicit) {
1961         nFtp->setProperty("_q_networksession", QVariant::fromValue(networkSessionExplicit));
1962     }
1963 #endif
1964     connect( nFtp, SIGNAL(commandStarted(int)),
1965              SLOT(commandStarted(int)) );
1966     connect( nFtp, SIGNAL(commandFinished(int,bool)),
1967              SLOT(commandFinished(int,bool)) );
1968     connect( nFtp, SIGNAL(done(bool)),
1969              SLOT(done(bool)) );
1970     connect( nFtp, SIGNAL(stateChanged(int)),
1971              SLOT(stateChanged(int)) );
1972     connect( nFtp, SIGNAL(listInfo(const QUrlInfo&)),
1973              SLOT(listInfo(const QUrlInfo&)) );
1974     connect( nFtp, SIGNAL(readyRead()),
1975              SLOT(readyRead()) );
1976     connect( nFtp, SIGNAL(dataTransferProgress(qint64, qint64)),
1977              SLOT(dataTransferProgress(qint64, qint64)) );
1978 
1979     return nFtp;
1980 }
1981 
addCommand(QFtp::Command cmd,int id)1982 void tst_QFtp::addCommand( QFtp::Command cmd, int id )
1983 {
1984     ids << id;
1985     CommandResult res;
1986     res.id = id;
1987     res.success = -1;
1988     resultMap[ cmd ] = res;
1989 }
1990 
fileExists(const QString & host,quint16 port,const QString & user,const QString & password,const QString & file,const QString & cdDir)1991 bool tst_QFtp::fileExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &file, const QString &cdDir )
1992 {
1993     init();
1994     ftp = newFtp();
1995     // ### make these tests work
1996     if (ftp->currentId() != 0) {
1997         qWarning("ftp->currentId() != 0");
1998         return FALSE;
1999     }
2000 
2001     if (ftp->state() != QFtp::Unconnected) {
2002         qWarning("ftp->state() != QFtp::Unconnected");
2003         return FALSE;
2004     }
2005 
2006     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
2007     addCommand( QFtp::Login, ftp->login( user, password ) );
2008     if ( !cdDir.isNull() )
2009         addCommand( QFtp::Cd, ftp->cd( cdDir ) );
2010     addCommand( QFtp::List, ftp->list( file ) );
2011     addCommand( QFtp::Close, ftp->close() );
2012 
2013     inFileDirExistsFunction = TRUE;
2014     QTestEventLoop::instance().enterLoop( 30 );
2015     delete ftp;
2016     ftp = 0;
2017     if ( QTestEventLoop::instance().timeout() ) {
2018         // ### make this test work
2019         qWarning("tst_QFtp::fileExists: Network operation timed out");
2020         return FALSE;
2021     }
2022     inFileDirExistsFunction = FALSE;
2023 
2024     ResMapIt it = resultMap.find( QFtp::ConnectToHost );
2025     // ### make these tests work
2026     if (it == resultMap.end()) {
2027         qWarning("it != resultMap.end()");
2028         return FALSE;
2029     }
2030 
2031     if (it.value().success == -1) {
2032         qWarning("it.value().success != -1");
2033         return FALSE;
2034     }
2035 
2036     if ( it.value().success == 1 ) {
2037         for ( uint i=0; i < (uint) listInfo_i.count(); i++ ) {
2038             if ( QFileInfo(listInfo_i[i].name()).fileName() == QFileInfo(file).fileName() )
2039                 return TRUE;
2040         }
2041     }
2042 
2043     //this is not a good warning considering sometime this function is used to test that a file does not exist
2044     //qWarning("file doesn't exist");
2045     return FALSE;
2046 }
2047 
dirExists(const QString & host,quint16 port,const QString & user,const QString & password,const QString & cdDir,const QString & dirToCreate)2048 bool tst_QFtp::dirExists( const QString &host, quint16 port, const QString &user, const QString &password, const QString &cdDir, const QString &dirToCreate )
2049 {
2050     init();
2051     ftp = newFtp();
2052     // ### make these tests work
2053     //    QCOMPARE( ftp->currentId(), 0 );
2054     //    QCOMPARE( (int)ftp->state(), (int)QFtp::Unconnected );
2055 
2056     addCommand( QFtp::ConnectToHost, ftp->connectToHost( host, port ) );
2057     addCommand( QFtp::Login, ftp->login( user, password ) );
2058     if ( dirToCreate.startsWith( "/" ) )
2059         addCommand( QFtp::Cd, ftp->cd( dirToCreate ) );
2060     else
2061         addCommand( QFtp::Cd, ftp->cd( cdDir + "/" + dirToCreate ) );
2062     addCommand( QFtp::Close, ftp->close() );
2063 
2064     inFileDirExistsFunction = TRUE;
2065     QTestEventLoop::instance().enterLoop( 30 );
2066     delete ftp;
2067     ftp = 0;
2068     if ( QTestEventLoop::instance().timeout() ) {
2069         // ### make this test work
2070         // QFAIL( "Network operation timed out" );
2071         qWarning("tst_QFtp::dirExists: Network operation timed out");
2072         return FALSE;
2073     }
2074     inFileDirExistsFunction = FALSE;
2075 
2076     ResMapIt it = resultMap.find( QFtp::Cd );
2077     // ### make these tests work
2078     //    QVERIFY( it != resultMap.end() );
2079     //    QVERIFY( it.value().success != -1 );
2080     return it.value().success == 1;
2081 }
2082 
doneSignal()2083 void tst_QFtp::doneSignal()
2084 {
2085     QFtp ftp;
2086     QSignalSpy spy(&ftp, SIGNAL(done(bool)));
2087 
2088     ftp.connectToHost(QtNetworkSettings::serverName());
2089     ftp.login("anonymous");
2090     ftp.list();
2091     ftp.close();
2092 
2093     done_success = 0;
2094     connect(&ftp, SIGNAL(done(bool)), &(QTestEventLoop::instance()), SLOT(exitLoop()));
2095     QTestEventLoop::instance().enterLoop(61);
2096     if (QTestEventLoop::instance().timeout())
2097         QFAIL("Network operation timed out");
2098 
2099     QTest::qWait(200);
2100 
2101     QCOMPARE(spy.count(), 1);
2102     QCOMPARE(spy.first().first().toBool(), false);
2103 }
2104 
queueMoreCommandsInDoneSlot()2105 void tst_QFtp::queueMoreCommandsInDoneSlot()
2106 {
2107     QSKIP("Task 127050 && 113966", SkipSingle);
2108 
2109     QFtp ftp;
2110     QSignalSpy doneSpy(&ftp, SIGNAL(done(bool)));
2111     QSignalSpy commandFinishedSpy(&ftp, SIGNAL(commandFinished(int, bool)));
2112 
2113     this->ftp = &ftp;
2114     connect(&ftp, SIGNAL(done(bool)), this, SLOT(cdUpSlot(bool)));
2115 
2116     ftp.connectToHost("ftp.qt.nokia.com");
2117     ftp.login();
2118     ftp.cd("qt");
2119     ftp.rmdir("qtest-removedir-noexist");
2120 
2121     while ( ftp.hasPendingCommands() || ftp.currentCommand() != QFtp::None ) {
2122         QCoreApplication::instance()->processEvents(QEventLoop::AllEvents
2123                                                     | QEventLoop::WaitForMoreEvents);
2124     }
2125 
2126     QCOMPARE(doneSpy.count(), 2);
2127     QCOMPARE(doneSpy.first().first().toBool(), true);
2128     QCOMPARE(doneSpy.last().first().toBool(), false);
2129 
2130     QCOMPARE(commandFinishedSpy.count(), 6);
2131     int firstId = commandFinishedSpy.at(0).at(0).toInt();
2132     QCOMPARE(commandFinishedSpy.at(0).at(1).toBool(), false);
2133     QCOMPARE(commandFinishedSpy.at(1).at(0).toInt(), firstId + 1);
2134     QCOMPARE(commandFinishedSpy.at(1).at(1).toBool(), false);
2135     QCOMPARE(commandFinishedSpy.at(2).at(0).toInt(), firstId + 2);
2136     QCOMPARE(commandFinishedSpy.at(2).at(1).toBool(), false);
2137     QCOMPARE(commandFinishedSpy.at(3).at(0).toInt(), firstId + 3);
2138     QCOMPARE(commandFinishedSpy.at(3).at(1).toBool(), true);
2139     QCOMPARE(commandFinishedSpy.at(4).at(0).toInt(), firstId + 4);
2140     QCOMPARE(commandFinishedSpy.at(4).at(1).toBool(), false);
2141     QCOMPARE(commandFinishedSpy.at(5).at(0).toInt(), firstId + 5);
2142     QCOMPARE(commandFinishedSpy.at(5).at(1).toBool(), false);
2143 
2144     this->ftp = 0;
2145 }
2146 
cdUpSlot(bool error)2147 void tst_QFtp::cdUpSlot(bool error)
2148 {
2149     if (error) {
2150         ftp->cd("..");
2151         ftp->cd("qt");
2152     }
2153 }
2154 
qtbug7359Crash()2155 void tst_QFtp::qtbug7359Crash()
2156 {
2157     QFtp ftp;
2158     ftp.connectToHost("127.0.0.1");
2159 
2160     QTime t;
2161     int elapsed;
2162 
2163     t.start();
2164     while ((elapsed = t.elapsed()) < 200)
2165         QCoreApplication::processEvents(QEventLoop::AllEvents, 200 - elapsed);
2166 
2167     ftp.close();
2168     t.restart();
2169     while ((elapsed = t.elapsed()) < 1000)
2170         QCoreApplication::processEvents(QEventLoop::AllEvents, 1000 - elapsed);
2171 
2172     ftp.connectToHost("127.0.0.1");
2173 
2174     t.restart();
2175     while ((elapsed = t.elapsed()) < 2000)
2176         QCoreApplication::processEvents(QEventLoop::AllEvents, 2000 - elapsed);
2177 }
2178 
2179 QTEST_MAIN(tst_QFtp)
2180 
2181 #include "tst_qftp.moc"
2182