Merge lp:~mandel/ubuntuone-client/guard-ipc-connect into lp:ubuntuone-client

Proposed by Manuel de la Peña on 2012-08-29
Status: Merged
Approved by: Alejandro J. Cura on 2012-08-29
Approved revision: 1303
Merged at revision: 1302
Proposed branch: lp:~mandel/ubuntuone-client/guard-ipc-connect
Merge into: lp:ubuntuone-client
Diff against target: 171 lines (+121/-6)
2 files modified
tests/platform/ipc/test_perspective_broker.py (+109/-0)
ubuntuone/platform/ipc/ipc_client.py (+12/-6)
To merge this branch: bzr merge lp:~mandel/ubuntuone-client/guard-ipc-connect
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) Approve on 2012-08-29
Roberto Alsina (community) 2012-08-29 Approve on 2012-08-29
Review via email: mp+121854@code.launchpad.net

Commit Message

- Add a guard so that async calls are perform after each other and sd is not started more than once (LP: #1043287).

Description of the Change

- Add a guard so that async calls are perform after each other and sd is not started more than once (LP: #1043287).

To post a comment you must log in.
Roberto Alsina (ralsina) wrote :

I am not confident I am following the tests correctly, but it seems to work, ad the lock part is fairly obvious.

review: Approve
Alejandro J. Cura (alecu) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'tests/platform/ipc/test_perspective_broker.py'
2--- tests/platform/ipc/test_perspective_broker.py 2012-05-22 15:27:36 +0000
3+++ tests/platform/ipc/test_perspective_broker.py 2012-08-29 12:47:18 +0000
4@@ -27,6 +27,7 @@
5 # version. If you delete this exception statement from all source
6 # files in the program, then also delete it here.
7 """IPC tests on perspective broker."""
8+import itertools
9 import os
10
11 from mocker import MockerTestCase, ANY
12@@ -62,6 +63,7 @@
13 Status,
14 SyncDaemon,
15 )
16+from ubuntuone.platform.ipc import ipc_client
17 from ubuntuone.platform.ipc.ipc_client import (
18 signal,
19 ConfigClient,
20@@ -764,3 +766,110 @@
21 lambda _: defer.fail(ipc.AlreadyStartedError()))
22 is_running = yield ipc.is_already_running()
23 self.assertTrue(is_running, "Should be running by now.")
24+
25+
26+class MultipleConnectionsTestCase(TestCase):
27+ """Test the execution of the client with multiple connections."""
28+
29+ @defer.inlineCallbacks
30+ def setUp(self):
31+ """Set the different tests."""
32+ yield super(MultipleConnectionsTestCase, self).setUp()
33+ self.client_connect_d = defer.Deferred() # called when we connected
34+ self.client_root_obj_d = defer.Deferred() # called when we got root
35+ self.remote_obj_d = defer.Deferred() # called when we got the remotes
36+ self.register_to_signals_d = defer.Deferred() # called with signals
37+ self.called = []
38+ self.num_clients = 4
39+
40+ @defer.inlineCallbacks
41+ def fake_get_root_object():
42+ """Fake getting a root objects."""
43+ yield self.client_root_obj_d
44+ self.called.append('getRootObject')
45+ defer.returnValue(True)
46+
47+ @defer.inlineCallbacks
48+ def fake_ipc_client_connect(factory):
49+ """Fake ipc_client_connect."""
50+ yield self.client_connect_d
51+ self.called.append('ipc_client_connect')
52+
53+ # lets patch the factory getRootObjects function
54+ self.patch(factory, 'getRootObject', fake_get_root_object)
55+ defer.returnValue(True)
56+
57+ self.patch(ipc_client, 'ipc_client_connect', fake_ipc_client_connect)
58+
59+ @defer.inlineCallbacks
60+ def fake_request_remote_objects(my_self, root):
61+ """Fake request_remote_objects."""
62+ yield self.remote_obj_d
63+ self.called.append('_request_remote_objects')
64+ defer.returnValue(True)
65+
66+ self.patch(ipc_client.UbuntuOneClient, '_request_remote_objects',
67+ fake_request_remote_objects)
68+
69+ @defer.inlineCallbacks
70+ def fake_register_to_signals(my_self):
71+ """Fake registering to signals."""
72+ yield self.register_to_signals_d
73+ self.called.append('register_to_signals')
74+ defer.returnValue(True)
75+
76+ self.patch(ipc_client.UbuntuOneClient, 'register_to_signals',
77+ fake_register_to_signals)
78+
79+ def grouper(self, n, iterable, fillvalue=None):
80+ "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
81+ args = [iter(iterable)] * n
82+ return itertools.izip_longest(*args, fillvalue=fillvalue)
83+
84+ @defer.inlineCallbacks
85+ def test_multiple_connections(self):
86+ """Test that we only perform connect once but all other are correct."""
87+ deferreds = [self.client_connect_d, self.client_root_obj_d,
88+ self.remote_obj_d, self.register_to_signals_d]
89+
90+ # the order in which the calls are expected
91+ expected_calls = ('ipc_client_connect','getRootObject',
92+ '_request_remote_objects', 'register_to_signals')
93+
94+ clients = []
95+ while len(clients) < self.num_clients:
96+ clients.append(ipc_client.UbuntuOneClient())
97+
98+ connected_d = []
99+
100+ for num_steps in range(len(deferreds)):
101+ # tell the first client to connect
102+ connected_d.append(clients[0].connect())
103+
104+ # perform the number of connection steps so far
105+ for index, step_d in enumerate(deferreds):
106+ if index > num_steps:
107+ break
108+ step_d.callback(True)
109+
110+ # call connect to all the other clients
111+ for client in clients[1:]:
112+ connected_d.append(client.connect())
113+
114+ # perform the rest of steps
115+ for step_d in deferreds[num_steps + 1:]:
116+ step_d.callback(True)
117+
118+ yield defer.gatherResults(connected_d)
119+ # reset all the deferreds for the next round of testing
120+ for index, d_name in enumerate(('client_connect_d',
121+ 'client_root_obj_d', 'remote_obj_d',
122+ 'register_to_signals_d')):
123+ new_d = defer.Deferred()
124+ setattr(self, d_name, new_d)
125+ deferreds[index] = new_d
126+
127+ # assert that all connect calls have been done in the correct
128+ # order
129+ for calls in self.grouper(4, self.called, None):
130+ self.assertEqual(expected_calls, calls)
131
132=== modified file 'ubuntuone/platform/ipc/ipc_client.py'
133--- ubuntuone/platform/ipc/ipc_client.py 2012-08-27 15:22:13 +0000
134+++ ubuntuone/platform/ipc/ipc_client.py 2012-08-29 12:47:18 +0000
135@@ -719,6 +719,8 @@
136 class UbuntuOneClient(object):
137 """Root object that provides access to all the remote objects."""
138
139+ connection_lock = defer.DeferredLock()
140+
141 def __init__(self):
142 """Create a new instance."""
143 self.status = None
144@@ -765,17 +767,21 @@
145 def connect(self):
146 """Connect to the syncdaemon service."""
147 # pylint: disable=W0702
148+ yield self.connection_lock.acquire()
149 try:
150- # connect to the remote objects
151- self.factory = PBClientFactory()
152- self.client = yield ipc_client_connect(self.factory)
153- root = yield self.factory.getRootObject()
154- yield self._request_remote_objects(root)
155- yield self.register_to_signals()
156+ if self.client is None:
157+ # connect to the remote objects
158+ self.factory = PBClientFactory()
159+ self.client = yield ipc_client_connect(self.factory)
160+ root = yield self.factory.getRootObject()
161+ yield self._request_remote_objects(root)
162+ yield self.register_to_signals()
163 defer.returnValue(self)
164 except Exception, e:
165 raise SyncDaemonClientConnectionError(
166 'Could not connect to the syncdaemon ipc.', e)
167+ finally:
168+ self.connection_lock.release()
169 # pylint: disable=W0702
170
171 @defer.inlineCallbacks

Subscribers

People subscribed via source and target branches