Fix conflict detection

Fix conflict detection by providing finer rules. Meetings on alternating
weeks no longer conflict. Meetings on overlapping times now conflict.

Add proper tests to check all combinations.

Change-Id: I069cdd40fecb5fd7a2ab828a495bdf627ca1a811
This commit is contained in:
Thierry Carrez 2015-02-25 12:16:50 +01:00
parent d6963905f1
commit 40f12c0d63
3 changed files with 73 additions and 22 deletions

View File

@ -28,15 +28,17 @@ class Schedule(object):
self.time = datetime.datetime.strptime(sched_yaml['time'], '%H%M') self.time = datetime.datetime.strptime(sched_yaml['time'], '%H%M')
self.day = sched_yaml['day'] self.day = sched_yaml['day']
self.irc = sched_yaml['irc'] self.irc = sched_yaml['irc']
self.freq = sched_yaml['frequency']
self.recurrence = supported_recurrences[sched_yaml['frequency']] self.recurrence = supported_recurrences[sched_yaml['frequency']]
def __eq__(self, other): def conflicts(self, other):
#TODO(ttx): This is a bit overzealous (it will report as conflict """Checks for conflicting schedules."""
# biweekly-odd/biweekly-even on same date/hour/irc) so this should be alternating = set(['biweekly-odd', 'biweekly-even'])
# revamped especially if we want to add more complex recurrence rules return (
return ((self.day == other.day) and ((self.day == other.day) and
(self.time == other.time) and (abs(self.time - other.time) < datetime.timedelta(hours=1)) and
(self.irc == other.irc)) (self.irc == other.irc)) and
(set([self.freq, other.freq]) != alternating))
class Meeting(object): class Meeting(object):
@ -106,7 +108,7 @@ def check_for_meeting_conflicts(meetings):
other_schedules = meetings[j].schedules other_schedules = meetings[j].schedules
for schedule in schedules: for schedule in schedules:
for other_schedule in other_schedules: for other_schedule in other_schedules:
if schedule == other_schedule: if schedule.conflicts(other_schedule):
msg_dict = {'one': schedule.filefrom, msg_dict = {'one': schedule.filefrom,
'two': other_schedule.filefrom} 'two': other_schedule.filefrom}
raise MeetingConflictError( raise MeetingConflictError(

View File

@ -14,7 +14,7 @@
"""Sample meeting data to use for testing.""" """Sample meeting data to use for testing."""
FIRST_MEETING_YAML = """ WEEKLY_MEETING = """
project: OpenStack Subteam Meeting project: OpenStack Subteam Meeting
schedule: schedule:
- time: '1200' - time: '1200'
@ -28,10 +28,10 @@ agenda: |
* Top bugs this week * Top bugs this week
""" """
SECOND_MEETING_YAML = """ CONFLICTING_WEEKLY_MEETING = """
project: OpenStack Subteam Meeting 2 project: OpenStack Subteam Meeting 2
schedule: schedule:
- time: '1200' - time: '1230'
day: Wednesday day: Wednesday
irc: openstack-meeting irc: openstack-meeting
frequency: weekly frequency: weekly
@ -42,7 +42,7 @@ agenda: |
* New features * New features
""" """
THIRD_MEETING_YAML = """ WEEKLY_OTHER_CHANNEL_MEETING = """
project: OpenStack Subteam Meeting 3 project: OpenStack Subteam Meeting 3
schedule: schedule:
- time: '1200' - time: '1200'
@ -56,13 +56,40 @@ agenda: |
* New features * New features
""" """
BIWEEKLY_MEETING_YAML = """ ALTERNATING_MEETING = """
project: OpenStack Subteam Meeting project: OpenStack Subteam Meeting
schedule: schedule:
- time: '1200' - time: '1200'
day: Wednesday day: Wednesday
irc: openstack-meeting irc: openstack-meeting
frequency: biweekly-even frequency: biweekly-even
- time: '2200'
day: Wednesday
irc: openstack-meeting
frequency: biweekly-odd
chair: Jane Developer
description: >
Weekly meeting for Subteam project.
agenda: |
* Top bugs this week
"""
BIWEEKLY_EVEN_MEETING = """
project: OpenStack Subteam 12 Meeting
schedule:
- time: '2200'
day: Wednesday
irc: openstack-meeting
frequency: biweekly-even
chair: Jane Developer
description: >
Weekly meeting for Subteam project.
agenda: |
* Top bugs this week
"""
BIWEEKLY_ODD_MEETING = """
project: OpenStack Subteam 12 Meeting
schedule: schedule:
- time: '2200' - time: '2200'
day: Wednesday day: Wednesday

View File

@ -19,24 +19,46 @@ from yaml2ical.tests import sample_data
class MeetingTestCase(unittest.TestCase): class MeetingTestCase(unittest.TestCase):
def test_load_yaml_file(self): def test_load_yaml_file(self):
m = meeting.load_meetings(sample_data.FIRST_MEETING_YAML)[0] m = meeting.load_meetings(sample_data.WEEKLY_MEETING)[0]
self.assertEqual('OpenStack Subteam Meeting', m.project) self.assertEqual('OpenStack Subteam Meeting', m.project)
self.assertEqual('Joe Developer', m.chair) self.assertEqual('Joe Developer', m.chair)
self.assertEqual('Weekly meeting for Subteam project.\n', self.assertEqual('Weekly meeting for Subteam project.\n',
m.description) m.description)
def test_exception_raised_when_conflict_detected(self): def should_be_conflicting(self, yaml1, yaml2):
"""Exception is raised when a meeting conflict is detected.""" """Exception is raised when meetings should conflict."""
meeting_one = meeting.load_meetings(sample_data.FIRST_MEETING_YAML) meeting_one = meeting.load_meetings(yaml1)
meeting_two = meeting.load_meetings(sample_data.SECOND_MEETING_YAML) meeting_two = meeting.load_meetings(yaml2)
meeting_list = [meeting_one.pop(), meeting_two.pop()] meeting_list = [meeting_one.pop(), meeting_two.pop()]
self.assertRaises(meeting.MeetingConflictError, self.assertRaises(meeting.MeetingConflictError,
meeting.check_for_meeting_conflicts, meeting.check_for_meeting_conflicts,
meeting_list) meeting_list)
def test_no_exception_raised_with_diff_irc_rooms(self): def should_not_conflict(self, yaml1, yaml2):
"""No exception raised when using different IRC rooms.""" """No exception raised when meetings shouldn't conflict."""
meeting_one = meeting.load_meetings(sample_data.FIRST_MEETING_YAML) meeting_one = meeting.load_meetings(yaml1)
meeting_two = meeting.load_meetings(sample_data.THIRD_MEETING_YAML) meeting_two = meeting.load_meetings(yaml2)
meeting_list = [meeting_one.pop(), meeting_two.pop()] meeting_list = [meeting_one.pop(), meeting_two.pop()]
meeting.check_for_meeting_conflicts(meeting_list) meeting.check_for_meeting_conflicts(meeting_list)
def test_weekly_conflict(self):
self.should_be_conflicting(
sample_data.WEEKLY_MEETING,
sample_data.CONFLICTING_WEEKLY_MEETING)
self.should_not_conflict(
sample_data.WEEKLY_MEETING,
sample_data.WEEKLY_OTHER_CHANNEL_MEETING)
def test_biweekly_conflict(self):
self.should_be_conflicting(
sample_data.WEEKLY_MEETING,
sample_data.ALTERNATING_MEETING)
self.should_not_conflict(
sample_data.ALTERNATING_MEETING,
sample_data.BIWEEKLY_EVEN_MEETING)
self.should_be_conflicting(
sample_data.ALTERNATING_MEETING,
sample_data.BIWEEKLY_ODD_MEETING)
self.should_not_conflict(
sample_data.BIWEEKLY_ODD_MEETING,
sample_data.BIWEEKLY_EVEN_MEETING)