From d18a61f84e847d05e4a4707b2f806b82c55cf3b5 Mon Sep 17 00:00:00 2001 From: dzhuang <dzhuang.scut@gmail.com> Date: Tue, 27 Feb 2018 14:19:48 +0800 Subject: [PATCH] Refactored grading interface tests into test_grading. --- tests/test_grading.py | 265 +++++++++++++++++++++++++++++++ tests/test_pages/test_generic.py | 261 +----------------------------- 2 files changed, 273 insertions(+), 253 deletions(-) create mode 100644 tests/test_grading.py diff --git a/tests/test_grading.py b/tests/test_grading.py new file mode 100644 index 00000000..99ac8e4d --- /dev/null +++ b/tests/test_grading.py @@ -0,0 +1,265 @@ +from __future__ import division + +__copyright__ = "Copyright (C) 2018 Dong Zhuang" + +__license__ = """ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import os + +from django.core import mail +from django.test import TestCase + +from tests.base_test_mixins import SingleCoursePageTestMixin +from tests.test_pages import QUIZ_FLOW_ID +from tests import factories + + +class SingleCourseQuizPageGradeInterfaceTestMixin(SingleCoursePageTestMixin): + + flow_id = QUIZ_FLOW_ID + + @classmethod + def setUpTestData(cls): # noqa + super(SingleCourseQuizPageGradeInterfaceTestMixin, cls).setUpTestData() + cls.c.force_login(cls.student_participation.user) + cls.start_flow(cls.flow_id) + cls.this_flow_session_id = cls.default_flow_params["flow_session_id"] + cls.any_up_page_id = "anyup" + cls.submit_any_upload_question() + + def submit_any_upload_question_null(self): + return self.post_answer_by_page_id( + "anyup", {"uploaded_file": []}) + + @classmethod + def submit_any_upload_question(cls): + with open( + os.path.join(os.path.dirname(__file__), + 'fixtures', 'test_file.txt'), 'rb') as fp: + answer_data = {"uploaded_file": fp} + return cls.post_answer_by_page_id_class( + cls.any_up_page_id, answer_data, **cls.default_flow_params) + + +class SingleCourseQuizPageGradeInterfaceTest( + SingleCourseQuizPageGradeInterfaceTestMixin, TestCase): + + @classmethod + def setUpTestData(cls): # noqa + super(SingleCourseQuizPageGradeInterfaceTest, cls).setUpTestData() + cls.end_flow() + + def setUp(self): # noqa + # This is needed to ensure student is logged in to submit page or end flow. + self.c.force_login(self.student_participation.user) + + def test_post_grades(self): + grade_data = { + "grade_percent": ["100"], + "released": ["on"] + } + resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertTrue(resp.status_code, 200) + self.assertSessionScoreEqual(5) + + grade_data = { + "grade_points": ["4"], + "released": [] + } + resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertTrue(resp.status_code, 200) + + self.assertSessionScoreEqual(None) + + grade_data = { + "grade_points": ["4"], + "released": ["on"] + } + resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertTrue(resp.status_code, 200) + + self.assertSessionScoreEqual(4) + + def test_post_grades_success(self): + grade_data = { + "grade_percent": ["100"], + "released": ['on'] + } + + resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertTrue(resp.status_code, 200) + + self.assertSessionScoreEqual(5) + + def test_post_grades_huge_points_failure(self): + grade_data = { + "grade_percent": ["2000"], + "released": ['on'] + } + + resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertTrue(resp.status_code, 200) + + # value exceeded allowed + self.assertResponseContextContains( + resp, "grading_form_html", + "Ensure this value is less than or equal to") + + self.assertSessionScoreEqual(None) + + def test_post_grades_forbidden(self): + grade_data = { + "grade_percent": ["100"], + "released": ['on'] + } + + # with self.student_participation.user logged in + resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data, + force_login_instructor=False) + self.assertTrue(resp.status_code, 403) + + self.assertSessionScoreEqual(None) + + def test_feedback_and_notify(self): + grade_data = { + "grade_percent": ["100"], + "released": ['on'], + "feedback_text": ['test feedback'] + } + + self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertEqual(len(mail.outbox), 0) + + grade_data["notify"] = ["on"] + self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].reply_to, []) + + def test_feedback_email_may_reply(self): + grade_data = { + "grade_percent": ["100"], + "released": ['on'], + "feedback_text": ['test feedback'], + "notify": ["on"], + "may_reply": ["on"] + } + + with self.temporarily_switch_to_user(self.ta_participation.user): + self.post_grade_by_page_id(self.any_up_page_id, grade_data, + force_login_instructor=False) + self.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].reply_to, + [self.ta_participation.user.email]) + + def test_notes_and_notify(self): + grade_data = { + "grade_percent": ["100"], + "released": ['on'], + "notes": ['test notes'] + } + + self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertEqual(len(mail.outbox), 0) + + grade_data["notify_instructor"] = ["on"] + self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertEqual(len(mail.outbox), 1) + + # {{{ tests on grading history dropdown + def test_grade_history_failure_no_perm(self): + ta_flow_session = factories.FlowSessionFactory( + participation=self.ta_participation) + + # no pperm to view other's grade_history + resp = self.c.post( + self.get_page_grade_history_url_by_ordinal( + page_ordinal=1, flow_session_id=ta_flow_session.pk)) + self.assertEqual(resp.status_code, 403) + + def test_grade_history_failure_not_ajax(self): + resp = self.c.get( + self.get_page_grade_history_url_by_ordinal( + page_ordinal=1)) + self.assertEqual(resp.status_code, 403) + + def test_submit_history_failure_not_get(self): + resp = self.c.post( + self.get_page_grade_history_url_by_ordinal( + page_ordinal=1), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(resp.status_code, 403) + + def test_grade_history_failure_not_authenticated(self): + with self.temporarily_switch_to_user(None): + resp = self.c.get( + self.get_page_grade_history_url_by_ordinal( + page_ordinal=1), HTTP_X_REQUESTED_WITH='XMLHttpRequest') + self.assertEqual(resp.status_code, 403) + + # }}} + + +class SingleCourseQuizPageGradeInterfaceTestExtra( + SingleCourseQuizPageGradeInterfaceTestMixin, TestCase): + + def setUp(self): # noqa + # This is needed to ensure student is logged in to submit page or end flow. + self.c.force_login(self.student_participation.user) + + def test_post_grades_history(self): + # This submission failed + resp = self.submit_any_upload_question_null() + self.assertFormErrorLoose(resp, "This field is required.") + + # 2nd submission succeeded + resp = self.submit_any_upload_question() + self.end_flow() + + grade_data = { + "grade_percent": ["100"], + "released": ["on"] + } + resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertTrue(resp.status_code, 200) + self.assertSessionScoreEqual(5) + + ordinal = self.get_page_ordinal_via_page_id(self.any_up_page_id) + self.assertGradeHistoryItemsCount(page_ordinal=ordinal, expected_count=3) + + grade_data = { + "grade_points": ["4"], + "released": [] + } + resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertTrue(resp.status_code, 200) + self.assertSessionScoreEqual(None) + self.assertGradeHistoryItemsCount(page_ordinal=ordinal, expected_count=4) + + grade_data = { + "grade_points": ["4"], + "released": ["on"] + } + resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) + self.assertTrue(resp.status_code, 200) + self.assertSessionScoreEqual(4) + self.assertGradeHistoryItemsCount(page_ordinal=ordinal, + expected_count=5) + +# vim: fdm=marker diff --git a/tests/test_pages/test_generic.py b/tests/test_pages/test_generic.py index f62d9e08..95c592fb 100644 --- a/tests/test_pages/test_generic.py +++ b/tests/test_pages/test_generic.py @@ -28,7 +28,6 @@ from base64 import b64encode import unittest from django.test import TestCase from django.urls import resolve -from django.core import mail from course.models import FlowSession from course.constants import MAX_EXTRA_CREDIT_FACTOR @@ -39,7 +38,8 @@ from course.page.base import ( from tests.base_test_mixins import ( SingleCoursePageTestMixin, FallBackStorageMessageTestMixin, SubprocessRunpyContainerMixin) -from tests.utils import LocmemBackendTestsMixin, mock +from tests.utils import mock +from tests import factories QUIZ_FLOW_ID = "quiz-test" @@ -286,6 +286,8 @@ class SingleCourseQuizPageTest(SingleCoursePageTestMixin, '../fixtures', 'test_file.txt'), 'rb') as fp: resp = self.post_answer_by_page_id( page_id, {"uploaded_file": fp}) + + # https://github.com/inducer/relate/issues/351 self.assertEqual(resp.status_code, 200) self.assertResponseMessagesContains(resp, [MESSAGE_ANSWER_FAILED_SAVE_TEXT]) @@ -365,259 +367,12 @@ class SingleCourseQuizPageTest(SingleCoursePageTestMixin, self.get_page_submit_history_url_by_ordinal(page_ordinal=1)) self.assertEqual(resp.status_code, 403) - # }}} - - -class SingleCourseQuizPageTestExtra(SingleCoursePageTestMixin, - FallBackStorageMessageTestMixin, TestCase): - flow_id = QUIZ_FLOW_ID - - @classmethod - def setUpTestData(cls): # noqa - super(SingleCourseQuizPageTestExtra, cls).setUpTestData() - # this time we create a session submitted by ta - cls.c.force_login(cls.ta_participation.user) - cls.start_flow(cls.flow_id) - - def setUp(self): # noqa - super(SingleCourseQuizPageTestExtra, self).setUp() - # This is needed to ensure student is logged in - self.c.force_login(self.student_participation.user) - - def test_grade_history_failure_no_perm(self): - self.end_flow() - - # no pperm to view other's grade_history - resp = self.c.post( - self.get_page_grade_history_url_by_ordinal( - page_ordinal=1)) - self.assertEqual(resp.status_code, 403) - def test_submit_history_failure_no_perm(self): # student have no pperm to view ta's submit history - resp = self.c.post( - self.get_page_submit_history_url_by_ordinal(page_ordinal=1)) - self.assertEqual(resp.status_code, 403) - - -class SingleCourseQuizPageGradeInterfaceTest(LocmemBackendTestsMixin, - SingleCoursePageTestMixin, - FallBackStorageMessageTestMixin, TestCase): - flow_id = QUIZ_FLOW_ID - - @classmethod - def setUpTestData(cls): # noqa - super(SingleCourseQuizPageGradeInterfaceTest, cls).setUpTestData() - cls.c.force_login(cls.student_participation.user) - cls.start_flow(cls.flow_id) - cls.this_flow_session_id = cls.default_flow_params["flow_session_id"] - cls.any_up_page_id = "anyup" - cls.submit_any_upload_question() - - def setUp(self): # noqa - super(SingleCourseQuizPageGradeInterfaceTest, self).setUp() - # This is needed to ensure student is logged in - self.c.force_login(self.student_participation.user) - - def submit_any_upload_question_null_failure(self): - self.post_answer_by_page_id( - "anyup", {"uploaded_file": []}) - - @classmethod - def submit_any_upload_question(cls): - with open( - os.path.join(os.path.dirname(__file__), - '../fixtures', 'test_file.txt'), 'rb') as fp: - answer_data = {"uploaded_file": fp} - cls.post_answer_by_page_id_class( - cls.any_up_page_id, answer_data, **cls.default_flow_params) - - def test_post_grades(self): - self.end_flow() - grade_data = { - "grade_percent": ["100"], - "released": ["on"] - } - resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertTrue(resp.status_code, 200) - self.assertSessionScoreEqual(5) - - grade_data = { - "grade_points": ["4"], - "released": [] - } - resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertTrue(resp.status_code, 200) - - self.assertSessionScoreEqual(None) - - grade_data = { - "grade_points": ["4"], - "released": ["on"] - } - resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertTrue(resp.status_code, 200) - - self.assertSessionScoreEqual(4) - - def test_post_grades_history(self): - # failure - self.post_answer_by_page_id("anyup", {"uploaded_file": []}) - - # 2nd success - self.submit_any_upload_question() - self.end_flow() - - grade_data = { - "grade_percent": ["100"], - "released": ["on"] - } - resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertTrue(resp.status_code, 200) - self.assertSessionScoreEqual(5) - - ordinal = self.get_page_ordinal_via_page_id(self.any_up_page_id) - self.assertGradeHistoryItemsCount(page_ordinal=ordinal, expected_count=3) - - grade_data = { - "grade_points": ["4"], - "released": [] - } - resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertTrue(resp.status_code, 200) - self.assertSessionScoreEqual(None) - self.assertGradeHistoryItemsCount(page_ordinal=ordinal, expected_count=4) - - grade_data = { - "grade_points": ["4"], - "released": ["on"] - } - resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertTrue(resp.status_code, 200) - self.assertSessionScoreEqual(4) - self.assertGradeHistoryItemsCount(page_ordinal=ordinal, - expected_count=5) - - def test_post_grades_success(self): - self.end_flow() - - grade_data = { - "grade_percent": ["100"], - "released": ['on'] - } - - resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertTrue(resp.status_code, 200) - - self.assertSessionScoreEqual(5) - - def test_post_grades_huge_points_failure(self): - self.end_flow() - - grade_data = { - "grade_percent": ["2000"], - "released": ['on'] - } - - resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertTrue(resp.status_code, 200) - - # value exceeded allowed - self.assertResponseContextContains( - resp, "grading_form_html", - "Ensure this value is less than or equal to") - - self.assertSessionScoreEqual(None) - - def test_post_grades_forbidden(self): - self.end_flow() - - grade_data = { - "grade_percent": ["100"], - "released": ['on'] - } - - # with self.student_participation.user logged in - resp = self.post_grade_by_page_id(self.any_up_page_id, grade_data, - force_login_instructor=False) - self.assertTrue(resp.status_code, 403) - - self.assertSessionScoreEqual(None) - - def test_feedback_and_notify(self): - self.end_flow() - - grade_data = { - "grade_percent": ["100"], - "released": ['on'], - "feedback_text": ['test feedback'] - } - - self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertEqual(len(mail.outbox), 0) - - grade_data["notify"] = ["on"] - self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].reply_to, []) - - def test_feedback_email_may_reply(self): - self.end_flow() - - grade_data = { - "grade_percent": ["100"], - "released": ['on'], - "feedback_text": ['test feedback'], - "notify": ["on"], - "may_reply": ["on"] - } - - with self.temporarily_switch_to_user(self.ta_participation.user): - self.post_grade_by_page_id(self.any_up_page_id, grade_data, - force_login_instructor=False) - self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].reply_to, [self.ta_participation.user.email]) - - def test_notes_and_notify(self): - self.end_flow() - - grade_data = { - "grade_percent": ["100"], - "released": ['on'], - "notes": ['test notes'] - } - - self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertEqual(len(mail.outbox), 0) - - grade_data["notify_instructor"] = ["on"] - self.post_grade_by_page_id(self.any_up_page_id, grade_data) - self.assertEqual(len(mail.outbox), 1) - - # {{{ tests on grading history dropdown - def test_grade_history_failure_not_ajax(self): - self.end_flow() - - resp = self.c.get( - self.get_page_grade_history_url_by_ordinal( - page_ordinal=1)) - self.assertEqual(resp.status_code, 403) - - def test_submit_history_failure_not_get(self): - self.end_flow() - - resp = self.c.post( - self.get_page_grade_history_url_by_ordinal( - page_ordinal=1)) - self.assertEqual(resp.status_code, 403) - - def test_grade_history_failure_not_authenticated(self): - self.end_flow() - - with self.temporarily_switch_to_user(None): - resp = self.c.post( - self.get_page_grade_history_url_by_ordinal( - page_ordinal=1)) + ta_flow_session = factories.FlowSessionFactory( + participation=self.ta_participation) + resp = self.get_page_submit_history_by_ordinal( + page_ordinal=1, flow_session_id=ta_flow_session.id) self.assertEqual(resp.status_code, 403) # }}} -- GitLab