1 /***************************************************************************
2 testqgsfilefiledownloader.cpp
3 --------------------------------------
4 Date : 11.8.2016
5 Copyright : (C) 2016 Alessandro Pasotti
6 Email : apasotti at boundlessgeo dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16
17 #include "qgstest.h"
18 #include <QObject>
19 #include <QTemporaryFile>
20 #include <QTemporaryDir>
21 #include <QUrl>
22 #include <QEventLoop>
23 #include <QTimer>
24
25 #include <qgsapplication.h>
26 #include <qgsfiledownloader.h>
27
28 class TestQgsFileDownloader: public QObject
29 {
30 Q_OBJECT
31 public:
32 TestQgsFileDownloader() = default;
33
34 public slots:
35 //! Called when the download has completed successfully
downloadCompleted()36 void downloadCompleted()
37 {
38 mCompleted = true;
39 }
40 //! Called when the download exits
downloadExited()41 void downloadExited()
42 {
43 mExited = true;
44 }
45 //! Called when the download was canceled by the user
downloadCanceled()46 void downloadCanceled()
47 {
48 mCanceled = true;
49 }
50 //! Called when an error makes the download fail
downloadError(QStringList errorMessages)51 void downloadError( QStringList errorMessages )
52 {
53 mError = true;
54 errorMessages.sort();
55 mErrorMessage = errorMessages.join( QLatin1Char( ';' ) );
56 }
57 //! Called when data ready to be processed
downloadProgress(qint64 bytesReceived,qint64 bytesTotal)58 void downloadProgress( qint64 bytesReceived, qint64 bytesTotal )
59 {
60 Q_UNUSED( bytesReceived );
61 Q_UNUSED( bytesTotal );
62 mProgress = true;
63 }
64
65 private slots:
66 void initTestCase(); // will be called before the first testfunction is executed.
67 void cleanupTestCase(); // will be called after the last testfunction was executed.
68 void init(); // will be called before each testfunction is executed.
69 void cleanup(); // will be called after every testfunction.
70
71 void testValidDownload();
72 void testInValidDownload();
73 void testInvalidFile();
74 void testCanceledDownload();
75 void testInvalidUrl();
76 void testBlankUrl();
77 void testLacksWritePermissionsError();
78 #ifndef QT_NO_SSL
79 void testSslError_data();
80 void testSslError();
81 #endif
82
83 private:
84 void makeCall( QUrl url, QString fileName, bool cancel = false );
85 QTemporaryFile *mTempFile = nullptr;
86 QString mErrorMessage;
87 bool mCanceled = false ;
88 bool mProgress = false ;
89 bool mError = false ;
90 bool mCompleted = false ;
91 bool mExited = false ;
92 QgsFileDownloader *mFileDownloader = nullptr;
93 };
94
makeCall(QUrl url,QString fileName,bool cancel)95 void TestQgsFileDownloader::makeCall( QUrl url, QString fileName, bool cancel )
96 {
97 QEventLoop loop;
98
99 mFileDownloader = new QgsFileDownloader( url, fileName );
100 connect( mFileDownloader, &QgsFileDownloader::downloadCompleted, this, &TestQgsFileDownloader::downloadCompleted );
101 connect( mFileDownloader, &QgsFileDownloader::downloadCanceled, this, &TestQgsFileDownloader::downloadCanceled );
102 connect( mFileDownloader, &QgsFileDownloader::downloadExited, this, &TestQgsFileDownloader::downloadExited );
103 connect( mFileDownloader, &QgsFileDownloader::downloadError, this, &TestQgsFileDownloader::downloadError );
104 connect( mFileDownloader, &QgsFileDownloader::downloadProgress, this, &TestQgsFileDownloader::downloadProgress );
105
106 connect( mFileDownloader, &QgsFileDownloader::downloadExited, &loop, &QEventLoop::quit );
107
108 if ( cancel )
109 QTimer::singleShot( 1000, mFileDownloader, &QgsFileDownloader::cancelDownload );
110
111 loop.exec();
112
113 }
114
initTestCase()115 void TestQgsFileDownloader::initTestCase()
116 {
117 QgsApplication::init();
118 QgsApplication::initQgis();
119
120 }
121
cleanupTestCase()122 void TestQgsFileDownloader::cleanupTestCase()
123 {
124 QgsApplication::exitQgis();
125 }
126
init()127 void TestQgsFileDownloader::init()
128 {
129 mErrorMessage.clear();
130 mCanceled = false;
131 mProgress = false;
132 mError = false;
133 mCompleted = false;
134 mExited = false;
135 mTempFile = new QTemporaryFile();
136 QVERIFY( mTempFile->open() );
137 mTempFile->close();
138 }
139
140
141
cleanup()142 void TestQgsFileDownloader::cleanup()
143 {
144 delete mTempFile;
145 }
146
testValidDownload()147 void TestQgsFileDownloader::testValidDownload()
148 {
149 QVERIFY( ! mTempFile->fileName().isEmpty() );
150 makeCall( QUrl( QStringLiteral( "http://www.qgis.org" ) ), mTempFile->fileName() );
151 QVERIFY( mExited );
152 QVERIFY( mCompleted );
153 QVERIFY( mProgress );
154 QVERIFY( !mError );
155 QVERIFY( !mCanceled );
156 QVERIFY( mTempFile->size() > 0 );
157 }
158
testInValidDownload()159 void TestQgsFileDownloader::testInValidDownload()
160 {
161 QVERIFY( ! mTempFile->fileName().isEmpty() );
162 makeCall( QUrl( QStringLiteral( "http://www.doesnotexistofthatimsure.qgis" ) ), mTempFile->fileName() );
163 QVERIFY( mExited );
164 QVERIFY( !mCompleted );
165 QVERIFY( mError );
166 QVERIFY( !mCanceled );
167 QVERIFY( mTempFile->size() == 0 );
168 QCOMPARE( mErrorMessage, QString( "Download failed: Host www.doesnotexistofthatimsure.qgis not found" ) );
169 }
170
testCanceledDownload()171 void TestQgsFileDownloader::testCanceledDownload()
172 {
173 QVERIFY( ! mTempFile->fileName().isEmpty() );
174 makeCall( QUrl( QStringLiteral( "https://github.com/qgis/QGIS/archive/master.zip" ) ), mTempFile->fileName(), true );
175 QVERIFY( mExited );
176 QVERIFY( !mCompleted );
177 QVERIFY( !mError );
178 QVERIFY( mProgress );
179 QVERIFY( mCanceled );
180 QVERIFY( !mTempFile->exists() );
181 }
182
testInvalidFile()183 void TestQgsFileDownloader::testInvalidFile()
184 {
185 makeCall( QUrl( QStringLiteral( "https://github.com/qgis/QGIS/archive/master.zip" ) ), QString() );
186 QVERIFY( mExited );
187 QVERIFY( !mCompleted );
188 QVERIFY( mError );
189 QVERIFY( !mCanceled );
190 QCOMPARE( mErrorMessage, QString( "No output filename specified" ) );
191 }
192
testInvalidUrl()193 void TestQgsFileDownloader::testInvalidUrl()
194 {
195 QVERIFY( ! mTempFile->fileName().isEmpty() );
196 makeCall( QUrl( QStringLiteral( "xyz://www" ) ), mTempFile->fileName() );
197 QVERIFY( mExited );
198 QVERIFY( !mCompleted );
199 QVERIFY( mError );
200 QVERIFY( !mCanceled );
201 QCOMPARE( mErrorMessage, QString( "Download failed: Protocol \"xyz\" is unknown" ) );
202 }
203
testBlankUrl()204 void TestQgsFileDownloader::testBlankUrl()
205 {
206 QVERIFY( ! mTempFile->fileName().isEmpty() );
207 makeCall( QUrl( QString() ), mTempFile->fileName() );
208 QVERIFY( mExited );
209 QVERIFY( !mCompleted );
210 QVERIFY( mError );
211 QVERIFY( !mCanceled );
212 QCOMPARE( mErrorMessage, QString( "Download failed: Protocol \"\" is unknown" ) );
213 }
214
215 #ifndef QT_NO_SSL
testSslError_data()216 void TestQgsFileDownloader::testSslError_data()
217 {
218 QTest::addColumn<QString>( "url" );
219 QTest::addColumn<QString>( "result" );
220
221 QTest::newRow( "expired" ) << "https://expired.badssl.com/"
222 << "SSL Errors: ;The certificate has expired";
223 QTest::newRow( "self-signed" ) << "https://self-signed.badssl.com/"
224 << "SSL Errors: ;The certificate is self-signed, and untrusted";
225 QTest::newRow( "untrusted-root" ) << "https://untrusted-root.badssl.com/"
226 << "No certificates could be verified;SSL Errors: ;The issuer certificate of a locally looked up certificate could not be found";
227 }
228
testSslError()229 void TestQgsFileDownloader::testSslError()
230 {
231 QFETCH( QString, url );
232 QFETCH( QString, result );
233 QVERIFY( ! mTempFile->fileName().isEmpty() );
234 makeCall( QUrl( url ), mTempFile->fileName() );
235 QCOMPARE( mErrorMessage, result );
236 QVERIFY( !mCompleted );
237 QVERIFY( mError );
238 QVERIFY( !mCanceled );
239 }
240
testLacksWritePermissionsError()241 void TestQgsFileDownloader::testLacksWritePermissionsError()
242 {
243 const QTemporaryDir dir;
244 QFile tmpDir( dir.path( ) );
245 tmpDir.setPermissions( tmpDir.permissions() & ~( QFile::Permission::WriteGroup | QFile::Permission::WriteUser | QFile::Permission::WriteOther | QFile::Permission::WriteOwner ) );
246 QVERIFY( ! tmpDir.isWritable() );
247 const QString fileName( dir.path() + '/' + QStringLiteral( "tmp.bin" ) );
248 makeCall( QUrl( QStringLiteral( "http://www.qgis.org" ) ), fileName );
249 QVERIFY( mExited );
250 QVERIFY( !mCompleted );
251 QVERIFY( mError );
252 QVERIFY( !mCanceled );
253 QVERIFY( ! QFileInfo::exists( fileName ) );
254 }
255
256
257 #endif
258
259
260 QGSTEST_MAIN( TestQgsFileDownloader )
261 #include "testqgsfiledownloader.moc"
262
263
264