diff options
Diffstat (limited to 'yaksh/test_views.py')
-rw-r--r-- | yaksh/test_views.py | 1069 |
1 files changed, 957 insertions, 112 deletions
diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 2dddcef..ad5b714 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -9,6 +9,7 @@ except ImportError: import zipfile import shutil from textwrap import dedent +from markdown import Markdown from django.contrib.auth.models import Group from django.contrib.auth import authenticate @@ -23,7 +24,8 @@ from django.core.files.uploadedfile import SimpleUploadedFile from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\ QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\ AssignmentUpload, FileUpload, McqTestCase, IntegerTestCase, StringTestCase,\ - FloatTestCase, FIXTURES_DIR_PATH + FloatTestCase, FIXTURES_DIR_PATH, LearningModule, LearningUnit, Lesson,\ + LessonFile from yaksh.decorators import user_has_profile @@ -492,8 +494,15 @@ class TestMonitor(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) + self.learning_unit = LearningUnit.objects.create( + order=1, type="quiz", quiz=self.quiz) + self.learning_module = LearningModule.objects.create( + order=1, name="test module", description="test", + creator=self.user, check_prerequisite=False) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module) self.question = Question.objects.create( summary="Test_question", description="Add two numbers", @@ -514,7 +523,7 @@ class TestMonitor(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - percent=1, marks_obtained=1 + percent=1, marks_obtained=1, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) @@ -529,6 +538,8 @@ class TestMonitor(TestCase): self.question.delete() self.question_paper.delete() self.new_answer.delete() + self.learning_module.delete() + self.learning_unit.delete() def test_monitor_denies_student(self): """ @@ -568,7 +579,8 @@ class TestMonitor(TestCase): password=self.user_plaintext_pass ) response = self.client.get(reverse('yaksh:monitor', - kwargs={'quiz_id': self.quiz.id}), + kwargs={'quiz_id': self.quiz.id, + 'course_id': self.course.id}), follow=True ) @@ -588,7 +600,8 @@ class TestMonitor(TestCase): ) response = self.client.get(reverse('yaksh:user_data', kwargs={'user_id':self.student.id, - 'questionpaper_id': self.question_paper.id}), + 'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id}), follow=True ) self.assertEqual(response.status_code, 200) @@ -655,8 +668,15 @@ class TestGradeUser(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) + self.learning_unit = LearningUnit.objects.create( + order=1, type="quiz", quiz=self.quiz) + self.learning_module = LearningModule.objects.create( + order=1, name="test module", description="test", + creator=self.user, check_prerequisite=False) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module) self.question = Question.objects.create( summary="Test_question", description="Add two numbers", @@ -677,7 +697,7 @@ class TestGradeUser(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - marks_obtained=0.5 + marks_obtained=0.5, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) @@ -693,6 +713,8 @@ class TestGradeUser(TestCase): self.question.delete() self.question_paper.delete() self.new_answer.delete() + self.learning_module.delete() + self.learning_unit.delete() def test_grade_user_denies_student(self): """ @@ -731,7 +753,8 @@ class TestGradeUser(TestCase): password=self.user_plaintext_pass ) response = self.client.get(reverse('yaksh:grade_user', - kwargs={"quiz_id": self.quiz.id}), + kwargs={"quiz_id": self.quiz.id, + 'course_id': self.course.id}), follow=True ) self.assertEqual(response.status_code, 200) @@ -751,6 +774,7 @@ class TestGradeUser(TestCase): ) response = self.client.get(reverse('yaksh:grade_user', kwargs={"quiz_id": self.quiz.id, + "course_id": self.course.id, "user_id": self.student.id}), follow=True ) @@ -771,6 +795,7 @@ class TestGradeUser(TestCase): ) self.client.get(reverse('yaksh:grade_user', kwargs={"quiz_id": self.quiz.id, + "course_id": self.course.id, "user_id": self.student.id}), follow=True ) @@ -778,6 +803,7 @@ class TestGradeUser(TestCase): response = self.client.post(reverse('yaksh:grade_user', kwargs={"quiz_id": self.quiz.id, "user_id": self.student.id, + "course_id": self.course.id, "attempt_number": self.answerpaper.attempt_number}), data={question_marks: 1.0} ) @@ -848,9 +874,15 @@ class TestDownloadAssignment(TestCase): end_date_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzone), duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, - description='demo_quiz', pass_criteria=40, - language='Python', course=self.course + description='demo_quiz', pass_criteria=40 ) + self.learning_unit = LearningUnit.objects.create( + order=1, type="quiz", quiz=self.quiz) + self.learning_module = LearningModule.objects.create( + order=1, name="test module", description="test", + creator=self.user, check_prerequisite=False) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module) self.question = Question.objects.create( summary="Test_question", description="Assignment Upload", @@ -886,6 +918,8 @@ class TestDownloadAssignment(TestCase): self.assignment2.delete() self.quiz.delete() self.course.delete() + self.learning_module.delete() + self.learning_unit.delete() dir_name = self.quiz.description.replace(" ", "_") file_path = os.sep.join((settings.MEDIA_ROOT, dir_name)) if os.path.exists(file_path): @@ -999,24 +1033,13 @@ class TestAddQuiz(TestCase): self.course = Course.objects.create(name="Python Course", enrollment="Enroll Request", creator=self.user) - self.pre_req_quiz = Quiz.objects.create( - start_date_time=datetime(2014, 2, 1, 5, 8, 15, 0, tzone), - end_date_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzone), - duration=30, active=True, instructions="Demo Instructions", - attempts_allowed=-1, time_between_attempts=0, - description='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.course - ) - self.quiz = Quiz.objects.create( start_date_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_date_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzone), duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', prerequisite=self.pre_req_quiz, - course=self.course + creator=self.user ) def tearDown(self): @@ -1024,18 +1047,16 @@ class TestAddQuiz(TestCase): self.user.delete() self.student.delete() self.quiz.delete() - self.pre_req_quiz.delete() self.course.delete() def test_add_quiz_denies_anonymous(self): """ If not logged in redirect to login page """ - response = self.client.get(reverse('yaksh:add_quiz', - kwargs={'course_id': self.course.id}), + response = self.client.get(reverse('yaksh:add_quiz'), follow=True ) - redirect_destination = '/exam/login/?next=/exam/manage/addquiz/{0}/'.format(self.course.id) + redirect_destination = '/exam/login/?next=/exam/manage/addquiz/' self.assertRedirects(response, redirect_destination) def test_add_quiz_denies_non_moderator(self): @@ -1047,8 +1068,7 @@ class TestAddQuiz(TestCase): password=self.student_plaintext_pass ) course_id = self.course.id - response = self.client.get(reverse('yaksh:add_quiz', - kwargs={'course_id': self.course.id}), + response = self.client.get(reverse('yaksh:add_quiz'), follow=True ) self.assertEqual(response.status_code, 404) @@ -1061,8 +1081,7 @@ class TestAddQuiz(TestCase): username=self.user.username, password=self.user_plaintext_pass ) - response = self.client.get(reverse('yaksh:add_quiz', - kwargs={'course_id': self.course.id}) + response = self.client.get(reverse('yaksh:add_quiz') ) self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, 'yaksh/add_quiz.html') @@ -1078,7 +1097,7 @@ class TestAddQuiz(TestCase): ) tzone = pytz.timezone('UTC') response = self.client.post(reverse('yaksh:edit_quiz', - kwargs={'course_id':self.course.id, 'quiz_id': self.quiz.id}), + kwargs={'quiz_id': self.quiz.id}), data={ 'start_date_time': '2016-01-10 09:00:15', 'end_date_time': '2016-01-15 09:00:15', @@ -1088,10 +1107,8 @@ class TestAddQuiz(TestCase): 'time_between_attempts': 1, 'description': 'updated demo quiz', 'pass_criteria': 40, - 'language': 'java', 'instructions': "Demo Instructions", - 'prerequisite': self.pre_req_quiz.id, - 'course': self.course.id + 'weightage': 1.0 } ) @@ -1108,12 +1125,9 @@ class TestAddQuiz(TestCase): self.assertEqual(updated_quiz.time_between_attempts, 1) self.assertEqual(updated_quiz.description, 'updated demo quiz') self.assertEqual(updated_quiz.pass_criteria, 40) - self.assertEqual(updated_quiz.language, 'java') - self.assertEqual(updated_quiz.prerequisite, self.pre_req_quiz) - self.assertEqual(updated_quiz.course, self.course) self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/courses/') + self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') def test_add_quiz_post_new_quiz(self): """ @@ -1125,8 +1139,7 @@ class TestAddQuiz(TestCase): ) tzone = pytz.timezone('UTC') - response = self.client.post(reverse('yaksh:add_quiz', - kwargs={"course_id": self.course.id}), + response = self.client.post(reverse('yaksh:add_quiz'), data={ 'start_date_time': '2016-01-10 09:00:15', 'end_date_time': '2016-01-15 09:00:15', @@ -1136,10 +1149,8 @@ class TestAddQuiz(TestCase): 'time_between_attempts': 2, 'description': 'new demo quiz', 'pass_criteria': 50, - 'language': 'python', 'instructions': "Demo Instructions", - 'prerequisite': self.pre_req_quiz.id, - 'course': self.course.id + 'weightage': 1.0 } ) quiz_list = Quiz.objects.all().order_by('-id') @@ -1156,12 +1167,23 @@ class TestAddQuiz(TestCase): self.assertEqual(new_quiz.time_between_attempts, 2) self.assertEqual(new_quiz.description, 'new demo quiz') self.assertEqual(new_quiz.pass_criteria, 50) - self.assertEqual(new_quiz.language, 'python') - self.assertEqual(new_quiz.prerequisite, self.pre_req_quiz) - self.assertEqual(new_quiz.course, self.course) self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/courses/') + self.assertRedirects(response, '/exam/manage/courses/all_quizzes/') + + def test_show_all_quizzes(self): + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:show_all_quizzes'), + follow=True + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['type'], "quiz") + self.assertEqual(response.context['quizzes'][0], self.quiz) + self.assertTemplateUsed(response, "yaksh/courses.html") class TestAddTeacher(TestCase): @@ -1212,8 +1234,7 @@ class TestAddTeacher(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.course + creator=self.user ) self.quiz = Quiz.objects.create( @@ -1222,8 +1243,7 @@ class TestAddTeacher(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', prerequisite=self.pre_req_quiz, - course=self.course + creator=self.user ) def tearDown(self): @@ -1372,8 +1392,7 @@ class TestRemoveTeacher(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.course + creator=self.user ) self.quiz = Quiz.objects.create( @@ -1382,8 +1401,7 @@ class TestRemoveTeacher(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', prerequisite=self.pre_req_quiz, - course=self.course + creator=self.user ) def tearDown(self): self.client.logout() @@ -1520,16 +1538,43 @@ class TestCourses(TestCase): last_name='student_last_name', email='demo_student@test.com' ) + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Aeronautical', + position='Moderator', + timezone='UTC' + ) + + self.teacher_plaintext_pass = 'teacher' + self.teacher = User.objects.create_user( + username='teacher', + password=self.teacher_plaintext_pass, + first_name='teacher_first_name', + last_name='teacher_last_name', + email='demo_teacher@test.com' + ) # Add to moderator group self.mod_group.user_set.add(self.user1) self.mod_group.user_set.add(self.user2) + self.mod_group.user_set.add(self.teacher) + + # Create a learning module to add to course + self.learning_module = LearningModule.objects.create( + order=0, name="test module", description="module", + check_prerequisite=False, creator=self.teacher) self.user1_course = Course.objects.create(name="Python Course", enrollment="Enroll Request", creator=self.user1) + # Add teacher to user1 course + self.user1_course.teachers.add(self.teacher) + self.user2_course = Course.objects.create(name="Java Course", enrollment="Enroll Request", creator=self.user2) + self.user2_course.learning_module.add(self.learning_module) def tearDown(self): self.client.logout() @@ -1538,8 +1583,8 @@ class TestCourses(TestCase): self.student.delete() self.user1_course.delete() self.user2_course.delete() - - + self.teacher.delete() + self.learning_module.delete() def test_courses_denies_anonymous(self): """ @@ -1583,6 +1628,167 @@ class TestCourses(TestCase): self.assertIn(self.user1_course, response.context['courses']) self.assertNotIn(self.user2_course, response.context['courses']) + def test_teacher_can_design_course(self): + """ Check if teacher can design the course i.e add learning modules """ + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + response = self.client.post( + reverse('yaksh:design_course', + kwargs={"course_id": self.user1_course.id}), + data={"Add": "Add", + "module_list": [str(self.learning_module.id)] + }) + + # Test add learning module + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/design_course_session.html') + added_learning_module = self.user1_course.learning_module.all().first() + self.assertEqual(self.learning_module, added_learning_module) + self.assertEqual(added_learning_module.order, 1) + + # Test change order of learning module + response = self.client.post( + reverse('yaksh:design_course', + kwargs={"course_id": self.user1_course.id}), + data={"Change": "Change", "ordered_list": ",".join( + [str(self.learning_module.id)+":"+"0"] + )} + ) + updated_learning_module = LearningModule.objects.get( + id=self.learning_module.id) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/design_course_session.html') + self.assertEqual(updated_learning_module.order, 0) + + # Test change check prerequisite + response = self.client.post( + reverse('yaksh:design_course', + kwargs={"course_id": self.user1_course.id}), + data={"Change_prerequisite": "Change_prerequisite", + "check_prereq": [str(self.learning_module.id)] + }) + updated_learning_module = LearningModule.objects.get( + id=self.learning_module.id) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/design_course_session.html') + self.assertTrue(updated_learning_module.check_prerequisite) + + # Test to remove learning module from course + response = self.client.post( + reverse('yaksh:design_course', + kwargs={"course_id": self.user1_course.id}), + data={"Remove": "Remove", + "delete_list": [str(self.learning_module.id)] + }) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/design_course_session.html') + self.assertFalse(self.user1_course.learning_module.all().exists()) + + def test_get_course_modules(self): + """ Test to check if student gets course modules """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:course_modules', + kwargs={"course_id": self.user1_course.id}), + follow=True + ) + # Student is not allowed if not enrolled in the course + err_msg = "You are not enrolled for this course!" + self.assertEqual(response.context['msg'], err_msg) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/quizzes_user.html") + + # enroll student in the course + self.user1_course.students.add(self.student) + # deactivate the course and check if student is able to view course + self.user1_course.active = False + self.user1_course.save() + response = self.client.get( + reverse('yaksh:course_modules', + kwargs={"course_id": self.user1_course.id}), + follow=True + ) + err_msg = "{0} is either expired or not active".format( + self.user1_course.name) + self.assertEqual(response.context['msg'], err_msg) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/quizzes_user.html") + + # activate the course and check if students gets course modules + self.user1_course.active = True + self.user1_course.save() + self.user1_course.learning_module.add(self.learning_module) + response = self.client.get( + reverse('yaksh:course_modules', + kwargs={"course_id": self.user1_course.id}), + follow=True + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/course_modules.html") + self.assertEqual(response.context['course'], self.user1_course) + self.assertEqual(response.context['learning_modules'][0], + self.learning_module) + + def test_duplicate_course(self): + """ Test To clone/duplicate course """ + + # Student Login + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + response = self.client.get( + reverse('yaksh:duplicate_course', + kwargs={"course_id": self.user2_course.id}), + follow=True + ) + self.assertEqual(response.status_code, 404) + + # Teacher Login + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + + # Denies teacher not added in the course + response = self.client.get( + reverse('yaksh:duplicate_course', + kwargs={"course_id": self.user2_course.id}), + follow=True + ) + err_msg = "You do not have permissions" + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/complete.html") + self.assertIn(err_msg, response.context['message']) + + # Moderator/Course creator login + self.client.login( + username=self.user2.username, + password=self.user2_plaintext_pass + ) + + # Allows creator to duplicate the course + response = self.client.get( + reverse('yaksh:duplicate_course', + kwargs={"course_id": self.user2_course.id}), + follow=True + ) + + self.assertEqual(response.status_code, 200) + courses = Course.objects.filter( + creator=self.user2).order_by("id") + self.assertEqual(courses.count(), 2) + self.assertEqual(courses.last().creator, self.user2) + self.assertEqual(courses.last().name, "Copy Of Java Course") + self.assertEqual(courses.last().get_learning_modules()[0].id, + self.user2_course.get_learning_modules()[0].id) + class TestAddCourse(TestCase): def setUp(self): @@ -1632,8 +1838,7 @@ class TestAddCourse(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.course + creator=self.user ) self.quiz = Quiz.objects.create( @@ -1642,8 +1847,7 @@ class TestAddCourse(TestCase): duration=30, active=True, attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', prerequisite=self.pre_req_quiz, - course=self.course + creator=self.user ) def tearDown(self): @@ -1714,7 +1918,8 @@ class TestAddCourse(TestCase): self.assertEqual(new_course.enrollment, 'open') self.assertEqual(new_course.active, True) self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/manage/') + self.assertRedirects(response, '/exam/manage/courses', + target_status_code=301) class TestCourseDetail(TestCase): @@ -2082,12 +2287,11 @@ class TestCourseDetail(TestCase): response = self.client.post(reverse('yaksh:toggle_course_status', kwargs={'course_id': self.user1_course.id}) ) - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 302) course = Course.objects.get(name="Python Course") self.assertFalse(course.active) - self.assertEqual(self.user1_course, response.context['course']) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') + self.assertRedirects(response, '/exam/manage/courses', + target_status_code=301) def test_send_mail_to_course_students(self): """ Check if bulk mail is sent to multiple students enrolled in a course @@ -2150,6 +2354,27 @@ class TestCourseDetail(TestCase): self.assertEqual(get_response.context['course'], self.user1_course) self.assertEqual(get_response.context['state'], 'mail') + def test_download_users_template(self): + """ Test to check download users template """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + # Denies student to download users upload template + response = self.client.get(reverse('yaksh:download_sample_csv')) + self.assertEqual(response.status_code, 404) + + # Moderator Login + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + response = self.client.get(reverse('yaksh:download_sample_csv')) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.get('Content-Disposition'), + 'attachment; filename="sample_user_upload"') + class TestEnrollRequest(TestCase): def setUp(self): @@ -2281,8 +2506,8 @@ class TestViewAnswerPaper(TestCase): self.question = Question.objects.create(summary='Dummy', points=1, type='code', user=self.user1) - self.quiz = Quiz.objects.create(time_between_attempts=0, course=self.course, - description='demo quiz', language='Python') + self.quiz = Quiz.objects.create(time_between_attempts=0, + description='demo quiz') self.user3 = User.objects.get(username="demo_user3") self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, total_marks=1.0) @@ -2292,7 +2517,8 @@ class TestViewAnswerPaper(TestCase): self.ans_paper = AnswerPaper.objects.create(user=self.user3, attempt_number=1, question_paper=self.question_paper, start_time=timezone.now(), user_ip='101.0.0.1', - end_time=timezone.now()+timezone.timedelta(minutes=20)) + end_time=timezone.now()+timezone.timedelta(minutes=20), + course=self.course) def tearDown(self): User.objects.all().delete() @@ -2305,11 +2531,13 @@ class TestViewAnswerPaper(TestCase): def test_anonymous_user(self): # Given, user not logged in redirect_destination = ('/exam/login/?next=/exam' - '/view_answerpaper/{0}/'.format(self.question_paper.id)) + '/view_answerpaper/{0}/{1}'.format( + self.question_paper.id, self.course.id)) # When response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} + kwargs={'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id} ), follow=True ) @@ -2331,7 +2559,8 @@ class TestViewAnswerPaper(TestCase): # When response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} + kwargs={'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id} ), follow=True ) @@ -2354,7 +2583,8 @@ class TestViewAnswerPaper(TestCase): # When response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} + kwargs={'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id} ), follow=True ) @@ -2368,7 +2598,8 @@ class TestViewAnswerPaper(TestCase): # When, wrong question paper id response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': 190} + kwargs={'questionpaper_id': 190, + 'course_id': self.course.id} ), follow=True ) @@ -2391,7 +2622,8 @@ class TestViewAnswerPaper(TestCase): # When response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} + kwargs={'questionpaper_id': self.question_paper.id, + 'course_id': self.course.id} ), follow=True ) @@ -2565,8 +2797,8 @@ class TestGrader(TestCase): self.question = Question.objects.create(summary='Dummy', points=1, type='code', user=self.user1) - self.quiz = Quiz.objects.create(time_between_attempts=0, course=self.course, - description='demo quiz', language='Python') + self.quiz = Quiz.objects.create(time_between_attempts=0, + description='demo quiz') self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, total_marks=1.0) @@ -2576,7 +2808,8 @@ class TestGrader(TestCase): self.answerpaper = AnswerPaper.objects.create(user=self.user2, attempt_number=1, question_paper=self.question_paper, start_time=timezone.now(), user_ip='101.0.0.1', - end_time=timezone.now()+timezone.timedelta(minutes=20)) + end_time=timezone.now()+timezone.timedelta(minutes=20), + course=self.course) def tearDown(self): User.objects.all().delete() @@ -2832,7 +3065,7 @@ class TestModeratorDashboard(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) self.question = Question.objects.create( @@ -2856,20 +3089,22 @@ class TestModeratorDashboard(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - marks_obtained=0.5 + marks_obtained=0.5, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) self.answerpaper.questions.add(self.question) # moderator trial answerpaper + self.trial_course = Course.objects.create(name="Trial Course", + enrollment="Enroll Request", creator=self.user, is_trial=True) self.trial_quiz = Quiz.objects.create( start_date_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_date_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzone), duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='trial quiz', pass_criteria=40, - language='Python', course=self.course, is_trial=True + is_trial=True ) self.trial_question_paper = QuestionPaper.objects.create( @@ -2887,7 +3122,7 @@ class TestModeratorDashboard(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - marks_obtained=0.5 + marks_obtained=0.5, course=self.trial_course ) self.trial_answerpaper.answers.add(self.new_answer1) self.trial_answerpaper.questions_answered.add(self.question) @@ -2913,7 +3148,6 @@ class TestModeratorDashboard(TestCase): follow=True ) self.assertEqual(response.status_code, 200) - self.assertRedirects(response, '/exam/quizzes/') def test_moderator_dashboard_get_for_user_without_profile(self): """ @@ -2954,12 +3188,7 @@ class TestModeratorDashboard(TestCase): self.assertEqual(response.status_code, 200) self.assertTemplateUsed(response, "yaksh/moderator_dashboard.html") self.assertEqual(response.context['trial_paper'][0], self.trial_answerpaper) - paper, answer_papers, users_passed, users_failed =\ - response.context['users_per_paper'][0] - self.assertEqual(paper, self.question_paper) - self.assertEqual(answer_papers[0], self.answerpaper) - self.assertEqual(users_passed, 1) - self.assertEqual(users_failed, 0) + self.assertEqual(response.context['courses'][0], self.course) def test_moderator_dashboard_delete_trial_papers(self): """ @@ -2982,7 +3211,7 @@ class TestModeratorDashboard(TestCase): description=self.trial_question_paper.quiz.description ) updated_course = Course.objects.filter( - name=self.trial_question_paper.quiz.course.name) + name=self.trial_course.name) self.assertSequenceEqual(updated_answerpaper, []) self.assertSequenceEqual(updated_quiz, []) self.assertSequenceEqual(updated_course, []) @@ -3103,7 +3332,7 @@ class TestDownloadcsv(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) self.question = Question.objects.create( @@ -3127,7 +3356,7 @@ class TestDownloadcsv(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - marks_obtained=0.5 + marks_obtained=0.5, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) @@ -3405,7 +3634,11 @@ class TestShowQuestions(TestCase): trial_que_paper = QuestionPaper.objects.get( quiz__description="trial_questions" ) - redirection_url = "/exam/start/1/{}".format(trial_que_paper.id) + trial_course = Course.objects.get(name="trial_course") + trial_module = trial_course.learning_module.all()[0] + redirection_url = "/exam/start/1/{0}/{1}/{2}".format( + trial_module.id, trial_que_paper.id, trial_course.id + ) self.assertEqual(response.status_code, 302) self.assertRedirects(response, redirection_url, target_status_code=301) @@ -3427,6 +3660,27 @@ class TestShowQuestions(TestCase): self.assertTemplateUsed(response, 'yaksh/ajax_question_filter.html') self.assertEqual(response.context['questions'][0], self.question1) + def test_download_question_yaml_template(self): + """ Test to check download question yaml template """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + # Denies student to download question yaml template + response = self.client.get(reverse('yaksh:download_yaml_template')) + self.assertEqual(response.status_code, 404) + + # Moderator Login + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:download_yaml_template')) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.get('Content-Disposition'), + 'attachment; filename="questions_dump.yaml"') + class TestShowStatistics(TestCase): def setUp(self): @@ -3484,7 +3738,7 @@ class TestShowStatistics(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) self.question = Question.objects.create( @@ -3506,7 +3760,7 @@ class TestShowStatistics(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="completed", passed=True, - percent=1, marks_obtained=1 + percent=1, marks_obtained=1, course=self.course ) self.answerpaper.answers.add(self.new_answer) self.answerpaper.questions_answered.add(self.question) @@ -3532,7 +3786,8 @@ class TestShowStatistics(TestCase): password=self.student_plaintext_pass ) response = self.client.get(reverse('yaksh:show_statistics', - kwargs={"questionpaper_id": self.question_paper.id}), + kwargs={"questionpaper_id": self.question_paper.id, + "course_id": self.course.id}), follow=True ) self.assertEqual(response.status_code, 404) @@ -3546,7 +3801,8 @@ class TestShowStatistics(TestCase): password=self.user_plaintext_pass ) response = self.client.get(reverse('yaksh:show_statistics', - kwargs={'questionpaper_id': self.question_paper.id}), + kwargs={'questionpaper_id': self.question_paper.id, + "course_id": self.course.id}), follow=True ) self.assertEqual(response.status_code, 200) @@ -3567,7 +3823,8 @@ class TestShowStatistics(TestCase): ) response = self.client.get(reverse('yaksh:show_statistics', kwargs={'questionpaper_id': self.question_paper.id, - 'attempt_number': self.answerpaper.attempt_number}), + 'attempt_number': self.answerpaper.attempt_number, + "course_id": self.course.id}), follow=True ) self.assertEqual(response.status_code, 200) @@ -3616,9 +3873,17 @@ class TestQuestionPaper(TestCase): duration=30, active=True, instructions="Demo Instructions", attempts_allowed=-1, time_between_attempts=0, description='demo quiz', pass_criteria=40, - language='Python', course=self.course + creator=self.user ) + self.learning_unit = LearningUnit.objects.create( + order=1, type="quiz", quiz=self.quiz) + self.learning_module = LearningModule.objects.create( + order=1, name="test module", description="module", + check_prerequisite=False, creator=self.user) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module) + # Mcq Question self.question_mcq = Question.objects.create( summary="Test_mcq_question", description="Test MCQ", @@ -3706,7 +3971,7 @@ class TestQuestionPaper(TestCase): start_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), end_time=datetime(2014, 10, 9, 10, 15, 15, 0, tzone), user_ip="127.0.0.1", status="inprogress", passed=False, - percent=0, marks_obtained=0 + percent=0, marks_obtained=0, course=self.course ) self.answerpaper.questions.add(*questions_list) @@ -3720,6 +3985,8 @@ class TestQuestionPaper(TestCase): self.question_mcc.delete() self.question_int.delete() self.question_paper.delete() + self.learning_module.delete() + self.learning_unit.delete() def test_mcq_attempt_right_after_wrong(self): """ Case:- Check if answerpaper and answer marks are updated after @@ -3738,7 +4005,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcq.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3753,7 +4022,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcq.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3778,7 +4049,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcq.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3793,7 +4066,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcq.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3818,7 +4093,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcc.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3833,7 +4110,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_mcc.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3858,7 +4137,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_int.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3873,7 +4154,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_int.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3898,7 +4181,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_str.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3913,7 +4198,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_str.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) @@ -3938,7 +4225,9 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_float.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": right_user_answer} ) @@ -3953,10 +4242,566 @@ class TestQuestionPaper(TestCase): self.client.post( reverse('yaksh:check', kwargs={"q_id": self.question_float.id, "attempt_num": 1, - "questionpaper_id": self.question_paper.id}), + "questionpaper_id": self.question_paper.id, + "course_id": self.course.id, + "module_id": self.learning_module.id}), data={"answer": wrong_user_answer} ) # Then wrong_answer_paper = AnswerPaper.objects.get(id=self.answerpaper.id) self.assertEqual(wrong_answer_paper.marks_obtained, 0) + + +class TestLearningModule(TestCase): + def setUp(self): + self.client = Client() + + self.mod_group = Group.objects.create(name='moderator') + tzone = pytz.timezone('UTC') + # Create Moderator with profile + self.user_plaintext_pass = 'demo' + self.user = User.objects.create_user( + username='demo_user', + password=self.user_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + + # Create a student + self.student_plaintext_pass = 'demo_student' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@student.com' + ) + + # Create a teacher to add to the course + self.teacher_plaintext_pass = 'demo_teacher' + self.teacher = User.objects.create_user( + username='demo_teacher', + password=self.teacher_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@student.com' + ) + + # Add to moderator group + self.mod_group.user_set.add(self.user) + self.mod_group.user_set.add(self.teacher) + + self.course = Course.objects.create( + name="Python Course", + enrollment="Open Enrollment", creator=self.user) + + self.question = Question.objects.create( + summary="Test_question", description="Add two numbers", + points=1.0, language="python", type="code", user=self.user + ) + self.quiz = Quiz.objects.create( + start_date_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), + end_date_time=datetime(2199, 10, 9, 10, 8, 15, 0, tzone), + duration=30, active=True, instructions="Demo Instructions", + attempts_allowed=-1, time_between_attempts=0, + description='demo quiz', pass_criteria=40, + creator=self.user + ) + + self.question_paper = QuestionPaper.objects.create( + quiz=self.quiz, + total_marks=5.0, fixed_question_order=str(self.question.id) + ) + + self.question_paper.fixed_questions.add(self.question) + + self.lesson = Lesson.objects.create( + name="test lesson", description="test description", + creator=self.user) + # create quiz learning unit + self.learning_unit = LearningUnit.objects.create( + order=0, type="quiz", quiz=self.quiz) + # create lesson learning unit + self.learning_unit1 = LearningUnit.objects.create( + order=1, type="lesson", lesson=self.lesson) + # create learning module + self.learning_module = LearningModule.objects.create( + order=0, name="test module", description="module", + check_prerequisite=False, creator=self.user) + self.learning_module.learning_unit.add(self.learning_unit) + self.learning_module.learning_unit.add(self.learning_unit1) + self.learning_module1 = LearningModule.objects.create( + order=0, name="my module", description="my description", + check_prerequisite=False, creator=self.user) + self.course.teachers.add(self.teacher) + self.course.learning_module.add(self.learning_module) + + self.expected_url = "/exam/manage/courses/all_learning_module/" + + def tearDown(self): + self.user.delete() + self.student.delete() + self.teacher.delete() + self.quiz.delete() + self.course.delete() + self.learning_unit.delete() + self.learning_module.delete() + + def test_add_new_module_denies_non_moderator(self): + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + # Student tries to add learning module + response = self.client.post(reverse('yaksh:add_module'), + data={"name": "test module1", + "description": "my test1", + "Save": "Save"}) + self.assertEqual(response.status_code, 404) + + # Student tries to view learning modules + response = self.client.get(reverse('yaksh:show_all_modules')) + self.assertEqual(response.status_code, 404) + + def test_add_new_module(self): + """ Check if new module is created """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + + # Test add new module + response = self.client.post(reverse('yaksh:add_module'), + data={"name": "test module1", + "description": "my test1", + "Save": "Save"}) + + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, self.expected_url) + learning_module = LearningModule.objects.get(name="test module1") + self.assertEqual(learning_module.description, "my test1") + self.assertEqual(learning_module.creator, self.user) + self.assertTrue(learning_module.check_prerequisite) + self.assertEqual(learning_module.html_data, + Markdown().convert("my test1")) + + def test_edit_module(self): + """ Check if existing module is editable """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + + # Test add new module + response = self.client.post( + reverse('yaksh:edit_module', + kwargs={"module_id": self.learning_module.id}), + data={"name": "test module2", + "description": "my test2", + "Save": "Save"}) + + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, self.expected_url) + learning_module = LearningModule.objects.get(name="test module2") + self.assertEqual(learning_module.description, "my test2") + self.assertEqual(learning_module.creator, self.user) + self.assertFalse(learning_module.check_prerequisite) + self.assertEqual(learning_module.html_data, + Markdown().convert("my test2")) + + def test_show_all_modules(self): + """Try to get all learning modules""" + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:show_all_modules')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/courses.html') + self.assertEqual(response.context['type'], "learning_module") + self.assertEqual(response.context['learning_modules'][0], + self.learning_module) + + def test_teacher_can_edit_module(self): + """ Check if teacher can edit the module """ + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + response = self.client.post( + reverse('yaksh:edit_module', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id}), + data={"name": "teacher module 2", + "description": "teacher module 2", + "Save": "Save"}) + + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, "/exam/manage/courses/") + learning_module = LearningModule.objects.get(name="teacher module 2") + self.assertEqual(learning_module.description, "teacher module 2") + self.assertEqual(learning_module.creator, self.user) + + def test_teacher_can_design_module(self): + """ Check if teacher can design the module i.e add learning units """ + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + response = self.client.post( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id}), + data={"Add": "Add", + "choosen_list": ",".join([str(self.quiz.id)+":"+"quiz"]) + }) + + # Test add learning unit + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + learning_unit = self.learning_module1.learning_unit.all().first() + self.assertEqual(self.quiz, learning_unit.quiz) + self.assertEqual(learning_unit.type, "quiz") + self.assertEqual(learning_unit.order, 1) + + # Test change order of learning unit + response = self.client.post( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id}), + data={"Change": "Change", + "ordered_list": ",".join([str(learning_unit.id)+":"+"0"]) + }) + updated_learning_unit = LearningUnit.objects.get(id=learning_unit.id) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + self.assertEqual(updated_learning_unit.order, 0) + + # Test change check prerequisite + response = self.client.post( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id}), + data={"Change_prerequisite": "Change_prerequisite", + "check_prereq": [str(learning_unit.id)] + }) + updated_learning_unit = LearningUnit.objects.get(id=learning_unit.id) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + self.assertFalse(updated_learning_unit.check_prerequisite) + + # Test to remove learning unit from learning module + response = self.client.post( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id}), + data={"Remove": "Remove", + "delete_list": [str(learning_unit.id)] + }) + updated_learning_unit = LearningUnit.objects.filter( + id=learning_unit.id).exists() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + self.assertFalse(updated_learning_unit) + self.assertFalse(self.learning_module1.learning_unit.all().exists()) + + def test_get_learning_units_for_design(self): + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:design_module', + kwargs={"module_id": self.learning_module1.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/add_module.html') + self.assertEqual(response.context['quiz_les_list'], set()) + self.assertEqual(len(response.context['learning_units']), 0) + self.assertEqual(response.context['status'], "design") + self.assertEqual(response.context['module_id'], + str(self.learning_module1.id)) + self.assertEqual(response.context['course_id'], str(self.course.id)) + + def test_view_module(self): + """ Student tries to view a module containing learning units """ + + # Student is not enrolled in the course is thrown out + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:view_module', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 404) + + # add student to the course + self.course.students.add(self.student.id) + + # check if enrolled student can view module + response = self.client.get( + reverse('yaksh:view_module', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/show_video.html") + self.assertEqual(response.context['learning_units'][0], + self.learning_unit) + self.assertEqual(response.context["state"], "module") + self.assertEqual(response.context["first_unit"], self.learning_unit) + self.assertEqual(response.context["user"], self.student) + + def test_get_next_unit(self): + """ Check if we get correct next unit """ + + # Student who is not enrolled is thrown out + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:view_module', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 404) + + # Enroll student in the course + self.course.students.add(self.student.id) + + # Get First unit as next unit + response = self.client.get( + reverse('yaksh:next_unit', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id, + "current_unit_id": self.learning_unit.id, + "first_unit": "1"}), + follow=True) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['attempt_num'], 1) + self.assertEqual(response.context["questionpaper"], + self.question_paper) + self.assertEqual(response.context["course"], self.course) + self.assertEqual(response.context["module"], self.learning_module) + self.assertEqual(response.context["user"], self.student) + + # Get next unit after first unit + response = self.client.get( + reverse('yaksh:next_unit', + kwargs={"module_id": self.learning_module.id, + "course_id": self.course.id, + "current_unit_id": self.learning_unit.id}), + follow=True) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["state"], "lesson") + self.assertEqual(response.context["current_unit"].id, + self.learning_unit1.id) + + +class TestLessons(TestCase): + def setUp(self): + self.client = Client() + + self.mod_group = Group.objects.create(name='moderator') + tzone = pytz.timezone('UTC') + # Create Moderator with profile + self.user_plaintext_pass = 'demo' + self.user = User.objects.create_user( + username='demo_user', + password=self.user_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + + # Create a student + self.student_plaintext_pass = 'demo_student' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@student.com' + ) + + # Create a teacher to add to the course + self.teacher_plaintext_pass = 'demo_teacher' + self.teacher = User.objects.create_user( + username='demo_teacher', + password=self.teacher_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@student.com' + ) + + # Add to moderator group + self.mod_group.user_set.add(self.user) + self.mod_group.user_set.add(self.teacher) + + self.course = Course.objects.create( + name="Python Course", + enrollment="Open Enrollment", creator=self.user) + + self.quiz = Quiz.objects.create( + start_date_time=datetime(2014, 10, 9, 10, 8, 15, 0, tzone), + end_date_time=datetime(2015, 10, 9, 10, 8, 15, 0, tzone), + duration=30, active=True, instructions="Demo Instructions", + attempts_allowed=-1, time_between_attempts=0, + description='demo quiz', pass_criteria=40, + creator=self.user + ) + + self.lesson = Lesson.objects.create( + name="test lesson", description="test description", + creator=self.user) + self.learning_unit = LearningUnit.objects.create( + order=0, type="lesson", lesson=self.lesson) + self.learning_module = LearningModule.objects.create( + order=0, name="test module", description="module", + check_prerequisite=False, creator=self.user) + self.learning_module.learning_unit.add(self.learning_unit.id) + self.course.learning_module.add(self.learning_module.id) + self.course.teachers.add(self.teacher.id) + + self.expected_url = "/exam/manage/courses/" + + def tearDown(self): + self.user.delete() + self.student.delete() + self.teacher.delete() + self.quiz.delete() + self.course.delete() + self.learning_unit.delete() + self.learning_module.delete() + self.lesson.delete() + + def test_edit_lesson_denies_non_moderator(self): + """ Student should not be allowed to edit lesson """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + # Student tries to edit lesson + response = self.client.get( + reverse('yaksh:edit_lesson', + kwargs={"lesson_id": self.lesson.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 404) + + def test_teacher_can_edit_lesson(self): + """ Teacher should be allowed to edit lesson """ + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + dummy_file = SimpleUploadedFile("test.txt", b"test") + response = self.client.post( + reverse('yaksh:edit_lesson', + kwargs={"lesson_id": self.lesson.id, + "course_id": self.course.id}), + data={"name": "updated lesson", + "description": "updated description", + "Lesson_files": dummy_file, + "Save": "Save"} + ) + + # Teacher edits existing lesson and adds file + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, self.expected_url) + updated_lesson = Lesson.objects.get(name="updated lesson") + self.assertEqual(updated_lesson.description, "updated description") + self.assertEqual(updated_lesson.creator, self.user) + self.assertEqual(updated_lesson.html_data, + Markdown().convert("updated description")) + lesson_files = LessonFile.objects.filter( + lesson=self.lesson).first() + self.assertIn("test.txt", lesson_files.file.name) + lesson_file_path = lesson_files.file.path + # Teacher removes the lesson file + response = self.client.post( + reverse('yaksh:edit_lesson', + kwargs={"lesson_id": self.lesson.id, + "course_id": self.course.id}), + data={"delete_files": [str(lesson_files.id)], + "Delete": "Delete"} + ) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, self.expected_url) + lesson_file_exists = LessonFile.objects.filter( + lesson=self.lesson).exists() + self.assertFalse(lesson_file_exists) + self.assertFalse(os.path.exists(lesson_file_path)) + + def test_show_lesson(self): + """ Student should be able to view lessons """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.get( + reverse('yaksh:show_lesson', + kwargs={"lesson_id": self.lesson.id, + "module_id": self.learning_module.id, + "course_id": self.course.id})) + # Student is unable to view lesson + self.assertEqual(response.status_code, 404) + + # Add student to course + self.course.students.add(self.student.id) + response = self.client.get( + reverse('yaksh:show_lesson', + kwargs={"lesson_id": self.lesson.id, + "module_id": self.learning_module.id, + "course_id": self.course.id})) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context["state"], "lesson") + self.assertEqual(response.context["current_unit"], self.learning_unit) + + def test_show_all_lessons(self): + """ Moderator should be able to see all created lessons""" + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:show_all_lessons')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/courses.html") + self.assertEqual(response.context["type"], "lesson") + self.assertEqual(response.context["lessons"][0], self.lesson) + + def test_preview_lesson_description(self): + """ Test preview lesson description converted from md to html""" + self.client.login( + username=self.teacher.username, + password=self.teacher_plaintext_pass + ) + lesson = json.dumps({'description': self.lesson.description}) + response = self.client.post( + reverse('yaksh:preview_html_text'), + data=lesson, content_type="application/json" + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json()['data'], '<p>test description</p>') |