Merge lp:~michihenning/storage-framework/more-tests into lp:storage-framework/devel
- more-tests
- Merge into devel
Status: | Merged |
---|---|
Approved by: | James Henstridge |
Approved revision: | 89 |
Merged at revision: | 73 |
Proposed branch: | lp:~michihenning/storage-framework/more-tests |
Merge into: | lp:storage-framework/devel |
Prerequisite: | lp:~michihenning/storage-framework/api2 |
Diff against target: |
1420 lines (+796/-151) 18 files modified
include/unity/storage/qt/Account.h (+1/-1) include/unity/storage/qt/Item.h (+1/-1) include/unity/storage/qt/VoidJob.h (+20/-4) include/unity/storage/qt/internal/AccountImpl.h (+1/-1) include/unity/storage/qt/internal/ItemImpl.h (+2/-1) include/unity/storage/qt/internal/ItemJobImpl.h (+4/-4) include/unity/storage/qt/internal/ItemListJobImpl.h (+3/-3) include/unity/storage/qt/internal/VoidJobImpl.h (+69/-0) src/qt/CMakeLists.txt (+4/-0) src/qt/VoidJob.cpp (+57/-0) src/qt/internal/AccountImpl.cpp (+16/-7) src/qt/internal/ItemImpl.cpp (+23/-19) src/qt/internal/ItemJobImpl.cpp (+12/-1) src/qt/internal/ItemListJobImpl.cpp (+11/-0) src/qt/internal/RuntimeImpl.cpp (+2/-0) src/qt/internal/VoidJobImpl.cpp (+117/-0) tests/remote-client/MockProvider.cpp (+32/-2) tests/remote-client/remote-client_test.cpp (+421/-107) |
To merge this branch: | bzr merge lp:~michihenning/storage-framework/more-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Henstridge | Approve | ||
unity-api-1-bot | continuous-integration | Approve | |
Review via email:
|
Commit message
Added VoidJob.
Implemeted get().
Implemeted deleteItem().
Some minor refactoring and tidy-up.
Lots more tests.
Description of the change
Added VoidJob.
Implemeted get().
Implemeted deleteItem().
Some minor refactoring and tidy-up.
Lots more tests.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
unity-api-1-bot (unity-api-1-bot) wrote : | # |
- 88. By Michi Henning
-
Fixed whitespace.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
unity-api-1-bot (unity-api-1-bot) wrote : | # |
PASSED: Continuous integration, rev:88
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 : | # |
Just a few minor issues that I've included as inline comments.
- 89. By Michi Henning
-
Review comments from James.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michi Henning (michihenning) wrote : | # |
Thanks for the review!
I'll go and make the corresponding changes in the follow-up branches.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
unity-api-1-bot (unity-api-1-bot) wrote : | # |
PASSED: Continuous integration, rev:89
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:/
Preview Diff
1 | === modified file 'include/unity/storage/qt/Account.h' |
2 | --- include/unity/storage/qt/Account.h 2016-09-26 02:12:30 +0000 |
3 | +++ include/unity/storage/qt/Account.h 2016-09-29 13:09:41 +0000 |
4 | @@ -94,7 +94,7 @@ |
5 | |
6 | template<> struct Q_DECL_EXPORT hash<unity::storage::qt::Account> |
7 | { |
8 | - std::size_t operator()(unity::storage::qt::Account const& a) |
9 | + std::size_t operator()(unity::storage::qt::Account const& a) const |
10 | { |
11 | return a.hash(); |
12 | } |
13 | |
14 | === modified file 'include/unity/storage/qt/Item.h' |
15 | --- include/unity/storage/qt/Item.h 2016-09-26 02:12:30 +0000 |
16 | +++ include/unity/storage/qt/Item.h 2016-09-29 13:09:41 +0000 |
17 | @@ -146,7 +146,7 @@ |
18 | |
19 | template<> struct Q_DECL_EXPORT hash<unity::storage::qt::Item> |
20 | { |
21 | - std::size_t operator()(unity::storage::qt::Item const& i) |
22 | + std::size_t operator()(unity::storage::qt::Item const& i) const |
23 | { |
24 | return i.hash(); |
25 | } |
26 | |
27 | === modified file 'include/unity/storage/qt/VoidJob.h' |
28 | --- include/unity/storage/qt/VoidJob.h 2016-09-20 23:52:45 +0000 |
29 | +++ include/unity/storage/qt/VoidJob.h 2016-09-29 13:09:41 +0000 |
30 | @@ -20,22 +20,29 @@ |
31 | |
32 | #include <QObject> |
33 | |
34 | +#include <memory> |
35 | + |
36 | namespace unity |
37 | { |
38 | namespace storage |
39 | { |
40 | namespace qt |
41 | { |
42 | +namespace internal |
43 | +{ |
44 | + |
45 | +class VoidJobImpl; |
46 | + |
47 | +} // namespace internal |
48 | |
49 | class StorageError; |
50 | |
51 | class Q_DECL_EXPORT VoidJob final : public QObject |
52 | { |
53 | - // TODO: notify, CONSTANT where needed |
54 | Q_OBJECT |
55 | - Q_PROPERTY(bool READ isValid FINAL) |
56 | - Q_PROPERTY(unity::storage::qt::VoidJob::Status READ status NOTIFY statusChanged FINAL) |
57 | - Q_PROPERTY(unity::storage::qt::StorageError READ error FINAL) |
58 | + Q_PROPERTY(bool isValid READ isValid NOTIFY statusChanged FINAL) |
59 | + Q_PROPERTY(unity::storage::qt::VoidJob::Status status READ status NOTIFY statusChanged FINAL) |
60 | + Q_PROPERTY(unity::storage::qt::StorageError error READ error NOTIFY statusChanged FINAL) |
61 | |
62 | public: |
63 | virtual ~VoidJob(); |
64 | @@ -49,8 +56,17 @@ |
65 | |
66 | Q_SIGNALS: |
67 | void statusChanged(unity::storage::qt::VoidJob::Status status) const; |
68 | + |
69 | +private: |
70 | + VoidJob(std::unique_ptr<internal::VoidJobImpl> p); |
71 | + |
72 | + std::unique_ptr<internal::VoidJobImpl> const p_; |
73 | + |
74 | + friend class internal::VoidJobImpl; |
75 | }; |
76 | |
77 | } // namespace qt |
78 | } // namespace storage |
79 | } // namespace unity |
80 | + |
81 | +Q_DECLARE_METATYPE(unity::storage::qt::VoidJob::Status) |
82 | |
83 | === modified file 'include/unity/storage/qt/internal/AccountImpl.h' |
84 | --- include/unity/storage/qt/internal/AccountImpl.h 2016-09-20 02:24:36 +0000 |
85 | +++ include/unity/storage/qt/internal/AccountImpl.h 2016-09-29 13:09:41 +0000 |
86 | @@ -63,7 +63,7 @@ |
87 | |
88 | size_t hash() const; |
89 | |
90 | - //std::shared_ptr<RuntimeImpl> runtime() const; |
91 | + std::shared_ptr<RuntimeImpl> runtime() const; |
92 | std::shared_ptr<ProviderInterface> provider() const; |
93 | |
94 | static Account make_account(std::shared_ptr<RuntimeImpl> const& runtime, |
95 | |
96 | === modified file 'include/unity/storage/qt/internal/ItemImpl.h' |
97 | --- include/unity/storage/qt/internal/ItemImpl.h 2016-09-26 02:12:30 +0000 |
98 | +++ include/unity/storage/qt/internal/ItemImpl.h 2016-09-29 13:09:41 +0000 |
99 | @@ -49,7 +49,6 @@ |
100 | QString itemId() const; |
101 | QString name() const; |
102 | Account account() const; |
103 | - //Item root() const; |
104 | QString etag() const; |
105 | Item::Type type() const; |
106 | QVariantMap metadata() const; |
107 | @@ -82,6 +81,8 @@ |
108 | storage::internal::ItemMetadata const& md, |
109 | std::shared_ptr<AccountImpl> const& account); |
110 | |
111 | + std::shared_ptr<RuntimeImpl> runtime() const; |
112 | + |
113 | private: |
114 | //std::shared_ptr<RuntimeImpl> get_runtime(QString const& method) const; |
115 | |
116 | |
117 | === modified file 'include/unity/storage/qt/internal/ItemJobImpl.h' |
118 | --- include/unity/storage/qt/internal/ItemJobImpl.h 2016-09-26 02:12:30 +0000 |
119 | +++ include/unity/storage/qt/internal/ItemJobImpl.h 2016-09-29 13:09:41 +0000 |
120 | @@ -20,10 +20,10 @@ |
121 | |
122 | #include <unity/storage/qt/ItemJob.h> |
123 | |
124 | -#include <unity/storage/qt/Account.h> |
125 | -#include <unity/storage/qt/internal/Handler.h> |
126 | #include <unity/storage/qt/StorageError.h> |
127 | |
128 | +#include <QDBusPendingReply> |
129 | + |
130 | namespace unity |
131 | { |
132 | namespace storage |
133 | @@ -33,14 +33,14 @@ |
134 | |
135 | class ItemMetadata; |
136 | |
137 | -} |
138 | +} // namespace internal |
139 | |
140 | namespace qt |
141 | { |
142 | namespace internal |
143 | { |
144 | |
145 | -class RuntimeImpl; |
146 | +class AccountImpl; |
147 | |
148 | class ItemJobImpl : public QObject |
149 | { |
150 | |
151 | === modified file 'include/unity/storage/qt/internal/ItemListJobImpl.h' |
152 | --- include/unity/storage/qt/internal/ItemListJobImpl.h 2016-09-26 02:12:30 +0000 |
153 | +++ include/unity/storage/qt/internal/ItemListJobImpl.h 2016-09-29 13:09:41 +0000 |
154 | @@ -20,10 +20,10 @@ |
155 | |
156 | #include <unity/storage/qt/ItemListJob.h> |
157 | |
158 | -#include <unity/storage/qt/Account.h> |
159 | -#include <unity/storage/qt/internal/Handler.h> |
160 | #include <unity/storage/qt/StorageError.h> |
161 | |
162 | +#include <QDBusPendingReply> |
163 | + |
164 | namespace unity |
165 | { |
166 | namespace storage |
167 | @@ -40,7 +40,7 @@ |
168 | namespace internal |
169 | { |
170 | |
171 | -class RuntimeImpl; |
172 | +class AccountImpl; |
173 | |
174 | class ItemListJobImpl : public QObject |
175 | { |
176 | |
177 | === added file 'include/unity/storage/qt/internal/VoidJobImpl.h' |
178 | --- include/unity/storage/qt/internal/VoidJobImpl.h 1970-01-01 00:00:00 +0000 |
179 | +++ include/unity/storage/qt/internal/VoidJobImpl.h 2016-09-29 13:09:41 +0000 |
180 | @@ -0,0 +1,69 @@ |
181 | +/* |
182 | + * Copyright (C) 2016 Canonical Ltd |
183 | + * |
184 | + * This program is free software: you can redistribute it and/or modify |
185 | + * it under the terms of the GNU Lesser General Public License version 3 as |
186 | + * published by the Free Software Foundation. |
187 | + * |
188 | + * This program is distributed in the hope that it will be useful, |
189 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
190 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
191 | + * GNU Lesser General Public License for more details. |
192 | + * |
193 | + * You should have received a copy of the GNU Lesser General Public License |
194 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
195 | + * |
196 | + * Authors: Michi Henning <michi.henning@canonical.com> |
197 | + */ |
198 | + |
199 | +#pragma once |
200 | + |
201 | +#include <unity/storage/qt/VoidJob.h> |
202 | + |
203 | +#include <unity/storage/qt/StorageError.h> |
204 | + |
205 | +#include <QDBusPendingReply> |
206 | + |
207 | +namespace unity |
208 | +{ |
209 | +namespace storage |
210 | +{ |
211 | +namespace qt |
212 | +{ |
213 | +namespace internal |
214 | +{ |
215 | + |
216 | +class ItemImpl; |
217 | + |
218 | +class VoidJobImpl : public QObject |
219 | +{ |
220 | + Q_OBJECT |
221 | +public: |
222 | + virtual ~VoidJobImpl() = default; |
223 | + |
224 | + bool isValid() const; |
225 | + VoidJob::Status status() const; |
226 | + StorageError error() const; |
227 | + |
228 | + static VoidJob* make_void_job(std::shared_ptr<ItemImpl> const& item, |
229 | + QString const& method, |
230 | + QDBusPendingReply<void> const& reply); |
231 | + static VoidJob* make_void_job(StorageError const& e); |
232 | + |
233 | +private: |
234 | + VoidJobImpl(std::shared_ptr<ItemImpl> const& item, |
235 | + QString const& method, |
236 | + QDBusPendingReply<void> const& reply); |
237 | + VoidJobImpl(StorageError const& e); |
238 | + |
239 | + VoidJob* public_instance_; |
240 | + VoidJob::Status status_; |
241 | + StorageError error_; |
242 | + QString method_; |
243 | + std::shared_ptr<ItemImpl> item_; |
244 | +}; |
245 | + |
246 | +} // namespace internal |
247 | +} // namespace qt |
248 | +} // namespace storage |
249 | +} // namespace unity |
250 | |
251 | === modified file 'src/qt/CMakeLists.txt' |
252 | --- src/qt/CMakeLists.txt 2016-09-16 06:25:08 +0000 |
253 | +++ src/qt/CMakeLists.txt 2016-09-29 13:09:41 +0000 |
254 | @@ -23,6 +23,7 @@ |
255 | ItemListJob.cpp |
256 | Runtime.cpp |
257 | StorageError.cpp |
258 | + VoidJob.cpp |
259 | internal/AccountImpl.cpp |
260 | internal/AccountsJobImpl.cpp |
261 | internal/HandlerBase.cpp |
262 | @@ -33,16 +34,19 @@ |
263 | internal/StorageErrorImpl.cpp |
264 | internal/unmarshal_error.cpp |
265 | internal/validate.cpp |
266 | + internal/VoidJobImpl.cpp |
267 | ${generated_files} |
268 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/AccountsJob.h |
269 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/Item.h |
270 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/ItemJob.h |
271 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/ItemListJob.h |
272 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/Runtime.h |
273 | + ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/VoidJob.h |
274 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/AccountsJobImpl.h |
275 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/HandlerBase.h |
276 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/ItemJobImpl.h |
277 | ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/ItemListJobImpl.h |
278 | + ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/internal/VoidJobImpl.h |
279 | ) |
280 | |
281 | add_library(storage-framework-qt-client-v2 SHARED |
282 | |
283 | === added file 'src/qt/VoidJob.cpp' |
284 | --- src/qt/VoidJob.cpp 1970-01-01 00:00:00 +0000 |
285 | +++ src/qt/VoidJob.cpp 2016-09-29 13:09:41 +0000 |
286 | @@ -0,0 +1,57 @@ |
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 | +#include <unity/storage/qt/VoidJob.h> |
306 | + |
307 | +#include <unity/storage/qt/internal/VoidJobImpl.h> |
308 | + |
309 | +using namespace unity::storage::qt; |
310 | +using namespace std; |
311 | + |
312 | +namespace unity |
313 | +{ |
314 | +namespace storage |
315 | +{ |
316 | +namespace qt |
317 | +{ |
318 | + |
319 | +VoidJob::VoidJob(unique_ptr<internal::VoidJobImpl> p) |
320 | + : p_(move(p)) |
321 | +{ |
322 | +} |
323 | + |
324 | +VoidJob::~VoidJob() = default; |
325 | + |
326 | +bool VoidJob::isValid() const |
327 | +{ |
328 | + return p_->isValid(); |
329 | +} |
330 | + |
331 | +VoidJob::Status VoidJob::status() const |
332 | +{ |
333 | + return p_->status(); |
334 | +} |
335 | + |
336 | +StorageError VoidJob::error() const |
337 | +{ |
338 | + return p_->error(); |
339 | +} |
340 | + |
341 | +} // namespace qt |
342 | +} // namespace storage |
343 | +} // namespace unity |
344 | |
345 | === modified file 'src/qt/internal/AccountImpl.cpp' |
346 | --- src/qt/internal/AccountImpl.cpp 2016-09-22 01:52:20 +0000 |
347 | +++ src/qt/internal/AccountImpl.cpp 2016-09-29 13:09:41 +0000 |
348 | @@ -24,6 +24,7 @@ |
349 | #include <unity/storage/qt/internal/ItemJobImpl.h> |
350 | #include <unity/storage/qt/internal/ItemListJobImpl.h> |
351 | #include <unity/storage/qt/internal/RuntimeImpl.h> |
352 | +#include <unity/storage/qt/internal/StorageErrorImpl.h> |
353 | #include <unity/storage/qt/Runtime.h> |
354 | |
355 | #include <boost/functional/hash.hpp> |
356 | @@ -82,24 +83,25 @@ |
357 | |
358 | ItemListJob* AccountImpl::roots() const |
359 | { |
360 | + QString const method = "Account::roots()"; |
361 | + |
362 | auto runtime = runtime_.lock(); |
363 | if (!runtime || !runtime->isValid()) |
364 | { |
365 | - auto e = StorageErrorImpl::runtime_destroyed_error("Account::roots(): Runtime was destroyed previously"); |
366 | + auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously"); |
367 | return ItemListJobImpl::make_item_list_job(e); |
368 | } |
369 | |
370 | - auto validate = [](storage::internal::ItemMetadata const& md) |
371 | + auto validate = [method](storage::internal::ItemMetadata const& md) |
372 | { |
373 | if (md.type != ItemType::root) |
374 | { |
375 | - QString msg = "provider returned non-root item type: " + QString::number(int(md.type)); |
376 | + QString msg = method + ": provider returned non-root item type: " + QString::number(int(md.type)); |
377 | qCritical() << msg; |
378 | throw StorageErrorImpl::local_comms_error(msg); |
379 | } |
380 | }; |
381 | |
382 | - QString method = "Account::roots()"; |
383 | auto reply = provider_->Roots(); |
384 | auto This = const_pointer_cast<AccountImpl>(shared_from_this()); |
385 | return ItemListJobImpl::make_item_list_job(This, method, reply, validate); |
386 | @@ -107,19 +109,21 @@ |
387 | |
388 | ItemJob* AccountImpl::get(QString const& itemId) const |
389 | { |
390 | + QString const method = "Account::get()"; |
391 | + |
392 | auto runtime = runtime_.lock(); |
393 | if (!runtime || !runtime->isValid()) |
394 | { |
395 | - auto e = StorageErrorImpl::runtime_destroyed_error("Account::get(): Runtime was destroyed previously"); |
396 | + auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously"); |
397 | return ItemJobImpl::make_item_job(e); |
398 | } |
399 | |
400 | - // TODO: use defaulted param? |
401 | + // LCOV_EXCL_START |
402 | auto validate = [](storage::internal::ItemMetadata const&) |
403 | { |
404 | }; |
405 | + // LCOV_EXCL_STOP |
406 | |
407 | - QString method = "Item::get()"; |
408 | auto reply = provider_->Metadata(itemId); |
409 | auto This = const_pointer_cast<AccountImpl>(shared_from_this()); |
410 | return ItemJobImpl::make_item_job(This, method, reply, validate); |
411 | @@ -187,6 +191,11 @@ |
412 | return !operator<(other); |
413 | } |
414 | |
415 | +shared_ptr<RuntimeImpl> AccountImpl::runtime() const |
416 | +{ |
417 | + return runtime_.lock(); |
418 | +} |
419 | + |
420 | shared_ptr<ProviderInterface> AccountImpl::provider() const |
421 | { |
422 | return provider_; |
423 | |
424 | === modified file 'src/qt/internal/ItemImpl.cpp' |
425 | --- src/qt/internal/ItemImpl.cpp 2016-09-26 02:12:30 +0000 |
426 | +++ src/qt/internal/ItemImpl.cpp 2016-09-29 13:09:41 +0000 |
427 | @@ -23,6 +23,8 @@ |
428 | #include <unity/storage/qt/internal/AccountImpl.h> |
429 | #include <unity/storage/qt/internal/ItemJobImpl.h> |
430 | #include <unity/storage/qt/internal/RuntimeImpl.h> |
431 | +#include <unity/storage/qt/internal/StorageErrorImpl.h> |
432 | +#include <unity/storage/qt/internal/VoidJobImpl.h> |
433 | #include <unity/storage/qt/internal/validate.h> |
434 | |
435 | #include <boost/functional/hash.hpp> |
436 | @@ -70,13 +72,6 @@ |
437 | return is_valid_ ? account_ : Account(); |
438 | } |
439 | |
440 | -#if 0 |
441 | -Item ItemImpl::root() const |
442 | -{ |
443 | - return is_valid_ ? root_ : Item(); |
444 | -} |
445 | -#endif |
446 | - |
447 | QString ItemImpl::etag() const |
448 | { |
449 | return is_valid_ ? md_.etag : ""; |
450 | @@ -131,7 +126,25 @@ |
451 | |
452 | VoidJob* ItemImpl::deleteItem() const |
453 | { |
454 | - return nullptr; // TODO |
455 | + QString const method = "Item::deleteItem()"; |
456 | + |
457 | + assert(account_); |
458 | + auto runtime = account_->runtime(); |
459 | + if (!runtime || !runtime->isValid()) |
460 | + { |
461 | + auto e = StorageErrorImpl::runtime_destroyed_error(method + ": Runtime was destroyed previously"); |
462 | + return VoidJobImpl::make_void_job(e); |
463 | + } |
464 | + |
465 | + if (md_.type == storage::ItemType::root) |
466 | + { |
467 | + auto e = StorageErrorImpl::logic_error(method + ": cannot delete root"); |
468 | + return VoidJobImpl::make_void_job(e); |
469 | + } |
470 | + |
471 | + auto reply = account_->provider()->Delete(md_.item_id); |
472 | + auto This = const_pointer_cast<ItemImpl>(shared_from_this()); |
473 | + return VoidJobImpl::make_void_job(This, method, reply); |
474 | } |
475 | |
476 | Uploader* ItemImpl::createUploader(Item::ConflictPolicy policy, qint64 sizeInBytes) const |
477 | @@ -248,19 +261,10 @@ |
478 | return Item(p); |
479 | } |
480 | |
481 | -#if 0 |
482 | -shared_ptr<RuntimeImpl> ItemImpl::get_runtime(QString const& method) const |
483 | +shared_ptr<RuntimeImpl> ItemImpl::runtime() const |
484 | { |
485 | - auto runtime = account_->runtime_.lock(); |
486 | - if (!runtime || !runtime->isValid()) |
487 | - { |
488 | - QString msg = method + ": Runtime was destroyed previously"; |
489 | - auto This = const_cast<ItemImpl*>(this); |
490 | - This->error_ = StorageErrorImpl::runtime_destroyed_error(msg); |
491 | - } |
492 | - return runtime; |
493 | + return account_->runtime(); |
494 | } |
495 | -#endif |
496 | |
497 | } // namespace internal |
498 | } // namespace qt |
499 | |
500 | === modified file 'src/qt/internal/ItemJobImpl.cpp' |
501 | --- src/qt/internal/ItemJobImpl.cpp 2016-09-26 02:12:30 +0000 |
502 | +++ src/qt/internal/ItemJobImpl.cpp 2016-09-29 13:09:41 +0000 |
503 | @@ -20,8 +20,10 @@ |
504 | |
505 | #include <unity/storage/internal/dbusmarshal.h> |
506 | #include <unity/storage/internal/ItemMetadata.h> |
507 | +#include <unity/storage/qt/internal/AccountImpl.h> |
508 | #include <unity/storage/qt/internal/Handler.h> |
509 | #include <unity/storage/qt/internal/ItemImpl.h> |
510 | +#include <unity/storage/qt/internal/RuntimeImpl.h> |
511 | |
512 | using namespace std; |
513 | |
514 | @@ -49,6 +51,15 @@ |
515 | |
516 | auto process_reply = [this](decltype(reply)& r) |
517 | { |
518 | + auto runtime = account_->runtime(); |
519 | + if (!runtime || !runtime->isValid()) |
520 | + { |
521 | + error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously"); |
522 | + status_ = ItemJob::Error; |
523 | + Q_EMIT public_instance_->statusChanged(status_); |
524 | + return; |
525 | + } |
526 | + |
527 | auto metadata = r.value(); |
528 | try |
529 | { |
530 | @@ -98,7 +109,7 @@ |
531 | |
532 | Item ItemJobImpl::item() const |
533 | { |
534 | - return Item(); // TODO |
535 | + return item_; |
536 | } |
537 | |
538 | ItemJob* ItemJobImpl::make_item_job(shared_ptr<AccountImpl> const& account, |
539 | |
540 | === modified file 'src/qt/internal/ItemListJobImpl.cpp' |
541 | --- src/qt/internal/ItemListJobImpl.cpp 2016-09-26 02:12:30 +0000 |
542 | +++ src/qt/internal/ItemListJobImpl.cpp 2016-09-29 13:09:41 +0000 |
543 | @@ -20,8 +20,10 @@ |
544 | |
545 | #include <unity/storage/internal/dbusmarshal.h> |
546 | #include <unity/storage/internal/ItemMetadata.h> |
547 | +#include <unity/storage/qt/internal/AccountImpl.h> |
548 | #include <unity/storage/qt/internal/Handler.h> |
549 | #include <unity/storage/qt/internal/ItemImpl.h> |
550 | +#include <unity/storage/qt/internal/RuntimeImpl.h> |
551 | |
552 | using namespace std; |
553 | |
554 | @@ -49,6 +51,15 @@ |
555 | |
556 | auto process_reply = [this](decltype(reply)& r) |
557 | { |
558 | + auto runtime = account_->runtime(); |
559 | + if (!runtime || !runtime->isValid()) |
560 | + { |
561 | + error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously"); |
562 | + status_ = ItemListJob::Error; |
563 | + Q_EMIT public_instance_->statusChanged(status_); |
564 | + return; |
565 | + } |
566 | + |
567 | QList<Item> items; |
568 | auto metadata = r.value(); |
569 | for (auto const& md : metadata) |
570 | |
571 | === modified file 'src/qt/internal/RuntimeImpl.cpp' |
572 | --- src/qt/internal/RuntimeImpl.cpp 2016-09-26 02:12:30 +0000 |
573 | +++ src/qt/internal/RuntimeImpl.cpp 2016-09-29 13:09:41 +0000 |
574 | @@ -26,6 +26,7 @@ |
575 | #include <unity/storage/qt/ItemJob.h> |
576 | #include <unity/storage/qt/ItemListJob.h> |
577 | #include <unity/storage/qt/Runtime.h> |
578 | +#include <unity/storage/qt/VoidJob.h> |
579 | |
580 | #include <QDBusError> |
581 | #include <QDBusMetaType> |
582 | @@ -50,6 +51,7 @@ |
583 | qRegisterMetaType<QList<unity::storage::qt::Item>>(); |
584 | qRegisterMetaType<unity::storage::qt::ItemJob::Status>(); |
585 | qRegisterMetaType<unity::storage::qt::ItemListJob::Status>(); |
586 | + qRegisterMetaType<unity::storage::qt::VoidJob::Status>(); |
587 | |
588 | qDBusRegisterMetaType<unity::storage::internal::ItemMetadata>(); |
589 | qDBusRegisterMetaType<QList<unity::storage::internal::ItemMetadata>>(); |
590 | |
591 | === added file 'src/qt/internal/VoidJobImpl.cpp' |
592 | --- src/qt/internal/VoidJobImpl.cpp 1970-01-01 00:00:00 +0000 |
593 | +++ src/qt/internal/VoidJobImpl.cpp 2016-09-29 13:09:41 +0000 |
594 | @@ -0,0 +1,117 @@ |
595 | +/* |
596 | + * Copyright (C) 2016 Canonical Ltd |
597 | + * |
598 | + * This program is free software: you can redistribute it and/or modify |
599 | + * it under the terms of the GNU Lesser General Public License version 3 as |
600 | + * published by the Free Software Foundation. |
601 | + * |
602 | + * This program is distributed in the hope that it will be useful, |
603 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
604 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
605 | + * GNU Lesser General Public License for more details. |
606 | + * |
607 | + * You should have received a copy of the GNU Lesser General Public License |
608 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
609 | + * |
610 | + * Authors: Michi Henning <michi.henning@canonical.com> |
611 | + */ |
612 | + |
613 | +#include <unity/storage/qt/internal/VoidJobImpl.h> |
614 | + |
615 | +#include <unity/storage/qt/internal/Handler.h> |
616 | +#include <unity/storage/qt/internal/ItemImpl.h> |
617 | +#include <unity/storage/qt/internal/RuntimeImpl.h> |
618 | + |
619 | +using namespace std; |
620 | + |
621 | +namespace unity |
622 | +{ |
623 | +namespace storage |
624 | +{ |
625 | +namespace qt |
626 | +{ |
627 | +namespace internal |
628 | +{ |
629 | + |
630 | +VoidJobImpl::VoidJobImpl(shared_ptr<ItemImpl> const& item, |
631 | + QString const& method, |
632 | + QDBusPendingReply<void> const& reply) |
633 | + : status_(VoidJob::Loading) |
634 | + , method_(method) |
635 | + , item_(item) |
636 | +{ |
637 | + assert(!method_.isEmpty()); |
638 | + assert(item); |
639 | + |
640 | + auto process_reply = [this](decltype(reply)&) |
641 | + { |
642 | + auto runtime = item_->runtime(); |
643 | + if (!runtime || !runtime->isValid()) |
644 | + { |
645 | + error_ = StorageErrorImpl::runtime_destroyed_error(method_ + ": Runtime was destroyed previously"); |
646 | + status_ = VoidJob::Error; |
647 | + Q_EMIT public_instance_->statusChanged(status_); |
648 | + return; |
649 | + } |
650 | + |
651 | + status_ = VoidJob::Finished; |
652 | + Q_EMIT public_instance_->statusChanged(status_); |
653 | + }; |
654 | + |
655 | + auto process_error = [this](StorageError const& error) |
656 | + { |
657 | + error_ = error; |
658 | + status_ = VoidJob::Error; |
659 | + Q_EMIT public_instance_->statusChanged(status_); |
660 | + }; |
661 | + |
662 | + new Handler<void>(this, reply, process_reply, process_error); |
663 | +} |
664 | + |
665 | +VoidJobImpl::VoidJobImpl(StorageError const& error) |
666 | + : status_(VoidJob::Error) |
667 | + , error_(error) |
668 | +{ |
669 | +} |
670 | + |
671 | +bool VoidJobImpl::isValid() const |
672 | +{ |
673 | + return status_ != VoidJob::Status::Error; |
674 | +} |
675 | + |
676 | +VoidJob::Status VoidJobImpl::status() const |
677 | +{ |
678 | + return status_; |
679 | +} |
680 | + |
681 | +StorageError VoidJobImpl::error() const |
682 | +{ |
683 | + return error_; |
684 | +} |
685 | + |
686 | +VoidJob* VoidJobImpl::make_void_job(shared_ptr<ItemImpl> const& item, |
687 | + QString const& method, |
688 | + QDBusPendingReply<void> const& reply) |
689 | +{ |
690 | + unique_ptr<VoidJobImpl> impl(new VoidJobImpl(item, method, reply)); |
691 | + auto job = new VoidJob(move(impl)); |
692 | + job->p_->public_instance_ = job; |
693 | + return job; |
694 | +} |
695 | + |
696 | +VoidJob* VoidJobImpl::make_void_job(StorageError const& error) |
697 | +{ |
698 | + unique_ptr<VoidJobImpl> impl(new VoidJobImpl(error)); |
699 | + auto job = new VoidJob(move(impl)); |
700 | + job->p_->public_instance_ = job; |
701 | + QMetaObject::invokeMethod(job, |
702 | + "statusChanged", |
703 | + Qt::QueuedConnection, |
704 | + Q_ARG(unity::storage::qt::VoidJob::Status, job->p_->status_)); |
705 | + return job; |
706 | +} |
707 | + |
708 | +} // namespace internal |
709 | +} // namespace qt |
710 | +} // namespace storage |
711 | +} // namespace unity |
712 | |
713 | === modified file 'tests/remote-client/MockProvider.cpp' |
714 | --- tests/remote-client/MockProvider.cpp 2016-09-16 06:25:08 +0000 |
715 | +++ tests/remote-client/MockProvider.cpp 2016-09-29 13:09:41 +0000 |
716 | @@ -46,7 +46,19 @@ |
717 | |
718 | boost::future<ItemList> MockProvider::roots(Context const&) |
719 | { |
720 | - cerr << "roots CALLED" << endl; |
721 | + if (cmd_ == "slow_roots") |
722 | + { |
723 | + this_thread::sleep_for(chrono::seconds(1)); |
724 | + } |
725 | + if (cmd_ == "not_a_root") |
726 | + { |
727 | + ItemList roots = |
728 | + { |
729 | + {"root_id", {}, "Root", "etag", ItemType::file, {}} |
730 | + }; |
731 | + return make_ready_future<ItemList>(roots); |
732 | + } |
733 | + |
734 | ItemList roots = |
735 | { |
736 | {"root_id", {}, "Root", "etag", ItemType::root, {}} |
737 | @@ -103,6 +115,15 @@ |
738 | |
739 | boost::future<Item> MockProvider::metadata(string const& item_id, Context const&) |
740 | { |
741 | + if (cmd_ == "slow_metadata") |
742 | + { |
743 | + this_thread::sleep_for(chrono::seconds(1)); |
744 | + } |
745 | + if (cmd_ == "empty_id") |
746 | + { |
747 | + Item metadata{"", {}, "Root", "etag", ItemType::root, {}}; |
748 | + return make_ready_future<Item>(metadata); |
749 | + } |
750 | if (item_id == "root_id") |
751 | { |
752 | Item metadata{"root_id", {}, "Root", "etag", ItemType::root, {}}; |
753 | @@ -168,8 +189,17 @@ |
754 | } |
755 | |
756 | boost::future<void> MockProvider::delete_item( |
757 | - string const&, Context const&) |
758 | + string const& item_id, Context const&) |
759 | { |
760 | + if (cmd_ == "slow_delete") |
761 | + { |
762 | + this_thread::sleep_for(chrono::seconds(1)); |
763 | + } |
764 | + if (cmd_ == "delete_no_such_item") |
765 | + { |
766 | + string msg = "delete_item(): no such item: " + item_id; |
767 | + return make_exceptional_future<void>(NotExistsException(msg, item_id)); |
768 | + } |
769 | return make_ready_future(); |
770 | } |
771 | |
772 | |
773 | === modified file 'tests/remote-client/remote-client_test.cpp' |
774 | --- tests/remote-client/remote-client_test.cpp 2016-09-26 02:37:03 +0000 |
775 | +++ tests/remote-client/remote-client_test.cpp 2016-09-29 13:09:41 +0000 |
776 | @@ -24,6 +24,8 @@ |
777 | #include <gtest/gtest.h> |
778 | #include <QSignalSpy> |
779 | |
780 | +#include <unordered_set> |
781 | + |
782 | using namespace unity::storage; |
783 | using namespace unity::storage::qt; |
784 | using namespace std; |
785 | @@ -52,10 +54,12 @@ |
786 | Account acc_; |
787 | }; |
788 | |
789 | -class RuntimeTest : public ProviderFixture {}; |
790 | class AccountTest : public RemoteClientTest {}; |
791 | +class DeleteTest : public RemoteClientTest {}; |
792 | +class GetTest : public RemoteClientTest {}; |
793 | +class ItemTest : public RemoteClientTest {}; |
794 | class RootsTest : public RemoteClientTest {}; |
795 | -class ItemTest : public RemoteClientTest {}; |
796 | +class RuntimeTest : public ProviderFixture {}; |
797 | |
798 | TEST(Runtime, lifecycle) |
799 | { |
800 | @@ -75,6 +79,7 @@ |
801 | } |
802 | |
803 | #if 0 |
804 | +// TODO, how to test this? |
805 | TEST_F(RuntimeTest, init_error) |
806 | { |
807 | QDBusConnection conn(connection()); |
808 | @@ -299,9 +304,12 @@ |
809 | |
810 | TEST_F(AccountTest, hash) |
811 | { |
812 | + unordered_set<Account>(); // Just to show that this works. |
813 | + |
814 | Account a1; |
815 | + EXPECT_EQ(0, hash<Account>()(a1)); |
816 | EXPECT_EQ(0, a1.hash()); |
817 | - EXPECT_EQ(a1.hash(), qHash(a1)); |
818 | + EXPECT_EQ(0, qHash(a1)); |
819 | |
820 | auto a2 = runtime_->make_test_account(service_connection_->baseService(), object_path(), "a", "a", "a"); |
821 | // Due to different return types (size_t vs uint), hash() and qHash() do not return the same value. |
822 | @@ -317,11 +325,11 @@ |
823 | EXPECT_EQ(StorageError::NoError, j->error().type()); |
824 | EXPECT_EQ(QList<Account>(), j->accounts()); // We haven't waited for the result yet. |
825 | |
826 | - QSignalSpy spy(j.get(), &unity::storage::qt::AccountsJob::statusChanged); |
827 | + QSignalSpy spy(j.get(), &AccountsJob::statusChanged); |
828 | spy.wait(SIGNAL_WAIT_TIME); |
829 | ASSERT_EQ(1, spy.count()); |
830 | auto arg = spy.takeFirst(); |
831 | - EXPECT_EQ(AccountsJob::Finished, qvariant_cast<unity::storage::qt::AccountsJob::Status>(arg.at(0))); |
832 | + EXPECT_EQ(AccountsJob::Finished, qvariant_cast<AccountsJob::Status>(arg.at(0))); |
833 | |
834 | EXPECT_TRUE(j->isValid()); |
835 | EXPECT_EQ(AccountsJob::Finished, j->status()); |
836 | @@ -342,16 +350,15 @@ |
837 | EXPECT_FALSE(j->isValid()); |
838 | EXPECT_EQ(AccountsJob::Error, j->status()); |
839 | EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type()); |
840 | - EXPECT_EQ("Runtime::accounts(): Runtime was destroyed previously", |
841 | - j->error().message()) << j->error().message().toStdString(); |
842 | + EXPECT_EQ("Runtime::accounts(): Runtime was destroyed previously", j->error().message()); |
843 | EXPECT_EQ(QList<Account>(), j->accounts()); |
844 | |
845 | // Signal must be received. |
846 | - QSignalSpy spy(j, &unity::storage::qt::AccountsJob::statusChanged); |
847 | + QSignalSpy spy(j, &AccountsJob::statusChanged); |
848 | spy.wait(SIGNAL_WAIT_TIME); |
849 | ASSERT_EQ(1, spy.count()); |
850 | auto arg = spy.takeFirst(); |
851 | - EXPECT_EQ(AccountsJob::Error, qvariant_cast<unity::storage::qt::AccountsJob::Status>(arg.at(0))); |
852 | + EXPECT_EQ(AccountsJob::Error, qvariant_cast<AccountsJob::Status>(arg.at(0))); |
853 | } |
854 | |
855 | TEST_F(RootsTest, roots) |
856 | @@ -364,19 +371,19 @@ |
857 | EXPECT_EQ(StorageError::NoError, j->error().type()); |
858 | |
859 | // Check that we get the statusChanged and itemsReady signals. |
860 | - QSignalSpy ready_spy(j.get(), &unity::storage::qt::ItemListJob::itemsReady); |
861 | - QSignalSpy status_spy(j.get(), &unity::storage::qt::ItemListJob::statusChanged); |
862 | + QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady); |
863 | + QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged); |
864 | |
865 | ASSERT_TRUE(ready_spy.wait(SIGNAL_WAIT_TIME)); |
866 | |
867 | ASSERT_EQ(1, ready_spy.count()); |
868 | auto arg = ready_spy.takeFirst(); |
869 | auto items = qvariant_cast<QList<Item>>(arg.at(0)); |
870 | - EXPECT_EQ(1, items.size()); |
871 | + ASSERT_EQ(1, items.size()); |
872 | |
873 | ASSERT_EQ(1, status_spy.count()); |
874 | arg = status_spy.takeFirst(); |
875 | - EXPECT_EQ(ItemListJob::Finished, qvariant_cast<unity::storage::qt::ItemListJob::Status>(arg.at(0))); |
876 | + EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
877 | EXPECT_EQ(StorageError::NoError, j->error().type()); |
878 | |
879 | EXPECT_TRUE(j->isValid()); |
880 | @@ -403,38 +410,349 @@ |
881 | EXPECT_FALSE(j->isValid()); |
882 | EXPECT_EQ(ItemListJob::Error, j->status()); |
883 | EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type()); |
884 | - EXPECT_EQ("Account::roots(): Runtime was destroyed previously", |
885 | - j->error().message()) << j->error().message().toStdString(); |
886 | - |
887 | - // Signal must be received. |
888 | - QSignalSpy spy(j.get(), &unity::storage::qt::ItemListJob::statusChanged); |
889 | - spy.wait(SIGNAL_WAIT_TIME); |
890 | - ASSERT_EQ(1, spy.count()); |
891 | - auto arg = spy.takeFirst(); |
892 | - EXPECT_EQ(ItemListJob::Error, qvariant_cast<unity::storage::qt::ItemListJob::Status>(arg.at(0))); |
893 | -} |
894 | - |
895 | -TEST_F(ItemTest, comparison) |
896 | + EXPECT_EQ("Account::roots(): Runtime was destroyed previously", j->error().message()); |
897 | + |
898 | + // Signal must be received. |
899 | + QSignalSpy spy(j.get(), &ItemListJob::statusChanged); |
900 | + spy.wait(SIGNAL_WAIT_TIME); |
901 | + ASSERT_EQ(1, spy.count()); |
902 | + auto arg = spy.takeFirst(); |
903 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
904 | +} |
905 | + |
906 | +TEST_F(RootsTest, runtime_destroyed_while_item_list_job_running) |
907 | +{ |
908 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("slow_roots"))); |
909 | + |
910 | + unique_ptr<ItemListJob> j(acc_.roots()); |
911 | + EXPECT_TRUE(j->isValid()); |
912 | + EXPECT_EQ(ItemListJob::Loading, j->status()); |
913 | + EXPECT_EQ(StorageError::NoError, j->error().type()); |
914 | + |
915 | + EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping |
916 | + |
917 | + // Signal must be received. |
918 | + QSignalSpy spy(j.get(), &ItemListJob::statusChanged); |
919 | + spy.wait(SIGNAL_WAIT_TIME); |
920 | + ASSERT_EQ(1, spy.count()); |
921 | + auto arg = spy.takeFirst(); |
922 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
923 | + |
924 | + EXPECT_EQ("Account::roots(): Runtime was destroyed previously", j->error().message()); |
925 | +} |
926 | + |
927 | +TEST_F(RootsTest, not_a_root) |
928 | +{ |
929 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("not_a_root"))); |
930 | + |
931 | + unique_ptr<ItemListJob> j(acc_.roots()); |
932 | + |
933 | + QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady); |
934 | + QSignalSpy status_spy(j.get(), &ItemListJob::statusChanged); |
935 | + status_spy.wait(SIGNAL_WAIT_TIME); |
936 | + auto arg = status_spy.takeFirst(); |
937 | + |
938 | + // Bad metadata is ignored, so status is finished, and itemsReady was never called. |
939 | + EXPECT_EQ(ItemListJob::Finished, qvariant_cast<ItemListJob::Status>(arg.at(0))); |
940 | + EXPECT_EQ(0, status_spy.count()); |
941 | +} |
942 | + |
943 | +TEST_F(GetTest, basic) |
944 | +{ |
945 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider())); |
946 | + |
947 | + // Get root. |
948 | + { |
949 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
950 | + |
951 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
952 | + spy.wait(SIGNAL_WAIT_TIME); |
953 | + |
954 | + EXPECT_EQ("root_id", j->item().itemId()); |
955 | + EXPECT_EQ("Root", j->item().name()); |
956 | + EXPECT_EQ(Item::Root, j->item().type()); |
957 | + } |
958 | + |
959 | + // Get a file. |
960 | + { |
961 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
962 | + |
963 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
964 | + spy.wait(SIGNAL_WAIT_TIME); |
965 | + |
966 | + EXPECT_EQ("child_id", j->item().itemId()); |
967 | + EXPECT_EQ("Child", j->item().name()); |
968 | + EXPECT_EQ(Item::File, j->item().type()); |
969 | + } |
970 | + |
971 | + // Get a folder. |
972 | + { |
973 | + unique_ptr<ItemJob> j(acc_.get("child_folder_id")); |
974 | + |
975 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
976 | + spy.wait(SIGNAL_WAIT_TIME); |
977 | + |
978 | + EXPECT_EQ("child_folder_id", j->item().itemId()); |
979 | + EXPECT_EQ("Child_Folder", j->item().name()); |
980 | + EXPECT_EQ(Item::Folder, j->item().type()); |
981 | + } |
982 | +} |
983 | + |
984 | +TEST_F(GetTest, runtime_destroyed) |
985 | +{ |
986 | + EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime. |
987 | + |
988 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
989 | + EXPECT_FALSE(j->isValid()); |
990 | + EXPECT_EQ(ItemJob::Error, j->status()); |
991 | + EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type()); |
992 | + EXPECT_EQ("Account::get(): Runtime was destroyed previously", j->error().message()); |
993 | + |
994 | + // Signal must be received. |
995 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
996 | + spy.wait(SIGNAL_WAIT_TIME); |
997 | + auto arg = spy.takeFirst(); |
998 | + EXPECT_EQ(ItemJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0))); |
999 | + |
1000 | + EXPECT_EQ("Account::get(): Runtime was destroyed previously", j->error().message()); |
1001 | +} |
1002 | + |
1003 | +TEST_F(GetTest, runtime_destroyed_while_item_job_running) |
1004 | +{ |
1005 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("slow_metadata"))); |
1006 | + |
1007 | + unique_ptr<ItemJob> j(acc_.get("child_folder_id")); |
1008 | + EXPECT_TRUE(j->isValid()); |
1009 | + |
1010 | + EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping |
1011 | + |
1012 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1013 | + spy.wait(SIGNAL_WAIT_TIME); |
1014 | + auto arg = spy.takeFirst(); |
1015 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0))); |
1016 | + |
1017 | + EXPECT_EQ("Account::get(): Runtime was destroyed previously", j->error().message()); |
1018 | +} |
1019 | + |
1020 | +TEST_F(GetTest, empty_id_from_provider) |
1021 | +{ |
1022 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("empty_id"))); |
1023 | + |
1024 | + unique_ptr<ItemJob> j(acc_.get("child_folder_id")); |
1025 | + EXPECT_TRUE(j->isValid()); |
1026 | + |
1027 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1028 | + spy.wait(SIGNAL_WAIT_TIME); |
1029 | + auto arg = spy.takeFirst(); |
1030 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0))); |
1031 | + |
1032 | + EXPECT_EQ("Account::get(): received invalid metadata from provider: item_id cannot be empty", j->error().message()); |
1033 | +} |
1034 | + |
1035 | +TEST_F(GetTest, no_such_id) |
1036 | +{ |
1037 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider())); |
1038 | + |
1039 | + unique_ptr<ItemJob> j(acc_.get("no_such_id")); |
1040 | + EXPECT_TRUE(j->isValid()); |
1041 | + |
1042 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1043 | + spy.wait(SIGNAL_WAIT_TIME); |
1044 | + auto arg = spy.takeFirst(); |
1045 | + EXPECT_EQ(ItemListJob::Error, qvariant_cast<ItemJob::Status>(arg.at(0))); |
1046 | + |
1047 | + EXPECT_EQ("metadata(): no such item: no_such_id", j->error().message()) << j->error().message().toStdString(); |
1048 | + EXPECT_EQ("no_such_id", j->error().itemId()); |
1049 | +} |
1050 | + |
1051 | +TEST_F(DeleteTest, basic) |
1052 | +{ |
1053 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider)); |
1054 | + |
1055 | + Item item; |
1056 | + { |
1057 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1058 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1059 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1060 | + item = j->item(); |
1061 | + } |
1062 | + |
1063 | + unique_ptr<VoidJob> j(item.deleteItem()); |
1064 | + EXPECT_TRUE(j->isValid()); |
1065 | + EXPECT_EQ(VoidJob::Loading, j->status()); |
1066 | + EXPECT_EQ(StorageError::NoError, j->error().type()); |
1067 | + |
1068 | + EXPECT_EQ("child_id", item.itemId()); |
1069 | + |
1070 | + QSignalSpy spy(j.get(), &VoidJob::statusChanged); |
1071 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1072 | + |
1073 | + EXPECT_EQ(VoidJob::Finished, j->status()); |
1074 | + EXPECT_TRUE(j->isValid()); |
1075 | + EXPECT_EQ(StorageError::NoError, j->error().type()); |
1076 | + EXPECT_EQ(VoidJob::Finished, j->status()); |
1077 | +} |
1078 | + |
1079 | +TEST_F(DeleteTest, no_such_item) |
1080 | +{ |
1081 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("delete_no_such_item"))); |
1082 | + |
1083 | + Item item; |
1084 | + { |
1085 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1086 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1087 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1088 | + item = j->item(); |
1089 | + } |
1090 | + |
1091 | + unique_ptr<VoidJob> j(item.deleteItem()); |
1092 | + EXPECT_TRUE(j->isValid()); |
1093 | + EXPECT_EQ(VoidJob::Loading, j->status()); |
1094 | + EXPECT_EQ(StorageError::NoError, j->error().type()); |
1095 | + |
1096 | + EXPECT_EQ("child_id", item.itemId()); |
1097 | + |
1098 | + QSignalSpy spy(j.get(), &VoidJob::statusChanged); |
1099 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1100 | + |
1101 | + EXPECT_EQ(VoidJob::Error, j->status()); |
1102 | + EXPECT_FALSE(j->isValid()); |
1103 | + EXPECT_EQ(StorageError::NotExists, j->error().type()); |
1104 | + EXPECT_EQ("delete_item(): no such item: child_id", j->error().message()); |
1105 | +} |
1106 | + |
1107 | +TEST_F(DeleteTest, delete_root) |
1108 | +{ |
1109 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider)); |
1110 | + |
1111 | + Item item; |
1112 | + { |
1113 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
1114 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1115 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1116 | + item = j->item(); |
1117 | + } |
1118 | + |
1119 | + unique_ptr<VoidJob> j(item.deleteItem()); |
1120 | + EXPECT_FALSE(j->isValid()); |
1121 | + EXPECT_EQ(VoidJob::Error, j->status()); |
1122 | + EXPECT_EQ(StorageError::LogicError, j->error().type()); |
1123 | + |
1124 | + // Signal must be received. |
1125 | + QSignalSpy spy(j.get(), &VoidJob::statusChanged); |
1126 | + spy.wait(SIGNAL_WAIT_TIME); |
1127 | + auto arg = spy.takeFirst(); |
1128 | + EXPECT_EQ(ItemJob::Error, qvariant_cast<VoidJob::Status>(arg.at(0))); |
1129 | + |
1130 | + EXPECT_EQ("Item::deleteItem(): cannot delete root", j->error().message()); |
1131 | +} |
1132 | + |
1133 | +TEST_F(DeleteTest, runtime_destroyed) |
1134 | +{ |
1135 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider)); |
1136 | + |
1137 | + Item item; |
1138 | + { |
1139 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1140 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1141 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1142 | + item = j->item(); |
1143 | + } |
1144 | + |
1145 | + EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime. |
1146 | + |
1147 | + unique_ptr<VoidJob> j(item.deleteItem()); |
1148 | + EXPECT_FALSE(j->isValid()); |
1149 | + EXPECT_EQ(ItemJob::Error, j->status()); |
1150 | + EXPECT_EQ(StorageError::RuntimeDestroyed, j->error().type()); |
1151 | + EXPECT_EQ("Item::deleteItem(): Runtime was destroyed previously", j->error().message()); |
1152 | + |
1153 | + // Signal must be received. |
1154 | + QSignalSpy spy(j.get(), &VoidJob::statusChanged); |
1155 | + spy.wait(SIGNAL_WAIT_TIME); |
1156 | + auto arg = spy.takeFirst(); |
1157 | + EXPECT_EQ(ItemJob::Error, qvariant_cast<VoidJob::Status>(arg.at(0))); |
1158 | + |
1159 | + EXPECT_EQ("Item::deleteItem(): Runtime was destroyed previously", j->error().message()); |
1160 | +} |
1161 | + |
1162 | +TEST_F(DeleteTest, runtime_destroyed_while_void_job_running) |
1163 | +{ |
1164 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("slow_delete"))); |
1165 | + |
1166 | + Item item; |
1167 | + { |
1168 | + unique_ptr<ItemJob> j(acc_.get("child_id")); |
1169 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1170 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1171 | + item = j->item(); |
1172 | + } |
1173 | + |
1174 | + unique_ptr<VoidJob> j(item.deleteItem()); |
1175 | + EXPECT_TRUE(j->isValid()); |
1176 | + EXPECT_EQ(VoidJob::Loading, j->status()); |
1177 | + EXPECT_EQ(StorageError::NoError, j->error().type()); |
1178 | + |
1179 | + EXPECT_EQ(StorageError::NoError, runtime_->shutdown().type()); // Destroy runtime. |
1180 | + |
1181 | + // Signal must be received. |
1182 | + QSignalSpy spy(j.get(), &VoidJob::statusChanged); |
1183 | + spy.wait(SIGNAL_WAIT_TIME); |
1184 | + auto arg = spy.takeFirst(); |
1185 | + EXPECT_EQ(VoidJob::Error, qvariant_cast<VoidJob::Status>(arg.at(0))); |
1186 | + |
1187 | + EXPECT_EQ("Item::deleteItem(): Runtime was destroyed previously", j->error().message()) << j->error().message().toStdString(); |
1188 | +} |
1189 | + |
1190 | +#if 0 |
1191 | +// TODO: need to make internal symbols available for testing. |
1192 | +TEST_F(ValidateTest, basic) |
1193 | +{ |
1194 | + using namespace unity::storage::qt::internal; |
1195 | + |
1196 | + unity::storage::internal::ItemMetadata md; |
1197 | + |
1198 | + validate("foo", md); |
1199 | +} |
1200 | +#endif |
1201 | + |
1202 | + |
1203 | +TEST_F(ItemTest, comparison_and_hash) |
1204 | { |
1205 | set_provider(unique_ptr<provider::ProviderBase>(new MockProvider)); |
1206 | |
1207 | { |
1208 | // Both items invalid. |
1209 | Item i1; |
1210 | - Item a2; |
1211 | - EXPECT_TRUE(i1 == a2); |
1212 | - EXPECT_FALSE(i1 != a2); |
1213 | - EXPECT_FALSE(i1 < a2); |
1214 | - EXPECT_TRUE(i1 <= a2); |
1215 | - EXPECT_FALSE(i1 > a2); |
1216 | - EXPECT_TRUE(i1 >= a2); |
1217 | + Item i2; |
1218 | + EXPECT_TRUE(i1 == i2); |
1219 | + EXPECT_FALSE(i1 != i2); |
1220 | + EXPECT_FALSE(i1 < i2); |
1221 | + EXPECT_TRUE(i1 <= i2); |
1222 | + EXPECT_FALSE(i1 > i2); |
1223 | + EXPECT_TRUE(i1 >= i2); |
1224 | + |
1225 | + unordered_set<Item>(); // Just to show that this works. |
1226 | + |
1227 | + EXPECT_EQ(0, hash<Item>()(i1)); |
1228 | + EXPECT_EQ(0, i1.hash()); |
1229 | + EXPECT_EQ(0, qHash(i1)); |
1230 | } |
1231 | |
1232 | -#if 0 |
1233 | { |
1234 | // i1 valid, i2 invalid |
1235 | - auto i1 = runtime_->make_test_account(service_connection_->baseService(), bus_path()); |
1236 | - Account i2; |
1237 | + unique_ptr<ItemListJob> j(acc_.roots()); |
1238 | + |
1239 | + QSignalSpy ready_spy(j.get(), &ItemListJob::itemsReady); |
1240 | + ASSERT_TRUE(ready_spy.wait(SIGNAL_WAIT_TIME)); |
1241 | + |
1242 | + ASSERT_EQ(1, ready_spy.count()); |
1243 | + auto arg = ready_spy.takeFirst(); |
1244 | + auto items = qvariant_cast<QList<Item>>(arg.at(0)); |
1245 | + ASSERT_EQ(1, items.size()); |
1246 | + |
1247 | + auto i1 = items[0]; |
1248 | + Item i2; |
1249 | EXPECT_FALSE(i1 == i2); |
1250 | EXPECT_TRUE(i1 != i2); |
1251 | EXPECT_FALSE(i1 < i2); |
1252 | @@ -449,75 +767,69 @@ |
1253 | EXPECT_TRUE(i2 <= i1); |
1254 | EXPECT_FALSE(i2 > i1); |
1255 | EXPECT_FALSE(i2 >= i1); |
1256 | - } |
1257 | - |
1258 | - { |
1259 | - // i1 < i2 for owner ID |
1260 | - auto i1 = runtime_->make_test_account(service_connection_->baseService(), bus_path(), "a", "x", "x"); |
1261 | - auto i2 = runtime_->make_test_account(service_connection_->baseService(), bus_path(), "b", "x", "x"); |
1262 | - |
1263 | - EXPECT_FALSE(i1 == i2); |
1264 | - EXPECT_TRUE(i1 != i2); |
1265 | - EXPECT_TRUE(i1 < i2); |
1266 | - EXPECT_TRUE(i1 <= i2); |
1267 | - EXPECT_FALSE(i1 > i2); |
1268 | - EXPECT_FALSE(i1 >= i2); |
1269 | - |
1270 | - // And with swapped operands: |
1271 | - EXPECT_FALSE(i2 == i1); |
1272 | - EXPECT_TRUE(i2 != i1); |
1273 | - EXPECT_FALSE(i2 < i1); |
1274 | - EXPECT_FALSE(i2 <= i1); |
1275 | - EXPECT_TRUE(i2 > i1); |
1276 | - EXPECT_TRUE(i2 >= i1); |
1277 | - } |
1278 | - |
1279 | - { |
1280 | - // i1 < i2 for owner |
1281 | - auto i1 = runtime_->make_test_account(service_connection_->baseService(), bus_path(), "a", "a", "x"); |
1282 | - auto i2 = runtime_->make_test_account(service_connection_->baseService(), bus_path(), "a", "b", "x"); |
1283 | - |
1284 | - EXPECT_FALSE(i1 == i2); |
1285 | - EXPECT_TRUE(i1 != i2); |
1286 | - EXPECT_TRUE(i1 < i2); |
1287 | - EXPECT_TRUE(i1 <= i2); |
1288 | - EXPECT_FALSE(i1 > i2); |
1289 | - EXPECT_FALSE(i1 >= i2); |
1290 | - |
1291 | - // And with swapped operands: |
1292 | - EXPECT_FALSE(i2 == i1); |
1293 | - EXPECT_TRUE(i2 != i1); |
1294 | - EXPECT_FALSE(i2 < i1); |
1295 | - EXPECT_FALSE(i2 <= i1); |
1296 | - EXPECT_TRUE(i2 > i1); |
1297 | - EXPECT_TRUE(i2 >= i1); |
1298 | - } |
1299 | - |
1300 | - { |
1301 | - // i1 < i2 for description |
1302 | - auto i1 = runtime_->make_test_account(service_connection_->baseService(), bus_path(), "a", "a", "a"); |
1303 | - auto i2 = runtime_->make_test_account(service_connection_->baseService(), bus_path(), "a", "a", "b"); |
1304 | - |
1305 | - EXPECT_FALSE(i1 == i2); |
1306 | - EXPECT_TRUE(i1 != i2); |
1307 | - EXPECT_TRUE(i1 < i2); |
1308 | - EXPECT_TRUE(i1 <= i2); |
1309 | - EXPECT_FALSE(i1 > i2); |
1310 | - EXPECT_FALSE(i1 >= i2); |
1311 | - |
1312 | - // And with swapped operands: |
1313 | - EXPECT_FALSE(i2 == i1); |
1314 | - EXPECT_TRUE(i2 != i1); |
1315 | - EXPECT_FALSE(i2 < i1); |
1316 | - EXPECT_FALSE(i2 <= i1); |
1317 | - EXPECT_TRUE(i2 > i1); |
1318 | - EXPECT_TRUE(i2 >= i1); |
1319 | - } |
1320 | - |
1321 | - { |
1322 | - // i1 == i2 |
1323 | - auto i1 = runtime_->make_test_account(service_connection_->baseService(), bus_path(), "a", "a", "a"); |
1324 | - auto i2 = runtime_->make_test_account(service_connection_->baseService(), bus_path(), "a", "a", "a"); |
1325 | + |
1326 | + EXPECT_NE(0, i1.hash()); |
1327 | + EXPECT_NE(0, qHash(i1)); |
1328 | + } |
1329 | + |
1330 | + { |
1331 | + // Both items valid with identical metadata, but different accounts (a1 < a2). |
1332 | + |
1333 | + auto a1 = runtime_->make_test_account(service_connection_->baseService(), object_path(), "a", "x", "x"); |
1334 | + auto a2 = runtime_->make_test_account(service_connection_->baseService(), object_path(), "b", "x", "x"); |
1335 | + |
1336 | + Item i1; |
1337 | + Item i2; |
1338 | + |
1339 | + { |
1340 | + unique_ptr<ItemJob> j(a1.get("root_id")); |
1341 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1342 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1343 | + i1 = j->item(); |
1344 | + } |
1345 | + { |
1346 | + unique_ptr<ItemJob> j(a2.get("root_id")); |
1347 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1348 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1349 | + i2 = j->item(); |
1350 | + } |
1351 | + |
1352 | + ASSERT_EQ(i1.itemId(), i2.itemId()); |
1353 | + |
1354 | + EXPECT_FALSE(i1 == i2); |
1355 | + EXPECT_TRUE(i1 != i2); |
1356 | + EXPECT_TRUE(i1 < i2); |
1357 | + EXPECT_TRUE(i1 <= i2); |
1358 | + EXPECT_FALSE(i1 > i2); |
1359 | + EXPECT_FALSE(i1 >= i2); |
1360 | + |
1361 | + // And with swapped operands: |
1362 | + EXPECT_FALSE(i2 == i1); |
1363 | + EXPECT_TRUE(i2 != i1); |
1364 | + EXPECT_FALSE(i2 < i1); |
1365 | + EXPECT_FALSE(i2 <= i1); |
1366 | + EXPECT_TRUE(i2 > i1); |
1367 | + EXPECT_TRUE(i2 >= i1); |
1368 | + } |
1369 | + |
1370 | + { |
1371 | + // Both items valid with identical metadata, but different instances, so we do deep comparison. |
1372 | + |
1373 | + Item i1; |
1374 | + Item i2; |
1375 | + |
1376 | + { |
1377 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
1378 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1379 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1380 | + i1 = j->item(); |
1381 | + } |
1382 | + { |
1383 | + unique_ptr<ItemJob> j(acc_.get("root_id")); |
1384 | + QSignalSpy spy(j.get(), &ItemJob::statusChanged); |
1385 | + ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME)); |
1386 | + i2 = j->item(); |
1387 | + } |
1388 | |
1389 | EXPECT_TRUE(i1 == i2); |
1390 | EXPECT_FALSE(i1 != i2); |
1391 | @@ -533,8 +845,10 @@ |
1392 | EXPECT_TRUE(i2 <= i1); |
1393 | EXPECT_FALSE(i2 > i1); |
1394 | EXPECT_TRUE(i2 >= i1); |
1395 | + |
1396 | + EXPECT_EQ(i1.hash(), i2.hash()); |
1397 | + EXPECT_EQ(qHash(i1), qHash(i2)); |
1398 | } |
1399 | -#endif |
1400 | } |
1401 | |
1402 | #if 0 |
1403 | @@ -1290,7 +1604,7 @@ |
1404 | |
1405 | TEST_F(DestroyedTest, get_destroyed_while_reply_outstanding) |
1406 | { |
1407 | - set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("metadata slow"))); |
1408 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("slow_metadata"))); |
1409 | |
1410 | auto root = call(acc_->roots())[0]; |
1411 | auto fut = root->get("root_id"); |
1412 | @@ -1328,7 +1642,7 @@ |
1413 | |
1414 | TEST_F(DestroyedTest, move_destroyed_while_reply_outstanding) |
1415 | { |
1416 | - set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("move slow"))); |
1417 | + set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("slow_move"))); |
1418 | |
1419 | auto root = call(acc_->roots())[0]; |
1420 | auto file = dynamic_pointer_cast<File>(call(root->get("child_id"))); |
FAILED: Continuous integration, rev:87 /jenkins. canonical. com/unity- api-1/job/ lp-storage- framework- ci/128/ /jenkins. canonical. com/unity- api-1/job/ build/768/ console /jenkins. canonical. com/unity- api-1/job/ build-0- fetch/774 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 582/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 582/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 582/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 582/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 582/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 582/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 582/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 582/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= yakkety/ 582/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/unity- api-1/job/ lp-storage- framework- ci/128/ rebuild
https:/