Merge lp:~renatofilho/address-book-service/fix-1387763-rtm into lp:address-book-service/rtm-14.09

Proposed by Renato Araujo Oliveira Filho
Status: Merged
Approved by: Bill Filler
Approved revision: 137
Merged at revision: 137
Proposed branch: lp:~renatofilho/address-book-service/fix-1387763-rtm
Merge into: lp:address-book-service/rtm-14.09
Diff against target: 443 lines (+275/-41)
5 files modified
lib/addressbook.cpp (+75/-40)
lib/addressbook.h (+1/-1)
tests/CMakeLists.txt (+3/-0)
tests/unittest/CMakeLists.txt (+54/-0)
tests/unittest/contact-collection-test.cpp (+142/-0)
To merge this branch: bzr merge lp:~renatofilho/address-book-service/fix-1387763-rtm
Reviewer Review Type Date Requested Status
Bill Filler (community) Approve
Review via email: mp+243444@code.launchpad.net

Commit message

Avoid create sources with duplicated Id;
Remove address book sources based on source name instead of source id.

To post a comment you must log in.
Revision history for this message
Bill Filler (bfiller) wrote :

approved

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/addressbook.cpp'
2--- lib/addressbook.cpp 2014-09-30 16:42:48 +0000
3+++ lib/addressbook.cpp 2014-12-02 19:11:11 +0000
4@@ -69,10 +69,12 @@
5 class CreateSourceData
6 {
7 public:
8+ QString m_sourceId;
9 QString m_sourceName;
10 bool m_setAsPrimary;
11 galera::AddressBook *m_addressbook;
12 QDBusMessage m_message;
13+ ESource *m_source;
14 };
15
16 class RemoveSourceData
17@@ -82,6 +84,32 @@
18 QDBusMessage m_message;
19 };
20
21+ESource* create_esource_from_data(const CreateSourceData &data, ESourceRegistry **registry)
22+{
23+ GError *error = NULL;
24+ ESource *source = e_source_new_with_uid(data.m_sourceId.toUtf8().data(), NULL, &error);
25+ if (error) {
26+ qWarning() << "Fail to create source" << error->message;
27+ g_error_free(error);
28+ return 0;
29+ }
30+
31+ e_source_set_parent(source, "local-stub");
32+ e_source_set_display_name(source, data.m_sourceName.toUtf8().data());
33+ ESourceAddressBook *ext = E_SOURCE_ADDRESS_BOOK(e_source_get_extension(source, E_SOURCE_EXTENSION_ADDRESS_BOOK));
34+ e_source_backend_set_backend_name(E_SOURCE_BACKEND(ext), "local");
35+
36+ *registry = e_source_registry_new_sync(NULL, &error);
37+ if (error) {
38+ qWarning() << "Fail to change default contact address book" << error->message;
39+ g_error_free(error);
40+ g_object_unref(source);
41+ return 0;
42+ }
43+
44+ return source;
45+}
46+
47 }
48
49 namespace galera
50@@ -335,12 +363,12 @@
51 return Source();
52 }
53
54-Source AddressBook::createSource(const QString &sourceId, bool setAsPrimary, const QDBusMessage &message)
55+Source AddressBook::createSource(const QString &sourceName, bool setAsPrimary, const QDBusMessage &message)
56 {
57 CreateSourceData *data = new CreateSourceData;
58 data->m_addressbook = this;
59 data->m_message = message;
60- data->m_sourceName = sourceId;
61+ data->m_sourceName = sourceName;
62 data->m_setAsPrimary = setAsPrimary;
63
64 FolksPersonaStore *store = folks_individual_aggregator_get_primary_store(m_individualAggregator);
65@@ -359,22 +387,37 @@
66 NULL, NULL, NULL, NULL, NULL, NULL);
67
68 gee_collection_add_all(GEE_COLLECTION(storesIds), GEE_COLLECTION(storesKeys));
69- gee_collection_add(GEE_COLLECTION(storesIds), sourceId.toUtf8().constData());
70+ gee_collection_add(GEE_COLLECTION(storesIds), sourceName.toUtf8().constData());
71 folks_backend_set_persona_stores(dummy, storesIds);
72
73 g_object_unref(storesIds);
74 g_object_unref(backendStore);
75 g_object_unref(dummy);
76
77- Source src(sourceId, sourceId, false, false);
78+ Source src(sourceName, sourceName, false, false);
79 QDBusMessage reply = message.createReply(QVariant::fromValue<Source>(src));
80 QDBusConnection::sessionBus().send(reply);
81 } else if (personaStoreTypeId == "eds") {
82- edsf_persona_store_create_address_book(sourceId.toUtf8().data(),
83- (GAsyncReadyCallback) AddressBook::createSourceDone,
84- data);
85+ data->m_sourceId = QUuid::createUuid().toString().remove("{").remove("}");
86+ ESourceRegistry *registry = NULL;
87+ ESource *source = create_esource_from_data(*data, &registry);
88+ if (source) {
89+ data->m_source = source;
90+ e_source_registry_commit_source(registry,
91+ source,
92+ NULL,
93+ (GAsyncReadyCallback) AddressBook::createSourceDone,
94+ data);
95+ } else {
96+ delete data;
97+ QDBusMessage reply = message.createReply(QVariant::fromValue<Source>(Source()));
98+ QDBusConnection::sessionBus().send(reply);
99+ }
100 } else {
101 qWarning() << "Not supported, create sources on persona store with type id:" << personaStoreTypeId;
102+ delete data;
103+ QDBusMessage reply = message.createReply(QVariant::fromValue<Source>(Source()));
104+ QDBusConnection::sessionBus().send(reply);
105 }
106 return Source();
107 }
108@@ -386,19 +429,30 @@
109 bool error = false;
110 if (backend) {
111 GeeMap *storesMap = folks_backend_get_persona_stores(backend);
112- if (gee_map_has_key(storesMap, sourceId.toUtf8().constData())) {
113- EdsfPersonaStore *ps = EDSF_PERSONA_STORE(gee_map_get(storesMap, sourceId.toUtf8().constData()));
114-
115- RemoveSourceData *rData = new RemoveSourceData;
116- rData->m_addressbook = this;
117- rData->m_message = message;
118- edsf_persona_store_remove_address_book(ps, AddressBook::removeSourceDone, rData);
119+ GeeCollection *stores = gee_map_get_values(storesMap);
120+ GeeIterator *i = gee_iterable_iterator(GEE_ITERABLE(stores));
121+ RemoveSourceData *rData = 0;
122+ while (gee_iterator_next(i)) {
123+ FolksPersonaStore *ps = FOLKS_PERSONA_STORE(gee_iterator_get(i));
124+ // We need to compare using source name due the missing API to handle sources diff from contacts
125+ if (g_strcmp0(folks_persona_store_get_display_name(ps), sourceId.toUtf8().constData()) == 0) {
126+ rData = new RemoveSourceData;
127+ rData->m_addressbook = this;
128+ rData->m_message = message;
129+ edsf_persona_store_remove_address_book(EDSF_PERSONA_STORE(ps), AddressBook::removeSourceDone, rData);
130+ g_object_unref(ps);
131+ break;
132+ }
133 g_object_unref(ps);
134- } else {
135+ }
136+
137+ g_object_unref(backend);
138+ g_object_unref(stores);
139+
140+ if (!rData) {
141 qWarning() << "Source not found to remove:" << sourceId;
142 error = true;
143 }
144- g_object_unref(backend);
145 } else {
146 qWarning() << "Fail to create eds backend during the source removal:" << sourceId;
147 error = true;
148@@ -486,36 +540,18 @@
149 CreateSourceData *cData = static_cast<CreateSourceData*>(data);
150 GError *error = 0;
151 Source src;
152- edsf_persona_store_create_address_book_finish(res, &error);
153+ e_source_registry_commit_source_finish(E_SOURCE_REGISTRY(source), res, &error);
154 if (error) {
155 qWarning() << "Fail to create source" << error->message;
156 g_error_free(error);
157 } else {
158- src = Source(cData->m_sourceName, cData->m_sourceName, false, cData->m_setAsPrimary);
159+ // set as primary if necessary
160 if (cData->m_setAsPrimary) {
161- ESourceRegistry *r = e_source_registry_new_sync(NULL, &error);
162- if (error) {
163- qWarning() << "Fail to change default contact address book" << error->message;
164- g_error_free(error);
165- } else {
166- ESource *edsSource = 0;
167- GList *sources = e_source_registry_list_sources(r, E_SOURCE_EXTENSION_ADDRESS_BOOK);
168- for(GList *i = sources; i != -0; i = sources->next) {
169- edsSource = E_SOURCE(i->data);
170- if (strcmp(cData->m_sourceName.toUtf8().constData(), e_source_get_uid(edsSource)) == 0) {
171- break;
172- }
173- }
174- if (edsSource) {
175- e_source_registry_set_default_address_book(r, edsSource);
176- } else {
177- qWarning() << "Fail to find source:" << cData->m_sourceName;
178- }
179- g_list_free_full(sources, g_object_unref);
180- }
181- g_object_unref(r);
182+ e_source_registry_set_default_address_book(E_SOURCE_REGISTRY(source), cData->m_source);
183 }
184+ src = Source(cData->m_sourceId, cData->m_sourceName, false, cData->m_setAsPrimary);
185 }
186+ g_object_unref(source);
187 QDBusMessage reply = cData->m_message.createReply(QVariant::fromValue<Source>(src));
188 QDBusConnection::sessionBus().send(reply);
189 delete cData;
190@@ -630,7 +666,6 @@
191 }
192
193 result << Source(id, displayName, !canWrite, isPrimary);
194-
195 g_object_unref(store);
196 }
197
198
199=== modified file 'lib/addressbook.h'
200--- lib/addressbook.h 2014-09-30 16:23:53 +0000
201+++ lib/addressbook.h 2014-12-02 19:11:11 +0000
202@@ -70,7 +70,7 @@
203 void shutdown();
204 SourceList availableSources(const QDBusMessage &message);
205 Source source(const QDBusMessage &message);
206- Source createSource(const QString &sourceId, bool setAsPrimary, const QDBusMessage &message);
207+ Source createSource(const QString &sourceName, bool setAsPrimary, const QDBusMessage &message);
208 void removeSource(const QString &sourceId, const QDBusMessage &message);
209 QString createContact(const QString &contact, const QString &source, const QDBusMessage &message = QDBusMessage());
210 int removeContacts(const QStringList &contactIds, const QDBusMessage &message);
211
212=== modified file 'tests/CMakeLists.txt'
213--- tests/CMakeLists.txt 2013-05-21 20:11:19 +0000
214+++ tests/CMakeLists.txt 2014-12-02 19:11:11 +0000
215@@ -1,2 +1,5 @@
216+find_program(EVOLUTION_ADDRESSBOOK_FACTORY_BIN evolution-addressbook-factory
217+ PATHS /usr/lib/evolution/)
218+set(EVOLUTION_ADDRESSBOOK_SERVICE_NAME "org.gnome.evolution.dataserver.AddressBook6")
219 add_subdirectory(data)
220 add_subdirectory(unittest)
221
222=== modified file 'tests/unittest/CMakeLists.txt'
223--- tests/unittest/CMakeLists.txt 2014-05-27 14:41:55 +0000
224+++ tests/unittest/CMakeLists.txt 2014-12-02 19:11:11 +0000
225@@ -36,6 +36,57 @@
226 TIMEOUT ${CTEST_TESTING_TIMEOUT})
227 endmacro()
228
229+macro(declare_eds_test TESTNAME)
230+ add_executable(${TESTNAME}
231+ ${ARGN}
232+ ${TESTNAME}.cpp
233+ )
234+ qt5_use_modules(${TESTNAME} Core Contacts Versit Test DBus)
235+
236+ if(TEST_XML_OUTPUT)
237+ set(TEST_ARGS -p -xunitxml -p -o -p test_${testname}.xml)
238+ else()
239+ set(TEST_ARGS "")
240+ endif()
241+
242+ target_link_libraries(${TESTNAME}
243+ address-book-service-lib
244+ ${CONTACTS_SERVICE_LIB}
245+ ${GLIB_LIBRARIES}
246+ ${GIO_LIBRARIES}
247+ ${FOLKS_LIBRARIES}
248+ )
249+
250+ add_test(${TESTNAME}
251+ ${DBUS_RUNNER}
252+ --keep-env
253+ --task ${EVOLUTION_ADDRESSBOOK_FACTORY_BIN} --task-name "evolution-addressbook" -r
254+ --task ${address-book-service_BINARY_DIR}/address-book-service --wait-for=${EVOLUTION_ADDRESSBOOK_SERVICE_NAME} -r
255+ --task ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME} ${TEST_ARGS} --wait-for=com.canonical.pim --wait-until-complete)
256+
257+ execute_process(COMMAND mktemp -d /tmp/${TESTNAME}_XXXX
258+ OUTPUT_VARIABLE TMP_HOME_DIR)
259+ list(APPEND TEST_ENVIRONMENT_LIST "QT_QPA_PLATFORM=minimal")
260+ list(APPEND TEST_ENVIRONMENT_LIST "FOLKS_BACKENDS_ALLOWED=eds")
261+ list(APPEND TEST_ENVIRONMENT_LIST "HOME=${TMP_HOME_DIR}")
262+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_RUNTIME_DIR=${TMP_HOME_DIR}")
263+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_CACHE_HOME=${TMP_HOME_DIR}/.cache")
264+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_CONFIG_HOME=${TMP_HOME_DIR}/.config")
265+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_CONFIG_HOME=${TMP_HOME_DIR}/.local/share")
266+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_DOCUMENTS_DIR=${TMP_HOME_DIR}")
267+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_DOWNLOAD_DIR=${TMP_HOME_DIR}")
268+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_MUSIC_DIR=${TMP_HOME_DIR}")
269+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_PICTURES_DIR=${TMP_HOME_DIR}")
270+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_PUBLICSHARE_DIR=${TMP_HOME_DIR}")
271+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_TEMPLATES_DIR=${TMP_HOME_DIR}")
272+ list(APPEND TEST_ENVIRONMENT_LIST "XDG_VIDEOS_DIR=${TMP_HOME_DIR}")
273+ list(APPEND TEST_ENVIRONMENT_LIST "QORGANIZER_EDS_DEBUG=On")
274+
275+ set_tests_properties(${TESTNAME} PROPERTIES
276+ ENVIRONMENT ${TEST_ENVIRONMENT_LIST}
277+ TIMEOUT ${CTEST_TESTING_TIMEOUT})
278+endmacro()
279+
280 include_directories(
281 ${CMAKE_SOURCE_DIR}
282 ${CMAKE_BINARY_DIR}
283@@ -77,6 +128,8 @@
284 declare_test(qcontacts-test True ${BASE_CLIENT_TEST_SRC})
285 declare_test(qcontacts-create-source-test True ${BASE_CLIENT_TEST_SRC})
286 declare_test(qcontacts-async-request-test True ${BASE_CLIENT_TEST_SRC})
287+
288+ declare_eds_test(contact-collection-test)
289 elseif()
290 message(STATUS "DBus test runner not found. Some tests will be disabled")
291 endif()
292@@ -101,3 +154,4 @@
293 ${FOLKS_LIBRARIES}
294 )
295
296+
297
298=== added file 'tests/unittest/contact-collection-test.cpp'
299--- tests/unittest/contact-collection-test.cpp 1970-01-01 00:00:00 +0000
300+++ tests/unittest/contact-collection-test.cpp 2014-12-02 19:11:11 +0000
301@@ -0,0 +1,142 @@
302+/*
303+ * Copyright 2013 Canonical Ltd.
304+ *
305+ * This file is part of contact-service-app.
306+ *
307+ * contact-service-app is free software; you can redistribute it and/or modify
308+ * it under the terms of the GNU General Public License as published by
309+ * the Free Software Foundation; version 3.
310+ *
311+ * contact-service-app is distributed in the hope that it will be useful,
312+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
313+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
314+ * GNU General Public License for more details.
315+ *
316+ * You should have received a copy of the GNU General Public License
317+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
318+ */
319+
320+#include <QObject>
321+#include <QtTest>
322+#include <QDebug>
323+#include <QtContacts>
324+
325+#include "config.h"
326+
327+using namespace QtContacts;
328+
329+class ContactCollectionTest : public QObject
330+{
331+ Q_OBJECT
332+private:
333+ QContactManager *m_manager;
334+
335+private Q_SLOTS:
336+ void initTestCase()
337+ {
338+ QCoreApplication::setLibraryPaths(QStringList() << QT_PLUGINS_BINARY_DIR);
339+ // wait for address-book-service
340+ QTest::qWait(1000);
341+ }
342+
343+ void init()
344+ {
345+ m_manager = new QContactManager("galera");
346+ }
347+
348+ void cleanup()
349+ {
350+ delete m_manager;
351+ }
352+
353+ /*
354+ * Test create a new collection
355+ */
356+ void testCreateAddressBook()
357+ {
358+ QContact c;
359+ c.setType(QContactType::TypeGroup);
360+ QContactDisplayLabel label;
361+ QString uniqueName = QString("source@%1").arg(QUuid::createUuid().toString().remove("{").remove("}"));
362+ label.setLabel(uniqueName);
363+ c.saveDetail(&label);
364+
365+ bool saveResult = m_manager->saveContact(&c);
366+ QVERIFY(saveResult);
367+
368+ QContactDetailFilter filter;
369+ filter.setDetailType(QContactDetail::TypeType, QContactType::FieldType);
370+ filter.setValue(QContactType::TypeGroup);
371+
372+ QList<QContact> contacts = m_manager->contacts(filter);
373+ Q_FOREACH(const QContact &contact, contacts) {
374+ if ((contact.detail<QContactDisplayLabel>().label() == uniqueName) &&
375+ (contact.id() == c.id())) {
376+ return;
377+ }
378+ }
379+ QFAIL("New collection not found");
380+ }
381+
382+ /*
383+ * Test remove a collection
384+ */
385+ void testRemoveAddressBook()
386+ {
387+ // create a source
388+ QContact c;
389+ c.setType(QContactType::TypeGroup);
390+ QContactDisplayLabel label;
391+ QString uniqueName = QString("source@%1").arg(QUuid::createUuid().toString().remove("{").remove("}"));
392+ label.setLabel(uniqueName);
393+ c.saveDetail(&label);
394+
395+ bool saveResult = m_manager->saveContact(&c);
396+ QVERIFY(saveResult);
397+
398+ // try to remove new source
399+ // WORKAROUND: Since qcontacts does not cotains a API to remove address book we use the contact label as id
400+ // for addressbook. This Id must contain a "@" to be handled as address book name.
401+ QContactId addressBookId = QContactId::fromString(QString("qtcontacts:galera::%1").arg(uniqueName));
402+ bool removeResult = m_manager->removeContact(addressBookId);
403+ QVERIFY(removeResult);
404+
405+ // check if the source was removed
406+ QContactDetailFilter filter;
407+ filter.setDetailType(QContactDetail::TypeType, QContactType::FieldType);
408+ filter.setValue(QContactType::TypeGroup);
409+ QList<QContact> contacts = m_manager->contacts(filter);
410+ Q_FOREACH(const QContact &contact, contacts) {
411+ if (contact.id() == c.id()) {
412+ QFAIL("Collection not removed");
413+ }
414+ }
415+ }
416+
417+ /*
418+ * Test query for collections using the contact group type
419+ */
420+ void testQueryAddressBook()
421+ {
422+ // filter all contact groups/addressbook
423+ QContactDetailFilter filter;
424+ filter.setDetailType(QContactDetail::TypeType, QContactType::FieldType);
425+ filter.setValue(QContactType::TypeGroup);
426+
427+ // check result for the default source
428+ QList<QContact> contacts = m_manager->contacts(filter);
429+ Q_FOREACH(const QContact &c, contacts) {
430+ QCOMPARE(c.type(), QContactType::TypeGroup);
431+ if (c.id().toString() == QStringLiteral("qtcontacts:galera::system-address-book")) {
432+ QContactDisplayLabel label = c.detail(QContactDisplayLabel::Type);
433+ QCOMPARE(label.label(), QStringLiteral("Personal"));
434+ return;
435+ }
436+ }
437+ QFAIL("Fail to query for collections");
438+ }
439+};
440+
441+QTEST_MAIN(ContactCollectionTest)
442+
443+#include "contact-collection-test.moc"

Subscribers

People subscribed via source and target branches