|
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 |
@@ -5444,12 +5445,16 @@ def test_iphone_app_json(self): |
5444 | 5445 | self.assertTrue(msessions.filter(group__acronym=s['group']['acronym']).exists()) |
5445 | 5446 |
|
5446 | 5447 | class FinalizeProceedingsTests(TestCase): |
5447 | | - @patch('urllib.request.urlopen') |
5448 | | - def test_finalize_proceedings(self, mock_urlopen): |
5449 | | - mock_urlopen.return_value = BytesIO(b'[{"LastName":"Smith","FirstName":"John","Company":"ABC","Country":"US"}]') |
| 5448 | + @override_settings(STATS_REGISTRATION_ATTENDEES_JSON_URL='https://ietf.example.com/{number}') |
| 5449 | + @requests_mock.Mocker() |
| 5450 | + def test_finalize_proceedings(self, mock): |
5450 | 5451 | make_meeting_test_data() |
5451 | 5452 | meeting = Meeting.objects.filter(type_id='ietf').order_by('id').last() |
5452 | 5453 | meeting.session_set.filter(group__acronym='mars').first().sessionpresentation_set.create(document=Document.objects.filter(type='draft').first(),rev=None) |
| 5454 | + mock.get( |
| 5455 | + settings.STATS_REGISTRATION_ATTENDEES_JSON_URL.format(number=meeting.number), |
| 5456 | + text=json.dumps([{"LastName": "Smith", "FirstName": "John", "Company": "ABC", "Country": "US"}]), |
| 5457 | + ) |
5453 | 5458 |
|
5454 | 5459 | url = urlreverse('ietf.meeting.views.finalize_proceedings',kwargs={'num':meeting.number}) |
5455 | 5460 | login_testing_unauthorized(self,"secretary",url) |
@@ -5644,8 +5649,10 @@ def test_upload_minutes_agenda(self): |
5644 | 5649 | self.assertEqual(doc.rev,'02') |
5645 | 5650 |
|
5646 | 5651 | # Verify that we don't have dead links |
5647 | | - url = url=urlreverse('ietf.meeting.views.session_details', kwargs={'num':session.meeting.number, 'acronym': session.group.acronym}) |
| 5652 | + url = urlreverse('ietf.meeting.views.session_details', kwargs={'num':session.meeting.number, 'acronym': session.group.acronym}) |
5648 | 5653 | top = '/meeting/%s/' % session.meeting.number |
| 5654 | + self.requests_mock.get(f'{session.notes_url()}/download', text='markdown notes') |
| 5655 | + self.requests_mock.get(f'{session.notes_url()}/info', text=json.dumps({'title': 'title', 'updatetime': '2021-12-01T17:11:00z'})) |
5649 | 5656 | self.crawl_materials(url=url, top=top) |
5650 | 5657 |
|
5651 | 5658 | def test_upload_minutes_agenda_unscheduled(self): |
@@ -5692,8 +5699,10 @@ def test_upload_minutes_agenda_interim(self): |
5692 | 5699 | self.assertEqual(doc.rev,'00') |
5693 | 5700 |
|
5694 | 5701 | # Verify that we don't have dead links |
5695 | | - url = url=urlreverse('ietf.meeting.views.session_details', kwargs={'num':session.meeting.number, 'acronym': session.group.acronym}) |
| 5702 | + url = urlreverse('ietf.meeting.views.session_details', kwargs={'num':session.meeting.number, 'acronym': session.group.acronym}) |
5696 | 5703 | top = '/meeting/%s/' % session.meeting.number |
| 5704 | + self.requests_mock.get(f'{session.notes_url()}/download', text='markdown notes') |
| 5705 | + self.requests_mock.get(f'{session.notes_url()}/info', text=json.dumps({'title': 'title', 'updatetime': '2021-12-01T17:11:00z'})) |
5697 | 5706 | self.crawl_materials(url=url, top=top) |
5698 | 5707 |
|
5699 | 5708 | def test_upload_slides(self): |
@@ -5967,6 +5976,151 @@ def test_submit_and_approve_multiple_versions(self): |
5967 | 5976 | self.assertIn('third version', contents) |
5968 | 5977 |
|
5969 | 5978 |
|
| 5979 | +@override_settings(IETF_NOTES_URL='https://notes.ietf.org/') |
| 5980 | +class ImportNotesTests(TestCase): |
| 5981 | + settings_temp_path_overrides = TestCase.settings_temp_path_overrides + ['AGENDA_PATH'] |
| 5982 | + |
| 5983 | + def setUp(self): |
| 5984 | + super().setUp() |
| 5985 | + self.session = SessionFactory(meeting__type_id='ietf') |
| 5986 | + self.meeting = self.session.meeting |
| 5987 | + |
| 5988 | + def test_retrieves_note(self): |
| 5989 | + """Can import and preview a note from notes.ietf.org""" |
| 5990 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 5991 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 5992 | + |
| 5993 | + self.client.login(username='secretary', password='secretary+password') |
| 5994 | + with requests_mock.Mocker() as mock: |
| 5995 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='markdown text') |
| 5996 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', |
| 5997 | + text=json.dumps({"title": "title", "updatetime": "2021-12-02T11:22:33z"})) |
| 5998 | + r = self.client.get(url) |
| 5999 | + self.assertEqual(r.status_code, 200) |
| 6000 | + q = PyQuery(r.content) |
| 6001 | + iframe = q('iframe#preview') |
| 6002 | + self.assertEqual('<p>markdown text</p>', iframe.attr('srcdoc')) |
| 6003 | + markdown_text_input = q('form #id_markdown_text') |
| 6004 | + self.assertEqual(markdown_text_input.val(), 'markdown text') |
| 6005 | + |
| 6006 | + def test_retrieves_with_broken_metadata(self): |
| 6007 | + """Can import and preview a note even if it has a metadata problem""" |
| 6008 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6009 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6010 | + |
| 6011 | + self.client.login(username='secretary', password='secretary+password') |
| 6012 | + with requests_mock.Mocker() as mock: |
| 6013 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='markdown text') |
| 6014 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', text='this is not valid json {]') |
| 6015 | + r = self.client.get(url) |
| 6016 | + self.assertEqual(r.status_code, 200) |
| 6017 | + q = PyQuery(r.content) |
| 6018 | + iframe = q('iframe#preview') |
| 6019 | + self.assertEqual('<p>markdown text</p>', iframe.attr('srcdoc')) |
| 6020 | + markdown_text_input = q('form #id_markdown_text') |
| 6021 | + self.assertEqual(markdown_text_input.val(), 'markdown text') |
| 6022 | + |
| 6023 | + def test_redirects_on_success(self): |
| 6024 | + """Redirects to session details page after import""" |
| 6025 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6026 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6027 | + |
| 6028 | + self.client.login(username='secretary', password='secretary+password') |
| 6029 | + r = self.client.post(url, {'markdown_text': 'markdown text'}) |
| 6030 | + self.assertRedirects( |
| 6031 | + r, |
| 6032 | + urlreverse( |
| 6033 | + 'ietf.meeting.views.session_details', |
| 6034 | + kwargs={ |
| 6035 | + 'num': self.meeting.number, |
| 6036 | + 'acronym': self.session.group.acronym, |
| 6037 | + }, |
| 6038 | + ), |
| 6039 | + ) |
| 6040 | + |
| 6041 | + def test_imports_previewed_text(self): |
| 6042 | + """Import text that was shown as preview even if notes site is updated""" |
| 6043 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6044 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6045 | + |
| 6046 | + self.client.login(username='secretary', password='secretary+password') |
| 6047 | + with requests_mock.Mocker() as mock: |
| 6048 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='updated markdown text') |
| 6049 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', |
| 6050 | + text=json.dumps({"title": "title", "updatetime": "2021-12-02T11:22:33z"})) |
| 6051 | + r = self.client.post(url, {'markdown_text': 'original markdown text'}) |
| 6052 | + self.assertEqual(r.status_code, 302) |
| 6053 | + minutes_path = Path(self.meeting.get_materials_path()) / 'minutes' |
| 6054 | + with (minutes_path / self.session.minutes().uploaded_filename).open() as f: |
| 6055 | + self.assertEqual(f.read(), 'original markdown text') |
| 6056 | + |
| 6057 | + def test_refuses_identical_import(self): |
| 6058 | + """Should not be able to import text identical to the current revision""" |
| 6059 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6060 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6061 | + |
| 6062 | + self.client.login(username='secretary', password='secretary+password') |
| 6063 | + r = self.client.post(url, {'markdown_text': 'original markdown text'}) # create a rev |
| 6064 | + self.assertEqual(r.status_code, 302) |
| 6065 | + with requests_mock.Mocker() as mock: |
| 6066 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='original markdown text') |
| 6067 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', |
| 6068 | + text=json.dumps({"title": "title", "updatetime": "2021-12-02T11:22:33z"})) |
| 6069 | + r = self.client.get(url) # try to import the same text |
| 6070 | + self.assertContains(r, "This document is identical", status_code=200) |
| 6071 | + q = PyQuery(r.content) |
| 6072 | + self.assertEqual(len(q('button:disabled[type="submit"]')), 1) |
| 6073 | + self.assertEqual(len(q('button:not(:disabled)[type="submit"]')), 0) |
| 6074 | + |
| 6075 | + def test_handles_missing_previous_revision_file(self): |
| 6076 | + """Should still allow import if the file for the previous revision is missing""" |
| 6077 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6078 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6079 | + |
| 6080 | + self.client.login(username='secretary', password='secretary+password') |
| 6081 | + r = self.client.post(url, {'markdown_text': 'original markdown text'}) # create a rev |
| 6082 | + # remove the file uploaded for the first rev |
| 6083 | + minutes_docs = self.session.sessionpresentation_set.filter(document__type='minutes') |
| 6084 | + self.assertEqual(minutes_docs.count(), 1) |
| 6085 | + Path(minutes_docs.first().document.get_file_name()).unlink() |
| 6086 | + |
| 6087 | + self.assertEqual(r.status_code, 302) |
| 6088 | + with requests_mock.Mocker() as mock: |
| 6089 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/download', text='original markdown text') |
| 6090 | + mock.get(f'https://notes.ietf.org/{self.session.notes_id()}/info', |
| 6091 | + text=json.dumps({"title": "title", "updatetime": "2021-12-02T11:22:33z"})) |
| 6092 | + r = self.client.get(url) |
| 6093 | + self.assertEqual(r.status_code, 200) |
| 6094 | + q = PyQuery(r.content) |
| 6095 | + iframe = q('iframe#preview') |
| 6096 | + self.assertEqual('<p>original markdown text</p>', iframe.attr('srcdoc')) |
| 6097 | + markdown_text_input = q('form #id_markdown_text') |
| 6098 | + self.assertEqual(markdown_text_input.val(), 'original markdown text') |
| 6099 | + |
| 6100 | + def test_handles_note_does_not_exist(self): |
| 6101 | + """Should not try to import a note that does not exist""" |
| 6102 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6103 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6104 | + |
| 6105 | + self.client.login(username='secretary', password='secretary+password') |
| 6106 | + with requests_mock.Mocker() as mock: |
| 6107 | + mock.get(requests_mock.ANY, status_code=404) |
| 6108 | + r = self.client.get(url, follow=True) |
| 6109 | + self.assertContains(r, 'Could not import', status_code=200) |
| 6110 | + |
| 6111 | + def test_handles_notes_server_failure(self): |
| 6112 | + """Problems communicating with the notes server should be handled gracefully""" |
| 6113 | + url = urlreverse('ietf.meeting.views.import_session_minutes', |
| 6114 | + kwargs={'num': self.meeting.number, 'session_id': self.session.pk}) |
| 6115 | + self.client.login(username='secretary', password='secretary+password') |
| 6116 | + |
| 6117 | + with requests_mock.Mocker() as mock: |
| 6118 | + mock.get(re.compile(r'.+/download'), exc=requests.exceptions.ConnectTimeout) |
| 6119 | + mock.get(re.compile(r'.+//info'), text='{}') |
| 6120 | + r = self.client.get(url, follow=True) |
| 6121 | + self.assertContains(r, 'Could not reach the notes server', status_code=200) |
| 6122 | + |
| 6123 | + |
5970 | 6124 | class SessionTests(TestCase): |
5971 | 6125 |
|
5972 | 6126 | def test_meeting_requests(self): |
@@ -6950,27 +7104,34 @@ def test_proceedings_acknowledgements_link(self): |
6950 | 7104 | 0, |
6951 | 7105 | ) |
6952 | 7106 |
|
6953 | | - @patch('ietf.meeting.utils.requests.get') |
6954 | | - def test_proceedings_attendees(self, mockobj): |
6955 | | - mockobj.return_value.text = b'[{"LastName":"Smith","FirstName":"John","Company":"ABC","Country":"US"}]' |
6956 | | - mockobj.return_value.json = lambda: json.loads(b'[{"LastName":"Smith","FirstName":"John","Company":"ABC","Country":"US"}]') |
| 7107 | + @override_settings(STATS_REGISTRATION_ATTENDEES_JSON_URL='https://ietf.example.com/{number}') |
| 7108 | + @requests_mock.Mocker() |
| 7109 | + def test_proceedings_attendees(self, mock): |
6957 | 7110 | make_meeting_test_data() |
6958 | 7111 | meeting = MeetingFactory(type_id='ietf', date=datetime.date(2016,7,14), number="97") |
| 7112 | + mock.get( |
| 7113 | + settings.STATS_REGISTRATION_ATTENDEES_JSON_URL.format(number=meeting.number), |
| 7114 | + text=json.dumps([{"LastName": "Smith", "FirstName": "John", "Company": "ABC", "Country": "US"}]), |
| 7115 | + ) |
6959 | 7116 | finalize(meeting) |
6960 | 7117 | url = urlreverse('ietf.meeting.views.proceedings_attendees',kwargs={'num':97}) |
6961 | 7118 | response = self.client.get(url) |
6962 | 7119 | self.assertContains(response, 'Attendee List') |
6963 | 7120 | q = PyQuery(response.content) |
6964 | 7121 | self.assertEqual(1,len(q("#id_attendees tbody tr"))) |
6965 | 7122 |
|
6966 | | - @patch('urllib.request.urlopen') |
6967 | | - def test_proceedings_overview(self, mock_urlopen): |
| 7123 | + @override_settings(STATS_REGISTRATION_ATTENDEES_JSON_URL='https://ietf.example.com/{number}') |
| 7124 | + @requests_mock.Mocker() |
| 7125 | + def test_proceedings_overview(self, mock): |
6968 | 7126 | '''Test proceedings IETF Overview page. |
6969 | 7127 | Note: old meetings aren't supported so need to add a new meeting then test. |
6970 | 7128 | ''' |
6971 | | - mock_urlopen.return_value = BytesIO(b'[{"LastName":"Smith","FirstName":"John","Company":"ABC","Country":"US"}]') |
6972 | 7129 | make_meeting_test_data() |
6973 | 7130 | meeting = MeetingFactory(type_id='ietf', date=datetime.date(2016,7,14), number="97") |
| 7131 | + mock.get( |
| 7132 | + settings.STATS_REGISTRATION_ATTENDEES_JSON_URL.format(number=meeting.number), |
| 7133 | + text=json.dumps([{"LastName": "Smith", "FirstName": "John", "Company": "ABC", "Country": "US"}]), |
| 7134 | + ) |
6974 | 7135 | finalize(meeting) |
6975 | 7136 | url = urlreverse('ietf.meeting.views.proceedings_overview',kwargs={'num':97}) |
6976 | 7137 | response = self.client.get(url) |
|
0 commit comments