Merge lp:~michihenning/storage-framework/more-tests into lp:storage-framework/devel

Proposed by Michi Henning
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
Reviewer Review Type Date Requested Status
James Henstridge Approve
unity-api-1-bot continuous-integration Approve
Review via email: mp+306744@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
88. By Michi Henning

Fixed whitespace.

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

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

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

review: Approve (continuous-integration)
Revision history for this message
James Henstridge (jamesh) wrote :

Just a few minor issues that I've included as inline comments.

review: Needs Fixing
89. By Michi Henning

Review comments from James.

Revision history for this message
Michi Henning (michihenning) wrote :

Thanks for the review!

I'll go and make the corresponding changes in the follow-up branches.

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

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

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

review: Approve (continuous-integration)
Revision history for this message
James Henstridge (jamesh) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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")));

Subscribers

People subscribed via source and target branches

to all changes: