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

Proposed by Michi Henning
Status: Merged
Approved by: Michi Henning
Approved revision: 108
Merged at revision: 80
Proposed branch: lp:~michihenning/storage-framework/upload-download
Merge into: lp:storage-framework/devel
Diff against target: 957 lines (+730/-77)
7 files modified
include/unity/storage/qt/internal/StorageErrorImpl.h (+2/-3)
src/qt/internal/DownloaderImpl.cpp (+1/-1)
src/qt/internal/ItemImpl.cpp (+4/-2)
src/qt/internal/StorageErrorImpl.cpp (+0/-18)
src/qt/internal/UploaderImpl.cpp (+1/-1)
tests/remote-client/MockProvider.cpp (+25/-1)
tests/remote-client/remote-client_test.cpp (+697/-51)
To merge this branch: bzr merge lp:~michihenning/storage-framework/upload-download
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Approve
Unity API Team Pending
Review via email: mp+308336@code.launchpad.net

Commit message

Lots of upload tests.

Description of the change

Lots of upload tests.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

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

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

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/unity/storage/qt/internal/StorageErrorImpl.h'
2--- include/unity/storage/qt/internal/StorageErrorImpl.h 2016-10-12 06:05:29 +0000
3+++ include/unity/storage/qt/internal/StorageErrorImpl.h 2016-10-13 06:49:18 +0000
4@@ -56,13 +56,12 @@
5 static StorageError make_error(StorageError::Type, QString const& msg);
6
7 // Factories to make things more convenient and ensure consistency.
8+ // Note that we deliberately have no factories for errors that are
9+ // never created locally and can only come from the server.
10 static StorageError local_comms_error(QString const& msg);
11- static StorageError remote_comms_error(QString const& msg);
12 static StorageError runtime_destroyed_error(QString const& msg);
13 static StorageError not_exists_error(QString const& msg, QString const& key);
14 static StorageError exists_error(QString const& msg, QString const& item_id, QString const& item_name);
15- static StorageError conflict_error(QString const& msg);
16- static StorageError permission_error(QString const& msg);
17 static StorageError cancelled_error(QString const& msg);
18 static StorageError logic_error(QString const& msg);
19 static StorageError invalid_argument_error(QString const& msg);
20
21=== modified file 'src/qt/internal/DownloaderImpl.cpp'
22--- src/qt/internal/DownloaderImpl.cpp 2016-10-12 07:23:15 +0000
23+++ src/qt/internal/DownloaderImpl.cpp 2016-10-13 06:49:18 +0000
24@@ -115,7 +115,7 @@
25 case Downloader::Status::Error:
26 break;
27 case Downloader::Status::Ready:
28- public_instance_->abort();
29+ cancel();
30 break;
31 default:
32 abort(); // Impossible. // LCOV_EXCL_LINE
33
34=== modified file 'src/qt/internal/ItemImpl.cpp'
35--- src/qt/internal/ItemImpl.cpp 2016-10-12 14:06:48 +0000
36+++ src/qt/internal/ItemImpl.cpp 2016-10-13 06:49:18 +0000
37@@ -248,7 +248,7 @@
38 }
39 if (sizeInBytes < 0)
40 {
41- auto e = StorageErrorImpl::logic_error(method + ": size must be >= 0");
42+ auto e = StorageErrorImpl::invalid_argument_error(method + ": size must be >= 0");
43 return UploaderImpl::make_job(e);
44 }
45
46@@ -256,7 +256,9 @@
47 {
48 if (md.type != storage::ItemType::file)
49 {
50- throw StorageErrorImpl::local_comms_error(method + ": impossible directory item returned by provider");
51+ QString msg = method + ": impossible directory item returned by provider";
52+ qCritical().noquote() << msg;
53+ throw StorageErrorImpl::local_comms_error(msg);
54 }
55 };
56
57
58=== modified file 'src/qt/internal/StorageErrorImpl.cpp'
59--- src/qt/internal/StorageErrorImpl.cpp 2016-10-12 06:05:29 +0000
60+++ src/qt/internal/StorageErrorImpl.cpp 2016-10-13 06:49:18 +0000
61@@ -169,12 +169,6 @@
62 return StorageError(move(p));
63 }
64
65-StorageError StorageErrorImpl::remote_comms_error(QString const& msg)
66-{
67- unique_ptr<StorageErrorImpl> p(new StorageErrorImpl(StorageError::Type::RemoteCommsError, msg));
68- return StorageError(move(p));
69-}
70-
71 StorageError StorageErrorImpl::runtime_destroyed_error(QString const& msg)
72 {
73 unique_ptr<StorageErrorImpl> p(new StorageErrorImpl(StorageError::Type::RuntimeDestroyed, msg));
74@@ -193,18 +187,6 @@
75 return StorageError(move(p));
76 }
77
78-StorageError StorageErrorImpl::conflict_error(QString const& msg)
79-{
80- unique_ptr<StorageErrorImpl> p(new StorageErrorImpl(StorageError::Type::Conflict, msg));
81- return StorageError(move(p));
82-}
83-
84-StorageError StorageErrorImpl::permission_error(QString const& msg)
85-{
86- unique_ptr<StorageErrorImpl> p(new StorageErrorImpl(StorageError::Type::PermissionDenied, msg));
87- return StorageError(move(p));
88-}
89-
90 StorageError StorageErrorImpl::cancelled_error(QString const& msg)
91 {
92 unique_ptr<StorageErrorImpl> p(new StorageErrorImpl(StorageError::Type::Cancelled, msg));
93
94=== modified file 'src/qt/internal/UploaderImpl.cpp'
95--- src/qt/internal/UploaderImpl.cpp 2016-10-12 07:50:18 +0000
96+++ src/qt/internal/UploaderImpl.cpp 2016-10-13 06:49:18 +0000
97@@ -124,7 +124,7 @@
98 case Uploader::Status::Error:
99 break;
100 case Uploader::Status::Ready:
101- public_instance_->abort();
102+ cancel();
103 break;
104 default:
105 abort(); // Impossible. // LCOV_EXCL_LINE
106
107=== modified file 'tests/remote-client/MockProvider.cpp'
108--- tests/remote-client/MockProvider.cpp 2016-10-12 05:25:20 +0000
109+++ tests/remote-client/MockProvider.cpp 2016-10-13 06:49:18 +0000
110@@ -268,7 +268,18 @@
111 boost::future<unique_ptr<UploadJob>> MockProvider::update(
112 string const&, int64_t, string const&, Context const&)
113 {
114- return make_ready_future<unique_ptr<UploadJob>>(new MockUploadJob());
115+ if (cmd_ == "upload_slow")
116+ {
117+ this_thread::sleep_for(chrono::seconds(1));
118+ }
119+ if (cmd_ == "upload_error")
120+ {
121+ unique_ptr<UploadJob> job(new MockUploadJob());
122+ ConflictException e("version mismatch");
123+ job->report_error(make_exception_ptr(e));
124+ return make_exceptional_future<unique_ptr<UploadJob>>(e);
125+ }
126+ return make_ready_future<unique_ptr<UploadJob>>(new MockUploadJob(cmd_));
127 }
128
129 boost::future<unique_ptr<DownloadJob>> MockProvider::download(
130@@ -384,6 +395,19 @@
131
132 boost::future<Item> MockUploadJob::finish()
133 {
134+ if (cmd_ == "finish_upload_slow" || cmd_ == "finish_upload_slow_error")
135+ {
136+ this_thread::sleep_for(chrono::seconds(1));
137+ }
138+ if (cmd_ == "finish_upload_error" || cmd_ == "finish_upload_slow_error")
139+ {
140+ return make_exceptional_future<Item>(ResourceException("out of memory", 99));
141+ }
142+ if (cmd_ == "upload_returns_dir")
143+ {
144+ Item metadata{"some_id", { "root_id" }, "some_upload", "etag", ItemType::folder, {}};
145+ return make_ready_future<Item>(metadata);
146+ }
147 Item metadata
148 {
149 "some_id", { "root_id" }, "some_upload", "etag", ItemType::file,
150
151=== modified file 'tests/remote-client/remote-client_test.cpp'
152--- tests/remote-client/remote-client_test.cpp 2016-10-12 14:06:48 +0000
153+++ tests/remote-client/remote-client_test.cpp 2016-10-13 06:49:18 +0000
154@@ -2237,6 +2237,53 @@
155 EXPECT_EQ(StorageError::Type::PermissionDenied, j->error().type());
156 }
157
158+TEST_F(DownloadTest, basic)
159+{
160+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
161+
162+ Item root;
163+ {
164+ unique_ptr<ItemJob> j(acc_.get("root_id"));
165+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
166+ spy.wait(SIGNAL_WAIT_TIME);
167+ root = j->item();
168+ }
169+
170+ Item child;
171+ {
172+ unique_ptr<ItemJob> j(acc_.get("child_id"));
173+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
174+ spy.wait(SIGNAL_WAIT_TIME);
175+ child = j->item();
176+ }
177+
178+ unique_ptr<Downloader> downloader(child.createDownloader());
179+ EXPECT_TRUE(downloader->isValid());
180+ EXPECT_EQ(Downloader::Status::Loading, downloader->status());
181+ EXPECT_EQ(StorageError::NoError, downloader->error().type());
182+ EXPECT_EQ(child, downloader->item());
183+
184+ QSignalSpy status_spy(downloader.get(), &Downloader::statusChanged);
185+ {
186+ QSignalSpy read_spy(downloader.get(), &Downloader::readyRead);
187+ ASSERT_TRUE(status_spy.wait(SIGNAL_WAIT_TIME));
188+ auto arg = status_spy.takeFirst();
189+ EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
190+
191+ if (read_spy.count() != 1)
192+ {
193+ read_spy.wait(SIGNAL_WAIT_TIME);
194+ }
195+ }
196+ auto data = downloader->readAll();
197+ EXPECT_EQ(QByteArray("Hello world", -1), data);
198+
199+ downloader->finishDownload();
200+ ASSERT_TRUE(status_spy.wait(SIGNAL_WAIT_TIME));
201+ auto arg = status_spy.takeFirst();
202+ EXPECT_EQ(Downloader::Status::Finished, qvariant_cast<Downloader::Status>(arg.at(0)));
203+}
204+
205 // TODO: This leaks:
206 // ==4645== 1,369 (272 direct, 1,097 indirect) bytes in 1 blocks are definitely lost in loss record 193 of 203
207 // ==4645== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
208@@ -2252,7 +2299,7 @@
209 // ==4645== by 0x504D9A6: void __gnu_cxx::new_allocator<unity::storage::provider::internal::AccountData>::destroy<unity::storage::provider::internal::AccountData>(unity::storage::provider::internal::AccountData*) (new_allocator.h:124)
210 // ==4645== by 0x504D8AA: void std::allocator_traits<std::allocator<unity::storage::provider::internal::AccountData> >::destroy<unity::storage::provider::internal::AccountData>(std::allocator<unity::storage::provider::internal::AccountData>&, unity::storage::provider::internal::AccountData*) (alloc_traits.h:542)
211
212-TEST_F(DownloadTest, memory_leak)
213+TEST_F(DownloadTest, abandoned)
214 {
215 set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
216
217@@ -2274,9 +2321,6 @@
218
219 unique_ptr<Downloader> downloader(child.createDownloader());
220 EXPECT_TRUE(downloader->isValid());
221- EXPECT_EQ(Downloader::Status::Loading, downloader->status());
222- EXPECT_EQ(StorageError::NoError, downloader->error().type());
223- EXPECT_EQ(child, downloader->item());
224
225 {
226 QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
227@@ -2286,53 +2330,6 @@
228 }
229 }
230
231-TEST_F(DownloadTest, basic)
232-{
233- set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
234-
235- Item root;
236- {
237- unique_ptr<ItemJob> j(acc_.get("root_id"));
238- QSignalSpy spy(j.get(), &ItemJob::statusChanged);
239- spy.wait(SIGNAL_WAIT_TIME);
240- root = j->item();
241- }
242-
243- Item child;
244- {
245- unique_ptr<ItemJob> j(acc_.get("child_id"));
246- QSignalSpy spy(j.get(), &ItemJob::statusChanged);
247- spy.wait(SIGNAL_WAIT_TIME);
248- child = j->item();
249- }
250-
251- unique_ptr<Downloader> downloader(child.createDownloader());
252- EXPECT_TRUE(downloader->isValid());
253- EXPECT_EQ(Downloader::Status::Loading, downloader->status());
254- EXPECT_EQ(StorageError::NoError, downloader->error().type());
255- EXPECT_EQ(child, downloader->item());
256-
257- QSignalSpy status_spy(downloader.get(), &Downloader::statusChanged);
258- {
259- QSignalSpy read_spy(downloader.get(), &Downloader::readyRead);
260- ASSERT_TRUE(status_spy.wait(SIGNAL_WAIT_TIME));
261- auto arg = status_spy.takeFirst();
262- EXPECT_EQ(Downloader::Status::Ready, qvariant_cast<Downloader::Status>(arg.at(0)));
263-
264- if (read_spy.count() != 1)
265- {
266- read_spy.wait(SIGNAL_WAIT_TIME);
267- }
268- }
269- auto data = downloader->readAll();
270- EXPECT_EQ(QByteArray("Hello world", -1), data);
271-
272- downloader->finishDownload();
273- ASSERT_TRUE(status_spy.wait(SIGNAL_WAIT_TIME));
274- auto arg = status_spy.takeFirst();
275- EXPECT_EQ(Downloader::Status::Finished, qvariant_cast<Downloader::Status>(arg.at(0)));
276-}
277-
278 TEST_F(DownloadTest, runtime_destroyed)
279 {
280 set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
281@@ -2627,6 +2624,8 @@
282 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
283 auto arg = spy.takeFirst();
284 EXPECT_EQ(Downloader::Status::Finished, qvariant_cast<Downloader::Status>(arg.at(0)));
285+
286+ EXPECT_EQ(Downloader::Status::Finished, downloader->status());
287 }
288
289 TEST_F(DownloadTest, finish_error)
290@@ -2676,6 +2675,32 @@
291 EXPECT_EQ("NotExists", downloader->error().name());
292 }
293
294+TEST_F(DownloadTest, wrong_type)
295+{
296+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
297+
298+ Item root;
299+ {
300+ unique_ptr<ItemJob> j(acc_.get("root_id"));
301+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
302+ spy.wait(SIGNAL_WAIT_TIME);
303+ root = j->item();
304+ }
305+
306+ unique_ptr<Downloader> downloader(root.createDownloader());
307+ EXPECT_FALSE(downloader->isValid());
308+ EXPECT_EQ(Downloader::Status::Error, downloader->status());
309+ EXPECT_EQ(StorageError::Type::LogicError, downloader->error().type());
310+ EXPECT_EQ("Item::createDownloader(): cannot download a directory", downloader->error().message());
311+
312+ {
313+ QSignalSpy spy(downloader.get(), &Downloader::statusChanged);
314+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
315+ auto arg = spy.takeFirst();
316+ EXPECT_EQ(Downloader::Status::Error, qvariant_cast<Downloader::Status>(arg.at(0)));
317+ }
318+}
319+
320 TEST_F(DownloadTest, cancel)
321 {
322 set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("finish_download_slow_error")));
323@@ -2802,6 +2827,8 @@
324 EXPECT_EQ(Uploader::Status::Loading, uploader->status());
325 EXPECT_EQ(StorageError::NoError, uploader->error().type());
326 EXPECT_EQ(child, uploader->item());
327+ EXPECT_EQ(Item::ConflictPolicy::Overwrite, uploader->policy());
328+ EXPECT_EQ(contents.size(), uploader->sizeInBytes());
329
330 {
331 QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
332@@ -2821,6 +2848,625 @@
333 EXPECT_EQ(Uploader::Status::Finished, uploader->status());
334 }
335
336+TEST_F(UploadTest, abandoned)
337+{
338+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
339+
340+ Item root;
341+ {
342+ unique_ptr<ItemJob> j(acc_.get("root_id"));
343+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
344+ spy.wait(SIGNAL_WAIT_TIME);
345+ root = j->item();
346+ }
347+
348+ Item child;
349+ {
350+ unique_ptr<ItemJob> j(acc_.get("child_id"));
351+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
352+ spy.wait(SIGNAL_WAIT_TIME);
353+ child = j->item();
354+ }
355+
356+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 5));
357+ EXPECT_TRUE(uploader->isValid());
358+
359+ {
360+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
361+ spy.wait(SIGNAL_WAIT_TIME);
362+ auto arg = spy.takeFirst();
363+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
364+ }
365+}
366+
367+TEST_F(UploadTest, runtime_destroyed)
368+{
369+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
370+
371+ Item root;
372+ {
373+ unique_ptr<ItemJob> j(acc_.get("root_id"));
374+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
375+ spy.wait(SIGNAL_WAIT_TIME);
376+ root = j->item();
377+ }
378+
379+ Item child;
380+ {
381+ unique_ptr<ItemJob> j(acc_.get("child_id"));
382+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
383+ spy.wait(SIGNAL_WAIT_TIME);
384+ child = j->item();
385+ }
386+
387+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type());
388+
389+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 20));
390+ EXPECT_FALSE(uploader->isValid());
391+ EXPECT_EQ(Downloader::Status::Error, uploader->status());
392+ EXPECT_EQ(StorageError::RuntimeDestroyed, uploader->error().type());
393+ EXPECT_EQ("RuntimeDestroyed: Item::createUploader(): Runtime was destroyed previously",
394+ uploader->error().errorString());
395+ EXPECT_EQ(Item(), uploader->item());
396+
397+ // Signal must arrive.
398+ {
399+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
400+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
401+ auto arg = spy.takeFirst();
402+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
403+ }
404+}
405+
406+TEST_F(UploadTest, runtime_destroyed_while_upload_running)
407+{
408+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("upload_slow")));
409+
410+ Item root;
411+ {
412+ unique_ptr<ItemJob> j(acc_.get("root_id"));
413+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
414+ spy.wait(SIGNAL_WAIT_TIME);
415+ root = j->item();
416+ }
417+
418+ Item child;
419+ {
420+ unique_ptr<ItemJob> j(acc_.get("child_id"));
421+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
422+ spy.wait(SIGNAL_WAIT_TIME);
423+ child = j->item();
424+ }
425+
426+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::ErrorIfConflict, 20));
427+ EXPECT_TRUE(uploader->isValid());
428+
429+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
430+
431+ // Signal must arrive.
432+ {
433+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
434+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
435+ auto arg = spy.takeFirst();
436+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
437+ }
438+
439+ EXPECT_FALSE(uploader->isValid());
440+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
441+ EXPECT_EQ(StorageError::RuntimeDestroyed, uploader->error().type());
442+ EXPECT_EQ("RuntimeDestroyed: Item::createUploader(): Runtime was destroyed previously",
443+ uploader->error().errorString());
444+ EXPECT_EQ(Item(), uploader->item());
445+}
446+
447+TEST_F(UploadTest, upload_error)
448+{
449+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("upload_error")));
450+
451+ Item root;
452+ {
453+ unique_ptr<ItemJob> j(acc_.get("root_id"));
454+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
455+ spy.wait(SIGNAL_WAIT_TIME);
456+ root = j->item();
457+ }
458+
459+ Item child;
460+ {
461+ unique_ptr<ItemJob> j(acc_.get("child_id"));
462+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
463+ spy.wait(SIGNAL_WAIT_TIME);
464+ child = j->item();
465+ }
466+
467+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::ErrorIfConflict, 100));
468+ EXPECT_TRUE(uploader->isValid());
469+
470+ // Signal must arrive.
471+ {
472+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
473+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
474+ auto arg = spy.takeFirst();
475+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
476+ }
477+
478+ EXPECT_FALSE(uploader->isValid());
479+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
480+ EXPECT_EQ(StorageError::Conflict, uploader->error().type());
481+ EXPECT_EQ("Conflict: version mismatch", uploader->error().errorString());
482+ EXPECT_EQ(Item(), uploader->item());
483+
484+ // For coverage: call finishUpload() while in the Error state.
485+ {
486+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
487+ uploader->finishUpload();
488+ EXPECT_FALSE(spy.wait(1000));
489+ }
490+}
491+
492+TEST_F(UploadTest, finish_too_soon)
493+{
494+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
495+
496+ Item root;
497+ {
498+ unique_ptr<ItemJob> j(acc_.get("root_id"));
499+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
500+ spy.wait(SIGNAL_WAIT_TIME);
501+ root = j->item();
502+ }
503+
504+ Item child;
505+ {
506+ unique_ptr<ItemJob> j(acc_.get("child_id"));
507+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
508+ spy.wait(SIGNAL_WAIT_TIME);
509+ child = j->item();
510+ }
511+
512+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 0));
513+ EXPECT_TRUE(uploader->isValid());
514+
515+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
516+
517+ uploader->finishUpload();
518+
519+ ASSERT_EQ(1, spy.count());
520+ auto arg = spy.takeFirst();
521+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
522+
523+ EXPECT_FALSE(uploader->isValid());
524+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
525+ EXPECT_EQ(StorageError::LogicError, uploader->error().type());
526+ EXPECT_EQ("LogicError: Uploader::finishUpload(): cannot finalize while Uploader is not in the Ready state",
527+ uploader->error().errorString());
528+}
529+
530+TEST_F(UploadTest, finish_runtime_destroyed)
531+{
532+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
533+
534+ Item root;
535+ {
536+ unique_ptr<ItemJob> j(acc_.get("root_id"));
537+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
538+ spy.wait(SIGNAL_WAIT_TIME);
539+ root = j->item();
540+ }
541+
542+ Item child;
543+ {
544+ unique_ptr<ItemJob> j(acc_.get("child_id"));
545+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
546+ spy.wait(SIGNAL_WAIT_TIME);
547+ child = j->item();
548+ }
549+
550+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 0));
551+ EXPECT_TRUE(uploader->isValid());
552+
553+ {
554+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
555+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
556+ auto arg = spy.takeFirst();
557+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
558+ }
559+
560+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
561+
562+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime
563+
564+ uploader->finishUpload();
565+
566+ ASSERT_EQ(1, spy.count());
567+ auto arg = spy.takeFirst();
568+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
569+
570+ EXPECT_FALSE(uploader->isValid());
571+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
572+ EXPECT_EQ(StorageError::RuntimeDestroyed, uploader->error().type());
573+ EXPECT_EQ("Uploader::finishUpload(): Runtime was destroyed previously", uploader->error().message());
574+}
575+
576+TEST_F(UploadTest, finish_runtime_destroyed_while_reply_outstanding)
577+{
578+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("finish_upload_slow")));
579+
580+ Item root;
581+ {
582+ unique_ptr<ItemJob> j(acc_.get("root_id"));
583+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
584+ spy.wait(SIGNAL_WAIT_TIME);
585+ root = j->item();
586+ }
587+
588+ Item child;
589+ {
590+ unique_ptr<ItemJob> j(acc_.get("child_id"));
591+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
592+ spy.wait(SIGNAL_WAIT_TIME);
593+ child = j->item();
594+ }
595+
596+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 0));
597+ EXPECT_TRUE(uploader->isValid());
598+
599+ {
600+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
601+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
602+ auto arg = spy.takeFirst();
603+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
604+ }
605+
606+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
607+
608+ uploader->finishUpload();
609+
610+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime, provider still sleeping
611+
612+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
613+ auto arg = spy.takeFirst();
614+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
615+
616+ EXPECT_FALSE(uploader->isValid());
617+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
618+ EXPECT_EQ(StorageError::RuntimeDestroyed, uploader->error().type());
619+ EXPECT_EQ("Uploader::finishUpload(): Runtime was destroyed previously", uploader->error().message());
620+}
621+
622+TEST_F(UploadTest, finish_twice)
623+{
624+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
625+
626+ Item root;
627+ {
628+ unique_ptr<ItemJob> j(acc_.get("root_id"));
629+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
630+ spy.wait(SIGNAL_WAIT_TIME);
631+ root = j->item();
632+ }
633+
634+ Item child;
635+ {
636+ unique_ptr<ItemJob> j(acc_.get("child_id"));
637+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
638+ spy.wait(SIGNAL_WAIT_TIME);
639+ child = j->item();
640+ }
641+
642+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 0));
643+ EXPECT_TRUE(uploader->isValid());
644+
645+ {
646+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
647+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
648+ auto arg = spy.takeFirst();
649+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
650+ }
651+
652+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
653+
654+ uploader->finishUpload();
655+ uploader->finishUpload();
656+
657+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
658+ auto arg = spy.takeFirst();
659+ EXPECT_EQ(Uploader::Status::Finished, qvariant_cast<Uploader::Status>(arg.at(0)));
660+
661+ EXPECT_EQ(Uploader::Status::Finished, uploader->status());
662+}
663+
664+TEST_F(UploadTest, finish_error)
665+{
666+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("finish_upload_error")));
667+
668+ Item root;
669+ {
670+ unique_ptr<ItemJob> j(acc_.get("root_id"));
671+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
672+ spy.wait(SIGNAL_WAIT_TIME);
673+ root = j->item();
674+ }
675+
676+ Item child;
677+ {
678+ unique_ptr<ItemJob> j(acc_.get("child_id"));
679+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
680+ spy.wait(SIGNAL_WAIT_TIME);
681+ child = j->item();
682+ }
683+
684+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 0));
685+ EXPECT_TRUE(uploader->isValid());
686+
687+ {
688+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
689+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
690+ auto arg = spy.takeFirst();
691+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
692+ }
693+
694+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
695+
696+ uploader->finishUpload();
697+
698+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
699+ auto arg = spy.takeFirst();
700+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
701+
702+ EXPECT_FALSE(uploader->isValid());
703+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
704+ EXPECT_EQ(StorageError::ResourceError, uploader->error().type());
705+ EXPECT_EQ("out of memory", uploader->error().message());
706+ EXPECT_EQ(99, uploader->error().errorCode());
707+}
708+
709+TEST_F(UploadTest, wrong_type)
710+{
711+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
712+
713+ Item root;
714+ {
715+ unique_ptr<ItemJob> j(acc_.get("root_id"));
716+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
717+ spy.wait(SIGNAL_WAIT_TIME);
718+ root = j->item();
719+ }
720+
721+ unique_ptr<Uploader> uploader(root.createUploader(Item::ConflictPolicy::Overwrite, 0));
722+ EXPECT_FALSE(uploader->isValid());
723+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
724+ EXPECT_EQ(StorageError::Type::LogicError, uploader->error().type());
725+ EXPECT_EQ("Item::createUploader(): cannot upload to a directory", uploader->error().message());
726+
727+ {
728+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
729+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
730+ auto arg = spy.takeFirst();
731+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
732+ }
733+}
734+
735+TEST_F(UploadTest, wrong_size)
736+{
737+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
738+
739+ Item root;
740+ {
741+ unique_ptr<ItemJob> j(acc_.get("root_id"));
742+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
743+ spy.wait(SIGNAL_WAIT_TIME);
744+ root = j->item();
745+ }
746+
747+ Item child;
748+ {
749+ unique_ptr<ItemJob> j(acc_.get("child_id"));
750+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
751+ spy.wait(SIGNAL_WAIT_TIME);
752+ child = j->item();
753+ }
754+
755+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, -1));
756+ EXPECT_FALSE(uploader->isValid());
757+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
758+ EXPECT_EQ(StorageError::Type::InvalidArgument, uploader->error().type());
759+ EXPECT_EQ("Item::createUploader(): size must be >= 0", uploader->error().message());
760+
761+ {
762+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
763+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
764+ auto arg = spy.takeFirst();
765+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
766+ }
767+}
768+
769+TEST_F(UploadTest, wrong_return_type)
770+{
771+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("upload_returns_dir")));
772+
773+ Item root;
774+ {
775+ unique_ptr<ItemJob> j(acc_.get("root_id"));
776+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
777+ spy.wait(SIGNAL_WAIT_TIME);
778+ root = j->item();
779+ }
780+
781+ Item child;
782+ {
783+ unique_ptr<ItemJob> j(acc_.get("child_id"));
784+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
785+ spy.wait(SIGNAL_WAIT_TIME);
786+ child = j->item();
787+ }
788+
789+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 0));
790+ EXPECT_TRUE(uploader->isValid());
791+
792+ {
793+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
794+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
795+ auto arg = spy.takeFirst();
796+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
797+ }
798+
799+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
800+ uploader->finishUpload();
801+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
802+ auto arg = spy.takeFirst();
803+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
804+
805+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
806+ EXPECT_EQ(StorageError::Type::LocalCommsError, uploader->error().type());
807+ EXPECT_EQ("Item::createUploader(): impossible directory item returned by provider", uploader->error().message());
808+}
809+
810+TEST_F(UploadTest, cancel_success)
811+{
812+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider()));
813+
814+ Item root;
815+ {
816+ unique_ptr<ItemJob> j(acc_.get("root_id"));
817+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
818+ spy.wait(SIGNAL_WAIT_TIME);
819+ root = j->item();
820+ }
821+
822+ Item child;
823+ {
824+ unique_ptr<ItemJob> j(acc_.get("child_id"));
825+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
826+ spy.wait(SIGNAL_WAIT_TIME);
827+ child = j->item();
828+ }
829+
830+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 0));
831+ EXPECT_TRUE(uploader->isValid());
832+
833+ {
834+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
835+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
836+ auto arg = spy.takeFirst();
837+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
838+ }
839+
840+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
841+ uploader->cancel();
842+
843+ EXPECT_EQ(1, spy.count());
844+ auto arg = spy.takeFirst();
845+ EXPECT_EQ(Uploader::Status::Cancelled, qvariant_cast<Uploader::Status>(arg.at(0)));
846+
847+ EXPECT_EQ(Uploader::Status::Cancelled, uploader->status());
848+ EXPECT_EQ(StorageError::Type::Cancelled, uploader->error().type());
849+ EXPECT_EQ("Uploader::cancel(): upload was cancelled", uploader->error().message());
850+
851+ // We wait here to get coverage for when the successful reply for the cancel message.
852+ EXPECT_FALSE(spy.wait(2000));
853+}
854+
855+TEST_F(UploadTest, cancel_error)
856+{
857+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("finish_upload_slow_error")));
858+
859+ Item root;
860+ {
861+ unique_ptr<ItemJob> j(acc_.get("root_id"));
862+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
863+ spy.wait(SIGNAL_WAIT_TIME);
864+ root = j->item();
865+ }
866+
867+ Item child;
868+ {
869+ unique_ptr<ItemJob> j(acc_.get("child_id"));
870+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
871+ spy.wait(SIGNAL_WAIT_TIME);
872+ child = j->item();
873+ }
874+
875+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 0));
876+ EXPECT_TRUE(uploader->isValid());
877+
878+ {
879+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
880+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
881+ auto arg = spy.takeFirst();
882+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
883+ }
884+
885+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
886+
887+ uploader->finishUpload();
888+
889+ uploader->cancel();
890+ uploader->cancel(); // Second time for coverage
891+
892+ uploader->finishUpload(); // Second time for coverage
893+
894+ EXPECT_EQ(1, spy.count());
895+ auto arg = spy.takeFirst();
896+ EXPECT_EQ(Uploader::Status::Cancelled, qvariant_cast<Uploader::Status>(arg.at(0)));
897+
898+ EXPECT_EQ(Uploader::Status::Cancelled, uploader->status());
899+ EXPECT_EQ(StorageError::Type::Cancelled, uploader->error().type());
900+ EXPECT_EQ("Uploader::cancel(): upload was cancelled", uploader->error().message());
901+
902+ // We wait here to get coverage for when the reply to a finishUpload() call
903+ // finds the uploader in a final state.
904+ EXPECT_FALSE(spy.wait(2000));
905+}
906+
907+TEST_F(UploadTest, cancel_runtime_destroyed)
908+{
909+ set_provider(unique_ptr<provider::ProviderBase>(new MockProvider("finish_upload_slow_error")));
910+
911+ Item root;
912+ {
913+ unique_ptr<ItemJob> j(acc_.get("root_id"));
914+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
915+ spy.wait(SIGNAL_WAIT_TIME);
916+ root = j->item();
917+ }
918+
919+ Item child;
920+ {
921+ unique_ptr<ItemJob> j(acc_.get("child_id"));
922+ QSignalSpy spy(j.get(), &ItemJob::statusChanged);
923+ spy.wait(SIGNAL_WAIT_TIME);
924+ child = j->item();
925+ }
926+
927+ unique_ptr<Uploader> uploader(child.createUploader(Item::ConflictPolicy::Overwrite, 0));
928+ EXPECT_TRUE(uploader->isValid());
929+
930+ {
931+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
932+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
933+ auto arg = spy.takeFirst();
934+ EXPECT_EQ(Uploader::Status::Ready, qvariant_cast<Uploader::Status>(arg.at(0)));
935+ }
936+
937+ QSignalSpy spy(uploader.get(), &Uploader::statusChanged);
938+
939+ EXPECT_EQ(StorageError::Type::NoError, runtime_->shutdown().type()); // Destroy runtime
940+
941+ uploader->cancel();
942+
943+ if (spy.count() == 0)
944+ {
945+ ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
946+ }
947+ auto arg = spy.takeFirst();
948+ EXPECT_EQ(Uploader::Status::Error, qvariant_cast<Uploader::Status>(arg.at(0)));
949+
950+ EXPECT_EQ(Uploader::Status::Error, uploader->status());
951+ EXPECT_EQ(StorageError::Type::RuntimeDestroyed, uploader->error().type());
952+ EXPECT_EQ("Uploader::cancel(): Runtime was destroyed previously", uploader->error().message());
953+}
954+
955 int main(int argc, char** argv)
956 {
957 QCoreApplication app(argc, argv);

Subscribers

People subscribed via source and target branches

to all changes: