Merge lp:~dobey/ubuntuone-client/update-4-0 into lp:ubuntuone-client/stable-4-0

Proposed by dobey
Status: Merged
Merged at revision: 1256
Proposed branch: lp:~dobey/ubuntuone-client/update-4-0
Merge into: lp:ubuntuone-client/stable-4-0
Diff against target: 2941 lines (+894/-756)
31 files modified
contrib/testing/testcase.py (+11/-3)
run-mac-tests (+1/-1)
tests/platform/filesystem_notifications/common.py (+122/-303)
tests/platform/filesystem_notifications/test_darwin.py (+84/-388)
tests/platform/filesystem_notifications/test_fsevents_daemon.py (+8/-8)
tests/platform/filesystem_notifications/test_windows.py (+344/-0)
tests/platform/ipc/test_external_interface.py (+14/-0)
tests/platform/test_tools.py (+10/-0)
tests/status/test_aggregator.py (+82/-1)
tests/syncdaemon/test_fsm.py (+27/-0)
tests/syncdaemon/test_interaction_interfaces.py (+28/-20)
tests/syncdaemon/test_vm.py (+13/-2)
ubuntuone/platform/filesystem_notifications/monitor/__init__.py (+3/-0)
ubuntuone/platform/filesystem_notifications/monitor/common.py (+1/-0)
ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_daemon.py (+20/-20)
ubuntuone/platform/ipc/ipc_client.py (+17/-1)
ubuntuone/platform/ipc/linux.py (+33/-0)
ubuntuone/platform/ipc/perspective_broker.py (+7/-2)
ubuntuone/platform/os_helper/__init__.py (+1/-0)
ubuntuone/platform/os_helper/darwin.py (+5/-2)
ubuntuone/platform/os_helper/linux.py (+1/-0)
ubuntuone/platform/os_helper/unix.py (+5/-0)
ubuntuone/platform/os_helper/windows.py (+2/-0)
ubuntuone/platform/tools/__init__.py (+7/-0)
ubuntuone/status/aggregator.py (+16/-1)
ubuntuone/syncdaemon/__init__.py (+5/-0)
ubuntuone/syncdaemon/event_queue.py (+1/-0)
ubuntuone/syncdaemon/filesystem_manager.py (+3/-1)
ubuntuone/syncdaemon/interaction_interfaces.py (+6/-2)
ubuntuone/syncdaemon/status_listener.py (+13/-1)
ubuntuone/syncdaemon/volume_manager.py (+4/-0)
To merge this branch: bzr merge lp:~dobey/ubuntuone-client/update-4-0
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Review via email: mp+120847@code.launchpad.net

Commit message

[Diego Sarmentero]

    - Fixing ipc signals in windows and changing deque size to 5.
    - Adding ipc support to share the menu data (LP: #1032659).
    - Collect and return the data for the menu from aggregator (LP: #1032659).
    - Refactoring test for filesystem notifications
    - Use the correct name space (LP: 1026209).

[Rodney Dawes]

    - Move the patching of user_home to before where it is used elsewhere in setUp.

[Alejandro J. Cura]

    - DownloadFinished ipc signal is now thrown after the partial is commited. (LP: #1031197)

[Roberto Alsina]

    - Added check for UDF path not being a file (LP:1033582).

To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) :
review: Approve
Revision history for this message
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (254.9 KiB)

The attempt to merge lp:~dobey/ubuntuone-client/update-4-0 into lp:ubuntuone-client/stable-4-0 failed. Below is the output from the failed tests.

/usr/bin/gnome-autogen.sh
checking for autoconf >= 2.53...
  testing autoconf2.50... not found.
  testing autoconf... found 2.69
checking for automake >= 1.10...
  testing automake-1.11... found 1.11.5
checking for libtool >= 1.5...
  testing libtoolize... found 2.4.2
checking for intltool >= 0.30...
  testing intltoolize... found 0.50.2
checking for pkg-config >= 0.14.0...
  testing pkg-config... found 0.26
checking for gtk-doc >= 1.0...
  testing gtkdocize... found 1.18
Checking for required M4 macros...
Checking for forbidden M4 macros...
Processing ./configure.ac
Running libtoolize...
libtoolize: 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...
Running gtkdocize...
Running aclocal-1.11...
Running autoconf...
Running autoheader...
Running automake-1.11...
Running ./configure --enable-gtk-doc --enable-debug ...
checking 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... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking how to create a ustar tar archive... gnutar
checking whether make supports nested variables... 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... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking how to print strings... printf
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......

1256. By dobey

[Diego Sarmentero]

    - Fixing ipc signals in windows and changing deque size to 5.
    - Adding ipc support to share the menu data (LP: #1032659).
    - Collect and return the data for the menu from aggregator (LP: #1032659).
    - Refactoring test for filesystem notifications
    - Use the correct name space (LP: 1026209).

[Rodney Dawes]

    - Move the patching of user_home to before where it is used elsewhere in setUp.

[Alejandro J. Cura]

    - DownloadFinished ipc signal is now thrown after the partial is commited. (LP: #1031197)

[Roberto Alsina]

    - Added check for UDF path not being a file (LP:1033582).

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 2012-06-22 09:59:14 +0000
3+++ contrib/testing/testcase.py 2012-08-22 18:22:29 +0000
4@@ -57,6 +57,8 @@
5 main,
6 local_rescan,
7 tritcask,
8+ RECENT_TRANSFERS,
9+ UPLOADING,
10 )
11 from ubuntuone.syncdaemon import logger
12 from ubuntuone import platform
13@@ -208,6 +210,10 @@
14
15 show_all_notifications = True
16
17+ def menu_data(self):
18+ """Fake menu_data."""
19+ return {RECENT_TRANSFERS: [], UPLOADING: []}
20+
21
22 class FakeMain(main.Main):
23 """ A fake Main class to setup the tests """
24@@ -385,6 +391,11 @@
25 def setUp(self):
26 yield super(BaseTwistedTestCase, self).setUp()
27 self.__root = None
28+
29+ # Patch the user home
30+ self.home_dir = self.mktemp('ubuntuonehacker')
31+ self.patch(platform, "user_home", self.home_dir)
32+
33 # use the config from the branch
34 new_get_config_files = lambda: [os.path.join(os.environ['ROOTDIR'],
35 'data', 'syncdaemon.conf')]
36@@ -405,9 +416,6 @@
37 self.log = logging.getLogger("ubuntuone.SyncDaemon.TEST")
38 self.log.info("starting test %s.%s", self.__class__.__name__,
39 self._testMethodName)
40- # Patch the user home
41- self.home_dir = self.mktemp('ubuntuonehacker')
42- self.patch(platform, "user_home", self.home_dir)
43 self.patch(action_queue.tunnel_runner, "TunnelRunner",
44 self.tunnel_runner_class)
45
46
47=== modified file 'run-mac-tests'
48--- run-mac-tests 2012-07-30 19:31:32 +0000
49+++ run-mac-tests 2012-08-22 18:22:29 +0000
50@@ -27,7 +27,7 @@
51 # version. If you delete this exception statement from all source
52 # files in the program, then also delete it here.
53
54-PYTHONPATH=../ubuntu-sso-client/:../ubuntuone-storage-protocol:../ubuntuone-dev-tools:$PYTHONPATH
55+PYTHONPATH=../ubuntu-sso-client/:../ubuntuone-storage-protocol:../ubuntuone-dev-tools:../ubuntuone-fsevents-daemon/python:$PYTHONPATH
56
57 set -e
58 if [ $# -ne 0 ]; then
59
60=== renamed file 'tests/platform/filesystem_notifications/test_windows.py' => 'tests/platform/filesystem_notifications/common.py'
61--- tests/platform/filesystem_notifications/test_windows.py 2012-07-18 15:18:04 +0000
62+++ tests/platform/filesystem_notifications/common.py 2012-08-22 18:22:29 +0000
63@@ -38,42 +38,45 @@
64 import itertools
65
66 from twisted.internet import defer
67-from win32file import FILE_NOTIFY_INFORMATION
68-
69 from contrib.testing.testcase import BaseTwistedTestCase
70 from ubuntuone.devtools.handlers import MementoHandler
71-from ubuntuone.platform.os_helper import windows as os_helper
72 from ubuntuone.platform.filesystem_notifications.pyinotify_agnostic import (
73+ EventsCodes,
74 ProcessEvent,
75 IN_CLOSE_WRITE,
76 IN_CREATE,
77 IN_DELETE,
78 IN_OPEN,
79 )
80-from ubuntuone.platform.filesystem_notifications.monitor import (
81- windows as filesystem_notifications,
82-)
83 from ubuntuone.platform.filesystem_notifications import notify_processor
84 from ubuntuone.platform.filesystem_notifications.monitor.common import (
85 FilesystemMonitor,
86 Watch,
87 WatchManager,
88 )
89-from ubuntuone.platform.filesystem_notifications.monitor.windows import (
90- ACTIONS,
91- FILE_NOTIFY_CHANGE_FILE_NAME,
92- FILE_NOTIFY_CHANGE_DIR_NAME,
93- FILE_NOTIFY_CHANGE_ATTRIBUTES,
94- FILE_NOTIFY_CHANGE_SIZE,
95- FILE_NOTIFY_CHANGE_LAST_WRITE,
96- FILE_NOTIFY_CHANGE_SECURITY,
97- FILE_NOTIFY_CHANGE_LAST_ACCESS,
98-)
99+from ubuntuone.platform.filesystem_notifications.monitor import ACTIONS
100+from ubuntuone.platform.os_helper import get_os_valid_path
101+
102+OP_FLAGS = EventsCodes.FLAG_COLLECTIONS['OP_FLAGS']
103+IS_DIR = EventsCodes.FLAG_COLLECTIONS['SPECIAL_FLAGS']['IN_ISDIR']
104
105 #create a rever mapping to use it in the tests.
106-REVERSE_WINDOWS_ACTIONS = {}
107-for key, value in ACTIONS.iteritems():
108- REVERSE_WINDOWS_ACTIONS[value] = key
109+REVERSE_OS_ACTIONS = {}
110+for key, value in ACTIONS.items():
111+ REVERSE_OS_ACTIONS[value] = key
112+
113+
114+class FakeEventsProcessor(object):
115+
116+ """Handle fake events creation and processing."""
117+
118+ def create_fake_event(self):
119+ """Create a fake filesystem event."""
120+ raise NotImplementedError
121+
122+ def custom_process_events(self):
123+ """Process a fake event."""
124+ raise NotImplementedError
125
126
127 class FakeException(Exception):
128@@ -127,32 +130,17 @@
129 @defer.inlineCallbacks
130 def setUp(self):
131 yield super(TestWatch, self).setUp()
132+ self.path = ''
133+ self.invalid_path = ''
134+ self.common_path = ''
135 self.basedir = self.mktemp('test_root')
136- self.mask = FILE_NOTIFY_CHANGE_FILE_NAME | \
137- FILE_NOTIFY_CHANGE_DIR_NAME | \
138- FILE_NOTIFY_CHANGE_ATTRIBUTES | \
139- FILE_NOTIFY_CHANGE_SIZE | \
140- FILE_NOTIFY_CHANGE_LAST_WRITE | \
141- FILE_NOTIFY_CHANGE_SECURITY | \
142- FILE_NOTIFY_CHANGE_LAST_ACCESS
143+ self.mask = None
144 self.memento = MementoHandler()
145 self.memento.setLevel(logging.DEBUG)
146 self.raw_events = []
147 self.paths_checked = []
148 old_is_dir = Watch._path_is_dir
149-
150- def file_notify_information_wrapper(buf, data):
151- """Wrapper that gets the events and adds them to the list."""
152- events = FILE_NOTIFY_INFORMATION(buf, data)
153- # we want to append the list because that is what will be logged.
154- # If we use extend we wont have the same logging because it will
155- # group all events in a single lists which is not what the COM API
156- # does.
157- str_events = [
158- (filesystem_notifications.ACTIONS_NAMES[action], path) for action, path in
159- events]
160- self.raw_events.append(str_events)
161- return events
162+ self.fake_events_processor = FakeEventsProcessor()
163
164 def path_is_dir_wrapper(watch, path):
165 """Wrapper that gets the checked paths."""
166@@ -160,8 +148,6 @@
167 self.paths_checked.append((path, result))
168 return result
169
170- self.patch(filesystem_notifications, 'FILE_NOTIFY_INFORMATION',
171- file_notify_information_wrapper)
172 self.patch(Watch, '_path_is_dir', path_is_dir_wrapper)
173
174 @defer.inlineCallbacks
175@@ -169,7 +155,7 @@
176 """Perform the file operations and returns the recorded events."""
177 handler = TestCaseHandler(number_events=number_events)
178 manager = WatchManager(handler)
179- yield manager.add_watch(os_helper.get_windows_valid_path(path), mask)
180+ yield manager.add_watch(get_os_valid_path(path), mask)
181 # change the logger so that we can check the logs if we wanted
182 manager._wdm[0].log.addHandler(self.memento)
183 # clean logger later
184@@ -198,7 +184,7 @@
185 create_file, 1)
186 event = events[0]
187 self.assertFalse(event.dir)
188- self.assertEqual(0x100, event.mask)
189+ self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
190 self.assertEqual('IN_CREATE', event.maskname)
191 self.assertEqual(os.path.split(file_name)[1], event.name)
192 self.assertEqual('.', event.path)
193@@ -218,7 +204,7 @@
194 create_dir, 1)
195 event = events[0]
196 self.assertTrue(event.dir)
197- self.assertEqual(0x40000100, event.mask)
198+ self.assertEqual(OP_FLAGS['IN_CREATE'] | IS_DIR, event.mask)
199 self.assertEqual('IN_CREATE|IN_ISDIR', event.maskname)
200 self.assertEqual(os.path.split(dir_name)[1], event.name)
201 self.assertEqual('.', event.path)
202@@ -240,7 +226,7 @@
203 remove_file, 1)
204 event = events[0]
205 self.assertFalse(event.dir)
206- self.assertEqual(0x200, event.mask)
207+ self.assertEqual(OP_FLAGS['IN_DELETE'], event.mask)
208 self.assertEqual('IN_DELETE', event.maskname)
209 self.assertEqual(os.path.split(file_name)[1], event.name)
210 self.assertEqual('.', event.path)
211@@ -262,36 +248,15 @@
212 remove_dir, 1)
213 event = events[0]
214 self.assertTrue(event.dir)
215- self.assertEqual(0x40000200, event.mask)
216+ self.assertEqual(OP_FLAGS['IN_DELETE'] | IS_DIR, event.mask)
217 self.assertEqual('IN_DELETE|IN_ISDIR', event.maskname)
218 self.assertEqual('.', event.path)
219 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
220 self.assertEqual(0, event.wd)
221
222- @defer.inlineCallbacks
223 def test_file_write(self):
224 """Test that the correct event is raised when a file is written."""
225- file_name = os.path.join(self.basedir, 'test_file_write')
226- # create the file before recording
227- fd = open(file_name, 'w')
228- # clean behind us by removing the file
229- self.addCleanup(os.remove, file_name)
230-
231- def write_file():
232- """Action for the test."""
233- fd.write('test')
234- fd.close()
235-
236- events = yield self._perform_operations(self.basedir, self.mask,
237- write_file, 1)
238- event = events[0]
239- self.assertFalse(event.dir)
240- self.assertEqual(0x2, event.mask)
241- self.assertEqual('IN_MODIFY', event.maskname)
242- self.assertEqual(os.path.split(file_name)[1], event.name)
243- self.assertEqual('.', event.path)
244- self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
245- self.assertEqual(0, event.wd)
246+ raise NotImplementedError
247
248 @defer.inlineCallbacks
249 def test_file_moved_to_watched_dir_same_watcher(self):
250@@ -313,7 +278,7 @@
251 move_to_event = events[1]
252 # first test the move from
253 self.assertFalse(move_from_event.dir)
254- self.assertEqual(0x40, move_from_event.mask)
255+ self.assertEqual(OP_FLAGS['IN_MOVED_FROM'], move_from_event.mask)
256 self.assertEqual('IN_MOVED_FROM', move_from_event.maskname)
257 self.assertEqual(os.path.split(from_file_name)[1],
258 move_from_event.name)
259@@ -323,7 +288,7 @@
260 self.assertEqual(0, move_from_event.wd)
261 # test the move to
262 self.assertFalse(move_to_event.dir)
263- self.assertEqual(0x80, move_to_event.mask)
264+ self.assertEqual(OP_FLAGS['IN_MOVED_TO'], move_to_event.mask)
265 self.assertEqual('IN_MOVED_TO', move_to_event.maskname)
266 self.assertEqual(os.path.split(to_file_name)[1], move_to_event.name)
267 self.assertEqual('.', move_to_event.path)
268@@ -354,7 +319,7 @@
269 move_file, 1)
270 event = events[0]
271 self.assertFalse(event.dir)
272- self.assertEqual(0x200, event.mask)
273+ self.assertEqual(OP_FLAGS['IN_DELETE'], event.mask)
274 self.assertEqual('IN_DELETE', event.maskname)
275 self.assertEqual(os.path.split(from_file_name)[1], event.name)
276 self.assertEqual('.', event.path)
277@@ -382,7 +347,7 @@
278 move_files, 1)
279 event = events[0]
280 self.assertFalse(event.dir)
281- self.assertEqual(0x100, event.mask)
282+ self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
283 self.assertEqual('IN_CREATE', event.maskname)
284 self.assertEqual(os.path.split(to_file_name)[1], event.name)
285 self.assertEqual('.', event.path)
286@@ -409,7 +374,8 @@
287 move_to_event = events[1]
288 # first test the move from
289 self.assertTrue(move_from_event.dir)
290- self.assertEqual(0x40000040, move_from_event.mask)
291+ self.assertEqual(OP_FLAGS['IN_MOVED_FROM'] | IS_DIR,
292+ move_from_event.mask)
293 self.assertEqual('IN_MOVED_FROM|IN_ISDIR', move_from_event.maskname)
294 self.assertEqual(os.path.split(from_dir_name)[1], move_from_event.name)
295 self.assertEqual('.', move_from_event.path)
296@@ -418,7 +384,7 @@
297 self.assertEqual(0, move_from_event.wd)
298 # test the move to
299 self.assertTrue(move_to_event.dir)
300- self.assertEqual(0x40000080, move_to_event.mask)
301+ self.assertEqual(OP_FLAGS['IN_MOVED_TO'] | IS_DIR, move_to_event.mask)
302 self.assertEqual('IN_MOVED_TO|IN_ISDIR', move_to_event.maskname)
303 self.assertEqual(os.path.split(to_dir_name)[1], move_to_event.name)
304 self.assertEqual('.', move_to_event.path)
305@@ -447,7 +413,7 @@
306 move_dir, 1)
307 event = events[0]
308 self.assertTrue(event.dir)
309- self.assertEqual(0x40000200, event.mask)
310+ self.assertEqual(OP_FLAGS['IN_DELETE'] | IS_DIR, event.mask)
311 self.assertEqual('IN_DELETE|IN_ISDIR', event.maskname)
312 self.assertEqual('.', event.path)
313 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
314@@ -471,7 +437,7 @@
315 move_dir, 1)
316 event = events[0]
317 self.assertTrue(event.dir)
318- self.assertEqual(0x40000100, event.mask)
319+ self.assertEqual(OP_FLAGS['IN_CREATE'] | IS_DIR, event.mask)
320 self.assertEqual('IN_CREATE|IN_ISDIR', event.maskname)
321 self.assertEqual(os.path.split(from_dir_name)[1], event.name)
322 self.assertEqual('.', event.path)
323@@ -484,8 +450,9 @@
324 handler = TestCaseHandler(number_events=0)
325 manager = WatchManager(handler)
326 # add a watch that will always exclude all actions
327- manager.add_watch(os_helper.get_windows_valid_path(self.basedir),
328- self.mask, exclude_filter=lambda x: True)
329+ manager.add_watch(get_os_valid_path(self.basedir),
330+ self.mask, auto_add=True,
331+ exclude_filter=lambda x: True)
332 # execution the actions
333 file_name = os.path.join(self.basedir, 'test_file_create')
334 open(file_name, 'w').close()
335@@ -502,16 +469,18 @@
336 """Memorize the processed events."""
337 events.append(event)
338
339- path = u'\\\\?\\C:\\path' # a valid windows path
340- child = u'child'
341- watch = Watch(1, path, fake_processor)
342- watch.ignore_path(os.path.join(path, child))
343+ child = 'child'
344+ watch = Watch(1, self.path, None)
345+ watch.ignore_path(os.path.join(self.path, child))
346 paths_to_ignore = []
347 for file_name in 'abcdef':
348- paths_to_ignore.append((1, os.path.join(child, file_name)))
349+ paths_to_ignore.append(
350+ self.fake_events_processor.create_fake_event(
351+ os.path.join(child, file_name)))
352 # ensure that the watch is watching
353- watch._watching = True
354- watch.platform_watch._process_events(paths_to_ignore)
355+ watch.platform_watch.watching = True
356+ self.fake_events_processor.custom_process_events(
357+ watch, paths_to_ignore)
358 self.assertEqual(0, len(events),
359 'All events should have been ignored.')
360
361@@ -523,17 +492,18 @@
362 """Memorize the processed events."""
363 events.append(event)
364
365- path = u'\\\\?\\C:\\path' # a valid windows path
366- child = u'child'
367- watch = Watch(1, path, fake_processor)
368- watch.ignore_path(os.path.join(path, child))
369+ child = 'child'
370+ watch = Watch(1, self.path, fake_processor)
371+ watch.ignore_path(os.path.join(self.path, child))
372 paths_not_to_ignore = []
373 for file_name in 'abcdef':
374- paths_not_to_ignore.append((1, os.path.join(
375- child + file_name, file_name)))
376+ event = self.fake_events_processor.create_fake_event(
377+ os.path.join(child + file_name, file_name))
378+ paths_not_to_ignore.append(event)
379 # ensure that the watch is watching
380 watch.platform_watch.watching = True
381- watch.platform_watch._process_events(paths_not_to_ignore)
382+ self.fake_events_processor.custom_process_events(
383+ watch, paths_not_to_ignore)
384 self.assertEqual(len(paths_not_to_ignore), len(events),
385 'No events should have been ignored.')
386
387@@ -545,21 +515,22 @@
388 """Memorize the processed events."""
389 events.append(event.pathname)
390
391- child = u'child'
392- path = u'\\\\?\\C:\\path\\' # a valid windows path
393- watch = Watch(1, path, fake_processor)
394- watch.ignore_path(os.path.join(path, child))
395+ child = 'child'
396+ watch = Watch(1, self.path, fake_processor)
397+ watch.ignore_path(os.path.join(self.path, child))
398 paths_not_to_ignore = []
399 paths_to_ignore = []
400 expected_events = []
401 for file_name in 'abcdef':
402 valid = os.path.join(child + file_name, file_name)
403 paths_to_ignore.append((1, os.path.join(child, file_name)))
404- paths_not_to_ignore.append((1, valid))
405- expected_events.append(os.path.join('C:\\path', valid))
406+ paths_not_to_ignore.append(
407+ self.fake_events_processor.create_fake_event(valid))
408+ expected_events.append(os.path.join(self.common_path, valid))
409 # ensure that the watch is watching
410 watch.platform_watch.watching = True
411- watch.platform_watch._process_events(paths_not_to_ignore)
412+ self.fake_events_processor.custom_process_events(
413+ watch, paths_not_to_ignore)
414 self.assertEqual(len(paths_not_to_ignore), len(events),
415 'Wrong number of events ignored.')
416 self.assertTrue(all([event in expected_events for event in events]),
417@@ -573,17 +544,19 @@
418 """Memorize the processed events."""
419 events.append(event)
420
421- path = u'\\\\?\\C:\\path' # a valid windows path
422- child = u'child'
423- watch = Watch(1, path, fake_processor)
424- watch.ignore_path(os.path.join(path, child))
425- watch.remove_ignored_path(os.path.join(path, child))
426+ child = 'child'
427+ watch = Watch(1, self.path, fake_processor)
428+ watch.ignore_path(os.path.join(self.path, child))
429+ watch.remove_ignored_path(os.path.join(self.path, child))
430 paths_not_to_ignore = []
431 for file_name in 'abcdef':
432- paths_not_to_ignore.append((1, os.path.join(child, file_name)))
433+ event = self.fake_events_processor.create_fake_event(
434+ os.path.join(child, file_name))
435+ paths_not_to_ignore.append(event)
436 # ensure that the watch is watching
437 watch.platform_watch.watching = True
438- watch.platform_watch._process_events(paths_not_to_ignore)
439+ self.fake_events_processor.custom_process_events(
440+ watch, paths_not_to_ignore)
441 self.assertEqual(len(paths_not_to_ignore), len(events),
442 'All events should have been accepted.')
443
444@@ -595,190 +568,98 @@
445 """Memorize the processed events."""
446 events.append(event.pathname)
447
448- path = u'\\\\?\\C:\\path' # a valid windows path
449- child_a = u'childa'
450- child_b = u'childb'
451- watch = Watch(1, path, fake_processor)
452- watch.ignore_path(os.path.join(path, child_a))
453- watch.ignore_path(os.path.join(path, child_b))
454- watch.remove_ignored_path(os.path.join(path, child_a))
455+ child_a = 'childa'
456+ child_b = 'childb'
457+ watch = Watch(1, self.path, fake_processor)
458+ watch.ignore_path(os.path.join(self.path, child_a))
459+ watch.ignore_path(os.path.join(self.path, child_b))
460+ watch.remove_ignored_path(os.path.join(self.path, child_a))
461 paths_to_ignore = []
462 paths_not_to_ignore = []
463 expected_events = []
464 for file_name in 'abcdef':
465 paths_to_ignore.append((1, os.path.join(child_b, file_name)))
466 valid = os.path.join(child_a, file_name)
467- paths_not_to_ignore.append((1, valid))
468- expected_events.append(os.path.join('C:\\path', valid))
469+ event = self.fake_events_processor.create_fake_event(valid)
470+ paths_not_to_ignore.append(event)
471+ expected_events.append(os.path.join(self.common_path, valid))
472 # ensure that the watch is watching
473 watch.platform_watch.watching = True
474- watch.platform_watch._process_events(paths_not_to_ignore)
475+ self.fake_events_processor.custom_process_events(
476+ watch, paths_not_to_ignore)
477 self.assertEqual(len(paths_not_to_ignore), len(events),
478 'All events should have been accepted.')
479 self.assertTrue(all([event in expected_events for event in events]),
480 'Paths ignored that should have not been ignored.')
481
482- @defer.inlineCallbacks
483- def test_call_deferred_already_called(self):
484- """Test that the function is not called."""
485- method_args = []
486-
487- def fake_call(*args, **kwargs):
488- """Execute the call."""
489- method_args.append((args, kwargs),)
490-
491- path = u'\\\\?\\C:\\path' # a valid windows path
492- watch = Watch(1, path, None)
493- yield watch.platform_watch._watch_started_deferred.callback(True)
494- watch.platform_watch._call_deferred(fake_call, None)
495- self.assertEqual(0, len(method_args))
496-
497- def test_call_deferred_not_called(self):
498- """Test that is indeed called."""
499- method_args = []
500-
501- def fake_call(*args, **kwargs):
502- """Execute the call."""
503- method_args.append((args, kwargs),)
504-
505- path = u'\\\\?\\C:\\path' # a valid windows path
506- watch = Watch(1, path, None)
507- watch.platform_watch._call_deferred(fake_call, None)
508- self.assertEqual(1, len(method_args))
509-
510- def test_started_property(self):
511- """Test that the started property returns the started deferred."""
512- path = u'\\\\?\\C:\\path' # a valid windows path
513- watch = Watch(1, path, None)
514- self.assertEqual(watch.started, watch.platform_watch._watch_started_deferred)
515-
516- def test_stopped_property(self):
517- """Test that the stopped property returns the stopped deferred."""
518- path = u'\\\\?\\C:\\path' # a valid windows path
519- watch = Watch(1, path, None)
520- self.assertEqual(watch.stopped, watch.platform_watch._watch_stopped_deferred)
521-
522 def random_error(self, *args):
523 """Throw a fake exception."""
524 raise FakeException()
525
526- @defer.inlineCallbacks
527- def test_start_watching_fails_early_in_thread(self):
528- """An early failure inside the thread should errback the deferred."""
529- test_path = self.mktemp("test_directory")
530- self.patch(filesystem_notifications, "CreateFileW", self.random_error)
531- watch = Watch(1, test_path, None)
532- d = watch.start_watching()
533- yield self.assertFailure(d, FakeException)
534-
535- @defer.inlineCallbacks
536- def test_start_watching_fails_late_in_thread(self):
537- """A late failure inside the thread should errback the deferred."""
538- test_path = self.mktemp("test_directory")
539- self.patch(filesystem_notifications, "ReadDirectoryChangesW",
540- self.random_error)
541- watch = Watch(1, test_path, None)
542- d = watch.start_watching()
543- yield self.assertFailure(d, FakeException)
544-
545- @defer.inlineCallbacks
546- def test_close_handle_is_called_on_error(self):
547- """CloseHandle is called when there's an error in the watch thread."""
548- test_path = self.mktemp("test_directory")
549- close_called = []
550- self.patch(filesystem_notifications, "CreateFileW", lambda *_: None)
551- self.patch(filesystem_notifications, "CloseHandle",
552- close_called.append)
553- self.patch(filesystem_notifications, "ReadDirectoryChangesW",
554- self.random_error)
555- watch = Watch(1, test_path, None)
556- d = watch.start_watching()
557- yield self.assertFailure(d, FakeException)
558- self.assertEqual(len(close_called), 1)
559- yield watch.stop_watching()
560-
561- @defer.inlineCallbacks
562- def test_stop_watching_fired_when_watch_thread_finishes(self):
563- """The deferred returned is fired when the watch thread finishes."""
564- test_path = self.mktemp("another_test_directory")
565- watch = Watch(1, test_path, None)
566- yield watch.start_watching()
567- self.assertNotEqual(watch.platform_watch._watch_handle, None)
568- yield watch.stop_watching()
569- self.assertEqual(watch.platform_watch._watch_handle, None)
570-
571 def test_is_path_dir_missing_no_subdir(self):
572 """Test when the path does not exist and is no a subdir."""
573- path = u'\\\\?\\C:\\path\\to\\no\\dir'
574 test_path = self.mktemp("test_directory")
575 self.patch(os.path, 'exists', lambda path: False)
576 watch = Watch(1, test_path, None)
577- self.assertFalse(watch._path_is_dir(path))
578+ self.assertFalse(watch._path_is_dir(self.invalid_path))
579
580 def test_is_path_dir_missing_in_subdir(self):
581 """Test when the path does not exist and is a subdir."""
582- path = u'\\\\?\\C:\\path\\to\\no\\dir'
583 test_path = self.mktemp("test_directory")
584 self.patch(os.path, 'exists', lambda path: False)
585 watch = Watch(1, test_path, None)
586- watch._subdirs.add(path)
587- self.assertTrue(watch._path_is_dir(path))
588+ watch._subdirs.add(self.invalid_path)
589+ self.assertTrue(watch._path_is_dir(self.invalid_path))
590
591 def test_is_path_dir_present_is_dir(self):
592 """Test when the path is present and is dir."""
593- path = u'\\\\?\\C:\\path\\to\\no\\dir'
594 test_path = self.mktemp("test_directory")
595 self.patch(os.path, 'exists', lambda path: True)
596 self.patch(os.path, 'isdir', lambda path: True)
597 watch = Watch(1, test_path, None)
598- watch._subdirs.add(path)
599- self.assertTrue(watch._path_is_dir(path))
600+ watch._subdirs.add(self.invalid_path)
601+ self.assertTrue(watch._path_is_dir(self.invalid_path))
602
603 def test_is_path_dir_present_no_dir(self):
604 """Test when the path is present but not a dir."""
605- path = u'\\\\?\\C:\\path\\to\\no\\dir'
606 test_path = self.mktemp("test_directory")
607 self.patch(os.path, 'exists', lambda path: True)
608 self.patch(os.path, 'isdir', lambda path: False)
609 watch = Watch(1, test_path, None)
610- watch._subdirs.add(path)
611- self.assertFalse(watch._path_is_dir(path))
612+ watch._subdirs.add(self.invalid_path)
613+ self.assertFalse(watch._path_is_dir(self.invalid_path))
614
615 def test_update_subdirs_create_not_present(self):
616 """Test when we update on a create event and not present."""
617- path = u'\\\\?\\C:\\path\\to\\no\\dir'
618 test_path = self.mktemp("test_directory")
619 watch = Watch(1, test_path, None)
620- watch._update_subdirs(path, REVERSE_WINDOWS_ACTIONS[IN_CREATE])
621- self.assertTrue(path in watch._subdirs)
622+ watch._update_subdirs(self.invalid_path, REVERSE_OS_ACTIONS[IN_CREATE])
623+ self.assertTrue(self.invalid_path in watch._subdirs)
624
625 def test_update_subdirs_create_present(self):
626 """Test when we update on a create event and is present."""
627- path = u'\\\\?\\C:\\path\\to\\no\\dir'
628 test_path = self.mktemp("test_directory")
629 watch = Watch(1, test_path, None)
630- watch._subdirs.add(path)
631+ watch._subdirs.add(self.invalid_path)
632 old_length = len(watch._subdirs)
633- watch._update_subdirs(path, REVERSE_WINDOWS_ACTIONS[IN_CREATE])
634- self.assertTrue(path in watch._subdirs)
635+ watch._update_subdirs(self.invalid_path, REVERSE_OS_ACTIONS[IN_CREATE])
636+ self.assertTrue(self.invalid_path in watch._subdirs)
637 self.assertEqual(old_length, len(watch._subdirs))
638
639 def test_update_subdirs_delete_not_present(self):
640 """Test when we delete and is not present."""
641- path = u'\\\\?\\C:\\path\\to\\no\\dir'
642 test_path = self.mktemp("test_directory")
643 watch = Watch(1, test_path, None)
644- watch._update_subdirs(path, REVERSE_WINDOWS_ACTIONS[IN_DELETE])
645- self.assertTrue(path not in watch._subdirs)
646+ watch._update_subdirs(self.invalid_path, REVERSE_OS_ACTIONS[IN_DELETE])
647+ self.assertTrue(self.invalid_path not in watch._subdirs)
648
649 def test_update_subdirs_delete_present(self):
650 """Test when we delete and is present."""
651- path = u'\\\\?\\C:\\path\\to\\no\\dir'
652 test_path = self.mktemp("test_directory")
653 watch = Watch(1, test_path, None)
654- watch._subdirs.add(path)
655- watch._update_subdirs(path, REVERSE_WINDOWS_ACTIONS[IN_DELETE])
656- self.assertTrue(path not in watch._subdirs)
657+ watch._subdirs.add(self.invalid_path)
658+ watch._update_subdirs(self.invalid_path, REVERSE_OS_ACTIONS[IN_DELETE])
659+ self.assertTrue(self.invalid_path not in watch._subdirs)
660
661
662 class TestWatchManager(BaseTwistedTestCase):
663@@ -788,11 +669,8 @@
664 def setUp(self):
665 """Set each of the tests."""
666 yield super(TestWatchManager, self).setUp()
667- self.parent_path = u'\\\\?\\C:\\' # a valid windows path
668- self.path = self.parent_path + u'path'
669- self.watch = Watch(1, self.path, None)
670 self.manager = WatchManager(None)
671- self.manager._wdm = {1: self.watch}
672+ self.fake_events_processor = FakeEventsProcessor()
673
674 @defer.inlineCallbacks
675 def test_stop(self):
676@@ -808,25 +686,9 @@
677 yield self.manager.stop()
678 self.assertTrue(self.was_called, 'The watch stop should be called.')
679
680- @defer.inlineCallbacks
681 def test_stop_multiple(self):
682 """Test that stop is fired when *all* watches have stopped."""
683-
684- def fake_stop_watching(watch):
685- """Another fake stop watch."""
686- return watch.stopped
687-
688- self.patch(Watch, "stop_watching", fake_stop_watching)
689- second_path = self.parent_path + u"second_path"
690- second_watch = Watch(2, second_path, None)
691- self.manager._wdm[2] = second_watch
692- d = self.manager.stop()
693- self.assertFalse(d.called, "Not fired before all watches end")
694- self.watch.stopped.callback(None)
695- self.assertFalse(d.called, "Not fired before all watches end")
696- second_watch.stopped.callback(None)
697- yield d
698- self.assertTrue(d.called, "Fired after the watches ended")
699+ raise NotImplementedError
700
701 def test_get_present_watch(self):
702 """Test that we can get a Watch using is wd."""
703@@ -836,7 +698,6 @@
704 """Test that we get an error when trying to get a missing wd."""
705 self.assertRaises(KeyError, self.manager.get_watch, (1,))
706
707- @defer.inlineCallbacks
708 def test_delete_present_watch(self):
709 """Test that we can remove a present watch."""
710 self.was_called = False
711@@ -865,7 +726,6 @@
712 self.manager.add_watch(self.path, mask)
713 self.assertEqual(1, len(self.manager._wdm))
714 self.assertTrue(self.was_called, 'The watch start was not called.')
715- self.assertEqual(self.path + os.path.sep, self.manager._wdm[0].path)
716
717 def test_get_watch_present_wd(self):
718 """Test that the correct path is returned."""
719@@ -889,10 +749,8 @@
720 """A watch on an unwatched path returns None."""
721 self.assertEqual(None, self.manager.get_wd(self.parent_path))
722
723- @defer.inlineCallbacks
724 def test_rm_present_wd(self):
725 """Test the removal of a present watch."""
726-
727 def fake_stop_watching():
728 """Fake stop watch."""
729 return defer.succeed(True)
730@@ -913,8 +771,9 @@
731 self.manager.rm_path(self.path)
732 self.assertEqual(self.watch, self.manager._wdm.get(1))
733 self.watch._watching = True
734- self.watch.platform_watch._process_events(
735- [(1, os.path.join(self.path, 'test'))])
736+ event = self.fake_events_processor.create_fake_event(
737+ os.path.join(self.path, 'test'))
738+ self.fake_events_processor.custom_process_events(self.watch, [event])
739 self.assertEqual(0, len(events))
740
741 def test_rm_child_path(self):
742@@ -926,41 +785,27 @@
743 events.append(event.pathname)
744
745 self.watch._processor = fake_processor
746- child = os.path.join(self.path, u'child')
747+ child = os.path.join(self.path, 'child')
748 self.manager.rm_path(child)
749 self.assertEqual(self.watch, self.manager._wdm[1])
750 # assert that the correct event is ignored
751 self.watch.platform_watch.watching = True
752- self.watch.platform_watch._process_events(
753- [(1, os.path.join('child', 'test'))])
754+ event = self.fake_events_processor.create_fake_event(
755+ os.path.join('child', 'test'))
756+ self.fake_events_processor.custom_process_events(self.watch, [event])
757 self.assertEqual(0, len(events))
758 # assert that other events are not ignored
759- self.watch.platform_watch._process_events([(1, 'test')])
760+ event2 = self.fake_events_processor.create_fake_event('test')
761+ self.fake_events_processor.custom_process_events(self.watch, [event2])
762 self.assertEqual(1, len(events))
763
764
765 class TestWatchManagerAddWatches(BaseTwistedTestCase):
766 """Test the watch manager."""
767- timeout = 5
768
769 def test_add_watch_twice(self):
770 """Adding a watch twice succeeds when the watch is running."""
771- self.patch(Watch, "start_watching", lambda self: self.started)
772- manager = WatchManager(None)
773- # no need to stop watching because start_watching is fake
774-
775- path = u'\\\\?\\C:\\test' # a valid windows path
776- mask = 'fake bit mask'
777- d1 = manager.add_watch(path, mask)
778- d2 = manager.add_watch(path, mask)
779-
780- self.assertFalse(d1.called, "Should not be called yet.")
781- self.assertFalse(d2.called, "Should not be called yet.")
782-
783- manager._wdm.values()[0].started.callback(True)
784-
785- self.assertTrue(d1.called, "Should already be called.")
786- self.assertTrue(d2.called, "Should already be called.")
787+ raise NotImplementedError
788
789
790 class FakeEvent(object):
791@@ -1083,16 +928,6 @@
792 self.assertEqual(event, self.general.called_methods[0][1])
793 self.assertEqual(paths, self.general.called_methods[0][2])
794
795- def test_platform_is_ignored(self):
796- """Test that we do indeed ignore the correct paths."""
797- not_ignored = 'test'
798- ignored = not_ignored + '.lnk'
799- path_is_ignored = notify_processor.common.path_is_ignored
800- self.assertFalse(path_is_ignored(not_ignored),
801- 'Only links should be ignored.')
802- self.assertTrue(path_is_ignored(ignored),
803- 'Links should be ignored.')
804-
805 def test_is_ignored(self):
806 """Test that we do ensure that the path is ignored."""
807 path = 'path'
808@@ -1406,31 +1241,15 @@
809
810 class FilesystemMonitorTestCase(BaseTwistedTestCase):
811 """Tests for the FilesystemMonitor."""
812+
813 timeout = 5
814
815 def test_add_watch_twice(self):
816 """Check the deferred returned by a second add_watch."""
817- self.patch(Watch, "start_watching", lambda self: self.started)
818- monitor = FilesystemMonitor(None, None)
819- # no need to stop watching because start_watching is fake
820-
821- parent_path = 'C:\\test' # a valid windows path in utf-8 bytes
822- child_path = parent_path + "\\child"
823- d1 = monitor.add_watch(parent_path)
824- d2 = monitor.add_watch(child_path)
825-
826- self.assertFalse(d1.called, "Should not be called yet.")
827- self.assertFalse(d2.called, "Should not be called yet.")
828-
829- monitor._watch_manager._wdm.values()[0].started.callback(True)
830-
831- self.assertTrue(d1.called, "Should already be called.")
832- self.assertTrue(d2.called, "Should already be called.")
833-
834- @defer.inlineCallbacks
835+ raise NotImplementedError
836+
837 def test_add_watches_to_udf_ancestors(self):
838 """Test that the ancestor watches are not added."""
839-
840 class FakeVolume(object):
841 """A fake UDF."""
842
843
844=== modified file 'tests/platform/filesystem_notifications/test_darwin.py'
845--- tests/platform/filesystem_notifications/test_darwin.py 2012-07-18 15:18:04 +0000
846+++ tests/platform/filesystem_notifications/test_darwin.py 2012-08-22 18:22:29 +0000
847@@ -28,16 +28,13 @@
848 # files in the program, then also delete it here.
849 """Test the filesystem notifications on MAC OS."""
850
851+import itertools
852 import logging
853 import os
854 import tempfile
855 import thread
856-import itertools
857
858-import fsevents
859 from twisted.internet import defer
860-
861-from contrib.testing.testcase import BaseTwistedTestCase
862 from ubuntuone.devtools.handlers import MementoHandler
863 from ubuntuone.platform.filesystem_notifications.monitor import (
864 common,
865@@ -51,7 +48,6 @@
866 WatchManager,
867 )
868 from ubuntuone.platform.filesystem_notifications.pyinotify_agnostic import (
869- EventsCodes,
870 ProcessEvent,
871 IN_CLOSE_WRITE,
872 IN_CREATE,
873@@ -59,6 +55,7 @@
874 IN_OPEN,
875 )
876 from tests.platform.filesystem_notifications import BaseFSMonitorTestCase
877+from tests.platform.filesystem_notifications import common as common_tests
878
879
880 # A reverse mapping for the tests
881@@ -67,23 +64,18 @@
882 REVERSE_MACOS_ACTIONS[value] = key
883
884
885-OP_FLAGS = EventsCodes.FLAG_COLLECTIONS['OP_FLAGS']
886-IS_DIR = EventsCodes.FLAG_COLLECTIONS['SPECIAL_FLAGS']['IN_ISDIR']
887-
888-
889-class FakeException(Exception):
890- """A fake Exception used in tests."""
891-
892-
893-class FakeVolume(object):
894- """A fake volume."""
895-
896- def __init__(self, path, ancestors):
897- """Create a new instance."""
898- super(FakeVolume, self).__init__()
899- self.volume_id = path
900- self.path = path
901- self.ancestors = ancestors
902+class FakeEventsProcessor(object):
903+
904+ """Handle fake events creation and processing."""
905+
906+ def create_fake_event(self, filename):
907+ """Create a fake file event."""
908+ return FakeFileEvent(256, None, filename)
909+
910+ def custom_process_events(self, watch, events):
911+ """Adapt to each platform way to process events."""
912+ for event in events:
913+ watch.platform_watch._process_events(event)
914
915
916 class FakeFileEvent(object):
917@@ -135,7 +127,7 @@
918 assert self.main_thread_id == thread.get_ident()
919
920
921-class TestWatch(BaseTwistedTestCase):
922+class TestWatch(common_tests.TestWatch):
923 """Test the watch so that it returns the same events as pyinotify."""
924
925 timeout = 5
926@@ -143,6 +135,9 @@
927 @defer.inlineCallbacks
928 def setUp(self):
929 yield super(TestWatch, self).setUp()
930+ self.path = '/Users/username/folder'
931+ self.common_path = '/Users/username/folder'
932+ self.invalid_path = '/Users/username/path/to/not/dir'
933 self.basedir = self.mktemp('test_root')
934 self.mask = None
935 self.stream = None
936@@ -151,6 +146,7 @@
937 self.raw_events = []
938 self.paths_checked = []
939 old_is_dir = Watch._path_is_dir
940+ self.fake_events_processor = FakeEventsProcessor()
941
942 def path_is_dir_wrapper(watch, path):
943 """Wrapper that gets the checked paths."""
944@@ -158,37 +154,32 @@
945 self.paths_checked.append((path, result))
946 return result
947
948- self.patch(Watch, '_path_is_dir',
949- path_is_dir_wrapper)
950-
951- @defer.inlineCallbacks
952- def _perform_operations(self, path, mask, actions, number_events):
953- """Perform the file operations and returns the recorded events."""
954- handler = TestCaseHandler(number_events=number_events)
955- manager = WatchManager(handler)
956- yield manager.add_watch(path, mask)
957- # change the logger so that we can check the logs if we wanted
958- manager._wdm[0].log.addHandler(self.memento)
959- # clean logger later
960- self.addCleanup(manager._wdm[0].log.removeHandler, self.memento)
961- # execution the actions
962- actions()
963- # process the recorded events
964- ret = yield handler.deferred
965- self.addCleanup(manager.stop)
966- defer.returnValue(ret)
967-
968- def _assert_logs(self, events):
969- """Assert the debug logs."""
970- logs = []
971- msg = 'Is path %r a dir? %s'
972- logs.extend([msg % data for data in self.paths_checked])
973- msg = 'Pushing event %r to processor.'
974- logs.extend([msg % e for e in events])
975- for msg in logs:
976- self.assertTrue(self.memento.check_debug(msg))
977-
978- @defer.inlineCallbacks
979+ self.patch(Watch, '_path_is_dir', path_is_dir_wrapper)
980+
981+ def test_not_ignore_path(self):
982+ """Test that we do get the events when they do not match."""
983+ self.patch(filesystem_notifications.reactor, 'callFromThread',
984+ lambda x, e: x(e))
985+ super(TestWatch, self).test_not_ignore_path()
986+
987+ def test_undo_ignore_path_ignored(self):
988+ """Test that we do deal with events from and old ignored path."""
989+ self.patch(filesystem_notifications.reactor, 'callFromThread',
990+ lambda x, e: x(e))
991+ super(TestWatch, self).test_not_ignore_path()
992+
993+ def test_undo_ignore_path_other_ignored(self):
994+ """Test that we can undo and the other path is ignored."""
995+ self.patch(filesystem_notifications.reactor, 'callFromThread',
996+ lambda x, e: x(e))
997+ super(TestWatch, self).test_not_ignore_path()
998+
999+ def test_mixed_ignore_path(self):
1000+ """Test that we do get the correct events."""
1001+ self.patch(filesystem_notifications.reactor, 'callFromThread',
1002+ lambda x, e: x(e))
1003+ super(TestWatch, self).test_mixed_ignore_path()
1004+
1005 def test_file_create(self):
1006 """Test that the correct event is returned on a file create."""
1007 file_name = os.path.join(self.basedir, 'test_file_create')
1008@@ -205,14 +196,12 @@
1009 create_file, 1)
1010 event = events[0]
1011 self.assertFalse(event.dir)
1012- self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
1013+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'], event.mask)
1014 self.assertEqual('IN_CREATE', event.maskname)
1015 self.assertEqual(os.path.split(file_name)[1], event.name)
1016 self.assertEqual('.', event.path)
1017 self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
1018 self.assertEqual(0, event.wd)
1019- # assert the logging
1020- self._assert_logs(events)
1021
1022 @defer.inlineCallbacks
1023 def test_dir_create(self):
1024@@ -227,14 +216,13 @@
1025 create_dir, 1)
1026 event = events[0]
1027 self.assertTrue(event.dir)
1028- self.assertEqual(OP_FLAGS['IN_CREATE'] | IS_DIR, event.mask)
1029+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'] |
1030+ common_tests.IS_DIR, event.mask)
1031 self.assertEqual('IN_CREATE|IN_ISDIR', event.maskname)
1032 self.assertEqual(os.path.split(dir_name)[1], event.name)
1033 self.assertEqual('.', event.path)
1034 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
1035 self.assertEqual(0, event.wd)
1036- # assert the logging
1037- self._assert_logs(events)
1038
1039 @defer.inlineCallbacks
1040 def test_file_remove(self):
1041@@ -251,14 +239,12 @@
1042 remove_file, 1)
1043 event = events[0]
1044 self.assertFalse(event.dir)
1045- self.assertEqual(OP_FLAGS['IN_DELETE'], event.mask)
1046+ self.assertEqual(common_tests.OP_FLAGS['IN_DELETE'], event.mask)
1047 self.assertEqual('IN_DELETE', event.maskname)
1048 self.assertEqual(os.path.split(file_name)[1], event.name)
1049 self.assertEqual('.', event.path)
1050 self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
1051 self.assertEqual(0, event.wd)
1052- # assert the logging
1053- self._assert_logs(events)
1054
1055 @defer.inlineCallbacks
1056 def test_dir_remove(self):
1057@@ -275,13 +261,12 @@
1058 remove_dir, 1)
1059 event = events[0]
1060 self.assertTrue(event.dir)
1061- self.assertEqual(OP_FLAGS['IN_DELETE'] | IS_DIR, event.mask)
1062+ self.assertEqual(common_tests.OP_FLAGS['IN_DELETE'] |
1063+ common_tests.IS_DIR, event.mask)
1064 self.assertEqual('IN_DELETE|IN_ISDIR', event.maskname)
1065 self.assertEqual('.', event.path)
1066 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
1067 self.assertEqual(0, event.wd)
1068- # assert the logging
1069- self._assert_logs(events)
1070
1071 @defer.inlineCallbacks
1072 def test_file_write(self):
1073@@ -301,14 +286,12 @@
1074 write_file, 1)
1075 event = events[0]
1076 self.assertFalse(event.dir)
1077- self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
1078+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'], event.mask)
1079 self.assertEqual('IN_CREATE', event.maskname)
1080 self.assertEqual(os.path.split(file_name)[1], event.name)
1081 self.assertEqual('.', event.path)
1082 self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
1083 self.assertEqual(0, event.wd)
1084- # assert the logging
1085- self._assert_logs(events)
1086
1087 @defer.inlineCallbacks
1088 def test_file_moved_to_watched_dir_same_watcher(self):
1089@@ -330,7 +313,8 @@
1090 move_to_event = events[1]
1091 # first test the move from
1092 self.assertFalse(move_from_event.dir)
1093- self.assertEqual(OP_FLAGS['IN_MOVED_FROM'], move_from_event.mask)
1094+ self.assertEqual(common_tests.OP_FLAGS['IN_MOVED_FROM'],
1095+ move_from_event.mask)
1096 self.assertEqual('IN_MOVED_FROM', move_from_event.maskname)
1097 self.assertEqual(os.path.split(from_file_name)[1],
1098 move_from_event.name)
1099@@ -340,7 +324,8 @@
1100 self.assertEqual(0, move_from_event.wd)
1101 # test the move to
1102 self.assertFalse(move_to_event.dir)
1103- self.assertEqual(OP_FLAGS['IN_MOVED_TO'], move_to_event.mask)
1104+ self.assertEqual(common_tests.OP_FLAGS['IN_MOVED_TO'],
1105+ move_to_event.mask)
1106 self.assertEqual('IN_MOVED_TO', move_to_event.maskname)
1107 self.assertEqual(os.path.split(to_file_name)[1], move_to_event.name)
1108 self.assertEqual('.', move_to_event.path)
1109@@ -351,8 +336,6 @@
1110 self.assertEqual(0, move_to_event.wd)
1111 # assert that both cookies are the same
1112 self.assertEqual(move_from_event.cookie, move_to_event.cookie)
1113- # assert the logging
1114- self._assert_logs(events)
1115
1116 @defer.inlineCallbacks
1117 def test_file_moved_to_not_watched_dir(self):
1118@@ -372,15 +355,13 @@
1119 move_file, 1)
1120 event = events[0]
1121 self.assertFalse(event.dir)
1122- self.assertEqual(OP_FLAGS['IN_DELETE'], event.mask)
1123+ self.assertEqual(common_tests.OP_FLAGS['IN_DELETE'], event.mask)
1124 self.assertEqual('IN_DELETE', event.maskname)
1125 self.assertEqual(os.path.split(from_file_name)[1], event.name)
1126 self.assertEqual('.', event.path)
1127 self.assertEqual(os.path.join(self.basedir, from_file_name),
1128 event.pathname)
1129 self.assertEqual(0, event.wd)
1130- # assert the logging
1131- self._assert_logs(events)
1132
1133 @defer.inlineCallbacks
1134 def test_file_move_from_not_watched_dir(self):
1135@@ -402,15 +383,13 @@
1136 move_files, 1)
1137 event = events[0]
1138 self.assertFalse(event.dir)
1139- self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
1140+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'], event.mask)
1141 self.assertEqual('IN_CREATE', event.maskname)
1142 self.assertEqual(os.path.split(to_file_name)[1], event.name)
1143 self.assertEqual('.', event.path)
1144 self.assertEqual(os.path.join(self.basedir, to_file_name),
1145 event.pathname)
1146 self.assertEqual(0, event.wd)
1147- # assert the logging
1148- self._assert_logs(events)
1149
1150 @defer.inlineCallbacks
1151 def test_dir_moved_to_watched_dir_same_watcher(self):
1152@@ -431,7 +410,8 @@
1153 move_to_event = events[1]
1154 # first test the move from
1155 self.assertTrue(move_from_event.dir)
1156- self.assertEqual(OP_FLAGS['IN_MOVED_FROM'] | IS_DIR,
1157+ self.assertEqual(common_tests.OP_FLAGS['IN_MOVED_FROM'] |
1158+ common_tests.IS_DIR,
1159 move_from_event.mask)
1160 self.assertEqual('IN_MOVED_FROM|IN_ISDIR', move_from_event.maskname)
1161 self.assertEqual(os.path.split(from_dir_name)[1], move_from_event.name)
1162@@ -441,7 +421,8 @@
1163 self.assertEqual(0, move_from_event.wd)
1164 # test the move to
1165 self.assertTrue(move_to_event.dir)
1166- self.assertEqual(OP_FLAGS['IN_MOVED_TO'] | IS_DIR, move_to_event.mask)
1167+ self.assertEqual(common_tests.OP_FLAGS['IN_MOVED_TO'] |
1168+ common_tests.IS_DIR, move_to_event.mask)
1169 self.assertEqual('IN_MOVED_TO|IN_ISDIR', move_to_event.maskname)
1170 self.assertEqual(os.path.split(to_dir_name)[1], move_to_event.name)
1171 self.assertEqual('.', move_to_event.path)
1172@@ -452,8 +433,6 @@
1173 self.assertEqual(0, move_to_event.wd)
1174 # assert that both cookies are the same
1175 self.assertEqual(move_from_event.cookie, move_to_event.cookie)
1176- # assert the logging
1177- self._assert_logs(events)
1178
1179 @defer.inlineCallbacks
1180 def test_dir_moved_to_not_watched_dir(self):
1181@@ -473,13 +452,12 @@
1182 move_dir, 1)
1183 event = events[0]
1184 self.assertTrue(event.dir)
1185- self.assertEqual(OP_FLAGS['IN_DELETE'] | IS_DIR, event.mask)
1186+ self.assertEqual(common_tests.OP_FLAGS['IN_DELETE'] |
1187+ common_tests.IS_DIR, event.mask)
1188 self.assertEqual('IN_DELETE|IN_ISDIR', event.maskname)
1189 self.assertEqual('.', event.path)
1190 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
1191 self.assertEqual(0, event.wd)
1192- # assert the logging
1193- self._assert_logs(events)
1194
1195 @defer.inlineCallbacks
1196 def test_dir_move_from_not_watched_dir(self):
1197@@ -499,7 +477,8 @@
1198 move_dir, 1)
1199 event = events[0]
1200 self.assertTrue(event.dir)
1201- self.assertEqual(OP_FLAGS['IN_CREATE'] | IS_DIR, event.mask)
1202+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'] |
1203+ common_tests.IS_DIR, event.mask)
1204 self.assertEqual('IN_CREATE|IN_ISDIR', event.maskname)
1205 self.assertEqual(os.path.split(from_dir_name)[1], event.name)
1206 self.assertEqual('.', event.path)
1207@@ -521,149 +500,6 @@
1208 self.assertEqual(0, len(handler.processed_events))
1209 test_exclude_filter.skip = "we must rethink this test."
1210
1211- def test_ignore_path(self):
1212- """Test that events from a path are ignored."""
1213- events = []
1214-
1215- def fake_processor(event):
1216- """Memorize the processed events."""
1217- events.append(event)
1218-
1219- path = '/Users/username/folder'
1220- child = 'child'
1221- watch = Watch(1, path, fake_processor)
1222- watch.ignore_path(os.path.join(path, child))
1223- # ensure that the watch is watching
1224- watch.platform_watch.watching = True
1225- for file_name in 'abcdef':
1226- event = FakeFileEvent(256, None, os.path.join(child, file_name))
1227- watch.platform_watch._process_events(event)
1228- self.assertEqual(0, len(events),
1229- 'All events should have been ignored.')
1230-
1231- def test_not_ignore_path(self):
1232- """Test that we do get the events when they do not match."""
1233- events = []
1234-
1235- def fake_processor(event):
1236- """Memorize the processed events."""
1237- events.append(event)
1238-
1239- self.patch(filesystem_notifications.reactor, 'callFromThread',
1240- lambda x, e: x(e))
1241-
1242- path = '/Users/username/folder'
1243- child = 'child'
1244- watch = Watch(1, path, fake_processor)
1245- watch.ignore_path(os.path.join(path, child))
1246- paths_not_to_ignore = []
1247- for file_name in 'abcdef':
1248- event = FakeFileEvent(256, None, os.path.join(child + file_name,
1249- file_name))
1250- paths_not_to_ignore.append(event)
1251- # ensure that the watch is watching
1252- watch.platform_watch.watching = True
1253- for event in paths_not_to_ignore:
1254- watch.platform_watch._process_events(event)
1255- self.assertEqual(len(paths_not_to_ignore), len(events),
1256- 'No events should have been ignored.')
1257-
1258- def test_mixed_ignore_path(self):
1259- """Test that we do get the correct events."""
1260- events = []
1261-
1262- def fake_processor(event):
1263- """Memorize the processed events."""
1264- events.append(event.pathname)
1265-
1266- self.patch(filesystem_notifications.reactor, 'callFromThread',
1267- lambda x, e: x(e))
1268-
1269- child = 'child'
1270- path = '/Users/username/folder'
1271- watch = Watch(1, path, fake_processor)
1272- watch.ignore_path(os.path.join(path, child))
1273- paths_not_to_ignore = []
1274- paths_to_ignore = []
1275- expected_events = []
1276- for file_name in 'abcdef':
1277- valid = os.path.join(child + file_name, file_name)
1278- paths_to_ignore.append((1, os.path.join(child, file_name)))
1279- event = FakeFileEvent(256, None, valid)
1280- paths_not_to_ignore.append(event)
1281- expected_events.append(os.path.join(path, valid))
1282- # ensure that the watch is watching
1283- watch.platform_watch.watching = True
1284- for event in paths_not_to_ignore:
1285- watch.platform_watch._process_events(event)
1286- self.assertEqual(len(paths_not_to_ignore), len(events),
1287- 'Wrong number of events ignored.')
1288- self.assertTrue(all([event in expected_events for event in events]),
1289- 'Paths ignored that should have not been ignored.')
1290-
1291- def test_undo_ignore_path_ignored(self):
1292- """Test that we do deal with events from and old ignored path."""
1293- events = []
1294-
1295- def fake_processor(event):
1296- """Memorize the processed events."""
1297- events.append(event)
1298-
1299- self.patch(filesystem_notifications.reactor, 'callFromThread',
1300- lambda x, e: x(e))
1301-
1302- path = '/Users/username/folder'
1303- child = 'child'
1304- watch = Watch(1, path, fake_processor)
1305- watch.ignore_path(os.path.join(path, child))
1306- watch.remove_ignored_path(os.path.join(path, child))
1307- paths_not_to_ignore = []
1308- for file_name in 'abcdef':
1309- event = FakeFileEvent(256, None, os.path.join(child, file_name))
1310- paths_not_to_ignore.append(event)
1311- # ensure that the watch is watching
1312- watch.platform_watch.watching = True
1313- for event in paths_not_to_ignore:
1314- watch.platform_watch._process_events(event)
1315- self.assertEqual(len(paths_not_to_ignore), len(events),
1316- 'All events should have been accepted.')
1317-
1318- def test_undo_ignore_path_other_ignored(self):
1319- """Test that we can undo and the other path is ignored."""
1320- events = []
1321-
1322- def fake_processor(event):
1323- """Memorize the processed events."""
1324- events.append(event.pathname)
1325-
1326- self.patch(filesystem_notifications.reactor, 'callFromThread',
1327- lambda x, e: x(e))
1328-
1329- path = '/Users/username/folder'
1330- child_a = 'childa'
1331- child_b = 'childb'
1332- watch = Watch(1, path, fake_processor)
1333- watch.ignore_path(os.path.join(path, child_a))
1334- watch.ignore_path(os.path.join(path, child_b))
1335- watch.remove_ignored_path(os.path.join(path, child_a))
1336- paths_to_ignore = []
1337- paths_not_to_ignore = []
1338- expected_events = []
1339- for file_name in 'abcdef':
1340- paths_to_ignore.append((1, os.path.join(child_b, file_name)))
1341- valid = os.path.join(child_a, file_name)
1342- event = FakeFileEvent(256, None, valid)
1343- paths_not_to_ignore.append(event)
1344- expected_events.append(os.path.join(path, valid))
1345- # ensure that the watch is watching
1346- watch.platform_watch.watching = True
1347- for event in paths_not_to_ignore:
1348- watch.platform_watch._process_events(event)
1349- self.assertEqual(len(paths_not_to_ignore), len(events),
1350- 'All events should have been accepted.')
1351- self.assertTrue(all([event in expected_events for event in events]),
1352- 'Paths ignored that should have not been ignored.')
1353-
1354 def test_stream_created(self):
1355 """Test that the stream is created."""
1356 def fake_call(*args, **kwargs):
1357@@ -684,7 +520,7 @@
1358
1359 def random_error(self, *args):
1360 """Throw a fake exception."""
1361- raise FakeException()
1362+ raise common_tests.FakeException()
1363
1364 def test_is_path_dir_missing_no_subdir(self):
1365 """Test when the path does not exist and is no a subdir."""
1366@@ -760,7 +596,7 @@
1367 self.assertTrue(path not in watch._subdirs)
1368
1369
1370-class TestWatchManager(BaseTwistedTestCase):
1371+class TestWatchManager(common_tests.TestWatchManager):
1372 """Test the watch manager."""
1373
1374 @defer.inlineCallbacks
1375@@ -772,24 +608,19 @@
1376 self.watch = Watch(1, self.path, None)
1377 self.manager = WatchManager(None)
1378 self.manager._wdm = {1: self.watch}
1379+ self.stream = None
1380+ self.fake_events_processor = FakeEventsProcessor()
1381
1382 @defer.inlineCallbacks
1383 def test_stop(self):
1384 """Test that the different watches are stopped."""
1385- self.was_called = False
1386-
1387- def fake_stop_watching(watch):
1388- """Fake stop watch."""
1389- self.was_called = True
1390- return defer.succeed(True)
1391-
1392- self.patch(Watch, "stop_watching", fake_stop_watching)
1393+ self.patch(self.manager.manager.observer, "unschedule",
1394+ lambda x: None)
1395 self.patch(self.manager.manager.observer, "unschedule", lambda x: None)
1396- yield self.manager.stop()
1397- self.assertTrue(self.was_called, 'The watch stop should be called.')
1398+ yield super(TestWatchManager, self).test_stop()
1399
1400 def test_stop_multiple(self):
1401- """The watches should became watching=False and the observer stopped."""
1402+ """Watches should became watching=False and the observer stopped."""
1403 self.patch(self.manager.manager.observer, "unschedule", lambda x: None)
1404 second_path = self.parent_path + "second_path"
1405 second_watch = Watch(2, second_path, None)
1406@@ -810,28 +641,6 @@
1407 """Test that we get an error when trying to get a missing wd."""
1408 self.assertRaises(KeyError, self.manager.get_watch, (1,))
1409
1410- @defer.inlineCallbacks
1411- def test_delete_present_watch(self):
1412- """Test that we can remove a present watch."""
1413- self.was_called = False
1414-
1415- def stop_watching():
1416- """Fake stop watch."""
1417- self.was_called = True
1418- return defer.succeed(True)
1419-
1420- def fake_unschedule(s):
1421- """Fake function that should receive a Stream object."""
1422- self.stream = s
1423-
1424- self.patch(self.manager.manager.observer, "unschedule",
1425- fake_unschedule)
1426-
1427- self.watch.stop_watching = stop_watching
1428- yield self.manager.del_watch(1)
1429- self.assertIsInstance(self.stream, fsevents.Stream)
1430- self.assertRaises(KeyError, self.manager.get_watch, (1,))
1431-
1432 def test_add_single_watch(self):
1433 """Test the addition of a new single watch."""
1434 self.was_called = False
1435@@ -849,10 +658,6 @@
1436 self.assertTrue(self.was_called, 'The watch start was not called.')
1437 self.assertEqual(self.path + os.path.sep, self.manager._wdm[0].path)
1438
1439- def test_get_watch_present_wd(self):
1440- """Test that the correct path is returned."""
1441- self.assertEqual(self.path + os.path.sep, self.manager.get_path(1))
1442-
1443 def test_get_watch_missing_wd(self):
1444 """Test that the correct path is returned."""
1445 self.manager._wdm = {}
1446@@ -873,60 +678,24 @@
1447
1448 def test_rm_present_wd(self):
1449 """Test the removal of a present watch."""
1450- self.patch(self.watch, "stop_watching", lambda: None)
1451 self.patch(self.manager.manager.observer, "unschedule", lambda x: None)
1452- self.manager.rm_watch(1)
1453- self.assertEqual(None, self.manager._wdm.get(1))
1454-
1455- def test_rm_root_path(self):
1456- """Test the removal of a root path."""
1457- events = []
1458-
1459- def fake_processor(event):
1460- """Memorize the processed events."""
1461- events.append(event.pathname)
1462-
1463- self.watch._processor = fake_processor
1464- self.manager.rm_path(self.path)
1465- self.assertEqual(self.watch, self.manager._wdm.get(1))
1466- self.watch._watching = True
1467- event = FakeFileEvent(256, None, os.path.join(self.path, 'test'))
1468- self.watch.platform_watch._process_events(event)
1469- self.assertEqual(0, len(events))
1470+ super(TestWatchManager, self).test_rm_present_wd()
1471
1472 def test_rm_child_path(self):
1473 """Test the removal of a child path."""
1474- events = []
1475-
1476- def fake_processor(event):
1477- """Memorize the processed events."""
1478- events.append(event.pathname)
1479-
1480 self.patch(filesystem_notifications.reactor, 'callFromThread',
1481 lambda x, e: x(e))
1482-
1483- self.watch._processor = fake_processor
1484- child = os.path.join(self.path, 'child')
1485- self.manager.rm_path(child)
1486- self.assertEqual(self.watch, self.manager._wdm[1])
1487- # assert that the correct event is ignored
1488- self.watch.platform_watch.watching = True
1489- event = FakeFileEvent(256, None, os.path.join('child', 'test'))
1490- self.watch.platform_watch._process_events(event)
1491- self.assertEqual(0, len(events))
1492- # assert that other events are not ignored
1493- event2 = FakeFileEvent(256, None, 'test')
1494- self.watch.platform_watch._process_events(event2)
1495- self.assertEqual(1, len(events))
1496-
1497-
1498-class TestWatchManagerAddWatches(BaseTwistedTestCase):
1499+ super(TestWatchManager, self).test_rm_child_path()
1500+
1501+
1502+class TestWatchManagerAddWatches(common_tests.TestWatchManagerAddWatches):
1503 """Test the watch manager."""
1504 timeout = 5
1505
1506 def test_add_watch_twice(self):
1507 """Adding a watch twice succeeds when the watch is running."""
1508 self.patch(Watch, "start_watching", lambda self: None)
1509+ self.patch(Watch, "started", lambda self: True)
1510 manager = WatchManager(None)
1511 # no need to stop watching because start_watching is fake
1512
1513@@ -936,7 +705,7 @@
1514 d2 = manager.add_watch(path, mask)
1515
1516 self.assertTrue(d1.result, "Should not be called yet.")
1517- self.assertFalse(d2.result, "Should not be called yet.")
1518+ self.assertTrue(d2, "Should not be called yet.")
1519
1520
1521 class FakeEvent(object):
1522@@ -953,88 +722,15 @@
1523 self.cookie = cookie
1524
1525
1526-class FakeLog(object):
1527- """A fake log that is used by the general processor."""
1528-
1529- def __init__(self):
1530- """Create the fake."""
1531- self.called_methods = []
1532-
1533- def info(self, *args):
1534- """Fake the info call."""
1535- self.called_methods.append(('info', args))
1536-
1537-
1538-class FakeGeneralProcessor(object):
1539- """Fake implementation of the general processor."""
1540-
1541- def __init__(self):
1542- """Create the fake."""
1543- self.called_methods = []
1544- self.paths_to_return = []
1545- self.log = FakeLog()
1546- self.share_id = None
1547- self.ignore = False
1548-
1549- def rm_from_mute_filter(self, event, paths):
1550- """Fake rm_from_mute_filter."""
1551- self.called_methods.append(('rm_from_mute_filter', event, paths))
1552-
1553- def add_to_mute_filter(self, event, paths):
1554- """Fake add_to_move_filter."""
1555- self.called_methods.append(('add_to_mute_filter', event, paths))
1556-
1557- def is_ignored(self, path):
1558- """Fake is_ignored."""
1559- self.called_methods.append(('is_ignored', path))
1560- return self.ignore
1561-
1562- def push_event(self, event):
1563- """Fake push event."""
1564- self.called_methods.append(('push_event', event))
1565-
1566- def eq_push(self, event, path=None, path_to=None, path_from=None):
1567- """Fake event to push event."""
1568- self.called_methods.append(('eq_push', event, path, path_to,
1569- path_from))
1570-
1571- def get_paths_starting_with(self, fullpath, include_base=False):
1572- """Fake get_paths_starting_with."""
1573- self.called_methods.append(('get_paths_starting_with', fullpath,
1574- include_base))
1575- return self.paths_to_return
1576-
1577- def get_path_share_id(self, path):
1578- """Fake get_path_share_id."""
1579- self.called_methods.append(('get_path_share_id', path))
1580- return self.share_id
1581-
1582- def rm_watch(self, path):
1583- """Fake the remove watch."""
1584- self.called_methods.append(('rm_watch', path))
1585-
1586- def freeze_begin(self, path):
1587- """Fake freeze_begin"""
1588- self.called_methods.append(('freeze_begin', path))
1589-
1590- def freeze_rollback(self):
1591- """Fake rollback."""
1592- self.called_methods.append(('freeze_rollback',))
1593-
1594- def freeze_commit(self, path):
1595- """Fake freeze commit."""
1596- self.called_methods.append(('freeze_commit', path))
1597-
1598-
1599-class TestNotifyProcessor(BaseTwistedTestCase):
1600+class TestNotifyProcessor(common_tests.TestNotifyProcessor):
1601 """Test the notify processor."""
1602
1603 @defer.inlineCallbacks
1604 def setUp(self):
1605- """set up the diffeent tests."""
1606+ """set up the different tests."""
1607 yield super(TestNotifyProcessor, self).setUp()
1608 self.processor = notify_processor.NotifyProcessor(None)
1609- self.general = FakeGeneralProcessor()
1610+ self.general = common_tests.FakeGeneralProcessor()
1611 self.processor.general_processor = self.general
1612
1613 def test_rm_from_mute_filter(self):
1614
1615=== modified file 'tests/platform/filesystem_notifications/test_fsevents_daemon.py'
1616--- tests/platform/filesystem_notifications/test_fsevents_daemon.py 2012-07-19 14:13:06 +0000
1617+++ tests/platform/filesystem_notifications/test_fsevents_daemon.py 2012-08-22 18:22:29 +0000
1618@@ -26,14 +26,14 @@
1619 # do not wish to do so, delete this exception statement from your
1620 # version. If you delete this exception statement from all source
1621 # files in the program, then also delete it here.
1622-"""Tests for the fsevents daemon integration."""
1623+"""Tests for the fseventsd daemon integration."""
1624
1625 import os
1626
1627 from twisted.internet import defer, protocol
1628
1629 from contrib.testing.testcase import BaseTwistedTestCase
1630-from ubuntuone.darwin import fsevents
1631+from ubuntuone import fseventsd
1632 from ubuntuone.devtools.testcases.txsocketserver import TidyUnixServer
1633 from ubuntuone.platform.filesystem_notifications.monitor.darwin import (
1634 fsevents_daemon,
1635@@ -272,7 +272,7 @@
1636 head, _ = os.path.split(destination_path)
1637 self.factory.watched_paths.append(head)
1638 event = FakeDaemonEvent()
1639- event.event_type = fsevents.FSE_RENAME
1640+ event.event_type = fseventsd.FSE_RENAME
1641 event.event_paths.extend([source_path, destination_path])
1642 converted_events = self.factory.convert_in_pyinotify_event(event)
1643 self.assertEqual(1, len(converted_events))
1644@@ -289,7 +289,7 @@
1645 head, _ = os.path.split(source_path)
1646 self.factory.watched_paths.append(head)
1647 event = FakeDaemonEvent()
1648- event.event_type = fsevents.FSE_RENAME
1649+ event.event_type = fseventsd.FSE_RENAME
1650 event.event_paths.extend([source_path, destination_path])
1651 converted_events = self.factory.convert_in_pyinotify_event(event)
1652 self.assertEqual(1, len(converted_events))
1653@@ -306,7 +306,7 @@
1654 head, _ = os.path.split(source_path)
1655 self.factory.watched_paths.append(head)
1656 event = FakeDaemonEvent()
1657- event.event_type = fsevents.FSE_RENAME
1658+ event.event_type = fseventsd.FSE_RENAME
1659 event.event_paths.extend([source_path, destination_path])
1660 converted_events = self.factory.convert_in_pyinotify_event(event)
1661 self.assertEqual(2, len(converted_events))
1662@@ -337,7 +337,7 @@
1663 """Test processing the drop of the events."""
1664 func_called = []
1665 event = FakeDaemonEvent()
1666- event.event_type = fsevents.FSE_EVENTS_DROPPED
1667+ event.event_type = fseventsd.FSE_EVENTS_DROPPED
1668
1669 def fake_events_dropped():
1670 """A fake events dropped implementation."""
1671@@ -354,7 +354,7 @@
1672 self.factory.ignored_paths.append(head)
1673 event = FakeDaemonEvent()
1674 event.event_paths.append(event_path)
1675- event.event_type = fsevents.FSE_CREATE_FILE
1676+ event.event_type = fseventsd.FSE_CREATE_FILE
1677 self.factory.process_event(event)
1678 self.assertEqual(0, len(self.processor.processed_events))
1679
1680@@ -365,7 +365,7 @@
1681 self.factory.watched_paths.append(head)
1682 event = FakeDaemonEvent()
1683 event.event_paths.append(event_path)
1684- event.event_type = fsevents.FSE_CREATE_FILE
1685+ event.event_type = fseventsd.FSE_CREATE_FILE
1686 self.factory.process_event(event)
1687 self.assertEqual(1, len(self.processor.processed_events))
1688 self.assertEqual(event_path,
1689
1690=== added file 'tests/platform/filesystem_notifications/test_windows.py'
1691--- tests/platform/filesystem_notifications/test_windows.py 1970-01-01 00:00:00 +0000
1692+++ tests/platform/filesystem_notifications/test_windows.py 2012-08-22 18:22:29 +0000
1693@@ -0,0 +1,344 @@
1694+#
1695+# Authors: Manuel de la Pena <manuel@canonical.com>
1696+# Alejandro J. Cura <alecu@canonical.com>
1697+#
1698+# Copyright 2011-2012 Canonical Ltd.
1699+#
1700+# This program is free software: you can redistribute it and/or modify it
1701+# under the terms of the GNU General Public License version 3, as published
1702+# by the Free Software Foundation.
1703+#
1704+# This program is distributed in the hope that it will be useful, but
1705+# WITHOUT ANY WARRANTY; without even the implied warranties of
1706+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1707+# PURPOSE. See the GNU General Public License for more details.
1708+#
1709+# You should have received a copy of the GNU General Public License along
1710+# with this program. If not, see <http://www.gnu.org/licenses/>.
1711+#
1712+# In addition, as a special exception, the copyright holders give
1713+# permission to link the code of portions of this program with the
1714+# OpenSSL library under certain conditions as described in each
1715+# individual source file, and distribute linked combinations
1716+# including the two.
1717+# You must obey the GNU General Public License in all respects
1718+# for all of the code used other than OpenSSL. If you modify
1719+# file(s) with this exception, you may extend this exception to your
1720+# version of the file(s), but you are not obligated to do so. If you
1721+# do not wish to do so, delete this exception statement from your
1722+# version. If you delete this exception statement from all source
1723+# files in the program, then also delete it here.
1724+"""Test the filesystem notifications on windows."""
1725+
1726+import os
1727+
1728+from twisted.internet import defer
1729+from win32file import FILE_NOTIFY_INFORMATION
1730+
1731+from ubuntuone.platform.filesystem_notifications.monitor import (
1732+ common,
1733+ windows as filesystem_notifications,
1734+)
1735+from ubuntuone.platform.filesystem_notifications.monitor.common import (
1736+ FilesystemMonitor,
1737+ Watch,
1738+ WatchManager,
1739+)
1740+from ubuntuone.platform.filesystem_notifications.monitor.windows import (
1741+ FILE_NOTIFY_CHANGE_FILE_NAME,
1742+ FILE_NOTIFY_CHANGE_DIR_NAME,
1743+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
1744+ FILE_NOTIFY_CHANGE_SIZE,
1745+ FILE_NOTIFY_CHANGE_LAST_WRITE,
1746+ FILE_NOTIFY_CHANGE_SECURITY,
1747+ FILE_NOTIFY_CHANGE_LAST_ACCESS,
1748+)
1749+from tests.platform.filesystem_notifications import common as common_tests
1750+
1751+
1752+class FakeEventsProcessor(object):
1753+
1754+ """Handle fake events creation and processing."""
1755+
1756+ def create_fake_event(self, filename):
1757+ """Create a fake file event."""
1758+ return (1, filename)
1759+
1760+ def custom_process_events(self, watch, events):
1761+ """Adapt to each platform way to process events."""
1762+ watch.platform_watch._process_events(events)
1763+
1764+
1765+class TestWatch(common_tests.TestWatch):
1766+ """Test the watch so that it returns the same events as pyinotify."""
1767+
1768+ timeout = 5
1769+
1770+ @defer.inlineCallbacks
1771+ def setUp(self):
1772+ yield super(TestWatch, self).setUp()
1773+ self.path = u'\\\\?\\C:\\path' # a valid windows path
1774+ self.common_path = u'C:\\path'
1775+ self.invalid_path = u'\\\\?\\C:\\path\\to\\no\\dir'
1776+ self.mask = FILE_NOTIFY_CHANGE_FILE_NAME | \
1777+ FILE_NOTIFY_CHANGE_DIR_NAME | \
1778+ FILE_NOTIFY_CHANGE_ATTRIBUTES | \
1779+ FILE_NOTIFY_CHANGE_SIZE | \
1780+ FILE_NOTIFY_CHANGE_LAST_WRITE | \
1781+ FILE_NOTIFY_CHANGE_SECURITY | \
1782+ FILE_NOTIFY_CHANGE_LAST_ACCESS
1783+ self.fake_events_processor = FakeEventsProcessor()
1784+
1785+ def file_notify_information_wrapper(buf, data):
1786+ """Wrapper that gets the events and adds them to the list."""
1787+ events = FILE_NOTIFY_INFORMATION(buf, data)
1788+ # we want to append the list because that is what will be logged.
1789+ # If we use extend we wont have the same logging because it will
1790+ # group all events in a single lists which is not what the COM API
1791+ # does.
1792+ str_events = [
1793+ (common.ACTIONS_NAMES[action], path) for action, path in
1794+ events]
1795+ self.raw_events.append(str_events)
1796+ return events
1797+
1798+ self.patch(filesystem_notifications, 'FILE_NOTIFY_INFORMATION',
1799+ file_notify_information_wrapper)
1800+
1801+ @defer.inlineCallbacks
1802+ def test_file_write(self):
1803+ """Test that the correct event is raised when a file is written."""
1804+ file_name = os.path.join(self.basedir, 'test_file_write')
1805+ # create the file before recording
1806+ fd = open(file_name, 'w')
1807+ # clean behind us by removing the file
1808+ self.addCleanup(os.remove, file_name)
1809+
1810+ def write_file():
1811+ """Action for the test."""
1812+ fd.write('test')
1813+ fd.close()
1814+
1815+ events = yield self._perform_operations(self.basedir, self.mask,
1816+ write_file, 1)
1817+ event = events[0]
1818+ self.assertFalse(event.dir)
1819+ self.assertEqual(0x2, event.mask)
1820+ self.assertEqual('IN_MODIFY', event.maskname)
1821+ self.assertEqual(os.path.split(file_name)[1], event.name)
1822+ self.assertEqual('.', event.path)
1823+ self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
1824+ self.assertEqual(0, event.wd)
1825+
1826+ @defer.inlineCallbacks
1827+ def test_call_deferred_already_called(self):
1828+ """Test that the function is not called."""
1829+ method_args = []
1830+
1831+ def fake_call(*args, **kwargs):
1832+ """Execute the call."""
1833+ method_args.append((args, kwargs),)
1834+
1835+ watch = Watch(1, self.path, None)
1836+ yield watch.platform_watch._watch_started_deferred.callback(True)
1837+ watch.platform_watch._call_deferred(fake_call, None)
1838+ self.assertEqual(0, len(method_args))
1839+
1840+ def test_call_deferred_not_called(self):
1841+ """Test that is indeed called."""
1842+ method_args = []
1843+
1844+ def fake_call(*args, **kwargs):
1845+ """Execute the call."""
1846+ method_args.append((args, kwargs),)
1847+
1848+ watch = Watch(1, self.path, None)
1849+ watch.platform_watch._call_deferred(fake_call, None)
1850+ self.assertEqual(1, len(method_args))
1851+
1852+ def test_started_property(self):
1853+ """Test that the started property returns the started deferred."""
1854+ watch = Watch(1, self.path, None)
1855+ self.assertEqual(watch.started,
1856+ watch.platform_watch._watch_started_deferred)
1857+
1858+ def test_stopped_property(self):
1859+ """Test that the stopped property returns the stopped deferred."""
1860+ watch = Watch(1, self.path, None)
1861+ self.assertEqual(watch.stopped,
1862+ watch.platform_watch._watch_stopped_deferred)
1863+
1864+ @defer.inlineCallbacks
1865+ def test_start_watching_fails_early_in_thread(self):
1866+ """An early failure inside the thread should errback the deferred."""
1867+ test_path = self.mktemp("test_directory")
1868+ self.patch(filesystem_notifications, "CreateFileW", self.random_error)
1869+ watch = Watch(1, test_path, None)
1870+ d = watch.start_watching()
1871+ yield self.assertFailure(d, common_tests.FakeException)
1872+
1873+ @defer.inlineCallbacks
1874+ def test_start_watching_fails_late_in_thread(self):
1875+ """A late failure inside the thread should errback the deferred."""
1876+ test_path = self.mktemp("test_directory")
1877+ self.patch(filesystem_notifications, "ReadDirectoryChangesW",
1878+ self.random_error)
1879+ watch = Watch(1, test_path, None)
1880+ d = watch.start_watching()
1881+ yield self.assertFailure(d, common_tests.FakeException)
1882+
1883+ @defer.inlineCallbacks
1884+ def test_close_handle_is_called_on_error(self):
1885+ """CloseHandle is called when there's an error in the watch thread."""
1886+ test_path = self.mktemp("test_directory")
1887+ close_called = []
1888+ self.patch(filesystem_notifications, "CreateFileW", lambda *_: None)
1889+ self.patch(filesystem_notifications, "CloseHandle",
1890+ close_called.append)
1891+ self.patch(filesystem_notifications, "ReadDirectoryChangesW",
1892+ self.random_error)
1893+ watch = Watch(1, test_path, self.mask)
1894+ d = watch.start_watching()
1895+ yield self.assertFailure(d, common_tests.FakeException)
1896+ self.assertEqual(len(close_called), 1)
1897+ yield watch.stop_watching()
1898+
1899+ @defer.inlineCallbacks
1900+ def test_stop_watching_fired_when_watch_thread_finishes(self):
1901+ """The deferred returned is fired when the watch thread finishes."""
1902+ test_path = self.mktemp("another_test_directory")
1903+ watch = Watch(1, test_path, self.mask)
1904+ yield watch.start_watching()
1905+ self.assertNotEqual(watch.platform_watch._watch_handle, None)
1906+ yield watch.stop_watching()
1907+ self.assertEqual(watch.platform_watch._watch_handle, None)
1908+
1909+
1910+class TestWatchManager(common_tests.TestWatchManager):
1911+ """Test the watch manager."""
1912+
1913+ @defer.inlineCallbacks
1914+ def setUp(self):
1915+ """Set each of the tests."""
1916+ yield super(TestWatchManager, self).setUp()
1917+ self.parent_path = u'\\\\?\\C:\\' # a valid windows path
1918+ self.path = self.parent_path + u'path'
1919+ self.watch = Watch(1, self.path, None)
1920+ self.manager._wdm = {1: self.watch}
1921+ self.fake_events_processor = FakeEventsProcessor()
1922+
1923+ def test_add_single_watch(self):
1924+ """Test the addition of a new single watch."""
1925+ self.was_called = False
1926+
1927+ def fake_start_watching(*args):
1928+ """Fake start watch."""
1929+ self.was_called = True
1930+
1931+ self.patch(Watch, "start_watching", fake_start_watching)
1932+ self.manager._wdm = {}
1933+
1934+ mask = 'bit_mask'
1935+ self.manager.add_watch(self.path, mask)
1936+ self.assertEqual(1, len(self.manager._wdm))
1937+ self.assertTrue(self.was_called, 'The watch start was not called.')
1938+ self.assertEqual(self.path + os.path.sep, self.manager._wdm[0].path)
1939+ self.assertEqual(filesystem_notifications.FILESYSTEM_MONITOR_MASK,
1940+ self.manager._wdm[0].platform_watch._mask)
1941+
1942+ @defer.inlineCallbacks
1943+ def test_stop_multiple(self):
1944+ """Test that stop is fired when *all* watches have stopped."""
1945+
1946+ def fake_stop_watching(watch):
1947+ """Another fake stop watch."""
1948+ return watch.stopped
1949+
1950+ self.patch(Watch, "stop_watching", fake_stop_watching)
1951+ second_path = self.parent_path + u"second_path"
1952+ second_watch = Watch(2, second_path, None)
1953+ self.manager._wdm[2] = second_watch
1954+ d = self.manager.stop()
1955+ self.assertFalse(d.called, "Not fired before all watches end")
1956+ self.watch.stopped.callback(None)
1957+ self.assertFalse(d.called, "Not fired before all watches end")
1958+ second_watch.stopped.callback(None)
1959+ yield d
1960+ self.assertTrue(d.called, "Fired after the watches ended")
1961+
1962+
1963+class TestWatchManagerAddWatches(common_tests.TestWatchManagerAddWatches):
1964+ """Test the watch manager."""
1965+ timeout = 5
1966+
1967+ def test_add_watch_twice(self):
1968+ """Adding a watch twice succeeds when the watch is running."""
1969+ self.patch(Watch, "start_watching", lambda self: self.started)
1970+ manager = WatchManager(None)
1971+ # no need to stop watching because start_watching is fake
1972+
1973+ path = u'\\\\?\\C:\\test' # a valid windows path
1974+ mask = 'fake bit mask'
1975+ d1 = manager.add_watch(path, mask)
1976+ d2 = manager.add_watch(path, mask)
1977+
1978+ self.assertFalse(d1.called, "Should not be called yet.")
1979+ self.assertFalse(d2.called, "Should not be called yet.")
1980+
1981+ manager._wdm.values()[0].started.callback(True)
1982+
1983+ self.assertTrue(d1.called, "Should already be called.")
1984+ self.assertTrue(d2.called, "Should already be called.")
1985+
1986+
1987+class TestNotifyProcessor(common_tests.TestNotifyProcessor):
1988+ """Test the notify processor."""
1989+
1990+ @defer.inlineCallbacks
1991+ def setUp(self):
1992+ """set up the diffeent tests."""
1993+ yield super(TestNotifyProcessor, self).setUp()
1994+
1995+
1996+class FilesystemMonitorTestCase(common_tests.FilesystemMonitorTestCase):
1997+ """Tests for the FilesystemMonitor."""
1998+ timeout = 5
1999+
2000+ def test_add_watch_twice(self):
2001+ """Check the deferred returned by a second add_watch."""
2002+ self.patch(Watch, "start_watching", lambda self: self.started)
2003+ monitor = FilesystemMonitor(None, None)
2004+ # no need to stop watching because start_watching is fake
2005+
2006+ parent_path = 'C:\\test' # a valid windows path in utf-8 bytes
2007+ child_path = parent_path + "\\child"
2008+ d1 = monitor.add_watch(parent_path)
2009+ d2 = monitor.add_watch(child_path)
2010+
2011+ self.assertFalse(d1.called, "Should not be called yet.")
2012+ self.assertFalse(d2.called, "Should not be called yet.")
2013+
2014+ monitor._watch_manager._wdm.values()[0].started.callback(True)
2015+
2016+ self.assertTrue(d1.called, "Should already be called.")
2017+ self.assertTrue(d2.called, "Should already be called.")
2018+
2019+ @defer.inlineCallbacks
2020+ def test_add_watches_to_udf_ancestors(self):
2021+ """Test that the ancestor watches are not added."""
2022+
2023+ class FakeVolume(object):
2024+ """A fake UDF."""
2025+
2026+ def __init__(self, ancestors):
2027+ """Create a new instance."""
2028+ self.ancestors = ancestors
2029+
2030+ ancestors = ['~', '~\\Pictures', '~\\Pictures\\Home', ]
2031+ volume = FakeVolume(ancestors)
2032+ monitor = FilesystemMonitor(None, None)
2033+ added = yield monitor.add_watches_to_udf_ancestors(volume)
2034+ self.assertTrue(added, 'We should always return true.')
2035+ # lets ensure that we never added the watches
2036+ self.assertEqual(0, len(monitor._watch_manager._wdm.values()),
2037+ 'No watches should have been added.')
2038
2039=== modified file 'tests/platform/ipc/test_external_interface.py'
2040--- tests/platform/ipc/test_external_interface.py 2012-04-30 14:24:55 +0000
2041+++ tests/platform/ipc/test_external_interface.py 2012-08-22 18:22:29 +0000
2042@@ -40,6 +40,10 @@
2043 StatusTestCase,
2044 SyncDaemonTestCase,
2045 )
2046+from ubuntuone.syncdaemon import (
2047+ RECENT_TRANSFERS,
2048+ UPLOADING,
2049+)
2050
2051 STR = 'something'
2052 STR_STR_DICT = {'foo': 'bar'}
2053@@ -132,6 +136,16 @@
2054 self.assert_remote_method('waiting_metadata',
2055 in_signature=None, out_signature='a(sa{ss})')
2056
2057+ @defer.inlineCallbacks
2058+ def test_sync_menu(self):
2059+ """Test sync_menu."""
2060+ result = {RECENT_TRANSFERS: [], UPLOADING: []}
2061+ method = 'sync_menu'
2062+ yield self.assert_method_called(self.service.status,
2063+ method, result)
2064+ self.assert_remote_method(method,
2065+ in_signature=None, out_signature='a{sv}')
2066+
2067
2068 class EventsTests(EventsTestCase):
2069 """Basic tests for the Events exposed object."""
2070
2071=== modified file 'tests/platform/test_tools.py'
2072--- tests/platform/test_tools.py 2012-05-30 15:35:49 +0000
2073+++ tests/platform/test_tools.py 2012-08-22 18:22:29 +0000
2074@@ -36,12 +36,15 @@
2075 from ubuntuone.devtools.handlers import MementoHandler
2076
2077 from contrib.testing.testcase import FakeCommand, skipIfOS
2078+
2079 from ubuntuone.syncdaemon import (
2080 action_queue,
2081 event_queue,
2082 interaction_interfaces,
2083 states,
2084 volume_manager,
2085+ RECENT_TRANSFERS,
2086+ UPLOADING,
2087 )
2088 from ubuntuone.platform import tools
2089 from tests.platform import IPCTestCase
2090@@ -243,6 +246,13 @@
2091 self.assertEqual('share_id', result['volume_id'])
2092 self.assertEqual(False, self.main.vm.shares['share_id'].accepted)
2093
2094+ @defer.inlineCallbacks
2095+ def test_sync_menu(self):
2096+ """Test accept_share method."""
2097+ result = yield self.tool.sync_menu()
2098+ self.assertIn(RECENT_TRANSFERS, result)
2099+ self.assertIn(UPLOADING, result)
2100+
2101
2102 class TestWaitForSignals(TestToolsBase):
2103 """Test case for the wait_for_signals method from SyncDaemonTool."""
2104
2105=== modified file 'tests/status/test_aggregator.py'
2106--- tests/status/test_aggregator.py 2012-04-09 20:07:05 +0000
2107+++ tests/status/test_aggregator.py 2012-08-22 18:22:29 +0000
2108@@ -42,7 +42,11 @@
2109 from ubuntuone.status import aggregator
2110 from ubuntuone.status.notification import AbstractNotification
2111 from ubuntuone.status.messaging import AbstractMessaging
2112-from ubuntuone.syncdaemon import status_listener
2113+from ubuntuone.syncdaemon import (
2114+ status_listener,
2115+ RECENT_TRANSFERS,
2116+ UPLOADING,
2117+)
2118 from ubuntuone.syncdaemon.volume_manager import Share, UDF, Root
2119
2120 FILENAME = 'example.txt'
2121@@ -706,6 +710,8 @@
2122 self.share_id = path
2123 self.node_id = path
2124 self.deflated_size = 10000
2125+ self.size = 0
2126+ self.n_bytes_written = 0
2127
2128
2129 class FakeVolumeManager(object):
2130@@ -733,6 +739,7 @@
2131 self.files_uploading = []
2132 self.files_downloading = []
2133 self.progress_events = []
2134+ self.recent_transfers = aggregator.deque(maxlen=10)
2135
2136 def queue_done(self):
2137 """The queue completed all operations."""
2138@@ -762,6 +769,7 @@
2139 """An upload just finished."""
2140 if command in self.files_uploading:
2141 self.files_uploading.remove(command)
2142+ self.recent_transfers.append(command.path)
2143 self.queued_commands.discard(command)
2144
2145 def progress_made(self, share_id, node_id, n_bytes, deflated_size):
2146@@ -796,6 +804,70 @@
2147 self.fakevm,
2148 self.status_frontend)
2149
2150+ def test_recent_transfers(self):
2151+ """Check that it generates a tuple with the recent transfers."""
2152+ self.patch(status_listener.action_queue, "Upload", FakeCommand)
2153+ fake_command = FakeCommand('path1')
2154+ self.listener.handle_SYS_QUEUE_ADDED(fake_command)
2155+ self.listener.handle_SYS_QUEUE_REMOVED(fake_command)
2156+ fake_command = FakeCommand('path2')
2157+ self.listener.handle_SYS_QUEUE_ADDED(fake_command)
2158+ self.listener.handle_SYS_QUEUE_REMOVED(fake_command)
2159+ fake_command = FakeCommand('path3')
2160+ self.listener.handle_SYS_QUEUE_ADDED(fake_command)
2161+ self.listener.handle_SYS_QUEUE_REMOVED(fake_command)
2162+ transfers = self.status_frontend.recent_transfers()
2163+ expected = ['path1', 'path2', 'path3']
2164+ self.assertEqual(transfers, expected)
2165+
2166+ menu_data = self.listener.menu_data()
2167+ self.assertEqual(menu_data,
2168+ {UPLOADING: [], RECENT_TRANSFERS: expected})
2169+
2170+ def test_file_uploading(self):
2171+ """Check that it returns a list with the path, size, and progress."""
2172+ fc = FakeCommand(path='testfile.txt')
2173+ fc.size = 200
2174+ self.status_frontend.upload_started(fc)
2175+ uploading = self.status_frontend.files_uploading()
2176+ expected = [('testfile.txt', 200, 0)]
2177+ self.assertEqual(uploading, expected)
2178+ menu_data = self.listener.menu_data()
2179+ self.assertEqual(menu_data,
2180+ {UPLOADING: expected, RECENT_TRANSFERS: []})
2181+
2182+ fc.size = 1000
2183+ fc.n_bytes_written = 200
2184+ fc2 = FakeCommand(path='testfile2.txt')
2185+ fc2.size = 2000
2186+ fc2.n_bytes_written = 450
2187+ self.status_frontend.upload_started(fc2)
2188+ uploading = self.status_frontend.files_uploading()
2189+ expected = [('testfile.txt', 1000, 200), ('testfile2.txt', 2000, 450)]
2190+ self.assertEqual(uploading, expected)
2191+
2192+ menu_data = self.listener.menu_data()
2193+ self.assertEqual(menu_data,
2194+ {UPLOADING: expected, RECENT_TRANSFERS: []})
2195+
2196+ def test_menu_data_full_response(self):
2197+ """Check that listener.menu_data returns both uploading and recent."""
2198+ self.patch(status_listener.action_queue, "Upload", FakeCommand)
2199+ fake_command = FakeCommand('path1')
2200+ self.listener.handle_SYS_QUEUE_ADDED(fake_command)
2201+ self.listener.handle_SYS_QUEUE_REMOVED(fake_command)
2202+ fc = FakeCommand(path='testfile.txt')
2203+ fc.size = 1000
2204+ fc.n_bytes_written = 200
2205+ self.status_frontend.upload_started(fc)
2206+ uploading = self.status_frontend.files_uploading()
2207+ transfers = self.status_frontend.recent_transfers()
2208+ expected = {UPLOADING: [('testfile.txt', 1000, 200)],
2209+ RECENT_TRANSFERS: ['path1']}
2210+
2211+ self.assertEqual(
2212+ {UPLOADING: uploading, RECENT_TRANSFERS: transfers}, expected)
2213+
2214 def test_file_published(self):
2215 """A file published event is processed."""
2216 share_id = "fake share id"
2217@@ -1308,6 +1380,15 @@
2218 self.assertEqual(
2219 {(fc.share_id, fc.node_id): (fc.deflated_size)},
2220 self.aggregator.progress)
2221+ self.assertEqual(len(self.aggregator.recent_transfers), 1)
2222+
2223+ def test_max_recent_files(self):
2224+ """Check that the queue doesn't exceed the 5 items."""
2225+ for i in range(15):
2226+ fc = FakeCommand()
2227+ self.status_frontend.upload_started(fc)
2228+ self.status_frontend.upload_finished(fc)
2229+ self.assertEqual(len(self.aggregator.recent_transfers), 5)
2230
2231 def test_progress_made(self):
2232 """Progress on up and downloads is tracked."""
2233
2234=== modified file 'tests/syncdaemon/test_fsm.py'
2235--- tests/syncdaemon/test_fsm.py 2012-04-09 20:07:05 +0000
2236+++ tests/syncdaemon/test_fsm.py 2012-08-22 18:22:29 +0000
2237@@ -1626,6 +1626,33 @@
2238 mdobj = self.fsm.get_by_mdid(mdid)
2239 self.assertEqual(mdobj.stat, stat_path(path))
2240
2241+ def test_commit_partial_pushes_event(self):
2242+ """Test that the right event is pushed after the commit."""
2243+ listener = Listener()
2244+ self.eq.subscribe(listener)
2245+
2246+ path = os.path.join(self.share.path, "thisfile")
2247+ open_file(path, "w").close()
2248+ mdobj = self.create_node("thisfile")
2249+ mdid = mdobj.mdid
2250+ oldstat = stat_path(path)
2251+ self.assertEqual(mdobj.stat, oldstat)
2252+
2253+ # create a partial
2254+ self.fsm.create_partial(mdobj.node_id, mdobj.share_id)
2255+ fh = self.fsm.get_partial_for_writing(mdobj.node_id, mdobj.share_id)
2256+ fh.write("foobar")
2257+ fh.close()
2258+ mdobj = self.fsm.get_by_mdid(mdid)
2259+ self.assertEqual(mdobj.stat, oldstat)
2260+
2261+ # commit the partial
2262+ self.fsm.commit_partial(mdobj.node_id, mdobj.share_id, "localhash")
2263+ mdobj = self.fsm.get_by_mdid(mdid)
2264+
2265+ kwargs = dict(share_id=mdobj.share_id, node_id=mdobj.node_id)
2266+ self.assertTrue(("FSM_PARTIAL_COMMITED", kwargs) in listener.events)
2267+
2268 def test_move(self):
2269 """Test that move refreshes stat."""
2270 path1 = os.path.join(self.share.path, "thisfile1")
2271
2272=== modified file 'tests/syncdaemon/test_interaction_interfaces.py'
2273--- tests/syncdaemon/test_interaction_interfaces.py 2012-04-09 20:07:05 +0000
2274+++ tests/syncdaemon/test_interaction_interfaces.py 2012-08-22 18:22:29 +0000
2275@@ -1226,18 +1226,19 @@
2276 self.addCleanup(self.main.event_q.unsubscribe, self.sd_obj)
2277
2278
2279-class DownloadTestCase(SyncdaemonEventListenerTestCase):
2280- """Test the Download events in SyncdaemonEventListener."""
2281+class UploadTestCase(SyncdaemonEventListenerTestCase):
2282+ """Test the Upload events in SyncdaemonEventListener."""
2283
2284 add_fsm_key = True
2285- direction = 'Download'
2286- bytes_key = 'n_bytes_read'
2287- hash_kwarg = 'server_hash'
2288- extra_finished_args = {}
2289+ direction = 'Upload'
2290+ bytes_key = 'n_bytes_written'
2291+ hash_kwarg = 'hash'
2292+ extra_finished_args = dict(new_generation='new_generation', hash='')
2293+ finished_event = 'AQ_UPLOAD_FINISHED'
2294
2295 @defer.inlineCallbacks
2296 def setUp(self):
2297- yield super(DownloadTestCase, self).setUp()
2298+ yield super(UploadTestCase, self).setUp()
2299 self.deferred = None
2300 self.signal_name = None
2301 if self.add_fsm_key:
2302@@ -1304,7 +1305,7 @@
2303 return self.deferred
2304
2305 def test_handle_finished(self):
2306- """Test the handle_AQ_<direction>_FINISHED method."""
2307+ """Test the handle_<finished_event> method."""
2308 self.signal_name = self.direction + 'Finished'
2309 self.deferred = defer.Deferred()
2310
2311@@ -1320,10 +1321,9 @@
2312 self.patch(self.sd_obj.interface.status, 'SignalError',
2313 self.error_handler)
2314
2315- kwargs = {'share_id': '', 'node_id': 'node_id', self.hash_kwarg: ''}
2316+ kwargs = {'share_id': '', 'node_id': 'node_id'}
2317 kwargs.update(self.extra_finished_args)
2318- self.main.event_q.push('AQ_%s_FINISHED' % self.direction.upper(),
2319- **kwargs)
2320+ self.main.event_q.push(self.finished_event, **kwargs)
2321 return self.deferred
2322
2323 def test_handle_event_error(self):
2324@@ -1350,21 +1350,29 @@
2325 return self.deferred
2326
2327
2328+class DownloadTestCase(UploadTestCase):
2329+ """Test the Download events in SyncdaemonEventListener."""
2330+
2331+ direction = 'Download'
2332+ bytes_key = 'n_bytes_read'
2333+ hash_kwarg = 'server_hash'
2334+ extra_finished_args = {}
2335+ finished_event = 'FSM_PARTIAL_COMMITED'
2336+
2337+ # The download is special, because we don't want to throw the ipc signal on
2338+ # AQ_DOWNLOAD_FINISHED but instead we should wait for FSM_PARTIAL_COMMITED
2339+
2340+ def test_ignore_pre_partial_commit_event(self):
2341+ """The AQ_DOWNLOAD_FINISHED signal is ignored."""
2342+ self.assertNotIn("handle_AQ_DOWNLOAD_FINISHED", vars(self.sd_class))
2343+
2344+
2345 class DownloadNoKeyTestCase(DownloadTestCase):
2346 """Test the Download events when there is a fsm KeyError."""
2347
2348 add_fsm_key = False
2349
2350
2351-class UploadTestCase(DownloadTestCase):
2352- """Test the Upload events in SyncdaemonEventListener."""
2353-
2354- direction = 'Upload'
2355- bytes_key = 'n_bytes_written'
2356- hash_kwarg = 'hash'
2357- extra_finished_args = dict(new_generation='new_generation')
2358-
2359-
2360 class UploadNoKeyTestCase(UploadTestCase):
2361 """Test the Upload events when there is a fsm KeyError."""
2362
2363
2364=== modified file 'tests/syncdaemon/test_vm.py'
2365--- tests/syncdaemon/test_vm.py 2012-04-09 20:07:05 +0000
2366+++ tests/syncdaemon/test_vm.py 2012-08-22 18:22:29 +0000
2367@@ -2752,7 +2752,7 @@
2368
2369 result, msg = self.vm.validate_path_for_folder(folder_path)
2370 self.assertTrue(result)
2371- self.assertIs(msg, "",
2372+ self.assertIs(msg, "",
2373 '%r must be a valid path for creating a folder.' % folder_path)
2374
2375 def test_validate_UDF_path_if_folder_shares_a_prefix_with_an_udf(self):
2376@@ -2769,7 +2769,7 @@
2377
2378 result, msg = self.vm.validate_path_for_folder(tricky_path)
2379 self.assertTrue(result)
2380- self.assertIs(msg, "",
2381+ self.assertIs(msg, "",
2382 '%r must be a valid path for creating a folder.' % tricky_path)
2383
2384 def test_validate_UDF_path_not_valid_if_outside_home(self):
2385@@ -2818,6 +2818,17 @@
2386 self.assertIsNot(msg, "",
2387 '%r must be an invalid path for creating a folder.' % udf_parent)
2388
2389+ def test_not_valid_if_folder_is_file(self):
2390+ """A link path is not valid."""
2391+ self.patch(volume_manager.os.path, 'isdir', lambda p: False)
2392+ self.patch(volume_manager, 'path_exists', lambda p: True)
2393+ path_link = os.path.join(self.home_dir, 'Test Me')
2394+
2395+ result, msg = self.vm.validate_path_for_folder(path_link)
2396+ self.assertFalse(result)
2397+ self.assertIsNot(msg, "",
2398+ '%r must be an invalid path for creating a folder.' % path_link)
2399+
2400 def test_not_valid_if_folder_is_link(self):
2401 """A link path is not valid."""
2402 self.patch(volume_manager, 'is_link', lambda p: True)
2403
2404=== modified file 'ubuntuone/platform/filesystem_notifications/monitor/__init__.py'
2405--- ubuntuone/platform/filesystem_notifications/monitor/__init__.py 2012-07-18 15:18:04 +0000
2406+++ ubuntuone/platform/filesystem_notifications/monitor/__init__.py 2012-08-22 18:22:29 +0000
2407@@ -42,11 +42,13 @@
2408 if sys.platform == 'win32':
2409 from ubuntuone.platform.filesystem_notifications.monitor import (
2410 common,
2411+ windows,
2412 )
2413
2414 FILEMONITOR_IDS = {
2415 DEFAULT_MONITOR: common.FilesystemMonitor,
2416 }
2417+ ACTIONS = windows.ACTIONS
2418
2419 elif sys.platform == 'darwin':
2420 from ubuntuone.platform.filesystem_notifications.monitor import darwin
2421@@ -58,6 +60,7 @@
2422 DEFAULT_MONITOR: common.FilesystemMonitor,
2423 'daemon': darwin.fsevents_daemon.FilesystemMonitor,
2424 }
2425+ ACTIONS = darwin.fsevents_client.ACTIONS
2426 else:
2427 from ubuntuone.platform.filesystem_notifications.monitor import (
2428 linux,
2429
2430=== modified file 'ubuntuone/platform/filesystem_notifications/monitor/common.py'
2431--- ubuntuone/platform/filesystem_notifications/monitor/common.py 2012-07-18 09:05:26 +0000
2432+++ ubuntuone/platform/filesystem_notifications/monitor/common.py 2012-08-22 18:22:29 +0000
2433@@ -65,6 +65,7 @@
2434 else:
2435 raise ImportError('Not supported platform')
2436
2437+
2438 # a map between the few events that we have on common platforms and those
2439 # found in pyinotify
2440 ACTIONS = source.ACTIONS
2441
2442=== modified file 'ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_daemon.py'
2443--- ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_daemon.py 2012-07-19 14:13:06 +0000
2444+++ ubuntuone/platform/filesystem_notifications/monitor/darwin/fsevents_daemon.py 2012-08-22 18:22:29 +0000
2445@@ -25,7 +25,7 @@
2446 # do not wish to do so, delete this exception statement from your
2447 # version. If you delete this exception statement from all source
2448 # files in the program, then also delete it here.
2449-"""Filesystem notifications based on the fsevents daemon.."""
2450+"""Filesystem notifications based on the fseventsd daemon.."""
2451
2452 import logging
2453 import os
2454@@ -42,7 +42,7 @@
2455 )
2456
2457 from ubuntuone import logger
2458-from ubuntuone.darwin import fsevents
2459+from ubuntuone import fseventsd
2460 from ubuntuone.platform.filesystem_notifications.notify_processor import (
2461 NotifyProcessor,
2462 )
2463@@ -61,24 +61,24 @@
2464
2465 TRACE = logger.TRACE
2466
2467-# map the fsevents actions to those from pyinotify
2468+# map the fseventsd actions to those from pyinotify
2469 DARWIN_ACTIONS = {
2470- fsevents.FSE_CREATE_FILE: IN_CREATE,
2471- fsevents.FSE_DELETE: IN_DELETE,
2472- fsevents.FSE_STAT_CHANGED: IN_MODIFY,
2473- fsevents.FSE_CONTENT_MODIFIED: IN_MODIFY,
2474- fsevents.FSE_CREATE_DIR: IN_CREATE,
2475+ fseventsd.FSE_CREATE_FILE: IN_CREATE,
2476+ fseventsd.FSE_DELETE: IN_DELETE,
2477+ fseventsd.FSE_STAT_CHANGED: IN_MODIFY,
2478+ fseventsd.FSE_CONTENT_MODIFIED: IN_MODIFY,
2479+ fseventsd.FSE_CREATE_DIR: IN_CREATE,
2480 }
2481
2482 # list of those events from which we do not care
2483 DARWIN_IGNORED_ACTIONS = (
2484- fsevents.FSE_UNKNOWN,
2485- fsevents.FSE_INVALID,
2486- fsevents.FSE_EXCHANGE,
2487- fsevents.FSE_FINDER_INFO_CHANGED,
2488- fsevents.FSE_CHOWN,
2489- fsevents.FSE_XATTR_MODIFIED,
2490- fsevents.FSE_XATTR_REMOVED,
2491+ fseventsd.FSE_UNKNOWN,
2492+ fseventsd.FSE_INVALID,
2493+ fseventsd.FSE_EXCHANGE,
2494+ fseventsd.FSE_FINDER_INFO_CHANGED,
2495+ fseventsd.FSE_CHOWN,
2496+ fseventsd.FSE_XATTR_MODIFIED,
2497+ fseventsd.FSE_XATTR_REMOVED,
2498 )
2499
2500 # translates quickly the event and it's is_dir state to our standard events
2501@@ -95,7 +95,7 @@
2502 IN_MOVED_TO: 'FS_FILE_CREATE',
2503 IN_MOVED_TO | IN_ISDIR: 'FS_DIR_CREATE'}
2504
2505-# TODO: This should be in fsevents to be imported!
2506+# TODO: This should be in fseventsd to be imported!
2507 # Path to the socket used by the daemon
2508 DAEMON_SOCKET = '/var/run/ubuntuone_fsevents_daemon'
2509
2510@@ -134,14 +134,14 @@
2511 return unicodedata.normalize('NFC', path).encode('utf-8')
2512
2513
2514-class PyInotifyEventsFactory(fsevents.FsEventsFactory):
2515+class PyInotifyEventsFactory(fseventsd.FsEventsFactory):
2516 """Factory that process events and converts them in pyinotify ones."""
2517
2518 def __init__(self, processor,
2519 ignored_events=DARWIN_IGNORED_ACTIONS):
2520 """Create a new instance."""
2521 # old style class
2522- fsevents.FsEventsFactory.__init__(self)
2523+ fseventsd.FsEventsFactory.__init__(self)
2524 self._processor = processor
2525 self._ignored_events = ignored_events
2526 self.watched_paths = []
2527@@ -215,7 +215,7 @@
2528 """Get an event from the daemon and convert it in a pyinotify one."""
2529 # the rename is a special type of event because it has to be either
2530 # converted is a pair of events or in a single one (CREATE or DELETE)
2531- if event.event_type == fsevents.FSE_RENAME:
2532+ if event.event_type == fseventsd.FSE_RENAME:
2533 is_create = self.is_create(event)
2534 if is_create or self.is_delete(event):
2535 mask = IN_CREATE if is_create else IN_DELETE
2536@@ -278,7 +278,7 @@
2537 if event.event_type in self._ignored_events:
2538 # Do nothing because sd does not care about such info
2539 return
2540- if event.event_type == fsevents.FSE_EVENTS_DROPPED:
2541+ if event.event_type == fseventsd.FSE_EVENTS_DROPPED:
2542 # this should not be very common but we have to deal with it
2543 return self.events_dropper()
2544 events = self.convert_in_pyinotify_event(event)
2545
2546=== modified file 'ubuntuone/platform/ipc/ipc_client.py'
2547--- ubuntuone/platform/ipc/ipc_client.py 2012-05-22 14:28:56 +0000
2548+++ ubuntuone/platform/ipc/ipc_client.py 2012-08-22 18:22:29 +0000
2549@@ -197,6 +197,22 @@
2550 def current_uploads(self):
2551 """Return a list of files with a upload in progress."""
2552
2553+ @remote
2554+ def sync_menu(self):
2555+ """
2556+ This method returns a dictionary, with the following keys and values:
2557+
2558+ Key: 'recent-transfers'
2559+ Value: a list of strings (paths), each being the name of a file that
2560+ was recently transferred.
2561+
2562+ Key: 'uploading'
2563+ Value: a list of tuples, with each tuple having the following items:
2564+ * str: the path of a file that's currently being uploaded
2565+ * int: size of the file
2566+ * int: bytes written
2567+ """
2568+
2569 @signal
2570 def on_content_queue_changed(self):
2571 """Emit ContentQueueChanged."""
2572@@ -234,7 +250,7 @@
2573 """Emit UploadFileProgress."""
2574
2575 @signal
2576- def on_upload_finished(self, upload, **info):
2577+ def on_upload_finished(self, upload, *info):
2578 """Emit UploadFinished."""
2579
2580 @signal
2581
2582=== modified file 'ubuntuone/platform/ipc/linux.py'
2583--- ubuntuone/platform/ipc/linux.py 2012-05-22 14:07:55 +0000
2584+++ ubuntuone/platform/ipc/linux.py 2012-08-22 18:22:29 +0000
2585@@ -38,6 +38,10 @@
2586 from xml.etree import ElementTree
2587
2588 from ubuntuone.platform.launcher import UbuntuOneLauncher
2589+from ubuntuone.syncdaemon import (
2590+ RECENT_TRANSFERS,
2591+ UPLOADING,
2592+)
2593
2594 # Disable the "Invalid Name" check here, as we have lots of DBus style names
2595 # pylint: disable-msg=C0103
2596@@ -173,6 +177,35 @@
2597 warnings.warn('Use "waiting" method instead.', DeprecationWarning)
2598 return self.service.status.waiting_content()
2599
2600+ @dbus.service.method(DBUS_IFACE_STATUS_NAME, out_signature='a{sv}')
2601+ def sync_menu(self):
2602+ """
2603+ This method returns a dictionary, with the following keys and values:
2604+
2605+ Key: 'recent-transfers'
2606+ Value: a list of strings (paths), each being the name of a file that
2607+ was recently transferred.
2608+
2609+ Key: 'uploading'
2610+ Value: a list of tuples, with each tuple having the following items:
2611+ * str: the path of a file that's currently being uploaded
2612+ * int: size of the file
2613+ * int: bytes written
2614+ """
2615+ data = self.service.status.sync_menu()
2616+ uploading = data[UPLOADING]
2617+ transfers = data[RECENT_TRANSFERS]
2618+ upload_data = dbus.Array(signature="(sii)")
2619+ transfer_data = dbus.Array(signature="s")
2620+ for up in uploading:
2621+ upload_data.append(dbus.Struct(up, signature="sii"))
2622+ for transfer in transfers:
2623+ transfer_data.append(transfer)
2624+ result = dbus.Dictionary(signature="sv")
2625+ result[UPLOADING] = upload_data
2626+ result[RECENT_TRANSFERS] = transfer_data
2627+ return result
2628+
2629 @dbus.service.signal(DBUS_IFACE_STATUS_NAME)
2630 def DownloadStarted(self, path):
2631 """Fire a signal to notify that a download has started."""
2632
2633=== modified file 'ubuntuone/platform/ipc/perspective_broker.py'
2634--- ubuntuone/platform/ipc/perspective_broker.py 2012-07-13 16:06:27 +0000
2635+++ ubuntuone/platform/ipc/perspective_broker.py 2012-08-22 18:22:29 +0000
2636@@ -231,6 +231,7 @@
2637 'waiting',
2638 'waiting_metadata',
2639 'waiting_content',
2640+ 'sync_menu',
2641 ]
2642
2643 signal_mapping = {
2644@@ -291,6 +292,10 @@
2645 warnings.warn('Use "waiting" method instead.', DeprecationWarning)
2646 return self.service.status.waiting_content()
2647
2648+ def sync_menu(self):
2649+ """Return the info necessary to construct the menu."""
2650+ return self.service.status.sync_menu()
2651+
2652 @signal
2653 def DownloadStarted(self, path):
2654 """Fire a signal to notify that a download has started."""
2655@@ -300,7 +305,7 @@
2656 """Fire a signal to notify about a download progress."""
2657
2658 @signal
2659- def DownloadFinished(self, path, info):
2660+ def DownloadFinished(self, path, *info):
2661 """Fire a signal to notify that a download has finished."""
2662
2663 @signal
2664@@ -312,7 +317,7 @@
2665 """Fire a signal to notify about an upload progress."""
2666
2667 @signal
2668- def UploadFinished(self, path, info):
2669+ def UploadFinished(self, path, *info):
2670 """Fire a signal to notify that an upload has finished."""
2671
2672 @signal
2673
2674=== modified file 'ubuntuone/platform/os_helper/__init__.py'
2675--- ubuntuone/platform/os_helper/__init__.py 2012-06-22 19:37:36 +0000
2676+++ ubuntuone/platform/os_helper/__init__.py 2012-08-22 18:22:29 +0000
2677@@ -73,6 +73,7 @@
2678
2679 # Decorators
2680
2681+get_os_valid_path = source.get_os_valid_path
2682 is_valid_syncdaemon_path = source.is_valid_syncdaemon_path
2683 is_valid_os_path = source.is_valid_os_path
2684 os_path = source.os_path
2685
2686=== modified file 'ubuntuone/platform/os_helper/darwin.py'
2687--- ubuntuone/platform/os_helper/darwin.py 2012-07-10 18:41:15 +0000
2688+++ ubuntuone/platform/os_helper/darwin.py 2012-08-22 18:22:29 +0000
2689@@ -29,8 +29,8 @@
2690 """
2691 Darwin import for ubuntuone-client
2692
2693-This module has to have all darwin specific modules and provide the api required
2694-to support the darwin platform.
2695+This module has to have all darwin specific modules and provide the
2696+api required to support the darwin platform.
2697 """
2698
2699 import errno
2700@@ -70,6 +70,7 @@
2701 is_root = unix.is_root
2702 get_path_list = unix.get_path_list
2703 normpath = unix.normpath
2704+get_os_valid_path = unix.get_os_valid_path
2705
2706
2707 def move_to_trash(path):
2708@@ -121,6 +122,8 @@
2709 def is_valid_os_path(path_indexes=None):
2710 def decorator(func):
2711 def wrapped(*args, **kwargs):
2712+ for i in path_indexes:
2713+ assert isinstance(args[i], str), 'Path %r should be str.'
2714 return func(*args, **kwargs)
2715 return wrapped
2716 return decorator
2717
2718=== modified file 'ubuntuone/platform/os_helper/linux.py'
2719--- ubuntuone/platform/os_helper/linux.py 2012-06-27 12:51:20 +0000
2720+++ ubuntuone/platform/os_helper/linux.py 2012-08-22 18:22:29 +0000
2721@@ -123,6 +123,7 @@
2722 is_root = unix.is_root
2723 get_path_list = unix.get_path_list
2724 normpath = unix.normpath
2725+get_os_valid_path = unix.get_os_valid_path
2726 is_valid_syncdaemon_path = None
2727 is_valid_os_path = None
2728 os_path = None
2729
2730=== modified file 'ubuntuone/platform/os_helper/unix.py'
2731--- ubuntuone/platform/os_helper/unix.py 2012-06-27 14:02:14 +0000
2732+++ ubuntuone/platform/os_helper/unix.py 2012-08-22 18:22:29 +0000
2733@@ -185,3 +185,8 @@
2734 def normpath(path):
2735 """Normalize path, eliminating double slashes, etc."""
2736 return os.path.normpath(path)
2737+
2738+
2739+def get_os_valid_path(path):
2740+ """Return a valid os path."""
2741+ return os.path.abspath(path)
2742
2743=== modified file 'ubuntuone/platform/os_helper/windows.py'
2744--- ubuntuone/platform/os_helper/windows.py 2012-07-03 17:16:57 +0000
2745+++ ubuntuone/platform/os_helper/windows.py 2012-08-22 18:22:29 +0000
2746@@ -249,6 +249,8 @@
2747 assert_windows_path(result)
2748 return result
2749
2750+get_os_valid_path = get_windows_valid_path
2751+
2752
2753 def _unicode_to_bytes(path):
2754 """Convert a unicode path to a bytes path."""
2755
2756=== modified file 'ubuntuone/platform/tools/__init__.py'
2757--- ubuntuone/platform/tools/__init__.py 2012-05-30 15:35:49 +0000
2758+++ ubuntuone/platform/tools/__init__.py 2012-08-22 18:22:29 +0000
2759@@ -326,6 +326,13 @@
2760
2761 @defer.inlineCallbacks
2762 @log_call(logger.debug)
2763+ def sync_menu(self):
2764+ """Return a deferred that will be fired with the sync menu data."""
2765+ results = yield self.proxy.call_method('status', 'sync_menu')
2766+ defer.returnValue(results)
2767+
2768+ @defer.inlineCallbacks
2769+ @log_call(logger.debug)
2770 def accept_share(self, share_id):
2771 """Accept the share with id: share_id."""
2772 d = self.wait_for_signals(signal_ok='ShareAnswerResponse',
2773
2774=== modified file 'ubuntuone/status/aggregator.py'
2775--- ubuntuone/status/aggregator.py 2012-04-09 20:07:05 +0000
2776+++ ubuntuone/status/aggregator.py 2012-08-22 18:22:29 +0000
2777@@ -33,7 +33,7 @@
2778 import itertools
2779 import operator
2780 import os
2781-
2782+from collections import deque
2783
2784 import gettext
2785
2786@@ -624,6 +624,7 @@
2787 self.finished_delay = 10
2788 self.progress = {}
2789 self.to_do = {}
2790+ self.recent_transfers = deque(maxlen=5)
2791
2792 def get_notification(self):
2793 """Create a new toggleable notification object."""
2794@@ -775,6 +776,7 @@
2795 if command.deflated_size is not None:
2796 self.progress[
2797 (command.share_id, command.node_id)] = command.deflated_size
2798+ self.recent_transfers.append(command.path)
2799 logger.debug("unqueueing command: %s", command.__class__.__name__)
2800 self.update_progressbar()
2801
2802@@ -806,6 +808,19 @@
2803 self.messaging = Messaging()
2804 self.quota_timer = None
2805
2806+ def recent_transfers(self):
2807+ """Return a tuple with the recent transfers paths."""
2808+ return list(self.aggregator.recent_transfers)
2809+
2810+ def files_uploading(self):
2811+ """Return a list with the files being uploading."""
2812+ uploading = []
2813+ for upload in self.aggregator.files_uploading:
2814+ if upload.size != 0:
2815+ uploading.append((upload.path, upload.size,
2816+ upload.n_bytes_written))
2817+ return uploading
2818+
2819 def file_published(self, public_url):
2820 """A file was published."""
2821 status_event = FilePublishingStatus(new_public_url=public_url)
2822
2823=== modified file 'ubuntuone/syncdaemon/__init__.py'
2824--- ubuntuone/syncdaemon/__init__.py 2012-04-09 20:07:05 +0000
2825+++ ubuntuone/syncdaemon/__init__.py 2012-08-22 18:22:29 +0000
2826@@ -36,3 +36,8 @@
2827 "volumes",
2828 "generations",
2829 ])
2830+
2831+
2832+#Sync Menu data constants
2833+RECENT_TRANSFERS = 'recent-transfers'
2834+UPLOADING = 'uploading'
2835
2836=== modified file 'ubuntuone/syncdaemon/event_queue.py'
2837--- ubuntuone/syncdaemon/event_queue.py 2012-07-31 08:26:30 +0000
2838+++ ubuntuone/syncdaemon/event_queue.py 2012-08-22 18:22:29 +0000
2839@@ -159,6 +159,7 @@
2840
2841 'FSM_FILE_CONFLICT': ('old_name', 'new_name'),
2842 'FSM_DIR_CONFLICT': ('old_name', 'new_name'),
2843+ 'FSM_PARTIAL_COMMITED': ('share_id', 'node_id'),
2844
2845 'VM_UDF_SUBSCRIBED': ('udf',),
2846 'VM_UDF_SUBSCRIBE_ERROR': ('udf_id', 'error'),
2847
2848=== modified file 'ubuntuone/syncdaemon/filesystem_manager.py'
2849--- ubuntuone/syncdaemon/filesystem_manager.py 2012-06-22 11:29:10 +0000
2850+++ ubuntuone/syncdaemon/filesystem_manager.py 2012-08-22 18:22:29 +0000
2851@@ -1142,7 +1142,7 @@
2852 return fd
2853
2854 def commit_partial(self, node_id, share_id, local_hash):
2855- """Create a .partial in disk and set the flag in metadata."""
2856+ """Commit a file from a .partial to disk."""
2857 mdid = self._idx_node_id[(share_id, node_id)]
2858 mdobj = self.fs[mdid]
2859 if mdobj["is_dir"]:
2860@@ -1166,6 +1166,8 @@
2861 mdobj["info"]["is_partial"] = False
2862 mdobj["stat"] = get_stat(path)
2863 self.fs[mdid] = mdobj
2864+ self.eq.push("FSM_PARTIAL_COMMITED", share_id=share_id,
2865+ node_id=node_id)
2866
2867 def remove_partial(self, node_id, share_id):
2868 """Remove a .partial in disk and set the flag in metadata."""
2869
2870=== modified file 'ubuntuone/syncdaemon/interaction_interfaces.py'
2871--- ubuntuone/syncdaemon/interaction_interfaces.py 2012-05-22 14:07:55 +0000
2872+++ ubuntuone/syncdaemon/interaction_interfaces.py 2012-08-22 18:22:29 +0000
2873@@ -302,6 +302,10 @@
2874 waiting_content.append(data)
2875 return waiting_content
2876
2877+ def sync_menu(self):
2878+ """Return the info necessary to construct the menu."""
2879+ return self.main.status_listener.menu_data()
2880+
2881
2882 class SyncdaemonFileSystem(SyncdaemonObject):
2883 """An interface to the FileSystem Manager."""
2884@@ -816,8 +820,8 @@
2885 self._path_from_ids(share_id, node_id, 'DownloadFileProgress', info)
2886
2887 @log_call(logger.debug)
2888- def handle_AQ_DOWNLOAD_FINISHED(self, share_id, node_id, server_hash):
2889- """Handle AQ_DOWNLOAD_FINISHED."""
2890+ def handle_FSM_PARTIAL_COMMITED(self, share_id, node_id):
2891+ """Handle FSM_PARTIAL_COMMITED."""
2892 self._path_from_ids(share_id, node_id, 'DownloadFinished', info={})
2893
2894 @log_call(logger.debug)
2895
2896=== modified file 'ubuntuone/syncdaemon/status_listener.py'
2897--- ubuntuone/syncdaemon/status_listener.py 2012-04-09 20:07:05 +0000
2898+++ ubuntuone/syncdaemon/status_listener.py 2012-08-22 18:22:29 +0000
2899@@ -31,7 +31,12 @@
2900 """Listener for event queue that updates the UI to show syncdaemon status."""
2901
2902 from ubuntuone.status.aggregator import StatusFrontend
2903-from ubuntuone.syncdaemon import action_queue, config
2904+from ubuntuone.syncdaemon import (
2905+ action_queue,
2906+ config,
2907+ RECENT_TRANSFERS,
2908+ UPLOADING,
2909+)
2910 from ubuntuone.syncdaemon.interaction_interfaces import (
2911 get_share_dict, get_udf_dict)
2912 from ubuntuone.syncdaemon.volume_manager import UDF, Root
2913@@ -66,6 +71,13 @@
2914 user_conf = config.get_user_config()
2915 self.show_all_notifications = user_conf.get_show_all_notifications()
2916
2917+ def menu_data(self):
2918+ """Return the info necessary to construct the sync menu."""
2919+ uploading = self.status_frontend.files_uploading()
2920+ transfers = self.status_frontend.recent_transfers()
2921+ data = {RECENT_TRANSFERS: transfers, UPLOADING: uploading}
2922+ return data
2923+
2924 def get_show_all_notifications(self):
2925 """Get the value of show_all_notifications."""
2926 return self._show_all_notifications
2927
2928=== modified file 'ubuntuone/syncdaemon/volume_manager.py'
2929--- ubuntuone/syncdaemon/volume_manager.py 2012-05-14 21:24:24 +0000
2930+++ ubuntuone/syncdaemon/volume_manager.py 2012-08-22 18:22:29 +0000
2931@@ -1207,6 +1207,10 @@
2932 if is_link(path):
2933 return (False, "UDFs can not be a symlink")
2934
2935+ # check if path exists but is not a directory
2936+ if path_exists(path) and not os.path.isdir(path):
2937+ return (False, "The path exists but is not a folder")
2938+
2939 # check if the path it's ok (outside root and
2940 # isn't a ancestor or child of another UDF)
2941 if self._is_nested_udf(path):

Subscribers

People subscribed via source and target branches

to all changes: