Merge lp:~diegosarmentero/ubuntuone-client/darwin-tests-refactoring into lp:ubuntuone-client

Proposed by Diego Sarmentero on 2012-07-03
Status: Merged
Approved by: Alejandro J. Cura on 2012-08-07
Approved revision: 1289
Merged at revision: 1287
Proposed branch: lp:~diegosarmentero/ubuntuone-client/darwin-tests-refactoring
Merge into: lp:ubuntuone-client
Prerequisite: lp:~diegosarmentero/ubuntuone-client/darwin4-fsevents
Diff against target: 2036 lines (+569/-694)
11 files modified
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_windows.py (+344/-0)
ubuntuone/platform/filesystem_notifications/monitor/__init__.py (+3/-0)
ubuntuone/platform/filesystem_notifications/monitor/common.py (+1/-0)
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)
To merge this branch: bzr merge lp:~diegosarmentero/ubuntuone-client/darwin-tests-refactoring
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) 2012-07-03 Approve on 2012-08-02
Manuel de la Peña (community) Approve on 2012-07-19
Review via email: mp+113289@code.launchpad.net

Commit Message

- Refactoring test for filesystem notifications

Description of the Change

Put together the shared code between darwin and windows.

To post a comment you must log in.
Alejandro J. Cura (alecu) wrote :

Great branch so far!

A few comments:
---

Why is self._assert_logs removed from many places in darwin.py?

---

There is no need for the empty setUp in TestNotifyProcessor.

review: Needs Information
Manuel de la Peña (mandel) wrote :

Lint:

PYTHONPATH=""::.:."" SRCDIR="." USE_PYFLAKES="true" u1lint
== Python Lint Notices ==

./ubuntuone/platform/filesystem_notifications/common.py:
    37: 'IN_MODIFY' imported but unused

make: *** [lint] Error 1

review: Needs Fixing
Manuel de la Peña (mandel) wrote :

Why are there some tests that are raising a not implemented error? Should they either be implemented (the tests) or not be there or be skipped?

review: Needs Information
Manuel de la Peña (mandel) wrote :

Do we still need the mask in the common code?

79 + self.mask = None

I mean, we never test on windows different masks, maybe a good way to simplify and unify the tests is to simply remove its need, right?

I really don't like code doing thins like this:

54 +filesystem_notifications = None
55 +NotifyProcessor = None
56 +Watch = None
57 +WatchManager = None
58 +get_os_valid_path = lambda x: x
59 +create_fake_event = None
60 +custom_process_events = None

This is the same issue we had with the common.py implementation, can't we do the same? Having windows and darwin set those values smells a little.

review: Needs Fixing
Manuel de la Peña (mandel) wrote :

Minor things:

+for key, value in filesystem_notifications.common.ACTIONS.iteritems():

can we use items, is less efficient but will make the work to port it to python3 easier.

The following confuses me:

+from ubuntuone.platform import os_helper
+get_os_valid_path = os_helper.get_os_valid_path

Can't we do:

from ubuntuone.platfor.os_helper import get_os_falid_path

Same comment for:

4 +NotifyProcessor = filesystem_notifications.common.NotifyProcessor
55 +Watch = filesystem_notifications.common.Watch
56 +WatchManager = filesystem_notifications.common.WatchManager

Can't we just import either common or wach of the objects form common?

Why was the timeout removed?

757 - timeout = 5

Ae we going to use the defaul twisted trial timeout, that is too long right?

Why is this back in common?

2306 + IN_MODIFY as in_modify,
2307 IN_MOVED_FROM,
2308 IN_MOVED_TO,
2309 )
2310 @@ -66,6 +67,12 @@
2311 else:
2312 raise ImportError('Not supported platform')
2313
2314 +
2315 +# This is done to avoid lint issues with pyflakes.
2316 +# And because all the other IN_* are being consumed from this module,
2317 +# it would be best if we do the same with IN_MODIFY.
2318 +IN_MODIFY = in_modify

I though we removed it and we not longer had issues with it.

review: Needs Fixing
Diego Sarmentero (diegosarmentero) wrote :

> Minor things:
>
> +for key, value in filesystem_notifications.common.ACTIONS.iteritems():
>
> can we use items, is less efficient but will make the work to port it to
> python3 easier.
>
> The following confuses me:
>
> +from ubuntuone.platform import os_helper
> +get_os_valid_path = os_helper.get_os_valid_path
>
> Can't we do:
>
> from ubuntuone.platfor.os_helper import get_os_falid_path
>
> Same comment for:
>
> 4 +NotifyProcessor = filesystem_notifications.common.NotifyProcessor
> 55 +Watch = filesystem_notifications.common.Watch
> 56 +WatchManager = filesystem_notifications.common.WatchManager
>
> Can't we just import either common or wach of the objects form common?
>
> Why was the timeout removed?
>
> 757 - timeout = 5
>
> Ae we going to use the defaul twisted trial timeout, that is too long right?

Fixed!

>
> Why is this back in common?
>
> 2306 + IN_MODIFY as in_modify,
> 2307 IN_MOVED_FROM,
> 2308 IN_MOVED_TO,
> 2309 )
> 2310 @@ -66,6 +67,12 @@
> 2311 else:
> 2312 raise ImportError('Not supported platform')
> 2313
> 2314 +
> 2315 +# This is done to avoid lint issues with pyflakes.
> 2316 +# And because all the other IN_* are being consumed from this module,
> 2317 +# it would be best if we do the same with IN_MODIFY.
> 2318 +IN_MODIFY = in_modify
>
> I though we removed it and we not longer had issues with it.

That should be there, if we remove that we are going to have pyflakes issues.

Manuel de la Peña (mandel) wrote :

Looks good to me.

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

After recent branches that landed on trunk this branch is giving merge errors.

review: Needs Fixing
Alejandro J. Cura (alecu) wrote :

Branch looks good now. Thanks a lot for working on this!

review: Approve
Ubuntu One Auto Pilot (otto-pilot) wrote :
Download full text (254.3 KiB)

The attempt to merge lp:~diegosarmentero/ubuntuone-client/darwin-tests-refactoring into lp:ubuntuone-client 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 ...

Ubuntu One Auto Pilot (otto-pilot) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'run-mac-tests'
2--- run-mac-tests 2012-07-30 19:31:32 +0000
3+++ run-mac-tests 2012-08-06 16:57:22 +0000
4@@ -27,7 +27,7 @@
5 # version. If you delete this exception statement from all source
6 # files in the program, then also delete it here.
7
8-PYTHONPATH=../ubuntu-sso-client/:../ubuntuone-storage-protocol:../ubuntuone-dev-tools:$PYTHONPATH
9+PYTHONPATH=../ubuntu-sso-client/:../ubuntuone-storage-protocol:../ubuntuone-dev-tools:../ubuntuone-fsevents-daemon/python:$PYTHONPATH
10
11 set -e
12 if [ $# -ne 0 ]; then
13
14=== renamed file 'tests/platform/filesystem_notifications/test_windows.py' => 'tests/platform/filesystem_notifications/common.py'
15--- tests/platform/filesystem_notifications/test_windows.py 2012-07-18 15:18:04 +0000
16+++ tests/platform/filesystem_notifications/common.py 2012-08-06 16:57:22 +0000
17@@ -38,42 +38,45 @@
18 import itertools
19
20 from twisted.internet import defer
21-from win32file import FILE_NOTIFY_INFORMATION
22-
23 from contrib.testing.testcase import BaseTwistedTestCase
24 from ubuntuone.devtools.handlers import MementoHandler
25-from ubuntuone.platform.os_helper import windows as os_helper
26 from ubuntuone.platform.filesystem_notifications.pyinotify_agnostic import (
27+ EventsCodes,
28 ProcessEvent,
29 IN_CLOSE_WRITE,
30 IN_CREATE,
31 IN_DELETE,
32 IN_OPEN,
33 )
34-from ubuntuone.platform.filesystem_notifications.monitor import (
35- windows as filesystem_notifications,
36-)
37 from ubuntuone.platform.filesystem_notifications import notify_processor
38 from ubuntuone.platform.filesystem_notifications.monitor.common import (
39 FilesystemMonitor,
40 Watch,
41 WatchManager,
42 )
43-from ubuntuone.platform.filesystem_notifications.monitor.windows import (
44- ACTIONS,
45- FILE_NOTIFY_CHANGE_FILE_NAME,
46- FILE_NOTIFY_CHANGE_DIR_NAME,
47- FILE_NOTIFY_CHANGE_ATTRIBUTES,
48- FILE_NOTIFY_CHANGE_SIZE,
49- FILE_NOTIFY_CHANGE_LAST_WRITE,
50- FILE_NOTIFY_CHANGE_SECURITY,
51- FILE_NOTIFY_CHANGE_LAST_ACCESS,
52-)
53+from ubuntuone.platform.filesystem_notifications.monitor import ACTIONS
54+from ubuntuone.platform.os_helper import get_os_valid_path
55+
56+OP_FLAGS = EventsCodes.FLAG_COLLECTIONS['OP_FLAGS']
57+IS_DIR = EventsCodes.FLAG_COLLECTIONS['SPECIAL_FLAGS']['IN_ISDIR']
58
59 #create a rever mapping to use it in the tests.
60-REVERSE_WINDOWS_ACTIONS = {}
61-for key, value in ACTIONS.iteritems():
62- REVERSE_WINDOWS_ACTIONS[value] = key
63+REVERSE_OS_ACTIONS = {}
64+for key, value in ACTIONS.items():
65+ REVERSE_OS_ACTIONS[value] = key
66+
67+
68+class FakeEventsProcessor(object):
69+
70+ """Handle fake events creation and processing."""
71+
72+ def create_fake_event(self):
73+ """Create a fake filesystem event."""
74+ raise NotImplementedError
75+
76+ def custom_process_events(self):
77+ """Process a fake event."""
78+ raise NotImplementedError
79
80
81 class FakeException(Exception):
82@@ -127,32 +130,17 @@
83 @defer.inlineCallbacks
84 def setUp(self):
85 yield super(TestWatch, self).setUp()
86+ self.path = ''
87+ self.invalid_path = ''
88+ self.common_path = ''
89 self.basedir = self.mktemp('test_root')
90- self.mask = FILE_NOTIFY_CHANGE_FILE_NAME | \
91- FILE_NOTIFY_CHANGE_DIR_NAME | \
92- FILE_NOTIFY_CHANGE_ATTRIBUTES | \
93- FILE_NOTIFY_CHANGE_SIZE | \
94- FILE_NOTIFY_CHANGE_LAST_WRITE | \
95- FILE_NOTIFY_CHANGE_SECURITY | \
96- FILE_NOTIFY_CHANGE_LAST_ACCESS
97+ self.mask = None
98 self.memento = MementoHandler()
99 self.memento.setLevel(logging.DEBUG)
100 self.raw_events = []
101 self.paths_checked = []
102 old_is_dir = Watch._path_is_dir
103-
104- def file_notify_information_wrapper(buf, data):
105- """Wrapper that gets the events and adds them to the list."""
106- events = FILE_NOTIFY_INFORMATION(buf, data)
107- # we want to append the list because that is what will be logged.
108- # If we use extend we wont have the same logging because it will
109- # group all events in a single lists which is not what the COM API
110- # does.
111- str_events = [
112- (filesystem_notifications.ACTIONS_NAMES[action], path) for action, path in
113- events]
114- self.raw_events.append(str_events)
115- return events
116+ self.fake_events_processor = FakeEventsProcessor()
117
118 def path_is_dir_wrapper(watch, path):
119 """Wrapper that gets the checked paths."""
120@@ -160,8 +148,6 @@
121 self.paths_checked.append((path, result))
122 return result
123
124- self.patch(filesystem_notifications, 'FILE_NOTIFY_INFORMATION',
125- file_notify_information_wrapper)
126 self.patch(Watch, '_path_is_dir', path_is_dir_wrapper)
127
128 @defer.inlineCallbacks
129@@ -169,7 +155,7 @@
130 """Perform the file operations and returns the recorded events."""
131 handler = TestCaseHandler(number_events=number_events)
132 manager = WatchManager(handler)
133- yield manager.add_watch(os_helper.get_windows_valid_path(path), mask)
134+ yield manager.add_watch(get_os_valid_path(path), mask)
135 # change the logger so that we can check the logs if we wanted
136 manager._wdm[0].log.addHandler(self.memento)
137 # clean logger later
138@@ -198,7 +184,7 @@
139 create_file, 1)
140 event = events[0]
141 self.assertFalse(event.dir)
142- self.assertEqual(0x100, event.mask)
143+ self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
144 self.assertEqual('IN_CREATE', event.maskname)
145 self.assertEqual(os.path.split(file_name)[1], event.name)
146 self.assertEqual('.', event.path)
147@@ -218,7 +204,7 @@
148 create_dir, 1)
149 event = events[0]
150 self.assertTrue(event.dir)
151- self.assertEqual(0x40000100, event.mask)
152+ self.assertEqual(OP_FLAGS['IN_CREATE'] | IS_DIR, event.mask)
153 self.assertEqual('IN_CREATE|IN_ISDIR', event.maskname)
154 self.assertEqual(os.path.split(dir_name)[1], event.name)
155 self.assertEqual('.', event.path)
156@@ -240,7 +226,7 @@
157 remove_file, 1)
158 event = events[0]
159 self.assertFalse(event.dir)
160- self.assertEqual(0x200, event.mask)
161+ self.assertEqual(OP_FLAGS['IN_DELETE'], event.mask)
162 self.assertEqual('IN_DELETE', event.maskname)
163 self.assertEqual(os.path.split(file_name)[1], event.name)
164 self.assertEqual('.', event.path)
165@@ -262,36 +248,15 @@
166 remove_dir, 1)
167 event = events[0]
168 self.assertTrue(event.dir)
169- self.assertEqual(0x40000200, event.mask)
170+ self.assertEqual(OP_FLAGS['IN_DELETE'] | IS_DIR, event.mask)
171 self.assertEqual('IN_DELETE|IN_ISDIR', event.maskname)
172 self.assertEqual('.', event.path)
173 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
174 self.assertEqual(0, event.wd)
175
176- @defer.inlineCallbacks
177 def test_file_write(self):
178 """Test that the correct event is raised when a file is written."""
179- file_name = os.path.join(self.basedir, 'test_file_write')
180- # create the file before recording
181- fd = open(file_name, 'w')
182- # clean behind us by removing the file
183- self.addCleanup(os.remove, file_name)
184-
185- def write_file():
186- """Action for the test."""
187- fd.write('test')
188- fd.close()
189-
190- events = yield self._perform_operations(self.basedir, self.mask,
191- write_file, 1)
192- event = events[0]
193- self.assertFalse(event.dir)
194- self.assertEqual(0x2, event.mask)
195- self.assertEqual('IN_MODIFY', event.maskname)
196- self.assertEqual(os.path.split(file_name)[1], event.name)
197- self.assertEqual('.', event.path)
198- self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
199- self.assertEqual(0, event.wd)
200+ raise NotImplementedError
201
202 @defer.inlineCallbacks
203 def test_file_moved_to_watched_dir_same_watcher(self):
204@@ -313,7 +278,7 @@
205 move_to_event = events[1]
206 # first test the move from
207 self.assertFalse(move_from_event.dir)
208- self.assertEqual(0x40, move_from_event.mask)
209+ self.assertEqual(OP_FLAGS['IN_MOVED_FROM'], move_from_event.mask)
210 self.assertEqual('IN_MOVED_FROM', move_from_event.maskname)
211 self.assertEqual(os.path.split(from_file_name)[1],
212 move_from_event.name)
213@@ -323,7 +288,7 @@
214 self.assertEqual(0, move_from_event.wd)
215 # test the move to
216 self.assertFalse(move_to_event.dir)
217- self.assertEqual(0x80, move_to_event.mask)
218+ self.assertEqual(OP_FLAGS['IN_MOVED_TO'], move_to_event.mask)
219 self.assertEqual('IN_MOVED_TO', move_to_event.maskname)
220 self.assertEqual(os.path.split(to_file_name)[1], move_to_event.name)
221 self.assertEqual('.', move_to_event.path)
222@@ -354,7 +319,7 @@
223 move_file, 1)
224 event = events[0]
225 self.assertFalse(event.dir)
226- self.assertEqual(0x200, event.mask)
227+ self.assertEqual(OP_FLAGS['IN_DELETE'], event.mask)
228 self.assertEqual('IN_DELETE', event.maskname)
229 self.assertEqual(os.path.split(from_file_name)[1], event.name)
230 self.assertEqual('.', event.path)
231@@ -382,7 +347,7 @@
232 move_files, 1)
233 event = events[0]
234 self.assertFalse(event.dir)
235- self.assertEqual(0x100, event.mask)
236+ self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
237 self.assertEqual('IN_CREATE', event.maskname)
238 self.assertEqual(os.path.split(to_file_name)[1], event.name)
239 self.assertEqual('.', event.path)
240@@ -409,7 +374,8 @@
241 move_to_event = events[1]
242 # first test the move from
243 self.assertTrue(move_from_event.dir)
244- self.assertEqual(0x40000040, move_from_event.mask)
245+ self.assertEqual(OP_FLAGS['IN_MOVED_FROM'] | IS_DIR,
246+ move_from_event.mask)
247 self.assertEqual('IN_MOVED_FROM|IN_ISDIR', move_from_event.maskname)
248 self.assertEqual(os.path.split(from_dir_name)[1], move_from_event.name)
249 self.assertEqual('.', move_from_event.path)
250@@ -418,7 +384,7 @@
251 self.assertEqual(0, move_from_event.wd)
252 # test the move to
253 self.assertTrue(move_to_event.dir)
254- self.assertEqual(0x40000080, move_to_event.mask)
255+ self.assertEqual(OP_FLAGS['IN_MOVED_TO'] | IS_DIR, move_to_event.mask)
256 self.assertEqual('IN_MOVED_TO|IN_ISDIR', move_to_event.maskname)
257 self.assertEqual(os.path.split(to_dir_name)[1], move_to_event.name)
258 self.assertEqual('.', move_to_event.path)
259@@ -447,7 +413,7 @@
260 move_dir, 1)
261 event = events[0]
262 self.assertTrue(event.dir)
263- self.assertEqual(0x40000200, event.mask)
264+ self.assertEqual(OP_FLAGS['IN_DELETE'] | IS_DIR, event.mask)
265 self.assertEqual('IN_DELETE|IN_ISDIR', event.maskname)
266 self.assertEqual('.', event.path)
267 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
268@@ -471,7 +437,7 @@
269 move_dir, 1)
270 event = events[0]
271 self.assertTrue(event.dir)
272- self.assertEqual(0x40000100, event.mask)
273+ self.assertEqual(OP_FLAGS['IN_CREATE'] | IS_DIR, event.mask)
274 self.assertEqual('IN_CREATE|IN_ISDIR', event.maskname)
275 self.assertEqual(os.path.split(from_dir_name)[1], event.name)
276 self.assertEqual('.', event.path)
277@@ -484,8 +450,9 @@
278 handler = TestCaseHandler(number_events=0)
279 manager = WatchManager(handler)
280 # add a watch that will always exclude all actions
281- manager.add_watch(os_helper.get_windows_valid_path(self.basedir),
282- self.mask, exclude_filter=lambda x: True)
283+ manager.add_watch(get_os_valid_path(self.basedir),
284+ self.mask, auto_add=True,
285+ exclude_filter=lambda x: True)
286 # execution the actions
287 file_name = os.path.join(self.basedir, 'test_file_create')
288 open(file_name, 'w').close()
289@@ -502,16 +469,18 @@
290 """Memorize the processed events."""
291 events.append(event)
292
293- path = u'\\\\?\\C:\\path' # a valid windows path
294- child = u'child'
295- watch = Watch(1, path, fake_processor)
296- watch.ignore_path(os.path.join(path, child))
297+ child = 'child'
298+ watch = Watch(1, self.path, None)
299+ watch.ignore_path(os.path.join(self.path, child))
300 paths_to_ignore = []
301 for file_name in 'abcdef':
302- paths_to_ignore.append((1, os.path.join(child, file_name)))
303+ paths_to_ignore.append(
304+ self.fake_events_processor.create_fake_event(
305+ os.path.join(child, file_name)))
306 # ensure that the watch is watching
307- watch._watching = True
308- watch.platform_watch._process_events(paths_to_ignore)
309+ watch.platform_watch.watching = True
310+ self.fake_events_processor.custom_process_events(
311+ watch, paths_to_ignore)
312 self.assertEqual(0, len(events),
313 'All events should have been ignored.')
314
315@@ -523,17 +492,18 @@
316 """Memorize the processed events."""
317 events.append(event)
318
319- path = u'\\\\?\\C:\\path' # a valid windows path
320- child = u'child'
321- watch = Watch(1, path, fake_processor)
322- watch.ignore_path(os.path.join(path, child))
323+ child = 'child'
324+ watch = Watch(1, self.path, fake_processor)
325+ watch.ignore_path(os.path.join(self.path, child))
326 paths_not_to_ignore = []
327 for file_name in 'abcdef':
328- paths_not_to_ignore.append((1, os.path.join(
329- child + file_name, file_name)))
330+ event = self.fake_events_processor.create_fake_event(
331+ os.path.join(child + file_name, file_name))
332+ paths_not_to_ignore.append(event)
333 # ensure that the watch is watching
334 watch.platform_watch.watching = True
335- watch.platform_watch._process_events(paths_not_to_ignore)
336+ self.fake_events_processor.custom_process_events(
337+ watch, paths_not_to_ignore)
338 self.assertEqual(len(paths_not_to_ignore), len(events),
339 'No events should have been ignored.')
340
341@@ -545,21 +515,22 @@
342 """Memorize the processed events."""
343 events.append(event.pathname)
344
345- child = u'child'
346- path = u'\\\\?\\C:\\path\\' # a valid windows path
347- watch = Watch(1, path, fake_processor)
348- watch.ignore_path(os.path.join(path, child))
349+ child = 'child'
350+ watch = Watch(1, self.path, fake_processor)
351+ watch.ignore_path(os.path.join(self.path, child))
352 paths_not_to_ignore = []
353 paths_to_ignore = []
354 expected_events = []
355 for file_name in 'abcdef':
356 valid = os.path.join(child + file_name, file_name)
357 paths_to_ignore.append((1, os.path.join(child, file_name)))
358- paths_not_to_ignore.append((1, valid))
359- expected_events.append(os.path.join('C:\\path', valid))
360+ paths_not_to_ignore.append(
361+ self.fake_events_processor.create_fake_event(valid))
362+ expected_events.append(os.path.join(self.common_path, valid))
363 # ensure that the watch is watching
364 watch.platform_watch.watching = True
365- watch.platform_watch._process_events(paths_not_to_ignore)
366+ self.fake_events_processor.custom_process_events(
367+ watch, paths_not_to_ignore)
368 self.assertEqual(len(paths_not_to_ignore), len(events),
369 'Wrong number of events ignored.')
370 self.assertTrue(all([event in expected_events for event in events]),
371@@ -573,17 +544,19 @@
372 """Memorize the processed events."""
373 events.append(event)
374
375- path = u'\\\\?\\C:\\path' # a valid windows path
376- child = u'child'
377- watch = Watch(1, path, fake_processor)
378- watch.ignore_path(os.path.join(path, child))
379- watch.remove_ignored_path(os.path.join(path, child))
380+ child = 'child'
381+ watch = Watch(1, self.path, fake_processor)
382+ watch.ignore_path(os.path.join(self.path, child))
383+ watch.remove_ignored_path(os.path.join(self.path, child))
384 paths_not_to_ignore = []
385 for file_name in 'abcdef':
386- paths_not_to_ignore.append((1, os.path.join(child, file_name)))
387+ event = self.fake_events_processor.create_fake_event(
388+ os.path.join(child, file_name))
389+ paths_not_to_ignore.append(event)
390 # ensure that the watch is watching
391 watch.platform_watch.watching = True
392- watch.platform_watch._process_events(paths_not_to_ignore)
393+ self.fake_events_processor.custom_process_events(
394+ watch, paths_not_to_ignore)
395 self.assertEqual(len(paths_not_to_ignore), len(events),
396 'All events should have been accepted.')
397
398@@ -595,190 +568,98 @@
399 """Memorize the processed events."""
400 events.append(event.pathname)
401
402- path = u'\\\\?\\C:\\path' # a valid windows path
403- child_a = u'childa'
404- child_b = u'childb'
405- watch = Watch(1, path, fake_processor)
406- watch.ignore_path(os.path.join(path, child_a))
407- watch.ignore_path(os.path.join(path, child_b))
408- watch.remove_ignored_path(os.path.join(path, child_a))
409+ child_a = 'childa'
410+ child_b = 'childb'
411+ watch = Watch(1, self.path, fake_processor)
412+ watch.ignore_path(os.path.join(self.path, child_a))
413+ watch.ignore_path(os.path.join(self.path, child_b))
414+ watch.remove_ignored_path(os.path.join(self.path, child_a))
415 paths_to_ignore = []
416 paths_not_to_ignore = []
417 expected_events = []
418 for file_name in 'abcdef':
419 paths_to_ignore.append((1, os.path.join(child_b, file_name)))
420 valid = os.path.join(child_a, file_name)
421- paths_not_to_ignore.append((1, valid))
422- expected_events.append(os.path.join('C:\\path', valid))
423+ event = self.fake_events_processor.create_fake_event(valid)
424+ paths_not_to_ignore.append(event)
425+ expected_events.append(os.path.join(self.common_path, valid))
426 # ensure that the watch is watching
427 watch.platform_watch.watching = True
428- watch.platform_watch._process_events(paths_not_to_ignore)
429+ self.fake_events_processor.custom_process_events(
430+ watch, paths_not_to_ignore)
431 self.assertEqual(len(paths_not_to_ignore), len(events),
432 'All events should have been accepted.')
433 self.assertTrue(all([event in expected_events for event in events]),
434 'Paths ignored that should have not been ignored.')
435
436- @defer.inlineCallbacks
437- def test_call_deferred_already_called(self):
438- """Test that the function is not called."""
439- method_args = []
440-
441- def fake_call(*args, **kwargs):
442- """Execute the call."""
443- method_args.append((args, kwargs),)
444-
445- path = u'\\\\?\\C:\\path' # a valid windows path
446- watch = Watch(1, path, None)
447- yield watch.platform_watch._watch_started_deferred.callback(True)
448- watch.platform_watch._call_deferred(fake_call, None)
449- self.assertEqual(0, len(method_args))
450-
451- def test_call_deferred_not_called(self):
452- """Test that is indeed called."""
453- method_args = []
454-
455- def fake_call(*args, **kwargs):
456- """Execute the call."""
457- method_args.append((args, kwargs),)
458-
459- path = u'\\\\?\\C:\\path' # a valid windows path
460- watch = Watch(1, path, None)
461- watch.platform_watch._call_deferred(fake_call, None)
462- self.assertEqual(1, len(method_args))
463-
464- def test_started_property(self):
465- """Test that the started property returns the started deferred."""
466- path = u'\\\\?\\C:\\path' # a valid windows path
467- watch = Watch(1, path, None)
468- self.assertEqual(watch.started, watch.platform_watch._watch_started_deferred)
469-
470- def test_stopped_property(self):
471- """Test that the stopped property returns the stopped deferred."""
472- path = u'\\\\?\\C:\\path' # a valid windows path
473- watch = Watch(1, path, None)
474- self.assertEqual(watch.stopped, watch.platform_watch._watch_stopped_deferred)
475-
476 def random_error(self, *args):
477 """Throw a fake exception."""
478 raise FakeException()
479
480- @defer.inlineCallbacks
481- def test_start_watching_fails_early_in_thread(self):
482- """An early failure inside the thread should errback the deferred."""
483- test_path = self.mktemp("test_directory")
484- self.patch(filesystem_notifications, "CreateFileW", self.random_error)
485- watch = Watch(1, test_path, None)
486- d = watch.start_watching()
487- yield self.assertFailure(d, FakeException)
488-
489- @defer.inlineCallbacks
490- def test_start_watching_fails_late_in_thread(self):
491- """A late failure inside the thread should errback the deferred."""
492- test_path = self.mktemp("test_directory")
493- self.patch(filesystem_notifications, "ReadDirectoryChangesW",
494- self.random_error)
495- watch = Watch(1, test_path, None)
496- d = watch.start_watching()
497- yield self.assertFailure(d, FakeException)
498-
499- @defer.inlineCallbacks
500- def test_close_handle_is_called_on_error(self):
501- """CloseHandle is called when there's an error in the watch thread."""
502- test_path = self.mktemp("test_directory")
503- close_called = []
504- self.patch(filesystem_notifications, "CreateFileW", lambda *_: None)
505- self.patch(filesystem_notifications, "CloseHandle",
506- close_called.append)
507- self.patch(filesystem_notifications, "ReadDirectoryChangesW",
508- self.random_error)
509- watch = Watch(1, test_path, None)
510- d = watch.start_watching()
511- yield self.assertFailure(d, FakeException)
512- self.assertEqual(len(close_called), 1)
513- yield watch.stop_watching()
514-
515- @defer.inlineCallbacks
516- def test_stop_watching_fired_when_watch_thread_finishes(self):
517- """The deferred returned is fired when the watch thread finishes."""
518- test_path = self.mktemp("another_test_directory")
519- watch = Watch(1, test_path, None)
520- yield watch.start_watching()
521- self.assertNotEqual(watch.platform_watch._watch_handle, None)
522- yield watch.stop_watching()
523- self.assertEqual(watch.platform_watch._watch_handle, None)
524-
525 def test_is_path_dir_missing_no_subdir(self):
526 """Test when the path does not exist and is no a subdir."""
527- path = u'\\\\?\\C:\\path\\to\\no\\dir'
528 test_path = self.mktemp("test_directory")
529 self.patch(os.path, 'exists', lambda path: False)
530 watch = Watch(1, test_path, None)
531- self.assertFalse(watch._path_is_dir(path))
532+ self.assertFalse(watch._path_is_dir(self.invalid_path))
533
534 def test_is_path_dir_missing_in_subdir(self):
535 """Test when the path does not exist and is a subdir."""
536- path = u'\\\\?\\C:\\path\\to\\no\\dir'
537 test_path = self.mktemp("test_directory")
538 self.patch(os.path, 'exists', lambda path: False)
539 watch = Watch(1, test_path, None)
540- watch._subdirs.add(path)
541- self.assertTrue(watch._path_is_dir(path))
542+ watch._subdirs.add(self.invalid_path)
543+ self.assertTrue(watch._path_is_dir(self.invalid_path))
544
545 def test_is_path_dir_present_is_dir(self):
546 """Test when the path is present and is dir."""
547- path = u'\\\\?\\C:\\path\\to\\no\\dir'
548 test_path = self.mktemp("test_directory")
549 self.patch(os.path, 'exists', lambda path: True)
550 self.patch(os.path, 'isdir', lambda path: True)
551 watch = Watch(1, test_path, None)
552- watch._subdirs.add(path)
553- self.assertTrue(watch._path_is_dir(path))
554+ watch._subdirs.add(self.invalid_path)
555+ self.assertTrue(watch._path_is_dir(self.invalid_path))
556
557 def test_is_path_dir_present_no_dir(self):
558 """Test when the path is present but not a dir."""
559- path = u'\\\\?\\C:\\path\\to\\no\\dir'
560 test_path = self.mktemp("test_directory")
561 self.patch(os.path, 'exists', lambda path: True)
562 self.patch(os.path, 'isdir', lambda path: False)
563 watch = Watch(1, test_path, None)
564- watch._subdirs.add(path)
565- self.assertFalse(watch._path_is_dir(path))
566+ watch._subdirs.add(self.invalid_path)
567+ self.assertFalse(watch._path_is_dir(self.invalid_path))
568
569 def test_update_subdirs_create_not_present(self):
570 """Test when we update on a create event and not present."""
571- path = u'\\\\?\\C:\\path\\to\\no\\dir'
572 test_path = self.mktemp("test_directory")
573 watch = Watch(1, test_path, None)
574- watch._update_subdirs(path, REVERSE_WINDOWS_ACTIONS[IN_CREATE])
575- self.assertTrue(path in watch._subdirs)
576+ watch._update_subdirs(self.invalid_path, REVERSE_OS_ACTIONS[IN_CREATE])
577+ self.assertTrue(self.invalid_path in watch._subdirs)
578
579 def test_update_subdirs_create_present(self):
580 """Test when we update on a create event and is present."""
581- path = u'\\\\?\\C:\\path\\to\\no\\dir'
582 test_path = self.mktemp("test_directory")
583 watch = Watch(1, test_path, None)
584- watch._subdirs.add(path)
585+ watch._subdirs.add(self.invalid_path)
586 old_length = len(watch._subdirs)
587- watch._update_subdirs(path, REVERSE_WINDOWS_ACTIONS[IN_CREATE])
588- self.assertTrue(path in watch._subdirs)
589+ watch._update_subdirs(self.invalid_path, REVERSE_OS_ACTIONS[IN_CREATE])
590+ self.assertTrue(self.invalid_path in watch._subdirs)
591 self.assertEqual(old_length, len(watch._subdirs))
592
593 def test_update_subdirs_delete_not_present(self):
594 """Test when we delete and is not present."""
595- path = u'\\\\?\\C:\\path\\to\\no\\dir'
596 test_path = self.mktemp("test_directory")
597 watch = Watch(1, test_path, None)
598- watch._update_subdirs(path, REVERSE_WINDOWS_ACTIONS[IN_DELETE])
599- self.assertTrue(path not in watch._subdirs)
600+ watch._update_subdirs(self.invalid_path, REVERSE_OS_ACTIONS[IN_DELETE])
601+ self.assertTrue(self.invalid_path not in watch._subdirs)
602
603 def test_update_subdirs_delete_present(self):
604 """Test when we delete and is present."""
605- path = u'\\\\?\\C:\\path\\to\\no\\dir'
606 test_path = self.mktemp("test_directory")
607 watch = Watch(1, test_path, None)
608- watch._subdirs.add(path)
609- watch._update_subdirs(path, REVERSE_WINDOWS_ACTIONS[IN_DELETE])
610- self.assertTrue(path not in watch._subdirs)
611+ watch._subdirs.add(self.invalid_path)
612+ watch._update_subdirs(self.invalid_path, REVERSE_OS_ACTIONS[IN_DELETE])
613+ self.assertTrue(self.invalid_path not in watch._subdirs)
614
615
616 class TestWatchManager(BaseTwistedTestCase):
617@@ -788,11 +669,8 @@
618 def setUp(self):
619 """Set each of the tests."""
620 yield super(TestWatchManager, self).setUp()
621- self.parent_path = u'\\\\?\\C:\\' # a valid windows path
622- self.path = self.parent_path + u'path'
623- self.watch = Watch(1, self.path, None)
624 self.manager = WatchManager(None)
625- self.manager._wdm = {1: self.watch}
626+ self.fake_events_processor = FakeEventsProcessor()
627
628 @defer.inlineCallbacks
629 def test_stop(self):
630@@ -808,25 +686,9 @@
631 yield self.manager.stop()
632 self.assertTrue(self.was_called, 'The watch stop should be called.')
633
634- @defer.inlineCallbacks
635 def test_stop_multiple(self):
636 """Test that stop is fired when *all* watches have stopped."""
637-
638- def fake_stop_watching(watch):
639- """Another fake stop watch."""
640- return watch.stopped
641-
642- self.patch(Watch, "stop_watching", fake_stop_watching)
643- second_path = self.parent_path + u"second_path"
644- second_watch = Watch(2, second_path, None)
645- self.manager._wdm[2] = second_watch
646- d = self.manager.stop()
647- self.assertFalse(d.called, "Not fired before all watches end")
648- self.watch.stopped.callback(None)
649- self.assertFalse(d.called, "Not fired before all watches end")
650- second_watch.stopped.callback(None)
651- yield d
652- self.assertTrue(d.called, "Fired after the watches ended")
653+ raise NotImplementedError
654
655 def test_get_present_watch(self):
656 """Test that we can get a Watch using is wd."""
657@@ -836,7 +698,6 @@
658 """Test that we get an error when trying to get a missing wd."""
659 self.assertRaises(KeyError, self.manager.get_watch, (1,))
660
661- @defer.inlineCallbacks
662 def test_delete_present_watch(self):
663 """Test that we can remove a present watch."""
664 self.was_called = False
665@@ -865,7 +726,6 @@
666 self.manager.add_watch(self.path, mask)
667 self.assertEqual(1, len(self.manager._wdm))
668 self.assertTrue(self.was_called, 'The watch start was not called.')
669- self.assertEqual(self.path + os.path.sep, self.manager._wdm[0].path)
670
671 def test_get_watch_present_wd(self):
672 """Test that the correct path is returned."""
673@@ -889,10 +749,8 @@
674 """A watch on an unwatched path returns None."""
675 self.assertEqual(None, self.manager.get_wd(self.parent_path))
676
677- @defer.inlineCallbacks
678 def test_rm_present_wd(self):
679 """Test the removal of a present watch."""
680-
681 def fake_stop_watching():
682 """Fake stop watch."""
683 return defer.succeed(True)
684@@ -913,8 +771,9 @@
685 self.manager.rm_path(self.path)
686 self.assertEqual(self.watch, self.manager._wdm.get(1))
687 self.watch._watching = True
688- self.watch.platform_watch._process_events(
689- [(1, os.path.join(self.path, 'test'))])
690+ event = self.fake_events_processor.create_fake_event(
691+ os.path.join(self.path, 'test'))
692+ self.fake_events_processor.custom_process_events(self.watch, [event])
693 self.assertEqual(0, len(events))
694
695 def test_rm_child_path(self):
696@@ -926,41 +785,27 @@
697 events.append(event.pathname)
698
699 self.watch._processor = fake_processor
700- child = os.path.join(self.path, u'child')
701+ child = os.path.join(self.path, 'child')
702 self.manager.rm_path(child)
703 self.assertEqual(self.watch, self.manager._wdm[1])
704 # assert that the correct event is ignored
705 self.watch.platform_watch.watching = True
706- self.watch.platform_watch._process_events(
707- [(1, os.path.join('child', 'test'))])
708+ event = self.fake_events_processor.create_fake_event(
709+ os.path.join('child', 'test'))
710+ self.fake_events_processor.custom_process_events(self.watch, [event])
711 self.assertEqual(0, len(events))
712 # assert that other events are not ignored
713- self.watch.platform_watch._process_events([(1, 'test')])
714+ event2 = self.fake_events_processor.create_fake_event('test')
715+ self.fake_events_processor.custom_process_events(self.watch, [event2])
716 self.assertEqual(1, len(events))
717
718
719 class TestWatchManagerAddWatches(BaseTwistedTestCase):
720 """Test the watch manager."""
721- timeout = 5
722
723 def test_add_watch_twice(self):
724 """Adding a watch twice succeeds when the watch is running."""
725- self.patch(Watch, "start_watching", lambda self: self.started)
726- manager = WatchManager(None)
727- # no need to stop watching because start_watching is fake
728-
729- path = u'\\\\?\\C:\\test' # a valid windows path
730- mask = 'fake bit mask'
731- d1 = manager.add_watch(path, mask)
732- d2 = manager.add_watch(path, mask)
733-
734- self.assertFalse(d1.called, "Should not be called yet.")
735- self.assertFalse(d2.called, "Should not be called yet.")
736-
737- manager._wdm.values()[0].started.callback(True)
738-
739- self.assertTrue(d1.called, "Should already be called.")
740- self.assertTrue(d2.called, "Should already be called.")
741+ raise NotImplementedError
742
743
744 class FakeEvent(object):
745@@ -1083,16 +928,6 @@
746 self.assertEqual(event, self.general.called_methods[0][1])
747 self.assertEqual(paths, self.general.called_methods[0][2])
748
749- def test_platform_is_ignored(self):
750- """Test that we do indeed ignore the correct paths."""
751- not_ignored = 'test'
752- ignored = not_ignored + '.lnk'
753- path_is_ignored = notify_processor.common.path_is_ignored
754- self.assertFalse(path_is_ignored(not_ignored),
755- 'Only links should be ignored.')
756- self.assertTrue(path_is_ignored(ignored),
757- 'Links should be ignored.')
758-
759 def test_is_ignored(self):
760 """Test that we do ensure that the path is ignored."""
761 path = 'path'
762@@ -1406,31 +1241,15 @@
763
764 class FilesystemMonitorTestCase(BaseTwistedTestCase):
765 """Tests for the FilesystemMonitor."""
766+
767 timeout = 5
768
769 def test_add_watch_twice(self):
770 """Check the deferred returned by a second add_watch."""
771- self.patch(Watch, "start_watching", lambda self: self.started)
772- monitor = FilesystemMonitor(None, None)
773- # no need to stop watching because start_watching is fake
774-
775- parent_path = 'C:\\test' # a valid windows path in utf-8 bytes
776- child_path = parent_path + "\\child"
777- d1 = monitor.add_watch(parent_path)
778- d2 = monitor.add_watch(child_path)
779-
780- self.assertFalse(d1.called, "Should not be called yet.")
781- self.assertFalse(d2.called, "Should not be called yet.")
782-
783- monitor._watch_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-
788- @defer.inlineCallbacks
789+ raise NotImplementedError
790+
791 def test_add_watches_to_udf_ancestors(self):
792 """Test that the ancestor watches are not added."""
793-
794 class FakeVolume(object):
795 """A fake UDF."""
796
797
798=== modified file 'tests/platform/filesystem_notifications/test_darwin.py'
799--- tests/platform/filesystem_notifications/test_darwin.py 2012-07-18 15:18:04 +0000
800+++ tests/platform/filesystem_notifications/test_darwin.py 2012-08-06 16:57:22 +0000
801@@ -28,16 +28,13 @@
802 # files in the program, then also delete it here.
803 """Test the filesystem notifications on MAC OS."""
804
805+import itertools
806 import logging
807 import os
808 import tempfile
809 import thread
810-import itertools
811
812-import fsevents
813 from twisted.internet import defer
814-
815-from contrib.testing.testcase import BaseTwistedTestCase
816 from ubuntuone.devtools.handlers import MementoHandler
817 from ubuntuone.platform.filesystem_notifications.monitor import (
818 common,
819@@ -51,7 +48,6 @@
820 WatchManager,
821 )
822 from ubuntuone.platform.filesystem_notifications.pyinotify_agnostic import (
823- EventsCodes,
824 ProcessEvent,
825 IN_CLOSE_WRITE,
826 IN_CREATE,
827@@ -59,6 +55,7 @@
828 IN_OPEN,
829 )
830 from tests.platform.filesystem_notifications import BaseFSMonitorTestCase
831+from tests.platform.filesystem_notifications import common as common_tests
832
833
834 # A reverse mapping for the tests
835@@ -67,23 +64,18 @@
836 REVERSE_MACOS_ACTIONS[value] = key
837
838
839-OP_FLAGS = EventsCodes.FLAG_COLLECTIONS['OP_FLAGS']
840-IS_DIR = EventsCodes.FLAG_COLLECTIONS['SPECIAL_FLAGS']['IN_ISDIR']
841-
842-
843-class FakeException(Exception):
844- """A fake Exception used in tests."""
845-
846-
847-class FakeVolume(object):
848- """A fake volume."""
849-
850- def __init__(self, path, ancestors):
851- """Create a new instance."""
852- super(FakeVolume, self).__init__()
853- self.volume_id = path
854- self.path = path
855- self.ancestors = ancestors
856+class FakeEventsProcessor(object):
857+
858+ """Handle fake events creation and processing."""
859+
860+ def create_fake_event(self, filename):
861+ """Create a fake file event."""
862+ return FakeFileEvent(256, None, filename)
863+
864+ def custom_process_events(self, watch, events):
865+ """Adapt to each platform way to process events."""
866+ for event in events:
867+ watch.platform_watch._process_events(event)
868
869
870 class FakeFileEvent(object):
871@@ -135,7 +127,7 @@
872 assert self.main_thread_id == thread.get_ident()
873
874
875-class TestWatch(BaseTwistedTestCase):
876+class TestWatch(common_tests.TestWatch):
877 """Test the watch so that it returns the same events as pyinotify."""
878
879 timeout = 5
880@@ -143,6 +135,9 @@
881 @defer.inlineCallbacks
882 def setUp(self):
883 yield super(TestWatch, self).setUp()
884+ self.path = '/Users/username/folder'
885+ self.common_path = '/Users/username/folder'
886+ self.invalid_path = '/Users/username/path/to/not/dir'
887 self.basedir = self.mktemp('test_root')
888 self.mask = None
889 self.stream = None
890@@ -151,6 +146,7 @@
891 self.raw_events = []
892 self.paths_checked = []
893 old_is_dir = Watch._path_is_dir
894+ self.fake_events_processor = FakeEventsProcessor()
895
896 def path_is_dir_wrapper(watch, path):
897 """Wrapper that gets the checked paths."""
898@@ -158,37 +154,32 @@
899 self.paths_checked.append((path, result))
900 return result
901
902- self.patch(Watch, '_path_is_dir',
903- path_is_dir_wrapper)
904-
905- @defer.inlineCallbacks
906- def _perform_operations(self, path, mask, actions, number_events):
907- """Perform the file operations and returns the recorded events."""
908- handler = TestCaseHandler(number_events=number_events)
909- manager = WatchManager(handler)
910- yield manager.add_watch(path, mask)
911- # change the logger so that we can check the logs if we wanted
912- manager._wdm[0].log.addHandler(self.memento)
913- # clean logger later
914- self.addCleanup(manager._wdm[0].log.removeHandler, self.memento)
915- # execution the actions
916- actions()
917- # process the recorded events
918- ret = yield handler.deferred
919- self.addCleanup(manager.stop)
920- defer.returnValue(ret)
921-
922- def _assert_logs(self, events):
923- """Assert the debug logs."""
924- logs = []
925- msg = 'Is path %r a dir? %s'
926- logs.extend([msg % data for data in self.paths_checked])
927- msg = 'Pushing event %r to processor.'
928- logs.extend([msg % e for e in events])
929- for msg in logs:
930- self.assertTrue(self.memento.check_debug(msg))
931-
932- @defer.inlineCallbacks
933+ self.patch(Watch, '_path_is_dir', path_is_dir_wrapper)
934+
935+ def test_not_ignore_path(self):
936+ """Test that we do get the events when they do not match."""
937+ self.patch(filesystem_notifications.reactor, 'callFromThread',
938+ lambda x, e: x(e))
939+ super(TestWatch, self).test_not_ignore_path()
940+
941+ def test_undo_ignore_path_ignored(self):
942+ """Test that we do deal with events from and old ignored path."""
943+ self.patch(filesystem_notifications.reactor, 'callFromThread',
944+ lambda x, e: x(e))
945+ super(TestWatch, self).test_not_ignore_path()
946+
947+ def test_undo_ignore_path_other_ignored(self):
948+ """Test that we can undo and the other path is ignored."""
949+ self.patch(filesystem_notifications.reactor, 'callFromThread',
950+ lambda x, e: x(e))
951+ super(TestWatch, self).test_not_ignore_path()
952+
953+ def test_mixed_ignore_path(self):
954+ """Test that we do get the correct events."""
955+ self.patch(filesystem_notifications.reactor, 'callFromThread',
956+ lambda x, e: x(e))
957+ super(TestWatch, self).test_mixed_ignore_path()
958+
959 def test_file_create(self):
960 """Test that the correct event is returned on a file create."""
961 file_name = os.path.join(self.basedir, 'test_file_create')
962@@ -205,14 +196,12 @@
963 create_file, 1)
964 event = events[0]
965 self.assertFalse(event.dir)
966- self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
967+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'], event.mask)
968 self.assertEqual('IN_CREATE', event.maskname)
969 self.assertEqual(os.path.split(file_name)[1], event.name)
970 self.assertEqual('.', event.path)
971 self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
972 self.assertEqual(0, event.wd)
973- # assert the logging
974- self._assert_logs(events)
975
976 @defer.inlineCallbacks
977 def test_dir_create(self):
978@@ -227,14 +216,13 @@
979 create_dir, 1)
980 event = events[0]
981 self.assertTrue(event.dir)
982- self.assertEqual(OP_FLAGS['IN_CREATE'] | IS_DIR, event.mask)
983+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'] |
984+ common_tests.IS_DIR, event.mask)
985 self.assertEqual('IN_CREATE|IN_ISDIR', event.maskname)
986 self.assertEqual(os.path.split(dir_name)[1], event.name)
987 self.assertEqual('.', event.path)
988 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
989 self.assertEqual(0, event.wd)
990- # assert the logging
991- self._assert_logs(events)
992
993 @defer.inlineCallbacks
994 def test_file_remove(self):
995@@ -251,14 +239,12 @@
996 remove_file, 1)
997 event = events[0]
998 self.assertFalse(event.dir)
999- self.assertEqual(OP_FLAGS['IN_DELETE'], event.mask)
1000+ self.assertEqual(common_tests.OP_FLAGS['IN_DELETE'], event.mask)
1001 self.assertEqual('IN_DELETE', event.maskname)
1002 self.assertEqual(os.path.split(file_name)[1], event.name)
1003 self.assertEqual('.', event.path)
1004 self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
1005 self.assertEqual(0, event.wd)
1006- # assert the logging
1007- self._assert_logs(events)
1008
1009 @defer.inlineCallbacks
1010 def test_dir_remove(self):
1011@@ -275,13 +261,12 @@
1012 remove_dir, 1)
1013 event = events[0]
1014 self.assertTrue(event.dir)
1015- self.assertEqual(OP_FLAGS['IN_DELETE'] | IS_DIR, event.mask)
1016+ self.assertEqual(common_tests.OP_FLAGS['IN_DELETE'] |
1017+ common_tests.IS_DIR, event.mask)
1018 self.assertEqual('IN_DELETE|IN_ISDIR', event.maskname)
1019 self.assertEqual('.', event.path)
1020 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
1021 self.assertEqual(0, event.wd)
1022- # assert the logging
1023- self._assert_logs(events)
1024
1025 @defer.inlineCallbacks
1026 def test_file_write(self):
1027@@ -301,14 +286,12 @@
1028 write_file, 1)
1029 event = events[0]
1030 self.assertFalse(event.dir)
1031- self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
1032+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'], event.mask)
1033 self.assertEqual('IN_CREATE', event.maskname)
1034 self.assertEqual(os.path.split(file_name)[1], event.name)
1035 self.assertEqual('.', event.path)
1036 self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
1037 self.assertEqual(0, event.wd)
1038- # assert the logging
1039- self._assert_logs(events)
1040
1041 @defer.inlineCallbacks
1042 def test_file_moved_to_watched_dir_same_watcher(self):
1043@@ -330,7 +313,8 @@
1044 move_to_event = events[1]
1045 # first test the move from
1046 self.assertFalse(move_from_event.dir)
1047- self.assertEqual(OP_FLAGS['IN_MOVED_FROM'], move_from_event.mask)
1048+ self.assertEqual(common_tests.OP_FLAGS['IN_MOVED_FROM'],
1049+ move_from_event.mask)
1050 self.assertEqual('IN_MOVED_FROM', move_from_event.maskname)
1051 self.assertEqual(os.path.split(from_file_name)[1],
1052 move_from_event.name)
1053@@ -340,7 +324,8 @@
1054 self.assertEqual(0, move_from_event.wd)
1055 # test the move to
1056 self.assertFalse(move_to_event.dir)
1057- self.assertEqual(OP_FLAGS['IN_MOVED_TO'], move_to_event.mask)
1058+ self.assertEqual(common_tests.OP_FLAGS['IN_MOVED_TO'],
1059+ move_to_event.mask)
1060 self.assertEqual('IN_MOVED_TO', move_to_event.maskname)
1061 self.assertEqual(os.path.split(to_file_name)[1], move_to_event.name)
1062 self.assertEqual('.', move_to_event.path)
1063@@ -351,8 +336,6 @@
1064 self.assertEqual(0, move_to_event.wd)
1065 # assert that both cookies are the same
1066 self.assertEqual(move_from_event.cookie, move_to_event.cookie)
1067- # assert the logging
1068- self._assert_logs(events)
1069
1070 @defer.inlineCallbacks
1071 def test_file_moved_to_not_watched_dir(self):
1072@@ -372,15 +355,13 @@
1073 move_file, 1)
1074 event = events[0]
1075 self.assertFalse(event.dir)
1076- self.assertEqual(OP_FLAGS['IN_DELETE'], event.mask)
1077+ self.assertEqual(common_tests.OP_FLAGS['IN_DELETE'], event.mask)
1078 self.assertEqual('IN_DELETE', event.maskname)
1079 self.assertEqual(os.path.split(from_file_name)[1], event.name)
1080 self.assertEqual('.', event.path)
1081 self.assertEqual(os.path.join(self.basedir, from_file_name),
1082 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_move_from_not_watched_dir(self):
1089@@ -402,15 +383,13 @@
1090 move_files, 1)
1091 event = events[0]
1092 self.assertFalse(event.dir)
1093- self.assertEqual(OP_FLAGS['IN_CREATE'], event.mask)
1094+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'], event.mask)
1095 self.assertEqual('IN_CREATE', event.maskname)
1096 self.assertEqual(os.path.split(to_file_name)[1], event.name)
1097 self.assertEqual('.', event.path)
1098 self.assertEqual(os.path.join(self.basedir, to_file_name),
1099 event.pathname)
1100 self.assertEqual(0, event.wd)
1101- # assert the logging
1102- self._assert_logs(events)
1103
1104 @defer.inlineCallbacks
1105 def test_dir_moved_to_watched_dir_same_watcher(self):
1106@@ -431,7 +410,8 @@
1107 move_to_event = events[1]
1108 # first test the move from
1109 self.assertTrue(move_from_event.dir)
1110- self.assertEqual(OP_FLAGS['IN_MOVED_FROM'] | IS_DIR,
1111+ self.assertEqual(common_tests.OP_FLAGS['IN_MOVED_FROM'] |
1112+ common_tests.IS_DIR,
1113 move_from_event.mask)
1114 self.assertEqual('IN_MOVED_FROM|IN_ISDIR', move_from_event.maskname)
1115 self.assertEqual(os.path.split(from_dir_name)[1], move_from_event.name)
1116@@ -441,7 +421,8 @@
1117 self.assertEqual(0, move_from_event.wd)
1118 # test the move to
1119 self.assertTrue(move_to_event.dir)
1120- self.assertEqual(OP_FLAGS['IN_MOVED_TO'] | IS_DIR, move_to_event.mask)
1121+ self.assertEqual(common_tests.OP_FLAGS['IN_MOVED_TO'] |
1122+ common_tests.IS_DIR, move_to_event.mask)
1123 self.assertEqual('IN_MOVED_TO|IN_ISDIR', move_to_event.maskname)
1124 self.assertEqual(os.path.split(to_dir_name)[1], move_to_event.name)
1125 self.assertEqual('.', move_to_event.path)
1126@@ -452,8 +433,6 @@
1127 self.assertEqual(0, move_to_event.wd)
1128 # assert that both cookies are the same
1129 self.assertEqual(move_from_event.cookie, move_to_event.cookie)
1130- # assert the logging
1131- self._assert_logs(events)
1132
1133 @defer.inlineCallbacks
1134 def test_dir_moved_to_not_watched_dir(self):
1135@@ -473,13 +452,12 @@
1136 move_dir, 1)
1137 event = events[0]
1138 self.assertTrue(event.dir)
1139- self.assertEqual(OP_FLAGS['IN_DELETE'] | IS_DIR, event.mask)
1140+ self.assertEqual(common_tests.OP_FLAGS['IN_DELETE'] |
1141+ common_tests.IS_DIR, event.mask)
1142 self.assertEqual('IN_DELETE|IN_ISDIR', event.maskname)
1143 self.assertEqual('.', event.path)
1144 self.assertEqual(os.path.join(self.basedir, dir_name), event.pathname)
1145 self.assertEqual(0, event.wd)
1146- # assert the logging
1147- self._assert_logs(events)
1148
1149 @defer.inlineCallbacks
1150 def test_dir_move_from_not_watched_dir(self):
1151@@ -499,7 +477,8 @@
1152 move_dir, 1)
1153 event = events[0]
1154 self.assertTrue(event.dir)
1155- self.assertEqual(OP_FLAGS['IN_CREATE'] | IS_DIR, event.mask)
1156+ self.assertEqual(common_tests.OP_FLAGS['IN_CREATE'] |
1157+ common_tests.IS_DIR, event.mask)
1158 self.assertEqual('IN_CREATE|IN_ISDIR', event.maskname)
1159 self.assertEqual(os.path.split(from_dir_name)[1], event.name)
1160 self.assertEqual('.', event.path)
1161@@ -521,149 +500,6 @@
1162 self.assertEqual(0, len(handler.processed_events))
1163 test_exclude_filter.skip = "we must rethink this test."
1164
1165- def test_ignore_path(self):
1166- """Test that events from a path are ignored."""
1167- events = []
1168-
1169- def fake_processor(event):
1170- """Memorize the processed events."""
1171- events.append(event)
1172-
1173- path = '/Users/username/folder'
1174- child = 'child'
1175- watch = Watch(1, path, fake_processor)
1176- watch.ignore_path(os.path.join(path, child))
1177- # ensure that the watch is watching
1178- watch.platform_watch.watching = True
1179- for file_name in 'abcdef':
1180- event = FakeFileEvent(256, None, os.path.join(child, file_name))
1181- watch.platform_watch._process_events(event)
1182- self.assertEqual(0, len(events),
1183- 'All events should have been ignored.')
1184-
1185- def test_not_ignore_path(self):
1186- """Test that we do get the events when they do not match."""
1187- events = []
1188-
1189- def fake_processor(event):
1190- """Memorize the processed events."""
1191- events.append(event)
1192-
1193- self.patch(filesystem_notifications.reactor, 'callFromThread',
1194- lambda x, e: x(e))
1195-
1196- path = '/Users/username/folder'
1197- child = 'child'
1198- watch = Watch(1, path, fake_processor)
1199- watch.ignore_path(os.path.join(path, child))
1200- paths_not_to_ignore = []
1201- for file_name in 'abcdef':
1202- event = FakeFileEvent(256, None, os.path.join(child + file_name,
1203- file_name))
1204- paths_not_to_ignore.append(event)
1205- # ensure that the watch is watching
1206- watch.platform_watch.watching = True
1207- for event in paths_not_to_ignore:
1208- watch.platform_watch._process_events(event)
1209- self.assertEqual(len(paths_not_to_ignore), len(events),
1210- 'No events should have been ignored.')
1211-
1212- def test_mixed_ignore_path(self):
1213- """Test that we do get the correct events."""
1214- events = []
1215-
1216- def fake_processor(event):
1217- """Memorize the processed events."""
1218- events.append(event.pathname)
1219-
1220- self.patch(filesystem_notifications.reactor, 'callFromThread',
1221- lambda x, e: x(e))
1222-
1223- child = 'child'
1224- path = '/Users/username/folder'
1225- watch = Watch(1, path, fake_processor)
1226- watch.ignore_path(os.path.join(path, child))
1227- paths_not_to_ignore = []
1228- paths_to_ignore = []
1229- expected_events = []
1230- for file_name in 'abcdef':
1231- valid = os.path.join(child + file_name, file_name)
1232- paths_to_ignore.append((1, os.path.join(child, file_name)))
1233- event = FakeFileEvent(256, None, valid)
1234- paths_not_to_ignore.append(event)
1235- expected_events.append(os.path.join(path, valid))
1236- # ensure that the watch is watching
1237- watch.platform_watch.watching = True
1238- for event in paths_not_to_ignore:
1239- watch.platform_watch._process_events(event)
1240- self.assertEqual(len(paths_not_to_ignore), len(events),
1241- 'Wrong number of events ignored.')
1242- self.assertTrue(all([event in expected_events for event in events]),
1243- 'Paths ignored that should have not been ignored.')
1244-
1245- def test_undo_ignore_path_ignored(self):
1246- """Test that we do deal with events from and old ignored path."""
1247- events = []
1248-
1249- def fake_processor(event):
1250- """Memorize the processed events."""
1251- events.append(event)
1252-
1253- self.patch(filesystem_notifications.reactor, 'callFromThread',
1254- lambda x, e: x(e))
1255-
1256- path = '/Users/username/folder'
1257- child = 'child'
1258- watch = Watch(1, path, fake_processor)
1259- watch.ignore_path(os.path.join(path, child))
1260- watch.remove_ignored_path(os.path.join(path, child))
1261- paths_not_to_ignore = []
1262- for file_name in 'abcdef':
1263- event = FakeFileEvent(256, None, os.path.join(child, file_name))
1264- paths_not_to_ignore.append(event)
1265- # ensure that the watch is watching
1266- watch.platform_watch.watching = True
1267- for event in paths_not_to_ignore:
1268- watch.platform_watch._process_events(event)
1269- self.assertEqual(len(paths_not_to_ignore), len(events),
1270- 'All events should have been accepted.')
1271-
1272- def test_undo_ignore_path_other_ignored(self):
1273- """Test that we can undo and the other path is ignored."""
1274- events = []
1275-
1276- def fake_processor(event):
1277- """Memorize the processed events."""
1278- events.append(event.pathname)
1279-
1280- self.patch(filesystem_notifications.reactor, 'callFromThread',
1281- lambda x, e: x(e))
1282-
1283- path = '/Users/username/folder'
1284- child_a = 'childa'
1285- child_b = 'childb'
1286- watch = Watch(1, path, fake_processor)
1287- watch.ignore_path(os.path.join(path, child_a))
1288- watch.ignore_path(os.path.join(path, child_b))
1289- watch.remove_ignored_path(os.path.join(path, child_a))
1290- paths_to_ignore = []
1291- paths_not_to_ignore = []
1292- expected_events = []
1293- for file_name in 'abcdef':
1294- paths_to_ignore.append((1, os.path.join(child_b, file_name)))
1295- valid = os.path.join(child_a, file_name)
1296- event = FakeFileEvent(256, None, valid)
1297- paths_not_to_ignore.append(event)
1298- expected_events.append(os.path.join(path, valid))
1299- # ensure that the watch is watching
1300- watch.platform_watch.watching = True
1301- for event in paths_not_to_ignore:
1302- watch.platform_watch._process_events(event)
1303- self.assertEqual(len(paths_not_to_ignore), len(events),
1304- 'All events should have been accepted.')
1305- self.assertTrue(all([event in expected_events for event in events]),
1306- 'Paths ignored that should have not been ignored.')
1307-
1308 def test_stream_created(self):
1309 """Test that the stream is created."""
1310 def fake_call(*args, **kwargs):
1311@@ -684,7 +520,7 @@
1312
1313 def random_error(self, *args):
1314 """Throw a fake exception."""
1315- raise FakeException()
1316+ raise common_tests.FakeException()
1317
1318 def test_is_path_dir_missing_no_subdir(self):
1319 """Test when the path does not exist and is no a subdir."""
1320@@ -760,7 +596,7 @@
1321 self.assertTrue(path not in watch._subdirs)
1322
1323
1324-class TestWatchManager(BaseTwistedTestCase):
1325+class TestWatchManager(common_tests.TestWatchManager):
1326 """Test the watch manager."""
1327
1328 @defer.inlineCallbacks
1329@@ -772,24 +608,19 @@
1330 self.watch = Watch(1, self.path, None)
1331 self.manager = WatchManager(None)
1332 self.manager._wdm = {1: self.watch}
1333+ self.stream = None
1334+ self.fake_events_processor = FakeEventsProcessor()
1335
1336 @defer.inlineCallbacks
1337 def test_stop(self):
1338 """Test that the different watches are stopped."""
1339- self.was_called = False
1340-
1341- def fake_stop_watching(watch):
1342- """Fake stop watch."""
1343- self.was_called = True
1344- return defer.succeed(True)
1345-
1346- self.patch(Watch, "stop_watching", fake_stop_watching)
1347+ self.patch(self.manager.manager.observer, "unschedule",
1348+ lambda x: None)
1349 self.patch(self.manager.manager.observer, "unschedule", lambda x: None)
1350- yield self.manager.stop()
1351- self.assertTrue(self.was_called, 'The watch stop should be called.')
1352+ yield super(TestWatchManager, self).test_stop()
1353
1354 def test_stop_multiple(self):
1355- """The watches should became watching=False and the observer stopped."""
1356+ """Watches should became watching=False and the observer stopped."""
1357 self.patch(self.manager.manager.observer, "unschedule", lambda x: None)
1358 second_path = self.parent_path + "second_path"
1359 second_watch = Watch(2, second_path, None)
1360@@ -810,28 +641,6 @@
1361 """Test that we get an error when trying to get a missing wd."""
1362 self.assertRaises(KeyError, self.manager.get_watch, (1,))
1363
1364- @defer.inlineCallbacks
1365- def test_delete_present_watch(self):
1366- """Test that we can remove a present watch."""
1367- self.was_called = False
1368-
1369- def stop_watching():
1370- """Fake stop watch."""
1371- self.was_called = True
1372- return defer.succeed(True)
1373-
1374- def fake_unschedule(s):
1375- """Fake function that should receive a Stream object."""
1376- self.stream = s
1377-
1378- self.patch(self.manager.manager.observer, "unschedule",
1379- fake_unschedule)
1380-
1381- self.watch.stop_watching = stop_watching
1382- yield self.manager.del_watch(1)
1383- self.assertIsInstance(self.stream, fsevents.Stream)
1384- self.assertRaises(KeyError, self.manager.get_watch, (1,))
1385-
1386 def test_add_single_watch(self):
1387 """Test the addition of a new single watch."""
1388 self.was_called = False
1389@@ -849,10 +658,6 @@
1390 self.assertTrue(self.was_called, 'The watch start was not called.')
1391 self.assertEqual(self.path + os.path.sep, self.manager._wdm[0].path)
1392
1393- def test_get_watch_present_wd(self):
1394- """Test that the correct path is returned."""
1395- self.assertEqual(self.path + os.path.sep, self.manager.get_path(1))
1396-
1397 def test_get_watch_missing_wd(self):
1398 """Test that the correct path is returned."""
1399 self.manager._wdm = {}
1400@@ -873,60 +678,24 @@
1401
1402 def test_rm_present_wd(self):
1403 """Test the removal of a present watch."""
1404- self.patch(self.watch, "stop_watching", lambda: None)
1405 self.patch(self.manager.manager.observer, "unschedule", lambda x: None)
1406- self.manager.rm_watch(1)
1407- self.assertEqual(None, self.manager._wdm.get(1))
1408-
1409- def test_rm_root_path(self):
1410- """Test the removal of a root path."""
1411- events = []
1412-
1413- def fake_processor(event):
1414- """Memorize the processed events."""
1415- events.append(event.pathname)
1416-
1417- self.watch._processor = fake_processor
1418- self.manager.rm_path(self.path)
1419- self.assertEqual(self.watch, self.manager._wdm.get(1))
1420- self.watch._watching = True
1421- event = FakeFileEvent(256, None, os.path.join(self.path, 'test'))
1422- self.watch.platform_watch._process_events(event)
1423- self.assertEqual(0, len(events))
1424+ super(TestWatchManager, self).test_rm_present_wd()
1425
1426 def test_rm_child_path(self):
1427 """Test the removal of a child path."""
1428- events = []
1429-
1430- def fake_processor(event):
1431- """Memorize the processed events."""
1432- events.append(event.pathname)
1433-
1434 self.patch(filesystem_notifications.reactor, 'callFromThread',
1435 lambda x, e: x(e))
1436-
1437- self.watch._processor = fake_processor
1438- child = os.path.join(self.path, 'child')
1439- self.manager.rm_path(child)
1440- self.assertEqual(self.watch, self.manager._wdm[1])
1441- # assert that the correct event is ignored
1442- self.watch.platform_watch.watching = True
1443- event = FakeFileEvent(256, None, os.path.join('child', 'test'))
1444- self.watch.platform_watch._process_events(event)
1445- self.assertEqual(0, len(events))
1446- # assert that other events are not ignored
1447- event2 = FakeFileEvent(256, None, 'test')
1448- self.watch.platform_watch._process_events(event2)
1449- self.assertEqual(1, len(events))
1450-
1451-
1452-class TestWatchManagerAddWatches(BaseTwistedTestCase):
1453+ super(TestWatchManager, self).test_rm_child_path()
1454+
1455+
1456+class TestWatchManagerAddWatches(common_tests.TestWatchManagerAddWatches):
1457 """Test the watch manager."""
1458 timeout = 5
1459
1460 def test_add_watch_twice(self):
1461 """Adding a watch twice succeeds when the watch is running."""
1462 self.patch(Watch, "start_watching", lambda self: None)
1463+ self.patch(Watch, "started", lambda self: True)
1464 manager = WatchManager(None)
1465 # no need to stop watching because start_watching is fake
1466
1467@@ -936,7 +705,7 @@
1468 d2 = manager.add_watch(path, mask)
1469
1470 self.assertTrue(d1.result, "Should not be called yet.")
1471- self.assertFalse(d2.result, "Should not be called yet.")
1472+ self.assertTrue(d2, "Should not be called yet.")
1473
1474
1475 class FakeEvent(object):
1476@@ -953,88 +722,15 @@
1477 self.cookie = cookie
1478
1479
1480-class FakeLog(object):
1481- """A fake log that is used by the general processor."""
1482-
1483- def __init__(self):
1484- """Create the fake."""
1485- self.called_methods = []
1486-
1487- def info(self, *args):
1488- """Fake the info call."""
1489- self.called_methods.append(('info', args))
1490-
1491-
1492-class FakeGeneralProcessor(object):
1493- """Fake implementation of the general processor."""
1494-
1495- def __init__(self):
1496- """Create the fake."""
1497- self.called_methods = []
1498- self.paths_to_return = []
1499- self.log = FakeLog()
1500- self.share_id = None
1501- self.ignore = False
1502-
1503- def rm_from_mute_filter(self, event, paths):
1504- """Fake rm_from_mute_filter."""
1505- self.called_methods.append(('rm_from_mute_filter', event, paths))
1506-
1507- def add_to_mute_filter(self, event, paths):
1508- """Fake add_to_move_filter."""
1509- self.called_methods.append(('add_to_mute_filter', event, paths))
1510-
1511- def is_ignored(self, path):
1512- """Fake is_ignored."""
1513- self.called_methods.append(('is_ignored', path))
1514- return self.ignore
1515-
1516- def push_event(self, event):
1517- """Fake push event."""
1518- self.called_methods.append(('push_event', event))
1519-
1520- def eq_push(self, event, path=None, path_to=None, path_from=None):
1521- """Fake event to push event."""
1522- self.called_methods.append(('eq_push', event, path, path_to,
1523- path_from))
1524-
1525- def get_paths_starting_with(self, fullpath, include_base=False):
1526- """Fake get_paths_starting_with."""
1527- self.called_methods.append(('get_paths_starting_with', fullpath,
1528- include_base))
1529- return self.paths_to_return
1530-
1531- def get_path_share_id(self, path):
1532- """Fake get_path_share_id."""
1533- self.called_methods.append(('get_path_share_id', path))
1534- return self.share_id
1535-
1536- def rm_watch(self, path):
1537- """Fake the remove watch."""
1538- self.called_methods.append(('rm_watch', path))
1539-
1540- def freeze_begin(self, path):
1541- """Fake freeze_begin"""
1542- self.called_methods.append(('freeze_begin', path))
1543-
1544- def freeze_rollback(self):
1545- """Fake rollback."""
1546- self.called_methods.append(('freeze_rollback',))
1547-
1548- def freeze_commit(self, path):
1549- """Fake freeze commit."""
1550- self.called_methods.append(('freeze_commit', path))
1551-
1552-
1553-class TestNotifyProcessor(BaseTwistedTestCase):
1554+class TestNotifyProcessor(common_tests.TestNotifyProcessor):
1555 """Test the notify processor."""
1556
1557 @defer.inlineCallbacks
1558 def setUp(self):
1559- """set up the diffeent tests."""
1560+ """set up the different tests."""
1561 yield super(TestNotifyProcessor, self).setUp()
1562 self.processor = notify_processor.NotifyProcessor(None)
1563- self.general = FakeGeneralProcessor()
1564+ self.general = common_tests.FakeGeneralProcessor()
1565 self.processor.general_processor = self.general
1566
1567 def test_rm_from_mute_filter(self):
1568
1569=== added file 'tests/platform/filesystem_notifications/test_windows.py'
1570--- tests/platform/filesystem_notifications/test_windows.py 1970-01-01 00:00:00 +0000
1571+++ tests/platform/filesystem_notifications/test_windows.py 2012-08-06 16:57:22 +0000
1572@@ -0,0 +1,344 @@
1573+#
1574+# Authors: Manuel de la Pena <manuel@canonical.com>
1575+# Alejandro J. Cura <alecu@canonical.com>
1576+#
1577+# Copyright 2011-2012 Canonical Ltd.
1578+#
1579+# This program is free software: you can redistribute it and/or modify it
1580+# under the terms of the GNU General Public License version 3, as published
1581+# by the Free Software Foundation.
1582+#
1583+# This program is distributed in the hope that it will be useful, but
1584+# WITHOUT ANY WARRANTY; without even the implied warranties of
1585+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1586+# PURPOSE. See the GNU General Public License for more details.
1587+#
1588+# You should have received a copy of the GNU General Public License along
1589+# with this program. If not, see <http://www.gnu.org/licenses/>.
1590+#
1591+# In addition, as a special exception, the copyright holders give
1592+# permission to link the code of portions of this program with the
1593+# OpenSSL library under certain conditions as described in each
1594+# individual source file, and distribute linked combinations
1595+# including the two.
1596+# You must obey the GNU General Public License in all respects
1597+# for all of the code used other than OpenSSL. If you modify
1598+# file(s) with this exception, you may extend this exception to your
1599+# version of the file(s), but you are not obligated to do so. If you
1600+# do not wish to do so, delete this exception statement from your
1601+# version. If you delete this exception statement from all source
1602+# files in the program, then also delete it here.
1603+"""Test the filesystem notifications on windows."""
1604+
1605+import os
1606+
1607+from twisted.internet import defer
1608+from win32file import FILE_NOTIFY_INFORMATION
1609+
1610+from ubuntuone.platform.filesystem_notifications.monitor import (
1611+ common,
1612+ windows as filesystem_notifications,
1613+)
1614+from ubuntuone.platform.filesystem_notifications.monitor.common import (
1615+ FilesystemMonitor,
1616+ Watch,
1617+ WatchManager,
1618+)
1619+from ubuntuone.platform.filesystem_notifications.monitor.windows import (
1620+ FILE_NOTIFY_CHANGE_FILE_NAME,
1621+ FILE_NOTIFY_CHANGE_DIR_NAME,
1622+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
1623+ FILE_NOTIFY_CHANGE_SIZE,
1624+ FILE_NOTIFY_CHANGE_LAST_WRITE,
1625+ FILE_NOTIFY_CHANGE_SECURITY,
1626+ FILE_NOTIFY_CHANGE_LAST_ACCESS,
1627+)
1628+from tests.platform.filesystem_notifications import common as common_tests
1629+
1630+
1631+class FakeEventsProcessor(object):
1632+
1633+ """Handle fake events creation and processing."""
1634+
1635+ def create_fake_event(self, filename):
1636+ """Create a fake file event."""
1637+ return (1, filename)
1638+
1639+ def custom_process_events(self, watch, events):
1640+ """Adapt to each platform way to process events."""
1641+ watch.platform_watch._process_events(events)
1642+
1643+
1644+class TestWatch(common_tests.TestWatch):
1645+ """Test the watch so that it returns the same events as pyinotify."""
1646+
1647+ timeout = 5
1648+
1649+ @defer.inlineCallbacks
1650+ def setUp(self):
1651+ yield super(TestWatch, self).setUp()
1652+ self.path = u'\\\\?\\C:\\path' # a valid windows path
1653+ self.common_path = u'C:\\path'
1654+ self.invalid_path = u'\\\\?\\C:\\path\\to\\no\\dir'
1655+ self.mask = FILE_NOTIFY_CHANGE_FILE_NAME | \
1656+ FILE_NOTIFY_CHANGE_DIR_NAME | \
1657+ FILE_NOTIFY_CHANGE_ATTRIBUTES | \
1658+ FILE_NOTIFY_CHANGE_SIZE | \
1659+ FILE_NOTIFY_CHANGE_LAST_WRITE | \
1660+ FILE_NOTIFY_CHANGE_SECURITY | \
1661+ FILE_NOTIFY_CHANGE_LAST_ACCESS
1662+ self.fake_events_processor = FakeEventsProcessor()
1663+
1664+ def file_notify_information_wrapper(buf, data):
1665+ """Wrapper that gets the events and adds them to the list."""
1666+ events = FILE_NOTIFY_INFORMATION(buf, data)
1667+ # we want to append the list because that is what will be logged.
1668+ # If we use extend we wont have the same logging because it will
1669+ # group all events in a single lists which is not what the COM API
1670+ # does.
1671+ str_events = [
1672+ (common.ACTIONS_NAMES[action], path) for action, path in
1673+ events]
1674+ self.raw_events.append(str_events)
1675+ return events
1676+
1677+ self.patch(filesystem_notifications, 'FILE_NOTIFY_INFORMATION',
1678+ file_notify_information_wrapper)
1679+
1680+ @defer.inlineCallbacks
1681+ def test_file_write(self):
1682+ """Test that the correct event is raised when a file is written."""
1683+ file_name = os.path.join(self.basedir, 'test_file_write')
1684+ # create the file before recording
1685+ fd = open(file_name, 'w')
1686+ # clean behind us by removing the file
1687+ self.addCleanup(os.remove, file_name)
1688+
1689+ def write_file():
1690+ """Action for the test."""
1691+ fd.write('test')
1692+ fd.close()
1693+
1694+ events = yield self._perform_operations(self.basedir, self.mask,
1695+ write_file, 1)
1696+ event = events[0]
1697+ self.assertFalse(event.dir)
1698+ self.assertEqual(0x2, event.mask)
1699+ self.assertEqual('IN_MODIFY', event.maskname)
1700+ self.assertEqual(os.path.split(file_name)[1], event.name)
1701+ self.assertEqual('.', event.path)
1702+ self.assertEqual(os.path.join(self.basedir, file_name), event.pathname)
1703+ self.assertEqual(0, event.wd)
1704+
1705+ @defer.inlineCallbacks
1706+ def test_call_deferred_already_called(self):
1707+ """Test that the function is not called."""
1708+ method_args = []
1709+
1710+ def fake_call(*args, **kwargs):
1711+ """Execute the call."""
1712+ method_args.append((args, kwargs),)
1713+
1714+ watch = Watch(1, self.path, None)
1715+ yield watch.platform_watch._watch_started_deferred.callback(True)
1716+ watch.platform_watch._call_deferred(fake_call, None)
1717+ self.assertEqual(0, len(method_args))
1718+
1719+ def test_call_deferred_not_called(self):
1720+ """Test that is indeed called."""
1721+ method_args = []
1722+
1723+ def fake_call(*args, **kwargs):
1724+ """Execute the call."""
1725+ method_args.append((args, kwargs),)
1726+
1727+ watch = Watch(1, self.path, None)
1728+ watch.platform_watch._call_deferred(fake_call, None)
1729+ self.assertEqual(1, len(method_args))
1730+
1731+ def test_started_property(self):
1732+ """Test that the started property returns the started deferred."""
1733+ watch = Watch(1, self.path, None)
1734+ self.assertEqual(watch.started,
1735+ watch.platform_watch._watch_started_deferred)
1736+
1737+ def test_stopped_property(self):
1738+ """Test that the stopped property returns the stopped deferred."""
1739+ watch = Watch(1, self.path, None)
1740+ self.assertEqual(watch.stopped,
1741+ watch.platform_watch._watch_stopped_deferred)
1742+
1743+ @defer.inlineCallbacks
1744+ def test_start_watching_fails_early_in_thread(self):
1745+ """An early failure inside the thread should errback the deferred."""
1746+ test_path = self.mktemp("test_directory")
1747+ self.patch(filesystem_notifications, "CreateFileW", self.random_error)
1748+ watch = Watch(1, test_path, None)
1749+ d = watch.start_watching()
1750+ yield self.assertFailure(d, common_tests.FakeException)
1751+
1752+ @defer.inlineCallbacks
1753+ def test_start_watching_fails_late_in_thread(self):
1754+ """A late failure inside the thread should errback the deferred."""
1755+ test_path = self.mktemp("test_directory")
1756+ self.patch(filesystem_notifications, "ReadDirectoryChangesW",
1757+ self.random_error)
1758+ watch = Watch(1, test_path, None)
1759+ d = watch.start_watching()
1760+ yield self.assertFailure(d, common_tests.FakeException)
1761+
1762+ @defer.inlineCallbacks
1763+ def test_close_handle_is_called_on_error(self):
1764+ """CloseHandle is called when there's an error in the watch thread."""
1765+ test_path = self.mktemp("test_directory")
1766+ close_called = []
1767+ self.patch(filesystem_notifications, "CreateFileW", lambda *_: None)
1768+ self.patch(filesystem_notifications, "CloseHandle",
1769+ close_called.append)
1770+ self.patch(filesystem_notifications, "ReadDirectoryChangesW",
1771+ self.random_error)
1772+ watch = Watch(1, test_path, self.mask)
1773+ d = watch.start_watching()
1774+ yield self.assertFailure(d, common_tests.FakeException)
1775+ self.assertEqual(len(close_called), 1)
1776+ yield watch.stop_watching()
1777+
1778+ @defer.inlineCallbacks
1779+ def test_stop_watching_fired_when_watch_thread_finishes(self):
1780+ """The deferred returned is fired when the watch thread finishes."""
1781+ test_path = self.mktemp("another_test_directory")
1782+ watch = Watch(1, test_path, self.mask)
1783+ yield watch.start_watching()
1784+ self.assertNotEqual(watch.platform_watch._watch_handle, None)
1785+ yield watch.stop_watching()
1786+ self.assertEqual(watch.platform_watch._watch_handle, None)
1787+
1788+
1789+class TestWatchManager(common_tests.TestWatchManager):
1790+ """Test the watch manager."""
1791+
1792+ @defer.inlineCallbacks
1793+ def setUp(self):
1794+ """Set each of the tests."""
1795+ yield super(TestWatchManager, self).setUp()
1796+ self.parent_path = u'\\\\?\\C:\\' # a valid windows path
1797+ self.path = self.parent_path + u'path'
1798+ self.watch = Watch(1, self.path, None)
1799+ self.manager._wdm = {1: self.watch}
1800+ self.fake_events_processor = FakeEventsProcessor()
1801+
1802+ def test_add_single_watch(self):
1803+ """Test the addition of a new single watch."""
1804+ self.was_called = False
1805+
1806+ def fake_start_watching(*args):
1807+ """Fake start watch."""
1808+ self.was_called = True
1809+
1810+ self.patch(Watch, "start_watching", fake_start_watching)
1811+ self.manager._wdm = {}
1812+
1813+ mask = 'bit_mask'
1814+ self.manager.add_watch(self.path, mask)
1815+ self.assertEqual(1, len(self.manager._wdm))
1816+ self.assertTrue(self.was_called, 'The watch start was not called.')
1817+ self.assertEqual(self.path + os.path.sep, self.manager._wdm[0].path)
1818+ self.assertEqual(filesystem_notifications.FILESYSTEM_MONITOR_MASK,
1819+ self.manager._wdm[0].platform_watch._mask)
1820+
1821+ @defer.inlineCallbacks
1822+ def test_stop_multiple(self):
1823+ """Test that stop is fired when *all* watches have stopped."""
1824+
1825+ def fake_stop_watching(watch):
1826+ """Another fake stop watch."""
1827+ return watch.stopped
1828+
1829+ self.patch(Watch, "stop_watching", fake_stop_watching)
1830+ second_path = self.parent_path + u"second_path"
1831+ second_watch = Watch(2, second_path, None)
1832+ self.manager._wdm[2] = second_watch
1833+ d = self.manager.stop()
1834+ self.assertFalse(d.called, "Not fired before all watches end")
1835+ self.watch.stopped.callback(None)
1836+ self.assertFalse(d.called, "Not fired before all watches end")
1837+ second_watch.stopped.callback(None)
1838+ yield d
1839+ self.assertTrue(d.called, "Fired after the watches ended")
1840+
1841+
1842+class TestWatchManagerAddWatches(common_tests.TestWatchManagerAddWatches):
1843+ """Test the watch manager."""
1844+ timeout = 5
1845+
1846+ def test_add_watch_twice(self):
1847+ """Adding a watch twice succeeds when the watch is running."""
1848+ self.patch(Watch, "start_watching", lambda self: self.started)
1849+ manager = WatchManager(None)
1850+ # no need to stop watching because start_watching is fake
1851+
1852+ path = u'\\\\?\\C:\\test' # a valid windows path
1853+ mask = 'fake bit mask'
1854+ d1 = manager.add_watch(path, mask)
1855+ d2 = manager.add_watch(path, mask)
1856+
1857+ self.assertFalse(d1.called, "Should not be called yet.")
1858+ self.assertFalse(d2.called, "Should not be called yet.")
1859+
1860+ manager._wdm.values()[0].started.callback(True)
1861+
1862+ self.assertTrue(d1.called, "Should already be called.")
1863+ self.assertTrue(d2.called, "Should already be called.")
1864+
1865+
1866+class TestNotifyProcessor(common_tests.TestNotifyProcessor):
1867+ """Test the notify processor."""
1868+
1869+ @defer.inlineCallbacks
1870+ def setUp(self):
1871+ """set up the diffeent tests."""
1872+ yield super(TestNotifyProcessor, self).setUp()
1873+
1874+
1875+class FilesystemMonitorTestCase(common_tests.FilesystemMonitorTestCase):
1876+ """Tests for the FilesystemMonitor."""
1877+ timeout = 5
1878+
1879+ def test_add_watch_twice(self):
1880+ """Check the deferred returned by a second add_watch."""
1881+ self.patch(Watch, "start_watching", lambda self: self.started)
1882+ monitor = FilesystemMonitor(None, None)
1883+ # no need to stop watching because start_watching is fake
1884+
1885+ parent_path = 'C:\\test' # a valid windows path in utf-8 bytes
1886+ child_path = parent_path + "\\child"
1887+ d1 = monitor.add_watch(parent_path)
1888+ d2 = monitor.add_watch(child_path)
1889+
1890+ self.assertFalse(d1.called, "Should not be called yet.")
1891+ self.assertFalse(d2.called, "Should not be called yet.")
1892+
1893+ monitor._watch_manager._wdm.values()[0].started.callback(True)
1894+
1895+ self.assertTrue(d1.called, "Should already be called.")
1896+ self.assertTrue(d2.called, "Should already be called.")
1897+
1898+ @defer.inlineCallbacks
1899+ def test_add_watches_to_udf_ancestors(self):
1900+ """Test that the ancestor watches are not added."""
1901+
1902+ class FakeVolume(object):
1903+ """A fake UDF."""
1904+
1905+ def __init__(self, ancestors):
1906+ """Create a new instance."""
1907+ self.ancestors = ancestors
1908+
1909+ ancestors = ['~', '~\\Pictures', '~\\Pictures\\Home', ]
1910+ volume = FakeVolume(ancestors)
1911+ monitor = FilesystemMonitor(None, None)
1912+ added = yield monitor.add_watches_to_udf_ancestors(volume)
1913+ self.assertTrue(added, 'We should always return true.')
1914+ # lets ensure that we never added the watches
1915+ self.assertEqual(0, len(monitor._watch_manager._wdm.values()),
1916+ 'No watches should have been added.')
1917
1918=== modified file 'ubuntuone/platform/filesystem_notifications/monitor/__init__.py'
1919--- ubuntuone/platform/filesystem_notifications/monitor/__init__.py 2012-07-18 15:18:04 +0000
1920+++ ubuntuone/platform/filesystem_notifications/monitor/__init__.py 2012-08-06 16:57:22 +0000
1921@@ -42,11 +42,13 @@
1922 if sys.platform == 'win32':
1923 from ubuntuone.platform.filesystem_notifications.monitor import (
1924 common,
1925+ windows,
1926 )
1927
1928 FILEMONITOR_IDS = {
1929 DEFAULT_MONITOR: common.FilesystemMonitor,
1930 }
1931+ ACTIONS = windows.ACTIONS
1932
1933 elif sys.platform == 'darwin':
1934 from ubuntuone.platform.filesystem_notifications.monitor import darwin
1935@@ -58,6 +60,7 @@
1936 DEFAULT_MONITOR: common.FilesystemMonitor,
1937 'daemon': darwin.fsevents_daemon.FilesystemMonitor,
1938 }
1939+ ACTIONS = darwin.fsevents_client.ACTIONS
1940 else:
1941 from ubuntuone.platform.filesystem_notifications.monitor import (
1942 linux,
1943
1944=== modified file 'ubuntuone/platform/filesystem_notifications/monitor/common.py'
1945--- ubuntuone/platform/filesystem_notifications/monitor/common.py 2012-07-18 09:05:26 +0000
1946+++ ubuntuone/platform/filesystem_notifications/monitor/common.py 2012-08-06 16:57:22 +0000
1947@@ -65,6 +65,7 @@
1948 else:
1949 raise ImportError('Not supported platform')
1950
1951+
1952 # a map between the few events that we have on common platforms and those
1953 # found in pyinotify
1954 ACTIONS = source.ACTIONS
1955
1956=== modified file 'ubuntuone/platform/os_helper/__init__.py'
1957--- ubuntuone/platform/os_helper/__init__.py 2012-06-22 19:37:36 +0000
1958+++ ubuntuone/platform/os_helper/__init__.py 2012-08-06 16:57:22 +0000
1959@@ -73,6 +73,7 @@
1960
1961 # Decorators
1962
1963+get_os_valid_path = source.get_os_valid_path
1964 is_valid_syncdaemon_path = source.is_valid_syncdaemon_path
1965 is_valid_os_path = source.is_valid_os_path
1966 os_path = source.os_path
1967
1968=== modified file 'ubuntuone/platform/os_helper/darwin.py'
1969--- ubuntuone/platform/os_helper/darwin.py 2012-07-10 18:41:15 +0000
1970+++ ubuntuone/platform/os_helper/darwin.py 2012-08-06 16:57:22 +0000
1971@@ -29,8 +29,8 @@
1972 """
1973 Darwin import for ubuntuone-client
1974
1975-This module has to have all darwin specific modules and provide the api required
1976-to support the darwin platform.
1977+This module has to have all darwin specific modules and provide the
1978+api required to support the darwin platform.
1979 """
1980
1981 import errno
1982@@ -70,6 +70,7 @@
1983 is_root = unix.is_root
1984 get_path_list = unix.get_path_list
1985 normpath = unix.normpath
1986+get_os_valid_path = unix.get_os_valid_path
1987
1988
1989 def move_to_trash(path):
1990@@ -121,6 +122,8 @@
1991 def is_valid_os_path(path_indexes=None):
1992 def decorator(func):
1993 def wrapped(*args, **kwargs):
1994+ for i in path_indexes:
1995+ assert isinstance(args[i], str), 'Path %r should be str.'
1996 return func(*args, **kwargs)
1997 return wrapped
1998 return decorator
1999
2000=== modified file 'ubuntuone/platform/os_helper/linux.py'
2001--- ubuntuone/platform/os_helper/linux.py 2012-06-27 12:51:20 +0000
2002+++ ubuntuone/platform/os_helper/linux.py 2012-08-06 16:57:22 +0000
2003@@ -123,6 +123,7 @@
2004 is_root = unix.is_root
2005 get_path_list = unix.get_path_list
2006 normpath = unix.normpath
2007+get_os_valid_path = unix.get_os_valid_path
2008 is_valid_syncdaemon_path = None
2009 is_valid_os_path = None
2010 os_path = None
2011
2012=== modified file 'ubuntuone/platform/os_helper/unix.py'
2013--- ubuntuone/platform/os_helper/unix.py 2012-06-27 14:02:14 +0000
2014+++ ubuntuone/platform/os_helper/unix.py 2012-08-06 16:57:22 +0000
2015@@ -185,3 +185,8 @@
2016 def normpath(path):
2017 """Normalize path, eliminating double slashes, etc."""
2018 return os.path.normpath(path)
2019+
2020+
2021+def get_os_valid_path(path):
2022+ """Return a valid os path."""
2023+ return os.path.abspath(path)
2024
2025=== modified file 'ubuntuone/platform/os_helper/windows.py'
2026--- ubuntuone/platform/os_helper/windows.py 2012-07-03 17:16:57 +0000
2027+++ ubuntuone/platform/os_helper/windows.py 2012-08-06 16:57:22 +0000
2028@@ -249,6 +249,8 @@
2029 assert_windows_path(result)
2030 return result
2031
2032+get_os_valid_path = get_windows_valid_path
2033+
2034
2035 def _unicode_to_bytes(path):
2036 """Convert a unicode path to a bytes path."""

Subscribers

People subscribed via source and target branches