Merge lp:~nataliabidart/ubuntuone-client/credentials-shutdown into lp:ubuntuone-client

Proposed by Natalia Bidart
Status: Merged
Approved by: Natalia Bidart
Approved revision: 799
Merged at revision: 799
Proposed branch: lp:~nataliabidart/ubuntuone-client/credentials-shutdown
Merge into: lp:ubuntuone-client
Diff against target: 387 lines (+231/-15)
3 files modified
bin/ubuntuone-login (+4/-2)
tests/credentials/test_credentials.py (+189/-12)
ubuntuone/credentials/__init__.py (+38/-1)
To merge this branch: bzr merge lp:~nataliabidart/ubuntuone-client/credentials-shutdown
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Eric Casteleijn (community) Approve
Review via email: mp+45927@code.launchpad.net

Commit message

The service should shutdown when unused (LP: #701606).

Description of the change

To test, run from this branch:

killall ubuntuone-login; DEBUG=True PYTHONPATH=. ./bin/ubuntuone-login

And open d-feet and play with the com.ubuntuone.Credentials interface. You should expect to see the service quitting once there is no more requests to process.

To post a comment you must log in.
Revision history for this message
Eric Casteleijn (thisfred) wrote :

Looks good & works

review: Approve
Revision history for this message
Roberto Alsina (ralsina) wrote :

I like it.

review: Approve
Revision history for this message
dobey (dobey) wrote :
Download full text (167.4 KiB)

The attempt to merge lp:~nataliabidart/ubuntuone-client/credentials-shutdown into lp:ubuntuone-client failed. Below is the output from the failed tests.

/usr/bin/gnome-autogen.sh
checking for autoconf >= 2.53...
(B testing autoconf2.50... not found.
  testing autoconf... found 2.67
checking for automake >= 1.10...
(B testing automake-1.11... found 1.11.1
checking for libtool >= 1.5...
(B testing libtoolize... found 2.2.6b
checking for intltool >= 0.30...
(B testing intltoolize... found 0.41.1
checking for pkg-config >= 0.14.0...
(B testing pkg-config... found 0.25
checking for gtk-doc >= 1.0...
(B testing gtkdocize... found 1.15
Checking for required M4 macros...
(BChecking for forbidden M4 macros...
(BProcessing ./configure.ac
(BRunning libtoolize...
(Blibtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
Running intltoolize...
(BRunning gtkdocize...
(BRunning aclocal-1.11...
(BRunning autoconf...
(BRunning autoheader...
(BRunning automake-1.11...
(BRunning ./configure --enable-gtk-doc --enable-debug ...
(Bchecking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for style of include used by make... GNU
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking dependency style of gcc... gcc3
checking for library containing strerror... none required
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking dependency style of gcc... (cached) gcc3
checking build system type... i686-pc-linux-gnu
checking host system type... i686-pc-linux-gnu
checking for a sed that does not truncate output... /bin/sed
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for fgrep... /bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 1572864
checking whether the shell understands some XSI constructs... yes
che...

Revision history for this message
dobey (dobey) wrote :
Download full text (182.5 KiB)

The attempt to merge lp:~nataliabidart/ubuntuone-client/credentials-shutdown into lp:ubuntuone-client failed. Below is the output from the failed tests.

/usr/bin/gnome-autogen.sh
checking for autoconf >= 2.53...
(B testing autoconf2.50... not found.
  testing autoconf... found 2.67
checking for automake >= 1.10...
(B testing automake-1.11... found 1.11.1
checking for libtool >= 1.5...
(B testing libtoolize... found 2.2.6b
checking for intltool >= 0.30...
(B testing intltoolize... found 0.41.1
checking for pkg-config >= 0.14.0...
(B testing pkg-config... found 0.25
checking for gtk-doc >= 1.0...
(B testing gtkdocize... found 1.15
Checking for required M4 macros...
(BChecking for forbidden M4 macros...
(BProcessing ./configure.ac
(BRunning libtoolize...
(Blibtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
Running intltoolize...
(BRunning gtkdocize...
(BRunning aclocal-1.11...
(BRunning autoconf...
(BRunning autoheader...
(BRunning automake-1.11...
(BRunning ./configure --enable-gtk-doc --enable-debug ...
(Bchecking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for style of include used by make... GNU
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking dependency style of gcc... gcc3
checking for library containing strerror... none required
checking for gcc... (cached) gcc
checking whether we are using the GNU C compiler... (cached) yes
checking whether gcc accepts -g... (cached) yes
checking for gcc option to accept ISO C89... (cached) none needed
checking dependency style of gcc... (cached) gcc3
checking build system type... i686-pc-linux-gnu
checking host system type... i686-pc-linux-gnu
checking for a sed that does not truncate output... /bin/sed
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for fgrep... /bin/grep -F
checking for ld used by gcc... /usr/bin/ld
checking if the linker (/usr/bin/ld) is GNU ld... yes
checking for BSD- or MS-compatible name lister (nm)... /usr/bin/nm -B
checking the name lister (/usr/bin/nm -B) interface... BSD nm
checking whether ln -s works... yes
checking the maximum length of command line arguments... 1572864
checking whether the shell understands some XSI constructs... yes
che...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/ubuntuone-login'
2--- bin/ubuntuone-login 2011-01-04 13:09:01 +0000
3+++ bin/ubuntuone-login 2011-01-11 22:44:10 +0000
4@@ -45,7 +45,9 @@
5
6 logger.info("Starting Ubuntu One login manager for bus %r.", DBUS_BUS_NAME)
7 bus_name = dbus.service.BusName(DBUS_BUS_NAME, bus=dbus.SessionBus())
8- CredentialsManagement(bus_name, object_path=DBUS_CREDENTIALS_PATH)
9-
10 mainloop = glib.MainLoop()
11+ CredentialsManagement(timeout_func=glib.timeout_add,
12+ shutdown_func=mainloop.quit,
13+ bus_name=bus_name, object_path=DBUS_CREDENTIALS_PATH)
14+
15 mainloop.run()
16
17=== modified file 'tests/credentials/test_credentials.py'
18--- tests/credentials/test_credentials.py 2011-01-04 13:09:01 +0000
19+++ tests/credentials/test_credentials.py 2011-01-11 22:44:10 +0000
20@@ -25,7 +25,7 @@
21 from ubuntuone.devtools.handlers import MementoHandler
22
23 from ubuntuone.credentials import (dbus, logger, logging, ubuntu_sso,
24- CredentialsManagement,
25+ CredentialsManagement, TIMEOUT_INTERVAL,
26 DBUS_BUS_NAME, DBUS_CREDENTIALS_PATH, DBUS_CREDENTIALS_IFACE,
27 APP_NAME, HELP_TEXT_KEY, DESCRIPTION, TC_URL_KEY, TC_URL,
28 PING_URL_KEY, PING_URL, WINDOW_ID_KEY,
29@@ -159,17 +159,15 @@
30 self.register(app_name, args)
31
32
33-class CredentialsManagementTestCase(TestCase):
34- """Test case for the DBus object that manages Ubuntu One credentials."""
35+class BaseTestCase(TestCase):
36+ """Base test case."""
37
38 timeout = 2
39 app_name = APP_NAME
40 error_dict = None
41- signals = ('CredentialsFound', 'CredentialsNotFound', 'CredentialsCleared',
42- 'CredentialsStored', 'CredentialsError', 'AuthorizationDenied')
43
44 def setUp(self):
45- super(CredentialsManagementTestCase, self).setUp()
46+ super(BaseTestCase, self).setUp()
47 FakedSSOService.app_name = self.app_name
48 FakedSSOService.error_dict = self.error_dict
49
50@@ -181,12 +179,6 @@
51 self.sso_server = self.register_server(ubuntu_sso.DBUS_BUS_NAME,
52 ubuntu_sso.DBUS_CREDENTIALS_PATH,
53 FakedSSOService) # faked SSO server
54- self.creds_server = self.register_server(DBUS_BUS_NAME,
55- DBUS_CREDENTIALS_PATH,
56- CredentialsManagement) # real service
57-
58- self.deferred = Deferred()
59- self.proxy = self.get_creds_proxy()
60
61 def register_server(self, bus_name, object_path, service_class):
62 """Register a service on the session bus."""
63@@ -209,6 +201,22 @@
64 object_path=ubuntu_sso.DBUS_CREDENTIALS_PATH,
65 dbus_interface=ubuntu_sso.DBUS_CREDENTIALS_IFACE)
66
67+
68+class CredentialsManagementTestCase(BaseTestCase):
69+ """Test case for the DBus object that manages Ubuntu One credentials."""
70+
71+ signals = ('CredentialsFound', 'CredentialsNotFound', 'CredentialsCleared',
72+ 'CredentialsStored', 'CredentialsError', 'AuthorizationDenied')
73+
74+ def setUp(self):
75+ super(CredentialsManagementTestCase, self).setUp()
76+ self.creds_server = self.register_server(DBUS_BUS_NAME,
77+ DBUS_CREDENTIALS_PATH,
78+ CredentialsManagement) # real service
79+
80+ self.deferred = Deferred()
81+ self.proxy = self.get_creds_proxy()
82+
83 def get_creds_proxy(self):
84 return self.get_proxy(bus_name=DBUS_BUS_NAME,
85 object_path=DBUS_CREDENTIALS_PATH,
86@@ -578,3 +586,172 @@
87
88 app_name = APP_NAME * 2
89 error_dict = {'error_type': 'Test'}
90+
91+
92+class RefCountingTestCase(BaseTestCase):
93+ """Tests for the CredentialsManagement ref counting."""
94+
95+ def setUp(self):
96+ super(RefCountingTestCase, self).setUp()
97+ self._called = False
98+ self.client = CredentialsManagement()
99+
100+ def _set_called(self, *args, **kwargs):
101+ """Keep track of method calls."""
102+ self._called = (args, kwargs)
103+
104+ def test_ref_counting(self):
105+ """Ref counting is in place."""
106+ self.assertEqual(self.client.ref_count, 0)
107+
108+ def test_find_credentials(self):
109+ """Keep proper track of on going requests."""
110+ self.client.find_credentials()
111+
112+ self.assertEqual(self.client.ref_count, 1)
113+
114+ def test_clear_credentials(self):
115+ """Keep proper track of on going requests."""
116+ self.client.clear_credentials()
117+
118+ self.assertEqual(self.client.ref_count, 1)
119+
120+ def test_store_credentials(self):
121+ """Keep proper track of on going requests."""
122+ self.client.store_credentials(FAKED_CREDENTIALS)
123+
124+ self.assertEqual(self.client.ref_count, 1)
125+
126+ def test_register(self):
127+ """Keep proper track of on going requests."""
128+ self.client.register()
129+
130+ self.assertEqual(self.client.ref_count, 1)
131+
132+ def test_login(self):
133+ """Keep proper track of on going requests."""
134+ self.client.login()
135+
136+ self.assertEqual(self.client.ref_count, 1)
137+
138+ def test_several_requests(self):
139+ """Requests can be nested."""
140+ self.client.login()
141+ self.client.clear_credentials()
142+ self.client.find_credentials()
143+ self.client.register()
144+ self.client.store_credentials(FAKED_CREDENTIALS)
145+
146+ self.assertEqual(self.client.ref_count, 5)
147+
148+ def test_credentials_found(self):
149+ """Ref counter is decreased when a signal is sent."""
150+ self.client.ref_count = 3
151+ self.client.CredentialsFound(FAKED_CREDENTIALS)
152+
153+ self.assertEqual(self.client.ref_count, 2)
154+
155+ def test_credentials_not_found(self):
156+ """Ref counter is decreased when a signal is sent."""
157+ self.client.ref_count = 3
158+ self.client.CredentialsNotFound()
159+
160+ self.assertEqual(self.client.ref_count, 2)
161+
162+ def test_credentials_cleared(self):
163+ """Ref counter is decreased when a signal is sent."""
164+ self.client.ref_count = 3
165+ self.client.CredentialsCleared()
166+
167+ self.assertEqual(self.client.ref_count, 2)
168+
169+ def test_credentials_stored(self):
170+ """Ref counter is decreased when a signal is sent."""
171+ self.client.ref_count = 3
172+ self.client.CredentialsStored()
173+
174+ self.assertEqual(self.client.ref_count, 2)
175+
176+ def test_credentials_error(self):
177+ """Ref counter is decreased when a signal is sent."""
178+ self.client.ref_count = 3
179+ self.client.CredentialsError({'error_type': 'test'})
180+
181+ self.assertEqual(self.client.ref_count, 2)
182+
183+ def test_authorization_denied(self):
184+ """Ref counter is decreased when a signal is sent."""
185+ self.client.ref_count = 3
186+ self.client.AuthorizationDenied()
187+
188+ self.assertEqual(self.client.ref_count, 2)
189+
190+ def test_credentials_found_when_ref_count_is_not_positive(self):
191+ """Ref counter is decreased when a signal is sent."""
192+ self.client._ref_count = -3
193+ self.client.CredentialsFound(FAKED_CREDENTIALS)
194+
195+ self.assertEqual(self.client.ref_count, 0)
196+ msg = 'Attempting to decrease ref_count to a negative value (-4).'
197+ self.assertTrue(self.memento.check_warning(msg))
198+
199+ def test_credentials_not_found_when_ref_count_is_not_positive(self):
200+ """Ref counter is decreased when a signal is sent."""
201+ self.client._ref_count = -3
202+ self.client.CredentialsNotFound()
203+
204+ self.assertEqual(self.client.ref_count, 0)
205+ msg = 'Attempting to decrease ref_count to a negative value (-4).'
206+ self.assertTrue(self.memento.check_warning(msg))
207+
208+ def test_credentials_cleared_when_ref_count_is_not_positive(self):
209+ """Ref counter is decreased when a signal is sent."""
210+ self.client._ref_count = -3
211+ self.client.CredentialsCleared()
212+
213+ self.assertEqual(self.client.ref_count, 0)
214+ msg = 'Attempting to decrease ref_count to a negative value (-4).'
215+ self.assertTrue(self.memento.check_warning(msg))
216+
217+ def test_credentials_stored_when_ref_count_is_not_positive(self):
218+ """Ref counter is decreased when a signal is sent."""
219+ self.client._ref_count = -3
220+ self.client.CredentialsStored()
221+
222+ self.assertEqual(self.client.ref_count, 0)
223+ msg = 'Attempting to decrease ref_count to a negative value (-4).'
224+ self.assertTrue(self.memento.check_warning(msg))
225+
226+ def test_credentials_error_when_ref_count_is_not_positive(self):
227+ """Ref counter is decreased when a signal is sent."""
228+ self.client._ref_count = -3
229+ self.client.CredentialsError({'error_type': 'test'})
230+
231+ self.assertEqual(self.client.ref_count, 0)
232+ msg = 'Attempting to decrease ref_count to a negative value (-4).'
233+ self.assertTrue(self.memento.check_warning(msg))
234+
235+ def test_autorization_denied_when_ref_count_is_not_positive(self):
236+ """Ref counter is decreased when a signal is sent."""
237+ self.client._ref_count = -3
238+ self.client.AuthorizationDenied()
239+
240+ self.assertEqual(self.client.ref_count, 0)
241+ msg = 'Attempting to decrease ref_count to a negative value (-4).'
242+ self.assertTrue(self.memento.check_warning(msg))
243+
244+ def test_on_zero_ref_count_shutdown(self):
245+ """When ref count reaches 0, queue shutdown op."""
246+ self.client.timeout_func = self._set_called
247+ self.client.find_credentials()
248+ self.client.CredentialsFound(FAKED_CREDENTIALS)
249+
250+ self.assertEqual(self._called,
251+ ((TIMEOUT_INTERVAL, self.client.shutdown_func), {}))
252+
253+ def test_on_non_zero_ref_count_do_not_shutdown(self):
254+ """If ref count is not 0, do not queue shutdown op."""
255+ self.client.timeout_func = self._set_called
256+ self.client.find_credentials()
257+
258+ self.assertEqual(self._called, False)
259
260=== modified file 'ubuntuone/credentials/__init__.py'
261--- ubuntuone/credentials/__init__.py 2011-01-04 16:46:18 +0000
262+++ ubuntuone/credentials/__init__.py 2011-01-11 22:44:10 +0000
263@@ -35,6 +35,7 @@
264
265 Q_ = lambda string: gettext.dgettext(GETTEXT_PACKAGE, string)
266 NO_OP = lambda *args, **kwargs: None
267+TIMEOUT_INTERVAL = 500
268
269 LOG_LEVEL = logging.DEBUG
270 path = os.path.join(LOGFOLDER, 'credentials.log')
271@@ -68,8 +69,13 @@
272 class CredentialsManagement(dbus.service.Object):
273 """DBus object that manages Ubuntu One credentials."""
274
275- def __init__(self, *args, **kwargs):
276+ def __init__(self, timeout_func=lambda *a: None,
277+ shutdown_func=lambda *a: None, *args, **kwargs):
278 super(CredentialsManagement, self).__init__(*args, **kwargs)
279+ self._ref_count = 0
280+ self.timeout_func = timeout_func
281+ self.shutdown_func = shutdown_func
282+
283 self.sso_match = None
284 self.sso_proxy = self._get_sso_proxy()
285
286@@ -113,42 +119,69 @@
287
288 return proxy
289
290+ def _get_ref_count(self):
291+ """Get value of ref_count."""
292+ logger.debug('ref_count is %r.', self._ref_count)
293+ return self._ref_count
294+
295+ def _set_ref_count(self, new_value):
296+ """Set a new value to ref_count."""
297+ logger.debug('ref_count is %r, changing value to %r.',
298+ self._ref_count, new_value)
299+ if new_value < 0:
300+ self._ref_count = 0
301+ msg = 'Attempting to decrease ref_count to a negative value (%r).'
302+ logger.warning(msg, new_value)
303+ else:
304+ self._ref_count = new_value
305+
306+ if self._ref_count == 0:
307+ self.timeout_func(TIMEOUT_INTERVAL, self.shutdown_func)
308+
309+ ref_count = property(fget=_get_ref_count, fset=_set_ref_count)
310+
311 # Operator not preceded by a space (fails with dbus decorators)
312 # pylint: disable=C0322
313
314 @dbus.service.signal(DBUS_CREDENTIALS_IFACE)
315 def AuthorizationDenied(self):
316 """Signal thrown when the user denies the authorization."""
317+ self.ref_count -= 1
318 logger.info('%s: emitting AuthorizationDenied.',
319 self.__class__.__name__)
320
321 @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='a{ss}')
322 def CredentialsFound(self, credentials):
323 """Signal thrown when the credentials are found."""
324+ self.ref_count -= 1
325 logger.info('%s: emitting CredentialsFound.',
326 self.__class__.__name__)
327
328 @dbus.service.signal(DBUS_CREDENTIALS_IFACE)
329 def CredentialsNotFound(self):
330 """Signal thrown when the credentials are not found."""
331+ self.ref_count -= 1
332 logger.info('%s: emitting CredentialsNotFound.',
333 self.__class__.__name__)
334
335 @dbus.service.signal(DBUS_CREDENTIALS_IFACE)
336 def CredentialsCleared(self):
337 """Signal thrown when the credentials were cleared."""
338+ self.ref_count -= 1
339 logger.info('%s: emitting CredentialsCleared.',
340 self.__class__.__name__)
341
342 @dbus.service.signal(DBUS_CREDENTIALS_IFACE)
343 def CredentialsStored(self):
344 """Signal thrown when the credentials were cleared."""
345+ self.ref_count -= 1
346 logger.info('%s: emitting CredentialsStored.',
347 self.__class__.__name__)
348
349 @dbus.service.signal(DBUS_CREDENTIALS_IFACE, signature='a{ss}')
350 def CredentialsError(self, error_dict):
351 """Signal thrown when there is a problem getting the credentials."""
352+ self.ref_count -= 1
353 logger.error('%s: emitting CredentialsError with error_dict %r.',
354 self.__class__.__name__, error_dict)
355
356@@ -156,6 +189,7 @@
357 async_callbacks=("reply_handler", "error_handler"))
358 def find_credentials(self, reply_handler=NO_OP, error_handler=NO_OP):
359 """Ask the Ubuntu One credentials."""
360+ self.ref_count += 1
361 self.sso_proxy.find_credentials(APP_NAME, {},
362 reply_handler=reply_handler, error_handler=error_handler)
363
364@@ -164,6 +198,7 @@
365 async_callbacks=("reply_handler", "error_handler"))
366 def clear_credentials(self, reply_handler=NO_OP, error_handler=NO_OP):
367 """Clear the Ubuntu One credentials."""
368+ self.ref_count += 1
369 self.sso_proxy.clear_credentials(APP_NAME, {},
370 reply_handler=reply_handler, error_handler=error_handler)
371
372@@ -173,6 +208,7 @@
373 def store_credentials(self, credentials,
374 reply_handler=NO_OP, error_handler=NO_OP):
375 """Store the token for Ubuntu One application."""
376+ self.ref_count += 1
377 self.sso_proxy.store_credentials(APP_NAME, credentials,
378 reply_handler=reply_handler, error_handler=error_handler)
379
380@@ -180,6 +216,7 @@
381 async_callbacks=("reply_handler", "error_handler"))
382 def register(self, reply_handler=NO_OP, error_handler=NO_OP):
383 """Get credentials if found else prompt to register to Ubuntu One."""
384+ self.ref_count += 1
385 params = {HELP_TEXT_KEY: DESCRIPTION, TC_URL_KEY: TC_URL,
386 PING_URL_KEY: PING_URL, WINDOW_ID_KEY: '0'}
387 self.sso_proxy.register(APP_NAME, params,

Subscribers

People subscribed via source and target branches