Merge lp:~xavi-garcia-mena/keeper/cancel-feature into lp:keeper/devel

Proposed by Xavi Garcia
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
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%

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

PASSED: Continuous integration, rev:113
https://jenkins.canonical.com/unity-api-1/job/lp-keeper-ci/93/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/788
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/794
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/602
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/602/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/602
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/602/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/602
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/602/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/602
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/602/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/602
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/602/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/602
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/602/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/602
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/602/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/602
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/602/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/602
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/602/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

Looks really good.

Some minor optional suggestions inline

review: Approve
114. By Xavi Garcia

addedn suggested modifications

Revision history for this message
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.

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

PASSED: Continuous integration, rev:114
https://jenkins.canonical.com/unity-api-1/job/lp-keeper-ci/94/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/826
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/833
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/636
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/636/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/636
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/636/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/636
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/636/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/636
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/636/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/636
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/636/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/636
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/636/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/636
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/636/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/636
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/636/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/636
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/636/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '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();

Subscribers

People subscribed via source and target branches

to all changes: