diff --git a/.travis.yml b/.travis.yml index 2638532..3bb2c49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,5 @@ script: matrix: allow_failures: - # radicale db storage is broken in 0.8 + # radicale db storage is broken in 0.8, all tests fail - env: DAV_SERVER=radicale RADICALE_BACKEND=database REQUIREMENTS=release - - env: DAV_SERVER=owncloud REQUIREMENTS=release diff --git a/tests/storage/__init__.py b/tests/storage/__init__.py index 9471738..a774529 100644 --- a/tests/storage/__init__.py +++ b/tests/storage/__init__.py @@ -162,3 +162,4 @@ class StorageTests(object): assert not s.has('asd') href, etag = s.upload(self._create_bogus_item(1)) assert s.has(href) + assert not s.has('asd') diff --git a/tests/storage/dav/test_main.py b/tests/storage/dav/test_main.py index 2098841..b0257fa 100644 --- a/tests/storage/dav/test_main.py +++ b/tests/storage/dav/test_main.py @@ -91,6 +91,17 @@ class DavStorageTests(ServerMixin, StorageTests): pass assert not list(s.list()) + @pytest.mark.xfail(dav_server == 'owncloud', + reason='See issue #16') + def test_wrong_etag(self): + super(DavStorageTests, self).test_wrong_etag() + + @pytest.mark.xfail(dav_server == 'owncloud', + reason='See issue #16') + def test_update_nonexisting(self): + super(DavStorageTests, self).test_update_nonexisting() + + class TestCaldavStorage(DavStorageTests): storage_class = CaldavStorage diff --git a/vdirsyncer/storage/base.py b/vdirsyncer/storage/base.py index c342898..83f89c7 100644 --- a/vdirsyncer/storage/base.py +++ b/vdirsyncer/storage/base.py @@ -7,6 +7,7 @@ :license: MIT, see LICENSE for more details. ''' +from .. import exceptions class Item(object): @@ -80,6 +81,8 @@ class Storage(object): ''' :param href: href to fetch :returns: (item, etag) + :raises: :exc:`vdirsyncer.exceptions.PreconditionFailed` if item can't + be found. ''' raise NotImplementedError() @@ -87,7 +90,7 @@ class Storage(object): ''' :param hrefs: list of hrefs to fetch :raises: :exc:`vdirsyncer.exceptions.PreconditionFailed` if one of the - items couldn't be found. + items couldn't be found. :returns: iterable of (href, item, etag) ''' for href in hrefs: @@ -99,7 +102,12 @@ class Storage(object): check if item exists by href :returns: True or False ''' - raise NotImplementedError() + try: + self.get(href) + except exceptions.PreconditionFailed: + return False + else: + return True def upload(self, item): ''' diff --git a/vdirsyncer/storage/dav.py b/vdirsyncer/storage/dav.py index f9fcea0..181de99 100644 --- a/vdirsyncer/storage/dav.py +++ b/vdirsyncer/storage/dav.py @@ -189,14 +189,6 @@ class DavStorage(Storage): raise exceptions.NotFoundError(href) return rv - def has(self, href): - try: - self.get(href) - except exceptions.NotFoundError: - return False - else: - return True - def _put(self, href, item, etag): headers = self._default_headers() headers['Content-Type'] = self.item_mimetype diff --git a/vdirsyncer/storage/filesystem.py b/vdirsyncer/storage/filesystem.py index 95eea69..b98efce 100644 --- a/vdirsyncer/storage/filesystem.py +++ b/vdirsyncer/storage/filesystem.py @@ -109,12 +109,16 @@ class FilesystemStorage(Storage): def get(self, href): fpath = self._get_filepath(href) - with open(fpath, 'rb') as f: - return (Item(f.read().decode(self.encoding)), - _get_etag(fpath)) - - def has(self, href): - return os.path.isfile(self._get_filepath(href)) + try: + with open(fpath, 'rb') as f: + return (Item(f.read().decode(self.encoding)), + _get_etag(fpath)) + except IOError as e: + import errno + if e.errno == errno.ENOENT: + raise exceptions.NotFoundError(href) + else: + raise def upload(self, item): href = self._get_href(item.uid) diff --git a/vdirsyncer/storage/http.py b/vdirsyncer/storage/http.py index 517fcb3..847e6f3 100644 --- a/vdirsyncer/storage/http.py +++ b/vdirsyncer/storage/http.py @@ -115,6 +115,3 @@ class HttpStorage(Storage): def get(self, href): x = self._items[href] return x, hashlib.sha256(x.raw).hexdigest() - - def has(self, href): - return href in self._items