def test_user_customized_lang_code_as_settings_language_code(self): with override_settings(USE_I18N=True, LANGUAGES=self.LANGUAGES_CONF2, LANGUAGE_CODE='user_customized_lang_code'): with self.assertRaises(IOError): # because there's no file named "user_customized_lang_code.mo" get_course_specific_language_choices() with mock.patch(REAL_TRANSLATION_FUNCTION_TO_MOCK) as mock_gettext: mock_gettext.side_effect = real_trans_side_effect choices = get_course_specific_language_choices() # The language description is the language_code, because it can't # be found in django.conf.locale.LANG_INFO self.assertEqual(choices[1][1], "user_customized_lang_code") with override_settings(USE_I18N=False, LANGUAGES=self.LANGUAGES_CONF2, LANGUAGE_CODE='user_customized_lang_code'): with mock.patch(REAL_TRANSLATION_FUNCTION_TO_MOCK) as mock_gettext: mock_gettext.side_effect = real_trans_side_effect choices = get_course_specific_language_choices() # The language description is the language_code, because it can't # be found in django.conf.locale.LANG_INFO self.assertIn("user_customized_lang_code", choices[0][1])
def test_set_up_new_course_failed_to_delete_repo(self): resp = self.get_set_up_new_course() self.assertTrue(resp.status_code, 403) def force_remove_path_side_effect(path): # we need to delete the path, or tests followed will fail force_remove_path(path) raise OSError("my os error") data = SINGLE_COURSE_SETUP_LIST[0]["course"] with mock.patch( "dulwich.client.GitClient.fetch") as mock_fetch, mock.patch( 'relate.utils.force_remove_path' ) as mock_force_remove_path: mock_fetch.side_effect = RuntimeError("my fetch error") mock_force_remove_path.side_effect = force_remove_path_side_effect resp = self.post_create_course(data, raise_error=False) self.assertTrue(resp.status_code, 200) self.assertEqual(Course.objects.count(), 0) self.assertAddMessageCallCount(2) self.assertAddMessageCalledWith( "Failed to delete unused repository directory", reset=False) self.assertAddMessageCalledWith( "Course creation failed: RuntimeError: my fetch error")
def test_purge_page_view_superuser(self): with self.temporarily_switch_to_user(self.superuser): resp = self.get_purget_page_view() self.assertEqual(resp.status_code, 200) self.assertEqual( resp.context.get("form").fields["course"].queryset.count(), 2) with mock.patch("celery.app.task.Task.delay") \ as mocked_delay,\ mock.patch("course.views.monitor_task"): # post without "submit" resp = self.post_purget_page_view(self.course1.pk, add_submit=False) # Nothing happened self.assertEqual(resp.status_code, 200) self.assertEqual(mocked_delay.call_count, 0) # post with "submit" # Manually fake an async result id faked_async_result_id = "64907302-3166-43d8-b822" mocked_delay.return_value.id = faked_async_result_id resp = self.post_purget_page_view(self.course1.pk) self.assertRedirects(resp, reverse("relate-monitor_task", args=[faked_async_result_id]), fetch_redirect_response=False) self.assertEqual(mocked_delay.call_count, 1) self.assertTrue(self.course1.id in mocked_delay.call_args[0])
def test_set_up_new_course_failed_to_delete_repo(self): resp = self.get_set_up_new_course() self.assertTrue(resp.status_code, 403) def force_remove_path_side_effect(path): # we need to delete the path, or tests followed will fail force_remove_path(path) raise OSError("my os error") data = SINGLE_COURSE_SETUP_LIST[0]["course"] with mock.patch( "dulwich.client.GitClient.fetch" ) as mock_fetch, mock.patch( 'relate.utils.force_remove_path' )as mock_force_remove_path: mock_fetch.side_effect = RuntimeError("my fetch error") mock_force_remove_path.side_effect = force_remove_path_side_effect resp = self.post_create_course(data, raise_error=False) self.assertTrue(resp.status_code, 200) self.assertEqual(Course.objects.count(), 0) self.assertAddMessageCallCount(2) self.assertAddMessageCalledWith( "Failed to delete unused repository directory", reset=False) self.assertAddMessageCalledWith( "Course creation failed: RuntimeError: my fetch error")
def test_markup_body_for_title_not_implemented(self): with mock.patch("course.page.static.Page.markup_body_for_title")\ as mock_markup_body_for_title,\ mock.patch("warnings.warn") as mock_warn: mock_markup_body_for_title.side_effect = NotImplementedError mock_warn.side_effect = [None, None, None] markdown = ( PAGE_WITH_TITLE_MARKDOWN_PATTERN % {"attr_title": "", "content_title": ""}) resp = self.get_page_sandbox_preview_response(markdown) self.assertEqual(resp.status_code, 200) self.assertSandboxNotHasValidPage(resp) self.assertResponseContextContains( resp, PAGE_ERRORS, "no title found in body or title attribute") # There are other warnings besides this expected warning self.assertTrue(mock_warn.call_count >= 1) warned_with_expected_msg = False expected_warn_msg = ("PageBaseWithTitle subclass 'Page' does not " "implement markup_body_for_title()") for args in mock_warn.call_args_list: if expected_warn_msg in args[0]: warned_with_expected_msg = True break if not warned_with_expected_msg: self.fail("%s is not warned as expected" % expected_warn_msg)
def test_set_up_new_course(self): # In this test, we use client instead of request factory to simplify # the logic. with self.temporarily_switch_to_user(self.instructor): # the permission is cached, need to repopulated from db resp = self.get_set_up_new_course() self.assertTrue(resp.status_code, 200) with mock.patch("dulwich.client.GitClient.fetch", return_value={b"HEAD": b"some_commit_sha"}), \ mock.patch("course.versioning.transfer_remote_refs", return_value=None), \ mock.patch("course.validation.validate_course_content", return_value=None): data = self.get_set_up_new_course_form_data() resp = self.post_create_course(data, raise_error=False, login_superuser=False) self.assertTrue(resp.status_code, 200) self.assertEqual(Course.objects.count(), 1) self.assertEqual(Participation.objects.count(), 1) self.assertEqual(Participation.objects.first().user.username, "test_instructor") self.assertAddMessageCalledWith( "Course content validated, creation succeeded.") from course.enrollment import get_participation_role_identifiers # the user who setup the course has role instructor self.assertTrue( get_participation_role_identifiers( Course.objects.first(), Participation.objects.first()), "instructor")
def test_validate_point_count_called(self): import random with mock.patch("course.page.base.validate_point_count") \ as mock_validate_point_count, \ mock.patch("course.page.base.get_auto_feedback") \ as mock_get_auto_feedback: mock_validate_point_count.side_effect = lambda x: x mock_get_auto_feedback.side_effect = lambda x: x for i in range(10): correctness = random.uniform(0, 15) feedback = "some feedback" AnswerFeedback(correctness, feedback) mock_validate_point_count.assert_called_once_with(correctness) # because feedback is not None self.assertEqual(mock_get_auto_feedback.call_count, 0) mock_validate_point_count.reset_mock() for i in range(10): correctness = random.uniform(0, 15) AnswerFeedback(correctness) # because get_auto_feedback is mocked, the call_count of # mock_validate_point_count is only once mock_validate_point_count.assert_called_once_with(correctness) mock_validate_point_count.reset_mock() # because feedback is None self.assertEqual(mock_get_auto_feedback.call_count, 1) mock_get_auto_feedback.reset_mock() AnswerFeedback(correctness=None) mock_validate_point_count.assert_called_once_with(None)
def test_post_form_deprecated(self): page_id = "half" with mock.patch( "course.page.text.TextQuestionBase.process_form_post", autospec=True ) as mock_process_form_post, mock.patch( "course.page.text.TextQuestionBase.post_form", autospec=True) as mock_post_form, mock.patch( "warnings.warn") as mock_warn: mock_process_form_post.side_effect = process_form_post_side_effect_super mock_post_form.side_effect = post_form_side_effect self.post_answer_by_page_id( page_id, answer_data={"answer": "1/2"}) self.assertTrue(mock_warn.call_count >= 1) expected_warn_msg = ( "TextQuestion is using the post_form compatiblity hook, " "which is deprecated.") warned_with_expected_msg = False for args in mock_warn.call_args_list: if expected_warn_msg in args[0]: warned_with_expected_msg = True break if not warned_with_expected_msg: self.fail("'%s' is not warned as expected" % expected_warn_msg) self.assertEqual(self.end_flow().status_code, 200) self.assertSessionScoreEqual(5)
def setUp(self): super(FlowRuleExceptionTest, self).setUp() user = factories.UserFactory() self.participation = factories.ParticipationFactory(course=self.course, user=user) fake_get_course_repo = mock.patch("course.content.get_course_repo") self.mock_get_course_repo = fake_get_course_repo.start() self.mock_get_course_repo.return_value = mock.MagicMock() self.addCleanup(fake_get_course_repo.stop) fake_get_flow_desc = mock.patch("course.content.get_flow_desc") self.mock_get_flow_desc = fake_get_flow_desc.start() self.addCleanup(fake_get_flow_desc.stop) fake_validate_session_start_rule = mock.patch( "course.validation.validate_session_start_rule") self.mock_validate_session_start_rule = ( fake_validate_session_start_rule.start()) self.addCleanup(fake_validate_session_start_rule.stop) fake_validate_session_access_rule = mock.patch( "course.validation.validate_session_access_rule") self.mock_validate_session_access_rule = ( fake_validate_session_access_rule.start()) self.addCleanup(fake_validate_session_access_rule.stop) fake_validate_session_grading_rule = mock.patch( "course.validation.validate_session_grading_rule") self.mock_validate_session_grading_rule = ( fake_validate_session_grading_rule.start()) self.addCleanup(fake_validate_session_grading_rule.stop)
def test_deprecated_make_page_data_has_warning(self): with mock.patch("course.page.text.TextQuestionBase.make_page_data", autospec=True) as mock_make_page_data, mock.patch( "warnings.warn") as mock_warn: mock_make_page_data.side_effect = make_page_data_side_effect_has_data resp = self.get_page_sandbox_preview_response(TEXT_QUESTION_MARKDOWN) self.assertEqual(resp.status_code, 200) self.assertSandboxHasValidPage(resp) self.assertSandboxWarningTextContain(resp, None) # There are other warnings besides this expected warning self.assertTrue(mock_warn.call_count >= 1) expected_warn_msg = ( "TextQuestion is using the make_page_data compatiblity " "hook, which is deprecated.") warned_with_expected_msg = False for args in mock_warn.call_args_list: if expected_warn_msg in args[0]: warned_with_expected_msg = True break if not warned_with_expected_msg: self.fail("'%s' is not warned as expected" % expected_warn_msg)
def test_send_email_failure_when_request_python_run_with_retries_raise_uncaught_error(self): # noqa with mock.patch( RUNPY_WITH_RETRIES_PATH, autospec=True ) as mock_runpy: expected_error_str = ("This is an error raised with " "request_python_run_with_retries") mock_runpy.side_effect = RuntimeError(expected_error_str) with mock.patch("course.page.PageContext") as mock_page_context: mock_page_context.return_value.in_sandbox = False # This remove the warning caused by mocked commit_sha value # "CacheKeyWarning: Cache key contains characters that # will cause errors ..." mock_page_context.return_value.commit_sha = b"1234" with mock.patch("django.core.mail.message.EmailMessage.send") as mock_send: # noqa mock_send.side_effect = RuntimeError("some email send error") resp = self.get_page_sandbox_submit_answer_response( markdowns.CODE_MARKDWON, answer_data={"answer": ['c = b + a\r']}) self.assertContains(resp, expected_error_str) self.assertEqual(resp.status_code, 200) self.assertResponseContextAnswerFeedbackCorrectnessEquals(resp, None) self.assertEqual(len(mail.outbox), 0)
def setUp(self): super(FlowRuleExceptionTest, self).setUp() user = factories.UserFactory() self.participation = factories.ParticipationFactory( course=self.course, user=user) fake_get_course_repo = mock.patch("course.content.get_course_repo") self.mock_get_course_repo = fake_get_course_repo.start() self.mock_get_course_repo.return_value = mock.MagicMock() self.addCleanup(fake_get_course_repo.stop) fake_get_flow_desc = mock.patch("course.content.get_flow_desc") self.mock_get_flow_desc = fake_get_flow_desc.start() self.addCleanup(fake_get_flow_desc.stop) fake_validate_session_start_rule = mock.patch( "course.validation.validate_session_start_rule") self.mock_validate_session_start_rule = ( fake_validate_session_start_rule.start()) self.addCleanup(fake_validate_session_start_rule.stop) fake_validate_session_access_rule = mock.patch( "course.validation.validate_session_access_rule") self.mock_validate_session_access_rule = ( fake_validate_session_access_rule.start()) self.addCleanup(fake_validate_session_access_rule.stop) fake_validate_session_grading_rule = mock.patch( "course.validation.validate_session_grading_rule") self.mock_validate_session_grading_rule = ( fake_validate_session_grading_rule.start()) self.addCleanup(fake_validate_session_grading_rule.stop)
def test_validate_point_count_called(self): import random with mock.patch("course.page.base.validate_point_count")\ as mock_validate_point_count,\ mock.patch("course.page.base.get_auto_feedback")\ as mock_get_auto_feedback: mock_validate_point_count.side_effect = lambda x: x mock_get_auto_feedback.side_effect = lambda x: x for i in range(10): correctness = random.uniform(0, 15) feedback = "some feedback" AnswerFeedback(correctness, feedback) mock_validate_point_count.assert_called_once_with(correctness) # because feedback is not None self.assertEqual(mock_get_auto_feedback.call_count, 0) mock_validate_point_count.reset_mock() for i in range(10): correctness = random.uniform(0, 15) AnswerFeedback(correctness) # because get_auto_feedback is mocked, the call_count of # mock_validate_point_count is only once mock_validate_point_count.assert_called_once_with(correctness) mock_validate_point_count.reset_mock() # because feedback is None self.assertEqual(mock_get_auto_feedback.call_count, 1) mock_get_auto_feedback.reset_mock() AnswerFeedback(correctness=None) mock_validate_point_count.assert_called_once_with(None)
def test_success_test_restrict_to_first_attempt_invalid(self): with mock.patch( "course.analytics.make_grade_histogram" ) as mock_make_g_his, mock.patch( "course.analytics.make_page_answer_stats_list" ) as mock_make_stats_list, mock.patch( "course.analytics.make_time_histogram" ) as mock_make_t_his, mock.patch( "course.analytics.count_participants" ) as mock_count_particpt: resp = self.get_flow_analytics_view(flow_id=self.flow_id, restrict_to_first_attempt="foo") self.assertEqual(resp.status_code, 200) self.assertResponseContextEqual( resp, "flow_identifier", self.flow_id) # make_page_answer_stats_list is called # using restrict_to_first_attempt = 0 self.assertIn(0, mock_make_stats_list.call_args[0]) self.assertResponseContextEqual(resp, "restrict_to_first_attempt", 0) self.assertEqual(mock_make_g_his.call_count, 1) self.assertEqual(mock_make_stats_list.call_count, 1) self.assertEqual(mock_make_t_his.call_count, 1) self.assertEqual(mock_count_particpt.call_count, 1)
def test_languages_configured_course_has_force_lang_get_language_none( self): self.set_course_lang_to_ko() with mock.patch("course.utils.translation.get_language")\ as mock_get_language,\ mock.patch("course.utils.translation.deactivate_all")\ as mock_deactivate_all: mock_get_language.return_value = None home_visit_result = self.home_resp_contains_korean_with_diff_settings( ) self.assertEqual( # Display Korean according to i18n, language_code and browser home_visit_result[0], [False, True, False, True]) self.assertEqual(mock_deactivate_all.call_count, 0) mock_deactivate_all.reset_mock() course_page_visit_result = ( self.course_resp_contains_korean_with_diff_settings()) self.assertEqual( # All display Korean course_page_visit_result[0], [True, True, True, True]) # There are 4 visit, each will call deactivate_all() self.assertEqual(mock_deactivate_all.call_count, 4)
def test_success_test_restrict_to_first_attempt_invalid(self): with mock.patch( "course.analytics.make_grade_histogram" ) as mock_make_g_his, mock.patch( "course.analytics.make_page_answer_stats_list" ) as mock_make_stats_list, mock.patch( "course.analytics.make_time_histogram" ) as mock_make_t_his, mock.patch( "course.analytics.count_participants") as mock_count_particpt: resp = self.get_flow_analytics_view( flow_id=self.flow_id, restrict_to_first_attempt="foo") self.assertEqual(resp.status_code, 200) self.assertResponseContextEqual(resp, "flow_identifier", self.flow_id) # make_page_answer_stats_list is called # using restrict_to_first_attempt = 0 self.assertIn(0, mock_make_stats_list.call_args[0]) self.assertResponseContextEqual(resp, "restrict_to_first_attempt", 0) self.assertEqual(mock_make_g_his.call_count, 1) self.assertEqual(mock_make_stats_list.call_count, 1) self.assertEqual(mock_make_t_his.call_count, 1) self.assertEqual(mock_count_particpt.call_count, 1)
def verify_result_with_configure(self, my_site_name): # home page with mock.patch(REAL_TRANSLATION_FUNCTION_TO_MOCK) as mock_gettext: mock_gettext.side_effect = real_trans_side_effect resp = self.c.get("/") self.assertEqual(resp.status_code, 200) self.assertContains(resp, "<title>%s</title>" % my_site_name, html=True) # Three translations in nav_bar brand, html title and # "Welcome to RELATE", respectively self.assertEqual( self.get_translation_count(mock_gettext, my_site_name), 3) mock_gettext.reset_mock() # course page resp = self.c.get(self.get_course_page_url()) self.assertEqual(resp.status_code, 200) test_site_name_re = re.compile( ".+<title>.+-.+%s.+</title>.+" % my_site_name, re.DOTALL) self.assertRegex(resp.content.decode(), test_site_name_re) # One translation in html title self.assertEqual( self.get_translation_count(mock_gettext, my_site_name), 1) # email with override_settings(RELATE_REGISTRATION_ENABLED=True, USE_I18N=True): # render() is mocked so as to count string translated in email rendering with \ mock.patch(REAL_TRANSLATION_FUNCTION_TO_MOCK) \ as mock_gettext_global, \ mock.patch("course.auth._") as mock_gettext_auth, \ mock.patch('course.auth.messages'), \ mock.patch('course.auth.render'): mock_gettext_global.return_value = "foo" mock_gettext_auth.return_value = "foo" with self.temporarily_switch_to_user(None): resp = self.post_sign_up(data={ "username": "******", "email": "*****@*****.**" }, follow=False) self.assertTrue(resp.status_code, 200) self.assertEqual(len(mail.outbox), 1) # In the view, tranlating RELATE for email title. self.assertEqual( self.get_translation_count(mock_gettext_auth, my_site_name), 1) # Three RELATE in the email template self.assertEqual( self.get_translation_count(mock_gettext_global, my_site_name), 3)
def setUp(self): super(RunCourseUpdateCommandTest, self).setUp() self.course = factories.CourseFactory( active_git_commit_sha=self.default_old_sha) user = factories.UserFactory() instructor_role = factories.ParticipationRoleFactory( course=self.course, identifier="instructor" ) self.participation = factories.ParticipationFactory( course=self.course, preview_git_commit_sha=None, user=user) self.participation.roles.set([instructor_role]) self.request = mock.MagicMock() self.request.user = user self.pctx = mock.MagicMock() self.pctx.course = self.course self.pctx.participation = self.participation self.repo = mock.MagicMock() self.content_repo = self.repo fake_get_dulwich_client_and_remote_path_from_course = mock.patch( "course.versioning.get_dulwich_client_and_remote_path_from_course") self.mock_get_dulwich_client_and_remote_path_from_course = ( fake_get_dulwich_client_and_remote_path_from_course.start() ) self.mock_client = mock.MagicMock() remote_path = "/remote/path" self.mock_get_dulwich_client_and_remote_path_from_course.return_value = ( self.mock_client, remote_path ) self.mock_client.fetch.return_value = { b"HEAD": self.default_switch_to_sha.encode()} self.addCleanup(fake_get_dulwich_client_and_remote_path_from_course.stop) fake_transfer_remote_refs = mock.patch( "course.versioning.transfer_remote_refs") self.mock_transfer_remote_refs = fake_transfer_remote_refs.start() self.addCleanup(fake_transfer_remote_refs.stop) fake_is_parent_commit = mock.patch("course.versioning.is_parent_commit") self.mock_is_parent_commit = fake_is_parent_commit.start() self.mock_is_parent_commit.return_value = False self.addCleanup(fake_is_parent_commit.stop) fake_validate_course_content = mock.patch( "course.validation.validate_course_content") self.mock_validate_course_content = fake_validate_course_content.start() self.mock_validate_course_content.return_value = [] self.addCleanup(fake_validate_course_content.stop)
def test_attribute_error2(self): dtime = datetime.datetime(2019, 1, 1) with mock.patch("django.utils.formats.date_format" ) as mock_date_format, mock.patch( "django.utils.dateformat.format") as mock_format: mock_date_format.side_effect = date_format_side_effect mock_format.side_effect = format_side_effectformat result = format_datetime_local(dtime, format="foo") self.assertEqual( result, date_format(dtime, format=get_format("DATETIME_FORMAT")))
def test_form_not_valid(self): with mock.patch("course.versioning.GitUpdateForm.is_valid" ) as mock_form_valid, mock.patch( "course.versioning.run_course_update_command" ) as mock_run_update: mock_form_valid.return_value = False resp = self.post_update_course_content("some_commit_sha", command="update") self.assertEqual(resp.status_code, 200) self.assertEqual(mock_run_update.call_count, 0)
def test_form_not_valid(self): with mock.patch( "course.versioning.GitUpdateForm.is_valid" ) as mock_form_valid, mock.patch( "course.versioning.run_course_update_command" ) as mock_run_update: mock_form_valid.return_value = False resp = self.post_update_course_content( "some_commit_sha", command="update") self.assertEqual(resp.status_code, 200) self.assertEqual(mock_run_update.call_count, 0)
def test_attribute_error2(self): dtime = datetime.datetime(2019, 1, 1) with mock.patch( "django.utils.formats.date_format" ) as mock_date_format, mock.patch( "django.utils.dateformat.format" ) as mock_format: mock_date_format.side_effect = date_format_side_effect mock_format.side_effect = format_side_effectformat result = format_datetime_local( dtime, format="foo") self.assertEqual( result, date_format(dtime, format=get_format("DATETIME_FORMAT")))
def test_set_up_new_course_git_source_invalid(self): data = self.get_set_up_new_course_form_data() request = self.rf.post(self.get_set_up_new_course_url(), data=data) request.user = self.instructor with mock.patch("dulwich.client.GitClient.fetch", return_value=None), \ mock.patch("course.models.Course.save") as mock_save, \ mock.patch("course.versioning.render"): resp = versioning.set_up_new_course(request) self.assertTrue(resp.status_code, 200) self.assertEqual(mock_save.call_count, 0) self.assertAddMessageCalledWith( "No refs found in remote repository")
def verify_result_with_configure(self, my_site_name): # home page with mock.patch(REAL_TRANSLATION_FUNCTION_TO_MOCK) as mock_gettext: mock_gettext.side_effect = real_trans_side_effect resp = self.c.get("/") self.assertEqual(resp.status_code, 200) self.assertContains(resp, "<title>%s</title>" % my_site_name, html=True) # Three translations in nav_bar brand, html title and # "Welcome to RELATE", respectively self.assertEqual( self.get_translation_count(mock_gettext, my_site_name), 3) mock_gettext.reset_mock() # course page resp = self.c.get(self.get_course_page_url()) self.assertEqual(resp.status_code, 200) test_site_name_re = re.compile( ".+<title>.+-.+%s.+</title>.+" % my_site_name, re.DOTALL) self.assertRegex(resp.content.decode(), test_site_name_re) # One translation in html title self.assertEqual( self.get_translation_count(mock_gettext, my_site_name), 1) # email with override_settings(RELATE_REGISTRATION_ENABLED=True, USE_I18N=True): # render() is mocked so as to count string translated in email rendering with mock.patch(REAL_TRANSLATION_FUNCTION_TO_MOCK) as mock_gettext,\ mock.patch("course.auth._") as mock_ugettext,\ mock.patch('course.auth.messages'),\ mock.patch('course.auth.render'): mock_gettext.return_value = "foo" with self.temporarily_switch_to_user(None): resp = self.post_sign_up( data={"username": "******", "email": "*****@*****.**"}, follow=False ) self.assertTrue(resp.status_code, 200) self.assertEqual(len(mail.outbox), 1) # In the view, tranlating RELATE for email title. self.assertEqual( self.get_translation_count(mock_ugettext, my_site_name), 1) # Three RELATE in the email template self.assertEqual( self.get_translation_count(mock_gettext, my_site_name), 3)
def test_update_course_user_not_active(self): user = factories.UserFactory(is_active=False) factories.ParticipationFactory(course=self.course, user=user, status=participation_status.requested) factories.ParticipationPreapprovalFactory(course=self.course, email=user.email) with mock.patch( "course.models.ParticipationPreapproval.objects.get")\ as mock_pprvl_get,\ mock.patch(HANDLE_ENROLLMENT_PATH) as mock_handle_enrollment: self.course.listed = not self.course.listed self.course.save() self.assertEqual(mock_pprvl_get.call_count, 0) self.assertEqual(mock_handle_enrollment.call_count, 0)
def test_custom_get_full_name_method_failed(self): """ Test when RELATE_USER_FULL_NAME_FORMAT_METHOD failed, default method is used. """ user = UserFactory.create(first_name="my_first", last_name="my_last") default_get_full_name = user.get_full_name() custom_get_full_name_path = ( "tests.resource.my_customized_get_full_name_method") get_custom_full_name_method_path = ( "accounts.utils.RelateUserMethodSettingsInitializer" ".custom_full_name_method") with override_settings( RELATE_USER_FULL_NAME_FORMAT_METHOD=custom_get_full_name_path): from accounts.utils import relate_user_method_settings # clear cached value relate_user_method_settings.__dict__ = {} # If custom method works, the returned value is different with # default value. self.assertNotEqual(default_get_full_name, user.get_full_name()) with mock.patch(get_custom_full_name_method_path) as mock_custom_method: # clear cached value relate_user_method_settings.__dict__ = {} # raise an error when calling custom method mock_custom_method.side_effect = Exception() # the value falls back to default value self.assertEqual(user.get_full_name(), default_get_full_name)
def test_feedback_notify_with_grader_feedback_connection(self): grade_data_extra_kwargs = { "feedback_text": 'test feedback', "notify": "on" } from django.core.mail import get_connection connection = get_connection( backend='django.core.mail.backends.locmem.EmailBackend') with mock.patch( "django.core.mail.get_connection") as mock_get_connection: mock_get_connection.return_value = connection self.submit_page_human_grading_by_page_id_and_test( self.page_id, grade_data_extra_kwargs=grade_data_extra_kwargs) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].from_email, "*****@*****.**") self.assertEqual(mock_get_connection.call_args[1]["backend"], "tests.resource.MyFakeEmailBackend") # make sure the name (appellation) is in the email body, not the masked one self.assertIn(self.student_participation.user.get_email_appellation(), mail.outbox[0].body) self.assertNotIn(self.student_participation.user.get_masked_profile(), mail.outbox[0].body) self.assertNotIn("Dear user", mail.outbox[0].body)
def test_choice_not_stringifiable(self): expected_page_error = ( "choice 10: unable to convert to string") class BadChoice(object): def __str__(self): raise Exception from relate.utils import dict_to_struct fake_page_desc = dict_to_struct( {'type': 'SurveyChoiceQuestion', 'id': 'age_group_with_comment', 'answer_comment': 'this is a survey question', 'prompt': '\n# Age\n\nHow old are you?\n', 'choices': [ '0-10 years', '11-20 years', '21-30 years', '31-40 years', '41-50 years', '51-60 years', '61-70 years', '71-80 years', '81-90 years', BadChoice()], '_field_names': ['type', 'id', 'answer_comment', 'prompt', 'choices']} ) with mock.patch("relate.utils.dict_to_struct") as mock_dict_to_struct: mock_dict_to_struct.return_value = fake_page_desc markdown = SURVEY_CHOICE_QUESTION_MARKDOWN resp = ( self.get_page_sandbox_preview_response(markdown)) self.assertEqual(resp.status_code, 200) self.assertSandboxNotHasValidPage(resp) self.assertResponseContextContains(resp, PAGE_ERRORS, expected_page_error)
def test_finish_in_progress_sessions_past_due_only_dued(self): # now_datetime > grading_rule.due fake_grading_rule = self.get_hacked_session_grading_rule( due=now() + timedelta(days=1)) with mock.patch("course.flow.get_session_grading_rule") as \ mock_get_grading_rule: mock_get_grading_rule.return_value = fake_grading_rule finish_in_progress_sessions(self.gopp.course_id, self.gopp.flow_id, rule_tag=None, now_datetime=now() + timedelta(days=3), past_due_only=True) self.assertEqual( models.FlowSession.objects.filter(in_progress=True).count(), 0) self.assertEqual( models.FlowSession.objects.filter(in_progress=False).count(), self.all_sessions_count) self.assertEqual( models.FlowPageVisitGrade.objects.filter( visit__flow_session__in=self.ended_sessions).count(), 0) for ended_session in self.in_progress_sessions: self.assertTrue( models.FlowPageVisitGrade.objects.filter( visit__flow_session=ended_session).count() > 0) self.assertEqual(self.mock_update_state.call_count, self.in_progress_sessions_count)
def test_finish_in_progress_sessions_past_due_only_dued(self): # now_datetime > grading_rule.due fake_grading_rule = self.get_hacked_session_grading_rule( due=now() + timedelta(days=1)) with mock.patch("course.flow.get_session_grading_rule") as \ mock_get_grading_rule: mock_get_grading_rule.return_value = fake_grading_rule finish_in_progress_sessions( self.gopp.course_id, self.gopp.flow_id, rule_tag=None, now_datetime=now()+timedelta(days=3), past_due_only=True) self.assertEqual( models.FlowSession.objects.filter(in_progress=True).count(), 0) self.assertEqual( models.FlowSession.objects.filter(in_progress=False).count(), self.all_sessions_count) self.assertEqual( models.FlowPageVisitGrade.objects.filter( visit__flow_session__in=self.ended_sessions).count(), 0) for ended_session in self.in_progress_sessions: self.assertTrue( models.FlowPageVisitGrade.objects.filter( visit__flow_session=ended_session).count() > 0) self.assertEqual( self.mock_update_state.call_count, self.in_progress_sessions_count)
def test_markup_to_html_plain_wrapp_by_p_tag(self): with mock.patch("course.page.choice.markup_to_html") as mock_mth: mock_mth.side_effect = lambda x, y: "<p>%s</p>" % y fake_page_context = object self.assertEqual(markup_to_html_plain(fake_page_context, "abcd"), "abcd") self.assertEqual(markup_to_html_plain(fake_page_context, ""), "")
def test_no_pperm(self): with mock.patch( "course.utils.CoursePageContext.has_permission" ) as mock_has_pperm: mock_has_pperm.return_value = False resp = self.get_course_calendar_view() self.assertEqual(resp.status_code, 403)
def test_attribute_error1(self): dtime = datetime.datetime(2019, 1, 1) with mock.patch( "django.utils.formats.date_format") as mock_date_format: mock_date_format.side_effect = date_format_side_effect result = format_datetime_local(dtime, format="foo") self.assertEqual(result, date_format(dtime, format="foo"))
def test_post_form_not_valid(self): with mock.patch( "course.calendar.RenumberEventsForm.is_valid" ) as mock_form_valid: mock_form_valid.return_value = False resp = self.post_renumber_events_view( data=self.get_post_renumber_evt_data(starting_ordinal=3)) self.assertEqual(resp.status_code, 200) all_default_evts = Event.objects.filter(kind=self.default_event_kind) self.assertEqual(all_default_evts.count(), 5) self.assertListEqual( list(all_default_evts.values_list("ordinal", flat=True)), [1, 3, 5, 7, 9]) t = None for evt in all_default_evts: if t is None: t = evt.time continue else: self.assertEqual(evt.time - t, datetime.timedelta(weeks=1)) t = evt.time # other events also not affected self.evt_another_kind1.refresh_from_db() self.evt_another_kind2.refresh_from_db() self.assertEqual( self.evt_another_kind1.ordinal, self.evt_another_kind1_ordinal) self.assertEqual( self.evt_another_kind2.ordinal, self.evt_another_kind2_ordinal)
def test_form_invalid(self): with mock.patch( "course.exam.ExamCheckInForm.is_valid") as mock_is_valid: mock_is_valid.return_value = False resp = self.post_check_in_for_exam_view(data=self.get_post_data()) self.assertEqual(resp.status_code, 200) self.assertEqual(self.ticket.state, constants.exam_ticket_states.valid)
def setUp(self): self.requset = mock.MagicMock() self.requset.relate_facilities = ["fa1", "fa2"] fake_get_facilities_config = mock.patch( "course.utils.get_facilities_config") self.mock_get_facilities_config = fake_get_facilities_config.start() self.addCleanup(fake_get_facilities_config.stop)
def test_update_course_no_requested(self): with mock.patch(HANDLE_ENROLLMENT_PATH) as mock_handle_enrollment: mock_handle_enrollment.return_value = None self.course.listed = not self.course.listed self.course.save() self.assertEqual(mock_handle_enrollment.call_count, 0)
def test_form_invalid(self): with mock.patch("course.exam.BatchIssueTicketsForm.is_valid" ) as mock_is_valid: mock_is_valid.return_value = False resp = self.post_batch_issue_exam_ticket_view(data=self.get_post_data()) self.assertEqual(resp.status_code, 200) self.assertEqual(ExamTicket.objects.count(), 0)
def test_expire_in_progress_sessions_past_due_only_not_dued(self): # now_datetime <= grading_rule.due fake_grading_rule = self.get_hacked_session_grading_rule( due=now() + timedelta(days=1)) with mock.patch("course.flow.get_session_grading_rule") as \ mock_get_grading_rule: mock_get_grading_rule.return_value = fake_grading_rule expire_in_progress_sessions( self.gopp.course.id, self.gopp.flow_id, rule_tag=None, now_datetime=now(), past_due_only=True) self.assertEqual( models.FlowSession.objects.filter(in_progress=True).count(), self.in_progress_sessions_count) self.assertEqual( models.FlowSession.objects.filter(in_progress=False).count(), self.ended_sessions_count) self.assertEqual(self.mock_update_state.call_count, self.in_progress_sessions_count) self.assertEqual( self.mock_update_state.call_count, self.in_progress_sessions_count)
def test_form_invalid(self): with mock.patch("course.exam.ExamCheckInForm.is_valid" ) as mock_is_valid: mock_is_valid.return_value = False resp = self.post_check_in_for_exam_view(data=self.get_post_data()) self.assertEqual(resp.status_code, 200) self.assertEqual(self.ticket.state, constants.exam_ticket_states.valid)
def test_regrade_with_access_rules_tag(self): with mock.patch("course.flow.regrade_session") as mock_regrade: regrade_flow_sessions(self.gopp.course_id, self.gopp.flow_id, access_rules_tag="None exist tag", inprog_value=None ) mock_regrade.return_value = None # no regrade happened self.assertEqual(mock_regrade.call_count, 0) first_session = models.FlowSession.objects.first() first_session.access_rules_tag = "some tag" first_session.save() regrade_flow_sessions(self.gopp.course_id, self.gopp.flow_id, access_rules_tag="some tag", inprog_value=None ) self.assertEqual(mock_regrade.call_count, 1) self.assertIn(first_session, mock_regrade.call_args[0]) self.assertEqual(self.mock_update_state.call_count, 1)
def test_symbolic_expression_matcher_validation_error(self): with mock.patch("pymbolic.parse") as mock_pymbolic_parse: expected_error_msg = "some error" mock_pymbolic_parse.side_effect = ValueError(expected_error_msg) with self.assertRaises(ValidationError) as cm: SymbolicExpressionMatcher(None, "", "abcd") self.assertIn(expected_error_msg, str(cm.exception))
def test_expire_in_progress_sessions_past_due_only_not_dued(self): # now_datetime <= grading_rule.due fake_grading_rule = self.get_hacked_session_grading_rule( due=now() + timedelta(days=1)) with mock.patch("course.flow.get_session_grading_rule") as \ mock_get_grading_rule: mock_get_grading_rule.return_value = fake_grading_rule expire_in_progress_sessions(self.gopp.course.id, self.gopp.flow_id, rule_tag=None, now_datetime=now(), past_due_only=True) self.assertEqual( models.FlowSession.objects.filter(in_progress=True).count(), self.in_progress_sessions_count) self.assertEqual( models.FlowSession.objects.filter(in_progress=False).count(), self.ended_sessions_count) self.assertEqual(self.mock_update_state.call_count, self.in_progress_sessions_count) self.assertEqual(self.mock_update_state.call_count, self.in_progress_sessions_count)
def test_notes_and_notify_with_grader_feedback_connection(self): grade_data_extra_kwargs = { "notes": 'test notes', "notify_instructor": "on" } from django.core.mail import get_connection connection = get_connection( backend='django.core.mail.backends.locmem.EmailBackend') with mock.patch("django.core.mail.get_connection") as mock_get_connection: mock_get_connection.return_value = connection with self.temporarily_switch_to_user(self.ta_participation.user): self.submit_page_human_grading_by_page_id_and_test( self.page_id, grade_data_extra_kwargs=grade_data_extra_kwargs, force_login_instructor=False) self.assertEqual(len(mail.outbox), 1) self.assertIn(self.course.notify_email, mail.outbox[0].recipients()) self.assertEqual(mail.outbox[0].from_email, "*****@*****.**") self.assertEqual( mock_get_connection.call_args[1]["backend"], "tests.resource.MyFakeEmailBackend" ) # make sure the name (appellation) is in the email body, not the masked one self.assertIn( self.student_participation.user.get_email_appellation(), mail.outbox[0].body) self.assertNotIn( self.student_participation.user.get_masked_profile(), mail.outbox[0].body)
def test_regrade_with_access_rules_tag(self): with mock.patch("course.flow.regrade_session") as mock_regrade: regrade_flow_sessions(self.gopp.course_id, self.gopp.flow_id, access_rules_tag="None exist tag", inprog_value=None) mock_regrade.return_value = None # no regrade happened self.assertEqual(mock_regrade.call_count, 0) first_session = models.FlowSession.objects.first() first_session.access_rules_tag = "some tag" first_session.save() regrade_flow_sessions(self.gopp.course_id, self.gopp.flow_id, access_rules_tag="some tag", inprog_value=None) self.assertEqual(mock_regrade.call_count, 1) self.assertIn(first_session, mock_regrade.call_args[0]) self.assertEqual(self.mock_update_state.call_count, 1)
def test_feedback_notify_with_grader_feedback_connection(self): grade_data_extra_kwargs = { "feedback_text": 'test feedback', "notify": "on" } from django.core.mail import get_connection connection = get_connection( backend='django.core.mail.backends.locmem.EmailBackend') with mock.patch("django.core.mail.get_connection") as mock_get_connection: mock_get_connection.return_value = connection self.submit_page_human_grading_by_page_id_and_test( self.page_id, grade_data_extra_kwargs=grade_data_extra_kwargs) self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].from_email, "*****@*****.**") self.assertEqual( mock_get_connection.call_args[1]["backend"], "tests.resource.MyFakeEmailBackend" ) # make sure the name (appellation) is in the email body, not the masked one self.assertIn( self.student_participation.user.get_email_appellation(), mail.outbox[0].body) self.assertNotIn( self.student_participation.user.get_masked_profile(), mail.outbox[0].body) self.assertNotIn( "Dear user", mail.outbox[0].body)
def test_markup_to_html_plain_wrapp_by_p_other_tag(self): with mock.patch("course.page.choice.markup_to_html") as mock_mth: mock_mth.side_effect = lambda x, y: "<div>%s</div>" % y fake_page_context = object self.assertEqual( markup_to_html_plain(fake_page_context, "abcd"), "<div>abcd</div>")
def test_notes_and_notify_with_grader_feedback_connection(self): grade_data_extra_kwargs = { "notes": 'test notes', "notify_instructor": "on" } from django.core.mail import get_connection connection = get_connection( backend='django.core.mail.backends.locmem.EmailBackend') with mock.patch( "django.core.mail.get_connection") as mock_get_connection: mock_get_connection.return_value = connection with self.temporarily_switch_to_user(self.ta_participation.user): self.submit_page_human_grading_by_page_id_and_test( self.page_id, grade_data_extra_kwargs=grade_data_extra_kwargs, force_login_instructor=False) self.assertEqual(len(mail.outbox), 1) self.assertIn(self.course.notify_email, mail.outbox[0].recipients()) self.assertEqual(mail.outbox[0].from_email, "*****@*****.**") self.assertEqual(mock_get_connection.call_args[1]["backend"], "tests.resource.MyFakeEmailBackend") # make sure the name (appellation) is in the email body, not the masked one self.assertIn(self.student_participation.user.get_email_appellation(), mail.outbox[0].body) self.assertNotIn(self.student_participation.user.get_masked_profile(), mail.outbox[0].body)
def test_invalid_path(self): with override_settings(RELATE_OVERRIDE_TEMPLATES_DIRS=self.INVALID_CONF3): with mock.patch("relate.checks.os.path.isdir", side_effect=is_dir_side_effect): self.assertCheckMessages( ["relate_override_templates_dirs.W001", "relate_override_templates_dirs.W001"])