sync_ics2gcal/tests/test_sync.py

202 lines
6.4 KiB
Python
Raw Permalink Normal View History

2018-04-07 14:25:09 +00:00
import datetime
import hashlib
import operator
2018-04-09 12:08:45 +00:00
from copy import deepcopy
from random import shuffle
2022-06-03 21:57:38 +00:00
from typing import Union, List, Dict, Optional, AnyStr
2018-04-07 14:25:09 +00:00
import dateutil.parser
2018-04-17 19:41:14 +00:00
import pytest
2018-04-07 14:25:09 +00:00
from pytz import timezone, utc
2022-06-03 21:57:38 +00:00
from sync_ics2gcal import CalendarSync, DateDateTime
from sync_ics2gcal.gcal import EventDateOrDateTime, EventData, EventList
2018-04-07 14:25:09 +00:00
2022-06-03 21:57:38 +00:00
def sha1(s: AnyStr) -> str:
2018-04-17 19:41:14 +00:00
h = hashlib.sha1()
2022-06-03 21:57:38 +00:00
h.update(str(s).encode("utf8") if isinstance(s, str) else s)
2018-04-17 19:41:14 +00:00
return h.hexdigest()
2018-04-17 19:53:56 +00:00
2022-03-08 15:46:21 +00:00
def gen_events(
start: int,
stop: int,
2022-06-03 21:57:38 +00:00
start_time: DateDateTime,
2022-03-08 15:46:21 +00:00
no_time: bool = False,
2022-06-03 21:57:38 +00:00
) -> EventList:
duration: datetime.timedelta
date_key: str
date_end: str
2018-04-17 19:41:14 +00:00
if no_time:
2022-03-08 15:46:21 +00:00
start_time = datetime.date(start_time.year, start_time.month, start_time.day)
2022-06-03 21:57:38 +00:00
duration = datetime.date(1, 1, 2) - datetime.date(1, 1, 1)
date_key = "date"
date_end = ""
2018-04-17 19:41:14 +00:00
else:
2022-06-03 21:57:38 +00:00
start_time = utc.normalize(start_time.astimezone(utc)).replace(tzinfo=None) # type: ignore
duration = datetime.datetime(1, 1, 1, 2) - datetime.datetime(1, 1, 1, 1)
date_key = "dateTime"
date_end = "Z"
result: EventList = []
2018-04-17 19:41:14 +00:00
for i in range(start, stop):
event_start = start_time + (duration * i)
event_end = event_start + duration
2022-06-03 21:57:38 +00:00
updated: DateDateTime = event_start
if no_time:
2018-04-17 19:41:14 +00:00
updated = datetime.datetime(
2022-03-08 15:46:21 +00:00
updated.year, updated.month, updated.day, 0, 0, 0, 1, tzinfo=utc
)
2018-04-17 19:41:14 +00:00
2022-06-03 21:57:38 +00:00
event: EventData = {
2022-03-08 15:46:21 +00:00
"summary": "test event __ {}".format(i),
"location": "la la la {}".format(i),
"description": "test TEST -- test event {}".format(i),
2018-04-17 19:41:14 +00:00
"iCalUID": "{}@test.com".format(sha1("test - event {}".format(i))),
2022-03-08 15:46:21 +00:00
"updated": updated.isoformat() + "Z",
"created": updated.isoformat() + "Z",
2022-06-03 21:57:38 +00:00
"start": {date_key: event_start.isoformat() + date_end}, # type: ignore
"end": {date_key: event_end.isoformat() + date_end}, # type: ignore
2018-04-17 19:41:14 +00:00
}
result.append(event)
return result
2018-04-17 19:53:56 +00:00
def gen_list_to_compare(start: int, stop: int) -> EventList:
result: EventList = []
2018-04-17 19:41:14 +00:00
for i in range(start, stop):
2022-03-08 15:46:21 +00:00
result.append({"iCalUID": "test{:06d}".format(i)})
2018-04-17 19:41:14 +00:00
return result
2018-04-17 19:53:56 +00:00
2022-06-03 21:57:38 +00:00
def get_start_date(event: EventData) -> DateDateTime:
event_start: EventDateOrDateTime = event["start"]
2021-05-01 10:47:02 +00:00
start_date: Optional[str] = None
2018-04-17 19:41:14 +00:00
is_date = False
2022-03-08 15:46:21 +00:00
if "date" in event_start:
2022-06-03 21:57:38 +00:00
start_date = event_start["date"] # type: ignore
2018-04-17 19:41:14 +00:00
is_date = True
2022-03-08 15:46:21 +00:00
if "dateTime" in event_start:
2022-06-03 21:57:38 +00:00
start_date = event_start["dateTime"] # type: ignore
2018-04-17 19:41:14 +00:00
2022-06-03 21:57:38 +00:00
result: DateDateTime = dateutil.parser.parse(str(start_date))
2018-04-17 19:41:14 +00:00
if is_date:
result = datetime.date(result.year, result.month, result.day)
return result
2018-04-17 19:53:56 +00:00
def test_compare() -> None:
part_len: int = 20
2018-04-17 19:41:14 +00:00
# [1..2n]
lst_src = gen_list_to_compare(1, 1 + part_len * 2)
# [n..3n]
2022-03-08 15:46:21 +00:00
lst_dst = gen_list_to_compare(1 + part_len, 1 + part_len * 3)
2018-04-17 19:41:14 +00:00
lst_src_rnd = deepcopy(lst_src)
lst_dst_rnd = deepcopy(lst_dst)
shuffle(lst_src_rnd)
shuffle(lst_dst_rnd)
2022-03-08 15:46:21 +00:00
to_ins, to_upd, to_del = CalendarSync._events_list_compare(lst_src_rnd, lst_dst_rnd)
2018-04-17 19:41:14 +00:00
2018-04-17 19:53:56 +00:00
assert len(to_ins) == part_len
assert len(to_upd) == part_len
assert len(to_del) == part_len
2018-04-17 19:41:14 +00:00
2022-03-08 15:46:21 +00:00
assert sorted(to_ins, key=lambda x: x["iCalUID"]) == lst_src[:part_len]
assert sorted(to_del, key=lambda x: x["iCalUID"]) == lst_dst[part_len:]
2018-04-17 19:41:14 +00:00
to_upd_ok = list(zip(lst_src[part_len:], lst_dst[:part_len]))
2018-04-17 19:53:56 +00:00
assert len(to_upd) == len(to_upd_ok)
2018-04-17 19:41:14 +00:00
for item in to_upd_ok:
assert item in to_upd
2018-04-17 19:53:56 +00:00
2022-03-08 15:46:21 +00:00
@pytest.mark.parametrize("no_time", [True, False], ids=["date", "dateTime"])
def test_filter_events_by_date(no_time: bool) -> None:
2022-03-08 15:46:21 +00:00
msk = timezone("Europe/Moscow")
2018-04-17 19:41:14 +00:00
now = utc.localize(datetime.datetime.utcnow())
msk_now = msk.normalize(now.astimezone(msk))
part_len = 5
if no_time:
2022-03-08 15:46:21 +00:00
duration = datetime.date(1, 1, 2) - datetime.date(1, 1, 1)
2018-04-17 19:41:14 +00:00
else:
2022-03-08 15:46:21 +00:00
duration = datetime.datetime(1, 1, 1, 2) - datetime.datetime(1, 1, 1, 1)
2022-06-03 21:57:38 +00:00
date_cmp: DateDateTime = msk_now + (duration * part_len)
2018-04-09 12:08:45 +00:00
2018-04-17 19:41:14 +00:00
if no_time:
2022-03-08 15:46:21 +00:00
date_cmp = datetime.date(date_cmp.year, date_cmp.month, date_cmp.day)
2018-04-07 14:25:09 +00:00
2022-03-08 15:46:21 +00:00
events = gen_events(1, 1 + (part_len * 2), msk_now, no_time)
2018-04-17 19:41:14 +00:00
shuffle(events)
2018-04-07 14:25:09 +00:00
2022-03-08 15:46:21 +00:00
events_pending = CalendarSync._filter_events_by_date(events, date_cmp, operator.ge)
events_past = CalendarSync._filter_events_by_date(events, date_cmp, operator.lt)
2018-04-07 14:25:09 +00:00
2018-04-17 19:53:56 +00:00
assert len(events_pending) == 1 + part_len
assert len(events_past) == part_len - 1
2018-04-07 14:25:09 +00:00
2018-04-17 19:41:14 +00:00
for event in events_pending:
assert get_start_date(event) >= date_cmp
2018-04-17 19:41:14 +00:00
for event in events_past:
assert get_start_date(event) < date_cmp
2018-04-07 14:25:09 +00:00
def test_filter_events_to_update() -> None:
2022-03-08 15:46:21 +00:00
msk = timezone("Europe/Moscow")
2018-04-17 19:41:14 +00:00
now = utc.localize(datetime.datetime.utcnow())
msk_now = msk.normalize(now.astimezone(msk))
2018-04-07 14:25:09 +00:00
2022-03-08 15:46:21 +00:00
one_hour = datetime.datetime(1, 1, 1, 2) - datetime.datetime(1, 1, 1, 1)
2018-04-17 19:41:14 +00:00
date_upd = msk_now + (one_hour * 5)
2018-04-07 14:25:09 +00:00
2018-04-17 19:41:14 +00:00
count = 10
events_old = gen_events(1, 1 + count, msk_now)
events_new = gen_events(1, 1 + count, date_upd)
2018-04-07 14:25:09 +00:00
sync1 = CalendarSync(None, None) # type: ignore
2018-04-17 19:41:14 +00:00
sync1.to_update = list(zip(events_new, events_old))
sync1._filter_events_to_update()
2018-04-07 14:25:09 +00:00
sync2 = CalendarSync(None, None) # type: ignore
2018-04-17 19:41:14 +00:00
sync2.to_update = list(zip(events_old, events_new))
sync2._filter_events_to_update()
2018-04-07 14:25:09 +00:00
2018-04-17 19:53:56 +00:00
assert len(sync1.to_update) == count
2018-04-17 19:41:14 +00:00
assert sync2.to_update == []
def test_filter_events_no_updated() -> None:
2022-02-22 06:52:28 +00:00
"""
test filtering events that not have 'updated' field
such events should always pass the filter
"""
now = datetime.datetime.utcnow()
yesterday = now - datetime.timedelta(days=-1)
count = 10
events_old = gen_events(1, 1 + count, now)
2022-02-22 06:52:28 +00:00
events_new = gen_events(1, 1 + count, now)
2022-02-22 06:52:28 +00:00
# 1/2 updated=yesterday, 1/2 no updated field
i = 0
for event in events_new:
2022-02-22 06:52:28 +00:00
if 0 == i % 2:
2022-03-08 15:46:21 +00:00
event["updated"] = yesterday.isoformat() + "Z"
2022-02-22 06:52:28 +00:00
else:
2022-03-08 15:46:21 +00:00
del event["updated"]
2022-02-22 06:52:28 +00:00
i += 1
sync = CalendarSync(None, None) # type: ignore
2022-02-22 06:52:28 +00:00
sync.to_update = list(zip(events_old, events_new))
sync._filter_events_to_update()
assert len(sync.to_update) == count // 2