示例#1
0
 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
示例#2
0
 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
示例#3
0
 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
示例#4
0
 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
示例#5
0
    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)
示例#6
0
 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)
示例#10
0
 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
示例#11
0
    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
示例#13
0
 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
示例#14
0
 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'
示例#15
0
 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'
示例#16
0
 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
示例#17
0
 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.'
示例#18
0
 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
示例#19
0
 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
示例#20
0
 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')
示例#21
0
 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
示例#24
0
 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,
         )
示例#25
0
 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,
         )
示例#26
0
 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,
         )
示例#27
0
 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
示例#28
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
示例#29
0
 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