Repository: pimutils/khal
Pull request #577 (2017-02-15 14:46:36)

Tweak sleep_time to be as precise as possible
Tweak sleep_time to be as precise as possible, and also account for possible rounding error when our sleep is equal to the maximum precision (basically, for rounding in our favour).

See [this discussion](https://github.com/pimutils/khal/pull/575#pullrequestreview-22009618).

untitaker: It appears your last value of `1.1` is still not enough. I'd try starting with `0.001` and adding `0.001` until the mtime changes.
hobarrera: This new change should be safer.
untitaker: Hm, now this will return None on second-precision fs I think
untitaker: Suggestion:

    i = 0.000001
    while True:
        a = touch_and_mtime()
        sleep(i * 1.1)
        b = touch_and_mtime()
        if a != b:
            return i * 1.1
        i *= 10
hobarrera: Returning `i * 10` sounds safer because we're sure our sleeps are an order of magnitude above the timestamp precision. 
This is 10ms on most modern systems, so the entire test suite doesn't even increase in a single second.
hobarrera: As another alternative, we can `mock` the result of `os.stat`. This sounds like the best idea, and doesn't involve any sleeping.
untitaker: >Returning i * 10 sounds safer because we're sure our sleeps are an order of magnitude above the timestamp precision.

And it's 10 seconds on a system with second-precision
geier: I don't like mocking this, I'd go with untitaker's solution and wait till it fails somewhere again.
hobarrera: Back to this PR then, [this](https://github.com/pimutils/khal/pull/577#issuecomment-280055820) suggestion won't work.

Assume that precision is 100ms:
* Current time is 11:42:20.99999
* Record `a`
* Sleep 11ms
* Record `b`
* We noticed the `mtime` differ
* Okay, we return 11ms (WRONG!)

The chances of this happening are actually about 10%, so it's something worth considering.

This should work though:

```python
i = 0.000001
while True:
    a = touch_and_mtime()
    sleep(i)
    b = touch_and_mtime()
    sleep(i)
    c = touch_and_mtime()
    if a != b != c:
        return i * 1.1
    i *= 10
```

This fixes the above scenario. Chances of failure because of the current time are practically inexistant.

---

Note (mostly for the fun of it): This can fail on [leap seconds](https://en.wikipedia.org/wiki/Leap_second). Seriously, I don't care this means the loop has to be run *at an exact time* (with sub-second precision) in a window that only available once every year.
untitaker: Good point and I agree that your solution is excellent.

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index f3ac366..d51d3c8 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -7,19 +7,6 @@ Package maintainers and users who have to manually update their installation
 may want to subscribe to `GitHub's tag feed
 <https://github.com/geier/khal/tags.atom>`_.
 
-0.9.3
-=====
-not released yet
-
-* FIX `list` (and commands based on it like `calendar` and `at`) crashed
-  if `--notstarted` was given and allday events were found (introduced in 0.9.2)
-* FIX `list --notstarted` (and commands based on it) would show events only on
-  the first day of their occurrence and not on all further days
-* FIX `configure` would crash if neither "import config from vdirsyncer" nor
-  "create locale vdir" was selected
-
-* NEW khal will now show cancelled events with a big CANCELLED in front (can be
-  configured via event formatting)
 
 0.9.2
 =====
diff --git a/doc/source/usage.rst b/doc/source/usage.rst
index f211df3..d43e390 100644
--- a/doc/source/usage.rst
+++ b/doc/source/usage.rst
@@ -138,14 +138,6 @@ Several options are common to almost all of :program:`khal`'s commands
    end-necessary-long
         Same as end-necessary but uses datelong and datetimelong.
 
-   status
-       The status of the event (if this event has one), something like
-       `CONFIRMED` or `CANCELLED`.
-
-   cancelled
-       The string `CANCELLED` (plus one blank) if the event's status is
-       cancelled, otherwise nothing.
-
    By default all-day events have no times. To see a start and end time anyway simply
    add `-full` to the end of any template with start/end, for instance
    `start-time` becomes `start-time-full` and will always show start and end times (instead
diff --git a/khal/cli.py b/khal/cli.py
index 73210d5..c9bab59 100644
--- a/khal/cli.py
+++ b/khal/cli.py
@@ -258,11 +258,9 @@ def _get_cli():
                   help=('The format of the events.'))
     @click.option('--day-format', '-df',
                   help=('The format of the day line.'))
-    @click.option(
-        '--once', '-o',
-        help=('Print each event only once (even if it is repeated or spans multiple days).'),
-        is_flag=True)
-    @click.option('--notstarted', help=('Print only events that have not started.'),
+    @click.option('--once', '-o', help=('Print event only once'),
+                  is_flag=True)
+    @click.option('--notstarted', help=('Print only events that have not started'),
                   is_flag=True)
     @click.argument('DATERANGE', nargs=-1, required=False)
     @click.pass_context
@@ -299,11 +297,10 @@ def _get_cli():
                   help=('The format of the events.'))
     @click.option('--day-format', '-df',
                   help=('The format of the day line.'))
-    @click.option('--once', '-o', is_flag=True,
-                  help=('Print each event only once '
-                        '(even if it is repeated or spans multiple days).')
-                  )
-    @click.option('--notstarted', help=('Print only events that have not started.'),
+    @click.option(
+        '--once', '-o', is_flag=True,
+        help='Print events only once, even if they span multiple days')
+    @click.option('--notstarted', help=('Print only events that have not started'),
                   is_flag=True)
     @click.argument('DATERANGE', nargs=-1, required=False,
                     metavar='[DATETIME [DATETIME | RANGE]]')
diff --git a/khal/configwizard.py b/khal/configwizard.py
index 4d8b86b..0a61df4 100644
--- a/khal/configwizard.py
+++ b/khal/configwizard.py
@@ -146,12 +146,12 @@ def create_vdir(names=[]):
         print("Could not create directory {} because of {}. Exiting".format(path, error))
         raise
     print("Created new vdir at {}".format(path))
-    return [(name, path, 'calendar')]
+    return (name, path, 'calendar')
 
 
 def create_config(vdirs, dateformat, timeformat):
     config = ['[calendars]']
-    for name, path, type_ in sorted(vdirs or ()):
+    for name, path, type_ in sorted(vdirs) or ():
         config.append('\n[[{name}]]'.format(name=name))
         config.append('path = {path}'.format(path=path))
         config.append('type = {type}'.format(type=type_))
@@ -186,13 +186,10 @@ def configwizard():
     print()
     if not vdirs:
         try:
-            vdirs = create_vdir()
+            vdirs = [create_vdir()]
         except OSError as error:
             raise FatalError(error)
 
-    if not vdirs:
-        print("\nWARNING: no vdir configured, khal will not be usable like this!\n")
-
     config = create_config(vdirs, dateformat=dateformat, timeformat=timeformat)
     config_path = join(xdg.BaseDirectory.xdg_config_home, 'khal', 'config')
     if not confirm(
diff --git a/khal/controllers.py b/khal/controllers.py
index c0e7084..ffe7a5a 100644
--- a/khal/controllers.py
+++ b/khal/controllers.py
@@ -78,8 +78,7 @@ def calendar(collection, agenda_format=None, notstarted=False, once=False, dater
              highlight_event_days=0,
              full=False,
              bold_for_light_color=True,
-             env=None,
-             ):
+             **kwargs):
     term_width, _ = get_terminal_size()
     lwidth = 27 if conf['locale']['weeknumbers'] == 'right' else 25
     rwidth = term_width - lwidth - 4
@@ -102,8 +101,7 @@ def calendar(collection, agenda_format=None, notstarted=False, once=False, dater
         once=once,
         notstarted=notstarted,
         width=rwidth,
-        env=env,
-    )
+        **kwargs)
     calendar_column = calendar_display.vertical_month(
         month=start.month,
         year=start.year,
@@ -144,14 +142,59 @@ def start_end_from_daterange(daterange, locale,
     return start, end
 
 
-def get_events_between(
-        collection, locale, start, end, agenda_format=None, notstarted=False,
-        env=None, width=None, seen=None, original_start=None):
+def get_list_from_str(collection, locale, start, end, notstarted=False,
+                      agenda_format=None, day_format=None, once=False,
+                      env=None, show_all_days=False,
+                      **kwargs):
+    """returns a list of events scheduled in between `start` and `end`.
+
+    :param collection:
+    :type collection: khalendar.CalendarCollection
+    :param locale: locale settings
+    :type locale: dict
+    :param notstarted: True if each event should start after start (instead of
+        be active between start and end)
+    :type nostarted: bool
+    :param agenda_format: a format string that can be used in python string formatting
+    :type agenda_format: str
+    :param once: True if each event should only appear once
+    :type once: bool
+    :returns: a list to be printed as the agenda for the given datetime range
+    :rtype: list(str)
+    """
+
+    event_column = []
+    if once:
+        kwargs["seen"] = set()
+    if env is None:
+        env = {}
+    while start < end:
+        if start.date() == end.date():
+            day_end = end
+        else:
+            day_end = datetime.combine(start.date(), time.max)
+        current_events = get_list(
+            collection, locale=locale, agenda_format=agenda_format, start=start,
+            end=day_end, notstarted=notstarted, env=env,
+            **kwargs)
+        if day_format and (show_all_days or current_events):
+            event_column.append(format_day(start.date(), day_format, locale))
+        event_column.extend(current_events)
+        start = datetime(*start.date().timetuple()[:3]) + timedelta(days=1)
+
+    if event_column == []:
+        event_column = [style('No events', bold=True)]
+    return event_column
+
+
+def get_list(collection, locale, start, end, agenda_format=None, notstarted=False,
+             env=None, width=None, seen=None):
     """returns a list of events scheduled between start and end. Start and end
     are strings or datetimes (of some kind).
 
     :param collection:
     :type collection: khalendar.CalendarCollection
+
     :param start: the start datetime
     :param end: the end datetime
     :param agenda_format: a format string that can be used in python string formatting
@@ -160,14 +203,11 @@ def get_events_between(
     :type env: dict
     :param nostarted: True if each event should start after start (instead of
     be active between start and end)
-    :type nostarted: bool
-    :param original_start: start datetime to compare against of notstarted is set
-    :type original_start: datetime.datetime
+    :type nostarted: Boolean
     :returns: a list to be printed as the agenda for the given days
     :rtype: list(str)
-    """
-    assert not (notstarted and not original_start)
 
+    """
     event_list = []
     if env is None:
         env = {}
@@ -183,33 +223,25 @@ def get_events_between(
     events_float = sorted(collection.get_floating(start, end))
     events = sorted(events + events_float)
     for event in events:
-        # yes the the logic could be simplified, but I believe it's easier
-        # to understand what's going on here this way
-        if notstarted:
-            if event.allday and event.start < original_start.date():
-                    continue
-            elif not event.allday and event.start_local < original_start:
-                    continue
-        if seen is not None and event.uid in seen:
-            continue
-
-        try:
-            event_string = event.format(agenda_format, relative_to=(start, end), env=env)
-        except KeyError as error:
-            raise FatalError(error)
-
-        if width:
-            event_list += textwrap.wrap(event_string, width)
-        else:
-            event_list.append(event_string)
-        if seen is not None:
-            seen.add(event.uid)
+        if not (notstarted and event.event_start.replace(tzinfo=None) < start):
+            if seen is None or event.uid not in seen:
+                try:
+                    event_string = event.format(agenda_format, relative_to=(start, end), env=env)
+                except KeyError as error:
+                    raise FatalError(error)
+
+                if width:
+                    event_list += textwrap.wrap(event_string, width)
+                else:
+                    event_list.append(event_string)
+                if seen is not None:
+                    seen.add(event.uid)
 
     return event_list
 
 
 def khal_list(collection, daterange, conf=None, agenda_format=None, day_format=None,
-              once=False, notstarted=False, width=False, env=None):
+              once=False, notstarted=False, width=False, **kwargs):
     """returns a list of all events in `daterange`"""
     # because empty strings are also Falsish
     if agenda_format is None:
@@ -222,31 +254,13 @@ def khal_list(collection, daterange, conf=None, agenda_format=None, day_format=N
         default_timedelta_date=conf['default']['timedelta'],
         default_timedelta_datetime=conf['default']['timedelta'],
     )
-
-    event_column = []
-    once = set() if once else None
-    if env is None:
-        env = {}
-
-    original_start = conf['locale']['local_timezone'].localize(start)
-    while start < end:
-        if start.date() == end.date():
-            day_end = end
-        else:
-            day_end = datetime.combine(start.date(), time.max)
-        current_events = get_events_between(
-            collection, locale=conf['locale'], agenda_format=agenda_format, start=start,
-            end=day_end, notstarted=notstarted, original_start=original_start,
-            env=env,
-            seen=once,
-        )
-        if day_format and (conf['default']['show_all_days'] or current_events):
-            event_column.append(format_day(start.date(), day_format, conf['locale']))
-        event_column.extend(current_events)
-        start = datetime(*start.date().timetuple()[:3]) + timedelta(days=1)
-
-    if event_column == []:
-        event_column = [style('No events', bold=True)]
+    event_column = get_list_from_str(
+        collection, agenda_format=agenda_format, start=start, end=end, day_format=day_format,
+        once=once, notstarted=notstarted,
+        show_all_days=conf['default']['show_all_days'],
+        locale=conf['locale'],
+        width=width,
+        **kwargs)
     return event_column
 
 
diff --git a/khal/khalendar/event.py b/khal/khalendar/event.py
index 832dbb3..5d51a12 100644
--- a/khal/khalendar/event.py
+++ b/khal/khalendar/event.py
@@ -575,9 +575,6 @@ class Event(object):
             attributes['reset'] = attributes['bold'] = ''
             for c in ["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"]:
                 attributes[c] = attributes[c + '-bold'] = ''
-
-        attributes['status'] = self.status
-        attributes['cancelled'] = 'CANCELLED ' if self.status == 'CANCELLED' else ''
         return format_string.format(**dict(attributes)) + attributes["reset"]
 
     def duplicate(self):
@@ -614,10 +611,6 @@ class Event(object):
         for key in to_pop:
             self._vevents.pop(key)
 
-    @property
-    def status(self):
-        return self._vevents[self.ref].get('STATUS', '')
-
 
 class DatetimeEvent(Event):
     pass
diff --git a/khal/settings/khal.spec b/khal/settings/khal.spec
index b2ce793..7e7b47e 100644
--- a/khal/settings/khal.spec
+++ b/khal/settings/khal.spec
@@ -242,7 +242,7 @@ bold_for_light_color = boolean(default=True)
 # ignored in `ikhal`, where events will always be shown in the color of the
 # calendar they belong to.
 # The syntax is the same as for :option:`--format`.
-agenda_event_format = string(default='{calendar-color}{cancelled}{start-end-time-style} {title}{repeat-symbol}{description-separator}{description}{reset}')
+agenda_event_format = string(default='{calendar-color}{start-end-time-style} {title}{repeat-symbol}{description-separator}{description}{reset}')
 
 # Specifies how each *day header* is formated.
 agenda_day_format = string(default='{bold}{name}, {date-long}{reset}')
@@ -252,7 +252,7 @@ agenda_day_format = string(default='{bold}{name}, {date-long}{reset}')
 # :command:`list` and :command:`calendar`. It is therefore probably a sensible
 # choice to include the start- and end-date.
 # The syntax is the same as for :option:`--format`.
-event_format = string(default='{calendar-color}{cancelled}{start}-{end} {title}{repeat-symbol}{description-separator}{description}{reset}')
+event_format = string(default='{calendar-color}{start}-{end} {title}{repeat-symbol}{description-separator}{description}{reset}')
 
 # When highlight_event_days is enabled, this section specifies how
 # the highlighting/coloring of days is handled.


Test patch:
diff --git a/tests/cli_test.py b/tests/cli_test.py
index cf884ad..4177f72 100644
--- a/tests/cli_test.py
+++ b/tests/cli_test.py
@@ -182,69 +182,6 @@ def test_days(runner):
     assert not result.exception
 
 
-def test_notstarted(runner):
-    with freeze_time('2015-6-1 15:00'):
-        runner = runner(default_command='calendar', days=2)
-        for command in [
-                'new 30.5.2015 5.6.2015 long event',
-                'new 2.6.2015 4.6.2015 two day event',
-                'new 1.6.2015 14:00 18:00 four hour event',
-                'new 1.6.2015 16:00 17:00 one hour event',
-                'new 2.6.2015 10:00 13:00 three hour event',
-        ]:
-            result = runner.invoke(main_khal, command.split())
-            assert not result.exception
-
-        result = runner.invoke(main_khal, 'list now'.split())
-        assert result.output == \
-            """Today, 01.06.2015
-↔ long event
-14:00-18:00 four hour event
-16:00-17:00 one hour event
-Tomorrow, 02.06.2015
-↔ long event
-↦ two day event
-10:00-13:00 three hour event
-Wednesday, 03.06.2015
-↔ long event
-↔ two day event
-"""
-        assert not result.exception
-        result = runner.invoke(main_khal, 'list now --notstarted'.split())
-        assert result.output == \
-            """Today, 01.06.2015
-16:00-17:00 one hour event
-Tomorrow, 02.06.2015
-↦ two day event
-10:00-13:00 three hour event
-Wednesday, 03.06.2015
-↔ two day event
-"""
-        assert not result.exception
-
-        result = runner.invoke(main_khal, 'list now --once'.split())
-        assert result.output == \
-            """Today, 01.06.2015
-↔ long event
-14:00-18:00 four hour event
-16:00-17:00 one hour event
-Tomorrow, 02.06.2015
-↦ two day event
-10:00-13:00 three hour event
-"""
-        assert not result.exception
-
-        result = runner.invoke(main_khal, 'list now --once --notstarted'.split())
-        assert result.output == \
-            """Today, 01.06.2015
-16:00-17:00 one hour event
-Tomorrow, 02.06.2015
-↦ two day event
-10:00-13:00 three hour event
-"""
-        assert not result.exception
-
-
 def test_calendar(runner):
     with freeze_time('2015-6-1'):
         runner = runner(default_command='calendar', days=0)
@@ -511,6 +448,7 @@ def choices(ordering=0, separator=0, dateconfirm=True,
             create_vdir=False,
             write_config=True):
     """helper function to generate input for testing `configure`"""
+    assert parse_vdirsyncer_conf != create_vdir
     confirm = {True: 'y', False: 'n'}
 
     out = [
@@ -717,18 +655,6 @@ def test_configure_command_cannot_create_vdir(runner):
     assert result.exit_code == 1
 
 
-def test_configure_no_vdir(runner):
-    runner = runner()
-    runner.config_file.remove()
-    result = runner.invoke(
-        main_khal, ['configure'],
-        input=choices(parse_vdirsyncer_conf=False, create_vdir=False),
-    )
-    assert 'khal will not be usable like this' in result.output
-    assert result.exit_code == 0
-    assert not result.exception
-
-
 def test_edit(runner):
     runner = runner()
     result = runner.invoke(main_khal, ['list'])
diff --git a/tests/conftest.py b/tests/conftest.py
index acf87fd..9ad5a0c 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -54,6 +54,8 @@ def never_echo_bytes(monkeypatch):
 @pytest.fixture(scope='session')
 def sleep_time(tmpdir_factory):
     """
+    Returns the filesystem's mtime precision
+
     Returns how long we need to sleep for the filesystem's mtime precision to
     pick up differences.
 
@@ -67,10 +69,21 @@ def sleep_time(tmpdir_factory):
         stat = os.stat(str(tmpfile))
         return getattr(stat, 'st_mtime_ns', stat.st_mtime)
 
-    first = touch_and_mtime()
-    sleep(0.1)
-    second = touch_and_mtime()
-
-    if first < second:
-        return 0.01
-    return 1.1
+    i = 0.00001
+    while i < 100:
+        # Measure three times to avoid things like 12::18:11.9994 [mis]passing
+        first = touch_and_mtime()
+        sleep(i)
+        second = touch_and_mtime()
+        sleep(i)
+        third = touch_and_mtime()
+
+        if first != second != third:
+            return i * 1.1
+        i = i * 10
+
+    # This should never happen, but oh, well:
+    raise Exception(
+        'Filesystem does not seem to save modified times of files. \n'
+        'Cannot run tests that depend on this.'
+    )
diff --git a/tests/controller_test.py b/tests/controller_test.py
index 34a3c4a..24de827 100644
--- a/tests/controller_test.py
+++ b/tests/controller_test.py
@@ -4,7 +4,7 @@ from textwrap import dedent
 from freezegun import freeze_time
 
 from khal.khalendar.vdir import Item
-from khal.controllers import import_ics, khal_list, start_end_from_daterange
+from khal.controllers import import_ics, get_list_from_str, start_end_from_daterange
 
 from .utils import _get_text
 from . import utils
@@ -31,26 +31,28 @@ item_today = Item(event_today)
 event_format = '{calendar-color}{start-end-time-style:16} {title}'
 event_format += '{repeat-symbol}{description-separator}{description}{calendar-color}'
 
-conf = {'locale': utils.LOCALE_BERLIN,
-        'default': {'timedelta': dt.timedelta(days=2), 'show_all_days': False}
-        }
-
 
 class TestGetAgenda(object):
     def test_new_event(self, coll_vdirs):
         coll, vdirs = coll_vdirs
         event = coll.new_event(event_today, utils.cal1)
         coll.new(event)
+        start, end = start_end_from_daterange([], utils.LOCALE_BERLIN)
         assert ['                 a meeting :: short description\x1b[0m'] == \
-            khal_list(coll, [], conf, agenda_format=event_format, day_format="")
+            get_list_from_str(
+                coll, utils.LOCALE_BERLIN, start, end, agenda_format=event_format, day_format="")
 
     def test_new_event_day_format(self, coll_vdirs):
         coll, vdirs = coll_vdirs
         event = coll.new_event(event_today, utils.cal1)
         coll.new(event)
+        start, end = start_end_from_daterange([], utils.LOCALE_BERLIN)
         assert ['Today\x1b[0m',
                 '                 a meeting :: short description\x1b[0m'] == \
-            khal_list(coll, [], conf, agenda_format=event_format, day_format="{name}")
+            get_list_from_str(
+                coll, utils.LOCALE_BERLIN, start, end,
+                agenda_format=event_format, day_format="{name}",
+            )
 
     def test_empty_recurrence(self, coll_vdirs):
         coll, vidrs = coll_vdirs
@@ -65,8 +67,10 @@ class TestGetAgenda(object):
             'DTEND:20110908T170000\r\n'
             'END:VEVENT\r\n'
         ), utils.cal1))
+        start, end = start_end_from_daterange([], utils.LOCALE_BERLIN)
         assert 'no events' in '\n'.join(
-            khal_list(coll, [], conf, agenda_format=event_format, day_format="{name}")).lower()
+            get_list_from_str(coll, utils.LOCALE_BERLIN, start, end, agenda_format=event_format)
+        ).lower()
 
 
 class TestImport(object):
diff --git a/tests/event_test.py b/tests/event_test.py
index 7110700..dd1e002 100644
--- a/tests/event_test.py
+++ b/tests/event_test.py
@@ -15,9 +15,8 @@ from .utils import normalize_component, _get_text, \
 
 EVENT_KWARGS = {'calendar': 'foobar', 'locale': LOCALE_BERLIN}
 
-LIST_FORMAT = '{calendar-color}{cancelled}{start-end-time-style} {title} {repeat-symbol}'
-SEARCH_FORMAT = '{calendar-color}{cancelled}{start-long}{to-style}' + \
-    '{end-necessary-long} {title} {repeat-symbol}'
+LIST_FORMAT = '{calendar-color}{start-end-time-style} {title} {repeat-symbol}'
+SEARCH_FORMAT = '{calendar-color}{start-long}{to-style}{end-necessary-long} {title} {repeat-symbol}'
 
 
 def test_no_initialization():
@@ -342,16 +341,6 @@ def test_multi_uid():
         assert line in event.raw.split('\r\n')
 
 
-def test_cancelled_instance():
-    orig_event_str = _get_text('event_rrule_recuid_cancelled')
-    event = Event.fromString(orig_event_str, ref='1405314000', **EVENT_KWARGS)
-    assert event.format(SEARCH_FORMAT, date(2014, 7, 14)) == \
-        'CANCELLED 14.07.2014 07:00-12:00 Arbeit ⟳\x1b[0m'
-    event = Event.fromString(orig_event_str, **EVENT_KWARGS)
-    assert event.format(SEARCH_FORMAT, date(2014, 7, 14)) == \
-        '30.06.2014 07:00-12:00 Arbeit ⟳\x1b[0m'
-
-
 def test_recur():
     event = Event.fromString(_get_text('event_dt_rr'), **EVENT_KWARGS)
     assert event.recurring is True
diff --git a/tests/ics/event_rrule_recuid_cancelled.ics b/tests/ics/event_rrule_recuid_cancelled.ics
deleted file mode 100644
index c01516d..0000000
--- a/tests/ics/event_rrule_recuid_cancelled.ics
+++ /dev/null
@@ -1,26 +0,0 @@
-BEGIN:VCALENDAR
-VERSION:2.0
-PRODID:-//CALENDARSERVER.ORG//NONSGML Version 1//EN
-BEGIN:VEVENT
-UID:event_rrule_recurrence_id
-SUMMARY:Arbeit
-RRULE:FREQ=WEEKLY;UNTIL=20140806T060000Z
-DTSTART;TZID=Europe/Berlin:20140630T070000
-DTEND;TZID=Europe/Berlin:20140630T120000
-END:VEVENT
-BEGIN:VEVENT
-UID:event_rrule_recurrence_id
-SUMMARY:Arbeit
-RECURRENCE-ID:20140707T050000Z
-DTSTART;TZID=Europe/Berlin:20140707T090000
-DTEND;TZID=Europe/Berlin:20140707T140000
-END:VEVENT
-BEGIN:VEVENT
-UID:event_rrule_recurrence_id
-SUMMARY:Arbeit
-RECURRENCE-ID:20140714T050000Z
-DTSTART;TZID=Europe/Berlin:20140714T070000
-DTEND;TZID=Europe/Berlin:20140714T120000
-STATUS:CANCELLED
-END:VEVENT
-END:VCALENDAR