From 6a0bac488cd746ba962d0242649c640692d8bc2b Mon Sep 17 00:00:00 2001 From: zwang180 Date: Sun, 9 Apr 2017 05:56:09 -0500 Subject: [PATCH 01/21] waste too many time on getting more participations enrolled, focus on getting tests case done first --- test/test_grade.py | 113 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 2 deletions(-) diff --git a/test/test_grade.py b/test/test_grade.py index 3d011fc3..7ac0d21e 100644 --- a/test/test_grade.py +++ b/test/test_grade.py @@ -22,8 +22,117 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -from django.test import TestCase +import shutil +from django.test import TestCase, Client +from django.urls import resolve, reverse +from accounts.models import User +from course.models import FlowSession, Course, GradingOpportunity #, Participation + class GradeTest(TestCase): - pass + # @classmethod + # def setUpClass(cls): + # super(GradeTest, cls).setUpClass() + # cls.modify_settings(EMAIL_BACKEND= + # 'django.core.mail.backends.console.EmailBackend') + + @classmethod + def setUpTestData(cls): + # Set up data for the whole TestCase + # Admin account + cls.admin = User.objects.create_superuser( + username="testadmin", + password="test", + email="test@example.com", + first_name="Test", + last_name="Admin") + cls.admin.save() + + # User account + # cls.user1 = User.objects.create_user( + # username="tester1", + # password="test", + # email="tester1@example.com", + # first_name="Test1", + # last_name="Tester") + # cls.user1.save() + # + # cls.user2 = User.objects.create_user( + # username="tester2", + # password="test", + # email="tester2@example.com", + # first_name="Test2", + # last_name="Tester") + # cls.user2.save() + + # Create the course here and check later to + # avoid exceptions raised here + cls.c = Client() + cls.c.login( + username="testadmin", + password="test") + cls.c.post("/new-course/", dict( + identifier="test-course", + name="Test Course", + number="CS123", + time_period="Fall 2016", + hidden=False, + listed=True, + accepts_enrollment=True, + git_source="git://github.com/inducer/relate-sample", + course_file="course.yml", + events_file="events.yml", + enrollment_approval_required=False, + enrollment_required_email_suffix=None, + from_email="inform@tiker.net", + notify_email="inform@tiker.net")) + + # Some classwise sharing data + cls.datas = {"course_identifier": "test-course", "flow_id": "quiz-test"} + cls.datas["flow_session_id"] = [] + + # Make sure admin is logged in after all this + # cls.do_quiz(cls.user1) + # cls.do_quiz(cls.user2) + cls.do_quiz(cls.admin) + + @classmethod + def tearDownClass(cls): + # Remove created folder + shutil.rmtree('../' + cls.datas["course_identifier"]) + super(GradeTest, cls).tearDownClass() + + # Use specified user to take a quiz + @classmethod + def do_quiz(cls, user): + # Login user first + cls.c.logout() + cls.c.login( + username=user.username, + password="test") + + # Enroll if not admin + # Little hacky for not using enrollment view + # if not user.is_superuser: + # participation = Participation() + # participation.user = user + # participation.course = Course.objects.filter(identifier= + # "test-course")[0] + # participation.status = "active" + # participation.save() + + params = cls.datas.copy() + del params["flow_session_id"] + resp = cls.c.post(reverse("relate-view_start_flow", kwargs=params)) + + # Yep, no regax! + _, _, kwargs = resolve(resp.url) + # Store flow_session_id + cls.datas["flow_session_id"].append(kwargs["flow_session_id"]) + + # Let it raise error + # Use pop() will not + del kwargs["ordinal"] + resp = cls.c.post(reverse("relate-finish_flow_session_view", + kwargs=kwargs), {'submit': ['']}) -- GitLab From b2807d6722f41255577a02b83330ec81cc8e0ba8 Mon Sep 17 00:00:00 2001 From: zwang180 Date: Sun, 9 Apr 2017 05:57:29 -0500 Subject: [PATCH 02/21] waste too many time on getting more participations enrolled, focus on getting tests case done first --- test/{test_grade.py => not_test_grade.py} | 106 ++++++++++++++++++++++ 1 file changed, 106 insertions(+) rename test/{test_grade.py => not_test_grade.py} (58%) diff --git a/test/test_grade.py b/test/not_test_grade.py similarity index 58% rename from test/test_grade.py rename to test/not_test_grade.py index 7ac0d21e..2a394c31 100644 --- a/test/test_grade.py +++ b/test/not_test_grade.py @@ -136,3 +136,109 @@ class GradeTest(TestCase): del kwargs["ordinal"] resp = cls.c.post(reverse("relate-finish_flow_session_view", kwargs=kwargs), {'submit': ['']}) + + def test_view_my_grade(self): + resp = self.c.get(reverse("relate-view_participant_grades", + args=self.datas["course_identifier"])) + self.assertEqual(resp.status_code, 200) + + def test_view_participant_grades(self): + params = {"course_identifier": self.datas["course_identifier"], + "participation_id": self.admin.id} + resp = self.c.get(reverse("relate-view_participant_grades", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + def test_view_participant_list(self): + resp = self.c.get(reverse("relate-view_participant_list", + args=self.datas["course_identifier"])) + self.assertEqual(resp.status_code, 200) + + def test_view_grading_opportunity_list(self): + resp = self.c.get(reverse("relate-view_grading_opportunity_list", + args=self.datas["course_identifier"])) + self.assertEqual(resp.status_code, 200) + + def test_view_gradebook(self): + resp = self.c.get(reverse("relate-view_gradebook", + args=self.datas["course_identifier"])) + self.assertEqual(resp.status_code, 200) + + def test_view_export_gradebook_csv(self): + resp = self.c.get(reverse("relate-export_gradebook_csv", + args=self.datas["course_identifier"])) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp["Content-Disposition"], + 'attachment; filename="grades-test-course.csv"') + + def test_view_grades_by_opportunity(self): + print len(GradingOpportunity.objects.all()) + + + + +# url(r"^course" +# "/" + COURSE_ID_REGEX + +# "/grading/by-opportunity" +# "/(?P[0-9]+)" +# "/$", +# course.grades.view_grades_by_opportunity, +# name="relate-view_grades_by_opportunity"), +# url(r"^course" +# "/" + COURSE_ID_REGEX + +# "/grading/single-grade" +# "/(?P[0-9]+)" +# "/(?P[0-9]+)" +# "/$", +# course.grades.view_single_grade, +# name="relate-view_single_grade"), +# url(r"^course" +# "/" + COURSE_ID_REGEX + +# "/grading/reopen-session" +# "/(?P[0-9]+)" +# "/(?P[0-9]+)" +# "/$", +# course.grades.view_reopen_session, +# name="relate-view_reopen_session"), +# +# url(r"^course" +# "/" + COURSE_ID_REGEX + +# "/grading" +# "/csv-import" +# "/$", +# course.grades.import_grades, +# name="relate-import_grades"), +# +# url(r"^course" +# "/" + COURSE_ID_REGEX + +# "/grading" +# "/flow-page" +# "/(?P[0-9]+)" +# "/(?P[0-9]+)" +# "/$", +# course.grading.grade_flow_page, +# name="relate-grade_flow_page"), +# +# url(r"^course" +# "/" + COURSE_ID_REGEX + +# "/grading/statistics" +# "/" + FLOW_ID_REGEX + +# "/$", +# course.grading.show_grader_statistics, +# name="relate-show_grader_statistics"), +# +# url(r"^course" +# "/" + COURSE_ID_REGEX + +# "/grading/download-submissions" +# "/" + FLOW_ID_REGEX + +# "/$", +# course.grades.download_all_submissions, +# name="relate-download_all_submissions"), +# +# url(r"^course" +# "/" + COURSE_ID_REGEX + +# "/edit-grading-opportunity" +# "/(?P[-0-9]+)" +# "/$", +# course.grades.edit_grading_opportunity, +# name="relate-edit_grading_opportunity") -- GitLab From da2f28a9cc4355624c27593b9cd8e89b20fa7ece Mon Sep 17 00:00:00 2001 From: zwang180 Date: Sun, 9 Apr 2017 08:53:16 -0500 Subject: [PATCH 03/21] most of the grade tests ready for review, four more tests coming --- test/not_test_grade.py | 244 ------------------------------ test/test_course.py | 6 +- test/test_grade.py | 335 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 340 insertions(+), 245 deletions(-) delete mode 100644 test/not_test_grade.py create mode 100644 test/test_grade.py diff --git a/test/not_test_grade.py b/test/not_test_grade.py deleted file mode 100644 index 2a394c31..00000000 --- a/test/not_test_grade.py +++ /dev/null @@ -1,244 +0,0 @@ -from __future__ import division - -__copyright__ = "Copyright (C) 2014 Andreas Kloeckner" - -__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 shutil -from django.test import TestCase, Client -from django.urls import resolve, reverse -from accounts.models import User -from course.models import FlowSession, Course, GradingOpportunity #, Participation - - - -class GradeTest(TestCase): - # @classmethod - # def setUpClass(cls): - # super(GradeTest, cls).setUpClass() - # cls.modify_settings(EMAIL_BACKEND= - # 'django.core.mail.backends.console.EmailBackend') - - @classmethod - def setUpTestData(cls): - # Set up data for the whole TestCase - # Admin account - cls.admin = User.objects.create_superuser( - username="testadmin", - password="test", - email="test@example.com", - first_name="Test", - last_name="Admin") - cls.admin.save() - - # User account - # cls.user1 = User.objects.create_user( - # username="tester1", - # password="test", - # email="tester1@example.com", - # first_name="Test1", - # last_name="Tester") - # cls.user1.save() - # - # cls.user2 = User.objects.create_user( - # username="tester2", - # password="test", - # email="tester2@example.com", - # first_name="Test2", - # last_name="Tester") - # cls.user2.save() - - # Create the course here and check later to - # avoid exceptions raised here - cls.c = Client() - cls.c.login( - username="testadmin", - password="test") - cls.c.post("/new-course/", dict( - identifier="test-course", - name="Test Course", - number="CS123", - time_period="Fall 2016", - hidden=False, - listed=True, - accepts_enrollment=True, - git_source="git://github.com/inducer/relate-sample", - course_file="course.yml", - events_file="events.yml", - enrollment_approval_required=False, - enrollment_required_email_suffix=None, - from_email="inform@tiker.net", - notify_email="inform@tiker.net")) - - # Some classwise sharing data - cls.datas = {"course_identifier": "test-course", "flow_id": "quiz-test"} - cls.datas["flow_session_id"] = [] - - # Make sure admin is logged in after all this - # cls.do_quiz(cls.user1) - # cls.do_quiz(cls.user2) - cls.do_quiz(cls.admin) - - @classmethod - def tearDownClass(cls): - # Remove created folder - shutil.rmtree('../' + cls.datas["course_identifier"]) - super(GradeTest, cls).tearDownClass() - - # Use specified user to take a quiz - @classmethod - def do_quiz(cls, user): - # Login user first - cls.c.logout() - cls.c.login( - username=user.username, - password="test") - - # Enroll if not admin - # Little hacky for not using enrollment view - # if not user.is_superuser: - # participation = Participation() - # participation.user = user - # participation.course = Course.objects.filter(identifier= - # "test-course")[0] - # participation.status = "active" - # participation.save() - - params = cls.datas.copy() - del params["flow_session_id"] - resp = cls.c.post(reverse("relate-view_start_flow", kwargs=params)) - - # Yep, no regax! - _, _, kwargs = resolve(resp.url) - # Store flow_session_id - cls.datas["flow_session_id"].append(kwargs["flow_session_id"]) - - # Let it raise error - # Use pop() will not - del kwargs["ordinal"] - resp = cls.c.post(reverse("relate-finish_flow_session_view", - kwargs=kwargs), {'submit': ['']}) - - def test_view_my_grade(self): - resp = self.c.get(reverse("relate-view_participant_grades", - args=self.datas["course_identifier"])) - self.assertEqual(resp.status_code, 200) - - def test_view_participant_grades(self): - params = {"course_identifier": self.datas["course_identifier"], - "participation_id": self.admin.id} - resp = self.c.get(reverse("relate-view_participant_grades", - kwargs=params)) - self.assertEqual(resp.status_code, 200) - - def test_view_participant_list(self): - resp = self.c.get(reverse("relate-view_participant_list", - args=self.datas["course_identifier"])) - self.assertEqual(resp.status_code, 200) - - def test_view_grading_opportunity_list(self): - resp = self.c.get(reverse("relate-view_grading_opportunity_list", - args=self.datas["course_identifier"])) - self.assertEqual(resp.status_code, 200) - - def test_view_gradebook(self): - resp = self.c.get(reverse("relate-view_gradebook", - args=self.datas["course_identifier"])) - self.assertEqual(resp.status_code, 200) - - def test_view_export_gradebook_csv(self): - resp = self.c.get(reverse("relate-export_gradebook_csv", - args=self.datas["course_identifier"])) - self.assertEqual(resp.status_code, 200) - self.assertEqual(resp["Content-Disposition"], - 'attachment; filename="grades-test-course.csv"') - - def test_view_grades_by_opportunity(self): - print len(GradingOpportunity.objects.all()) - - - - -# url(r"^course" -# "/" + COURSE_ID_REGEX + -# "/grading/by-opportunity" -# "/(?P[0-9]+)" -# "/$", -# course.grades.view_grades_by_opportunity, -# name="relate-view_grades_by_opportunity"), -# url(r"^course" -# "/" + COURSE_ID_REGEX + -# "/grading/single-grade" -# "/(?P[0-9]+)" -# "/(?P[0-9]+)" -# "/$", -# course.grades.view_single_grade, -# name="relate-view_single_grade"), -# url(r"^course" -# "/" + COURSE_ID_REGEX + -# "/grading/reopen-session" -# "/(?P[0-9]+)" -# "/(?P[0-9]+)" -# "/$", -# course.grades.view_reopen_session, -# name="relate-view_reopen_session"), -# -# url(r"^course" -# "/" + COURSE_ID_REGEX + -# "/grading" -# "/csv-import" -# "/$", -# course.grades.import_grades, -# name="relate-import_grades"), -# -# url(r"^course" -# "/" + COURSE_ID_REGEX + -# "/grading" -# "/flow-page" -# "/(?P[0-9]+)" -# "/(?P[0-9]+)" -# "/$", -# course.grading.grade_flow_page, -# name="relate-grade_flow_page"), -# -# url(r"^course" -# "/" + COURSE_ID_REGEX + -# "/grading/statistics" -# "/" + FLOW_ID_REGEX + -# "/$", -# course.grading.show_grader_statistics, -# name="relate-show_grader_statistics"), -# -# url(r"^course" -# "/" + COURSE_ID_REGEX + -# "/grading/download-submissions" -# "/" + FLOW_ID_REGEX + -# "/$", -# course.grades.download_all_submissions, -# name="relate-download_all_submissions"), -# -# url(r"^course" -# "/" + COURSE_ID_REGEX + -# "/edit-grading-opportunity" -# "/(?P[-0-9]+)" -# "/$", -# course.grades.edit_grading_opportunity, -# name="relate-edit_grading_opportunity") diff --git a/test/test_course.py b/test/test_course.py index 0fee626c..cc4ee960 100644 --- a/test/test_course.py +++ b/test/test_course.py @@ -26,7 +26,7 @@ import shutil from django.test import TestCase, Client from django.urls import resolve, reverse from accounts.models import User -from course.models import FlowSession, FlowPageVisit +from course.models import FlowSession, FlowPageVisit, Course from decimal import Decimal @@ -70,11 +70,15 @@ class CourseTest(TestCase): super(CourseTest, cls).tearDownClass() def test_user_creation(self): + # Should only have one user + self.assertEqual(len(User.objects.all()), 1) self.assertTrue(self.c.login( username="testadmin", password="test")) def test_course_creation(self): + # Should only have one course + self.assertEqual(len(Course.objects.all()), 1) resp = self.c.get(reverse("relate-course_page", args=["test-course"])) # 200 != 302 is better than False is not True self.assertEqual(resp.status_code, 200) diff --git a/test/test_grade.py b/test/test_grade.py new file mode 100644 index 00000000..5e01c462 --- /dev/null +++ b/test/test_grade.py @@ -0,0 +1,335 @@ +from __future__ import division + +__copyright__ = "Copyright (C) 2014 Andreas Kloeckner" + +__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 shutil +from django.test import TestCase, Client +from django.urls import resolve, reverse +from accounts.models import User +from course.models import FlowSession, Course, GradingOpportunity #, Participation + + + +class GradeTest(TestCase): + # @classmethod + # def setUpClass(cls): + # super(GradeTest, cls).setUpClass() + # cls.modify_settings(EMAIL_BACKEND= + # 'django.core.mail.backends.console.EmailBackend') + + @classmethod + def setUpTestData(cls): + # Set up data for the whole TestCase + # Admin account + cls.admin = User.objects.create_superuser( + username="testadmin", + password="test", + email="test@example.com", + first_name="Test", + last_name="Admin") + cls.admin.save() + + # User account + # cls.user1 = User.objects.create_user( + # username="tester1", + # password="test", + # email="tester1@example.com", + # first_name="Test1", + # last_name="Tester") + # cls.user1.save() + # + # cls.user2 = User.objects.create_user( + # username="tester2", + # password="test", + # email="tester2@example.com", + # first_name="Test2", + # last_name="Tester") + # cls.user2.save() + + # Create the course here and check later to + # avoid exceptions raised here + cls.c = Client() + cls.c.login( + username="testadmin", + password="test") + cls.c.post("/new-course/", dict( + identifier="test-course", + name="Test Course", + number="CS123", + time_period="Fall 2016", + hidden=False, + listed=True, + accepts_enrollment=True, + git_source="git://github.com/inducer/relate-sample", + course_file="course.yml", + events_file="events.yml", + enrollment_approval_required=False, + enrollment_required_email_suffix=None, + from_email="inform@tiker.net", + notify_email="inform@tiker.net")) + + cls.course = Course.objects.all()[0] + # Some classwise sharing data + cls.datas = {"course_identifier": cls.course.identifier, + "flow_id": "quiz-test"} + cls.datas["flow_session_id"] = [] + + # Make sure admin is logged in after all this + # cls.do_quiz(cls.user1) + # cls.do_quiz(cls.user2) + cls.do_quiz(cls.admin) + + @classmethod + def tearDownClass(cls): + # Remove created folder + shutil.rmtree('../' + cls.datas["course_identifier"]) + super(GradeTest, cls).tearDownClass() + + # Use specified user to take a quiz + @classmethod + def do_quiz(cls, user): + # Login user first + cls.c.logout() + cls.c.login( + username=user.username, + password="test") + + # Enroll if not admin + # Little hacky for not using enrollment view + # if not user.is_superuser: + # participation = Participation() + # participation.user = user + # participation.course = Course.objects.filter(identifier= + # "test-course")[0] + # participation.status = "active" + # participation.save() + + params = cls.datas.copy() + del params["flow_session_id"] + resp = cls.c.post(reverse("relate-view_start_flow", kwargs=params)) + + # Yep, no regax! + _, _, kwargs = resolve(resp.url) + # Store flow_session_id + cls.datas["flow_session_id"].append(kwargs["flow_session_id"]) + + # Let it raise error + # Use pop() will not + del kwargs["ordinal"] + resp = cls.c.post(reverse("relate-finish_flow_session_view", + kwargs=kwargs), {'submit': ['']}) + + # Seperate the test here + def test_grading_opportunity(self): + # Should only have one grading opportunity object + self.assertEqual(len(GradingOpportunity.objects.all()), 1) + + def test_view_my_grade(self): + resp = self.c.get(reverse("relate-view_participant_grades", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + + def test_view_participant_grades(self): + params = {"course_identifier": self.datas["course_identifier"], + "participation_id": self.admin.id} + resp = self.c.get(reverse("relate-view_participant_grades", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + def test_view_participant_list(self): + resp = self.c.get(reverse("relate-view_participant_list", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + + def test_view_grading_opportunity_list(self): + resp = self.c.get(reverse("relate-view_grading_opportunity_list", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + + def test_view_gradebook(self): + resp = self.c.get(reverse("relate-view_gradebook", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + + def test_view_export_gradebook_csv(self): + resp = self.c.get(reverse("relate-export_gradebook_csv", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp["Content-Disposition"], + 'attachment; filename="grades-test-course.csv"') + + def test_view_grades_by_opportunity(self): + # Check attributes + opportunity = GradingOpportunity.objects.all()[0] + self.assertEqual(self.course, opportunity.course) + self.assertEqual(self.datas["flow_id"], opportunity.flow_id) + + # Check page + params = {"course_identifier": self.datas["course_identifier"], + "opp_id": opportunity.id} + resp = self.c.get(reverse("relate-view_grades_by_opportunity", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + def test_view_participant_grade_by_opportunity(self): + # Check attributes + opportunity = GradingOpportunity.objects.all()[0] + self.assertEqual(self.course, opportunity.course) + self.assertEqual(self.datas["flow_id"], opportunity.flow_id) + + # Check page + params = {"course_identifier": self.datas["course_identifier"], + "opportunity_id": opportunity.id, + "participation_id": self.admin.id} + resp = self.c.get(reverse("relate-view_single_grade", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + def test_view_reopen_session(self): + # Check attributes + opportunity = GradingOpportunity.objects.all()[0] + self.assertEqual(self.course, opportunity.course) + self.assertEqual(self.datas["flow_id"], opportunity.flow_id) + + # Check flow, should have only one + self.assertEqual(len(FlowSession.objects.all()), 1) + + # Finished flow session + flow_session = FlowSession.objects.all()[0] + self.assertEqual(flow_session.in_progress, False) + + # Check reopen session form + params = {"course_identifier": self.datas["course_identifier"], + "opportunity_id": opportunity.id, + "flow_session_id": self.datas["flow_session_id"][0]} + resp = self.c.get(reverse("relate-view_reopen_session", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + # Reopen session + datas = {'set_access_rules_tag': ['<<>>'], 'comment': ['test-reopen'], + 'unsubmit_pages': ['on'], 'reopen': ['Reopen']} + resp = self.c.post(reverse("relate-view_reopen_session", + kwargs=params), datas) + + # Should still have one + self.assertEqual(len(FlowSession.objects.all()), 1) + flow_session = FlowSession.objects.all()[0] + self.assertEqual(flow_session.in_progress, True) + + # Only test if import form is working for now + # Maybe try export then import? + def test_view_import_grades(self): + resp = self.c.get(reverse("relate-import_grades", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + + # Seems just show the answer + def test_view_grade_flow_page(self): + params = {"course_identifier": self.datas["course_identifier"], + "flow_session_id": self.datas["flow_session_id"][0]} + for i in xrange(18): + params["page_ordinal"] = str(i) + resp = self.c.get(reverse("relate-grade_flow_page", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + # flow_session_id and flow_id + # Consistency plz :( + # Should be flow_session_id? + def test_view_grader_statistics(self): + params = {"course_identifier": self.datas["course_identifier"], + "flow_id": self.datas["flow_session_id"][0]} + resp = self.c.get(reverse("relate-show_grader_statistics", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + def test_view_download_submissions(self): + params = {"course_identifier": self.datas["course_identifier"], + "flow_id": self.datas["flow_id"]} + + # Check download form first + resp = self.c.get(reverse("relate-download_all_submissions", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + # Check download here, only test intro page + # Maybe we should include an "all" option in the future? + datas = {'restrict_to_rules_tag': ['<<>>'], 'which_attempt': ['last'], + 'extra_file': [''], 'download': ['Download'], + 'page_id': ['intro/welcome'], 'non_in_progress_only': ['on']} + resp = self.c.post(reverse("relate-download_all_submissions", + kwargs=params), datas) + self.assertEqual(resp.status_code, 200) + prefix, zip_file = resp["Content-Disposition"].split('=') + self.assertEqual(prefix, "attachment; filename") + zip_file_name = zip_file.replace('"', '').split('_') + self.assertEqual(zip_file_name[0], "submissions") + self.assertEqual(zip_file_name[1], self.datas["course_identifier"]) + self.assertEqual(zip_file_name[2], self.datas["flow_id"]) + self.assertEqual(zip_file_name[3], "intro") + self.assertEqual(zip_file_name[4], "welcome") + self.assertTrue(zip_file_name[5].endswith(".zip")) + + def test_view_edit_grading_opportunity(self): + # Check attributes + opportunity = GradingOpportunity.objects.all()[0] + self.assertEqual(self.course, opportunity.course) + self.assertEqual(self.datas["flow_id"], opportunity.flow_id) + + params = {"course_identifier": self.datas["course_identifier"], + "opportunity_id": opportunity.id} + # Check page + resp = self.c.get(reverse("relate-edit_grading_opportunity", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + # Try making a change + self.assertEqual(opportunity.page_scores_in_participant_gradebook, False) + datas = {'page_scores_in_participant_gradebook': ['on'], + 'name': ['Flow: RELATE Test Quiz'], + 'hide_superseded_grade_history_before': [''], + 'submit': ['Update'], + 'shown_in_participant_grade_book': ['on'], + 'aggregation_strategy': ['use_latest'], + 'shown_in_grade_book': ['on'], + 'result_shown_in_participant_grade_book': ['on']} + resp = self.c.post(reverse("relate-edit_grading_opportunity", + kwargs=params), datas) + self.assertEqual(resp.status_code, 302) + self.assertEqual(resp.url, reverse("relate-edit_grading_opportunity", + kwargs=params)) + + # Check objects and attributes + # Should still be one + self.assertEqual(len(GradingOpportunity.objects.all()), 1) + opportunity = GradingOpportunity.objects.all()[0] + self.assertEqual(self.course, opportunity.course) + self.assertEqual(self.datas["flow_id"], opportunity.flow_id) + # Check changes + self.assertEqual(opportunity.page_scores_in_participant_gradebook, True) + +# @TODO remain tests +# http://localhost:8000/course/course-test/flow-analytics/quiz-test/ +# http://localhost:8000/course/course-test/regrade-flows/ +# http://localhost:8000/course/course-test/grant-exception/ +# http://localhost:8000/course/course-test/batch-issue-exam-tickets/ -- GitLab From 753b28d6e52d4d730f8305308fa8e5dca8104e2e Mon Sep 17 00:00:00 2001 From: zwang180 Date: Sun, 9 Apr 2017 09:05:14 -0500 Subject: [PATCH 04/21] pipeline errors --- test/test_grade.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/test_grade.py b/test/test_grade.py index 5e01c462..2974f16a 100644 --- a/test/test_grade.py +++ b/test/test_grade.py @@ -26,8 +26,7 @@ import shutil from django.test import TestCase, Client from django.urls import resolve, reverse from accounts.models import User -from course.models import FlowSession, Course, GradingOpportunity #, Participation - +from course.models import FlowSession, Course, GradingOpportunity # , Participation class GradeTest(TestCase): @@ -248,7 +247,7 @@ class GradeTest(TestCase): def test_view_grade_flow_page(self): params = {"course_identifier": self.datas["course_identifier"], "flow_session_id": self.datas["flow_session_id"][0]} - for i in xrange(18): + for i in range(18): params["page_ordinal"] = str(i) resp = self.c.get(reverse("relate-grade_flow_page", kwargs=params)) -- GitLab From 45084ac9a3a882251aae6baeb0c4cc6f09d70f9f Mon Sep 17 00:00:00 2001 From: zwang180 Date: Mon, 10 Apr 2017 04:22:05 -0500 Subject: [PATCH 05/21] all test cases ready to view --- test/test_grade.py | 138 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 8 deletions(-) diff --git a/test/test_grade.py b/test/test_grade.py index 2974f16a..45c7ac64 100644 --- a/test/test_grade.py +++ b/test/test_grade.py @@ -26,7 +26,8 @@ import shutil from django.test import TestCase, Client from django.urls import resolve, reverse from accounts.models import User -from course.models import FlowSession, Course, GradingOpportunity # , Participation +from course.models import FlowSession, Course, GradingOpportunity, \ + Participation, FlowRuleException class GradeTest(TestCase): @@ -37,7 +38,7 @@ class GradeTest(TestCase): # 'django.core.mail.backends.console.EmailBackend') @classmethod - def setUpTestData(cls): + def setUpTestData(cls): # noqa # Set up data for the whole TestCase # Admin account cls.admin = User.objects.create_superuser( @@ -130,7 +131,7 @@ class GradeTest(TestCase): # Yep, no regax! _, _, kwargs = resolve(resp.url) # Store flow_session_id - cls.datas["flow_session_id"].append(kwargs["flow_session_id"]) + cls.datas["flow_session_id"].append(int(kwargs["flow_session_id"])) # Let it raise error # Use pop() will not @@ -327,8 +328,129 @@ class GradeTest(TestCase): # Check changes self.assertEqual(opportunity.page_scores_in_participant_gradebook, True) -# @TODO remain tests -# http://localhost:8000/course/course-test/flow-analytics/quiz-test/ -# http://localhost:8000/course/course-test/regrade-flows/ -# http://localhost:8000/course/course-test/grant-exception/ -# http://localhost:8000/course/course-test/batch-issue-exam-tickets/ + def test_view_flow_list_analytics(self): + resp = self.c.get(reverse("relate-flow_list", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + + def test_view_flow_analytics(self): + params = {"course_identifier": self.datas["course_identifier"], + "flow_id": self.datas["flow_id"]} + resp = self.c.get(reverse("relate-flow_analytics", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + # Only check page for now + def test_view_regrade_flow(self): + resp = self.c.get(reverse("relate-regrade_flows_view", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + + def test_view_grant_exception_new_session(self): + # Perform all checking before moving to stage three + params = self.check_stage_one_and_two() + + # Should have only one flow session now + self.assertEqual(len(FlowSession.objects.all()), 1) + self.assertEqual(FlowSession.objects.all()[0].id, + self.datas["flow_session_id"][0]) + + # Grant a new one + datas = {'access_rules_tag_for_new_session': ['<<>>'], + 'create_session': ['Create session']} + resp = self.c.post(reverse("relate-grant_exception_stage_2", + kwargs=params), datas) + self.assertEqual(resp.status_code, 200) + + # Should have two flow sessions now + self.assertEqual(len(FlowSession.objects.all()), 2) + + + def test_view_grant_exception_exist_session(self): + # Perform all checking before moving to stage three + params = self.check_stage_one_and_two() + + # Should have only one flow session now + self.assertEqual(len(FlowSession.objects.all()), 1) + flow_session = FlowSession.objects.all()[0] + self.assertEqual(flow_session.id, + self.datas["flow_session_id"][0]) + + # Grant an existing one + datas = {'session': [str(flow_session.id)], 'next': ['Next \xbb']} + resp = self.c.post(reverse("relate-grant_exception_stage_2", + kwargs=params), datas) + self.assertEqual(resp.status_code, 302) + + # Prepare parameters + params["session_id"] = datas["session"][0] + # Check redirect + self.assertEqual(resp.url, reverse("relate-grant_exception_stage_3", + kwargs=params)) + + # Check stage three page + resp = self.c.get(reverse("relate-grant_exception_stage_3", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + # Should have no exception rule now + self.assertEqual(len(FlowRuleException.objects.all()), 0) + + # Create a new exception rule + datas = {'comment': ['test-rule'], 'save': ['Save'], 'view': ['on'], + 'see_answer_after_submission': ['on'], + 'create_grading_exception': ['on'], + 'create_access_exception': ['on'], + 'access_expires': [''], 'due': [''], + 'bonus_points': ['0.0'], 'max_points': [''], + 'credit_percent': ['100.0'], 'max_points_enforced_cap': [''], + 'generates_grade': ['on'], 'see_correctness': ['on']} + resp = self.c.post(reverse("relate-grant_exception_stage_3", + kwargs=params), datas) + self.assertEqual(resp.status_code, 302) + + # Check redirect + self.assertEqual(resp.url, reverse("relate-grant_exception", + args=[self.datas["course_identifier"]])) + + # Should have two exception rules now + # One for access and one for grading + self.assertEqual(len(FlowRuleException.objects.all()), 2) + + + # Helper method for testing grant exception view + def check_stage_one_and_two(self): + # Check stage one page + resp = self.c.get(reverse("relate-grant_exception", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + + # Move to stage two + # Shoud be only one participation record + self.assertEqual(len(Participation.objects.all()), 1) + participation = Participation.objects.all()[0] + + datas = {"next": ["Next \xbb"], "participation": [str(participation.id)], + "flow_id": [self.datas["flow_id"]]} + resp = self.c.post(reverse("relate-grant_exception", + args=[self.datas["course_identifier"]]), datas) + self.assertEqual(resp.status_code, 302) + + # Prepare parameters + params = datas.copy() + params["participation_id"] = params["participation"][0] + params["course_identifier"] = self.datas["course_identifier"] + params["flow_id"] = params["flow_id"][0] + del params["next"] + del params["participation"] + # Check redirect + self.assertEqual(resp.url, reverse("relate-grant_exception_stage_2", + kwargs=params)) + + # Check stage two page + resp = self.c.get(reverse("relate-grant_exception_stage_2", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + # Return params to reuse + return params -- GitLab From 758fae7d709ddfc8319c14724ee0dbe6d3779efa Mon Sep 17 00:00:00 2001 From: zwang180 Date: Mon, 10 Apr 2017 04:24:34 -0500 Subject: [PATCH 06/21] remove extra lines between functions --- test/test_grade.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test_grade.py b/test/test_grade.py index 45c7ac64..220201ca 100644 --- a/test/test_grade.py +++ b/test/test_grade.py @@ -365,7 +365,6 @@ class GradeTest(TestCase): # Should have two flow sessions now self.assertEqual(len(FlowSession.objects.all()), 2) - def test_view_grant_exception_exist_session(self): # Perform all checking before moving to stage three params = self.check_stage_one_and_two() @@ -417,7 +416,6 @@ class GradeTest(TestCase): # One for access and one for grading self.assertEqual(len(FlowRuleException.objects.all()), 2) - # Helper method for testing grant exception view def check_stage_one_and_two(self): # Check stage one page -- GitLab From d20aacfa0ac97b137e4b71033cdc6d86808618a6 Mon Sep 17 00:00:00 2001 From: zwang180 Date: Thu, 13 Apr 2017 00:53:29 -0500 Subject: [PATCH 07/21] correctly use flow_id and flow_session_id --- test/test_grade.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/test_grade.py b/test/test_grade.py index 220201ca..a8c8e56d 100644 --- a/test/test_grade.py +++ b/test/test_grade.py @@ -254,12 +254,9 @@ class GradeTest(TestCase): kwargs=params)) self.assertEqual(resp.status_code, 200) - # flow_session_id and flow_id - # Consistency plz :( - # Should be flow_session_id? def test_view_grader_statistics(self): params = {"course_identifier": self.datas["course_identifier"], - "flow_id": self.datas["flow_session_id"][0]} + "flow_id": self.datas["flow_id"]} resp = self.c.get(reverse("relate-show_grader_statistics", kwargs=params)) self.assertEqual(resp.status_code, 200) -- GitLab From 694071384ec807cf15bb931f3b49aa16790d6f35 Mon Sep 17 00:00:00 2001 From: zwang180 Date: Tue, 18 Apr 2017 16:01:41 -0500 Subject: [PATCH 08/21] hack through participation system, need to fix test cases on next step --- test/{test_grade.py => base_grade_tests.py} | 71 +++++++++------------ test/{test_course.py => not_test_course.py} | 0 test/test_grade_instructor.py | 39 +++++++++++ test/test_grade_ta.py | 41 ++++++++++++ 4 files changed, 109 insertions(+), 42 deletions(-) rename test/{test_grade.py => base_grade_tests.py} (91%) rename test/{test_course.py => not_test_course.py} (100%) create mode 100644 test/test_grade_instructor.py create mode 100644 test/test_grade_ta.py diff --git a/test/test_grade.py b/test/base_grade_tests.py similarity index 91% rename from test/test_grade.py rename to test/base_grade_tests.py index a8c8e56d..c8c98e2b 100644 --- a/test/test_grade.py +++ b/test/base_grade_tests.py @@ -22,20 +22,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -import shutil -from django.test import TestCase, Client +from django.test import Client from django.urls import resolve, reverse from accounts.models import User from course.models import FlowSession, Course, GradingOpportunity, \ - Participation, FlowRuleException + Participation, FlowRuleException, ParticipationRole -class GradeTest(TestCase): - # @classmethod - # def setUpClass(cls): - # super(GradeTest, cls).setUpClass() - # cls.modify_settings(EMAIL_BACKEND= - # 'django.core.mail.backends.console.EmailBackend') +# Nice little tricks :) +class BaseGradeTest(object): @classmethod def setUpTestData(cls): # noqa @@ -50,21 +45,13 @@ class GradeTest(TestCase): cls.admin.save() # User account - # cls.user1 = User.objects.create_user( - # username="tester1", - # password="test", - # email="tester1@example.com", - # first_name="Test1", - # last_name="Tester") - # cls.user1.save() - # - # cls.user2 = User.objects.create_user( - # username="tester2", - # password="test", - # email="tester2@example.com", - # first_name="Test2", - # last_name="Tester") - # cls.user2.save() + cls.student = User.objects.create_user( + username="tester1", + password="test", + email="tester1@example.com", + first_name="Student", + last_name="Tester") + cls.student.save() # Create the course here and check later to # avoid exceptions raised here @@ -94,20 +81,13 @@ class GradeTest(TestCase): "flow_id": "quiz-test"} cls.datas["flow_session_id"] = [] - # Make sure admin is logged in after all this - # cls.do_quiz(cls.user1) - # cls.do_quiz(cls.user2) - cls.do_quiz(cls.admin) - - @classmethod - def tearDownClass(cls): - # Remove created folder - shutil.rmtree('../' + cls.datas["course_identifier"]) - super(GradeTest, cls).tearDownClass() + # Make sure admin is logged in after all this in all sub classes + # Student takes quiz anyway + cls.do_quiz(cls.student, "student") # Use specified user to take a quiz @classmethod - def do_quiz(cls, user): + def do_quiz(cls, user, assign_role=None): # Login user first cls.c.logout() cls.c.login( @@ -116,13 +96,20 @@ class GradeTest(TestCase): # Enroll if not admin # Little hacky for not using enrollment view - # if not user.is_superuser: - # participation = Participation() - # participation.user = user - # participation.course = Course.objects.filter(identifier= - # "test-course")[0] - # participation.status = "active" - # participation.save() + if assign_role: + participation = Participation() + participation.user = user + participation.course = Course.objects.filter(identifier= + cls.datas["course_identifier"])[0] + participation.status = "active" + participation.save() + + if assign_role == "student": + role = ParticipationRole.objects.filter(id=3)[0] + elif assign_role == "ta": + role = ParticipationRole.objects.filter(id=2)[0] + participation.roles.add(role) + params = cls.datas.copy() del params["flow_session_id"] diff --git a/test/test_course.py b/test/not_test_course.py similarity index 100% rename from test/test_course.py rename to test/not_test_course.py diff --git a/test/test_grade_instructor.py b/test/test_grade_instructor.py new file mode 100644 index 00000000..3c2a0708 --- /dev/null +++ b/test/test_grade_instructor.py @@ -0,0 +1,39 @@ +from __future__ import division + +__copyright__ = "Copyright (C) 2014 Andreas Kloeckner" + +__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 shutil +from base_grade_tests import BaseGradeTest +from django.test import TestCase + +class InstructorGradeTest(BaseGradeTest, TestCase): + @classmethod + def setUpTestData(cls): # noqa + super(InstructorGradeTest, cls).setUpTestData() + cls.do_quiz(cls.admin) + + @classmethod + def tearDownClass(cls): + # Remove created folder + shutil.rmtree('../' + cls.datas["course_identifier"]) + super(InstructorGradeTest, cls).tearDownClass() diff --git a/test/test_grade_ta.py b/test/test_grade_ta.py new file mode 100644 index 00000000..8d5548c5 --- /dev/null +++ b/test/test_grade_ta.py @@ -0,0 +1,41 @@ +from __future__ import division + +__copyright__ = "Copyright (C) 2014 Andreas Kloeckner" + +__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 shutil +from base_grade_tests import BaseGradeTest +from django.test import TestCase + + +class TAGradeTest(BaseGradeTest, TestCase): + @classmethod + def setUpTestData(cls): # noqa + super(TAGradeTest, cls).setUpTestData() + # cls.do_quiz(cls.ta, "ta") + cls.do_quiz(cls.admin) + + @classmethod + def tearDownClass(cls): + # Remove created folder + shutil.rmtree('../' + cls.datas["course_identifier"]) + super(TAGradeTest, cls).tearDownClass() -- GitLab From f0fa67ece05cbe39863de9da95ed17f129312fc3 Mon Sep 17 00:00:00 2001 From: zwang180 Date: Tue, 18 Apr 2017 17:17:44 -0500 Subject: [PATCH 09/21] get some things work for now, at least --- test/base_grade_tests.py | 114 ++++++++++++++++++++-------------- test/test_grade_instructor.py | 1 + test/test_grade_ta.py | 13 +++- 3 files changed, 79 insertions(+), 49 deletions(-) diff --git a/test/base_grade_tests.py b/test/base_grade_tests.py index c8c98e2b..22b6376b 100644 --- a/test/base_grade_tests.py +++ b/test/base_grade_tests.py @@ -29,6 +29,7 @@ from course.models import FlowSession, Course, GradingOpportunity, \ Participation, FlowRuleException, ParticipationRole +# This serve as a base test cases for other grade tests to subclass # Nice little tricks :) class BaseGradeTest(object): @@ -44,7 +45,7 @@ class BaseGradeTest(object): last_name="Admin") cls.admin.save() - # User account + # Student account cls.student = User.objects.create_user( username="tester1", password="test", @@ -103,7 +104,7 @@ class BaseGradeTest(object): cls.datas["course_identifier"])[0] participation.status = "active" participation.save() - + if assign_role == "student": role = ParticipationRole.objects.filter(id=3)[0] elif assign_role == "ta": @@ -198,31 +199,16 @@ class BaseGradeTest(object): self.assertEqual(self.course, opportunity.course) self.assertEqual(self.datas["flow_id"], opportunity.flow_id) - # Check flow, should have only one - self.assertEqual(len(FlowSession.objects.all()), 1) - - # Finished flow session - flow_session = FlowSession.objects.all()[0] - self.assertEqual(flow_session.in_progress, False) - - # Check reopen session form - params = {"course_identifier": self.datas["course_identifier"], - "opportunity_id": opportunity.id, - "flow_session_id": self.datas["flow_session_id"][0]} - resp = self.c.get(reverse("relate-view_reopen_session", - kwargs=params)) - self.assertEqual(resp.status_code, 200) + # Check flow numbers + self.assertEqual(len(FlowSession.objects.all()), + len(self.datas["flow_session_id"])) - # Reopen session - datas = {'set_access_rules_tag': ['<<>>'], 'comment': ['test-reopen'], - 'unsubmit_pages': ['on'], 'reopen': ['Reopen']} - resp = self.c.post(reverse("relate-view_reopen_session", - kwargs=params), datas) + # Check each flow session + for session in FlowSession.objects.all(): + self.check_reopen_session(session.id, opportunity.id) - # Should still have one + # Check flow numbers again self.assertEqual(len(FlowSession.objects.all()), 1) - flow_session = FlowSession.objects.all()[0] - self.assertEqual(flow_session.in_progress, True) # Only test if import form is working for now # Maybe try export then import? @@ -331,14 +317,36 @@ class BaseGradeTest(object): self.assertEqual(resp.status_code, 200) def test_view_grant_exception_new_session(self): - # Perform all checking before moving to stage three - params = self.check_stage_one_and_two() + # Check number of flow sessions and ids + self.assertEqual(len(FlowSession.objects.all()), + len(self.datas["flow_session_id"])) + for session in FlowSession.objects.all(): + # Perform all checking before moving to stage three + params = self.check_stage_one_and_two(session.participation) + self.assertTrue(session.id in self.datas["flow_session_id"]) + self.check_grant_new_exception(params) - # Should have only one flow session now - self.assertEqual(len(FlowSession.objects.all()), 1) - self.assertEqual(FlowSession.objects.all()[0].id, - self.datas["flow_session_id"][0]) + # Should have two flow sessions now + self.assertEqual(len(FlowSession.objects.all()), 2 * self.datas["accounts"]) + + def test_view_grant_exception_exist_session(self): + # Store numbers to reuse + session_nums = len(self.datas["flow_session_id"]) + # Check session numbers + self.assertEqual(len(FlowSession.objects.all()), session_nums) + + # Check for each existing session + for session in FlowSession.objects.all(): + # Perform all checking before moving to stage three + params = self.check_stage_one_and_two(session.participation) + self.check_grant_exist_exception(session.id, params) + + # Should have two exception rules now + # One for access and one for grading + self.assertEqual(len(FlowRuleException.objects.all()), session_nums + 1) + # Helper method for testing grant exceptions for new session + def check_grant_new_exception(self, params): # Grant a new one datas = {'access_rules_tag_for_new_session': ['<<>>'], 'create_session': ['Create session']} @@ -346,18 +354,11 @@ class BaseGradeTest(object): kwargs=params), datas) self.assertEqual(resp.status_code, 200) - # Should have two flow sessions now - self.assertEqual(len(FlowSession.objects.all()), 2) - - def test_view_grant_exception_exist_session(self): - # Perform all checking before moving to stage three - params = self.check_stage_one_and_two() - - # Should have only one flow session now - self.assertEqual(len(FlowSession.objects.all()), 1) - flow_session = FlowSession.objects.all()[0] - self.assertEqual(flow_session.id, - self.datas["flow_session_id"][0]) + # Helper method for testing grant exceptions for existing one + def check_grant_exist_exception(self, session_id, parameters): + params = parameters.copy() + flow_session = FlowSession.objects.filter(id=session_id)[0] + self.assertTrue(flow_session.id in self.datas["flow_session_id"]) # Grant an existing one datas = {'session': [str(flow_session.id)], 'next': ['Next \xbb']} @@ -396,12 +397,30 @@ class BaseGradeTest(object): self.assertEqual(resp.url, reverse("relate-grant_exception", args=[self.datas["course_identifier"]])) - # Should have two exception rules now - # One for access and one for grading - self.assertEqual(len(FlowRuleException.objects.all()), 2) + # Helper method for testing reopen session + def check_reopen_session(self, session_id, opportunity_id): + flow_session = FlowSession.objects.filter(id=session_id)[0] + self.assertEqual(flow_session.in_progress, False) + + # Check reopen session form + params = {"course_identifier": self.datas["course_identifier"], + "opportunity_id": opportunity_id, + "flow_session_id": session_id} + resp = self.c.get(reverse("relate-view_reopen_session", + kwargs=params)) + self.assertEqual(resp.status_code, 200) + + # Reopen session + datas = {'set_access_rules_tag': ['<<>>'], 'comment': ['test-reopen'], + 'unsubmit_pages': ['on'], 'reopen': ['Reopen']} + resp = self.c.post(reverse("relate-view_reopen_session", + kwargs=params), datas) + + flow_session = FlowSession.objects.filter(id=session_id)[0] + self.assertEqual(flow_session.in_progress, True) # Helper method for testing grant exception view - def check_stage_one_and_two(self): + def check_stage_one_and_two(self, participation): # Check stage one page resp = self.c.get(reverse("relate-grant_exception", args=[self.datas["course_identifier"]])) @@ -409,8 +428,7 @@ class BaseGradeTest(object): # Move to stage two # Shoud be only one participation record - self.assertEqual(len(Participation.objects.all()), 1) - participation = Participation.objects.all()[0] + self.assertEqual(len(Participation.objects.all()), self.datas["accounts"]) datas = {"next": ["Next \xbb"], "participation": [str(participation.id)], "flow_id": [self.datas["flow_id"]]} diff --git a/test/test_grade_instructor.py b/test/test_grade_instructor.py index 3c2a0708..018f5af7 100644 --- a/test/test_grade_instructor.py +++ b/test/test_grade_instructor.py @@ -31,6 +31,7 @@ class InstructorGradeTest(BaseGradeTest, TestCase): def setUpTestData(cls): # noqa super(InstructorGradeTest, cls).setUpTestData() cls.do_quiz(cls.admin) + cls.datas["accounts"] = 2 @classmethod def tearDownClass(cls): diff --git a/test/test_grade_ta.py b/test/test_grade_ta.py index 8d5548c5..4d18a568 100644 --- a/test/test_grade_ta.py +++ b/test/test_grade_ta.py @@ -25,14 +25,25 @@ THE SOFTWARE. import shutil from base_grade_tests import BaseGradeTest from django.test import TestCase +from accounts.models import User class TAGradeTest(BaseGradeTest, TestCase): @classmethod def setUpTestData(cls): # noqa super(TAGradeTest, cls).setUpTestData() - # cls.do_quiz(cls.ta, "ta") + # TA account + cls.ta = User.objects.create_user( + username="ta1", + password="test", + email="ta1@example.com", + first_name="TA", + last_name="Tester") + cls.ta.save() + + cls.do_quiz(cls.ta, "ta") cls.do_quiz(cls.admin) + cls.datas["accounts"] = 3 @classmethod def tearDownClass(cls): -- GitLab From 9a2d9cd8dfd9cf38fc64d97abbdb878daaa75e6c Mon Sep 17 00:00:00 2001 From: zwang180 Date: Tue, 18 Apr 2017 17:30:07 -0500 Subject: [PATCH 10/21] get test cases for both instructor and ta working, start working on csv import --- test/base_grade_tests.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/base_grade_tests.py b/test/base_grade_tests.py index 22b6376b..c99c959a 100644 --- a/test/base_grade_tests.py +++ b/test/base_grade_tests.py @@ -208,7 +208,8 @@ class BaseGradeTest(object): self.check_reopen_session(session.id, opportunity.id) # Check flow numbers again - self.assertEqual(len(FlowSession.objects.all()), 1) + self.assertEqual(len(FlowSession.objects.all()), + len(self.datas["flow_session_id"])) # Only test if import form is working for now # Maybe try export then import? @@ -343,7 +344,7 @@ class BaseGradeTest(object): # Should have two exception rules now # One for access and one for grading - self.assertEqual(len(FlowRuleException.objects.all()), session_nums + 1) + self.assertEqual(len(FlowRuleException.objects.all()), 2 * session_nums) # Helper method for testing grant exceptions for new session def check_grant_new_exception(self, params): @@ -377,9 +378,6 @@ class BaseGradeTest(object): kwargs=params)) self.assertEqual(resp.status_code, 200) - # Should have no exception rule now - self.assertEqual(len(FlowRuleException.objects.all()), 0) - # Create a new exception rule datas = {'comment': ['test-rule'], 'save': ['Save'], 'view': ['on'], 'see_answer_after_submission': ['on'], -- GitLab From 2281f0c6e764d9a622ed348ce7222354e85682e4 Mon Sep 17 00:00:00 2001 From: zwang180 Date: Thu, 20 Apr 2017 20:34:50 -0500 Subject: [PATCH 11/21] done with all grade tests --- test/base_grade_tests.py | 93 +++++++++++++++++---- test/{not_test_course.py => test_course.py} | 0 2 files changed, 79 insertions(+), 14 deletions(-) rename test/{not_test_course.py => test_course.py} (100%) diff --git a/test/base_grade_tests.py b/test/base_grade_tests.py index c99c959a..ccf19f12 100644 --- a/test/base_grade_tests.py +++ b/test/base_grade_tests.py @@ -22,11 +22,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ +import cStringIO +import csv from django.test import Client from django.urls import resolve, reverse from accounts.models import User from course.models import FlowSession, Course, GradingOpportunity, \ - Participation, FlowRuleException, ParticipationRole + Participation, FlowRuleException, ParticipationRole, \ + GradeChange # This serve as a base test cases for other grade tests to subclass @@ -40,7 +43,7 @@ class BaseGradeTest(object): cls.admin = User.objects.create_superuser( username="testadmin", password="test", - email="test@example.com", + email="testadmin@example.com", first_name="Test", last_name="Admin") cls.admin.save() @@ -168,6 +171,7 @@ class BaseGradeTest(object): def test_view_grades_by_opportunity(self): # Check attributes + self.assertEqual(len(GradingOpportunity.objects.all()), 1) opportunity = GradingOpportunity.objects.all()[0] self.assertEqual(self.course, opportunity.course) self.assertEqual(self.datas["flow_id"], opportunity.flow_id) @@ -181,6 +185,7 @@ class BaseGradeTest(object): def test_view_participant_grade_by_opportunity(self): # Check attributes + self.assertEqual(len(GradingOpportunity.objects.all()), 1) opportunity = GradingOpportunity.objects.all()[0] self.assertEqual(self.course, opportunity.course) self.assertEqual(self.datas["flow_id"], opportunity.flow_id) @@ -195,28 +200,34 @@ class BaseGradeTest(object): def test_view_reopen_session(self): # Check attributes + self.assertEqual(len(GradingOpportunity.objects.all()), 1) opportunity = GradingOpportunity.objects.all()[0] self.assertEqual(self.course, opportunity.course) self.assertEqual(self.datas["flow_id"], opportunity.flow_id) + all_session = FlowSession.objects.all() # Check flow numbers - self.assertEqual(len(FlowSession.objects.all()), + self.assertEqual(len(all_session), len(self.datas["flow_session_id"])) # Check each flow session - for session in FlowSession.objects.all(): + for session in all_session: self.check_reopen_session(session.id, opportunity.id) # Check flow numbers again self.assertEqual(len(FlowSession.objects.all()), len(self.datas["flow_session_id"])) - # Only test if import form is working for now - # Maybe try export then import? - def test_view_import_grades(self): - resp = self.c.get(reverse("relate-import_grades", - args=[self.datas["course_identifier"]])) - self.assertEqual(resp.status_code, 200) + def test_view_import_grades_without_header(self): + csv_datas = [("testadmin", 99, "Almost!"), + ("tester1", 50, "I hate this course :(")] + self.check_import_grade(csv_datas) + + def test_view_import_grades_with_header(self): + csv_datas = [("username", "grade", "feedback"), + ("testadmin", 99, "Almost!"), + ("tester1", 50, "I hate this course :(")] + self.check_import_grade(csv_datas, True) # Seems just show the answer def test_view_grade_flow_page(self): @@ -264,6 +275,7 @@ class BaseGradeTest(object): def test_view_edit_grading_opportunity(self): # Check attributes + self.assertEqual(len(GradingOpportunity.objects.all()), 1) opportunity = GradingOpportunity.objects.all()[0] self.assertEqual(self.course, opportunity.course) self.assertEqual(self.datas["flow_id"], opportunity.flow_id) @@ -318,10 +330,11 @@ class BaseGradeTest(object): self.assertEqual(resp.status_code, 200) def test_view_grant_exception_new_session(self): + all_session = FlowSession.objects.all() # Check number of flow sessions and ids - self.assertEqual(len(FlowSession.objects.all()), + self.assertEqual(len(all_session), len(self.datas["flow_session_id"])) - for session in FlowSession.objects.all(): + for session in all_session: # Perform all checking before moving to stage three params = self.check_stage_one_and_two(session.participation) self.assertTrue(session.id in self.datas["flow_session_id"]) @@ -333,11 +346,13 @@ class BaseGradeTest(object): def test_view_grant_exception_exist_session(self): # Store numbers to reuse session_nums = len(self.datas["flow_session_id"]) + + all_session = FlowSession.objects.all() # Check session numbers - self.assertEqual(len(FlowSession.objects.all()), session_nums) + self.assertEqual(len(all_session), session_nums) # Check for each existing session - for session in FlowSession.objects.all(): + for session in all_session: # Perform all checking before moving to stage three params = self.check_stage_one_and_two(session.participation) self.check_grant_exist_exception(session.id, params) @@ -346,6 +361,56 @@ class BaseGradeTest(object): # One for access and one for grading self.assertEqual(len(FlowRuleException.objects.all()), 2 * session_nums) + # Helper method for creating in memory csv files to test import grades + def creat_grading_csv(self, datas): + csvfile = cStringIO.StringIO() + csvwriter = csv.writer(csvfile) + for data in datas: + # (username, grades, feedback) + csvwriter.writerow([data[0], data[1], data[2]]) + # Reset back to the start of file to avoid invalid form error + # Otherwise it will consider the file as empty + csvfile.seek(0) + return csvfile + + # Helper method for testing import grades + def check_import_grade(self, csv_datas, headers=False): + # Check import form works well + resp = self.c.get(reverse("relate-import_grades", + args=[self.datas["course_identifier"]])) + self.assertEqual(resp.status_code, 200) + + # Check number of GradeChange + self.assertEqual(len(GradeChange.objects.all()), self.datas["accounts"]) + + # Check attributes + self.assertEqual(len(GradingOpportunity.objects.all()), 1) + opportunity = GradingOpportunity.objects.all()[0] + self.assertEqual(self.course, opportunity.course) + self.assertEqual(self.datas["flow_id"], opportunity.flow_id) + + # Prepare datas + # Prepare csv + csv_file = self.creat_grading_csv(csv_datas) + # Prepare form datas + datas = {'points_column': ['2'], 'attr_column': ['1'], + 'feedback_column': ['3'], + 'grading_opportunity': [str(opportunity.id)], + 'format': ['csv' + ('head' if headers else '')], + 'attempt_id': ['main'], 'max_points': ['100'], + 'import': ['Import'], 'attr_type': ['email_or_id'], + 'file': csv_file} + + # Check importing + resp = self.c.post(reverse("relate-import_grades", + args=[self.datas["course_identifier"]]), datas) + self.assertEqual(resp.status_code, 200) + + # Check number of GradeChange + num_diff = len(csv_datas) - 1 if headers else len(csv_datas) + self.assertEqual(len(GradeChange.objects.all()), + self.datas["accounts"] + num_diff) + # Helper method for testing grant exceptions for new session def check_grant_new_exception(self, params): # Grant a new one diff --git a/test/not_test_course.py b/test/test_course.py similarity index 100% rename from test/not_test_course.py rename to test/test_course.py -- GitLab From 4b67595b41c9f97f9a843291953c2b165cb913ab Mon Sep 17 00:00:00 2001 From: zwang180 Date: Thu, 20 Apr 2017 20:45:29 -0500 Subject: [PATCH 12/21] style issue --- test/base_grade_tests.py | 5 ++--- test/test_grade_instructor.py | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/base_grade_tests.py b/test/base_grade_tests.py index ccf19f12..64cbdbde 100644 --- a/test/base_grade_tests.py +++ b/test/base_grade_tests.py @@ -103,8 +103,8 @@ class BaseGradeTest(object): if assign_role: participation = Participation() participation.user = user - participation.course = Course.objects.filter(identifier= - cls.datas["course_identifier"])[0] + participation.course = Course.objects.filter(identifier=\ + cls.datas["course_identifier"])[0] participation.status = "active" participation.save() @@ -114,7 +114,6 @@ class BaseGradeTest(object): role = ParticipationRole.objects.filter(id=2)[0] participation.roles.add(role) - params = cls.datas.copy() del params["flow_session_id"] resp = cls.c.post(reverse("relate-view_start_flow", kwargs=params)) diff --git a/test/test_grade_instructor.py b/test/test_grade_instructor.py index 018f5af7..cd8ad7bd 100644 --- a/test/test_grade_instructor.py +++ b/test/test_grade_instructor.py @@ -26,6 +26,7 @@ import shutil from base_grade_tests import BaseGradeTest from django.test import TestCase + class InstructorGradeTest(BaseGradeTest, TestCase): @classmethod def setUpTestData(cls): # noqa -- GitLab From 09fde590ad01b8fb95a06411a6e7fc0ffd8c6cb1 Mon Sep 17 00:00:00 2001 From: zwang180 Date: Thu, 20 Apr 2017 20:47:34 -0500 Subject: [PATCH 13/21] style issue --- test/base_grade_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/base_grade_tests.py b/test/base_grade_tests.py index 64cbdbde..be4b379b 100644 --- a/test/base_grade_tests.py +++ b/test/base_grade_tests.py @@ -103,8 +103,8 @@ class BaseGradeTest(object): if assign_role: participation = Participation() participation.user = user - participation.course = Course.objects.filter(identifier=\ - cls.datas["course_identifier"])[0] + participation.course = Course.objects.filter( + identifier=cls.datas["course_identifier"])[0] participation.status = "active" participation.save() -- GitLab From 6417e92ad350d739c4538a0acbe73c0d21da7c2f Mon Sep 17 00:00:00 2001 From: zwang180 Date: Thu, 20 Apr 2017 20:51:42 -0500 Subject: [PATCH 14/21] module compatibility between Python 2 and Python 3 --- test/base_grade_tests.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/base_grade_tests.py b/test/base_grade_tests.py index be4b379b..e0af1003 100644 --- a/test/base_grade_tests.py +++ b/test/base_grade_tests.py @@ -22,7 +22,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -import cStringIO +# For compatibility between Python 2 and Python 3 +try: + import cStringIO +except ImportError: + import io as cStringIO + import csv from django.test import Client from django.urls import resolve, reverse -- GitLab From 1e010f4eab259417f010d7726387ff1edd8efad6 Mon Sep 17 00:00:00 2001 From: zwang180 Date: Thu, 20 Apr 2017 20:53:04 -0500 Subject: [PATCH 15/21] style issue --- test/base_grade_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/base_grade_tests.py b/test/base_grade_tests.py index e0af1003..d6c6b311 100644 --- a/test/base_grade_tests.py +++ b/test/base_grade_tests.py @@ -27,7 +27,7 @@ try: import cStringIO except ImportError: import io as cStringIO - + import csv from django.test import Client from django.urls import resolve, reverse -- GitLab From bb179ebf848a7c19b344264330c68ad5909c1865 Mon Sep 17 00:00:00 2001 From: zwang180 Date: Sat, 22 Apr 2017 23:05:44 -0500 Subject: [PATCH 16/21] add a simple test for page sandbox --- test/test_other.py | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 test/test_other.py diff --git a/test/test_other.py b/test/test_other.py new file mode 100644 index 00000000..38847d8a --- /dev/null +++ b/test/test_other.py @@ -0,0 +1,95 @@ +from __future__ import division + +__copyright__ = "Copyright (C) 2014 Andreas Kloeckner" + +__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 shutil +from django.test import TestCase, Client +from django.urls import resolve, reverse +from accounts.models import User + + +class CourseTest(TestCase): + @classmethod + def setUpTestData(cls): # noqa + # Set up data for the whole TestCase + cls.admin = User.objects.create_superuser( + username="testadmin", + password="test", + email="test@example.com", + first_name="Test", + last_name="Admin") + cls.admin.save() + # Create the course here and check later to + # avoid exceptions raised here + cls.c = Client() + cls.c.login( + username="testadmin", + password="test") + cls.c.post("/new-course/", dict( + identifier="test-course", + name="Test Course", + number="CS123", + time_period="Fall 2016", + hidden=True, + listed=True, + accepts_enrollment=True, + git_source="git://github.com/inducer/relate-sample", + course_file="course.yml", + events_file="events.yml", + enrollment_approval_required=True, + enrollment_required_email_suffix=None, + from_email="inform@tiker.net", + notify_email="inform@tiker.net")) + + @classmethod + def tearDownClass(cls): + # Remove created folder + shutil.rmtree('../test-course') + super(CourseTest, cls).tearDownClass() + + def test_page_sandbox(self): + # Check if page is there + resp = self.c.get(reverse("relate-view_page_sandbox", args=["test-course"])) + self.assertEqual(resp.status_code, 200) + + # Check one of the quiz questions + question_markup = ("type: TextQuestion\r\n" + "id: half\r\nvalue: 5\r\n" + "prompt: |\r\n # A half\r\n" + " What's a half?\r\n" + "answers:\r\n\r\n" + " - type: float\r\n" + " value: 0.5\r\n" + " rtol: 1e-4\r\n" + " - half\r\n" + " - a half") + datas = {'content': [question_markup], 'preview': ['Preview']} + resp = self.c.post(reverse("relate-view_page_sandbox", + args=["test-course"]), datas) + self.assertEqual(resp.status_code, 200) + + # Try to answer the rendered question + datas = {'answer': ['0.5'], 'submit': ['Submit answer']} + resp = self.c.post(reverse("relate-view_page_sandbox", + args=["test-course"]), datas) + self.assertEqual(resp.status_code, 200) -- GitLab From 88beda312df9d545fab121f0066913e2213354cf Mon Sep 17 00:00:00 2001 From: zwang180 Date: Sat, 22 Apr 2017 23:20:36 -0500 Subject: [PATCH 17/21] remove unused import --- test/test_other.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_other.py b/test/test_other.py index 38847d8a..1badedc8 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -24,7 +24,7 @@ THE SOFTWARE. import shutil from django.test import TestCase, Client -from django.urls import resolve, reverse +from django.urls import reverse from accounts.models import User -- GitLab From 36c8291ee8f525c08de91aec667a4c3076741f29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kl=C3=B6ckner?= Date: Sun, 23 Apr 2017 14:08:47 -0400 Subject: [PATCH 18/21] Fix copyright in base_grade_test.py. --- test/base_grade_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/base_grade_tests.py b/test/base_grade_tests.py index d6c6b311..6c6f204a 100644 --- a/test/base_grade_tests.py +++ b/test/base_grade_tests.py @@ -1,6 +1,6 @@ from __future__ import division -__copyright__ = "Copyright (C) 2014 Andreas Kloeckner" +__copyright__ = "Copyright (C) 2014 Zesheng Wang" __license__ = """ Permission is hereby granted, free of charge, to any person obtaining a copy -- GitLab From 6d42329f16578b3ccc827cf9cb182d58d8370d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kl=C3=B6ckner?= Date: Sun, 23 Apr 2017 14:09:29 -0400 Subject: [PATCH 19/21] Re-Fix copyright in base_grade_tests.py --- test/base_grade_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/base_grade_tests.py b/test/base_grade_tests.py index 6c6f204a..0504e4b8 100644 --- a/test/base_grade_tests.py +++ b/test/base_grade_tests.py @@ -1,6 +1,6 @@ from __future__ import division -__copyright__ = "Copyright (C) 2014 Zesheng Wang" +__copyright__ = "Copyright (C) 2017 Zesheng Wang" __license__ = """ Permission is hereby granted, free of charge, to any person obtaining a copy -- GitLab From d94b876737d09eab7c2e1550d5e3ade91b8bf07a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kl=C3=B6ckner?= Date: Sun, 23 Apr 2017 14:10:53 -0400 Subject: [PATCH 20/21] Fix copyright in test_other.py --- test/test_other.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_other.py b/test/test_other.py index 1badedc8..64666501 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -1,6 +1,6 @@ from __future__ import division -__copyright__ = "Copyright (C) 2014 Andreas Kloeckner" +__copyright__ = "Copyright (C) 2017 Zesheng Wang" __license__ = """ Permission is hereby granted, free of charge, to any person obtaining a copy -- GitLab From 29192c1219caf5de27627b7f3b587356d00ea3fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kl=C3=B6ckner?= Date: Sun, 23 Apr 2017 14:11:09 -0400 Subject: [PATCH 21/21] Fix copyright in test_grade_ta.py --- test/test_grade_ta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_grade_ta.py b/test/test_grade_ta.py index 4d18a568..901868fb 100644 --- a/test/test_grade_ta.py +++ b/test/test_grade_ta.py @@ -1,6 +1,6 @@ from __future__ import division -__copyright__ = "Copyright (C) 2014 Andreas Kloeckner" +__copyright__ = "Copyright (C) 2017 Zesheng Wang" __license__ = """ Permission is hereby granted, free of charge, to any person obtaining a copy -- GitLab