2222from django .contrib .auth .models import User
2323from django .test import Client , override_settings
2424from django .db .models import F
25+ from django .http import QueryDict
2526
2627import debug # pyflakes:ignore
2728
3738from ietf .meeting .test_data import make_meeting_test_data , make_interim_meeting , make_interim_test_data
3839from ietf .meeting .utils import finalize , condition_slide_order
3940from ietf .meeting .utils import add_event_info_to_session_qs
40- from ietf .meeting .views import session_draft_list
41+ from ietf .meeting .views import session_draft_list , parse_agenda_filter_params
4142from ietf .name .models import SessionStatusName , ImportantDateName , RoleName
4243from ietf .utils .decorators import skip_coverage
4344from ietf .utils .mail import outbox , empty_outbox , get_payload_text
6162 "location indicated in settings.py." )
6263 print (" " + skip_message )
6364
65+
66+ def assert_ical_response_is_valid (test_inst , response , expected_event_summaries = None , expected_event_count = None ):
67+ """Validate an HTTP response containing iCal data
68+
69+ Based on RFC2445, but not exhaustive by any means. Assumes a single iCalendar object.
70+ """
71+ test_inst .assertEqual (response .get ('Content-Type' ), "text/calendar" )
72+
73+ # Validate iCalendar object
74+ test_inst .assertContains (response , 'BEGIN:VCALENDAR' , count = 1 )
75+ test_inst .assertContains (response , 'END:VCALENDAR' , count = 1 )
76+ test_inst .assertContains (response , 'PRODID:' , count = 1 )
77+ test_inst .assertContains (response , 'VERSION' , count = 1 )
78+
79+ # Validate event objects
80+ if expected_event_summaries is not None :
81+ for summary in expected_event_summaries :
82+ test_inst .assertContains (response , 'SUMMARY:' + summary )
83+
84+ if expected_event_count is not None :
85+ test_inst .assertContains (response , 'BEGIN:VEVENT' , count = expected_event_count )
86+ test_inst .assertContains (response , 'END:VEVENT' , count = expected_event_count )
87+ test_inst .assertContains (response , 'UID' , count = expected_event_count )
88+
89+
6490class MeetingTests (TestCase ):
6591 def setUp (self ):
6692 self .materials_dir = self .tempdir ('materials' )
@@ -580,28 +606,6 @@ def test_important_dates(self):
580606 post_date = meeting .importantdate_set .get (name = idn ).date
581607 self .assertEqual (pre_date , post_date + datetime .timedelta (days = 1 ))
582608
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-
605609 def test_group_ical (self ):
606610 meeting = make_meeting_test_data ()
607611 s1 = Session .objects .filter (meeting = meeting , group__acronym = "mars" ).first ()
@@ -614,17 +618,18 @@ def test_group_ical(self):
614618 #
615619 url = urlreverse ('ietf.meeting.views.agenda_ical' , kwargs = {'num' :meeting .number , 'acronym' :s1 .group .acronym , })
616620 r = self .client .get (url )
617- self .assert_ical_response_is_valid (r ,
618- expected_event_summaries = ['mars - Martian Special Interest Group' ],
619- expected_event_count = 2 )
621+ assert_ical_response_is_valid (self ,
622+ r ,
623+ expected_event_summaries = ['mars - Martian Special Interest Group' ],
624+ expected_event_count = 2 )
620625 self .assertContains (r , t1 .time .strftime ('%Y%m%dT%H%M%S' ))
621626 self .assertContains (r , t2 .time .strftime ('%Y%m%dT%H%M%S' ))
622627 #
623628 url = urlreverse ('ietf.meeting.views.agenda_ical' , kwargs = {'num' :meeting .number , 'session_id' :s1 .id , })
624629 r = self .client .get (url )
625- self . assert_ical_response_is_valid (r ,
626- expected_event_summaries = ['mars - Martian Special Interest Group' ],
627- expected_event_count = 1 )
630+ assert_ical_response_is_valid (self , r ,
631+ expected_event_summaries = ['mars - Martian Special Interest Group' ],
632+ expected_event_count = 1 )
628633 self .assertContains (r , t1 .time .strftime ('%Y%m%dT%H%M%S' ))
629634 self .assertNotContains (r , t2 .time .strftime ('%Y%m%dT%H%M%S' ))
630635
@@ -652,7 +657,36 @@ def test_meeting_agenda_has_static_ical_links(self):
652657 for g in groups :
653658 if g .parent_id is not None :
654659 self .assertIn ('%s?show=%s' % (ical_url , g .parent .acronym .lower ()), content )
655-
660+
661+ def test_parse_agenda_filter_params (self ):
662+ def _r (show = (), hide = (), showtypes = (), hidetypes = ()):
663+ """Helper to create expected result dict"""
664+ return dict (show = set (show ), hide = set (hide ), showtypes = set (showtypes ), hidetypes = set (hidetypes ))
665+
666+ self .assertIsNone (parse_agenda_filter_params (QueryDict ('' )))
667+
668+ self .assertRaises (ValueError , parse_agenda_filter_params , QueryDict ('unknown' )) # unknown param
669+ self .assertRaises (ValueError , parse_agenda_filter_params , QueryDict ('unknown=x' )) # unknown param
670+
671+ # test valid combos (not exhaustive)
672+ for qstr , expected in (
673+ ('show=' , _r ()), ('hide=' , _r ()), ('showtypes=' , _r ()), ('hidetypes=' , _r ()),
674+ ('show=x' , _r (show = ['x' ])), ('hide=x' , _r (hide = ['x' ])),
675+ ('showtypes=x' , _r (showtypes = ['x' ])), ('hidetypes=x' , _r (hidetypes = ['x' ])),
676+ ('show=x,y,z' , _r (show = ['x' ,'y' ,'z' ])),
677+ ('hide=x,y,z' , _r (hide = ['x' ,'y' ,'z' ])),
678+ ('showtypes=x,y,z' , _r (showtypes = ['x' ,'y' ,'z' ])),
679+ ('hidetypes=x,y,z' , _r (hidetypes = ['x' ,'y' ,'z' ])),
680+ ('show=a&hide=a' , _r (show = ['a' ], hide = ['a' ])),
681+ ('show=a&hide=b' , _r (show = ['a' ], hide = ['b' ])),
682+ ('show=a&hide=b&showtypes=c&hidetypes=d' , _r (show = ['a' ], hide = ['b' ], showtypes = ['c' ], hidetypes = ['d' ])),
683+ ):
684+ self .assertEqual (
685+ parse_agenda_filter_params (QueryDict (qstr )),
686+ expected ,
687+ 'Parsed "%s" incorrectly' % qstr ,
688+ )
689+
656690 def test_ical_filter_invalid_syntaxes (self ):
657691 meeting = make_meeting_test_data ()
658692 url = urlreverse ('ietf.meeting.views.agenda_ical' , kwargs = {'num' :meeting .number })
@@ -667,7 +701,10 @@ def do_ical_filter_test(self, meeting, querystring, expected_session_summaries):
667701 url = urlreverse ('ietf.meeting.views.agenda_ical' , kwargs = {'num' :meeting .number })
668702 r = self .client .get (url + querystring )
669703 self .assertEqual (r .status_code , 200 )
670- self .assert_ical_response_is_valid (r , expected_event_summaries = expected_session_summaries )
704+ assert_ical_response_is_valid (self ,
705+ r ,
706+ expected_event_summaries = expected_session_summaries ,
707+ expected_event_count = len (expected_session_summaries ))
671708
672709 def test_ical_filter_default (self ):
673710 meeting = make_meeting_test_data ()
@@ -1799,37 +1836,179 @@ def test_past(self):
17991836 #self.assertIn('CANCELLED', q('[id*="'+id+'"]').text())
18001837 self .assertIn ('CANCELLED' , q ('tr>td>a>span' ).text ())
18011838
1802- def test_upcoming (self ):
1803- make_meeting_test_data (create_interims = True )
1839+ def do_upcoming_test (self , querystring = None , create_meeting = True ):
1840+ if create_meeting :
1841+ make_meeting_test_data (create_interims = True )
18041842 url = urlreverse ("ietf.meeting.views.upcoming" )
1843+ if querystring is not None :
1844+ url += '?' + querystring
1845+
18051846 today = datetime .date .today ()
18061847 add_event_info_to_session_qs (Session .objects .filter (meeting__type = 'interim' , group__acronym = 'mars' )).filter (current_status = 'apprw' ).first ()
1807- mars_interim = add_event_info_to_session_qs (Session .objects .filter (meeting__type = 'interim' , meeting__date__gt = today , group__acronym = 'mars' )).filter (current_status = 'sched' ).first ().meeting
1808- ames_interim = add_event_info_to_session_qs (Session .objects .filter (meeting__type = 'interim' , meeting__date__gt = today , group__acronym = 'ames' )).filter (current_status = 'canceled' ).first ().meeting
1809- r = self .client .get (url )
1810- self .assertContains (r , mars_interim .number )
1811- self .assertContains (r , ames_interim .number )
1848+ interims = dict (
1849+ mars = add_event_info_to_session_qs (Session .objects .filter (meeting__type = 'interim' , meeting__date__gt = today , group__acronym = 'mars' )).filter (current_status = 'sched' ).first ().meeting ,
1850+ ames = add_event_info_to_session_qs (Session .objects .filter (meeting__type = 'interim' , meeting__date__gt = today , group__acronym = 'ames' )).filter (current_status = 'canceled' ).first ().meeting ,
1851+ )
1852+ self .check_interim_tabs (url )
1853+ return self .client .get (url ), interims
1854+
1855+ def test_upcoming (self ):
1856+ r , interims = self .do_upcoming_test ()
1857+ self .assertContains (r , interims ['mars' ].number )
1858+ self .assertContains (r , interims ['ames' ].number )
18121859 self .assertContains (r , 'IETF 72' )
18131860 # cancelled session
18141861 q = PyQuery (r .content )
18151862 self .assertIn ('CANCELLED' , q ('tr>td.text-right>span' ).text ())
1816- self .check_interim_tabs (url )
18171863
1818- def test_upcoming_ical (self ):
1864+ def test_upcoming_filter_show (self ):
1865+ r , interims = self .do_upcoming_test ('show=ames' )
1866+ self .assertNotContains (r , interims ['mars' ].number )
1867+ self .assertContains (r , interims ['ames' ].number )
1868+ self .assertContains (r , 'IETF 72' )
1869+ # cancelled session
1870+ q = PyQuery (r .content )
1871+ self .assertIn ('CANCELLED' , q ('tr>td.text-right>span' ).text ())
1872+
1873+ def test_upcoming_filter_show_area (self ):
18191874 make_meeting_test_data (create_interims = True )
1875+ area = Group .objects .get (acronym = 'mars' ).parent
1876+ self .assertEqual (area ,
1877+ Group .objects .get (acronym = 'ames' ).parent ,
1878+ 'The mars and ames groups have different areas; this breaks this test' )
1879+ r , interims = self .do_upcoming_test ('show=%s' % area .acronym , create_meeting = False )
1880+ self .assertContains (r , interims ['mars' ].number )
1881+ self .assertContains (r , interims ['ames' ].number )
1882+ self .assertContains (r , 'IETF 72' )
1883+
1884+ def test_upcoming_filter_hide (self ):
1885+ r , interims = self .do_upcoming_test ('hide=mars' )
1886+ self .assertNotContains (r , interims ['mars' ].number )
1887+ self .assertNotContains (r , interims ['ames' ].number )
1888+ self .assertContains (r , 'IETF 72' )
1889+
1890+ def test_upcoming_filter_show_and_hide (self ):
1891+ r , interims = self .do_upcoming_test ('show=mars,ames&hide=ames' )
1892+ self .assertContains (r , interims ['mars' ].number )
1893+ self .assertNotContains (r , interims ['ames' ].number )
1894+ self .assertContains (r , 'IETF 72' )
1895+
1896+ def do_upcoming_ical_test (self , querystring = None ):
1897+ make_meeting_test_data (create_interims = True )
1898+
1899+ # Create a group with a plenary interim session for testing type filters
1900+ somegroup = GroupFactory (acronym = 'sg' , name = 'Some Group' )
1901+ sg_interim = make_interim_meeting (somegroup , datetime .date .today () + datetime .timedelta (days = 20 ))
1902+ sg_sess = sg_interim .session_set .first ()
1903+ sg_slot = sg_sess .timeslotassignments .first ().timeslot
1904+ sg_sess .type_id = 'plenary'
1905+ sg_slot .type_id = 'plenary'
1906+ sg_sess .save ()
1907+ sg_slot .save ()
1908+
18201909 url = urlreverse ("ietf.meeting.views.upcoming_ical" )
1910+ if querystring is not None :
1911+ url += '?' + querystring
18211912 r = self .client .get (url )
18221913 self .assertEqual (r .status_code , 200 )
1823- self .assertEqual (r .get ('Content-Type' ), "text/calendar" )
1824- self .assertEqual (r .content .count (b'UID' ), 8 )
1825- # check filtered output
1826- url = url + '?filters=mars'
1827- r = self .client .get (url )
1828- self .assertEqual (r .status_code , 200 )
1829- self .assertEqual (r .get ('Content-Type' ), "text/calendar" )
1830- # print r.content
1831- self .assertEqual (r .content .count (b'UID' ), 2 )
1914+ return r
18321915
1916+ def test_upcoming_ical (self ):
1917+ r = self .do_upcoming_ical_test ()
1918+ print (r .content .decode ())
1919+ assert_ical_response_is_valid (self , r ,
1920+ expected_event_summaries = [
1921+ 'ames - Asteroid Mining Equipment Standardization Group' ,
1922+ 'mars - Martian Special Interest Group' ,
1923+ 'sg - Some Group' ,
1924+ ],
1925+ expected_event_count = 9 )
1926+
1927+ def test_upcoming_ical_filter_show (self ):
1928+ r = self .do_upcoming_ical_test ('show=mars,ames' )
1929+ assert_ical_response_is_valid (self , r ,
1930+ expected_event_summaries = [
1931+ 'mars - Martian Special Interest Group' ,
1932+ 'ames - Asteroid Mining Equipment Standardization Group' ,
1933+ ])
1934+
1935+ def test_upcoming_ical_filter_hide (self ):
1936+ r = self .do_upcoming_ical_test ('hide=mars' )
1937+ assert_ical_response_is_valid (self , r , expected_event_summaries = [])
1938+
1939+ def test_upcoming_ical_filter_show_and_hide (self ):
1940+ r = self .do_upcoming_ical_test ('show=mars,ames&hide=mars' )
1941+ assert_ical_response_is_valid (self , r ,
1942+ expected_event_summaries = [
1943+ 'ames - Asteroid Mining Equipment Standardization Group' ,
1944+ ])
1945+
1946+ def test_upcoming_ical_filter_showtypes (self ):
1947+ r = self .do_upcoming_ical_test ('showtypes=regular' )
1948+ assert_ical_response_is_valid (self , r ,
1949+ expected_event_summaries = [
1950+ 'mars - Martian Special Interest Group' ,
1951+ 'ames - Asteroid Mining Equipment Standardization Group' ,
1952+ ])
1953+
1954+ def test_upcoming_ical_filter_hidetypes (self ):
1955+ r = self .do_upcoming_ical_test ('hidetypes=regular' )
1956+ assert_ical_response_is_valid (self , r , expected_event_summaries = [])
1957+
1958+ def test_upcoming_ical_filter_showtypes_and_hidetypes (self ):
1959+ r = self .do_upcoming_ical_test ('showtypes=plenary,regular&hidetypes=regular' )
1960+ assert_ical_response_is_valid (self , r ,
1961+ expected_event_summaries = [
1962+ 'sg - Some Group' ,
1963+ ])
1964+
1965+ def test_upcoming_ical_filter_show_and_showtypes (self ):
1966+ r = self .do_upcoming_ical_test ('show=mars&showtypes=plenary' )
1967+ assert_ical_response_is_valid (self , r ,
1968+ expected_event_summaries = [
1969+ 'mars - Martian Special Interest Group' ,
1970+ 'sg - Some Group' ,
1971+ ])
1972+
1973+ def test_upcoming_ical_filter_show_and_hidetypes (self ):
1974+ r = self .do_upcoming_ical_test ('show=mars,sg&showtypes=regular' )
1975+ assert_ical_response_is_valid (self , r ,
1976+ expected_event_summaries = [
1977+ 'sg - Some Group' ,
1978+ ])
1979+
1980+ def test_upcoming_ical_filter_hide_and_showtypes (self ):
1981+ r = self .do_upcoming_ical_test ('hide=mars&showtypes=regular' )
1982+ assert_ical_response_is_valid (self , r ,
1983+ expected_event_summaries = [
1984+ 'ames - Asteroid Mining Equipment Standardization Group' ,
1985+ ])
1986+
1987+ def test_upcoming_ical_filter_hide_and_hidetypes (self ):
1988+ r = self .do_upcoming_ical_test ('hide=mars&hidetypes=regular' )
1989+ assert_ical_response_is_valid (self , r , expected_event_summaries = [])
1990+
1991+ def test_upcoming_ical_filter_show_hide_and_showtypes (self ):
1992+ r = self .do_upcoming_ical_test ('show=ames&hide=mars&showtypes=regular,plenary' )
1993+ assert_ical_response_is_valid (self , r ,
1994+ expected_event_summaries = [
1995+ 'ames - Asteroid Mining Equipment Standardization Group' ,
1996+ 'sg - Some Group' ,
1997+ ])
1998+
1999+ def test_upcoming_ical_filter_show_hide_and_hidetypes (self ):
2000+ r = self .do_upcoming_ical_test ('show=ames,sg&hide=mars&hidetypes=regular' )
2001+ assert_ical_response_is_valid (self , r ,
2002+ expected_event_summaries = [
2003+ 'sg - Some Group' ,
2004+ ])
2005+
2006+ def test_upcoming_ical_filter_all_params (self ):
2007+ r = self .do_upcoming_ical_test ('show=sg&hide=ames&showtypes=regular&hidetypes=plenary' )
2008+ assert_ical_response_is_valid (self , r ,
2009+ expected_event_summaries = [
2010+ 'mars - Martian Special Interest Group' ,
2011+ ])
18332012
18342013 def test_upcoming_json (self ):
18352014 make_meeting_test_data (create_interims = True )
0 commit comments