Skip to content

Commit

Permalink
Mock inotify & test the c-d-c-d-ds-i-ds-i sequence
Browse files Browse the repository at this point in the history
c = IN_CREATE|IS_DIR
d = IN_DELETE|IS_DIR
ds = IN_DELETE_SELF
i = IN_IGNORE

These are inotify events, not watchdog events

The new test is written in a new module because it required a
different teardown function to stop the emitter before undoing
the mock
  • Loading branch information
danilobellini committed Sep 24, 2016
1 parent 5fdc62a commit 69d4ca4
Showing 1 changed file with 117 additions and 0 deletions.
117 changes: 117 additions & 0 deletions tests/test_inotify_c.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
from __future__ import unicode_literals
import os
import pytest
import logging
import contextlib
from tests import Queue
from functools import partial
from .shell import rm, mkdtemp
from watchdog.utils import platform
from watchdog.events import DirCreatedEvent, DirDeletedEvent, DirModifiedEvent
from watchdog.observers.api import ObservedWatch

if platform.is_linux():
from watchdog.observers.inotify import InotifyFullEmitter, InotifyEmitter


logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)


def setup_function(function):
global p, event_queue
tmpdir = os.path.realpath(mkdtemp())
p = partial(os.path.join, tmpdir)
event_queue = Queue()


@contextlib.contextmanager
def watching(path=None, use_full_emitter=False):
path = p('') if path is None else path
global emitter
Emitter = InotifyFullEmitter if use_full_emitter else InotifyEmitter
emitter = Emitter(event_queue, ObservedWatch(path, recursive=True))
emitter.start()
yield
emitter.stop()
emitter.join(5)


def teardown_function(function):
rm(p(''), recursive=True)
assert not emitter.is_alive()


@pytest.mark.skipif(not platform.is_linux(),
reason="Testing with inotify messages (Linux only)")
def test_late_double_deletion(monkeypatch):
inotify_fd = type(str("FD"), (object,), {})() # Empty object
inotify_fd.last = 0
inotify_fd.wds = []

# CREATE DELETE CREATE DELETE DELETE_SELF IGNORE DELETE_SELF IGNORE
inotify_fd.buf = (
# IN_CREATE|IS_DIR (wd = 1, path = subdir1)
b"\x01\x00\x00\x00\x00\x01\x00\x40\x00\x00\x00\x00\x10\x00\x00\x00"
b"\x73\x75\x62\x64\x69\x72\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# IN_DELETE|IS_DIR (wd = 1, path = subdir1)
b"\x01\x00\x00\x00\x00\x02\x00\x40\x00\x00\x00\x00\x10\x00\x00\x00"
b"\x73\x75\x62\x64\x69\x72\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00"
) * 2 + (
# IN_DELETE_SELF (wd = 2)
b"\x02\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# IN_IGNORE (wd = 2)
b"\x02\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# IN_DELETE_SELF (wd = 3)
b"\x03\x00\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
# IN_IGNORE (wd = 3)
b"\x03\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
)

os_read_bkp = os.read
def fakeread(fd, length):
if fd is inotify_fd:
result, fd.buf = fd.buf[:length], fd.buf[length:]
return result
return os_read_bkp(fd, length)

os_close_bkp = os.close
def fakeclose(fd):
if fd is not inotify_fd:
os_close_bkp(fd)

def inotify_init():
return inotify_fd

def inotify_add_watch(fd, path, mask):
fd.last += 1
logger.debug("New wd = %d" % fd.last)
fd.wds.append(fd.last)
return fd.last

def inotify_rm_watch(fd, wd):
logger.debug("Removing wd = %d" % wd)
fd.wds.remove(wd)
return 0

# Mocks the API!
from watchdog.observers import inotify_c
monkeypatch.setattr(os, "read", fakeread)
monkeypatch.setattr(os, "close", fakeclose)
monkeypatch.setattr(inotify_c, "inotify_init", inotify_init)
monkeypatch.setattr(inotify_c, "inotify_add_watch", inotify_add_watch)
monkeypatch.setattr(inotify_c, "inotify_rm_watch", inotify_rm_watch)

with watching(p('')):
# Watchdog Events
for evt_cls in [DirCreatedEvent, DirDeletedEvent] * 2:
event = event_queue.get(timeout=5)[0]
assert isinstance(event, evt_cls)
assert event.src_path == p('subdir1')
event = event_queue.get(timeout=5)[0]
assert isinstance(event, DirModifiedEvent)
assert event.src_path == p('').rstrip(os.path.sep)

assert inotify_fd.last == 3 # Number of directories
assert inotify_fd.buf == b"" # Didn't miss any event
assert inotify_fd.wds == [2, 3] # Only 1 is removed explicitly

0 comments on commit 69d4ca4

Please sign in to comment.