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

Proposed by Michi Henning
Status: Merged
Approved by: James Henstridge
Approved revision: 80
Merged at revision: 41
Proposed branch: lp:~michihenning/storage-framework/more-coverage
Merge into: lp:storage-framework/devel
Prerequisite: lp:~michihenning/storage-framework/increase-coverage
Diff against target: 4904 lines (+1998/-1062)
25 files modified
include/unity/storage/qt/client/Exceptions.h (+1/-3)
include/unity/storage/qt/client/internal/ItemBase.h (+2/-0)
include/unity/storage/qt/client/internal/local_client/ItemImpl.h (+4/-4)
include/unity/storage/qt/client/internal/local_client/UploaderImpl.h (+1/-5)
include/unity/storage/qt/client/internal/local_client/storage_exception.h (+94/-0)
include/unity/storage/qt/client/internal/make_future.h (+14/-74)
include/unity/storage/qt/client/internal/remote_client/Handler.h (+1/-0)
include/unity/storage/qt/client/internal/remote_client/ItemImpl.h (+0/-3)
src/qt/client/Exceptions.cpp (+1/-7)
src/qt/client/internal/ItemBase.cpp (+15/-0)
src/qt/client/internal/local_client/CMakeLists.txt (+1/-0)
src/qt/client/internal/local_client/DownloaderImpl.cpp (+9/-0)
src/qt/client/internal/local_client/FileImpl.cpp (+23/-43)
src/qt/client/internal/local_client/FolderImpl.cpp (+72/-106)
src/qt/client/internal/local_client/ItemImpl.cpp (+131/-165)
src/qt/client/internal/local_client/RootImpl.cpp (+67/-62)
src/qt/client/internal/local_client/RuntimeImpl.cpp (+1/-0)
src/qt/client/internal/local_client/UploaderImpl.cpp (+16/-39)
src/qt/client/internal/local_client/storage_exception.cpp (+99/-0)
src/qt/client/internal/remote_client/FileImpl.cpp (+12/-19)
src/qt/client/internal/remote_client/FolderImpl.cpp (+19/-19)
src/qt/client/internal/remote_client/ItemImpl.cpp (+44/-82)
src/qt/client/internal/remote_client/RuntimeImpl.cpp (+1/-0)
tests/local-client/local-client_test.cpp (+1361/-422)
tests/remote-client/remote-client_test.cpp (+9/-9)
To merge this branch: bzr merge lp:~michihenning/storage-framework/more-coverage
Reviewer Review Type Date Requested Status
James Henstridge Approve
unity-api-1-bot continuous-integration Needs Fixing
Review via email: mp+301450@code.launchpad.net

This proposal supersedes a proposal from 2016-07-29.

Commit message

Improved coverage. Better error reporting/handling.

Description of the change

Very boring branch. Lots of extra tests for proper coverage, particularly for error handling/reporting. Refactored a bunch of code to get rid of repeated exception checks.

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

A few coverage suppressions.

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

FAILED: Continuous integration, rev:76
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/43/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/266/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/272
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=vivid+overlay/206
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=xenial+overlay/206
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=yakkety/206
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/135/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/135/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/135/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/135/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/135/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/135/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/135/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/135/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/135/console

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

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

Fixed hang in test. Fixed sigpipe problem when cancelling upload.

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

FAILED: Continuous integration, rev:77
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/44/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/271/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/277
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=vivid+overlay/211
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=xenial+overlay/211
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=yakkety/211
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/140/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/140/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/140/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/140/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/140/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/140/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/140/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/140/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/140/console

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

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

Added a few missing checks for destroyed runtime or item.

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

FAILED: Continuous integration, rev:78
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/47/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/274/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/280
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=vivid+overlay/214
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=xenial+overlay/214
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=yakkety/214
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/143/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/143/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/143/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/143/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/143/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/143/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/143/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/143/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/143/console

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

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

Fixed incorrect check for parent destruction in copy() and move().

80. By Michi Henning

Fix typos.

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

FAILED: Continuous integration, rev:80
https://jenkins.canonical.com/unity-api-1/job/lp-storage-framework-ci/48/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/275/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/281
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=vivid+overlay/215
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=xenial+overlay/215
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=yakkety/215
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/144/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/144/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/144/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/144/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/144/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/144/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/144/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/144/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/144/console

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

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

Let's merge this.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'include/unity/storage/qt/client/Exceptions.h'
--- include/unity/storage/qt/client/Exceptions.h 2016-08-03 06:10:39 +0000
+++ include/unity/storage/qt/client/Exceptions.h 2016-08-03 06:10:39 +0000
@@ -85,18 +85,16 @@
85class UNITY_STORAGE_EXPORT DeletedException : public StorageException85class UNITY_STORAGE_EXPORT DeletedException : public StorageException
86{86{
87public:87public:
88 DeletedException(QString const& error_message, QString const& identity_, QString const& name_);88 DeletedException(QString const& error_message, QString const& identity_);
89 ~DeletedException();89 ~DeletedException();
9090
91 virtual DeletedException* clone() const override;91 virtual DeletedException* clone() const override;
92 virtual void raise() const override;92 virtual void raise() const override;
9393
94 QString native_identity() const;94 QString native_identity() const;
95 QString name() const;
9695
97private:96private:
98 QString identity_;97 QString identity_;
99 QString name_;
100};98};
10199
102/**100/**
103101
=== modified file 'include/unity/storage/qt/client/internal/ItemBase.h'
--- include/unity/storage/qt/client/internal/ItemBase.h 2016-08-03 06:10:39 +0000
+++ include/unity/storage/qt/client/internal/ItemBase.h 2016-08-03 06:10:39 +0000
@@ -83,11 +83,13 @@
8383
84protected:84protected:
85 std::shared_ptr<Root> get_root() const noexcept;85 std::shared_ptr<Root> get_root() const noexcept;
86 void throw_if_destroyed(QString const& method) const;
8687
87 const QString identity_;88 const QString identity_;
88 const ItemType type_;89 const ItemType type_;
89 std::weak_ptr<Root> root_;90 std::weak_ptr<Root> root_;
90 std::weak_ptr<Item> public_instance_;91 std::weak_ptr<Item> public_instance_;
92 bool deleted_ = false;
9193
92 friend class ItemImpl;94 friend class ItemImpl;
93};95};
9496
=== modified file 'include/unity/storage/qt/client/internal/local_client/ItemImpl.h'
--- include/unity/storage/qt/client/internal/local_client/ItemImpl.h 2016-08-03 06:10:39 +0000
+++ include/unity/storage/qt/client/internal/local_client/ItemImpl.h 2016-08-03 06:10:39 +0000
@@ -68,14 +68,14 @@
68 static boost::filesystem::path sanitize(QString const& name, QString const& method);68 static boost::filesystem::path sanitize(QString const& name, QString const& method);
69 static bool is_reserved_path(boost::filesystem::path const& path) noexcept;69 static bool is_reserved_path(boost::filesystem::path const& path) noexcept;
7070
71 DeletedException deleted_ex(QString const& method) const noexcept;
72
73 bool deleted_;
74 QString name_;71 QString name_;
75 QString etag_;72 QString etag_;
76 QDateTime modified_time_;73 QDateTime modified_time_;
77 QVariantMap metadata_;74 QVariantMap metadata_;
78 std::mutex mutable mutex_;75 std::recursive_mutex mutable mutex_;
76
77private:
78 static void copy_recursively(boost::filesystem::path const& source, boost::filesystem::path const& target);
79};79};
8080
81} // namespace local_client81} // namespace local_client
8282
=== modified file 'include/unity/storage/qt/client/internal/local_client/UploaderImpl.h'
--- include/unity/storage/qt/client/internal/local_client/UploaderImpl.h 2016-08-03 06:10:39 +0000
+++ include/unity/storage/qt/client/internal/local_client/UploaderImpl.h 2016-08-03 06:10:39 +0000
@@ -68,7 +68,6 @@
68private Q_SLOTS:68private Q_SLOTS:
69 void on_bytes_ready();69 void on_bytes_ready();
70 void on_read_channel_finished();70 void on_read_channel_finished();
71 void on_error();
7271
73private:72private:
74 void read_and_write_chunk();73 void read_and_write_chunk();
@@ -91,11 +90,8 @@
91 QFutureInterface<std::shared_ptr<File>>& qf_;90 QFutureInterface<std::shared_ptr<File>>& qf_;
92 QFutureInterface<void>& worker_initialized_;91 QFutureInterface<void>& worker_initialized_;
93 QString error_msg_;92 QString error_msg_;
94<<<<<<< TREE93 int error_code_ = 0;
95 bool use_linkat_ = true;94 bool use_linkat_ = true;
96=======
97 int error_code_ = 0;
98>>>>>>> MERGE-SOURCE
99};95};
10096
101class UploadThread : public QThread97class UploadThread : public QThread
10298
=== added file 'include/unity/storage/qt/client/internal/local_client/storage_exception.h'
--- include/unity/storage/qt/client/internal/local_client/storage_exception.h 1970-01-01 00:00:00 +0000
+++ include/unity/storage/qt/client/internal/local_client/storage_exception.h 2016-08-03 06:10:39 +0000
@@ -0,0 +1,94 @@
1/*
2 * Copyright (C) 2016 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Michi Henning <michi.henning@canonical.com>
17 */
18
19#pragma once
20
21#include <unity/storage/qt/client/Exceptions.h>
22#include <unity/storage/qt/client/internal/local_client/boost_filesystem.h>
23
24#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
26#pragma GCC diagnostic ignored "-Wcast-align"
27#include <QFuture>
28#pragma GCC diagnostic pop
29#include <QFutureInterface>
30
31class QString;
32
33namespace unity
34{
35namespace storage
36{
37namespace qt
38{
39namespace client
40{
41namespace internal
42{
43namespace local_client
44{
45
46void throw_storage_exception(QString const& method,
47 std::exception_ptr ep) __attribute__ ((noreturn));
48
49void throw_storage_exception(QString const& method,
50 std::exception_ptr ep,
51 QString const& key) __attribute__ ((noreturn));
52
53template<typename T>
54QFuture<T> make_exceptional_future(QString const& method, std::exception_ptr ep)
55{
56 try
57 {
58 throw_storage_exception(method, ep);
59 }
60 catch (StorageException const& e)
61 {
62 QFutureInterface<T> qf;
63 qf.reportException(e);
64 qf.reportFinished();
65 return qf.future();
66 }
67 abort(); // Impossible. // LCOV_EXCL_LINE
68}
69
70template<typename T>
71QFuture<T> make_exceptional_future(QString const& method,
72 std::exception_ptr ep,
73 QString const& key)
74{
75 try
76 {
77 throw_storage_exception(method, ep, key);
78 }
79 catch (StorageException const& e)
80 {
81 QFutureInterface<T> qf;
82 qf.reportException(e);
83 qf.reportFinished();
84 return qf.future();
85 }
86 abort(); // Impossible. // LCOV_EXCL_LINE
87}
88
89} // namespace local_client
90} // namespace internal
91} // namespace client
92} // namespace qt
93} // namespace storage
94} // namespace unity
095
=== renamed file 'include/unity/storage/qt/client/internal/local_client/tmpfile-prefix.h' => 'include/unity/storage/qt/client/internal/local_client/tmpfile_prefix.h'
=== modified file 'include/unity/storage/qt/client/internal/make_future.h'
--- include/unity/storage/qt/client/internal/make_future.h 2016-08-03 06:10:39 +0000
+++ include/unity/storage/qt/client/internal/make_future.h 2016-08-03 06:10:39 +0000
@@ -18,9 +18,6 @@
1818
19#pragma once19#pragma once
2020
21#include <unity/storage/qt/client/Exceptions.h>
22#include <unity/storage/qt/client/internal/boost_filesystem.h>
23
24#pragma GCC diagnostic push21#pragma GCC diagnostic push
25#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"22#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
26#pragma GCC diagnostic ignored "-Wcast-align"23#pragma GCC diagnostic ignored "-Wcast-align"
@@ -39,21 +36,6 @@
39namespace internal36namespace internal
40{37{
4138
42template<typename T = void>
43QFuture<T> make_ready_future()
44{
45 QFutureInterface<void> qf;
46 qf.reportFinished();
47 return qf.future();
48}
49
50template<typename T = void>
51QFuture<T> make_ready_future(QFutureInterface<T> qf)
52{
53 qf.reportFinished();
54 return qf.future();
55}
56
57template<typename T>39template<typename T>
58QFuture<T> make_ready_future(T const& val)40QFuture<T> make_ready_future(T const& val)
59{41{
@@ -71,6 +53,20 @@
71 return qf.future();53 return qf.future();
72}54}
7355
56template<typename T = void>
57QFuture<T> make_ready_future(QFutureInterface<T> qf)
58{
59 qf.reportFinished();
60 return qf.future();
61}
62
63template<typename T = void>
64QFuture<T> make_ready_future()
65{
66 QFutureInterface<void> qf;
67 return make_ready_future(qf);
68}
69
74template<typename E>70template<typename E>
75QFuture<void> make_exceptional_future(E const& ex)71QFuture<void> make_exceptional_future(E const& ex)
76{72{
@@ -97,62 +93,6 @@
97 return qf.future();93 return qf.future();
98}94}
9995
100template<typename T>
101QFuture<T> make_exceptional_future(QString const& msg, boost::filesystem::filesystem_error const& e)
102{
103 QFutureInterface<T> qf;
104 switch (e.code().value())
105 {
106 case EACCES:
107 case EPERM:
108 {
109 qf.reportException(PermissionException(msg));
110 break;
111 }
112 case EDQUOT:
113 case ENOSPC:
114 {
115 qf.reportException(QuotaException(msg));
116 break;
117 }
118 case ENOENT:
119 {
120 //qf.reportException(NotExistsException(msg));
121 qDebug() << "ENOENT";
122 qf.reportException(ResourceException(msg, e.code().value()));
123 break;
124 }
125 default:
126 {
127 qf.reportException(ResourceException(msg, e.code().value()));
128 break;
129 }
130 }
131 qf.reportFinished();
132 return qf.future();
133}
134
135template<typename T>
136QFuture<T> make_exceptional_future(QString const& msg, boost::filesystem::filesystem_error const& e, QString const& key)
137{
138 QFutureInterface<T> qf;
139 switch (e.code().value())
140 {
141 case ENOENT:
142 {
143 qf.reportException(NotExistsException(msg, key));
144 break;
145 }
146 default:
147 {
148 return make_exceptional_future<T>(msg, e);
149 break;
150 }
151 }
152 qf.reportFinished();
153 return qf.future();
154}
155
156} // namespace internal96} // namespace internal
157} // namespace client97} // namespace client
158} // namespace qt98} // namespace qt
15999
=== modified file 'include/unity/storage/qt/client/internal/remote_client/Handler.h'
--- include/unity/storage/qt/client/internal/remote_client/Handler.h 2016-08-03 06:10:39 +0000
+++ include/unity/storage/qt/client/internal/remote_client/Handler.h 2016-08-03 06:10:39 +0000
@@ -18,6 +18,7 @@
1818
19#pragma once19#pragma once
2020
21#include <unity/storage/qt/client/Exceptions.h>
21#include <unity/storage/qt/client/internal/make_future.h>22#include <unity/storage/qt/client/internal/make_future.h>
22#include <unity/storage/qt/client/internal/remote_client/HandlerBase.h>23#include <unity/storage/qt/client/internal/remote_client/HandlerBase.h>
2324
2425
=== modified file 'include/unity/storage/qt/client/internal/remote_client/ItemImpl.h'
--- include/unity/storage/qt/client/internal/remote_client/ItemImpl.h 2016-07-22 00:17:24 +0000
+++ include/unity/storage/qt/client/internal/remote_client/ItemImpl.h 2016-08-03 06:10:39 +0000
@@ -66,9 +66,6 @@
66 static std::shared_ptr<Item> make_item(storage::internal::ItemMetadata const& md, std::weak_ptr<Root> root);66 static std::shared_ptr<Item> make_item(storage::internal::ItemMetadata const& md, std::weak_ptr<Root> root);
6767
68protected:68protected:
69 DeletedException deleted_ex(QString const& method) const noexcept;
70
71 bool deleted_ = false;
72 storage::internal::ItemMetadata md_;69 storage::internal::ItemMetadata md_;
7370
74 friend class DeleteHandler;71 friend class DeleteHandler;
7572
=== modified file 'src/qt/client/Exceptions.cpp'
--- src/qt/client/Exceptions.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/Exceptions.cpp 2016-08-03 06:10:39 +0000
@@ -81,10 +81,9 @@
81 throw *this;81 throw *this;
82}82}
8383
84DeletedException::DeletedException(QString const& error_message, QString const& identity, QString const& name)84DeletedException::DeletedException(QString const& error_message, QString const& identity)
85 : StorageException("DeletedException", error_message)85 : StorageException("DeletedException", error_message)
86 , identity_(identity)86 , identity_(identity)
87 , name_(name)
88{87{
89}88}
9089
@@ -105,11 +104,6 @@
105 return identity_;104 return identity_;
106}105}
107106
108QString DeletedException::name() const
109{
110 return name_;
111}
112
113RuntimeDestroyedException::RuntimeDestroyedException(QString const& method)107RuntimeDestroyedException::RuntimeDestroyedException(QString const& method)
114 : StorageException("RuntimeDestroyedException", method + ": Runtime was destroyed previously")108 : StorageException("RuntimeDestroyedException", method + ": Runtime was destroyed previously")
115{109{
116110
=== modified file 'src/qt/client/internal/ItemBase.cpp'
--- src/qt/client/internal/ItemBase.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/ItemBase.cpp 2016-08-03 06:10:39 +0000
@@ -48,11 +48,13 @@
4848
49QString ItemBase::native_identity() const49QString ItemBase::native_identity() const
50{50{
51 throw_if_destroyed("Item::native_identity()");
51 return identity_;52 return identity_;
52}53}
5354
54ItemType ItemBase::type() const55ItemType ItemBase::type() const
55{56{
57 throw_if_destroyed("Item::type()");
56 return type_;58 return type_;
57}59}
5860
@@ -95,6 +97,19 @@
95 return nullptr;97 return nullptr;
96}98}
9799
100void ItemBase::throw_if_destroyed(QString const& method) const
101{
102 if (deleted_)
103 {
104 QString msg = method + ": \"" + identity_ + "\" was deleted previously";
105 throw DeletedException(msg, identity_);
106 }
107 if (!get_root())
108 {
109 throw RuntimeDestroyedException(method);
110 }
111}
112
98} // namespace internal113} // namespace internal
99} // namespace client114} // namespace client
100} // namespace qt115} // namespace qt
101116
=== modified file 'src/qt/client/internal/local_client/CMakeLists.txt'
--- src/qt/client/internal/local_client/CMakeLists.txt 2016-07-22 00:17:24 +0000
+++ src/qt/client/internal/local_client/CMakeLists.txt 2016-08-03 06:10:39 +0000
@@ -7,6 +7,7 @@
7 ${CMAKE_CURRENT_SOURCE_DIR}/RootImpl.cpp7 ${CMAKE_CURRENT_SOURCE_DIR}/RootImpl.cpp
8 ${CMAKE_CURRENT_SOURCE_DIR}/Runtime_create.cpp8 ${CMAKE_CURRENT_SOURCE_DIR}/Runtime_create.cpp
9 ${CMAKE_CURRENT_SOURCE_DIR}/RuntimeImpl.cpp9 ${CMAKE_CURRENT_SOURCE_DIR}/RuntimeImpl.cpp
10 ${CMAKE_CURRENT_SOURCE_DIR}/storage_exception.cpp
10 ${CMAKE_CURRENT_SOURCE_DIR}/UploaderImpl.cpp11 ${CMAKE_CURRENT_SOURCE_DIR}/UploaderImpl.cpp
11 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/client/internal/local_client/DownloaderImpl.h12 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/client/internal/local_client/DownloaderImpl.h
12 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/client/internal/local_client/UploaderImpl.h13 ${CMAKE_SOURCE_DIR}/include/unity/storage/qt/client/internal/local_client/UploaderImpl.h
1314
=== modified file 'src/qt/client/internal/local_client/DownloaderImpl.cpp'
--- src/qt/client/internal/local_client/DownloaderImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/local_client/DownloaderImpl.cpp 2016-08-03 06:10:39 +0000
@@ -79,8 +79,10 @@
79 input_file_.reset(new QFile(filename_));79 input_file_.reset(new QFile(filename_));
80 if (!input_file_->open(QIODevice::ReadOnly))80 if (!input_file_->open(QIODevice::ReadOnly))
81 {81 {
82 // LCOV_EXCL_START
82 handle_error("cannot open " + filename_ + ": " + input_file_->errorString(), input_file_->error());83 handle_error("cannot open " + filename_ + ": " + input_file_->errorString(), input_file_->error());
83 return;84 return;
85 // LCOV_EXCL_STOP
84 }86 }
85 bytes_to_write_ = input_file_->size();87 bytes_to_write_ = input_file_->size();
8688
@@ -189,6 +191,7 @@
189191
190void DownloadWorker::on_error()192void DownloadWorker::on_error()
191{193{
194 disconnect(write_socket_.get(), nullptr, this, nullptr);
192 handle_error(write_socket_->errorString(), write_socket_->error());195 handle_error(write_socket_->errorString(), write_socket_->error());
193}196}
194197
@@ -203,21 +206,27 @@
203 auto bytes_read = input_file_->read(buf.data(), buf.size());206 auto bytes_read = input_file_->read(buf.data(), buf.size());
204 if (bytes_read == -1)207 if (bytes_read == -1)
205 {208 {
209 // LCOV_EXCL_START
206 handle_error(filename_ + ": read error: " + input_file_->errorString(), input_file_->error());210 handle_error(filename_ + ": read error: " + input_file_->errorString(), input_file_->error());
207 return;211 return;
212 // LCOV_EXCL_STOP
208 }213 }
209 buf.resize(bytes_read);214 buf.resize(bytes_read);
210215
211 auto bytes_written = write_socket_->write(buf);216 auto bytes_written = write_socket_->write(buf);
212 if (bytes_written == -1)217 if (bytes_written == -1)
213 {218 {
219 // LCOV_EXCL_START
214 handle_error(filename_ + ": socket error: " + write_socket_->errorString(), write_socket_->error());220 handle_error(filename_ + ": socket error: " + write_socket_->errorString(), write_socket_->error());
221 // LCOV_EXCL_STOP
215 }222 }
216 else if (bytes_written != bytes_read)223 else if (bytes_written != bytes_read)
217 {224 {
225 // LCOV_EXCL_START
218 QString msg = filename_ + ": write error, requested " + bytes_read + " B, but wrote only "226 QString msg = filename_ + ": write error, requested " + bytes_read + " B, but wrote only "
219 + bytes_written + " B.";227 + bytes_written + " B.";
220 handle_error(msg, 0);228 handle_error(msg, 0);
229 // LCOV_EXCL_STOP
221 }230 }
222}231}
223232
224233
=== modified file 'src/qt/client/internal/local_client/FileImpl.cpp'
--- src/qt/client/internal/local_client/FileImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/local_client/FileImpl.cpp 2016-08-03 06:10:39 +0000
@@ -22,6 +22,7 @@
22#include <unity/storage/qt/client/Exceptions.h>22#include <unity/storage/qt/client/Exceptions.h>
23#include <unity/storage/qt/client/File.h>23#include <unity/storage/qt/client/File.h>
24#include <unity/storage/qt/client/internal/local_client/DownloaderImpl.h>24#include <unity/storage/qt/client/internal/local_client/DownloaderImpl.h>
25#include <unity/storage/qt/client/internal/local_client/storage_exception.h>
25#include <unity/storage/qt/client/internal/local_client/UploaderImpl.h>26#include <unity/storage/qt/client/internal/local_client/UploaderImpl.h>
26#include <unity/storage/qt/client/internal/make_future.h>27#include <unity/storage/qt/client/internal/make_future.h>
27#include <unity/storage/qt/client/Uploader.h>28#include <unity/storage/qt/client/Uploader.h>
@@ -50,65 +51,44 @@
5051
51QString FileImpl::name() const52QString FileImpl::name() const
52{53{
53 lock_guard<mutex> guard(mutex_);54 lock_guard<decltype(mutex_)> guard(mutex_);
5455
55 if (deleted_)56 throw_if_destroyed("File::name()");
56 {
57 throw deleted_ex("File::name()");
58 }
59 if (!get_root())
60 {
61 throw RuntimeDestroyedException("File::name()");
62 }
63 return name_;57 return name_;
64}58}
6559
66int64_t FileImpl::size() const60int64_t FileImpl::size() const
67{61{
68 lock_guard<mutex> guard(mutex_);62 lock_guard<decltype(mutex_)> guard(mutex_);
6963
70 if (deleted_)64 throw_if_destroyed("File::size()");
71 {
72 throw deleted_ex("File::size()");
73 }
74 if (!get_root())
75 {
76 throw RuntimeDestroyedException("File::size()");
77 }
78
79 try65 try
80 {66 {
81 boost::filesystem::path p = identity_.toStdString();67 boost::filesystem::path p = identity_.toStdString();
82 return file_size(p);68 return file_size(p);
83 }69 }
84 catch (boost::filesystem::filesystem_error const& e)70 catch (std::exception const&)
85 {71 {
86 throw ResourceException(e.what(), e.code().value());72 throw_storage_exception(QString("File::size()"), current_exception());
87 }
88 catch (std::exception const& e)
89 {
90 throw ResourceException(e.what(), 0);
91 }73 }
92}74}
9375
94QFuture<Uploader::SPtr> FileImpl::create_uploader(ConflictPolicy policy, int64_t size)76QFuture<Uploader::SPtr> FileImpl::create_uploader(ConflictPolicy policy, int64_t size)
95{77{
96 lock_guard<mutex> guard(mutex_);78 lock_guard<decltype(mutex_)> guard(mutex_);
9779
98 if (deleted_)80 try
99 {81 {
100 return make_exceptional_future<Uploader::SPtr>(deleted_ex("File::create_uploader()"));82 throw_if_destroyed("File::create_uploader()");
83 }
84 catch (StorageException const& e)
85 {
86 return internal::make_exceptional_future<Uploader::SPtr>(e);
101 }87 }
102 if (size < 0)88 if (size < 0)
103 {89 {
104 QString msg = "File::create_uploader(): size must be >= 0";90 QString msg = "File::create_uploader(): size must be >= 0";
105 return make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));91 return internal::make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));
106 }
107
108 auto root = get_root();
109 if (!root)
110 {
111 return make_exceptional_future<Uploader::SPtr>(RuntimeDestroyedException("File::create_uploader()"));
112 }92 }
11393
114 auto file = dynamic_pointer_cast<File>(public_instance_.lock());94 auto file = dynamic_pointer_cast<File>(public_instance_.lock());
@@ -120,15 +100,15 @@
120100
121QFuture<Downloader::SPtr> FileImpl::create_downloader()101QFuture<Downloader::SPtr> FileImpl::create_downloader()
122{102{
123 lock_guard<mutex> guard(mutex_);103 lock_guard<decltype(mutex_)> guard(mutex_);
124104
125 if (deleted_)105 try
126 {106 {
127 return make_exceptional_future<Downloader::SPtr>(deleted_ex("File::create_downloader()"));107 throw_if_destroyed("File::create_downloader()");
128 }108 }
129 if (!get_root())109 catch (StorageException const& e)
130 {110 {
131 throw RuntimeDestroyedException("File::create_downloader()");111 return internal::make_exceptional_future<Downloader::SPtr>(e);
132 }112 }
133113
134 auto pi = public_instance_.lock();114 auto pi = public_instance_.lock();
135115
=== modified file 'src/qt/client/internal/local_client/FolderImpl.cpp'
--- src/qt/client/internal/local_client/FolderImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/local_client/FolderImpl.cpp 2016-08-03 06:10:39 +0000
@@ -24,7 +24,8 @@
24#include <unity/storage/qt/client/Uploader.h>24#include <unity/storage/qt/client/Uploader.h>
25#include <unity/storage/qt/client/internal/make_future.h>25#include <unity/storage/qt/client/internal/make_future.h>
26#include <unity/storage/qt/client/internal/local_client/FileImpl.h>26#include <unity/storage/qt/client/internal/local_client/FileImpl.h>
27#include <unity/storage/qt/client/internal/local_client/tmpfile-prefix.h>27#include <unity/storage/qt/client/internal/local_client/storage_exception.h>
28#include <unity/storage/qt/client/internal/local_client/tmpfile_prefix.h>
28#include <unity/storage/qt/client/internal/local_client/UploaderImpl.h>29#include <unity/storage/qt/client/internal/local_client/UploaderImpl.h>
2930
30#include <boost/algorithm/string/predicate.hpp>31#include <boost/algorithm/string/predicate.hpp>
@@ -64,36 +65,34 @@
6465
65QString FolderImpl::name() const66QString FolderImpl::name() const
66{67{
67 lock_guard<mutex> guard(mutex_);68 lock_guard<decltype(mutex_)> guard(mutex_);
6869
69 if (deleted_)70 throw_if_destroyed("Folder::name()");
70 {
71 throw deleted_ex("Folder::name()");
72 }
73 return name_;71 return name_;
74}72}
7573
76QFuture<QVector<Item::SPtr>> FolderImpl::list() const74QFuture<QVector<Item::SPtr>> FolderImpl::list() const
77{75{
76 try
77 {
78 throw_if_destroyed("Folder::list()");
79 }
80 catch (StorageException const& e)
81 {
82 return internal::make_exceptional_future<QVector<Item::SPtr>>(e);
83 }
84
78 auto This = dynamic_pointer_cast<FolderImpl const>(shared_from_this()); // Keep this folder alive while the lambda is alive.85 auto This = dynamic_pointer_cast<FolderImpl const>(shared_from_this()); // Keep this folder alive while the lambda is alive.
79 auto list = [This]()86 auto list = [This]()
80 {87 {
81 lock_guard<mutex> guard(This->mutex_);88 lock_guard<decltype(mutex_)> guard(This->mutex_);
8289
83 if (This->deleted_)90 This->throw_if_destroyed("Folder::list()");
84 {
85 throw This->deleted_ex("Folder::list()");
86 }
87 auto root = This->get_root();
88 if (!root)
89 {
90 throw RuntimeDestroyedException("Folder::list()");
91 }
92
93 try91 try
94 {92 {
95 using namespace boost::filesystem;93 using namespace boost::filesystem;
9694
95 auto root = This->root_.lock();
97 QVector<Item::SPtr> results;96 QVector<Item::SPtr> results;
98 for (directory_iterator it(This->native_identity().toStdString()); it != directory_iterator(); ++it)97 for (directory_iterator it(This->native_identity().toStdString()); it != directory_iterator(); ++it)
99 {98 {
@@ -119,13 +118,9 @@
119 }118 }
120 return results;119 return results;
121 }120 }
122 catch (boost::filesystem::filesystem_error const& e)121 catch (std::exception const&)
123 {122 {
124 throw ResourceException(QString("Folder::list(): ") + e.what(), e.code().value());123 throw_storage_exception("Folder::list()", current_exception());
125 }
126 catch (std::exception const& e)
127 {
128 throw ResourceException(QString("Folder::list(): ") + e.what(), errno);
129 }124 }
130 };125 };
131 return QtConcurrent::run(list);126 return QtConcurrent::run(list);
@@ -133,30 +128,31 @@
133128
134QFuture<QVector<Item::SPtr>> FolderImpl::lookup(QString const& name) const129QFuture<QVector<Item::SPtr>> FolderImpl::lookup(QString const& name) const
135{130{
131 try
132 {
133 throw_if_destroyed("Folder::lookup()");
134 }
135 catch (StorageException const& e)
136 {
137 return internal::make_exceptional_future<QVector<Item::SPtr>>(e);
138 }
139
136 auto This = dynamic_pointer_cast<FolderImpl const>(shared_from_this()); // Keep this folder alive while the lambda is alive.140 auto This = dynamic_pointer_cast<FolderImpl const>(shared_from_this()); // Keep this folder alive while the lambda is alive.
137 auto lookup = [This, name]() -> QVector<Item::SPtr>141 auto lookup = [This, name]() -> QVector<Item::SPtr>
138 {142 {
139 lock_guard<mutex> guard(This->mutex_);143 lock_guard<decltype(mutex_)> guard(This->mutex_);
140144
141 if (This->deleted_)145 This->throw_if_destroyed("Folder::lookup()"); // LCOV_EXCL_LINE
142 {
143 throw This->deleted_ex("Folder::lookup()");
144 }
145 auto root = This->get_root();
146 if (!root)
147 {
148 throw RuntimeDestroyedException("Folder::lookup()");
149 }
150
151 try146 try
152 {147 {
153 using namespace boost::filesystem;148 using namespace boost::filesystem;
154149
150 auto root = This->root_.lock();
155 path p = This->native_identity().toStdString();151 path p = This->native_identity().toStdString();
156 auto sanitized_name = sanitize(name, "Folder::lookup()");152 auto sanitized_name = sanitize(name, "Folder::lookup()");
157 if (is_reserved_path(sanitized_name))153 if (is_reserved_path(sanitized_name))
158 {154 {
159 throw NotExistsException("Folder::lookup(): no such item: " + name, name);155 throw NotExistsException("Folder::lookup(): no such item: \"" + name + "\"", name);
160 }156 }
161 p /= sanitized_name;157 p /= sanitized_name;
162 file_status s = status(p);158 file_status s = status(p);
@@ -172,23 +168,11 @@
172 v.append(FileImpl::make_file(QString::fromStdString(p.native()), root));168 v.append(FileImpl::make_file(QString::fromStdString(p.native()), root));
173 return v;169 return v;
174 }170 }
175 throw NotExistsException("Folder::lookup(): no such item: " + name, name);171 throw NotExistsException("Folder::lookup(): no such item: \"" + name + "\"", name);
176 }172 }
177 catch (StorageException const&)173 catch (std::exception const&)
178 {174 {
179 throw;175 throw_storage_exception("Folder::lookup()", current_exception());
180 }
181 catch (boost::filesystem::filesystem_error const& e)
182 {
183 if (e.code().value() == ENOENT)
184 {
185 throw NotExistsException("Folder::lookup(): no such item: " + name, name);
186 }
187 throw ResourceException(QString("Folder::lookup(): ") + e.what(), e.code().value());
188 }
189 catch (std::exception const& e)
190 {
191 throw ResourceException(QString("Folder::lookup(): ") + e.what(), errno);
192 }176 }
193 };177 };
194 return QtConcurrent::run(lookup);178 return QtConcurrent::run(lookup);
@@ -196,17 +180,15 @@
196180
197QFuture<Folder::SPtr> FolderImpl::create_folder(QString const& name)181QFuture<Folder::SPtr> FolderImpl::create_folder(QString const& name)
198{182{
199 lock_guard<mutex> guard(mutex_);183 lock_guard<decltype(mutex_)> guard(mutex_);
200184
201 QFutureInterface<Folder::SPtr> qf;185 try
202 if (deleted_)
203 {186 {
204 return make_exceptional_future<Folder::SPtr>(deleted_ex("Folder::create_folder()"));187 throw_if_destroyed("Folder::create_folder()");
205 }188 }
206 auto root = get_root();189 catch (StorageException const& e)
207 if (!root)
208 {190 {
209 return make_exceptional_future<Folder::SPtr>(RuntimeDestroyedException("Folder::create_folder()"));191 return internal::make_exceptional_future<Folder::SPtr>(e);
210 }192 }
211193
212 try194 try
@@ -217,46 +199,40 @@
217 auto sanitized_name = sanitize(name, "Folder::create_folder()");199 auto sanitized_name = sanitize(name, "Folder::create_folder()");
218 if (is_reserved_path(sanitized_name))200 if (is_reserved_path(sanitized_name))
219 {201 {
220 QString msg = "Folder::create_folder(): names beginning with " + QString(TMPFILE_PREFIX) + " are reserved";202 QString msg = "Folder::create_folder(): names beginning with \"" + QString(TMPFILE_PREFIX) + "\" are reserved";
221 return make_exceptional_future<Folder::SPtr>(InvalidArgumentException(msg));203 throw InvalidArgumentException(msg);
222 }204 }
223 p /= sanitized_name;205 p /= sanitized_name;
206 if (exists(p))
207 {
208 QString msg = "Folder::create_folder(): item with name \"" + name + "\" exists already";
209 throw ExistsException(msg, native_identity() + "/" + name, name);
210 }
224 create_directory(p);211 create_directory(p);
225 return make_ready_future(make_folder(QString::fromStdString(p.native()), root));212 return make_ready_future(make_folder(QString::fromStdString(p.native()), root_));
226 }213 }
227 catch (StorageException const& e)214 catch (std::exception const&)
228 {215 {
229 return make_exceptional_future<Folder::SPtr>(e);216 return make_exceptional_future<Folder::SPtr>("Folder::create_folder()", current_exception());
230 }
231 catch (boost::filesystem::filesystem_error const& e)
232 {
233 return make_exceptional_future<Folder::SPtr>(ResourceException(QString("Folder::create_folder: ") + e.what(),
234 e.code().value()));
235 }
236 catch (std::exception const& e)
237 {
238 return make_exceptional_future<Folder::SPtr>(ResourceException(QString("Folder::create_folder: ") + e.what(),
239 errno));
240 }217 }
241}218}
242219
243QFuture<shared_ptr<Uploader>> FolderImpl::create_file(QString const& name, int64_t size)220QFuture<shared_ptr<Uploader>> FolderImpl::create_file(QString const& name, int64_t size)
244{221{
245 unique_lock<mutex> guard(mutex_);222 lock_guard<decltype(mutex_)> guard(mutex_);
246223
247 if (deleted_)224 try
248 {225 {
249 return make_exceptional_future<Uploader::SPtr>(deleted_ex("Folder::create_file()"));226 throw_if_destroyed("Folder::create_file()");
227 }
228 catch (StorageException const& e)
229 {
230 return internal::make_exceptional_future<shared_ptr<Uploader>>(e);
250 }231 }
251 if (size < 0)232 if (size < 0)
252 {233 {
253 QString msg = "Folder::create_file(): size must be >= 0";234 QString msg = "Folder::create_file(): size must be >= 0";
254 return make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));235 return internal::make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));
255 }
256 auto root = get_root();
257 if (!root)
258 {
259 return make_exceptional_future<Uploader::SPtr>(RuntimeDestroyedException("Folder::create_file()"));
260 }236 }
261237
262 try238 try
@@ -267,36 +243,26 @@
267 auto sanitized_name = sanitize(name, "Folder::create_file()");243 auto sanitized_name = sanitize(name, "Folder::create_file()");
268 if (is_reserved_path(sanitized_name))244 if (is_reserved_path(sanitized_name))
269 {245 {
270 QString msg = "Folder::create_file(): names beginning with " + QString(TMPFILE_PREFIX) + " are reserved";246 QString msg = "Folder::create_file(): names beginning with \"" + QString(TMPFILE_PREFIX) + "\" are reserved";
271 return make_exceptional_future<Uploader::SPtr>(InvalidArgumentException(msg));247 throw InvalidArgumentException(msg);
272 }248 }
273 p /= sanitized_name;249 p /= sanitized_name;
274 if (exists(p))250 if (exists(p))
275 {251 {
276 QString msg = "Folder::create_file(): item with name \"" + name + "\" exists already";252 QString msg = "Folder::create_file(): item with name \"" + name + "\" exists already";
277 return make_exceptional_future<Uploader::SPtr>(ExistsException(msg, native_identity(), name));253 throw ExistsException(msg, native_identity() + "/" + name, name);
278 }254 }
279 auto impl = new UploaderImpl(shared_ptr<File>(),255 auto impl = new UploaderImpl(shared_ptr<File>(),
280 size,256 size,
281 QString::fromStdString(p.native()),257 QString::fromStdString(p.native()),
282 ConflictPolicy::error_if_conflict,258 ConflictPolicy::error_if_conflict,
283 root);259 root_);
284 Uploader::SPtr uploader(new Uploader(impl));260 Uploader::SPtr uploader(new Uploader(impl));
285 return make_ready_future(uploader);261 return make_ready_future(uploader);
286 }262 }
287 catch (StorageException const& e)263 catch (std::exception const&)
288 {264 {
289 return make_exceptional_future<Uploader::SPtr>(e);265 return make_exceptional_future<Uploader::SPtr>("Folder::create_file()", current_exception());
290 }
291 catch (boost::filesystem::filesystem_error const& e)
292 {
293 return make_exceptional_future<Uploader::SPtr>(ResourceException(QString("Folder::create_file: ") + e.what(),
294 e.code().value()));
295 }
296 catch (std::exception const& e)
297 {
298 return make_exceptional_future<Uploader::SPtr>(ResourceException(QString("Folder::create_file: ") + e.what(),
299 errno));
300 }266 }
301}267}
302268
303269
=== modified file 'src/qt/client/internal/local_client/ItemImpl.cpp'
--- src/qt/client/internal/local_client/ItemImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/local_client/ItemImpl.cpp 2016-08-03 06:10:39 +0000
@@ -21,11 +21,12 @@
21#include <unity/storage/internal/safe_strerror.h>21#include <unity/storage/internal/safe_strerror.h>
22#include <unity/storage/qt/client/Account.h>22#include <unity/storage/qt/client/Account.h>
23#include <unity/storage/qt/client/Exceptions.h>23#include <unity/storage/qt/client/Exceptions.h>
24#include <unity/storage/qt/client/internal/make_future.h>
25#include <unity/storage/qt/client/internal/local_client/AccountImpl.h>24#include <unity/storage/qt/client/internal/local_client/AccountImpl.h>
26#include <unity/storage/qt/client/internal/local_client/FileImpl.h>25#include <unity/storage/qt/client/internal/local_client/FileImpl.h>
27#include <unity/storage/qt/client/internal/local_client/RootImpl.h>26#include <unity/storage/qt/client/internal/local_client/RootImpl.h>
28#include <unity/storage/qt/client/internal/local_client/tmpfile-prefix.h>27#include <unity/storage/qt/client/internal/local_client/storage_exception.h>
28#include <unity/storage/qt/client/internal/local_client/tmpfile_prefix.h>
29#include <unity/storage/qt/client/internal/make_future.h>
2930
30#include <boost/algorithm/string/predicate.hpp>31#include <boost/algorithm/string/predicate.hpp>
31#pragma GCC diagnostic push32#pragma GCC diagnostic push
@@ -54,7 +55,6 @@
5455
55ItemImpl::ItemImpl(QString const& identity, ItemType type)56ItemImpl::ItemImpl(QString const& identity, ItemType type)
56 : ItemBase(identity, type)57 : ItemBase(identity, type)
57 , deleted_(false)
58{58{
59 assert(!identity.isEmpty());59 assert(!identity.isEmpty());
60 auto path = boost::filesystem::canonical(identity.toStdString());60 auto path = boost::filesystem::canonical(identity.toStdString());
@@ -66,87 +66,49 @@
6666
67QString ItemImpl::etag() const67QString ItemImpl::etag() const
68{68{
69 lock_guard<mutex> guard(mutex_);69 lock_guard<decltype(mutex_)> guard(mutex_);
7070
71 if (deleted_)71 throw_if_destroyed("Item::etag()");
72 {
73 throw deleted_ex("Item::etag()");
74 }
75 if (!get_root())
76 {
77 throw RuntimeDestroyedException("Item::etag()");
78 }
79 return etag_;72 return etag_;
80}73}
8174
82QVariantMap ItemImpl::metadata() const75QVariantMap ItemImpl::metadata() const
83{76{
84 lock_guard<mutex> guard(mutex_);77 lock_guard<decltype(mutex_)> guard(mutex_);
8578
86 if (deleted_)79 throw_if_destroyed("Item::metadata()");
87 {
88 throw deleted_ex("Item::metadata()");
89 }
90 if (!get_root())
91 {
92 throw RuntimeDestroyedException("Item::metadata()");
93 }
94 return metadata_;80 return metadata_;
95}81}
9682
97QDateTime ItemImpl::last_modified_time() const83QDateTime ItemImpl::last_modified_time() const
98{84{
99 lock_guard<mutex> guard(mutex_);85 lock_guard<decltype(mutex_)> guard(mutex_);
10086
101 if (deleted_)87 throw_if_destroyed("Item::last_modified_time()");
102 {
103 throw deleted_ex("Item::last_modified_time()");
104 }
105 if (!get_root())
106 {
107 throw RuntimeDestroyedException("Item::last_modified_time()");
108 }
109 return modified_time_;88 return modified_time_;
110}89}
11190
112namespace
113{
114
115using namespace boost::filesystem;
116
117void copy_recursively(path const& source, path const& target)
118{
119 auto s = status(source);
120 if (is_regular_file(s))
121 {
122 copy_file(source, target);
123 return;
124 }
125 else if (is_directory(s))
126 {
127 copy_directory(source, target); // Poorly named in boost; this creates the target dir without recursion
128 for (directory_iterator it(source); it != directory_iterator(); ++it)
129 {
130 path source_entry = it->path();
131 path target_entry = target;
132 target_entry /= source_entry.filename();
133 copy_recursively(source_entry, target_entry);
134 }
135 }
136 else
137 {
138 // Ignore everything that's not a directory or file.
139 }
140}
141
142} // namespace
143
144QFuture<shared_ptr<Item>> ItemImpl::copy(shared_ptr<Folder> const& new_parent, QString const& new_name)91QFuture<shared_ptr<Item>> ItemImpl::copy(shared_ptr<Folder> const& new_parent, QString const& new_name)
145{92{
146 if (!new_parent)93 if (!new_parent)
147 {94 {
148 QString msg = "Item::copy(): new_parent cannot be nullptr";95 QString msg = "Item::copy(): new_parent cannot be nullptr";
149 return make_exceptional_future<shared_ptr<Item>>(InvalidArgumentException(msg));96 return internal::make_exceptional_future<shared_ptr<Item>>(InvalidArgumentException(msg));
97 }
98 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
99
100 lock(mutex_, new_parent_impl->mutex_);
101 lock_guard<decltype(mutex_)> this_guard(mutex_, std::adopt_lock);
102 lock_guard<decltype(mutex_)> other_guard(new_parent_impl->mutex_, adopt_lock);
103
104 try
105 {
106 throw_if_destroyed("Item::copy()");
107 new_parent_impl->throw_if_destroyed("Item::copy()");
108 }
109 catch (StorageException const& e)
110 {
111 return internal::make_exceptional_future<shared_ptr<Item>>(e);
150 }112 }
151113
152 auto This = dynamic_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.114 auto This = dynamic_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.
@@ -155,23 +117,17 @@
155 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);117 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
156118
157 lock(This->mutex_, new_parent_impl->mutex_);119 lock(This->mutex_, new_parent_impl->mutex_);
158 lock_guard<mutex> this_guard(This->mutex_, std::adopt_lock);120 lock_guard<decltype(mutex_)> this_guard(This->mutex_, std::adopt_lock);
159 lock_guard<mutex> other_guard(new_parent_impl->mutex_, adopt_lock);121 lock_guard<decltype(mutex_)> other_guard(new_parent_impl->mutex_, adopt_lock);
160122
161 if (This->deleted_)123 This->throw_if_destroyed("Item::copy()");
162 {124 new_parent_impl->throw_if_destroyed("Item::copy()");
163 throw This->deleted_ex("Item::copy()");
164 }
165 if (new_parent_impl->deleted_)
166 {
167 throw new_parent_impl->deleted_ex("Item::copy()");
168 }
169125
170 // TODO: This needs to deeply compare account identity because the client may have refreshed the accounts list.126 // TODO: This needs to deeply compare account identity because the client may have refreshed the accounts list.
171 if (This->root()->account() != new_parent->root()->account()) // Throws if account or runtime were destroyed.127 if (This->root()->account() != new_parent->root()->account()) // Throws if account or runtime were destroyed.
172 {128 {
173 // Can't do cross-account copy.129 // Can't do cross-account copy.
174 QString msg = QString("Item::copy(): Source (") + This->name_ + ") and target ("130 QString msg = QString("Item::copy(): source (") + This->name_ + ") and target ("
175 + new_name + ") must belong to the same account";131 + new_name + ") must belong to the same account";
176 throw LogicException(msg);132 throw LogicException(msg);
177 }133 }
@@ -187,22 +143,22 @@
187 target_path /= sanitized_name;143 target_path /= sanitized_name;
188 if (is_reserved_path(target_path))144 if (is_reserved_path(target_path))
189 {145 {
190 QString msg = "Item::copy(): names beginning with " + QString(TMPFILE_PREFIX) + " are reserved";146 QString msg = "Item::copy(): names beginning with \"" + QString(TMPFILE_PREFIX) + "\" are reserved";
191 throw InvalidArgumentException(msg);147 throw InvalidArgumentException(msg);
192 }148 }
193149
150 if (exists(target_path))
151 {
152 QString msg = "Item::copy(): item with name \"" + new_name + "\" exists already";
153 throw ExistsException(msg, This->identity_, This->name_);
154 }
155
194 if (This->type_ == ItemType::file)156 if (This->type_ == ItemType::file)
195 {157 {
196 copy_file(source_path, target_path);158 copy_file(source_path, target_path);
197 return FileImpl::make_file(QString::fromStdString(target_path.native()), new_parent_impl->root_);159 return FileImpl::make_file(QString::fromStdString(target_path.native()), new_parent_impl->root_);
198 }160 }
199161
200 if (exists(target_path))
201 {
202 QString msg = "Item::copy(): item with name \"" + new_name + "\" exists already";
203 throw ExistsException(msg, This->identity_, This->name_);
204 }
205
206 // For recursive copy, we create a temporary directory in lieu of target_path and recursively copy162 // For recursive copy, we create a temporary directory in lieu of target_path and recursively copy
207 // everything into the temporary directory. This ensures that we don't invalidate directory iterators163 // everything into the temporary directory. This ensures that we don't invalidate directory iterators
208 // by creating things while we are iterating, potentially getting trapped in an infinite loop.164 // by creating things while we are iterating, potentially getting trapped in an infinite loop.
@@ -211,7 +167,7 @@
211 create_directories(tmp_path);167 create_directories(tmp_path);
212 for (directory_iterator it(source_path); it != directory_iterator(); ++it)168 for (directory_iterator it(source_path); it != directory_iterator(); ++it)
213 {169 {
214 if (tmp_path.compare(canonical(it->path())) == 0)170 if (is_reserved_path(it->path()))
215 {171 {
216 continue; // Don't recurse into the temporary directory172 continue; // Don't recurse into the temporary directory
217 }173 }
@@ -221,23 +177,15 @@
221 path source_entry = it->path();177 path source_entry = it->path();
222 path target_entry = tmp_path;178 path target_entry = tmp_path;
223 target_entry /= source_entry.filename();179 target_entry /= source_entry.filename();
224 copy_recursively(source_entry, target_entry);180 ItemImpl::copy_recursively(source_entry, target_entry);
225 }181 }
226 }182 }
227 rename(tmp_path, target_path);183 rename(tmp_path, target_path);
228 return FolderImpl::make_folder(QString::fromStdString(target_path.native()), new_parent_impl->root_);184 return FolderImpl::make_folder(QString::fromStdString(target_path.native()), new_parent_impl->root_);
229 }185 }
230 catch (StorageException const&)186 catch (std::exception const&)
231 {187 {
232 throw;188 throw_storage_exception("Item::copy()", current_exception());
233 }
234 catch (boost::filesystem::filesystem_error const& e)
235 {
236 throw ResourceException(QString("Item::copy(): ") + e.what(), e.code().value());
237 }
238 catch (std::exception const& e)
239 {
240 throw ResourceException(QString("Item::copy(): ") + e.what(), errno);
241 }189 }
242 };190 };
243 return QtConcurrent::run(copy);191 return QtConcurrent::run(copy);
@@ -248,7 +196,22 @@
248 if (!new_parent)196 if (!new_parent)
249 {197 {
250 QString msg = "Item::move(): new_parent cannot be nullptr";198 QString msg = "Item::move(): new_parent cannot be nullptr";
251 return make_exceptional_future<shared_ptr<Item>>(InvalidArgumentException(msg));199 return internal::make_exceptional_future<shared_ptr<Item>>(InvalidArgumentException(msg));
200 }
201 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
202
203 lock(mutex_, new_parent_impl->mutex_);
204 lock_guard<decltype(mutex_)> this_guard(mutex_, std::adopt_lock);
205 lock_guard<decltype(mutex_)> other_guard(new_parent_impl->mutex_, adopt_lock);
206
207 try
208 {
209 throw_if_destroyed("Item::move()");
210 new_parent_impl->throw_if_destroyed("Item::move()");
211 }
212 catch (StorageException const& e)
213 {
214 return internal::make_exceptional_future<shared_ptr<Item>>(e);
252 }215 }
253216
254 auto This = dynamic_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.217 auto This = dynamic_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.
@@ -257,30 +220,24 @@
257 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);220 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
258221
259 lock(This->mutex_, new_parent_impl->mutex_);222 lock(This->mutex_, new_parent_impl->mutex_);
260 lock_guard<mutex> this_guard(This->mutex_, std::adopt_lock);223 lock_guard<decltype(mutex_)> this_guard(This->mutex_, std::adopt_lock);
261 lock_guard<mutex> other_guard(new_parent_impl->mutex_, adopt_lock);224 lock_guard<decltype(mutex_)> other_guard(new_parent_impl->mutex_, adopt_lock);
262225
263 if (This->deleted_)226 This->throw_if_destroyed("Item::move()");
264 {227 new_parent_impl->throw_if_destroyed("Item::move()");
265 throw This->deleted_ex("Item::move()");
266 }
267 if (new_parent_impl->deleted_)
268 {
269 throw new_parent_impl->deleted_ex("Item::move()");
270 }
271228
272 // TODO: This needs to deeply compare account identity because the client may have refreshed the accounts list.229 // TODO: This needs to deeply compare account identity because the client may have refreshed the accounts list.
273 if (This->root()->account() != new_parent->root()->account()) // Throws if account or runtime were destroyed.230 if (This->root()->account() != new_parent->root()->account()) // Throws if account or runtime were destroyed.
274 {231 {
275 // Can't do cross-account move.232 // Can't do cross-account move.
276 QString msg = QString("Item::move(): Source (") + This->name_ + ") and target ("233 QString msg = QString("Item::move(): source (") + This->name_ + ") and target ("
277 + new_name + ") must belong to the same account";234 + new_name + ") must belong to the same account";
278 throw LogicException(msg);235 throw LogicException(msg);
279 }236 }
280 if (This->type_ == ItemType::root)237 if (This->type_ == ItemType::root)
281 {238 {
282 // Can't move a root.239 // Can't move a root.
283 throw LogicException("Item::move(): Cannot move root folder");240 throw LogicException("Item::move(): cannot move root folder");
284 }241 }
285242
286 try243 try
@@ -296,7 +253,7 @@
296 }253 }
297 if (is_reserved_path(target_path))254 if (is_reserved_path(target_path))
298 {255 {
299 QString msg = "Item::move(): names beginning with " + QString(TMPFILE_PREFIX) + " are reserved";256 QString msg = "Item::move(): names beginning with \"" + QString(TMPFILE_PREFIX) + "\" are reserved";
300 throw InvalidArgumentException(msg);257 throw InvalidArgumentException(msg);
301 }258 }
302 rename(This->native_identity().toStdString(), target_path);259 rename(This->native_identity().toStdString(), target_path);
@@ -307,17 +264,9 @@
307 }264 }
308 return FileImpl::make_file(QString::fromStdString(target_path.native()), new_parent_impl->root_);265 return FileImpl::make_file(QString::fromStdString(target_path.native()), new_parent_impl->root_);
309 }266 }
310 catch (StorageException const&)267 catch (std::exception const&)
311 {268 {
312 throw;269 throw_storage_exception(QString("Item::move(): "), current_exception());
313 }
314 catch (boost::filesystem::filesystem_error const& e)
315 {
316 throw ResourceException(QString("Item::move(): ") + e.what(), e.code().value());
317 }
318 catch (std::exception const& e)
319 {
320 throw ResourceException(QString("Item::move(): ") + e.what(), errno);
321 }270 }
322 };271 };
323 return QtConcurrent::run(move);272 return QtConcurrent::run(move);
@@ -325,18 +274,15 @@
325274
326QFuture<QVector<Folder::SPtr>> ItemImpl::parents() const275QFuture<QVector<Folder::SPtr>> ItemImpl::parents() const
327{276{
328 lock_guard<mutex> guard(mutex_);277 lock_guard<decltype(mutex_)> guard(mutex_);
329278
330 QFutureInterface<QVector<Folder::SPtr>> qf;279 try
331 if (deleted_)
332 {280 {
333 return make_exceptional_future<QVector<Folder::SPtr>>(deleted_ex("Item::parents()"));281 throw_if_destroyed("Item::parents()");
334 }282 }
335283 catch (StorageException const& e)
336 auto root = get_root();
337 if (!root)
338 {284 {
339 return make_exceptional_future<QVector<Folder::SPtr>>(RuntimeDestroyedException("Item::parents()"));285 return internal::make_exceptional_future<QVector<Folder::SPtr>>(e);
340 }286 }
341287
342 using namespace boost::filesystem;288 using namespace boost::filesystem;
@@ -345,6 +291,7 @@
345 path p = native_identity().toStdString();291 path p = native_identity().toStdString();
346 QString parent_path = QString::fromStdString(p.parent_path().native());292 QString parent_path = QString::fromStdString(p.parent_path().native());
347293
294 auto root = root_.lock();
348 QVector<Folder::SPtr> results;295 QVector<Folder::SPtr> results;
349 if (parent_path != root->native_identity())296 if (parent_path != root->native_identity())
350 {297 {
@@ -359,16 +306,9 @@
359306
360QVector<QString> ItemImpl::parent_ids() const307QVector<QString> ItemImpl::parent_ids() const
361{308{
362 lock_guard<mutex> guard(mutex_);309 lock_guard<decltype(mutex_)> guard(mutex_);
363310
364 if (deleted_)311 throw_if_destroyed("Item::parent_ids()");
365 {
366 throw deleted_ex("Item::parent_ids()");
367 }
368 if (!get_root())
369 {
370 throw RuntimeDestroyedException("Item::parent_ids()");
371 }
372312
373 using namespace boost::filesystem;313 using namespace boost::filesystem;
374314
@@ -383,36 +323,31 @@
383323
384QFuture<void> ItemImpl::delete_item()324QFuture<void> ItemImpl::delete_item()
385{325{
326 lock_guard<decltype(mutex_)> guard(mutex_);
327
328 try
329 {
330 throw_if_destroyed("Item::delete_item()");
331 }
332 catch (StorageException const& e)
333 {
334 return internal::make_exceptional_future(e);
335 }
336
386 auto This = dynamic_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.337 auto This = dynamic_pointer_cast<ItemImpl>(shared_from_this()); // Keep this item alive while the lambda is alive.
387 auto destroy = [This]()338 auto destroy = [This]()
388 {339 {
389 lock_guard<mutex> guard(This->mutex_);340 lock_guard<decltype(mutex_)> guard(This->mutex_);
390341
391 if (This->deleted_)342 This->throw_if_destroyed("Item::delete_item()");
392 {
393 throw This->deleted_ex("Item::delete_item()");
394 }
395 if (!This->get_root())
396 {
397 throw RuntimeDestroyedException("Item::delete_item()");
398 }
399
400 try343 try
401 {344 {
402 boost::filesystem::remove_all(This->native_identity().toStdString());345 boost::filesystem::remove_all(This->native_identity().toStdString());
403 This->deleted_ = true;346 This->deleted_ = true;
404 }347 }
405 catch (StorageException const&)348 catch (std::exception const&)
406 {349 {
407 throw;350 throw_storage_exception(QString("Item::delete_item()"), current_exception());
408 }
409 catch (boost::filesystem::filesystem_error const& e)
410 {
411 throw ResourceException(QString("Item::delete_item(): ") + e.what(), e.code().value());
412 }
413 catch (std::exception const& e)
414 {
415 throw ResourceException(QString("Item::delete_item(): ") + e.what(), errno);
416 }351 }
417 };352 };
418 return QtConcurrent::run(destroy);353 return QtConcurrent::run(destroy);
@@ -420,11 +355,17 @@
420355
421QDateTime ItemImpl::creation_time() const356QDateTime ItemImpl::creation_time() const
422{357{
358 lock_guard<decltype(mutex_)> guard(mutex_);
359
360 throw_if_destroyed("Item::creation_time()");
423 return QDateTime();361 return QDateTime();
424}362}
425363
426MetadataMap ItemImpl::native_metadata() const364MetadataMap ItemImpl::native_metadata() const
427{365{
366 lock_guard<decltype(mutex_)> guard(mutex_);
367
368 throw_if_destroyed("Item::native_metadata()");
428 return MetadataMap();369 return MetadataMap();
429}370}
430371
@@ -438,8 +379,8 @@
438 }379 }
439380
440 lock(mutex_, other_impl->mutex_);381 lock(mutex_, other_impl->mutex_);
441 lock_guard<mutex> this_guard(mutex_, std::adopt_lock);382 lock_guard<decltype(mutex_)> this_guard(mutex_, std::adopt_lock);
442 lock_guard<mutex> other_guard(other_impl->mutex_, adopt_lock);383 lock_guard<decltype(mutex_)> other_guard(other_impl->mutex_, adopt_lock);
443384
444 if (deleted_ || other_impl->deleted_)385 if (deleted_ || other_impl->deleted_)
445 {386 {
@@ -450,7 +391,7 @@
450391
451void ItemImpl::set_timestamps() noexcept392void ItemImpl::set_timestamps() noexcept
452{393{
453 lock_guard<mutex> guard(mutex_);394 lock_guard<decltype(mutex_)> guard(mutex_);
454395
455 string id = identity_.toStdString();396 string id = identity_.toStdString();
456 // Use nano-second resolution for the ETag, if the file system supports it.397 // Use nano-second resolution for the ETag, if the file system supports it.
@@ -467,7 +408,7 @@
467408
468bool ItemImpl::has_conflict() const noexcept409bool ItemImpl::has_conflict() const noexcept
469{410{
470 lock_guard<mutex> guard(mutex_);411 lock_guard<decltype(mutex_)> guard(mutex_);
471412
472 string id = identity_.toStdString();413 string id = identity_.toStdString();
473 struct stat st;414 struct stat st;
@@ -515,10 +456,35 @@
515 return boost::starts_with(filename, TMPFILE_PREFIX);456 return boost::starts_with(filename, TMPFILE_PREFIX);
516}457}
517458
518DeletedException ItemImpl::deleted_ex(QString const& method) const noexcept459void ItemImpl::copy_recursively(boost::filesystem::path const& source, boost::filesystem::path const& target)
519{460{
520 QString msg = method + ": \"" + identity_ + "\" was deleted previously";461 using namespace boost::filesystem;
521 return DeletedException(msg, identity_, name_);462
463 if (is_reserved_path(source))
464 {
465 return; // Don't copy temporary directories.
466 }
467
468 auto s = status(source);
469 if (is_regular_file(s))
470 {
471 copy_file(source, target);
472 }
473 else if (is_directory(s))
474 {
475 copy_directory(source, target); // Poorly named in boost; this creates the target dir without recursion
476 for (directory_iterator it(source); it != directory_iterator(); ++it)
477 {
478 path source_entry = it->path();
479 path target_entry = target;
480 target_entry /= source_entry.filename();
481 copy_recursively(source_entry, target_entry);
482 }
483 }
484 else
485 {
486 // Ignore everything that's not a directory or file.
487 }
522}488}
523489
524} // namespace local_client490} // namespace local_client
525491
=== modified file 'src/qt/client/internal/local_client/RootImpl.cpp'
--- src/qt/client/internal/local_client/RootImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/local_client/RootImpl.cpp 2016-08-03 06:10:39 +0000
@@ -21,6 +21,7 @@
21#include <unity/storage/qt/client/Exceptions.h>21#include <unity/storage/qt/client/Exceptions.h>
22#include <unity/storage/qt/client/internal/make_future.h>22#include <unity/storage/qt/client/internal/make_future.h>
23#include <unity/storage/qt/client/internal/local_client/FileImpl.h>23#include <unity/storage/qt/client/internal/local_client/FileImpl.h>
24#include <unity/storage/qt/client/internal/local_client/storage_exception.h>
24#include <unity/storage/qt/client/Root.h>25#include <unity/storage/qt/client/Root.h>
2526
26using namespace std;27using namespace std;
@@ -68,46 +69,55 @@
6869
69QString RootImpl::name() const70QString RootImpl::name() const
70{71{
71 if (!get_root())72 lock_guard<decltype(mutex_)> guard(mutex_);
72 {73
73 throw RuntimeDestroyedException("Root::name()");74 throw_if_destroyed("Root::name()");
74 }
75 return "";75 return "";
76}76}
7777
78QFuture<QVector<Folder::SPtr>> RootImpl::parents() const78QFuture<QVector<Folder::SPtr>> RootImpl::parents() const
79{79{
80 if (!get_root())80 lock_guard<decltype(mutex_)> guard(mutex_);
81 {81
82 throw RuntimeDestroyedException("Root::parents()");82 throw_if_destroyed("Root::parents()");
83 }
84 return make_ready_future(QVector<Folder::SPtr>()); // For the root, we return an empty vector.83 return make_ready_future(QVector<Folder::SPtr>()); // For the root, we return an empty vector.
85}84}
8685
87QVector<QString> RootImpl::parent_ids() const86QVector<QString> RootImpl::parent_ids() const
88{87{
89 if (!get_root())88 lock_guard<decltype(mutex_)> guard(mutex_);
90 {89
91 throw RuntimeDestroyedException("Root::parent_ids()");90 throw_if_destroyed("Root::parent_ids()");
92 }
93 return QVector<QString>(); // For the root, we return an empty vector.91 return QVector<QString>(); // For the root, we return an empty vector.
94}92}
9593
96QFuture<void> RootImpl::delete_item()94QFuture<void> RootImpl::delete_item()
97{95{
98 if (!get_root())96 lock_guard<decltype(mutex_)> guard(mutex_);
99 {97
100 throw RuntimeDestroyedException("Root::delete_item()");98 try
99 {
100 throw_if_destroyed("Root::delete_item()");
101 }
102 catch (StorageException const& e)
103 {
104 return internal::make_exceptional_future(e);
101 }105 }
102 // Cannot delete root.106 // Cannot delete root.
103 return make_exceptional_future(LogicException("Root::delete_item(): Cannot delete root folder"));107 return internal::make_exceptional_future(LogicException("Root::delete_item(): Cannot delete root folder"));
104}108}
105109
106QFuture<int64_t> RootImpl::free_space_bytes() const110QFuture<int64_t> RootImpl::free_space_bytes() const
107{111{
108 if (!get_root())112 lock_guard<decltype(mutex_)> guard(mutex_);
109 {113
110 throw RuntimeDestroyedException("Root::free_space_bytes()");114 try
115 {
116 throw_if_destroyed("Root::free_space_bytes()");
117 }
118 catch (StorageException const& e)
119 {
120 return internal::make_exceptional_future<int64_t>(e);
111 }121 }
112122
113 using namespace boost::filesystem;123 using namespace boost::filesystem;
@@ -118,24 +128,24 @@
118 return make_ready_future<int64_t>(si.available);128 return make_ready_future<int64_t>(si.available);
119 }129 }
120 // LCOV_EXCL_START130 // LCOV_EXCL_START
121 catch (boost::filesystem::filesystem_error const& e)131 catch (std::exception const&)
122 {132 {
123 return make_exceptional_future<int64_t>(ResourceException(QString("Root::free_space_bytes(): ") + e.what(),133 return make_exceptional_future<int64_t>(QString("Root::free_space_bytes()"), current_exception());
124 e.code().value()));
125 }
126 catch (std::exception const& e)
127 {
128 return make_exceptional_future<int64_t>(ResourceException(QString("Root::free_space_bytes(): ") + e.what(),
129 errno));
130 }134 }
131 // LCOV_EXCL_STOP135 // LCOV_EXCL_STOP
132}136}
133137
134QFuture<int64_t> RootImpl::used_space_bytes() const138QFuture<int64_t> RootImpl::used_space_bytes() const
135{139{
136 if (!get_root())140 lock_guard<decltype(mutex_)> guard(mutex_);
137 {141
138 throw RuntimeDestroyedException("Root::used_space_bytes()");142 try
143 {
144 throw_if_destroyed("Root::used_space_bytes()");
145 }
146 catch (StorageException const& e)
147 {
148 return internal::make_exceptional_future<int64_t>(e);
139 }149 }
140150
141 using namespace boost::filesystem;151 using namespace boost::filesystem;
@@ -146,25 +156,30 @@
146 return make_ready_future<int64_t>(si.capacity - si.available);156 return make_ready_future<int64_t>(si.capacity - si.available);
147 }157 }
148 // LCOV_EXCL_START158 // LCOV_EXCL_START
149 catch (boost::filesystem::filesystem_error const& e)159 catch (std::exception const&)
150 {160 {
151 return make_exceptional_future<int64_t>(ResourceException(QString("Root::used_space_bytes(): ") + e.what(),161 return make_exceptional_future<int64_t>(QString("Root::used_space_bytes()"), current_exception());
152 e.code().value()));
153 }
154 catch (std::exception const& e)
155 {
156 return make_exceptional_future<int64_t>(ResourceException(QString("Root::used_space_bytes(): ") + e.what(),
157 errno));
158 }162 }
159 // LCOV_EXCL_STOP163 // LCOV_EXCL_STOP
160}164}
161165
162QFuture<Item::SPtr> RootImpl::get(QString native_identity) const166QFuture<Item::SPtr> RootImpl::get(QString native_identity) const
163{167{
168 lock_guard<decltype(mutex_)> guard(mutex_);
169
170 try
171 {
172 throw_if_destroyed("Root::get()");
173 }
174 catch (StorageException const& e)
175 {
176 return internal::make_exceptional_future<Item::SPtr>(e);
177 }
178
164 auto root = get_root();179 auto root = get_root();
165 if (!root)180 if (!root)
166 {181 {
167 throw RuntimeDestroyedException("Root::native_identity()");182 return internal::make_exceptional_future<Item::SPtr>(RuntimeDestroyedException("Root::get()"));
168 }183 }
169184
170 using namespace boost::filesystem;185 using namespace boost::filesystem;
@@ -176,7 +191,7 @@
176 if (!id_path.is_absolute())191 if (!id_path.is_absolute())
177 {192 {
178 QString msg = "Root::get(): identity \"" + native_identity + "\" must be an absolute path";193 QString msg = "Root::get(): identity \"" + native_identity + "\" must be an absolute path";
179 return make_exceptional_future<Item::SPtr>(InvalidArgumentException(msg));194 throw InvalidArgumentException(msg);
180 }195 }
181196
182 // Make sure that native_identity is contained in or equal to the root path.197 // Make sure that native_identity is contained in or equal to the root path.
@@ -189,14 +204,14 @@
189 // Too few components, or wrong path prefix. Therefore, native_identity can't204 // Too few components, or wrong path prefix. Therefore, native_identity can't
190 // possibly point at something below the root.205 // possibly point at something below the root.
191 QString msg = QString("Root::get(): identity \"") + native_identity + "\" points outside the root folder";206 QString msg = QString("Root::get(): identity \"") + native_identity + "\" points outside the root folder";
192 return make_exceptional_future<Item::SPtr>(InvalidArgumentException(msg));207 throw InvalidArgumentException(msg);
193 }208 }
194209
195 // Don't allow reserved files to be found.210 // Don't allow reserved files to be found.
196 if (is_reserved_path(id_path))211 if (is_reserved_path(id_path))
197 {212 {
198 QString msg = "Root::get(): no such item: " + native_identity;213 QString msg = "Root::get(): no such item: \"" + native_identity + "\"";
199 return make_exceptional_future<Item::SPtr>(NotExistsException(msg, native_identity));214 throw NotExistsException(msg, native_identity);
200 }215 }
201216
202 file_status s = status(id_path);217 file_status s = status(id_path);
@@ -213,23 +228,13 @@
213 {228 {
214 return make_ready_future<Item::SPtr>(FileImpl::make_file(path, root));229 return make_ready_future<Item::SPtr>(FileImpl::make_file(path, root));
215 }230 }
216 QString msg = "Root::get(): no such item: " + native_identity;231 QString msg = "Root::get(): no such item: \"" + native_identity + "\"";
217 return make_exceptional_future<Item::SPtr>(NotExistsException(msg, native_identity));232 throw NotExistsException(msg, native_identity);
218 }233 }
219 catch (StorageException const& e)234 catch (std::exception const&)
220 {235 {
221 return make_exceptional_future<Item::SPtr>(e);236 return make_exceptional_future<Item::SPtr>(QString("Root::get()"), current_exception(), native_identity);
222 }237 }
223 catch (boost::filesystem::filesystem_error const& e)
224 {
225 return make_exceptional_future<Item::SPtr>(QString("Root::get(): ") + e.what(), e, native_identity);
226 }
227 // LCOV_EXCL_START
228 catch (std::exception const& e)
229 {
230 return make_exceptional_future<Item::SPtr>(ResourceException(QString("Root::get(): ") + e.what(), errno));
231 }
232 // LCOV_EXCL_STOP
233}238}
234239
235Root::SPtr RootImpl::make_root(QString const& identity, std::weak_ptr<Account> const& account)240Root::SPtr RootImpl::make_root(QString const& identity, std::weak_ptr<Account> const& account)
236241
=== modified file 'src/qt/client/internal/local_client/RuntimeImpl.cpp'
--- src/qt/client/internal/local_client/RuntimeImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/local_client/RuntimeImpl.cpp 2016-08-03 06:10:39 +0000
@@ -19,6 +19,7 @@
19#include <unity/storage/qt/client/internal/local_client/RuntimeImpl.h>19#include <unity/storage/qt/client/internal/local_client/RuntimeImpl.h>
2020
21#include <unity/storage/qt/client/Account.h>21#include <unity/storage/qt/client/Account.h>
22#include <unity/storage/qt/client/Exceptions.h>
22#include <unity/storage/qt/client/internal/make_future.h>23#include <unity/storage/qt/client/internal/make_future.h>
23#include <unity/storage/qt/client/internal/local_client/AccountImpl.h>24#include <unity/storage/qt/client/internal/local_client/AccountImpl.h>
2425
2526
=== modified file 'src/qt/client/internal/local_client/UploaderImpl.cpp'
--- src/qt/client/internal/local_client/UploaderImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/local_client/UploaderImpl.cpp 2016-08-03 06:10:39 +0000
@@ -22,7 +22,7 @@
22#include <unity/storage/qt/client/Exceptions.h>22#include <unity/storage/qt/client/Exceptions.h>
23#include <unity/storage/qt/client/File.h>23#include <unity/storage/qt/client/File.h>
24#include <unity/storage/qt/client/internal/local_client/FileImpl.h>24#include <unity/storage/qt/client/internal/local_client/FileImpl.h>
25#include <unity/storage/qt/client/internal/local_client/tmpfile-prefix.h>25#include <unity/storage/qt/client/internal/local_client/tmpfile_prefix.h>
26#include <unity/storage/qt/client/internal/make_future.h>26#include <unity/storage/qt/client/internal/make_future.h>
2727
28#include <QLocalSocket>28#include <QLocalSocket>
@@ -93,8 +93,6 @@
93 // Monitor read socket for ready-to-read, disconnected, and error events.93 // Monitor read socket for ready-to-read, disconnected, and error events.
94 connect(read_socket_.get(), &QLocalSocket::readyRead, this, &UploadWorker::on_bytes_ready);94 connect(read_socket_.get(), &QLocalSocket::readyRead, this, &UploadWorker::on_bytes_ready);
95 connect(read_socket_.get(), &QIODevice::readChannelFinished, this, &UploadWorker::on_read_channel_finished);95 connect(read_socket_.get(), &QIODevice::readChannelFinished, this, &UploadWorker::on_read_channel_finished);
96 connect(read_socket_.get(), static_cast<void(QLocalSocket::*)(QLocalSocket::LocalSocketError)>(&QLocalSocket::error),
97 this, &UploadWorker::on_error);
9896
99 using namespace boost::filesystem;97 using namespace boost::filesystem;
10098
@@ -114,10 +112,11 @@
114 tmp_fd_.reset(mkstemp(const_cast<char*>(tmpfile.data())));112 tmp_fd_.reset(mkstemp(const_cast<char*>(tmpfile.data())));
115 if (tmp_fd_.get() == -1)113 if (tmp_fd_.get() == -1)
116 {114 {
115 int error_code = errno;
117 worker_initialized_.reportFinished();116 worker_initialized_.reportFinished();
118 QString msg = "cannot create temp file \"" + QString::fromStdString(tmpfile)117 QString msg = "cannot create temp file \"" + QString::fromStdString(tmpfile)
119 + "\": " + QString::fromStdString(storage::internal::safe_strerror(errno));118 + "\": " + QString::fromStdString(storage::internal::safe_strerror(errno));
120 handle_error(msg);119 handle_error(msg, error_code);
121 return;120 return;
122 }121 }
123 output_file_.reset(new QFile(QString::fromStdString(tmpfile)));122 output_file_.reset(new QFile(QString::fromStdString(tmpfile)));
@@ -140,11 +139,6 @@
140139
141void UploadWorker::do_finish()140void UploadWorker::do_finish()
142{141{
143 if (qf_.future().isFinished())
144 {
145 return; // Future was set previously, no point in continuing.
146 }
147
148 switch (state_)142 switch (state_)
149 {143 {
150 case in_progress:144 case in_progress:
@@ -165,8 +159,10 @@
165 }159 }
166 case error:160 case error:
167 {161 {
162 // LCOV_EXCL_START
168 make_exceptional_future(qf_, ResourceException(error_msg_, error_code_));163 make_exceptional_future(qf_, ResourceException(error_msg_, error_code_));
169 break;164 break;
165 // LCOV_EXCL_STOP
170 }166 }
171 default:167 default:
172 {168 {
@@ -201,23 +197,15 @@
201 auto bytes_written = output_file_->write(buf);197 auto bytes_written = output_file_->write(buf);
202 if (bytes_written == -1)198 if (bytes_written == -1)
203 {199 {
204<<<<<<< TREE200 handle_error("socket error: " + output_file_->errorString(), output_file_->error()); // LCOV_EXCL_LINE
205 handle_error("socket error: " + output_file_->errorString()); // LCOV_EXCL_LINE
206=======
207 handle_error("socket error: " + output_file_->errorString(), output_file_->error());
208>>>>>>> MERGE-SOURCE
209 }201 }
210 else if (bytes_written != buf.size())202 else if (bytes_written != buf.size())
211 {203 {
212 // LCOV_EXCL_START204 // LCOV_EXCL_START
213 QString msg = "write error, requested " + QString::number(buf.size()) + " B, but wrote only "205 QString msg = "write error, requested " + QString::number(buf.size()) + " B, but wrote only "
214 + bytes_written + " B.";206 + bytes_written + " B.";
215<<<<<<< TREE
216 handle_error(msg);
217 // LCOV_EXCL_STOP
218=======
219 handle_error(msg, 0);207 handle_error(msg, 0);
220>>>>>>> MERGE-SOURCE208 // LCOV_EXCL_STOP
221 }209 }
222 }210 }
223}211}
@@ -228,11 +216,6 @@
228 do_finish();216 do_finish();
229}217}
230218
231void UploadWorker::on_error()
232{
233 handle_error(read_socket_->errorString(), read_socket_->error());
234}
235
236void UploadWorker::finalize()219void UploadWorker::finalize()
237{220{
238 auto file = file_.lock();221 auto file = file_.lock();
@@ -287,7 +270,6 @@
287 }270 }
288271
289 // Link the anonymous tmp file into the file system.272 // Link the anonymous tmp file into the file system.
290<<<<<<< TREE
291 auto new_path = file->native_identity().toStdString();273 auto new_path = file->native_identity().toStdString();
292 if (use_linkat_)274 if (use_linkat_)
293 {275 {
@@ -296,11 +278,12 @@
296 if (linkat(-1, old_path.c_str(), tmp_fd_.get(), new_path.c_str(), AT_SYMLINK_FOLLOW) == -1)278 if (linkat(-1, old_path.c_str(), tmp_fd_.get(), new_path.c_str(), AT_SYMLINK_FOLLOW) == -1)
297 {279 {
298 // LCOV_EXCL_START280 // LCOV_EXCL_START
281 int error_code = errno;
299 state_ = error;282 state_ = error;
300 QString msg = "Uploader::finish_upload(): linkat \"" + QString::fromStdString(old_path)283 QString msg = "Uploader::finish_upload(): linkat \"" + QString::fromStdString(old_path)
301 + "\" to \"" + file->native_identity() + "\" failed: "284 + "\" to \"" + file->native_identity() + "\" failed: "
302 + QString::fromStdString(storage::internal::safe_strerror(errno));285 + QString::fromStdString(storage::internal::safe_strerror(errno));
303 make_exceptional_future(qf_, ResourceException(msg));286 make_exceptional_future(qf_, ResourceException(msg, error_code));
304 return;287 return;
305 // LCOV_EXCL_STOP288 // LCOV_EXCL_STOP
306 }289 }
@@ -311,26 +294,15 @@
311 auto old_path = output_file_->fileName().toStdString();294 auto old_path = output_file_->fileName().toStdString();
312 if (rename(old_path.c_str(), new_path.c_str()) == -1)295 if (rename(old_path.c_str(), new_path.c_str()) == -1)
313 {296 {
297 int error_code = errno;
314 state_ = error;298 state_ = error;
315 QString msg = "Uploader::finish_upload(): rename \"" + QString::fromStdString(old_path)299 QString msg = "Uploader::finish_upload(): rename \"" + QString::fromStdString(old_path)
316 + "\" to \"" + file->native_identity() + "\" failed: "300 + "\" to \"" + file->native_identity() + "\" failed: "
317 + QString::fromStdString(storage::internal::safe_strerror(errno));301 + QString::fromStdString(storage::internal::safe_strerror(errno));
318 make_exceptional_future(qf_, ResourceException(msg));302 make_exceptional_future(qf_, ResourceException(msg, error_code));
319 return;303 return;
320 }304 }
321 // LCOV_EXCL_STOP305 // LCOV_EXCL_STOP
322=======
323 string oldpath = string("/proc/self/fd/") + std::to_string(tmp_fd_.get());
324 string newpath = file->native_identity().toStdString();
325 ::unlink(newpath.c_str()); // linkat() will not remove existing file: http://lwn.net/Articles/559969/
326 if (linkat(-1, oldpath.c_str(), tmp_fd_.get(), newpath.c_str(), AT_SYMLINK_FOLLOW) == -1)
327 {
328 state_ = error;
329 QString msg = "Uploader::finish_upload(): linkat \"" + file->native_identity() + "\" failed: "
330 + QString::fromStdString(storage::internal::safe_strerror(errno));
331 make_exceptional_future(qf_, ResourceException(msg, errno));
332 return;
333>>>>>>> MERGE-SOURCE
334 }306 }
335307
336 state_ = finalized;308 state_ = finalized;
@@ -339,6 +311,7 @@
339 make_ready_future(qf_, file);311 make_ready_future(qf_, file);
340}312}
341313
314// LCOV_EXCL_START
342void UploadWorker::handle_error(QString const& msg, int error_code)315void UploadWorker::handle_error(QString const& msg, int error_code)
343{316{
344 if (state_ == in_progress)317 if (state_ == in_progress)
@@ -351,6 +324,7 @@
351 error_code_ = error_code;324 error_code_ = error_code;
352 do_finish();325 do_finish();
353}326}
327// LCOV_EXCL_STOP
354328
355UploadThread::UploadThread(UploadWorker* worker)329UploadThread::UploadThread(UploadWorker* worker)
356 : worker_(worker)330 : worker_(worker)
@@ -427,6 +401,7 @@
427 if (write_socket_->state() == QLocalSocket::ConnectedState)401 if (write_socket_->state() == QLocalSocket::ConnectedState)
428 {402 {
429 write_socket_->disconnectFromServer();403 write_socket_->disconnectFromServer();
404 write_socket_->close();
430 }405 }
431 return qf_.future();406 return qf_.future();
432}407}
@@ -434,6 +409,8 @@
434QFuture<void> UploaderImpl::cancel() noexcept409QFuture<void> UploaderImpl::cancel() noexcept
435{410{
436 Q_EMIT do_cancel();411 Q_EMIT do_cancel();
412 upload_thread_->wait();
413 write_socket_->abort();
437 return qf_.future();414 return qf_.future();
438}415}
439416
440417
=== added file 'src/qt/client/internal/local_client/storage_exception.cpp'
--- src/qt/client/internal/local_client/storage_exception.cpp 1970-01-01 00:00:00 +0000
+++ src/qt/client/internal/local_client/storage_exception.cpp 2016-08-03 06:10:39 +0000
@@ -0,0 +1,99 @@
1/*
2 * Copyright (C) 2016 Canonical Ltd
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Michi Henning <michi.henning@canonical.com>
17 */
18
19#include <unity/storage/qt/client/Exceptions.h>
20#include <unity/storage/qt/client/internal/local_client/storage_exception.h>
21
22namespace unity
23{
24namespace storage
25{
26namespace qt
27{
28namespace client
29{
30namespace internal
31{
32namespace local_client
33{
34
35using namespace boost::filesystem;
36
37void throw_storage_exception(QString const& method, std::exception_ptr ep)
38{
39 int error_code = errno;
40 try
41 {
42 std::rethrow_exception(ep);
43 }
44 catch (StorageException const&)
45 {
46 throw;
47 }
48 catch (filesystem_error const& e)
49 {
50 QString msg = method + ": " + e.what();
51 switch (e.code().value())
52 {
53 case EACCES:
54 case EPERM:
55 {
56 throw PermissionException(msg);
57 }
58 case EDQUOT:
59 case ENOSPC:
60 {
61 throw QuotaException(msg); // Too messy to cover with a test case. // LCOV_EXCL_LINE
62 }
63 default:
64 {
65 throw ResourceException(msg, e.code().value());
66 }
67 }
68 }
69 // LCOV_EXCL_START
70 catch (std::exception const& e)
71 {
72 QString msg = method + ": " + e.what();
73 throw ResourceException(msg, error_code);
74 }
75 // LCOV_EXCL_STOP
76}
77
78void throw_storage_exception(QString const& method, std::exception_ptr ep, QString const& key)
79{
80 try
81 {
82 std::rethrow_exception(ep);
83 }
84 catch (filesystem_error const& e)
85 {
86 if (e.code().value() == ENOENT)
87 {
88 throw NotExistsException(method + ": " + e.what(), key);
89 }
90 }
91 throw_storage_exception(method, ep);
92}
93
94} // namespace local_client
95} // namespace internal
96} // namespace client
97} // namespace qt
98} // namespace storage
99} // namespace unity
0100
=== modified file 'src/qt/client/internal/remote_client/FileImpl.cpp'
--- src/qt/client/internal/remote_client/FileImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/remote_client/FileImpl.cpp 2016-08-03 06:10:39 +0000
@@ -48,32 +48,25 @@
4848
49int64_t FileImpl::size() const49int64_t FileImpl::size() const
50{50{
51 if (deleted_)51 throw_if_destroyed("File::size()");
52 {
53 throw deleted_ex("File::size()");
54 }
55 if (!get_root())
56 {
57 throw RuntimeDestroyedException("File::size()");
58 }
59 return 0; // TODO52 return 0; // TODO
60}53}
6154
62QFuture<shared_ptr<Uploader>> FileImpl::create_uploader(ConflictPolicy policy, int64_t size)55QFuture<shared_ptr<Uploader>> FileImpl::create_uploader(ConflictPolicy policy, int64_t size)
63{56{
64 if (deleted_)57 try
65 {58 {
66 return make_exceptional_future<shared_ptr<Uploader>>(deleted_ex("File::create_uploader()"));59 throw_if_destroyed("File::create_uploader()()");
60 }
61 catch (StorageException const& e)
62 {
63 return make_exceptional_future<shared_ptr<Uploader>>(e);
67 }64 }
68 if (size < 0)65 if (size < 0)
69 {66 {
70 QString msg = "File::create_uploader(): size must be >= 0";67 QString msg = "File::create_uploader(): size must be >= 0";
71 return make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));68 return make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));
72 }69 }
73 if (!get_root())
74 {
75 return make_exceptional_future<shared_ptr<Uploader>>(RuntimeDestroyedException("File::create_uploader()"));
76 }
7770
78 QString old_etag = policy == ConflictPolicy::overwrite ? "" : md_.etag;71 QString old_etag = policy == ConflictPolicy::overwrite ? "" : md_.etag;
79 auto prov = provider();72 auto prov = provider();
@@ -108,13 +101,13 @@
108101
109QFuture<shared_ptr<Downloader>> FileImpl::create_downloader()102QFuture<shared_ptr<Downloader>> FileImpl::create_downloader()
110{103{
111 if (deleted_)104 try
112 {105 {
113 return make_exceptional_future<shared_ptr<Downloader>>(deleted_ex("File::create_downloader()"));106 throw_if_destroyed("File::create_downloader()()");
114 }107 }
115 if (!get_root())108 catch (StorageException const& e)
116 {109 {
117 return make_exceptional_future<shared_ptr<Downloader>>(RuntimeDestroyedException("File::create_downloader()"));110 return make_exceptional_future<shared_ptr<Downloader>>(e);
118 }111 }
119112
120 auto prov = provider();113 auto prov = provider();
121114
=== modified file 'src/qt/client/internal/remote_client/FolderImpl.cpp'
--- src/qt/client/internal/remote_client/FolderImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/remote_client/FolderImpl.cpp 2016-08-03 06:10:39 +0000
@@ -57,13 +57,13 @@
5757
58QFuture<QVector<shared_ptr<Item>>> FolderImpl::list() const58QFuture<QVector<shared_ptr<Item>>> FolderImpl::list() const
59{59{
60 if (deleted_)60 try
61 {61 {
62 return make_exceptional_future<QVector<shared_ptr<Item>>>(deleted_ex("Folder::list()"));62 throw_if_destroyed("Folder::list()");
63 }63 }
64 if (!get_root())64 catch (StorageException const& e)
65 {65 {
66 return make_exceptional_future<QVector<shared_ptr<Item>>>(RuntimeDestroyedException("Folder::list()"));66 return make_exceptional_future<QVector<shared_ptr<Item>>>(e);
67 }67 }
6868
69 auto prov = provider();69 auto prov = provider();
@@ -117,13 +117,13 @@
117117
118QFuture<QVector<shared_ptr<Item>>> FolderImpl::lookup(QString const& name) const118QFuture<QVector<shared_ptr<Item>>> FolderImpl::lookup(QString const& name) const
119{119{
120 if (deleted_)120 try
121 {121 {
122 return make_exceptional_future<QVector<shared_ptr<Item>>>(deleted_ex("Folder::lookup()"));122 throw_if_destroyed("Folder::lookup()");
123 }123 }
124 if (!get_root())124 catch (StorageException const& e)
125 {125 {
126 return make_exceptional_future<QVector<shared_ptr<Item>>>(RuntimeDestroyedException("Folder::lookup()"));126 return make_exceptional_future<QVector<shared_ptr<Item>>>(e);
127 }127 }
128128
129 auto prov = provider();129 auto prov = provider();
@@ -163,13 +163,13 @@
163163
164QFuture<shared_ptr<Folder>> FolderImpl::create_folder(QString const& name)164QFuture<shared_ptr<Folder>> FolderImpl::create_folder(QString const& name)
165{165{
166 if (deleted_)166 try
167 {167 {
168 return make_exceptional_future<shared_ptr<Folder>>(deleted_ex("Folder::create_folder()"));168 throw_if_destroyed("Folder::create_folder()");
169 }169 }
170 if (!get_root())170 catch (StorageException const& e)
171 {171 {
172 return make_exceptional_future<shared_ptr<Folder>>(RuntimeDestroyedException("Folder::create_folder()"));172 return make_exceptional_future<shared_ptr<Folder>>(e);
173 }173 }
174174
175 auto prov = provider();175 auto prov = provider();
@@ -203,19 +203,19 @@
203203
204QFuture<shared_ptr<Uploader>> FolderImpl::create_file(QString const& name, int64_t size)204QFuture<shared_ptr<Uploader>> FolderImpl::create_file(QString const& name, int64_t size)
205{205{
206 if (deleted_)206 try
207 {207 {
208 return make_exceptional_future<shared_ptr<Uploader>>(deleted_ex("Folder::create_file()"));208 throw_if_destroyed("Folder::create_file()");
209 }
210 catch (StorageException const& e)
211 {
212 return make_exceptional_future<shared_ptr<Uploader>>(e);
209 }213 }
210 if (size < 0)214 if (size < 0)
211 {215 {
212 QString msg = "Folder::create_file(): size must be >= 0";216 QString msg = "Folder::create_file(): size must be >= 0";
213 return make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));217 return make_exceptional_future<shared_ptr<Uploader>>(InvalidArgumentException(msg));
214 }218 }
215 if (!get_root())
216 {
217 return make_exceptional_future<shared_ptr<Uploader>>(RuntimeDestroyedException("Folder::create_file()"));
218 }
219219
220 auto prov = provider();220 auto prov = provider();
221 auto reply = prov->CreateFile(md_.item_id, name, size, "application/octet-stream", false);221 auto reply = prov->CreateFile(md_.item_id, name, size, "application/octet-stream", false);
222222
=== modified file 'src/qt/client/internal/remote_client/ItemImpl.cpp'
--- src/qt/client/internal/remote_client/ItemImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/remote_client/ItemImpl.cpp 2016-08-03 06:10:39 +0000
@@ -50,68 +50,48 @@
5050
51QString ItemImpl::name() const51QString ItemImpl::name() const
52{52{
53 if (deleted_)53 throw_if_destroyed("Item::name()");
54 {
55 throw deleted_ex("Item::name()");
56 }
57 if (!get_root())
58 {
59 throw RuntimeDestroyedException("Item::name()");
60 }
61 return md_.name;54 return md_.name;
62}55}
6356
64QString ItemImpl::etag() const57QString ItemImpl::etag() const
65{58{
66 if (deleted_)59 throw_if_destroyed("Item::etag()");
67 {
68 throw deleted_ex("Item::etag()");
69 }
70 if (!get_root())
71 {
72 throw RuntimeDestroyedException("Item::etag()");
73 }
74 return md_.etag;60 return md_.etag;
75}61}
7662
77QVariantMap ItemImpl::metadata() const63QVariantMap ItemImpl::metadata() const
78{64{
79 if (deleted_)65 throw_if_destroyed("Item::metadata()");
80 {
81 throw deleted_ex("Item::metadata()");
82 }
83 if (!get_root())
84 {
85 throw RuntimeDestroyedException("Item::metadata()");
86 }
87 // TODO: need to agree on metadata representation66 // TODO: need to agree on metadata representation
88 return QVariantMap();67 return QVariantMap();
89}68}
9069
91QDateTime ItemImpl::last_modified_time() const70QDateTime ItemImpl::last_modified_time() const
92{71{
93 if (deleted_)72 throw_if_destroyed("Item::last_modified_time()");
94 {
95 throw deleted_ex("Item::last_modified_time()");
96 }
97 if (!get_root())
98 {
99 throw RuntimeDestroyedException("Item::last_modified_time()");
100 }
101 // TODO: need to agree on metadata representation73 // TODO: need to agree on metadata representation
102 return QDateTime();74 return QDateTime();
103}75}
10476
105QFuture<shared_ptr<Item>> ItemImpl::copy(shared_ptr<Folder> const& new_parent, QString const& new_name)77QFuture<shared_ptr<Item>> ItemImpl::copy(shared_ptr<Folder> const& new_parent, QString const& new_name)
106{78{
107 if (deleted_)79 if (!new_parent)
108 {80 {
109 return make_exceptional_future<shared_ptr<Item>>(deleted_ex("Item::copy()"));81 QString msg = "Item::copy(): new_parent cannot be nullptr";
110 }82 return internal::make_exceptional_future<shared_ptr<Item>>(InvalidArgumentException(msg));
111 if (!get_root())83 }
112 {84
113 return make_exceptional_future<shared_ptr<Item>>(RuntimeDestroyedException("Item::copy()"));85 try
114 }86 {
87 throw_if_destroyed("Item::copy()");
88 }
89 catch (StorageException const& e)
90 {
91 return make_exceptional_future<shared_ptr<Item>>(e);
92 }
93 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
94 new_parent_impl->throw_if_destroyed("Item::copy()");
11595
116 auto prov = provider();96 auto prov = provider();
117 auto reply = prov->Copy(md_.item_id, new_parent->native_identity(), new_name);97 auto reply = prov->Copy(md_.item_id, new_parent->native_identity(), new_name);
@@ -144,14 +124,22 @@
144124
145QFuture<shared_ptr<Item>> ItemImpl::move(shared_ptr<Folder> const& new_parent, QString const& new_name)125QFuture<shared_ptr<Item>> ItemImpl::move(shared_ptr<Folder> const& new_parent, QString const& new_name)
146{126{
147 if (deleted_)127 if (!new_parent)
148 {128 {
149 return make_exceptional_future<shared_ptr<Item>>(deleted_ex("Item::move()"));129 QString msg = "Item::move(): new_parent cannot be nullptr";
150 }130 return internal::make_exceptional_future<shared_ptr<Item>>(InvalidArgumentException(msg));
151 if (!get_root())131 }
152 {132
153 return make_exceptional_future<shared_ptr<Item>>(RuntimeDestroyedException("Item::copy()"));133 try
154 }134 {
135 throw_if_destroyed("Item::move()");
136 }
137 catch (StorageException const& e)
138 {
139 return make_exceptional_future<shared_ptr<Item>>(e);
140 }
141 auto new_parent_impl = dynamic_pointer_cast<FolderImpl>(new_parent->p_);
142 new_parent_impl->throw_if_destroyed("Item::move()");
155143
156 auto prov = provider();144 auto prov = provider();
157 if (!prov)145 if (!prov)
@@ -186,13 +174,13 @@
186174
187QFuture<QVector<Folder::SPtr>> ItemImpl::parents() const175QFuture<QVector<Folder::SPtr>> ItemImpl::parents() const
188{176{
189 if (deleted_)177 try
190 {178 {
191 return make_exceptional_future<QVector<Folder::SPtr>>(deleted_ex("Item::parents()"));179 throw_if_destroyed("Item::parents()");
192 }180 }
193 if (!get_root())181 catch (StorageException const& e)
194 {182 {
195 return make_exceptional_future<QVector<Folder::SPtr>>(RuntimeDestroyedException("Item::parents()"));183 return make_exceptional_future<QVector<Folder::SPtr>>(e);
196 }184 }
197 // TODO, need different metadata representation, affects xml185 // TODO, need different metadata representation, affects xml
198 return QFuture<QVector<Folder::SPtr>>();186 return QFuture<QVector<Folder::SPtr>>();
@@ -200,28 +188,14 @@
200188
201QVector<QString> ItemImpl::parent_ids() const189QVector<QString> ItemImpl::parent_ids() const
202{190{
203 if (deleted_)191 throw_if_destroyed("Item::parent_ids()");
204 {
205 throw deleted_ex("Item::parent_ids()");
206 }
207 if (!get_root())
208 {
209 RuntimeDestroyedException("Item::parent_ids()");
210 }
211 // TODO, need different metadata representation, affects xml192 // TODO, need different metadata representation, affects xml
212 return QVector<QString>();193 return QVector<QString>();
213}194}
214195
215QFuture<void> ItemImpl::delete_item()196QFuture<void> ItemImpl::delete_item()
216{197{
217 if (deleted_)198 throw_if_destroyed("Item::delete_item()");
218 {
219 return make_exceptional_future(deleted_ex("Item::delete_item()"));
220 }
221 if (!get_root())
222 {
223 return make_exceptional_future(RuntimeDestroyedException("Item::parents()"));
224 }
225199
226 auto prov = provider();200 auto prov = provider();
227 auto reply = prov->Delete(md_.item_id);201 auto reply = prov->Delete(md_.item_id);
@@ -238,20 +212,14 @@
238212
239QDateTime ItemImpl::creation_time() const213QDateTime ItemImpl::creation_time() const
240{214{
241 if (deleted_)215 throw_if_destroyed("Item::creation_time()");
242 {
243 throw deleted_ex("Item::creation_time()");
244 }
245 // TODO: need to agree on metadata representation216 // TODO: need to agree on metadata representation
246 return QDateTime();217 return QDateTime();
247}218}
248219
249MetadataMap ItemImpl::native_metadata() const220MetadataMap ItemImpl::native_metadata() const
250{221{
251 if (deleted_)222 throw_if_destroyed("Item::native_metadata()");
252 {
253 throw deleted_ex("Item::native_metadata()");
254 }
255 // TODO: need to agree on metadata representation223 // TODO: need to agree on metadata representation
256 return MetadataMap();224 return MetadataMap();
257}225}
@@ -316,12 +284,6 @@
316 return item;284 return item;
317}285}
318286
319DeletedException ItemImpl::deleted_ex(QString const& method) const noexcept
320{
321 QString msg = method + ": " + identity_ + " was deleted previously";
322 return DeletedException(msg, identity_, md_.name);
323}
324
325} // namespace remote_client287} // namespace remote_client
326} // namespace internal288} // namespace internal
327} // namespace client289} // namespace client
328290
=== modified file 'src/qt/client/internal/remote_client/RuntimeImpl.cpp'
--- src/qt/client/internal/remote_client/RuntimeImpl.cpp 2016-08-03 06:10:39 +0000
+++ src/qt/client/internal/remote_client/RuntimeImpl.cpp 2016-08-03 06:10:39 +0000
@@ -19,6 +19,7 @@
19#include <unity/storage/qt/client/internal/remote_client/RuntimeImpl.h>19#include <unity/storage/qt/client/internal/remote_client/RuntimeImpl.h>
2020
21#include <unity/storage/qt/client/Account.h>21#include <unity/storage/qt/client/Account.h>
22#include <unity/storage/qt/client/Exceptions.h>
22#include <unity/storage/qt/client/internal/make_future.h>23#include <unity/storage/qt/client/internal/make_future.h>
23#include <unity/storage/qt/client/internal/remote_client/AccountImpl.h>24#include <unity/storage/qt/client/internal/remote_client/AccountImpl.h>
24#include <unity/storage/qt/client/internal/remote_client/dbusmarshal.h>25#include <unity/storage/qt/client/internal/remote_client/dbusmarshal.h>
2526
=== modified file 'tests/local-client/local-client_test.cpp'
--- tests/local-client/local-client_test.cpp 2016-08-03 06:10:39 +0000
+++ tests/local-client/local-client_test.cpp 2016-08-03 06:10:39 +0000
@@ -18,12 +18,8 @@
1818
19#include <unity/storage/qt/client/client-api.h>19#include <unity/storage/qt/client/client-api.h>
2020
21<<<<<<< TREE
22#include <unity/storage/qt/client/internal/local_client/boost_filesystem.h>21#include <unity/storage/qt/client/internal/local_client/boost_filesystem.h>
23=======22#include <unity/storage/qt/client/internal/local_client/tmpfile_prefix.h>
24#include <unity/storage/qt/client/internal/boost_filesystem.h>
25#include <unity/storage/qt/client/internal/local_client/tmpfile-prefix.h>
26>>>>>>> MERGE-SOURCE
2723
28#include <gtest/gtest.h>24#include <gtest/gtest.h>
29#include <QCoreApplication>25#include <QCoreApplication>
@@ -39,6 +35,8 @@
3935
40#include <fstream>36#include <fstream>
4137
38Q_DECLARE_METATYPE(QLocalSocket::LocalSocketState)
39
42using namespace unity::storage;40using namespace unity::storage;
43using namespace unity::storage::qt::client;41using namespace unity::storage::qt::client;
44using namespace std;42using namespace std;
@@ -47,31 +45,61 @@
4745
48// Bunch of helper function to reduce the amount of noise in the tests.46// Bunch of helper function to reduce the amount of noise in the tests.
4947
48template<typename T>
49void wait(T fut)
50{
51 QFutureWatcher<decltype(fut.result())> w;
52 QSignalSpy spy(&w, &decltype(w)::finished);
53 w.setFuture(fut);
54 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
55}
56
57template<>
58void wait(QFuture<void> fut)
59{
60 QFutureWatcher<void> w;
61 QSignalSpy spy(&w, &decltype(w)::finished);
62 w.setFuture(fut);
63 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
64}
65
66template <typename T>
67T call(QFuture<T> fut)
68{
69 wait(fut);
70 return fut.result();
71}
72
73template <>
74void call(QFuture<void> fut)
75{
76 wait(fut);
77 fut.waitForFinished();
78}
79
50Account::SPtr get_account(Runtime::SPtr const& runtime)80Account::SPtr get_account(Runtime::SPtr const& runtime)
51{81{
52 auto accounts = runtime->accounts().result();82 auto accounts = call(runtime->accounts());
53 assert(accounts.size() == 1);
54 return accounts[0];83 return accounts[0];
55}84}
5685
57Root::SPtr get_root(Runtime::SPtr const& runtime)86Root::SPtr get_root(Runtime::SPtr const& runtime)
58{87{
59 auto acc = get_account(runtime);88 auto acc = get_account(runtime);
60 auto roots = acc->roots().result();89 auto roots = call(acc->roots());
61 assert(roots.size() == 1);
62 return roots[0];90 return roots[0];
63}91}
6492
65Folder::SPtr get_parent(Item::SPtr const& item)93Folder::SPtr get_parent(Item::SPtr const& item)
66{94{
67 assert(item->type() != ItemType::root);95 assert(item->type() != ItemType::root);
68 auto parents = item->parents().result();96 auto parents = call(item->parents());
69 return parents[0];97 return parents[0];
70}98}
7199
72void clear_folder(Folder::SPtr folder)100void clear_folder(Folder::SPtr folder)
73{101{
74 auto items = folder->list().result();102 auto items = call(folder->list());
75 for (auto i : items)103 for (auto i : items)
76 {104 {
77 i->delete_item().waitForFinished();105 i->delete_item().waitForFinished();
@@ -86,7 +114,7 @@
86 return buf == expected;114 return buf == expected;
87}115}
88116
89void write_file(Folder::SPtr const& folder, QString const& name, QByteArray const& contents)117File::SPtr write_file(Folder::SPtr const& folder, QString const& name, QByteArray const& contents)
90{118{
91 QString ofile = folder->native_identity() + "/" + name;119 QString ofile = folder->native_identity() + "/" + name;
92 QFile f(ofile);120 QFile f(ofile);
@@ -95,6 +123,23 @@
95 {123 {
96 assert(f.write(contents));124 assert(f.write(contents));
97 }125 }
126 f.close();
127 auto items = call(folder->lookup(name));
128 return dynamic_pointer_cast<File>(items[0]);
129}
130
131File::SPtr make_deleted_file(Folder::SPtr parent, QString const& name)
132{
133 auto file = write_file(parent, name, "bytes");
134 call(file->delete_item());
135 return file;
136}
137
138Folder::SPtr make_deleted_folder(Folder::SPtr parent, QString const& name)
139{
140 auto folder = call(parent->create_folder(name));
141 call(folder->delete_item());
142 return folder;
98}143}
99144
100TEST(Runtime, lifecycle)145TEST(Runtime, lifecycle)
@@ -123,11 +168,11 @@
123 auto runtime = Runtime::create();168 auto runtime = Runtime::create();
124169
125 auto acc = get_account(runtime);170 auto acc = get_account(runtime);
126 auto roots = acc->roots().result();171 auto roots = call(acc->roots());
127 EXPECT_EQ(1, roots.size());172 EXPECT_EQ(1, roots.size());
128173
129 // Get roots again, to get coverage for lazy initialization.174 // Get roots again, to get coverage for lazy initialization.
130 roots = acc->roots().result();175 roots = call(acc->roots());
131 ASSERT_EQ(1, roots.size());176 ASSERT_EQ(1, roots.size());
132}177}
133178
@@ -142,23 +187,31 @@
142 EXPECT_EQ("", root->name());187 EXPECT_EQ("", root->name());
143 EXPECT_NE("", root->etag());188 EXPECT_NE("", root->etag());
144189
145 auto parents = root->parents().result();190 {
146 EXPECT_TRUE(parents.isEmpty());191 auto parents = call(root->parents());
147 EXPECT_TRUE(root->parent_ids().isEmpty());192 EXPECT_TRUE(parents.isEmpty());
193 EXPECT_TRUE(root->parent_ids().isEmpty());
194 }
148195
149 // get(<root-path>) must return the root.196 {
150 auto item = root->get(root->native_identity()).result();197 // get(<root-path>) must return the root.
151 EXPECT_NE(nullptr, dynamic_pointer_cast<Root>(item));198 auto item = call(root->get(root->native_identity()));
152 EXPECT_TRUE(root->equal_to(item));199 EXPECT_NE(nullptr, dynamic_pointer_cast<Root>(item));
200 EXPECT_TRUE(root->equal_to(item));
201 }
153202
154 // Free and used space can be anything, but must be > 0.203 // Free and used space can be anything, but must be > 0.
155 auto free_space = root->free_space_bytes().result();204 {
156 cerr << "bytes free: " << free_space << endl;205 auto free_space = call(root->free_space_bytes());
157 EXPECT_GT(free_space, 0);206 cerr << "bytes free: " << free_space << endl;
207 EXPECT_GT(free_space, 0);
208 }
158209
159 auto used_space = root->used_space_bytes().result();210 {
160 cerr << "bytes used: " << used_space << endl;211 auto used_space = call(root->used_space_bytes());
161 EXPECT_GT(used_space, 0);212 cerr << "bytes used: " << used_space << endl;
213 EXPECT_GT(used_space, 0);
214 }
162}215}
163216
164TEST(Folder, basic)217TEST(Folder, basic)
@@ -169,43 +222,43 @@
169 auto root = get_root(runtime);222 auto root = get_root(runtime);
170 clear_folder(root);223 clear_folder(root);
171224
172 auto items = root->list().result();225 auto items = call(root->list());
173 EXPECT_TRUE(items.isEmpty());226 EXPECT_TRUE(items.isEmpty());
174227
175 // Create a file and check that it was created with correct type, name, and size 0.228 // Create a file and check that it was created with correct type, name, and size 0.
176 auto uploader = root->create_file("file1", 0).result();229 auto uploader = call(root->create_file("file1", 0));
177 auto file = uploader->finish_upload().result();230 auto file = call(uploader->finish_upload());
178 EXPECT_EQ(ItemType::file, file->type());231 EXPECT_EQ(ItemType::file, file->type());
179 EXPECT_EQ("file1", file->name());232 EXPECT_EQ("file1", file->name());
180 EXPECT_EQ(0, file->size());233 EXPECT_EQ(0, file->size());
181 EXPECT_EQ(root->native_identity() + "/file1", file->native_identity());234 EXPECT_EQ(root->native_identity() + "/file1", file->native_identity());
182235
183 // Create a folder and check that it was created with correct type and name.236 // Create a folder and check that it was created with correct type and name.
184 auto folder = root->create_folder("folder1").result();237 auto folder = call(root->create_folder("folder1"));
185 EXPECT_EQ(ItemType::folder, folder->type());238 EXPECT_EQ(ItemType::folder, folder->type());
186 EXPECT_EQ("folder1", folder->name());239 EXPECT_EQ("folder1", folder->name());
187 EXPECT_EQ(root->native_identity() + "/folder1", folder->native_identity());240 EXPECT_EQ(root->native_identity() + "/folder1", folder->native_identity());
188241
189 // Check that we can find both file1 and folder1.242 // Check that we can find both file1 and folder1.
190 auto item = root->lookup("file1").result()[0];243 auto item = call(root->lookup("file1"))[0];
191 file = dynamic_pointer_cast<File>(item);244 file = dynamic_pointer_cast<File>(item);
192 ASSERT_NE(nullptr, file);245 ASSERT_NE(nullptr, file);
193 EXPECT_EQ("file1", file->name());246 EXPECT_EQ("file1", file->name());
194 EXPECT_EQ(0, file->size());247 EXPECT_EQ(0, file->size());
195248
196 item = root->lookup("folder1").result()[0];249 item = call(root->lookup("folder1"))[0];
197 folder = dynamic_pointer_cast<Folder>(item);250 folder = dynamic_pointer_cast<Folder>(item);
198 ASSERT_NE(nullptr, folder);251 ASSERT_NE(nullptr, folder);
199 ASSERT_EQ(nullptr, dynamic_pointer_cast<Root>(folder));252 ASSERT_EQ(nullptr, dynamic_pointer_cast<Root>(folder));
200 EXPECT_EQ("folder1", folder->name());253 EXPECT_EQ("folder1", folder->name());
201254
202 item = root->get(file->native_identity()).result();255 item = call(root->get(file->native_identity()));
203 file = dynamic_pointer_cast<File>(item);256 file = dynamic_pointer_cast<File>(item);
204 ASSERT_NE(nullptr, file);257 ASSERT_NE(nullptr, file);
205 EXPECT_EQ("file1", file->name());258 EXPECT_EQ("file1", file->name());
206 EXPECT_EQ(0, file->size());259 EXPECT_EQ(0, file->size());
207260
208 item = root->get(folder->native_identity()).result();261 item = call(root->get(folder->native_identity()));
209 folder = dynamic_pointer_cast<Folder>(item);262 folder = dynamic_pointer_cast<Folder>(item);
210 ASSERT_NE(nullptr, folder);263 ASSERT_NE(nullptr, folder);
211 ASSERT_EQ(nullptr, dynamic_pointer_cast<Root>(folder));264 ASSERT_EQ(nullptr, dynamic_pointer_cast<Root>(folder));
@@ -241,8 +294,8 @@
241 EXPECT_EQ(root->native_identity(), folder->parent_ids()[0]);294 EXPECT_EQ(root->native_identity(), folder->parent_ids()[0]);
242295
243 // Delete the file and check that only the directory is left.296 // Delete the file and check that only the directory is left.
244 file->delete_item().waitForFinished();297 call(file->delete_item());
245 items = root->list().result();298 items = call(root->list());
246 ASSERT_EQ(1, items.size());299 ASSERT_EQ(1, items.size());
247 folder = dynamic_pointer_cast<Folder>(items[0]);300 folder = dynamic_pointer_cast<Folder>(items[0]);
248 ASSERT_NE(nullptr, folder);301 ASSERT_NE(nullptr, folder);
@@ -250,7 +303,7 @@
250303
251 // Delete the folder and check that the root is empty.304 // Delete the folder and check that the root is empty.
252 folder->delete_item().waitForFinished();305 folder->delete_item().waitForFinished();
253 items = root->list().result();306 items = call(root->list());
254 ASSERT_EQ(0, items.size());307 ASSERT_EQ(0, items.size());
255}308}
256309
@@ -262,8 +315,8 @@
262 auto root = get_root(runtime);315 auto root = get_root(runtime);
263 clear_folder(root);316 clear_folder(root);
264317
265 auto d1 = root->create_folder("d1").result();318 auto d1 = call(root->create_folder("d1"));
266 auto d2 = d1->create_folder("d2").result();319 auto d2 = call(d1->create_folder("d2"));
267320
268 // Parent of d2 must be d1.321 // Parent of d2 must be d1.
269 EXPECT_TRUE(get_parent(d2)->equal_to(d1));322 EXPECT_TRUE(get_parent(d2)->equal_to(d1));
@@ -271,28 +324,10 @@
271324
272 // Delete is recursive325 // Delete is recursive
273 d1->delete_item().waitForFinished();326 d1->delete_item().waitForFinished();
274 auto items = root->list().result();327 auto items = call(root->list());
275 ASSERT_EQ(0, items.size());328 ASSERT_EQ(0, items.size());
276}329}
277330
278template<typename T>
279bool wait(T fut)
280{
281 QFutureWatcher<decltype(fut.result())> w;
282 QSignalSpy spy(&w, &decltype(w)::finished);
283 w.setFuture(fut);
284 return spy.wait(SIGNAL_WAIT_TIME);
285}
286
287template<>
288bool wait(QFuture<void> fut)
289{
290 QFutureWatcher<void> w;
291 QSignalSpy spy(&w, &decltype(w)::finished);
292 w.setFuture(fut);
293 return spy.wait(SIGNAL_WAIT_TIME);
294}
295
296TEST(File, upload)331TEST(File, upload)
297{332{
298 auto runtime = Runtime::create();333 auto runtime = Runtime::create();
@@ -304,79 +339,73 @@
304 {339 {
305 // Upload a few bytes.340 // Upload a few bytes.
306 QByteArray const contents = "Hello\n";341 QByteArray const contents = "Hello\n";
307 auto uploader = root->create_file("new_file", contents.size()).result();342 auto uploader = call(root->create_file("new_file", contents.size()));
308 auto written = uploader->socket()->write(contents);343 auto written = uploader->socket()->write(contents);
309 ASSERT_EQ(contents.size(), written);344 ASSERT_EQ(contents.size(), written);
310345
311 auto file_fut = uploader->finish_upload();346 auto file = call(uploader->finish_upload());
312 ASSERT_TRUE(wait(file_fut));
313 auto file = file_fut.result();
314 EXPECT_EQ(contents.size(), file->size());347 EXPECT_EQ(contents.size(), file->size());
315 ASSERT_TRUE(content_matches(file, contents));348 ASSERT_TRUE(content_matches(file, contents));
316349
317 // Calling finish_upload() more than once must return the original future.350 // Calling finish_upload() more than once must return the original future.
318 auto file2 = uploader->finish_upload().result();351 auto file2 = call(uploader->finish_upload());
319 EXPECT_TRUE(file2->equal_to(file));352 EXPECT_TRUE(file2->equal_to(file));
320353
321 // Calling cancel() after finish_upload must do nothing.354 // Calling cancel() after finish_upload must do nothing.
322 uploader->cancel();355 uploader->cancel();
323 file2 = uploader->finish_upload().result();356 file2 = call(uploader->finish_upload());
324 EXPECT_TRUE(file2->equal_to(file));357 EXPECT_TRUE(file2->equal_to(file));
325358
326 file->delete_item().waitForFinished();359 call(file->delete_item());
327 }360 }
328361
329 {362 {
330 // Upload exactly 64 KB.363 // Upload exactly 64 KB.
331 QByteArray const contents(64 * 1024, 'a');364 QByteArray const contents(64 * 1024, 'a');
332 auto uploader = root->create_file("new_file", contents.size()).result();365 auto uploader = call(root->create_file("new_file", contents.size()));
333 auto written = uploader->socket()->write(contents);366 auto written = uploader->socket()->write(contents);
334 ASSERT_EQ(contents.size(), written);367 ASSERT_EQ(contents.size(), written);
335368
336 auto file_fut = uploader->finish_upload();369 auto file = call(uploader->finish_upload());
337 ASSERT_TRUE(wait(file_fut));
338 auto file = file_fut.result();
339 EXPECT_EQ(contents.size(), file->size());370 EXPECT_EQ(contents.size(), file->size());
340 ASSERT_TRUE(content_matches(file, contents));371 ASSERT_TRUE(content_matches(file, contents));
341372
342 file->delete_item().waitForFinished();373 call(file->delete_item());
343 }374 }
344375
345 {376 {
346 // Upload 1000 KBj377 // Upload 1000 KBj
347 QByteArray const contents(1000 * 1024, 'a');378 QByteArray const contents(1000 * 1024, 'a');
348 auto uploader = root->create_file("new_file", contents.size()).result();379 auto uploader = call(root->create_file("new_file", contents.size()));
349 auto written = uploader->socket()->write(contents);380 auto written = uploader->socket()->write(contents);
350 ASSERT_EQ(contents.size(), written);381 ASSERT_EQ(contents.size(), written);
351382
352 auto file_fut = uploader->finish_upload();383 auto file = call(uploader->finish_upload());
353 ASSERT_TRUE(wait(file_fut));
354 auto file = file_fut.result();
355 EXPECT_EQ(contents.size(), file->size());384 EXPECT_EQ(contents.size(), file->size());
356 ASSERT_TRUE(content_matches(file, contents));385 ASSERT_TRUE(content_matches(file, contents));
357386
358 file->delete_item().waitForFinished();387 call(file->delete_item());
359 }388 }
360389
361 {390 {
362 // Upload empty file.391 // Upload empty file.
363 auto uploader = root->create_file("new_file", 0).result();392 auto uploader = call(root->create_file("new_file", 0));
364 auto file = uploader->finish_upload().result();393 auto file = call(uploader->finish_upload());
365 ASSERT_EQ(0, file->size());394 ASSERT_EQ(0, file->size());
366395
367 // Again, and check that the ETag is different.396 // Again, and check that the ETag is different.
368 auto old_etag = file->etag();397 auto old_etag = file->etag();
369 sleep(1);398 sleep(1);
370 uploader = file->create_uploader(ConflictPolicy::overwrite, 0).result();399 uploader = call(file->create_uploader(ConflictPolicy::overwrite, 0));
371 file = uploader->finish_upload().result();400 file = call(uploader->finish_upload());
372 EXPECT_NE(old_etag, file->etag());401 EXPECT_NE(old_etag, file->etag());
373402
374 file->delete_item().waitForFinished();403 call(file->delete_item());
375 }404 }
376405
377 {406 {
378 // Let the uploader go out of scope and check that the file was not created.407 // Let the uploader go out of scope and check that the file was not created.
379 root->create_file("new_file", 0).result();408 call(root->create_file("new_file", 0));
380 boost::filesystem::path path(TEST_DIR "/storage-framework/new_file");409 boost::filesystem::path path(TEST_DIR "/storage-framework/new_file");
381 auto status = boost::filesystem::status(path);410 auto status = boost::filesystem::status(path);
382 ASSERT_FALSE(boost::filesystem::exists(status));411 ASSERT_FALSE(boost::filesystem::exists(status));
@@ -392,31 +421,25 @@
392 clear_folder(root);421 clear_folder(root);
393422
394 // Make a new file first.423 // Make a new file first.
395 auto uploader = root->create_file("new_file", 0).result();424 auto uploader = call(root->create_file("new_file", 0));
396 auto file_fut = uploader->finish_upload();425 auto file = call(uploader->finish_upload());
397 ASSERT_TRUE(wait(file_fut));
398 auto file = file_fut.result();
399 EXPECT_EQ(0, file->size());426 EXPECT_EQ(0, file->size());
400 auto old_etag = file->etag();427 auto old_etag = file->etag();
401428
402 // Create uploader for the file and write nothing.429 // Create uploader for the file and write nothing.
403 uploader = file->create_uploader(ConflictPolicy::overwrite, 0).result();430 uploader = call(file->create_uploader(ConflictPolicy::overwrite, 0));
404 file_fut = uploader->finish_upload();431 file = call(uploader->finish_upload());
405 ASSERT_TRUE(wait(file_fut));
406 file = file_fut.result();
407 EXPECT_EQ(0, file->size());432 EXPECT_EQ(0, file->size());
408433
409 // Same test again, but this time, we write a bunch of data.434 // Same test again, but this time, we write a bunch of data.
410 std::string s(1000000, 'a');435 std::string s(1000000, 'a');
411 uploader = file->create_uploader(ConflictPolicy::overwrite, s.size()).result();436 uploader = call(file->create_uploader(ConflictPolicy::overwrite, s.size()));
412 uploader->socket()->write(&s[0], s.size());437 uploader->socket()->write(&s[0], s.size());
413438
414 // Need to sleep here, otherwise it is possible for the439 // Need to sleep here, otherwise it is possible for the
415 // upload to finish within the granularity of the file system time stamps.440 // upload to finish within the granularity of the file system time stamps.
416 sleep(1);441 sleep(1);
417 file_fut = uploader->finish_upload();442 file = call(uploader->finish_upload());
418 ASSERT_TRUE(wait(file_fut));
419 file = file_fut.result();
420 EXPECT_EQ(1000000, file->size());443 EXPECT_EQ(1000000, file->size());
421 EXPECT_NE(old_etag, file->etag());444 EXPECT_NE(old_etag, file->etag());
422445
@@ -432,12 +455,12 @@
432 clear_folder(root);455 clear_folder(root);
433456
434 {457 {
435 auto uploader = root->create_file("new_file", 20).result();458 auto uploader = call(root->create_file("new_file", 20));
436459
437 // We haven't called finish_upload(), so the cancel is guaranteed460 // We haven't called finish_upload(), so the cancel is guaranteed
438 // to catch the uploader in the in_progress state.461 // to catch the uploader in the in_progress state.
439 uploader->cancel();462 uploader->cancel();
440 EXPECT_THROW(uploader->finish_upload().result(), CancelledException);463 EXPECT_THROW(call(uploader->finish_upload()), CancelledException);
441464
442 boost::filesystem::path path(TEST_DIR "/storage-framework/new_file");465 boost::filesystem::path path(TEST_DIR "/storage-framework/new_file");
443 auto status = boost::filesystem::status(path);466 auto status = boost::filesystem::status(path);
@@ -447,28 +470,25 @@
447 {470 {
448 // Create a file with a few bytes.471 // Create a file with a few bytes.
449 QByteArray original_contents = "Hello World!\n";472 QByteArray original_contents = "Hello World!\n";
450 write_file(root, "new_file", original_contents);473 auto file = write_file(root, "new_file", original_contents);
451 auto file = dynamic_pointer_cast<File>(root->lookup("new_file").result()[0]);
452 ASSERT_NE(nullptr, file);
453474
454 // Create an uploader for the file and write a bunch of bytes.475 // Create an uploader for the file and write a bunch of bytes.
455 auto uploader = file->create_uploader(ConflictPolicy::overwrite, original_contents.size()).result();476 auto uploader = call(file->create_uploader(ConflictPolicy::overwrite, original_contents.size()));
456 QByteArray const contents(1024 * 1024, 'a');477 QByteArray const contents(1024 * 1024, 'a');
457 auto written = uploader->socket()->write(contents);478 auto written = uploader->socket()->write(contents);
458 ASSERT_EQ(contents.size(), written);479 ASSERT_EQ(contents.size(), written);
459480
460 // No finish_upload() here, so the transfer is still in progress. Now cancel.481 // No finish_upload() here, so the transfer is still in progress. Now cancel.
461 auto cancel_fut = uploader->cancel();482 uploader->cancel();
462 ASSERT_TRUE(wait(cancel_fut));
463483
464 // finish_upload() must indicate that the upload was cancelled.484 // finish_upload() must indicate that the upload was cancelled.
465 EXPECT_THROW(uploader->finish_upload().result(), CancelledException);485 EXPECT_THROW(call(uploader->finish_upload()), CancelledException);
466486
467 // The original file contents must still be intact.487 // The original file contents must still be intact.
468 EXPECT_EQ(original_contents.size(), file->size());488 EXPECT_EQ(original_contents.size(), file->size());
469 ASSERT_TRUE(content_matches(file, original_contents));489 ASSERT_TRUE(content_matches(file, original_contents));
470490
471 file->delete_item().waitForFinished();491 call(file->delete_item());
472 }492 }
473}493}
474494
@@ -482,10 +502,8 @@
482502
483 // Make a new file on disk.503 // Make a new file on disk.
484 QByteArray const contents = "";504 QByteArray const contents = "";
485 write_file(root, "new_file", contents);505 auto file = write_file(root, "new_file", contents);
486 auto file = dynamic_pointer_cast<File>(root->lookup("new_file").result()[0]);506 auto uploader = call(file->create_uploader(ConflictPolicy::error_if_conflict, contents.size()));
487 ASSERT_NE(nullptr, file);
488 auto uploader = file->create_uploader(ConflictPolicy::error_if_conflict, contents.size()).result();
489507
490 // Touch the file on disk to give it a new time stamp.508 // Touch the file on disk to give it a new time stamp.
491 sleep(1);509 sleep(1);
@@ -494,7 +512,7 @@
494 try512 try
495 {513 {
496 // Must get an exception because the time stamps no longer match.514 // Must get an exception because the time stamps no longer match.
497 uploader->finish_upload().result();515 call(uploader->finish_upload());
498 FAIL();516 FAIL();
499 }517 }
500 catch (ConflictException const&)518 catch (ConflictException const&)
@@ -502,7 +520,52 @@
502 // TODO: check exception details.520 // TODO: check exception details.
503 }521 }
504522
505 file->delete_item().waitForFinished();523 call(file->delete_item());
524}
525
526TEST(File, upload_error)
527{
528 auto runtime = Runtime::create();
529
530 auto acc = get_account(runtime);
531 auto root = get_root(runtime);
532 clear_folder(root);
533
534 auto uploader = call(root->create_file("new_file", 0));
535 // Make new_file, so it gets in the way during finish_upload().
536 write_file(root, "new_file", "");
537
538 try
539 {
540 call(uploader->finish_upload());
541 FAIL();
542 }
543 catch (ExistsException const& e)
544 {
545 EXPECT_TRUE(e.error_message().startsWith("Uploader::finish_upload(): item with name \""));
546 EXPECT_TRUE(e.error_message().endsWith("\" exists already"));
547 EXPECT_EQ(TEST_DIR "/storage-framework/new_file", e.native_identity()) << e.native_identity().toStdString();
548 EXPECT_EQ("new_file", e.name());
549 }
550}
551
552TEST(File, create_uploader_bad_arg)
553{
554 auto runtime = Runtime::create();
555
556 auto acc = get_account(runtime);
557 auto root = get_root(runtime);
558 clear_folder(root);
559
560 auto file = write_file(root, "new_file", 0);
561 try
562 {
563 call(file->create_uploader(ConflictPolicy::overwrite, -1));
564 }
565 catch (InvalidArgumentException const& e)
566 {
567 EXPECT_EQ("File::create_uploader(): size must be >= 0", e.error_message());
568 }
506}569}
507570
508TEST(File, download)571TEST(File, download)
@@ -516,13 +579,9 @@
516 {579 {
517 // Download a few bytes.580 // Download a few bytes.
518 QByteArray const contents = "Hello\n";581 QByteArray const contents = "Hello\n";
519 write_file(root, "file", contents);582 auto file = write_file(root, "file", contents);
520583
521 auto item = root->lookup("file").result()[0];584 auto downloader = call(file->create_downloader());
522 File::SPtr file = dynamic_pointer_cast<File>(item);
523 ASSERT_FALSE(file == nullptr);
524
525 auto downloader = file->create_downloader().result();
526 EXPECT_TRUE(file->equal_to(downloader->file()));585 EXPECT_TRUE(file->equal_to(downloader->file()));
527586
528 auto socket = downloader->socket();587 auto socket = downloader->socket();
@@ -530,17 +589,20 @@
530 do589 do
531 {590 {
532 // Need to pump the event loop while the socket does its thing.591 // Need to pump the event loop while the socket does its thing.
533 QSignalSpy spy(downloader->socket().get(), &QIODevice::readyRead);592 QSignalSpy spy(socket.get(), &QIODevice::readyRead);
534 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
535 auto bytes_to_read = socket->bytesAvailable();593 auto bytes_to_read = socket->bytesAvailable();
594 if (bytes_to_read == 0)
595 {
596 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
597 }
536 buf.append(socket->read(bytes_to_read));598 buf.append(socket->read(bytes_to_read));
537 } while (buf.size() < contents.size());599 } while (buf.size() < contents.size());
538600
539 // Wait for disconnected signal.601 // Wait for disconnected signal.
540 QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);602 QSignalSpy spy(socket.get(), &QLocalSocket::disconnected);
541 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));603 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
542604
543 ASSERT_NO_THROW(downloader->finish_download().waitForFinished());605 ASSERT_NO_THROW(call(downloader->finish_download()));
544606
545 // Contents must match.607 // Contents must match.
546 EXPECT_EQ(contents, buf);608 EXPECT_EQ(contents, buf);
@@ -549,13 +611,9 @@
549 {611 {
550 // Download exactly 64 KB.612 // Download exactly 64 KB.
551 QByteArray const contents(64 * 1024, 'a');613 QByteArray const contents(64 * 1024, 'a');
552 write_file(root, "file", contents);614 auto file = write_file(root, "file", contents);
553615
554 auto item = root->lookup("file").result()[0];616 auto downloader = call(file->create_downloader());
555 File::SPtr file = dynamic_pointer_cast<File>(item);
556 ASSERT_FALSE(file == nullptr);
557
558 auto downloader = file->create_downloader().result();
559 EXPECT_TRUE(file->equal_to(downloader->file()));617 EXPECT_TRUE(file->equal_to(downloader->file()));
560618
561 auto socket = downloader->socket();619 auto socket = downloader->socket();
@@ -563,17 +621,20 @@
563 do621 do
564 {622 {
565 // Need to pump the event loop while the socket does its thing.623 // Need to pump the event loop while the socket does its thing.
566 QSignalSpy spy(downloader->socket().get(), &QIODevice::readyRead);624 QSignalSpy spy(socket.get(), &QIODevice::readyRead);
567 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
568 auto bytes_to_read = socket->bytesAvailable();625 auto bytes_to_read = socket->bytesAvailable();
626 if (bytes_to_read == 0)
627 {
628 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
629 }
569 buf.append(socket->read(bytes_to_read));630 buf.append(socket->read(bytes_to_read));
570 } while (buf.size() < contents.size());631 } while (buf.size() < contents.size());
571632
572 // Wait for disconnected signal.633 // Wait for disconnected signal.
573 QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);634 QSignalSpy spy(socket.get(), &QLocalSocket::disconnected);
574 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));635 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
575636
576 ASSERT_NO_THROW(downloader->finish_download().waitForFinished());637 ASSERT_NO_THROW(call(downloader->finish_download()));
577638
578 // Contents must match639 // Contents must match
579 EXPECT_EQ(contents, buf);640 EXPECT_EQ(contents, buf);
@@ -582,13 +643,9 @@
582 {643 {
583 // Download 1 MB + 1 bytes.644 // Download 1 MB + 1 bytes.
584 QByteArray const contents(1024 * 1024 + 1, 'a');645 QByteArray const contents(1024 * 1024 + 1, 'a');
585 write_file(root, "file", contents);646 auto file = write_file(root, "file", contents);
586647
587 auto item = root->lookup("file").result()[0];648 auto downloader = call(file->create_downloader());
588 File::SPtr file = dynamic_pointer_cast<File>(item);
589 ASSERT_FALSE(file == nullptr);
590
591 auto downloader = file->create_downloader().result();
592 EXPECT_TRUE(file->equal_to(downloader->file()));649 EXPECT_TRUE(file->equal_to(downloader->file()));
593650
594 auto socket = downloader->socket();651 auto socket = downloader->socket();
@@ -596,17 +653,20 @@
596 do653 do
597 {654 {
598 // Need to pump the event loop while the socket does its thing.655 // Need to pump the event loop while the socket does its thing.
599 QSignalSpy spy(downloader->socket().get(), &QIODevice::readyRead);656 QSignalSpy spy(socket.get(), &QIODevice::readyRead);
600 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
601 auto bytes_to_read = socket->bytesAvailable();657 auto bytes_to_read = socket->bytesAvailable();
658 if (bytes_to_read == 0)
659 {
660 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
661 }
602 buf.append(socket->read(bytes_to_read));662 buf.append(socket->read(bytes_to_read));
603 } while (buf.size() < contents.size());663 } while (buf.size() < contents.size());
604664
605 // Wait for disconnected signal.665 // Wait for disconnected signal.
606 QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);666 QSignalSpy spy(socket.get(), &QLocalSocket::disconnected);
607 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));667 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
608668
609 ASSERT_NO_THROW(downloader->finish_download().waitForFinished());669 ASSERT_NO_THROW(call(downloader->finish_download()));
610670
611 // Contents must match671 // Contents must match
612 EXPECT_EQ(contents, buf);672 EXPECT_EQ(contents, buf);
@@ -615,85 +675,84 @@
615 {675 {
616 // Download file containing zero bytes676 // Download file containing zero bytes
617 QByteArray const contents;677 QByteArray const contents;
618 write_file(root, "file", contents);678 auto file = write_file(root, "file", contents);
619679
620 auto item = root->lookup("file").result()[0];680 auto downloader = call(file->create_downloader());
621 File::SPtr file = dynamic_pointer_cast<File>(item);
622 ASSERT_FALSE(file == nullptr);
623
624 auto downloader = file->create_downloader().result();
625 EXPECT_TRUE(file->equal_to(downloader->file()));681 EXPECT_TRUE(file->equal_to(downloader->file()));
626682
627 auto socket = downloader->socket();683 auto socket = downloader->socket();
628684
629 // No readyRead every arrives in this case, just wait for disconnected.685 // No readyRead ever arrives in this case, just wait for disconnected.
630 QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);686 QSignalSpy spy(socket.get(), &QLocalSocket::disconnected);
631 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));687 if (socket->state() != QLocalSocket::UnconnectedState)
688 {
689 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
690 }
632691
633 ASSERT_NO_THROW(downloader->finish_download().waitForFinished());692 ASSERT_NO_THROW(call(downloader->finish_download()));
634 }693 }
635694
636 {695 {
637 // Don't ever call read on empty file.696 // Don't ever call read on empty file.
638 QByteArray const contents;697 QByteArray const contents;
639 write_file(root, "file", contents);698 auto file = write_file(root, "file", contents);
640699
641 auto item = root->lookup("file").result()[0];700 auto downloader = call(file->create_downloader());
642 File::SPtr file = dynamic_pointer_cast<File>(item);
643 ASSERT_FALSE(file == nullptr);
644
645 auto downloader = file->create_downloader().result();
646 EXPECT_TRUE(file->equal_to(downloader->file()));701 EXPECT_TRUE(file->equal_to(downloader->file()));
647702
703 auto socket = downloader->socket();
704
648 // No readyRead ever arrives in this case, just wait for disconnected.705 // No readyRead ever arrives in this case, just wait for disconnected.
649 QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);706 QSignalSpy spy(socket.get(), &QLocalSocket::disconnected);
650 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));707 if (socket->state() != QLocalSocket::UnconnectedState)
708 {
709 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
710 }
651711
652 // This succeeds because the provider disconnects as soon712 // This succeeds because the provider disconnects as soon
653 // as it realizes that there is nothing to write.713 // as it realizes that there is nothing to write.
654 ASSERT_NO_THROW(downloader->finish_download().waitForFinished());714 ASSERT_NO_THROW(call(downloader->finish_download()));
655 }715 }
656716
657 {717 {
658 // Don't ever call read on small file.718 // Don't ever call read on small file.
659 QByteArray const contents("some contents");719 QByteArray const contents("some contents");
660 write_file(root, "file", contents);720 auto file = write_file(root, "file", contents);
661721
662 auto item = root->lookup("file").result()[0];722 auto downloader = call(file->create_downloader());
663 File::SPtr file = dynamic_pointer_cast<File>(item);
664 ASSERT_FALSE(file == nullptr);
665
666 auto downloader = file->create_downloader().result();
667 EXPECT_TRUE(file->equal_to(downloader->file()));723 EXPECT_TRUE(file->equal_to(downloader->file()));
668724
725 auto socket = downloader->socket();
726
669 // Wait for disconnected.727 // Wait for disconnected.
670 QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);728 if (socket->state() != QLocalSocket::UnconnectedState)
671 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));729 {
730 QSignalSpy spy(socket.get(), &QLocalSocket::disconnected);
731 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
732 }
672733
673 // This succeeds because the provider has written everything and disconnected.734 // This succeeds because the provider has written everything and disconnected.
674 ASSERT_NO_THROW(downloader->finish_download().waitForFinished());735 ASSERT_NO_THROW(call(downloader->finish_download()));
675 }736 }
676737
677 {738 {
678 // Don't ever call read on large file.739 // Don't ever call read on large file.
679 QByteArray const contents(1024 * 1024, 'a');740 QByteArray const contents(1024 * 1024, 'a');
680 write_file(root, "file", contents);741 auto file = write_file(root, "file", contents);
681742
682 auto item = root->lookup("file").result()[0];743 auto downloader = call(file->create_downloader());
683 File::SPtr file = dynamic_pointer_cast<File>(item);
684 ASSERT_FALSE(file == nullptr);
685
686 auto downloader = file->create_downloader().result();
687 EXPECT_TRUE(file->equal_to(downloader->file()));744 EXPECT_TRUE(file->equal_to(downloader->file()));
688745
746 auto socket = downloader->socket();
747
689 // Wait for first readyRead. Not all data fits into the socket buffer.748 // Wait for first readyRead. Not all data fits into the socket buffer.
690 QSignalSpy spy(downloader->socket().get(), &QLocalSocket::readyRead);749 QSignalSpy spy(socket.get(), &QLocalSocket::readyRead);
691 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));750 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
692751
693 // This fails because the provider still has data left to write.752 // This fails because the provider still has data left to write.
694 try753 try
695 {754 {
696 downloader->finish_download().waitForFinished();755 call(downloader->finish_download());
697 FAIL();756 FAIL();
698 }757 }
699 catch (StorageException const& e)758 catch (StorageException const& e)
@@ -705,25 +764,17 @@
705 {764 {
706 // Let downloader go out of scope.765 // Let downloader go out of scope.
707 QByteArray const contents(1024 * 1024, 'a');766 QByteArray const contents(1024 * 1024, 'a');
708 write_file(root, "file", contents);767 auto file = write_file(root, "file", contents);
709768
710 auto item = root->lookup("file").result()[0];769 auto downloader = call(file->create_downloader());
711 File::SPtr file = dynamic_pointer_cast<File>(item);
712 ASSERT_FALSE(file == nullptr);
713
714 auto downloader = file->create_downloader().result();
715 }770 }
716771
717 {772 {
718 // Let downloader future go out of scope.773 // Let downloader future go out of scope.
719 QByteArray const contents(1024 * 1024, 'a');774 QByteArray const contents(1024 * 1024, 'a');
720 write_file(root, "file", contents);775 auto file = write_file(root, "file", contents);
721776
722 auto item = root->lookup("file").result()[0];777 file->create_downloader();
723 File::SPtr file = dynamic_pointer_cast<File>(item);
724 ASSERT_FALSE(file == nullptr);
725
726 auto downloader_fut = file->create_downloader();
727 }778 }
728}779}
729780
@@ -738,55 +789,111 @@
738 {789 {
739 // Download enough bytes to prevent a single write in the provider from completing the download.790 // Download enough bytes to prevent a single write in the provider from completing the download.
740 QByteArray const contents(1024 * 1024, 'a');791 QByteArray const contents(1024 * 1024, 'a');
741 write_file(root, "file", contents);792 auto file = write_file(root, "file", contents);
742793
743 auto item = root->lookup("file").result()[0];794 auto downloader = call(file->create_downloader());
744 File::SPtr file = dynamic_pointer_cast<File>(item);
745 ASSERT_FALSE(file == nullptr);
746
747 auto download_fut = file->create_downloader();
748 ASSERT_TRUE(wait(download_fut));
749 auto downloader = download_fut.result();
750795
751 // We haven't read anything, so the cancel is guaranteed to catch the796 // We haven't read anything, so the cancel is guaranteed to catch the
752 // downloader in the in_progress state.797 // downloader in the in_progress state.
753 auto cancel_fut = downloader->cancel();798 downloader->cancel();
754 ASSERT_TRUE(wait(cancel_fut));799 ASSERT_THROW(call(downloader->finish_download()), CancelledException);
755 ASSERT_THROW(downloader->finish_download().waitForFinished(), CancelledException);
756 }800 }
757801
758 {802 {
759 // Download a few bytes.803 // Download a few bytes.
760 QByteArray const contents = "Hello\n";804 QByteArray const contents = "Hello\n";
761 write_file(root, "file", contents);805 auto file = write_file(root, "file", contents);
762
763 auto item = root->lookup("file").result()[0];
764 File::SPtr file = dynamic_pointer_cast<File>(item);
765 ASSERT_FALSE(file == nullptr);
766806
767 // Finish the download.807 // Finish the download.
768 auto downloader = file->create_downloader().result();808 auto downloader = call(file->create_downloader());
769 auto socket = downloader->socket();809 auto socket = downloader->socket();
770 QByteArray buf;810 QByteArray buf;
771 do811 do
772 {812 {
773 // Need to pump the event loop while the socket does its thing.813 // Need to pump the event loop while the socket does its thing.
774 QSignalSpy spy(downloader->socket().get(), &QIODevice::readyRead);814 QSignalSpy spy(socket.get(), &QIODevice::readyRead);
775 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
776 auto bytes_to_read = socket->bytesAvailable();815 auto bytes_to_read = socket->bytesAvailable();
816 if (bytes_to_read == 0)
817 {
818 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
819 }
777 buf.append(socket->read(bytes_to_read));820 buf.append(socket->read(bytes_to_read));
778 } while (buf.size() < contents.size());821 } while (buf.size() < contents.size());
779822
780 // Wait for disconnected signal.823 // Wait for disconnected signal.
781 QSignalSpy spy(downloader->socket().get(), &QLocalSocket::disconnected);824 if (socket->state() != QLocalSocket::UnconnectedState)
782 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));825 {
826 QSignalSpy spy(socket.get(), &QLocalSocket::disconnected);
827 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
828 }
783829
784 // Now send the cancel. The download is finished already, and the cancel830 // Now send the cancel. The download is finished already, and the cancel
785 // is too late, so finish_download() must report that the download831 // is too late, so finish_download() must report that the download
786 // worked OK.832 // worked OK.
787 downloader->cancel();833 downloader->cancel();
788 ASSERT_NO_THROW(downloader->finish_download().waitForFinished());834 ASSERT_NO_THROW(call(downloader->finish_download()));
789 }835 }
836}
837
838TEST(File, download_error)
839{
840 auto runtime = Runtime::create();
841
842 auto acc = get_account(runtime);
843 auto root = get_root(runtime);
844 clear_folder(root);
845
846 QByteArray const contents(1024 * 1024, 'a');
847 auto file = write_file(root, "file", contents);
848
849 auto downloader = call(file->create_downloader());
850 EXPECT_TRUE(file->equal_to(downloader->file()));
851
852 auto socket = downloader->socket();
853
854 {
855 // Wait for first readyRead. Not all data fits into the socket buffer.
856 QSignalSpy spy(socket.get(), &QLocalSocket::readyRead);
857 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
858 }
859
860 {
861 // Now close the socket, to force an error at the writing end.
862 // This gives us coverage of the error handling logic in the download worker.
863 socket->abort();
864 // Wait a little, to give the worker a chance to notice the problem.
865 // We don't wait for a signal here because all attempts to disable the
866 // socket (via close(), abort(), or disconnectFromServer() also
867 // stop the stateChanged signal from arriving.
868 QTimer timer;
869 QSignalSpy spy(&timer, &QTimer::timeout);
870 timer.start(1000);
871 spy.wait();
872 }
873
874 try
875 {
876 call(downloader->finish_download());
877 FAIL();
878 }
879 catch (ResourceException const& e)
880 {
881 EXPECT_TRUE(e.error_message().startsWith("Downloader: QLocalSocket: "));
882 }
883}
884
885TEST(File, size_error)
886{
887 auto runtime = Runtime::create();
888
889 auto acc = get_account(runtime);
890 auto root = get_root(runtime);
891 clear_folder(root);
892
893 auto file = write_file(root, "file", "");
894
895 ASSERT_EQ(0, system("rm " TEST_DIR "/storage-framework/file"));
896 EXPECT_THROW(file->size(), ResourceException);
790}897}
791898
792TEST(Item, move)899TEST(Item, move)
@@ -799,25 +906,22 @@
799906
800 // Check that rename works within the same folder.907 // Check that rename works within the same folder.
801 QByteArray const contents = "Hello\n";908 QByteArray const contents = "Hello\n";
802 write_file(root, "f1", contents);909 auto f1 = write_file(root, "f1", contents);
803 auto f1 = root->lookup("f1").result()[0];910 auto f2 = call(f1->move(root, "f2"));
804 auto f2 = f1->move(root, "f2").result();
805 EXPECT_EQ("f2", f2->name());
806 EXPECT_THROW(f1->name(), DeletedException); // TODO: check exception details.
807911
808 // File must be found under new name.912 // File must be found under new name.
809 auto items = root->list().result();913 auto items = call(root->list());
810 ASSERT_EQ(1, items.size());914 ASSERT_EQ(1, items.size());
811 f2 = dynamic_pointer_cast<File>(items[0]);915 f2 = dynamic_pointer_cast<File>(items[0]);
812 ASSERT_FALSE(f2 == nullptr);916 ASSERT_FALSE(f2 == nullptr);
813917
814 // Make a folder and move f2 into it.918 // Make a folder and move f2 into it.
815 auto folder = root->create_folder("folder").result();919 auto folder = call(root->create_folder("folder"));
816 f2 = f2->move(folder, "f2").result();920 f2 = call(f2->move(folder, "f2"));
817 EXPECT_TRUE(get_parent(f2)->equal_to(folder));921 EXPECT_TRUE(get_parent(f2)->equal_to(folder));
818922
819 // Move the folder923 // Move the folder
820 auto item = folder->move(root, "folder2").result();924 auto item = call(folder->move(root, "folder2"));
821 folder = dynamic_pointer_cast<Folder>(item);925 folder = dynamic_pointer_cast<Folder>(item);
822 EXPECT_EQ("folder2", folder->name());926 EXPECT_EQ("folder2", folder->name());
823}927}
@@ -831,10 +935,8 @@
831 clear_folder(root);935 clear_folder(root);
832936
833 QByteArray const contents = "hello\n";937 QByteArray const contents = "hello\n";
834 write_file(root, "file", contents);938 auto item = write_file(root, "file", contents);
835939 auto copied_item = call(item->copy(root, "copy_of_file"));
836 auto item = root->lookup("file").result()[0];
837 auto copied_item = item->copy(root, "copy_of_file").result();
838 EXPECT_EQ("copy_of_file", copied_item->name());940 EXPECT_EQ("copy_of_file", copied_item->name());
839 File::SPtr copied_file = dynamic_pointer_cast<File>(item);941 File::SPtr copied_file = dynamic_pointer_cast<File>(item);
840 ASSERT_NE(nullptr, copied_file);942 ASSERT_NE(nullptr, copied_file);
@@ -854,7 +956,9 @@
854 // folder/empty_folder956 // folder/empty_folder
855 // folder/non_empty_folder957 // folder/non_empty_folder
856 // folder/non_empty_folder/nested_file958 // folder/non_empty_folder/nested_file
959 // folder/non_empty_folder/<TMPFILE_PREFIX>1234-1234-1234-1234
857 // folder/file960 // folder/file
961 // folder/<TMPFILE_PREFIX>1234-1234-1234-1234
858962
859 string root_path = root->native_identity().toStdString();963 string root_path = root->native_identity().toStdString();
860 ASSERT_EQ(0, mkdir((root_path + "/folder").c_str(), 0700));964 ASSERT_EQ(0, mkdir((root_path + "/folder").c_str(), 0700));
@@ -863,23 +967,26 @@
863 ofstream(root_path + "/folder/non_empty_folder/nested_file");967 ofstream(root_path + "/folder/non_empty_folder/nested_file");
864 ofstream(root_path + "/folder/file");968 ofstream(root_path + "/folder/file");
865969
970 // Add dirs that look like a tmp dirs, to get coverage on skipping those.
971 ASSERT_EQ(0, mkdir((root_path + "/folder/" + TMPFILE_PREFIX "1234-1234-1234-1234").c_str(), 0700));
972 ASSERT_EQ(0, mkdir((root_path + "/folder/non_empty_folder/" + TMPFILE_PREFIX "1234-1234-1234-1234").c_str(), 0700));
866 // Copy folder to folder2973 // Copy folder to folder2
867 auto folder = dynamic_pointer_cast<Folder>(root->lookup("folder").result()[0]);974 auto folder = dynamic_pointer_cast<Folder>(call(root->lookup("folder"))[0]);
868 ASSERT_NE(nullptr, folder);975 ASSERT_NE(nullptr, folder);
869 auto item = folder->copy(root, "folder2").result();976 auto item = call(folder->copy(root, "folder2"));
870977
871 // Verify that folder2 now contains the same structure as folder.978 // Verify that folder2 now contains the same structure as folder.
872 auto folder2 = dynamic_pointer_cast<Folder>(item);979 auto folder2 = dynamic_pointer_cast<Folder>(item);
873 ASSERT_NE(nullptr, folder2);980 ASSERT_NE(nullptr, folder2);
874 EXPECT_NO_THROW(folder2->lookup("empty_folder").result()[0]);981 EXPECT_NO_THROW(call(folder2->lookup("empty_folder"))[0]);
875 item = folder2->lookup("non_empty_folder").result()[0];982 item = call(folder2->lookup("non_empty_folder"))[0];
876 auto non_empty_folder = dynamic_pointer_cast<Folder>(item);983 auto non_empty_folder = dynamic_pointer_cast<Folder>(item);
877 ASSERT_NE(nullptr, non_empty_folder);984 ASSERT_NE(nullptr, non_empty_folder);
878 EXPECT_NO_THROW(non_empty_folder->lookup("nested_file").result()[0]);985 EXPECT_NO_THROW(call(non_empty_folder->lookup("nested_file"))[0]);
879 EXPECT_NO_THROW(folder2->lookup("file").result()[0]);986 EXPECT_NO_THROW(call(folder2->lookup("file"))[0]);
880}987}
881988
882TEST(Item, modified_time)989TEST(Item, time)
883{990{
884 auto runtime = Runtime::create();991 auto runtime = Runtime::create();
885992
@@ -889,14 +996,15 @@
889996
890 auto now = QDateTime::currentDateTimeUtc();997 auto now = QDateTime::currentDateTimeUtc();
891 sleep(1);998 sleep(1);
892 auto uploader = root->create_file("file", 0).result();999 auto uploader = call(root->create_file("file", 0));
893 auto file_fut = uploader->finish_upload();1000 auto file = call(uploader->finish_upload());
894 ASSERT_TRUE(wait(file_fut));
895 auto file = file_fut.result();
896 auto t = file->last_modified_time();1001 auto t = file->last_modified_time();
897 // Rough check that the time is sane.1002 // Rough check that the time is sane.
898 EXPECT_LE(now, t);1003 EXPECT_LE(now, t);
899 EXPECT_LE(t, now.addSecs(5));1004 EXPECT_LE(t, now.addSecs(5));
1005
1006 auto creation_time = file->creation_time();
1007 EXPECT_FALSE(creation_time.isValid());
900}1008}
9011009
902TEST(Item, comparison)1010TEST(Item, comparison)
@@ -908,36 +1016,338 @@
908 clear_folder(root);1016 clear_folder(root);
9091017
910 // Create two files.1018 // Create two files.
911 auto uploader = root->create_file("file1", 0).result();1019 auto uploader = call(root->create_file("file1", 0));
912 auto file_fut = uploader->finish_upload();1020 auto file1 = call(uploader->finish_upload());
913 ASSERT_TRUE(wait(file_fut));
914 auto file1 = file_fut.result();
9151021
916 uploader = root->create_file("file2", 0).result();1022 uploader = call(root->create_file("file2", 0));
917 file_fut = uploader->finish_upload();1023 auto file2 = call(uploader->finish_upload());
918 ASSERT_TRUE(wait(file_fut));
919 auto file2 = file_fut.result();
9201024
921 EXPECT_FALSE(file1->equal_to(file2));1025 EXPECT_FALSE(file1->equal_to(file2));
9221026
923 // Retrieve file1 via lookup, so we get a different proxy.1027 // Retrieve file1 via lookup, so we get a different proxy.
924 auto item = root->lookup("file1").result()[0];1028 auto item = call(root->lookup("file1"))[0];
925 auto other_file1 = dynamic_pointer_cast<File>(item);1029 auto other_file1 = dynamic_pointer_cast<File>(item);
926 EXPECT_NE(file1, other_file1); // Compares shared_ptr values1030 EXPECT_NE(file1, other_file1); // Compares shared_ptr values
927 EXPECT_TRUE(file1->equal_to(other_file1)); // Deep comparison1031 EXPECT_TRUE(file1->equal_to(other_file1)); // Deep comparison
9281032
929 // Comparing against a deleted file must return false.1033 // Comparing against a deleted file must return false.
930 auto delete_fut = file1->delete_item();1034 call(file1->delete_item());
931 ASSERT_TRUE(wait(delete_fut));
932 EXPECT_FALSE(file1->equal_to(file2));1035 EXPECT_FALSE(file1->equal_to(file2));
933 EXPECT_FALSE(file2->equal_to(file1));1036 EXPECT_FALSE(file2->equal_to(file1));
9341037
935 // Delete file2 as well and compare again.1038 // Delete file2 as well and compare again.
936 delete_fut = file2->delete_item();1039 call(file2->delete_item());
937 ASSERT_TRUE(wait(delete_fut));
938 EXPECT_FALSE(file1->equal_to(file2));1040 EXPECT_FALSE(file1->equal_to(file2));
939}1041}
9401042
1043TEST(Item, exceptions)
1044{
1045 auto runtime = Runtime::create();
1046
1047 auto acc = get_account(runtime);
1048 auto root = get_root(runtime);
1049 clear_folder(root);
1050
1051 try
1052 {
1053 call(root->copy(nullptr, "new name"));
1054 FAIL();
1055 }
1056 catch (InvalidArgumentException const& e)
1057 {
1058 EXPECT_EQ("Item::copy(): new_parent cannot be nullptr", e.error_message());
1059 }
1060
1061 auto file = write_file(root, "file", 0);
1062
1063 try
1064 {
1065 call(file->copy(root, TMPFILE_PREFIX "copy_of_file"));
1066 FAIL();
1067 }
1068 catch (InvalidArgumentException const& e)
1069 {
1070 EXPECT_EQ("Item::copy(): names beginning with \".storage-framework-\" are reserved", e.error_message());
1071 }
1072
1073 try
1074 {
1075 call(file->copy(root, file->name()));
1076 FAIL();
1077 }
1078 catch (ExistsException const& e)
1079 {
1080 EXPECT_EQ("Item::copy(): item with name \"file\" exists already", e.error_message());
1081 EXPECT_EQ("file", e.name());
1082 EXPECT_EQ(TEST_DIR "/storage-framework/file", e.native_identity());
1083 }
1084
1085 try
1086 {
1087 auto file = write_file(root, "file", "");
1088 ASSERT_EQ(0, unlink(file->native_identity().toStdString().c_str()));
1089
1090 call(file->copy(root, file->name()));
1091 FAIL();
1092 }
1093 catch (ResourceException const& e)
1094 {
1095 EXPECT_TRUE(e.error_message().startsWith("Item::copy(): "));
1096 }
1097
1098 try
1099 {
1100 auto file = write_file(root, "file", "");
1101 ASSERT_EQ(0, unlink(file->native_identity().toStdString().c_str()));
1102
1103 call(file->move(root, "new_name"));
1104 FAIL();
1105 }
1106 catch (ResourceException const& e)
1107 {
1108 EXPECT_TRUE(e.error_message().startsWith("Item::move(): "));
1109 }
1110
1111 try
1112 {
1113 auto file = write_file(root, "file", "");
1114 ASSERT_EQ(0, unlink(file->native_identity().toStdString().c_str()));
1115 ASSERT_EQ(0, system("chmod -x " TEST_DIR "/storage-framework"));
1116
1117 call(file->delete_item());
1118 FAIL();
1119 }
1120 catch (PermissionException const& e)
1121 {
1122 ASSERT_EQ(0, system("chmod +x " TEST_DIR "/storage-framework"));
1123 EXPECT_TRUE(e.error_message().startsWith("Item::delete_item(): "));
1124 }
1125 catch (std::exception const&)
1126 {
1127 ASSERT_EQ(0, system("chmod +x " TEST_DIR "/storage-framework"));
1128 FAIL();
1129 }
1130 ASSERT_EQ(0, system("chmod +x " TEST_DIR "/storage-framework"));
1131
1132 try
1133 {
1134 call(root->move(nullptr, "new name"));
1135 FAIL();
1136 }
1137 catch (InvalidArgumentException const& e)
1138 {
1139 EXPECT_EQ("Item::move(): new_parent cannot be nullptr", e.error_message());
1140 }
1141
1142 try
1143 {
1144 call(root->move(root, "new name"));
1145 FAIL();
1146 }
1147 catch (LogicException const& e)
1148 {
1149 EXPECT_EQ("Item::move(): cannot move root folder", e.error_message());
1150 }
1151
1152 try
1153 {
1154 auto file = write_file(root, "file", "");
1155 call(file->move(root, file->name()));
1156 FAIL();
1157 }
1158 catch (ExistsException const& e)
1159 {
1160 EXPECT_EQ("Item::move(): item with name \"file\" exists already", e.error_message());
1161 EXPECT_EQ("file", e.name());
1162 EXPECT_EQ(TEST_DIR "/storage-framework/file", e.native_identity());
1163 }
1164
1165 try
1166 {
1167 call(file->move(root, TMPFILE_PREFIX "copy_of_file"));
1168 FAIL();
1169 }
1170 catch (InvalidArgumentException const& e)
1171 {
1172 EXPECT_EQ("Item::move(): names beginning with \".storage-framework-\" are reserved", e.error_message());
1173 }
1174
1175 try
1176 {
1177 call(root->lookup("abc/def"));
1178 }
1179 catch (InvalidArgumentException const& e)
1180 {
1181 EXPECT_EQ("Folder::lookup(): name \"abc/def\" contains more than one path component",
1182 e.error_message()) << e.what();
1183 }
1184
1185 try
1186 {
1187 call(root->create_folder(".."));
1188 }
1189 catch (InvalidArgumentException const& e)
1190 {
1191 EXPECT_EQ("Folder::create_folder(): invalid name: \"..\"", e.error_message()) << e.what();
1192 }
1193}
1194
1195TEST(Folder, exceptions)
1196{
1197 auto runtime = Runtime::create();
1198
1199 auto acc = get_account(runtime);
1200 auto root = get_root(runtime);
1201 clear_folder(root);
1202
1203 try
1204 {
1205 write_file(root, TMPFILE_PREFIX "file", "");
1206 call(root->lookup(TMPFILE_PREFIX "file"));
1207 FAIL();
1208 }
1209 catch (NotExistsException const& e)
1210 {
1211 string cmd = "rm ";
1212 cmd += string(TEST_DIR) + "/storage-framework/" + TMPFILE_PREFIX "file";
1213 ASSERT_EQ(0, system(cmd.c_str()));
1214 EXPECT_EQ("Folder::lookup(): no such item: \".storage-framework-file\"", e.error_message());
1215 EXPECT_EQ(".storage-framework-file", e.key());
1216 }
1217
1218 {
1219 auto fifo_id = root->native_identity() + "/fifo";
1220 string cmd = "mkfifo " + fifo_id.toStdString();
1221 ASSERT_EQ(0, system(cmd.c_str()));
1222
1223 try
1224 {
1225 call(root->lookup("fifo"));
1226 FAIL();
1227 }
1228 catch (NotExistsException const& e)
1229 {
1230 EXPECT_EQ("Folder::lookup(): no such item: \"fifo\"", e.error_message()) << e.what();
1231 EXPECT_EQ("fifo", e.key());
1232 }
1233
1234 cmd = "rm " + fifo_id.toStdString();
1235 ASSERT_EQ(0, system(cmd.c_str()));
1236 }
1237
1238 try
1239 {
1240 call(root->lookup("no_such_file"));
1241 FAIL();
1242 }
1243 catch (NotExistsException const& e)
1244 {
1245 EXPECT_EQ("Folder::lookup(): no such item: \"no_such_file\"", e.error_message());
1246 EXPECT_EQ("no_such_file", e.key());
1247 }
1248
1249 try
1250 {
1251 call(root->create_folder(TMPFILE_PREFIX "folder"));
1252 FAIL();
1253 }
1254 catch (InvalidArgumentException const& e)
1255 {
1256 EXPECT_EQ("Folder::create_folder(): names beginning with \".storage-framework-\" are reserved", e.error_message());
1257 }
1258
1259 try
1260 {
1261 EXPECT_NO_THROW(call(root->create_folder("folder")));
1262 call(root->create_folder("folder"));
1263 FAIL();
1264 }
1265 catch (ExistsException const& e)
1266 {
1267 EXPECT_EQ("Folder::create_folder(): item with name \"folder\" exists already", e.error_message());
1268 EXPECT_EQ("folder", e.name());
1269 EXPECT_EQ(TEST_DIR "/storage-framework/folder", e.native_identity());
1270 }
1271
1272 try
1273 {
1274 call(root->create_file("new_file", -1));
1275 FAIL();
1276 }
1277 catch (InvalidArgumentException const& e)
1278 {
1279 EXPECT_EQ("Folder::create_file(): size must be >= 0", e.error_message());
1280 }
1281
1282 try
1283 {
1284 call(root->create_file(TMPFILE_PREFIX "new_file", 0));
1285 FAIL();
1286 }
1287 catch (InvalidArgumentException const& e)
1288 {
1289 EXPECT_EQ("Folder::create_file(): names beginning with \".storage-framework-\" are reserved", e.error_message());
1290 }
1291
1292 try
1293 {
1294 write_file(root, "file", "");
1295 call(root->create_file("file", 0));
1296 FAIL();
1297 }
1298 catch (ExistsException const& e)
1299 {
1300 EXPECT_EQ("Folder::create_file(): item with name \"file\" exists already", e.error_message());
1301 EXPECT_EQ("file", e.name());
1302 EXPECT_EQ(TEST_DIR "/storage-framework/file", e.native_identity());
1303 }
1304
1305 ASSERT_EQ(0, system("chmod -x " TEST_DIR "/storage-framework"));
1306 try
1307 {
1308 call(root->create_file("new_file", 0));
1309 FAIL();
1310 }
1311 catch (PermissionException const& e)
1312 {
1313 EXPECT_TRUE(e.error_message().startsWith("Folder::create_file(): "));
1314 ASSERT_EQ(0, system("chmod +x " TEST_DIR "/storage-framework"));
1315 }
1316 catch (std::exception const& e)
1317 {
1318 ASSERT_EQ(0, system("chmod +x " TEST_DIR "/storage-framework"));
1319 FAIL();
1320 }
1321 ASSERT_EQ(0, system("chmod +x " TEST_DIR "/storage-framework"));
1322
1323 ASSERT_EQ(0, system("chmod -x " TEST_DIR "/storage-framework"));
1324 try
1325 {
1326 call(root->create_folder("new_folder"));
1327 FAIL();
1328 }
1329 catch (PermissionException const& e)
1330 {
1331 EXPECT_TRUE(e.error_message().startsWith("Folder::create_folder(): "));
1332 ASSERT_EQ(0, system("chmod +x " TEST_DIR "/storage-framework"));
1333 }
1334 catch (std::exception const& e)
1335 {
1336 ASSERT_EQ(0, system("chmod +x " TEST_DIR "/storage-framework"));
1337 FAIL();
1338 }
1339 ASSERT_EQ(0, system("chmod +x " TEST_DIR "/storage-framework"));
1340
1341 try
1342 {
1343 call(root->create_file("new_file", -1));
1344 }
1345 catch (InvalidArgumentException const& e)
1346 {
1347 EXPECT_EQ("Folder::create_file(): size must be >= 0", e.error_message());
1348 }
1349}
1350
941TEST(Root, root_exceptions)1351TEST(Root, root_exceptions)
942{1352{
943 auto runtime = Runtime::create();1353 auto runtime = Runtime::create();
@@ -946,51 +1356,39 @@
946 auto root = get_root(runtime);1356 auto root = get_root(runtime);
947 clear_folder(root);1357 clear_folder(root);
9481358
949 {1359 try
950 auto fut = root->delete_item();1360 {
951 try1361 call(root->delete_item());
952 {1362 FAIL();
953 fut.waitForFinished();1363 }
954 FAIL();1364 catch (LogicException const& e)
955 }1365 {
956 catch (LogicException const& e)1366 EXPECT_EQ("Root::delete_item(): Cannot delete root folder", e.error_message());
957 {1367 }
958 EXPECT_EQ("Root::delete_item(): Cannot delete root folder", e.error_message());1368
959 }1369 try
960 }1370 {
9611371 call(root->get("abc"));
962 {1372 FAIL();
963 auto fut = root->get("abc");1373 }
964 try1374 catch (InvalidArgumentException const& e)
965 {1375 {
966 fut.waitForFinished();1376 EXPECT_EQ("Root::get(): identity \"abc\" must be an absolute path", e.error_message());
967 FAIL();1377 }
968 }1378
969 catch (InvalidArgumentException const& e)1379 try
970 {1380 {
971 EXPECT_EQ("Root::get(): identity \"abc\" must be an absolute path", e.error_message());1381 call(root->get("/etc"));
972 }1382 FAIL();
973 }1383 }
9741384 catch (InvalidArgumentException const& e)
975 {1385 {
976 auto fut = root->get("/etc");1386 EXPECT_EQ("Root::get(): identity \"/etc\" points outside the root folder", e.error_message());
977 try1387 }
978 {1388
979 fut.waitForFinished();1389 {
980 FAIL();1390 auto folder = call(root->create_folder("folder"));
981 }1391 auto file = write_file(folder, "testfile", "hello");
982 catch (InvalidArgumentException const& e)
983 {
984 EXPECT_EQ("Root::get(): identity \"/etc\" points outside the root folder", e.error_message());
985 }
986 }
987
988 {
989 auto folder = root->create_folder("folder").result();
990 write_file(root, "folder/testfile", "hello");
991
992 auto file = dynamic_pointer_cast<File>(folder->lookup("testfile").result()[0]);
993 ASSERT_NE(nullptr, file);
9941392
995 // Remove permission from folder.1393 // Remove permission from folder.
996 string cmd = "chmod -x " + folder->native_identity().toStdString();1394 string cmd = "chmod -x " + folder->native_identity().toStdString();
@@ -998,7 +1396,7 @@
9981396
999 try1397 try
1000 {1398 {
1001 file = dynamic_pointer_cast<File>(root->get(file->native_identity()).result());1399 file = dynamic_pointer_cast<File>(call(root->get(file->native_identity())));
1002 FAIL();1400 FAIL();
1003 }1401 }
1004 catch (PermissionException const& e)1402 catch (PermissionException const& e)
@@ -1006,6 +1404,11 @@
1006 EXPECT_TRUE(e.error_message().startsWith("Root::get(): "));1404 EXPECT_TRUE(e.error_message().startsWith("Root::get(): "));
1007 EXPECT_TRUE(e.error_message().contains("Permission denied"));1405 EXPECT_TRUE(e.error_message().contains("Permission denied"));
1008 }1406 }
1407 catch (...)
1408 {
1409 cmd = "chmod +x " + folder->native_identity().toStdString();
1410 ASSERT_EQ(0, system(cmd.c_str()));
1411 }
10091412
1010 cmd = "chmod +x " + folder->native_identity().toStdString();1413 cmd = "chmod +x " + folder->native_identity().toStdString();
1011 ASSERT_EQ(0, system(cmd.c_str()));1414 ASSERT_EQ(0, system(cmd.c_str()));
@@ -1014,17 +1417,14 @@
1014 }1417 }
10151418
1016 {1419 {
1017 write_file(root, "testfile", "hello");1420 auto file = write_file(root, "testfile", "hello");
1018
1019 auto file = dynamic_pointer_cast<File>(root->lookup("testfile").result()[0]);
1020 ASSERT_NE(nullptr, file);
10211421
1022 QString id = file->native_identity();1422 QString id = file->native_identity();
1023 id.append("_doesnt_exist");1423 id.append("_doesnt_exist");
10241424
1025 try1425 try
1026 {1426 {
1027 file = dynamic_pointer_cast<File>(root->get(id).result());1427 file = dynamic_pointer_cast<File>(call(root->get(id)));
1028 FAIL();1428 FAIL();
1029 }1429 }
1030 catch (NotExistsException const& e)1430 catch (NotExistsException const& e)
@@ -1042,7 +1442,7 @@
10421442
1043 try1443 try
1044 {1444 {
1045 root->get(fifo_id).result();1445 call(root->get(fifo_id));
1046 FAIL();1446 FAIL();
1047 }1447 }
1048 catch (NotExistsException const& e)1448 catch (NotExistsException const& e)
@@ -1051,17 +1451,20 @@
1051 }1451 }
10521452
1053 cmd = "rm " + fifo_id.toStdString();1453 cmd = "rm " + fifo_id.toStdString();
1054 system(cmd.c_str());1454 ASSERT_EQ(0, system(cmd.c_str()));
1055 }1455 }
10561456
1057 {1457 {
1058 QString reserved_name = TMPFILE_PREFIX "somefile";1458 string reserved_name = TMPFILE_PREFIX "somefile";
1059 write_file(root, reserved_name, "some bytes");1459 string full_path = string(TEST_DIR) + "/storage-framework/" + reserved_name;
1460 string cmd = "touch ";
1461 cmd += full_path;
1462 ASSERT_EQ(0, system(cmd.c_str()));
10601463
1061 auto reserved_id = QString(TEST_DIR) + "/storage-framework/" + reserved_name;1464 auto reserved_id = QString::fromStdString(full_path);
1062 try1465 try
1063 {1466 {
1064 root->get(reserved_id).result();1467 call(root->get(reserved_id));
1065 FAIL();1468 FAIL();
1066 }1469 }
1067 catch (NotExistsException const& e)1470 catch (NotExistsException const& e)
@@ -1073,27 +1476,6 @@
1073 }1476 }
1074}1477}
10751478
1076File::SPtr make_deleted_file(Folder::SPtr parent, QString const& name)
1077{
1078 write_file(parent, name, "bytes");
1079 auto file_fut = parent->lookup("file");
1080 assert(wait(file_fut));
1081 auto file = dynamic_pointer_cast<File>(file_fut.result()[0]);
1082 auto void_fut = file->delete_item();
1083 assert(wait(void_fut));
1084 return file;
1085}
1086
1087Folder::SPtr make_deleted_folder(Folder::SPtr parent, QString const& name)
1088{
1089 auto fut = parent->create_folder(name);
1090 assert(wait(fut));
1091 auto folder = fut.result();
1092 auto void_fut = folder->delete_item();
1093 assert(wait(void_fut));
1094 return folder;
1095}
1096
1097TEST(Item, deleted_exceptions)1479TEST(Item, deleted_exceptions)
1098{1480{
1099 auto runtime = Runtime::create();1481 auto runtime = Runtime::create();
@@ -1110,7 +1492,6 @@
1110 }1492 }
1111 catch (DeletedException const& e)1493 catch (DeletedException const& e)
1112 {1494 {
1113 EXPECT_EQ("file", e.name());
1114 EXPECT_TRUE(e.error_message().startsWith("Item::etag(): "));1495 EXPECT_TRUE(e.error_message().startsWith("Item::etag(): "));
1115 EXPECT_TRUE(e.error_message().endsWith(" was deleted previously"));1496 EXPECT_TRUE(e.error_message().endsWith(" was deleted previously"));
1116 EXPECT_EQ(TEST_DIR "/storage-framework/file", e.native_identity());1497 EXPECT_EQ(TEST_DIR "/storage-framework/file", e.native_identity());
@@ -1124,7 +1505,6 @@
1124 }1505 }
1125 catch (DeletedException const& e)1506 catch (DeletedException const& e)
1126 {1507 {
1127 EXPECT_EQ("file", e.name());
1128 EXPECT_TRUE(e.error_message().startsWith("Item::metadata(): "));1508 EXPECT_TRUE(e.error_message().startsWith("Item::metadata(): "));
1129 }1509 }
11301510
@@ -1136,7 +1516,6 @@
1136 }1516 }
1137 catch (DeletedException const& e)1517 catch (DeletedException const& e)
1138 {1518 {
1139 EXPECT_EQ("file", e.name());
1140 EXPECT_TRUE(e.error_message().startsWith("Item::last_modified_time(): "));1519 EXPECT_TRUE(e.error_message().startsWith("Item::last_modified_time(): "));
1141 }1520 }
11421521
@@ -1144,14 +1523,11 @@
1144 {1523 {
1145 // Copying deleted file must fail.1524 // Copying deleted file must fail.
1146 auto file = make_deleted_file(root, "file");1525 auto file = make_deleted_file(root, "file");
1147 auto fut = file->copy(root, "copy_of_file");1526 call(file->copy(root, "copy_of_file"));
1148 ASSERT_TRUE(wait(fut));
1149 fut.result();
1150 FAIL();1527 FAIL();
1151 }1528 }
1152 catch (DeletedException const& e)1529 catch (DeletedException const& e)
1153 {1530 {
1154 EXPECT_EQ("file", e.name());
1155 EXPECT_TRUE(e.error_message().startsWith("Item::copy(): "));1531 EXPECT_TRUE(e.error_message().startsWith("Item::copy(): "));
1156 }1532 }
11571533
@@ -1160,30 +1536,20 @@
1160 // Copying file into deleted folder must fail.1536 // Copying file into deleted folder must fail.
11611537
1162 // Make target folder.1538 // Make target folder.
1163 auto fut = root->create_folder("folder");1539 auto folder = call(root->create_folder("folder"));
1164 ASSERT_TRUE(wait(fut));
1165 auto folder = fut.result();
11661540
1167 // Make a file in the root.1541 // Make a file in the root.
1168 auto uploader_fut = root->create_file("file", 0);1542 auto uploader = call(root->create_file("file", 0));
1169 ASSERT_TRUE(wait(uploader_fut));1543 auto file = call(uploader->finish_upload());
1170 auto uploader = uploader_fut.result();
1171 auto finish_fut = uploader->finish_upload();
1172 ASSERT_TRUE(wait(finish_fut));
1173 auto file = finish_fut.result();
11741544
1175 // Delete folder.1545 // Delete folder.
1176 auto void_fut = folder->delete_item();1546 call(folder->delete_item());
1177 ASSERT_TRUE(wait(void_fut));
11781547
1179 auto copy_fut = file->copy(folder, "file");1548 call(file->copy(folder, "file"));
1180 ASSERT_TRUE(wait(copy_fut));
1181 copy_fut.result();
1182 FAIL();1549 FAIL();
1183 }1550 }
1184 catch (DeletedException const& e)1551 catch (DeletedException const& e)
1185 {1552 {
1186 EXPECT_EQ("folder", e.name());
1187 EXPECT_TRUE(e.error_message().startsWith("Item::copy(): "));1553 EXPECT_TRUE(e.error_message().startsWith("Item::copy(): "));
1188 }1554 }
1189 clear_folder(root);1555 clear_folder(root);
@@ -1192,14 +1558,11 @@
1192 {1558 {
1193 // Moving deleted file must fail.1559 // Moving deleted file must fail.
1194 auto file = make_deleted_file(root, "file");1560 auto file = make_deleted_file(root, "file");
1195 auto fut = file->move(root, "moved_file");1561 call(file->move(root, "moved_file"));
1196 ASSERT_TRUE(wait(fut));
1197 fut.result();
1198 FAIL();1562 FAIL();
1199 }1563 }
1200 catch (DeletedException const& e)1564 catch (DeletedException const& e)
1201 {1565 {
1202 EXPECT_EQ("file", e.name());
1203 EXPECT_TRUE(e.error_message().startsWith("Item::move(): "));1566 EXPECT_TRUE(e.error_message().startsWith("Item::move(): "));
1204 }1567 }
12051568
@@ -1208,30 +1571,20 @@
1208 // Moving file into deleted folder must fail.1571 // Moving file into deleted folder must fail.
12091572
1210 // Make target folder.1573 // Make target folder.
1211 auto fut = root->create_folder("folder");1574 auto folder = call(root->create_folder("folder"));
1212 ASSERT_TRUE(wait(fut));
1213 auto folder = fut.result();
12141575
1215 // Make a file in the root.1576 // Make a file in the root.
1216 auto uploader_fut = root->create_file("file", 0);1577 auto uploader = call(root->create_file("file", 0));
1217 ASSERT_TRUE(wait(uploader_fut));1578 auto file = call(uploader->finish_upload());
1218 auto uploader = uploader_fut.result();
1219 auto finish_fut = uploader->finish_upload();
1220 ASSERT_TRUE(wait(finish_fut));
1221 auto file = finish_fut.result();
12221579
1223 // Delete folder.1580 // Delete folder.
1224 auto void_fut = folder->delete_item();1581 call(folder->delete_item());
1225 ASSERT_TRUE(wait(void_fut));
12261582
1227 auto move_fut = file->move(folder, "file");1583 call(file->move(folder, "file"));
1228 ASSERT_TRUE(wait(move_fut));
1229 move_fut.result();
1230 FAIL();1584 FAIL();
1231 }1585 }
1232 catch (DeletedException const& e)1586 catch (DeletedException const& e)
1233 {1587 {
1234 EXPECT_EQ("folder", e.name());
1235 EXPECT_TRUE(e.error_message().startsWith("Item::move(): "));1588 EXPECT_TRUE(e.error_message().startsWith("Item::move(): "));
1236 }1589 }
1237 clear_folder(root);1590 clear_folder(root);
@@ -1239,12 +1592,11 @@
1239 try1592 try
1240 {1593 {
1241 auto file = make_deleted_file(root, "file");1594 auto file = make_deleted_file(root, "file");
1242 file->parents().result();1595 call(file->parents());
1243 FAIL();1596 FAIL();
1244 }1597 }
1245 catch (DeletedException const& e)1598 catch (DeletedException const& e)
1246 {1599 {
1247 EXPECT_EQ("file", e.name());
1248 EXPECT_TRUE(e.error_message().startsWith("Item::parents(): "));1600 EXPECT_TRUE(e.error_message().startsWith("Item::parents(): "));
1249 }1601 }
12501602
@@ -1256,7 +1608,6 @@
1256 }1608 }
1257 catch (DeletedException const& e)1609 catch (DeletedException const& e)
1258 {1610 {
1259 EXPECT_EQ("file", e.name());
1260 EXPECT_TRUE(e.error_message().startsWith("Item::parent_ids(): "));1611 EXPECT_TRUE(e.error_message().startsWith("Item::parent_ids(): "));
1261 }1612 }
12621613
@@ -1264,14 +1615,11 @@
1264 {1615 {
1265 // Deleting a deleted item must fail.1616 // Deleting a deleted item must fail.
1266 auto file = make_deleted_file(root, "file");1617 auto file = make_deleted_file(root, "file");
1267 auto delete_fut = file->delete_item();1618 call(file->delete_item());
1268 ASSERT_TRUE(wait(delete_fut));
1269 delete_fut.waitForFinished();
1270 FAIL();1619 FAIL();
1271 }1620 }
1272 catch (DeletedException const& e)1621 catch (DeletedException const& e)
1273 {1622 {
1274 EXPECT_EQ("file", e.name());
1275 EXPECT_TRUE(e.error_message().startsWith("Item::delete_item(): "));1623 EXPECT_TRUE(e.error_message().startsWith("Item::delete_item(): "));
1276 }1624 }
1277}1625}
@@ -1292,65 +1640,146 @@
1292 }1640 }
1293 catch (DeletedException const& e)1641 catch (DeletedException const& e)
1294 {1642 {
1295 EXPECT_EQ("folder", e.name());
1296 EXPECT_TRUE(e.error_message().startsWith("Folder::name(): "));1643 EXPECT_TRUE(e.error_message().startsWith("Folder::name(): "));
1297 }1644 }
12981645
1299 try1646 try
1300 {1647 {
1301 auto folder = make_deleted_folder(root, "folder");1648 auto folder = make_deleted_folder(root, "folder");
1302 auto fut = folder->list();1649 call(folder->list());
1303 ASSERT_TRUE(wait(fut));
1304 fut.result();
1305 FAIL();1650 FAIL();
1306 }1651 }
1307 catch (DeletedException const& e)1652 catch (DeletedException const& e)
1308 {1653 {
1309 EXPECT_EQ("folder", e.name());
1310 EXPECT_TRUE(e.error_message().startsWith("Folder::list(): "));1654 EXPECT_TRUE(e.error_message().startsWith("Folder::list(): "));
1311 }1655 }
13121656
1313 try1657 try
1314 {1658 {
1315 auto folder = make_deleted_folder(root, "folder");1659 auto folder = make_deleted_folder(root, "folder");
1316 auto fut = folder->lookup("something");1660 call(folder->lookup("something"));
1317 ASSERT_TRUE(wait(fut));
1318 fut.result();
1319 FAIL();1661 FAIL();
1320 }1662 }
1321 catch (DeletedException const& e)1663 catch (DeletedException const& e)
1322 {1664 {
1323 EXPECT_EQ("folder", e.name());
1324 EXPECT_TRUE(e.error_message().startsWith("Folder::lookup(): "));1665 EXPECT_TRUE(e.error_message().startsWith("Folder::lookup(): "));
1325 }1666 }
13261667
1327 try1668 try
1328 {1669 {
1329 auto folder = make_deleted_folder(root, "folder");1670 auto folder = make_deleted_folder(root, "folder");
1330 auto fut = folder->create_folder("nested_folder");1671 call(folder->list());
1331 ASSERT_TRUE(wait(fut));1672 FAIL();
1332 fut.result();1673 }
1333 FAIL();1674 catch (DeletedException const& e)
1334 }1675 {
1335 catch (DeletedException const& e)1676 EXPECT_TRUE(e.error_message().startsWith("Folder::list(): "));
1336 {1677 }
1337 EXPECT_EQ("folder", e.name());1678
1679 try
1680 {
1681 auto folder = make_deleted_folder(root, "folder");
1682 call(folder->create_folder("nested_folder"));
1683 FAIL();
1684 }
1685 catch (DeletedException const& e)
1686 {
1338 EXPECT_TRUE(e.error_message().startsWith("Folder::create_folder(): "));1687 EXPECT_TRUE(e.error_message().startsWith("Folder::create_folder(): "));
1339 }1688 }
13401689
1341 try1690 try
1342 {1691 {
1343 auto folder = make_deleted_folder(root, "folder");1692 auto folder = make_deleted_folder(root, "folder");
1344 auto fut = folder->create_file("nested_file", 0);1693 call(folder->create_file("nested_file", 0));
1345 ASSERT_TRUE(wait(fut));
1346 fut.result();
1347 FAIL();1694 FAIL();
1348 }1695 }
1349 catch (DeletedException const& e)1696 catch (DeletedException const& e)
1350 {1697 {
1351 EXPECT_EQ("folder", e.name());
1352 EXPECT_TRUE(e.error_message().startsWith("Folder::create_file(): "));1698 EXPECT_TRUE(e.error_message().startsWith("Folder::create_file(): "));
1353 }1699 }
1700
1701 try
1702 {
1703 auto folder = make_deleted_folder(root, "folder");
1704 folder->creation_time();
1705 FAIL();
1706 }
1707 catch (DeletedException const& e)
1708 {
1709 EXPECT_TRUE(e.error_message().startsWith("Item::creation_time(): ")) << e.what();
1710 }
1711
1712 try
1713 {
1714 auto folder = make_deleted_folder(root, "folder");
1715 folder->native_metadata();
1716 FAIL();
1717 }
1718 catch (DeletedException const& e)
1719 {
1720 EXPECT_TRUE(e.error_message().startsWith("Item::native_metadata(): ")) << e.what();
1721 }
1722}
1723
1724TEST(File, deleted_exceptions)
1725{
1726 auto runtime = Runtime::create();
1727
1728 auto acc = get_account(runtime);
1729 auto root = get_root(runtime);
1730 clear_folder(root);
1731
1732 try
1733 {
1734 auto file = make_deleted_file(root, "file");
1735 file->name();
1736 FAIL();
1737 }
1738 catch (DeletedException const& e)
1739 {
1740 EXPECT_TRUE(e.error_message().startsWith("File::name(): "));
1741 EXPECT_TRUE(e.error_message().endsWith(" was deleted previously"));
1742 EXPECT_EQ(TEST_DIR "/storage-framework/file", e.native_identity());
1743 }
1744
1745 try
1746 {
1747 auto file = make_deleted_file(root, "file");
1748 file->size();
1749 FAIL();
1750 }
1751 catch (DeletedException const& e)
1752 {
1753 EXPECT_TRUE(e.error_message().startsWith("File::size(): "));
1754 EXPECT_TRUE(e.error_message().endsWith(" was deleted previously"));
1755 EXPECT_EQ(TEST_DIR "/storage-framework/file", e.native_identity());
1756 }
1757
1758 try
1759 {
1760 auto file = make_deleted_file(root, "file");
1761 call(file->create_uploader(ConflictPolicy::overwrite, 0));
1762 FAIL();
1763 }
1764 catch (DeletedException const& e)
1765 {
1766 EXPECT_TRUE(e.error_message().startsWith("File::create_uploader(): "));
1767 EXPECT_TRUE(e.error_message().endsWith(" was deleted previously"));
1768 EXPECT_EQ(TEST_DIR "/storage-framework/file", e.native_identity());
1769 }
1770
1771 try
1772 {
1773 auto file = make_deleted_file(root, "file");
1774 call(file->create_downloader());
1775 FAIL();
1776 }
1777 catch (DeletedException const& e)
1778 {
1779 EXPECT_TRUE(e.error_message().startsWith("File::create_downloader(): "));
1780 EXPECT_TRUE(e.error_message().endsWith(" was deleted previously"));
1781 EXPECT_EQ(TEST_DIR "/storage-framework/file", e.native_identity());
1782 }
1354}1783}
13551784
1356TEST(Runtime, runtime_destroyed_exceptions)1785TEST(Runtime, runtime_destroyed_exceptions)
@@ -1387,6 +1816,21 @@
1387 }1816 }
1388 }1817 }
13891818
1819 // Getting accounts after shutting down the runtime must fail.
1820 {
1821 auto runtime = Runtime::create();
1822 runtime->shutdown();
1823 try
1824 {
1825 runtime->accounts();
1826 FAIL();
1827 }
1828 catch (RuntimeDestroyedException const& e)
1829 {
1830 EXPECT_EQ("Runtime::accounts(): Runtime was destroyed previously", e.error_message());
1831 }
1832 }
1833
1390 // Getting the account from a root with a destroyed runtime must fail.1834 // Getting the account from a root with a destroyed runtime must fail.
1391 {1835 {
1392 auto runtime = Runtime::create();1836 auto runtime = Runtime::create();
@@ -1429,13 +1873,7 @@
1429 auto root = get_root(runtime);1873 auto root = get_root(runtime);
1430 clear_folder(root);1874 clear_folder(root);
14311875
1432 auto create_fut = root->create_file("file1", 0);1876 auto file = write_file(root, "file", "");
1433 ASSERT_TRUE(wait(create_fut));
1434 auto uploader = create_fut.result();
1435 auto finish_fut = uploader->finish_upload();
1436 ASSERT_TRUE(wait(finish_fut));
1437 auto file = finish_fut.result();
1438
1439 runtime.reset();1877 runtime.reset();
1440 try1878 try
1441 {1879 {
@@ -1455,17 +1893,9 @@
1455 auto root = get_root(runtime);1893 auto root = get_root(runtime);
1456 clear_folder(root);1894 clear_folder(root);
14571895
1458 auto create_fut = root->create_file("file1", 0);1896 auto file = write_file(root, "file", "");
1459 ASSERT_TRUE(wait(create_fut));
1460 auto uploader = create_fut.result();
1461 auto finish_fut = uploader->finish_upload();
1462 ASSERT_TRUE(wait(finish_fut));
1463 auto file = finish_fut.result();
1464
1465 runtime.reset();1897 runtime.reset();
1466 qDebug() << "shared count:" << acc.use_count();
1467 acc.reset();1898 acc.reset();
1468 qDebug() << "shared count:" << acc.use_count();
1469 root.reset();1899 root.reset();
1470 try1900 try
1471 {1901 {
@@ -1478,7 +1908,515 @@
1478 }1908 }
1479 }1909 }
14801910
1481 // TODO: Lots more places to cover here.1911 // etag() with destroyed runtime must fail.
1912 {
1913 auto runtime = Runtime::create();
1914 auto acc = get_account(runtime);
1915 auto root = get_root(runtime);
1916 clear_folder(root);
1917
1918 auto file = write_file(root, "file", "");
1919 runtime->shutdown();
1920 try
1921 {
1922 file->etag();
1923 FAIL();
1924 }
1925 catch (RuntimeDestroyedException const& e)
1926 {
1927 EXPECT_EQ("Item::etag(): Runtime was destroyed previously", e.error_message());
1928 }
1929 }
1930
1931 // metadata() with destroyed runtime must fail.
1932 {
1933 auto runtime = Runtime::create();
1934 auto acc = get_account(runtime);
1935 auto root = get_root(runtime);
1936 clear_folder(root);
1937
1938 auto file = write_file(root, "file", "");
1939 runtime->shutdown();
1940 try
1941 {
1942 file->metadata();
1943 FAIL();
1944 }
1945 catch (RuntimeDestroyedException const& e)
1946 {
1947 EXPECT_EQ("Item::metadata(): Runtime was destroyed previously", e.error_message());
1948 }
1949 }
1950
1951 // last_modified_time() with destroyed runtime must fail.
1952 {
1953 auto runtime = Runtime::create();
1954 auto acc = get_account(runtime);
1955 auto root = get_root(runtime);
1956 clear_folder(root);
1957
1958 auto file = write_file(root, "file", "");
1959 runtime->shutdown();
1960 try
1961 {
1962 file->last_modified_time();
1963 FAIL();
1964 }
1965 catch (RuntimeDestroyedException const& e)
1966 {
1967 EXPECT_EQ("Item::last_modified_time(): Runtime was destroyed previously", e.error_message());
1968 }
1969 }
1970
1971 // copy() with destroyed runtime must fail.
1972 {
1973 auto runtime = Runtime::create();
1974 auto acc = get_account(runtime);
1975 auto root = get_root(runtime);
1976 clear_folder(root);
1977
1978 auto file = write_file(root, "file", "");
1979 runtime->shutdown();
1980 try
1981 {
1982 call(file->copy(root, "file2"));
1983 FAIL();
1984 }
1985 catch (RuntimeDestroyedException const& e)
1986 {
1987 EXPECT_EQ("Item::copy(): Runtime was destroyed previously", e.error_message());
1988 }
1989 }
1990
1991 // move() with destroyed runtime must fail.
1992 {
1993 auto runtime = Runtime::create();
1994 auto acc = get_account(runtime);
1995 auto root = get_root(runtime);
1996 clear_folder(root);
1997
1998 auto file = write_file(root, "file", "");
1999 runtime->shutdown();
2000 try
2001 {
2002 call(file->move(root, "file2"));
2003 FAIL();
2004 }
2005 catch (RuntimeDestroyedException const& e)
2006 {
2007 EXPECT_EQ("Item::move(): Runtime was destroyed previously", e.error_message());
2008 }
2009 }
2010
2011 // parents() on root with destroyed runtime must fail.
2012 {
2013 auto runtime = Runtime::create();
2014 auto acc = get_account(runtime);
2015 auto root = get_root(runtime);
2016 clear_folder(root);
2017
2018 auto file = write_file(root, "file", "");
2019 runtime->shutdown();
2020 try
2021 {
2022 call(root->parents());
2023 FAIL();
2024 }
2025 catch (RuntimeDestroyedException const& e)
2026 {
2027 EXPECT_EQ("Root::parents(): Runtime was destroyed previously", e.error_message());
2028 }
2029 }
2030
2031 // parents() on file with destroyed runtime must fail.
2032 {
2033 auto runtime = Runtime::create();
2034 auto acc = get_account(runtime);
2035 auto root = get_root(runtime);
2036 clear_folder(root);
2037
2038 auto file = write_file(root, "file", "");
2039 runtime->shutdown();
2040 try
2041 {
2042 call(file->parents());
2043 FAIL();
2044 }
2045 catch (RuntimeDestroyedException const& e)
2046 {
2047 EXPECT_EQ("Item::parents(): Runtime was destroyed previously", e.error_message());
2048 }
2049 }
2050
2051 // parent_ids() with destroyed runtime must fail.
2052 {
2053 auto runtime = Runtime::create();
2054 auto acc = get_account(runtime);
2055 auto root = get_root(runtime);
2056 clear_folder(root);
2057
2058 auto file = write_file(root, "file", "");
2059 runtime->shutdown();
2060 try
2061 {
2062 file->parent_ids();
2063 FAIL();
2064 }
2065 catch (RuntimeDestroyedException const& e)
2066 {
2067 EXPECT_EQ("Item::parent_ids(): Runtime was destroyed previously", e.error_message());
2068 }
2069 }
2070
2071 // parent_ids() on root with destroyed runtime must fail.
2072 {
2073 auto runtime = Runtime::create();
2074 auto acc = get_account(runtime);
2075 auto root = get_root(runtime);
2076 clear_folder(root);
2077
2078 runtime->shutdown();
2079 try
2080 {
2081 root->parent_ids();
2082 FAIL();
2083 }
2084 catch (RuntimeDestroyedException const& e)
2085 {
2086 EXPECT_EQ("Root::parent_ids(): Runtime was destroyed previously", e.error_message());
2087 }
2088 }
2089
2090 // delete_item() with destroyed runtime must fail.
2091 {
2092 auto runtime = Runtime::create();
2093 auto acc = get_account(runtime);
2094 auto root = get_root(runtime);
2095 clear_folder(root);
2096
2097 auto file = write_file(root, "file", "");
2098 runtime->shutdown();
2099 try
2100 {
2101 call(file->delete_item());
2102 FAIL();
2103 }
2104 catch (RuntimeDestroyedException const& e)
2105 {
2106 EXPECT_EQ("Item::delete_item(): Runtime was destroyed previously", e.error_message());
2107 }
2108 }
2109
2110 // delete_item() on root with destroyed runtime must fail.
2111 {
2112 auto runtime = Runtime::create();
2113 auto acc = get_account(runtime);
2114 auto root = get_root(runtime);
2115 clear_folder(root);
2116
2117 runtime->shutdown();
2118 try
2119 {
2120 call(root->delete_item());
2121 FAIL();
2122 }
2123 catch (RuntimeDestroyedException const& e)
2124 {
2125 EXPECT_EQ("Root::delete_item(): Runtime was destroyed previously", e.error_message());
2126 }
2127 }
2128
2129 // creation_time() with destroyed runtime must fail.
2130 {
2131 auto runtime = Runtime::create();
2132 auto acc = get_account(runtime);
2133 auto root = get_root(runtime);
2134 clear_folder(root);
2135
2136 auto file = write_file(root, "file", "");
2137 runtime->shutdown();
2138 try
2139 {
2140 file->creation_time();
2141 FAIL();
2142 }
2143 catch (RuntimeDestroyedException const& e)
2144 {
2145 EXPECT_EQ("Item::creation_time(): Runtime was destroyed previously", e.error_message());
2146 }
2147 }
2148
2149 // native_metadata() with destroyed runtime must fail.
2150 {
2151 auto runtime = Runtime::create();
2152 auto acc = get_account(runtime);
2153 auto root = get_root(runtime);
2154 clear_folder(root);
2155
2156 auto file = write_file(root, "file", "");
2157 runtime->shutdown();
2158 try
2159 {
2160 file->native_metadata();
2161 FAIL();
2162 }
2163 catch (RuntimeDestroyedException const& e)
2164 {
2165 EXPECT_EQ("Item::native_metadata(): Runtime was destroyed previously", e.error_message());
2166 }
2167 }
2168
2169 // name() on root with destroyed runtime must fail.
2170 {
2171 auto runtime = Runtime::create();
2172 auto acc = get_account(runtime);
2173 auto root = get_root(runtime);
2174 clear_folder(root);
2175
2176 runtime->shutdown();
2177 try
2178 {
2179 root->name();
2180 FAIL();
2181 }
2182 catch (RuntimeDestroyedException const& e)
2183 {
2184 EXPECT_EQ("Root::name(): Runtime was destroyed previously", e.error_message());
2185 }
2186 }
2187
2188 // name() on folder with destroyed runtime must fail.
2189 {
2190 auto runtime = Runtime::create();
2191 auto acc = get_account(runtime);
2192 auto root = get_root(runtime);
2193 clear_folder(root);
2194
2195 auto folder = call(root->create_folder("folder"));
2196 runtime->shutdown();
2197 try
2198 {
2199 folder->name();
2200 FAIL();
2201 }
2202 catch (RuntimeDestroyedException const& e)
2203 {
2204 EXPECT_EQ("Folder::name(): Runtime was destroyed previously", e.error_message());
2205 }
2206 }
2207
2208 // name() on file with destroyed runtime must fail.
2209 {
2210 auto runtime = Runtime::create();
2211 auto acc = get_account(runtime);
2212 auto root = get_root(runtime);
2213 clear_folder(root);
2214
2215 auto file = write_file(root, "file", "");
2216 runtime->shutdown();
2217 try
2218 {
2219 file->name();
2220 FAIL();
2221 }
2222 catch (RuntimeDestroyedException const& e)
2223 {
2224 EXPECT_EQ("File::name(): Runtime was destroyed previously", e.error_message());
2225 }
2226 }
2227
2228 // list() with destroyed runtime must fail.
2229 {
2230 auto runtime = Runtime::create();
2231 auto acc = get_account(runtime);
2232 auto root = get_root(runtime);
2233 clear_folder(root);
2234
2235 runtime->shutdown();
2236 try
2237 {
2238 call(root->list());
2239 FAIL();
2240 }
2241 catch (RuntimeDestroyedException const& e)
2242 {
2243 EXPECT_EQ("Folder::list(): Runtime was destroyed previously", e.error_message());
2244 }
2245 }
2246
2247 // lookup() with destroyed runtime must fail.
2248 {
2249 auto runtime = Runtime::create();
2250 auto acc = get_account(runtime);
2251 auto root = get_root(runtime);
2252 clear_folder(root);
2253
2254 runtime->shutdown();
2255 try
2256 {
2257 call(root->lookup("file"));
2258 FAIL();
2259 }
2260 catch (RuntimeDestroyedException const& e)
2261 {
2262 EXPECT_EQ("Folder::lookup(): Runtime was destroyed previously", e.error_message());
2263 }
2264 }
2265
2266 // create_folder() with destroyed runtime must fail.
2267 {
2268 auto runtime = Runtime::create();
2269 auto acc = get_account(runtime);
2270 auto root = get_root(runtime);
2271 clear_folder(root);
2272
2273 runtime->shutdown();
2274 try
2275 {
2276 call(root->create_folder("folder"));
2277 FAIL();
2278 }
2279 catch (RuntimeDestroyedException const& e)
2280 {
2281 EXPECT_EQ("Folder::create_folder(): Runtime was destroyed previously", e.error_message());
2282 }
2283 }
2284
2285 // create_file() with destroyed runtime must fail.
2286 {
2287 auto runtime = Runtime::create();
2288 auto acc = get_account(runtime);
2289 auto root = get_root(runtime);
2290 clear_folder(root);
2291
2292 runtime->shutdown();
2293 try
2294 {
2295 call(root->create_file("file", 0));
2296 FAIL();
2297 }
2298 catch (RuntimeDestroyedException const& e)
2299 {
2300 EXPECT_EQ("Folder::create_file(): Runtime was destroyed previously", e.error_message());
2301 }
2302 }
2303
2304 // size() with destroyed runtime must fail.
2305 {
2306 auto runtime = Runtime::create();
2307 auto acc = get_account(runtime);
2308 auto root = get_root(runtime);
2309 clear_folder(root);
2310
2311 auto file = write_file(root, "file", "");
2312 runtime->shutdown();
2313 try
2314 {
2315 file->size();
2316 FAIL();
2317 }
2318 catch (RuntimeDestroyedException const& e)
2319 {
2320 EXPECT_EQ("File::size(): Runtime was destroyed previously", e.error_message());
2321 }
2322 }
2323
2324 // create_uploader() with destroyed runtime must fail.
2325 {
2326 auto runtime = Runtime::create();
2327 auto acc = get_account(runtime);
2328 auto root = get_root(runtime);
2329 clear_folder(root);
2330
2331 auto file = write_file(root, "file", "");
2332 runtime->shutdown();
2333 try
2334 {
2335 call(file->create_uploader(ConflictPolicy::overwrite, 0));
2336 FAIL();
2337 }
2338 catch (RuntimeDestroyedException const& e)
2339 {
2340 EXPECT_EQ("File::create_uploader(): Runtime was destroyed previously", e.error_message());
2341 }
2342 }
2343
2344 // create_downloader() with destroyed runtime must fail.
2345 {
2346 auto runtime = Runtime::create();
2347 auto acc = get_account(runtime);
2348 auto root = get_root(runtime);
2349 clear_folder(root);
2350
2351 auto file = write_file(root, "file", "");
2352 runtime->shutdown();
2353 try
2354 {
2355 call(file->create_downloader());
2356 FAIL();
2357 }
2358 catch (RuntimeDestroyedException const& e)
2359 {
2360 EXPECT_EQ("File::create_downloader(): Runtime was destroyed previously", e.error_message());
2361 }
2362 }
2363
2364 // free_space_bytes() with destroyed runtime must fail.
2365 {
2366 auto runtime = Runtime::create();
2367 auto acc = get_account(runtime);
2368 auto root = get_root(runtime);
2369 clear_folder(root);
2370
2371 runtime->shutdown();
2372 try
2373 {
2374 call(root->free_space_bytes());
2375 FAIL();
2376 }
2377 catch (RuntimeDestroyedException const& e)
2378 {
2379 EXPECT_EQ("Root::free_space_bytes(): Runtime was destroyed previously", e.error_message());
2380 }
2381 }
2382
2383 // used_space_bytes() with destroyed runtime must fail.
2384 {
2385 auto runtime = Runtime::create();
2386 auto acc = get_account(runtime);
2387 auto root = get_root(runtime);
2388 clear_folder(root);
2389
2390 runtime->shutdown();
2391 try
2392 {
2393 call(root->used_space_bytes());
2394 FAIL();
2395 }
2396 catch (RuntimeDestroyedException const& e)
2397 {
2398 EXPECT_EQ("Root::used_space_bytes(): Runtime was destroyed previously", e.error_message());
2399 }
2400 }
2401
2402 // get() with destroyed runtime must fail.
2403 {
2404 auto runtime = Runtime::create();
2405 auto acc = get_account(runtime);
2406 auto root = get_root(runtime);
2407 clear_folder(root);
2408
2409 runtime->shutdown();
2410 try
2411 {
2412 call(root->get("some_id"));
2413 FAIL();
2414 }
2415 catch (RuntimeDestroyedException const& e)
2416 {
2417 EXPECT_EQ("Root::get(): Runtime was destroyed previously", e.error_message());
2418 }
2419 }
1482}2420}
14832421
1484int main(int argc, char** argv)2422int main(int argc, char** argv)
@@ -1488,6 +2426,7 @@
1488 setenv("STORAGE_FRAMEWORK_ROOT", TEST_DIR, true);2426 setenv("STORAGE_FRAMEWORK_ROOT", TEST_DIR, true);
14892427
1490 QCoreApplication app(argc, argv);2428 QCoreApplication app(argc, argv);
2429 qRegisterMetaType<QLocalSocket::LocalSocketState>();
14912430
1492 ::testing::InitGoogleTest(&argc, argv);2431 ::testing::InitGoogleTest(&argc, argv);
1493 return RUN_ALL_TESTS();2432 return RUN_ALL_TESTS();
14942433
=== modified file 'tests/remote-client/remote-client_test.cpp'
--- tests/remote-client/remote-client_test.cpp 2016-08-03 06:10:39 +0000
+++ tests/remote-client/remote-client_test.cpp 2016-08-03 06:10:39 +0000
@@ -262,7 +262,7 @@
262 QFutureWatcher<QVector<Item::SPtr>> w;262 QFutureWatcher<QVector<Item::SPtr>> w;
263 QSignalSpy spy(&w, &decltype(w)::finished);263 QSignalSpy spy(&w, &decltype(w)::finished);
264 w.setFuture(list_fut);264 w.setFuture(list_fut);
265 assert(spy.wait(SIGNAL_WAIT_TIME));265 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
266 }266 }
267 auto items = list_fut.result();267 auto items = list_fut.result();
268 ASSERT_EQ(1, items.size());268 ASSERT_EQ(1, items.size());
@@ -273,7 +273,7 @@
273 QFutureWatcher<Uploader::SPtr> w;273 QFutureWatcher<Uploader::SPtr> w;
274 QSignalSpy spy(&w, &decltype(w)::finished);274 QSignalSpy spy(&w, &decltype(w)::finished);
275 w.setFuture(create_file_fut);275 w.setFuture(create_file_fut);
276 assert(spy.wait(SIGNAL_WAIT_TIME));276 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
277 }277 }
278 auto uploader = create_file_fut.result();278 auto uploader = create_file_fut.result();
279 auto finish_upload_fut = uploader->finish_upload();279 auto finish_upload_fut = uploader->finish_upload();
@@ -281,7 +281,7 @@
281 QFutureWatcher<File::SPtr> w;281 QFutureWatcher<File::SPtr> w;
282 QSignalSpy spy(&w, &decltype(w)::finished);282 QSignalSpy spy(&w, &decltype(w)::finished);
283 w.setFuture(finish_upload_fut);283 w.setFuture(finish_upload_fut);
284 assert(spy.wait(SIGNAL_WAIT_TIME));284 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
285 }285 }
286 auto file = finish_upload_fut.result();286 auto file = finish_upload_fut.result();
287 EXPECT_EQ(ItemType::file, file->type());287 EXPECT_EQ(ItemType::file, file->type());
@@ -295,7 +295,7 @@
295 QFutureWatcher<Item::SPtr> w;295 QFutureWatcher<Item::SPtr> w;
296 QSignalSpy spy(&w, &decltype(w)::finished);296 QSignalSpy spy(&w, &decltype(w)::finished);
297 w.setFuture(get_fut);297 w.setFuture(get_fut);
298 assert(spy.wait(SIGNAL_WAIT_TIME));298 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
299 }299 }
300 file = dynamic_pointer_cast<File>(get_fut.result());300 file = dynamic_pointer_cast<File>(get_fut.result());
301 EXPECT_EQ("child_id", file->native_identity());301 EXPECT_EQ("child_id", file->native_identity());
@@ -308,7 +308,7 @@
308 QFutureWatcher<Folder::SPtr> w;308 QFutureWatcher<Folder::SPtr> w;
309 QSignalSpy spy(&w, &decltype(w)::finished);309 QSignalSpy spy(&w, &decltype(w)::finished);
310 w.setFuture(create_folder_fut);310 w.setFuture(create_folder_fut);
311 assert(spy.wait(SIGNAL_WAIT_TIME));311 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
312 }312 }
313 EXPECT_EQ(ItemType::folder, folder->type());313 EXPECT_EQ(ItemType::folder, folder->type());
314 EXPECT_EQ("folder1", folder->name());314 EXPECT_EQ("folder1", folder->name());
@@ -408,7 +408,7 @@
408 QFutureWatcher<QVector<Item::SPtr>> w;408 QFutureWatcher<QVector<Item::SPtr>> w;
409 QSignalSpy spy(&w, &decltype(w)::finished);409 QSignalSpy spy(&w, &decltype(w)::finished);
410 w.setFuture(lookup_fut);410 w.setFuture(lookup_fut);
411 assert(spy.wait(SIGNAL_WAIT_TIME));411 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
412 }412 }
413 auto children = lookup_fut.result();413 auto children = lookup_fut.result();
414 ASSERT_EQ(1, children.size());414 ASSERT_EQ(1, children.size());
@@ -421,7 +421,7 @@
421 QFutureWatcher<Uploader::SPtr> w;421 QFutureWatcher<Uploader::SPtr> w;
422 QSignalSpy spy(&w, &decltype(w)::finished);422 QSignalSpy spy(&w, &decltype(w)::finished);
423 w.setFuture(create_uploader_fut);423 w.setFuture(create_uploader_fut);
424 assert(spy.wait(SIGNAL_WAIT_TIME));424 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
425 }425 }
426 auto uploader = create_uploader_fut.result();426 auto uploader = create_uploader_fut.result();
427427
@@ -430,7 +430,7 @@
430 QFutureWatcher<File::SPtr> w;430 QFutureWatcher<File::SPtr> w;
431 QSignalSpy spy(&w, &decltype(w)::finished);431 QSignalSpy spy(&w, &decltype(w)::finished);
432 w.setFuture(finish_upload_fut);432 w.setFuture(finish_upload_fut);
433 assert(spy.wait(SIGNAL_WAIT_TIME));433 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
434 }434 }
435 auto uploaded_file = finish_upload_fut.result();435 auto uploaded_file = finish_upload_fut.result();
436 EXPECT_EQ("some_id", uploaded_file->native_identity());436 EXPECT_EQ("some_id", uploaded_file->native_identity());
@@ -446,7 +446,7 @@
446 QFutureWatcher<File::SPtr> w;446 QFutureWatcher<File::SPtr> w;
447 QSignalSpy spy(&w, &decltype(w)::finished);447 QSignalSpy spy(&w, &decltype(w)::finished);
448 w.setFuture(finish_upload_fut);448 w.setFuture(finish_upload_fut);
449 assert(spy.wait(SIGNAL_WAIT_TIME));449 ASSERT_TRUE(spy.wait(SIGNAL_WAIT_TIME));
450 }450 }
451 auto file = finish_upload_fut.result();451 auto file = finish_upload_fut.result();
452 }452 }

Subscribers

People subscribed via source and target branches

to all changes: