Merge lp:~alecu/ubuntuone-control-panel/backend-born into lp:~nataliabidart/ubuntuone-control-panel/trunk

Proposed by Alejandro J. Cura
Status: Merged
Merged at revision: 4
Proposed branch: lp:~alecu/ubuntuone-control-panel/backend-born
Merge into: lp:~nataliabidart/ubuntuone-control-panel/trunk
Diff against target: 555 lines (+494/-0)
10 files modified
integration/run-tests (+28/-0)
integration/test_dbus_client.py (+73/-0)
integration/test_dbus_service.py (+90/-0)
integration/test_webclient.py (+90/-0)
ubuntuone/controlpanel/__init__.py (+6/-0)
ubuntuone/controlpanel/backend.py (+22/-0)
ubuntuone/controlpanel/dbus_client.py (+54/-0)
ubuntuone/controlpanel/dbus_service.py (+74/-0)
ubuntuone/controlpanel/tests/test_backend.py (+31/-0)
ubuntuone/controlpanel/webclient.py (+26/-0)
To merge this branch: bzr merge lp:~alecu/ubuntuone-control-panel/backend-born
Reviewer Review Type Date Requested Status
Natalia Bidart Approve
Review via email: mp+36435@code.launchpad.net

Commit message

The foundations of the control panel backend

Description of the change

The foundations of the control panel backend

To post a comment you must log in.
9. By Alejandro J. Cura

fix pylint complaints

10. By Alejandro J. Cura

style fixes

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Very nice!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'integration'
2=== added file 'integration/__init__.py'
3=== added file 'integration/run-tests'
4--- integration/run-tests 1970-01-01 00:00:00 +0000
5+++ integration/run-tests 2010-09-24 23:06:03 +0000
6@@ -0,0 +1,28 @@
7+#! /bin/bash
8+#
9+# Author: Natalia Bidart <natalia.bidart@gmail.com>
10+# Author: Alejandro J. Cura <alecu@canonical.com>
11+#
12+# Copyright 2010 Canonical Ltd.
13+#
14+# This program is free software: you can redistribute it and/or modify it
15+# under the terms of the GNU General Public License version 3, as published
16+# by the Free Software Foundation.
17+#
18+# This program is distributed in the hope that it will be useful, but
19+# WITHOUT ANY WARRANTY; without even the implied warranties of
20+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
21+# PURPOSE. See the GNU General Public License for more details.
22+#
23+# You should have received a copy of the GNU General Public License along
24+# with this program. If not, see <http://www.gnu.org/licenses/>.
25+
26+if [ $# -ne 0 ]; then
27+ MODULE="$@"
28+else
29+ MODULE="integration"
30+fi
31+
32+echo "Running test suite for ""$MODULE"
33+PYTHONPATH=. `which xvfb-run` u1trial "$MODULE"
34+rm -rf _trial_temp
35
36=== added file 'integration/test_dbus_client.py'
37--- integration/test_dbus_client.py 1970-01-01 00:00:00 +0000
38+++ integration/test_dbus_client.py 2010-09-24 23:06:03 +0000
39@@ -0,0 +1,73 @@
40+# -*- coding: utf-8 -*-
41+
42+# Authors: Alejandro J. Cura <alecu@canonical.com>
43+#
44+# Copyright 2010 Canonical Ltd.
45+#
46+# This program is free software: you can redistribute it and/or modify it
47+# under the terms of the GNU General Public License version 3, as published
48+# by the Free Software Foundation.
49+#
50+# This program is distributed in the hope that it will be useful, but
51+# WITHOUT ANY WARRANTY; without even the implied warranties of
52+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
53+# PURPOSE. See the GNU General Public License for more details.
54+#
55+# You should have received a copy of the GNU General Public License along
56+# with this program. If not, see <http://www.gnu.org/licenses/>.
57+
58+"""Tests for the control panel backend DBus service."""
59+
60+import dbus
61+
62+from twisted.internet import defer
63+from twisted.trial import unittest
64+
65+from ubuntuone.controlpanel import dbus_service
66+from ubuntuone.controlpanel import dbus_client
67+from ubuntuone.controlpanel import (DBUS_BUS_NAME, DBUS_PREFERENCES_PATH,
68+ DBUS_PREFERENCES_IFACE)
69+from ubuntuone.controlpanel.dbus_client import (DBUS_SSO_NAME, DBUS_SSO_PATH,
70+ DBUS_SSO_IFACE)
71+
72+SAMPLE_CREDS = {
73+ "token": "ABCDEF12345678",
74+ "access_token": "DEADCAFE2010",
75+}
76+
77+class MockDBusSSOClient(dbus.service.Object):
78+ """A mock object that mimicks ussoc."""
79+
80+ @dbus.service.method(dbus_interface=DBUS_SSO_IFACE, in_signature="sssx")
81+ def login_or_register_to_get_credentials(self, app_name, tcurl, help, wid):
82+ """Get creds from the keyring, login/register if needed."""
83+ self.CredentialsFound(app_name, SAMPLE_CREDS)
84+
85+ @dbus.service.signal(dbus_interface=DBUS_SSO_IFACE, signature="sa{ss}")
86+ def CredentialsFound(self, app_name, credentials):
87+ """Credentials were finally found."""
88+
89+class DBusClientTestCase(unittest.TestCase):
90+ """test for the dbus client."""
91+ timeout = 5
92+
93+ def setUp(self):
94+ super(DBusClientTestCase, self).setUp()
95+ dbus_service.init_mainloop()
96+
97+ def register_mockserver(self, bus_name, object_path, object_class):
98+ """The mock service is registered on the DBus."""
99+ session_bus = dbus.SessionBus()
100+ name = session_bus.request_name(bus_name,
101+ dbus.bus.NAME_FLAG_DO_NOT_QUEUE)
102+ self.assertNotEqual(name, dbus.bus.REQUEST_NAME_REPLY_EXISTS)
103+ bus_name = dbus.service.BusName(bus_name, bus=dbus.SessionBus())
104+ object_class(object_path=DBUS_SSO_PATH, bus_name=bus_name)
105+
106+ @defer.inlineCallbacks
107+ def test_get_credentials_ok(self):
108+ """Test the success case for get_credentials."""
109+ self.register_mockserver(DBUS_SSO_NAME, DBUS_SSO_PATH,
110+ MockDBusSSOClient)
111+ creds = yield dbus_client.get_credentials()
112+ self.assertEqual(creds, SAMPLE_CREDS)
113
114=== added file 'integration/test_dbus_service.py'
115--- integration/test_dbus_service.py 1970-01-01 00:00:00 +0000
116+++ integration/test_dbus_service.py 2010-09-24 23:06:03 +0000
117@@ -0,0 +1,90 @@
118+# -*- coding: utf-8 -*-
119+
120+# Authors: Alejandro J. Cura <alecu@canonical.com>
121+#
122+# Copyright 2010 Canonical Ltd.
123+#
124+# This program is free software: you can redistribute it and/or modify it
125+# under the terms of the GNU General Public License version 3, as published
126+# by the Free Software Foundation.
127+#
128+# This program is distributed in the hope that it will be useful, but
129+# WITHOUT ANY WARRANTY; without even the implied warranties of
130+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
131+# PURPOSE. See the GNU General Public License for more details.
132+#
133+# You should have received a copy of the GNU General Public License along
134+# with this program. If not, see <http://www.gnu.org/licenses/>.
135+
136+"""Tests for the control panel backend DBus service."""
137+
138+import dbus
139+
140+from twisted.internet import defer
141+from twisted.trial import unittest
142+
143+from ubuntuone.controlpanel import dbus_service
144+from ubuntuone.controlpanel import (DBUS_BUS_NAME, DBUS_PREFERENCES_PATH,
145+ DBUS_PREFERENCES_IFACE)
146+
147+
148+class DBusServiceTestCase(unittest.TestCase):
149+ """Test for the DBus service."""
150+ timeout = 5
151+
152+ def setUp(self):
153+ """Initialize each test run."""
154+ super(DBusServiceTestCase, self).setUp()
155+ dbus_service.init_mainloop()
156+
157+ def test_register_service(self):
158+ """The DBus service is successfully registered."""
159+ ret = dbus_service.register_service()
160+ self.assertTrue(ret)
161+
162+ def test_cant_register_twice(self):
163+ """The DBus service can't register if it already did."""
164+ ret = dbus_service.register_service()
165+ self.assertTrue(ret)
166+ ret = dbus_service.register_service()
167+ self.assertFalse(ret)
168+ test_cant_register_twice.skip = "Must run 2nd check in another process."
169+
170+ def test_dbus_busname_created(self):
171+ """The DBus BusName is created."""
172+ busname = dbus_service.get_busname()
173+ self.assertEqual(busname.get_name(), DBUS_BUS_NAME)
174+
175+ def test_account_info_returned(self):
176+ """The account info is successfully returned."""
177+ dbus_service.publish_backend()
178+
179+ bus = dbus.SessionBus()
180+ obj = bus.get_object(bus_name=DBUS_BUS_NAME,
181+ object_path=DBUS_PREFERENCES_PATH,
182+ follow_name_owner_changes=True)
183+ self.iface_name = DBUS_PREFERENCES_IFACE
184+ backend = dbus.Interface(object=obj,
185+ dbus_interface=DBUS_PREFERENCES_IFACE)
186+ d = defer.Deferred()
187+
188+ def got_signal(account_info):
189+ """The correct signal was fired."""
190+ self.assertIn("quota_used", account_info)
191+ self.assertIn("quota_total", account_info)
192+ self.assertIn("type", account_info)
193+ self.assertIn("name", account_info)
194+ self.assertIn("email", account_info)
195+ d.callback("success")
196+
197+ def got_error(*a):
198+ """Some error happened in the DBus call."""
199+ d.errback(*a)
200+
201+ def ignore(*a):
202+ """Do nothing with the returned value."""
203+
204+ backend.connect_to_signal("AccountInfoReady", got_signal)
205+
206+ backend.account_info(reply_handler=ignore, error_handler=got_error)
207+ return d
208
209=== added file 'integration/test_webclient.py'
210--- integration/test_webclient.py 1970-01-01 00:00:00 +0000
211+++ integration/test_webclient.py 2010-09-24 23:06:03 +0000
212@@ -0,0 +1,90 @@
213+# -*- coding: utf-8 -*-
214+
215+# Authors: Alejandro J. Cura <alecu@canonical.com>
216+#
217+# Copyright 2010 Canonical Ltd.
218+#
219+# This program is free software: you can redistribute it and/or modify it
220+# under the terms of the GNU General Public License version 3, as published
221+# by the Free Software Foundation.
222+#
223+# This program is distributed in the hope that it will be useful, but
224+# WITHOUT ANY WARRANTY; without even the implied warranties of
225+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
226+# PURPOSE. See the GNU General Public License for more details.
227+#
228+# You should have received a copy of the GNU General Public License along
229+# with this program. If not, see <http://www.gnu.org/licenses/>.
230+
231+"""Tests for the control panel backend webservice client."""
232+
233+from twisted.application import internet, service
234+from twisted.internet import defer
235+from twisted.internet.defer import inlineCallbacks
236+from twisted.internet.threads import deferToThread
237+from twisted.trial import unittest
238+from twisted.web import vhost, static, server, resource
239+
240+from ubuntuone.controlpanel import webclient
241+
242+SAMPLE_RESOURCE = "sample resource"
243+
244+
245+class MockResource(resource.Resource):
246+ """A simple web resource."""
247+ isLeaf = True
248+ contents = ""
249+
250+ def getChild(self, name, request):
251+ """Get a given child resource."""
252+ if name == '':
253+ return self
254+ return resource.Resource.getChild(self, name, request)
255+
256+ def render_GET(self, request):
257+ """Make a bit of html out of these resource's content."""
258+ return self.contents
259+
260+
261+class MockWebService(object):
262+ """A mock webservice for testing"""
263+
264+ def __init__(self):
265+ """Start up this instance."""
266+ root = MockResource()
267+ root.contents = SAMPLE_RESOURCE
268+ site = server.Site(root)
269+ application = service.Application('web')
270+ self.serviceCollection = service.IServiceCollection(application)
271+ self.tcpserver = internet.TCPServer(0, site)
272+ self.tcpserver.setServiceParent(self.serviceCollection)
273+ self.serviceCollection.startService()
274+
275+ def get_url(self):
276+ """Build the url for this mock server."""
277+ portNum = self.tcpserver._port.getHost().port
278+ return "http://localhost:%d/" % portNum
279+
280+ def stop(self):
281+ """Shut it down."""
282+ self.serviceCollection.stopService()
283+
284+
285+class WebClientTestCase(unittest.TestCase):
286+ """Test for the webservice client."""
287+ timeout = 5
288+
289+ def setUp(self):
290+ super(WebClientTestCase, self).setUp()
291+ self.ws = MockWebService()
292+
293+ def tearDown(self):
294+ super(WebClientTestCase, self).tearDown()
295+ self.ws.stop()
296+
297+ @inlineCallbacks
298+ def test_connect(self):
299+ """Connect to the mock webservice."""
300+ webclient.BASE_URL = self.ws.get_url()
301+ ret = yield deferToThread(webclient.getinfo)
302+ self.assertEqual(ret, SAMPLE_RESOURCE)
303
304=== modified file 'ubuntuone/controlpanel/__init__.py'
305--- ubuntuone/controlpanel/__init__.py 2010-09-15 21:43:48 +0000
306+++ ubuntuone/controlpanel/__init__.py 2010-09-24 23:06:03 +0000
307@@ -1,6 +1,7 @@
308 # -*- coding: utf-8 -*-
309
310 # Authors: Natalia B Bidart <natalia.bidart@canonical.com>
311+# Authors: Alejandro J. Cura <alecu@canonical.com>
312 #
313 # Copyright 2010 Canonical Ltd.
314 #
315@@ -22,3 +23,8 @@
316 their Ubuntu One subscription and preferences.
317
318 """
319+
320+# constants
321+DBUS_BUS_NAME = "com.ubuntuone.controlpanel"
322+DBUS_PREFERENCES_PATH = "/preferences"
323+DBUS_PREFERENCES_IFACE = "com.ubuntuone.controlpanel.Preferences"
324
325=== added file 'ubuntuone/controlpanel/backend.py'
326--- ubuntuone/controlpanel/backend.py 1970-01-01 00:00:00 +0000
327+++ ubuntuone/controlpanel/backend.py 2010-09-24 23:06:03 +0000
328@@ -0,0 +1,22 @@
329+# -*- coding: utf-8 -*-
330+
331+# Authors: Alejandro J. Cura <alecu@canonical.com>
332+#
333+# Copyright 2010 Canonical Ltd.
334+#
335+# This program is free software: you can redistribute it and/or modify it
336+# under the terms of the GNU General Public License version 3, as published
337+# by the Free Software Foundation.
338+#
339+# This program is distributed in the hope that it will be useful, but
340+# WITHOUT ANY WARRANTY; without even the implied warranties of
341+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
342+# PURPOSE. See the GNU General Public License for more details.
343+#
344+# You should have received a copy of the GNU General Public License along
345+# with this program. If not, see <http://www.gnu.org/licenses/>.
346+
347+"""A backend for the Ubuntu One Control Panel."""
348+
349+class ControlBackend(object):
350+ """A backend."""
351
352=== added file 'ubuntuone/controlpanel/dbus_client.py'
353--- ubuntuone/controlpanel/dbus_client.py 1970-01-01 00:00:00 +0000
354+++ ubuntuone/controlpanel/dbus_client.py 2010-09-24 23:06:03 +0000
355@@ -0,0 +1,54 @@
356+# -*- coding: utf-8 -*-
357+
358+# Authors: Alejandro J. Cura <alecu@canonical.com>
359+#
360+# Copyright 2010 Canonical Ltd.
361+#
362+# This program is free software: you can redistribute it and/or modify it
363+# under the terms of the GNU General Public License version 3, as published
364+# by the Free Software Foundation.
365+#
366+# This program is distributed in the hope that it will be useful, but
367+# WITHOUT ANY WARRANTY; without even the implied warranties of
368+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
369+# PURPOSE. See the GNU General Public License for more details.
370+#
371+# You should have received a copy of the GNU General Public License along
372+# with this program. If not, see <http://www.gnu.org/licenses/>.
373+
374+"""Client to use other DBus services."""
375+
376+import dbus.service
377+
378+from twisted.internet import defer
379+
380+DBUS_SSO_NAME = "com.ubuntu.sso"
381+DBUS_SSO_PATH = "/credentials"
382+DBUS_SSO_IFACE = "com.ubuntu.sso.ApplicationCredentials"
383+
384+
385+def get_credentials():
386+ """Get the credentials from the ubuntu-sso-client."""
387+ bus = dbus.SessionBus()
388+ obj = bus.get_object(bus_name=DBUS_SSO_NAME,
389+ object_path=DBUS_SSO_PATH,
390+ follow_name_owner_changes=True)
391+ proxy = dbus.Interface(object=obj, dbus_interface=DBUS_SSO_IFACE)
392+ d = defer.Deferred()
393+
394+ def ignore_return(*a):
395+ """The return value of the call to the proxy can be safely ignored."""
396+
397+ def flag_error(*a):
398+ """Make a twisted error from the error returned by the DBus call."""
399+ d.errback(*a)
400+
401+ def found_credentials(app_name, creds):
402+ """Credentials have been found."""
403+ d.callback(creds)
404+
405+ proxy.connect_to_signal("CredentialsFound", found_credentials)
406+ proxy.login_or_register_to_get_credentials("app", "tcurl", "help", 0,
407+ reply_handler=ignore_return,
408+ error_handler=flag_error)
409+ return d
410
411=== added file 'ubuntuone/controlpanel/dbus_service.py'
412--- ubuntuone/controlpanel/dbus_service.py 1970-01-01 00:00:00 +0000
413+++ ubuntuone/controlpanel/dbus_service.py 2010-09-24 23:06:03 +0000
414@@ -0,0 +1,74 @@
415+# -*- coding: utf-8 -*-
416+
417+# Authors: Alejandro J. Cura <alecu@canonical.com>
418+#
419+# Copyright 2010 Canonical Ltd.
420+#
421+# This program is free software: you can redistribute it and/or modify it
422+# under the terms of the GNU General Public License version 3, as published
423+# by the Free Software Foundation.
424+#
425+# This program is distributed in the hope that it will be useful, but
426+# WITHOUT ANY WARRANTY; without even the implied warranties of
427+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
428+# PURPOSE. See the GNU General Public License for more details.
429+#
430+# You should have received a copy of the GNU General Public License along
431+# with this program. If not, see <http://www.gnu.org/licenses/>.
432+
433+"""Export the control backend thru DBus."""
434+
435+import dbus.service
436+
437+from dbus.mainloop.glib import DBusGMainLoop
438+from dbus.service import method, signal
439+
440+from ubuntuone.controlpanel import (DBUS_BUS_NAME, DBUS_PREFERENCES_PATH,
441+ DBUS_PREFERENCES_IFACE)
442+
443+# XXX: should get this info from the web service
444+SAMPLE_DATA = {
445+ "quota_used": "12345",
446+ "quota_total": "54321",
447+ "type": "paying customer",
448+ "name": "john carlos",
449+ "email": "john@carlos.com",
450+}
451+
452+class ControlPanelBackend(dbus.service.Object):
453+ """Export the Control Panel backend thru DBus."""
454+ # pylint: disable=C0103
455+
456+ @method(dbus_interface=DBUS_PREFERENCES_IFACE, in_signature="")
457+ def account_info(self):
458+ """Find out the account info for the current logged in user."""
459+ self.AccountInfoReady(SAMPLE_DATA)
460+
461+ @signal(dbus_interface=DBUS_PREFERENCES_IFACE, signature="a{ss}")
462+ def AccountInfoReady(self, info):
463+ """The info for the current user is available now."""
464+
465+def init_mainloop():
466+ """Start the DBus mainloop."""
467+ DBusGMainLoop(set_as_default=True)
468+
469+def register_service():
470+ """Try to register DBus service for making sure we run only one instance.
471+
472+ Return True if succesfully registered, False if already running.
473+ """
474+ session_bus = dbus.SessionBus()
475+ name = session_bus.request_name(DBUS_BUS_NAME,
476+ dbus.bus.NAME_FLAG_DO_NOT_QUEUE)
477+ return name != dbus.bus.REQUEST_NAME_REPLY_EXISTS
478+
479+
480+def get_busname():
481+ """Build the DBus BusName."""
482+ return dbus.service.BusName(DBUS_BUS_NAME, bus=dbus.SessionBus())
483+
484+
485+def publish_backend():
486+ """Publish the backend on the DBus."""
487+ ControlPanelBackend(object_path=DBUS_PREFERENCES_PATH,
488+ bus_name=get_busname())
489
490=== added file 'ubuntuone/controlpanel/tests/test_backend.py'
491--- ubuntuone/controlpanel/tests/test_backend.py 1970-01-01 00:00:00 +0000
492+++ ubuntuone/controlpanel/tests/test_backend.py 2010-09-24 23:06:03 +0000
493@@ -0,0 +1,31 @@
494+# -*- coding: utf-8 -*-
495+
496+# Authors: Alejandro J. Cura <alecu@canonical.com>
497+#
498+# Copyright 2010 Canonical Ltd.
499+#
500+# This program is free software: you can redistribute it and/or modify it
501+# under the terms of the GNU General Public License version 3, as published
502+# by the Free Software Foundation.
503+#
504+# This program is distributed in the hope that it will be useful, but
505+# WITHOUT ANY WARRANTY; without even the implied warranties of
506+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
507+# PURPOSE. See the GNU General Public License for more details.
508+#
509+# You should have received a copy of the GNU General Public License along
510+# with this program. If not, see <http://www.gnu.org/licenses/>.
511+
512+"""Tests for the control panel backend."""
513+
514+from twisted.trial.unittest import TestCase
515+
516+from ubuntuone.controlpanel import backend
517+
518+class BackendBasicTestCase(TestCase):
519+ """Simple tests for the backend."""
520+
521+ def test_backend_creation(self):
522+ """The backend instance is created."""
523+ be = backend.ControlBackend()
524+ self.assertNotEqual(be, None)
525
526=== added file 'ubuntuone/controlpanel/webclient.py'
527--- ubuntuone/controlpanel/webclient.py 1970-01-01 00:00:00 +0000
528+++ ubuntuone/controlpanel/webclient.py 2010-09-24 23:06:03 +0000
529@@ -0,0 +1,26 @@
530+# Authors: Alejandro J. Cura <alecu@canonical.com>
531+#
532+# Copyright 2010 Canonical Ltd.
533+#
534+# This program is free software: you can redistribute it and/or modify it
535+# under the terms of the GNU General Public License version 3, as published
536+# by the Free Software Foundation.
537+#
538+# This program is distributed in the hope that it will be useful, but
539+# WITHOUT ANY WARRANTY; without even the implied warranties of
540+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
541+# PURPOSE. See the GNU General Public License for more details.
542+#
543+# You should have received a copy of the GNU General Public License along
544+# with this program. If not, see <http://www.gnu.org/licenses/>.
545+
546+"""The control panel backend webservice client."""
547+
548+import urllib
549+
550+BASE_URL = "https://one.ubuntu.com/api/1.0/"
551+
552+def getinfo():
553+ """Get the info from the url."""
554+ f = urllib.urlopen(BASE_URL + "devices/")
555+ return f.read()

Subscribers

People subscribed via source and target branches