|
8 | 8 | import re |
9 | 9 | import shutil |
10 | 10 | import pytz |
| 11 | +import requests.exceptions |
| 12 | +import requests_mock |
11 | 13 |
|
12 | 14 | from unittest import skipIf |
13 | 15 | from mock import patch, PropertyMock |
|
19 | 21 | from PIL import Image |
20 | 22 | from pathlib import Path |
21 | 23 |
|
22 | | - |
23 | 24 | from django.urls import reverse as urlreverse |
24 | 25 | from django.conf import settings |
25 | 26 | from django.contrib.auth.models import User |
@@ -5405,12 +5406,16 @@ def test_iphone_app_json(self): |
5405 | 5406 | self.assertTrue(msessions.filter(group__acronym=s['group']['acronym']).exists()) |
5406 | 5407 |
|
5407 | 5408 | class FinalizeProceedingsTests(TestCase): |
5408 | | - @patch('urllib.request.urlopen') |
5409 | | - def test_finalize_proceedings(self, mock_urlopen): |
5410 | | - mock_urlopen.return_value = BytesIO(b'[{"LastName":"Smith","FirstName":"John","Company":"ABC","Country":"US"}]') |
| 5409 | + @override_settings(STATS_REGISTRATION_ATTENDEES_JSON_URL='https://ietf.example.com/{number}') |
| 5410 | + @requests_mock.Mocker() |
| 5411 | + def test_finalize_proceedings(self, mock): |
5411 | 5412 | make_meeting_test_data() |
5412 | 5413 | meeting = Meeting.objects.filter(type_id='ietf').order_by('id').last() |
5413 | 5414 | meeting.session_set.filter(group__acronym='mars').first().sessionpresentation_set.create(document=Document.objects.filter(type='draft').first(),rev=None) |
| 5415 | + mock.get( |
| 5416 | + settings.STATS_REGISTRATION_ATTENDEES_JSON_URL.format(number=meeting.number), |
| 5417 | + text=json.dumps([{"LastName": "Smith", "FirstName": "John", "Company": "ABC", "Country": "US"}]), |
| 5418 | + ) |
5414 | 5419 |
|
5415 | 5420 | url = urlreverse('ietf.meeting.views.finalize_proceedings',kwargs={'num':meeting.number}) |
5416 | 5421 | login_testing_unauthorized(self,"secretary",url) |
@@ -5605,8 +5610,10 @@ def test_upload_minutes_agenda(self): |
5605 | 5610 | self.assertEqual(doc.rev,'02') |
5606 | 5611 |
|
5607 | 5612 | # Verify that we don't have dead links |
5608 | | - url = url=urlreverse('ietf.meeting.views.session_details', kwargs={'num':session.meeting.number, 'acronym': session.group.acronym}) |
| 5613 | + url = urlreverse('ietf.meeting.views.session_details', kwargs={'num':session.meeting.number, 'acronym': session.group.acronym}) |
5609 | 5614 | top = '/meeting/%s/' % session.meeting.number |
| 5615 | + self.requests_mock.get(f'{session.notes_url()}/download', text='markdown notes') |
| 5616 | + self.requests_mock.get(f'{session.notes_url()}/info', text=json.dumps({'title': 'title', 'updatetime': '2021-12-01T17:11:00z'})) |
5610 | 5617 | self.crawl_materials(url=url, top=top) |
5611 | 5618 |
|
5612 | 5619 | def test_upload_minutes_agenda_unscheduled(self): |
@@ -5653,8 +5660,10 @@ def test_upload_minutes_agenda_interim(self): |
5653 | 5660 | self.assertEqual(doc.rev,'00') |
5654 | 5661 |
|
5655 | 5662 | # Verify that we don't have dead links |
5656 | | - url = url=urlreverse('ietf.meeting.views.session_details', kwargs={'num':session.meeting.number, 'acronym': session.group.acronym}) |
| 5663 | + url = urlreverse('ietf.meeting.views.session_details', kwargs={'num':session.meeting.number, 'acronym': session.group.acronym}) |
5657 | 5664 | top = '/meeting/%s/' % session.meeting.number |
| 5665 | + self.requests_mock.get(f'{session.notes_url()}/download', text='markdown notes') |
| 5666 | + self.requests_mock.get(f'{session.notes_url()}/info', text=json.dumps({'title': 'title', 'updatetime': '2021-12-01T17:11:00z'})) |
5658 | 5667 | self.crawl_materials(url=url, top=top) |
5659 | 5668 |
|
5660 | 5669 | def test_upload_slides(self): |
@@ -5928,6 +5937,151 @@ def test_submit_and_approve_multiple_versions(self): |
5928 | 5937 | self.assertIn('third version', contents) |
5929 | 5938 |
|
5930 | 5939 |
|
| 5940 | +@override_settings(IETF_NOTES_URL='https://notes.ietf.org/') |
| 5941 | +class ImportNotesTests(TestCase): |
| 5942 | + settings_temp_path_overrides = TestCase.settings_temp_path_overrides + ['AGENDA_PATH'] |
| 5943 | + |
| 5944 | + def setUp(self): |
| 5945 | + super().setUp() |
| 5946 | + self.session = SessionFactory(meeting__type_id='ietf') |
| 5947 | + self.meeting = self.session.meeting |
| 5948 | + |
| 5949 | + def test_retrieves_note(self): |
| 5950 | + """Can import and preview a note from notes.ietf.org""" |
| 5951 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 5952 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 5953 | + |
| 5954 | + self.client.login(username='secretary', password='secretary+password') |
| 5955 | + with requests_mock.Mocker() as mock: |
| 5956 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='markdown text') |
| 5957 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', |
| 5958 | + text=json.dumps({"title": "title", "updatetime": "2021-12-02T11:22:33z"})) |
| 5959 | + r = self.client.get(url) |
| 5960 | + self.assertEqual(r.status_code, 200) |
| 5961 | + q = PyQuery(r.content) |
| 5962 | + iframe = q('iframe#preview') |
| 5963 | + self.assertEqual('<p>markdown text</p>', iframe.attr('srcdoc')) |
| 5964 | + markdown_text_input = q('form #id_markdown_text') |
| 5965 | + self.assertEqual(markdown_text_input.val(), 'markdown text') |
| 5966 | + |
| 5967 | + def test_retrieves_with_broken_metadata(self): |
| 5968 | + """Can import and preview a note even if it has a metadata problem""" |
| 5969 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 5970 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 5971 | + |
| 5972 | + self.client.login(username='secretary', password='secretary+password') |
| 5973 | + with requests_mock.Mocker() as mock: |
| 5974 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='markdown text') |
| 5975 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', text='this is not valid json {]') |
| 5976 | + r = self.client.get(url) |
| 5977 | + self.assertEqual(r.status_code, 200) |
| 5978 | + q = PyQuery(r.content) |
| 5979 | + iframe = q('iframe#preview') |
| 5980 | + self.assertEqual('<p>markdown text</p>', iframe.attr('srcdoc')) |
| 5981 | + markdown_text_input = q('form #id_markdown_text') |
| 5982 | + self.assertEqual(markdown_text_input.val(), 'markdown text') |
| 5983 | + |
| 5984 | + def test_redirects_on_success(self): |
| 5985 | + """Redirects to session details page after import""" |
| 5986 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 5987 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 5988 | + |
| 5989 | + self.client.login(username='secretary', password='secretary+password') |
| 5990 | + r = self.client.post(url, {'markdown_text': 'markdown text'}) |
| 5991 | + self.assertRedirects( |
| 5992 | + r, |
| 5993 | + urlreverse( |
| 5994 | + 'ietf.meeting.views.session_details', |
| 5995 | + kwargs={ |
| 5996 | + 'num': self.meeting.number, |
| 5997 | + 'acronym': self.session.group.acronym, |
| 5998 | + }, |
| 5999 | + ), |
| 6000 | + ) |
| 6001 | + |
| 6002 | + def test_imports_previewed_text(self): |
| 6003 | + """Import text that was shown as preview even if notes site is updated""" |
| 6004 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6005 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6006 | + |
| 6007 | + self.client.login(username='secretary', password='secretary+password') |
| 6008 | + with requests_mock.Mocker() as mock: |
| 6009 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='updated markdown text') |
| 6010 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', |
| 6011 | + text=json.dumps({"title": "title", "updatetime": "2021-12-02T11:22:33z"})) |
| 6012 | + r = self.client.post(url, {'markdown_text': 'original markdown text'}) |
| 6013 | + self.assertEqual(r.status_code, 302) |
| 6014 | + minutes_path = Path(self.meeting.get_materials_path()) / 'minutes' |
| 6015 | + with (minutes_path / self.session.minutes().uploaded_filename).open() as f: |
| 6016 | + self.assertEqual(f.read(), 'original markdown text') |
| 6017 | + |
| 6018 | + def test_refuses_identical_import(self): |
| 6019 | + """Should not be able to import text identical to the current revision""" |
| 6020 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6021 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6022 | + |
| 6023 | + self.client.login(username='secretary', password='secretary+password') |
| 6024 | + r = self.client.post(url, {'markdown_text': 'original markdown text'}) # create a rev |
| 6025 | + self.assertEqual(r.status_code, 302) |
| 6026 | + with requests_mock.Mocker() as mock: |
| 6027 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='original markdown text') |
| 6028 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', |
| 6029 | + text=json.dumps({"title": "title", "updatetime": "2021-12-02T11:22:33z"})) |
| 6030 | + r = self.client.get(url) # try to import the same text |
| 6031 | + self.assertContains(r, "This document is identical", status_code=200) |
| 6032 | + q = PyQuery(r.content) |
| 6033 | + self.assertEqual(len(q('button:disabled[type="submit"]')), 1) |
| 6034 | + self.assertEqual(len(q('button:not(:disabled)[type="submit"]')), 0) |
| 6035 | + |
| 6036 | + def test_handles_missing_previous_revision_file(self): |
| 6037 | + """Should still allow import if the file for the previous revision is missing""" |
| 6038 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6039 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6040 | + |
| 6041 | + self.client.login(username='secretary', password='secretary+password') |
| 6042 | + r = self.client.post(url, {'markdown_text': 'original markdown text'}) # create a rev |
| 6043 | + # remove the file uploaded for the first rev |
| 6044 | + minutes_docs = self.session.sessionpresentation_set.filter(document__type='minutes') |
| 6045 | + self.assertEqual(minutes_docs.count(), 1) |
| 6046 | + Path(minutes_docs.first().document.get_file_name()).unlink() |
| 6047 | + |
| 6048 | + self.assertEqual(r.status_code, 302) |
| 6049 | + with requests_mock.Mocker() as mock: |
| 6050 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='original markdown text') |
| 6051 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', |
| 6052 | + text=json.dumps({"title": "title", "updatetime": "2021-12-02T11:22:33z"})) |
| 6053 | + r = self.client.get(url) |
| 6054 | + self.assertEqual(r.status_code, 200) |
| 6055 | + q = PyQuery(r.content) |
| 6056 | + iframe = q('iframe#preview') |
| 6057 | + self.assertEqual('<p>original markdown text</p>', iframe.attr('srcdoc')) |
| 6058 | + markdown_text_input = q('form #id_markdown_text') |
| 6059 | + self.assertEqual(markdown_text_input.val(), 'original markdown text') |
| 6060 | + |
| 6061 | + def test_handles_note_does_not_exist(self): |
| 6062 | + """Should not try to import a note that does not exist""" |
| 6063 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6064 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6065 | + |
| 6066 | + self.client.login(username='secretary', password='secretary+password') |
| 6067 | + with requests_mock.Mocker() as mock: |
| 6068 | + mock.get(requests_mock.ANY, status_code=404) |
| 6069 | + r = self.client.get(url, follow=True) |
| 6070 | + self.assertContains(r, 'Could not import', status_code=200) |
| 6071 | + |
| 6072 | + def test_handles_notes_server_failure(self): |
| 6073 | + """Problems communicating with the notes server should be handled gracefully""" |
| 6074 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6075 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6076 | + self.client.login(username='secretary', password='secretary+password') |
| 6077 | + |
| 6078 | + with requests_mock.Mocker() as mock: |
| 6079 | + mock.get(re.compile(r'.+/download'), exc=requests.exceptions.ConnectTimeout) |
| 6080 | + mock.get(re.compile(r'.+//info'), text='{}') |
| 6081 | + r = self.client.get(url, follow=True) |
| 6082 | + self.assertContains(r, 'Could not reach the notes server', status_code=200) |
| 6083 | + |
| 6084 | + |
5931 | 6085 | class SessionTests(TestCase): |
5932 | 6086 |
|
5933 | 6087 | def test_meeting_requests(self): |
@@ -6911,27 +7065,34 @@ def test_proceedings_acknowledgements_link(self): |
6911 | 7065 | 0, |
6912 | 7066 | ) |
6913 | 7067 |
|
6914 | | - @patch('ietf.meeting.utils.requests.get') |
6915 | | - def test_proceedings_attendees(self, mockobj): |
6916 | | - mockobj.return_value.text = b'[{"LastName":"Smith","FirstName":"John","Company":"ABC","Country":"US"}]' |
6917 | | - mockobj.return_value.json = lambda: json.loads(b'[{"LastName":"Smith","FirstName":"John","Company":"ABC","Country":"US"}]') |
| 7068 | + @override_settings(STATS_REGISTRATION_ATTENDEES_JSON_URL='https://ietf.example.com/{number}') |
| 7069 | + @requests_mock.Mocker() |
| 7070 | + def test_proceedings_attendees(self, mock): |
6918 | 7071 | make_meeting_test_data() |
6919 | 7072 | meeting = MeetingFactory(type_id='ietf', date=datetime.date(2016,7,14), number="97") |
| 7073 | + mock.get( |
| 7074 | + settings.STATS_REGISTRATION_ATTENDEES_JSON_URL.format(number=meeting.number), |
| 7075 | + text=json.dumps([{"LastName": "Smith", "FirstName": "John", "Company": "ABC", "Country": "US"}]), |
| 7076 | + ) |
6920 | 7077 | finalize(meeting) |
6921 | 7078 | url = urlreverse('ietf.meeting.views.proceedings_attendees',kwargs={'num':97}) |
6922 | 7079 | response = self.client.get(url) |
6923 | 7080 | self.assertContains(response, 'Attendee List') |
6924 | 7081 | q = PyQuery(response.content) |
6925 | 7082 | self.assertEqual(1,len(q("#id_attendees tbody tr"))) |
6926 | 7083 |
|
6927 | | - @patch('urllib.request.urlopen') |
6928 | | - def test_proceedings_overview(self, mock_urlopen): |
| 7084 | + @override_settings(STATS_REGISTRATION_ATTENDEES_JSON_URL='https://ietf.example.com/{number}') |
| 7085 | + @requests_mock.Mocker() |
| 7086 | + def test_proceedings_overview(self, mock): |
6929 | 7087 | '''Test proceedings IETF Overview page. |
6930 | 7088 | Note: old meetings aren't supported so need to add a new meeting then test. |
6931 | 7089 | ''' |
6932 | | - mock_urlopen.return_value = BytesIO(b'[{"LastName":"Smith","FirstName":"John","Company":"ABC","Country":"US"}]') |
6933 | 7090 | make_meeting_test_data() |
6934 | 7091 | meeting = MeetingFactory(type_id='ietf', date=datetime.date(2016,7,14), number="97") |
| 7092 | + mock.get( |
| 7093 | + settings.STATS_REGISTRATION_ATTENDEES_JSON_URL.format(number=meeting.number), |
| 7094 | + text=json.dumps([{"LastName": "Smith", "FirstName": "John", "Company": "ABC", "Country": "US"}]), |
| 7095 | + ) |
6935 | 7096 | finalize(meeting) |
6936 | 7097 | url = urlreverse('ietf.meeting.views.proceedings_overview',kwargs={'num':97}) |
6937 | 7098 | response = self.client.get(url) |
|
0 commit comments