Merge lp:~xavi-garcia-mena/keeper/cancel-feature into lp:keeper/devel
- cancel-feature
- Merge into devel
Status: | Merged |
---|---|
Merged at revision: | 115 |
Proposed branch: | lp:~xavi-garcia-mena/keeper/cancel-feature |
Merge into: | lp:keeper/devel |
Diff against target: |
390 lines (+226/-5) 11 files modified
src/service/keeper-task.cpp (+17/-0) src/service/keeper-task.h (+2/-0) src/service/keeper-user.cpp (+1/-3) src/service/keeper.cpp (+13/-0) src/service/keeper.h (+2/-0) src/service/private/keeper-task_p.h (+2/-0) src/service/task-manager.cpp (+24/-0) src/service/task-manager.h (+2/-0) tests/integration/helpers/helpers-test.cc (+73/-2) tests/integration/helpers/test-helpers-base.cpp (+88/-0) tests/integration/helpers/test-helpers-base.h (+2/-0) |
To merge this branch: | bzr merge lp:~xavi-garcia-mena/keeper/cancel-feature |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
unity-api-1-bot | continuous-integration | Approve | |
Charles Kerr (community) | Approve | ||
Review via email: mp+307030@code.launchpad.net |
Commit message
Cancel feature implemented.
Description of the change
Cancel feature implemented.
The branch also adds an integration test that cancels the first task when it reaches 20%
unity-api-1-bot (unity-api-1-bot) wrote : | # |
Charles Kerr (charlesk) wrote : | # |
Looks really good.
Some minor optional suggestions inline
- 114. By Xavi Garcia
-
addedn suggested modifications
Xavi Garcia (xavi-garcia-mena) wrote : | # |
Thanks for the review and suggestions, Charles. I've committed the suggested changes.
Comments inline.
I'm going to merge this with devel.
unity-api-1-bot (unity-api-1-bot) wrote : | # |
PASSED: Continuous integration, rev:114
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | === modified file 'src/service/keeper-task.cpp' |
2 | --- src/service/keeper-task.cpp 2016-09-13 08:47:14 +0000 |
3 | +++ src/service/keeper-task.cpp 2016-09-30 09:23:25 +0000 |
4 | @@ -149,6 +149,14 @@ |
5 | Q_EMIT(q_ptr->task_state_changed(state)); |
6 | } |
7 | |
8 | +void KeeperTaskPrivate::cancel() |
9 | +{ |
10 | + if (helper_) |
11 | + { |
12 | + helper_->stop(); |
13 | + } |
14 | +} |
15 | + |
16 | QVariantMap KeeperTaskPrivate::get_initial_state(KeeperTask::TaskData const &td) |
17 | { |
18 | QVariantMap ret; |
19 | @@ -188,12 +196,14 @@ |
20 | bool KeeperTask::start() |
21 | { |
22 | Q_D(KeeperTask); |
23 | + |
24 | return d->start(); |
25 | } |
26 | |
27 | QVariantMap KeeperTask::state() const |
28 | { |
29 | Q_D(const KeeperTask); |
30 | + |
31 | return d->state(); |
32 | } |
33 | |
34 | @@ -201,3 +211,10 @@ |
35 | { |
36 | return KeeperTaskPrivate::get_initial_state(td); |
37 | } |
38 | + |
39 | +void KeeperTask::cancel() |
40 | +{ |
41 | + Q_D(KeeperTask); |
42 | + |
43 | + return d->cancel(); |
44 | +} |
45 | |
46 | === modified file 'src/service/keeper-task.h' |
47 | --- src/service/keeper-task.h 2016-09-07 17:07:23 +0000 |
48 | +++ src/service/keeper-task.h 2016-09-30 09:23:25 +0000 |
49 | @@ -57,6 +57,8 @@ |
50 | |
51 | static QVariantMap get_initial_state(KeeperTask::TaskData const &td); |
52 | |
53 | + void cancel(); |
54 | + |
55 | Q_SIGNALS: |
56 | void task_state_changed(Helper::State state); |
57 | void task_socket_ready(int socket_descriptor); |
58 | |
59 | === modified file 'src/service/keeper-user.cpp' |
60 | --- src/service/keeper-user.cpp 2016-09-07 16:35:26 +0000 |
61 | +++ src/service/keeper-user.cpp 2016-09-30 09:23:25 +0000 |
62 | @@ -81,9 +81,7 @@ |
63 | void |
64 | KeeperUser::Cancel() |
65 | { |
66 | - // FIXME: writeme |
67 | - |
68 | - qDebug() << "hello world"; |
69 | + keeper_.cancel(); |
70 | } |
71 | |
72 | QVariantDictMap |
73 | |
74 | === modified file 'src/service/keeper.cpp' |
75 | --- src/service/keeper.cpp 2016-09-07 16:35:26 +0000 |
76 | +++ src/service/keeper.cpp 2016-09-30 09:23:25 +0000 |
77 | @@ -135,6 +135,11 @@ |
78 | return QDBusUnixFileDescriptor(0); |
79 | } |
80 | |
81 | + void cancel() |
82 | + { |
83 | + task_manager_.cancel(); |
84 | + } |
85 | + |
86 | private: |
87 | |
88 | Keeper * const q_ptr; |
89 | @@ -201,3 +206,11 @@ |
90 | |
91 | return d->get_state(); |
92 | } |
93 | + |
94 | +void |
95 | +Keeper::cancel() |
96 | +{ |
97 | + Q_D(Keeper); |
98 | + |
99 | + return d->cancel(); |
100 | +} |
101 | |
102 | === modified file 'src/service/keeper.h' |
103 | --- src/service/keeper.h 2016-09-07 16:47:55 +0000 |
104 | +++ src/service/keeper.h 2016-09-30 09:23:25 +0000 |
105 | @@ -63,6 +63,8 @@ |
106 | |
107 | QVariantDictMap get_state() const; |
108 | |
109 | + void cancel(); |
110 | + |
111 | private: |
112 | QScopedPointer<KeeperPrivate> const d_ptr; |
113 | }; |
114 | |
115 | === modified file 'src/service/private/keeper-task_p.h' |
116 | --- src/service/private/keeper-task_p.h 2016-09-07 14:50:51 +0000 |
117 | +++ src/service/private/keeper-task_p.h 2016-09-30 09:23:25 +0000 |
118 | @@ -36,6 +36,8 @@ |
119 | QVariantMap state() const; |
120 | void ask_for_storage_framework_socket(quint64 n_bytes); |
121 | |
122 | + void cancel(); |
123 | + |
124 | static QVariantMap get_initial_state(KeeperTask::TaskData const &td); |
125 | |
126 | protected: |
127 | |
128 | === modified file 'src/service/task-manager.cpp' |
129 | --- src/service/task-manager.cpp 2016-09-13 08:47:14 +0000 |
130 | +++ src/service/task-manager.cpp 2016-09-30 09:23:25 +0000 |
131 | @@ -73,6 +73,23 @@ |
132 | } |
133 | } |
134 | |
135 | + void cancel() |
136 | + { |
137 | + if (task_) |
138 | + { |
139 | + task_->cancel(); |
140 | + } |
141 | + for (auto const & task: remaining_tasks_) |
142 | + { |
143 | + auto& td = task_data_[task]; |
144 | + td.action = QStringLiteral("cancelled"); // TODO i18n |
145 | + set_initial_task_state(td); |
146 | + } |
147 | + // notify the initial state once for all tasks |
148 | + notify_state_changed(); |
149 | + remaining_tasks_.clear(); |
150 | + } |
151 | + |
152 | private: |
153 | |
154 | enum class Mode { IDLE, BACKUP, RESTORE }; |
155 | @@ -321,3 +338,10 @@ |
156 | |
157 | d->ask_for_uploader(n_bytes); |
158 | } |
159 | + |
160 | +void TaskManager::cancel() |
161 | +{ |
162 | + Q_D(TaskManager); |
163 | + |
164 | + d->cancel(); |
165 | +} |
166 | |
167 | === modified file 'src/service/task-manager.h' |
168 | --- src/service/task-manager.h 2016-09-07 17:07:23 +0000 |
169 | +++ src/service/task-manager.h 2016-09-30 09:23:25 +0000 |
170 | @@ -58,6 +58,8 @@ |
171 | |
172 | void ask_for_uploader(quint64 n_bytes); |
173 | |
174 | + void cancel(); |
175 | + |
176 | Q_SIGNALS: |
177 | void socket_ready(int reply); |
178 | void state_changed(); |
179 | |
180 | === modified file 'tests/integration/helpers/helpers-test.cc' |
181 | --- tests/integration/helpers/helpers-test.cc 2016-09-15 16:02:54 +0000 |
182 | +++ tests/integration/helpers/helpers-test.cc 2016-09-30 09:23:25 +0000 |
183 | @@ -73,7 +73,7 @@ |
184 | QDBusReply<QVariantDictMap> choices = user_iface->call("GetBackupChoices"); |
185 | EXPECT_TRUE(choices.isValid()) << qPrintable(choices.error().message()); |
186 | |
187 | - QString user_option = "XDG_MUSIC_DIR"; |
188 | + QString user_option = QStringLiteral("XDG_MUSIC_DIR"); |
189 | |
190 | auto user_dir = qgetenv(user_option.toLatin1().data()); |
191 | ASSERT_FALSE(user_dir.isEmpty()); |
192 | @@ -87,7 +87,7 @@ |
193 | ASSERT_FALSE(user_folder_uuid.isEmpty()); |
194 | qDebug() << "User folder UUID is:" << user_folder_uuid; |
195 | |
196 | - QString user_option_2 = "XDG_VIDEOS_DIR"; |
197 | + QString user_option_2 = QStringLiteral("XDG_VIDEOS_DIR"); |
198 | |
199 | auto user_dir_2 = qgetenv(user_option_2.toLatin1().data()); |
200 | ASSERT_FALSE(user_dir_2.isEmpty()); |
201 | @@ -127,6 +127,77 @@ |
202 | EXPECT_TRUE(check_storage_framework_files(QStringList{user_dir, user_dir_2})); |
203 | } |
204 | |
205 | +TEST_F(TestHelpers, StartFullTestCancelling) |
206 | +{ |
207 | + XdgUserDirsSandbox tmp_dir; |
208 | + |
209 | + // starts the services, including keeper-service |
210 | + start_tasks(); |
211 | + |
212 | + QSharedPointer<DBusInterfaceKeeperUser> user_iface(new DBusInterfaceKeeperUser( |
213 | + DBusTypes::KEEPER_SERVICE, |
214 | + DBusTypes::KEEPER_USER_PATH, |
215 | + dbus_test_runner.sessionConnection() |
216 | + ) ); |
217 | + |
218 | + ASSERT_TRUE(user_iface->isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message()); |
219 | + |
220 | + // ask for a list of backup choices |
221 | + QDBusReply<QVariantDictMap> choices = user_iface->call("GetBackupChoices"); |
222 | + EXPECT_TRUE(choices.isValid()) << qPrintable(choices.error().message()); |
223 | + |
224 | + QString user_option = QStringLiteral("XDG_MUSIC_DIR"); |
225 | + |
226 | + auto user_dir = qgetenv(user_option.toLatin1().data()); |
227 | + ASSERT_FALSE(user_dir.isEmpty()); |
228 | + qDebug() << "USER DIR:" << user_dir; |
229 | + |
230 | + // fill something in the music dir |
231 | + FileUtils::fillTemporaryDirectory(user_dir, qrand() % 100); |
232 | + |
233 | + // search for the user folder uuid |
234 | + auto user_folder_uuid = get_uuid_for_xdg_folder_path(user_dir, choices.value()); |
235 | + ASSERT_FALSE(user_folder_uuid.isEmpty()); |
236 | + qDebug() << "User folder UUID is:" << user_folder_uuid; |
237 | + |
238 | + QString user_option_2 = QStringLiteral("XDG_VIDEOS_DIR"); |
239 | + |
240 | + auto user_dir_2 = qgetenv(user_option_2.toLatin1().data()); |
241 | + ASSERT_FALSE(user_dir_2.isEmpty()); |
242 | + qDebug() << "USER DIR 2:" << user_dir_2; |
243 | + |
244 | + // fill something in the music dir |
245 | + FileUtils::fillTemporaryDirectory(user_dir_2, qrand() % 100); |
246 | + |
247 | + // search for the user folder uuid |
248 | + auto user_folder_uuid_2 = get_uuid_for_xdg_folder_path(user_dir_2, choices.value()); |
249 | + ASSERT_FALSE(user_folder_uuid_2.isEmpty()); |
250 | + qDebug() << "User folder 2 UUID is:" << user_folder_uuid_2; |
251 | + |
252 | + QSharedPointer<DBusPropertiesInterface> properties_interface(new DBusPropertiesInterface( |
253 | + DBusTypes::KEEPER_SERVICE, |
254 | + DBusTypes::KEEPER_USER_PATH, |
255 | + dbus_test_runner.sessionConnection() |
256 | + ) ); |
257 | + |
258 | + ASSERT_TRUE(properties_interface->isValid()) << qPrintable(QDBusConnection::sessionBus().lastError().message()); |
259 | + |
260 | + QSignalSpy spy(properties_interface.data(),&DBusPropertiesInterface::PropertiesChanged); |
261 | + |
262 | + // Now we know the music folder uuid, let's start the backup for it. |
263 | + QDBusReply<void> backup_reply = user_iface->call("StartBackup", QStringList{user_folder_uuid, user_folder_uuid_2}); |
264 | + ASSERT_TRUE(backup_reply.isValid()) << qPrintable(dbus_test_runner.sessionConnection().lastError().message()); |
265 | + |
266 | + EXPECT_TRUE(cancel_first_task_at_percentage(spy, 0.20, user_iface)); |
267 | + |
268 | + // wait until all the tasks have the action state "complete" |
269 | + // this one uses pooling so it should just call Get once |
270 | + EXPECT_TRUE(wait_for_all_tasks_have_action_state({user_folder_uuid, user_folder_uuid_2}, "cancelled", user_iface)); |
271 | + |
272 | + // check that we have no files in storage framework |
273 | + EXPECT_EQ(0, check_storage_framework_nb_files()); |
274 | +} |
275 | + |
276 | TEST_F(TestHelpers, SimplyCheckThatTheSecondDBusInterfaceIsFine) |
277 | { |
278 | XdgUserDirsSandbox tmp_dir; |
279 | |
280 | === modified file 'tests/integration/helpers/test-helpers-base.cpp' |
281 | --- tests/integration/helpers/test-helpers-base.cpp 2016-09-08 14:06:56 +0000 |
282 | +++ tests/integration/helpers/test-helpers-base.cpp 2016-09-30 09:23:25 +0000 |
283 | @@ -598,6 +598,94 @@ |
284 | return analyze_tasks_values(uuids_state); |
285 | } |
286 | |
287 | +bool TestHelpersBase::cancel_first_task_at_percentage(QSignalSpy & spy, double expected_percentage, QSharedPointer<DBusInterfaceKeeperUser> const & user_iface, int max_timeout_msec) |
288 | +{ |
289 | + QMap<QString, QList<QVariantMap>> uuids_state; |
290 | + QMap<QString, QString> uuids_current_state; |
291 | + |
292 | + QElapsedTimer timer; |
293 | + timer.start(); |
294 | + bool finished = false; |
295 | + while (!timer.hasExpired(max_timeout_msec) && !finished) |
296 | + { |
297 | + spy.wait(); |
298 | + |
299 | + qDebug() << "PropertiesChanged SIGNALS RECEIVED: " << spy.count(); |
300 | + while (spy.count()) |
301 | + { |
302 | + auto arguments = spy.takeFirst(); |
303 | + |
304 | + if (arguments.size() != 3) |
305 | + { |
306 | + qWarning() << "Bad number of arguments in PropertiesChanged signal"; |
307 | + return false; |
308 | + } |
309 | + |
310 | + // verify interface and invalidated_properties arguments |
311 | + if(!verify_signal_interface_and_invalidated_properties(arguments.at(0), arguments.at(2), DBusTypes::KEEPER_USER_INTERFACE, "State")) |
312 | + { |
313 | + return false; |
314 | + } |
315 | + QVariantDictMap keeper_state; |
316 | + if (!get_property_qvariant_dict_map("State", arguments.at(1), keeper_state)) |
317 | + { |
318 | + return false; |
319 | + } |
320 | + for (auto iter = keeper_state.begin(); iter != keeper_state.end(); ++iter ) |
321 | + { |
322 | + QVariantMap task_state; |
323 | + if (!qvariant_to_map((*iter), task_state)) |
324 | + { |
325 | + qWarning() << "Error converting second argument in PropertiesChanged signal to QVariantMap for uuid: " << iter.key(); |
326 | + return false; |
327 | + } |
328 | + qDebug() << "State for uuid: " << iter.key() << " : " << task_state; |
329 | + |
330 | + QVariant action; |
331 | + if (get_task_property("action", task_state, action)) |
332 | + { |
333 | + if (action.type() != QVariant::String) |
334 | + { |
335 | + qWarning() << "Property [action] is not a string"; |
336 | + return false; |
337 | + } |
338 | + if ( action.toString() == "saving") |
339 | + { |
340 | + // the helper is saving data... check for the percentage |
341 | + QVariant percentage; |
342 | + if (!get_task_property("percent-done", task_state, percentage)) |
343 | + { |
344 | + qWarning() << Q_FUNC_INFO << ": Percentage was not found for task: " << iter.key(); |
345 | + return false; |
346 | + } |
347 | + bool ok_double; |
348 | + auto percentage_double = percentage.toDouble(&ok_double); |
349 | + if (!ok_double) |
350 | + { |
351 | + qWarning() << Q_FUNC_INFO << ": Error converting percent-done to double for uuid: " << iter.key() << ". State: " << (*iter); |
352 | + return false; |
353 | + } |
354 | + if (percentage_double >= expected_percentage) |
355 | + { |
356 | + qDebug() << "CANCELLING ******************************"; |
357 | + // found... cancel keeper |
358 | + QDBusReply<void> backup_reply = user_iface->call("Cancel"); |
359 | + if (!backup_reply.isValid()) |
360 | + { |
361 | + qWarning() << "Error calling Cancel in the dbus user interface: " << backup_reply.error().message(); |
362 | + return false; |
363 | + } |
364 | + return true; |
365 | + } |
366 | + } |
367 | + } |
368 | + } |
369 | + } |
370 | + } |
371 | + qWarning() << Q_FUNC_INFO << ":Error no task was not found or the expected percentage was not reached"; |
372 | + return false; |
373 | +} |
374 | + |
375 | QString TestHelpersBase::get_uuid_for_xdg_folder_path(QString const &path, QVariantDictMap const & choices) const |
376 | { |
377 | for(auto iter = choices.begin(); iter != choices.end(); ++iter) |
378 | |
379 | === modified file 'tests/integration/helpers/test-helpers-base.h' |
380 | --- tests/integration/helpers/test-helpers-base.h 2016-09-07 21:09:15 +0000 |
381 | +++ tests/integration/helpers/test-helpers-base.h 2016-09-30 09:23:25 +0000 |
382 | @@ -101,6 +101,8 @@ |
383 | |
384 | bool capture_and_check_state_until_all_tasks_complete(QSignalSpy & spy, QStringList const & uuids, QString const & action_state, int max_timeout_msec = 15000); |
385 | |
386 | + bool cancel_first_task_at_percentage(QSignalSpy & spy, double expected_percentage, QSharedPointer<DBusInterfaceKeeperUser> const & user_iface, int max_timeout_msec = 15000); |
387 | + |
388 | QString get_uuid_for_xdg_folder_path(QString const &path, QVariantDictMap const & choices) const; |
389 | |
390 | bool start_dbus_monitor(); |
PASSED: Continuous integration, rev:113 /jenkins. canonical. com/unity- api-1/job/ lp-keeper- ci/93/ /jenkins. canonical. com/unity- api-1/job/ build/788 /jenkins. canonical. com/unity- api-1/job/ build-0- fetch/794 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 602 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 602/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 602 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 602/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 602 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 602/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 602 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 602/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 602 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 602/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 602 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 602/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 602 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 602/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 602 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 602/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= yakkety/ 602 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= yakkety/ 602/artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/unity- api-1/job/ lp-keeper- ci/93/rebuild
https:/