mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-03-25 08:55:50 +00:00
175 lines
5.4 KiB
Python
175 lines
5.4 KiB
Python
from __future__ import annotations
|
|
|
|
import datetime
|
|
from textwrap import dedent
|
|
|
|
import aiohttp
|
|
import aiostream
|
|
import pytest
|
|
from aioresponses import aioresponses
|
|
|
|
from tests import EVENT_TEMPLATE
|
|
from tests import TASK_TEMPLATE
|
|
from tests import VCARD_TEMPLATE
|
|
from tests.storage import format_item
|
|
from vdirsyncer import exceptions
|
|
from vdirsyncer.storage.dav import CalDAVStorage
|
|
|
|
from . import DAVStorageTests
|
|
from . import dav_server
|
|
|
|
|
|
class TestCalDAVStorage(DAVStorageTests):
|
|
storage_class = CalDAVStorage
|
|
|
|
@pytest.fixture(params=["VTODO", "VEVENT"])
|
|
def item_type(self, request):
|
|
return request.param
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_doesnt_accept_vcard(self, item_type, get_storage_args):
|
|
s = self.storage_class(item_types=(item_type,), **await get_storage_args())
|
|
|
|
try:
|
|
await s.upload(format_item(VCARD_TEMPLATE))
|
|
except (exceptions.Error, aiohttp.ClientResponseError):
|
|
# Most storages hard-fail, but xandikos doesn't.
|
|
pass
|
|
|
|
assert not await aiostream.stream.list(s.list())
|
|
|
|
# The `arg` param is not named `item_types` because that would hit
|
|
# https://bitbucket.org/pytest-dev/pytest/issue/745/
|
|
@pytest.mark.parametrize(
|
|
"arg,calls_num",
|
|
[
|
|
(("VTODO",), 1),
|
|
(("VEVENT",), 1),
|
|
(("VTODO", "VEVENT"), 2),
|
|
(("VTODO", "VEVENT", "VJOURNAL"), 3),
|
|
((), 1),
|
|
],
|
|
)
|
|
@pytest.mark.xfail(dav_server == "baikal", reason="Baikal returns 500.")
|
|
@pytest.mark.asyncio
|
|
async def test_item_types_performance(
|
|
self, get_storage_args, arg, calls_num, monkeypatch
|
|
):
|
|
s = self.storage_class(item_types=arg, **await get_storage_args())
|
|
old_parse = s._parse_prop_responses
|
|
calls = []
|
|
|
|
def new_parse(*a, **kw):
|
|
calls.append(None)
|
|
return old_parse(*a, **kw)
|
|
|
|
monkeypatch.setattr(s, "_parse_prop_responses", new_parse)
|
|
await aiostream.stream.list(s.list())
|
|
assert len(calls) == calls_num
|
|
|
|
@pytest.mark.xfail(
|
|
dav_server == "radicale", reason="Radicale doesn't support timeranges."
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_timerange_correctness(self, get_storage_args):
|
|
start_date = datetime.datetime(2013, 9, 10)
|
|
end_date = datetime.datetime(2013, 9, 13)
|
|
s = self.storage_class(
|
|
start_date=start_date, end_date=end_date, **await get_storage_args()
|
|
)
|
|
|
|
too_old_item = format_item(
|
|
dedent(
|
|
"""
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:19970714T170000Z
|
|
DTEND:19970715T035959Z
|
|
SUMMARY:Bastille Day Party
|
|
X-SOMETHING:{r}
|
|
UID:{r}
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
"""
|
|
).strip()
|
|
)
|
|
|
|
too_new_item = format_item(
|
|
dedent(
|
|
"""
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:20150714T170000Z
|
|
DTEND:20150715T035959Z
|
|
SUMMARY:Another Bastille Day Party
|
|
X-SOMETHING:{r}
|
|
UID:{r}
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
"""
|
|
).strip()
|
|
)
|
|
|
|
good_item = format_item(
|
|
dedent(
|
|
"""
|
|
BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
|
|
BEGIN:VEVENT
|
|
DTSTART:20130911T170000Z
|
|
DTEND:20130912T035959Z
|
|
SUMMARY:What's with all these Bastille Day Partys
|
|
X-SOMETHING:{r}
|
|
UID:{r}
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
"""
|
|
).strip()
|
|
)
|
|
|
|
await s.upload(too_old_item)
|
|
await s.upload(too_new_item)
|
|
expected_href, _ = await s.upload(good_item)
|
|
|
|
((actual_href, _),) = await aiostream.stream.list(s.list())
|
|
assert actual_href == expected_href
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_invalid_resource(self, monkeypatch, get_storage_args):
|
|
args = await get_storage_args(collection=None)
|
|
|
|
with aioresponses() as m:
|
|
m.add(args["url"], method="PROPFIND", status=200, body="Hello world")
|
|
|
|
with pytest.raises(ValueError):
|
|
s = self.storage_class(**args)
|
|
await aiostream.stream.list(s.list())
|
|
|
|
assert len(m.requests) == 1
|
|
|
|
@pytest.mark.skipif(dav_server == "icloud", reason="iCloud only accepts VEVENT")
|
|
@pytest.mark.skipif(
|
|
dav_server == "fastmail", reason="Fastmail has non-standard hadling of VTODOs."
|
|
)
|
|
@pytest.mark.xfail(dav_server == "baikal", reason="Baikal returns 500.")
|
|
@pytest.mark.asyncio
|
|
async def test_item_types_general(self, s):
|
|
event = (await s.upload(format_item(EVENT_TEMPLATE)))[0]
|
|
task = (await s.upload(format_item(TASK_TEMPLATE)))[0]
|
|
s.item_types = ("VTODO", "VEVENT")
|
|
|
|
async def hrefs():
|
|
return {href async for href, etag in s.list()}
|
|
|
|
assert await hrefs() == {event, task}
|
|
s.item_types = ("VTODO",)
|
|
assert await hrefs() == {task}
|
|
s.item_types = ("VEVENT",)
|
|
assert await hrefs() == {event}
|
|
s.item_types = ()
|
|
assert await hrefs() == {event, task}
|