Merge lp:~nataliabidart/ubuntuone-client/851810-notify-on-volumes into lp:ubuntuone-client

Proposed by Natalia Bidart
Status: Merged
Approved by: Natalia Bidart
Approved revision: 1223
Merged at revision: 1218
Proposed branch: lp:~nataliabidart/ubuntuone-client/851810-notify-on-volumes
Merge into: lp:ubuntuone-client
Diff against target: 297 lines (+113/-9)
12 files modified
tests/platform/test_external_interface.py (+2/-0)
tests/platform/test_tools.py (+23/-5)
tests/syncdaemon/test_interaction_interfaces.py (+18/-0)
tests/syncdaemon/test_vm.py (+27/-0)
ubuntuone/platform/linux/dbus_interface.py (+4/-0)
ubuntuone/platform/tools/__init__.py (+9/-2)
ubuntuone/platform/tools/windows.py (+1/-0)
ubuntuone/platform/windows/ipc.py (+5/-0)
ubuntuone/platform/windows/ipc_client.py (+9/-1)
ubuntuone/syncdaemon/event_queue.py (+1/-1)
ubuntuone/syncdaemon/interaction_interfaces.py (+11/-0)
ubuntuone/syncdaemon/volume_manager.py (+3/-0)
To merge this branch: bzr merge lp:~nataliabidart/ubuntuone-client/851810-notify-on-volumes
Reviewer Review Type Date Requested Status
Brian Curtin (community) Approve
Roberto Alsina (community) Approve
Review via email: mp+99829@code.launchpad.net

Commit message

- Emit a notification when volumes are ready after a server rescan, allowing clients to follow and update their information accordingly (LP: #851810).

To post a comment you must log in.
1223. By Natalia Bidart

- Attaching bug #851810.

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

+1

review: Approve
Revision history for this message
Brian Curtin (brian.curtin) wrote :

This looks familiar :)

Approved. Tests pass on Windows.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'tests/platform/test_external_interface.py'
2--- tests/platform/test_external_interface.py 2012-02-03 14:29:52 +0000
3+++ tests/platform/test_external_interface.py 2012-03-28 21:44:19 +0000
4@@ -31,6 +31,7 @@
5
6 STR = 'something'
7 STR_STR_DICT = {'foo': 'bar'}
8+STR_LST_DICT = [STR_STR_DICT]
9
10
11 class StatusTests(StatusTestCase):
12@@ -146,6 +147,7 @@
13 signal_mapping = [
14 ('RootMismatch', (STR, STR)),
15 ('QuotaExceeded', (STR_STR_DICT,)),
16+ ('VolumesChanged', (STR_LST_DICT,)),
17 ]
18
19 @defer.inlineCallbacks
20
21=== modified file 'tests/platform/test_tools.py'
22--- tests/platform/test_tools.py 2012-01-17 20:00:44 +0000
23+++ tests/platform/test_tools.py 2012-03-28 21:44:19 +0000
24@@ -898,11 +898,29 @@
25 @defer.inlineCallbacks
26 def test_refresh_volumes(self):
27 """Test for refresh_volumes method."""
28- d = defer.Deferred()
29- self.patch(self.main.action_q, 'list_volumes',
30- lambda: d.callback(True))
31- yield self.tool.refresh_volumes()
32- yield d
33+ udf = self._create_udf()
34+ yield self.main.vm.add_udf(udf)
35+
36+ share = self._create_share()
37+ yield self.main.vm.add_share(share)
38+
39+ volumes = list(self.main.vm.get_volumes(all_volumes=True))
40+
41+ def volumes_changed():
42+ """Fake volumes_changed."""
43+ self.main.event_q.push('VM_VOLUMES_CHANGED', volumes=volumes)
44+
45+ self.patch(self.main.vm, 'refresh_volumes', volumes_changed)
46+ result = yield self.tool.refresh_volumes()
47+
48+ str_volumes = []
49+ for volume in volumes:
50+ if isinstance(volume, volume_manager.UDF):
51+ str_vol = interaction_interfaces.get_udf_dict(volume)
52+ else:
53+ str_vol = interaction_interfaces.get_share_dict(volume)
54+ str_volumes.append(str_vol)
55+ self.assertEqual(result, str_volumes)
56
57 @defer.inlineCallbacks
58 def test_rescan_from_scratch(self):
59
60=== modified file 'tests/syncdaemon/test_interaction_interfaces.py'
61--- tests/syncdaemon/test_interaction_interfaces.py 2012-03-01 19:08:12 +0000
62+++ tests/syncdaemon/test_interaction_interfaces.py 2012-03-28 21:44:19 +0000
63@@ -1750,6 +1750,24 @@
64 self.assertEqual(error, error_msg)
65
66 @defer.inlineCallbacks
67+ def test_handle_VM_VOLUMES_CHANGED(self):
68+ """Test the handle_VM_VOLUMES_CHANGED method."""
69+ share = self._create_share(accepted=True)
70+ udf = self._create_udf()
71+ volumes = [share, udf, self.main.vm.root]
72+ d = defer.Deferred()
73+ self.patch(self.sd_obj.interface.sync_daemon, 'VolumesChanged',
74+ d.callback)
75+
76+ self.main.event_q.push('VM_VOLUMES_CHANGED', volumes=volumes)
77+
78+ info = yield d
79+
80+ str_volumes = sorted((get_share_dict(share), get_udf_dict(udf),
81+ get_share_dict(self.main.vm.root)))
82+ self.assertEqual(str_volumes, sorted(info))
83+
84+ @defer.inlineCallbacks
85 def test_handle_VM_VOLUME_DELETED_folder(self):
86 """Test the handle_VM_VOLUME_DELETED method for a folder."""
87 udf = self._create_udf()
88
89=== modified file 'tests/syncdaemon/test_vm.py'
90--- tests/syncdaemon/test_vm.py 2012-02-09 23:32:10 +0000
91+++ tests/syncdaemon/test_vm.py 2012-03-28 21:44:19 +0000
92@@ -1893,6 +1893,27 @@
93 """Test handle_AQ_LIST_VOLUMES event with an inactive udf."""
94 yield self._test_handle_AQ_LIST_VOLUMES_udf(False)
95
96+ @defer.inlineCallbacks
97+ def test_handle_AQ_LIST_VOLUMES_emits_volumes_changed(self):
98+ """When handling a new volume list, VM_VOLUMES_CHANGED is pushed."""
99+ share = self._create_share_volume()
100+ udf = self._create_udf_volume()
101+ root_volume = volumes.RootVolume(uuid.uuid4(), 17, 10)
102+ response = [share, udf, root_volume]
103+
104+ udf_created_d = defer.Deferred()
105+ self._listen_for('VM_UDF_CREATED', udf_created_d.callback)
106+
107+ volumes_changed_d = defer.Deferred()
108+ self._listen_for('VM_VOLUMES_CHANGED', volumes_changed_d.callback)
109+
110+ self.vm.handle_AQ_LIST_VOLUMES(response)
111+
112+ yield udf_created_d
113+ actual = yield volumes_changed_d
114+ expected = {'volumes': list(self.vm.get_volumes(all_volumes=True))}
115+ self.assertEqual(expected, actual)
116+
117
118 class VolumeManagerOperationsTests(BaseVolumeManagerTests):
119 """Test UDF/Volumes operations."""
120@@ -3104,12 +3125,18 @@
121 vol_rescan_d.callback) # autosubscribe is False
122 server_rescan_d = defer.Deferred()
123 self._listen_for('SYS_SERVER_RESCAN_DONE', server_rescan_d.callback)
124+ volumes_changed_d = defer.Deferred()
125+ self._listen_for('VM_VOLUMES_CHANGED', volumes_changed_d.callback)
126 yield self.vm.server_rescan()
127 yield server_rescan_d
128 events = yield vol_rescan_d
129+ vols = yield volumes_changed_d
130
131 self.assertEqual({'generation': 1, 'volume_id': ''}, events)
132
133+ expected = list(self.vm.get_volumes(all_volumes=True))
134+ self.assertEqual({'volumes' : expected}, vols)
135+
136 @defer.inlineCallbacks
137 def test_server_rescan_with_share_autosubscribe(self):
138 """Test the server_rescan method."""
139
140=== modified file 'ubuntuone/platform/linux/dbus_interface.py'
141--- ubuntuone/platform/linux/dbus_interface.py 2012-02-18 16:13:04 +0000
142+++ ubuntuone/platform/linux/dbus_interface.py 2012-03-28 21:44:19 +0000
143@@ -326,6 +326,10 @@
144 def QuotaExceeded(self, volume_dict):
145 """QuotaExceeded signal, the user ran out of space."""
146
147+ @dbus.service.signal(DBUS_IFACE_SYNC_NAME, signature='aa{ss}')
148+ def VolumesChanged(self, volumes):
149+ """Volumes list changed."""
150+
151
152 class FileSystem(DBusExposedObject):
153 """An interface to the FileSystem Manager."""
154
155=== modified file 'ubuntuone/platform/tools/__init__.py'
156--- ubuntuone/platform/tools/__init__.py 2012-02-03 14:29:52 +0000
157+++ ubuntuone/platform/tools/__init__.py 2012-03-28 21:44:19 +0000
158@@ -64,7 +64,7 @@
159 """Converts a dict returned by the IPC client to a dict of strings."""
160 str_dict = {}
161 for key in a_dict:
162- str_dict[key] = unicode(a_dict[key])
163+ str_dict[unicode(key)] = unicode(a_dict[key])
164 return str_dict
165
166 def shutdown(self):
167@@ -642,10 +642,17 @@
168 """Enable/disable udf_autosubscribe."""
169 return self.enable_setting('udf_autosubscribe', enabled)
170
171+ @defer.inlineCallbacks
172 @log_call(logger.debug)
173 def refresh_volumes(self):
174 """Request the volumes list to the server."""
175- return self.proxy.call_method('folders', 'refresh_volumes')
176+ d = self.wait_for_signals('VolumesChanged')
177+ self.proxy.call_method('folders', 'refresh_volumes')
178+
179+ (results,) = yield d
180+
181+ volumes_info = [self._get_dict(r) for r in results]
182+ defer.returnValue(volumes_info)
183
184 @log_call(logger.debug)
185 def rescan_from_scratch(self, volume_id):
186
187=== modified file 'ubuntuone/platform/tools/windows.py'
188--- ubuntuone/platform/tools/windows.py 2011-11-30 14:53:56 +0000
189+++ ubuntuone/platform/tools/windows.py 2012-03-28 21:44:19 +0000
190@@ -88,6 +88,7 @@
191 'ShareUnSubscribed': ('shares', 'on_share_unsubscribed_cb'),
192 'ShareUnSubscribeError': ('shares', 'on_share_unsubscribe_error_cb'),
193 'StatusChanged': ('status', 'on_status_changed_cb'),
194+ 'VolumesChanged': ('sync_daemon', 'on_volumes_changed_cb'),
195 }
196
197 # All methods and instance variables that should not be handled by
198
199=== modified file 'ubuntuone/platform/windows/ipc.py'
200--- ubuntuone/platform/windows/ipc.py 2012-02-18 16:13:04 +0000
201+++ ubuntuone/platform/windows/ipc.py 2012-03-28 21:44:19 +0000
202@@ -382,6 +382,7 @@
203 signal_mapping = {
204 'RootMismatch': 'on_root_mismatch',
205 'QuotaExceeded': 'on_quota_exceeded',
206+ 'VolumesChanged': 'on_volumes_changed',
207 }
208
209 def connect(self):
210@@ -439,6 +440,10 @@
211 def QuotaExceeded(self, volume_dict):
212 """QuotaExceeded signal, the user ran out of space."""
213
214+ @signal
215+ def VolumesChanged(self, volumes):
216+ """Volumes list has changed."""
217+
218
219 class FileSystem(IPCExposedObject):
220 """An interface to the FileSystem Manager."""
221
222=== modified file 'ubuntuone/platform/windows/ipc_client.py'
223--- ubuntuone/platform/windows/ipc_client.py 2012-02-03 14:29:52 +0000
224+++ ubuntuone/platform/windows/ipc_client.py 2012-03-28 21:44:19 +0000
225@@ -253,7 +253,11 @@
226 __metaclass__ = RemoteMeta
227
228 # calls that will be accessible remotely
229- signal_handlers = ['on_root_mismatch', 'on_quota_exceeded']
230+ signal_handlers = [
231+ 'on_root_mismatch',
232+ 'on_quota_exceeded',
233+ 'on_volumes_changed',
234+ ]
235
236 @remote
237 def connect(self):
238@@ -301,6 +305,10 @@
239 def on_quota_exceeded(self, volume_dict):
240 """Emit QuotaExceeded signal."""
241
242+ @signal
243+ def on_volumes_changed(self, volumes):
244+ """Emit VolumesChanged signal."""
245+
246
247 class FileSystemClient(RemoteClient):
248 """An ipc interface to the FileSystem Manager."""
249
250=== modified file 'ubuntuone/syncdaemon/event_queue.py'
251--- ubuntuone/syncdaemon/event_queue.py 2011-10-14 20:02:23 +0000
252+++ ubuntuone/syncdaemon/event_queue.py 2012-03-28 21:44:19 +0000
253@@ -160,7 +160,7 @@
254 'VM_VOLUME_DELETED': ('volume',),
255 'VM_VOLUME_DELETE_ERROR': ('volume_id', 'error'),
256 'VM_SHARE_CHANGED': ('share_id',),
257-
258+ 'VM_VOLUMES_CHANGED': ('volumes',),
259 }
260
261 DEFAULT_HANDLER = "handle_default" # receives (event_name, **kwargs)
262
263=== modified file 'ubuntuone/syncdaemon/interaction_interfaces.py'
264--- ubuntuone/syncdaemon/interaction_interfaces.py 2012-03-19 13:20:36 +0000
265+++ ubuntuone/syncdaemon/interaction_interfaces.py 2012-03-28 21:44:19 +0000
266@@ -1039,6 +1039,17 @@
267 self.interface.shares.ShareChanged(get_share_dict(share))
268
269 @log_call(logger.debug)
270+ def handle_VM_VOLUMES_CHANGED(self, volumes):
271+ """Handle VM_VOLUMES_CHANGED event, emit VolumeChanged signal."""
272+ str_volumes = []
273+ for volume in volumes:
274+ if isinstance(volume, UDF):
275+ str_volumes.append(get_udf_dict(volume))
276+ else:
277+ str_volumes.append(get_share_dict(volume))
278+ self.interface.sync_daemon.VolumesChanged(str_volumes)
279+
280+ @log_call(logger.debug)
281 def handle_AQ_CHANGE_PUBLIC_ACCESS_OK(self, share_id, node_id,
282 is_public, public_url):
283 """Handle the AQ_CHANGE_PUBLIC_ACCESS_OK event."""
284
285=== modified file 'ubuntuone/syncdaemon/volume_manager.py'
286--- ubuntuone/syncdaemon/volume_manager.py 2012-02-09 23:32:10 +0000
287+++ ubuntuone/syncdaemon/volume_manager.py 2012-03-28 21:44:19 +0000
288@@ -636,6 +636,9 @@
289 # update the free_bytes on the volume
290 self.update_free_space(volume_id, new_volume.free_bytes)
291
292+ volumes = list(self.get_volumes(all_volumes=True))
293+ events.append(("VM_VOLUMES_CHANGED", dict(volumes=volumes)))
294+
295 # push the collected events
296 for event in events:
297 self.m.event_q.push(event[0], **event[1])

Subscribers

People subscribed via source and target branches