Merge lp:~michihenning/storage-framework/upload-download into lp:storage-framework/devel

Proposed by Michi Henning
Status: Merged
Approved by: Michi Henning
Approved revision: 106
Merged at revision: 79
Proposed branch: lp:~michihenning/storage-framework/upload-download
Merge into: lp:storage-framework/devel
Diff against target: 3131 lines (+1837/-204)
38 files modified
include/unity/storage/qt/Downloader.h (+27/-16)
include/unity/storage/qt/Item.h (+4/-0)
include/unity/storage/qt/StorageError.h (+2/-3)
include/unity/storage/qt/Uploader.h (+26/-14)
include/unity/storage/qt/internal/AccountImpl.h (+4/-4)
include/unity/storage/qt/internal/AccountsJobImpl.h (+3/-3)
include/unity/storage/qt/internal/DownloaderImpl.h (+71/-0)
include/unity/storage/qt/internal/Handler.h (+19/-3)
include/unity/storage/qt/internal/ItemImpl.h (+5/-5)
include/unity/storage/qt/internal/ItemJobImpl.h (+8/-8)
include/unity/storage/qt/internal/ItemListJobImpl.h (+8/-8)
include/unity/storage/qt/internal/ListJobImplBase.h (+2/-2)
include/unity/storage/qt/internal/MultiItemJobImpl.h (+4/-4)
include/unity/storage/qt/internal/MultiItemListJobImpl.h (+6/-6)
include/unity/storage/qt/internal/StorageErrorImpl.h (+0/-1)
include/unity/storage/qt/internal/UploaderImpl.h (+90/-0)
include/unity/storage/qt/internal/VoidJobImpl.h (+8/-5)
src/provider/CMakeLists.txt (+6/-1)
src/provider/internal/Handler.cpp (+0/-1)
src/qt/CMakeLists.txt (+10/-2)
src/qt/Downloader.cpp (+76/-0)
src/qt/Item.cpp (+0/-1)
src/qt/Uploader.cpp (+86/-0)
src/qt/client/CMakeLists.txt (+1/-1)
src/qt/internal/AccountImpl.cpp (+7/-7)
src/qt/internal/AccountsJobImpl.cpp (+7/-7)
src/qt/internal/DownloaderImpl.cpp (+280/-0)
src/qt/internal/ItemImpl.cpp (+71/-25)
src/qt/internal/ItemJobImpl.cpp (+10/-9)
src/qt/internal/ItemListJobImpl.cpp (+15/-15)
src/qt/internal/ListJobImplBase.cpp (+3/-3)
src/qt/internal/MultiItemJobImpl.cpp (+11/-11)
src/qt/internal/MultiItemListJobImpl.cpp (+9/-8)
src/qt/internal/StorageErrorImpl.cpp (+1/-9)
src/qt/internal/UploaderImpl.cpp (+332/-0)
src/qt/internal/VoidJobImpl.cpp (+6/-6)
tests/remote-client/MockProvider.cpp (+28/-12)
tests/remote-client/remote-client_test.cpp (+591/-4)
To merge this branch: bzr merge lp:~michihenning/storage-framework/upload-download
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Approve
Unity API Team Pending
Review via email: mp+308209@code.launchpad.net

Commit message

Download implementation.

Description of the change

Download implementation.

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)
100. By Michi Henning

Upload implementation with basic test only.

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
101. By Michi Henning

Fixed typos.

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:101
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/149/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/870/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/877
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/683/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/683
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/683/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/683
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/683/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/683/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/683
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/683/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/683
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/683/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/683/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/683
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/683/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/683
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/683/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/149/rebuild

review: Needs Fixing (continuous-integration)
102. By Michi Henning

Got rid of DeletedError (not needed). Setting error info on cancallation now.

103. By Michi Henning

Work around compiler bug on Vivid: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60420

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:103
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/150/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/871/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/878
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/684/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/684
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/684/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/684
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/684/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/684/console
    ABORTED: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/684/console
    ABORTED: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/684/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/684/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/684
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/684/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/684
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/684/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/150/rebuild

review: Needs Fixing (continuous-integration)
104. By Michi Henning

Another fix for non-const reply argument.
Added suppression for tons of warnings on Vivid from provider/internal/ProviderInterface.cpp.

105. By Michi Henning

Two more Vivid errors.

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:104
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/151/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/872/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/879
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/685/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/685/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/685
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/685/artifact/output/*zip*/output.zip
    ABORTED: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/685/console
    ABORTED: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/685/console
    ABORTED: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/685/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/685/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/685
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/685/artifact/output/*zip*/output.zip
    ABORTED: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/685/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/151/rebuild

review: Needs Fixing (continuous-integration)
106. By Michi Henning

Fixed more compiler warnings.

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

PASSED: Continuous integration, rev:105
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/152/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/873
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/880
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/686
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/686/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/686
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/686/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/686
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/686/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/686
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/686/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/686
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/686/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/686
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/686/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/686
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/686/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/686
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/686/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/686
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/686/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/152/rebuild

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

PASSED: Continuous integration, rev:106
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/153/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/874
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/881
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/687
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/687
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/687
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/687
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/687
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/687
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/687
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/687
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/687/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/687
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/687/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/153/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/unity/storage/qt/Downloader.h'
2--- include/unity/storage/qt/Downloader.h 2016-10-10 04:07:07 +0000
3+++ include/unity/storage/qt/Downloader.h 2016-10-12 08:09:09 +0000
4@@ -18,7 +18,10 @@
5
6 #pragma once
7
8-#include <QIODevice>
9+#include <unity/storage/qt/Item.h>
10+#include <unity/storage/qt/StorageError.h>
11+
12+#include <QLocalSocket>
13
14 namespace unity
15 {
16@@ -26,17 +29,20 @@
17 {
18 namespace qt
19 {
20-
21-class Item;
22-class StorageError;
23-
24-class Q_DECL_EXPORT Downloader final : public QIODevice
25+namespace internal
26+{
27+
28+class DownloaderImpl;
29+
30+} // namespace internal
31+
32+class Q_DECL_EXPORT Downloader final : public QLocalSocket
33 {
34 Q_OBJECT
35 Q_PROPERTY(bool isValid READ isValid NOTIFY statusChanged FINAL)
36- Q_PROPERTY(unity::Storage::qt::Downloader::Status status READ status NOTIFY statusChanged FINAL)
37- Q_PROPERTY(unity::Storage::qt::StorageError error READ error NOTIFY statusChanged FINAL)
38- Q_PROPERTY(unity::Storage::qt::Item item READ item NOTIFY statusChanged FINAL)
39+ Q_PROPERTY(unity::storage::qt::Downloader::Status status READ status NOTIFY statusChanged FINAL)
40+ Q_PROPERTY(unity::storage::qt::StorageError error READ error NOTIFY statusChanged FINAL)
41+ Q_PROPERTY(unity::storage::qt::Item item READ item NOTIFY statusChanged FINAL)
42
43 public:
44 enum Status { Loading, Ready, Cancelled, Finished, Error };
45@@ -45,12 +51,12 @@
46 Downloader();
47 virtual ~Downloader();
48
49- bool isValid();
50+ bool isValid() const; // Not nice, hides QLocalSocket::isValid()
51 Status status() const;
52- StorageError error() const;
53- Item item() const;
54+ StorageError error() const; // Not nice, hides QLocalSocket::error()
55+ Item item() const; // TODO: Should we keep this?
56
57- Q_INVOKABLE void finishDownload(); // TODO: finish()
58+ Q_INVOKABLE void finishDownload();
59 Q_INVOKABLE void cancel();
60
61 // TODO: will probably need QML invokable methods for reading and writing to/from QIODevice
62@@ -58,11 +64,16 @@
63 Q_SIGNALS:
64 void statusChanged(unity::storage::qt::Downloader::Status status) const;
65
66-protected:
67- virtual qint64 readData(char* data, qint64 maxSize) override;
68- virtual qint64 writeData(char const* data, qint64 maxSize) override;
69+private:
70+ Downloader(std::unique_ptr<internal::DownloaderImpl> p);
71+
72+ std::unique_ptr<internal::DownloaderImpl> p_;
73+
74+ friend class internal::DownloaderImpl;
75 };
76
77 } // namespace qt
78 } // namespace storage
79 } // namespace unity
80+
81+Q_DECLARE_METATYPE(unity::storage::qt::Downloader::Status)
82
83=== modified file 'include/unity/storage/qt/Item.h'
84--- include/unity/storage/qt/Item.h 2016-10-10 05:27:03 +0000
85+++ include/unity/storage/qt/Item.h 2016-10-12 08:09:09 +0000
86@@ -39,6 +39,8 @@
87 {
88
89 class ItemImpl;
90+class DownloaderImpl;
91+class UploaderImpl;
92
93 } // namespace internal
94
95@@ -126,6 +128,8 @@
96 std::shared_ptr<internal::ItemImpl> p_;
97
98 friend class internal::ItemImpl;
99+ friend class internal::DownloaderImpl;
100+ friend class internal::UploaderImpl;
101 };
102
103 // Note: qHash(Item) does *not* return the same hash value is std::hash<Item> because
104
105=== modified file 'include/unity/storage/qt/StorageError.h'
106--- include/unity/storage/qt/StorageError.h 2016-10-10 04:07:07 +0000
107+++ include/unity/storage/qt/StorageError.h 2016-10-12 08:09:09 +0000
108@@ -58,9 +58,8 @@
109
110 enum Type
111 {
112- NoError, LocalCommsError, RemoteCommsError, Deleted, RuntimeDestroyed, NotExists,
113- Exists, Conflict, PermissionDenied, Cancelled, LogicError, InvalidArgument, ResourceError,
114- QuotaExceeded,
115+ NoError, LocalCommsError, RemoteCommsError, RuntimeDestroyed, NotExists, Exists, Conflict,
116+ PermissionDenied, Cancelled, LogicError, InvalidArgument, ResourceError, QuotaExceeded,
117 __LAST_STORAGE_ERROR
118 };
119 Q_ENUMS(Type)
120
121=== modified file 'include/unity/storage/qt/Uploader.h'
122--- include/unity/storage/qt/Uploader.h 2016-10-10 04:07:07 +0000
123+++ include/unity/storage/qt/Uploader.h 2016-10-12 08:09:09 +0000
124@@ -18,9 +18,10 @@
125
126 #pragma once
127
128-#include <unity/storage/common.h>
129+#include <unity/storage/qt/Item.h>
130+#include <unity/storage/qt/StorageError.h>
131
132-#include <QIODevice>
133+#include <QLocalSocket>
134
135 namespace unity
136 {
137@@ -28,31 +29,37 @@
138 {
139 namespace qt
140 {
141+namespace internal
142+{
143+
144+class UploaderImpl;
145+
146+} // namespace internal
147
148 class Item;
149 class StorageError;
150
151-class Q_DECL_EXPORT Uploader final : public QIODevice
152+class Q_DECL_EXPORT Uploader final : public QLocalSocket
153 {
154 Q_OBJECT
155- Q_PROPERTY(bool isValid READ isValid NOTIFY statusChanged FINAL) // TODO: Need notify
156+ Q_PROPERTY(bool isValid READ isValid NOTIFY statusChanged FINAL)
157 Q_PROPERTY(unity::storage::qt::Uploader::Status status READ status NOTIFY statusChanged FINAL)
158- Q_PROPERTY(unity::storage::qt::StorageError READ error NOTIFY statusChanged FINAL)
159- Q_PROPERTY(unity::storage::qt::Item::ConflictPolicy policy READ policy CONSTANT FINAL)
160- Q_PROPERTY(qint64 sizeInBytes READ sizeInBytes CONSTANT FINAL)
161+ Q_PROPERTY(unity::storage::qt::StorageError error READ error NOTIFY statusChanged FINAL)
162+ Q_PROPERTY(unity::storage::qt::Item::ConflictPolicy policy READ policy NOTIFY statusChanged FINAL)
163+ Q_PROPERTY(qint64 sizeInBytes READ sizeInBytes NOTIFY statusChanged FINAL)
164 Q_PROPERTY(unity::storage::qt::Item item READ item NOTIFY statusChanged FINAL)
165
166 public:
167- enum Status { Loading, Cancelled, Finished, Error };
168+ enum Status { Loading, Ready, Cancelled, Finished, Error };
169 Q_ENUMS(Status)
170
171 Uploader();
172 virtual ~Uploader();
173
174- bool isValid() const;
175+ bool isValid() const; // Not nice, hides QLocalSocket::isValid()
176 Status status() const;
177- StorageError error() const;
178- ConflictPolicy policy() const;
179+ StorageError error() const; // Not nice, hides QLocalSocket::error()
180+ Item::ConflictPolicy policy() const;
181 qint64 sizeInBytes() const;
182 Item item() const;
183
184@@ -62,11 +69,16 @@
185 Q_SIGNALS:
186 void statusChanged(unity::storage::qt::Uploader::Status status) const;
187
188-protected:
189- virtual qint64 readData(char* data, qint64 maxSize) override;
190- virtual qint64 writeData(char const* data, qint64 maxSize) override;
191+private:
192+ Uploader(std::unique_ptr<internal::UploaderImpl> p);
193+
194+ std::unique_ptr<internal::UploaderImpl> p_;
195+
196+ friend class internal::UploaderImpl;
197 };
198
199 } // namespace qt
200 } // namespace storage
201 } // namespace unity
202+
203+Q_DECLARE_METATYPE(unity::storage::qt::Uploader::Status)
204
205=== modified file 'include/unity/storage/qt/internal/AccountImpl.h'
206--- include/unity/storage/qt/internal/AccountImpl.h 2016-09-26 08:57:05 +0000
207+++ include/unity/storage/qt/internal/AccountImpl.h 2016-10-12 08:09:09 +0000
208@@ -63,10 +63,10 @@
209
210 size_t hash() const;
211
212- std::shared_ptr<RuntimeImpl> runtime() const;
213+ std::shared_ptr<RuntimeImpl> runtime_impl() const;
214 std::shared_ptr<ProviderInterface> provider() const;
215
216- static Account make_account(std::shared_ptr<RuntimeImpl> const& runtime,
217+ static Account make_account(std::shared_ptr<RuntimeImpl> const& runtime_impl,
218 QString const& bus_name,
219 QString const& object_path,
220 QString const& owner_id,
221@@ -74,7 +74,7 @@
222 QString const& description);
223
224 private:
225- AccountImpl(std::shared_ptr<RuntimeImpl> const& runtime,
226+ AccountImpl(std::shared_ptr<RuntimeImpl> const& runtime_impl,
227 QString const& bus_name,
228 QString const& object_path,
229 QString const& owner_id,
230@@ -87,7 +87,7 @@
231 QString owner_id_;
232 QString owner_;
233 QString description_;
234- std::weak_ptr<RuntimeImpl> runtime_;
235+ std::weak_ptr<RuntimeImpl> runtime_impl_;
236 std::shared_ptr<ProviderInterface> provider_;
237
238 friend class unity::storage::qt::Account;
239
240=== modified file 'include/unity/storage/qt/internal/AccountsJobImpl.h'
241--- include/unity/storage/qt/internal/AccountsJobImpl.h 2016-09-26 02:12:30 +0000
242+++ include/unity/storage/qt/internal/AccountsJobImpl.h 2016-10-12 08:09:09 +0000
243@@ -35,7 +35,7 @@
244 {
245 Q_OBJECT
246 public:
247- AccountsJobImpl(AccountsJob* public_instance, std::shared_ptr<RuntimeImpl> const& runtime);
248+ AccountsJobImpl(AccountsJob* public_instance, std::shared_ptr<RuntimeImpl> const& runtime_impl);
249 AccountsJobImpl(AccountsJob* public_instance, StorageError const& error);
250 virtual ~AccountsJobImpl() = default;
251
252@@ -49,7 +49,7 @@
253 void timeout();
254
255 private:
256- std::shared_ptr<RuntimeImpl> get_runtime(QString const& method) const;
257+ std::shared_ptr<RuntimeImpl> get_runtime_impl(QString const& method) const;
258 void initialize_accounts();
259 AccountsJob::Status emit_status_changed(AccountsJob::Status new_status) const;
260
261@@ -57,7 +57,7 @@
262 AccountsJob::Status status_;
263 StorageError error_;
264 QList<unity::storage::qt::Account> accounts_;
265- std::weak_ptr<RuntimeImpl> const runtime_;
266+ std::weak_ptr<RuntimeImpl> const runtime_impl_;
267 QTimer timer_;
268
269 friend class unity::storage::qt::AccountsJob;
270
271=== added file 'include/unity/storage/qt/internal/DownloaderImpl.h'
272--- include/unity/storage/qt/internal/DownloaderImpl.h 1970-01-01 00:00:00 +0000
273+++ include/unity/storage/qt/internal/DownloaderImpl.h 2016-10-12 08:09:09 +0000
274@@ -0,0 +1,71 @@
275+/*
276+ * Copyright (C) 2016 Canonical Ltd
277+ *
278+ * This program is free software: you can redistribute it and/or modify
279+ * it under the terms of the GNU Lesser General Public License version 3 as
280+ * published by the Free Software Foundation.
281+ *
282+ * This program is distributed in the hope that it will be useful,
283+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
284+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
285+ * GNU Lesser General Public License for more details.
286+ *
287+ * You should have received a copy of the GNU Lesser General Public License
288+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
289+ *
290+ * Authors: Michi Henning <michi.henning@canonical.com>
291+ */
292+
293+#pragma once
294+
295+#include <unity/storage/qt/Downloader.h>
296+
297+#include <QDBusPendingReply>
298+#include <QDBusUnixFileDescriptor>
299+
300+namespace unity
301+{
302+namespace storage
303+{
304+namespace qt
305+{
306+namespace internal
307+{
308+
309+class DownloaderImpl : public QObject
310+{
311+ Q_OBJECT
312+public:
313+ DownloaderImpl(std::shared_ptr<ItemImpl> const& item_impl,
314+ QString const& method,
315+ QDBusPendingReply<QString, QDBusUnixFileDescriptor>& reply);
316+ DownloaderImpl(StorageError const& e);
317+ virtual ~DownloaderImpl();
318+
319+ bool isValid() const;
320+ Downloader::Status status() const;
321+ StorageError error() const;
322+ Item item() const;
323+
324+ void finishDownload();
325+ void cancel();
326+
327+ static Downloader* make_job(std::shared_ptr<ItemImpl> const& item_impl,
328+ QString const& method,
329+ QDBusPendingReply<QString, QDBusUnixFileDescriptor>& reply);
330+ static Downloader* make_job(StorageError const& e);
331+
332+private:
333+ Downloader* public_instance_;
334+ Downloader::Status status_;
335+ StorageError error_;
336+ std::shared_ptr<ItemImpl> item_impl_;
337+ QString download_id_;
338+ QDBusUnixFileDescriptor fd_;
339+ bool finalizing_ = false;
340+};
341+
342+} // namespace internal
343+} // namespace qt
344+} // namespace storage
345+} // namespace unity
346
347=== modified file 'include/unity/storage/qt/internal/Handler.h'
348--- include/unity/storage/qt/internal/Handler.h 2016-09-29 03:17:56 +0000
349+++ include/unity/storage/qt/internal/Handler.h 2016-10-12 08:09:09 +0000
350@@ -36,18 +36,32 @@
351 namespace internal
352 {
353
354+// TODO: HACK: The reply argument really should be passed by const reference, which also
355+// would make the explicit conversion of the call to QDBusPendingReply<QDBusArgs...>
356+// unnecessary. But this doesn't work with gcc 4.9: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60420
357+// Once we get rid of Vivid, this should be changed back to
358+//
359+// Handler(QObject* parent,
360+// QDBusPendingReply<DBusArgs...> const& reply,
361+// std::function<void(decltype(reply)&)> const& success_closure,
362+// std::function<void(StorageError const&)> const& error_closure)
363+//
364+// Unfortunately, this const error ripples through the entire call hierarchy, so
365+// the various JobImpl that process replies also need to be changed back to accept
366+// a non-const reply.
367+
368 template<typename T>
369 class Handler : public HandlerBase
370 {
371 public:
372 template<typename ... DBusArgs>
373 Handler(QObject* parent,
374- QDBusPendingReply<DBusArgs...> const& reply,
375+ QDBusPendingReply<DBusArgs...>& reply,
376 std::function<void(decltype(reply)&)> const& success_closure,
377 std::function<void(StorageError const&)> const& error_closure)
378 : HandlerBase(parent,
379 reply,
380- [this, success_closure, error_closure](QDBusPendingCallWatcher& call)
381+ [this, &reply, success_closure, error_closure](QDBusPendingCallWatcher& call)
382 {
383 if (call.isError())
384 {
385@@ -81,8 +95,10 @@
386 error_closure(e);
387 return;
388 }
389+ // TODO: See HACK above. Should just be success_closure(call);
390+ // We do the assignment to get an lvalue from the reference.
391 QDBusPendingReply<DBusArgs...> r = call;
392- success_closure(call);
393+ success_closure(r);
394 })
395 {
396 }
397
398=== modified file 'include/unity/storage/qt/internal/ItemImpl.h'
399--- include/unity/storage/qt/internal/ItemImpl.h 2016-10-10 04:07:07 +0000
400+++ include/unity/storage/qt/internal/ItemImpl.h 2016-10-12 08:09:09 +0000
401@@ -42,7 +42,7 @@
402 public:
403 ItemImpl();
404 ItemImpl(storage::internal::ItemMetadata const& md,
405- std::shared_ptr<AccountImpl> const& account);
406+ std::shared_ptr<AccountImpl> const& account_impl);
407 ItemImpl(ItemImpl const&) = default;
408 ItemImpl(ItemImpl&&) = delete;
409 ~ItemImpl() = default;
410@@ -82,9 +82,9 @@
411
412 static Item make_item(QString const& method,
413 storage::internal::ItemMetadata const& md,
414- std::shared_ptr<AccountImpl> const& account);
415+ std::shared_ptr<AccountImpl> const& account_impl);
416
417- std::shared_ptr<RuntimeImpl> runtime() const;
418+ std::shared_ptr<RuntimeImpl> runtime_impl() const;
419 std::shared_ptr<AccountImpl> account_impl() const;
420
421 private:
422@@ -98,7 +98,7 @@
423
424 bool is_valid_;
425 storage::internal::ItemMetadata md_;
426- std::shared_ptr<AccountImpl> account_;
427+ std::shared_ptr<AccountImpl> account_impl_;
428
429 friend class unity::storage::qt::Item;
430 };
431@@ -111,7 +111,7 @@
432 auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid item");
433 return T::make_job(e);
434 }
435- auto runtime = account_->runtime();
436+ auto runtime = account_impl_->runtime_impl();
437 if (!runtime || !runtime->isValid())
438 {
439 auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously");
440
441=== modified file 'include/unity/storage/qt/internal/ItemJobImpl.h'
442--- include/unity/storage/qt/internal/ItemJobImpl.h 2016-09-29 02:40:05 +0000
443+++ include/unity/storage/qt/internal/ItemJobImpl.h 2016-10-12 08:09:09 +0000
444@@ -53,24 +53,24 @@
445 StorageError error() const;
446 Item item() const;
447
448- static ItemJob* make_job(std::shared_ptr<AccountImpl> const& account,
449+ static ItemJob* make_job(std::shared_ptr<AccountImpl> const& account_impl,
450 QString const& method,
451- QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
452+ QDBusPendingReply<storage::internal::ItemMetadata>& reply,
453 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
454- static ItemJob* make_job(std::shared_ptr<ItemImpl> const&,
455+ static ItemJob* make_job(std::shared_ptr<ItemImpl> const& item_impl,
456 QString const& method,
457- QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
458+ QDBusPendingReply<storage::internal::ItemMetadata>& reply,
459 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
460 static ItemJob* make_job(StorageError const& e);
461
462 private:
463 ItemJobImpl(std::shared_ptr<AccountImpl> const& account,
464 QString const& method,
465- QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
466+ QDBusPendingReply<storage::internal::ItemMetadata>& reply,
467 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
468- ItemJobImpl(std::shared_ptr<ItemImpl> const& item,
469+ ItemJobImpl(std::shared_ptr<ItemImpl> const& item_impl,
470 QString const& method,
471- QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
472+ QDBusPendingReply<storage::internal::ItemMetadata>& reply,
473 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
474 ItemJobImpl(StorageError const& e);
475
476@@ -78,7 +78,7 @@
477 ItemJob::Status status_;
478 StorageError error_;
479 QString method_;
480- std::shared_ptr<AccountImpl> account_;
481+ std::shared_ptr<AccountImpl> account_impl_;
482 std::shared_ptr<ItemImpl> item_impl_;
483 std::function<void(storage::internal::ItemMetadata const&)> validate_;
484 Item item_;
485
486=== modified file 'include/unity/storage/qt/internal/ItemListJobImpl.h'
487--- include/unity/storage/qt/internal/ItemListJobImpl.h 2016-10-10 03:55:32 +0000
488+++ include/unity/storage/qt/internal/ItemListJobImpl.h 2016-10-12 08:09:09 +0000
489@@ -48,25 +48,25 @@
490 public:
491 virtual ~ItemListJobImpl() = default;
492
493- static ItemListJob* make_job(std::shared_ptr<AccountImpl> const& account,
494+ static ItemListJob* make_job(std::shared_ptr<AccountImpl> const& account_impl,
495 QString const& method,
496- QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
497+ QDBusPendingReply<QList<storage::internal::ItemMetadata>>& reply,
498 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
499- static ItemListJob* make_job(std::shared_ptr<ItemImpl> const& item,
500+ static ItemListJob* make_job(std::shared_ptr<ItemImpl> const& item_impl,
501 QString const& method,
502- QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
503+ QDBusPendingReply<QList<storage::internal::ItemMetadata>>& reply,
504 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
505 static ItemListJob* make_job(StorageError const& error);
506
507 private:
508 ItemListJobImpl() = default;
509- ItemListJobImpl(std::shared_ptr<AccountImpl> const& account,
510+ ItemListJobImpl(std::shared_ptr<AccountImpl> const& account_impl,
511 QString const& method,
512- QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
513+ QDBusPendingReply<QList<storage::internal::ItemMetadata>>& reply,
514 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
515- ItemListJobImpl(std::shared_ptr<ItemImpl> const& account,
516+ ItemListJobImpl(std::shared_ptr<ItemImpl> const& item_impl,
517 QString const& method,
518- QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
519+ QDBusPendingReply<QList<storage::internal::ItemMetadata>>& reply,
520 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
521
522 std::shared_ptr<ItemImpl> item_impl_;
523
524=== modified file 'include/unity/storage/qt/internal/ListJobImplBase.h'
525--- include/unity/storage/qt/internal/ListJobImplBase.h 2016-10-10 03:55:32 +0000
526+++ include/unity/storage/qt/internal/ListJobImplBase.h 2016-10-12 08:09:09 +0000
527@@ -49,7 +49,7 @@
528 {
529 public:
530 ListJobImplBase(); // Makes job in Finished state.
531- ListJobImplBase(std::shared_ptr<AccountImpl> const& account,
532+ ListJobImplBase(std::shared_ptr<AccountImpl> const& account_impl,
533 QString const& method,
534 std::function<void(storage::internal::ItemMetadata const&)> const& validate);
535 ListJobImplBase(StorageError const& error);
536@@ -69,7 +69,7 @@
537 ItemListJob::Status status_;
538 StorageError error_;
539 QString method_;
540- std::shared_ptr<AccountImpl> account_;
541+ std::shared_ptr<AccountImpl> account_impl_;
542 std::function<void(storage::internal::ItemMetadata const&)> validate_;
543 };
544
545
546=== modified file 'include/unity/storage/qt/internal/MultiItemJobImpl.h'
547--- include/unity/storage/qt/internal/MultiItemJobImpl.h 2016-09-30 01:48:08 +0000
548+++ include/unity/storage/qt/internal/MultiItemJobImpl.h 2016-10-12 08:09:09 +0000
549@@ -50,16 +50,16 @@
550
551 virtual ~MultiItemJobImpl() = default;
552
553- static ItemListJob* make_job(std::shared_ptr<AccountImpl> const& account,
554+ static ItemListJob* make_job(std::shared_ptr<AccountImpl> const& account_impl,
555 QString const& method,
556- ReplyType const& replies,
557+ ReplyType& replies,
558 ValidateFunc const& validate);
559
560 private:
561 MultiItemJobImpl() = default;
562- MultiItemJobImpl(std::shared_ptr<AccountImpl> const& account,
563+ MultiItemJobImpl(std::shared_ptr<AccountImpl> const& account_impl,
564 QString const& method,
565- ReplyType const& replies,
566+ ReplyType& replies,
567 ValidateFunc const& validate);
568
569 int replies_remaining_;
570
571=== modified file 'include/unity/storage/qt/internal/MultiItemListJobImpl.h'
572--- include/unity/storage/qt/internal/MultiItemListJobImpl.h 2016-10-10 03:55:32 +0000
573+++ include/unity/storage/qt/internal/MultiItemListJobImpl.h 2016-10-12 08:09:09 +0000
574@@ -47,23 +47,23 @@
575 public:
576 using ReplyType = QDBusPendingReply<QList<storage::internal::ItemMetadata>, QString>;
577 using ValidateFunc = std::function<void(storage::internal::ItemMetadata const&)>;
578- using FetchFunc = std::function<QDBusPendingReply<QList<unity::storage::internal::ItemMetadata>,
579- QString>(QString const& page_token)>;
580+ using FetchFunc = std::function
581+ <QDBusPendingReply<QList<unity::storage::internal::ItemMetadata>, QString>(QString const& page_token)>;
582
583 virtual ~MultiItemListJobImpl() = default;
584
585- static ItemListJob* make_job(std::shared_ptr<ItemImpl> const& item,
586+ static ItemListJob* make_job(std::shared_ptr<ItemImpl> const& item_impl,
587 QString const& method,
588- ReplyType const& reply,
589+ ReplyType& reply,
590 ValidateFunc const& validate,
591 FetchFunc const& fetch_next);
592 static ItemListJob* make_job(StorageError const& error);
593
594 private:
595 MultiItemListJobImpl() = default;
596- MultiItemListJobImpl(std::shared_ptr<ItemImpl> const& item,
597+ MultiItemListJobImpl(std::shared_ptr<ItemImpl> const& item_impl,
598 QString const& method,
599- ReplyType const& reply,
600+ ReplyType& reply,
601 ValidateFunc const& validate,
602 FetchFunc const& fetch_next);
603
604
605=== modified file 'include/unity/storage/qt/internal/StorageErrorImpl.h'
606--- include/unity/storage/qt/internal/StorageErrorImpl.h 2016-10-10 01:18:01 +0000
607+++ include/unity/storage/qt/internal/StorageErrorImpl.h 2016-10-12 08:09:09 +0000
608@@ -58,7 +58,6 @@
609 // Factories to make things more convenient and ensure consistency.
610 static StorageError local_comms_error(QString const& msg);
611 static StorageError remote_comms_error(QString const& msg);
612- static StorageError deleted_error(QString const& msg, QString const& item_id);
613 static StorageError runtime_destroyed_error(QString const& msg);
614 static StorageError not_exists_error(QString const& msg, QString const& key);
615 static StorageError exists_error(QString const& msg, QString const& item_id, QString const& item_name);
616
617=== added file 'include/unity/storage/qt/internal/UploaderImpl.h'
618--- include/unity/storage/qt/internal/UploaderImpl.h 1970-01-01 00:00:00 +0000
619+++ include/unity/storage/qt/internal/UploaderImpl.h 2016-10-12 08:09:09 +0000
620@@ -0,0 +1,90 @@
621+/*
622+ * Copyright (C) 2016 Canonical Ltd
623+ *
624+ * This program is free software: you can redistribute it and/or modify
625+ * it under the terms of the GNU Lesser General Public License version 3 as
626+ * published by the Free Software Foundation.
627+ *
628+ * This program is distributed in the hope that it will be useful,
629+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
630+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
631+ * GNU Lesser General Public License for more details.
632+ *
633+ * You should have received a copy of the GNU Lesser General Public License
634+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
635+ *
636+ * Authors: Michi Henning <michi.henning@canonical.com>
637+ */
638+
639+#pragma once
640+
641+#include <unity/storage/qt/Uploader.h>
642+
643+#include <QDBusPendingReply>
644+#include <QDBusUnixFileDescriptor>
645+
646+namespace unity
647+{
648+namespace storage
649+{
650+namespace internal
651+{
652+
653+class ItemMetadata;
654+
655+} // namespace internal
656+
657+namespace qt
658+{
659+namespace internal
660+{
661+
662+class UploaderImpl : public QObject
663+{
664+ Q_OBJECT
665+public:
666+ UploaderImpl(std::shared_ptr<ItemImpl> const& item_impl,
667+ QString const& method,
668+ QDBusPendingReply<QString, QDBusUnixFileDescriptor>& reply,
669+ std::function<void(storage::internal::ItemMetadata const&)> const& validate,
670+ Item::ConflictPolicy policy,
671+ qint64 size_in_bytes);
672+ UploaderImpl(StorageError const& e);
673+ virtual ~UploaderImpl();
674+
675+ bool isValid() const;
676+ Uploader::Status status() const;
677+ StorageError error() const;
678+ Item::ConflictPolicy policy() const;
679+ qint64 sizeInBytes() const;
680+ Item item() const;
681+
682+ void finishUpload();
683+ void cancel();
684+
685+ static Uploader* make_job(std::shared_ptr<ItemImpl> const& item_impl,
686+ QString const& method,
687+ QDBusPendingReply<QString, QDBusUnixFileDescriptor>& reply,
688+ std::function<void(storage::internal::ItemMetadata const&)> const& validate,
689+ Item::ConflictPolicy policy,
690+ qint64 size_in_bytes);
691+ static Uploader* make_job(StorageError const& e);
692+
693+private:
694+ Uploader* public_instance_;
695+ Uploader::Status status_;
696+ StorageError error_;
697+ QString method_;
698+ std::shared_ptr<ItemImpl> item_impl_;
699+ std::function<void(storage::internal::ItemMetadata const&)> validate_;
700+ Item::ConflictPolicy policy_ = Item::ConflictPolicy::Overwrite;
701+ qint64 size_in_bytes_ = 0;
702+ QString upload_id_;
703+ QDBusUnixFileDescriptor fd_;
704+ bool finalizing_ = false;
705+};
706+
707+} // namespace internal
708+} // namespace qt
709+} // namespace storage
710+} // namespace unity
711
712=== modified file 'include/unity/storage/qt/internal/VoidJobImpl.h'
713--- include/unity/storage/qt/internal/VoidJobImpl.h 2016-09-28 04:37:14 +0000
714+++ include/unity/storage/qt/internal/VoidJobImpl.h 2016-10-12 08:09:09 +0000
715@@ -22,7 +22,10 @@
716
717 #include <unity/storage/qt/StorageError.h>
718
719+#pragma GCC diagnostic push
720+#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
721 #include <QDBusPendingReply>
722+#pragma GCC diagnostic pop
723
724 namespace unity
725 {
726@@ -45,22 +48,22 @@
727 VoidJob::Status status() const;
728 StorageError error() const;
729
730- static VoidJob* make_job(std::shared_ptr<ItemImpl> const& item,
731+ static VoidJob* make_job(std::shared_ptr<ItemImpl> const& item_impl,
732 QString const& method,
733- QDBusPendingReply<void> const& reply);
734+ QDBusPendingReply<void>& reply);
735 static VoidJob* make_job(StorageError const& e);
736
737 private:
738- VoidJobImpl(std::shared_ptr<ItemImpl> const& item,
739+ VoidJobImpl(std::shared_ptr<ItemImpl> const& item_impl,
740 QString const& method,
741- QDBusPendingReply<void> const& reply);
742+ QDBusPendingReply<void>& reply);
743 VoidJobImpl(StorageError const& e);
744
745 VoidJob* public_instance_;
746 VoidJob::Status status_;
747 StorageError error_;
748 QString method_;
749- std::shared_ptr<ItemImpl> item_;
750+ std::shared_ptr<ItemImpl> item_impl_;
751 };
752
753 } // namespace internal
754
755=== modified file 'src/provider/CMakeLists.txt'
756--- src/provider/CMakeLists.txt 2016-09-03 00:53:43 +0000
757+++ src/provider/CMakeLists.txt 2016-10-12 08:09:09 +0000
758@@ -6,7 +6,7 @@
759 qt5_add_dbus_interface(generated_files bus.xml businterface)
760
761 set_source_files_properties(${generated_files} PROPERTIES
762- COMPILE_FLAGS "-Wno-ctor-dtor-privacy -Wmissing-field-initializers"
763+ COMPILE_FLAGS "-Wno-ctor-dtor-privacy -Wno-missing-field-initializers"
764 GENERATED TRUE
765 )
766
767@@ -42,6 +42,11 @@
768 ${CMAKE_SOURCE_DIR}/include/unity/storage/provider/internal/TempfileUploadJobImpl.h
769 ${CMAKE_SOURCE_DIR}/include/unity/storage/provider/internal/UploadJobImpl.h
770 )
771+
772+set_source_files_properties(internal/ProviderInterface.cpp PROPERTIES
773+ COMPILE_FLAGS "-Wno-missing-field-initializers"
774+)
775+
776 add_dependencies(sf-provider-objects sf-provider-generated-files)
777 set_target_properties(sf-provider-objects PROPERTIES
778 AUTOMOC TRUE
779
780=== modified file 'src/provider/internal/Handler.cpp'
781--- src/provider/internal/Handler.cpp 2016-08-12 06:19:22 +0000
782+++ src/provider/internal/Handler.cpp 2016-10-12 08:09:09 +0000
783@@ -105,7 +105,6 @@
784 }
785 catch (std::exception const& e)
786 {
787- qDebug() << e.what();
788 marshal_exception(current_exception());
789 }
790 QMetaObject::invokeMethod(this, "send_reply", Qt::QueuedConnection);
791
792=== modified file 'src/qt/CMakeLists.txt'
793--- src/qt/CMakeLists.txt 2016-10-10 05:24:16 +0000
794+++ src/qt/CMakeLists.txt 2016-10-12 08:09:09 +0000
795@@ -9,8 +9,8 @@
796 ${CMAKE_SOURCE_DIR}/data/provider.xml
797 ProviderInterface
798 )
799-set_source_files_properties(${generated_files} PROPERTIES
800- COMPILE_FLAGS "-Wno-ctor-dtor-privacy -Wmissing-field-initializers"
801+set_source_files_properties(${generated_files} dbusmarshal.cpp PROPERTIES
802+ COMPILE_FLAGS "-Wno-ctor-dtor-privacy -Wno-missing-field-initializers"
803 GENERATED TRUE
804 )
805
806@@ -18,14 +18,17 @@
807 set(QT_CLIENT_LIB_V2_SRC
808 Account.cpp
809 AccountsJob.cpp
810+ Downloader.cpp
811 Item.cpp
812 ItemJob.cpp
813 ItemListJob.cpp
814 Runtime.cpp
815 StorageError.cpp
816+ Uploader.cpp
817 VoidJob.cpp
818 internal/AccountImpl.cpp
819 internal/AccountsJobImpl.cpp
820+ internal/DownloaderImpl.cpp
821 internal/HandlerBase.cpp
822 internal/ItemImpl.cpp
823 internal/ItemJobImpl.cpp
824@@ -37,15 +40,19 @@
825 internal/StorageErrorImpl.cpp
826 internal/unmarshal_error.cpp
827 internal/validate.cpp
828+ internal/UploaderImpl.cpp
829 internal/VoidJobImpl.cpp
830 ${generated_files}
831 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/Account.h
832 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/AccountsJob.h
833+ ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/Downloader.h
834 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/Item.h
835 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/ItemJob.h
836 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/ItemListJob.h
837 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/Runtime.h
838+ ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/Uploader.h
839 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/VoidJob.h
840+ ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/DownloaderImpl.h
841 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/AccountsJobImpl.h
842 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/HandlerBase.h
843 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/ItemJobImpl.h
844@@ -53,6 +60,7 @@
845 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/ListJobImplBase.h
846 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/MultiItemJobImpl.h
847 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/MultiItemListJobImpl.h
848+ ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/UploaderImpl.h
849 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/VoidJobImpl.h
850 )
851
852
853=== added file 'src/qt/Downloader.cpp'
854--- src/qt/Downloader.cpp 1970-01-01 00:00:00 +0000
855+++ src/qt/Downloader.cpp 2016-10-12 08:09:09 +0000
856@@ -0,0 +1,76 @@
857+/*
858+ * Copyright (C) 2016 Canonical Ltd
859+ *
860+ * This program is free software: you can redistribute it and/or modify
861+ * it under the terms of the GNU Lesser General Public License version 3 as
862+ * published by the Free Software Foundation.
863+ *
864+ * This program is distributed in the hope that it will be useful,
865+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
866+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
867+ * GNU Lesser General Public License for more details.
868+ *
869+ * You should have received a copy of the GNU Lesser General Public License
870+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
871+ *
872+ * Authors: Michi Henning <michi.henning@canonical.com>
873+ */
874+
875+#include <unity/storage/qt/Downloader.h>
876+
877+#include <unity/storage/qt/internal/DownloaderImpl.h>
878+
879+#include <cassert>
880+
881+using namespace std;
882+
883+namespace unity
884+{
885+namespace storage
886+{
887+namespace qt
888+{
889+
890+Downloader::Downloader() = default;
891+
892+Downloader::Downloader(unique_ptr<internal::DownloaderImpl> p)
893+ : p_(move(p))
894+{
895+ assert(p_);
896+}
897+
898+Downloader::~Downloader() = default;
899+
900+bool Downloader::isValid() const
901+{
902+ return p_->isValid();
903+}
904+
905+Downloader::Status Downloader::status() const
906+{
907+ return p_->status();
908+}
909+
910+StorageError Downloader::error() const
911+{
912+ return p_->error();
913+}
914+
915+Item Downloader::item() const
916+{
917+ return p_->item();
918+}
919+
920+void Downloader::finishDownload()
921+{
922+ p_->finishDownload();
923+}
924+
925+void Downloader::cancel()
926+{
927+ p_->cancel();
928+}
929+
930+} // namespace qt
931+} // namespace storage
932+} // namespace unity
933
934=== modified file 'src/qt/Item.cpp'
935--- src/qt/Item.cpp 2016-09-28 04:37:14 +0000
936+++ src/qt/Item.cpp 2016-10-12 08:09:09 +0000
937@@ -20,7 +20,6 @@
938 #include <unity/storage/qt/internal/ItemImpl.h>
939
940 #include <cassert>
941-#include <QDebug> // TODO: remove this
942
943 using namespace std;
944
945
946=== added file 'src/qt/Uploader.cpp'
947--- src/qt/Uploader.cpp 1970-01-01 00:00:00 +0000
948+++ src/qt/Uploader.cpp 2016-10-12 08:09:09 +0000
949@@ -0,0 +1,86 @@
950+/*
951+ * Copyright (C) 2016 Canonical Ltd
952+ *
953+ * This program is free software: you can redistribute it and/or modify
954+ * it under the terms of the GNU Lesser General Public License version 3 as
955+ * published by the Free Software Foundation.
956+ *
957+ * This program is distributed in the hope that it will be useful,
958+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
959+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
960+ * GNU Lesser General Public License for more details.
961+ *
962+ * You should have received a copy of the GNU Lesser General Public License
963+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
964+ *
965+ * Authors: Michi Henning <michi.henning@canonical.com>
966+ */
967+
968+#include <unity/storage/qt/Uploader.h>
969+
970+#include <unity/storage/qt/internal/UploaderImpl.h>
971+
972+#include <cassert>
973+
974+using namespace std;
975+
976+namespace unity
977+{
978+namespace storage
979+{
980+namespace qt
981+{
982+
983+Uploader::Uploader() = default;
984+
985+Uploader::Uploader(unique_ptr<internal::UploaderImpl> p)
986+ : p_(move(p))
987+{
988+ assert(p_);
989+}
990+
991+Uploader::~Uploader() = default;
992+
993+bool Uploader::isValid() const
994+{
995+ return p_->isValid();
996+}
997+
998+Uploader::Status Uploader::status() const
999+{
1000+ return p_->status();
1001+}
1002+
1003+StorageError Uploader::error() const
1004+{
1005+ return p_->error();
1006+}
1007+
1008+Item::ConflictPolicy Uploader::policy() const
1009+{
1010+ return p_->policy();
1011+}
1012+
1013+qint64 Uploader::sizeInBytes() const
1014+{
1015+ return p_->sizeInBytes();
1016+}
1017+
1018+Item Uploader::item() const
1019+{
1020+ return p_->item();
1021+}
1022+
1023+void Uploader::finishUpload()
1024+{
1025+ p_->finishUpload();
1026+}
1027+
1028+void Uploader::cancel()
1029+{
1030+ p_->cancel();
1031+}
1032+
1033+} // namespace qt
1034+} // namespace storage
1035+} // namespace unity
1036
1037=== modified file 'src/qt/client/CMakeLists.txt'
1038--- src/qt/client/CMakeLists.txt 2016-09-21 05:03:19 +0000
1039+++ src/qt/client/CMakeLists.txt 2016-10-12 08:09:09 +0000
1040@@ -88,7 +88,7 @@
1041 ProviderInterface
1042 )
1043 set_source_files_properties(${generated_files} PROPERTIES
1044- COMPILE_FLAGS "-Wno-ctor-dtor-privacy -Wmissing-field-initializers"
1045+ COMPILE_FLAGS "-Wno-ctor-dtor-privacy -Wno-missing-field-initializers"
1046 GENERATED TRUE
1047 )
1048
1049
1050=== modified file 'src/qt/internal/AccountImpl.cpp'
1051--- src/qt/internal/AccountImpl.cpp 2016-09-29 02:40:05 +0000
1052+++ src/qt/internal/AccountImpl.cpp 2016-10-12 08:09:09 +0000
1053@@ -47,7 +47,7 @@
1054 {
1055 }
1056
1057-AccountImpl::AccountImpl(shared_ptr<RuntimeImpl> const& runtime,
1058+AccountImpl::AccountImpl(shared_ptr<RuntimeImpl> const& runtime_impl,
1059 QString const& bus_name,
1060 QString const& object_path,
1061 QString const& owner_id,
1062@@ -59,8 +59,8 @@
1063 , owner_id_(owner_id)
1064 , owner_(owner)
1065 , description_(description)
1066- , runtime_(runtime)
1067- , provider_(new ProviderInterface(bus_name, object_path, runtime->connection()))
1068+ , runtime_impl_(runtime_impl)
1069+ , provider_(new ProviderInterface(bus_name, object_path, runtime_impl->connection()))
1070 {
1071 assert(!bus_name.isEmpty());
1072 assert(!object_path.isEmpty());
1073@@ -85,7 +85,7 @@
1074 {
1075 QString const method = "Account::roots()";
1076
1077- auto runtime = runtime_.lock();
1078+ auto runtime = runtime_impl_.lock();
1079 if (!is_valid_)
1080 {
1081 auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid account");
1082@@ -121,7 +121,7 @@
1083 auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid account");
1084 return ItemJobImpl::make_job(e);
1085 }
1086- auto runtime = runtime_.lock();
1087+ auto runtime = runtime_impl_.lock();
1088 if (!runtime || !runtime->isValid())
1089 {
1090 auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously");
1091@@ -199,9 +199,9 @@
1092 return !operator<(other);
1093 }
1094
1095-shared_ptr<RuntimeImpl> AccountImpl::runtime() const
1096+shared_ptr<RuntimeImpl> AccountImpl::runtime_impl() const
1097 {
1098- return runtime_.lock();
1099+ return runtime_impl_.lock();
1100 }
1101
1102 shared_ptr<ProviderInterface> AccountImpl::provider() const
1103
1104=== modified file 'src/qt/internal/AccountsJobImpl.cpp'
1105--- src/qt/internal/AccountsJobImpl.cpp 2016-09-29 03:17:56 +0000
1106+++ src/qt/internal/AccountsJobImpl.cpp 2016-10-12 08:09:09 +0000
1107@@ -50,13 +50,13 @@
1108
1109 } // namespace
1110
1111-AccountsJobImpl::AccountsJobImpl(AccountsJob* public_instance, shared_ptr<RuntimeImpl> const& runtime)
1112+AccountsJobImpl::AccountsJobImpl(AccountsJob* public_instance, shared_ptr<RuntimeImpl> const& runtime_impl)
1113 : public_instance_(public_instance)
1114 , status_(AccountsJob::Status::Loading)
1115- , runtime_(runtime)
1116+ , runtime_impl_(runtime_impl)
1117 {
1118 assert(public_instance);
1119- assert(runtime);
1120+ assert(runtime_impl);
1121
1122 initialize_accounts();
1123 }
1124@@ -89,7 +89,7 @@
1125
1126 QList<Account> AccountsJobImpl::accounts() const
1127 {
1128- auto runtime = get_runtime("AccountsJob::accounts()");
1129+ auto runtime = get_runtime_impl("AccountsJob::accounts()");
1130 if (!runtime)
1131 {
1132 return QList<Account>();
1133@@ -131,9 +131,9 @@
1134 return new_status;
1135 }
1136
1137-shared_ptr<RuntimeImpl> AccountsJobImpl::get_runtime(QString const& method) const
1138+shared_ptr<RuntimeImpl> AccountsJobImpl::get_runtime_impl(QString const& method) const
1139 {
1140- auto runtime = runtime_.lock();
1141+ auto runtime = runtime_impl_.lock();
1142 if (!runtime || !runtime->isValid())
1143 {
1144 QString msg = method + ": Runtime was destroyed previously";
1145@@ -146,7 +146,7 @@
1146
1147 void AccountsJobImpl::initialize_accounts()
1148 {
1149- auto runtime = get_runtime("AccountsJob()");
1150+ auto runtime = get_runtime_impl("AccountsJob()");
1151 assert(runtime);
1152
1153 auto manager = runtime->accounts_manager();
1154
1155=== added file 'src/qt/internal/DownloaderImpl.cpp'
1156--- src/qt/internal/DownloaderImpl.cpp 1970-01-01 00:00:00 +0000
1157+++ src/qt/internal/DownloaderImpl.cpp 2016-10-12 08:09:09 +0000
1158@@ -0,0 +1,280 @@
1159+/*
1160+ * Copyright (C) 2016 Canonical Ltd
1161+ *
1162+ * This program is free software: you can redistribute it and/or modify
1163+ * it under the terms of the GNU Lesser General Public License version 3 as
1164+ * published by the Free Software Foundation.
1165+ *
1166+ * This program is distributed in the hope that it will be useful,
1167+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1168+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1169+ * GNU Lesser General Public License for more details.
1170+ *
1171+ * You should have received a copy of the GNU Lesser General Public License
1172+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1173+ *
1174+ * Authors: Michi Henning <michi.henning@canonical.com>
1175+ */
1176+
1177+#include <unity/storage/qt/internal/DownloaderImpl.h>
1178+
1179+#include "ProviderInterface.h"
1180+#include <unity/storage/qt/internal/Handler.h>
1181+#include <unity/storage/qt/internal/ItemImpl.h>
1182+#include <unity/storage/qt/internal/VoidJobImpl.h>
1183+#include <unity/storage/qt/ItemJob.h>
1184+
1185+#include <cassert>
1186+
1187+using namespace std;
1188+
1189+namespace unity
1190+{
1191+namespace storage
1192+{
1193+namespace qt
1194+{
1195+namespace internal
1196+{
1197+
1198+DownloaderImpl::DownloaderImpl(shared_ptr<ItemImpl> const& item_impl,
1199+ QString const& method,
1200+ QDBusPendingReply<QString, QDBusUnixFileDescriptor>& reply)
1201+ : status_(Downloader::Status::Loading)
1202+ , item_impl_(item_impl)
1203+{
1204+ assert(item_impl);
1205+ assert(!method.isEmpty());
1206+
1207+ auto process_reply = [this, method](decltype(reply)& r)
1208+ {
1209+ if (status_ != Downloader::Status::Loading)
1210+ {
1211+ return; // Don't transition to a final state more than once.
1212+ }
1213+
1214+ auto runtime = item_impl_->runtime_impl();
1215+ if (!runtime || !runtime->isValid())
1216+ {
1217+ QString msg = method + ": Runtime was destroyed previously";
1218+ error_ = StorageErrorImpl::runtime_destroyed_error(msg);
1219+ public_instance_->abort();
1220+ public_instance_->setErrorString(msg);
1221+ status_ = Downloader::Status::Error;
1222+ Q_EMIT public_instance_->statusChanged(status_);
1223+ return;
1224+ }
1225+
1226+ download_id_ = r.argumentAt<0>();
1227+ fd_ = r.argumentAt<1>();
1228+ if (fd_.fileDescriptor() < 0)
1229+ {
1230+ // LCOV_EXCL_START
1231+ QString msg = method + ": invalid file descriptor returned by provider";
1232+ qCritical().noquote() << msg;
1233+ error_ = StorageErrorImpl::local_comms_error(msg);
1234+ public_instance_->abort();
1235+ public_instance_->setErrorString(msg);
1236+ status_ = Downloader::Status::Error;
1237+ Q_EMIT public_instance_->statusChanged(status_);
1238+ return;
1239+ // LCOV_EXCL_STOP
1240+ }
1241+
1242+ public_instance_->setSocketDescriptor(fd_.fileDescriptor(), QLocalSocket::ConnectedState, QIODevice::ReadOnly);
1243+ status_ = Downloader::Status::Ready;
1244+ Q_EMIT public_instance_->statusChanged(status_);
1245+ };
1246+
1247+ auto process_error = [this](StorageError const& error)
1248+ {
1249+ // TODO: This does not set the method
1250+ error_ = error;
1251+ status_ = Downloader::Status::Error;
1252+ public_instance_->abort();
1253+ public_instance_->setErrorString(error.errorString());
1254+ Q_EMIT public_instance_->statusChanged(status_);
1255+ };
1256+
1257+ new Handler<storage::internal::ItemMetadata>(this, reply, process_reply, process_error);
1258+}
1259+
1260+DownloaderImpl::DownloaderImpl(StorageError const& e)
1261+ : status_(Downloader::Status::Error)
1262+ , error_(e)
1263+{
1264+}
1265+
1266+DownloaderImpl::~DownloaderImpl()
1267+{
1268+ switch (status_)
1269+ {
1270+ case Downloader::Status::Loading:
1271+ case Downloader::Status::Finished:
1272+ case Downloader::Status::Cancelled:
1273+ case Downloader::Status::Error:
1274+ break;
1275+ case Downloader::Status::Ready:
1276+ public_instance_->abort();
1277+ break;
1278+ default:
1279+ abort(); // Impossible. // LCOV_EXCL_LINE
1280+ }
1281+}
1282+
1283+bool DownloaderImpl::isValid() const
1284+{
1285+ return status_ != Downloader::Status::Error && status_ != Downloader::Status::Cancelled;
1286+}
1287+
1288+Downloader::Status DownloaderImpl::status() const
1289+{
1290+ return status_;
1291+}
1292+
1293+StorageError DownloaderImpl::error() const
1294+{
1295+ return error_;
1296+}
1297+
1298+Item DownloaderImpl::item() const
1299+{
1300+ if (status_ == Downloader::Status::Error)
1301+ {
1302+ return Item();
1303+ }
1304+ return Item(item_impl_);
1305+}
1306+
1307+void DownloaderImpl::finishDownload()
1308+{
1309+ static QString const method = "Downloader::finishDownload()";
1310+
1311+ // If we encountered an error earlier or were cancelled, or if finishDownload() was
1312+ // called already, we ignore the call.
1313+ if (status_ == Downloader::Status::Error || status_ == Downloader::Status::Cancelled || finalizing_)
1314+ {
1315+ return;
1316+ }
1317+
1318+ // Complain if we are asked to finalize while in the Loading or Finished state.
1319+ if (status_ != Downloader::Ready)
1320+ {
1321+ QString msg = method + ": cannot finalize while Downloader is not in the Ready state";
1322+ error_ = StorageErrorImpl::logic_error(msg);
1323+ public_instance_->abort();
1324+ public_instance_->setErrorString(msg);
1325+ status_ = Downloader::Status::Error;
1326+ Q_EMIT public_instance_->statusChanged(status_);
1327+ return;
1328+ }
1329+
1330+ auto runtime = item_impl_->runtime_impl();
1331+ if (!runtime || !runtime->isValid())
1332+ {
1333+ QString msg = method + ": Runtime was destroyed previously";
1334+ error_ = StorageErrorImpl::runtime_destroyed_error(msg);
1335+ status_ = Downloader::Status::Error;
1336+ Q_EMIT public_instance_->statusChanged(status_);
1337+ return;
1338+ }
1339+
1340+ finalizing_ = true;
1341+ auto reply = item_impl_->account_impl()->provider()->FinishDownload(download_id_);
1342+
1343+ auto process_reply = [this](decltype(reply)&)
1344+ {
1345+ if (status_ == Downloader::Status::Cancelled || status_ == Downloader::Status::Error)
1346+ {
1347+ return; // Don't transition to a final state more than once.
1348+ }
1349+
1350+ auto runtime = item_impl_->runtime_impl();
1351+ if (!runtime || !runtime->isValid())
1352+ {
1353+ QString msg = method + ": Runtime was destroyed previously";
1354+ error_ = StorageErrorImpl::runtime_destroyed_error(msg);
1355+ public_instance_->abort();
1356+ public_instance_->setErrorString(msg);
1357+ status_ = Downloader::Status::Error;
1358+ Q_EMIT public_instance_->statusChanged(status_);
1359+ return;
1360+ }
1361+
1362+ status_ = Downloader::Status::Finished;
1363+ Q_EMIT public_instance_->statusChanged(status_);
1364+ };
1365+
1366+ auto process_error = [this](StorageError const& error)
1367+ {
1368+ if (status_ != Downloader::Status::Ready)
1369+ {
1370+ return; // Don't transition to a final state more than once.
1371+ }
1372+
1373+ // TODO: this doesn't set the method
1374+ error_ = error;
1375+ public_instance_->abort();
1376+ public_instance_->setErrorString(error.errorString());
1377+ status_ = Downloader::Status::Error;
1378+ Q_EMIT public_instance_->statusChanged(status_);
1379+ };
1380+
1381+ new Handler<void>(this, reply, process_reply, process_error);
1382+}
1383+
1384+void DownloaderImpl::cancel()
1385+{
1386+ static QString const method = "Downloader::cancel()";
1387+
1388+ // If we are in a final state already, ignore the call.
1389+ if ( status_ == Downloader::Status::Error
1390+ || status_ == Downloader::Status::Finished
1391+ || status_ == Downloader::Status::Cancelled)
1392+ {
1393+ return;
1394+ }
1395+ auto runtime = item_impl_->runtime_impl();
1396+ if (!runtime || !runtime->isValid())
1397+ {
1398+ QString msg = method + ": Runtime was destroyed previously";
1399+ error_ = StorageErrorImpl::runtime_destroyed_error(msg);
1400+ status_ = Downloader::Status::Error;
1401+ Q_EMIT public_instance_->statusChanged(status_);
1402+ return;
1403+ }
1404+
1405+ QString msg = method + ": download was cancelled";
1406+ error_ = StorageErrorImpl::cancelled_error(msg);
1407+ public_instance_->abort();
1408+ public_instance_->setErrorString(msg);
1409+ status_ = Downloader::Status::Cancelled;
1410+ Q_EMIT public_instance_->statusChanged(status_);
1411+}
1412+
1413+Downloader* DownloaderImpl::make_job(shared_ptr<ItemImpl> const& item_impl,
1414+ QString const& method,
1415+ QDBusPendingReply<QString, QDBusUnixFileDescriptor>& reply)
1416+{
1417+ unique_ptr<DownloaderImpl> impl(new DownloaderImpl(item_impl, method, reply));
1418+ auto downloader = new Downloader(move(impl));
1419+ downloader->p_->public_instance_ = downloader;
1420+ return downloader;
1421+}
1422+
1423+Downloader* DownloaderImpl::make_job(StorageError const& e)
1424+{
1425+ unique_ptr<DownloaderImpl> impl(new DownloaderImpl(e));
1426+ auto downloader = new Downloader(move(impl));
1427+ downloader->p_->public_instance_ = downloader;
1428+ QMetaObject::invokeMethod(downloader,
1429+ "statusChanged",
1430+ Qt::QueuedConnection,
1431+ Q_ARG(unity::storage::qt::Downloader::Status, downloader->p_->status_));
1432+ return downloader;
1433+}
1434+
1435+} // namespace internal
1436+} // namespace qt
1437+} // namespace storage
1438+} // namespace unity
1439
1440=== modified file 'src/qt/internal/ItemImpl.cpp'
1441--- src/qt/internal/ItemImpl.cpp 2016-10-10 23:31:31 +0000
1442+++ src/qt/internal/ItemImpl.cpp 2016-10-12 08:09:09 +0000
1443@@ -20,10 +20,12 @@
1444
1445 #include "ProviderInterface.h"
1446 #include <unity/storage/provider/metadata_keys.h>
1447+#include <unity/storage/qt/internal/DownloaderImpl.h>
1448 #include <unity/storage/qt/internal/ItemJobImpl.h>
1449 #include <unity/storage/qt/internal/ItemListJobImpl.h>
1450 #include <unity/storage/qt/internal/MultiItemJobImpl.h>
1451 #include <unity/storage/qt/internal/MultiItemListJobImpl.h>
1452+#include <unity/storage/qt/internal/UploaderImpl.h>
1453 #include <unity/storage/qt/internal/VoidJobImpl.h>
1454 #include <unity/storage/qt/internal/validate.h>
1455
1456@@ -49,12 +51,12 @@
1457 }
1458
1459 ItemImpl::ItemImpl(storage::internal::ItemMetadata const& md,
1460- std::shared_ptr<AccountImpl> const& account)
1461+ std::shared_ptr<AccountImpl> const& account_impl)
1462 : is_valid_(true)
1463 , md_(md)
1464- , account_(account)
1465+ , account_impl_(account_impl)
1466 {
1467- assert(account);
1468+ assert(account_impl);
1469 }
1470
1471 QString ItemImpl::itemId() const
1472@@ -69,7 +71,7 @@
1473
1474 Account ItemImpl::account() const
1475 {
1476- return is_valid_ ? account_ : Account();
1477+ return is_valid_ ? account_impl_ : Account();
1478 }
1479
1480 QString ItemImpl::etag() const
1481@@ -88,7 +90,7 @@
1482 case storage::ItemType::root:
1483 return Item::Type::Root;
1484 default:
1485- abort(); // LCOV_EXCL_LINE // Impossible
1486+ abort(); // Impossible. // LCOV_EXCL_LINE
1487 }
1488 }
1489
1490@@ -133,7 +135,7 @@
1491 QList<QDBusPendingReply<storage::internal::ItemMetadata>> replies;
1492 for (auto const& id : md_.parent_ids)
1493 {
1494- auto reply = account_->provider()->Metadata(id);
1495+ auto reply = account_impl_->provider()->Metadata(id);
1496 replies.append(reply);
1497 }
1498
1499@@ -147,7 +149,7 @@
1500 }
1501 };
1502
1503- return MultiItemJobImpl::make_job(account_, method, replies, validate);
1504+ return MultiItemJobImpl::make_job(account_impl_, method, replies, validate);
1505 }
1506
1507 ItemJob* ItemImpl::copy(Item const& newParent, QString const& newName) const
1508@@ -172,7 +174,7 @@
1509 }
1510 };
1511
1512- auto reply = account_->provider()->Copy(md_.item_id, newParent.itemId(), newName);
1513+ auto reply = account_impl_->provider()->Copy(md_.item_id, newParent.itemId(), newName);
1514 auto This = const_pointer_cast<ItemImpl>(shared_from_this());
1515 return ItemJobImpl::make_job(This, method, reply, validate);
1516 }
1517@@ -205,7 +207,7 @@
1518 }
1519 };
1520
1521- auto reply = account_->provider()->Move(md_.item_id, newParent.itemId(), newName);
1522+ auto reply = account_impl_->provider()->Move(md_.item_id, newParent.itemId(), newName);
1523 auto This = const_pointer_cast<ItemImpl>(shared_from_this());
1524 return ItemJobImpl::make_job(This, method, reply, validate);
1525 }
1526@@ -225,19 +227,63 @@
1527 return VoidJobImpl::make_job(e);
1528 }
1529
1530- auto reply = account_->provider()->Delete(md_.item_id);
1531+ auto reply = account_impl_->provider()->Delete(md_.item_id);
1532 auto This = const_pointer_cast<ItemImpl>(shared_from_this());
1533 return VoidJobImpl::make_job(This, method, reply);
1534 }
1535
1536 Uploader* ItemImpl::createUploader(Item::ConflictPolicy policy, qint64 sizeInBytes) const
1537 {
1538- return nullptr; // TODO
1539+ QString const method = "Item::createUploader()";
1540+
1541+ auto invalid_job = check_invalid_or_destroyed<UploaderImpl>(method);
1542+ if (invalid_job)
1543+ {
1544+ return invalid_job;
1545+ }
1546+ if (md_.type != storage::ItemType::file)
1547+ {
1548+ auto e = StorageErrorImpl::logic_error(method + ": cannot upload to a directory");
1549+ return UploaderImpl::make_job(e);
1550+ }
1551+ if (sizeInBytes < 0)
1552+ {
1553+ auto e = StorageErrorImpl::logic_error(method + ": size must be >= 0");
1554+ return UploaderImpl::make_job(e);
1555+ }
1556+
1557+ auto validate = [method](storage::internal::ItemMetadata const& md)
1558+ {
1559+ if (md.type != storage::ItemType::file)
1560+ {
1561+ throw StorageErrorImpl::local_comms_error(method + ": impossible directory item returned by provider");
1562+ }
1563+ };
1564+
1565+ auto etag = policy == Item::ConflictPolicy::Overwrite ? "" : md_.etag;
1566+ auto reply = account_impl_->provider()->Update(md_.item_id, sizeInBytes, etag);
1567+ auto This = const_pointer_cast<ItemImpl>(shared_from_this());
1568+ return UploaderImpl::make_job(This, method, reply, validate, policy, sizeInBytes);
1569 }
1570
1571 Downloader* ItemImpl::createDownloader() const
1572 {
1573- return nullptr; // TODO
1574+ QString const method = "Item::createDownloader()";
1575+
1576+ auto invalid_job = check_invalid_or_destroyed<DownloaderImpl>(method);
1577+ if (invalid_job)
1578+ {
1579+ return invalid_job;
1580+ }
1581+ if (md_.type != storage::ItemType::file)
1582+ {
1583+ auto e = StorageErrorImpl::logic_error(method + ": cannot download a directory");
1584+ return DownloaderImpl::make_job(e);
1585+ }
1586+
1587+ auto reply = account_impl_->provider()->Download(md_.item_id);
1588+ auto This = const_pointer_cast<ItemImpl>(shared_from_this());
1589+ return DownloaderImpl::make_job(This, method, reply);
1590 }
1591
1592 ItemListJob* ItemImpl::list() const
1593@@ -267,10 +313,10 @@
1594
1595 auto fetch_next = [this](QString const& page_token)
1596 {
1597- return account_->provider()->List(md_.item_id, page_token);
1598+ return account_impl_->provider()->List(md_.item_id, page_token);
1599 };
1600
1601- auto reply = account_->provider()->List(md_.item_id, "");
1602+ auto reply = account_impl_->provider()->List(md_.item_id, "");
1603 auto This = const_pointer_cast<ItemImpl>(shared_from_this());
1604 return MultiItemListJobImpl::make_job(This, method, reply, validate, fetch_next);
1605 }
1606@@ -294,7 +340,7 @@
1607 {
1608 };
1609
1610- auto reply = account_->provider()->Lookup(md_.item_id, name);
1611+ auto reply = account_impl_->provider()->Lookup(md_.item_id, name);
1612 auto This = const_pointer_cast<ItemImpl>(shared_from_this());
1613 return ItemListJobImpl::make_job(This, method, reply, validate);
1614 }
1615@@ -325,7 +371,7 @@
1616 throw StorageErrorImpl::local_comms_error(msg);
1617 };
1618
1619- auto reply = account_->provider()->CreateFolder(md_.item_id, name);
1620+ auto reply = account_impl_->provider()->CreateFolder(md_.item_id, name);
1621 auto This = const_pointer_cast<ItemImpl>(shared_from_this());
1622 return ItemJobImpl::make_job(This, method, reply, validate);
1623 }
1624@@ -350,7 +396,7 @@
1625 if (is_valid_)
1626 {
1627 return other.is_valid_
1628- && *account_ == *other.account_
1629+ && *account_impl_ == *other.account_impl_
1630 && md_.item_id == other.md_.item_id;
1631 }
1632 return !other.is_valid_;
1633@@ -372,11 +418,11 @@
1634 return false;
1635 }
1636 assert(is_valid_ && other.is_valid_);
1637- if (*account_ < *other.account_)
1638+ if (*account_impl_ < *other.account_impl_)
1639 {
1640 return true;
1641 }
1642- if (*account_ > *other.account_)
1643+ if (*account_impl_ > *other.account_impl_)
1644 {
1645 return false;
1646 }
1647@@ -405,28 +451,28 @@
1648 return 0;
1649 }
1650 size_t hash = 0;
1651- boost::hash_combine(hash, account_->hash());
1652+ boost::hash_combine(hash, account_impl_->hash());
1653 boost::hash_combine(hash, qHash(md_.item_id));
1654 return hash;
1655 }
1656
1657 Item ItemImpl::make_item(QString const& method,
1658 storage::internal::ItemMetadata const& md,
1659- std::shared_ptr<AccountImpl> const& account)
1660+ std::shared_ptr<AccountImpl> const& account_impl)
1661 {
1662 validate(method, md); // Throws if no good.
1663- auto p = make_shared<ItemImpl>(md, account);
1664+ auto p = make_shared<ItemImpl>(md, account_impl);
1665 return Item(p);
1666 }
1667
1668-shared_ptr<RuntimeImpl> ItemImpl::runtime() const
1669+shared_ptr<RuntimeImpl> ItemImpl::runtime_impl() const
1670 {
1671- return account_->runtime();
1672+ return account_impl_->runtime_impl();
1673 }
1674
1675 shared_ptr<AccountImpl> ItemImpl::account_impl() const
1676 {
1677- return account_;
1678+ return account_impl_;
1679 }
1680
1681 } // namespace internal
1682
1683=== modified file 'src/qt/internal/ItemJobImpl.cpp'
1684--- src/qt/internal/ItemJobImpl.cpp 2016-09-30 01:48:08 +0000
1685+++ src/qt/internal/ItemJobImpl.cpp 2016-10-12 08:09:09 +0000
1686@@ -36,22 +36,22 @@
1687 namespace internal
1688 {
1689
1690-ItemJobImpl::ItemJobImpl(shared_ptr<AccountImpl> const& account,
1691+ItemJobImpl::ItemJobImpl(shared_ptr<AccountImpl> const& account_impl,
1692 QString const& method,
1693- QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
1694+ QDBusPendingReply<storage::internal::ItemMetadata>& reply,
1695 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
1696 : status_(ItemJob::Status::Loading)
1697 , method_(method)
1698- , account_(account)
1699+ , account_impl_(account_impl)
1700 , validate_(validate)
1701 {
1702 assert(!method.isEmpty());
1703- assert(account);
1704+ assert(account_impl);
1705 assert(validate);
1706
1707 auto process_reply = [this](decltype(reply)& r)
1708 {
1709- auto runtime = account_->runtime();
1710+ auto runtime = account_impl_->runtime_impl();
1711 if (!runtime || !runtime->isValid())
1712 {
1713 error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
1714@@ -64,12 +64,13 @@
1715 try
1716 {
1717 validate_(metadata);
1718- item_ = ItemImpl::make_item(method_, metadata, account_);
1719+ item_ = ItemImpl::make_item(method_, metadata, account_impl_);
1720 status_ = ItemJob::Status::Finished;
1721 }
1722 catch (StorageError const& e)
1723 {
1724 // Bad metadata received from provider, validate_() or make_item() have logged it.
1725+ // TODO: This does not set the method.
1726 error_ = e;
1727 status_ = ItemJob::Status::Error;
1728 }
1729@@ -88,7 +89,7 @@
1730
1731 ItemJobImpl::ItemJobImpl(shared_ptr<ItemImpl> const& item,
1732 QString const& method,
1733- QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
1734+ QDBusPendingReply<storage::internal::ItemMetadata>& reply,
1735 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
1736 : ItemJobImpl(item->account_impl(), method, reply, validate)
1737 {
1738@@ -123,7 +124,7 @@
1739
1740 ItemJob* ItemJobImpl::make_job(shared_ptr<AccountImpl> const& account,
1741 QString const& method,
1742- QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
1743+ QDBusPendingReply<storage::internal::ItemMetadata>& reply,
1744 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
1745 {
1746 unique_ptr<ItemJobImpl> impl(new ItemJobImpl(account, method, reply, validate));
1747@@ -134,7 +135,7 @@
1748
1749 ItemJob* ItemJobImpl::make_job(shared_ptr<ItemImpl> const& item,
1750 QString const& method,
1751- QDBusPendingReply<storage::internal::ItemMetadata> const& reply,
1752+ QDBusPendingReply<storage::internal::ItemMetadata>& reply,
1753 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
1754 {
1755 unique_ptr<ItemJobImpl> impl(new ItemJobImpl(item, method, reply, validate));
1756
1757=== modified file 'src/qt/internal/ItemListJobImpl.cpp'
1758--- src/qt/internal/ItemListJobImpl.cpp 2016-10-10 03:55:32 +0000
1759+++ src/qt/internal/ItemListJobImpl.cpp 2016-10-12 08:09:09 +0000
1760@@ -35,15 +35,15 @@
1761 namespace internal
1762 {
1763
1764-ItemListJobImpl::ItemListJobImpl(shared_ptr<AccountImpl> const& account,
1765+ItemListJobImpl::ItemListJobImpl(shared_ptr<AccountImpl> const& account_impl,
1766 QString const& method,
1767- QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
1768+ QDBusPendingReply<QList<storage::internal::ItemMetadata>>& reply,
1769 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
1770- : ListJobImplBase(account, method, validate)
1771+ : ListJobImplBase(account_impl, method, validate)
1772 {
1773 auto process_reply = [this](decltype(reply)& r)
1774 {
1775- auto runtime = account_->runtime();
1776+ auto runtime = account_impl_->runtime_impl();
1777 if (!runtime || !runtime->isValid())
1778 {
1779 error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
1780@@ -59,7 +59,7 @@
1781 try
1782 {
1783 validate_(md);
1784- auto item = ItemImpl::make_item(method_, md, account_);
1785+ auto item = ItemImpl::make_item(method_, md, account_impl_);
1786 items.append(item);
1787 }
1788 catch (StorageError const&)
1789@@ -86,32 +86,32 @@
1790 new Handler<QList<storage::internal::ItemMetadata>>(this, reply, process_reply, process_error);
1791 }
1792
1793-ItemListJobImpl::ItemListJobImpl(shared_ptr<ItemImpl> const& item,
1794+ItemListJobImpl::ItemListJobImpl(shared_ptr<ItemImpl> const& item_impl,
1795 QString const& method,
1796- QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
1797+ QDBusPendingReply<QList<storage::internal::ItemMetadata>>& reply,
1798 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
1799- : ItemListJobImpl(item->account_impl(), method, reply, validate)
1800+ : ItemListJobImpl(item_impl->account_impl(), method, reply, validate)
1801 {
1802- item_impl_ = item;
1803+ item_impl_ = item_impl;
1804 }
1805
1806-ItemListJob* ItemListJobImpl::make_job(shared_ptr<AccountImpl> const& account,
1807+ItemListJob* ItemListJobImpl::make_job(shared_ptr<AccountImpl> const& account_impl,
1808 QString const& method,
1809- QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
1810+ QDBusPendingReply<QList<storage::internal::ItemMetadata>>& reply,
1811 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
1812 {
1813- unique_ptr<ItemListJobImpl> impl(new ItemListJobImpl(account, method, reply, validate));
1814+ unique_ptr<ItemListJobImpl> impl(new ItemListJobImpl(account_impl, method, reply, validate));
1815 auto job = new ItemListJob(move(impl));
1816 job->p_->set_public_instance(job);
1817 return job;
1818 }
1819
1820-ItemListJob* ItemListJobImpl::make_job(shared_ptr<ItemImpl> const& item,
1821+ItemListJob* ItemListJobImpl::make_job(shared_ptr<ItemImpl> const& item_impl,
1822 QString const& method,
1823- QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply,
1824+ QDBusPendingReply<QList<storage::internal::ItemMetadata>>& reply,
1825 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
1826 {
1827- unique_ptr<ItemListJobImpl> impl(new ItemListJobImpl(item, method, reply, validate));
1828+ unique_ptr<ItemListJobImpl> impl(new ItemListJobImpl(item_impl, method, reply, validate));
1829 auto job = new ItemListJob(move(impl));
1830 job->p_->set_public_instance(job);
1831 return job;
1832
1833=== modified file 'src/qt/internal/ListJobImplBase.cpp'
1834--- src/qt/internal/ListJobImplBase.cpp 2016-09-29 03:17:56 +0000
1835+++ src/qt/internal/ListJobImplBase.cpp 2016-10-12 08:09:09 +0000
1836@@ -41,16 +41,16 @@
1837 {
1838 }
1839
1840-ListJobImplBase::ListJobImplBase(shared_ptr<AccountImpl> const& account,
1841+ListJobImplBase::ListJobImplBase(shared_ptr<AccountImpl> const& account_impl,
1842 QString const& method,
1843 std::function<void(storage::internal::ItemMetadata const&)> const& validate)
1844 : status_(ItemListJob::Status::Loading)
1845 , method_(method)
1846- , account_(account)
1847+ , account_impl_(account_impl)
1848 , validate_(validate)
1849 {
1850 assert(!method.isEmpty());
1851- assert(account);
1852+ assert(account_impl);
1853 assert(validate);
1854 }
1855
1856
1857=== modified file 'src/qt/internal/MultiItemJobImpl.cpp'
1858--- src/qt/internal/MultiItemJobImpl.cpp 2016-09-30 01:48:08 +0000
1859+++ src/qt/internal/MultiItemJobImpl.cpp 2016-10-12 08:09:09 +0000
1860@@ -35,15 +35,15 @@
1861 namespace internal
1862 {
1863
1864-MultiItemJobImpl::MultiItemJobImpl(shared_ptr<AccountImpl> const& account,
1865+MultiItemJobImpl::MultiItemJobImpl(shared_ptr<AccountImpl> const& account_impl,
1866 QString const& method,
1867- ReplyType const& replies,
1868+ ReplyType& replies,
1869 ValidateFunc const& validate)
1870- : ListJobImplBase(account, method, validate)
1871+ : ListJobImplBase(account_impl, method, validate)
1872 , replies_remaining_(replies.size())
1873 {
1874 assert(!method.isEmpty());
1875- assert(account);
1876+ assert(account_impl);
1877 assert(validate);
1878
1879 // We ask the provider for the metadata for each of this item's parents.
1880@@ -52,7 +52,7 @@
1881 // If anything goes wrong at all, we report the first error and then ignore all
1882 // other replies.
1883
1884- auto process_reply = [this](QDBusPendingReply<storage::internal::ItemMetadata> const& r)
1885+ auto process_reply = [this](QDBusPendingReply<storage::internal::ItemMetadata>& r)
1886 {
1887 if (status_ != ItemListJob::Status::Loading)
1888 {
1889@@ -61,7 +61,7 @@
1890
1891 --replies_remaining_;
1892
1893- auto runtime = account_->runtime();
1894+ auto runtime = account_impl_->runtime_impl();
1895 if (!runtime || !runtime->isValid())
1896 {
1897 error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
1898@@ -75,7 +75,7 @@
1899 try
1900 {
1901 validate_(metadata);
1902- item = ItemImpl::make_item(method_, metadata, account_);
1903+ item = ItemImpl::make_item(method_, metadata, account_impl_);
1904 }
1905 catch (StorageError const& e)
1906 {
1907@@ -110,18 +110,18 @@
1908 Q_EMIT public_instance_->statusChanged(status_);
1909 };
1910
1911- for (auto const& reply : replies)
1912+ for (auto& reply : replies)
1913 {
1914 new Handler<storage::internal::ItemMetadata>(this, reply, process_reply, process_error);
1915 }
1916 }
1917
1918-ItemListJob* MultiItemJobImpl::make_job(shared_ptr<AccountImpl> const& account,
1919+ItemListJob* MultiItemJobImpl::make_job(shared_ptr<AccountImpl> const& account_impl,
1920 QString const& method,
1921- ReplyType const& replies,
1922+ ReplyType& replies,
1923 ValidateFunc const& validate)
1924 {
1925- unique_ptr<MultiItemJobImpl> impl(new MultiItemJobImpl(account, method, replies, validate));
1926+ unique_ptr<MultiItemJobImpl> impl(new MultiItemJobImpl(account_impl, method, replies, validate));
1927 auto job = new ItemListJob(move(impl));
1928 job->p_->set_public_instance(job);
1929 return job;
1930
1931=== modified file 'src/qt/internal/MultiItemListJobImpl.cpp'
1932--- src/qt/internal/MultiItemListJobImpl.cpp 2016-10-10 04:07:07 +0000
1933+++ src/qt/internal/MultiItemListJobImpl.cpp 2016-10-12 08:09:09 +0000
1934@@ -35,17 +35,17 @@
1935 namespace internal
1936 {
1937
1938-MultiItemListJobImpl::MultiItemListJobImpl(shared_ptr<ItemImpl> const& item,
1939+MultiItemListJobImpl::MultiItemListJobImpl(shared_ptr<ItemImpl> const& item_impl,
1940 QString const& method,
1941- ReplyType const& reply,
1942+ ReplyType& reply,
1943 ValidateFunc const& validate,
1944 FetchFunc const& fetch_next)
1945- : ListJobImplBase(item->account_impl(), method, validate)
1946+ : ListJobImplBase(item_impl->account_impl(), method, validate)
1947 , fetch_next_(fetch_next)
1948 {
1949 assert(fetch_next);
1950
1951- item_impl_ = item;
1952+ item_impl_ = item_impl;
1953
1954 process_reply_ = [this](ReplyType const& r)
1955 {
1956@@ -53,7 +53,7 @@
1957 {
1958 return;
1959 }
1960- auto runtime = item_impl_->account_impl()->runtime();
1961+ auto runtime = item_impl_->account_impl()->runtime_impl();
1962 if (!runtime || !runtime->isValid())
1963 {
1964 error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
1965@@ -69,7 +69,7 @@
1966 try
1967 {
1968 validate_(md);
1969- auto item = ItemImpl::make_item(method_, md, account_);
1970+ auto item = ItemImpl::make_item(method_, md, account_impl_);
1971 items.append(item);
1972 }
1973 catch (StorageError const& e)
1974@@ -96,7 +96,8 @@
1975 }
1976 else
1977 {
1978- new Handler<ReplyType>(this, fetch_next_(token), process_reply_, process_error_);
1979+ auto reply = fetch_next_(token);
1980+ new Handler<ReplyType>(this, reply, process_reply_, process_error_);
1981 }
1982 };
1983
1984@@ -115,7 +116,7 @@
1985
1986 ItemListJob* MultiItemListJobImpl::make_job(shared_ptr<ItemImpl> const& item,
1987 QString const& method,
1988- ReplyType const& reply,
1989+ ReplyType& reply,
1990 ValidateFunc const& validate,
1991 FetchFunc const& fetch_next)
1992 {
1993
1994=== modified file 'src/qt/internal/StorageErrorImpl.cpp'
1995--- src/qt/internal/StorageErrorImpl.cpp 2016-10-10 04:07:07 +0000
1996+++ src/qt/internal/StorageErrorImpl.cpp 2016-10-12 08:09:09 +0000
1997@@ -40,7 +40,6 @@
1998 QStringLiteral("NoError"),
1999 QStringLiteral("LocalCommsError"),
2000 QStringLiteral("RemoteCommsError"),
2001- QStringLiteral("Deleted"),
2002 QStringLiteral("RuntimeDestroyed"),
2003 QStringLiteral("NotExists"),
2004 QStringLiteral("Exists"),
2005@@ -86,8 +85,7 @@
2006 StorageErrorImpl::StorageErrorImpl(StorageError::Type type, QString const& msg, QString const& key)
2007 : StorageErrorImpl(type)
2008 {
2009- assert( type == StorageError::Type::Deleted
2010- || type == StorageError::Type::NotExists);
2011+ assert(type == StorageError::Type::NotExists);
2012 assert(!msg.isEmpty());
2013
2014 message_ = msg;
2015@@ -177,12 +175,6 @@
2016 return StorageError(move(p));
2017 }
2018
2019-StorageError StorageErrorImpl::deleted_error(QString const& msg, QString const& item_id)
2020-{
2021- unique_ptr<StorageErrorImpl> p(new StorageErrorImpl(StorageError::Type::Deleted, msg, item_id));
2022- return StorageError(move(p));
2023-}
2024-
2025 StorageError StorageErrorImpl::runtime_destroyed_error(QString const& msg)
2026 {
2027 unique_ptr<StorageErrorImpl> p(new StorageErrorImpl(StorageError::Type::RuntimeDestroyed, msg));
2028
2029=== added file 'src/qt/internal/UploaderImpl.cpp'
2030--- src/qt/internal/UploaderImpl.cpp 1970-01-01 00:00:00 +0000
2031+++ src/qt/internal/UploaderImpl.cpp 2016-10-12 08:09:09 +0000
2032@@ -0,0 +1,332 @@
2033+/*
2034+ * Copyright (C) 2016 Canonical Ltd
2035+ *
2036+ * This program is free software: you can redistribute it and/or modify
2037+ * it under the terms of the GNU Lesser General Public License version 3 as
2038+ * published by the Free Software Foundation.
2039+ *
2040+ * This program is distributed in the hope that it will be useful,
2041+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2042+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2043+ * GNU Lesser General Public License for more details.
2044+ *
2045+ * You should have received a copy of the GNU Lesser General Public License
2046+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2047+ *
2048+ * Authors: Michi Henning <michi.henning@canonical.com>
2049+ */
2050+
2051+#include <unity/storage/qt/internal/UploaderImpl.h>
2052+
2053+#include "ProviderInterface.h"
2054+#include <unity/storage/qt/internal/Handler.h>
2055+#include <unity/storage/qt/internal/ItemImpl.h>
2056+#include <unity/storage/qt/internal/VoidJobImpl.h>
2057+#include <unity/storage/qt/ItemJob.h>
2058+
2059+#include <cassert>
2060+
2061+using namespace std;
2062+
2063+namespace unity
2064+{
2065+namespace storage
2066+{
2067+namespace qt
2068+{
2069+namespace internal
2070+{
2071+
2072+UploaderImpl::UploaderImpl(shared_ptr<ItemImpl> const& item_impl,
2073+ QString const& method,
2074+ QDBusPendingReply<QString, QDBusUnixFileDescriptor>& reply,
2075+ std::function<void(storage::internal::ItemMetadata const&)> const& validate,
2076+ Item::ConflictPolicy policy,
2077+ qint64 size_in_bytes)
2078+ : status_(Uploader::Status::Loading)
2079+ , method_(method)
2080+ , item_impl_(item_impl)
2081+ , validate_(validate)
2082+ , policy_(policy)
2083+ , size_in_bytes_(size_in_bytes)
2084+{
2085+ assert(item_impl);
2086+ assert(validate);
2087+ assert(!method.isEmpty());
2088+ assert(size_in_bytes >= 0);
2089+
2090+ auto process_reply = [this, method](decltype(reply)& r)
2091+ {
2092+ if (status_ != Uploader::Status::Loading)
2093+ {
2094+ return; // Don't transition to a final state more than once.
2095+ }
2096+
2097+ auto runtime = item_impl_->runtime_impl();
2098+ if (!runtime || !runtime->isValid())
2099+ {
2100+ QString msg = method + ": Runtime was destroyed previously";
2101+ error_ = StorageErrorImpl::runtime_destroyed_error(msg);
2102+ public_instance_->abort();
2103+ public_instance_->setErrorString(msg);
2104+ status_ = Uploader::Status::Error;
2105+ Q_EMIT public_instance_->statusChanged(status_);
2106+ return;
2107+ }
2108+
2109+ upload_id_ = r.argumentAt<0>();
2110+ fd_ = r.argumentAt<1>();
2111+ if (fd_.fileDescriptor() < 0)
2112+ {
2113+ // LCOV_EXCL_START
2114+ QString msg = method + ": invalid file descriptor returned by provider";
2115+ qCritical().noquote() << msg;
2116+ error_ = StorageErrorImpl::local_comms_error(msg);
2117+ public_instance_->abort();
2118+ public_instance_->setErrorString(msg);
2119+ status_ = Uploader::Status::Error;
2120+ Q_EMIT public_instance_->statusChanged(status_);
2121+ return;
2122+ // LCOV_EXCL_STOP
2123+ }
2124+
2125+ public_instance_->setSocketDescriptor(fd_.fileDescriptor(), QLocalSocket::ConnectedState, QIODevice::WriteOnly);
2126+ status_ = Uploader::Status::Ready;
2127+ Q_EMIT public_instance_->statusChanged(status_);
2128+ };
2129+
2130+ auto process_error = [this](StorageError const& error)
2131+ {
2132+ // TODO: This does not set the method
2133+ error_ = error;
2134+ status_ = Uploader::Status::Error;
2135+ public_instance_->abort();
2136+ public_instance_->setErrorString(error.errorString());
2137+ Q_EMIT public_instance_->statusChanged(status_);
2138+ };
2139+
2140+ new Handler<storage::internal::ItemMetadata>(this, reply, process_reply, process_error);
2141+}
2142+
2143+UploaderImpl::UploaderImpl(StorageError const& e)
2144+ : status_(Uploader::Status::Error)
2145+ , error_(e)
2146+{
2147+}
2148+
2149+UploaderImpl::~UploaderImpl()
2150+{
2151+ switch (status_)
2152+ {
2153+ case Uploader::Status::Loading:
2154+ case Uploader::Status::Finished:
2155+ case Uploader::Status::Cancelled:
2156+ case Uploader::Status::Error:
2157+ break;
2158+ case Uploader::Status::Ready:
2159+ public_instance_->abort();
2160+ break;
2161+ default:
2162+ abort(); // Impossible. // LCOV_EXCL_LINE
2163+ }
2164+}
2165+
2166+bool UploaderImpl::isValid() const
2167+{
2168+ return status_ != Uploader::Status::Error && status_ != Uploader::Status::Cancelled;
2169+}
2170+
2171+Uploader::Status UploaderImpl::status() const
2172+{
2173+ return status_;
2174+}
2175+
2176+StorageError UploaderImpl::error() const
2177+{
2178+ return error_;
2179+}
2180+
2181+Item::ConflictPolicy UploaderImpl::policy() const
2182+{
2183+ return policy_;
2184+}
2185+
2186+qint64 UploaderImpl::sizeInBytes() const
2187+{
2188+ return size_in_bytes_;
2189+}
2190+
2191+Item UploaderImpl::item() const
2192+{
2193+ if (status_ == Uploader::Status::Error || status_ == Uploader::Status::Cancelled)
2194+ {
2195+ return Item();
2196+ }
2197+ return Item(item_impl_);
2198+}
2199+
2200+void UploaderImpl::finishUpload()
2201+{
2202+ static QString const method = "Uploader::finishUpload()";
2203+
2204+ // If we encountered an error earlier or were cancelled, or if finishUpload() was
2205+ // called already, we ignore the call.
2206+ if (status_ == Uploader::Status::Error || status_ == Uploader::Status::Cancelled || finalizing_)
2207+ {
2208+ return;
2209+ }
2210+
2211+ // Complain if we are asked to finalize while in the Loading or Finished state.
2212+ if (status_ != Uploader::Ready)
2213+ {
2214+ QString msg = method + ": cannot finalize while Uploader is not in the Ready state";
2215+ error_ = StorageErrorImpl::logic_error(msg);
2216+ public_instance_->abort();
2217+ public_instance_->setErrorString(msg);
2218+ status_ = Uploader::Status::Error;
2219+ Q_EMIT public_instance_->statusChanged(status_);
2220+ return;
2221+ }
2222+
2223+ auto runtime = item_impl_->runtime_impl();
2224+ if (!runtime || !runtime->isValid())
2225+ {
2226+ QString msg = method + ": Runtime was destroyed previously";
2227+ error_ = StorageErrorImpl::runtime_destroyed_error(msg);
2228+ status_ = Uploader::Status::Error;
2229+ Q_EMIT public_instance_->statusChanged(status_);
2230+ return;
2231+ }
2232+
2233+ finalizing_ = true;
2234+ public_instance_->disconnectFromServer();
2235+ auto reply = item_impl_->account_impl()->provider()->FinishUpload(upload_id_);
2236+
2237+ auto process_reply = [this](decltype(reply)& r)
2238+ {
2239+ if (status_ == Uploader::Status::Cancelled || status_ == Uploader::Status::Error)
2240+ {
2241+ return; // Don't transition to a final state more than once.
2242+ }
2243+
2244+ auto runtime = item_impl_->runtime_impl();
2245+ if (!runtime || !runtime->isValid())
2246+ {
2247+ QString msg = method + ": Runtime was destroyed previously";
2248+ error_ = StorageErrorImpl::runtime_destroyed_error(msg);
2249+ public_instance_->abort();
2250+ public_instance_->setErrorString(msg);
2251+ status_ = Uploader::Status::Error;
2252+ Q_EMIT public_instance_->statusChanged(status_);
2253+ return;
2254+ }
2255+
2256+ auto metadata = r.value();
2257+ try
2258+ {
2259+ validate_(metadata);
2260+ item_impl_ = make_shared<ItemImpl>(metadata, item_impl_->account_impl());
2261+ status_ = Uploader::Status::Finished;
2262+ }
2263+ catch (StorageError const& e)
2264+ {
2265+ // Bad metadata received from provider, validate_() or make_item() have logged it.
2266+ // TODO: This does not set the method.
2267+ error_ = e;
2268+ status_ = Uploader::Status::Error;
2269+ }
2270+ Q_EMIT public_instance_->statusChanged(status_);
2271+ };
2272+
2273+ auto process_error = [this](StorageError const& error)
2274+ {
2275+ if (status_ != Uploader::Status::Ready)
2276+ {
2277+ return; // Don't transition to a final state more than once.
2278+ }
2279+
2280+ // TODO: this doesn't set the method
2281+ error_ = error;
2282+ public_instance_->abort();
2283+ public_instance_->setErrorString(error.errorString());
2284+ status_ = Uploader::Status::Error;
2285+ Q_EMIT public_instance_->statusChanged(status_);
2286+ };
2287+
2288+ new Handler<void>(this, reply, process_reply, process_error);
2289+}
2290+
2291+void UploaderImpl::cancel()
2292+{
2293+ static QString const method = "Uploader::cancel()";
2294+
2295+ // If we are in a final state already, ignore the call.
2296+ if ( status_ == Uploader::Status::Error
2297+ || status_ == Uploader::Status::Finished
2298+ || status_ == Uploader::Status::Cancelled)
2299+ {
2300+ return;
2301+ }
2302+ auto runtime = item_impl_->runtime_impl();
2303+ if (!runtime || !runtime->isValid())
2304+ {
2305+ QString msg = method + ": Runtime was destroyed previously";
2306+ error_ = StorageErrorImpl::runtime_destroyed_error(msg);
2307+ status_ = Uploader::Status::Error;
2308+ Q_EMIT public_instance_->statusChanged(status_);
2309+ return;
2310+ }
2311+
2312+ if (!upload_id_.isEmpty())
2313+ {
2314+ // We just send the cancel and ignore any reply because it is best-effort only.
2315+ auto reply = item_impl_->account_impl()->provider()->CancelUpload(upload_id_);
2316+
2317+ auto process_reply = [](decltype(reply)&)
2318+ {
2319+ };
2320+
2321+ auto process_error = [](StorageError const&)
2322+ {
2323+ };
2324+
2325+ new Handler<void>(this, reply, process_reply, process_error);
2326+ }
2327+
2328+ QString msg = method + ": upload was cancelled";
2329+ error_ = StorageErrorImpl::cancelled_error(msg);
2330+ public_instance_->abort();
2331+ public_instance_->setErrorString(msg);
2332+ status_ = Uploader::Status::Cancelled;
2333+ Q_EMIT public_instance_->statusChanged(status_);
2334+}
2335+
2336+Uploader* UploaderImpl::make_job(shared_ptr<ItemImpl> const& item_impl,
2337+ QString const& method,
2338+ QDBusPendingReply<QString, QDBusUnixFileDescriptor>& reply,
2339+ std::function<void(storage::internal::ItemMetadata const&)> const& validate,
2340+ Item::ConflictPolicy policy,
2341+ qint64 size_in_bytes)
2342+{
2343+ unique_ptr<UploaderImpl> impl(new UploaderImpl(item_impl, method, reply, validate, policy, size_in_bytes));
2344+ auto uploader = new Uploader(move(impl));
2345+ uploader->p_->public_instance_ = uploader;
2346+ return uploader;
2347+}
2348+
2349+Uploader* UploaderImpl::make_job(StorageError const& e)
2350+{
2351+ unique_ptr<UploaderImpl> impl(new UploaderImpl(e));
2352+ auto uploader = new Uploader(move(impl));
2353+ uploader->p_->public_instance_ = uploader;
2354+ QMetaObject::invokeMethod(uploader,
2355+ "statusChanged",
2356+ Qt::QueuedConnection,
2357+ Q_ARG(unity::storage::qt::Uploader::Status, uploader->p_->status_));
2358+ return uploader;
2359+}
2360+
2361+} // namespace internal
2362+} // namespace qt
2363+} // namespace storage
2364+} // namespace unity
2365
2366=== modified file 'src/qt/internal/VoidJobImpl.cpp'
2367--- src/qt/internal/VoidJobImpl.cpp 2016-09-29 03:17:56 +0000
2368+++ src/qt/internal/VoidJobImpl.cpp 2016-10-12 08:09:09 +0000
2369@@ -33,19 +33,19 @@
2370 namespace internal
2371 {
2372
2373-VoidJobImpl::VoidJobImpl(shared_ptr<ItemImpl> const& item,
2374+VoidJobImpl::VoidJobImpl(shared_ptr<ItemImpl> const& item_impl,
2375 QString const& method,
2376- QDBusPendingReply<void> const& reply)
2377+ QDBusPendingReply<void>& reply)
2378 : status_(VoidJob::Status::Loading)
2379 , method_(method)
2380- , item_(item)
2381+ , item_impl_(item_impl)
2382 {
2383 assert(!method_.isEmpty());
2384- assert(item);
2385+ assert(item_impl);
2386
2387 auto process_reply = [this](decltype(reply)&)
2388 {
2389- auto runtime = item_->runtime();
2390+ auto runtime = item_impl_->runtime_impl();
2391 if (!runtime || !runtime->isValid())
2392 {
2393 error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously");
2394@@ -91,7 +91,7 @@
2395
2396 VoidJob* VoidJobImpl::make_job(shared_ptr<ItemImpl> const& item,
2397 QString const& method,
2398- QDBusPendingReply<void> const& reply)
2399+ QDBusPendingReply<void>& reply)
2400 {
2401 unique_ptr<VoidJobImpl> impl(new VoidJobImpl(item, method, reply));
2402 auto job = new VoidJob(move(impl));
2403
2404=== modified file 'tests/remote-client/MockProvider.cpp'
2405--- tests/remote-client/MockProvider.cpp 2016-10-10 03:55:32 +0000
2406+++ tests/remote-client/MockProvider.cpp 2016-10-12 08:09:09 +0000
2407@@ -46,7 +46,7 @@
2408
2409 boost::future<ItemList> MockProvider::roots(Context const&)
2410 {
2411- if (cmd_ == "slow_roots")
2412+ if (cmd_ == "roots_slow")
2413 {
2414 this_thread::sleep_for(chrono::seconds(1));
2415 }
2416@@ -258,37 +258,45 @@
2417 return make_ready_future<Item>(metadata);
2418 }
2419
2420-string make_job_id()
2421-{
2422- static int last_job_id = 0;
2423- return to_string(++last_job_id);
2424-}
2425-
2426 boost::future<unique_ptr<UploadJob>> MockProvider::create_file(
2427 string const&, string const&,
2428 int64_t, string const&, bool, Context const&)
2429 {
2430- return make_ready_future<unique_ptr<UploadJob>>(new MockUploadJob(make_job_id()));
2431+ return make_ready_future<unique_ptr<UploadJob>>(new MockUploadJob());
2432 }
2433
2434 boost::future<unique_ptr<UploadJob>> MockProvider::update(
2435 string const&, int64_t, string const&, Context const&)
2436 {
2437- return make_ready_future<unique_ptr<UploadJob>>(new MockUploadJob(make_job_id()));
2438+ return make_ready_future<unique_ptr<UploadJob>>(new MockUploadJob());
2439 }
2440
2441 boost::future<unique_ptr<DownloadJob>> MockProvider::download(
2442 string const&, Context const&)
2443 {
2444- unique_ptr<DownloadJob> job(new MockDownloadJob(make_job_id()));
2445+ if (cmd_ == "download_slow")
2446+ {
2447+ this_thread::sleep_for(chrono::seconds(1));
2448+ }
2449+ if (cmd_ == "download_error")
2450+ {
2451+ unique_ptr<DownloadJob> job(new MockDownloadJob());
2452+ ResourceException e("test error", 42);
2453+ job->report_error(make_exception_ptr(e));
2454+ return make_exceptional_future<unique_ptr<DownloadJob>>(e);
2455+ }
2456+ unique_ptr<DownloadJob> job(new MockDownloadJob(cmd_));
2457 const char contents[] = "Hello world";
2458- if (write(job->write_socket(), contents, sizeof(contents)) != sizeof(contents))
2459+ if (write(job->write_socket(), contents, strlen(contents)) != int(strlen(contents)))
2460 {
2461 ResourceException e("download(): write failed", errno);
2462 job->report_error(make_exception_ptr(e));
2463 return make_exceptional_future<unique_ptr<DownloadJob>>(e);
2464 }
2465- job->report_complete();
2466+ if (cmd_ != "finish_download_error" && cmd_ != "finish_download_slow_error")
2467+ {
2468+ job->report_complete();
2469+ }
2470 return make_ready_future(std::move(job));
2471 }
2472
2473@@ -402,5 +410,13 @@
2474
2475 boost::future<void> MockDownloadJob::finish()
2476 {
2477+ if (cmd_ == "finish_download_slow" || cmd_ == "finish_download_slow_error")
2478+ {
2479+ this_thread::sleep_for(chrono::seconds(1));
2480+ }
2481+ if (cmd_ == "finish_download_error" || cmd_ == "finish_download_slow_error")
2482+ {
2483+ return make_exceptional_future<void>(NotExistsException("no such item", "item_id"));
2484+ }
2485 return make_ready_future();
2486 }
2487
2488=== modified file 'tests/remote-client/remote-client_test.cpp'
2489--- tests/remote-client/remote-client_test.cpp 2016-10-10 23:31:31 +0000
2490+++ tests/remote-client/remote-client_test.cpp 2016-10-12 08:09:09 +0000
2491@@ -54,10 +54,13 @@
2492 Account acc_;
2493 };
2494
2495+class RuntimeTest : public ProviderFixture {};
2496+
2497 class AccountTest : public RemoteClientTest {};
2498 class CopyTest : public RemoteClientTest {};
2499 class CreateFolderTest : public RemoteClientTest {};
2500 class DeleteTest : public RemoteClientTest {};
2501+class DownloadTest : public RemoteClientTest {};
2502 class GetTest : public RemoteClientTest {};
2503 class ItemTest : public RemoteClientTest {};
2504 class ListTest : public RemoteClientTest {};
2505@@ -65,7 +68,7 @@
2506 class MoveTest : public RemoteClientTest {};
2507 class ParentsTest : public RemoteClientTest {};
2508 class RootsTest : public RemoteClientTest {};
2509-class RuntimeTest : public ProviderFixture {};
2510+class UploadTest : public RemoteClientTest {};
2511
2512 TEST(Runtime, lifecycle)
2513 {
2514@@ -428,7 +431,7 @@
2515
2516 TEST_F(RootsTest, runtime_destroyed_while_item_list_job_running)
2517 {
2518- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("slow_roots")));
2519+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("roots_slow")));
2520
2521 unique_ptr<ItemListJob> j(acc_.roots());
2522 EXPECT_TRUE(j->isValid());
2523@@ -767,7 +770,7 @@
2524 auto arg = spy.takeFirst();
2525 EXPECT_EQ(VoidJob::Status::Error, qvariant_cast<VoidJob::Status>(arg.at(0)));
2526
2527- EXPECT_EQ("Item::deleteItem(): Runtime was destroyed previously", j->error().message()) << j->error().message().toStdString();
2528+ EXPECT_EQ("Item::deleteItem(): Runtime was destroyed previously", j->error().message());
2529 }
2530
2531 TEST_F(DeleteTest, invalid_item)
2532@@ -1555,7 +1558,7 @@
2533 EXPECT_FALSE(j->isValid());
2534 EXPECT_EQ(ItemJob::Status::Error, j->status());
2535 EXPECT_EQ(StorageError::Type::LogicError, j->error().type());
2536- EXPECT_EQ("LogicError: Item::copy(): newParent cannot be a file", j->error().errorString()) << j->error().errorString().toStdString();
2537+ EXPECT_EQ("LogicError: Item::copy(): newParent cannot be a file", j->error().errorString());
2538
2539 QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2540 spy.wait(SIGNAL_WAIT_TIME);
2541@@ -2234,6 +2237,590 @@
2542 EXPECT_EQ(StorageError::Type::PermissionDenied, j->error().type());
2543 }
2544
2545+// TODO: This leaks:
2546+// ==4645== 1,369 (272 direct, 1,097 indirect) bytes in 1 blocks are definitely lost in loss record 193 of 203
2547+// ==4645== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
2548+// ==4645== by 0x4FD9D0A: boost::promise<void>::promise() (future.hpp:2309)
2549+// ==4645== by 0x4FDA6F2: boost::make_ready_future() (future.hpp:3935)
2550+// ==4645== by 0x4FD96B0: unity::storage::provider::internal::DownloadJobImpl::cancel(unity::storage::provider::DownloadJob&) (DownloadJobImpl.cpp:161)
2551+// ==4645== by 0x4FEE198: void unity::storage::provider::internal::PendingJobs::cancel_job<unity::storage::provider::DownloadJob>(std::shared_ptr<unity::storage::provider::DownloadJob> const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (PendingJobs.cpp:181)
2552+// ==4645== by 0x4FEA3BF: unity::storage::provider::internal::PendingJobs::~PendingJobs() (PendingJobs.cpp:55)
2553+// ==4645== by 0x4FEA6CD: unity::storage::provider::internal::PendingJobs::~PendingJobs() (PendingJobs.cpp:61)
2554+// ==4645== by 0x4F8E927: std::default_delete<unity::storage::provider::internal::PendingJobs>::operator()(unity::storage::provider::internal::PendingJobs*) const (unique_ptr.h:76)
2555+// ==4645== by 0x4F8D85B: std::unique_ptr<unity::storage::provider::internal::PendingJobs, std::default_delete<unity::storage::provider::internal::PendingJobs> >::~unique_ptr() (unique_ptr.h:236)
2556+// ==4645== by 0x4F89449: unity::storage::provider::internal::AccountData::~AccountData() (AccountData.h:51)
2557+// ==4645== by 0x504D9A6: void __gnu_cxx::new_allocator<unity::storage::provider::internal::AccountData>::destroy<unity::storage::provider::internal::AccountData>(unity::storage::provider::internal::AccountData*) (new_allocator.h:124)
2558+// ==4645== by 0x504D8AA: void std::allocator_traits<std::allocator<unity::storage::provider::internal::AccountData> >::destroy<unity::storage::provider::internal::AccountData>(std::allocator<unity::storage::provider::internal::AccountData>&, unity::storage::provider::internal::AccountData*) (alloc_traits.h:542)
2559+
2560+TEST_F(DownloadTest, memory_leak)
2561+{
2562+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2563+
2564+ Item root;
2565+ {
2566+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2567+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2568+ spy.wait(SIGNAL_WAIT_TIME);
2569+ root = j->item();
2570+ }
2571+
2572+ Item child;
2573+ {
2574+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2575+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2576+ spy.wait(SIGNAL_WAIT_TIME);
2577+ child = j->item();
2578+ }
2579+
2580+ unique_ptr<Downloader> downloader(child.createDownloader());
2581+ EXPECT_TRUE(downloader->isValid());
2582+ EXPECT_EQ(Downloader::Status::Loading, downloader->status());
2583+ EXPECT_EQ(StorageError::NoError, downloader->error().type());
2584+ EXPECT_EQ(child, downloader->item());
2585+
2586+ {
2587+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2588+ spy.wait(SIGNAL_WAIT_TIME);
2589+ auto arg = spy.takeFirst();
2590+ EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
2591+ }
2592+}
2593+
2594+TEST_F(DownloadTest, basic)
2595+{
2596+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2597+
2598+ Item root;
2599+ {
2600+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2601+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2602+ spy.wait(SIGNAL_WAIT_TIME);
2603+ root = j->item();
2604+ }
2605+
2606+ Item child;
2607+ {
2608+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2609+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2610+ spy.wait(SIGNAL_WAIT_TIME);
2611+ child = j->item();
2612+ }
2613+
2614+ unique_ptr<Downloader> downloader(child.createDownloader());
2615+ EXPECT_TRUE(downloader->isValid());
2616+ EXPECT_EQ(Downloader::Status::Loading, downloader->status());
2617+ EXPECT_EQ(StorageError::NoError, downloader->error().type());
2618+ EXPECT_EQ(child, downloader->item());
2619+
2620+ QSignalSpy status_spy(downloader.get(), &Downloader::statusChanged);
2621+ {
2622+ QSignalSpy read_spy(downloader.get(), &Downloader::readyRead);
2623+ ASSERT_TRUE(status_spy.wait(SIGNAL_WAIT_TIME));
2624+ auto arg = status_spy.takeFirst();
2625+ EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
2626+
2627+ if (read_spy.count() != 1)
2628+ {
2629+ read_spy.wait(SIGNAL_WAIT_TIME);
2630+ }
2631+ }
2632+ auto data = downloader->readAll();
2633+ EXPECT_EQ(QByteArray("Hello world", -1), data);
2634+
2635+ downloader->finishDownload();
2636+ ASSERT_TRUE(status_spy.wait(SIGNAL_WAIT_TIME));
2637+ auto arg = status_spy.takeFirst();
2638+ EXPECT_EQ(Downloader::Status::Finished, qvariant_cast<Downloader::Status>(arg.at(0)));
2639+}
2640+
2641+TEST_F(DownloadTest, runtime_destroyed)
2642+{
2643+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2644+
2645+ Item root;
2646+ {
2647+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2648+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2649+ spy.wait(SIGNAL_WAIT_TIME);
2650+ root = j->item();
2651+ }
2652+
2653+ Item child;
2654+ {
2655+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2656+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2657+ spy.wait(SIGNAL_WAIT_TIME);
2658+ child = j->item();
2659+ }
2660+
2661+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type());
2662+
2663+ unique_ptr<Downloader> downloader(child.createDownloader());
2664+ EXPECT_FALSE(downloader->isValid());
2665+ EXPECT_EQ(Downloader::Status::Error, downloader->status());
2666+ EXPECT_EQ(StorageError::RuntimeDestroyed, downloader->error().type());
2667+ EXPECT_EQ("RuntimeDestroyed: Item::createDownloader(): Runtime was destroyed previously",
2668+ downloader->error().errorString());
2669+ EXPECT_EQ(Item(), downloader->item());
2670+
2671+ // Signal must arrive.
2672+ {
2673+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2674+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2675+ auto arg = spy.takeFirst();
2676+ EXPECT_EQ(Downloader::Status::Error, qvariant_cast<Downloader::Status>(arg.at(0)));
2677+ }
2678+}
2679+
2680+TEST_F(DownloadTest, runtime_destroyed_while_download_running)
2681+{
2682+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("download_slow")));
2683+
2684+ Item root;
2685+ {
2686+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2687+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2688+ spy.wait(SIGNAL_WAIT_TIME);
2689+ root = j->item();
2690+ }
2691+
2692+ Item child;
2693+ {
2694+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2695+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2696+ spy.wait(SIGNAL_WAIT_TIME);
2697+ child = j->item();
2698+ }
2699+
2700+ unique_ptr<Downloader> downloader(child.createDownloader());
2701+ EXPECT_TRUE(downloader->isValid());
2702+
2703+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
2704+
2705+ // Signal must arrive.
2706+ {
2707+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2708+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2709+ auto arg = spy.takeFirst();
2710+ EXPECT_EQ(Downloader::Status::Error, qvariant_cast<Downloader::Status>(arg.at(0)));
2711+ }
2712+
2713+ EXPECT_FALSE(downloader->isValid());
2714+ EXPECT_EQ(Downloader::Status::Error, downloader->status());
2715+ EXPECT_EQ(StorageError::RuntimeDestroyed, downloader->error().type());
2716+ EXPECT_EQ("RuntimeDestroyed: Item::createDownloader(): Runtime was destroyed previously",
2717+ downloader->error().errorString());
2718+ EXPECT_EQ(Item(), downloader->item());
2719+}
2720+
2721+TEST_F(DownloadTest, download_error)
2722+{
2723+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("download_error")));
2724+
2725+ Item root;
2726+ {
2727+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2728+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2729+ spy.wait(SIGNAL_WAIT_TIME);
2730+ root = j->item();
2731+ }
2732+
2733+ Item child;
2734+ {
2735+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2736+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2737+ spy.wait(SIGNAL_WAIT_TIME);
2738+ child = j->item();
2739+ }
2740+
2741+ unique_ptr<Downloader> downloader(child.createDownloader());
2742+ EXPECT_TRUE(downloader->isValid());
2743+
2744+ // Signal must arrive.
2745+ {
2746+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2747+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2748+ auto arg = spy.takeFirst();
2749+ EXPECT_EQ(Downloader::Status::Error, qvariant_cast<Downloader::Status>(arg.at(0)));
2750+ }
2751+
2752+ EXPECT_FALSE(downloader->isValid());
2753+ EXPECT_EQ(Downloader::Status::Error, downloader->status());
2754+ EXPECT_EQ(StorageError::ResourceError, downloader->error().type());
2755+ EXPECT_EQ("ResourceError: test error", downloader->error().errorString());
2756+ EXPECT_EQ(42, downloader->error().errorCode());
2757+ EXPECT_EQ(Item(), downloader->item());
2758+
2759+ // For coverage: call finishDownload() while in the Error state.
2760+ {
2761+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2762+ downloader->finishDownload();
2763+ EXPECT_FALSE(spy.wait(1000));
2764+ }
2765+}
2766+
2767+TEST_F(DownloadTest, finish_too_soon)
2768+{
2769+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2770+
2771+ Item root;
2772+ {
2773+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2774+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2775+ spy.wait(SIGNAL_WAIT_TIME);
2776+ root = j->item();
2777+ }
2778+
2779+ Item child;
2780+ {
2781+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2782+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2783+ spy.wait(SIGNAL_WAIT_TIME);
2784+ child = j->item();
2785+ }
2786+
2787+ unique_ptr<Downloader> downloader(child.createDownloader());
2788+ EXPECT_TRUE(downloader->isValid());
2789+
2790+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2791+
2792+ downloader->finishDownload();
2793+
2794+ ASSERT_EQ(1, spy.count());
2795+ auto arg = spy.takeFirst();
2796+ EXPECT_EQ(Downloader::Status::Error, qvariant_cast<Downloader::Status>(arg.at(0)));
2797+
2798+ EXPECT_FALSE(downloader->isValid());
2799+ EXPECT_EQ(Downloader::Status::Error, downloader->status());
2800+ EXPECT_EQ(StorageError::LogicError, downloader->error().type());
2801+ EXPECT_EQ("LogicError: Downloader::finishDownload(): cannot finalize while Downloader is not in the Ready state",
2802+ downloader->error().errorString());
2803+}
2804+
2805+TEST_F(DownloadTest, finish_runtime_destroyed)
2806+{
2807+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2808+
2809+ Item root;
2810+ {
2811+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2812+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2813+ spy.wait(SIGNAL_WAIT_TIME);
2814+ root = j->item();
2815+ }
2816+
2817+ Item child;
2818+ {
2819+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2820+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2821+ spy.wait(SIGNAL_WAIT_TIME);
2822+ child = j->item();
2823+ }
2824+
2825+ unique_ptr<Downloader> downloader(child.createDownloader());
2826+ EXPECT_TRUE(downloader->isValid());
2827+
2828+ {
2829+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2830+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2831+ auto arg = spy.takeFirst();
2832+ EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
2833+ }
2834+
2835+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2836+
2837+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime
2838+
2839+ downloader->finishDownload();
2840+
2841+ ASSERT_EQ(1, spy.count());
2842+ auto arg = spy.takeFirst();
2843+ EXPECT_EQ(Downloader::Status::Error, qvariant_cast<Downloader::Status>(arg.at(0)));
2844+
2845+ EXPECT_FALSE(downloader->isValid());
2846+ EXPECT_EQ(Downloader::Status::Error, downloader->status());
2847+ EXPECT_EQ(StorageError::RuntimeDestroyed, downloader->error().type());
2848+ EXPECT_EQ("Downloader::finishDownload(): Runtime was destroyed previously", downloader->error().message());
2849+}
2850+
2851+TEST_F(DownloadTest, finish_runtime_destroyed_while_reply_outstanding)
2852+{
2853+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("finish_download_slow")));
2854+
2855+ Item root;
2856+ {
2857+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2858+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2859+ spy.wait(SIGNAL_WAIT_TIME);
2860+ root = j->item();
2861+ }
2862+
2863+ Item child;
2864+ {
2865+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2866+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2867+ spy.wait(SIGNAL_WAIT_TIME);
2868+ child = j->item();
2869+ }
2870+
2871+ unique_ptr<Downloader> downloader(child.createDownloader());
2872+ EXPECT_TRUE(downloader->isValid());
2873+
2874+ {
2875+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2876+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2877+ auto arg = spy.takeFirst();
2878+ EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
2879+ }
2880+
2881+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2882+
2883+ downloader->finishDownload();
2884+
2885+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
2886+
2887+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2888+ auto arg = spy.takeFirst();
2889+ EXPECT_EQ(Downloader::Status::Error, qvariant_cast<Downloader::Status>(arg.at(0)));
2890+
2891+ EXPECT_FALSE(downloader->isValid());
2892+ EXPECT_EQ(Downloader::Status::Error, downloader->status());
2893+ EXPECT_EQ(StorageError::RuntimeDestroyed, downloader->error().type());
2894+ EXPECT_EQ("Downloader::finishDownload(): Runtime was destroyed previously", downloader->error().message());
2895+}
2896+
2897+TEST_F(DownloadTest, finish_twice)
2898+{
2899+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
2900+
2901+ Item root;
2902+ {
2903+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2904+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2905+ spy.wait(SIGNAL_WAIT_TIME);
2906+ root = j->item();
2907+ }
2908+
2909+ Item child;
2910+ {
2911+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2912+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2913+ spy.wait(SIGNAL_WAIT_TIME);
2914+ child = j->item();
2915+ }
2916+
2917+ unique_ptr<Downloader> downloader(child.createDownloader());
2918+ EXPECT_TRUE(downloader->isValid());
2919+
2920+ {
2921+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2922+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2923+ auto arg = spy.takeFirst();
2924+ EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
2925+ }
2926+
2927+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2928+
2929+ downloader->finishDownload();
2930+ downloader->finishDownload();
2931+
2932+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2933+ auto arg = spy.takeFirst();
2934+ EXPECT_EQ(Downloader::Status::Finished, qvariant_cast<Downloader::Status>(arg.at(0)));
2935+}
2936+
2937+TEST_F(DownloadTest, finish_error)
2938+{
2939+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("finish_download_error")));
2940+
2941+ Item root;
2942+ {
2943+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2944+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2945+ spy.wait(SIGNAL_WAIT_TIME);
2946+ root = j->item();
2947+ }
2948+
2949+ Item child;
2950+ {
2951+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2952+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2953+ spy.wait(SIGNAL_WAIT_TIME);
2954+ child = j->item();
2955+ }
2956+
2957+ unique_ptr<Downloader> downloader(child.createDownloader());
2958+ EXPECT_TRUE(downloader->isValid());
2959+
2960+ {
2961+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2962+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2963+ auto arg = spy.takeFirst();
2964+ EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
2965+ }
2966+
2967+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
2968+
2969+ downloader->finishDownload();
2970+
2971+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
2972+ auto arg = spy.takeFirst();
2973+ EXPECT_EQ(Downloader::Status::Error, qvariant_cast<Downloader::Status>(arg.at(0)));
2974+
2975+ EXPECT_FALSE(downloader->isValid());
2976+ EXPECT_EQ(Downloader::Status::Error, downloader->status());
2977+ EXPECT_EQ(StorageError::NotExists, downloader->error().type());
2978+ EXPECT_EQ("no such item", downloader->error().message());
2979+ EXPECT_EQ("item_id", downloader->error().itemId());
2980+ EXPECT_EQ("item_id", downloader->error().itemName());
2981+ EXPECT_EQ("NotExists", downloader->error().name());
2982+}
2983+
2984+TEST_F(DownloadTest, cancel)
2985+{
2986+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("finish_download_slow_error")));
2987+
2988+ Item root;
2989+ {
2990+ unique_ptr<ItemJob> j(acc_.get("root_id"));
2991+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
2992+ spy.wait(SIGNAL_WAIT_TIME);
2993+ root = j->item();
2994+ }
2995+
2996+ Item child;
2997+ {
2998+ unique_ptr<ItemJob> j(acc_.get("child_id"));
2999+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3000+ spy.wait(SIGNAL_WAIT_TIME);
3001+ child = j->item();
3002+ }
3003+
3004+ unique_ptr<Downloader> downloader(child.createDownloader());
3005+ EXPECT_TRUE(downloader->isValid());
3006+
3007+ {
3008+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
3009+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
3010+ auto arg = spy.takeFirst();
3011+ EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
3012+ }
3013+
3014+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
3015+
3016+ downloader->finishDownload();
3017+
3018+ downloader->cancel();
3019+ downloader->cancel(); // Second time for coverage
3020+
3021+ downloader->finishDownload(); // Second time for coverage
3022+
3023+ EXPECT_EQ(1, spy.count());
3024+ auto arg = spy.takeFirst();
3025+ EXPECT_EQ(Downloader::Status::Cancelled, qvariant_cast<Downloader::Status>(arg.at(0)));
3026+
3027+ EXPECT_EQ(Downloader::Status::Cancelled, downloader->status());
3028+ EXPECT_EQ(StorageError::Type::Cancelled, downloader->error().type());
3029+ EXPECT_EQ("Downloader::cancel(): download was cancelled", downloader->error().message());
3030+
3031+ // We wait here to get coverage for when the reply to a finishDownload() call
3032+ // finds the downloader in a final state.
3033+ EXPECT_FALSE(spy.wait(2000));
3034+}
3035+
3036+TEST_F(DownloadTest, cancel_runtime_destroyed)
3037+{
3038+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("finish_download_slow_error")));
3039+
3040+ Item root;
3041+ {
3042+ unique_ptr<ItemJob> j(acc_.get("root_id"));
3043+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3044+ spy.wait(SIGNAL_WAIT_TIME);
3045+ root = j->item();
3046+ }
3047+
3048+ Item child;
3049+ {
3050+ unique_ptr<ItemJob> j(acc_.get("child_id"));
3051+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3052+ spy.wait(SIGNAL_WAIT_TIME);
3053+ child = j->item();
3054+ }
3055+
3056+ unique_ptr<Downloader> downloader(child.createDownloader());
3057+ EXPECT_TRUE(downloader->isValid());
3058+
3059+ {
3060+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
3061+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
3062+ auto arg = spy.takeFirst();
3063+ EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
3064+ }
3065+
3066+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
3067+
3068+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime
3069+
3070+ downloader->cancel();
3071+
3072+ if (spy.count() == 0)
3073+ {
3074+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
3075+ }
3076+ auto arg = spy.takeFirst();
3077+ EXPECT_EQ(Downloader::Status::Error, qvariant_cast<Downloader::Status>(arg.at(0)));
3078+
3079+ EXPECT_EQ(Downloader::Status::Error, downloader->status());
3080+ EXPECT_EQ(StorageError::Type::RuntimeDestroyed, downloader->error().type());
3081+ EXPECT_EQ("Downloader::cancel(): Runtime was destroyed previously", downloader->error().message());
3082+}
3083+
3084+TEST_F(UploadTest, basic)
3085+{
3086+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
3087+
3088+ Item root;
3089+ {
3090+ unique_ptr<ItemJob> j(acc_.get("root_id"));
3091+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3092+ spy.wait(SIGNAL_WAIT_TIME);
3093+ root = j->item();
3094+ }
3095+
3096+ Item child;
3097+ {
3098+ unique_ptr<ItemJob> j(acc_.get("child_id"));
3099+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
3100+ spy.wait(SIGNAL_WAIT_TIME);
3101+ child = j->item();
3102+ }
3103+
3104+ QByteArray contents("Hello world", -1);
3105+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, contents.size()));
3106+ EXPECT_TRUE(uploader->isValid());
3107+ EXPECT_EQ(Uploader::Status::Loading, uploader->status());
3108+ EXPECT_EQ(StorageError::NoError, uploader->error().type());
3109+ EXPECT_EQ(child, uploader->item());
3110+
3111+ {
3112+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
3113+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
3114+ auto arg = spy.takeFirst();
3115+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
3116+ }
3117+
3118+ EXPECT_EQ(contents.size(), uploader->write(contents));
3119+
3120+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
3121+ uploader->finishUpload();
3122+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
3123+ auto arg = spy.takeFirst();
3124+ EXPECT_EQ(Uploader::Status::Finished, qvariant_cast<Uploader::Status>(arg.at(0)));
3125+
3126+ EXPECT_EQ(Uploader::Status::Finished, uploader->status());
3127+}
3128+
3129 int main(int argc, char** argv)
3130 {
3131 QCoreApplication app(argc, argv);

Subscribers

People subscribed via source and target branches

to all changes: