Merge lp:~unity-api-team/keeper/restore into lp:keeper/devel

Proposed by Charles Kerr
Status: Needs review
Proposed branch: lp:~unity-api-team/keeper/restore
Merge into: lp:keeper/devel
Diff against target: 3175 lines (+1957/-302)
52 files modified
data/helper-registry.json.in (+6/-1)
include/helper/data-dir-registry.h (+2/-0)
include/helper/metadata.h (+1/-0)
include/helper/registry.h (+1/-0)
include/helper/restore-helper.h (+61/-0)
src/CMakeLists.txt (+1/-0)
src/cli/main.cpp (+42/-0)
src/helper/CMakeLists.txt (+2/-0)
src/helper/data-dir-registry.cpp (+43/-9)
src/helper/helper.cpp (+2/-2)
src/helper/metadata.cpp (+1/-0)
src/helper/restore-helper.cpp (+378/-0)
src/service/CMakeLists.txt (+1/-0)
src/service/keeper-helper.cpp (+5/-2)
src/service/keeper-task-backup.cpp (+2/-2)
src/service/keeper-task-backup.h (+1/-1)
src/service/keeper-task-restore.cpp (+129/-0)
src/service/keeper-task-restore.h (+46/-0)
src/service/keeper-task.cpp (+37/-4)
src/service/keeper-task.h (+3/-1)
src/service/keeper-user.cpp (+4/-2)
src/service/keeper.cpp (+103/-48)
src/service/keeper.h (+6/-1)
src/service/manifest.cpp (+3/-3)
src/service/private/keeper-task_p.h (+4/-2)
src/service/task-manager.cpp (+55/-12)
src/service/task-manager.h (+2/-0)
src/storage-framework/CMakeLists.txt (+3/-0)
src/storage-framework/downloader.h (+46/-0)
src/storage-framework/sf-downloader.cpp (+71/-0)
src/storage-framework/sf-downloader.h (+48/-0)
src/storage-framework/storage_framework_client.cpp (+16/-15)
src/storage-framework/storage_framework_client.h (+2/-1)
src/test-restore/CMakeLists.txt (+40/-0)
src/test-restore/main.cpp (+32/-0)
src/test-restore/test-restore-socket.cpp (+139/-0)
src/test-restore/test-restore-socket.h (+56/-0)
tests/CMakeLists.txt (+6/-0)
tests/com_canonical_keeper.py (+17/-0)
tests/fakes/CMakeLists.txt (+10/-0)
tests/fakes/fake-restore-helper.cpp (+101/-0)
tests/fakes/fake-restore-helper.h (+26/-0)
tests/fakes/restore-reader.cpp (+81/-0)
tests/fakes/restore-reader.h (+43/-0)
tests/integration/helpers/CMakeLists.txt (+4/-0)
tests/integration/helpers/helpers-test.cc (+219/-184)
tests/integration/helpers/test-helpers-base.cpp (+8/-3)
tests/unit/manifest/manifest-test.cpp (+1/-1)
tests/unit/storage-framework/create-uploader-test.cpp (+6/-7)
tests/utils/file-utils.cpp (+3/-1)
tests/utils/storage-framework-local.cpp (+34/-0)
tests/utils/storage-framework-local.h (+4/-0)
To merge this branch: bzr merge lp:~unity-api-team/keeper/restore
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Needs Fixing
Unity API Team Pending
Review via email: mp+311070@code.launchpad.net

Commit message

First version of restore.

Description of the change

DO NOT REVIEW YET, branch created for initial jenkins test

This is based on <https://code.launchpad.net/~xavi-garcia-mena/keeper/restore/> and is here so that multiple devs can kick the tires as neeed

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
lp:~unity-api-team/keeper/restore updated
131. By Charles Kerr

debug messages and whitespace

132. By Charles Kerr

eliminate some possible points of failure in the RestoreReader fake

133. By Charles Kerr

add more debugging info to FileUtils::compare_files()

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)

Unmerged revisions

133. By Charles Kerr

add more debugging info to FileUtils::compare_files()

132. By Charles Kerr

eliminate some possible points of failure in the RestoreReader fake

131. By Charles Kerr

debug messages and whitespace

130. By Charles Kerr

fix missing gpl copyright in keeper dbusmock template

129. By Charles Kerr

fix cppcheck warning: non-explicit object ctor taking one argument

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/helper-registry.json.in'
2--- data/helper-registry.json.in 2016-08-09 04:20:33 +0000
3+++ data/helper-registry.json.in 2016-11-17 00:23:33 +0000
4@@ -4,5 +4,10 @@
5 "@FOLDER_BACKUP_EXEC@",
6 "${subtype}"
7 ]
8- }
9+ ,
10+ "restore-urls": [
11+ "@FOLDER_RESTORE_EXEC@",
12+ "${subtype}"
13+ ]
14+ }
15 }
16
17=== modified file 'include/helper/data-dir-registry.h'
18--- include/helper/data-dir-registry.h 2016-08-09 05:44:25 +0000
19+++ include/helper/data-dir-registry.h 2016-11-17 00:23:33 +0000
20@@ -39,6 +39,8 @@
21
22 QStringList get_backup_helper_urls(Metadata const& metadata) override;
23
24+ QStringList get_restore_helper_urls(Metadata const& metadata) override;
25+
26 private:
27 class Impl;
28 friend class Impl;
29
30=== modified file 'include/helper/metadata.h'
31--- include/helper/metadata.h 2016-10-14 09:23:11 +0000
32+++ include/helper/metadata.h 2016-11-17 00:23:33 +0000
33@@ -42,6 +42,7 @@
34 static QString const TITLE_KEY;
35 static QString const VERSION_KEY;
36 static QString const FILE_NAME_KEY;
37+ static QString const DIR_NAME_KEY;
38 static QString const DISPLAY_NAME_KEY;
39
40 // metadata values
41
42=== modified file 'include/helper/registry.h'
43--- include/helper/registry.h 2016-08-08 04:56:35 +0000
44+++ include/helper/registry.h 2016-11-17 00:23:33 +0000
45@@ -30,6 +30,7 @@
46 Q_DISABLE_COPY(HelperRegistry)
47
48 virtual QStringList get_backup_helper_urls(Metadata const& task) =0;
49+ virtual QStringList get_restore_helper_urls(Metadata const& task) =0;
50
51 protected:
52 HelperRegistry() =default;
53
54=== added file 'include/helper/restore-helper.h'
55--- include/helper/restore-helper.h 1970-01-01 00:00:00 +0000
56+++ include/helper/restore-helper.h 2016-11-17 00:23:33 +0000
57@@ -0,0 +1,61 @@
58+/*
59+ * Copyright (C) 2016 Canonical, Ltd.
60+ *
61+ * This program is free software: you can redistribute it and/or modify it
62+ * under the terms of the GNU General Public License version 3, as published
63+ * by the Free Software Foundation.
64+ *
65+ * This program is distributed in the hope that it will be useful, but
66+ * WITHOUT ANY WARRANTY; without even the implied warranties of
67+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
68+ * PURPOSE. See the GNU General Public License for more details.
69+ *
70+ * You should have received a copy of the GNU General Public License along
71+ * with this program. If not, see <http://www.gnu.org/licenses/>.
72+ *
73+ * Authors:
74+ * Xavi Garcia <xavi.garcia.mena@canonical.com>
75+ * Charles Kerr <charles.kerr@canonical.com>
76+ */
77+
78+#pragma once
79+
80+#include "storage-framework/downloader.h"
81+#include "helper/helper.h" // parent class
82+#include "helper/registry.h"
83+
84+#include <QObject>
85+#include <QScopedPointer>
86+#include <QString>
87+
88+#include <memory>
89+
90+class RestoreHelperPrivate;
91+class RestoreHelper final: public Helper
92+{
93+ Q_OBJECT
94+ Q_DECLARE_PRIVATE(RestoreHelper)
95+
96+public:
97+ RestoreHelper(
98+ QString const & appid,
99+ clock_func const & clock=Helper::default_clock,
100+ QObject * parent=nullptr
101+ );
102+ virtual ~RestoreHelper();
103+ Q_DISABLE_COPY(RestoreHelper)
104+
105+ static constexpr int MAX_INACTIVITY_TIME = 15000;
106+
107+ void set_downloader(std::shared_ptr<Downloader> const& downloader);
108+ void start(QStringList const& urls) override;
109+ void stop() override;
110+ int get_helper_socket() const;
111+ QString to_string(Helper::State state) const override;
112+ void set_state(State) override;
113+protected:
114+ void on_helper_finished() override;
115+
116+private:
117+ QScopedPointer<RestoreHelperPrivate> const d_ptr;
118+};
119
120=== modified file 'src/CMakeLists.txt'
121--- src/CMakeLists.txt 2016-08-09 10:13:48 +0000
122+++ src/CMakeLists.txt 2016-11-17 00:23:33 +0000
123@@ -11,6 +11,7 @@
124 add_subdirectory(storage-framework)
125 add_subdirectory(tar)
126 add_subdirectory(util)
127+add_subdirectory(test-restore)
128
129 set(
130 COVERAGE_REPORT_TARGETS
131
132=== modified file 'src/cli/main.cpp'
133--- src/cli/main.cpp 2016-08-30 14:16:19 +0000
134+++ src/cli/main.cpp 2016-11-17 00:23:33 +0000
135@@ -88,6 +88,48 @@
136 qWarning() << "Error starting backup:" << backup_reply.error().message();
137 }
138 }
139+ else if(argc == 2 && QStringLiteral("--restore") == argv[1])
140+ {
141+ QScopedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser(
142+ DBusTypes::KEEPER_SERVICE,
143+ DBusTypes::KEEPER_USER_PATH,
144+ QDBusConnection::sessionBus()
145+ ) );
146+ QDBusPendingReply<QVariantDictMap> choices = user_iface->call("GetRestoreChoices");
147+ choices.waitForFinished();
148+ if (choices.isError())
149+ {
150+ qFatal("Call to '%s.GetRestoreChoices() at '%s' call failed: %s",
151+ DBusTypes::KEEPER_SERVICE,
152+ qPrintable(DBusTypes::KEEPER_USER_PATH),
153+ qPrintable(choices.error().message())
154+ );
155+ }
156+
157+ QStringList uuids;
158+ auto choices_values = choices.value();
159+ for(auto iter = choices_values.begin(); iter != choices_values.end(); ++iter)
160+ {
161+ const auto& values = iter.value();
162+ auto iter_values = values.find("type");
163+ if (iter_values != values.end())
164+ {
165+ if (iter_values.value().toString() == "folder")
166+ {
167+ qDebug() << "Adding uuid" << iter.key() << "with type:" << "folder";
168+ uuids << iter.key();
169+ }
170+ }
171+ }
172+
173+ QStringList restoreUUids{uuids.at(0)};
174+ QDBusPendingReply<void> backup_reply = user_iface->call("StartRestore", restoreUUids);
175+
176+ if (!backup_reply.isValid())
177+ {
178+ qWarning() << "Error starting restore:" << backup_reply.error().message();
179+ }
180+ }
181 else
182 {
183 qWarning() << "FIXME";
184
185=== modified file 'src/helper/CMakeLists.txt'
186--- src/helper/CMakeLists.txt 2016-09-06 01:31:59 +0000
187+++ src/helper/CMakeLists.txt 2016-11-17 00:23:33 +0000
188@@ -48,10 +48,12 @@
189 ${HELPER_LIB}
190 STATIC
191 backup-helper.cpp
192+ restore-helper.cpp
193 data-dir-registry.cpp
194 helper.cpp
195 metadata.cpp
196 ${CMAKE_SOURCE_DIR}/include/helper/backup-helper.h
197+ ${CMAKE_SOURCE_DIR}/include/helper/restore-helper.h
198 ${CMAKE_SOURCE_DIR}/include/helper/data-dir-registry.h
199 ${CMAKE_SOURCE_DIR}/include/helper/helper.h
200 ${CMAKE_SOURCE_DIR}/include/helper/registry.h
201
202=== modified file 'src/helper/data-dir-registry.cpp'
203--- src/helper/data-dir-registry.cpp 2016-08-10 02:29:17 +0000
204+++ src/helper/data-dir-registry.cpp 2016-11-17 00:23:33 +0000
205@@ -49,15 +49,29 @@
206
207 QStringList get_backup_helper_urls(Metadata const& task)
208 {
209+ return get_helper_urls(task, "backup");
210+ }
211+
212+ QStringList get_restore_helper_urls(Metadata const& task)
213+ {
214+ return get_helper_urls(task, "restore");
215+ }
216+
217+
218+
219+private:
220+
221+ QStringList get_helper_urls(Metadata const& task, QString const & prop)
222+ {
223 QStringList ret;
224
225 QString type;
226 if (task.get_property(Metadata::TYPE_KEY, type))
227 {
228- auto it = registry_.find(std::make_pair(type,QStringLiteral("backup")));
229+ auto it = registry_.find(std::make_pair(type,prop));
230 if (it == registry_.end())
231 {
232- qCritical() << "can't get backup helper urls for unhandled type" << type;
233+ qCritical() << "can't get " << prop << " helper urls for unhandled type" << type;
234 }
235 else
236 {
237@@ -73,8 +87,6 @@
238 return ret;
239 }
240
241-private:
242-
243 // replace "${key}" with task.get_property("key")
244 QStringList perform_url_substitution(Metadata const& task, QStringList const& urls_in)
245 {
246@@ -139,6 +151,10 @@
247 * "backup-urls": [
248 * "/path/to/helper.sh",
249 * "${subtype}"
250+ * ],
251+ * "restore-urls": [
252+ * "/path/to/helper.sh",
253+ * "${subtype}"
254 * ]
255 * }
256 * }
257@@ -160,21 +176,33 @@
258 for (auto tit=obj.begin(), tend=obj.end(); tit!=tend; ++tit)
259 {
260 auto const type = tit.key();
261- auto& info = registry_[std::make_pair(type,QStringLiteral("backup"))];
262-
263 auto const props = tit.value().toObject();
264+
265 auto const urls_jsonval = props["backup-urls"];
266 if (urls_jsonval.isArray())
267 {
268+ auto& info = registry_[std::make_pair(type,QStringLiteral("backup"))];
269 for (auto url_jsonval : urls_jsonval.toArray())
270 {
271 info.urls.push_back(url_jsonval.toString());
272 }
273+ qDebug() << "loaded" << type << "backup urls from" << path;
274+ for(auto const& url : info.urls)
275+ qDebug() << "\turl:" << url;
276 }
277
278- qDebug() << "loaded" << type << "backup urls from" << path;
279- for(auto const& url : info.urls)
280- qDebug() << "\turl:" << url;
281+ auto const urls_jsonval_restore = props["restore-urls"];
282+ if (urls_jsonval_restore.isArray())
283+ {
284+ auto& info = registry_[std::make_pair(type,QStringLiteral("restore"))];
285+ for (auto url_jsonval : urls_jsonval_restore.toArray())
286+ {
287+ info.urls.push_back(url_jsonval.toString());
288+ }
289+ qDebug() << "loaded" << type << "restore urls from" << path;
290+ for(auto const& url : info.urls)
291+ qDebug() << "\turl:" << url;
292+ }
293 }
294 }
295 }
296@@ -198,3 +226,9 @@
297 {
298 return impl_->get_backup_helper_urls(task);
299 }
300+
301+QStringList
302+DataDirRegistry::get_restore_helper_urls(Metadata const& task)
303+{
304+ return impl_->get_restore_helper_urls(task);
305+}
306
307=== modified file 'src/helper/helper.cpp'
308--- src/helper/helper.cpp 2016-09-15 14:05:17 +0000
309+++ src/helper/helper.cpp 2016-11-17 00:23:33 +0000
310@@ -301,7 +301,7 @@
311
312 void ual_stop()
313 {
314- qDebug() << "Stopping helper for app:" << appid_;
315+ qDebug() << "------------------------------------------------------ Stopping helper for app:" << appid_;
316 auto backupType = ubuntu::app_launch::Helper::Type::from_raw(HELPER_TYPE);
317
318 auto appid = ubuntu::app_launch::AppID::parse(appid_.toStdString());
319@@ -359,7 +359,7 @@
320
321 void on_max_time_waiting_for_ual_started()
322 {
323- qDebug() << "Max time reached waiting for UAL to start";
324+ qDebug() << "========================================================================== Max time reached waiting for UAL to start";
325 q_ptr->set_state(Helper::State::FAILED);
326 stop_wait_for_ual_timer();
327 }
328
329=== modified file 'src/helper/metadata.cpp'
330--- src/helper/metadata.cpp 2016-10-14 09:23:11 +0000
331+++ src/helper/metadata.cpp 2016-11-17 00:23:33 +0000
332@@ -42,6 +42,7 @@
333 const QString Metadata::TITLE_KEY = QStringLiteral("title");
334 const QString Metadata::VERSION_KEY = QStringLiteral("version");
335 const QString Metadata::FILE_NAME_KEY = QStringLiteral("file-name");
336+const QString Metadata::DIR_NAME_KEY = QStringLiteral("dir-name");
337 const QString Metadata::DISPLAY_NAME_KEY = QStringLiteral("display-name");
338
339 // Metadata values
340
341=== added file 'src/helper/restore-helper.cpp'
342--- src/helper/restore-helper.cpp 1970-01-01 00:00:00 +0000
343+++ src/helper/restore-helper.cpp 2016-11-17 00:23:33 +0000
344@@ -0,0 +1,378 @@
345+/*
346+ * Copyright (C) 2016 Canonical, Ltd.
347+ *
348+ * This program is free software: you can redistribute it and/or modify it
349+ * under the terms of the GNU General Public License version 3, as published
350+ * by the Free Software Foundation.
351+ *
352+ * This program is distributed in the hope that it will be useful, but
353+ * WITHOUT ANY WARRANTY; without even the implied warranties of
354+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
355+ * PURPOSE. See the GNU General Public License for more details.
356+ *
357+ * You should have received a copy of the GNU General Public License along
358+ * with this program. If not, see <http://www.gnu.org/licenses/>.
359+ *
360+ * Authors:
361+ * Xavi Garcia <xavi.garcia.mena@canonical.com>
362+ * Charles Kerr <charles.kerr@canonical.com>
363+ */
364+
365+#include "util/connection-helper.h"
366+#include "helper/restore-helper.h"
367+#include "service/app-const.h" // HELPER_TYPE
368+
369+#include <QByteArray>
370+#include <QDebug>
371+#include <QLocalSocket>
372+#include <QMap>
373+#include <QObject>
374+#include <QString>
375+#include <QTimer>
376+#include <QVector>
377+#include <QCryptographicHash>
378+
379+#include <fcntl.h>
380+#include <sys/types.h>
381+#include <sys/socket.h>
382+
383+#include <functional> // std::bind()
384+
385+
386+class RestoreHelperPrivate
387+{
388+public:
389+
390+ explicit RestoreHelperPrivate(
391+ RestoreHelper* backup_helper
392+ )
393+ : q_ptr(backup_helper)
394+ {
395+ // listen for inactivity from storage framework
396+ QObject::connect(&timer_, &QTimer::timeout,
397+ std::bind(&RestoreHelperPrivate::on_inactivity_detected, this)
398+ );
399+
400+ // fire up the sockets
401+ int fds[2];
402+ int rc = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds);
403+ if (rc == -1)
404+ {
405+ // TODO throw exception.
406+ qWarning() << "RestoreHelperPrivate: error creating socket pair to communicate with helper ";
407+ return;
408+ }
409+
410+ // helper socket is for the client.
411+ helper_socket_.setSocketDescriptor(fds[0], QLocalSocket::ConnectedState, QIODevice::ReadOnly);
412+
413+ write_socket_.setSocketDescriptor(fds[1], QLocalSocket::ConnectedState, QIODevice::WriteOnly);
414+ }
415+
416+ ~RestoreHelperPrivate() = default;
417+
418+ Q_DISABLE_COPY(RestoreHelperPrivate)
419+
420+ void start(QStringList const& urls)
421+ {
422+ q_ptr->Helper::start(urls);
423+ reset_inactivity_timer();
424+ }
425+
426+ void set_downloader(std::shared_ptr<Downloader> const& downloader)
427+ {
428+ qDebug() << "RestoreHelper::set_downloader";
429+ downloader_ = downloader;
430+ n_read_ = 0;
431+ n_uploaded_ = 0;
432+ read_error_ = false;
433+ write_error_ = false;
434+ cancelled_ = false;
435+
436+ q_ptr->set_expected_size(downloader->file_size());
437+
438+ qDebug() << "Storage framework socket is: " << static_cast<void *>(downloader_->socket().get());
439+
440+ // listen for data ready to read
441+ QObject::connect(downloader_->socket().get(), &QLocalSocket::readyRead,
442+ std::bind(&RestoreHelperPrivate::on_ready_read, this)
443+ );
444+
445+ connections_.remember(QObject::connect(
446+ &write_socket_, &QLocalSocket::bytesWritten,
447+ std::bind(&RestoreHelperPrivate::on_data_uploaded, this, std::placeholders::_1)
448+ ));
449+
450+ // maybe there's already readable data
451+ process_more();
452+
453+ reset_inactivity_timer();
454+ }
455+
456+ void stop()
457+ {
458+ write_socket_.disconnectFromServer();
459+ cancelled_ = true;
460+ q_ptr->Helper::stop();
461+ }
462+
463+ int get_helper_socket() const
464+ {
465+ return int(helper_socket_.socketDescriptor());
466+ }
467+
468+ QString to_string(Helper::State state) const
469+ {
470+ return state == Helper::State::STARTED
471+ ? QStringLiteral("restoring")
472+ : q_ptr->Helper::to_string(state);
473+ }
474+
475+ void on_state_changed(Helper::State state)
476+ {
477+ switch (state)
478+ {
479+ case Helper::State::CANCELLED:
480+ case Helper::State::FAILED:
481+ qDebug() << "cancelled/failed, calling downloader_.reset()";
482+ downloader_.reset();
483+ break;
484+
485+ case Helper::State::DATA_COMPLETE: {
486+ qDebug() << "Restore helper finished, calling downloader_.finish()";
487+ write_socket_.disconnectFromServer();
488+ downloader_->finish();
489+ downloader_.reset();
490+ break;
491+ }
492+
493+ //case Helper::State::NOT_STARTED:
494+ //case Helper::State::STARTED:
495+ default:
496+ break;
497+ }
498+ }
499+
500+ void on_helper_finished()
501+ {
502+ stop_inactivity_timer();
503+ check_for_done();
504+ }
505+
506+private:
507+
508+ void on_inactivity_detected()
509+ {
510+ stop_inactivity_timer();
511+ qWarning() << "Inactivity detected in the helper...stopping it";
512+ stop();
513+ }
514+
515+ void on_ready_read()
516+ {
517+ process_more();
518+ }
519+
520+ void on_data_uploaded(qint64 n)
521+ {
522+ n_uploaded_ += n;
523+ q_ptr->record_data_transferred(n);
524+ qDebug("n_read %zu n_uploaded %zu (newly uploaded %zu)", size_t(n_read_), size_t(n_uploaded_), size_t(n));
525+ process_more();
526+ check_for_done();
527+ }
528+
529+ void process_more()
530+ {
531+ qDebug() << Q_FUNC_INFO;
532+
533+ if (!downloader_)
534+ return;
535+
536+ qDebug() << Q_FUNC_INFO << "2";
537+
538+ char readbuf[UPLOAD_BUFFER_MAX_];
539+ auto socket = downloader_->socket();
540+ for(;;)
541+ {
542+ if (!socket->bytesAvailable())
543+ break;
544+ // try to fill the upload buf
545+ int max_bytes = (UPLOAD_BUFFER_MAX_) - upload_buffer_.size();
546+ if (max_bytes > 0) {
547+ const auto n = socket->read(readbuf, max_bytes);
548+ if (n > 0) {
549+ n_read_ += n;
550+ upload_buffer_.append(readbuf, int(n));
551+ qDebug("buffer_.size() is %zu after reading %zu", size_t(upload_buffer_.size()), size_t(n));
552+ }
553+ else if (n < 0) {
554+ read_error_ = true;
555+ qDebug() << "Read error in" << Q_FUNC_INFO << ":" << socket->errorString();
556+ stop();
557+ return;
558+ }
559+ }
560+
561+ // THIS IS JUST FOR EXTRA DEBUG INFORMATION
562+ QCryptographicHash hash(QCryptographicHash::Sha1);
563+ hash.addData(upload_buffer_.left(100));
564+ qDebug() << "************************************************ Hash send: " << hash.result().toHex() << " Size: " << upload_buffer_.size() << " Total: " << n_read_;
565+ // THIS IS JUST FOR EXTRA DEBUG INFORMATION
566+
567+ // try to empty the upload buf
568+ const auto n = write_socket_.write(upload_buffer_);
569+ if (n > 0) {
570+ upload_buffer_.remove(0, int(n));
571+ qDebug("buffer_.size() is %zu after writing %zu", size_t(upload_buffer_.size()), size_t(n));
572+ continue;
573+ }
574+ else {
575+ if (n < 0) {
576+ write_error_ = true;
577+ qWarning() << "Write error:" << write_socket_.errorString();
578+ stop();
579+ }
580+ break;
581+ }
582+ }
583+
584+ reset_inactivity_timer();
585+ }
586+
587+ void reset_inactivity_timer()
588+ {
589+ static constexpr int MAX_TIME_WAITING_FOR_DATA {RestoreHelper::MAX_INACTIVITY_TIME};
590+ timer_.start(MAX_TIME_WAITING_FOR_DATA);
591+ }
592+
593+ void stop_inactivity_timer()
594+ {
595+ timer_.stop();
596+ }
597+
598+ void check_for_done()
599+ {
600+ qDebug() << "Checking for done.";
601+ if (cancelled_)
602+ {
603+ q_ptr->set_state(Helper::State::CANCELLED);
604+ }
605+ else if (read_error_ || write_error_ || n_uploaded_ > q_ptr->expected_size())
606+ {
607+ if (!q_ptr->is_helper_running())
608+ {
609+ q_ptr->set_state(Helper::State::FAILED);
610+ }
611+ }
612+ else if (n_uploaded_ == q_ptr->expected_size())
613+ {
614+ if (downloader_)
615+ {
616+ if (q_ptr->is_helper_running())
617+ {
618+ // only in the case that the helper process finished we move to the next state
619+ // this is to prevent to start the next task too early
620+ q_ptr->set_state(Helper::State::DATA_COMPLETE);
621+ stop_inactivity_timer();
622+ }
623+ }
624+ else
625+ q_ptr->set_state(Helper::State::COMPLETE);
626+ }
627+ }
628+
629+ /***
630+ ****
631+ ***/
632+
633+ static constexpr int UPLOAD_BUFFER_MAX_ {1024*16};
634+
635+ RestoreHelper * const q_ptr;
636+ QTimer timer_;
637+ std::shared_ptr<Downloader> downloader_;
638+ QLocalSocket helper_socket_;
639+ QLocalSocket write_socket_;
640+ QByteArray upload_buffer_;
641+ qint64 n_read_ = 0;
642+ qint64 n_uploaded_ = 0;
643+ bool read_error_ = false;
644+ bool write_error_ = false;
645+ bool cancelled_ = false;
646+ ConnectionHelper connections_;
647+ QString uploader_committed_file_name_;
648+};
649+
650+/***
651+****
652+***/
653+
654+RestoreHelper::RestoreHelper(
655+ QString const & appid,
656+ clock_func const & clock,
657+ QObject * parent
658+)
659+ : Helper(appid, clock, parent)
660+ , d_ptr(new RestoreHelperPrivate(this))
661+{
662+}
663+
664+RestoreHelper::~RestoreHelper() =default;
665+
666+void
667+RestoreHelper::start(QStringList const& url)
668+{
669+ Q_D(RestoreHelper);
670+
671+ d->start(url);
672+}
673+
674+void
675+RestoreHelper::stop()
676+{
677+ Q_D(RestoreHelper);
678+
679+ d->stop();
680+}
681+
682+void
683+RestoreHelper::set_downloader(std::shared_ptr<Downloader> const& downloader)
684+{
685+ Q_D(RestoreHelper);
686+
687+ d->set_downloader(downloader);
688+}
689+
690+int
691+RestoreHelper::get_helper_socket() const
692+{
693+ Q_D(const RestoreHelper);
694+
695+ return d->get_helper_socket();
696+}
697+
698+QString
699+RestoreHelper::to_string(Helper::State state) const
700+{
701+ Q_D(const RestoreHelper);
702+
703+ return d->to_string(state);
704+}
705+
706+void
707+RestoreHelper::set_state(Helper::State state)
708+{
709+ Q_D(RestoreHelper);
710+
711+ qDebug() << Q_FUNC_INFO;
712+ Helper::set_state(state);
713+ d->on_state_changed(state);
714+}
715+
716+void RestoreHelper::on_helper_finished()
717+{
718+ Q_D(RestoreHelper);
719+
720+ Helper::on_helper_finished();
721+ d->on_helper_finished();
722+}
723
724=== modified file 'src/service/CMakeLists.txt'
725--- src/service/CMakeLists.txt 2016-10-28 15:11:21 +0000
726+++ src/service/CMakeLists.txt 2016-11-17 00:23:33 +0000
727@@ -15,6 +15,7 @@
728 task-manager.cpp
729 keeper-task.cpp
730 keeper-task-backup.cpp
731+ keeper-task-restore.cpp
732 manifest.cpp
733 metadata-provider.h
734 )
735
736=== modified file 'src/service/keeper-helper.cpp'
737--- src/service/keeper-helper.cpp 2016-08-10 02:06:08 +0000
738+++ src/service/keeper-helper.cpp 2016-11-17 00:23:33 +0000
739@@ -44,8 +44,11 @@
740
741 QDBusUnixFileDescriptor KeeperHelper::StartRestore()
742 {
743- // TODO get the file descriptor of the item in storage framework
744- return QDBusUnixFileDescriptor();
745+ // pass it back to Keeper to do the work
746+ Q_ASSERT(calledFromDBus());
747+ auto bus = connection();
748+ auto& msg = message();
749+ return keeper_.StartRestore(bus, msg);
750 }
751
752 void KeeperHelper::UpdateStatus(const QString &app_id, const QString &status, double percentage)
753
754=== modified file 'src/service/keeper-task-backup.cpp'
755--- src/service/keeper-task-backup.cpp 2016-10-06 14:53:44 +0000
756+++ src/service/keeper-task-backup.cpp 2016-11-17 00:23:33 +0000
757@@ -31,7 +31,7 @@
758 Q_DECLARE_PUBLIC(KeeperTaskBackup)
759 public:
760 KeeperTaskBackupPrivate(KeeperTask * keeper_task,
761- KeeperTask::TaskData const & task_data,
762+ KeeperTask::TaskData & task_data,
763 QSharedPointer<HelperRegistry> const & helper_registry,
764 QSharedPointer<StorageFrameworkClient> const & storage)
765 : KeeperTaskPrivate(keeper_task, task_data, helper_registry, storage)
766@@ -90,7 +90,7 @@
767 QString file_name_;
768 };
769
770-KeeperTaskBackup::KeeperTaskBackup(TaskData const & task_data,
771+KeeperTaskBackup::KeeperTaskBackup(TaskData & task_data,
772 QSharedPointer<HelperRegistry> const & helper_registry,
773 QSharedPointer<StorageFrameworkClient> const & storage,
774 QObject *parent)
775
776=== modified file 'src/service/keeper-task-backup.h'
777--- src/service/keeper-task-backup.h 2016-10-06 14:53:44 +0000
778+++ src/service/keeper-task-backup.h 2016-11-17 00:23:33 +0000
779@@ -29,7 +29,7 @@
780 Q_DECLARE_PRIVATE(KeeperTaskBackup)
781 public:
782
783- KeeperTaskBackup(TaskData const & task_data,
784+ KeeperTaskBackup(TaskData & task_data,
785 QSharedPointer<HelperRegistry> const & helper_registry,
786 QSharedPointer<StorageFrameworkClient> const & storage,
787 QObject *parent = nullptr);
788
789=== added file 'src/service/keeper-task-restore.cpp'
790--- src/service/keeper-task-restore.cpp 1970-01-01 00:00:00 +0000
791+++ src/service/keeper-task-restore.cpp 2016-11-17 00:23:33 +0000
792@@ -0,0 +1,129 @@
793+/*
794+ * Copyright (C) 2016 Canonical, Ltd.
795+ *
796+ * This program is free software: you can redistribute it and/or modify it
797+ * under the terms of the GNU General Public License version 3, as published
798+ * by the Free Software Foundation.
799+ *
800+ * This program is distributed in the hope that it will be useful, but
801+ * WITHOUT ANY WARRANTY; without even the implied warranties of
802+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
803+ * PURPOSE. See the GNU General Public License for more details.
804+ *
805+ * You should have received a copy of the GNU General Public License along
806+ * with this program. If not, see <http://www.gnu.org/licenses/>.
807+ *
808+ * Authors:
809+ * Xavi Garcia <xavi.garcia.mena@canonical.com>
810+ * Charles Kerr <charles.kerr@canonical.com>
811+ */
812+
813+#include "util/connection-helper.h"
814+#include "storage-framework/storage_framework_client.h"
815+#include "helper/restore-helper.h"
816+#include "service/app-const.h" // DEKKO_APP_ID
817+#include "service/keeper-task-restore.h"
818+#include "service/keeper-task.h"
819+#include "service/private/keeper-task_p.h"
820+
821+namespace sf = unity::storage::qt::client;
822+
823+class KeeperTaskRestorePrivate : public KeeperTaskPrivate
824+{
825+ Q_DECLARE_PUBLIC(KeeperTaskRestore)
826+public:
827+ KeeperTaskRestorePrivate(KeeperTask * keeper_task,
828+ KeeperTask::TaskData & task_data,
829+ QSharedPointer<HelperRegistry> const & helper_registry,
830+ QSharedPointer<StorageFrameworkClient> const & storage)
831+ : KeeperTaskPrivate(keeper_task, task_data, helper_registry, storage)
832+ {
833+ }
834+
835+ ~KeeperTaskRestorePrivate() = default;
836+
837+ QStringList get_helper_urls() const
838+ {
839+ return helper_registry_->get_restore_helper_urls(task_data_.metadata);
840+ }
841+
842+ void init_helper()
843+ {
844+ qDebug() << Q_FUNC_INFO;
845+ helper_.reset(new RestoreHelper(DEKKO_APP_ID), [](Helper *h){h->deleteLater();}); // TODO change this to a restore helper
846+ qDebug() << "Helper " << static_cast<void*>(helper_.data()) << " was created";
847+ }
848+
849+ void ask_for_downloader()
850+ {
851+ qDebug() << "asking storage framework for a socket for reading";
852+
853+ QString file_name;
854+ task_data_.metadata.get_property(Metadata::FILE_NAME_KEY, file_name);
855+ if (file_name.isEmpty())
856+ {
857+ qWarning() << "ERROR: the restore task does not provide a valid file name to read from.";
858+ return;
859+ }
860+
861+ QString dir_name;
862+ task_data_.metadata.get_property(Metadata::DIR_NAME_KEY, dir_name);
863+ if (dir_name.isEmpty())
864+ {
865+ qWarning() << "ERROR: the restore task does not provide a valid directory name.";
866+ return;
867+ }
868+
869+ // extract the dir_name.
870+ connections_.connect_future(
871+ storage_->get_new_downloader(dir_name, file_name),
872+ std::function<void(std::shared_ptr<Downloader> const&)>{
873+ [this](std::shared_ptr<Downloader> const& downloader){
874+ qDebug() << "Downloader is" << static_cast<void*>(downloader.get());
875+ int fd {-1};
876+ if (downloader) {
877+ qDebug() << "Helper is " << static_cast<void*>(helper_.data());
878+ auto restore_helper = qSharedPointerDynamicCast<RestoreHelper>(helper_);
879+ restore_helper->set_downloader(downloader);
880+ fd = restore_helper->get_helper_socket();
881+ }
882+ qDebug("emitting task_socket_ready(socket=%d)", fd);
883+ Q_EMIT(q_ptr->task_socket_ready(fd));
884+ }
885+ }
886+ );
887+ }
888+private:
889+ ConnectionHelper connections_;
890+};
891+
892+KeeperTaskRestore::KeeperTaskRestore(TaskData & task_data,
893+ QSharedPointer<HelperRegistry> const & helper_registry,
894+ QSharedPointer<StorageFrameworkClient> const & storage,
895+ QObject *parent)
896+ : KeeperTask(*new KeeperTaskRestorePrivate(this, task_data, helper_registry, storage), parent)
897+{
898+}
899+
900+KeeperTaskRestore::~KeeperTaskRestore() = default;
901+
902+QStringList KeeperTaskRestore::get_helper_urls() const
903+{
904+ Q_D(const KeeperTaskRestore);
905+
906+ return d->get_helper_urls();
907+}
908+
909+void KeeperTaskRestore::init_helper()
910+{
911+ Q_D(KeeperTaskRestore);
912+
913+ d->init_helper();
914+}
915+
916+void KeeperTaskRestore::ask_for_downloader()
917+{
918+ Q_D(KeeperTaskRestore);
919+
920+ d->ask_for_downloader();
921+}
922
923=== added file 'src/service/keeper-task-restore.h'
924--- src/service/keeper-task-restore.h 1970-01-01 00:00:00 +0000
925+++ src/service/keeper-task-restore.h 2016-11-17 00:23:33 +0000
926@@ -0,0 +1,46 @@
927+/*
928+ * Copyright (C) 2016 Canonical, Ltd.
929+ *
930+ * This program is free software: you can redistribute it and/or modify it
931+ * under the terms of the GNU General Public License version 3, as published
932+ * by the Free Software Foundation.
933+ *
934+ * This program is distributed in the hope that it will be useful, but
935+ * WITHOUT ANY WARRANTY; without even the implied warranties of
936+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
937+ * PURPOSE. See the GNU General Public License for more details.
938+ *
939+ * You should have received a copy of the GNU General Public License along
940+ * with this program. If not, see <http://www.gnu.org/licenses/>.
941+ *
942+ * Authors:
943+ * Xavi Garcia <xavi.garcia.mena@canonical.com>
944+ * Charles Kerr <charles.kerr@canonical.com>
945+ */
946+#pragma once
947+
948+#include "keeper-task.h"
949+
950+class KeeperTaskRestorePrivate;
951+
952+class KeeperTaskRestore : public KeeperTask
953+{
954+ Q_OBJECT
955+ Q_DECLARE_PRIVATE(KeeperTaskRestore)
956+
957+public:
958+ KeeperTaskRestore(TaskData & task_data,
959+ QSharedPointer<HelperRegistry> const & helper_registry,
960+ QSharedPointer<StorageFrameworkClient> const & storage,
961+ QObject *parent = nullptr);
962+ virtual ~KeeperTaskRestore();
963+
964+ Q_DISABLE_COPY(KeeperTaskRestore)
965+
966+ void ask_for_downloader();
967+
968+protected:
969+ QStringList get_helper_urls() const override;
970+ void init_helper() override;
971+
972+};
973
974=== modified file 'src/service/keeper-task.cpp'
975--- src/service/keeper-task.cpp 2016-09-30 09:23:09 +0000
976+++ src/service/keeper-task.cpp 2016-11-17 00:23:33 +0000
977@@ -28,7 +28,7 @@
978 #include <QString>
979
980 KeeperTaskPrivate::KeeperTaskPrivate(KeeperTask * keeper_task,
981- KeeperTask::TaskData const & task_data,
982+ KeeperTask::TaskData & task_data,
983 QSharedPointer<HelperRegistry> const & helper_registry,
984 QSharedPointer<StorageFrameworkClient> const & storage)
985 : q_ptr(keeper_task)
986@@ -132,7 +132,7 @@
987 auto const percent_done = helper_->percent_done();
988 ret.insert(QStringLiteral("percent-done"), double(percent_done));
989
990- if (task_data_.action == "failed")
991+ if (task_data_.action == "failed" || task_data_.action == "cancelled")
992 ret.insert(QStringLiteral("error"), task_data_.error);
993
994 ret.insert(QStringLiteral("uuid"), uuid);
995@@ -145,8 +145,13 @@
996
997 void KeeperTaskPrivate::calculate_and_notify_state(Helper::State state)
998 {
999+ recalculate_task_state();
1000+ Q_EMIT(q_ptr->task_state_changed(state));
1001+}
1002+
1003+void KeeperTaskPrivate::recalculate_task_state()
1004+{
1005 state_ = calculate_task_state();
1006- Q_EMIT(q_ptr->task_state_changed(state));
1007 }
1008
1009 void KeeperTaskPrivate::cancel()
1010@@ -175,7 +180,20 @@
1011 return ret;
1012 }
1013
1014-KeeperTask::KeeperTask(TaskData const & task_data,
1015+QString KeeperTaskPrivate::to_string(Helper::State state)
1016+{
1017+ if (helper_)
1018+ {
1019+ return helper_->to_string(state);
1020+ }
1021+ else
1022+ {
1023+ qWarning() << "Asking for the string of a state when the helper is not initialized yet";
1024+ return "bug";
1025+ }
1026+}
1027+
1028+KeeperTask::KeeperTask(TaskData & task_data,
1029 QSharedPointer<HelperRegistry> const & helper_registry,
1030 QSharedPointer<StorageFrameworkClient> const & storage,
1031 QObject *parent)
1032@@ -207,6 +225,14 @@
1033 return d->state();
1034 }
1035
1036+void KeeperTask::recalculate_task_state()
1037+{
1038+ Q_D(KeeperTask);
1039+
1040+ return d->recalculate_task_state();
1041+}
1042+
1043+
1044 QVariantMap KeeperTask::get_initial_state(KeeperTask::TaskData const &td)
1045 {
1046 return KeeperTaskPrivate::get_initial_state(td);
1047@@ -218,3 +244,10 @@
1048
1049 return d->cancel();
1050 }
1051+
1052+QString KeeperTask::to_string(Helper::State state)
1053+{
1054+ Q_D(KeeperTask);
1055+
1056+ return d->to_string(state);
1057+}
1058
1059=== modified file 'src/service/keeper-task.h'
1060--- src/service/keeper-task.h 2016-09-28 13:42:21 +0000
1061+++ src/service/keeper-task.h 2016-11-17 00:23:33 +0000
1062@@ -44,7 +44,7 @@
1063 Metadata metadata;
1064 };
1065
1066- KeeperTask(TaskData const & task_data,
1067+ KeeperTask(TaskData & task_data,
1068 QSharedPointer<HelperRegistry> const & helper_registry,
1069 QSharedPointer<StorageFrameworkClient> const & storage,
1070 QObject *parent = nullptr);
1071@@ -54,11 +54,13 @@
1072
1073 bool start();
1074 QVariantMap state() const;
1075+ void recalculate_task_state();
1076
1077 static QVariantMap get_initial_state(KeeperTask::TaskData const &td);
1078
1079 void cancel();
1080
1081+ QString to_string(Helper::State state);
1082 Q_SIGNALS:
1083 void task_state_changed(Helper::State state);
1084 void task_socket_ready(int socket_descriptor);
1085
1086=== modified file 'src/service/keeper-user.cpp'
1087--- src/service/keeper-user.cpp 2016-10-28 15:11:21 +0000
1088+++ src/service/keeper-user.cpp 2016-11-17 00:23:33 +0000
1089@@ -70,9 +70,11 @@
1090 void
1091 KeeperUser::StartRestore (const QStringList& keys)
1092 {
1093- // FIXME: writeme
1094+ Q_ASSERT(calledFromDBus());
1095
1096- qDebug() << keys;
1097+ auto bus = connection();
1098+ auto& msg = message();
1099+ keeper_.start_tasks(keys, bus, msg, true);
1100 }
1101
1102 QVariantDictMap
1103
1104=== modified file 'src/service/keeper.cpp'
1105--- src/service/keeper.cpp 2016-10-28 15:11:21 +0000
1106+++ src/service/keeper.cpp 2016-11-17 00:23:33 +0000
1107@@ -76,14 +76,25 @@
1108 {
1109 }
1110
1111+ enum class ChoicesType { BACKUP_CHOICES, RESTORES_CHOICES };
1112+
1113 ~KeeperPrivate() =default;
1114
1115 Q_DISABLE_COPY(KeeperPrivate)
1116
1117 void start_tasks(QStringList const & uuids,
1118- QDBusConnection bus,
1119- QDBusMessage const & msg)
1120+ QDBusConnection bus,
1121+ QDBusMessage const & msg,
1122+ bool reset_cached_choices)
1123 {
1124+ if (reset_cached_choices)
1125+ {
1126+ // if we start a restore right after a backup the uuid
1127+ // will be found as a backup uuid.
1128+ // Just clear the backup cache to avoid that.
1129+ cached_backup_choices_.clear();
1130+ }
1131+
1132 auto get_tasks = [](const QVector<Metadata>& pool, QStringList const& keys){
1133 QMap<QString,Metadata> tasks;
1134 for (auto const& key : keys) {
1135@@ -95,9 +106,10 @@
1136 };
1137
1138 // async part
1139+ qDebug() << "Looking for backup options....";
1140 connections_.connect_oneshot(
1141 this,
1142- &KeeperPrivate::choices_ready,
1143+ &KeeperPrivate::backup_choices_ready,
1144 std::function<void()>{[this, uuids, msg, bus, get_tasks](){
1145 auto tasks = get_tasks(cached_backup_choices_, uuids);
1146 if (!tasks.empty())
1147@@ -114,12 +126,15 @@
1148 }
1149 else // restore
1150 {
1151+ qDebug() << "Looking for restore options....";
1152 connections_.connect_oneshot(
1153 this,
1154- &KeeperPrivate::choices_ready,
1155+ &KeeperPrivate::restore_choices_ready,
1156 std::function<void()>{[this, uuids, msg, bus, get_tasks](){
1157+ qDebug() << "Choices ready";
1158 auto unhandled = QSet<QString>::fromList(uuids);
1159 auto restore_tasks = get_tasks(cached_restore_choices_, uuids);
1160+ qDebug() << "After getting tasks...";
1161 if (!restore_tasks.empty() && task_manager_.start_restore(restore_tasks.values()))
1162 unhandled.subtract(QSet<QString>::fromList(restore_tasks.keys()));
1163
1164@@ -130,34 +145,58 @@
1165 bus.send(reply);
1166 }}
1167 );
1168- get_restore_choices();
1169+ get_choices(restore_choices_, KeeperPrivate::ChoicesType::RESTORES_CHOICES);
1170 }
1171 }}
1172 );
1173
1174- get_backup_choices();
1175+ get_choices(backup_choices_, KeeperPrivate::ChoicesType::BACKUP_CHOICES);
1176 msg.setDelayedReply(true);
1177 }
1178
1179- void get_backup_choices()
1180- {
1181- if (cached_backup_choices_.isEmpty())
1182+ void emit_choices_ready(ChoicesType type)
1183+ {
1184+ switch(type)
1185+ {
1186+ case KeeperPrivate::ChoicesType::BACKUP_CHOICES:
1187+ Q_EMIT(backup_choices_ready());
1188+ break;
1189+ case KeeperPrivate::ChoicesType::RESTORES_CHOICES:
1190+ Q_EMIT(restore_choices_ready());
1191+ break;
1192+ }
1193+ }
1194+ void get_choices(const QSharedPointer<MetadataProvider> & provider, ChoicesType type)
1195+ {
1196+ qDebug() << Q_FUNC_INFO;
1197+ bool check_empty = (type == KeeperPrivate::ChoicesType::BACKUP_CHOICES)
1198+ ? cached_backup_choices_.isEmpty() : cached_restore_choices_.isEmpty();
1199+ if (check_empty)
1200 {
1201 connections_.connect_oneshot(
1202- backup_choices_.data(),
1203+ provider.data(),
1204 &MetadataProvider::finished,
1205- std::function<void()>{[this](){
1206- qDebug() << "Get backups finished";
1207- cached_backup_choices_ = backup_choices_->get_backups();
1208- Q_EMIT(choices_ready());
1209+ std::function<void()>{[this, provider, type](){
1210+ qDebug() << "Get choices finished";
1211+ switch (type)
1212+ {
1213+ case KeeperPrivate::ChoicesType::BACKUP_CHOICES:
1214+ cached_backup_choices_ = provider->get_backups();
1215+ break;
1216+ case KeeperPrivate::ChoicesType::RESTORES_CHOICES:
1217+ cached_restore_choices_ = provider->get_backups();
1218+ break;
1219+ };
1220+ emit_choices_ready(type);
1221 }}
1222 );
1223
1224- backup_choices_->get_backups_async();
1225+ provider->get_backups_async();
1226 }
1227 else
1228 {
1229- Q_EMIT(choices_ready());
1230+ qDebug() << "emit choices_ready()";
1231+ emit_choices_ready(type);
1232 }
1233 }
1234
1235@@ -166,7 +205,7 @@
1236 {
1237 connections_.connect_oneshot(
1238 this,
1239- &KeeperPrivate::choices_ready,
1240+ &KeeperPrivate::backup_choices_ready,
1241 std::function<void()>{[this, msg, bus](){
1242 qDebug() << "Backup choices are ready";
1243 // reply now to the dbus call
1244@@ -176,7 +215,7 @@
1245 }}
1246 );
1247
1248- get_backup_choices();
1249+ get_choices(backup_choices_, KeeperPrivate::ChoicesType::BACKUP_CHOICES);
1250 msg.setDelayedReply(true);
1251 return QVariantDictMap();
1252 }
1253@@ -186,7 +225,7 @@
1254 {
1255 connections_.connect_oneshot(
1256 this,
1257- &KeeperPrivate::choices_ready,
1258+ &KeeperPrivate::restore_choices_ready,
1259 std::function<void()>{[this, msg, bus](){
1260 qDebug() << "Restore choices are ready";
1261 // reply now to the dbus call
1262@@ -196,34 +235,11 @@
1263 }}
1264 );
1265
1266- get_restore_choices();
1267+ get_choices(restore_choices_, KeeperPrivate::ChoicesType::RESTORES_CHOICES);
1268 msg.setDelayedReply(true);
1269 return QVariantDictMap();
1270 }
1271
1272- // TODO REFACTOR THIS TO USE THE SAME METHOD POR RESTORES AND BACKUPS
1273- void get_restore_choices()
1274- {
1275- if (cached_restore_choices_.isEmpty())
1276- {
1277- connections_.connect_oneshot(
1278- restore_choices_.data(),
1279- &MetadataProvider::finished,
1280- std::function<void()>{[this](){
1281- qDebug() << "Get restores finished";
1282- cached_restore_choices_ = restore_choices_->get_backups();
1283- Q_EMIT(choices_ready());
1284- }}
1285- );
1286-
1287- restore_choices_->get_backups_async();
1288- }
1289- else
1290- {
1291- Q_EMIT(choices_ready());
1292- }
1293- }
1294-
1295 QVariantDictMap get_state() const
1296 {
1297 return task_manager_.get_state();
1298@@ -233,7 +249,7 @@
1299 QDBusMessage const & msg,
1300 quint64 n_bytes)
1301 {
1302- qDebug("Keeper::StartBackup(n_bytes=%zu)", size_t(n_bytes));
1303+ qDebug() << Q_FUNC_INFO << "n_bytes:" << n_bytes;
1304
1305 connections_.connect_oneshot(
1306 &task_manager_,
1307@@ -248,7 +264,7 @@
1308 }
1309 );
1310
1311- qDebug() << "Asking for an storage framework socket to the task manager";
1312+ qDebug() << "Asking TaskManager for a socket to upload to";
1313 task_manager_.ask_for_uploader(n_bytes);
1314
1315 // tell the caller that we'll be responding async
1316@@ -256,12 +272,41 @@
1317 return QDBusUnixFileDescriptor(0);
1318 }
1319
1320+
1321+ QDBusUnixFileDescriptor start_restore(QDBusConnection bus,
1322+ QDBusMessage const & msg)
1323+ {
1324+ qDebug() << Q_FUNC_INFO;
1325+
1326+ connections_.connect_oneshot(
1327+ &task_manager_,
1328+ &TaskManager::socket_ready,
1329+ std::function<void(int)>{
1330+ [bus,msg](int fd){
1331+ qDebug("TaskManager::ask_for_downloader() returned socket %d", fd);
1332+ auto reply = msg.createReply();
1333+ reply << QVariant::fromValue(QDBusUnixFileDescriptor(fd));
1334+ bus.send(reply);
1335+ }
1336+ }
1337+ );
1338+
1339+ qDebug() << "Asking TaskManager for a socket to download from";
1340+ task_manager_.ask_for_downloader();
1341+
1342+ // tell the caller that we'll be responding async
1343+ msg.setDelayedReply(true);
1344+ return QDBusUnixFileDescriptor(0);
1345+ }
1346+
1347 void cancel()
1348 {
1349 task_manager_.cancel();
1350 }
1351+
1352 Q_SIGNALS:
1353- void choices_ready();
1354+ void backup_choices_ready();
1355+ void restore_choices_ready();
1356
1357 private:
1358
1359@@ -305,11 +350,12 @@
1360 void
1361 Keeper::start_tasks(QStringList const & uuids,
1362 QDBusConnection bus,
1363- QDBusMessage const & msg)
1364+ QDBusMessage const & msg,
1365+ bool reset_cached_choices)
1366 {
1367 Q_D(Keeper);
1368
1369- d->start_tasks(uuids, bus, msg);
1370+ d->start_tasks(uuids, bus, msg, reset_cached_choices);
1371 }
1372
1373 QDBusUnixFileDescriptor
1374@@ -322,6 +368,15 @@
1375 return d->start_backup(bus, msg, n_bytes);
1376 }
1377
1378+QDBusUnixFileDescriptor
1379+Keeper::StartRestore(QDBusConnection bus,
1380+ QDBusMessage const & msg)
1381+{
1382+ Q_D(Keeper);
1383+
1384+ return d->start_restore(bus, msg);
1385+}
1386+
1387 QVariantDictMap
1388 Keeper::get_backup_choices_var_dict_map(QDBusConnection bus,
1389 QDBusMessage const & msg)
1390
1391=== modified file 'src/service/keeper.h'
1392--- src/service/keeper.h 2016-10-28 15:11:21 +0000
1393+++ src/service/keeper.h 2016-11-17 00:23:33 +0000
1394@@ -59,9 +59,14 @@
1395 QDBusMessage const & message,
1396 quint64 nbytes);
1397
1398+
1399+ QDBusUnixFileDescriptor StartRestore(QDBusConnection,
1400+ QDBusMessage const & message);
1401+
1402 void start_tasks(QStringList const & uuids,
1403 QDBusConnection bus,
1404- QDBusMessage const & msg);
1405+ QDBusMessage const & msg,
1406+ bool reset_cached_choices = false);
1407
1408 QVariantDictMap get_state() const;
1409
1410
1411=== modified file 'src/service/manifest.cpp'
1412--- src/service/manifest.cpp 2016-10-13 12:22:31 +0000
1413+++ src/service/manifest.cpp 2016-11-17 00:23:33 +0000
1414@@ -110,8 +110,8 @@
1415 {
1416 connections_.connect_future(
1417 storage_->get_new_downloader(dir_, MANIFEST_FILE_NAME),
1418- std::function<void(sf::Downloader::SPtr const&)>{
1419- [this](sf::Downloader::SPtr const& downloader){
1420+ std::function<void(std::shared_ptr<Downloader> const&)>{
1421+ [this](std::shared_ptr<Downloader> const& downloader){
1422 qDebug() << "Manifest downloader is" << static_cast<void*>(downloader.get());
1423 if (downloader)
1424 {
1425@@ -125,7 +125,7 @@
1426 }
1427 auto json_content = socket->readAll();
1428 from_json(json_content);
1429- downloader->finish_download();
1430+ downloader->finish();
1431 finish();
1432 }
1433 else
1434
1435=== modified file 'src/service/private/keeper-task_p.h'
1436--- src/service/private/keeper-task_p.h 2016-09-28 13:42:21 +0000
1437+++ src/service/private/keeper-task_p.h 2016-11-17 00:23:33 +0000
1438@@ -26,7 +26,7 @@
1439 Q_DECLARE_PUBLIC(KeeperTask)
1440 public:
1441 KeeperTaskPrivate(KeeperTask * keeper_task,
1442- KeeperTask::TaskData const & task_data,
1443+ KeeperTask::TaskData & task_data,
1444 QSharedPointer<HelperRegistry> const & helper_registry,
1445 QSharedPointer<StorageFrameworkClient> const & storage);
1446
1447@@ -40,17 +40,19 @@
1448
1449 static QVariantMap get_initial_state(KeeperTask::TaskData const &td);
1450
1451+ QString to_string(Helper::State state);
1452 protected:
1453 void set_current_task_action(QString const& action);
1454 void on_helper_percent_done_changed(float percent_done);
1455 QVariantMap calculate_task_state();
1456 void calculate_and_notify_state(Helper::State state);
1457+ void recalculate_task_state();
1458 void on_backup_socket_ready(std::shared_ptr<QLocalSocket> const & sf_socket);
1459
1460 virtual void on_helper_state_changed(Helper::State state);
1461
1462 KeeperTask * const q_ptr;
1463- KeeperTask::TaskData task_data_;
1464+ KeeperTask::TaskData & task_data_;
1465 QSharedPointer<HelperRegistry> helper_registry_;
1466 QSharedPointer<StorageFrameworkClient> storage_;
1467 QSharedPointer<Helper> helper_;
1468
1469=== modified file 'src/service/task-manager.cpp'
1470--- src/service/task-manager.cpp 2016-11-03 10:32:49 +0000
1471+++ src/service/task-manager.cpp 2016-11-17 00:23:33 +0000
1472@@ -20,6 +20,7 @@
1473
1474 #include "helper/metadata.h"
1475 #include "keeper-task-backup.h"
1476+#include "keeper-task-restore.h"
1477 #include "manifest.h"
1478 #include "storage-framework/storage_framework_client.h"
1479 #include "task-manager.h"
1480@@ -50,6 +51,7 @@
1481
1482 bool start_restore(QList<Metadata> const& tasks)
1483 {
1484+ qDebug() << "Starting restore...";
1485 return start_tasks(tasks, Mode::RESTORE);
1486 }
1487
1488@@ -78,6 +80,23 @@
1489 }
1490 }
1491
1492+ void ask_for_downloader()
1493+ {
1494+ qDebug() << Q_FUNC_INFO;
1495+
1496+ if (task_)
1497+ {
1498+ auto restore_task_ = qSharedPointerDynamicCast<KeeperTaskRestore>(task_);
1499+ if (!restore_task_)
1500+ {
1501+ qWarning() << "Only restore tasks are allowed to ask for storage framework downloaders";
1502+ // TODO Mark this as an error at the current task and move to the next task
1503+ return;
1504+ }
1505+ restore_task_->ask_for_downloader();
1506+ }
1507+ }
1508+
1509 void cancel()
1510 {
1511 if (task_)
1512@@ -140,19 +159,40 @@
1513 return success;
1514 }
1515
1516+ void manifest_stored(bool success)
1517+ {
1518+ qDebug() << "Manifest upload finished success = " << success << " current task=" << current_task_;
1519+ auto& td = task_data_[current_task_];
1520+ if (success)
1521+ {
1522+ update_task_state(td);
1523+ }
1524+ else
1525+ {
1526+ td.error = "Error storing manifest file";
1527+ set_current_task_action(task_->to_string(Helper::State::FAILED));
1528+ }
1529+ active_manifest_.reset();
1530+ }
1531+
1532 void on_helper_state_changed(Helper::State state)
1533 {
1534- qDebug() << "Task State changed";
1535+ auto backup_task_ = qSharedPointerDynamicCast<KeeperTaskBackup>(task_);
1536 auto& td = task_data_[current_task_];
1537 update_task_state(td);
1538
1539+ // for the last completed backup task we delay updating the
1540+ // state until the manifest file is stored
1541+ if (remaining_tasks_.size() || state != Helper::State::COMPLETE)
1542+ update_task_state(td);
1543+
1544 if (state == Helper::State::COMPLETE || state == Helper::State::FAILED)
1545 {
1546- auto backup_task_ = qSharedPointerDynamicCast<KeeperTaskBackup>(task_);
1547 if (backup_task_ && state == Helper::State::COMPLETE && active_manifest_)
1548 {
1549 qDebug() << "Backup task finished. The file created in storage framework is: [" << backup_task_->get_file_name() << "]";
1550 td.metadata.set_property(Metadata::FILE_NAME_KEY, backup_task_->get_file_name());
1551+ td.metadata.set_property(Metadata::DIR_NAME_KEY, backup_dir_name_);
1552 active_manifest_->add_entry(td.metadata);
1553 }
1554 if (remaining_tasks_.size())
1555@@ -162,9 +202,6 @@
1556 }
1557 else
1558 {
1559- // TODO we should revisit this.
1560- // TODO Maybe we could treat the manifest storage as a new task (with a different task type) to check
1561- // TODO when all tasks are finished and prompt something to the user.
1562 if (active_manifest_ && active_manifest_->get_entries().size())
1563 {
1564 qDebug() << "STORING MANIFEST------------";
1565@@ -172,11 +209,7 @@
1566 active_manifest_.data(),
1567 &Manifest::finished,
1568 std::function<void(bool)>{[this](bool success){
1569- if (!success)
1570- qWarning() << "Manifest store finished with error: " << active_manifest_->error();
1571- else
1572- qDebug() << "Manifest store finished successfully";
1573- active_manifest_.reset();
1574+ manifest_stored(success);
1575 }}
1576 );
1577 active_manifest_->store();
1578@@ -203,14 +236,16 @@
1579 qDebug() << "Creating task for uuid = " << uuid;
1580 // initialize a new task
1581
1582- task_.data()->disconnect();
1583+ if (task_)
1584+ task_.data()->disconnect();
1585+
1586 if (mode_ == Mode::BACKUP)
1587 {
1588 task_.reset(new KeeperTaskBackup(td, helper_registry_, storage_));
1589 }
1590 else
1591 {
1592- // TODO initialize a Restore task
1593+ task_.reset(new KeeperTaskRestore(td, helper_registry_, storage_));
1594 }
1595
1596 qDebug() << "task created: " << state_;
1597@@ -311,6 +346,7 @@
1598 {
1599 auto& td = task_data_[current_task_];
1600 td.action = action;
1601+ task_->recalculate_task_state();
1602 update_task_state(td);
1603 }
1604
1605@@ -381,6 +417,13 @@
1606 d->ask_for_uploader(n_bytes);
1607 }
1608
1609+void TaskManager::ask_for_downloader()
1610+{
1611+ Q_D(TaskManager);
1612+
1613+ d->ask_for_downloader();
1614+}
1615+
1616 void TaskManager::cancel()
1617 {
1618 Q_D(TaskManager);
1619
1620=== modified file 'src/service/task-manager.h'
1621--- src/service/task-manager.h 2016-09-28 13:42:21 +0000
1622+++ src/service/task-manager.h 2016-11-17 00:23:33 +0000
1623@@ -58,6 +58,8 @@
1624
1625 void ask_for_uploader(quint64 n_bytes);
1626
1627+ void ask_for_downloader();
1628+
1629 void cancel();
1630
1631 Q_SIGNALS:
1632
1633=== modified file 'src/storage-framework/CMakeLists.txt'
1634--- src/storage-framework/CMakeLists.txt 2016-09-05 17:24:18 +0000
1635+++ src/storage-framework/CMakeLists.txt 2016-11-17 00:23:33 +0000
1636@@ -11,6 +11,9 @@
1637 uploader.h
1638 sf-uploader.cpp
1639 sf-uploader.h
1640+ downloader.h
1641+ sf-downloader.cpp
1642+ sf-downloader.h
1643 )
1644
1645 set_target_properties(
1646
1647=== added file 'src/storage-framework/downloader.h'
1648--- src/storage-framework/downloader.h 1970-01-01 00:00:00 +0000
1649+++ src/storage-framework/downloader.h 2016-11-17 00:23:33 +0000
1650@@ -0,0 +1,46 @@
1651+/*
1652+ * Copyright (C) 2016 Canonical, Ltd.
1653+ *
1654+ * This program is free software: you can redistribute it and/or modify it
1655+ * under the terms of the GNU General Public License version 3, as published
1656+ * by the Free Software Foundation.
1657+ *
1658+ * This program is distributed in the hope that it will be useful, but
1659+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1660+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1661+ * PURPOSE. See the GNU General Public License for more details.
1662+ *
1663+ * You should have received a copy of the GNU General Public License along
1664+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1665+ *
1666+ * Authors:
1667+ * Charles Kerr <charles.kerr@canonical.com>
1668+ * Xavi Garcia Mena <xavi.garcia.mena@canonical.com>
1669+ */
1670+
1671+#pragma once
1672+
1673+#include <QLocalSocket>
1674+#include <QObject>
1675+
1676+#include <memory>
1677+
1678+class Downloader: public QObject
1679+{
1680+ Q_OBJECT
1681+
1682+public:
1683+
1684+ Q_DISABLE_COPY(Downloader)
1685+
1686+ Downloader(QObject *parent=nullptr): QObject(parent) {}
1687+ virtual ~Downloader() =default;
1688+
1689+ virtual std::shared_ptr<QLocalSocket> socket() =0;
1690+ virtual void finish() =0;
1691+ virtual qint64 file_size() const =0;
1692+
1693+Q_SIGNALS:
1694+
1695+ void download_finished();
1696+};
1697
1698=== added file 'src/storage-framework/sf-downloader.cpp'
1699--- src/storage-framework/sf-downloader.cpp 1970-01-01 00:00:00 +0000
1700+++ src/storage-framework/sf-downloader.cpp 2016-11-17 00:23:33 +0000
1701@@ -0,0 +1,71 @@
1702+/*
1703+ * Copyright (C) 2016 Canonical, Ltd.
1704+ *
1705+ * This program is free software: you can redistribute it and/or modify it
1706+ * under the terms of the GNU General Public License version 3, as published
1707+ * by the Free Software Foundation.
1708+ *
1709+ * This program is distributed in the hope that it will be useful, but
1710+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1711+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1712+ * PURPOSE. See the GNU General Public License for more details.
1713+ *
1714+ * You should have received a copy of the GNU General Public License along
1715+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1716+ *
1717+ * Authors:
1718+ * Charles Kerr <charles.kerr@canonical.com>
1719+ * Xavi Garcia Mena <xavi.garcia.mena@canonical.com>
1720+ */
1721+
1722+#include "storage-framework/sf-downloader.h"
1723+
1724+#include <QFuture>
1725+#include <QFutureWatcher>
1726+
1727+StorageFrameworkDownloader::StorageFrameworkDownloader(
1728+ unity::storage::qt::client::Downloader::SPtr const& downloader,
1729+ qint64 file_size,
1730+ QObject *parent
1731+):
1732+ Downloader(parent),
1733+ downloader_(downloader),
1734+ file_size_(file_size)
1735+{
1736+ qDebug() << "StorageFrameworkDownloader";
1737+}
1738+
1739+std::shared_ptr<QLocalSocket>
1740+StorageFrameworkDownloader::socket()
1741+{
1742+ return downloader_->socket();
1743+}
1744+
1745+void
1746+StorageFrameworkDownloader::finish()
1747+{
1748+ qDebug() << Q_FUNC_INFO << "is finishing";
1749+
1750+// connections_.connect_future(
1751+// uploader_->finish_upload(),
1752+// std::function<void(std::shared_ptr<unity::storage::qt::client::File> const&)>{
1753+// [this](std::shared_ptr<unity::storage::qt::client::File> const& file){
1754+// auto const success = bool(file);
1755+// qDebug() << "commit finished with" << success;
1756+// if (success)
1757+// {
1758+// file_name_after_commit_ = file->name();
1759+// }
1760+// Q_EMIT(commit_finished(success));
1761+// }
1762+// }
1763+// );
1764+ downloader_->finish_download();
1765+ Q_EMIT(download_finished()); // TODO add the code to call finish_download
1766+}
1767+
1768+qint64
1769+StorageFrameworkDownloader::file_size() const
1770+{
1771+ return file_size_;
1772+}
1773
1774=== added file 'src/storage-framework/sf-downloader.h'
1775--- src/storage-framework/sf-downloader.h 1970-01-01 00:00:00 +0000
1776+++ src/storage-framework/sf-downloader.h 2016-11-17 00:23:33 +0000
1777@@ -0,0 +1,48 @@
1778+/*
1779+ * Copyright (C) 2016 Canonical, Ltd.
1780+ *
1781+ * This program is free software: you can redistribute it and/or modify it
1782+ * under the terms of the GNU General Public License version 3, as published
1783+ * by the Free Software Foundation.
1784+ *
1785+ * This program is distributed in the hope that it will be useful, but
1786+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1787+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1788+ * PURPOSE. See the GNU General Public License for more details.
1789+ *
1790+ * You should have received a copy of the GNU General Public License along
1791+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1792+ *
1793+ * Authors:
1794+ * Charles Kerr <charles.kerr@canonical.com>
1795+ */
1796+
1797+#pragma once
1798+
1799+#include "util/connection-helper.h"
1800+#include "storage-framework/downloader.h"
1801+
1802+#include <unity/storage/qt/client/client-api.h>
1803+
1804+#include <QLocalSocket>
1805+
1806+#include <memory>
1807+
1808+class StorageFrameworkDownloader final: public Downloader
1809+{
1810+public:
1811+
1812+ StorageFrameworkDownloader(unity::storage::qt::client::Downloader::SPtr const& uploader,
1813+ qint64 file_size,
1814+ QObject * parent = nullptr);
1815+ std::shared_ptr<QLocalSocket> socket() override;
1816+ void finish() override;
1817+ qint64 file_size() const override;
1818+
1819+private:
1820+
1821+ unity::storage::qt::client::Downloader::SPtr const downloader_;
1822+ qint64 file_size_;
1823+
1824+ ConnectionHelper connections_;
1825+};
1826
1827=== modified file 'src/storage-framework/storage_framework_client.cpp'
1828--- src/storage-framework/storage_framework_client.cpp 2016-11-03 10:32:49 +0000
1829+++ src/storage-framework/storage_framework_client.cpp 2016-11-17 00:23:33 +0000
1830@@ -19,6 +19,7 @@
1831 */
1832
1833 #include "storage-framework/storage_framework_client.h"
1834+#include "storage-framework/sf-downloader.h"
1835 #include "storage-framework/sf-uploader.h"
1836
1837 #include <QDateTime>
1838@@ -39,7 +40,7 @@
1839 {
1840 }
1841
1842-StorageFrameworkClient::~StorageFrameworkClient() =default;
1843+StorageFrameworkClient::~StorageFrameworkClient() = default;
1844
1845 /***
1846 ****
1847@@ -154,10 +155,10 @@
1848 return fi.future();
1849 }
1850
1851-QFuture<sf::Downloader::SPtr>
1852+QFuture<std::shared_ptr<Downloader>>
1853 StorageFrameworkClient::get_new_downloader(QString const & dir_name, QString const & file_name)
1854 {
1855- QFutureInterface<sf::Downloader::SPtr> fi;
1856+ QFutureInterface<std::shared_ptr<Downloader>> fi;
1857
1858 add_roots_task([this, fi, dir_name, file_name](QVector<sf::Root::SPtr> const& roots)
1859 {
1860@@ -171,7 +172,7 @@
1861 if (!keeper_root)
1862 {
1863 qWarning() << "Error accessing keeper root folder";
1864- sf::Downloader::SPtr ret;
1865+ std::shared_ptr<Downloader> ret;
1866 QFutureInterface<decltype(ret)> qfi(fi);
1867 qfi.reportResult(ret);
1868 qfi.reportFinished();
1869@@ -183,27 +184,27 @@
1870 get_storage_framework_file(keeper_root, file_name),
1871 std::function<void(sf::File::SPtr const&)>{
1872 [this, fi](sf::File::SPtr const& sf_file){
1873- sf::Downloader::SPtr ret_null;
1874 if (sf_file) {
1875 connection_helper_.connect_future(
1876 sf_file->create_downloader(),
1877 std::function<void(sf::Downloader::SPtr const&)>{
1878- [this, fi, ret_null](sf::Downloader::SPtr const& sf_downloader){
1879- QFutureInterface<decltype(ret_null)> qfi(fi);
1880+ [this, fi, sf_file](sf::Downloader::SPtr const& sf_downloader){
1881+ std::shared_ptr<Downloader> ret;
1882 if (sf_downloader)
1883 {
1884- qfi.reportResult(sf_downloader);
1885- qfi.reportFinished();
1886- }
1887- else
1888- {
1889- qfi.reportResult(ret_null);
1890- qfi.reportFinished();
1891- }
1892+ ret.reset(
1893+ new StorageFrameworkDownloader(sf_downloader, sf_file->size(), this),
1894+ [](Downloader* d){d->deleteLater();}
1895+ );
1896+ }
1897+ QFutureInterface<decltype(ret)> qfi(fi);
1898+ qfi.reportResult(ret);
1899+ qfi.reportFinished();
1900 }
1901 }
1902 );
1903 } else {
1904+ std::shared_ptr<Downloader> ret_null;
1905 QFutureInterface<decltype(ret_null)> qfi(fi);
1906 qfi.reportResult(ret_null);
1907 qfi.reportFinished();
1908
1909=== modified file 'src/storage-framework/storage_framework_client.h'
1910--- src/storage-framework/storage_framework_client.h 2016-11-03 10:32:49 +0000
1911+++ src/storage-framework/storage_framework_client.h 2016-11-17 00:23:33 +0000
1912@@ -22,6 +22,7 @@
1913
1914 #include "util/connection-helper.h"
1915 #include "storage-framework/uploader.h"
1916+#include "storage-framework/downloader.h"
1917
1918 #include <unity/storage/qt/client/client-api.h>
1919
1920@@ -43,7 +44,7 @@
1921 virtual ~StorageFrameworkClient();
1922
1923 QFuture<std::shared_ptr<Uploader>> get_new_uploader(int64_t n_bytes, QString const & dir_name, QString const & file_name);
1924- QFuture<unity::storage::qt::client::Downloader::SPtr> get_new_downloader(QString const & dir_name, QString const & file_name);
1925+ QFuture<std::shared_ptr<Downloader>> get_new_downloader(QString const & dir_name, QString const & file_name);
1926 QFuture<QVector<QString>> get_keeper_dirs();
1927
1928 static QString const KEEPER_FOLDER;
1929
1930=== added directory 'src/test-restore'
1931=== added file 'src/test-restore/CMakeLists.txt'
1932--- src/test-restore/CMakeLists.txt 1970-01-01 00:00:00 +0000
1933+++ src/test-restore/CMakeLists.txt 2016-11-17 00:23:33 +0000
1934@@ -0,0 +1,40 @@
1935+set(TEST_RESTORE_EXEC "test-restore-socket")
1936+
1937+include_directories("${CMAKE_SOURCE_DIR}/src")
1938+include_directories("${CMAKE_BINARY_DIR}/src/qdbus-stubs")
1939+include_directories("${CMAKE_SOURCE_DIR}/src/qdbus-stubs")
1940+
1941+set(TEST_RESTORE_SOURCES
1942+ main.cpp
1943+ test-restore-socket.cpp
1944+)
1945+
1946+add_executable(
1947+ ${TEST_RESTORE_EXEC}
1948+ ${TEST_RESTORE_SOURCES}
1949+)
1950+
1951+link_directories(
1952+ ${SERVICE_DEPS_LIBRARY_DIRS}
1953+)
1954+
1955+set(
1956+ RESTORE_STATIC_LIBS
1957+ storage-framework
1958+ util
1959+# qdbus-stubs
1960+)
1961+
1962+target_link_libraries(
1963+ ${TEST_RESTORE_EXEC}
1964+ ${RESTORE_STATIC_LIBS}
1965+ ${SERVICE_DEVEL_SF_DEPS_LIBRARIES}
1966+ Qt5::Core
1967+ Qt5::DBus
1968+)
1969+
1970+install(
1971+ TARGETS
1972+ ${TEST_RESTORE_EXEC}
1973+ RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR}
1974+)
1975
1976=== added file 'src/test-restore/main.cpp'
1977--- src/test-restore/main.cpp 1970-01-01 00:00:00 +0000
1978+++ src/test-restore/main.cpp 2016-11-17 00:23:33 +0000
1979@@ -0,0 +1,32 @@
1980+/*
1981+ * Copyright (C) 2016 Canonical, Ltd.
1982+ *
1983+ * This program is free software: you can redistribute it and/or modify it
1984+ * under the terms of the GNU General Public License version 3, as published
1985+ * by the Free Software Foundation.
1986+ *
1987+ * This program is distributed in the hope that it will be useful, but
1988+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1989+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1990+ * PURPOSE. See the GNU General Public License for more details.
1991+ *
1992+ * You should have received a copy of the GNU General Public License along
1993+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1994+ *
1995+ * Authors:
1996+ * Charles Kerr <charles.kerr@canonical.com>
1997+ * Xavi Garcia Mena <xavi.garcia.mena@canonical.com>
1998+ */
1999+#include <QCoreApplication>
2000+
2001+#include "test-restore-socket.h"
2002+
2003+int main(int argc, char **argv)
2004+{
2005+ QCoreApplication app(argc, argv);
2006+
2007+ TestRestoreSocket test_restore;
2008+ test_restore.start("test_dir", "test_file");
2009+
2010+ return app.exec();
2011+}
2012
2013=== added file 'src/test-restore/test-restore-socket.cpp'
2014--- src/test-restore/test-restore-socket.cpp 1970-01-01 00:00:00 +0000
2015+++ src/test-restore/test-restore-socket.cpp 2016-11-17 00:23:33 +0000
2016@@ -0,0 +1,139 @@
2017+/*
2018+ * Copyright (C) 2016 Canonical, Ltd.
2019+ *
2020+ * This program is free software: you can redistribute it and/or modify it
2021+ * under the terms of the GNU General Public License version 3, as published
2022+ * by the Free Software Foundation.
2023+ *
2024+ * This program is distributed in the hope that it will be useful, but
2025+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2026+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2027+ * PURPOSE. See the GNU General Public License for more details.
2028+ *
2029+ * You should have received a copy of the GNU General Public License along
2030+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2031+ *
2032+ * Authors:
2033+ * Charles Kerr <charles.kerr@canonical.com>
2034+ * Xavi Garcia Mena <xavi.garcia.mena@canonical.com>
2035+ */
2036+
2037+#include "test-restore-socket.h"
2038+
2039+#include "storage-framework/storage_framework_client.h"
2040+#include "storage-framework/sf-downloader.h"
2041+
2042+constexpr int UPLOAD_BUFFER_MAX_ {1024*16};
2043+
2044+TestRestoreSocket::TestRestoreSocket(QObject *parent)
2045+ : QObject(parent)
2046+ , sf_client_(new StorageFrameworkClient)
2047+ , file_("/tmp/test-downloader")
2048+{
2049+ file_.open(QIODevice::WriteOnly);
2050+ connect (&future_watcher_, &QFutureWatcher<std::shared_ptr<Downloader>>::finished, [this]{on_socket_received(future_watcher_.result());});
2051+}
2052+
2053+TestRestoreSocket::~TestRestoreSocket() = default;
2054+
2055+void TestRestoreSocket::start(QString const & dir_name, QString const & file_name)
2056+{
2057+ qDebug() << "asking storage framework for a socket for reading";
2058+
2059+ future_watcher_.setFuture(sf_client_->get_new_downloader(dir_name, file_name));
2060+// connections_.connect_future(
2061+// sf_client_->get_new_downloader(dir_name, file_name),
2062+// std::function<void(std::shared_ptr<Downloader> const&)>{
2063+// [this](std::shared_ptr<Downloader> const& downloader){
2064+// qDebug() << "Downloader is" << static_cast<void*>(downloader.get());
2065+// if (downloader) {
2066+// this->on_socket_received(downloader);
2067+// }
2068+// }
2069+// }
2070+// );
2071+}
2072+
2073+void TestRestoreSocket::read_data()
2074+{
2075+ if (socket_->bytesAvailable())
2076+ {
2077+//// char readbuf[UPLOAD_BUFFER_MAX_];
2078+//// const auto n = socket_->read(readbuf, sizeof(readbuf));
2079+//// if (n > 0) {
2080+//// n_read_ += n;
2081+//// qDebug() << "Read " << n << " bytes. Total: " << n_read_;
2082+//
2083+// char readbuf[64 *1024];
2084+// // try to fill the upload buf
2085+// int max_bytes = UPLOAD_BUFFER_MAX_;// - upload_buffer_.size();
2086+// if (max_bytes > 0) {
2087+// const auto n = socket_->read(readbuf, max_bytes);
2088+// if (n > 0) {
2089+// n_read_ += n;
2090+// qDebug() << "Read " << n << " bytes. Total: " << n_read_;
2091+//
2092+//// if (file_.isOpen())
2093+//// {
2094+//// file_.write(readbuf, max_bytes);
2095+//// }
2096+//// }
2097+//// else if (n < 0) {
2098+//// qDebug() << "Read error: " << socket_->errorString();
2099+//// return;
2100+// if (file_.isOpen())
2101+// {
2102+// file_.write(readbuf, n);
2103+// }
2104+// }
2105+// else if (n < 0) {
2106+// qDebug() << "Read error: " << socket_->errorString();
2107+// return;
2108+// }
2109+// }
2110+
2111+ char readbuf[64 *1024];
2112+ const auto n = socket_->read(readbuf, sizeof(readbuf));
2113+ if (n > 0) {
2114+ n_read_ += n;
2115+ qDebug() << "Read " << n << " bytes. Total: " << n_read_;
2116+ if (file_.isOpen())
2117+ {
2118+ file_.write(readbuf, n);
2119+ }
2120+ }
2121+ else if (n < 0) {
2122+ qDebug() << "Read error: " << socket_->errorString();
2123+ return;
2124+ }
2125+ }
2126+}
2127+
2128+void TestRestoreSocket::on_disconnected()
2129+{
2130+ qDebug() << "Socket disconnected";
2131+ auto avail = socket_->bytesAvailable();
2132+ while (avail > 0)
2133+ {
2134+ read_data();
2135+ avail = socket_->bytesAvailable();
2136+ }
2137+
2138+ if (file_.isOpen())
2139+ {
2140+ file_.close();
2141+ }
2142+}
2143+
2144+void TestRestoreSocket::on_data_stored(qint64 /*n*/)
2145+{
2146+ read_data();
2147+}
2148+
2149+void TestRestoreSocket::on_socket_received(std::shared_ptr<Downloader> const & downloader)
2150+{
2151+ socket_ = downloader->socket();
2152+ QObject::connect(socket_.get(), &QLocalSocket::readyRead, this, &TestRestoreSocket::read_data);
2153+ QObject::connect(socket_.get(), &QLocalSocket::disconnected, this, &TestRestoreSocket::on_disconnected);
2154+ QObject::connect(&file_, &QIODevice::bytesWritten, this, &TestRestoreSocket::on_data_stored);
2155+}
2156
2157=== added file 'src/test-restore/test-restore-socket.h'
2158--- src/test-restore/test-restore-socket.h 1970-01-01 00:00:00 +0000
2159+++ src/test-restore/test-restore-socket.h 2016-11-17 00:23:33 +0000
2160@@ -0,0 +1,56 @@
2161+/*
2162+ * Copyright (C) 2016 Canonical, Ltd.
2163+ *
2164+ * This program is free software: you can redistribute it and/or modify it
2165+ * under the terms of the GNU General Public License version 3, as published
2166+ * by the Free Software Foundation.
2167+ *
2168+ * This program is distributed in the hope that it will be useful, but
2169+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2170+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2171+ * PURPOSE. See the GNU General Public License for more details.
2172+ *
2173+ * You should have received a copy of the GNU General Public License along
2174+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2175+ *
2176+ * Authors:
2177+ * Charles Kerr <charles.kerr@canonical.com>
2178+ * Xavi Garcia Mena <xavi.garcia.mena@canonical.com>
2179+ */
2180+#pragma once
2181+
2182+#include "util/connection-helper.h"
2183+
2184+#include <QObject>
2185+#include <QScopedPointer>
2186+#include <QFile>
2187+
2188+#include <memory>
2189+
2190+class QLocalSocket;
2191+class StorageFrameworkClient;
2192+class Downloader;
2193+
2194+class TestRestoreSocket : public QObject
2195+{
2196+ Q_OBJECT
2197+public:
2198+ explicit TestRestoreSocket(QObject *parent = nullptr);
2199+ virtual ~TestRestoreSocket();
2200+
2201+ void start(QString const & dir_name, QString const & file_name);
2202+
2203+public Q_SLOTS:
2204+ void read_data();
2205+ void on_socket_received(std::shared_ptr<Downloader> const & downloader);
2206+ void on_disconnected();
2207+ void on_data_stored(qint64 n);
2208+
2209+private:
2210+ std::shared_ptr<QLocalSocket> socket_;
2211+ QScopedPointer<StorageFrameworkClient> sf_client_;
2212+ ConnectionHelper connections_;
2213+ qint64 n_read_ = 0;
2214+ QFile file_;
2215+ QFutureWatcher<std::shared_ptr<Downloader>> future_watcher_;
2216+};
2217
2218=== modified file 'tests/CMakeLists.txt'
2219--- tests/CMakeLists.txt 2016-09-05 13:54:15 +0000
2220+++ tests/CMakeLists.txt 2016-11-17 00:23:33 +0000
2221@@ -20,6 +20,11 @@
2222 )
2223
2224 set(
2225+ RESTORE_HELPER
2226+ fake-restore-helper
2227+)
2228+
2229+set(
2230 BACKUP_HELPER_FAILURE
2231 fake-backup-helper-failure
2232 )
2233@@ -27,6 +32,7 @@
2234 set(KEEPER_TAR_CREATE_BIN ${CMAKE_BINARY_DIR}/src/tar/keeper-tar-create)
2235 set(KEEPER_HELPER_TEST_LOCATION ${CMAKE_BINARY_DIR}/tests/fakes/helpers-test.sh)
2236 set(BACKUP_HELPER_FAILURE_LOCATION ${CMAKE_BINARY_DIR}/tests/fakes/${BACKUP_HELPER_FAILURE})
2237+set(RESTORE_HELPER_TEST_LOCATION ${CMAKE_BINARY_DIR}/tests/fakes/${RESTORE_HELPER})
2238
2239 add_definitions(
2240 -DCMAKE_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
2241
2242=== modified file 'tests/com_canonical_keeper.py'
2243--- tests/com_canonical_keeper.py 2016-08-03 18:38:12 +0000
2244+++ tests/com_canonical_keeper.py 2016-11-17 00:23:33 +0000
2245@@ -1,3 +1,20 @@
2246+# Copyright (C) 2016 Canonical, Ltd.
2247+#
2248+# This program is free software: you can redistribute it and/or modify it
2249+# under the terms of the GNU General Public License version 3, as published
2250+# by the Free Software Foundation.
2251+#
2252+# This program is distributed in the hope that it will be useful, but
2253+# WITHOUT ANY WARRANTY; without even the implied warranties of
2254+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2255+# PURPOSE. See the GNU General Public License for more details.
2256+#
2257+# You should have received a copy of the GNU General Public License along
2258+# with this program. If not, see <http://www.gnu.org/licenses/>.
2259+#
2260+# Authors:
2261+# Charles Kerr <charles.kerr@canonical.com>
2262+
2263 import copy
2264 import dbus
2265 import dbus.service
2266
2267=== modified file 'tests/fakes/CMakeLists.txt'
2268--- tests/fakes/CMakeLists.txt 2016-08-30 12:50:46 +0000
2269+++ tests/fakes/CMakeLists.txt 2016-11-17 00:23:33 +0000
2270@@ -30,6 +30,16 @@
2271 )
2272
2273 add_executable(
2274+ ${RESTORE_HELPER}
2275+ fake-restore-helper.cpp
2276+ restore-reader.cpp
2277+)
2278+target_link_libraries(
2279+ ${RESTORE_HELPER}
2280+ ${LINK_LIBS}
2281+)
2282+
2283+add_executable(
2284 ${BACKUP_HELPER_FAILURE}
2285 fake-backup-helper.cpp
2286 )
2287
2288=== added file 'tests/fakes/fake-restore-helper.cpp'
2289--- tests/fakes/fake-restore-helper.cpp 1970-01-01 00:00:00 +0000
2290+++ tests/fakes/fake-restore-helper.cpp 2016-11-17 00:23:33 +0000
2291@@ -0,0 +1,101 @@
2292+/*
2293+ * Copyright (C) 2016 Canonical, Ltd.
2294+ *
2295+ * This program is free software: you can redistribute it and/or modify it
2296+ * under the terms of the GNU General Public License version 3, as published
2297+ * by the Free Software Foundation.
2298+ *
2299+ * This program is distributed in the hope that it will be useful, but
2300+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2301+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2302+ * PURPOSE. See the GNU General Public License for more details.
2303+ *
2304+ * You should have received a copy of the GNU General Public License along
2305+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2306+ *
2307+ * Authors:
2308+ * Charles Kerr <charles.kerr@canonical.com>
2309+ */
2310+
2311+#include "fake-restore-helper.h"
2312+#include "restore-reader.h"
2313+
2314+#include <qdbus-stubs/dbus-types.h>
2315+#include <qdbus-stubs/keeper_helper_interface.h>
2316+
2317+#include <QCoreApplication>
2318+#include <QDebug>
2319+#include <QDBusConnection>
2320+#include <QDBusInterface>
2321+#include <QDBusReply>
2322+#include <QProcessEnvironment>
2323+#include <QLocalSocket>
2324+#include <QtGlobal>
2325+
2326+#include <unistd.h>
2327+#include <sys/ioctl.h>
2328+
2329+void myMessageHandler(QtMsgType type, const QMessageLogContext &, const QString & msg)
2330+{
2331+ QString txt;
2332+ switch (type) {
2333+ case QtDebugMsg:
2334+ txt = QString("Debug: %1").arg(msg);
2335+ break;
2336+ case QtWarningMsg:
2337+ txt = QString("Warning: %1").arg(msg);
2338+ break;
2339+ case QtCriticalMsg:
2340+ txt = QString("Critical: %1").arg(msg);
2341+ break;
2342+ case QtFatalMsg:
2343+ txt = QString("Fatal: %1").arg(msg);
2344+ abort();
2345+ }
2346+ QFile outFile("/tmp/restore-helper-output");
2347+ outFile.open(QIODevice::WriteOnly | QIODevice::Append);
2348+ QTextStream ts(&outFile);
2349+ ts << txt << endl;
2350+}
2351+
2352+int
2353+main(int argc, char **argv)
2354+{
2355+ QCoreApplication app(argc, argv);
2356+ qInstallMessageHandler(myMessageHandler);
2357+
2358+ // dump the inputs to stdout
2359+ qDebug() << "argc:" << argc;
2360+ for(int i=0; i<argc; ++i)
2361+ qDebug() << "argv[" << i << "] is" << argv[i];
2362+ const auto env = QProcessEnvironment::systemEnvironment();
2363+ for(const auto& key : env.keys())
2364+ qDebug() << "env" << qPrintable(key) << "is" << qPrintable(env.value(key));
2365+
2366+ qDebug() << "Retrieving connection";
2367+
2368+ // ask the service for a socket
2369+ auto conn = QDBusConnection::connectToBus(QDBusConnection::SessionBus, DBusTypes::KEEPER_SERVICE);
2370+ const auto object_path = QString::fromUtf8(DBusTypes::KEEPER_HELPER_PATH);
2371+ DBusInterfaceKeeperHelper helper_iface (DBusTypes::KEEPER_SERVICE, object_path, conn);
2372+
2373+ qDebug() << "Is valid:" << helper_iface.isValid();
2374+
2375+ auto fd_reply = helper_iface.StartRestore();
2376+ fd_reply.waitForFinished();
2377+ if (fd_reply.isError())
2378+ {
2379+ qFatal("Call to '%s.StartRestore() at '%s' call failed: %s",
2380+ DBusTypes::KEEPER_SERVICE,
2381+ qPrintable(object_path),
2382+ qPrintable(fd_reply.error().message())
2383+ );
2384+ }
2385+ const auto ufd = fd_reply.value();
2386+
2387+ // write the blob
2388+ const auto fd = ufd.fileDescriptor();
2389+ qDebug() << "The file descriptor obtained is: " << fd;
2390+ RestoreReader reader(fd, TEST_RESTORE_FILE_PATH);
2391+ return app.exec();
2392+}
2393
2394=== added file 'tests/fakes/fake-restore-helper.h'
2395--- tests/fakes/fake-restore-helper.h 1970-01-01 00:00:00 +0000
2396+++ tests/fakes/fake-restore-helper.h 2016-11-17 00:23:33 +0000
2397@@ -0,0 +1,26 @@
2398+/*
2399+ * Copyright (C) 2016 Canonical, Ltd.
2400+ *
2401+ * This program is free software: you can redistribute it and/or modify it
2402+ * under the terms of the GNU General Public License version 3, as published
2403+ * by the Free Software Foundation.
2404+ *
2405+ * This program is distributed in the hope that it will be useful, but
2406+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2407+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2408+ * PURPOSE. See the GNU General Public License for more details.
2409+ *
2410+ * You should have received a copy of the GNU General Public License along
2411+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2412+ *
2413+ * Authors:
2414+ * Charles Kerr <charles.kerr@canonical.com>
2415+ */
2416+
2417+#pragma once
2418+
2419+namespace
2420+{
2421+static char const TEST_RESTORE_FILE_PATH[] = "/tmp/test-restore-helper";
2422+
2423+}
2424
2425=== added file 'tests/fakes/restore-reader.cpp'
2426--- tests/fakes/restore-reader.cpp 1970-01-01 00:00:00 +0000
2427+++ tests/fakes/restore-reader.cpp 2016-11-17 00:23:33 +0000
2428@@ -0,0 +1,81 @@
2429+/*
2430+ * Copyright (C) 2016 Canonical, Ltd.
2431+ *
2432+ * This program is free software: you can redistribute it and/or modify it
2433+ * under the terms of the GNU General Public License version 3, as published
2434+ * by the Free Software Foundation.
2435+ *
2436+ * This program is distributed in the hope that it will be useful, but
2437+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2438+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2439+ * PURPOSE. See the GNU General Public License for more details.
2440+ *
2441+ * You should have received a copy of the GNU General Public License along
2442+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2443+ *
2444+ * Authors:
2445+ * Xavi Garcia <xavi.garcia.mena@canonical.com>
2446+ */
2447+
2448+#include "restore-reader.h"
2449+
2450+#include <QCoreApplication>
2451+#include <QCryptographicHash>
2452+
2453+#include <unistd.h>
2454+
2455+//static constexpr int UPLOAD_BUFFER_MAX_ {1024*16};
2456+constexpr int UPLOAD_BUFFER_MAX_ = 16 * 1024;
2457+
2458+RestoreReader::RestoreReader(qint64 fd, QString const & file_path, QObject * parent)
2459+ : QObject(parent)
2460+ , file_(file_path)
2461+{
2462+ socket_.setSocketDescriptor(fd);
2463+ connect(&socket_, &QLocalSocket::readyRead, this, &RestoreReader::read_all);
2464+ connect(&socket_, &QLocalSocket::disconnected, this, &RestoreReader::finish);
2465+ if (!file_.open(QIODevice::WriteOnly | QIODevice::Truncate))
2466+ {
2467+ qFatal("Error opening file");
2468+ }
2469+
2470+ read_all();
2471+}
2472+
2473+void RestoreReader::read_all()
2474+{
2475+ qDebug() << Q_FUNC_INFO;
2476+
2477+ for (;;)
2478+ {
2479+ auto const chunk = socket_.readAll();
2480+ if (chunk.isEmpty())
2481+ {
2482+ qDebug() << "Failed to read from server" << socket_.errorString();
2483+ break;
2484+ }
2485+
2486+ n_bytes_read_ += chunk.size();
2487+ qDebug() << Q_FUNC_INFO << "n_bytes_read is now" << n_bytes_read_ << "after reading" << chunk.size();
2488+ if (file_.write(chunk) == -1)
2489+ qDebug() << Q_FUNC_INFO << "file write failed" << file_.errorString();
2490+
2491+ // THIS IS JUST FOR EXTRA DEBUG INFORMATION
2492+ QCryptographicHash hash(QCryptographicHash::Sha1);
2493+ hash.addData(chunk.data(), 100);
2494+ qInfo() << "Hash: bytes total: " << n_bytes_read_ << " " << hash.result().toHex();
2495+ // THIS IS JUST FOR EXTRA DEBUG INFORMATION
2496+ }
2497+}
2498+
2499+void RestoreReader::finish()
2500+{
2501+ qDebug() << "Finishing";
2502+ read_all();
2503+
2504+ file_.flush();
2505+ fsync(file_.handle());
2506+ file_.close();
2507+
2508+ QCoreApplication::exit();
2509+}
2510
2511=== added file 'tests/fakes/restore-reader.h'
2512--- tests/fakes/restore-reader.h 1970-01-01 00:00:00 +0000
2513+++ tests/fakes/restore-reader.h 2016-11-17 00:23:33 +0000
2514@@ -0,0 +1,43 @@
2515+/*
2516+ * Copyright (C) 2016 Canonical, Ltd.
2517+ *
2518+ * This program is free software: you can redistribute it and/or modify it
2519+ * under the terms of the GNU General Public License version 3, as published
2520+ * by the Free Software Foundation.
2521+ *
2522+ * This program is distributed in the hope that it will be useful, but
2523+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2524+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2525+ * PURPOSE. See the GNU General Public License for more details.
2526+ *
2527+ * You should have received a copy of the GNU General Public License along
2528+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2529+ *
2530+ * Authors:
2531+ * Xavi Garcia <xavi.garcia.mena@canonical.com>
2532+ */
2533+
2534+#pragma once
2535+
2536+#include <QObject>
2537+#include <QFile>
2538+#include <QLocalSocket>
2539+
2540+class RestoreReader : public QObject
2541+{
2542+ Q_OBJECT
2543+public:
2544+ RestoreReader(qint64 fd, QString const & file_path, QObject * parent = nullptr);
2545+ ~RestoreReader() = default;
2546+
2547+private Q_SLOTS:
2548+ void read_all();
2549+ void finish();
2550+
2551+private:
2552+ void check_for_done();
2553+
2554+ QLocalSocket socket_;
2555+ qint64 n_bytes_read_ = 0;
2556+ QFile file_;
2557+};
2558
2559=== modified file 'tests/integration/helpers/CMakeLists.txt'
2560--- tests/integration/helpers/CMakeLists.txt 2016-10-28 15:11:21 +0000
2561+++ tests/integration/helpers/CMakeLists.txt 2016-11-17 00:23:33 +0000
2562@@ -65,6 +65,10 @@
2563 FOLDER_BACKUP_EXEC
2564 ${KEEPER_HELPER_TEST_LOCATION}
2565 )
2566+set(
2567+ FOLDER_RESTORE_EXEC
2568+ ${RESTORE_HELPER_TEST_LOCATION}
2569+)
2570 configure_file(
2571 ${CMAKE_SOURCE_DIR}/data/${HELPER_REGISTRY_FILENAME}.in
2572 ${HELPERS_TEST}-registry.json
2573
2574=== modified file 'tests/integration/helpers/helpers-test.cc'
2575--- tests/integration/helpers/helpers-test.cc 2016-11-02 14:01:23 +0000
2576+++ tests/integration/helpers/helpers-test.cc 2016-11-17 00:23:33 +0000
2577@@ -20,6 +20,7 @@
2578 */
2579
2580 #include "test-helpers-base.h"
2581+#include "tests/fakes/fake-restore-helper.h"
2582
2583 class TestHelpers: public TestHelpersBase
2584 {
2585@@ -32,30 +33,31 @@
2586 }
2587 };
2588
2589-TEST_F(TestHelpers, StartHelper)
2590-{
2591- // starts the services, including keeper-service
2592- start_tasks();
2593-
2594- BackupHelper helper("com.test.multiple_first_1.2.3");
2595-
2596- QSignalSpy spy(&helper, &BackupHelper::state_changed);
2597-
2598- helper.start({"/bin/ls","/tmp"});
2599-
2600- // wait for 2 signals.
2601- // One for started, another one when the helper stops
2602- WAIT_FOR_SIGNALS(spy, 2, 15000);
2603-
2604- ASSERT_EQ(spy.count(), 2);
2605- QList<QVariant> arguments = spy.takeFirst();
2606- EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::STARTED);
2607- arguments = spy.takeFirst();
2608- EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::COMPLETE);
2609-}
2610+//TEST_F(TestHelpers, StartHelper)
2611+//{
2612+// // starts the services, including keeper-service
2613+// start_tasks();
2614+//
2615+// BackupHelper helper("com.test.multiple_first_1.2.3");
2616+//
2617+// QSignalSpy spy(&helper, &BackupHelper::state_changed);
2618+//
2619+// helper.start({"/bin/ls","/tmp"});
2620+//
2621+// // wait for 2 signals.
2622+// // One for started, another one when the helper stops
2623+// WAIT_FOR_SIGNALS(spy, 2, 15000);
2624+//
2625+// ASSERT_EQ(spy.count(), 2);
2626+// QList<QVariant> arguments = spy.takeFirst();
2627+// EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::STARTED);
2628+// arguments = spy.takeFirst();
2629+// EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::COMPLETE);
2630+//}
2631
2632 TEST_F(TestHelpers, StartFullTest)
2633 {
2634+ system("rm -f /tmp/restore-helper-output");
2635 XdgUserDirsSandbox tmp_dir;
2636
2637 // starts the services, including keeper-service
2638@@ -82,7 +84,7 @@
2639 qDebug() << "USER DIR:" << user_dir;
2640
2641 // fill something in the music dir
2642- FileUtils::fillTemporaryDirectory(user_dir, qrand() % 100);
2643+ FileUtils::fillTemporaryDirectory(user_dir, qrand() % 10);
2644
2645 // search for the user folder uuid
2646 auto user_folder_uuid = get_uuid_for_xdg_folder_path(user_dir, choices.value());
2647@@ -101,7 +103,7 @@
2648 qDebug() << "USER DIR 2:" << user_dir_2;
2649
2650 // fill something in the music dir
2651- FileUtils::fillTemporaryDirectory(user_dir_2, qrand() % 100);
2652+ FileUtils::fillTemporaryDirectory(user_dir_2, qrand() % 10);
2653
2654 // search for the user folder uuid
2655 auto user_folder_uuid_2 = get_uuid_for_xdg_folder_path(user_dir_2, choices.value());
2656@@ -140,164 +142,197 @@
2657
2658 // finally check that we have a valid manifest file.
2659 EXPECT_TRUE(check_manifest_file(backup_items));
2660-}
2661-
2662-TEST_F(TestHelpers, StartFullTestCancelling)
2663-{
2664- XdgUserDirsSandbox tmp_dir;
2665-
2666- // starts the services, including keeper-service
2667- start_tasks();
2668-
2669- QSharedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser(
2670- DBusTypes::KEEPER_SERVICE,
2671- DBusTypes::KEEPER_USER_PATH,
2672- dbus_test_runner.sessionConnection()
2673- ) );
2674-
2675- ASSERT_TRUE(user_iface->isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message());
2676-
2677- // ask for a list of backup choices
2678- QDBusReply<QVariantDictMap> choices = user_iface->call("GetBackupChoices");
2679- EXPECT_TRUE(choices.isValid()) << qPrintable(choices.error().message());
2680-
2681- QString user_option = QStringLiteral("XDG_MUSIC_DIR");
2682-
2683- auto user_dir = qgetenv(user_option.toLatin1().data());
2684- ASSERT_FALSE(user_dir.isEmpty());
2685- qDebug() << "USER DIR:" << user_dir;
2686-
2687- // fill something in the music dir
2688- FileUtils::fillTemporaryDirectory(user_dir, qrand() % 1000);
2689-
2690- // search for the user folder uuid
2691- auto user_folder_uuid = get_uuid_for_xdg_folder_path(user_dir, choices.value());
2692- ASSERT_FALSE(user_folder_uuid.isEmpty());
2693- qDebug() << "User folder UUID is:" << user_folder_uuid;
2694-
2695- QString user_option_2 = QStringLiteral("XDG_VIDEOS_DIR");
2696-
2697- auto user_dir_2 = qgetenv(user_option_2.toLatin1().data());
2698- ASSERT_FALSE(user_dir_2.isEmpty());
2699- qDebug() << "USER DIR 2:" << user_dir_2;
2700-
2701- // fill something in the music dir
2702- FileUtils::fillTemporaryDirectory(user_dir_2, qrand() % 1000);
2703-
2704- // search for the user folder uuid
2705- auto user_folder_uuid_2 = get_uuid_for_xdg_folder_path(user_dir_2, choices.value());
2706- ASSERT_FALSE(user_folder_uuid_2.isEmpty());
2707- qDebug() << "User folder 2 UUID is:" << user_folder_uuid_2;
2708-
2709- QSharedPointer<DBusPropertiesInterface> properties_interface(new DBusPropertiesInterface(
2710- DBusTypes::KEEPER_SERVICE,
2711- DBusTypes::KEEPER_USER_PATH,
2712- dbus_test_runner.sessionConnection()
2713- ) );
2714-
2715- ASSERT_TRUE(properties_interface->isValid()) << qPrintable(QDBusConnection::sessionBus().lastError().message());
2716-
2717- QSignalSpy spy(properties_interface.data(),&DBusPropertiesInterface::PropertiesChanged);
2718-
2719- // Now we know the music folder uuid, let's start the backup for it.
2720- QDBusReply<void> backup_reply = user_iface->call("StartBackup", QStringList{user_folder_uuid, user_folder_uuid_2});
2721- ASSERT_TRUE(backup_reply.isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message());
2722-
2723- EXPECT_TRUE(cancel_first_task_at_percentage(spy, 0.05, user_iface));
2724-
2725- // wait until all the tasks have the action state "complete"
2726- // this one uses pooling so it should just call Get once
2727- EXPECT_TRUE(wait_for_all_tasks_have_action_state({user_folder_uuid, user_folder_uuid_2}, "cancelled", user_iface));
2728-
2729- // check that we have no files in storage framework
2730- EXPECT_EQ(0, StorageFrameworkLocalUtils::check_storage_framework_nb_files());
2731-}
2732-
2733-TEST_F(TestHelpers, CheckBadUUIDS)
2734-{
2735- XdgUserDirsSandbox tmp_dir;
2736-
2737- // starts the services, including keeper-service
2738- start_tasks();
2739-
2740- QSharedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser(
2741- DBusTypes::KEEPER_SERVICE,
2742- DBusTypes::KEEPER_USER_PATH,
2743- dbus_test_runner.sessionConnection()
2744- ) );
2745-
2746- ASSERT_TRUE(user_iface->isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message());
2747-
2748- // Now we know the music folder uuid, let's start the backup for it.
2749- QDBusReply<void> backup_reply = user_iface->call("StartBackup", QStringList{"bad_uuid_1", "bad_uuid_2"});
2750-
2751- ASSERT_FALSE(backup_reply.isValid());
2752-
2753- // check the error message
2754- // the uuids are not printed always in the same order
2755- QString error_message = dbus_test_runner.sessionConnection().lastError().message();
2756- EXPECT_TRUE(error_message.startsWith("unhandled uuids: "));
2757- EXPECT_TRUE(error_message.contains("bad_uuid_1"));
2758- EXPECT_TRUE(error_message.contains("bad_uuid_2"));
2759-}
2760-
2761-TEST_F(TestHelpers, SimplyCheckThatTheSecondDBusInterfaceIsFine)
2762-{
2763- XdgUserDirsSandbox tmp_dir;
2764-
2765- // starts the services, including keeper-service
2766- start_tasks();
2767-
2768- QSharedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser(
2769- DBusTypes::KEEPER_SERVICE,
2770- DBusTypes::KEEPER_USER_PATH,
2771- dbus_test_runner.sessionConnection()
2772- ) );
2773-
2774- ASSERT_TRUE(user_iface->isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message());
2775-
2776-}
2777-
2778-TEST_F(TestHelpers, BadHelperPath)
2779-{
2780- // starts the services, including keeper-service
2781- start_tasks();
2782-
2783- BackupHelper helper("com.bar_foo_8432.13.1");
2784-
2785- QSignalSpy spy(&helper, &BackupHelper::state_changed);
2786- QStringList urls;
2787- urls << "blah" << "/tmp";
2788- helper.start(urls);
2789-
2790- WAIT_FOR_SIGNALS(spy, 1, Helper::MAX_UAL_WAIT_TIME + 1000);
2791-
2792- ASSERT_EQ(spy.count(), 1);
2793- QList<QVariant> arguments = spy.takeFirst();
2794- EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::FAILED);
2795-}
2796-
2797-TEST_F(TestHelpers, Inactivity)
2798-{
2799- // starts the services, including keeper-service
2800- start_tasks();
2801-
2802- BackupHelper helper("com.bar_foo_8432.13.1");
2803-
2804- QSignalSpy spy(&helper, &BackupHelper::state_changed);
2805- QStringList urls;
2806- urls << TEST_INACTIVE_HELPER << "/tmp";
2807- helper.start(urls);
2808-
2809- // wait 15 seconds at most.
2810- // the inactive helper sleeps for 100 seconds so
2811- // if we get the 2 signals it means it was stopped due to inactivity
2812- // We can also check at the end for the state, which should be CANCELLED
2813- WAIT_FOR_SIGNALS(spy, 2, BackupHelper::MAX_INACTIVITY_TIME + 2000);
2814-
2815- ASSERT_EQ(spy.count(), 2);
2816- QList<QVariant> arguments = spy.takeFirst();
2817- EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::STARTED);
2818- arguments = spy.takeFirst();
2819- EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::CANCELLED);
2820-}
2821+
2822+ QDBusPendingReply<QVariantDictMap> restore_choices_reply = user_iface->call("GetRestoreChoices");
2823+ restore_choices_reply.waitForFinished();
2824+ EXPECT_TRUE(restore_choices_reply.isValid()) << qPrintable(choices.error().message());
2825+
2826+ const auto restore_choices = restore_choices_reply.value();
2827+ EXPECT_EQ(2, restore_choices.size());
2828+
2829+ // check that we have the first uuid that we did the backup
2830+ const auto iter_restore = restore_choices.find(user_folder_uuid);
2831+ EXPECT_NE(iter_restore, restore_choices.end());
2832+ EXPECT_EQ(user_folder_uuid, iter_restore.key());
2833+
2834+ // ask to restore that uuid
2835+ QDBusPendingReply<void> restore_reply = user_iface->call("StartRestore", QStringList{iter_restore.key()});
2836+ restore_reply.waitForFinished();
2837+ ASSERT_TRUE(restore_reply.isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message());
2838+
2839+ // waits until all tasks are complete, recording PropertiesChanged signals
2840+ // and checks all the recorded values
2841+ EXPECT_TRUE(capture_and_check_state_until_all_tasks_complete(spy, {iter_restore.key()}, "complete"));
2842+
2843+ // verify that the file that the fake restore helper creates is one of the ones in storage framework
2844+ QString storage_framework_file_path;
2845+ EXPECT_TRUE(StorageFrameworkLocalUtils::get_storage_frameowork_file_equal_to(TEST_RESTORE_FILE_PATH, storage_framework_file_path));
2846+
2847+ // Finally check that the storage framework file that matched is the right one
2848+ // Keeper uses the display name plus .keeper extension for the files it creates
2849+ QFileInfo sf_file_info(storage_framework_file_path);
2850+ EXPECT_EQ(sf_file_info.fileName(), QStringLiteral("%1.keeper").arg(get_display_name_for_xdg_folder_path(user_dir, choices.value())));
2851+
2852+ qDebug() << "-----------------------------------------------------";
2853+ system("cat /tmp/restore-helper-output");
2854+}
2855+
2856+//TEST_F(TestHelpers, StartFullTestCancelling)
2857+//{
2858+// XdgUserDirsSandbox tmp_dir;
2859+//
2860+// // starts the services, including keeper-service
2861+// start_tasks();
2862+//
2863+// QSharedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser(
2864+// DBusTypes::KEEPER_SERVICE,
2865+// DBusTypes::KEEPER_USER_PATH,
2866+// dbus_test_runner.sessionConnection()
2867+// ) );
2868+//
2869+// ASSERT_TRUE(user_iface->isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message());
2870+//
2871+// // ask for a list of backup choices
2872+// QDBusReply<QVariantDictMap> choices = user_iface->call("GetBackupChoices");
2873+// EXPECT_TRUE(choices.isValid()) << qPrintable(choices.error().message());
2874+//
2875+// QString user_option = QStringLiteral("XDG_MUSIC_DIR");
2876+//
2877+// auto user_dir = qgetenv(user_option.toLatin1().data());
2878+// ASSERT_FALSE(user_dir.isEmpty());
2879+// qDebug() << "USER DIR:" << user_dir;
2880+//
2881+// // fill something in the music dir
2882+// FileUtils::fillTemporaryDirectory(user_dir, qrand() % 1000);
2883+//
2884+// // search for the user folder uuid
2885+// auto user_folder_uuid = get_uuid_for_xdg_folder_path(user_dir, choices.value());
2886+// ASSERT_FALSE(user_folder_uuid.isEmpty());
2887+// qDebug() << "User folder UUID is:" << user_folder_uuid;
2888+//
2889+// QString user_option_2 = QStringLiteral("XDG_VIDEOS_DIR");
2890+//
2891+// auto user_dir_2 = qgetenv(user_option_2.toLatin1().data());
2892+// ASSERT_FALSE(user_dir_2.isEmpty());
2893+// qDebug() << "USER DIR 2:" << user_dir_2;
2894+//
2895+// // fill something in the music dir
2896+// FileUtils::fillTemporaryDirectory(user_dir_2, qrand() % 1000);
2897+//
2898+// // search for the user folder uuid
2899+// auto user_folder_uuid_2 = get_uuid_for_xdg_folder_path(user_dir_2, choices.value());
2900+// ASSERT_FALSE(user_folder_uuid_2.isEmpty());
2901+// qDebug() << "User folder 2 UUID is:" << user_folder_uuid_2;
2902+//
2903+// QSharedPointer<DBusPropertiesInterface> properties_interface(new DBusPropertiesInterface(
2904+// DBusTypes::KEEPER_SERVICE,
2905+// DBusTypes::KEEPER_USER_PATH,
2906+// dbus_test_runner.sessionConnection()
2907+// ) );
2908+//
2909+// ASSERT_TRUE(properties_interface->isValid()) << qPrintable(QDBusConnection::sessionBus().lastError().message());
2910+//
2911+// QSignalSpy spy(properties_interface.data(),&DBusPropertiesInterface::PropertiesChanged);
2912+//
2913+// // Now we know the music folder uuid, let's start the backup for it.
2914+// QDBusReply<void> backup_reply = user_iface->call("StartBackup", QStringList{user_folder_uuid, user_folder_uuid_2});
2915+// ASSERT_TRUE(backup_reply.isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message());
2916+//
2917+// EXPECT_TRUE(cancel_first_task_at_percentage(spy, 0.05, user_iface));
2918+//
2919+// // wait until all the tasks have the action state "complete"
2920+// // this one uses pooling so it should just call Get once
2921+// EXPECT_TRUE(wait_for_all_tasks_have_action_state({user_folder_uuid, user_folder_uuid_2}, "cancelled", user_iface));
2922+//
2923+// // check that we have no files in storage framework
2924+// EXPECT_EQ(0, StorageFrameworkLocalUtils::check_storage_framework_nb_files());
2925+//}
2926+//
2927+//TEST_F(TestHelpers, CheckBadUUIDS)
2928+//{
2929+// XdgUserDirsSandbox tmp_dir;
2930+//
2931+// // starts the services, including keeper-service
2932+// start_tasks();
2933+//
2934+// QSharedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser(
2935+// DBusTypes::KEEPER_SERVICE,
2936+// DBusTypes::KEEPER_USER_PATH,
2937+// dbus_test_runner.sessionConnection()
2938+// ) );
2939+//
2940+// ASSERT_TRUE(user_iface->isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message());
2941+//
2942+// // Now we know the music folder uuid, let's start the backup for it.
2943+// QDBusReply<void> backup_reply = user_iface->call("StartBackup", QStringList{"bad_uuid_1", "bad_uuid_2"});
2944+//
2945+// ASSERT_FALSE(backup_reply.isValid());
2946+//
2947+// // check the error message
2948+// // the uuids are not printed always in the same order
2949+// QString error_message = dbus_test_runner.sessionConnection().lastError().message();
2950+// EXPECT_TRUE(error_message.startsWith("unhandled uuids: "));
2951+// EXPECT_TRUE(error_message.contains("bad_uuid_1"));
2952+// EXPECT_TRUE(error_message.contains("bad_uuid_2"));
2953+//}
2954+//
2955+//TEST_F(TestHelpers, SimplyCheckThatTheSecondDBusInterfaceIsFine)
2956+//{
2957+// XdgUserDirsSandbox tmp_dir;
2958+//
2959+// // starts the services, including keeper-service
2960+// start_tasks();
2961+//
2962+// QSharedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser(
2963+// DBusTypes::KEEPER_SERVICE,
2964+// DBusTypes::KEEPER_USER_PATH,
2965+// dbus_test_runner.sessionConnection()
2966+// ) );
2967+//
2968+// ASSERT_TRUE(user_iface->isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message());
2969+//
2970+//}
2971+//
2972+//TEST_F(TestHelpers, BadHelperPath)
2973+//{
2974+// // starts the services, including keeper-service
2975+// start_tasks();
2976+//
2977+// BackupHelper helper("com.bar_foo_8432.13.1");
2978+//
2979+// QSignalSpy spy(&helper, &BackupHelper::state_changed);
2980+// QStringList urls;
2981+// urls << "blah" << "/tmp";
2982+// helper.start(urls);
2983+//
2984+// WAIT_FOR_SIGNALS(spy, 1, Helper::MAX_UAL_WAIT_TIME + 1000);
2985+//
2986+// ASSERT_EQ(spy.count(), 1);
2987+// QList<QVariant> arguments = spy.takeFirst();
2988+// EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::FAILED);
2989+//}
2990+//
2991+//TEST_F(TestHelpers, Inactivity)
2992+//{
2993+// // starts the services, including keeper-service
2994+// start_tasks();
2995+//
2996+// BackupHelper helper("com.bar_foo_8432.13.1");
2997+//
2998+// QSignalSpy spy(&helper, &BackupHelper::state_changed);
2999+// QStringList urls;
3000+// urls << TEST_INACTIVE_HELPER << "/tmp";
3001+// helper.start(urls);
3002+//
3003+// // wait 15 seconds at most.
3004+// // the inactive helper sleeps for 100 seconds so
3005+// // if we get the 2 signals it means it was stopped due to inactivity
3006+// // We can also check at the end for the state, which should be CANCELLED
3007+// WAIT_FOR_SIGNALS(spy, 2, BackupHelper::MAX_INACTIVITY_TIME + 2000);
3008+//
3009+// ASSERT_EQ(spy.count(), 2);
3010+// QList<QVariant> arguments = spy.takeFirst();
3011+// EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::STARTED);
3012+// arguments = spy.takeFirst();
3013+// EXPECT_EQ(qvariant_cast<Helper::State>(arguments.at(0)), Helper::State::CANCELLED);
3014+//}
3015
3016=== modified file 'tests/integration/helpers/test-helpers-base.cpp'
3017--- tests/integration/helpers/test-helpers-base.cpp 2016-11-03 08:58:51 +0000
3018+++ tests/integration/helpers/test-helpers-base.cpp 2016-11-17 00:23:33 +0000
3019@@ -179,15 +179,19 @@
3020 {
3021 return previous == "saving" || previous == "queued";
3022 }
3023+ else if (current == "restoring")
3024+ {
3025+ return previous == "restoring" || previous == "queued";
3026+ }
3027 else if (current == "finishing")
3028 {
3029- return previous == "finishing" || previous == "saving";
3030+ return previous == "finishing" || previous == "saving" || previous == "restoring";
3031 }
3032 else if (current == "complete")
3033 {
3034 // we may pass from "saving" to "complete" if we don't have enough time
3035 // to emit the "finishing" state change
3036- return previous == "complete" || previous == "finishing" || previous == "saving";
3037+ return previous == "complete" || previous == "finishing" || previous == "saving" || previous == "restoring";
3038 }
3039 else if (current == "failed")
3040 {
3041@@ -704,7 +708,7 @@
3042 return false;
3043 }
3044
3045- QSharedPointer<StorageFrameworkClient> sf_client(new StorageFrameworkClient);
3046+ QSharedPointer<StorageFrameworkClient> sf_client(new StorageFrameworkClient, [](StorageFrameworkClient* sf){sf->deleteLater();});
3047 Manifest manifest_read(sf_client, dir_name);
3048 QSignalSpy spy_read(&manifest_read, &Manifest::finished);
3049
3050@@ -716,6 +720,7 @@
3051 if (!spy_read.count())
3052 {
3053 qWarning() << "Failed reading manifest file";
3054+ sf_client.reset();
3055 return false;
3056 }
3057
3058
3059=== modified file 'tests/unit/manifest/manifest-test.cpp'
3060--- tests/unit/manifest/manifest-test.cpp 2016-10-06 14:53:44 +0000
3061+++ tests/unit/manifest/manifest-test.cpp 2016-11-17 00:23:33 +0000
3062@@ -78,7 +78,7 @@
3063
3064 g_setenv("XDG_DATA_HOME", tmp_dir.path().toLatin1().data(), true);
3065
3066- QSharedPointer<StorageFrameworkClient> sf_client(new StorageFrameworkClient);
3067+ QSharedPointer<StorageFrameworkClient> sf_client(new StorageFrameworkClient, [](StorageFrameworkClient* sf){sf->deleteLater();});
3068 Manifest manifest(sf_client, test_dir);
3069
3070 auto objects_to_test = 10;
3071
3072=== modified file 'tests/unit/storage-framework/create-uploader-test.cpp'
3073--- tests/unit/storage-framework/create-uploader-test.cpp 2016-11-02 11:31:09 +0000
3074+++ tests/unit/storage-framework/create-uploader-test.cpp 2016-11-17 00:23:33 +0000
3075@@ -86,7 +86,7 @@
3076 // create a downloader
3077 auto downloader_fut = sf_client.get_new_downloader(test_dir, test_file_name);
3078 {
3079- QFutureWatcher<sf::Downloader::SPtr> w;
3080+ QFutureWatcher<std::shared_ptr<Downloader>> w;
3081 QSignalSpy spy(&w, &decltype(w)::finished);
3082 w.setFuture(downloader_fut);
3083 assert(spy.wait());
3084@@ -107,14 +107,13 @@
3085
3086 EXPECT_EQ(downloader_content, test_content);
3087
3088- auto finish_downloader_fut = downloader->finish_download();
3089+ QSignalSpy spy_downloader(downloader.get(), &Downloader::download_finished);
3090+ downloader->finish();
3091+ if (!spy_downloader.count())
3092 {
3093- QFutureWatcher<void> w;
3094- QSignalSpy spy(&w, &decltype(w)::finished);
3095- w.setFuture(finish_downloader_fut);
3096- assert(spy.wait());
3097- ASSERT_EQ(spy.count(), 1);
3098+ spy_downloader.wait();
3099 }
3100+ EXPECT_EQ(1, spy_downloader.count());
3101
3102 // get another uploader
3103 QString test_file_name_2 = QStringLiteral("test_file2");
3104
3105=== modified file 'tests/utils/file-utils.cpp'
3106--- tests/utils/file-utils.cpp 2016-11-02 10:43:30 +0000
3107+++ tests/utils/file-utils.cpp 2016-11-17 00:23:33 +0000
3108@@ -198,8 +198,10 @@
3109 qWarning() << "File to compare:" << info2.absoluteFilePath() << "does not exist";
3110 return false;
3111 }
3112+ qDebug() << "File 1 size: " << info1.size() << info1.absoluteFilePath();
3113+ qDebug() << "File 2 size: " << info2.size() << info2.absoluteFilePath();
3114 auto checksum1 = calculate_checksum(filePath1, QCryptographicHash::Md5);
3115- auto checksum2 = calculate_checksum(filePath1, QCryptographicHash::Md5);
3116+ auto checksum2 = calculate_checksum(filePath2, QCryptographicHash::Md5);
3117 if (checksum1 != checksum2)
3118 {
3119 qWarning() << "Checksum for file:" << filePath1 << "differ";
3120
3121=== modified file 'tests/utils/storage-framework-local.cpp'
3122--- tests/utils/storage-framework-local.cpp 2016-10-28 15:11:21 +0000
3123+++ tests/utils/storage-framework-local.cpp 2016-11-17 00:23:33 +0000
3124@@ -170,4 +170,38 @@
3125 : "";
3126 }
3127
3128+bool get_storage_frameowork_file_equal_to(QString const & file_path, QString & path)
3129+{
3130+ auto const backups = get_storage_framework_files();
3131+ for (auto const& backup : backups)
3132+ {
3133+ auto const backup_filename = backup.absoluteFilePath();
3134+ if (FileUtils::compareFiles(file_path, backup_filename))
3135+ {
3136+ path = backup_filename;
3137+ return true;
3138+ }
3139+ }
3140+ return false;
3141+}
3142+
3143+bool get_storage_frameowork_file_equal_in_size_to(QString const & file_path, QString & path)
3144+{
3145+ auto const backups = get_storage_framework_files();
3146+ for (auto const& backup : backups)
3147+ {
3148+ auto const backup_filename = backup.absoluteFilePath();
3149+ QFileInfo info1(backup_filename);
3150+ QFileInfo info2(file_path);
3151+ qDebug() << "File 1 size = " << info1.size();
3152+ qDebug() << "File 2 size = " << info2.size();
3153+ if (info1.size() == info2.size())
3154+ {
3155+ path = backup_filename;
3156+ return true;
3157+ }
3158+ }
3159+ return false;
3160+}
3161+
3162 } // namespace StorageFrameworkLocalUtils
3163
3164=== modified file 'tests/utils/storage-framework-local.h'
3165--- tests/utils/storage-framework-local.h 2016-10-28 15:11:21 +0000
3166+++ tests/utils/storage-framework-local.h 2016-11-17 00:23:33 +0000
3167@@ -41,4 +41,8 @@
3168 QFileInfoList get_storage_framework_files();
3169
3170 QString get_storage_framework_dir_name();
3171+
3172+ bool get_storage_frameowork_file_equal_to(QString const & file_path, QString & path);
3173+
3174+ bool get_storage_frameowork_file_equal_in_size_to(QString const & file_path, QString & path);
3175 }

Subscribers

People subscribed via source and target branches

to all changes: