From 1361c6da55b5a5cb2ef78e08472943277135f2b1 Mon Sep 17 00:00:00 2001 From: adityacp Date: Fri, 19 May 2017 16:03:27 +0530 Subject: Add tests for views functions --- yaksh/test_views.py | 2847 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 2101 insertions(+), 746 deletions(-) (limited to 'yaksh') diff --git a/yaksh/test_views.py b/yaksh/test_views.py index 37e5ce4..1a404c6 100644 --- a/yaksh/test_views.py +++ b/yaksh/test_views.py @@ -1,6 +1,13 @@ from datetime import datetime import pytz import os +import json +try: + from StringIO import StringIO as string_io +except ImportError: + from io import BytesIO as string_io +import zipfile +import shutil from django.contrib.auth.models import Group from django.contrib.auth import authenticate from django.core.urlresolvers import reverse @@ -8,10 +15,40 @@ from django.test import TestCase from django.test import Client from django.utils import timezone from django.core import mail +from django.conf import settings +from django.core.files.uploadedfile import SimpleUploadedFile from yaksh.models import User, Profile, Question, Quiz, QuestionPaper,\ - QuestionSet, AnswerPaper, Answer, Course, StandardTestCase,\ - StdIOBasedTestCase, has_profile + QuestionSet, AnswerPaper, Answer, Course, StandardTestCase, has_profile,\ + AssignmentUpload, FileUpload + + +class TestUserRegistration(TestCase): + def setUp(self): + self.client = Client() + + def tearDown(self): + self.registered_user.delete() + + def test_register_user_post(self): + response = self.client.post(reverse('yaksh:register'), + data={'username': 'register_user', + 'email':'register_user@mail.com', 'password': 'reg_user', + 'confirm_password': 'reg_user', 'first_name': 'user1_f_name', + 'last_name': 'user1_l_name', 'roll_number': '1', + 'institute': 'demo_institute', 'department': 'demo_dept', + 'position': 'student', 'timezone': pytz.utc.zone + } + ) + self.registered_user = User.objects.get(username='register_user') + self.assertEqual(self.registered_user.email, 'register_user@mail.com') + self.assertEqual(self.registered_user.first_name, 'user1_f_name') + self.assertEqual(self.registered_user.last_name, 'user1_l_name') + self.assertEqual(self.registered_user.profile.roll_number, '1') + self.assertEqual(self.registered_user.profile.institute, 'demo_institute') + self.assertEqual(self.registered_user.profile.department, 'demo_dept') + self.assertEqual(self.registered_user.profile.position, 'student') + self.assertEqual(self.registered_user.profile.timezone, 'UTC') class TestProfile(TestCase): @@ -187,13 +224,30 @@ class TestProfile(TestCase): self.assertTemplateUsed(response, 'yaksh/activation_status.html') -class TestAddQuiz(TestCase): +class TestStudentDashboard(TestCase): def setUp(self): self.client = Client() - self.mod_group = Group.objects.create(name='moderator') - tzone = pytz.timezone('UTC') - # Create Moderator with profile + # student + self.student_plaintext_pass = 'student' + self.student = User.objects.create_user( + username='student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='student@test.com' + ) + + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='student', + timezone='UTC' + ) + + # moderator self.user_plaintext_pass = 'demo' self.user = User.objects.create_user( username='demo_user', @@ -212,193 +266,77 @@ class TestAddQuiz(TestCase): timezone='UTC' ) - # Create Student - self.student_plaintext_pass = 'demo_student' - self.student = User.objects.create_user( - username='demo_student', - password=self.student_plaintext_pass, - first_name='student_first_name', - last_name='student_last_name', - email='demo_student@test.com' - ) - - # Add to moderator group - self.mod_group.user_set.add(self.user) - 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 - ) + self.hidden_course = Course.objects.create(name="Hidden Course", + enrollment="Enroll Request", creator=self.user, code="hide", + hidden=True) def tearDown(self): self.client.logout() 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}), - follow=True - ) - redirect_destination = '/exam/login/?next=/exam/manage/addquiz/{0}/'.format(self.course.id) - self.assertRedirects(response, redirect_destination) - - def test_add_quiz_denies_non_moderator(self): + def test_student_dashboard_all_courses_get(self): """ - If not moderator in redirect to login page + Check student dashboard for all non hidden courses """ self.client.login( username=self.student.username, 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:quizlist_user'), follow=True ) - self.assertEqual(response.status_code, 404) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/quizzes_user.html") + self.assertEqual(response.context['title'], 'All Courses') + self.assertEqual(response.context['courses'][0], self.course) - def test_add_quiz_get(self): + def test_student_dashboard_enrolled_courses_get(self): """ - GET request to add question should display add quiz form + Check student dashboard for all courses in which student is + enrolled """ self.client.login( - username=self.user.username, - password=self.user_plaintext_pass + username=self.student.username, + password=self.student_plaintext_pass ) - response = self.client.get(reverse('yaksh:add_quiz', - kwargs={'course_id': self.course.id}) + self.course.students.add(self.student) + response = self.client.get(reverse('yaksh:quizlist_user', + kwargs={'enrolled': "enrolled"}), + follow=True ) self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'yaksh/add_quiz.html') - self.assertIsNotNone(response.context['form']) + self.assertTemplateUsed(response, "yaksh/quizzes_user.html") + self.assertEqual(response.context['title'], 'Enrolled Courses') + self.assertEqual(response.context['courses'][0], self.course) - def test_add_quiz_post_existing_quiz(self): + def test_student_dashboard_hidden_courses_post(self): """ - POST request to add quiz should edit quiz if quiz exists + Get courses for student based on the course code """ - self.client.login( - username=self.user.username, - password=self.user_plaintext_pass - ) - tzone = pytz.timezone('UTC') - response = self.client.post(reverse('yaksh:edit_quiz', - kwargs={'course_id':self.course.id, 'quiz_id': self.quiz.id}), - data={ - 'start_date_time': '2016-01-10 09:00:15', - 'end_date_time': '2016-01-15 09:00:15', - 'duration': 30, - 'active': False, - 'attempts_allowed': 5, - '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 - } - ) - - updated_quiz = Quiz.objects.get(id=self.quiz.id) - self.assertEqual(updated_quiz.start_date_time, - datetime(2016, 1, 10, 9, 0, 15, 0, tzone) - ) - self.assertEqual(updated_quiz.end_date_time, - datetime(2016, 1, 15, 9, 0, 15, 0, tzone) - ) - self.assertEqual(updated_quiz.duration, 30) - self.assertEqual(updated_quiz.active, False) - self.assertEqual(updated_quiz.attempts_allowed, 5) - 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/') - def test_add_quiz_post_new_quiz(self): - """ - POST request to add quiz should add new quiz if no quiz exists - """ self.client.login( - username=self.user.username, - password=self.user_plaintext_pass - ) - - tzone = pytz.timezone('UTC') - response = self.client.post(reverse('yaksh:add_quiz', kwargs={"course_id": self.course.id}), - data={ - 'start_date_time': '2016-01-10 09:00:15', - 'end_date_time': '2016-01-15 09:00:15', - 'duration': 50, - 'active': True, - 'attempts_allowed': -1, - '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 - } - ) - quiz_list = Quiz.objects.all().order_by('-id') - new_quiz = quiz_list[0] - self.assertEqual(new_quiz.start_date_time, - datetime(2016, 1, 10, 9, 0, 15, 0, tzone) - ) - self.assertEqual(new_quiz.end_date_time, - datetime(2016, 1, 15, 9, 0, 15, 0, tzone) + username=self.student.username, + password=self.student_plaintext_pass ) - self.assertEqual(new_quiz.duration, 50) - self.assertEqual(new_quiz.active, True) - self.assertEqual(new_quiz.attempts_allowed, -1) - 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/') + response = self.client.post(reverse('yaksh:quizlist_user'), + data={'course_code': 'hide'} + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/quizzes_user.html") + self.assertEqual(response.context['title'], 'Search') + self.assertEqual(response.context['courses'][0], self.hidden_course) -class TestAddTeacher(TestCase): +class TestMonitor(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( @@ -428,136 +366,127 @@ class TestAddTeacher(TestCase): email='demo_student@test.com' ) + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + # Add to moderator group self.mod_group.user_set.add(self.user) 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, - attempts_allowed=-1, time_between_attempts=0, - description='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.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, + 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 + language='Python', course=self.course ) + self.question = Question.objects.create( + summary="Test_question", description="Add two numbers", + points=1.0, language="python", type="code", user=self.user + ) + + self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, + total_marks=1.0, fixed_question_order=str(self.question) + ) + self.question_paper.fixed_questions.add(self.question) + user_answer = "def add(a, b)\n\treturn a+b" + self.new_answer = Answer(question=self.question, answer=user_answer, + correct=True, error=json.dumps([])) + self.new_answer.save() + self.answerpaper = AnswerPaper.objects.create( + user=self.student, question_paper=self.question_paper, + attempt_number=1, + 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 + ) + self.answerpaper.answers.add(self.new_answer) + self.answerpaper.questions_answered.add(self.question) + def tearDown(self): self.client.logout() self.user.delete() self.student.delete() self.quiz.delete() - self.pre_req_quiz.delete() self.course.delete() + self.answerpaper.delete() + self.question.delete() + self.question_paper.delete() + self.new_answer.delete() - def test_add_teacher_denies_anonymous(self): - """ - If not logged in redirect to login page - """ - response = self.client.get(reverse('yaksh:add_teacher', - kwargs={'course_id': self.course.id} - ), - follow=True - ) - redirect_destination = ('/exam/login/?next=/exam' - '/manage/addteacher/{0}/'.format(self.course.id)) - self.assertRedirects(response, redirect_destination) - - def test_add_teacher_denies_non_moderator(self): + def test_monitor_display_quizzes(self): """ - If not moderator redirect to login page + Check all the available quizzes in monitor """ self.client.login( - username=self.student.username, - password=self.student_plaintext_pass - ) - - response = self.client.get(reverse('yaksh:add_teacher', - kwargs={'course_id': self.course.id} - ), - follow=True + username=self.user.username, + password=self.user_plaintext_pass ) - self.assertEqual(response.status_code, 404) + response = self.client.get(reverse('yaksh:monitor'), + follow=True + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/monitor.html") + self.assertEqual(response.context['course_details'][0], self.course) + self.assertEqual(response.context['msg'], "Monitor") - def test_add_teacher_get(self): + def test_monitor_display_quiz_results(self): """ - GET request to add teacher should display list of teachers + Check all the quiz results in monitor """ self.client.login( username=self.user.username, password=self.user_plaintext_pass ) - response = self.client.get(reverse('yaksh:add_teacher', - kwargs={'course_id': self.course.id} - ) - ) + response = self.client.get(reverse('yaksh:monitor', + kwargs={'quiz_id': self.quiz.id}), + follow=True + ) + self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'yaksh/addteacher.html') - self.assertEqual(response.context['course'], self.course) + self.assertTemplateUsed(response, "yaksh/monitor.html") + self.assertEqual(response.context['msg'], "Quiz Results") + self.assertEqual(response.context['papers'][0], self.answerpaper) + self.assertEqual(response.context['latest_attempts'][0], self.answerpaper) - def test_add_teacher_post(self): + def test_get_quiz_user_data(self): """ - POST request to add teacher should add teachers to a course + Check for getting user data for a quiz """ self.client.login( username=self.user.username, password=self.user_plaintext_pass ) - teacher_id_list = [] - - for i in range(5): - teacher = User.objects.create_user( - username='demo_teacher{}'.format(i), - password='demo_teacher_pass{}'.format(i), - first_name='teacher_first_name{}'.format(i), - last_name='teacher_last_name{}'.format(i), - email='demo{}@test.com'.format(i) - ) - - teacher_profile = Profile.objects.create( - user=teacher, - roll_number='T{}'.format(i), - institute='IIT', - department='Chemical', - position='Teacher', - timezone='UTC' - ) - teacher_id_list.append(teacher.id) - - response = self.client.post(reverse('yaksh:add_teacher', - kwargs={'course_id': self.course.id} - ), - data={'check': teacher_id_list} - ) - + response = self.client.get(reverse('yaksh:user_data', + kwargs={'user_id':self.student.id, + 'questionpaper_id': self.question_paper.id}), + follow=True + ) self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'yaksh/addteacher.html') - self.assertEqual(response.context['status'], True) - for t_id in teacher_id_list: - teacher_object = User.objects.get(id=t_id) - self.assertIn(teacher_object, response.context['teachers_added']) - self.assertIn(teacher_object, self.course.teachers.all()) - - -class TestRemoveTeacher(TestCase): + self.assertTemplateUsed(response, 'yaksh/user_data.html') + self.assertEqual(response.context['data']['papers'][0], self.answerpaper) + self.assertEqual(response.context['data']['profile'], self.student.profile) + self.assertEqual(response.context['data']['user'], self.student) + self.assertEqual(response.context['data']['questionpaperid'], + str(self.question_paper.id)) + +class TestGradeUser(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( @@ -587,132 +516,170 @@ class TestRemoveTeacher(TestCase): email='demo_student@test.com' ) + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + # Add to moderator group self.mod_group.user_set.add(self.user) 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, - attempts_allowed=-1, time_between_attempts=0, - description='pre requisite quiz', pass_criteria=40, - language='Python', prerequisite=None, - course=self.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, + 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 + language='Python', course=self.course ) + + self.question = Question.objects.create( + summary="Test_question", description="Add two numbers", + points=1.0, language="python", type="code", user=self.user + ) + + self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, + total_marks=1.0, fixed_question_order=str(self.question.id) + ) + self.question_paper.fixed_questions.add(self.question) + user_answer = "def add(a, b)\n\treturn a+b" + self.new_answer = Answer(question=self.question, answer=user_answer, + correct=True, error=json.dumps([]), marks=0.5) + self.new_answer.save() + self.answerpaper = AnswerPaper.objects.create( + user=self.student, question_paper=self.question_paper, + attempt_number=1, + 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 + ) + self.answerpaper.answers.add(self.new_answer) + self.answerpaper.questions_answered.add(self.question) + self.answerpaper.questions.add(self.question) + def tearDown(self): self.client.logout() self.user.delete() self.student.delete() self.quiz.delete() - self.pre_req_quiz.delete() self.course.delete() + self.answerpaper.delete() + self.question.delete() + self.question_paper.delete() + self.new_answer.delete() - def test_remove_teacher_denies_anonymous(self): + def test_grade_user_display_quizzes(self): """ - If not logged in redirect to login page + Check all the available quizzes in grade user """ - response = self.client.get(reverse('yaksh:remove_teacher', - kwargs={'course_id': self.course.id} - ), - follow=True + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass ) - redirect_destination = ('/exam/login/?next=/exam' - '/manage/remove_teachers/{0}/'.format(self.course.id)) - self.assertRedirects(response, redirect_destination) + response = self.client.get(reverse('yaksh:grade_user'), + follow=True + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/grade_user.html") + self.assertEqual(response.context['course_details'][0], self.course) - def test_remove_teacher_denies_non_moderator(self): + def test_grade_user_get_quiz_users(self): """ - If not moderator redirect to login page + Check all the available users in quiz in grade user """ self.client.login( - username=self.student.username, - password=self.student_plaintext_pass - ) - - response = self.client.get(reverse('yaksh:remove_teacher', - kwargs={'course_id': self.course.id} - ), - follow=True + username=self.user.username, + password=self.user_plaintext_pass ) - self.assertEqual(response.status_code, 404) + response = self.client.get(reverse('yaksh:grade_user', + kwargs={"quiz_id": self.quiz.id}), + follow=True + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/grade_user.html") + self.assertEqual(response.context['users'][0]['user__first_name'], + self.student.first_name) + self.assertEqual(response.context['quiz'], self.quiz) + self.assertFalse(response.context['has_quiz_assignments']) - def test_remove_teacher_post(self): + def test_grade_user_get_quiz_user_data(self): """ - POST request should remove moderator from course + Check student attempts and answers """ - teacher_id_list = [] self.client.login( username=self.user.username, password=self.user_plaintext_pass ) + response = self.client.get(reverse('yaksh:grade_user', + kwargs={"quiz_id": self.quiz.id, + "user_id": self.student.id}), + follow=True + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/grade_user.html") + self.assertFalse(response.context['has_user_assignments']) + self.assertEqual(response.context['quiz_id'], str(self.quiz.id)) + self.assertEqual(response.context['user_id'], str(self.student.id)) + self.assertEqual(response.context['attempts'][0], self.answerpaper) - for i in range(5): - teacher = User.objects.create_user( - username='remove_teacher{}'.format(i), - password='remove_teacher_pass{}'.format(i), - first_name='remove_teacher_first_name{}'.format(i), - last_name='remove_teacher_last_name{}'.format(i), - email='remove_teacher{}@test.com'.format(i) - ) - - teacher_profile = Profile.objects.create( - user=teacher, - roll_number='RT{}'.format(i), - institute='IIT', - department='Aeronautical', - position='Teacher', - timezone='UTC' - ) - teacher_id_list.append(teacher.id) - self.course.teachers.add(teacher) - - response = self.client.post(reverse('yaksh:remove_teacher', - kwargs={'course_id': self.course.id} - ), - data={'remove': teacher_id_list} - ) - - self.assertEqual(response.status_code, 302) - redirect_destination = '/exam/manage/courses' - self.assertRedirects(response, redirect_destination, - status_code=302, - target_status_code=301 + def test_grade_user_update_user_marks(self): + """ + Check update marks of student + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass ) - for t_id in teacher_id_list: - teacher = User.objects.get(id=t_id) - self.assertNotIn(teacher, self.course.teachers.all()) + self.client.get(reverse('yaksh:grade_user', + kwargs={"quiz_id": self.quiz.id, + "user_id": self.student.id}), + follow=True + ) + question_marks = "q{0}_marks".format(self.question.id) + response = self.client.post(reverse('yaksh:grade_user', + kwargs={"quiz_id": self.quiz.id, + "user_id": self.student.id, + "attempt_number": self.answerpaper.attempt_number}), + data={question_marks: 1.0} + ) + + updated_ans_paper = AnswerPaper.objects.get(user=self.student, + question_paper=self.question_paper, + attempt_number=self.answerpaper.attempt_number + ) + updated_ans = Answer.objects.get(question=self.question) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/grade_user.html") + self.assertEqual(updated_ans.marks, 1.0) + self.assertEqual(updated_ans_paper.marks_obtained, 1.0) -class TestCourses(TestCase): +class TestDownloadAssignment(TestCase): def setUp(self): self.client = Client() self.mod_group = Group.objects.create(name='moderator') + tzone = pytz.timezone('UTC') # Create Moderator with profile - self.user1_plaintext_pass = 'demo1' - self.user1 = User.objects.create_user( - username='demo_user1', - password=self.user1_plaintext_pass, - first_name='user1_first_name', - last_name='user1_last_name', + 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.user1, + user=self.user, roll_number=10, institute='IIT', department='Chemical', @@ -720,102 +687,136 @@ class TestCourses(TestCase): timezone='UTC' ) - self.user2_plaintext_pass = 'demo2' - self.user2 = User.objects.create_user( - username='demo_user2', - password=self.user2_plaintext_pass, - first_name='user2_first_name', - last_name='user2_last_name', - email='demo2@test.com' + # Create Student 1 + self.student1_plaintext_pass = 'demo_student1' + self.student1 = User.objects.create_user( + username='demo_student1', + password=self.student1_plaintext_pass, + first_name='student1_first_name', + last_name='student1_last_name', + email='demo_student1@test.com' ) - Profile.objects.create( - user=self.user2, - roll_number=10, - institute='IIT', - department='Aeronautical', - position='Moderator', - timezone='UTC' + # Create Student 2 + self.student2_plaintext_pass = 'demo_student2' + self.student2 = User.objects.create_user( + username='demo_student2', + password=self.student2_plaintext_pass, + first_name='student2_first_name', + last_name='student2_last_name', + email='demo_student2@test.com' ) - # Create Student - self.student_plaintext_pass = 'demo_student' - self.student = User.objects.create_user( - username='demo_student', - password=self.student_plaintext_pass, - first_name='student_first_name', - last_name='student_last_name', - email='demo_student@test.com' + self.course = Course.objects.create(name="Python Course", + enrollment="Enroll Request", 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, + language='Python', course=self.course ) - # Add to moderator group - self.mod_group.user_set.add(self.user1) - self.mod_group.user_set.add(self.user2) + self.question = Question.objects.create( + summary="Test_question", description="Assignment Upload", + points=1.0, language="python", type="upload", user=self.user + ) - self.user1_course = Course.objects.create(name="Python Course", - enrollment="Enroll Request", creator=self.user1) + self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, + total_marks=1.0, fixed_question_order=str(self.question.id) + ) + self.question_paper.fixed_questions.add(self.question) - self.user2_course = Course.objects.create(name="Java Course", - enrollment="Enroll Request", creator=self.user2) + # create assignment file + assignment_file1 = SimpleUploadedFile("file1.txt", b"Test") + assignment_file2 = SimpleUploadedFile("file2.txt", b"Test") + assignment_file3 = SimpleUploadedFile("file3.txt", b"Test") + self.assignment1 = AssignmentUpload.objects.create(user=self.student1, + assignmentQuestion=self.question, + assignmentFile=assignment_file1, + question_paper=self.question_paper + ) + self.assignment2 = AssignmentUpload.objects.create(user=self.student2, + assignmentQuestion=self.question, + assignmentFile=assignment_file2, + question_paper=self.question_paper + ) def tearDown(self): self.client.logout() - self.user1.delete() - self.user2.delete() - self.student.delete() - self.user1_course.delete() - self.user2_course.delete() - - def test_courses_denies_anonymous(self): - """ - If not logged in redirect to login page - """ - response = self.client.get(reverse('yaksh:courses'), - follow=True - ) - redirect_destination = ('/exam/login/?next=/exam' - '/manage/courses/') - self.assertRedirects(response, redirect_destination) + self.user.delete() + self.student1.delete() + self.student2.delete() + self.assignment1.delete() + self.assignment2.delete() + self.quiz.delete() + self.course.delete() + dir_name = self.quiz.description.replace(" ", "_") + file_path = os.sep.join((settings.MEDIA_ROOT, dir_name)) + if os.path.exists(file_path): + shutil.rmtree(file_path) - def test_courses_denies_non_moderator(self): + def test_download_assignment_per_quiz(self): """ - If not moderator redirect to login page + Check for download assignments per quiz """ self.client.login( - username=self.student.username, - password=self.student_plaintext_pass - ) - - response = self.client.get(reverse('yaksh:courses'), - follow=True + username=self.user.username, + password=self.user_plaintext_pass ) - self.assertEqual(response.status_code, 404) + response = self.client.get(reverse('yaksh:download_quiz_assignment', + kwargs={'quiz_id': self.quiz.id}), + follow=True + ) + file_name = "{0}_Assignment_files.zip".format(self.quiz.description) + file_name = file_name.replace(" ", "_") + self.assertEqual(response.status_code, 200) + self.assertEqual(response.get('Content-Disposition'), + "attachment; filename={0}".format(file_name)) + zip_file = string_io(response.content) + zipped_file = zipfile.ZipFile(zip_file, 'r') + self.assertIsNone(zipped_file.testzip()) + self.assertIn('file1.txt', zipped_file.namelist()[0]) + self.assertIn('file2.txt', zipped_file.namelist()[1]) + zip_file.close() + zipped_file.close() - def test_courses_get(self): + def test_download_assignment_per_user(self): """ - GET request should return courses page + Check for download assignments per quiz """ self.client.login( - username=self.user1.username, - password=self.user1_plaintext_pass - ) - response = self.client.get(reverse('yaksh:courses'), - follow=True + username=self.user.username, + password=self.user_plaintext_pass ) - + response = self.client.get(reverse('yaksh:download_user_assignment', + kwargs={'quiz_id': self.quiz.id, + 'question_id': self.question.id, + 'user_id': self.student2.id + }), + follow=True + ) + file_name = "{0}.zip".format(self.student2.get_full_name()) + file_name = file_name.replace(" ", "_") self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'yaksh/courses.html') - self.assertIn(self.user1_course, response.context['courses']) - self.assertNotIn(self.user2_course, response.context['courses']) + self.assertEqual(response.get('Content-Disposition'), + "attachment; filename={0}".format(file_name)) + zip_file = string_io(response.content) + zipped_file = zipfile.ZipFile(zip_file, 'r') + self.assertIsNone(zipped_file.testzip()) + self.assertIn('file2.txt', zipped_file.namelist()[0]) + zip_file.close() + zipped_file.close() -class TestAddCourse(TestCase): +class TestAddQuiz(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( @@ -854,7 +855,7 @@ class TestAddCourse(TestCase): 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, + 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, @@ -864,7 +865,7 @@ class TestAddCourse(TestCase): 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, + 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, @@ -879,18 +880,18 @@ class TestAddCourse(TestCase): self.pre_req_quiz.delete() self.course.delete() - def test_add_course_denies_anonymous(self): + def test_add_quiz_denies_anonymous(self): """ If not logged in redirect to login page """ - response = self.client.get(reverse('yaksh:add_course'), + response = self.client.get(reverse('yaksh:add_quiz', + kwargs={'course_id': self.course.id}), follow=True ) - redirect_destination = ('/exam/login/?next=/' - 'exam/manage/add_course/') + redirect_destination = '/exam/login/?next=/exam/manage/addquiz/{0}/'.format(self.course.id) self.assertRedirects(response, redirect_destination) - def test_add_course_denies_non_moderator(self): + def test_add_quiz_denies_non_moderator(self): """ If not moderator in redirect to login page """ @@ -899,68 +900,141 @@ class TestAddCourse(TestCase): password=self.student_plaintext_pass ) course_id = self.course.id - response = self.client.get(reverse('yaksh:add_course'), + response = self.client.get(reverse('yaksh:add_quiz', + kwargs={'course_id': self.course.id}), follow=True ) self.assertEqual(response.status_code, 404) - def test_add_course_get(self): + def test_add_quiz_get(self): """ - GET request to add course should display add course form + GET request to add question should display add quiz form """ self.client.login( username=self.user.username, password=self.user_plaintext_pass ) - response = self.client.get(reverse('yaksh:add_course')) + response = self.client.get(reverse('yaksh:add_quiz', + kwargs={'course_id': self.course.id}) + ) self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'yaksh/add_course.html') + self.assertTemplateUsed(response, 'yaksh/add_quiz.html') self.assertIsNotNone(response.context['form']) - def test_add_course_post_new_course(self): + def test_add_quiz_post_existing_quiz(self): """ - POST request to add course should add new courses if no course exists + POST request to add quiz should edit quiz if quiz exists """ self.client.login( username=self.user.username, password=self.user_plaintext_pass ) + tzone = pytz.timezone('UTC') + response = self.client.post(reverse('yaksh:edit_quiz', + kwargs={'course_id':self.course.id, 'quiz_id': self.quiz.id}), + data={ + 'start_date_time': '2016-01-10 09:00:15', + 'end_date_time': '2016-01-15 09:00:15', + 'duration': 30, + 'active': False, + 'attempts_allowed': 5, + '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 + } + ) - response = self.client.post(reverse('yaksh:add_course'), - data={'name': 'new_demo_course_1', + updated_quiz = Quiz.objects.get(id=self.quiz.id) + self.assertEqual(updated_quiz.start_date_time, + datetime(2016, 1, 10, 9, 0, 15, 0, tzone) + ) + self.assertEqual(updated_quiz.end_date_time, + datetime(2016, 1, 15, 9, 0, 15, 0, tzone) + ) + self.assertEqual(updated_quiz.duration, 30) + self.assertEqual(updated_quiz.active, False) + self.assertEqual(updated_quiz.attempts_allowed, 5) + 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/') + + def test_add_quiz_post_new_quiz(self): + """ + POST request to add quiz should add new quiz if no quiz exists + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + + tzone = pytz.timezone('UTC') + response = self.client.post(reverse('yaksh:add_quiz', kwargs={"course_id": self.course.id}), + data={ + 'start_date_time': '2016-01-10 09:00:15', + 'end_date_time': '2016-01-15 09:00:15', + 'duration': 50, 'active': True, - 'enrollment': 'open', - 'start_enroll_time': '2016-01-10 09:00:15', - 'end_enroll_time': '2016-01-15 09:00:15', + 'attempts_allowed': -1, + '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 } ) - course_list = Course.objects.all().order_by('-id') - new_course = course_list[0] - self.assertEqual(new_course.name, 'new_demo_course_1') - self.assertEqual(new_course.enrollment, 'open') - self.assertEqual(new_course.active, True) + quiz_list = Quiz.objects.all().order_by('-id') + new_quiz = quiz_list[0] + self.assertEqual(new_quiz.start_date_time, + datetime(2016, 1, 10, 9, 0, 15, 0, tzone) + ) + self.assertEqual(new_quiz.end_date_time, + datetime(2016, 1, 15, 9, 0, 15, 0, tzone) + ) + self.assertEqual(new_quiz.duration, 50) + self.assertEqual(new_quiz.active, True) + self.assertEqual(new_quiz.attempts_allowed, -1) + 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/') + self.assertRedirects(response, '/exam/manage/courses/') -class TestCourseDetail(TestCase): +class TestAddTeacher(TestCase): def setUp(self): self.client = Client() self.mod_group = Group.objects.create(name='moderator') + tzone = pytz.timezone('UTC') # Create Moderator with profile - self.user1_plaintext_pass = 'demo1' - self.user1 = User.objects.create_user( - username='demo_user1', - password=self.user1_plaintext_pass, - first_name='user1_first_name', - last_name='user1_last_name', + 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.user1, + user=self.user, roll_number=10, institute='IIT', department='Chemical', @@ -968,24 +1042,6 @@ class TestCourseDetail(TestCase): timezone='UTC' ) - self.user2_plaintext_pass = 'demo2' - self.user2 = User.objects.create_user( - username='demo_user2', - password=self.user2_plaintext_pass, - first_name='user2_first_name', - last_name='user2_last_name', - email='demo2@test.com' - ) - - Profile.objects.create( - user=self.user2, - roll_number=10, - institute='IIT', - department='Aeronautical', - position='Moderator', - timezone='UTC' - ) - # Create Student self.student_plaintext_pass = 'demo_student' self.student = User.objects.create_user( @@ -997,87 +1053,278 @@ class TestCourseDetail(TestCase): ) # 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.user) - self.user1_course = Course.objects.create(name="Python Course", - enrollment="Enroll Request", creator=self.user1) + 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, + 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, + attempts_allowed=-1, time_between_attempts=0, + description='demo quiz', pass_criteria=40, + language='Python', prerequisite=self.pre_req_quiz, + course=self.course + ) def tearDown(self): self.client.logout() - self.user1.delete() - self.user2.delete() + self.user.delete() self.student.delete() - self.user1_course.delete() + self.quiz.delete() + self.pre_req_quiz.delete() + self.course.delete() - def test_course_detail_denies_anonymous(self): + def test_add_teacher_denies_anonymous(self): """ If not logged in redirect to login page """ - response = self.client.get(reverse('yaksh:course_detail', - kwargs={'course_id': self.user1_course.id} + response = self.client.get(reverse('yaksh:add_teacher', + kwargs={'course_id': self.course.id} ), follow=True ) - redirect_destination = ('/exam/login/?next=/exam/' - 'manage/course_detail/1/') + redirect_destination = ('/exam/login/?next=/exam' + '/manage/addteacher/{0}/'.format(self.course.id)) self.assertRedirects(response, redirect_destination) - def test_course_detail_denies_non_moderator(self): + def test_add_teacher_denies_non_moderator(self): """ - If not moderator redirect to 404 + If not moderator redirect to login page """ self.client.login( username=self.student.username, password=self.student_plaintext_pass ) - response = self.client.get(reverse('yaksh:course_detail', - kwargs={'course_id': self.user1_course.id} + response = self.client.get(reverse('yaksh:add_teacher', + kwargs={'course_id': self.course.id} ), follow=True ) self.assertEqual(response.status_code, 404) - def test_course_detail_denies_unrelated_moderators(self): + def test_add_teacher_get(self): """ - If not creator of course or related teacher redirect to 404 + GET request to add teacher should display list of teachers """ self.client.login( - username=self.user2.username, - password=self.user2_plaintext_pass + username=self.user.username, + password=self.user_plaintext_pass ) - response = self.client.get(reverse('yaksh:course_detail', - kwargs={'course_id': self.user1_course.id} - ), - follow=True + response = self.client.get(reverse('yaksh:add_teacher', + kwargs={'course_id': self.course.id} + ) ) - self.assertEqual(response.status_code, 404) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/addteacher.html') + self.assertEqual(response.context['course'], self.course) - def test_course_detail_get(self): + def test_add_teacher_post(self): """ - If not creator of course or related teacher redirect to 404 + POST request to add teacher should add teachers to a course """ self.client.login( - username=self.user1.username, - password=self.user1_plaintext_pass - ) - response = self.client.get(reverse('yaksh:course_detail', - kwargs={'course_id': self.user1_course.id} - ), - follow=True + username=self.user.username, + password=self.user_plaintext_pass ) - self.assertEqual(self.user1_course, response.context['course']) - self.assertEqual(response.status_code, 200) - self.assertTemplateUsed(response, 'yaksh/course_detail.html') - + teacher_id_list = [] -class TestEnrollRequest(TestCase): - def setUp(self): - self.client = Client() + for i in range(5): + teacher = User.objects.create_user( + username='demo_teacher{}'.format(i), + password='demo_teacher_pass{}'.format(i), + first_name='teacher_first_name{}'.format(i), + last_name='teacher_last_name{}'.format(i), + email='demo{}@test.com'.format(i) + ) - self.mod_group = Group.objects.create(name='moderator') + teacher_profile = Profile.objects.create( + user=teacher, + roll_number='T{}'.format(i), + institute='IIT', + department='Chemical', + position='Teacher', + timezone='UTC' + ) + teacher_id_list.append(teacher.id) + + response = self.client.post(reverse('yaksh:add_teacher', + kwargs={'course_id': self.course.id} + ), + data={'check': teacher_id_list} + ) + + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/addteacher.html') + self.assertEqual(response.context['status'], True) + for t_id in teacher_id_list: + teacher_object = User.objects.get(id=t_id) + self.assertIn(teacher_object, response.context['teachers_added']) + self.assertIn(teacher_object, self.course.teachers.all()) + + +class TestRemoveTeacher(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 Student + self.student_plaintext_pass = 'demo_student' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='student_first_name', + last_name='student_last_name', + email='demo_student@test.com' + ) + + # Add to moderator group + self.mod_group.user_set.add(self.user) + + 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, + 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, + attempts_allowed=-1, time_between_attempts=0, + description='demo quiz', pass_criteria=40, + language='Python', prerequisite=self.pre_req_quiz, + course=self.course + ) + def tearDown(self): + self.client.logout() + self.user.delete() + self.student.delete() + self.quiz.delete() + self.pre_req_quiz.delete() + self.course.delete() + + def test_remove_teacher_denies_anonymous(self): + """ + If not logged in redirect to login page + """ + response = self.client.get(reverse('yaksh:remove_teacher', + kwargs={'course_id': self.course.id} + ), + follow=True + ) + redirect_destination = ('/exam/login/?next=/exam' + '/manage/remove_teachers/{0}/'.format(self.course.id)) + self.assertRedirects(response, redirect_destination) + + def test_remove_teacher_denies_non_moderator(self): + """ + If not moderator redirect to login page + """ + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + response = self.client.get(reverse('yaksh:remove_teacher', + kwargs={'course_id': self.course.id} + ), + follow=True + ) + self.assertEqual(response.status_code, 404) + + def test_remove_teacher_post(self): + """ + POST request should remove moderator from course + """ + teacher_id_list = [] + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + + for i in range(5): + teacher = User.objects.create_user( + username='remove_teacher{}'.format(i), + password='remove_teacher_pass{}'.format(i), + first_name='remove_teacher_first_name{}'.format(i), + last_name='remove_teacher_last_name{}'.format(i), + email='remove_teacher{}@test.com'.format(i) + ) + + teacher_profile = Profile.objects.create( + user=teacher, + roll_number='RT{}'.format(i), + institute='IIT', + department='Aeronautical', + position='Teacher', + timezone='UTC' + ) + teacher_id_list.append(teacher.id) + self.course.teachers.add(teacher) + + response = self.client.post(reverse('yaksh:remove_teacher', + kwargs={'course_id': self.course.id} + ), + data={'remove': teacher_id_list} + ) + + self.assertEqual(response.status_code, 302) + redirect_destination = '/exam/manage/courses' + self.assertRedirects(response, redirect_destination, + status_code=302, + target_status_code=301 + ) + for t_id in teacher_id_list: + teacher = User.objects.get(id=t_id) + self.assertNotIn(teacher, self.course.teachers.all()) + +class TestCourses(TestCase): + def setUp(self): + self.client = Client() + + self.mod_group = Group.objects.create(name='moderator') # Create Moderator with profile self.user1_plaintext_pass = 'demo1' self.user1 = User.objects.create_user( @@ -1129,202 +1376,203 @@ class TestEnrollRequest(TestCase): self.mod_group.user_set.add(self.user1) self.mod_group.user_set.add(self.user2) - self.course = Course.objects.create(name="Python Course", + self.user1_course = Course.objects.create(name="Python Course", enrollment="Enroll Request", creator=self.user1) + self.user2_course = Course.objects.create(name="Java Course", + enrollment="Enroll Request", creator=self.user2) + def tearDown(self): self.client.logout() self.user1.delete() self.user2.delete() self.student.delete() - self.course.delete() + self.user1_course.delete() + self.user2_course.delete() - def test_enroll_request_denies_anonymous(self): + def test_courses_denies_anonymous(self): """ If not logged in redirect to login page """ - response = self.client.get(reverse('yaksh:enroll_request', - kwargs={'course_id': self.course.id} - ), + response = self.client.get(reverse('yaksh:courses'), follow=True ) redirect_destination = ('/exam/login/?next=/exam' - '/enroll_request/{}/'.format(self.course.id)) + '/manage/courses/') self.assertRedirects(response, redirect_destination) - def test_enroll_request_get_for_student(self): + def test_courses_denies_non_moderator(self): + """ + If not moderator redirect to login page + """ self.client.login( username=self.student.username, password=self.student_plaintext_pass ) - response = self.client.get(reverse('yaksh:enroll_request', - kwargs={'course_id': self.course.id} - ), + response = self.client.get(reverse('yaksh:courses'), follow=True ) - self.assertRedirects(response, '/exam/quizzes/') + self.assertEqual(response.status_code, 404) - def test_enroll_request_get_for_moderator(self): + def test_courses_get(self): + """ + GET request should return courses page + """ self.client.login( - username=self.user2.username, - password=self.user2_plaintext_pass + username=self.user1.username, + password=self.user1_plaintext_pass ) - - response = self.client.get(reverse('yaksh:enroll_request', - kwargs={'course_id': self.course.id} - ), + response = self.client.get(reverse('yaksh:courses'), follow=True ) - self.assertRedirects(response, '/exam/manage/courses/') + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/courses.html') + self.assertIn(self.user1_course, response.context['courses']) + self.assertNotIn(self.user2_course, response.context['courses']) -class TestViewAnswerPaper(TestCase): + +class TestAddCourse(TestCase): def setUp(self): self.client = Client() - self.plaintext_pass = 'demo' - for i in range(1, 4): - User.objects.create_user( - username='demo_user{0}'.format(i), - password=self.plaintext_pass, - first_name='first_name', - last_name='last_name', - email='demo@test.com' - ) + self.mod_group = Group.objects.create(name='moderator') + tzone = pytz.timezone('UTC') - self.user1 = User.objects.get(pk=1) + # 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' + ) - self.course = Course.objects.create(name="Python Course", - enrollment="Enroll Request", - creator=self.user1) + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) - 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.question_paper = QuestionPaper.objects.create(quiz=self.quiz, - total_marks=1.0) - self.question_paper.fixed_questions.add(self.question) - self.question_paper.save() - - AnswerPaper.objects.create(user_id=3, - 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)) + # Create Student + self.student_plaintext_pass = 'demo_student' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='student_first_name', + last_name='student_last_name', + email='demo_student@test.com' + ) - def tearDown(self): - User.objects.all().delete() - Course.objects.all().delete() - Question.objects.all().delete() - Quiz.objects.all().delete() - QuestionPaper.objects.all().delete() - AnswerPaper.objects.all().delete() + # Add to moderator group + self.mod_group.user_set.add(self.user) - def test_anonymous_user(self): - # Given, user not logged in - redirect_destination = ('/exam/login/?next=/exam' - '/view_answerpaper/{0}/'.format(self.question_paper.id)) + self.course = Course.objects.create(name="Python Course", + enrollment="Enroll Request", creator=self.user) - # When - response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} - ), - follow=True + 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, + attempts_allowed=-1, time_between_attempts=0, + description='pre requisite quiz', pass_criteria=40, + language='Python', prerequisite=None, + course=self.course ) - # Then - self.assertRedirects(response, redirect_destination) - - def test_cannot_view(self): - # Given, enrolled user tries to view when not permitted by moderator - user2 = User.objects.get(pk=2) - self.course.students.add(user2) - self.course.save() - self.quiz.view_answerpaper = False - self.quiz.save() - self.client.login( - username=user2.username, - password=self.plaintext_pass + 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, + attempts_allowed=-1, time_between_attempts=0, + description='demo quiz', pass_criteria=40, + language='Python', prerequisite=self.pre_req_quiz, + course=self.course ) - # When - response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} - ), - follow=True - ) + def tearDown(self): + self.client.logout() + self.user.delete() + self.student.delete() + self.quiz.delete() + self.pre_req_quiz.delete() + self.course.delete() - # Then - self.assertRedirects(response, '/exam/quizzes/') + def test_add_course_denies_anonymous(self): + """ + If not logged in redirect to login page + """ + response = self.client.get(reverse('yaksh:add_course'), + follow=True + ) + redirect_destination = ('/exam/login/?next=/' + 'exam/manage/add_course/') + self.assertRedirects(response, redirect_destination) - def test_can_view(self): - # Given, user enrolled and can view - user3 = User.objects.get(pk=3) - self.course.students.add(user3) - self.course.save() - answerpaper = AnswerPaper.objects.get(pk=1) - self.quiz.view_answerpaper = True - self.quiz.save() + def test_add_course_denies_non_moderator(self): + """ + If not moderator in redirect to login page + """ self.client.login( - username=user3.username, - password=self.plaintext_pass + username=self.student.username, + password=self.student_plaintext_pass ) + course_id = self.course.id + response = self.client.get(reverse('yaksh:add_course'), + follow=True + ) + self.assertEqual(response.status_code, 404) - # When - response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} - ), - follow=True + def test_add_course_get(self): + """ + GET request to add course should display add course form + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass ) - - # Then + response = self.client.get(reverse('yaksh:add_course')) self.assertEqual(response.status_code, 200) - self.assertTrue('data' in response.context) - self.assertTrue('quiz' in response.context) - self.assertTemplateUsed(response, 'yaksh/view_answerpaper.html') - - - # When, wrong question paper id - response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': 190} - ), - follow=True - ) - - # Then - self.assertEqual(response.status_code, 404) - + self.assertTemplateUsed(response, 'yaksh/add_course.html') + self.assertIsNotNone(response.context['form']) - def test_view_when_not_enrolled(self): - # Given, user tries to view when not enrolled in the course - user2 = User.objects.get(pk=2) + def test_add_course_post_new_course(self): + """ + POST request to add course should add new courses if no course exists + """ self.client.login( - username=user2.username, - password=self.plaintext_pass + username=self.user.username, + password=self.user_plaintext_pass ) - self.course.students.remove(user2) - self.course.save() - self.quiz.view_answerpaper = True - self.quiz.save() - # When - response = self.client.get(reverse('yaksh:view_answerpaper', - kwargs={'questionpaper_id': self.question_paper.id} - ), - follow=True + response = self.client.post(reverse('yaksh:add_course'), + data={'name': 'new_demo_course_1', + 'active': True, + 'enrollment': 'open', + 'start_enroll_time': '2016-01-10 09:00:15', + 'end_enroll_time': '2016-01-15 09:00:15', + } ) - - # Then - self.assertRedirects(response, '/exam/quizzes/') + course_list = Course.objects.all().order_by('-id') + new_course = course_list[0] + self.assertEqual(new_course.name, 'new_demo_course_1') + self.assertEqual(new_course.enrollment, 'open') + self.assertEqual(new_course.active, True) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, '/exam/manage/') -class TestSelfEnroll(TestCase): +class TestCourseDetail(TestCase): def setUp(self): self.client = Client() + self.mod_group = Group.objects.create(name='moderator') + # Create Moderator with profile self.user1_plaintext_pass = 'demo1' self.user1 = User.objects.create_user( @@ -1371,12 +1619,20 @@ class TestSelfEnroll(TestCase): last_name='student_last_name', email='demo_student@test.com' ) + self.student1_plaintext_pass = 'demo_student1' + self.student1 = User.objects.create_user( + username='demo_student1', + password=self.student1_plaintext_pass, + first_name='student_first_name', + last_name='student_last_name', + email='demo_student1@test.com' + ) # Add to moderator group self.mod_group.user_set.add(self.user1) self.mod_group.user_set.add(self.user2) - self.course = Course.objects.create(name="Python Course", + self.user1_course = Course.objects.create(name="Python Course", enrollment="Enroll Request", creator=self.user1) def tearDown(self): @@ -1384,46 +1640,147 @@ class TestSelfEnroll(TestCase): self.user1.delete() self.user2.delete() self.student.delete() - self.course.delete() + self.user1_course.delete() - def test_self_enroll_denies_anonymous(self): - response = self.client.get(reverse('yaksh:self_enroll', - kwargs={'course_id': self.course.id} + def test_course_detail_denies_anonymous(self): + """ + If not logged in redirect to login page + """ + response = self.client.get(reverse('yaksh:course_detail', + kwargs={'course_id': self.user1_course.id} ), follow=True ) - redirect_destination = ('/exam/login/?next=/exam' - '/self_enroll/{}/'.format(self.course.id)) + redirect_destination = ('/exam/login/?next=/exam/' + 'manage/course_detail/1/') self.assertRedirects(response, redirect_destination) - def test_enroll_request_get_for_student(self): + def test_course_detail_denies_non_moderator(self): + """ + If not moderator redirect to 404 + """ self.client.login( username=self.student.username, password=self.student_plaintext_pass ) - response = self.client.get(reverse('yaksh:self_enroll', - kwargs={'course_id': self.course.id} + response = self.client.get(reverse('yaksh:course_detail', + kwargs={'course_id': self.user1_course.id} ), follow=True ) - self.assertRedirects(response, '/exam/quizzes/') + self.assertEqual(response.status_code, 404) - def test_enroll_request_get_for_moderator(self): + def test_course_detail_denies_unrelated_moderators(self): + """ + If not creator of course or related teacher redirect to 404 + """ self.client.login( username=self.user2.username, password=self.user2_plaintext_pass ) + response = self.client.get(reverse('yaksh:course_detail', + kwargs={'course_id': self.user1_course.id} + ), + follow=True + ) + self.assertEqual(response.status_code, 404) - response = self.client.get(reverse('yaksh:self_enroll', - kwargs={'course_id': self.course.id} + def test_course_detail_get(self): + """ + If not creator of course or related teacher redirect to 404 + """ + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + response = self.client.get(reverse('yaksh:course_detail', + kwargs={'course_id': self.user1_course.id} ), follow=True ) - self.assertRedirects(response, '/exam/manage/') + self.assertEqual(self.user1_course, response.context['course']) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/course_detail.html') + def test_student_course_enroll_get(self): + """ + Enroll student in a course using get request + """ + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + response = self.client.get(reverse('yaksh:enroll_user', + kwargs={'course_id': self.user1_course.id, + 'user_id': self.student.id}) + ) + enrolled_student = self.user1_course.students.all() + self.assertEqual(response.status_code, 200) + self.assertSequenceEqual([self.student], enrolled_student) -class TestGrader(TestCase): + def test_student_course_enroll_post(self): + """ + Enroll student in a course using post request + """ + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + response = self.client.post(reverse('yaksh:enroll_users', + kwargs={'course_id': self.user1_course.id}), + data={'check': self.student1.id} + ) + enrolled_student = self.user1_course.students.all() + self.assertEqual(response.status_code, 200) + self.assertSequenceEqual([self.student1], enrolled_student) + + def test_student_course_reject_get(self): + """ + Reject student in a course using get request + """ + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + response = self.client.get(reverse('yaksh:reject_user', + kwargs={'course_id': self.user1_course.id, + 'user_id': self.student.id}) + ) + enrolled_student = self.user1_course.rejected.all() + self.assertEqual(response.status_code, 200) + self.assertSequenceEqual([self.student], enrolled_student) + + def test_student_course_reject_post(self): + """ + Reject student in a course using post request + """ + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + response = self.client.post(reverse('yaksh:reject_users', + kwargs={'course_id': self.user1_course.id}), + data={'check': self.student1.id} + ) + enrolled_student = self.user1_course.rejected.all() + self.assertEqual(response.status_code, 200) + self.assertSequenceEqual([self.student1], enrolled_student) + + def test_toggle_course_status_get(self): + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + response = self.client.post(reverse('yaksh:toggle_course_status', + kwargs={'course_id': self.user1_course.id}) + ) + self.assertEqual(response.status_code, 200) + course = Course.objects.get(name="Python Course") + self.assertFalse(course.active) + + +class TestEnrollRequest(TestCase): def setUp(self): self.client = Client() @@ -1483,6 +1840,73 @@ class TestGrader(TestCase): self.course = Course.objects.create(name="Python Course", enrollment="Enroll Request", creator=self.user1) + def tearDown(self): + self.client.logout() + self.user1.delete() + self.user2.delete() + self.student.delete() + self.course.delete() + + def test_enroll_request_denies_anonymous(self): + """ + If not logged in redirect to login page + """ + response = self.client.get(reverse('yaksh:enroll_request', + kwargs={'course_id': self.course.id} + ), + follow=True + ) + redirect_destination = ('/exam/login/?next=/exam' + '/enroll_request/{}/'.format(self.course.id)) + self.assertRedirects(response, redirect_destination) + + def test_enroll_request_get_for_student(self): + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + response = self.client.get(reverse('yaksh:enroll_request', + kwargs={'course_id': self.course.id} + ), + follow=True + ) + self.assertRedirects(response, '/exam/quizzes/') + + def test_enroll_request_get_for_moderator(self): + self.client.login( + username=self.user2.username, + password=self.user2_plaintext_pass + ) + + response = self.client.get(reverse('yaksh:enroll_request', + kwargs={'course_id': self.course.id} + ), + follow=True + ) + self.assertRedirects(response, '/exam/manage/courses/') + + +class TestViewAnswerPaper(TestCase): + def setUp(self): + self.client = Client() + self.plaintext_pass = 'demo' + + for i in range(1, 4): + User.objects.create_user( + username='demo_user{0}'.format(i), + password=self.plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@test.com' + ) + + self.user1 = User.objects.get(pk=1) + + self.course = Course.objects.create(name="Python Course", + enrollment="Enroll Request", + creator=self.user1) + self.question = Question.objects.create(summary='Dummy', points=1, type='code', user=self.user1) @@ -1494,7 +1918,7 @@ class TestGrader(TestCase): self.question_paper.fixed_questions.add(self.question) self.question_paper.save() - self.answerpaper = AnswerPaper.objects.create(user_id=3, + AnswerPaper.objects.create(user_id=3, 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)) @@ -1507,129 +1931,116 @@ class TestGrader(TestCase): QuestionPaper.objects.all().delete() AnswerPaper.objects.all().delete() - def test_grader_denies_anonymous(self): - # Given - redirect_destination = ('/exam/login/?next=/exam/manage/grader/') + def test_anonymous_user(self): + # Given, user not logged in + redirect_destination = ('/exam/login/?next=/exam' + '/view_answerpaper/{0}/'.format(self.question_paper.id)) # When - response = self.client.get(reverse('yaksh:grader'), follow=True) - - # Then - self.assertRedirects(response, redirect_destination) - - - def test_grader_denies_students(self): - # Given - self.client.login( - username=self.student.username, - password=self.student_plaintext_pass + response = self.client.get(reverse('yaksh:view_answerpaper', + kwargs={'questionpaper_id': self.question_paper.id} + ), + follow=True ) - # When - response = self.client.get(reverse('yaksh:grader'), follow=True) - - # Then - self.assertEqual(response.status_code, 404) - - - def test_regrade_denies_anonymous(self): - # Given - redirect_destination = ('/exam/login/?next=/exam/manage/regrade/answerpaper/1/1/1/') - - # When - response = self.client.get(reverse('yaksh:regrade', - kwargs={'course_id': self.course.id, - 'question_id': self.question.id, - 'answerpaper_id': self.answerpaper.id}), - follow=True) - # Then self.assertRedirects(response, redirect_destination) - - def test_regrade_denies_students(self): - # Given + def test_cannot_view(self): + # Given, enrolled user tries to view when not permitted by moderator + user2 = User.objects.get(pk=2) + self.course.students.add(user2) + self.course.save() + self.quiz.view_answerpaper = False + self.quiz.save() self.client.login( - username=self.student.username, - password=self.student_plaintext_pass + username=user2.username, + password=self.plaintext_pass ) # When - response = self.client.get(reverse('yaksh:regrade', - kwargs={'course_id': self.course.id, - 'question_id': self.question.id, - 'answerpaper_id': self.answerpaper.id}), - follow=True) + response = self.client.get(reverse('yaksh:view_answerpaper', + kwargs={'questionpaper_id': self.question_paper.id} + ), + follow=True + ) # Then - self.assertEqual(response.status_code, 404) - + self.assertRedirects(response, '/exam/quizzes/') - def test_grader_by_moderator(self): - # Given + def test_can_view(self): + # Given, user enrolled and can view + user3 = User.objects.get(pk=3) + self.course.students.add(user3) + self.course.save() + answerpaper = AnswerPaper.objects.get(pk=1) + self.quiz.view_answerpaper = True + self.quiz.save() self.client.login( - username=self.user1.username, - password=self.user1_plaintext_pass + username=user3.username, + password=self.plaintext_pass ) # When - response = self.client.get(reverse('yaksh:grader'), - follow=True) + response = self.client.get(reverse('yaksh:view_answerpaper', + kwargs={'questionpaper_id': self.question_paper.id} + ), + follow=True + ) # Then self.assertEqual(response.status_code, 200) - self.assertTrue('courses' in response.context) - self.assertTemplateUsed(response, 'yaksh/regrade.html') + self.assertTrue('data' in response.context) + self.assertTrue('quiz' in response.context) + self.assertTemplateUsed(response, 'yaksh/view_answerpaper.html') - def test_regrade_by_moderator(self): - # Given - self.client.login( - username=self.user1.username, - password=self.user1_plaintext_pass + # When, wrong question paper id + response = self.client.get(reverse('yaksh:view_answerpaper', + kwargs={'questionpaper_id': 190} + ), + follow=True ) - # When - response = self.client.get(reverse('yaksh:regrade', - kwargs={'course_id': self.course.id, - 'question_id': self.question.id, - 'answerpaper_id': self.answerpaper.id}), - follow=True) - # Then - self.assertEqual(response.status_code, 200) - self.assertTrue('courses' in response.context) - self.assertTrue('details' in response.context) - self.assertTemplateUsed(response, 'yaksh/regrade.html') + self.assertEqual(response.status_code, 404) - def test_regrade_denies_moderator_not_in_course(self): - # Given + def test_view_when_not_enrolled(self): + # Given, user tries to view when not enrolled in the course + user2 = User.objects.get(pk=2) self.client.login( - username=self.user2.username, - password=self.user2_plaintext_pass + username=user2.username, + password=self.plaintext_pass ) + self.course.students.remove(user2) + self.course.save() + self.quiz.view_answerpaper = True + self.quiz.save() # When - response = self.client.get(reverse('yaksh:regrade', - kwargs={'course_id': self.course.id, - 'question_id': self.question.id, - 'answerpaper_id': self.answerpaper.id}), - follow=True) + response = self.client.get(reverse('yaksh:view_answerpaper', + kwargs={'questionpaper_id': self.question_paper.id} + ), + follow=True + ) # Then - self.assertEqual(response.status_code, 404) + self.assertRedirects(response, '/exam/quizzes/') -class TestPasswordReset(TestCase): + +class TestSelfEnroll(TestCase): def setUp(self): - # Create User with profile + self.client = Client() + self.mod_group = Group.objects.create(name='moderator') + # Create Moderator with profile self.user1_plaintext_pass = 'demo1' self.user1 = User.objects.create_user( username='demo_user1', password=self.user1_plaintext_pass, - first_name='first_name', - last_name='last_name', - email='demo1@test.com' + first_name='user1_first_name', + last_name='user1_last_name', + email='demo@test.com' ) Profile.objects.create( @@ -1637,33 +2048,232 @@ class TestPasswordReset(TestCase): roll_number=10, institute='IIT', department='Chemical', - position='Student', + position='Moderator', + timezone='UTC' + ) + + self.user2_plaintext_pass = 'demo2' + self.user2 = User.objects.create_user( + username='demo_user2', + password=self.user2_plaintext_pass, + first_name='user2_first_name', + last_name='user2_last_name', + email='demo2@test.com' + ) + + Profile.objects.create( + user=self.user2, + roll_number=10, + institute='IIT', + department='Aeronautical', + position='Moderator', timezone='UTC' ) + # Create Student + self.student_plaintext_pass = 'demo_student' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='student_first_name', + last_name='student_last_name', + email='demo_student@test.com' + ) + + # Add to moderator group + self.mod_group.user_set.add(self.user1) + self.mod_group.user_set.add(self.user2) + + self.course = Course.objects.create(name="Python Course", + enrollment="Enroll Request", creator=self.user1) + def tearDown(self): + self.client.logout() self.user1.delete() + self.user2.delete() + self.student.delete() + self.course.delete() + + def test_self_enroll_denies_anonymous(self): + response = self.client.get(reverse('yaksh:self_enroll', + kwargs={'course_id': self.course.id} + ), + follow=True + ) + redirect_destination = ('/exam/login/?next=/exam' + '/self_enroll/{}/'.format(self.course.id)) + self.assertRedirects(response, redirect_destination) + + def test_enroll_request_get_for_student(self): + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + response = self.client.get(reverse('yaksh:self_enroll', + kwargs={'course_id': self.course.id} + ), + follow=True + ) + self.assertRedirects(response, '/exam/quizzes/') + + def test_enroll_request_get_for_moderator(self): + self.client.login( + username=self.user2.username, + password=self.user2_plaintext_pass + ) + + response = self.client.get(reverse('yaksh:self_enroll', + kwargs={'course_id': self.course.id} + ), + follow=True + ) + self.assertRedirects(response, '/exam/manage/') + + +class TestGrader(TestCase): + def setUp(self): + self.client = Client() + + self.mod_group = Group.objects.create(name='moderator') + + # Create Moderator with profile + self.user1_plaintext_pass = 'demo1' + self.user1 = User.objects.create_user( + username='demo_user1', + password=self.user1_plaintext_pass, + first_name='user1_first_name', + last_name='user1_last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user1, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + + self.user2_plaintext_pass = 'demo2' + self.user2 = User.objects.create_user( + username='demo_user2', + password=self.user2_plaintext_pass, + first_name='user2_first_name', + last_name='user2_last_name', + email='demo2@test.com' + ) + + Profile.objects.create( + user=self.user2, + roll_number=10, + institute='IIT', + department='Aeronautical', + position='Moderator', + timezone='UTC' + ) + + # Create Student + self.student_plaintext_pass = 'demo_student' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='student_first_name', + last_name='student_last_name', + email='demo_student@test.com' + ) + + # Add to moderator group + self.mod_group.user_set.add(self.user1) + self.mod_group.user_set.add(self.user2) + + self.course = Course.objects.create(name="Python Course", + enrollment="Enroll Request", creator=self.user1) + + 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.question_paper = QuestionPaper.objects.create(quiz=self.quiz, + total_marks=1.0) + self.question_paper.fixed_questions.add(self.question) + self.question_paper.save() + + self.answerpaper = AnswerPaper.objects.create(user_id=3, + 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)) + + def tearDown(self): + User.objects.all().delete() + Course.objects.all().delete() + Question.objects.all().delete() + Quiz.objects.all().delete() + QuestionPaper.objects.all().delete() + AnswerPaper.objects.all().delete() + + def test_grader_denies_anonymous(self): + # Given + redirect_destination = ('/exam/login/?next=/exam/manage/grader/') - def test_password_reset_post(self): - """ - POST request to password_reset view should return a valid response - """ # When - response = self.client.post(reverse('password_reset'), - data={ - 'email': self.user1.email, - } + response = self.client.get(reverse('yaksh:grader'), follow=True) + + # Then + self.assertRedirects(response, redirect_destination) + + + def test_grader_denies_students(self): + # Given + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass ) + # When + response = self.client.get(reverse('yaksh:grader'), follow=True) + # Then - self.assertEqual(response.context['email'], self.user1.email) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/reset/password_reset/mail_sent/') + self.assertEqual(response.status_code, 404) - def test_password_change_post(self): - """ - POST request to password_change view should change the user password - """ + + def test_regrade_denies_anonymous(self): + # Given + redirect_destination = ('/exam/login/?next=/exam/manage/regrade/answerpaper/1/1/1/') + + # When + response = self.client.get(reverse('yaksh:regrade', + kwargs={'course_id': self.course.id, + 'question_id': self.question.id, + 'answerpaper_id': self.answerpaper.id}), + follow=True) + + # Then + self.assertRedirects(response, redirect_destination) + + + def test_regrade_denies_students(self): + # Given + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + + # When + response = self.client.get(reverse('yaksh:regrade', + kwargs={'course_id': self.course.id, + 'question_id': self.question.id, + 'answerpaper_id': self.answerpaper.id}), + follow=True) + + # Then + self.assertEqual(response.status_code, 404) + + + def test_grader_by_moderator(self): # Given self.client.login( username=self.user1.username, @@ -1671,18 +2281,763 @@ class TestPasswordReset(TestCase): ) # When - response = self.client.post(reverse('password_change'), - data={ - 'old_password': self.user1_plaintext_pass, - 'new_password1': 'new_demo1_pass', - 'new_password2': 'new_demo1_pass' - } - ) + response = self.client.get(reverse('yaksh:grader'), + follow=True) # Then - self.assertIsNotNone(authenticate(username='demo_user1', password='new_demo1_pass')) - self.assertEqual(response.status_code, 302) - self.assertRedirects(response, '/exam/reset/password_change/done/') + self.assertEqual(response.status_code, 200) + self.assertTrue('courses' in response.context) + self.assertTemplateUsed(response, 'yaksh/regrade.html') - # Finally - self.client.logout() + + def test_regrade_by_moderator(self): + # Given + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + + # When + response = self.client.get(reverse('yaksh:regrade', + kwargs={'course_id': self.course.id, + 'question_id': self.question.id, + 'answerpaper_id': self.answerpaper.id}), + follow=True) + + # Then + self.assertEqual(response.status_code, 200) + self.assertTrue('courses' in response.context) + self.assertTrue('details' in response.context) + self.assertTemplateUsed(response, 'yaksh/regrade.html') + + + def test_regrade_denies_moderator_not_in_course(self): + # Given + self.client.login( + username=self.user2.username, + password=self.user2_plaintext_pass + ) + + # When + response = self.client.get(reverse('yaksh:regrade', + kwargs={'course_id': self.course.id, + 'question_id': self.question.id, + 'answerpaper_id': self.answerpaper.id}), + follow=True) + + # Then + self.assertEqual(response.status_code, 404) + +class TestPasswordReset(TestCase): + def setUp(self): + # Create User with profile + self.user1_plaintext_pass = 'demo1' + self.user1 = User.objects.create_user( + username='demo_user1', + password=self.user1_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo1@test.com' + ) + + Profile.objects.create( + user=self.user1, + roll_number=10, + institute='IIT', + department='Chemical', + position='Student', + timezone='UTC' + ) + + def tearDown(self): + self.user1.delete() + + def test_password_reset_post(self): + """ + POST request to password_reset view should return a valid response + """ + # When + response = self.client.post(reverse('password_reset'), + data={ + 'email': self.user1.email, + } + ) + + # Then + self.assertEqual(response.context['email'], self.user1.email) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, '/exam/reset/password_reset/mail_sent/') + + def test_password_change_post(self): + """ + POST request to password_change view should change the user password + """ + # Given + self.client.login( + username=self.user1.username, + password=self.user1_plaintext_pass + ) + + # When + response = self.client.post(reverse('password_change'), + data={ + 'old_password': self.user1_plaintext_pass, + 'new_password1': 'new_demo1_pass', + 'new_password2': 'new_demo1_pass' + } + ) + + # Then + self.assertIsNotNone(authenticate(username='demo_user1', password='new_demo1_pass')) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, '/exam/reset/password_change/done/') + + # Finally + self.client.logout() + + +class TestModeratorDashboard(TestCase): + def setUp(self): + self.client = Client() + tzone = pytz.timezone("utc") + self.mod_group = Group.objects.create(name='moderator') + # student + self.student_plaintext_pass = 'student' + self.student = User.objects.create_user( + username='student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='student@test.com' + ) + + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='student', + timezone='UTC' + ) + + # moderator + self.user_plaintext_pass = 'demo' + self.user = User.objects.create_user( + username='demo_user', + password=self.user_plaintext_pass, + first_name='user_first_name', + last_name='user_last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + self.mod_group.user_set.add(self.user) + self.course = Course.objects.create(name="Python Course", + enrollment="Enroll Request", 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, + language='Python', course=self.course + ) + + self.question = Question.objects.create( + summary="Test_question", description="Add two numbers", + points=1.0, language="python", type="code", user=self.user + ) + + self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, + total_marks=1.0, fixed_question_order=str(self.question.id) + ) + self.question_paper.fixed_questions.add(self.question) + + # student answerpaper + user_answer = "def add(a, b)\n\treturn a+b" + self.new_answer = Answer(question=self.question, answer=user_answer, + correct=True, error=json.dumps([]), marks=0.5) + self.new_answer.save() + self.answerpaper = AnswerPaper.objects.create( + user=self.student, question_paper=self.question_paper, + attempt_number=1, + 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 + ) + 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_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 + ) + + self.trial_question_paper = QuestionPaper.objects.create( + quiz=self.trial_quiz, + total_marks=1.0, fixed_question_order=str(self.question.id) + ) + self.trial_question_paper.fixed_questions.add(self.question) + + self.new_answer1 = Answer(question=self.question, answer=user_answer, + correct=True, error=json.dumps([]), marks=0.5) + self.new_answer1.save() + self.trial_answerpaper = AnswerPaper.objects.create( + user=self.user, question_paper=self.trial_question_paper, + attempt_number=1, + 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 + ) + self.trial_answerpaper.answers.add(self.new_answer1) + self.trial_answerpaper.questions_answered.add(self.question) + self.trial_answerpaper.questions.add(self.question) + + def tearDown(self): + self.client.logout() + self.user.delete() + self.quiz.delete() + self.question_paper.delete() + self.answerpaper.delete() + self.new_answer.delete() + + def test_moderator_dashboard_get_all_quizzes(self): + """ + Check moderator dashboard to get all the moderator created quizzes + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + + response = self.client.get(reverse('yaksh:manage'), + follow=True + ) + 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) + + def test_moderator_dashboard_delete_trial_papers(self): + """ + Check moderator dashboard to delete trial papers + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + self.course.is_trial=True + self.course.save() + response = self.client.post(reverse('yaksh:manage'), + data={'delete_paper': [self.trial_answerpaper.id]} + ) + + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, "yaksh/moderator_dashboard.html") + updated_answerpaper = AnswerPaper.objects.filter(user=self.user) + updated_quiz = Quiz.objects.filter( + description=self.trial_question_paper.quiz.description + ) + updated_course = Course.objects.filter( + name=self.trial_question_paper.quiz.course.name) + self.assertSequenceEqual(updated_answerpaper, []) + self.assertSequenceEqual(updated_quiz, []) + self.assertSequenceEqual(updated_course, []) + +class TestUserLogin(TestCase): + def setUp(self): + self.client = Client() + + # Create Moderator with profile + self.user1_plaintext_pass = 'demo1' + self.user1 = User.objects.create_user( + username='demo_user1', + password=self.user1_plaintext_pass, + first_name='user1_first_name', + last_name='user1_last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user1, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + + def tearDown(self): + self.client.logout() + self.user1.delete() + + def test_successful_user_login(self): + """ + Check if user is successfully logged in + """ + response = self.client.post(reverse('yaksh:login'), + data={'username': self.user1.username, + 'password': self.user1_plaintext_pass} + ) + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, '/exam/quizzes/') + + def test_unsuccessful_user_login(self): + """ + Check for failed login attempt for incorrect username/password + """ + response = self.client.post(reverse('yaksh:login'), + data={'username': self.user1.username, + 'password': "demo"} + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/login.html') + + +class TestDownloadcsv(TestCase): + def setUp(self): + self.client = Client() + tzone = pytz.timezone("utc") + self.mod_group = Group.objects.create(name='moderator') + # student + self.student_plaintext_pass = 'student' + self.student = User.objects.create_user( + username='student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='student@test.com' + ) + + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='student', + timezone='UTC' + ) + + # moderator + self.user_plaintext_pass = 'demo' + self.user = User.objects.create_user( + username='demo_user', + password=self.user_plaintext_pass, + first_name='user_first_name', + last_name='user_last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + self.mod_group.user_set.add(self.user) + self.course = Course.objects.create(name="Python Course", + enrollment="Enroll Request", 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, + language='Python', course=self.course + ) + + self.question = Question.objects.create( + summary="Test_question", description="Add two numbers", + points=1.0, language="python", type="code", user=self.user + ) + + self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, + total_marks=1.0, fixed_question_order=str(self.question.id) + ) + self.question_paper.fixed_questions.add(self.question) + + # student answerpaper + user_answer = "def add(a, b)\n\treturn a+b" + self.new_answer = Answer(question=self.question, answer=user_answer, + correct=True, error=json.dumps([]), marks=0.5) + self.new_answer.save() + self.answerpaper = AnswerPaper.objects.create( + user=self.student, question_paper=self.question_paper, + attempt_number=1, + 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 + ) + self.answerpaper.answers.add(self.new_answer) + self.answerpaper.questions_answered.add(self.question) + self.answerpaper.questions.add(self.question) + + def tearDown(self): + self.client.logout() + self.user.delete() + self.student.delete() + self.quiz.delete() + self.course.delete() + + def test_download_course_csv(self): + """ + Check for csv result of a course + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:download_course_csv', + kwargs={'course_id': self.course.id}), + follow=True + ) + file_name = "{0}.csv".format(self.course.name.lower()) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.get('Content-Disposition'), + 'attachment; filename="{0}"'.format(file_name)) + + def test_download_quiz_csv(self): + """ + Check for csv result of a quiz + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:download_csv', + kwargs={'questionpaper_id': self.question_paper.id}), + follow=True + ) + file_name = "{0}.csv".format(self.quiz.description) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.get('Content-Disposition'), + 'attachment; filename="{0}"'.format(file_name)) + + +class TestShowQuestions(TestCase): + def setUp(self): + self.client = Client() + tzone = pytz.timezone("utc") + self.mod_group = Group.objects.create(name='moderator') + # student + self.student_plaintext_pass = 'student' + self.student = User.objects.create_user( + username='student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='student@test.com' + ) + + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='student', + timezone='UTC' + ) + + # moderator + self.user_plaintext_pass = 'demo' + self.user = User.objects.create_user( + username='demo_user', + password=self.user_plaintext_pass, + first_name='user_first_name', + last_name='user_last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + self.mod_group.user_set.add(self.user) + self.question = Question.objects.create( + summary="Test_question1", description="Add two numbers", + points=2.0, language="python", type="code", user=self.user, + active=True + ) + self.question1 = Question.objects.create( + summary="Test_question2", description="Add two numbers", + points=1.0, language="python", type="mcq", user=self.user, + active=True + ) + + def test_show_all_questions(self): + """ + Check if all the user created questions are shown + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:show_questions'), + follow=True + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/showquestions.html') + self.assertEqual(response.context['questions'][0], self.question) + + def test_download_questions(self): + """ + Check for downloading questions zip file + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.post(reverse('yaksh:show_questions'), + data={'question': [self.question.id], + 'download': 'download'} + ) + file_name = "{0}_questions.zip".format(self.user) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.get('Content-Disposition'), + "attachment; filename={0}".format(file_name)) + zip_file = string_io(response.content) + zipped_file = zipfile.ZipFile(zip_file, 'r') + self.assertIsNone(zipped_file.testzip()) + self.assertIn('questions_dump.json', zipped_file.namelist()) + zip_file.close() + zipped_file.close() + + response = self.client.post(reverse('yaksh:show_questions'), + data={'question': [], + 'download': 'download'} + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/showquestions.html') + self.assertIn("download", response.context['msg']) + + + def test_upload_questions(self): + """ + Check for uploading questions zip file + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + ques_file = os.path.join(settings.FIXTURE_DIRS, "demo_questions.zip") + f = open(ques_file, 'rb') + questions_file = SimpleUploadedFile(ques_file, f.read(), + content_type="application/zip") + response = self.client.post(reverse('yaksh:show_questions'), + data={'file': questions_file, + 'upload': 'upload'} + ) + uploaded_ques = Question.objects.filter(active=True, + summary="Yaksh Demo Question", + user=self.user).count() + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/showquestions.html') + self.assertEqual(uploaded_ques, 3) + f.close() + dummy_file = SimpleUploadedFile("test.txt", b"test") + response = self.client.post(reverse('yaksh:show_questions'), + data={'file': dummy_file, + 'upload': 'upload'} + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/showquestions.html') + self.assertIn("ZIP file", response.context['message']) + + def test_attempt_questions(self): + """ + Check for testing questions + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.post(reverse('yaksh:show_questions'), + data={'question': [self.question.id], + 'test': 'test'} + ) + redirection_url = "/exam/start/1/1" + self.assertEqual(response.status_code, 302) + self.assertRedirects(response, redirection_url, target_status_code=301) + + def test_ajax_questions_filter(self): + """ + Check for filter questions based type, marks and + language of a question + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.post(reverse('yaksh:questions_filter'), + data={'question_type': 'mcq', + 'marks': '1.0', 'language': 'python' + } + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/ajax_question_filter.html') + self.assertEqual(response.context['questions'][0], self.question1) + + +class TestShowStatistics(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 Student + self.student_plaintext_pass = 'demo_student' + self.student = User.objects.create_user( + username='demo_student', + password=self.student_plaintext_pass, + first_name='student_first_name', + last_name='student_last_name', + email='demo_student@test.com' + ) + + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + + # Add to moderator group + self.mod_group.user_set.add(self.user) + + 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, + language='Python', course=self.course + ) + + self.question = Question.objects.create( + summary="Test_question", description="Add two numbers", + points=1.0, language="python", type="code", user=self.user + ) + + self.question_paper = QuestionPaper.objects.create(quiz=self.quiz, + total_marks=1.0, fixed_question_order=str(self.question) + ) + self.question_paper.fixed_questions.add(self.question) + user_answer = "def add(a, b)\n\treturn a+b" + self.new_answer = Answer(question=self.question, answer=user_answer, + correct=True, error=json.dumps([])) + self.new_answer.save() + self.answerpaper = AnswerPaper.objects.create( + user=self.student, question_paper=self.question_paper, + attempt_number=1, + 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 + ) + self.answerpaper.answers.add(self.new_answer) + self.answerpaper.questions_answered.add(self.question) + self.answerpaper.questions.add(self.question) + + def tearDown(self): + self.client.logout() + self.user.delete() + self.student.delete() + self.quiz.delete() + self.course.delete() + self.answerpaper.delete() + self.question.delete() + self.question_paper.delete() + self.new_answer.delete() + + def test_show_statistics_for_student(self): + """ + Check for student statistics + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:show_statistics', + kwargs={'questionpaper_id': self.question_paper.id}), + follow=True + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/statistics_question.html') + self.assertEqual(response.context['quiz'], self.quiz) + self.assertEqual(response.context['attempts'][0], + self.answerpaper.attempt_number) + self.assertEqual(response.context['questionpaper_id'], + str(self.question_paper.id)) + + def test_show_statistics_for_student_per_attempt(self): + """ + Check for student statistics per attempt + """ + self.client.login( + username=self.user.username, + password=self.user_plaintext_pass + ) + response = self.client.get(reverse('yaksh:show_statistics', + kwargs={'questionpaper_id': self.question_paper.id, + 'attempt_number': self.answerpaper.attempt_number}), + follow=True + ) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/statistics_question.html') + self.assertSequenceEqual(response.context['question_stats'][self.question], + [1, 1]) + self.assertEqual(response.context['attempts'][0], 1) + self.assertEqual(response.context['total'], 1) -- cgit