Merge lp:~nataliabidart/ubuntuone-client/does-not-exist-to-u1fsfsm into lp:ubuntuone-client

Proposed by Natalia Bidart
Status: Merged
Approved by: Facundo Batista
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~nataliabidart/ubuntuone-client/does-not-exist-to-u1fsfsm
Merge into: lp:ubuntuone-client
Diff against target: 354 lines (+190/-20)
7 files modified
contrib/testing/testcase.py (+13/-0)
tests/syncdaemon/test_action_queue.py (+65/-14)
tests/syncdaemon/test_sync.py (+44/-2)
ubuntuone/syncdaemon/action_queue.py (+7/-2)
ubuntuone/syncdaemon/event_queue.py (+1/-0)
ubuntuone/syncdaemon/sync.py (+8/-2)
ubuntuone/syncdaemon/u1fsfsm.py (+52/-0)
To merge this branch: bzr merge lp:~nataliabidart/ubuntuone-client/does-not-exist-to-u1fsfsm
Reviewer Review Type Date Requested Status
Facundo Batista (community) Approve
Rick McBride (community) Approve
Review via email: mp+19057@code.launchpad.net

Commit message

Added a new event AQ_DOWNLOAD_DOES_NOT_EXIST and handlers for it on u1fsfsm.ods.

To post a comment you must log in.
Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Added a new event AQ_DOWNLOAD_DOES_NOT_EXIST so responses from the server with the error DOES_NOT_EXIST is correctly handled on the client.

Also binded proper handlers on u1fsfsm.ods spreadsheet.

Revision history for this message
Rick McBride (rmcbride) wrote :

Nice!

review: Approve
367. By Natalia Bidart

Removing server hash from AQ_DOWNLOAD_DOES_NOT_EXIST parameters.

368. By Natalia Bidart

Removing server_hash from event definition.

Revision history for this message
Facundo Batista (facundo) wrote :

Like it!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'contrib/testing/testcase.py'
2--- contrib/testing/testcase.py 2010-01-28 21:24:26 +0000
3+++ contrib/testing/testcase.py 2010-02-11 13:18:15 +0000
4@@ -602,3 +602,16 @@
5 def handle_default(self, event_name, *args, **kwargs):
6 """Keep record of every event."""
7 self.events.append((event_name, args, kwargs))
8+
9+
10+def noop(*args, **kwargs):
11+ """No op."""
12+
13+
14+class DummyClass(object):
15+ """Dummy class, does nothing."""
16+
17+ def __getattribute__(self, name):
18+ """Any attribute is a no-op."""
19+ return noop
20+
21
22=== modified file 'tests/syncdaemon/test_action_queue.py'
23--- tests/syncdaemon/test_action_queue.py 2010-01-29 18:09:48 +0000
24+++ tests/syncdaemon/test_action_queue.py 2010-02-11 13:18:15 +0000
25@@ -32,7 +32,7 @@
26
27 from contrib.testing.testcase import (
28 BaseTwistedTestCase, FakeMain,
29- MementoHandler,
30+ MementoHandler, DummyClass
31 )
32
33 from ubuntuone.storageprotocol import client, volumes
34@@ -40,7 +40,7 @@
35 from ubuntuone.syncdaemon.main import Main
36 from ubuntuone.syncdaemon.action_queue import (
37 ActionQueue, ActionQueueCommand, CreateUDF, DeleteVolume, ListVolumes,
38- NoisyRequestQueue, RequestQueue
39+ NoisyRequestQueue, RequestQueue, ListDir
40 )
41 from ubuntuone.syncdaemon.event_queue import EventQueue, EVENTS
42 from ubuntuone.syncdaemon.volume_manager import UDF
43@@ -187,18 +187,6 @@
44 ])
45
46
47-def noop(*args, **kwargs):
48- """No op."""
49-
50-
51-class DummyClass(object):
52- """Dummy class, does nothing."""
53-
54- def __getattribute__(self, name):
55- """Any attribute is a no-op."""
56- return noop
57-
58-
59 class FakedTwistedTestCase(unittest.TestCase):
60 """Helper for by-pass Twisted."""
61
62@@ -581,3 +569,66 @@
63 self.action_queue._node_state_callback(**kwargs)
64 self.assertEquals([('SV_HASH_NEW', (), kwargs)],
65 self.action_queue.event_queue.events)
66+
67+
68+class ListDirTestCase(FakedTwistedTestCase):
69+ """Test for ListDir ActionQueueCommand."""
70+
71+ def setUp(self):
72+ """Init."""
73+ super(ListDirTestCase, self).setUp()
74+
75+ request_queue = RequestQueue(name='FOO', action_queue=self.factory)
76+ self.command = ListDir(request_queue, share_id='a_share_id',
77+ node_id='a_node_id', server_hash='a_server_hash',
78+ fileobj_factory=lambda: None)
79+ self.command.start_unqueued()
80+
81+ def test_failure_with_CANCELLED(self):
82+ """AQ_DOWNLOAD_CANCELLED is pushed."""
83+ msg = 'CANCELLED'
84+ failure = Failure(DefaultException(msg))
85+ res = self.command.handle_failure(failure=failure)
86+ kwargs = dict(share_id='a_share_id', node_id='a_node_id',
87+ server_hash='a_server_hash')
88+ events = [('AQ_DOWNLOAD_CANCELLED', (), kwargs)]
89+ self.assertEquals(events, self.command.action_queue.event_queue.events)
90+ self.assertTrue(res is None)
91+
92+ def test_failure_without_CANCELLED(self):
93+ """AQ_DOWNLOAD_ERROR with proper error is pushed."""
94+ msg = 'NOT_CANCELLED'
95+ failure = Failure(DefaultException(msg))
96+ res = self.command.handle_failure(failure=failure)
97+ kwargs = dict(share_id='a_share_id', node_id='a_node_id',
98+ server_hash='a_server_hash', error=msg)
99+ events = [('AQ_DOWNLOAD_ERROR', (), kwargs)]
100+ self.assertEquals(events, self.command.action_queue.event_queue.events)
101+ self.assertTrue(res is None)
102+
103+ def test_failure_with_DOES_NOT_EXIST(self):
104+ """AQ_DOWNLOAD_DOES_NOT_EXIST is pushed."""
105+ msg = 'DOES_NOT_EXIST'
106+ failure = Failure(DefaultException(msg))
107+ res = self.command.handle_failure(failure=failure)
108+ kwargs = dict(share_id='a_share_id', node_id='a_node_id')
109+ events = [('AQ_DOWNLOAD_DOES_NOT_EXIST', (), kwargs)]
110+ self.assertEquals(events, self.command.action_queue.event_queue.events)
111+ self.assertTrue(res is None)
112+
113+ def test_failure_without_DOES_NOT_EXIST(self):
114+ """AQ_DOWNLOAD_ERROR with proper error is pushed."""
115+ msg = 'DOES_EXIST'
116+ failure = Failure(DefaultException(msg))
117+ res = self.command.handle_failure(failure=failure)
118+ kwargs = dict(share_id='a_share_id', node_id='a_node_id',
119+ server_hash='a_server_hash', error=msg)
120+ events = [('AQ_DOWNLOAD_ERROR', (), kwargs)]
121+ self.assertEquals(events, self.command.action_queue.event_queue.events)
122+ self.assertTrue(res is None)
123+
124+ def test_AQ_DOWNLOAD_DOES_NOT_EXIST_is_valid_event(self):
125+ """AQ_DOWNLOAD_DOES_NOT_EXIST is a valdi event."""
126+ event = 'AQ_DOWNLOAD_DOES_NOT_EXIST'
127+ self.assertTrue(event in EVENTS)
128+ self.assertEquals(('share_id', 'node_id'), EVENTS[event])
129
130=== modified file 'tests/syncdaemon/test_sync.py'
131--- tests/syncdaemon/test_sync.py 2010-01-22 20:31:51 +0000
132+++ tests/syncdaemon/test_sync.py 2010-02-11 13:18:15 +0000
133@@ -30,13 +30,13 @@
134 from contrib.testing.testcase import (
135 FakeVolumeManager,
136 BaseTwistedTestCase,
137- MementoHandler,
138+ MementoHandler, DummyClass
139 )
140
141 from ubuntuone.syncdaemon.dbus_interface import DBusInterface
142 from ubuntuone.syncdaemon.filesystem_manager import FileSystemManager
143 from ubuntuone.syncdaemon.main import Main
144-from ubuntuone.syncdaemon.sync import FSKey
145+from ubuntuone.syncdaemon.sync import FSKey, Sync, SyncStateMachineRunner
146 from ubuntuone.syncdaemon.volume_manager import Share
147 from ubuntuone.syncdaemon.event_queue import EventQueue
148
149@@ -181,7 +181,10 @@
150
151
152 class TestSync(BaseTwistedTestCase):
153+ """Test for Sync."""
154+
155 def setUp(self):
156+ """Init."""
157 BaseTwistedTestCase.setUp(self)
158 self.root = self.mktemp('root')
159 self.shares = self.mktemp('shares')
160@@ -204,6 +207,7 @@
161 dbus.service.BusName.__del__ = lambda _: None
162
163 def tearDown(self):
164+ """Clean up."""
165 self.main.shutdown()
166 shutil.rmtree(self.root)
167 shutil.rmtree(self.shares)
168@@ -215,6 +219,7 @@
169 BaseTwistedTestCase.tearDown(self)
170
171 def test_deleting_open_files_is_no_cause_for_despair(self):
172+ """test_deleting_open_files_is_no_cause_for_despair."""
173 def cb(_):
174 d0 = self.main.wait_for('HQ_HASH_NEW')
175 f = file(self.root + '/a_file', 'w')
176@@ -229,6 +234,7 @@
177 return d
178
179 def test_stomp_deleted_file_is_no_cause_for_despair_either(self):
180+ """test_stomp_deleted_file_is_no_cause_for_despair_either."""
181 def cb(_):
182 d0 = self.main.wait_for('HQ_HASH_NEW')
183 f = file(self.root + '/a_file', 'w')
184@@ -241,3 +247,39 @@
185 self.main.start()
186 d.addCallback(cb)
187 return d
188+
189+ def test_handle_AQ_DOWNLOAD_DOES_NOT_EXIST(self):
190+ """handle_AQ_DOWNLOAD_DOES_NOT_EXIST."""
191+ sync = Sync(main=self.main)
192+ self.called = False
193+
194+ def faked_nothing(ssmr, event, params, *args):
195+ """Wrap SSMR.nothing to test."""
196+ self.called = True
197+
198+ SyncStateMachineRunner.nothing = faked_nothing
199+ kwargs = dict(share_id='share_id', node_id='node_id')
200+ sync.handle_AQ_DOWNLOAD_DOES_NOT_EXIST(**kwargs)
201+ self.assertTrue(self.called, 'nothing was called')
202+
203+
204+class SyncStateMachineRunnerTestCase(BaseTwistedTestCase):
205+ """Tests for the SyncStateMachineRunner."""
206+
207+ def setUp(self):
208+ """Init."""
209+ BaseTwistedTestCase.setUp(self)
210+ self.ssmr = SyncStateMachineRunner(fsm=None, main=None,
211+ key=DummyClass(), logger=None)
212+
213+ def tearDown(self):
214+ """Clean up."""
215+ self.ssmr = None
216+ BaseTwistedTestCase.tearDown(self)
217+
218+ def test_delete_file(self):
219+ """delete_file can be called with or without the server hash."""
220+ self.ssmr.delete_file(event='AQ_DOWNLOAD_ERROR', params=None)
221+
222+ self.ssmr.delete_file(event='AQ_DOWNLOAD_ERROR', params=None,
223+ server_hash='')
224
225=== modified file 'ubuntuone/syncdaemon/action_queue.py'
226--- ubuntuone/syncdaemon/action_queue.py 2010-02-10 19:10:37 +0000
227+++ ubuntuone/syncdaemon/action_queue.py 2010-02-11 13:18:15 +0000
228@@ -2168,14 +2168,19 @@
229 downloading[self.share_id, self.node_id]['command'] is self:
230 del downloading[self.share_id, self.node_id]
231 self.reset_fileobj()
232- if failure.getErrorMessage() == 'CANCELLED':
233+ error_msg = failure.getErrorMessage()
234+ if error_msg == 'CANCELLED':
235 self.action_queue.event_queue.push('AQ_DOWNLOAD_CANCELLED',
236 share_id=self.share_id,
237 node_id=self.node_id,
238 server_hash=self.server_hash)
239+ elif error_msg == 'DOES_NOT_EXIST':
240+ self.action_queue.event_queue.push('AQ_DOWNLOAD_DOES_NOT_EXIST',
241+ share_id=self.share_id,
242+ node_id=self.node_id)
243 else:
244 self.action_queue.event_queue.push('AQ_DOWNLOAD_ERROR',
245- error=failure.getErrorMessage(),
246+ error=error_msg,
247 share_id=self.share_id,
248 node_id=self.node_id,
249 server_hash=self.server_hash)
250
251=== modified file 'ubuntuone/syncdaemon/event_queue.py'
252--- ubuntuone/syncdaemon/event_queue.py 2010-02-09 14:06:50 +0000
253+++ ubuntuone/syncdaemon/event_queue.py 2010-02-11 13:18:15 +0000
254@@ -56,6 +56,7 @@
255 'AQ_DOWNLOAD_FINISHED': ('share_id', 'node_id', 'server_hash'),
256 'AQ_DOWNLOAD_ERROR': ('share_id', 'node_id', 'server_hash', 'error'),
257 'AQ_DOWNLOAD_CANCELLED': ('share_id', 'node_id', 'server_hash'),
258+ 'AQ_DOWNLOAD_DOES_NOT_EXIST': ('share_id', 'node_id'),
259 'AQ_UPLOAD_STARTED' : ('share_id', 'node_id', 'hash'),
260 'AQ_UPLOAD_FINISHED': ('share_id', 'node_id', 'hash'),
261 'AQ_UPLOAD_ERROR': ('share_id', 'node_id', 'error', 'hash'),
262
263=== modified file 'ubuntuone/syncdaemon/sync.py'
264--- ubuntuone/syncdaemon/sync.py 2010-02-10 19:10:37 +0000
265+++ ubuntuone/syncdaemon/sync.py 2010-02-11 13:18:15 +0000
266@@ -737,8 +737,7 @@
267 self.key.remove_partial()
268 self.key.upload_finished(hash)
269
270-
271- def delete_file(self, event, params):
272+ def delete_file(self, event, params, *args, **kwargs):
273 """server file was deleted."""
274 try:
275 self.key.delete_file()
276@@ -945,6 +944,13 @@
277 ssmr = SyncStateMachineRunner(self.fsm, self.m, key, log)
278 ssmr.signal_event_with_hash("AQ_DOWNLOAD_CANCELLED", server_hash)
279
280+ def handle_AQ_DOWNLOAD_DOES_NOT_EXIST(self, share_id, node_id):
281+ """on AQ_DOWNLOAD_DOES_NOT_EXIST."""
282+ key = FSKey(self.m.fs, share_id=share_id, node_id=node_id)
283+ log = FileLogger(self.logger, key)
284+ ssmr = SyncStateMachineRunner(self.fsm, self.m, key, log)
285+ ssmr.on_event("AQ_DOWNLOAD_DOES_NOT_EXIST", {}, share_id, node_id)
286+
287 def handle_FS_FILE_CREATE(self, path):
288 """on FS_FILE_CREATE"""
289 key = FSKey(self.m.fs, path=path)
290
291=== modified file 'ubuntuone/syncdaemon/u1fsfsm.ods'
292Binary files ubuntuone/syncdaemon/u1fsfsm.ods 2010-01-22 17:25:09 +0000 and ubuntuone/syncdaemon/u1fsfsm.ods 2010-02-11 13:18:15 +0000 differ
293=== modified file 'ubuntuone/syncdaemon/u1fsfsm.py'
294--- ubuntuone/syncdaemon/u1fsfsm.py 2010-01-22 17:25:09 +0000
295+++ ubuntuone/syncdaemon/u1fsfsm.py 2010-02-11 13:18:15 +0000
296@@ -365,6 +365,58 @@
297 'STATE_OUT': {u'changed': u'=',
298 u'has_metadata': u'=',
299 u'is_directory': u'='}}],
300+ u'AQ_DOWNLOAD_DOES_NOT_EXIST': [{'ACTION': u'',
301+ 'ACTION_FUNC': u'delete_file',
302+ 'COMMENTS': u"Directory doesn't exist anymore, remove it",
303+ 'PARAMETERS': {u'hash_eq_local_hash': u'NA',
304+ u'hash_eq_server_hash': u'NA',
305+ u'not_authorized': u'NA',
306+ u'not_available': u'NA'},
307+ 'STATE': {u'changed': u'*',
308+ u'has_metadata': u'T',
309+ u'is_directory': u'T'},
310+ 'STATE_OUT': {u'changed': u'NA',
311+ u'has_metadata': u'F',
312+ u'is_directory': u'NA'}},
313+ {'ACTION': u'',
314+ 'ACTION_FUNC': u'delete_file',
315+ 'COMMENTS': u"File doesn't exist anymore, remove it",
316+ 'PARAMETERS': {u'hash_eq_local_hash': u'NA',
317+ u'hash_eq_server_hash': u'NA',
318+ u'not_authorized': u'NA',
319+ u'not_available': u'NA'},
320+ 'STATE': {u'changed': u'!LOCAL',
321+ u'has_metadata': u'T',
322+ u'is_directory': u'F'},
323+ 'STATE_OUT': {u'changed': u'NA',
324+ u'has_metadata': u'F',
325+ u'is_directory': u'NA'}},
326+ {'ACTION': u'',
327+ 'ACTION_FUNC': u'conflict_and_delete',
328+ 'COMMENTS': u"File doesn't exist on server, but has local changes",
329+ 'PARAMETERS': {u'hash_eq_local_hash': u'NA',
330+ u'hash_eq_server_hash': u'NA',
331+ u'not_authorized': u'NA',
332+ u'not_available': u'NA'},
333+ 'STATE': {u'changed': u'LOCAL',
334+ u'has_metadata': u'T',
335+ u'is_directory': u'F'},
336+ 'STATE_OUT': {u'changed': u'NA',
337+ u'has_metadata': u'F',
338+ u'is_directory': u'NA'}},
339+ {'ACTION': u'pass',
340+ 'ACTION_FUNC': u'nothing',
341+ 'COMMENTS': u'',
342+ 'PARAMETERS': {u'hash_eq_local_hash': u'NA',
343+ u'hash_eq_server_hash': u'NA',
344+ u'not_authorized': u'NA',
345+ u'not_available': u'NA'},
346+ 'STATE': {u'changed': u'*',
347+ u'has_metadata': u'F',
348+ u'is_directory': u'*'},
349+ 'STATE_OUT': {u'changed': u'=',
350+ u'has_metadata': u'=',
351+ u'is_directory': u'='}}],
352 u'AQ_DOWNLOAD_ERROR': [{'ACTION': u'md.remove_partial(uuid);',
353 'ACTION_FUNC': u'remove_partial',
354 'COMMENTS': u'error while downloading, remove the partial file',

Subscribers

People subscribed via source and target branches