Merge lp:~mandel/ubuntu-download-manager/test-space-left into lp:ubuntu-download-manager

Proposed by Manuel de la Peña on 2015-02-09
Status: Needs review
Proposed branch: lp:~mandel/ubuntu-download-manager/test-space-left
Merge into: lp:ubuntu-download-manager
Diff against target: 1478 lines (+846/-85)
16 files modified
CMakeLists.txt (+1/-1)
debian/control (+2/-0)
src/common/priv/CMakeLists.txt (+2/-0)
src/common/priv/ubuntu/transfers/system/file_manager.cpp (+24/-10)
src/common/priv/ubuntu/transfers/system/file_manager.h (+9/-11)
src/downloads/priv/ubuntu/downloads/file_download.cpp (+81/-11)
src/downloads/priv/ubuntu/downloads/file_download.h (+3/-1)
src/extractor/ubuntu/downloads/extractor/deflator.h (+3/-4)
src/extractor/ubuntu/downloads/extractor/main.cpp (+8/-3)
src/extractor/ubuntu/downloads/extractor/unzip.cpp (+58/-7)
src/extractor/ubuntu/downloads/extractor/unzip.h (+5/-5)
tests/common/CMakeLists.txt (+16/-14)
tests/common/file_manager.h (+5/-6)
tests/common/matchers.h (+15/-4)
tests/downloads/daemon/test_download.cpp (+601/-4)
tests/downloads/daemon/test_download.h (+13/-4)
To merge this branch: bzr merge lp:~mandel/ubuntu-download-manager/test-space-left
Reviewer Review Type Date Requested Status
Michael Sheldon (community) 2015-02-09 Needs Fixing on 2015-02-27
PS Jenkins bot continuous-integration Approve on 2015-02-26
Ricardo Salveti Needs Fixing on 2015-02-26
Review via email: mp+249093@code.launchpad.net

Commit Message

Add a new check to ensure that there is enough space left in the device for unity8 to boot. This commit adds two new dependencies:

libboost-filesystem-dev
libboost-system-dev

Description of the Change

This branch adds an extra test in the download manager that will ensure that files are not downloaded when the space left in the device is not enough for unity8 to start. If a file is downloaded and yet does not fit in the evice a file error is raised.

The check is done as lazy a possible in case the space was freed while the download was in progress.

To post a comment you must log in.
Michael Sheldon (michael-sheldon) wrote :

Raised a couple of small issues in the diff comments, but other than those this looks good to me. I've only done a code review so far though, haven't tested the functionality on a device yet.

review: Needs Fixing
340. By Manuel de la Peña on 2015-02-10

Update code according to code review.

Michael Sheldon (michael-sheldon) wrote :

It's still possible to run out of disk space if you download a large zipped album from 7 digital. I had 202MB free, I downloaded a 112MB album from 7 digital, download manager then unzipped it resulting in the system running out of space during the unzipping process.

review: Needs Fixing
341. By Manuel de la Peña on 2015-02-23

Check that when a file is unzip we do have enough space in the device.

Michael Sheldon (michael-sheldon) wrote :

The fix doesn't appear to be working correctly, with 220MB left on the device I'm still able to download a 117MB zip file from 7digital and have download manager unpack it and leaving the device with 0MB free.

Should the --size option really be added to the args alongside --unzip? Shouldn't there be a call to the helper with just --size prior to --unzip being called? I suspect it might be unzipping whilst checking the size.

Also I spotted a small typo in one of the comments (unity3 -> unity8)

As a future improvement I think it'd be a handy if we use the Content-Length header if the server provides it to determine whether there'll be enough space prior to starting the download as well as doing it afterwards; that way we can save the user from wasting their data allowance on downloads that we know in advance we won't be able to save.

review: Needs Fixing
342. By Manuel de la Peña on 2015-02-25

Add missing tests for the unzip path. Ensure that we do parse the --size result correctly.

Michael Sheldon (michael-sheldon) wrote :

Retested and it's still allowing the zip to be unpacked I'm afraid, it looks like the helper isn't reporting the correct size, I just tried running it manually via:

/usr/lib/arm-linux-gnueabihf/ubuntu-download-manager/udm-extractor --unzip --path /home/phablet/.cache/com.ubuntu.music/HubIncoming/3/Anais\ Mitchell\ -\ Xoa.zip --size

And its output was just "3" (the actual unpacked size is 114MB)

review: Needs Fixing
343. By Manuel de la Peña on 2015-02-26

Remember to just deal with the last line ot stdout from unzip.

Manuel de la Peña (mandel) wrote :

Fixed. Thx for the pointer.

Ricardo Salveti (rsalveti) wrote :

Small typo. Still need to test it.

review: Needs Fixing
344. By Manuel de la Peña on 2015-02-26

Fix small typo.

Michael Sheldon (michael-sheldon) wrote :

Still not working correctly I'm afraid, when the download completes a "Process Error" message is displayed briefly. Running the udm extractor manually on the file results in no output and a return code of 1 (presumably what triggers the process error).

review: Needs Fixing

Unmerged revisions

344. By Manuel de la Peña on 2015-02-26

Fix small typo.

343. By Manuel de la Peña on 2015-02-26

Remember to just deal with the last line ot stdout from unzip.

342. By Manuel de la Peña on 2015-02-25

Add missing tests for the unzip path. Ensure that we do parse the --size result correctly.

341. By Manuel de la Peña on 2015-02-23

Check that when a file is unzip we do have enough space in the device.

340. By Manuel de la Peña on 2015-02-10

Update code according to code review.

339. By Manuel de la Peña on 2015-02-09

Ensure that if the space left in the device is not enough that downloads will fail.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-11-17 23:07:13 +0000
3+++ CMakeLists.txt 2015-02-26 08:49:11 +0000
4@@ -45,7 +45,7 @@
5 find_package(Qt5Network REQUIRED)
6 find_package(Qt5Sql REQUIRED)
7 find_package(Qt5Test REQUIRED)
8-find_package(Boost COMPONENTS log program_options REQUIRED)
9+find_package(Boost COMPONENTS filesystem log program_options system REQUIRED)
10
11 find_package(PkgConfig REQUIRED)
12 pkg_check_modules(DBUS REQUIRED dbus-1)
13
14=== modified file 'debian/control'
15--- debian/control 2014-11-26 12:21:53 +0000
16+++ debian/control 2015-02-26 08:49:11 +0000
17@@ -9,8 +9,10 @@
18 google-mock,
19 qt5-default,
20 qtbase5-dev,
21+ libboost-filesystem-dev,
22 libboost-log-dev,
23 libboost-program-options-dev,
24+ libboost-system-dev,
25 libdbus-1-dev,
26 libqt5sql5-sqlite,
27 libnih-dbus-dev,
28
29=== modified file 'src/common/priv/CMakeLists.txt'
30--- src/common/priv/CMakeLists.txt 2014-11-24 15:28:20 +0000
31+++ src/common/priv/CMakeLists.txt 2015-02-26 08:49:11 +0000
32@@ -56,6 +56,7 @@
33 include_directories(${Qt5DBus_INCLUDE_DIRS})
34 include_directories(${Qt5Network_INCLUDE_DIRS})
35 include_directories(${Qt5Sql_INCLUDE_DIRS})
36+include_directories(${Boost_INCLUDE_DIRS})
37 include_directories(${DBUS_INCLUDE_DIRS})
38 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
39 include_directories(${CMAKE_CURRENT_BINARY_DIR})
40@@ -78,6 +79,7 @@
41 link_directories(${GLOG_DBUS_LIBDIR})
42
43 target_link_libraries(${TARGET}
44+ ${Boost_LIBRARIES}
45 ${NIH_DBUS_LIBRARIES}
46 ${GLOG_LIBRARIES}
47 ${Qt5Network_LIBRARIES}
48
49=== modified file 'src/common/priv/ubuntu/transfers/system/file_manager.cpp'
50--- src/common/priv/ubuntu/transfers/system/file_manager.cpp 2014-09-27 13:16:11 +0000
51+++ src/common/priv/ubuntu/transfers/system/file_manager.cpp 2015-02-26 08:49:11 +0000
52@@ -1,5 +1,5 @@
53 /*
54- * Copyright 2013-2014 Canonical Ltd.
55+ * Copyright 2013-2015 Canonical Ltd.
56 *
57 * This library is free software; you can redistribute it and/or
58 * modify it under the terms of version 3 of the GNU Lesser General Public
59@@ -16,11 +16,16 @@
60 * Boston, MA 02110-1301, USA.
61 */
62
63+#include <boost/filesystem.hpp>
64+
65 #include <QFile>
66 #include <QFileInfo>
67 #include <QTemporaryFile>
68+
69 #include "file_manager.h"
70
71+namespace fs = boost::filesystem;
72+
73 namespace Ubuntu {
74
75 namespace Transfers {
76@@ -99,12 +104,12 @@
77 QMutex FileManager::_mutex;
78
79 File*
80-FileManager::createFile(const QString& name) {
81+FileManager::createFile(const QString& name) const {
82 return new File(name);
83 }
84
85 File*
86-FileManager::copyToTempFile(const QString& name) {
87+FileManager::copyToTempFile(const QString& name) const {
88 // create a temp file, and copy the old name to the
89 // new file path
90 auto tempFile = new QTemporaryFile();
91@@ -114,26 +119,33 @@
92 }
93
94 bool
95-FileManager::remove(const QString& path) {
96+FileManager::remove(const QString& path) const {
97 return QFile::remove(path);
98 }
99
100 bool
101-FileManager::exists(const QString& path) {
102+FileManager::exists(const QString& path) const {
103 return QFile::exists(path);
104 }
105
106 bool
107-FileManager::rename(const QString& oldName, const QString& newName) {
108+FileManager::rename(const QString& oldName, const QString& newName) const {
109 return QFile::rename(oldName, newName);
110 }
111
112 bool
113-FileManager::isDir(const QString& path) {
114+FileManager::isDir(const QString& path) const {
115 return QFileInfo(path).isDir();
116 }
117
118-FileManager* FileManager::instance() {
119+quint64
120+FileManager::freeSpace(const QString& path) const {
121+ auto info = fs::space(path.toStdString());
122+ return static_cast<quint64>(info.available);
123+}
124+
125+FileManager*
126+FileManager::instance() {
127 if(_instance == nullptr) {
128 _mutex.lock();
129 if(_instance == nullptr)
130@@ -143,11 +155,13 @@
131 return _instance;
132 }
133
134-void FileManager::setInstance(FileManager* instance) {
135+void
136+FileManager::setInstance(FileManager* instance) {
137 _instance = instance;
138 }
139
140-void FileManager::deleteInstance() {
141+void
142+FileManager::deleteInstance() {
143 if(_instance != nullptr) {
144 _mutex.lock();
145 if(_instance != nullptr) {
146
147=== modified file 'src/common/priv/ubuntu/transfers/system/file_manager.h'
148--- src/common/priv/ubuntu/transfers/system/file_manager.h 2014-09-27 13:16:11 +0000
149+++ src/common/priv/ubuntu/transfers/system/file_manager.h 2015-02-26 08:49:11 +0000
150@@ -1,5 +1,5 @@
151 /*
152- * Copyright 2013-2014 Canonical Ltd.
153+ * Copyright 2013-2015 Canonical Ltd.
154 *
155 * This library is free software; you can redistribute it and/or
156 * modify it under the terms of version 3 of the GNU Lesser General Public
157@@ -16,8 +16,7 @@
158 * Boston, MA 02110-1301, USA.
159 */
160
161-#ifndef DOWNLOADER_LIB_FILE_MANAGER_H
162-#define DOWNLOADER_LIB_FILE_MANAGER_H
163+#pragma once
164
165 #include <QIODevice>
166 #include <QFile>
167@@ -64,12 +63,13 @@
168 Q_OBJECT
169
170 public:
171- virtual File* createFile(const QString& name);
172- virtual File* copyToTempFile(const QString& name);
173- virtual bool remove(const QString& path);
174- virtual bool exists(const QString& path);
175- virtual bool rename(const QString& oldName, const QString& newName);
176- virtual bool isDir(const QString& path);
177+ virtual File* createFile(const QString& name) const;
178+ virtual File* copyToTempFile(const QString& name) const;
179+ virtual bool remove(const QString& path) const;
180+ virtual bool exists(const QString& path) const;
181+ virtual bool rename(const QString& oldName, const QString& newName) const;
182+ virtual bool isDir(const QString& path) const;
183+ virtual quint64 freeSpace(const QString& path) const;
184
185 static FileManager* instance();
186
187@@ -92,5 +92,3 @@
188 } // Transfers
189
190 } // Ubuntu
191-
192-#endif // DOWNLOADER_LIB_FILE_MANAGER_H
193
194=== modified file 'src/downloads/priv/ubuntu/downloads/file_download.cpp'
195--- src/downloads/priv/ubuntu/downloads/file_download.cpp 2015-01-23 11:59:19 +0000
196+++ src/downloads/priv/ubuntu/downloads/file_download.cpp 2015-02-26 08:49:11 +0000
197@@ -1,5 +1,5 @@
198 /*
199- * Copyright 2013-2014 Canonical Ltd.
200+ * Copyright 2013-2015 Canonical Ltd.
201 *
202 * This library is free software; you can redistribute it and/or
203 * modify it under the terms of version 3 of the GNU Lesser General Public
204@@ -141,6 +141,7 @@
205 }
206
207 namespace {
208+ const int MINIMUM_SPACE = 100; // amount of space required to boot unity 8 in mb
209 const QString PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
210 const QString DOWNLOAD_INTERFACE = "com.canonical.applications.Download";
211 const QString PROPERTIES_CHANGED = "PropertiesChanged";
212@@ -499,6 +500,7 @@
213 if (!flushFile()) {
214 return;
215 }
216+
217 auto received = static_cast<qulonglong>(_currentData->size());
218
219 if (bytesTotal == -1) {
220@@ -797,6 +799,62 @@
221 }
222
223 void
224+FileDownload::onUnzipSizeCheckFinished(int exitCode,
225+ QProcess::ExitStatus exitStatus) {
226+ auto p = qobject_cast<Process*>(sender());
227+ if (exitCode == 0 && exitStatus == QProcess::NormalExit) {
228+ // grab the size from the stdout and decide if there is enough space in the device.
229+ // the result is returned in bytes
230+ auto fileMan = FileManager::instance();
231+ auto dir = QFileInfo(filePath()).absolutePath();
232+ auto spaceLeft = fileMan->freeSpace(dir)/1024;
233+ auto output = QString(p->readAllStandardOutput()).simplified().toLongLong() / 1024;
234+
235+ if ((spaceLeft - output) > MINIMUM_SPACE) {
236+ // notify that we are going to be unzipping the file
237+ emit processing(filePath());
238+
239+ auto postDownloadProcess = ProcessFactory::instance()->createProcess();
240+
241+ CHECK(connect(postDownloadProcess, &Process::finished,
242+ this, &FileDownload::onProcessFinished))
243+ << "Could not connect to signal";
244+ CHECK(connect(postDownloadProcess, &Process::error,
245+ this, &FileDownload::onProcessError))
246+ << "Could not connect to signal";
247+
248+ DOWN_LOG(INFO) << "Renaming '" << _tempFilePath << "'"
249+ << "' to '" << _filePath << "'";
250+
251+ QFileInfo fileInfo(filePath());
252+
253+ QString command = HELPER_DIR + QString(QDir::separator()) + "udm-extractor";
254+ QStringList args;
255+ args << "--unzip";
256+ args << "--path";
257+ args << filePath();
258+ args << "--destination";
259+ args << fileInfo.dir().absolutePath();
260+
261+ DOWN_LOG(INFO) << "Executing" << command << args;
262+ postDownloadProcess->start(command, args);
263+ } else {
264+ // we cannot unzip, there is not enough space in the device
265+ DOWN_LOG(ERROR) << "Could not write that in the file system there is not enough space."
266+ << " Space available: " << spaceLeft - output;
267+ emitError(QString(FILE_SYSTEM_ERROR).arg("There is not enough space in the device."));
268+ }
269+ } else {
270+ auto standardOut = p->readAllStandardOutput();
271+ auto standardErr = p->readAllStandardError();
272+ ProcessErrorStruct err(exitStatus, "ErrorInProcess", exitCode,
273+ standardOut, standardErr);
274+ emit processError(err);
275+ emitError(COMMAND_ERROR);
276+ }
277+ p->deleteLater();
278+}
279+void
280 FileDownload::onOnlineStateChanged(bool online) {
281 TRACE << online;
282 _connected = online;
283@@ -821,7 +879,6 @@
284
285 void
286 FileDownload::onPropertiesChanged(const QVariantMap& changes) {
287- qDebug() << "Emit freedesktop.org changes";
288 auto signal = QDBusMessage::createSignal(
289 path(), PROPERTIES_INTERFACE, PROPERTIES_CHANGED);
290 signal << DOWNLOAD_INTERFACE;
291@@ -908,13 +965,26 @@
292
293 bool
294 FileDownload::flushFile() {
295- auto flushed = _currentData->flush();
296- if (!flushed) {
297- auto err = _currentData->error();
298- DOWN_LOG(ERROR) << "Could not write that in the file system" << err;
299- emitError(QString(FILE_SYSTEM_ERROR).arg(err));
300+ // before writing on disk, do check that there is enough space, if not, we
301+ // will raise an error and do nothing
302+ auto fileMan = FileManager::instance();
303+ auto dir = QFileInfo(_tempFilePath).absolutePath();
304+ auto spaceLeft = fileMan->freeSpace(dir) / 1024;
305+
306+ if (spaceLeft > MINIMUM_SPACE) {
307+ auto flushed = _currentData->flush();
308+ if (!flushed) {
309+ auto err = _currentData->error();
310+ DOWN_LOG(ERROR) << "Could not write that in the file system" << err;
311+ emitError(QString(FILE_SYSTEM_ERROR).arg(err));
312+ }
313+ return flushed;
314+ } else {
315+ DOWN_LOG(ERROR) << "Could not write that in the file system there is not enough space."
316+ << " Space available: " << spaceLeft;
317+ emitError(QString(FILE_SYSTEM_ERROR).arg("There is not enough space in the device."));
318+ return false;
319 }
320- return flushed;
321 }
322
323 bool
324@@ -987,11 +1057,12 @@
325 if (_metadata.contains(Metadata::EXTRACT_KEY)
326 && _metadata[Metadata::EXTRACT_KEY].toBool()
327 && contentType == "application/zip") {
328+ DOWN_LOG(INFO) << "Downloaded file must be extracted";
329
330 auto postDownloadProcess = ProcessFactory::instance()->createProcess();
331
332 CHECK(connect(postDownloadProcess, &Process::finished,
333- this, &FileDownload::onProcessFinished))
334+ this, &FileDownload::onUnzipSizeCheckFinished))
335 << "Could not connect to signal";
336 CHECK(connect(postDownloadProcess, &Process::error,
337 this, &FileDownload::onProcessError))
338@@ -1014,8 +1085,7 @@
339 args << "--unzip";
340 args << "--path";
341 args << filePath();
342- args << "--destination";
343- args << fileInfo.dir().absolutePath();
344+ args << "--size";
345
346 DOWN_LOG(INFO) << "Executing" << command << args;
347 postDownloadProcess->start(command, args);
348
349=== modified file 'src/downloads/priv/ubuntu/downloads/file_download.h'
350--- src/downloads/priv/ubuntu/downloads/file_download.h 2015-01-22 22:08:41 +0000
351+++ src/downloads/priv/ubuntu/downloads/file_download.h 2015-02-26 08:49:11 +0000
352@@ -1,5 +1,5 @@
353 /*
354- * Copyright 2013-2014 Canonical Ltd.
355+ * Copyright 2013-2015 Canonical Ltd.
356 *
357 * This library is free software; you can redistribute it and/or
358 * modify it under the terms of version 3 of the GNU Lesser General Public
359@@ -137,6 +137,8 @@
360 void onProcessError(QProcess::ProcessError error);
361 void onProcessFinished(int exitCode,
362 QProcess::ExitStatus exitStatus);
363+ void onUnzipSizeCheckFinished(int exitCode,
364+ QProcess::ExitStatus exitStatus);
365 void onOnlineStateChanged(bool);
366 void onPropertiesChanged(const QVariantMap& changes);
367
368
369=== modified file 'src/extractor/ubuntu/downloads/extractor/deflator.h'
370--- src/extractor/ubuntu/downloads/extractor/deflator.h 2014-09-27 13:16:11 +0000
371+++ src/extractor/ubuntu/downloads/extractor/deflator.h 2015-02-26 08:49:11 +0000
372@@ -1,5 +1,5 @@
373 /*
374- * Copyright 2014 Canonical Ltd.
375+ * Copyright 2014-2015 Canonical Ltd.
376 *
377 * This library is free software; you can redistribute it and/or
378 * modify it under the terms of version 3 of the GNU Lesser General Public
379@@ -16,8 +16,7 @@
380 * Boston, MA 02110-1301, USA.
381 */
382
383-#ifndef UDM_EXTRACTOR_DEFLATOR_H
384-#define UDM_EXTRACTOR_DEFLATOR_H
385+#pragma once
386
387 #include <QObject>
388 #include <QString>
389@@ -40,6 +39,7 @@
390
391 public slots: // NOLINT (whitespace/indent)
392 virtual void deflate() = 0;
393+ virtual void size() = 0;
394
395 protected:
396 void setLastError(const QString& error);
397@@ -60,4 +60,3 @@
398
399 }
400
401-#endif
402
403=== modified file 'src/extractor/ubuntu/downloads/extractor/main.cpp'
404--- src/extractor/ubuntu/downloads/extractor/main.cpp 2014-09-27 13:16:11 +0000
405+++ src/extractor/ubuntu/downloads/extractor/main.cpp 2015-02-26 08:49:11 +0000
406@@ -40,6 +40,7 @@
407 ("help", "produce help message")
408 ("unzip", "unzip will be used to extract the data.")
409 ("untar", "untar will be used to extract the data.")
410+ ("size", "in cobinations with unzip/untar it returs the size of the file once expanded.")
411 ("path", po::value<std::string>(), "The path to be extracted.")
412 ("destination", po::value<std::string>(), "The path to be extracted.")
413 ;
414@@ -66,7 +67,7 @@
415 if (vm.count("destination")) {
416 destination = vm["destination"].as<std::string>();
417 } else {
418- return 1;
419+ destination = "";
420 }
421
422
423@@ -92,8 +93,12 @@
424 std::cout << factory->lastError().toStdString() << std::endl;
425 return 1;
426 } else {
427- // use a single shot timer to execute the extraction
428- QTimer::singleShot(0, deflator, SLOT(deflate()));
429+ // use a single shot timer to execute the extraction
430+ if(vm.count("size")) {
431+ QTimer::singleShot(0, deflator, SLOT(size()));
432+ } else {
433+ QTimer::singleShot(0, deflator, SLOT(deflate()));
434+ };
435 }
436
437 return a.exec();
438
439=== modified file 'src/extractor/ubuntu/downloads/extractor/unzip.cpp'
440--- src/extractor/ubuntu/downloads/extractor/unzip.cpp 2014-09-27 13:16:11 +0000
441+++ src/extractor/ubuntu/downloads/extractor/unzip.cpp 2015-02-26 08:49:11 +0000
442@@ -1,5 +1,5 @@
443 /*
444- * Copyright 2014 Canonical Ltd.
445+ * Copyright 2014-2015 Canonical Ltd.
446 *
447 * This library is free software; you can redistribute it and/or
448 * modify it under the terms of version 3 of the GNU Lesser General Public
449@@ -17,6 +17,9 @@
450 */
451
452 #include <QCoreApplication>
453+#include <QRegExp>
454+#include <QTextStream>
455+
456 #include <ubuntu/downloads/extractor/unzip.h>
457
458 namespace Ubuntu {
459@@ -37,16 +40,16 @@
460 void
461 UnZip::deflate() {
462 // use unzip to extract the file to the destination
463- QString program = "unzip";
464- QStringList arguments;
465- arguments << _path << "-d" << _destination;
466+ QString program = "unzip";
467+ QStringList arguments;
468+ arguments << _path << "-d" << _destination;
469
470- _process = new QProcess(this);
471+ _process = new QProcess(this);
472
473 // connect so that we foward the signals
474 connect(_process,
475 static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>
476- (&QProcess::finished), this, &UnZip::onFinished);
477+ (&QProcess::finished), this, &UnZip::onUnzipFinished);
478 connect(_process,
479 static_cast<void(QProcess::*)(QProcess::ProcessError)>
480 (&QProcess::error), this, &UnZip::onError);
481@@ -55,12 +58,32 @@
482 }
483
484 void
485+UnZip::size() {
486+ // use unzip to extract the file to the destination
487+ QString program = "unzip";
488+ QStringList arguments;
489+ arguments << "-Zh" << _path;
490+
491+ _process = new QProcess(this);
492+
493+ // connect so that we foward the signals
494+ connect(_process,
495+ static_cast<void(QProcess::*)(int, QProcess::ExitStatus)>
496+ (&QProcess::finished), this, &UnZip::onSizeFinished);
497+ connect(_process,
498+ static_cast<void(QProcess::*)(QProcess::ProcessError)>
499+ (&QProcess::error), this, &UnZip::onError);
500+
501+ _process->start(program, arguments);
502+}
503+
504+void
505 UnZip::onError(QProcess::ProcessError) {
506 QCoreApplication::instance()->exit(1);
507 }
508
509 void
510-UnZip::onFinished(int exitCode, QProcess::ExitStatus exitStatus) {
511+UnZip::onUnzipFinished(int exitCode, QProcess::ExitStatus exitStatus) {
512 if (exitStatus == QProcess::NormalExit || exitCode == 0) {
513 QCoreApplication::instance()->exit(0);
514 } else {
515@@ -68,6 +91,34 @@
516 }
517 }
518
519+void
520+UnZip::onSizeFinished(int exitCode, QProcess::ExitStatus exitStatus) {
521+ if (exitStatus == QProcess::NormalExit || exitCode == 0) {
522+ // we need to read the output from the child process and simply print out the result in stdout
523+ // which is of the type:
524+ // Archive: LightSweep - Free & Open-Source HDR Tutorial_files.zip
525+ // Zip file size: 27251310 bytes, number of entries: 56
526+ // therefore we need to ignore the first line, beause the path might have numbers in it, and use the
527+ // second line
528+ auto result = QString(_process->readAllStandardOutput());
529+ auto lines = result.split("\n");
530+ // the expected result is as follows:
531+ // Zip file size: 27251310 bytes, number of entries: 56
532+ QRegExp rx("(\\d+)");
533+ auto pos = rx.indexIn(QString(lines.last()));
534+ if (pos != -1) {
535+ auto size = rx.cap(1);
536+ QTextStream out(stdout, QIODevice::WriteOnly);
537+ out << size << "\n";
538+ QCoreApplication::instance()->exit(0);
539+ } else {
540+ QCoreApplication::instance()->exit(1);
541+ }
542+ } else {
543+ QCoreApplication::instance()->exit(exitCode);
544+ }
545+}
546+
547 }
548
549 }
550
551=== modified file 'src/extractor/ubuntu/downloads/extractor/unzip.h'
552--- src/extractor/ubuntu/downloads/extractor/unzip.h 2014-09-27 13:16:11 +0000
553+++ src/extractor/ubuntu/downloads/extractor/unzip.h 2015-02-26 08:49:11 +0000
554@@ -1,5 +1,5 @@
555 /*
556- * Copyright 2014 Canonical Ltd.
557+ * Copyright 2014-2015 Canonical Ltd.
558 *
559 * This library is free software; you can redistribute it and/or
560 * modify it under the terms of version 3 of the GNU Lesser General Public
561@@ -16,8 +16,7 @@
562 * Boston, MA 02110-1301, USA.
563 */
564
565-#ifndef UDM_EXTRACTOR_UNZIP_H
566-#define UDM_EXTRACTOR_UNZIP_H
567+#pragma once
568
569 #include <QProcess>
570 #include <ubuntu/downloads/extractor/deflator.h>
571@@ -38,10 +37,12 @@
572
573 public slots: // NOLINT (whitespace/indent)
574 void deflate() override;
575+ void size() override;
576
577 private slots:
578 void onError(QProcess::ProcessError error);
579- void onFinished(int exitCode, QProcess::ExitStatus exitStatus);
580+ void onUnzipFinished(int exitCode, QProcess::ExitStatus exitStatus);
581+ void onSizeFinished(int exitCode, QProcess::ExitStatus exitStatus);
582
583 private:
584 QProcess* _process = nullptr;
585@@ -54,4 +55,3 @@
586
587 }
588
589-#endif
590
591=== modified file 'tests/common/CMakeLists.txt'
592--- tests/common/CMakeLists.txt 2014-12-01 09:20:00 +0000
593+++ tests/common/CMakeLists.txt 2015-02-26 08:49:11 +0000
594@@ -28,6 +28,7 @@
595 include_directories(${Qt5Network_INCLUDE_DIRS})
596 include_directories(${Qt5Test_INCLUDE_DIRS})
597 include_directories(${Qt5Sql_INCLUDE_DIRS})
598+include_directories(${Boost_INCLUDE_DIRS})
599 include_directories(${DBUS_INCLUDE_DIRS})
600 include_directories(${GTEST_INCLUDE_DIRS})
601 include_directories(${GMOCK_INCLUDE_DIRS})
602@@ -43,21 +44,22 @@
603 link_directories(${GLOG_DBUS_LIBDIR})
604
605 add_library(${TARGET} STATIC
606- ${HEADERS}
607- ${SOURCES}
608+ ${HEADERS}
609+ ${SOURCES}
610 )
611
612 target_link_libraries(${TARGET}
613- ${NIH_DBUS_LIBRARIES}
614- ${GLOG_LIBRARIES}
615- ${Qt5Core_LIBRARIES}
616- ${Qt5Sql_LIBRARIES}
617- ${Qt5DBus_LIBRARIES}
618- ${Qt5Test_LIBRARIES}
619- ${GMOCK_LIBRARY}
620- ${GTEST_BOTH_LIBRARIES}
621- udm-common
622- udm-priv-common
623- ubuntu-download-manager-common
624- ubuntu-download-manager-client
625+ ${Boost_LIBRARIES}
626+ ${NIH_DBUS_LIBRARIES}
627+ ${GLOG_LIBRARIES}
628+ ${Qt5Core_LIBRARIES}
629+ ${Qt5Sql_LIBRARIES}
630+ ${Qt5DBus_LIBRARIES}
631+ ${Qt5Test_LIBRARIES}
632+ ${GMOCK_LIBRARY}
633+ ${GTEST_BOTH_LIBRARIES}
634+ udm-common
635+ udm-priv-common
636+ ubuntu-download-manager-common
637+ ubuntu-download-manager-client
638 )
639
640=== modified file 'tests/common/file_manager.h'
641--- tests/common/file_manager.h 2014-09-27 13:16:11 +0000
642+++ tests/common/file_manager.h 2015-02-26 08:49:11 +0000
643@@ -1,5 +1,5 @@
644 /*
645- * Copyright 2013-2014 Canonical Ltd.
646+ * Copyright 2013-2015 Canonical Ltd.
647 *
648 * This library is free software; you can redistribute it and/or
649 * modify it under the terms of version 3 of the GNU Lesser General Public
650@@ -16,8 +16,7 @@
651 * Boston, MA 02110-1301, USA.
652 */
653
654-#ifndef FAKE_FILE_MANAGER_H
655-#define FAKE_FILE_MANAGER_H
656+#pragma once
657
658 #include <QObject>
659 #include <ubuntu/transfers/system/file_manager.h>
660@@ -55,8 +54,9 @@
661 explicit MockFileManager(QObject *parent = 0)
662 : FileManager(parent) {}
663
664- MOCK_METHOD1(createFile, File*(const QString&));
665- MOCK_METHOD1(remove, bool(const QString&));
666+ MOCK_CONST_METHOD1(createFile, File*(const QString&));
667+ MOCK_CONST_METHOD1(remove, bool(const QString&));
668+ MOCK_CONST_METHOD1(freeSpace, quint64(const QString& path));
669 };
670
671 } // Ubuntu
672@@ -65,4 +65,3 @@
673
674 } // Tests
675
676-#endif // FAKE_FILE_MANAGER_H
677
678=== modified file 'tests/common/matchers.h'
679--- tests/common/matchers.h 2014-07-16 14:43:56 +0000
680+++ tests/common/matchers.h 2015-02-26 08:49:11 +0000
681@@ -1,5 +1,5 @@
682 /*
683- * Copyright 2014 Canonical Ltd.
684+ * Copyright 2014-2015 Canonical Ltd.
685 *
686 * This library is free software; you can redistribute it and/or
687 * modify it under the terms of version 3 of the GNU Lesser General Public
688@@ -16,8 +16,9 @@
689 * Boston, MA 02110-1301, USA.
690 */
691
692-#ifndef MATCHERS_H
693-#define MATCHERS_H
694+#pragma once
695+
696+#include <QDebug>
697
698 #include <QMap>
699 #include <QNetworkRequest>
700@@ -118,10 +119,12 @@
701
702 // compare the lists
703 if (list.count() != expectedList.count()) {
704+ qDebug() << list.count() << " |= " << expectedList.count();
705 return false;
706 } else {
707 foreach(auto str, expectedList) {
708 if (!list.contains(str)) {
709+ qDebug() << "Missing " << str;
710 return false;
711 }
712 }
713@@ -129,11 +132,19 @@
714 }
715 }
716
717+MATCHER_P(StringListContains, value, "Returns if the string is present in the list.") {
718+ auto list = static_cast<QStringList>(arg);
719+ auto expectedString = static_cast<QString>(value);
720+ return list.contains(expectedString);
721+}
722+
723 MATCHER_P(QStringEndsWith, value, "Returns if the string has the given postfix.") {
724 auto str = static_cast<QString>(arg);
725 auto post = static_cast<QString>(value);
726 return str.endsWith(post);
727 }
728
729-#endif
730+MATCHER_P(QStringEquals, value, "Returns if the strings are equal.") {
731+ return arg == value;
732+}
733
734
735=== modified file 'tests/downloads/daemon/test_download.cpp'
736--- tests/downloads/daemon/test_download.cpp 2015-02-02 11:05:15 +0000
737+++ tests/downloads/daemon/test_download.cpp 2015-02-26 08:49:11 +0000
738@@ -1,5 +1,5 @@
739 /*
740- * Copyright 2013-2014 Canonical Ltd.
741+ * Copyright 2013-2015 Canonical Ltd.
742 *
743 * This library is free software; you can redistribute it and/or
744 * modify it under the terms of version 3 of the GNU Lesser General Public
745@@ -283,6 +283,9 @@
746 EXPECT_CALL(*_networkSession, isOnline())
747 .WillRepeatedly(Return(true));
748
749+ EXPECT_CALL(*_fileManager, freeSpace(_))
750+ .WillRepeatedly(Return(200 * 1024));
751+
752 // set expectations to get the request and the reply correctly
753
754 EXPECT_CALL(*_reqFactory, get(_))
755@@ -371,6 +374,9 @@
756 EXPECT_CALL(*_networkSession, isOnline())
757 .WillRepeatedly(Return(true));
758
759+ EXPECT_CALL(*_fileManager, freeSpace(_))
760+ .WillRepeatedly(Return(200 * 1024));
761+
762 // set expectations to get the request and the reply correctly
763
764 EXPECT_CALL(*_reqFactory, get(_))
765@@ -445,6 +451,9 @@
766 EXPECT_CALL(*_networkSession, isOnline())
767 .WillRepeatedly(Return(true));
768
769+ EXPECT_CALL(*_fileManager, freeSpace(_))
770+ .WillRepeatedly(Return(200 * 1024));
771+
772 // set expectations to get the request and the reply correctly
773
774 EXPECT_CALL(*_reqFactory, get(_))
775@@ -893,6 +902,9 @@
776
777 // write the expectations of the reply which is what we are
778 // really testing
779+ //
780+ EXPECT_CALL(*_fileManager, freeSpace(_))
781+ .WillRepeatedly(Return(200 * 1024));
782
783 EXPECT_CALL(*_networkSession, isOnline())
784 .WillRepeatedly(Return(true));
785@@ -1047,6 +1059,9 @@
786 EXPECT_CALL(*_networkSession, isOnline())
787 .WillRepeatedly(Return(true));
788
789+ EXPECT_CALL(*_fileManager, freeSpace(_))
790+ .WillRepeatedly(Return(200 * 1024));
791+
792 EXPECT_CALL(*_reqFactory, get(_))
793 .Times(2)
794 .WillOnce(Return(firstReply))
795@@ -2026,6 +2041,9 @@
796 EXPECT_CALL(*_networkSession, isOnline())
797 .WillRepeatedly(Return(true));
798
799+ EXPECT_CALL(*_fileManager, freeSpace(_))
800+ .WillRepeatedly(Return(200 * 1024));
801+
802 QPair<QString, QString> rangeHeader("Range", QString::number(size));
803 EXPECT_CALL(*_reqFactory,
804 get(AnyOf(RequestHeadersEq(headers),
805@@ -3129,14 +3147,11 @@
806
807 QFileInfo fileInfo(filePath);
808 auto suffix = "." + fileInfo.completeSuffix();
809- qDebug() << "SUFIX" << suffix;
810 auto prefix = filePath.left(filePath.size() - suffix.size());
811- qDebug() << "PREFIX" << prefix;
812
813 // write the rest of the files
814 for(int index=1; index < count; index++) {
815 auto otherPath = QString("%1 (%2)%3").arg(prefix).arg(index).arg(suffix);
816- qDebug() << "Writing a new file" << otherPath;
817 QScopedPointer<QFile> otherFile(new QFile(otherPath));
818 otherFile->open(QIODevice::ReadWrite | QFile::Append);
819 otherFile->write("data data data!");
820@@ -3263,6 +3278,9 @@
821 EXPECT_CALL(*_networkSession, isOnline())
822 .WillRepeatedly(Return(true));
823
824+ EXPECT_CALL(*_fileManager, freeSpace(_))
825+ .WillRepeatedly(Return(200 * 1024));
826+
827 // set expectations to get the request and the reply correctly
828
829 EXPECT_CALL(*_reqFactory, get(_))
830@@ -3336,6 +3354,9 @@
831 EXPECT_CALL(*_networkSession, isOnline())
832 .WillRepeatedly(Return(true));
833
834+ EXPECT_CALL(*_fileManager, freeSpace(_))
835+ .WillRepeatedly(Return(200 * 1024));
836+
837 // set expectations to get the request and the reply correctly
838
839 EXPECT_CALL(*_reqFactory, get(_))
840@@ -3405,6 +3426,87 @@
841 verifyMocks();
842 }
843
844+
845+void
846+TestDownload::testFileSystemFull_data() {
847+ QTest::addColumn<int>("freeSpace");
848+
849+ QTest::newRow("Not enough") << 90;
850+ QTest::newRow("Zero") << 0;
851+}
852+
853+void
854+TestDownload::testFileSystemFull() {
855+ QFETCH(int, freeSpace);
856+ QScopedPointer<MockFile> file(new MockFile("test"));
857+ QScopedPointer<MockNetworkReply> reply(new MockNetworkReply());
858+
859+ EXPECT_CALL(*_networkSession, isOnline())
860+ .WillRepeatedly(Return(true));
861+
862+ EXPECT_CALL(*_fileManager, freeSpace(_))
863+ .WillRepeatedly(Return(freeSpace)); // not 0, we will use a diff test for that
864+
865+ // set expectations to get the request and the reply correctly
866+
867+ EXPECT_CALL(*_reqFactory, get(_))
868+ .Times(1)
869+ .WillOnce(Return(reply.data()));
870+
871+ EXPECT_CALL(*reply.data(), readAll())
872+ .Times(1)
873+ .WillOnce(Return(QByteArray()));
874+
875+ EXPECT_CALL(*reply.data(), setReadBufferSize(_))
876+ .Times(1);
877+
878+ // file system expectations
879+ EXPECT_CALL(*_fileManager, createFile(_))
880+ .Times(1)
881+ .WillOnce(Return(file.data()));
882+
883+ EXPECT_CALL(*file.data(), open(QIODevice::ReadWrite | QFile::Append))
884+ .Times(1)
885+ .WillOnce(Return(true));
886+
887+ EXPECT_CALL(*file.data(), write(_))
888+ .Times(1)
889+ .WillOnce(Return(0));
890+
891+ EXPECT_CALL(*file.data(), flush())
892+ .Times(0);
893+
894+ EXPECT_CALL(*file.data(), remove())
895+ .Times(1)
896+ .WillOnce(Return(true));
897+
898+ auto download = new FileDownload(_id, _appId, _path,
899+ _isConfined, _rootPath, _url, _metadata, _headers);
900+ SignalBarrier spy(download, SIGNAL(error(QString)));
901+ SignalBarrier startedSpy(download, SIGNAL(started(bool)));
902+
903+ download->start();
904+ download->startTransfer();
905+ QVERIFY(startedSpy.ensureSignalEmitted());
906+
907+ reply->downloadProgress(0, 13); // emit progress so that we try to write
908+
909+ // assert that the error signal is emitted
910+ QVERIFY(spy.ensureSignalEmitted());
911+ QTRY_COMPARE(spy.count(), 1);
912+
913+ auto arguments = spy.takeFirst();
914+ // assert that the size is not the received but the file size
915+ QCOMPARE(arguments.at(0).toString(),
916+ QString("FILE SYSTEM ERROR: %1").arg("There is not enough space in the device."));
917+
918+ delete download;
919+
920+ QVERIFY(Mock::VerifyAndClearExpectations(file.data()));
921+ QVERIFY(Mock::VerifyAndClearExpectations(reply.data()));
922+ verifyMocks();
923+}
924+
925 void
926 TestDownload::testRedirectCycle() {
927 QUrl redirectUrl("http://one.ubuntu.com");
928@@ -4174,4 +4276,499 @@
929 verifyMocks();
930 }
931
932+void
933+TestDownload::testUnzipSizeError_data() {
934+ QTest::addColumn<int>("code");
935+ QTest::addColumn<QString>("stdOut");
936+ QTest::addColumn<QString>("stdErr");
937+
938+ QTest::newRow("First row") << 1 << "Things hapened" <<
939+ "Errorooror";
940+ QTest::newRow("Second row") << 2 << "Time error" <<
941+ "Oh lords!";
942+ QTest::newRow("Second row") << 3 << "Read" <<
943+ "Error!";
944+}
945+
946+void
947+TestDownload::testUnzipSizeError() {
948+ QFETCH(int, code);
949+ QFETCH(QString, stdOut);
950+ QFETCH(QString, stdErr);
951+
952+ auto command = QString("udm-extractor");
953+ QVariantMap metadata;
954+ metadata["extract"] = true;
955+
956+ QStringList args; // not args
957+
958+ QScopedPointer<MockFile> file(new MockFile("test"));
959+ QScopedPointer<MockNetworkReply> reply(new MockNetworkReply());
960+ QScopedPointer<MockProcess> process(new MockProcess());
961+
962+ // write the expectations of the reply which is what we are
963+ // really testing
964+
965+ EXPECT_CALL(*_networkSession, isOnline())
966+ .WillRepeatedly(Return(true));
967+
968+ EXPECT_CALL(*_reqFactory, get(_))
969+ .Times(1)
970+ .WillOnce(Return(reply.data()));
971+
972+ EXPECT_CALL(*reply.data(), setReadBufferSize(_))
973+ .Times(1);
974+
975+ EXPECT_CALL(*reply.data(), attribute(_))
976+ .Times(1)
977+ .WillOnce(Return(QVariant(200)));
978+
979+ EXPECT_CALL(*reply.data(), hasRawHeader(QStringEquals("Content-Type")))
980+ .Times(1)
981+ .WillOnce(Return(true));
982+
983+ EXPECT_CALL(*reply.data(), hasRawHeader(QStringEquals("Content-Disposition")))
984+ .Times(1)
985+ .WillOnce(Return(false));
986+
987+ EXPECT_CALL(*reply.data(), rawHeader(QStringEquals("Content-Type")))
988+ .Times(1)
989+ .WillOnce(Return("application/zip"));
990+
991+ // file system expectations
992+ EXPECT_CALL(*_fileManager, createFile(_))
993+ .Times(1)
994+ .WillOnce(Return(file.data()));
995+
996+ EXPECT_CALL(*file.data(), open(QIODevice::ReadWrite | QFile::Append))
997+ .Times(1)
998+ .WillOnce(Return(true));
999+
1000+ EXPECT_CALL(*file.data(), remove())
1001+ .Times(1)
1002+ .WillOnce(Return(true));
1003+
1004+ EXPECT_CALL(*_cryptoFactory, createCryptographicHash(_, _))
1005+ .Times(0);
1006+
1007+ // process factory and process expectation
1008+ EXPECT_CALL(*_processFactory, createProcess())
1009+ .Times(1)
1010+ .WillOnce(Return(process.data()));
1011+
1012+ EXPECT_CALL(*process.data(), start(QStringEndsWith(command), StringListContains(QString("--size")), _))
1013+ .Times(1);
1014+
1015+ EXPECT_CALL(*process.data(), readAllStandardOutput())
1016+ .Times(1)
1017+ .WillOnce(Return(stdOut.toUtf8()));
1018+
1019+ EXPECT_CALL(*process.data(), readAllStandardError())
1020+ .Times(1)
1021+ .WillOnce(Return(stdErr.toUtf8()));
1022+
1023+ EXPECT_CALL(*process.data(), program())
1024+ .Times(1)
1025+ .WillOnce(Return(command));
1026+
1027+ EXPECT_CALL(*process.data(), arguments())
1028+ .Times(1)
1029+ .WillOnce(Return(QStringList()));
1030+
1031+ auto download = new FileDownload(_id, _appId, _path,
1032+ _isConfined, _rootPath, _url, metadata, _headers);
1033+
1034+ SignalBarrier spy(download, SIGNAL(error(QString)));
1035+ SignalBarrier startedSpy(download, SIGNAL(started(bool)));
1036+ SignalBarrier processingSpy(download, SIGNAL(processing(QString)));
1037+ SignalBarrier processErrorSpy(download,
1038+ SIGNAL(processError(ProcessErrorStruct)));
1039+
1040+ download->start(); // change state
1041+ download->startTransfer();
1042+
1043+ QVERIFY(startedSpy.ensureSignalEmitted());
1044+
1045+ // emit the finish signal and expect it to be raised
1046+ emit reply->finished();
1047+ emit process->error(static_cast<QProcess::ProcessError>(code));
1048+
1049+ QVERIFY(spy.ensureSignalEmitted());
1050+ QCOMPARE(spy.count(), 1);
1051+ QCOMPARE(processingSpy.count(), 0);
1052+ QCOMPARE(processErrorSpy.count(), 1);
1053+ QCOMPARE(download->state(), Download::ERROR);
1054+
1055+ delete download;
1056+
1057+ QVERIFY(Mock::VerifyAndClearExpectations(file.data()));
1058+ QVERIFY(Mock::VerifyAndClearExpectations(reply.data()));
1059+ QVERIFY(Mock::VerifyAndClearExpectations(process.data()));
1060+ verifyMocks();
1061+}
1062+
1063+void
1064+TestDownload::testUnzipNotEnoughSize_data() {
1065+ QTest::addColumn<QString>("size");
1066+ QTest::addColumn<qint64>("deviceSize");
1067+
1068+ QTest::newRow("First row") << "23323\n" << Q_INT64_C(101 * 1024);
1069+ QTest::newRow("Second row") << "23032\n" << Q_INT64_C(101 * 1024);
1070+ QTest::newRow("Third row") << "23223\n" << Q_INT64_C(101 * 1024);
1071+}
1072+
1073+void
1074+TestDownload::testUnzipNotEnoughSize() {
1075+ QFETCH(QString, size);
1076+ QFETCH(qint64, deviceSize);
1077+
1078+ auto command = QString("udm-extractor");
1079+ QVariantMap metadata;
1080+ metadata["extract"] = true;
1081+
1082+ QScopedPointer<MockFile> file(new MockFile("test"));
1083+ auto reply = new MockNetworkReply();
1084+ QScopedPointer<MockProcess> process(new MockProcess());
1085+
1086+ // write the expectations of the reply which is what we are
1087+ // really testing
1088+
1089+ EXPECT_CALL(*_fileManager, freeSpace(_))
1090+ .WillRepeatedly(Return(deviceSize));
1091+
1092+ EXPECT_CALL(*_networkSession, isOnline())
1093+ .WillRepeatedly(Return(true));
1094+
1095+ EXPECT_CALL(*_reqFactory, get(_))
1096+ .Times(1)
1097+ .WillOnce(Return(reply));
1098+
1099+ EXPECT_CALL(*reply, setReadBufferSize(_))
1100+ .Times(1);
1101+
1102+ EXPECT_CALL(*reply, attribute(_))
1103+ .Times(1)
1104+ .WillOnce(Return(QVariant(200)));
1105+
1106+ EXPECT_CALL(*reply, hasRawHeader(QStringEquals("Content-Type")))
1107+ .Times(1)
1108+ .WillOnce(Return(true));
1109+
1110+ EXPECT_CALL(*reply, hasRawHeader(QStringEquals("Content-Disposition")))
1111+ .Times(1)
1112+ .WillOnce(Return(false));
1113+
1114+ EXPECT_CALL(*reply, rawHeader(QStringEquals("Content-Type")))
1115+ .Times(1)
1116+ .WillOnce(Return("application/zip"));
1117+
1118+ // file system expectations
1119+ EXPECT_CALL(*_fileManager, createFile(_))
1120+ .Times(1)
1121+ .WillOnce(Return(file.data()));
1122+
1123+ EXPECT_CALL(*file.data(), open(QIODevice::ReadWrite | QFile::Append))
1124+ .Times(1)
1125+ .WillOnce(Return(true));
1126+
1127+ EXPECT_CALL(*file.data(), remove())
1128+ .Times(1)
1129+ .WillOnce(Return(true));
1130+
1131+ EXPECT_CALL(*_cryptoFactory, createCryptographicHash(_, _))
1132+ .Times(0);
1133+
1134+ // process factory and process expectation
1135+ EXPECT_CALL(*_processFactory, createProcess())
1136+ .Times(1)
1137+ .WillOnce(Return(process.data()));
1138+
1139+ EXPECT_CALL(*process.data(), start(QStringEndsWith(command), StringListContains(QString("--size")), _))
1140+ .Times(1);
1141+
1142+ EXPECT_CALL(*process.data(), readAllStandardOutput())
1143+ .Times(1)
1144+ .WillOnce(Return(size.toUtf8()));
1145+
1146+ auto download = new FileDownload(_id, _appId, _path,
1147+ _isConfined, _rootPath, _url, metadata, _headers);
1148+
1149+ SignalBarrier spy(download, SIGNAL(error(QString)));
1150+ SignalBarrier startedSpy(download, SIGNAL(started(bool)));
1151+ SignalBarrier processingSpy(download, SIGNAL(processing(QString)));
1152+ SignalBarrier errorSpy(download, SIGNAL(error(QString)));
1153+
1154+ download->start(); // change state
1155+ download->startTransfer();
1156+
1157+ QVERIFY(startedSpy.ensureSignalEmitted());
1158+
1159+ // emit the finish signal and expect it to be raised
1160+ emit reply->finished();
1161+ emit process->finished(0, QProcess::NormalExit);
1162+
1163+ QVERIFY(spy.ensureSignalEmitted());
1164+ QCOMPARE(spy.count(), 1);
1165+ QCOMPARE(processingSpy.count(), 0);
1166+ QCOMPARE(errorSpy.count(), 1);
1167+ QCOMPARE(download->state(), Download::ERROR);
1168+
1169+ delete download;
1170+
1171+ QVERIFY(Mock::VerifyAndClearExpectations(file.data()));
1172+ QVERIFY(Mock::VerifyAndClearExpectations(reply));
1173+ QVERIFY(Mock::VerifyAndClearExpectations(process.data()));
1174+ verifyMocks();
1175+
1176+ delete reply;
1177+}
1178+
1179+void
1180+TestDownload::testUnzipError_data() {
1181+ QTest::addColumn<QString>("size");
1182+ QTest::addColumn<qint64>("deviceSize");
1183+
1184+ QTest::newRow("First row") << "23323\n" << Q_INT64_C(300 * 1024);
1185+ QTest::newRow("Second row") << "23032\n" << Q_INT64_C(300 * 1024);
1186+ QTest::newRow("Third row") << "23223\n" << Q_INT64_C(300 * 1024);
1187+}
1188+
1189+void
1190+TestDownload::testUnzipError() {
1191+ QFETCH(QString, size);
1192+ QFETCH(qint64, deviceSize);
1193+
1194+ auto command = QString("udm-extractor");
1195+ QVariantMap metadata;
1196+ metadata["extract"] = true;
1197+
1198+ QScopedPointer<MockFile> file(new MockFile("test"));
1199+ auto reply = new MockNetworkReply();
1200+ QScopedPointer<MockProcess> sizeProcess(new MockProcess());
1201+ QScopedPointer<MockProcess> unzipProcess(new MockProcess());
1202+
1203+ // write the expectations of the reply which is what we are
1204+ // really testing
1205+
1206+ EXPECT_CALL(*_fileManager, freeSpace(_))
1207+ .WillRepeatedly(Return(deviceSize));
1208+
1209+ EXPECT_CALL(*_networkSession, isOnline())
1210+ .WillRepeatedly(Return(true));
1211+
1212+ EXPECT_CALL(*_reqFactory, get(_))
1213+ .Times(1)
1214+ .WillOnce(Return(reply));
1215+
1216+ EXPECT_CALL(*reply, setReadBufferSize(_))
1217+ .Times(1);
1218+
1219+ EXPECT_CALL(*reply, attribute(_))
1220+ .Times(1)
1221+ .WillOnce(Return(QVariant(200)));
1222+
1223+ EXPECT_CALL(*reply, hasRawHeader(QStringEquals("Content-Type")))
1224+ .Times(1)
1225+ .WillOnce(Return(true));
1226+
1227+ EXPECT_CALL(*reply, hasRawHeader(QStringEquals("Content-Disposition")))
1228+ .Times(1)
1229+ .WillOnce(Return(false));
1230+
1231+ EXPECT_CALL(*reply, rawHeader(QStringEquals("Content-Type")))
1232+ .Times(1)
1233+ .WillOnce(Return("application/zip"));
1234+
1235+ // file system expectations
1236+ EXPECT_CALL(*_fileManager, createFile(_))
1237+ .Times(1)
1238+ .WillOnce(Return(file.data()));
1239+
1240+ EXPECT_CALL(*file.data(), open(QIODevice::ReadWrite | QFile::Append))
1241+ .Times(1)
1242+ .WillOnce(Return(true));
1243+
1244+ EXPECT_CALL(*file.data(), remove())
1245+ .Times(1)
1246+ .WillOnce(Return(true));
1247+
1248+ EXPECT_CALL(*_cryptoFactory, createCryptographicHash(_, _))
1249+ .Times(0);
1250+
1251+ // process factory and process expectation
1252+ EXPECT_CALL(*_processFactory, createProcess())
1253+ .Times(2)
1254+ .WillOnce(Return(sizeProcess.data()))
1255+ .WillOnce(Return(unzipProcess.data()));
1256+
1257+ EXPECT_CALL(*sizeProcess.data(), start(QStringEndsWith(command), StringListContains(QString("--size")), _))
1258+ .Times(1);
1259+
1260+ EXPECT_CALL(*unzipProcess.data(), start(QStringEndsWith(command), StringListContains(QString("--destination")), _))
1261+ .Times(1);
1262+
1263+ EXPECT_CALL(*sizeProcess.data(), readAllStandardOutput())
1264+ .Times(1)
1265+ .WillOnce(Return(size.toUtf8()));
1266+
1267+ EXPECT_CALL(*unzipProcess.data(), readAllStandardOutput())
1268+ .Times(1)
1269+ .WillOnce(Return(QByteArray()));
1270+
1271+ EXPECT_CALL(*unzipProcess.data(), readAllStandardError())
1272+ .Times(1)
1273+ .WillOnce(Return(QByteArray()));
1274+
1275+ auto download = new FileDownload(_id, _appId, _path,
1276+ _isConfined, _rootPath, _url, metadata, _headers);
1277+
1278+ SignalBarrier spy(download, SIGNAL(error(QString)));
1279+ SignalBarrier startedSpy(download, SIGNAL(started(bool)));
1280+ SignalBarrier processingSpy(download, SIGNAL(processing(QString)));
1281+ SignalBarrier errorSpy(download, SIGNAL(error(QString)));
1282+
1283+ download->start(); // change state
1284+ download->startTransfer();
1285+
1286+ QVERIFY(startedSpy.ensureSignalEmitted());
1287+
1288+ // emit the finish signal and expect it to be raised
1289+ emit reply->finished();
1290+ emit sizeProcess->finished(0, QProcess::NormalExit);
1291+
1292+ QCOMPARE(processingSpy.count(), 1);
1293+
1294+ // emit an error due to the unzip operation
1295+ emit unzipProcess->finished(-1, QProcess::NormalExit);
1296+
1297+ QVERIFY(spy.ensureSignalEmitted());
1298+ QCOMPARE(spy.count(), 1);
1299+ QCOMPARE(errorSpy.count(), 1);
1300+ QCOMPARE(download->state(), Download::ERROR);
1301+
1302+ delete download;
1303+
1304+ QVERIFY(Mock::VerifyAndClearExpectations(file.data()));
1305+ QVERIFY(Mock::VerifyAndClearExpectations(reply));
1306+ QVERIFY(Mock::VerifyAndClearExpectations(sizeProcess.data()));
1307+ verifyMocks();
1308+
1309+ delete reply;
1310+}
1311+
1312+void
1313+TestDownload::testUnzip() {
1314+ QString size = "23323\n";
1315+ auto deviceSize = Q_INT64_C(300 * 1024);
1316+
1317+ auto command = QString("udm-extractor");
1318+ QVariantMap metadata;
1319+ metadata["extract"] = true;
1320+
1321+ QScopedPointer<MockFile> file(new MockFile("test"));
1322+ auto reply = new MockNetworkReply();
1323+ QScopedPointer<MockProcess> sizeProcess(new MockProcess());
1324+ QScopedPointer<MockProcess> unzipProcess(new MockProcess());
1325+
1326+ // write the expectations of the reply which is what we are
1327+ // really testing
1328+
1329+ EXPECT_CALL(*_fileManager, freeSpace(_))
1330+ .WillRepeatedly(Return(deviceSize));
1331+
1332+ EXPECT_CALL(*_networkSession, isOnline())
1333+ .WillRepeatedly(Return(true));
1334+
1335+ EXPECT_CALL(*_reqFactory, get(_))
1336+ .Times(1)
1337+ .WillOnce(Return(reply));
1338+
1339+ EXPECT_CALL(*reply, setReadBufferSize(_))
1340+ .Times(1);
1341+
1342+ EXPECT_CALL(*reply, attribute(_))
1343+ .Times(1)
1344+ .WillOnce(Return(QVariant(200)));
1345+
1346+ EXPECT_CALL(*reply, hasRawHeader(QStringEquals("Content-Type")))
1347+ .Times(1)
1348+ .WillOnce(Return(true));
1349+
1350+ EXPECT_CALL(*reply, hasRawHeader(QStringEquals("Content-Disposition")))
1351+ .Times(1)
1352+ .WillOnce(Return(false));
1353+
1354+ EXPECT_CALL(*reply, rawHeader(QStringEquals("Content-Type")))
1355+ .Times(1)
1356+ .WillOnce(Return("application/zip"));
1357+
1358+ // file system expectations
1359+ EXPECT_CALL(*_fileManager, createFile(_))
1360+ .Times(1)
1361+ .WillOnce(Return(file.data()));
1362+
1363+ EXPECT_CALL(*file.data(), open(QIODevice::ReadWrite | QFile::Append))
1364+ .Times(1)
1365+ .WillOnce(Return(true));
1366+
1367+ EXPECT_CALL(*file.data(), remove())
1368+ .Times(1)
1369+ .WillOnce(Return(true));
1370+
1371+ EXPECT_CALL(*_cryptoFactory, createCryptographicHash(_, _))
1372+ .Times(0);
1373+
1374+ // process factory and process expectation
1375+ EXPECT_CALL(*_processFactory, createProcess())
1376+ .Times(2)
1377+ .WillOnce(Return(sizeProcess.data()))
1378+ .WillOnce(Return(unzipProcess.data()));
1379+
1380+ EXPECT_CALL(*sizeProcess.data(), start(QStringEndsWith(command), StringListContains(QString("--size")), _))
1381+ .Times(1);
1382+
1383+ EXPECT_CALL(*unzipProcess.data(), start(QStringEndsWith(command), StringListContains(QString("--destination")), _))
1384+ .Times(1);
1385+
1386+ EXPECT_CALL(*sizeProcess.data(), readAllStandardOutput())
1387+ .Times(1)
1388+ .WillOnce(Return(size.toUtf8()));
1389+
1390+ auto download = new FileDownload(_id, _appId, _path,
1391+ _isConfined, _rootPath, _url, metadata, _headers);
1392+
1393+ SignalBarrier spy(download, SIGNAL(finished(QString)));
1394+ SignalBarrier startedSpy(download, SIGNAL(started(bool)));
1395+ SignalBarrier processingSpy(download, SIGNAL(processing(QString)));
1396+ SignalBarrier errorSpy(download, SIGNAL(error(QString)));
1397+
1398+ download->start(); // change state
1399+ download->startTransfer();
1400+
1401+ QVERIFY(startedSpy.ensureSignalEmitted());
1402+
1403+ // emit the finish signal and expect it to be raised
1404+ emit reply->finished();
1405+ emit sizeProcess->finished(0, QProcess::NormalExit);
1406+
1407+ QCOMPARE(processingSpy.count(), 1);
1408+
1409+ // emit an error due to the unzip operation
1410+ emit unzipProcess->finished(0, QProcess::NormalExit);
1411+
1412+ QVERIFY(spy.ensureSignalEmitted());
1413+ QCOMPARE(spy.count(), 1);
1414+ QCOMPARE(errorSpy.count(), 0);
1415+ QCOMPARE(download->state(), Download::FINISH);
1416+
1417+ delete download;
1418+
1419+ QVERIFY(Mock::VerifyAndClearExpectations(file.data()));
1420+ QVERIFY(Mock::VerifyAndClearExpectations(reply));
1421+ QVERIFY(Mock::VerifyAndClearExpectations(sizeProcess.data()));
1422+ verifyMocks();
1423+
1424+ delete reply;
1425+}
1426+
1427 QTEST_MAIN(TestDownload)
1428
1429=== modified file 'tests/downloads/daemon/test_download.h'
1430--- tests/downloads/daemon/test_download.h 2015-02-02 11:05:15 +0000
1431+++ tests/downloads/daemon/test_download.h 2015-02-26 08:49:11 +0000
1432@@ -1,5 +1,5 @@
1433 /*
1434- * Copyright 2013-2014 Canonical Ltd.
1435+ * Copyright 2013-2015 Canonical Ltd.
1436 *
1437 * This library is free software; you can redistribute it and/or
1438 * modify it under the terms of version 3 of the GNU Lesser General Public
1439@@ -16,8 +16,7 @@
1440 * Boston, MA 02110-1301, USA.
1441 */
1442
1443-#ifndef TEST_APP_DOWNLOAD_H
1444-#define TEST_APP_DOWNLOAD_H
1445+#pragma once
1446
1447 #include <QDir>
1448 #include <QObject>
1449@@ -161,6 +160,8 @@
1450 // we fwd the error
1451 void testFileSystemErrorProgress();
1452 void testFileSystemErrorPause();
1453+ void testFileSystemFull_data();
1454+ void testFileSystemFull();
1455
1456 // test different redirects
1457 void testRedirectCycle();
1458@@ -195,6 +196,15 @@
1459 void testDataUriPostProcessing_data();
1460 void testDataUriPostProcessing();
1461
1462+ // unzip tests
1463+ void testUnzipSizeError_data();
1464+ void testUnzipSizeError();
1465+ void testUnzipNotEnoughSize_data();
1466+ void testUnzipNotEnoughSize();
1467+ void testUnzipError_data();
1468+ void testUnzipError();
1469+ void testUnzip();
1470+
1471 private:
1472 QString _id = QString::null;
1473 QString _appId = QString::null;
1474@@ -214,4 +224,3 @@
1475
1476 Q_DECLARE_METATYPE(QNetworkConfiguration::BearerType)
1477
1478-#endif // TEST_APP_DOWNLOAD_H

Subscribers

People subscribed via source and target branches