Merge lp:~michihenning/storage-framework/parents into lp:storage-framework/devel
- parents
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Michi Henning |
Approved revision: | 92 |
Merged at revision: | 74 |
Proposed branch: | lp:~michihenning/storage-framework/parents |
Merge into: | lp:storage-framework/devel |
Prerequisite: | lp:~michihenning/storage-framework/more-tests |
Diff against target: |
1841 lines (+1086/-153) 26 files modified
include/unity/storage/internal/ItemMetadata.h (+1/-3) include/unity/storage/qt/Item.h (+2/-2) include/unity/storage/qt/ItemListJob.h (+8/-4) include/unity/storage/qt/internal/Handler.h (+3/-2) include/unity/storage/qt/internal/ItemImpl.h (+1/-2) include/unity/storage/qt/internal/ItemJobImpl.h (+5/-5) include/unity/storage/qt/internal/ItemListJobImpl.h (+8/-20) include/unity/storage/qt/internal/ListJobImplBase.h (+76/-0) include/unity/storage/qt/internal/MultiItemJobImpl.h (+68/-0) include/unity/storage/qt/internal/StorageErrorImpl.h (+2/-0) include/unity/storage/qt/internal/VoidJobImpl.h (+4/-4) src/qt/CMakeLists.txt (+4/-0) src/qt/Item.cpp (+2/-9) src/qt/ItemListJob.cpp (+2/-1) src/qt/client/internal/remote_client/ItemImpl.cpp (+8/-1) src/qt/internal/AccountImpl.cpp (+14/-4) src/qt/internal/ItemImpl.cpp (+55/-8) src/qt/internal/ItemJobImpl.cpp (+5/-5) src/qt/internal/ItemListJobImpl.cpp (+9/-45) src/qt/internal/ListJobImplBase.cpp (+111/-0) src/qt/internal/MultiItemJobImpl.cpp (+135/-0) src/qt/internal/StorageErrorImpl.cpp (+37/-24) src/qt/internal/VoidJobImpl.cpp (+4/-4) tests/provider-ProviderInterface/ProviderInterface_test.cpp (+7/-7) tests/remote-client/MockProvider.cpp (+43/-2) tests/remote-client/remote-client_test.cpp (+472/-1) |
To merge this branch: | bzr merge lp:~michihenning/storage-framework/parents |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
unity-api-1-bot | continuous-integration | Approve | |
James Henstridge | Approve | ||
Review via email:
|
Commit message
Changed ItemMetadata for parent_ids to QList (from QVector).
Added parents() implementation.
Refactored ItemListJobImpl and MultiItemJobImpl to use a base class that does most of the work, so we can create an ItemListJob from both a single invocation that returns a list, and from multiple invocations that return a single item each.
Minor renaming of the make_* factory methods for brevity.
A few minor bug fixes here and there.
Lots more tests.
Description of the change
Changed ItemMetadata for parent_ids to QList (from QVector).
Added parents() implementation.
Refactored ItemListJobImpl and MultiItemJobImpl to use a base class that does most of the work, so we can create an ItemListJob from both a single invocation that returns a list, and from multiple invocations that return a single item each.
Minor renaming of the make_* factory methods for brevity.
A few minor bug fixes here and there.
Lots more tests.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
unity-api-1-bot (unity-api-1-bot) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
unity-api-1-bot (unity-api-1-bot) wrote : | # |
PASSED: Continuous integration, rev:91
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
James Henstridge (jamesh) wrote : | # |
This looks good. I've left a few minor comments that are mostly stylistic in nature rather than issues with the branch. So I'm approving the branch but will leave it up to you to top-approve when you're ready.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michi Henning (michihenning) wrote : | # |
Thanks for the review! I've commented in-line.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michi Henning (michihenning) wrote : | # |
Thanks for the review! I've commented in-line.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
unity-api-1-bot (unity-api-1-bot) wrote : | # |
PASSED: Continuous integration, rev:92
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Autolanding.
Unapproved changes made after approval.
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
unity-api-1-bot (unity-api-1-bot) : | # |
Preview Diff
1 | === modified file 'include/unity/storage/internal/ItemMetadata.h' |
2 | --- include/unity/storage/internal/ItemMetadata.h 2016-09-16 06:25:08 +0000 |
3 | +++ include/unity/storage/internal/ItemMetadata.h 2016-10-10 01:18:55 +0000 |
4 | @@ -24,9 +24,7 @@ |
5 | #pragma GCC diagnostic ignored "-Wcast-align" |
6 | #pragma GCC diagnostic ignored "-Wctor-dtor-privacy" |
7 | #pragma GCC diagnostic ignored "-Wswitch-default" |
8 | -#include <QMap> |
9 | #include <QVariant> |
10 | -#include <QVector> |
11 | #pragma GCC diagnostic pop |
12 | |
13 | namespace unity |
14 | @@ -39,7 +37,7 @@ |
15 | struct ItemMetadata |
16 | { |
17 | QString item_id; |
18 | - QVector<QString> parent_ids; |
19 | + QList<QString> parent_ids; |
20 | QString name; |
21 | QString etag; |
22 | ItemType type; |
23 | |
24 | === modified file 'include/unity/storage/qt/Item.h' |
25 | --- include/unity/storage/qt/Item.h 2016-09-26 08:57:05 +0000 |
26 | +++ include/unity/storage/qt/Item.h 2016-10-10 01:18:55 +0000 |
27 | @@ -60,7 +60,7 @@ |
28 | Q_PROPERTY(unity::storage::qt::Item::Type type READ type FINAL) |
29 | Q_PROPERTY(QVariantMap metadata READ metadata FINAL) |
30 | Q_PROPERTY(QDateTime lastModifiedTime READ lastModifiedTime FINAL) |
31 | - Q_PROPERTY(QVector<QString> parentIds READ parentIds FINAL) |
32 | + Q_PROPERTY(QList<QString> parentIds READ parentIds FINAL) |
33 | |
34 | public: |
35 | Item(); |
36 | @@ -93,7 +93,7 @@ |
37 | Type type() const; |
38 | QVariantMap metadata() const; |
39 | QDateTime lastModifiedTime() const; |
40 | - QVector<QString> parentIds() const; // TODO: should be QList |
41 | + QList<QString> parentIds() const; |
42 | |
43 | Q_INVOKABLE ItemListJob* parents() const; |
44 | Q_INVOKABLE ItemJob* copy(Item const& newParent, QString const& newName) const; |
45 | |
46 | === modified file 'include/unity/storage/qt/ItemListJob.h' |
47 | --- include/unity/storage/qt/ItemListJob.h 2016-09-26 02:12:30 +0000 |
48 | +++ include/unity/storage/qt/ItemListJob.h 2016-10-10 01:18:55 +0000 |
49 | @@ -34,7 +34,9 @@ |
50 | namespace internal |
51 | { |
52 | |
53 | +class ListJobImplBase; |
54 | class ItemListJobImpl; |
55 | +class MultiItemJobImpl; |
56 | |
57 | } // namespace internal |
58 | |
59 | @@ -63,11 +65,13 @@ |
60 | void itemsReady(QList<unity::storage::qt::Item> const& items) const; |
61 | |
62 | private: |
63 | - ItemListJob(std::unique_ptr<internal::ItemListJobImpl> p); |
64 | - |
65 | - std::unique_ptr<internal::ItemListJobImpl> const p_; |
66 | - |
67 | + ItemListJob(std::unique_ptr<internal::ListJobImplBase> p); |
68 | + |
69 | + std::unique_ptr<internal::ListJobImplBase> const p_; |
70 | + |
71 | + friend class internal::ListJobImplBase; |
72 | friend class internal::ItemListJobImpl; |
73 | + friend class internal::MultiItemJobImpl; |
74 | }; |
75 | |
76 | } // namespace qt |
77 | |
78 | === modified file 'include/unity/storage/qt/internal/Handler.h' |
79 | --- include/unity/storage/qt/internal/Handler.h 2016-09-16 06:25:08 +0000 |
80 | +++ include/unity/storage/qt/internal/Handler.h 2016-10-10 01:18:55 +0000 |
81 | @@ -58,7 +58,7 @@ |
82 | { |
83 | // LCOV_EXCL_START |
84 | QString msg = "impossible provider exception: " + e.errorString(); |
85 | - qCritical() << msg; |
86 | + qCritical().noquote() << msg; |
87 | e = StorageErrorImpl::local_comms_error(msg); |
88 | break; |
89 | // LCOV_EXCL_STOP |
90 | @@ -68,7 +68,8 @@ |
91 | case StorageError::ResourceError: |
92 | { |
93 | // Log these errors because they are unexpected. |
94 | - qCritical() << "provider exception:" << e.errorString(); |
95 | + QString msg = "provider exception: " + e.errorString(); |
96 | + qCritical().noquote() << msg; |
97 | break; |
98 | } |
99 | default: |
100 | |
101 | === modified file 'include/unity/storage/qt/internal/ItemImpl.h' |
102 | --- include/unity/storage/qt/internal/ItemImpl.h 2016-09-26 08:57:05 +0000 |
103 | +++ include/unity/storage/qt/internal/ItemImpl.h 2016-10-10 01:18:55 +0000 |
104 | @@ -53,7 +53,7 @@ |
105 | Item::Type type() const; |
106 | QVariantMap metadata() const; |
107 | QDateTime lastModifiedTime() const; |
108 | - QVector<QString> parentIds() const; |
109 | + QList<QString> parentIds() const; |
110 | |
111 | ItemListJob* parents() const; |
112 | ItemJob* copy(Item const& newParent, QString const& newName) const; |
113 | @@ -89,7 +89,6 @@ |
114 | bool is_valid_; |
115 | storage::internal::ItemMetadata md_; |
116 | std::shared_ptr<AccountImpl> account_; |
117 | - //std::shared_ptr<RootImpl> root_; |
118 | |
119 | friend class unity::storage::qt::Item; |
120 | }; |
121 | |
122 | === modified file 'include/unity/storage/qt/internal/ItemJobImpl.h' |
123 | --- include/unity/storage/qt/internal/ItemJobImpl.h 2016-09-26 08:57:05 +0000 |
124 | +++ include/unity/storage/qt/internal/ItemJobImpl.h 2016-10-10 01:18:55 +0000 |
125 | @@ -53,11 +53,11 @@ |
126 | StorageError error() const; |
127 | Item item() const; |
128 | |
129 | - static ItemJob* make_item_job(std::shared_ptr<AccountImpl> const& account, |
130 | - QString const& method, |
131 | - QDBusPendingReply<storage::internal::ItemMetadata> const& reply, |
132 | - std::function<void(storage::internal::ItemMetadata const&)> const& validate); |
133 | - static ItemJob* make_item_job(StorageError const& e); |
134 | + static ItemJob* make_job(std::shared_ptr<AccountImpl> const& account, |
135 | + QString const& method, |
136 | + QDBusPendingReply<storage::internal::ItemMetadata> const& reply, |
137 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate); |
138 | + static ItemJob* make_job(StorageError const& e); |
139 | |
140 | private: |
141 | ItemJobImpl(std::shared_ptr<AccountImpl> const& account, |
142 | |
143 | === modified file 'include/unity/storage/qt/internal/ItemListJobImpl.h' |
144 | --- include/unity/storage/qt/internal/ItemListJobImpl.h 2016-09-26 08:57:05 +0000 |
145 | +++ include/unity/storage/qt/internal/ItemListJobImpl.h 2016-10-10 01:18:55 +0000 |
146 | @@ -18,10 +18,9 @@ |
147 | |
148 | #pragma once |
149 | |
150 | +#include <unity/storage/qt/internal/ListJobImplBase.h> |
151 | #include <unity/storage/qt/ItemListJob.h> |
152 | |
153 | -#include <unity/storage/qt/StorageError.h> |
154 | - |
155 | #include <QDBusPendingReply> |
156 | |
157 | namespace unity |
158 | @@ -42,35 +41,24 @@ |
159 | |
160 | class AccountImpl; |
161 | |
162 | -class ItemListJobImpl : public QObject |
163 | +class ItemListJobImpl : public ListJobImplBase |
164 | { |
165 | Q_OBJECT |
166 | public: |
167 | virtual ~ItemListJobImpl() = default; |
168 | |
169 | - bool isValid() const; |
170 | - ItemListJob::Status status() const; |
171 | - StorageError error() const; |
172 | - |
173 | - static ItemListJob* make_item_list_job(std::shared_ptr<AccountImpl> const& account, |
174 | - QString const& method, |
175 | - QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply, |
176 | - std::function<void(storage::internal::ItemMetadata const&)> const& validate); |
177 | - static ItemListJob* make_item_list_job(StorageError const& error); |
178 | + static ItemListJob* make_job(std::shared_ptr<AccountImpl> const& account, |
179 | + QString const& method, |
180 | + QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply, |
181 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate); |
182 | + static ItemListJob* make_job(StorageError const& error); |
183 | |
184 | private: |
185 | + ItemListJobImpl() = default; |
186 | ItemListJobImpl(std::shared_ptr<AccountImpl> const& account, |
187 | QString const& method, |
188 | QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply, |
189 | std::function<void(storage::internal::ItemMetadata const&)> const& validate); |
190 | - ItemListJobImpl(StorageError const& error); |
191 | - |
192 | - ItemListJob* public_instance_; |
193 | - ItemListJob::Status status_; |
194 | - StorageError error_; |
195 | - QString method_; |
196 | - std::shared_ptr<AccountImpl> account_; |
197 | - std::function<void(storage::internal::ItemMetadata const&)> validate_; |
198 | }; |
199 | |
200 | } // namespace internal |
201 | |
202 | === added file 'include/unity/storage/qt/internal/ListJobImplBase.h' |
203 | --- include/unity/storage/qt/internal/ListJobImplBase.h 1970-01-01 00:00:00 +0000 |
204 | +++ include/unity/storage/qt/internal/ListJobImplBase.h 2016-10-10 01:18:55 +0000 |
205 | @@ -0,0 +1,76 @@ |
206 | +/* |
207 | + * Copyright (C) 2016 Canonical Ltd |
208 | + * |
209 | + * This program is free software: you can redistribute it and/or modify |
210 | + * it under the terms of the GNU Lesser General Public License version 3 as |
211 | + * published by the Free Software Foundation. |
212 | + * |
213 | + * This program is distributed in the hope that it will be useful, |
214 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
215 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
216 | + * GNU Lesser General Public License for more details. |
217 | + * |
218 | + * You should have received a copy of the GNU Lesser General Public License |
219 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
220 | + * |
221 | + * Authors: Michi Henning <michi.henning@canonical.com> |
222 | + */ |
223 | + |
224 | +#pragma once |
225 | + |
226 | +#include <unity/storage/qt/ItemListJob.h> |
227 | +#include <unity/storage/qt/StorageError.h> |
228 | + |
229 | +#include <QDBusPendingReply> |
230 | + |
231 | +namespace unity |
232 | +{ |
233 | +namespace storage |
234 | +{ |
235 | +namespace internal |
236 | +{ |
237 | + |
238 | +class ItemMetadata; |
239 | + |
240 | +} // namespace internal |
241 | + |
242 | +namespace qt |
243 | +{ |
244 | +namespace internal |
245 | +{ |
246 | + |
247 | +class AccountImpl; |
248 | +class MultiItemJobImpl; |
249 | + |
250 | +class ListJobImplBase : public QObject |
251 | +{ |
252 | +public: |
253 | + ListJobImplBase(); // Makes job in Finished state. |
254 | + ListJobImplBase(std::shared_ptr<AccountImpl> const& account, |
255 | + QString const& method, |
256 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate); |
257 | + ListJobImplBase(StorageError const& error); |
258 | + virtual ~ListJobImplBase() = default; |
259 | + |
260 | + bool isValid() const; |
261 | + ItemListJob::Status status() const; |
262 | + StorageError error() const; |
263 | + |
264 | + void set_public_instance(ItemListJob* p); |
265 | + |
266 | + static ItemListJob* make_job(StorageError const& error); |
267 | + static ItemListJob* make_empty_job(); |
268 | + |
269 | +protected: |
270 | + ItemListJob* public_instance_; |
271 | + ItemListJob::Status status_; |
272 | + StorageError error_; |
273 | + QString method_; |
274 | + std::shared_ptr<AccountImpl> account_; |
275 | + std::function<void(storage::internal::ItemMetadata const&)> validate_; |
276 | +}; |
277 | + |
278 | +} // namespace internal |
279 | +} // namespace qt |
280 | +} // namespace storage |
281 | +} // namespace unity |
282 | |
283 | === added file 'include/unity/storage/qt/internal/MultiItemJobImpl.h' |
284 | --- include/unity/storage/qt/internal/MultiItemJobImpl.h 1970-01-01 00:00:00 +0000 |
285 | +++ include/unity/storage/qt/internal/MultiItemJobImpl.h 2016-10-10 01:18:55 +0000 |
286 | @@ -0,0 +1,68 @@ |
287 | +/* |
288 | + * Copyright (C) 2016 Canonical Ltd |
289 | + * |
290 | + * This program is free software: you can redistribute it and/or modify |
291 | + * it under the terms of the GNU Lesser General Public License version 3 as |
292 | + * published by the Free Software Foundation. |
293 | + * |
294 | + * This program is distributed in the hope that it will be useful, |
295 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
296 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
297 | + * GNU Lesser General Public License for more details. |
298 | + * |
299 | + * You should have received a copy of the GNU Lesser General Public License |
300 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
301 | + * |
302 | + * Authors: Michi Henning <michi.henning@canonical.com> |
303 | + */ |
304 | + |
305 | +#pragma once |
306 | + |
307 | +#include <unity/storage/qt/internal/ListJobImplBase.h> |
308 | +#include <unity/storage/qt/ItemListJob.h> |
309 | + |
310 | +#include <QDBusPendingReply> |
311 | + |
312 | +namespace unity |
313 | +{ |
314 | +namespace storage |
315 | +{ |
316 | +namespace internal |
317 | +{ |
318 | + |
319 | +class ItemMetadata; |
320 | + |
321 | +} // namespace internal |
322 | + |
323 | +namespace qt |
324 | +{ |
325 | +namespace internal |
326 | +{ |
327 | + |
328 | +class AccountImpl; |
329 | + |
330 | +class MultiItemJobImpl : public ListJobImplBase |
331 | +{ |
332 | + Q_OBJECT |
333 | +public: |
334 | + virtual ~MultiItemJobImpl() = default; |
335 | + |
336 | + static ItemListJob* make_job(std::shared_ptr<AccountImpl> const& account, |
337 | + QString const& method, |
338 | + QList<QDBusPendingReply<storage::internal::ItemMetadata>> const& replies, |
339 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate); |
340 | + |
341 | +private: |
342 | + MultiItemJobImpl() = default; |
343 | + MultiItemJobImpl(std::shared_ptr<AccountImpl> const& account, |
344 | + QString const& method, |
345 | + QList<QDBusPendingReply<storage::internal::ItemMetadata>> const& replies, |
346 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate); |
347 | + |
348 | + int replies_remaining_; |
349 | +}; |
350 | + |
351 | +} // namespace internal |
352 | +} // namespace qt |
353 | +} // namespace storage |
354 | +} // namespace unity |
355 | |
356 | === modified file 'include/unity/storage/qt/internal/StorageErrorImpl.h' |
357 | --- include/unity/storage/qt/internal/StorageErrorImpl.h 2016-09-16 06:25:08 +0000 |
358 | +++ include/unity/storage/qt/internal/StorageErrorImpl.h 2016-10-10 01:18:55 +0000 |
359 | @@ -70,6 +70,8 @@ |
360 | static StorageError resource_error(QString const& msg, int error_code); |
361 | |
362 | private: |
363 | + StorageErrorImpl(StorageError::Type type); |
364 | + |
365 | StorageError::Type type_; |
366 | QString name_; |
367 | QString message_; |
368 | |
369 | === modified file 'include/unity/storage/qt/internal/VoidJobImpl.h' |
370 | --- include/unity/storage/qt/internal/VoidJobImpl.h 2016-09-26 22:22:09 +0000 |
371 | +++ include/unity/storage/qt/internal/VoidJobImpl.h 2016-10-10 01:18:55 +0000 |
372 | @@ -45,10 +45,10 @@ |
373 | VoidJob::Status status() const; |
374 | StorageError error() const; |
375 | |
376 | - static VoidJob* make_void_job(std::shared_ptr<ItemImpl> const& item, |
377 | - QString const& method, |
378 | - QDBusPendingReply<void> const& reply); |
379 | - static VoidJob* make_void_job(StorageError const& e); |
380 | + static VoidJob* make_job(std::shared_ptr<ItemImpl> const& item, |
381 | + QString const& method, |
382 | + QDBusPendingReply<void> const& reply); |
383 | + static VoidJob* make_job(StorageError const& e); |
384 | |
385 | private: |
386 | VoidJobImpl(std::shared_ptr<ItemImpl> const& item, |
387 | |
388 | === modified file 'src/qt/CMakeLists.txt' |
389 | --- src/qt/CMakeLists.txt 2016-09-26 08:57:05 +0000 |
390 | +++ src/qt/CMakeLists.txt 2016-10-10 01:18:55 +0000 |
391 | @@ -30,6 +30,8 @@ |
392 | internal/ItemImpl.cpp |
393 | internal/ItemJobImpl.cpp |
394 | internal/ItemListJobImpl.cpp |
395 | + internal/ListJobImplBase.cpp |
396 | + internal/MultiItemJobImpl.cpp |
397 | internal/RuntimeImpl.cpp |
398 | internal/StorageErrorImpl.cpp |
399 | internal/unmarshal_error.cpp |
400 | @@ -46,6 +48,8 @@ |
401 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/HandlerBase.h |
402 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/ItemJobImpl.h |
403 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/ItemListJobImpl.h |
404 | + ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/ListJobImplBase.h |
405 | + ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/MultiItemJobImpl.h |
406 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/VoidJobImpl.h |
407 | ) |
408 | |
409 | |
410 | === modified file 'src/qt/Item.cpp' |
411 | --- src/qt/Item.cpp 2016-09-22 01:52:20 +0000 |
412 | +++ src/qt/Item.cpp 2016-10-10 01:18:55 +0000 |
413 | @@ -48,6 +48,7 @@ |
414 | } |
415 | |
416 | Item::Item(Item&& other) |
417 | + : p_(make_shared<internal::ItemImpl>()) |
418 | { |
419 | p_->is_valid_ = false; |
420 | swap(p_, other.p_); |
421 | @@ -92,14 +93,6 @@ |
422 | return p_->account(); |
423 | } |
424 | |
425 | -#if 0 |
426 | -Item Item::root() const |
427 | -{ |
428 | - |
429 | - return p_->root(); |
430 | -} |
431 | -#endif |
432 | - |
433 | QString Item::etag() const |
434 | { |
435 | return p_->etag(); |
436 | @@ -120,7 +113,7 @@ |
437 | return p_->lastModifiedTime(); |
438 | } |
439 | |
440 | -QVector<QString> Item::parentIds() const |
441 | +QList<QString> Item::parentIds() const |
442 | { |
443 | return p_->parentIds(); |
444 | } |
445 | |
446 | === modified file 'src/qt/ItemListJob.cpp' |
447 | --- src/qt/ItemListJob.cpp 2016-09-16 06:25:08 +0000 |
448 | +++ src/qt/ItemListJob.cpp 2016-10-10 01:18:55 +0000 |
449 | @@ -19,6 +19,7 @@ |
450 | #include <unity/storage/qt/ItemListJob.h> |
451 | |
452 | #include <unity/storage/qt/internal/ItemListJobImpl.h> |
453 | +#include <unity/storage/qt/internal/MultiItemJobImpl.h> |
454 | |
455 | using namespace unity::storage::qt; |
456 | using namespace std; |
457 | @@ -30,7 +31,7 @@ |
458 | namespace qt |
459 | { |
460 | |
461 | -ItemListJob::ItemListJob(unique_ptr<internal::ItemListJobImpl> p) |
462 | +ItemListJob::ItemListJob(unique_ptr<internal::ListJobImplBase> p) |
463 | : p_(move(p)) |
464 | { |
465 | } |
466 | |
467 | === modified file 'src/qt/client/internal/remote_client/ItemImpl.cpp' |
468 | --- src/qt/client/internal/remote_client/ItemImpl.cpp 2016-08-26 04:45:56 +0000 |
469 | +++ src/qt/client/internal/remote_client/ItemImpl.cpp 2016-10-10 01:18:55 +0000 |
470 | @@ -217,7 +217,14 @@ |
471 | { |
472 | throw_if_destroyed("Item::parent_ids()"); |
473 | // TODO, need different metadata representation, affects xml |
474 | - return md_.parent_ids; |
475 | + // We changed ItemMetadata to contain a QList for the v2 API, |
476 | + // so we copy here. |
477 | + QVector<QString> ids; |
478 | + for (auto const& id : md_.parent_ids) |
479 | + { |
480 | + ids.append(id); |
481 | + } |
482 | + return ids; |
483 | } |
484 | |
485 | QFuture<void> ItemImpl::delete_item() |
486 | |
487 | === modified file 'src/qt/internal/AccountImpl.cpp' |
488 | --- src/qt/internal/AccountImpl.cpp 2016-09-26 08:57:05 +0000 |
489 | +++ src/qt/internal/AccountImpl.cpp 2016-10-10 01:18:55 +0000 |
490 | @@ -86,10 +86,15 @@ |
491 | QString const method = "Account::roots()"; |
492 | |
493 | auto runtime = runtime_.lock(); |
494 | + if (!is_valid_) |
495 | + { |
496 | + auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid account"); |
497 | + return ItemListJobImpl::make_job(e); |
498 | + } |
499 | if (!runtime || !runtime->isValid()) |
500 | { |
501 | auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously"); |
502 | - return ItemListJobImpl::make_item_list_job(e); |
503 | + return ItemListJobImpl::make_job(e); |
504 | } |
505 | |
506 | auto validate = [method](storage::internal::ItemMetadata const& md) |
507 | @@ -104,18 +109,23 @@ |
508 | |
509 | auto reply = provider_->Roots(); |
510 | auto This = const_pointer_cast<AccountImpl>(shared_from_this()); |
511 | - return ItemListJobImpl::make_item_list_job(This, method, reply, validate); |
512 | + return ItemListJobImpl::make_job(This, method, reply, validate); |
513 | } |
514 | |
515 | ItemJob* AccountImpl::get(QString const& itemId) const |
516 | { |
517 | QString const method = "Account::get()"; |
518 | |
519 | + if (!is_valid_) |
520 | + { |
521 | + auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid account"); |
522 | + return ItemJobImpl::make_job(e); |
523 | + } |
524 | auto runtime = runtime_.lock(); |
525 | if (!runtime || !runtime->isValid()) |
526 | { |
527 | auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously"); |
528 | - return ItemJobImpl::make_item_job(e); |
529 | + return ItemJobImpl::make_job(e); |
530 | } |
531 | |
532 | // LCOV_EXCL_START |
533 | @@ -126,7 +136,7 @@ |
534 | |
535 | auto reply = provider_->Metadata(itemId); |
536 | auto This = const_pointer_cast<AccountImpl>(shared_from_this()); |
537 | - return ItemJobImpl::make_item_job(This, method, reply, validate); |
538 | + return ItemJobImpl::make_job(This, method, reply, validate); |
539 | } |
540 | |
541 | bool AccountImpl::operator==(AccountImpl const& other) const |
542 | |
543 | === modified file 'src/qt/internal/ItemImpl.cpp' |
544 | --- src/qt/internal/ItemImpl.cpp 2016-09-26 08:57:05 +0000 |
545 | +++ src/qt/internal/ItemImpl.cpp 2016-10-10 01:18:55 +0000 |
546 | @@ -22,6 +22,8 @@ |
547 | #include <unity/storage/provider/metadata_keys.h> |
548 | #include <unity/storage/qt/internal/AccountImpl.h> |
549 | #include <unity/storage/qt/internal/ItemJobImpl.h> |
550 | +#include <unity/storage/qt/internal/ItemListJobImpl.h> |
551 | +#include <unity/storage/qt/internal/MultiItemJobImpl.h> |
552 | #include <unity/storage/qt/internal/RuntimeImpl.h> |
553 | #include <unity/storage/qt/internal/StorageErrorImpl.h> |
554 | #include <unity/storage/qt/internal/VoidJobImpl.h> |
555 | @@ -104,14 +106,56 @@ |
556 | : QDateTime(); |
557 | } |
558 | |
559 | -QVector<QString> ItemImpl::parentIds() const |
560 | +QList<QString> ItemImpl::parentIds() const |
561 | { |
562 | - return is_valid_ ? md_.parent_ids : QVector<QString>(); |
563 | + if (!is_valid_ || md_.type == storage::ItemType::root) |
564 | + { |
565 | + return QList<QString>(); |
566 | + } |
567 | + return md_.parent_ids; |
568 | } |
569 | |
570 | ItemListJob* ItemImpl::parents() const |
571 | { |
572 | - return nullptr; // TODO |
573 | + QString const method = "Item::parents()"; |
574 | + |
575 | + if (!is_valid_) |
576 | + { |
577 | + auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid item"); |
578 | + return ListJobImplBase::make_job(e); |
579 | + } |
580 | + auto runtime = account_->runtime(); |
581 | + if (!runtime || !runtime->isValid()) |
582 | + { |
583 | + auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously"); |
584 | + return ListJobImplBase::make_job(e); |
585 | + } |
586 | + |
587 | + if (md_.type == storage::ItemType::root) |
588 | + { |
589 | + return ListJobImplBase::make_empty_job(); // Root has no parents. |
590 | + } |
591 | + |
592 | + assert(!md_.parent_ids.isEmpty()); |
593 | + |
594 | + QList<QDBusPendingReply<storage::internal::ItemMetadata>> replies; |
595 | + for (auto const& id : md_.parent_ids) |
596 | + { |
597 | + auto reply = account_->provider()->Metadata(id); |
598 | + replies.append(reply); |
599 | + } |
600 | + |
601 | + auto validate = [method](storage::internal::ItemMetadata const& md) |
602 | + { |
603 | + if (md.type == ItemType::file) |
604 | + { |
605 | + QString msg = method + ": provider returned a file as a parent"; |
606 | + qCritical() << msg; |
607 | + throw StorageErrorImpl::local_comms_error(msg); |
608 | + } |
609 | + }; |
610 | + |
611 | + return MultiItemJobImpl::make_job(account_, method, replies, validate); |
612 | } |
613 | |
614 | ItemJob* ItemImpl::copy(Item const& newParent, QString const& newName) const |
615 | @@ -128,23 +172,26 @@ |
616 | { |
617 | QString const method = "Item::deleteItem()"; |
618 | |
619 | - assert(account_); |
620 | + if (!is_valid_) |
621 | + { |
622 | + auto e = StorageErrorImpl::logic_error(method + ": cannot create job from invalid item"); |
623 | + return VoidJobImpl::make_job(e); |
624 | + } |
625 | auto runtime = account_->runtime(); |
626 | if (!runtime || !runtime->isValid()) |
627 | { |
628 | auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously"); |
629 | - return VoidJobImpl::make_void_job(e); |
630 | + return VoidJobImpl::make_job(e); |
631 | } |
632 | - |
633 | if (md_.type == storage::ItemType::root) |
634 | { |
635 | auto e = StorageErrorImpl::logic_error(method + ": cannot delete root"); |
636 | - return VoidJobImpl::make_void_job(e); |
637 | + return VoidJobImpl::make_job(e); |
638 | } |
639 | |
640 | auto reply = account_->provider()->Delete(md_.item_id); |
641 | auto This = const_pointer_cast<ItemImpl>(shared_from_this()); |
642 | - return VoidJobImpl::make_void_job(This, method, reply); |
643 | + return VoidJobImpl::make_job(This, method, reply); |
644 | } |
645 | |
646 | Uploader* ItemImpl::createUploader(Item::ConflictPolicy policy, qint64 sizeInBytes) const |
647 | |
648 | === modified file 'src/qt/internal/ItemJobImpl.cpp' |
649 | --- src/qt/internal/ItemJobImpl.cpp 2016-09-26 08:57:05 +0000 |
650 | +++ src/qt/internal/ItemJobImpl.cpp 2016-10-10 01:18:55 +0000 |
651 | @@ -112,10 +112,10 @@ |
652 | return item_; |
653 | } |
654 | |
655 | -ItemJob* ItemJobImpl::make_item_job(shared_ptr<AccountImpl> const& account, |
656 | - QString const& method, |
657 | - QDBusPendingReply<storage::internal::ItemMetadata> const& reply, |
658 | - std::function<void(storage::internal::ItemMetadata const&)> const& validate) |
659 | +ItemJob* ItemJobImpl::make_job(shared_ptr<AccountImpl> const& account, |
660 | + QString const& method, |
661 | + QDBusPendingReply<storage::internal::ItemMetadata> const& reply, |
662 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate) |
663 | { |
664 | unique_ptr<ItemJobImpl> impl(new ItemJobImpl(account, method, reply, validate)); |
665 | auto job = new ItemJob(move(impl)); |
666 | @@ -123,7 +123,7 @@ |
667 | return job; |
668 | } |
669 | |
670 | -ItemJob* ItemJobImpl::make_item_job(StorageError const& error) |
671 | +ItemJob* ItemJobImpl::make_job(StorageError const& error) |
672 | { |
673 | unique_ptr<ItemJobImpl> impl(new ItemJobImpl(error)); |
674 | auto job = new ItemJob(move(impl)); |
675 | |
676 | === modified file 'src/qt/internal/ItemListJobImpl.cpp' |
677 | --- src/qt/internal/ItemListJobImpl.cpp 2016-09-26 08:57:05 +0000 |
678 | +++ src/qt/internal/ItemListJobImpl.cpp 2016-10-10 01:18:55 +0000 |
679 | @@ -19,7 +19,6 @@ |
680 | #include <unity/storage/qt/internal/ItemListJobImpl.h> |
681 | |
682 | #include <unity/storage/internal/dbusmarshal.h> |
683 | -#include <unity/storage/internal/ItemMetadata.h> |
684 | #include <unity/storage/qt/internal/AccountImpl.h> |
685 | #include <unity/storage/qt/internal/Handler.h> |
686 | #include <unity/storage/qt/internal/ItemImpl.h> |
687 | @@ -40,15 +39,8 @@ |
688 | QString const& method, |
689 | QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply, |
690 | std::function<void(storage::internal::ItemMetadata const&)> const& validate) |
691 | - : status_(ItemListJob::Loading) |
692 | - , method_(method) |
693 | - , account_(account) |
694 | - , validate_(validate) |
695 | + : ListJobImplBase(account, method, validate) |
696 | { |
697 | - assert(!method.isEmpty()); |
698 | - assert(account); |
699 | - assert(validate); |
700 | - |
701 | auto process_reply = [this](decltype(reply)& r) |
702 | { |
703 | auto runtime = account_->runtime(); |
704 | @@ -82,6 +74,7 @@ |
705 | |
706 | auto process_error = [this](StorageError const& error) |
707 | { |
708 | + // TODO: method name is not being set this way. |
709 | error_ = error; |
710 | status_ = ItemListJob::Error; |
711 | Q_EMIT public_instance_->statusChanged(status_); |
712 | @@ -90,49 +83,20 @@ |
713 | new Handler<QList<storage::internal::ItemMetadata>>(this, reply, process_reply, process_error); |
714 | } |
715 | |
716 | -ItemListJobImpl::ItemListJobImpl(StorageError const& error) |
717 | - : status_(ItemListJob::Error) |
718 | - , error_(error) |
719 | -{ |
720 | -} |
721 | - |
722 | -bool ItemListJobImpl::isValid() const |
723 | -{ |
724 | - return status_ != ItemListJob::Status::Error; |
725 | -} |
726 | - |
727 | -ItemListJob::Status ItemListJobImpl::status() const |
728 | -{ |
729 | - return status_; |
730 | -} |
731 | - |
732 | -StorageError ItemListJobImpl::error() const |
733 | -{ |
734 | - return error_; |
735 | -} |
736 | - |
737 | -ItemListJob* ItemListJobImpl::make_item_list_job( |
738 | - shared_ptr<AccountImpl> const& account, |
739 | - QString const& method, |
740 | - QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply, |
741 | - std::function<void(storage::internal::ItemMetadata const&)> const& validate) |
742 | +ItemListJob* ItemListJobImpl::make_job(shared_ptr<AccountImpl> const& account, |
743 | + QString const& method, |
744 | + QDBusPendingReply<QList<storage::internal::ItemMetadata>> const& reply, |
745 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate) |
746 | { |
747 | unique_ptr<ItemListJobImpl> impl(new ItemListJobImpl(account, method, reply, validate)); |
748 | auto job = new ItemListJob(move(impl)); |
749 | - job->p_->public_instance_ = job; |
750 | + job->p_->set_public_instance(job); |
751 | return job; |
752 | } |
753 | |
754 | -ItemListJob* ItemListJobImpl::make_item_list_job(StorageError const& error) |
755 | +ItemListJob* ItemListJobImpl::make_job(StorageError const& error) |
756 | { |
757 | - unique_ptr<ItemListJobImpl> impl(new ItemListJobImpl(error)); |
758 | - auto job = new ItemListJob(move(impl)); |
759 | - job->p_->public_instance_ = job; |
760 | - QMetaObject::invokeMethod(job, |
761 | - "statusChanged", |
762 | - Qt::QueuedConnection, |
763 | - Q_ARG(unity::storage::qt::ItemListJob::Status, job->p_->status_)); |
764 | - return job; |
765 | + return ListJobImplBase::make_job(error); |
766 | } |
767 | |
768 | } // namespace internal |
769 | |
770 | === added file 'src/qt/internal/ListJobImplBase.cpp' |
771 | --- src/qt/internal/ListJobImplBase.cpp 1970-01-01 00:00:00 +0000 |
772 | +++ src/qt/internal/ListJobImplBase.cpp 2016-10-10 01:18:55 +0000 |
773 | @@ -0,0 +1,111 @@ |
774 | +/* |
775 | + * Copyright (C) 2016 Canonical Ltd |
776 | + * |
777 | + * This program is free software: you can redistribute it and/or modify |
778 | + * it under the terms of the GNU Lesser General Public License version 3 as |
779 | + * published by the Free Software Foundation. |
780 | + * |
781 | + * This program is distributed in the hope that it will be useful, |
782 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
783 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
784 | + * GNU Lesser General Public License for more details. |
785 | + * |
786 | + * You should have received a copy of the GNU Lesser General Public License |
787 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
788 | + * |
789 | + * Authors: Michi Henning <michi.henning@canonical.com> |
790 | + */ |
791 | + |
792 | +#include <unity/storage/qt/internal/ListJobImplBase.h> |
793 | + |
794 | +#include <unity/storage/internal/dbusmarshal.h> |
795 | +#include <unity/storage/internal/ItemMetadata.h> |
796 | +#include <unity/storage/qt/internal/AccountImpl.h> |
797 | +#include <unity/storage/qt/internal/Handler.h> |
798 | +#include <unity/storage/qt/internal/ItemImpl.h> |
799 | +#include <unity/storage/qt/internal/RuntimeImpl.h> |
800 | + |
801 | +using namespace std; |
802 | + |
803 | +namespace unity |
804 | +{ |
805 | +namespace storage |
806 | +{ |
807 | +namespace qt |
808 | +{ |
809 | +namespace internal |
810 | +{ |
811 | + |
812 | +ListJobImplBase::ListJobImplBase() |
813 | + : status_(ItemListJob::Finished) |
814 | +{ |
815 | +} |
816 | + |
817 | +ListJobImplBase::ListJobImplBase(shared_ptr<AccountImpl> const& account, |
818 | + QString const& method, |
819 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate) |
820 | + : status_(ItemListJob::Loading) |
821 | + , method_(method) |
822 | + , account_(account) |
823 | + , validate_(validate) |
824 | +{ |
825 | + assert(!method.isEmpty()); |
826 | + assert(account); |
827 | + assert(validate); |
828 | +} |
829 | + |
830 | +ListJobImplBase::ListJobImplBase(StorageError const& error) |
831 | + : status_(ItemListJob::Error) |
832 | + , error_(error) |
833 | +{ |
834 | +} |
835 | + |
836 | +bool ListJobImplBase::isValid() const |
837 | +{ |
838 | + return status_ != ItemListJob::Status::Error; |
839 | +} |
840 | + |
841 | +ItemListJob::Status ListJobImplBase::status() const |
842 | +{ |
843 | + return status_; |
844 | +} |
845 | + |
846 | +StorageError ListJobImplBase::error() const |
847 | +{ |
848 | + return error_; |
849 | +} |
850 | + |
851 | +void ListJobImplBase::set_public_instance(ItemListJob* p) |
852 | +{ |
853 | + assert(p); |
854 | + public_instance_ = p; |
855 | +} |
856 | + |
857 | +ItemListJob* ListJobImplBase::make_job(StorageError const& error) |
858 | +{ |
859 | + unique_ptr<ListJobImplBase> impl(new ListJobImplBase(error)); |
860 | + auto job = new ItemListJob(move(impl)); |
861 | + job->p_->public_instance_ = job; |
862 | + QMetaObject::invokeMethod(job, |
863 | + "statusChanged", |
864 | + Qt::QueuedConnection, |
865 | + Q_ARG(unity::storage::qt::ItemListJob::Status, job->status())); |
866 | + return job; |
867 | +} |
868 | + |
869 | +ItemListJob* ListJobImplBase::make_empty_job() |
870 | +{ |
871 | + unique_ptr<ListJobImplBase> impl(new ListJobImplBase()); |
872 | + auto job = new ItemListJob(move(impl)); |
873 | + job->p_->public_instance_ = job; |
874 | + QMetaObject::invokeMethod(job, |
875 | + "statusChanged", |
876 | + Qt::QueuedConnection, |
877 | + Q_ARG(unity::storage::qt::ItemListJob::Status, job->status())); |
878 | + return job; |
879 | +} |
880 | + |
881 | +} // namespace internal |
882 | +} // namespace qt |
883 | +} // namespace storage |
884 | +} // namespace unity |
885 | |
886 | === added file 'src/qt/internal/MultiItemJobImpl.cpp' |
887 | --- src/qt/internal/MultiItemJobImpl.cpp 1970-01-01 00:00:00 +0000 |
888 | +++ src/qt/internal/MultiItemJobImpl.cpp 2016-10-10 01:18:55 +0000 |
889 | @@ -0,0 +1,135 @@ |
890 | +/* |
891 | + * Copyright (C) 2016 Canonical Ltd |
892 | + * |
893 | + * This program is free software: you can redistribute it and/or modify |
894 | + * it under the terms of the GNU Lesser General Public License version 3 as |
895 | + * published by the Free Software Foundation. |
896 | + * |
897 | + * This program is distributed in the hope that it will be useful, |
898 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
899 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
900 | + * GNU Lesser General Public License for more details. |
901 | + * |
902 | + * You should have received a copy of the GNU Lesser General Public License |
903 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
904 | + * |
905 | + * Authors: Michi Henning <michi.henning@canonical.com> |
906 | + */ |
907 | + |
908 | +#include <unity/storage/qt/internal/MultiItemJobImpl.h> |
909 | + |
910 | +#include <unity/storage/internal/dbusmarshal.h> |
911 | +#include <unity/storage/qt/internal/AccountImpl.h> |
912 | +#include <unity/storage/qt/internal/Handler.h> |
913 | +#include <unity/storage/qt/internal/ItemImpl.h> |
914 | +#include <unity/storage/qt/internal/RuntimeImpl.h> |
915 | + |
916 | +using namespace std; |
917 | + |
918 | +namespace unity |
919 | +{ |
920 | +namespace storage |
921 | +{ |
922 | +namespace qt |
923 | +{ |
924 | +namespace internal |
925 | +{ |
926 | + |
927 | +MultiItemJobImpl::MultiItemJobImpl(shared_ptr<AccountImpl> const& account, |
928 | + QString const& method, |
929 | + QList<QDBusPendingReply<storage::internal::ItemMetadata>> const& replies, |
930 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate) |
931 | + : ListJobImplBase(account, method, validate) |
932 | + , replies_remaining_(replies.size()) |
933 | +{ |
934 | + assert(!method.isEmpty()); |
935 | + assert(account); |
936 | + assert(validate); |
937 | + |
938 | + // We ask the provider for the metadata for each of this item's parents. |
939 | + // As the replies trickle in, we track when the last reply has arrived and |
940 | + // signal that the job is complete. |
941 | + // If anything goes wrong at all, we report the first error and then ignore all |
942 | + // other replies. |
943 | + |
944 | + auto process_reply = [this](QDBusPendingReply<storage::internal::ItemMetadata> const& r) |
945 | + { |
946 | + assert(status_ != ItemListJob::Finished); |
947 | + |
948 | + --replies_remaining_; |
949 | + |
950 | + if (status_ == ItemListJob::Error) |
951 | + { |
952 | + return; |
953 | + } |
954 | + |
955 | + auto runtime = account_->runtime(); |
956 | + if (!runtime || !runtime->isValid()) |
957 | + { |
958 | + error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously"); |
959 | + status_ = ItemListJob::Error; |
960 | + Q_EMIT public_instance_->statusChanged(status_); |
961 | + return; |
962 | + } |
963 | + |
964 | + auto metadata = r.value(); |
965 | + Item item; |
966 | + try |
967 | + { |
968 | + validate_(metadata); |
969 | + item = ItemImpl::make_item(method_, metadata, account_); |
970 | + } |
971 | + catch (StorageError const& e) |
972 | + { |
973 | + // Bad metadata received from provider, validate_() or make_item() have logged it. |
974 | + status_ = ItemListJob::Error; |
975 | + error_ = e; |
976 | + Q_EMIT public_instance_->statusChanged(status_); |
977 | + return; |
978 | + } |
979 | + QList<Item> items; |
980 | + items.append(item); |
981 | + Q_EMIT public_instance_->itemsReady(items); |
982 | + |
983 | + if (replies_remaining_ == 0) |
984 | + { |
985 | + status_ = ItemListJob::Finished; |
986 | + Q_EMIT public_instance_->statusChanged(status_); |
987 | + } |
988 | + }; |
989 | + |
990 | + auto process_error = [this](StorageError const& error) |
991 | + { |
992 | + assert(status_ != ItemListJob::Finished); |
993 | + |
994 | + if (status_ == ItemListJob::Error) |
995 | + { |
996 | + return; |
997 | + } |
998 | + // TODO: method name is not being set this way. |
999 | + error_ = error; |
1000 | + status_ = ItemListJob::Error; |
1001 | + Q_EMIT public_instance_->statusChanged(status_); |
1002 | + }; |
1003 | + |
1004 | + for (auto const& reply : replies) |
1005 | + { |
1006 | + new Handler<storage::internal::ItemMetadata>(this, reply, process_reply, process_error); |
1007 | + } |
1008 | +} |
1009 | + |
1010 | +ItemListJob* MultiItemJobImpl::make_job(shared_ptr<AccountImpl> const& account, |
1011 | + QString const& method, |
1012 | + QList<QDBusPendingReply<storage::internal::ItemMetadata>> const& replies, |
1013 | + std::function<void(storage::internal::ItemMetadata const&)> const& validate) |
1014 | +{ |
1015 | + unique_ptr<MultiItemJobImpl> impl(new MultiItemJobImpl(account, method, replies, validate)); |
1016 | + auto job = new ItemListJob(move(impl)); |
1017 | + job->p_->set_public_instance(job); |
1018 | + return job; |
1019 | +} |
1020 | + |
1021 | +} // namespace internal |
1022 | +} // namespace qt |
1023 | +} // namespace storage |
1024 | +} // namespace unity |
1025 | |
1026 | === modified file 'src/qt/internal/StorageErrorImpl.cpp' |
1027 | --- src/qt/internal/StorageErrorImpl.cpp 2016-09-16 06:25:08 +0000 |
1028 | +++ src/qt/internal/StorageErrorImpl.cpp 2016-10-10 01:18:55 +0000 |
1029 | @@ -35,27 +35,40 @@ |
1030 | namespace |
1031 | { |
1032 | |
1033 | -static char const * const ERROR_NAMES[StorageError::__LAST_STORAGE_ERROR] = |
1034 | +static const QString ERROR_NAMES[StorageError::__LAST_STORAGE_ERROR] = |
1035 | { |
1036 | - "NoError", "LocalCommsError", "RemoteCommsError", "Deleted", "RuntimeDestroyed", "NotExists", |
1037 | - "Exists", "Conflict", "PermissionDenied", "Cancelled", "LogicError", "InvalidArgument", "ResourceError" |
1038 | + QStringLiteral("NoError"), |
1039 | + QStringLiteral("LocalCommsError"), |
1040 | + QStringLiteral("RemoteCommsError"), |
1041 | + QStringLiteral("Deleted"), |
1042 | + QStringLiteral("RuntimeDestroyed"), |
1043 | + QStringLiteral("NotExists"), |
1044 | + QStringLiteral("Exists"), |
1045 | + QStringLiteral("Conflict"), |
1046 | + QStringLiteral("PermissionDenied"), |
1047 | + QStringLiteral("Cancelled"), |
1048 | + QStringLiteral("LogicError"), |
1049 | + QStringLiteral("InvalidArgument"), |
1050 | + QStringLiteral("ResourceError") |
1051 | }; |
1052 | |
1053 | } // namespace |
1054 | |
1055 | +StorageErrorImpl::StorageErrorImpl(StorageError::Type type) |
1056 | + : type_(type) |
1057 | + , name_(ERROR_NAMES[type_]) |
1058 | + , error_code_(0) |
1059 | +{ |
1060 | +} |
1061 | + |
1062 | StorageErrorImpl::StorageErrorImpl() |
1063 | - : type_(StorageError::Type::NoError) |
1064 | - , name_(ERROR_NAMES[type_]) |
1065 | - , message_("No error") |
1066 | - , error_code_(0) |
1067 | + : StorageErrorImpl(StorageError::Type::NoError) |
1068 | { |
1069 | + message_ = "No error"; |
1070 | } |
1071 | |
1072 | StorageErrorImpl::StorageErrorImpl(StorageError::Type type, QString const& msg) |
1073 | - : type_(type) |
1074 | - , name_(ERROR_NAMES[type_]) |
1075 | - , message_(msg) |
1076 | - , error_code_(0) |
1077 | + : StorageErrorImpl(type) |
1078 | { |
1079 | assert( type == StorageError::Type::LocalCommsError |
1080 | || type == StorageError::Type::RemoteCommsError |
1081 | @@ -66,18 +79,18 @@ |
1082 | || type == StorageError::Type::LogicError |
1083 | || type == StorageError::Type::InvalidArgument); |
1084 | assert(!msg.isEmpty()); |
1085 | + |
1086 | + message_ = msg; |
1087 | } |
1088 | |
1089 | StorageErrorImpl::StorageErrorImpl(StorageError::Type type, QString const& msg, QString const& key) |
1090 | - : type_(type) |
1091 | - , name_(ERROR_NAMES[type_]) |
1092 | - , message_(msg) |
1093 | - , error_code_(0) |
1094 | + : StorageErrorImpl(type) |
1095 | { |
1096 | assert( type == StorageError::Type::Deleted |
1097 | || type == StorageError::Type::NotExists); |
1098 | assert(!msg.isEmpty()); |
1099 | |
1100 | + message_ = msg; |
1101 | item_id_ = key; |
1102 | if (type == StorageError::Type::NotExists) |
1103 | { |
1104 | @@ -89,26 +102,26 @@ |
1105 | QString const& msg, |
1106 | QString const& item_id, |
1107 | QString const& item_name) |
1108 | - : type_(type) |
1109 | - , name_(ERROR_NAMES[type_]) |
1110 | - , message_(msg) |
1111 | - , item_id_(item_id) |
1112 | - , item_name_(item_name) |
1113 | - , error_code_(0) |
1114 | + : StorageErrorImpl(type) |
1115 | { |
1116 | assert(type == StorageError::Type::Exists); |
1117 | assert(!msg.isEmpty()); |
1118 | assert(!item_id.isEmpty()); |
1119 | assert(!item_name.isEmpty()); |
1120 | + |
1121 | + message_ = msg; |
1122 | + item_id_ = item_id; |
1123 | + item_name_ = item_name; |
1124 | } |
1125 | |
1126 | StorageErrorImpl::StorageErrorImpl(StorageError::Type type, QString const& msg, int error_code) |
1127 | - : type_(type) |
1128 | - , message_(msg) |
1129 | - , error_code_(error_code) |
1130 | + : StorageErrorImpl(type) |
1131 | { |
1132 | assert(type == StorageError::Type::ResourceError); |
1133 | assert(!msg.isEmpty()); |
1134 | + |
1135 | + message_ = msg; |
1136 | + error_code_ = error_code; |
1137 | } |
1138 | |
1139 | StorageError::Type StorageErrorImpl::type() const |
1140 | |
1141 | === modified file 'src/qt/internal/VoidJobImpl.cpp' |
1142 | --- src/qt/internal/VoidJobImpl.cpp 2016-09-26 08:57:05 +0000 |
1143 | +++ src/qt/internal/VoidJobImpl.cpp 2016-10-10 01:18:55 +0000 |
1144 | @@ -89,9 +89,9 @@ |
1145 | return error_; |
1146 | } |
1147 | |
1148 | -VoidJob* VoidJobImpl::make_void_job(shared_ptr<ItemImpl> const& item, |
1149 | - QString const& method, |
1150 | - QDBusPendingReply<void> const& reply) |
1151 | +VoidJob* VoidJobImpl::make_job(shared_ptr<ItemImpl> const& item, |
1152 | + QString const& method, |
1153 | + QDBusPendingReply<void> const& reply) |
1154 | { |
1155 | unique_ptr<VoidJobImpl> impl(new VoidJobImpl(item, method, reply)); |
1156 | auto job = new VoidJob(move(impl)); |
1157 | @@ -99,7 +99,7 @@ |
1158 | return job; |
1159 | } |
1160 | |
1161 | -VoidJob* VoidJobImpl::make_void_job(StorageError const& error) |
1162 | +VoidJob* VoidJobImpl::make_job(StorageError const& error) |
1163 | { |
1164 | unique_ptr<VoidJobImpl> impl(new VoidJobImpl(error)); |
1165 | auto job = new VoidJob(move(impl)); |
1166 | |
1167 | === modified file 'tests/provider-ProviderInterface/ProviderInterface_test.cpp' |
1168 | --- tests/provider-ProviderInterface/ProviderInterface_test.cpp 2016-09-26 02:37:03 +0000 |
1169 | +++ tests/provider-ProviderInterface/ProviderInterface_test.cpp 2016-10-10 01:18:55 +0000 |
1170 | @@ -91,7 +91,7 @@ |
1171 | EXPECT_EQ(1, reply.value().size()); |
1172 | auto root = reply.value()[0]; |
1173 | EXPECT_EQ("root_id", root.item_id); |
1174 | - EXPECT_EQ(QVector<QString>(), root.parent_ids); |
1175 | + EXPECT_EQ(QList<QString>(), root.parent_ids); |
1176 | EXPECT_EQ("Root", root.name); |
1177 | EXPECT_EQ("etag", root.etag); |
1178 | EXPECT_EQ(ItemType::root, root.type); |
1179 | @@ -146,7 +146,7 @@ |
1180 | ASSERT_EQ(1, items.size()); |
1181 | auto item = items[0]; |
1182 | EXPECT_EQ("child_id", item.item_id); |
1183 | - EXPECT_EQ(QVector<QString>{ "root_id"}, item.parent_ids); |
1184 | + EXPECT_EQ(QList<QString>{ "root_id"}, item.parent_ids); |
1185 | EXPECT_EQ("Filename", item.name); |
1186 | EXPECT_EQ(ItemType::file, item.type); |
1187 | } |
1188 | @@ -160,7 +160,7 @@ |
1189 | ASSERT_TRUE(reply.isValid()) << reply.error().message().toStdString(); |
1190 | auto item = reply.value(); |
1191 | EXPECT_EQ("root_id", item.item_id); |
1192 | - EXPECT_EQ(QVector<QString>(), item.parent_ids); |
1193 | + EXPECT_EQ(QList<QString>(), item.parent_ids); |
1194 | EXPECT_EQ("Root", item.name); |
1195 | EXPECT_EQ(ItemType::root, item.type); |
1196 | } |
1197 | @@ -174,7 +174,7 @@ |
1198 | ASSERT_TRUE(reply.isValid()) << reply.error().message().toStdString(); |
1199 | auto item = reply.value(); |
1200 | EXPECT_EQ("new_folder_id", item.item_id); |
1201 | - EXPECT_EQ(QVector<QString>{ "root_id" }, item.parent_ids); |
1202 | + EXPECT_EQ(QList<QString>{ "root_id" }, item.parent_ids); |
1203 | EXPECT_EQ("New Folder", item.name); |
1204 | EXPECT_EQ(ItemType::folder, item.type); |
1205 | } |
1206 | @@ -224,7 +224,7 @@ |
1207 | ASSERT_TRUE(reply.isValid()) << reply.error().message().toStdString(); |
1208 | auto item = reply.value(); |
1209 | EXPECT_EQ("new_file_id", item.item_id); |
1210 | - EXPECT_EQ(QVector<QString>{ "parent_id" }, item.parent_ids); |
1211 | + EXPECT_EQ(QList<QString>{ "parent_id" }, item.parent_ids); |
1212 | EXPECT_EQ("file name", item.name); |
1213 | } |
1214 | |
1215 | @@ -761,7 +761,7 @@ |
1216 | ASSERT_TRUE(reply.isValid()) << reply.error().message().toStdString(); |
1217 | auto item = reply.value(); |
1218 | EXPECT_EQ("child_id", item.item_id); |
1219 | - EXPECT_EQ(QVector<QString>{ "new_parent_id" }, item.parent_ids); |
1220 | + EXPECT_EQ(QList<QString>{ "new_parent_id" }, item.parent_ids); |
1221 | EXPECT_EQ("New name", item.name); |
1222 | EXPECT_EQ(ItemType::file, item.type); |
1223 | } |
1224 | @@ -775,7 +775,7 @@ |
1225 | ASSERT_TRUE(reply.isValid()) << reply.error().message().toStdString(); |
1226 | auto item = reply.value(); |
1227 | EXPECT_EQ("new_id", item.item_id); |
1228 | - EXPECT_EQ(QVector<QString>{ "new_parent_id" }, item.parent_ids); |
1229 | + EXPECT_EQ(QList<QString>{ "new_parent_id" }, item.parent_ids); |
1230 | EXPECT_EQ("New name", item.name); |
1231 | EXPECT_EQ(ItemType::file, item.type); |
1232 | } |
1233 | |
1234 | === modified file 'tests/remote-client/MockProvider.cpp' |
1235 | --- tests/remote-client/MockProvider.cpp 2016-09-26 08:57:05 +0000 |
1236 | +++ tests/remote-client/MockProvider.cpp 2016-10-10 01:18:55 +0000 |
1237 | @@ -58,6 +58,11 @@ |
1238 | }; |
1239 | return make_ready_future<ItemList>(roots); |
1240 | } |
1241 | + if (cmd_ == "roots_throw") |
1242 | + { |
1243 | + string msg = "roots(): I'm sorry Dave, I'm afraid I can't do that."; |
1244 | + return make_exceptional_future<ItemList>(PermissionException(msg)); |
1245 | + } |
1246 | |
1247 | ItemList roots = |
1248 | { |
1249 | @@ -115,6 +120,8 @@ |
1250 | |
1251 | boost::future<Item> MockProvider::metadata(string const& item_id, Context const&) |
1252 | { |
1253 | + static int num_calls = 0; |
1254 | + |
1255 | if (cmd_ == "slow_metadata") |
1256 | { |
1257 | this_thread::sleep_for(chrono::seconds(1)); |
1258 | @@ -124,13 +131,47 @@ |
1259 | Item metadata{"", {}, "Root", "etag", ItemType::root, {}}; |
1260 | return make_ready_future<Item>(metadata); |
1261 | } |
1262 | + if (cmd_== "two_parents_throw") |
1263 | + { |
1264 | + ++num_calls; |
1265 | + switch (num_calls) |
1266 | + { |
1267 | + case 3: |
1268 | + return make_exceptional_future<Item>(ResourceException("metadata(): weird error", 42)); |
1269 | + case 4: |
1270 | + num_calls = 0; |
1271 | + return make_exceptional_future<Item>(RemoteCommsException("metadata(): HTTP broken")); |
1272 | + default: |
1273 | + break; |
1274 | + } |
1275 | + } |
1276 | if (item_id == "root_id") |
1277 | { |
1278 | + if (cmd_ == "bad_parent_metadata_from_child") |
1279 | + { |
1280 | + ++num_calls; |
1281 | + if (num_calls == 2) |
1282 | + { |
1283 | + num_calls = 0; |
1284 | + // On second call, we return type file for the root. |
1285 | + Item metadata{"root_id", {}, "Root", "etag", ItemType::file, {}}; |
1286 | + return make_ready_future<Item>(metadata); |
1287 | + } |
1288 | + } |
1289 | Item metadata{"root_id", {}, "Root", "etag", ItemType::root, {}}; |
1290 | return make_ready_future<Item>(metadata); |
1291 | } |
1292 | - else if (item_id == "child_id") |
1293 | + if (item_id == "child_id") |
1294 | { |
1295 | + if (cmd_ == "two_parents" || cmd_ == "two_parents_throw") |
1296 | + { |
1297 | + Item metadata |
1298 | + { |
1299 | + "child_id", { "root_id", "child_folder_id" }, "Child", "etag", ItemType::file, |
1300 | + { { SIZE_IN_BYTES, 0 }, { LAST_MODIFIED_TIME, "2007-04-05T14:30Z" } } |
1301 | + }; |
1302 | + return make_ready_future<Item>(metadata); |
1303 | + } |
1304 | Item metadata |
1305 | { |
1306 | "child_id", { "root_id" }, "Child", "etag", ItemType::file, |
1307 | @@ -138,7 +179,7 @@ |
1308 | }; |
1309 | return make_ready_future<Item>(metadata); |
1310 | } |
1311 | - else if (item_id == "child_folder_id") |
1312 | + if (item_id == "child_folder_id") |
1313 | { |
1314 | Item metadata{"child_folder_id", { "root_id" }, "Child_Folder", "etag", ItemType::folder, {}}; |
1315 | return make_ready_future<Item>(metadata); |
1316 | |
1317 | === modified file 'tests/remote-client/remote-client_test.cpp' |
1318 | --- tests/remote-client/remote-client_test.cpp 2016-09-29 13:09:00 +0000 |
1319 | +++ tests/remote-client/remote-client_test.cpp 2016-10-10 01:18:55 +0000 |
1320 | @@ -58,6 +58,7 @@ |
1321 | class DeleteTest : public RemoteClientTest {}; |
1322 | class GetTest : public RemoteClientTest {}; |
1323 | class ItemTest : public RemoteClientTest {}; |
1324 | +class ParentsTest : public RemoteClientTest {}; |
1325 | class RootsTest : public RemoteClientTest {}; |
1326 | class RuntimeTest : public ProviderFixture {}; |
1327 | |
1328 | @@ -397,7 +398,7 @@ |
1329 | EXPECT_EQ("root_id", root.itemId()); |
1330 | EXPECT_EQ("Root", root.name()); |
1331 | EXPECT_EQ("etag", root.etag()); |
1332 | - EXPECT_EQ(QVector<QString>(), root.parentIds()); |
1333 | + EXPECT_EQ(QList<QString>(), root.parentIds()); |
1334 | EXPECT_FALSE(root.lastModifiedTime().isValid()); |
1335 | EXPECT_EQ(acc_, root.account()); |
1336 | } |
1337 | @@ -441,6 +442,46 @@ |
1338 | EXPECT_EQ("Account::roots(): Runtime was destroyed previously", j->error().message()); |
1339 | } |
1340 | |
1341 | +TEST_F(RootsTest, invalid_account) |
1342 | +{ |
1343 | + Account a; |
1344 | + unique_ptr<ItemListJob> j(a.roots()); |
1345 | + EXPECT_FALSE(j->isValid()); |
1346 | + EXPECT_EQ(ItemListJob::Error, j->status()); |
1347 | + EXPECT_EQ(StorageError::LogicError, j->error().type()); |
1348 | + EXPECT_EQ("Account::roots(): cannot create job from invalid account", j->error().message()); |
1349 | + |
1350 | + // Signal must be received. |
1351 | + QSignalSpy spy(j.get(), &ItemListJob::statusChanged); |
1352 | + spy.wait(SIGNAL_WAIT_TIME); |
1353 | + ASSERT_EQ(1, spy.count()); |
1354 | + auto arg = spy.takeFirst(); |
1355 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
1356 | + |
1357 | + EXPECT_EQ("Account::roots(): cannot create job from invalid account", j->error().message()); |
1358 | +} |
1359 | + |
1360 | +TEST_F(RootsTest, exception) |
1361 | +{ |
1362 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("roots_throw"))); |
1363 | + |
1364 | + unique_ptr<ItemListJob> j(acc_.roots()); |
1365 | + EXPECT_TRUE(j->isValid()); |
1366 | + EXPECT_EQ(ItemListJob::Loading, j->status()); |
1367 | + EXPECT_EQ(StorageError::NoError, j->error().type()); |
1368 | + EXPECT_EQ("No error", j->error().message()); |
1369 | + |
1370 | + QSignalSpy spy(j.get(), &ItemListJob::statusChanged); |
1371 | + spy.wait(SIGNAL_WAIT_TIME); |
1372 | + ASSERT_EQ(1, spy.count()); |
1373 | + auto arg = spy.takeFirst(); |
1374 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
1375 | + |
1376 | + EXPECT_EQ(ItemListJob::Error, j->status()); |
1377 | + EXPECT_EQ(StorageError::PermissionDenied, j->error().type()); |
1378 | + EXPECT_EQ("PermissionDenied: roots(): I'm sorry Dave, I'm afraid I can't do that.", j->error().errorString()); |
1379 | +} |
1380 | + |
1381 | TEST_F(RootsTest, not_a_root) |
1382 | { |
1383 | set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("not_a_root"))); |
1384 | @@ -534,6 +575,25 @@ |
1385 | EXPECT_EQ("Account::get(): Runtime was destroyed previously", j->error().message()); |
1386 | } |
1387 | |
1388 | +TEST_F(GetTest, invalid_account) |
1389 | +{ |
1390 | + Account a; |
1391 | + unique_ptr<ItemJob> j(a.get("child_Id")); |
1392 | + EXPECT_FALSE(j->isValid()); |
1393 | + EXPECT_EQ(ItemJob::Error, j->status()); |
1394 | + EXPECT_EQ(StorageError::LogicError, j->error().type()); |
1395 | + EXPECT_EQ("Account::get(): cannot create job from invalid account", j->error().message()); |
1396 | + |
1397 | + // Signal must be received. |
1398 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1399 | + spy.wait(SIGNAL_WAIT_TIME); |
1400 | + ASSERT_EQ(1, spy.count()); |
1401 | + auto arg = spy.takeFirst(); |
1402 | + EXPECT_EQ(ItemJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0))); |
1403 | + |
1404 | + EXPECT_EQ("Account::get(): cannot create job from invalid account", j->error().message()); |
1405 | +} |
1406 | + |
1407 | TEST_F(GetTest, empty_id_from_provider) |
1408 | { |
1409 | set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("empty_id"))); |
1410 | @@ -704,6 +764,25 @@ |
1411 | EXPECT_EQ("Item::deleteItem(): Runtime was destroyed previously", j->error().message()) << j->error().message().toStdString(); |
1412 | } |
1413 | |
1414 | +TEST_F(DeleteTest, invalid_item) |
1415 | +{ |
1416 | + Item i; |
1417 | + unique_ptr<VoidJob> j(i.deleteItem()); |
1418 | + EXPECT_FALSE(j->isValid()); |
1419 | + EXPECT_EQ(VoidJob::Error, j->status()); |
1420 | + EXPECT_EQ(StorageError::LogicError, j->error().type()); |
1421 | + EXPECT_EQ("Item::deleteItem(): cannot create job from invalid item", j->error().message()); |
1422 | + |
1423 | + // Signal must be received. |
1424 | + QSignalSpy spy(j.get(), &unity::storage::qt::VoidJob::statusChanged); |
1425 | + spy.wait(SIGNAL_WAIT_TIME); |
1426 | + ASSERT_EQ(1, spy.count()); |
1427 | + auto arg = spy.takeFirst(); |
1428 | + EXPECT_EQ(VoidJob::Error, qvariant_cast<VoidJob::Status>(arg.at(0))); |
1429 | + |
1430 | + EXPECT_EQ("Item::deleteItem(): cannot create job from invalid item", j->error().message()); |
1431 | +} |
1432 | + |
1433 | #if 0 |
1434 | // TODO: need to make internal symbols available for testing. |
1435 | TEST_F(ValidateTest, basic) |
1436 | @@ -716,6 +795,112 @@ |
1437 | } |
1438 | #endif |
1439 | |
1440 | +TEST_F(ItemTest, basic) |
1441 | +{ |
1442 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider())); |
1443 | + |
1444 | + { |
1445 | + // Default constructor. |
1446 | + Item i; |
1447 | + EXPECT_FALSE(i.isValid()); |
1448 | + EXPECT_EQ("", i.itemId()); |
1449 | + EXPECT_EQ("", i.name()); |
1450 | + EXPECT_EQ("", i.etag()); |
1451 | + EXPECT_EQ(Item::File, i.type()); |
1452 | + auto mtime = i.lastModifiedTime(); |
1453 | + EXPECT_FALSE(mtime.isValid()); |
1454 | + auto pids = i.parentIds(); |
1455 | + EXPECT_EQ(0, pids.size()); |
1456 | + } |
1457 | + |
1458 | + { |
1459 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1460 | + |
1461 | + { |
1462 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1463 | + spy.wait(SIGNAL_WAIT_TIME); |
1464 | + } |
1465 | + Item i = j->item(); |
1466 | + EXPECT_TRUE(i.isValid()); |
1467 | + EXPECT_EQ("child_id", i.itemId()); |
1468 | + EXPECT_EQ("Child", i.name()); |
1469 | + EXPECT_TRUE(i.account().isValid()); |
1470 | + EXPECT_EQ("etag", i.etag()); |
1471 | + EXPECT_EQ(Item::File, i.type()); |
1472 | + |
1473 | + // Copy constructor |
1474 | + Item i2(i); |
1475 | + EXPECT_EQ(i, i2); |
1476 | + |
1477 | + // Move constructor |
1478 | + Item i3(move(i2)); |
1479 | + EXPECT_TRUE(i3.isValid()); |
1480 | + EXPECT_EQ(i, i3); |
1481 | + |
1482 | + // Moved-from object must be invalid |
1483 | + EXPECT_FALSE(i2.isValid()); |
1484 | + |
1485 | + // Moved-from object must be assignable |
1486 | + j.reset(acc_.get("child_id")); |
1487 | + { |
1488 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1489 | + spy.wait(SIGNAL_WAIT_TIME); |
1490 | + } |
1491 | + auto i4 = j->item(); |
1492 | + i2 = i4; |
1493 | + EXPECT_EQ(i4, i2); |
1494 | + } |
1495 | + |
1496 | + { |
1497 | + unique_ptr<ItemJob> j1(acc_.get("child_id")); |
1498 | + unique_ptr<ItemJob> j2(acc_.get("root_id")); |
1499 | + |
1500 | + QSignalSpy spy1(j1.get(), &ItemJob::statusChanged); |
1501 | + QSignalSpy spy2(j2.get(), &ItemJob::statusChanged); |
1502 | + spy2.wait(SIGNAL_WAIT_TIME); |
1503 | + ASSERT_EQ(1, spy1.count()); |
1504 | + |
1505 | + auto i1 = j1->item(); |
1506 | + auto i2 = j2->item(); |
1507 | + |
1508 | + // Copy assignment |
1509 | + i1 = i2; |
1510 | + EXPECT_TRUE(i2.isValid()); |
1511 | + EXPECT_EQ(i2, i1); |
1512 | + |
1513 | + // Self-assignment |
1514 | + i2 = i2; |
1515 | + EXPECT_TRUE(i2.isValid()); |
1516 | + EXPECT_EQ("root_id", i2.itemId()); |
1517 | + EXPECT_EQ("Root", i2.name()); |
1518 | + EXPECT_TRUE(i2.account().isValid()); |
1519 | + EXPECT_EQ("etag", i2.etag()); |
1520 | + EXPECT_EQ(Item::Root, i2.type()); |
1521 | + |
1522 | + // Move assignment |
1523 | + unique_ptr<ItemJob> j3(acc_.get("child_folder_id")); |
1524 | + QSignalSpy spy(j3.get(), &ItemJob::statusChanged); |
1525 | + spy.wait(SIGNAL_WAIT_TIME); |
1526 | + ASSERT_EQ(1, spy1.count()); |
1527 | + |
1528 | + auto i3 = j3->item(); |
1529 | + |
1530 | + i1 = move(i3); |
1531 | + EXPECT_TRUE(i1.isValid()); |
1532 | + EXPECT_EQ("child_folder_id", i1.itemId()); |
1533 | + EXPECT_EQ("Child_Folder", i1.name()); |
1534 | + EXPECT_EQ(i1.account(), i1.account()); |
1535 | + EXPECT_EQ("etag", i1.etag()); |
1536 | + EXPECT_EQ(Item::Folder, i1.type()); |
1537 | + |
1538 | + // Moved-from object must be invalid |
1539 | + EXPECT_FALSE(i3.isValid()); |
1540 | + |
1541 | + // Moved-from object must be assignable |
1542 | + i3 = i2; |
1543 | + EXPECT_EQ(i2, i3); |
1544 | + } |
1545 | +} |
1546 | |
1547 | TEST_F(ItemTest, comparison_and_hash) |
1548 | { |
1549 | @@ -851,6 +1036,292 @@ |
1550 | } |
1551 | } |
1552 | |
1553 | +TEST_F(ParentsTest, basic) |
1554 | +{ |
1555 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider())); |
1556 | + |
1557 | + Item root; |
1558 | + { |
1559 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
1560 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1561 | + spy.wait(SIGNAL_WAIT_TIME); |
1562 | + root = j->item(); |
1563 | + } |
1564 | + |
1565 | + { |
1566 | + // Getting parents from root does not call the provider and returns |
1567 | + // no parents immediately. |
1568 | + unique_ptr<ItemListJob> j(root.parents()); |
1569 | + EXPECT_TRUE(j->isValid()); |
1570 | + EXPECT_EQ(ItemListJob::Finished, j->status()); |
1571 | + EXPECT_EQ(StorageError::NoError, j->error().type()); |
1572 | + |
1573 | + // Signal must be received. |
1574 | + QSignalSpy spy(j.get(), &ItemListJob::statusChanged); |
1575 | + spy.wait(SIGNAL_WAIT_TIME); |
1576 | + ASSERT_EQ(1, spy.count()); |
1577 | + auto arg = spy.takeFirst(); |
1578 | + EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
1579 | + } |
1580 | + |
1581 | + Item child; |
1582 | + { |
1583 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1584 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1585 | + spy.wait(SIGNAL_WAIT_TIME); |
1586 | + child = j->item(); |
1587 | + } |
1588 | + |
1589 | + QList<Item> parents; |
1590 | + { |
1591 | + unique_ptr<ItemListJob> j(child.parents()); |
1592 | + EXPECT_TRUE(j->isValid()); |
1593 | + EXPECT_EQ(ItemListJob::Loading, j->status()); |
1594 | + EXPECT_EQ(StorageError::NoError, j->error().type()); |
1595 | + |
1596 | + QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady); |
1597 | + QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged); |
1598 | + ready_spy.wait(SIGNAL_WAIT_TIME); |
1599 | + ASSERT_EQ(1, ready_spy.count()); |
1600 | + auto list_arg = ready_spy.takeFirst(); |
1601 | + parents = qvariant_cast<QList<Item>>(list_arg.at(0)); |
1602 | + |
1603 | + // When the signal for the final item arrives, status must be Finished. |
1604 | + EXPECT_EQ(ItemListJob::Finished, j->status()); |
1605 | + |
1606 | + // Finished signal must be received. |
1607 | + if (status_spy.count() == 0) |
1608 | + { |
1609 | + status_spy.wait(SIGNAL_WAIT_TIME); |
1610 | + } |
1611 | + ASSERT_EQ(1, status_spy.count()); |
1612 | + auto status_arg = status_spy.takeFirst(); |
1613 | + EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0))); |
1614 | + |
1615 | + // Child must have one parent, namely the root. |
1616 | + ASSERT_EQ(1, parents.size()); |
1617 | + EXPECT_EQ(root, parents[0]); |
1618 | + } |
1619 | +} |
1620 | + |
1621 | +TEST_F(ParentsTest, two_parents) |
1622 | +{ |
1623 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("two_parents"))); |
1624 | + |
1625 | + Item root; |
1626 | + { |
1627 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
1628 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1629 | + spy.wait(SIGNAL_WAIT_TIME); |
1630 | + root = j->item(); |
1631 | + } |
1632 | + |
1633 | + Item child; |
1634 | + { |
1635 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1636 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1637 | + spy.wait(SIGNAL_WAIT_TIME); |
1638 | + child = j->item(); |
1639 | + } |
1640 | + |
1641 | + QList<Item> parents; |
1642 | + { |
1643 | + unique_ptr<ItemListJob> j(child.parents()); |
1644 | + EXPECT_TRUE(j->isValid()); |
1645 | + |
1646 | + QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady); |
1647 | + QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged); |
1648 | + |
1649 | + ready_spy.wait(SIGNAL_WAIT_TIME); |
1650 | + auto list_arg = ready_spy.takeFirst(); |
1651 | + auto this_parent = qvariant_cast<QList<Item>>(list_arg.at(0)); |
1652 | + parents.append(this_parent); |
1653 | + while (ready_spy.count() < 1) |
1654 | + { |
1655 | + ready_spy.wait(SIGNAL_WAIT_TIME); |
1656 | + } |
1657 | + list_arg = ready_spy.takeFirst(); |
1658 | + this_parent = qvariant_cast<QList<Item>>(list_arg.at(0)); |
1659 | + parents.append(this_parent); |
1660 | + |
1661 | + // Finished signal must be received. |
1662 | + if (status_spy.count() == 0) |
1663 | + { |
1664 | + status_spy.wait(SIGNAL_WAIT_TIME); |
1665 | + } |
1666 | + ASSERT_EQ(1, status_spy.count()); |
1667 | + auto status_arg = status_spy.takeFirst(); |
1668 | + EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(status_arg.at(0))); |
1669 | + |
1670 | + // Child must have two parents. |
1671 | + ASSERT_EQ(2, parents.size()); |
1672 | + EXPECT_EQ("root_id", parents[0].itemId()); |
1673 | + EXPECT_EQ("child_folder_id", parents[1].itemId()); |
1674 | + } |
1675 | +} |
1676 | + |
1677 | +TEST_F(ParentsTest, two_parents_throw) |
1678 | +{ |
1679 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("two_parents_throw"))); |
1680 | + |
1681 | + Item root; |
1682 | + { |
1683 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
1684 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1685 | + spy.wait(SIGNAL_WAIT_TIME); |
1686 | + root = j->item(); |
1687 | + } |
1688 | + |
1689 | + Item child; |
1690 | + { |
1691 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1692 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1693 | + spy.wait(SIGNAL_WAIT_TIME); |
1694 | + child = j->item(); |
1695 | + } |
1696 | + |
1697 | + QList<Item> parents; |
1698 | + { |
1699 | + unique_ptr<ItemListJob> j(child.parents()); |
1700 | + EXPECT_TRUE(j->isValid()); |
1701 | + |
1702 | + QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged); |
1703 | + QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady); |
1704 | + |
1705 | + status_spy.wait(SIGNAL_WAIT_TIME); |
1706 | + ASSERT_EQ(1, status_spy.count()); |
1707 | + auto status_arg = status_spy.takeFirst(); |
1708 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(status_arg.at(0))); |
1709 | + EXPECT_EQ(StorageError::ResourceError, j->error().type()); |
1710 | + EXPECT_EQ("ResourceError: metadata(): weird error", j->error().errorString()); |
1711 | + EXPECT_EQ(42, j->error().errorCode()); |
1712 | + |
1713 | + // We wait here to allow the error return for the second parent to arrive in MultiItemJobImpl. |
1714 | + // This gives us coverage on the early return in the process_error lambda, when the job is |
1715 | + // already in the error state. |
1716 | + EXPECT_FALSE(ready_spy.wait(1000)); |
1717 | + } |
1718 | +} |
1719 | + |
1720 | +TEST_F(ParentsTest, invalid_item) |
1721 | +{ |
1722 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider())); |
1723 | + |
1724 | + Item invalid; |
1725 | + unique_ptr<ItemListJob> j(invalid.parents()); |
1726 | + EXPECT_FALSE(j->isValid()); |
1727 | + EXPECT_EQ(ItemListJob::Error, j->status()); |
1728 | + EXPECT_EQ(StorageError::LogicError, j->error().type()); |
1729 | + EXPECT_EQ("Item::parents(): cannot create job from invalid item", j->error().message()); |
1730 | + |
1731 | + // Signal must be received. |
1732 | + QSignalSpy spy(j.get(), &ItemListJob::statusChanged); |
1733 | + spy.wait(SIGNAL_WAIT_TIME); |
1734 | + ASSERT_EQ(1, spy.count()); |
1735 | + auto arg = spy.takeFirst(); |
1736 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
1737 | +} |
1738 | + |
1739 | +TEST_F(ParentsTest, runtime_destroyed) |
1740 | +{ |
1741 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider())); |
1742 | + |
1743 | + Item root; |
1744 | + { |
1745 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
1746 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1747 | + spy.wait(SIGNAL_WAIT_TIME); |
1748 | + root = j->item(); |
1749 | + } |
1750 | + |
1751 | + EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime. |
1752 | + |
1753 | + unique_ptr<ItemListJob> j(root.parents()); |
1754 | + EXPECT_FALSE(j->isValid()); |
1755 | + EXPECT_EQ(ItemJob::Error, j->status()); |
1756 | + EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type()); |
1757 | + EXPECT_EQ("Item::parents(): Runtime was destroyed previously", j->error().message()); |
1758 | + |
1759 | + // Signal must be received. |
1760 | + QSignalSpy spy(j.get(), &ItemListJob::statusChanged); |
1761 | + spy.wait(SIGNAL_WAIT_TIME); |
1762 | + auto arg = spy.takeFirst(); |
1763 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
1764 | + |
1765 | + EXPECT_EQ("Item::parents(): Runtime was destroyed previously", j->error().message()); |
1766 | +} |
1767 | + |
1768 | +TEST_F(ParentsTest, runtime_destroyed_while_item_list_job_running) |
1769 | +{ |
1770 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("slow_metadata"))); |
1771 | + |
1772 | + Item root; |
1773 | + { |
1774 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
1775 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1776 | + spy.wait(SIGNAL_WAIT_TIME); |
1777 | + root = j->item(); |
1778 | + } |
1779 | + |
1780 | + Item child; |
1781 | + { |
1782 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1783 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1784 | + spy.wait(SIGNAL_WAIT_TIME); |
1785 | + child = j->item(); |
1786 | + } |
1787 | + |
1788 | + unique_ptr<ItemListJob> j(child.parents()); |
1789 | + |
1790 | + EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping |
1791 | + |
1792 | + // Signal must be received. |
1793 | + QSignalSpy spy(j.get(), &ItemListJob::statusChanged); |
1794 | + spy.wait(SIGNAL_WAIT_TIME); |
1795 | + ASSERT_EQ(1, spy.count()); |
1796 | + auto arg = spy.takeFirst(); |
1797 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
1798 | + |
1799 | + EXPECT_EQ("Item::parents(): Runtime was destroyed previously", j->error().message()); |
1800 | +} |
1801 | + |
1802 | +TEST_F(ParentsTest, bad_metadata) |
1803 | +{ |
1804 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("bad_parent_metadata_from_child"))); |
1805 | + |
1806 | + Item root; |
1807 | + { |
1808 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
1809 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1810 | + spy.wait(SIGNAL_WAIT_TIME); |
1811 | + root = j->item(); |
1812 | + } |
1813 | + |
1814 | + Item child; |
1815 | + { |
1816 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1817 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1818 | + spy.wait(SIGNAL_WAIT_TIME); |
1819 | + child = j->item(); |
1820 | + } |
1821 | + |
1822 | + QList<Item> parents; |
1823 | + { |
1824 | + unique_ptr<ItemListJob> j(child.parents()); |
1825 | + EXPECT_TRUE(j->isValid()); |
1826 | + EXPECT_EQ(ItemListJob::Loading, j->status()); |
1827 | + EXPECT_EQ(StorageError::NoError, j->error().type()); |
1828 | + |
1829 | + QSignalSpy spy(j.get(), &ItemListJob::statusChanged); |
1830 | + spy.wait(SIGNAL_WAIT_TIME); |
1831 | + ASSERT_EQ(1, spy.count()); |
1832 | + auto arg = spy.takeFirst(); |
1833 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
1834 | + |
1835 | + EXPECT_EQ("Item::parents(): provider returned a file as a parent", j->error().message()); |
1836 | + } |
1837 | +} |
1838 | + |
1839 | #if 0 |
1840 | TEST_F(RootTest, basic) |
1841 | { |
PASSED: Continuous integration, rev:89 /jenkins. canonical. com/unity- api-1/job/ lp-storage- framework- ci/130/ /jenkins. canonical. com/unity- api-1/job/ build/781 /jenkins. canonical. com/unity- api-1/job/ build-0- fetch/787 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 595 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 595/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 595 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 595/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 595 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 595/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 595 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 595/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 595 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 595/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 595 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 595/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 595 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 595/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 595 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 595/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= yakkety/ 595 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= yakkety/ 595/artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/unity- api-1/job/ lp-storage- framework- ci/130/ rebuild
https:/