Merge lp:~mardy/online-accounts-api/mock-template into lp:online-accounts-api

Proposed by Alberto Mardegan
Status: Rejected
Rejected by: Alberto Mardegan
Proposed branch: lp:~mardy/online-accounts-api/mock-template
Merge into: lp:online-accounts-api
Prerequisite: lp:~mardy/online-accounts-api/qt-api-impl
Diff against target: 340 lines (+314/-0)
4 files modified
src/daemon/online_accounts.py (+128/-0)
tests/CMakeLists.txt (+1/-0)
tests/daemon/mock_template/CMakeLists.txt (+28/-0)
tests/daemon/mock_template/mock_template.cpp (+157/-0)
To merge this branch: bzr merge lp:~mardy/online-accounts-api/mock-template
Reviewer Review Type Date Requested Status
Online Accounts Pending
Review via email: mp+252540@code.launchpad.net

Commit message

Create python-dbusmock template

And a couple of tests to ensure it's working properly.

Description of the change

Create python-dbusmock template

And a couple of tests to ensure it's working properly.

To post a comment you must log in.

Unmerged revisions

38. By Alberto Mardegan

Update library name

37. By Alberto Mardegan

Merge from qt branch

36. By Alberto Mardegan

Remove disabled tests, fix execution

35. By Alberto Mardegan

WIP

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'src/daemon/online_accounts.py'
2--- src/daemon/online_accounts.py 1970-01-01 00:00:00 +0000
3+++ src/daemon/online_accounts.py 2015-03-11 07:42:13 +0000
4@@ -0,0 +1,128 @@
5+'''online-accounts mock template
6+
7+This creates the expected methods and properties of the main
8+com.ubuntu.OnlineAccounts.Manager object. By default, all actions are rejected. You
9+can call AllowUnknown() and SetAllowed() on the mock D-BUS interface to control
10+which actions are allowed.
11+'''
12+
13+# This program is free software; you can redistribute it and/or modify it under
14+# the terms of the GNU Lesser General Public License as published by the Free
15+# Software Foundation; either version 3 of the License, or (at your option) any
16+# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
17+# of the license.
18+
19+__author__ = 'Alberto Mardegan'
20+__email__ = 'alberto.mardegan@canonical.com'
21+__copyright__ = '(c) 2015 Canonical Ltd.'
22+__license__ = 'LGPL 3+'
23+
24+import dbus
25+
26+from dbusmock import MOCK_IFACE
27+
28+BUS_NAME = 'com.ubuntu.OnlineAccounts.Manager'
29+MAIN_OBJ = '/com/ubuntu/OnlineAccounts/Manager'
30+MAIN_IFACE = 'com.ubuntu.OnlineAccounts.Manager'
31+SYSTEM_BUS = False
32+
33+ERROR_PREFIX = 'com.ubuntu.OnlineAccounts.Error.'
34+ERROR_NO_ACCOUNT = ERROR_PREFIX + 'NoAccount'
35+ERROR_CANCELED = ERROR_PREFIX + 'UserCanceled'
36+ERROR_PERMISSION_DENIED = ERROR_PREFIX + 'PermissionDenied'
37+ERROR_INTERACTION_REQUIRED = ERROR_PREFIX + 'InteractionRequired'
38+
39+CHANGE_TYPE_ENABLED = 0
40+CHANGE_TYPE_DISABLED = 1
41+CHANGE_TYPE_UPDATED = 2
42+
43+def load(mock, parameters):
44+ mock.AddMethod(MAIN_IFACE,
45+ 'GetAccounts',
46+ 'a{sv}',
47+ 'a(ua{sv})',
48+ '''ret = self.accounts.items()''')
49+
50+ mock.AddMethod(MAIN_IFACE,
51+ 'RequestAccess',
52+ 'sa{sv}',
53+ '(ua{sv})a{sv}',
54+ 'ret = self.request_access(args[0], args[1])')
55+
56+ mock.AddMethod(MAIN_IFACE,
57+ 'Authenticate',
58+ 'usbba{sv}',
59+ 'a{sv}',
60+ 'ret = self.authenticate(args[0], args[1], args[2], args[3], args[4])')
61+
62+ mock.accounts = {}
63+ mock.authentication_reply = {}
64+ mock.authentication_error = None
65+ mock.last_account_id = 0
66+ mock.new_account_details = {}
67+
68+ def request_access(self, service_id, params):
69+ if len(self.new_account_details) == 0:
70+ raise dbus.exceptions.DBusException('Permission denied',
71+ name=ERROR_PERMISSION_DENIED)
72+ self.AddAccount(self.new_account_details)
73+ authentication_reply = self.authenticate(self.last_account_id, service_id,
74+ True, False, params)
75+ return ((self.last_account_id, self.new_account_details), authentication_reply)
76+
77+ setattr(mock.__class__, "request_access", request_access)
78+
79+ def authenticate(self, account_id, service_id, interactive, invalidate, params):
80+ if account_id not in self.accounts:
81+ raise dbus.exceptions.DBusException('No account with id %s' % (account_id,),
82+ name=ERROR_NO_ACCOUNT)
83+ if self.authentication_error:
84+ raise dbus.exceptions.DBusException('Authentication error',
85+ name=self.authentication_error)
86+ return self.authentication_reply
87+
88+ setattr(mock.__class__, "authenticate", authenticate)
89+
90+@dbus.service.method(MOCK_IFACE, in_signature='a{sv}', out_signature='u')
91+def AddAccount(self, account_details):
92+ '''Add a new account to the DB
93+
94+ Returns the ID of the new account
95+ '''
96+ self.last_account_id += 1
97+ self.accounts[self.last_account_id] = account_details
98+ service = account_details.get('serviceId', '')
99+ signal_data = account_details.copy()
100+ signal_data['changeType'] = CHANGE_TYPE_ENABLED
101+ self.EmitSignal(MAIN_IFACE, 'AccountChanged', 's(ua{sv})',
102+ [service, (self.last_account_id, signal_data)])
103+ return self.last_account_id
104+
105+
106+@dbus.service.method(MOCK_IFACE, in_signature='u', out_signature='')
107+def RemoveAccount(self, account_id):
108+ '''Remove an existing account'''
109+
110+ account_details = self.accounts[account_id]
111+ service = account_details.get('serviceId', '')
112+ signal_data = account_details.copy()
113+ signal_data['changeType'] = CHANGE_TYPE_DISABLED
114+ self.EmitSignal(MAIN_IFACE, 'AccountChanged', 's(ua{sv})',
115+ [service, (account_id, signal_data)])
116+ del self.accounts[account_id]
117+
118+
119+@dbus.service.method(MOCK_IFACE, in_signature='a{sv}', out_signature='')
120+def SetRequestAccessReply(self, account_details):
121+ '''Prepares the reply for the next RequestAccess call'''
122+
123+ self.new_account_details = account_details
124+
125+
126+@dbus.service.method(MOCK_IFACE, in_signature='sa{sv}', out_signature='')
127+def SetAuthenticationReply(self, authentication_reply, error_name):
128+ '''Prepares the reply for the next Authenticate call'''
129+
130+ self.authentication_reply = authentication_reply
131+ self.authentication_error = error_name
132+
133
134=== modified file 'tests/CMakeLists.txt'
135--- tests/CMakeLists.txt 2015-03-11 07:42:13 +0000
136+++ tests/CMakeLists.txt 2015-03-11 07:42:13 +0000
137@@ -6,5 +6,6 @@
138 ${TEST_INCLUDE_DIRS}
139 )
140
141+add_subdirectory(daemon/mock_template)
142 add_subdirectory(lib/OnlineAccounts)
143 add_subdirectory(unit)
144
145=== added directory 'tests/daemon'
146=== added directory 'tests/daemon/mock_template'
147=== added file 'tests/daemon/mock_template/CMakeLists.txt'
148--- tests/daemon/mock_template/CMakeLists.txt 1970-01-01 00:00:00 +0000
149+++ tests/daemon/mock_template/CMakeLists.txt 2015-03-11 07:42:13 +0000
150@@ -0,0 +1,28 @@
151+set(TEST mock_template)
152+set(SOURCES
153+ mock_template.cpp
154+)
155+
156+pkg_check_modules(QTDBUSMOCK REQUIRED libqtdbusmock-1)
157+pkg_check_modules(QTDBUSTEST REQUIRED libqtdbustest-1)
158+
159+add_executable(${TEST} ${SOURCES})
160+include_directories(
161+ ${CMAKE_CURRENT_BINARY_DIR}
162+ ${OnlineAccountsQt_SOURCE_DIR}/..
163+ ${QTDBUSMOCK_INCLUDE_DIRS}
164+ ${QTDBUSTEST_INCLUDE_DIRS}
165+)
166+add_definitions(
167+ -DMOCK_TEMPLATE="${OnlineAccountsDaemon_SOURCE_DIR}/online_accounts.py"
168+)
169+
170+target_link_libraries(${TEST}
171+ OnlineAccountsQt
172+ ${QTDBUSMOCK_LIBRARIES}
173+ ${QTDBUSTEST_LIBRARIES}
174+)
175+
176+qt5_use_modules(${TEST} Core Test)
177+add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
178+add_dependencies(check ${TEST})
179
180=== added file 'tests/daemon/mock_template/mock_template.cpp'
181--- tests/daemon/mock_template/mock_template.cpp 1970-01-01 00:00:00 +0000
182+++ tests/daemon/mock_template/mock_template.cpp 2015-03-11 07:42:13 +0000
183@@ -0,0 +1,157 @@
184+/*
185+ * This file is part of libOnlineAccounts
186+ *
187+ * Copyright (C) 2015 Canonical Ltd.
188+ *
189+ * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
190+ *
191+ * This program is free software: you can redistribute it and/or modify it
192+ * under the terms of the GNU Lesser General Public License version 3, as
193+ * published by the Free Software Foundation.
194+ *
195+ * This program is distributed in the hope that it will be useful, but
196+ * WITHOUT ANY WARRANTY; without even the implied warranties of
197+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
198+ * PURPOSE. See the GNU Lesser General Public License for more details.
199+ *
200+ * You should have received a copy of the GNU Lesser General Public License
201+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
202+ */
203+
204+#include "OnlineAccounts/Account"
205+#include "OnlineAccounts/Manager"
206+#include "OnlineAccounts/OAuth1Data"
207+#include "OnlineAccounts/OAuth2Data"
208+#include "OnlineAccounts/PasswordData"
209+#include "OnlineAccounts/dbus_constants.h"
210+#include <QDBusConnection>
211+#include <QObject>
212+#include <QSignalSpy>
213+#include <QTest>
214+#include <libqtdbusmock/DBusMock.h>
215+
216+struct AccountDetails
217+{
218+ AccountDetails() {}
219+ AccountDetails(const QString &name, const QString &service,
220+ const QVariantMap &settings = QVariantMap()) {
221+ map[ONLINE_ACCOUNTS_INFO_KEY_DISPLAY_NAME] = name;
222+ map[ONLINE_ACCOUNTS_INFO_KEY_SERVICE_ID] = service;
223+ QMapIterator<QString, QVariant> it(settings);
224+ while (it.hasNext()) {
225+ it.next();
226+ map[ONLINE_ACCOUNTS_INFO_KEY_SETTINGS + it.key()] = it.value();
227+ }
228+ }
229+
230+ QVariantMap map;
231+};
232+
233+class MockTemplateTests: public QObject
234+{
235+ Q_OBJECT
236+
237+public:
238+ MockTemplateTests();
239+
240+ OrgFreedesktopDBusMockInterface &mocked() {
241+ return m_mock.mockInterface(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME,
242+ ONLINE_ACCOUNTS_MANAGER_PATH,
243+ ONLINE_ACCOUNTS_MANAGER_INTERFACE,
244+ QDBusConnection::SessionBus);
245+ }
246+
247+ uint addAccount(const AccountDetails &details);
248+ void setRequestAccessReply(const AccountDetails &details);
249+ void setAuthenticationReply(const QVariantMap &reply,
250+ const QString &errorName = QString());
251+
252+private Q_SLOTS:
253+ void testManagerAvailableAccounts();
254+ void testManagerRequestAccess();
255+
256+private:
257+ QtDBusTest::DBusTestRunner m_dbus;
258+ QtDBusMock::DBusMock m_mock;
259+};
260+
261+MockTemplateTests::MockTemplateTests():
262+ QObject(),
263+ m_mock(m_dbus)
264+{
265+ m_mock.registerCustomMock(ONLINE_ACCOUNTS_MANAGER_SERVICE_NAME,
266+ ONLINE_ACCOUNTS_MANAGER_PATH,
267+ ONLINE_ACCOUNTS_MANAGER_INTERFACE,
268+ QDBusConnection::SessionBus);
269+ m_dbus.startServices();
270+ mocked().AddTemplate(MOCK_TEMPLATE, QVariantMap());
271+}
272+
273+uint MockTemplateTests::addAccount(const AccountDetails &details)
274+{
275+ QDBusReply<uint> reply = mocked().call("AddAccount", details.map);
276+ return reply.isValid() ? reply.value() : 0;
277+}
278+
279+void MockTemplateTests::setRequestAccessReply(const AccountDetails &details)
280+{
281+ mocked().call("SetRequestAccessReply", details.map);
282+}
283+
284+void MockTemplateTests::setAuthenticationReply(const QVariantMap &reply,
285+ const QString &errorName)
286+{
287+ mocked().call("SetAuthenticationReply", reply, errorName);
288+}
289+
290+void MockTemplateTests::testManagerAvailableAccounts()
291+{
292+ OnlineAccounts::Manager manager("my-app");
293+ QSignalSpy accountAvailable(&manager,
294+ SIGNAL(accountAvailable(OnlineAccounts::Account*)));
295+
296+ manager.waitForReady();
297+ QVERIFY(manager.availableAccounts().isEmpty());
298+
299+ uint accountId = addAccount(AccountDetails("cold account", "cool service"));
300+ QVERIFY(accountId != 0);
301+
302+ if (accountAvailable.count() == 0) {
303+ accountAvailable.wait();
304+ }
305+ QCOMPARE(accountAvailable.count(), 1);
306+
307+ QList<OnlineAccounts::Account *> accounts = manager.availableAccounts();
308+ QCOMPARE(accounts.count(), 1);
309+
310+ OnlineAccounts::Account *account = accounts.first();
311+ QCOMPARE(uint(account->id()), accountId);
312+ QCOMPARE(account->displayName(), QString("cold account"));
313+ QCOMPARE(account->serviceId(), QString("cool service"));
314+}
315+
316+void MockTemplateTests::testManagerRequestAccess()
317+{
318+ OnlineAccounts::Manager manager("my-app");
319+ manager.waitForReady();
320+
321+ setRequestAccessReply(AccountDetails("Tom", "photos"));
322+ QVariantMap replyData;
323+ replyData[ONLINE_ACCOUNTS_AUTH_KEY_ACCESS_TOKEN] = QByteArray("go-on");
324+ setAuthenticationReply(replyData);
325+
326+ OnlineAccounts::OAuth2Data oauth;
327+ oauth.setClientId("happy app");
328+ OnlineAccounts::PendingCall call = manager.requestAccess("my-service",
329+ oauth);
330+ OnlineAccounts::RequestAccessReply accessReply(call);
331+ OnlineAccounts::Account *account = accessReply.account();
332+ QVERIFY(account);
333+ QCOMPARE(account->displayName(), QString("Tom"));
334+
335+ OnlineAccounts::OAuth2Reply oauthReply(call);
336+ QCOMPARE(oauthReply.accessToken(), QByteArray("go-on"));
337+}
338+
339+QTEST_MAIN(MockTemplateTests)
340+#include "mock_template.moc"

Subscribers

People subscribed via source and target branches