Merge lp:~renatofilho/buteo-syncfw-qml/release into lp:buteo-syncfw-qml
- release
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Michael Sheldon |
Approved revision: | 11 |
Merged at revision: | 3 |
Proposed branch: | lp:~renatofilho/buteo-syncfw-qml/release |
Merge into: | lp:buteo-syncfw-qml |
Diff against target: |
736 lines (+324/-95) 7 files modified
Buteo/buteo-sync-qml.cpp (+168/-71) Buteo/buteo-sync-qml.h (+23/-5) CMakeLists.txt (+14/-0) cmake/lcov.cmake (+67/-0) debian/control (+1/-1) tests/qml/buteo-syncfw.py (+17/-6) tests/qml/tst_ButeoSyncFW.qml (+34/-12) |
To merge this branch: | bzr merge lp:~renatofilho/buteo-syncfw-qml/release |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Approve | |
Michael Sheldon (community) | Approve | ||
Ken VanDine | packaging | Approve | |
Renato Araujo Oliveira Filho | Pending | ||
Review via email: mp+264336@code.launchpad.net |
This proposal supersedes a proposal from 2015-07-09.
Commit message
Added coverage.
Use async dbus call for "syncProfilesBy
Description of the change
- 4. By Renato Araujo Oliveira Filho
-
Renamed buteo package.
- 5. By Renato Araujo Oliveira Filho
-
Set 'buteo-syncfw' as reccomended package since the library can be used without buteo running.
- 6. By Renato Araujo Oliveira Filho
-
Added coverage build target.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 7. By Renato Araujo Oliveira Filho
-
Use async dbus call for "syncProfilesBy
Key". - 8. By Renato Araujo Oliveira Filho
-
Keep a cache with all profiles maped by category, to avoid reload it during the sync.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:7
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:8
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 9. By Renato Araujo Oliveira Filho
-
Fix property notify signal after async load profiles.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:9
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 10. By Renato Araujo Oliveira Filho
-
Use asyncCall for sync function to avoid block the UI.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:10
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Renato Araujo Oliveira Filho (renatofilho) wrote : | # |
Are there any related MPs required for this MP to build/function as expected?
NO
Is your branch in sync with latest trunk?
YES
Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator?
YES
Did you successfully run all tests found in your component's Test Plan on device or emulator?
YES
If you changed the UI, was the change specified/approved by design?
NO UI CHANGED
If you changed UI labels, did you update the pot file?
NO LABEL CHANGED
If you changed the packaging (debian), did you add a core-dev as a reviewer to this MP?
NO PACKAGE CHANGED
Ken VanDine (ken-vandine) wrote : | # |
Packaging changes look fine
Michael Sheldon (michael-sheldon) wrote : | # |
Added a comment and a question to the diff, other than that this looks good.
- 11. By Renato Araujo Oliveira Filho
-
Use "profiles()" instead of "visibleSyncPro
files() " in "profilesCount()" function.
Renato Araujo Oliveira Filho (renatofilho) wrote : | # |
Fixed
Michael Sheldon (michael-sheldon) wrote : | # |
Looks good
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:11
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'Buteo/buteo-sync-qml.cpp' |
2 | --- Buteo/buteo-sync-qml.cpp 2015-07-08 18:09:47 +0000 |
3 | +++ Buteo/buteo-sync-qml.cpp 2015-09-29 13:01:20 +0000 |
4 | @@ -1,4 +1,4 @@ |
5 | -/* |
6 | +/* |
7 | * Copyright (C) 2015 Canonical, Ltd. |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify |
10 | @@ -17,6 +17,7 @@ |
11 | #include "buteo-sync-qml.h" |
12 | |
13 | #include <QtCore/QDebug> |
14 | +#include <QtCore/QTimer> |
15 | #include <QtDBus/QDBusInterface> |
16 | #include <QtDBus/QDBusReply> |
17 | #include <QtXml/QDomDocument> |
18 | @@ -25,31 +26,33 @@ |
19 | #define BUTEO_DBUS_OBJECT_PATH "/synchronizer" |
20 | #define BUTEO_DBUS_INTERFACE "com.meego.msyncd" |
21 | |
22 | +typedef QPair<QString, bool> ProfileData; |
23 | + |
24 | ButeoSyncFW::ButeoSyncFW(QObject *parent) |
25 | - : QObject(parent) |
26 | + : QObject(parent), |
27 | + m_waitSyncStart(false) |
28 | { |
29 | + connect(this, SIGNAL(syncStatus(QString,int,QString,int)), SIGNAL(syncStatusChanged())); |
30 | + connect(this, SIGNAL(profileChanged(QString,int,QString)), SIGNAL(profilesChanged())); |
31 | } |
32 | |
33 | bool ButeoSyncFW::syncing() const |
34 | { |
35 | - return !(getRunningSyncList().isEmpty()); |
36 | + return (m_waitSyncStart || !getRunningSyncList().isEmpty()); |
37 | } |
38 | |
39 | QStringList ButeoSyncFW::visibleSyncProfiles() const |
40 | { |
41 | - if (m_iface) { |
42 | - QDBusReply<QStringList> result = m_iface->call("allVisibleSyncProfiles"); |
43 | - return result.value(); |
44 | - } |
45 | - return QStringList(); |
46 | + return profiles(); |
47 | +} |
48 | + |
49 | +int ButeoSyncFW::profilesCount() const |
50 | +{ |
51 | + return profiles().count(); |
52 | } |
53 | |
54 | void ButeoSyncFW::classBegin() |
55 | { |
56 | -} |
57 | - |
58 | -void ButeoSyncFW::componentComplete() |
59 | -{ |
60 | m_serviceWatcher.reset(new QDBusServiceWatcher(BUTEO_DBUS_SERVICE_NAME, |
61 | QDBusConnection::sessionBus(), |
62 | QDBusServiceWatcher::WatchForOwnerChange, |
63 | @@ -60,12 +63,17 @@ |
64 | initialize(); |
65 | } |
66 | |
67 | +void ButeoSyncFW::componentComplete() |
68 | +{ |
69 | +} |
70 | + |
71 | void ButeoSyncFW::initialize() |
72 | { |
73 | if (!m_iface.isNull()) { |
74 | return; |
75 | } |
76 | |
77 | + m_waitSyncStart = false; |
78 | m_iface.reset(new QDBusInterface(BUTEO_DBUS_SERVICE_NAME, |
79 | BUTEO_DBUS_OBJECT_PATH, |
80 | BUTEO_DBUS_INTERFACE)); |
81 | @@ -78,46 +86,68 @@ |
82 | |
83 | connect(m_iface.data(), |
84 | SIGNAL(syncStatus(QString, int, QString, int)), |
85 | - SIGNAL(syncStatus(QString, int, QString, int)), Qt::QueuedConnection); |
86 | + SIGNAL(syncStatus(QString, int, QString, int))); |
87 | connect(m_iface.data(), |
88 | SIGNAL(signalProfileChanged(QString, int, QString)), |
89 | SIGNAL(profileChanged(QString, int, QString)), Qt::QueuedConnection); |
90 | |
91 | + // track signals for internal state |
92 | + connect(m_iface.data(), |
93 | + SIGNAL(signalProfileChanged(QString, int, QString)), |
94 | + SLOT(reloadProfiles())); |
95 | + connect(m_iface.data(), |
96 | + SIGNAL(syncStatus(QString, int, QString, int)), |
97 | + SLOT(onSyncStatusChanged())); |
98 | + |
99 | + reloadProfiles(); |
100 | + |
101 | // notify changes on properties |
102 | - emit syncStatus("", 0, "", 0); |
103 | - emit profileChanged("", 0, ""); |
104 | + emit syncStatusChanged(); |
105 | } |
106 | |
107 | -bool ButeoSyncFW::startSync(const QString &aProfileId) const |
108 | +bool ButeoSyncFW::startSync(const QString &aProfileId) |
109 | { |
110 | - if (m_iface) { |
111 | - QDBusReply<bool> result = m_iface->call("startSync", aProfileId); |
112 | - return result.value(); |
113 | - } |
114 | - return false; |
115 | + if (!m_iface) { |
116 | + return false; |
117 | + } |
118 | + |
119 | + QDBusPendingCall pcall = m_iface->asyncCall(QLatin1String("startSync"), aProfileId); |
120 | + if (pcall.isError()) { |
121 | + qWarning() << "Fail to start sync:" << pcall.error().message(); |
122 | + return false; |
123 | + } |
124 | + |
125 | + if (!m_waitSyncStart) { |
126 | + m_waitSyncStart = true; |
127 | + emit syncStatusChanged(); |
128 | + } |
129 | + |
130 | + return true; |
131 | } |
132 | |
133 | -bool ButeoSyncFW::startSyncByCategory(const QString &category) const |
134 | +bool ButeoSyncFW::startSyncByCategory(const QString &category) |
135 | { |
136 | foreach(const QString &profile, syncProfilesByCategory(category)) { |
137 | if (!startSync(profile)) { |
138 | return false; |
139 | } |
140 | } |
141 | + |
142 | return true; |
143 | } |
144 | |
145 | + |
146 | void ButeoSyncFW::abortSync(const QString &aProfileId) const |
147 | { |
148 | if (m_iface) { |
149 | - m_iface->call("abortSync", aProfileId); |
150 | + m_iface->asyncCall(QLatin1String("abortSync"), aProfileId); |
151 | } |
152 | } |
153 | |
154 | QStringList ButeoSyncFW::getRunningSyncList() const |
155 | { |
156 | if (m_iface) { |
157 | - QDBusReply<QStringList> syncList = m_iface->call("runningSyncs"); |
158 | + QDBusReply<QStringList> syncList = m_iface->call(QLatin1String("runningSyncs")); |
159 | return syncList; |
160 | } |
161 | return QStringList(); |
162 | @@ -125,56 +155,13 @@ |
163 | |
164 | QStringList ButeoSyncFW::syncProfilesByCategory(const QString &category) const |
165 | { |
166 | - if (m_iface) { |
167 | - QDBusReply<QStringList> profiles = m_iface->call("syncProfilesByKey", "category", category); |
168 | - // extract ids |
169 | - QStringList ids; |
170 | - foreach(const QString &profile, profiles.value()) { |
171 | - QDomDocument doc; |
172 | - QString errorMsg; |
173 | - int errorLine; |
174 | - int errorColumn; |
175 | - if (doc.setContent(profile, &errorMsg, &errorLine, &errorColumn)) { |
176 | - QDomNodeList profileElements = doc.elementsByTagName("profile"); |
177 | - if (!profileElements.isEmpty()) { |
178 | - //check if is enabled |
179 | - QDomElement e = profileElements.item(0).toElement(); |
180 | - QDomNodeList values = e.elementsByTagName("key"); |
181 | - bool enabled = true; |
182 | - for(int i = 0; i < values.count(); i++) { |
183 | - QDomElement v = values.at(i).toElement(); |
184 | - if ((v.attribute("name") == "enabled") && |
185 | - (v.attribute("value") == "false")) { |
186 | - enabled = false; |
187 | - continue; |
188 | - } |
189 | - } |
190 | - if (!enabled) { |
191 | - continue; |
192 | - } |
193 | - QString profileName = e.attribute("name", ""); |
194 | - if (!profileName.isEmpty()) { |
195 | - ids << profileName; |
196 | - } else { |
197 | - qWarning() << "Profile name is empty in:" << profile; |
198 | - } |
199 | - } else { |
200 | - qWarning() << "Profile not found in:" << profile; |
201 | - } |
202 | - } else { |
203 | - qWarning() << "Fail to parse profile:" << profile; |
204 | - qWarning() << "Error:" << errorMsg << errorLine << errorColumn; |
205 | - } |
206 | - } |
207 | - return ids; |
208 | - } |
209 | - return QStringList(); |
210 | + return profiles(category, true); |
211 | } |
212 | |
213 | bool ButeoSyncFW::removeProfile(const QString &profileId) const |
214 | { |
215 | if (m_iface) { |
216 | - QDBusReply<bool> result = m_iface->call("removeProfile", profileId); |
217 | + QDBusReply<bool> result = m_iface->call(QLatin1String("removeProfile"), profileId); |
218 | return result; |
219 | } |
220 | return false; |
221 | @@ -197,8 +184,118 @@ |
222 | |
223 | void ButeoSyncFW::deinitialize() |
224 | { |
225 | + m_waitSyncStart = false; |
226 | + m_profilesByCategory.clear(); |
227 | + m_reloadProfilesWatcher.reset(); |
228 | m_iface.reset(); |
229 | + |
230 | // notify changes on properties |
231 | - emit syncStatus("", 0, "", 0); |
232 | - emit profileChanged("", 0, ""); |
233 | + emit profilesChanged(); |
234 | + emit syncStatusChanged(); |
235 | +} |
236 | + |
237 | +QStringList ButeoSyncFW::profiles(const QString &category, bool onlyEnabled) const |
238 | +{ |
239 | + QStringList result; |
240 | + QList<ProfileData> filter = category.isEmpty() ? |
241 | + m_profilesByCategory.values() : m_profilesByCategory.values(category); |
242 | + |
243 | + foreach(const ProfileData &p, filter) { |
244 | + if (!onlyEnabled || p.second) { |
245 | + result << p.first; |
246 | + } |
247 | + } |
248 | + return result; |
249 | +} |
250 | + |
251 | + |
252 | +QMultiMap<QString, QPair<QString, bool> > ButeoSyncFW::paserProfiles(const QStringList &profiles) const |
253 | +{ |
254 | + // extract category/ids |
255 | + QMultiMap<QString, ProfileData> profilesByCategory; |
256 | + |
257 | + foreach(const QString &profile, profiles) { |
258 | + QDomDocument doc; |
259 | + QString errorMsg; |
260 | + int errorLine; |
261 | + int errorColumn; |
262 | + if (doc.setContent(profile, &errorMsg, &errorLine, &errorColumn)) { |
263 | + QDomNodeList profileElements = doc.elementsByTagName("profile"); |
264 | + if (!profileElements.isEmpty()) { |
265 | + //check if is enabled |
266 | + QDomElement e = profileElements.item(0).toElement(); |
267 | + QDomNodeList values = e.elementsByTagName("key"); |
268 | + bool enabled = true; |
269 | + QString profileCategory; |
270 | + for(int i = 0; i < values.count(); i++) { |
271 | + QDomElement v = values.at(i).toElement(); |
272 | + if ((v.attribute("name") == "enabled") && |
273 | + (v.attribute("value") == "false")) { |
274 | + enabled = false; |
275 | + } |
276 | + if (v.attribute("name") == "category") { |
277 | + profileCategory = v.attribute("value"); |
278 | + } |
279 | + } |
280 | + |
281 | + QString profileName = e.attribute("name", ""); |
282 | + if (profileName.isEmpty() || profileCategory.isEmpty()) { |
283 | + qWarning() << "Fail to retrieve profile name and category"; |
284 | + } else { |
285 | + profilesByCategory.insertMulti(profileCategory, qMakePair(profileName, enabled)); |
286 | + } |
287 | + } else { |
288 | + qWarning() << "Profile not found in:" << profile; |
289 | + } |
290 | + } else { |
291 | + qWarning() << "Fail to parse profile:" << profile; |
292 | + qWarning() << "Error:" << errorMsg << errorLine << errorColumn; |
293 | + } |
294 | + } |
295 | + return profilesByCategory; |
296 | +} |
297 | + |
298 | +void ButeoSyncFW::reloadProfiles() |
299 | +{ |
300 | + if (m_reloadProfilesWatcher) { |
301 | + m_reloadProfilesWatcher.reset(); |
302 | + } |
303 | + |
304 | + if (!m_iface) { |
305 | + return; |
306 | + } |
307 | + |
308 | + // we only care about profiles that uses online-accounts |
309 | + QDBusPendingCall pcall = m_iface->asyncCall(QLatin1String("syncProfilesByKey"), |
310 | + QLatin1String("use_accounts"), |
311 | + QLatin1String("true")); |
312 | + if (pcall.isError()) { |
313 | + qWarning() << "Fail to call syncProfilesByKey:" << pcall.error().message(); |
314 | + } else { |
315 | + m_reloadProfilesWatcher.reset(new QDBusPendingCallWatcher(pcall, this)); |
316 | + connect(m_reloadProfilesWatcher.data(), SIGNAL(finished(QDBusPendingCallWatcher*)), |
317 | + SLOT(onAllVisibleSyncProfilesFinished(QDBusPendingCallWatcher*)), Qt::UniqueConnection); |
318 | + } |
319 | +} |
320 | + |
321 | +void ButeoSyncFW::onAllVisibleSyncProfilesFinished(QDBusPendingCallWatcher *watcher) |
322 | +{ |
323 | + QStringList profiles; |
324 | + QDBusPendingReply<QStringList> reply = *watcher; |
325 | + if (reply.isError()) { |
326 | + qWarning() << "Fail to call 'syncProfilesByKey'" << reply.error().message(); |
327 | + } else { |
328 | + profiles = reply.value(); |
329 | + } |
330 | + |
331 | + m_profilesByCategory = paserProfiles(profiles); |
332 | + m_reloadProfilesWatcher.take()->deleteLater(); |
333 | + |
334 | + // notify property change |
335 | + emit profilesChanged(); |
336 | +} |
337 | + |
338 | +void ButeoSyncFW::onSyncStatusChanged() |
339 | +{ |
340 | + m_waitSyncStart = false; |
341 | } |
342 | |
343 | === modified file 'Buteo/buteo-sync-qml.h' |
344 | --- Buteo/buteo-sync-qml.h 2015-07-08 18:09:47 +0000 |
345 | +++ Buteo/buteo-sync-qml.h 2015-09-29 13:01:20 +0000 |
346 | @@ -1,4 +1,4 @@ |
347 | -/* |
348 | +/* |
349 | * Copyright (C) 2015 Canonical, Ltd. |
350 | * |
351 | * This program is free software; you can redistribute it and/or modify |
352 | @@ -18,20 +18,23 @@ |
353 | #include <QtQml/QQmlParserStatus> |
354 | #include <QtDBus/QDBusInterface> |
355 | #include <QtDBus/QDBusServiceWatcher> |
356 | +#include <QtDBus/QDBusPendingCallWatcher> |
357 | |
358 | class ButeoSyncFW : public QObject, public QQmlParserStatus |
359 | { |
360 | Q_OBJECT |
361 | Q_INTERFACES(QQmlParserStatus) |
362 | |
363 | - Q_PROPERTY(bool syncing READ syncing NOTIFY syncStatus) |
364 | - Q_PROPERTY(QStringList visibleSyncProfiles READ visibleSyncProfiles NOTIFY profileChanged) |
365 | + Q_PROPERTY(bool syncing READ syncing NOTIFY syncStatusChanged) |
366 | + Q_PROPERTY(int profilesCount READ profilesCount NOTIFY profilesChanged) |
367 | + Q_PROPERTY(QStringList visibleSyncProfiles READ visibleSyncProfiles NOTIFY profilesChanged) |
368 | |
369 | public: |
370 | ButeoSyncFW(QObject *parent = 0); |
371 | |
372 | bool syncing() const; |
373 | QStringList visibleSyncProfiles() const; |
374 | + int profilesCount() const; |
375 | |
376 | // QQmlParserStatus |
377 | void classBegin(); |
378 | @@ -110,6 +113,12 @@ |
379 | void syncStatus(QString aProfileId, int aStatus, |
380 | QString aMessage, int aStatusDetails); |
381 | |
382 | + /*! |
383 | + * syncStatus notify signal |
384 | + */ |
385 | + void syncStatusChanged(); |
386 | + void profilesChanged(); |
387 | + |
388 | public slots: |
389 | /*! |
390 | * \brief Requests to starts synchronizing using a profile Id |
391 | @@ -124,7 +133,7 @@ |
392 | * \return True if a profile with the Id was found. Otherwise |
393 | * false and no status change signals will follow from this request. |
394 | */ |
395 | - bool startSync(const QString &aProfileId) const; |
396 | + bool startSync(const QString &aProfileId); |
397 | |
398 | /*! |
399 | * \brief Requests to starts synchronizing using a profile category |
400 | @@ -135,7 +144,7 @@ |
401 | * |
402 | * \see ButeoSyncFW::startSync |
403 | */ |
404 | - bool startSyncByCategory(const QString &category) const; |
405 | + bool startSyncByCategory(const QString &category); |
406 | |
407 | /*! |
408 | * \brief Stops synchronizing the profile with the given Id. |
409 | @@ -171,11 +180,20 @@ |
410 | |
411 | private slots: |
412 | void serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); |
413 | + void onSyncProfilesByKeyFinished(QDBusPendingCallWatcher *watcher); |
414 | + void onAllVisibleSyncProfilesFinished(QDBusPendingCallWatcher *watcher); |
415 | + void onSyncStatusChanged(); |
416 | + void reloadProfiles(); |
417 | |
418 | private: |
419 | QScopedPointer<QDBusInterface> m_iface; |
420 | QScopedPointer<QDBusServiceWatcher> m_serviceWatcher; |
421 | + QScopedPointer<QDBusPendingCallWatcher> m_reloadProfilesWatcher; |
422 | + QMultiMap<QString, QPair<QString, bool> > m_profilesByCategory; |
423 | + bool m_waitSyncStart; |
424 | |
425 | void initialize(); |
426 | void deinitialize(); |
427 | + QStringList profiles(const QString &category = QString(), bool onlyEnabled=false) const; |
428 | + QMultiMap<QString, QPair<QString, bool> > paserProfiles(const QStringList &profiles) const; |
429 | }; |
430 | |
431 | === modified file 'CMakeLists.txt' |
432 | --- CMakeLists.txt 2015-07-08 15:02:36 +0000 |
433 | +++ CMakeLists.txt 2015-09-29 13:01:20 +0000 |
434 | @@ -18,6 +18,20 @@ |
435 | find_package(Qt5DBus REQUIRED) |
436 | find_package(Qt5Xml REQUIRED) |
437 | |
438 | +# Coverage tools |
439 | +OPTION(ENABLE_COVERAGE "Build with coverage analysis support" OFF) |
440 | +if(ENABLE_COVERAGE) |
441 | + message(STATUS "Using coverage flags") |
442 | + find_program(COVERAGE_COMMAND gcov) |
443 | + if(NOT COVERAGE_COMMAND) |
444 | + message(FATAL_ERROR "gcov command not found") |
445 | + endif() |
446 | + SET(CMAKE_C_FLAGS "-g -O0 -Wall -fprofile-arcs -ftest-coverage") |
447 | + SET(CMAKE_CXX_FLAGS "-g -O0 -Wall -fprofile-arcs -ftest-coverage") |
448 | + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage -lgcov") |
449 | + include(${CMAKE_SOURCE_DIR}/cmake/lcov.cmake) |
450 | +endif() |
451 | + |
452 | enable_testing() |
453 | add_subdirectory(Buteo) |
454 | add_subdirectory(tests) |
455 | |
456 | === added directory 'cmake' |
457 | === added file 'cmake/lcov.cmake' |
458 | --- cmake/lcov.cmake 1970-01-01 00:00:00 +0000 |
459 | +++ cmake/lcov.cmake 2015-09-29 13:01:20 +0000 |
460 | @@ -0,0 +1,67 @@ |
461 | +# - This module creates a new 'lcov' target which generates |
462 | +# a coverage analysis html output. |
463 | +# LCOV is a graphical front-end for GCC's coverage testing tool gcov. Please see |
464 | +# http://ltp.sourceforge.net/coverage/lcov.php |
465 | +# |
466 | +# Usage: you must add an option to your CMakeLists.txt to build your application |
467 | +# with coverage support. Then you need to include this file to the lcov target. |
468 | +# |
469 | +# Example: |
470 | +# IF(BUILD_WITH_COVERAGE) |
471 | +# SET(CMAKE_C_FLAGS "-g -O0 -Wall -fprofile-arcs -ftest-coverage") |
472 | +# SET(CMAKE_CXX_FLAGS "-g -O0 -Wall -fprofile-arcs -ftest-coverage") |
473 | +# SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage -lgcov") |
474 | +# include(${CMAKE_SOURCE_DIR}/cmake/lcov.cmake) |
475 | +# ENDIF(BUILD_WITH_COVERAGE) |
476 | +#============================================================================= |
477 | +# Copyright 2010 ascolab GmbH |
478 | +# |
479 | +# Distributed under the OSI-approved BSD License (the "License"); |
480 | +# see accompanying file Copyright.txt for details. |
481 | +# |
482 | +# This software is distributed WITHOUT ANY WARRANTY; without even the |
483 | +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
484 | +# See the License for more information. |
485 | +#============================================================================= |
486 | +# (To distributed this file outside of CMake, substitute the full |
487 | +# License text for the above reference.) |
488 | + |
489 | +set(REMOVE_PATTERN |
490 | + q*.h |
491 | + *.moc |
492 | + moc_*.cpp |
493 | + locale_facets.h |
494 | + new |
495 | + move.h) |
496 | + |
497 | +## lcov target |
498 | +ADD_CUSTOM_TARGET(lcov) |
499 | +ADD_CUSTOM_COMMAND(TARGET lcov |
500 | + COMMAND mkdir -p coverage |
501 | + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} |
502 | + ) |
503 | +ADD_CUSTOM_COMMAND(TARGET lcov |
504 | + COMMAND lcov --directory . --zerocounters |
505 | + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} |
506 | + ) |
507 | +ADD_CUSTOM_COMMAND(TARGET lcov |
508 | + COMMAND make test |
509 | + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} |
510 | + ) |
511 | +ADD_CUSTOM_COMMAND(TARGET lcov |
512 | + COMMAND lcov --directory . --capture --output-file ./coverage/stap_all.info --no-checksum --compat-libtool |
513 | + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} |
514 | + ) |
515 | +ADD_CUSTOM_COMMAND(TARGET lcov |
516 | + COMMAND lcov --directory . -r ./coverage/stap_all.info ${REMOVE_PATTERN} --output-file ./coverage/stap.info |
517 | + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} |
518 | + ) |
519 | +ADD_CUSTOM_COMMAND(TARGET lcov |
520 | + COMMAND genhtml -o ./coverage --title "Code Coverage" --legend --show-details --demangle-cpp ./coverage/stap.info |
521 | + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} |
522 | + ) |
523 | +ADD_CUSTOM_COMMAND(TARGET lcov |
524 | + COMMAND echo "Open ${CMAKE_BINARY_DIR}/coverage/index.html to view the coverage analysis results." |
525 | + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} |
526 | + ) |
527 | + |
528 | |
529 | === modified file 'debian/control' |
530 | --- debian/control 2015-07-09 14:03:24 +0000 |
531 | +++ debian/control 2015-09-29 13:01:20 +0000 |
532 | @@ -25,7 +25,7 @@ |
533 | Pre-Depends: ${misc:Pre-Depends} |
534 | Depends: ${misc:Depends}, |
535 | ${shlibs:Depends}, |
536 | - buteo-syncfw-qt5, |
537 | +Recommends: buteo-syncfw |
538 | Description: Buteo sync framework client - QML bindings |
539 | buteo-syncfw manages data synchronization |
540 | . |
541 | |
542 | === modified file 'tests/qml/buteo-syncfw.py' |
543 | --- tests/qml/buteo-syncfw.py 2015-07-08 15:02:36 +0000 |
544 | +++ tests/qml/buteo-syncfw.py 2015-09-29 13:01:20 +0000 |
545 | @@ -30,6 +30,7 @@ |
546 | SYSTEM_BUS = False |
547 | |
548 | class ButeoSyncFw(dbus.service.Object): |
549 | + DBUS_NAME = None |
550 | PROFILES = [ |
551 | """<?xml version=\"1.0\" encoding=\"UTF-8\"?> |
552 | <profile type=\"sync\" name=\"test-profile\"> |
553 | @@ -90,6 +91,7 @@ |
554 | |
555 | def __init__(self, object_path): |
556 | dbus.service.Object.__init__(self, dbus.SessionBus(), object_path) |
557 | + self._mainloop = GObject.MainLoop() |
558 | self._activeSync = [] |
559 | self._profiles = ButeoSyncFw.PROFILES |
560 | |
561 | @@ -112,6 +114,12 @@ |
562 | @dbus.service.method(dbus_interface=MAIN_IFACE, |
563 | in_signature='s', out_signature='') |
564 | def abortSync(self, profileId): |
565 | + # WORKAROUND: using 'quit' as profileId will cause the service to dissapear |
566 | + # used on unit test |
567 | + if profileId == 'quit': |
568 | + self.quit() |
569 | + return |
570 | + |
571 | if profileId in self._activeSync: |
572 | self._activeSync.remove(profileId) |
573 | self.syncStatus(profileId, 5, 'aborted by the user', 0) |
574 | @@ -134,12 +142,12 @@ |
575 | @dbus.service.signal(dbus_interface=MAIN_IFACE, |
576 | signature='sisi') |
577 | def syncStatus(self, profileId, status, message, statusDetails): |
578 | - print("SyncStatus called") |
579 | + pass |
580 | |
581 | @dbus.service.signal(dbus_interface=MAIN_IFACE, |
582 | signature='sis') |
583 | def signalProfileChanged(self, profileId, status, changedProfile): |
584 | - print("profileChanged called") |
585 | + pass |
586 | |
587 | @dbus.service.method(dbus_interface=MAIN_IFACE, |
588 | in_signature='s', out_signature='b') |
589 | @@ -151,13 +159,16 @@ |
590 | else: |
591 | return False |
592 | |
593 | + def quit(self): |
594 | + ButeoSyncFw.DBUS_NAME = None |
595 | + self._mainloop.quit() |
596 | |
597 | + def _run(self): |
598 | + self._mainloop.run() |
599 | |
600 | if __name__ == '__main__': |
601 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) |
602 | |
603 | - name = dbus.service.BusName(BUS_NAME) |
604 | - mainloop = GObject.MainLoop() |
605 | + ButeoSyncFw.DBUS_NAME = dbus.service.BusName(BUS_NAME) |
606 | buteo = ButeoSyncFw(MAIN_OBJ) |
607 | - mainloop.run() |
608 | - |
609 | + buteo._run() |
610 | |
611 | === modified file 'tests/qml/tst_ButeoSyncFW.qml' |
612 | --- tests/qml/tst_ButeoSyncFW.qml 2015-07-08 15:02:36 +0000 |
613 | +++ tests/qml/tst_ButeoSyncFW.qml 2015-09-29 13:01:20 +0000 |
614 | @@ -24,12 +24,13 @@ |
615 | property var buteoComponent |
616 | |
617 | TestCase { |
618 | - id: vcardParser |
619 | name: 'ButeoSyncFWTestCase' |
620 | |
621 | function init() |
622 | { |
623 | buteoComponent = Qt.createQmlObject('import Buteo 0.1; ButeoSync{ }', root); |
624 | + // wait profiles to load |
625 | + tryCompare(buteoComponent, 'profilesCount', 4) |
626 | } |
627 | |
628 | function cleanup() |
629 | @@ -47,6 +48,27 @@ |
630 | } |
631 | } |
632 | |
633 | + function cleanupTestCase() |
634 | + { |
635 | + // Test service dissapear |
636 | + // We can only test it on 'cleanupTestCase' because it will cause the dbus |
637 | + // service to dissapear and any test after this call will fail |
638 | + buteoComponent = Qt.createQmlObject('import Buteo 0.1; ButeoSync{ }', root); |
639 | + |
640 | + var spy = Qt.createQmlObject('import QtTest 1.0; SignalSpy{ }', root); |
641 | + spy.target = buteoComponent |
642 | + spy.signalName = "profilesChanged" |
643 | + |
644 | + buteoComponent.abortSync('quit') |
645 | + |
646 | + tryCompare(spy, "count", 1) |
647 | + tryCompare(buteoComponent, 'syncing', false) |
648 | + tryCompare(buteoComponent, 'visibleSyncProfiles', []) |
649 | + |
650 | + buteoComponent.destroy() |
651 | + buteoComponent = null |
652 | + } |
653 | + |
654 | function test_start_sync() |
655 | { |
656 | var spy = Qt.createQmlObject('import QtTest 1.0; SignalSpy{ }', root); |
657 | @@ -99,7 +121,7 @@ |
658 | |
659 | function test_visibleSyncProfiles_property() |
660 | { |
661 | - compare(buteoComponent.visibleSyncProfiles.length, 4) |
662 | + tryCompare(buteoComponent, 'profilesCount', 4) |
663 | var spy = Qt.createQmlObject('import QtTest 1.0; SignalSpy{ }', root); |
664 | spy.target = buteoComponent |
665 | spy.signalName = "profileChanged" |
666 | @@ -109,7 +131,7 @@ |
667 | compare(spy.signalArguments[0][0], '3') |
668 | compare(spy.signalArguments[0][1], ButeoSync.ProfileRemoved) |
669 | compare(spy.signalArguments[0][2], 'deleted') |
670 | - compare(buteoComponent.visibleSyncProfiles.length, 3) |
671 | + tryCompare(buteoComponent, 'profilesCount', 3) |
672 | spy.clear() |
673 | |
674 | buteoComponent.removeProfile('2') |
675 | @@ -117,7 +139,7 @@ |
676 | compare(spy.signalArguments[0][0], '2') |
677 | compare(spy.signalArguments[0][1], ButeoSync.ProfileRemoved) |
678 | compare(spy.signalArguments[0][2], 'deleted') |
679 | - compare(buteoComponent.visibleSyncProfiles.length, 2) |
680 | + tryCompare(buteoComponent, 'profilesCount', 2) |
681 | spy.clear() |
682 | |
683 | buteoComponent.removeProfile('1') |
684 | @@ -125,7 +147,7 @@ |
685 | compare(spy.signalArguments[0][0], '1') |
686 | compare(spy.signalArguments[0][1], ButeoSync.ProfileRemoved) |
687 | compare(spy.signalArguments[0][2], 'deleted') |
688 | - compare(buteoComponent.visibleSyncProfiles.length, 1) |
689 | + tryCompare(buteoComponent, 'profilesCount', 1) |
690 | spy.clear() |
691 | |
692 | buteoComponent.removeProfile('0') |
693 | @@ -133,7 +155,7 @@ |
694 | compare(spy.signalArguments[0][0], '0') |
695 | compare(spy.signalArguments[0][1], ButeoSync.ProfileRemoved) |
696 | compare(spy.signalArguments[0][2], 'deleted') |
697 | - compare(buteoComponent.visibleSyncProfiles.length, 0) |
698 | + tryCompare(buteoComponent, 'profilesCount', 0) |
699 | spy.clear() |
700 | } |
701 | |
702 | @@ -141,8 +163,8 @@ |
703 | { |
704 | var profiles = buteoComponent.syncProfilesByCategory('contacts') |
705 | compare(profiles.length, 2) |
706 | - compare(profiles[0], 'test-profile') |
707 | - compare(profiles[1], '63807467') |
708 | + compare(profiles[0], '63807467') |
709 | + compare(profiles[1], 'test-profile') |
710 | } |
711 | |
712 | function test_sync_by_category() |
713 | @@ -156,19 +178,19 @@ |
714 | // wait for two signals (since we have two contacts profiles) |
715 | tryCompare(spy, "count", 2) |
716 | // first profile |
717 | - compare(spy.signalArguments[0][0], 'test-profile') |
718 | + compare(spy.signalArguments[0][0], '63807467') |
719 | compare(spy.signalArguments[0][1], ButeoSync.SyncStarted) |
720 | compare(spy.signalArguments[0][2], '') |
721 | |
722 | // secound profile |
723 | - compare(spy.signalArguments[1][0], '63807467') |
724 | + compare(spy.signalArguments[1][0], 'test-profile') |
725 | compare(spy.signalArguments[1][1], ButeoSync.SyncStarted) |
726 | compare(spy.signalArguments[1][2], '') |
727 | |
728 | var activeProfiles = buteoComponent.getRunningSyncList() |
729 | compare(activeProfiles.length, 2) |
730 | - compare(activeProfiles[0], 'test-profile') |
731 | - compare(activeProfiles[1], '63807467') |
732 | + compare(activeProfiles[0], '63807467') |
733 | + compare(activeProfiles[1], 'test-profile') |
734 | } |
735 | } |
736 | } |
PASSED: Continuous integration, rev:6 jenkins. qa.ubuntu. com/job/ buteo-syncfw- qml-ci/ 3/ jenkins. qa.ubuntu. com/job/ buteo-syncfw- qml-vivid- amd64-ci/ 3 jenkins. qa.ubuntu. com/job/ buteo-syncfw- qml-vivid- armhf-ci/ 3 jenkins. qa.ubuntu. com/job/ buteo-syncfw- qml-vivid- armhf-ci/ 3/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ buteo-syncfw- qml-vivid- i386-ci/ 3
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/buteo- syncfw- qml-ci/ 3/rebuild
http://