Merge lp:~renatofilho/buteo-syncfw-qml/release into lp:buteo-syncfw-qml

Proposed by Renato Araujo Oliveira Filho
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
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 "syncProfilesByKey".

To post a comment you must log in.
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
7. By Renato Araujo Oliveira Filho

Use async dbus call for "syncProfilesByKey".

8. By Renato Araujo Oliveira Filho

Keep a cache with all profiles maped by category, to avoid reload it during the sync.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
9. By Renato Araujo Oliveira Filho

Fix property notify signal after async load profiles.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
10. By Renato Araujo Oliveira Filho

Use asyncCall for sync function to avoid block the UI.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
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

Revision history for this message
Ken VanDine (ken-vandine) wrote :

Packaging changes look fine

review: Approve (packaging)
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Added a comment and a question to the diff, other than that this looks good.

review: Needs Information
11. By Renato Araujo Oliveira Filho

Use "profiles()" instead of "visibleSyncProfiles()" in "profilesCount()" function.

Revision history for this message
Renato Araujo Oliveira Filho (renatofilho) wrote :

Fixed

Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Looks good

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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 }

Subscribers

People subscribed via source and target branches