@@ -197,7 +197,7 @@ def test_meeting_agenda(self):
197197
198198 # iCal
199199 r = self .client .get (urlreverse ("ietf.meeting.views.agenda_ical" , kwargs = dict (num = meeting .number ))
200- + "?" + session .group .parent .acronym .upper ())
200+ + "?show= " + session .group .parent .acronym .upper ())
201201 self .assertContains (r , session .group .acronym )
202202 self .assertContains (r , session .group .name )
203203 self .assertContains (r , slot .location .name )
@@ -580,6 +580,28 @@ def test_important_dates(self):
580580 post_date = meeting .importantdate_set .get (name = idn ).date
581581 self .assertEqual (pre_date , post_date + datetime .timedelta (days = 1 ))
582582
583+ def assert_ical_response_is_valid (self , response , expected_event_summaries = None , expected_event_count = None ):
584+ """Validate an HTTP response containing iCal data
585+
586+ Based on RFC2445, but not exhaustive by any means. Assumes a single iCalendar object.
587+ """
588+ self .assertEqual (response .get ('Content-Type' ), "text/calendar" )
589+
590+ # Validate iCalendar object
591+ self .assertContains (response , 'BEGIN:VCALENDAR' , count = 1 )
592+ self .assertContains (response , 'END:VCALENDAR' , count = 1 )
593+ self .assertContains (response , 'PRODID:' , count = 1 )
594+ self .assertContains (response , 'VERSION' , count = 1 )
595+
596+ # Validate event objects
597+ if expected_event_count is None :
598+ expected_event_count = len (expected_event_summaries )
599+ self .assertContains (response , 'BEGIN:VEVENT' , count = expected_event_count )
600+ self .assertContains (response , 'END:VEVENT' , count = expected_event_count )
601+ self .assertContains (response , 'UID' , count = expected_event_count )
602+ for summary in expected_event_summaries :
603+ self .assertContains (response , 'SUMMARY:' + summary )
604+
583605 def test_group_ical (self ):
584606 meeting = make_meeting_test_data ()
585607 s1 = Session .objects .filter (meeting = meeting , group__acronym = "mars" ).first ()
@@ -592,23 +614,226 @@ def test_group_ical(self):
592614 #
593615 url = urlreverse ('ietf.meeting.views.agenda_ical' , kwargs = {'num' :meeting .number , 'acronym' :s1 .group .acronym , })
594616 r = self .client .get (url )
595- self .assertEqual (r .get ('Content-Type' ), "text/calendar" )
596- self .assertContains (r , 'BEGIN:VEVENT' )
597- self .assertEqual (r .content .count (b'UID' ), 2 )
598- self .assertContains (r , 'SUMMARY:mars - Martian Special Interest Group' )
617+ self .assert_ical_response_is_valid (r ,
618+ expected_event_summaries = ['mars - Martian Special Interest Group' ],
619+ expected_event_count = 2 )
599620 self .assertContains (r , t1 .time .strftime ('%Y%m%dT%H%M%S' ))
600621 self .assertContains (r , t2 .time .strftime ('%Y%m%dT%H%M%S' ))
601- self .assertContains (r , 'END:VEVENT' )
602622 #
603623 url = urlreverse ('ietf.meeting.views.agenda_ical' , kwargs = {'num' :meeting .number , 'session_id' :s1 .id , })
604624 r = self .client .get (url )
605- self .assertEqual (r .get ('Content-Type' ), "text/calendar" )
606- self .assertContains (r , 'BEGIN:VEVENT' )
607- self .assertEqual (r .content .count (b'UID' ), 1 )
608- self .assertContains (r , 'SUMMARY:mars - Martian Special Interest Group' )
625+ self .assert_ical_response_is_valid (r ,
626+ expected_event_summaries = ['mars - Martian Special Interest Group' ],
627+ expected_event_count = 1 )
609628 self .assertContains (r , t1 .time .strftime ('%Y%m%dT%H%M%S' ))
610629 self .assertNotContains (r , t2 .time .strftime ('%Y%m%dT%H%M%S' ))
611- self .assertContains (r , 'END:VEVENT' )
630+
631+ def test_meeting_agenda_has_static_ical_links (self ):
632+ """Links to the agenda_ical view must appear on the agenda page
633+
634+ Confirms that these have the correct querystrings. Does not test the JS-based
635+ 'Customized schedule' button.
636+ """
637+ meeting = make_meeting_test_data ()
638+
639+ # get the agenda
640+ url = urlreverse ('ietf.meeting.views.agenda' , kwargs = dict (num = meeting .number ))
641+ r = self .client .get (url )
642+
643+ # Check that it has the links we expect
644+ ical_url = urlreverse ('ietf.meeting.views.agenda_ical' , kwargs = dict (num = meeting .number ))
645+ q = PyQuery (r .content )
646+ content = q ('#content' ).html ().lower () # don't care about case
647+ # Should be a 'non-area events' link showing appropriate types
648+ self .assertIn ('%s?showtypes=plenary,other' % ical_url , content )
649+ assignments = meeting .schedule .assignments .exclude (timeslot__type__in = ['lead' , 'offagenda' ])
650+ # Assume the test meeting is not using historic groups
651+ groups = [a .session .group for a in assignments if a .session is not None ]
652+ for g in groups :
653+ if g .parent_id is not None :
654+ self .assertIn ('%s?show=%s' % (ical_url , g .parent .acronym .lower ()), content )
655+
656+ def test_ical_filter_invalid_syntaxes (self ):
657+ meeting = make_meeting_test_data ()
658+ url = urlreverse ('ietf.meeting.views.agenda_ical' , kwargs = {'num' :meeting .number })
659+
660+ r = self .client .get (url + '?unknownparam=mars' )
661+ self .assertEqual (r .status_code , 400 , 'Unknown parameter should be rejected' )
662+
663+ r = self .client .get (url + '?mars' )
664+ self .assertEqual (r .status_code , 400 , 'Missing parameter name should be rejected' )
665+
666+ def do_ical_filter_test (self , meeting , querystring , expected_session_summaries ):
667+ url = urlreverse ('ietf.meeting.views.agenda_ical' , kwargs = {'num' :meeting .number })
668+ r = self .client .get (url + querystring )
669+ self .assertEqual (r .status_code , 200 )
670+ self .assert_ical_response_is_valid (r , expected_event_summaries = expected_session_summaries )
671+
672+ def test_ical_filter_default (self ):
673+ meeting = make_meeting_test_data ()
674+ self .do_ical_filter_test (
675+ meeting ,
676+ querystring = '' ,
677+ expected_session_summaries = [
678+ 'Morning Break' ,
679+ 'Registration' ,
680+ 'IETF Plenary' ,
681+ 'ames - Asteroid Mining Equipment Standardization Group' ,
682+ 'mars - Martian Special Interest Group' ,
683+ ]
684+ )
685+
686+ def test_ical_filter_show (self ):
687+ meeting = make_meeting_test_data ()
688+ self .do_ical_filter_test (
689+ meeting ,
690+ querystring = '?show=mars' ,
691+ expected_session_summaries = [
692+ 'mars - Martian Special Interest Group' ,
693+ ]
694+ )
695+
696+ def test_ical_filter_hide (self ):
697+ meeting = make_meeting_test_data ()
698+ self .do_ical_filter_test (
699+ meeting ,
700+ querystring = '?hide=ietf' ,
701+ expected_session_summaries = []
702+ )
703+
704+ def test_ical_filter_show_and_hide (self ):
705+ meeting = make_meeting_test_data ()
706+ self .do_ical_filter_test (
707+ meeting ,
708+ querystring = '?show=ames&hide=mars' ,
709+ expected_session_summaries = [
710+ 'ames - Asteroid Mining Equipment Standardization Group' ,
711+ ]
712+ )
713+
714+ def test_ical_filter_show_and_hide_same_group (self ):
715+ meeting = make_meeting_test_data ()
716+ self .do_ical_filter_test (
717+ meeting ,
718+ querystring = '?show=ames&hide=ames' ,
719+ expected_session_summaries = []
720+ )
721+
722+ def test_ical_filter_showtypes (self ):
723+ meeting = make_meeting_test_data ()
724+ # Show break/plenary types
725+ self .do_ical_filter_test (
726+ meeting ,
727+ querystring = '?showtypes=break,plenary' ,
728+ expected_session_summaries = [
729+ 'IETF Plenary' ,
730+ 'Morning Break' ,
731+ ]
732+ )
733+
734+ def test_ical_filter_hidetypes (self ):
735+ meeting = make_meeting_test_data ()
736+ self .do_ical_filter_test (
737+ meeting ,
738+ querystring = '?hidetypes=plenary' ,
739+ expected_session_summaries = []
740+ )
741+
742+ def test_ical_filter_showtypes_and_hidetypes (self ):
743+ meeting = make_meeting_test_data ()
744+ self .do_ical_filter_test (
745+ meeting ,
746+ querystring = '?showtypes=break&hidetypes=plenary' ,
747+ expected_session_summaries = [
748+ 'Morning Break' ,
749+ ]
750+ )
751+
752+ def test_ical_filter_showtypes_and_hidetypes_same_type (self ):
753+ meeting = make_meeting_test_data ()
754+ self .do_ical_filter_test (
755+ meeting ,
756+ querystring = '?showtypes=plenary&hidetypes=plenary' ,
757+ expected_session_summaries = []
758+ )
759+
760+ def test_ical_filter_show_and_showtypes (self ):
761+ meeting = make_meeting_test_data ()
762+ self .do_ical_filter_test (
763+ meeting ,
764+ querystring = '?show=mars&showtypes=plenary' ,
765+ expected_session_summaries = [
766+ 'IETF Plenary' ,
767+ 'mars - Martian Special Interest Group' ,
768+ ]
769+ )
770+
771+ def test_ical_filter_hide_and_showtypes (self ):
772+ meeting = make_meeting_test_data ()
773+ self .do_ical_filter_test (
774+ meeting ,
775+ querystring = '?hide=ames&showtypes=regular' ,
776+ expected_session_summaries = [
777+ 'mars - Martian Special Interest Group' ,
778+ ]
779+ )
780+
781+ def test_ical_filter_show_and_hidetypes (self ):
782+ meeting = make_meeting_test_data ()
783+ self .do_ical_filter_test (
784+ meeting ,
785+ querystring = '?show=ietf,mars&hidetypes=plenary' ,
786+ expected_session_summaries = [
787+ 'mars - Martian Special Interest Group' ,
788+ ]
789+ )
790+
791+ def test_ical_filter_hide_and_hidetypes (self ):
792+ meeting = make_meeting_test_data ()
793+ self .do_ical_filter_test (
794+ meeting ,
795+ querystring = '?hide=ietf,mars&hidetypes=plenary' ,
796+ expected_session_summaries = []
797+ )
798+
799+ def test_ical_filter_show_hide_and_showtypes (self ):
800+ meeting = make_meeting_test_data ()
801+ # ames regular session should be suppressed
802+ self .do_ical_filter_test (
803+ meeting ,
804+ querystring = '?show=mars&hide=ames&showtypes=plenary,regular' ,
805+ expected_session_summaries = [
806+ 'IETF Plenary' ,
807+ 'mars - Martian Special Interest Group' ,
808+ ]
809+ )
810+
811+ def test_ical_filter_show_hide_and_hidetypes (self ):
812+ meeting = make_meeting_test_data ()
813+ # ietf plenary session should be suppressed
814+ self .do_ical_filter_test (
815+ meeting ,
816+ querystring = '?show=mars,ietf&hide=ames&hidetypes=plenary' ,
817+ expected_session_summaries = [
818+ 'mars - Martian Special Interest Group' ,
819+ ]
820+ )
821+
822+ def test_ical_filter_all_params (self ):
823+ meeting = make_meeting_test_data ()
824+ # should include Morning Break / Registration due to secretariat in show list
825+ # should include mars SIG because regular in showtypes list
826+ # should not include IETF plenary because plenary in hidetypes list
827+ # should not show ames SIG because ames in hide list
828+ self .do_ical_filter_test (
829+ meeting ,
830+ querystring = '?show=secretariat,ietf&hide=ames&showtypes=regular&hidetypes=plenary' ,
831+ expected_session_summaries = [
832+ 'Morning Break' ,
833+ 'Registration' ,
834+ 'mars - Martian Special Interest Group' ,
835+ ]
836+ )
612837
613838 def build_session_setup (self ):
614839 # This setup is intentionally unusual - the session has one draft attached as a session presentation,
0 commit comments