import datetime import json from unittest import mock import pytest from requests.exceptions import ConnectionError from requests.models import Response from chrono.agendas.models import Agenda, TimePeriod from chrono.utils.date import get_weekday_index from chrono.utils.lingo import CheckType, get_agenda_check_types from .utils import build_agendas, build_meetings_agenda, build_virtual_agenda, paris, utc def test_get_weekday_index(): for date in ( datetime.date(2021, 11, 1), # month starting a Monday datetime.date(2021, 12, 1), # month starting a Wednesday datetime.date(2021, 5, 1), # month starting a Sunday ): assert get_weekday_index(date) == 1 assert get_weekday_index(date.replace(day=3)) == 1 assert get_weekday_index(date.replace(day=7)) == 1 assert get_weekday_index(date.replace(day=8)) == 2 assert get_weekday_index(date.replace(day=10)) == 2 assert get_weekday_index(date.replace(day=14)) == 2 assert get_weekday_index(date.replace(day=15)) == 3 assert get_weekday_index(date.replace(day=21)) == 3 assert get_weekday_index(date.replace(day=22)) == 4 assert get_weekday_index(date.replace(day=28)) == 4 assert get_weekday_index(date.replace(day=29)) == 5 assert get_weekday_index(date.replace(day=30)) == 5 CHECK_TYPES_DATA = [ {'id': 'bar-reason', 'kind': 'presence', 'text': 'Bar reason'}, {'id': 'foo-reason', 'kind': 'absence', 'text': 'Foo reason'}, ] class MockedRequestResponse(mock.Mock): status_code = 200 def json(self): return json.loads(self.content) def test_get_agenda_check_types_no_service(settings): agenda = Agenda(slug='foo') settings.KNOWN_SERVICES = {} assert get_agenda_check_types(agenda) == [] settings.KNOWN_SERVICES = {'other': []} assert get_agenda_check_types(agenda) == [] def test_get_agenda_check_types(): agenda = Agenda(slug='foo') with mock.patch('requests.Session.get') as requests_get: requests_get.side_effect = ConnectionError() assert get_agenda_check_types(agenda) == [] with mock.patch('requests.Session.get') as requests_get: mock_resp = Response() mock_resp.status_code = 500 requests_get.return_value = mock_resp assert get_agenda_check_types(agenda) == [] with mock.patch('requests.Session.get') as requests_get: mock_resp = Response() mock_resp.status_code = 404 requests_get.return_value = mock_resp assert get_agenda_check_types(agenda) == [] with mock.patch('requests.Session.get') as requests_get: requests_get.return_value = MockedRequestResponse(content=json.dumps({'foo': 'bar'})) assert get_agenda_check_types(agenda) == [] data = {'data': []} with mock.patch('requests.Session.get') as requests_get: requests_get.return_value = MockedRequestResponse(content=json.dumps(data)) assert get_agenda_check_types(agenda) == [] assert requests_get.call_args_list[0][0] == ('api/agenda/foo/check-types/',) assert requests_get.call_args_list[0][1]['remote_service']['url'] == 'http://lingo.example.org' data = {'data': CHECK_TYPES_DATA} with mock.patch('requests.Session.get') as requests_get: requests_get.return_value = MockedRequestResponse(content=json.dumps(data)) assert get_agenda_check_types(agenda) == [ CheckType(slug='bar-reason', label='Bar reason', kind='presence'), CheckType(slug='foo-reason', label='Foo reason', kind='absence'), ] def test_build_meetings_agenda(db): agenda = build_meetings_agenda( meeting_types=[30], resources=['Re1'], desks=('Desk 1', 'monday-friday 09:00-12:00 14:00-17:00') ) assert agenda.slug == 'agenda' assert agenda.label == 'Agenda' assert agenda._mt_30 assert list(agenda.meetingtype_set.all()) == [agenda._mt_30] assert agenda.desk_set.count() == 1 assert agenda.desk_set.all()[0].slug == 'desk-1' timeperiods = agenda.desk_set.all()[0].timeperiod_set.all() assert timeperiods.count() == 10 assert set(timeperiods.values_list('weekday', flat=True)) == set(range(0, 5)) assert set(timeperiods.values_list('start_time', 'end_time')) == { (datetime.time(9), datetime.time(12)), (datetime.time(14), datetime.time(17)), } assert agenda.resources.count() == 1 assert agenda.resources.get().label == 'Re1' assert agenda.resources.get().slug == 're1' def test_build_meetings_agenda_multiple_desks(db): agenda = build_meetings_agenda( meeting_types=[30], desks={ 'desk-1': ['monday-friday 09:00-12:00'], 'desk-2': ['monday-friday 14:00-17:00'], }, ) desks = agenda.desk_set.all() assert set(desks.values_list('slug', flat=True)) == {'desk-1', 'desk-2'} assert agenda.desk_set.all()[0].slug == 'desk-1' timeperiods = TimePeriod.objects.filter(desk__in=desks) assert timeperiods.count() == 10 assert set(timeperiods.values_list('weekday', flat=True)) == set(range(0, 5)) assert set(timeperiods.values_list('start_time', 'end_time')) == { (datetime.time(9), datetime.time(12)), (datetime.time(14), datetime.time(17)), } def test_build_virtual_agenda(db): agenda = build_virtual_agenda( agendas={ 'Agenda 1': { 'desks': ('Bureau 1', 'monday-friday 08:00-12:00 14:00-17:00'), }, 'Agenda 2': { 'desks': ('Bureau 1', 'monday,tuesday 09:00-12:00'), }, 'Agenda 3': { 'desks': ('Bureau 1', 'monday-friday 15:00-17:00'), }, }, meeting_types=[30], ) assert agenda._agenda_1 assert agenda._agenda_1._mt_30 assert agenda._agenda_2 assert agenda._agenda_3 assert agenda._mt_30 assert agenda.real_agendas.count() == 3 timeperiods = TimePeriod.objects.filter(desk__agenda__in=agenda.real_agendas.all()) assert timeperiods.count() == 17 assert set(timeperiods.values_list('weekday', flat=True)) == set(range(0, 5)) assert set(timeperiods.values_list('start_time', 'end_time')) == { (datetime.time(8), datetime.time(12)), (datetime.time(9), datetime.time(12)), (datetime.time(14), datetime.time(17)), (datetime.time(15), datetime.time(17)), } assert agenda._agenda_1 def test_build_agendas(db): # pylint: disable=unused-variable ICS_SAMPLE = """BEGIN:VCALENDAR VERSION:2.0 PRODID:-//foo.bar//EN BEGIN:VEVENT DTSTAMP:20170824T082855Z DTSTART:20170831T170800Z DTEND:20170831T203400Z SEQUENCE:1 SUMMARY:Événement 1 END:VEVENT BEGIN:VEVENT DTSTAMP:20170824T092855Z DTSTART:20170830T180800Z DTEND:20170831T223400Z SEQUENCE:2 END:VEVENT END:VCALENDAR""" unavailability_calendar, agenda_1, agenda_2, virtual = build_agendas( ''' unavailability-calendar Congés exception Noël start_datetime paris('2023-12-25T00:00:00 24h') exception-source sample.ics ICS_SAMPLE meetings "Agenda 1" maximal_booking_delay=15 30 45 # comment 1 # comment 2 desk "Desk 1" timeperiod monday-friday 08:00-12:00 exception Grève start_datetime paris('2023-04-01T01:01:01') end_datetime paris('2023-04-01T01:01:01') exception-source sample.ics ICS_SAMPLE unavailability-calendar Congés desk "Bureau 2" timeperiod monday-friday 14:00-17:00 meetings 'Agenda 2' 30 desk "Desk 1" monday-friday 08:00-12:00 desk "Desk 2" monday,friday 14:00-17:00 virtual "Agenda 3" 30 meetings CNI desk bureau1 monday-friday 10:00-12:00 meetings Passeport desk bureau2 monday-friday 14:00-17:00 ''' ) assert unavailability_calendar.label == 'Congés' assert unavailability_calendar._noel assert unavailability_calendar._sample_ics assert agenda_1.label == 'Agenda 1' assert agenda_1.maximal_booking_delay == 15 assert agenda_1._desk_1._greve assert agenda_1._desk_1._sample_ics assert agenda_1._desk_1 assert agenda_1._desk_1._conges == unavailability_calendar assert agenda_1._bureau_2 assert agenda_1._mt_30 assert agenda_1._mt_45 assert agenda_2.label == 'Agenda 2' assert agenda_2._desk_1 assert agenda_2._desk_2 assert agenda_2._mt_30 assert virtual._cni._bureau1 assert virtual._cni._mt_30 assert virtual._mt_30 assert virtual._passeport._bureau2 assert virtual._passeport._mt_30 def test_build_agendas_indentation_mismatch(db): with pytest.raises(SyntaxError, match=r'on line 5'): build_agendas( ''' agenda xxx zobi dd kkk iii # here, bad indentation agenda "Agenda 1" 30 desk 1 desk 2 ''' ) def test_paris(): assert paris('2023-04-19T11:00:00').isoformat() == '2023-04-19T11:00:00+02:00' def test_utc(): assert utc('2023-04-19T11:00:00').isoformat() == '2023-04-19T11:00:00+00:00'