def test_demo_mode_unavailable(self, app, client, fake_auth): """Return 404 when dev_auth is not enabled.""" with override_config(app, 'DEVELOPER_AUTH_ENABLED', True): # Enable dev_auth to confirm that it is ignored with override_config(app, 'DEMO_MODE_AVAILABLE', False): fake_auth.login(admin_uid) assert client.post('/api/user/demo_mode').status_code == 404
def _assert_schedule_is_obsolete( self, expect_obsolete_dates, expect_obsolete_times, meeting, override_days=None, override_end_date=None, override_end_time=None, override_start_date=None, override_start_time=None, ): with test_approvals_workflow(app): with override_config(app, 'CURRENT_TERM_RECORDINGS_BEGIN', meeting['startDate']): with override_config(app, 'CURRENT_TERM_RECORDINGS_END', meeting['endDate']): mock_scheduled( meeting=meeting, override_days=override_days, override_end_date=override_end_date, override_end_time=override_end_time, override_start_date=override_start_date, override_start_time=override_start_time, section_id=self.section_id, term_id=self.term_id, ) course = SisSection.get_course(section_id=self.section_id, term_id=self.term_id) scheduled = course['scheduled'] assert are_scheduled_dates_obsolete(meeting=meeting, scheduled=scheduled) is expect_obsolete_dates assert are_scheduled_times_obsolete(meeting=meeting, scheduled=scheduled) is expect_obsolete_times
def test_no_activity_percentile_cutoff(self, app): """Respect percentile cutoff for alert creation.""" with override_config(app, 'ALERT_NO_ACTIVITY_PERCENTILE_CUTOFF', 10): Alert.update_all_for_term(2178) assert len(get_current_alerts('3456789012')) == 0 with override_config(app, 'ALERT_NO_ACTIVITY_PERCENTILE_CUTOFF', 20): Alert.update_all_for_term(2178) assert len(get_current_alerts('3456789012')) == 1
def test_infrequent_activity_percentile_cutoff(self, app): """Respect percentile cutoff for alert creation.""" with override_config(app, 'ALERT_INFREQUENT_ACTIVITY_ENABLED', True): with override_config(app, 'ALERT_INFREQUENT_ACTIVITY_PERCENTILE_CUTOFF', 10): Alert.update_all_for_term(2178) assert len(get_current_alerts('5678901234')) == 0 with override_config(app, 'ALERT_INFREQUENT_ACTIVITY_PERCENTILE_CUTOFF', 20): Alert.update_all_for_term(2178) assert len(get_current_alerts('5678901234')) == 1
def test_admin_alert_date_change(self, db_session): with enabled_job(job_key=AdminEmailsJob.key()): admin_uid = app.config['EMAIL_DIABLO_ADMIN_UID'] term_id = app.config['CURRENT_TERM_ID'] section_id = 50004 meeting = get_eligible_meeting(section_id=section_id, term_id=term_id) with test_approvals_workflow(app): with override_config(app, 'CURRENT_TERM_RECORDINGS_BEGIN', meeting['startDate']): with override_config(app, 'CURRENT_TERM_RECORDINGS_END', meeting['endDate']): def _run_jobs(): AdminEmailsJob(simply_yield).run() QueuedEmailsJob(simply_yield).run() def _schedule(): mock_scheduled( meeting=meeting, override_end_time='16:59', override_start_time='08:00', section_id=section_id, term_id=term_id, ) course = SisSection.get_course( section_id=section_id, term_id=term_id) scheduled = course['scheduled'] assert are_scheduled_dates_obsolete( meeting=meeting, scheduled=scheduled) is False assert are_scheduled_times_obsolete( meeting=meeting, scheduled=scheduled) is True def _assert_alert_count(count): emails_sent = SentEmail.get_emails_sent_to( uid=admin_uid) assert len(emails_sent) == count assert emails_sent[0].section_id == section_id assert emails_sent[ 0].template_type == 'admin_alert_date_change' # First time scheduled. _schedule() _run_jobs() _assert_alert_count(1) # Unschedule and schedule a second time. Scheduled.delete(section_id=section_id, term_id=term_id) _schedule() _run_jobs() # Another alert is emailed to admin because it is a new schedule. _assert_alert_count(2) # Run jobs again and expect no alerts. _run_jobs() _assert_alert_count(2)
def test_email_test_mode_on(self): with override_config(app, 'EMAIL_TEST_MODE', True): recipient = _get_mock_recipient() test_email_address = '*****@*****.**' # EMAIL_REDIRECT_WHEN_TESTING can be single email address (string) or list of addresses. expected = [test_email_address] with override_config(app, 'EMAIL_REDIRECT_WHEN_TESTING', test_email_address): assert BConnected.get_email_addresses(recipient) == expected with override_config(app, 'EMAIL_REDIRECT_WHEN_TESTING', [test_email_address]): assert BConnected.get_email_addresses(recipient) == expected
def test_two_terms(self, app): """Contains two items when current and future terms are consecutive.""" with override_config(app, 'CANVAS_CURRENT_ENROLLMENT_TERM', 'Summer 2021'), \ override_config(app, 'CANVAS_FUTURE_ENROLLMENT_TERM', 'Fall 2021'): options = grading_terms() assert options == [ { 'name': 'Summer 2021 (active)', 'value': '2215' }, { 'name': 'Fall 2021 (future)', 'value': '2218' }, ]
def test_run(self, app, metadata_db): """Uploads Canvas grade change logs to S3, then stores feeds in Redshift.""" with mock_s3(app): with override_config(app, 'TEST_CANVAS_COURSE_IDS', [1492459, 1488704, 1491827]): result = ImportCanvasGradeChangeLog().run_wrapped() assert result assert 'Canvas grade change log import completed for term 2178: 3 succeeded, ' in result assert '0 failed.' in result assert_background_job_status('ImportCanvasGradeChangeLog') schema = app.config['RDS_SCHEMA_METADATA'] count_results = rds.fetch( f'SELECT count(*) FROM {schema}.canvas_api_import_job_status') assert count_results[0]['count'] == 3 canvas_status_results = rds.fetch( f'SELECT DISTINCT status FROM {schema}.canvas_api_import_job_status' ) assert len(canvas_status_results) == 1 assert canvas_status_results[0]['status'] == 'created' sync_results = rds.fetch( f'SELECT * FROM {schema}.canvas_api_import_job_status LIMIT 1') assert sync_results[0]['job_id'].startswith( 'ImportCanvasGradeChangeLog_') assert sync_results[0]['course_id'] == '1492459' assert sync_results[0]['table_name'] == 'grade_change_log' assert sync_results[0]['details'] is None assert sync_results[0]['created_at'] assert sync_results[0]['updated_at']
def test_api_key_mismatch(self, app, client, mock_manually_added_advisee): """Returns 401 when bad api key is provided.""" with override_config(app, 'API_KEY', 'dongle'): headers = {'app_key': 'widget'} self._api_get_all(client=client, headers=headers, expected_status_code=401)
def test_authorized_user(self, app, client, fake_auth): """Gives access to admin user.""" with override_config(app, 'DEVELOPER_AUTH_ENABLED', True): fake_auth.login(admin_uid) response = client.post('/api/auth/become_user', data=json.dumps({'uid': advisor_uid}), content_type='application/json') assert response.status_code == 200 assert response.json['uid'] == advisor_uid
def test_appointment_marked_read(self, app, client, fake_auth): """Includes advising appointments.""" with override_config(app, 'FEATURE_FLAG_ADVISOR_APPOINTMENTS', True): sid = '3456789012' fake_auth.login(coe_scheduler_id) response = client.post( '/api/appointments/create', data=json.dumps({ 'deptCode': 'COENG', 'sid': sid, 'appointmentType': 'Drop-in', 'topics': ['Topic for appointments, 4'], }), content_type='application/json', ) assert response.status_code == 200 appointment_id = response.json['id'] def _is_appointment_read(): student = self._api_student_by_sid(client=client, sid=sid) appointments = student['notifications']['appointment'] appointment = next((a for a in appointments if a['id'] == appointment_id), None) assert appointment is not None return appointment['read'] fake_auth.login(asc_advisor_id) assert _is_appointment_read() is False client.post(f'/api/appointments/{appointment_id}/mark_read') assert _is_appointment_read() is True
def test_feature_flag(self, client, fake_auth, app): """Appointments feature is false.""" with override_config(app, 'FEATURE_FLAG_ADVISOR_APPOINTMENTS', False): fake_auth.login(coe_advisor_uid) response = client.get( '/api/appointments/advisors/find_by_name?q=Jo') assert response.status_code == 401
def test_search_admits_when_feature_flag_false(self, client, ce3_advisor): """Excludes admit results if feature flag is false.""" with override_config(app, 'FEATURE_FLAG_ADMITTED_STUDENTS', False): api_json = self._api_search_admits(client, '0000', expected_status_code=401) assert 'admits' not in api_json
def test_api_key_match(self, app, client): api_key = 'Hey ho, seely sheepe!' with override_config(app, 'API_KEY', api_key): headers = {'app_key': api_key} response = client.get('/api/admin/cachejob', headers=headers) assert response.status_code == 200 assert response.headers.get('Content-Type') == 'application/json'
def test_advisor_get_appointment_topics(self, app, client, fake_auth): """COE advisor can get topics.""" with override_config(app, 'DEPARTMENTS_SUPPORTING_DROP_INS', ['COENG']): fake_auth.login(coe_drop_in_advisor_uid) api_json = _topics_for_appointments(client) topics = _get_topic_labels(api_json) assert len(topics) == 9 assert topics[-1] == 'Other / Reason not listed'
def test_front_end_route_redirect(self, app, client, asc_advisor_session): """Server-side redirect to Vue.js (separate port) on developer workstation.""" vue_path = '/student/12345?r=1' vue_base_url = 'http://localhost:8080' with override_config(app, 'VUE_LOCALHOST_BASE_URL', vue_base_url): response = client.get(vue_path) assert response.status_code == 302 assert response.location == vue_base_url + vue_path
def test_update_withdrawal_alerts(self, app): """Can be created from SIS feeds.""" with override_config(app, 'ALERT_WITHDRAWAL_ENABLED', True): Alert.update_all_for_term(2178) alerts = get_current_alerts('2345678901') assert len(alerts) == 1 assert alerts[0]['key'] == '2178_withdrawal' assert alerts[0]['message'] == 'Student is no longer enrolled in the Fall 2017 term.'
def test_set_demo_mode(self, app, client, fake_auth): """Both admin and advisor can toggle demo mode.""" with override_config(app, 'DEVELOPER_AUTH_ENABLED', False): # Disable dev_auth to confirm that it is ignored with override_config(app, 'DEMO_MODE_AVAILABLE', True): for uid in admin_uid, coe_advisor_uid: fake_auth.login(uid) for in_demo_mode in [True, False]: response = client.post( '/api/user/demo_mode', data=json.dumps({'demoMode': in_demo_mode}), content_type='application/json', ) assert response.status_code == 200 assert response.json['inDemoMode'] is in_demo_mode user = AuthorizedUser.find_by_uid(uid) assert user.in_demo_mode is in_demo_mode
def test_search_admits_performed_by_non_ce3_advisor( self, client, coe_advisor): """Excludes admit results if user is a non-CE3 advisor.""" with override_config(app, 'FEATURE_FLAG_ADMITTED_STUDENTS', True): api_json = self._api_search_admits(client, '0000', expected_status_code=401) assert 'admits' not in api_json
def test_recording_end_date_with_offset(self): recordings_end_date = '2020-11-24' with override_config(app, 'CURRENT_TERM_RECORDINGS_END', recordings_end_date): meeting = { 'days': 'MO', 'endDate': '2020-12-11 00:00:00 UTC', } # The last recording is on a Monday. assert get_recording_end_date(meeting) == _to_datetime('2020-11-23')
def test_get_all_topics_including_deleted(self, app, client, fake_auth): """Get all appointment topic options, including deleted.""" with override_config(app, 'DEPARTMENTS_SUPPORTING_DROP_INS', ['COENG']): fake_auth.login(coe_drop_in_advisor_uid) api_json = _topics_for_appointments(client, include_deleted=True) deleted_items = list(filter(lambda row: row['deletedAt'], api_json)) assert 'Topic for appointments, deleted' in _get_topic_labels(deleted_items) # Verify custom sort assert _get_topic_labels(api_json)[-1] == 'Other / Reason not listed'
def test_feature_flag(self, client, fake_auth, app): """Appointments feature is false.""" dept_code = 'QCADV' advisor = DropInAdvisor.advisors_for_dept_code(dept_code)[0] fake_auth.login( AuthorizedUser.find_by_id(advisor.authorized_user_id).uid) appointment = AppointmentTestUtil.create_appointment(client, dept_code) with override_config(app, 'FEATURE_FLAG_ADVISOR_APPOINTMENTS', False): self._check_in(client, appointment['id'], expected_status_code=401)
def test_api_key_match(self, app, client, mock_manually_added_advisee): """Returns valid response when api key is provided.""" with override_config(app, 'API_KEY', 'dongle'): headers = {'app_key': 'dongle'} response = self._api_get_all(client=client, headers=headers, expected_status_code=200) assert len(response) == 1 assert response[0]['sid'] == advisee_sid
def test_unauthorized_user(self, app, client): """Fails if the chosen UID does not match an authorized user.""" with override_config(app, 'DEVELOPER_AUTH_ENABLED', True): self._api_dev_auth_login( client, password=app.config['DEVELOPER_AUTH_PASSWORD'], user_id=unauthorized_user_id, expected_status_code=403, )
def test_password_fail(self, app, client, authorized_user_id): """Fails if no match on developer password.""" with override_config(app, 'DEVELOPER_AUTH_ENABLED', True): self._api_dev_auth_login( client, user_id=authorized_user_id, password='******', expected_status_code=401, )
def test_disabled(self, app, client, authorized_user_id): """Blocks access unless enabled.""" with override_config(app, 'DEVELOPER_AUTH_ENABLED', False): self._api_dev_auth_login( client, user_id=authorized_user_id, password=app.config['DEVELOPER_AUTH_PASSWORD'], expected_status_code=404, )
def test_timestamps(self): """Epoch timestamp in PST timezone.""" with override_config(app, 'CURRENT_TERM_BEGIN', _get_wednesday_august_26()): first_day_start = get_first_matching_datetime_of_term( meeting_days=['TU', 'TH'], start_date=datetime.strptime(app.config['CURRENT_TERM_BEGIN'], '%Y-%m-%d'), time_hours=9, time_minutes=37, ) assert first_day_start.timestamp() == 1598546220.0
def test_first_meeting_is_week_after_term_begin(self): """First meeting is the Monday following first week of term.""" with override_config(app, 'CURRENT_TERM_BEGIN', _get_wednesday_august_26()): first_day_start = get_first_matching_datetime_of_term( meeting_days=['MO', 'TU'], start_date=datetime.strptime(app.config['CURRENT_TERM_BEGIN'], '%Y-%m-%d'), time_hours=8, time_minutes=45, ) assert first_day_start.day == 31
def test_first_meeting_is_day_after_term_begin(self): """First meeting is the day after start of term.""" with override_config(app, 'CURRENT_TERM_BEGIN', _get_wednesday_august_26()): first_day_start = get_first_matching_datetime_of_term( meeting_days=['TU', 'TH'], start_date=datetime.strptime(app.config['CURRENT_TERM_BEGIN'], '%Y-%m-%d'), time_hours=13, time_minutes=30, ) assert first_day_start.day == 27
def test_disabled(self, app, client, fake_auth): """Blocks access unless enabled.""" with override_config(app, 'DEVELOPER_AUTH_ENABLED', False): fake_auth.login(admin_uid) response = client.post( '/api/auth/become_user', data=json.dumps({'uid': advisor_uid}), content_type='application/json', ) assert response.status_code == 404