# Copyright The IETF Trust 2021, All Rights Reserved # -*- coding: utf-8 -*- """Tests of models in the Meeting application""" import datetime from mock import patch from django.conf import settings from django.test import override_settings from ietf.group.factories import GroupFactory, GroupHistoryFactory from ietf.meeting.factories import MeetingFactory, SessionFactory, AttendedFactory, SessionPresentationFactory from ietf.meeting.models import Session from ietf.stats.factories import MeetingRegistrationFactory from ietf.utils.test_utils import TestCase from ietf.utils.timezone import date_today, datetime_today class MeetingTests(TestCase): def test_get_attendance_pre110(self): """Pre-110 meetings do not calculate attendance""" meeting = MeetingFactory(type_id='ietf', number='109') MeetingRegistrationFactory.create_batch(3, meeting=meeting, reg_type='') MeetingRegistrationFactory.create_batch(4, meeting=meeting, reg_type='remote') MeetingRegistrationFactory.create_batch(5, meeting=meeting, reg_type='in_person') self.assertIsNone(meeting.get_attendance()) def test_get_attendance_110(self): """Look at attendance as captured at 110""" meeting = MeetingFactory(type_id='ietf', number='110') # start with attendees that should be ignored MeetingRegistrationFactory.create_batch(3, meeting=meeting, reg_type='', attended=True) MeetingRegistrationFactory(meeting=meeting, reg_type='', attended=False) attendance = meeting.get_attendance() self.assertIsNotNone(attendance) self.assertEqual(attendance.remote, 0) self.assertEqual(attendance.onsite, 0) # add online attendees with at least one who registered but did not attend MeetingRegistrationFactory.create_batch(4, meeting=meeting, reg_type='remote', attended=True) MeetingRegistrationFactory(meeting=meeting, reg_type='remote', attended=False) attendance = meeting.get_attendance() self.assertIsNotNone(attendance) self.assertEqual(attendance.remote, 4) self.assertEqual(attendance.onsite, 0) # and the same for onsite attendees MeetingRegistrationFactory.create_batch(5, meeting=meeting, reg_type='onsite', attended=True) MeetingRegistrationFactory(meeting=meeting, reg_type='in_person', attended=False) attendance = meeting.get_attendance() self.assertIsNotNone(attendance) self.assertEqual(attendance.remote, 4) self.assertEqual(attendance.onsite, 5) # and once more after removing all the online attendees meeting.meetingregistration_set.filter(reg_type='remote').delete() attendance = meeting.get_attendance() self.assertIsNotNone(attendance) self.assertEqual(attendance.remote, 0) self.assertEqual(attendance.onsite, 5) def test_get_attendance_113(self): """Simulate IETF 113 attendance gathering data""" meeting = MeetingFactory(type_id='ietf', number='113') MeetingRegistrationFactory(meeting=meeting, reg_type='onsite', attended=True, checkedin=False) MeetingRegistrationFactory(meeting=meeting, reg_type='onsite', attended=False, checkedin=True) p1 = MeetingRegistrationFactory(meeting=meeting, reg_type='onsite', attended=False, checkedin=False).person AttendedFactory(session__meeting=meeting, person=p1) p2 = MeetingRegistrationFactory(meeting=meeting, reg_type='remote', attended=False, checkedin=False).person AttendedFactory(session__meeting=meeting, person=p2) attendance = meeting.get_attendance() self.assertEqual(attendance.onsite, 3) self.assertEqual(attendance.remote, 1) def test_get_attendance_keeps_meetings_distinct(self): """No cross-talk between attendance for different meetings""" # numbers are arbitrary here first_mtg = MeetingFactory(type_id='ietf', number='114') second_mtg = MeetingFactory(type_id='ietf', number='115') # Create a person who attended a remote session for first_mtg and onsite for second_mtg without # checking in for either. p = MeetingRegistrationFactory(meeting=second_mtg, reg_type='onsite', attended=False, checkedin=False).person AttendedFactory(session__meeting=first_mtg, person=p) MeetingRegistrationFactory(meeting=first_mtg, person=p, reg_type='remote', attended=False, checkedin=False) AttendedFactory(session__meeting=second_mtg, person=p) att = first_mtg.get_attendance() self.assertEqual(att.onsite, 0) self.assertEqual(att.remote, 1) att = second_mtg.get_attendance() self.assertEqual(att.onsite, 1) self.assertEqual(att.remote, 0) def test_vtimezone(self): # normal time zone that should have a zoneinfo file meeting = MeetingFactory(type_id='ietf', time_zone='America/Los_Angeles', populate_schedule=False) vtz = meeting.vtimezone() self.assertIsNotNone(vtz) self.assertGreater(len(vtz), 0) # time zone that does not have a zoneinfo file should return None meeting = MeetingFactory(type_id='ietf', time_zone='Fake/Time_Zone', populate_schedule=False) vtz = meeting.vtimezone() self.assertIsNone(vtz) # ioerror trying to read zoneinfo should return None meeting = MeetingFactory(type_id='ietf', time_zone='America/Los_Angeles', populate_schedule=False) with patch('ietf.meeting.models.io.open', side_effect=IOError): vtz = meeting.vtimezone() self.assertIsNone(vtz) def test_group_at_the_time(self): m = MeetingFactory(type_id='ietf', date=date_today() - datetime.timedelta(days=10)) cached_groups = GroupFactory.create_batch(2) m.cached_groups_at_the_time = {g.pk: g for g in cached_groups} # fake the cache uncached_group_hist = GroupHistoryFactory(time=datetime_today() - datetime.timedelta(days=30)) self.assertEqual(m.group_at_the_time(uncached_group_hist.group), uncached_group_hist) self.assertIn(uncached_group_hist.group.pk, m.cached_groups_at_the_time) class SessionTests(TestCase): def test_chat_archive_url(self): session = SessionFactory( meeting__date=datetime.date.today(), meeting__number=120, # needs to use proceedings_format_version > 1 ) with override_settings(): if hasattr(settings, 'CHAT_ARCHIVE_URL_PATTERN'): del settings.CHAT_ARCHIVE_URL_PATTERN self.assertEqual(session.chat_archive_url(), session.chat_room_url()) settings.CHAT_ARCHIVE_URL_PATTERN = 'http://chat.example.com' self.assertEqual(session.chat_archive_url(), 'http://chat.example.com') chatlog = SessionPresentationFactory(session=session, document__type_id='chatlog').document self.assertEqual(session.chat_archive_url(), chatlog.get_href()) # datatracker 8.8.0 rolled out on 2022-07-15. Before that, chat logs were jabber logs hosted at www.ietf.org. session_with_jabber = SessionFactory(group__acronym='fakeacronym', meeting__date=datetime.date(2022,7,14)) self.assertEqual(session_with_jabber.chat_archive_url(), 'https://www.ietf.org/jabber/logs/fakeacronym?C=M;O=D') chatlog = SessionPresentationFactory(session=session_with_jabber, document__type_id='chatlog').document self.assertEqual(session_with_jabber.chat_archive_url(), chatlog.get_href()) def test_chat_room_name(self): session = SessionFactory(group__acronym='xyzzy') self.assertEqual(session.chat_room_name(), 'xyzzy') session.type_id = 'plenary' self.assertEqual(session.chat_room_name(), 'plenary') session.chat_room = 'fnord' self.assertEqual(session.chat_room_name(), 'fnord') def test_alpha_str(self): self.assertEqual(Session._alpha_str(0), "a") self.assertEqual(Session._alpha_str(1), "b") self.assertEqual(Session._alpha_str(25), "z") self.assertEqual(Session._alpha_str(26), "aa") self.assertEqual(Session._alpha_str(27 * 26 - 1), "zz") self.assertEqual(Session._alpha_str(27 * 26), "aaa") def test_session_recording_url(self): group_acronym = "foobar" meeting_date = date_today() meeting_number = 123 # IETF meeting session = SessionFactory( meeting__type_id='ietf', meeting__date=meeting_date, group__acronym=group_acronym, meeting__number=meeting_number, ) with override_settings(): if hasattr(settings, "MEETECHO_SESSION_RECORDING_URL"): del settings.MEETECHO_SESSION_RECORDING_URL self.assertIsNone(session.session_recording_url()) settings.MEETECHO_SESSION_RECORDING_URL = "http://player.example.com" self.assertEqual(session.session_recording_url(), "http://player.example.com") settings.MEETECHO_SESSION_RECORDING_URL = "http://player.example.com?{session_label}" self.assertIn(f"IETF{meeting_number}-{group_acronym.upper()}", session.session_recording_url()) self.assertIn(f"{meeting_date.strftime('%Y%m%d')}", session.session_recording_url()) self.assertTrue(session.session_recording_url().startswith("http://player.example.com")) # interim meeting session = SessionFactory( meeting__type_id='interim', meeting__date=meeting_date, group__acronym=group_acronym, ) with override_settings(): if hasattr(settings, "MEETECHO_SESSION_RECORDING_URL"): del settings.MEETECHO_SESSION_RECORDING_URL self.assertIsNone(session.session_recording_url()) settings.MEETECHO_SESSION_RECORDING_URL = "http://player.example.com" self.assertEqual(session.session_recording_url(), "http://player.example.com") settings.MEETECHO_SESSION_RECORDING_URL = "http://player.example.com?{session_label}" self.assertIn(f"IETF-{group_acronym.upper()}", session.session_recording_url()) self.assertIn(f"{meeting_date.strftime('%Y%m%d')}", session.session_recording_url()) self.assertTrue(session.session_recording_url().startswith("http://player.example.com"))