# Copyright The IETF Trust 2020, All Rights Reserved # -*- coding: utf-8 -*- from django.conf import settings from django.test import override_settings from ietf.group.factories import GroupFactory from ietf.group.models import Group from ietf.meeting.factories import SessionFactory, MeetingFactory, TimeSlotFactory from ietf.meeting.helpers import AgendaFilterOrganizer, AgendaKeywordTagger from ietf.meeting.models import SchedTimeSessAssignment from ietf.meeting.test_data import make_meeting_test_data from ietf.utils.test_utils import TestCase # override the legacy office hours setting to guarantee consistency with the tests @override_settings(MEETING_LEGACY_OFFICE_HOURS_END=111) class AgendaKeywordTaggerTests(TestCase): def do_test_tag_assignments_with_filter_keywords(self, meeting_num, bof=False, historic=None): """Assignments should be tagged properly The historic param can be None, group, or parent, to specify whether to test with no historic_group, a historic_group but no historic_parent, or both. """ # decide whether meeting should use legacy keywords (for office hours) legacy_keywords = meeting_num <= 111 # create meeting and groups meeting = MeetingFactory(type_id='ietf', number=meeting_num) group_state_id = 'bof' if bof else 'active' group = GroupFactory(state_id=group_state_id) # Set up the historic group and parent if needed. Keep track of these as expected_* # for later reference. If not using historic group or parent, fall back to the non-historic # groups. if historic: expected_group = GroupFactory(state_id=group_state_id) if historic == 'parent': expected_area = GroupFactory(type_id='area') expected_group.historic_parent = expected_area else: expected_area = expected_group.parent else: expected_group = group expected_area = group.parent # create sessions, etc session_data = [ { 'description': 'regular wg session', 'session': SessionFactory( group=group, meeting=meeting, add_to_schedule=False, purpose_id='none' if legacy_keywords else 'regular', type_id='regular', ), 'expected_keywords': { expected_group.acronym, expected_area.acronym, # if legacy_keywords, next line repeats a previous entry to avoid adding anything to the set expected_group.acronym if legacy_keywords else 'regular', f'{expected_group.acronym}-sessa', }, }, { 'description': 'plenary session', 'session': SessionFactory( group=group, meeting=meeting, add_to_schedule=False, name=f'{group.acronym} plenary', purpose_id='none' if legacy_keywords else 'plenary', type_id='plenary', ), 'expected_keywords': { expected_group.acronym, expected_area.acronym, f'{expected_group.acronym}-sessb', 'plenary', f'{group.acronym}-plenary', }, }, { 'description': 'office hours session', 'session': SessionFactory( group=group, meeting=meeting, add_to_schedule=False, name=f'{group.acronym} office hours', purpose_id='none' if legacy_keywords else 'officehours', type_id='other', ), 'expected_keywords': { expected_group.acronym, expected_area.acronym, f'{expected_group.acronym}-sessc', 'officehours', f'{group.acronym}-officehours' if legacy_keywords else 'officehours', # officehours in prev line is a repeated value - since this is a set, it will be ignored f'{group.acronym}-office-hours', }, } ] for sd in session_data: sd['session'].timeslotassignments.create( timeslot=TimeSlotFactory(meeting=meeting, type=sd['session'].type), schedule=meeting.schedule, ) assignments = meeting.schedule.assignments.all() # Set up historic groups if needed. if historic: for a in assignments: a.session.historic_group = expected_group # Execute the method under test AgendaKeywordTagger(assignments=assignments).apply() # Assert expected results # check the assignment count - paranoid, but the method mutates its input so let's be careful self.assertEqual(len(assignments), len(session_data), 'Should not change number of assignments') assignment_by_session_pk = {a.session.pk: a for a in assignments} for sd in session_data: assignment = assignment_by_session_pk[sd['session'].pk] expected_filter_keywords = sd['expected_keywords'] if bof: expected_filter_keywords.add('bof') self.assertCountEqual( assignment.filter_keywords, expected_filter_keywords, f'Assignment for "{sd["description"]}" has incorrect filter keywords' ) @override_settings(MEETING_LEGACY_OFFICE_HOURS_END=111) def test_tag_assignments_with_filter_keywords(self): # use distinct meeting numbers > 111 for non-legacy keyword tests self.do_test_tag_assignments_with_filter_keywords(112) self.do_test_tag_assignments_with_filter_keywords(113, historic='group') self.do_test_tag_assignments_with_filter_keywords(114, historic='parent') self.do_test_tag_assignments_with_filter_keywords(115, bof=True) self.do_test_tag_assignments_with_filter_keywords(116, bof=True, historic='group') self.do_test_tag_assignments_with_filter_keywords(117, bof=True, historic='parent') @override_settings(MEETING_LEGACY_OFFICE_HOURS_END=111) def test_tag_assignments_with_filter_keywords_legacy(self): # use distinct meeting numbers <= 111 for legacy keyword tests self.do_test_tag_assignments_with_filter_keywords(101) self.do_test_tag_assignments_with_filter_keywords(102, historic='group') self.do_test_tag_assignments_with_filter_keywords(103, historic='parent') self.do_test_tag_assignments_with_filter_keywords(104, bof=True) self.do_test_tag_assignments_with_filter_keywords(105, bof=True, historic='group') self.do_test_tag_assignments_with_filter_keywords(106, bof=True, historic='parent') class AgendaFilterOrganizerTests(TestCase): def test_get_filter_categories(self): self.do_get_filter_categories_test(False) def test_get_legacy_filter_categories(self): self.do_get_filter_categories_test(True) def do_get_filter_categories_test(self, legacy): # set up meeting = make_meeting_test_data() if legacy: meeting.session_set.all().update(purpose_id='none') # legacy meetings did not have purposes else: meeting.number = str(settings.MEETING_LEGACY_OFFICE_HOURS_END + 1) meeting.save() # create extra groups for testing iab = Group.objects.get(acronym='iab') iab_child = GroupFactory(type_id='iab', parent=iab) irtf = Group.objects.get(acronym='irtf') irtf_child = GroupFactory(parent=irtf, state_id='bof') # non-area group sessions SessionFactory(group=iab_child, meeting=meeting) SessionFactory(group=irtf_child, meeting=meeting) # office hours session SessionFactory( group=Group.objects.get(acronym='farfut'), purpose_id='officehours' if not legacy else 'none', type_id='other', name='FARFUT office hours', meeting=meeting ) if legacy: expected = [ [ # area category {'label': 'FARFUT', 'keyword': 'farfut', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'ames', 'keyword': 'ames', 'is_bof': False, 'toggled_by': ['farfut']}, {'label': 'mars', 'keyword': 'mars', 'is_bof': False, 'toggled_by': ['farfut']}, ]}, ], [ # non-area category {'label': 'IAB', 'keyword': 'iab', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': iab_child.acronym, 'keyword': iab_child.acronym, 'is_bof': False, 'toggled_by': ['iab']}, ]}, {'label': 'IRTF', 'keyword': 'irtf', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': irtf_child.acronym, 'keyword': irtf_child.acronym, 'is_bof': True, 'toggled_by': ['bof', 'irtf']}, ]}, ], [ # non-group category {'label': 'Office Hours', 'keyword': 'officehours', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'FARFUT', 'keyword': 'farfut-officehours', 'is_bof': False, 'toggled_by': ['officehours', 'farfut']} ]}, {'label': None, 'keyword': None,'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'BoF', 'keyword': 'bof', 'is_bof': False, 'toggled_by': []}, {'label': 'Plenary', 'keyword': 'plenary', 'is_bof': False, 'toggled_by': []}, ]}, ], ] else: expected = [ [ # area category {'label': 'FARFUT', 'keyword': 'farfut', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'ames', 'keyword': 'ames', 'is_bof': False, 'toggled_by': ['farfut']}, {'label': 'mars', 'keyword': 'mars', 'is_bof': False, 'toggled_by': ['farfut']}, ]}, ], [ # non-area category {'label': 'IAB', 'keyword': 'iab', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': iab_child.acronym, 'keyword': iab_child.acronym, 'is_bof': False, 'toggled_by': ['iab']}, ]}, {'label': 'IRTF', 'keyword': 'irtf', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': irtf_child.acronym, 'keyword': irtf_child.acronym, 'is_bof': True, 'toggled_by': ['bof', 'irtf']}, ]}, ], [ # non-group category {'label': 'Administrative', 'keyword': 'admin', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'Registration', 'keyword': 'registration', 'is_bof': False, 'toggled_by': ['admin', 'secretariat']}, ]}, {'label': 'Closed meeting', 'keyword': 'closed_meeting', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'IESG Breakfast', 'keyword': 'iesg-breakfast', 'is_bof': False, 'toggled_by': ['closed_meeting', 'iesg']}, ]}, {'label': 'Office hours', 'keyword': 'officehours', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'FARFUT office hours', 'keyword': 'farfut-office-hours', 'is_bof': False, 'toggled_by': ['officehours', 'farfut']} ]}, {'label': 'Plenary', 'keyword': 'plenary', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'IETF Plenary', 'keyword': 'ietf-plenary', 'is_bof': False, 'toggled_by': ['plenary', 'ietf']}, ]}, {'label': 'Social', 'keyword': 'social', 'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'Morning Break', 'keyword': 'morning-break', 'is_bof': False, 'toggled_by': ['social', 'secretariat']}, ]}, {'label': None, 'keyword': None,'is_bof': False, 'toggled_by': [], 'children': [ {'label': 'BoF', 'keyword': 'bof', 'is_bof': False, 'toggled_by': []}, ]}, ], ] # put all the above together for single-column tests expected_single_category = [sum(expected, [])] ### # test using sessions sessions = meeting.session_set.all() AgendaKeywordTagger(sessions=sessions).apply() # default filter_organizer = AgendaFilterOrganizer(sessions=sessions) self.assertEqual(filter_organizer.get_filter_categories(), expected) # single-column filter_organizer = AgendaFilterOrganizer(sessions=sessions, single_category=True) self.assertEqual(filter_organizer.get_filter_categories(), expected_single_category) ### # test again using assignments assignments = SchedTimeSessAssignment.objects.filter( schedule__in=(meeting.schedule, meeting.schedule.base) ) AgendaKeywordTagger(assignments=assignments).apply() # default filter_organizer = AgendaFilterOrganizer(assignments=assignments) self.assertEqual(filter_organizer.get_filter_categories(), expected) # single-column filter_organizer = AgendaFilterOrganizer(assignments=assignments, single_category=True) self.assertEqual(filter_organizer.get_filter_categories(), expected_single_category) def test_get_non_area_keywords(self): # set up meeting = make_meeting_test_data() # create a session in a 'special' group, which should then appear in the non-area keywords team = GroupFactory(type_id='team') SessionFactory(group=team, meeting=meeting) # and a BoF bof = GroupFactory(state_id='bof') SessionFactory(group=bof, meeting=meeting) expected = sorted(['bof', 'plenary', team.acronym.lower()]) ### # by sessions sessions = meeting.session_set.all() AgendaKeywordTagger(sessions=sessions).apply() filter_organizer = AgendaFilterOrganizer(sessions=sessions) self.assertEqual(filter_organizer.get_non_area_keywords(), expected) filter_organizer = AgendaFilterOrganizer(sessions=sessions, single_category=True) self.assertEqual(filter_organizer.get_non_area_keywords(), expected) ### # by assignments assignments = meeting.schedule.assignments.all() AgendaKeywordTagger(assignments=assignments).apply() filter_organizer = AgendaFilterOrganizer(assignments=assignments) self.assertEqual(filter_organizer.get_non_area_keywords(), expected) filter_organizer = AgendaFilterOrganizer(assignments=assignments, single_category=True) self.assertEqual(filter_organizer.get_non_area_keywords(), expected)