summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoradityacp2017-04-27 18:37:19 +0530
committeradityacp2017-04-27 18:37:19 +0530
commit624e752684125aa525d9b3643cbd7c9b7ba61682 (patch)
tree726da35ba55acacfde255e31bdc2233600f75395
parentb191455c7d9b0f6c3548da174a68c8ab8052abf0 (diff)
parent2694fd6dd4d37a1a6570792e234998feef21edca (diff)
downloadonline_test-624e752684125aa525d9b3643cbd7c9b7ba61682.tar.gz
online_test-624e752684125aa525d9b3643cbd7c9b7ba61682.tar.bz2
online_test-624e752684125aa525d9b3643cbd7c9b7ba61682.zip
Remove conflicts from views after rebase
-rw-r--r--.travis.yml4
-rw-r--r--online_test/test_settings.py4
-rw-r--r--requirements/requirements-common.txt1
-rw-r--r--yaksh/base_evaluator.py5
-rw-r--r--yaksh/bash_stdio_evaluator.py3
-rw-r--r--yaksh/cpp_stdio_evaluator.py3
-rw-r--r--yaksh/documentation/images/create_course.pngbin0 -> 51993 bytes
-rw-r--r--yaksh/documentation/moderator_docs/creating_course.rst15
-rw-r--r--yaksh/evaluator_tests/test_bash_evaluation.py10
-rw-r--r--yaksh/evaluator_tests/test_c_cpp_evaluation.py13
-rw-r--r--yaksh/evaluator_tests/test_java_evaluation.py16
-rw-r--r--yaksh/evaluator_tests/test_scilab_evaluation.py9
-rw-r--r--yaksh/forms.py13
-rw-r--r--yaksh/hook_evaluator.py6
-rw-r--r--yaksh/java_stdio_evaluator.py3
-rw-r--r--yaksh/models.py6
-rw-r--r--yaksh/stdio_evaluator.py13
-rw-r--r--yaksh/templates/yaksh/quizzes_user.html26
-rw-r--r--yaksh/views.py41
19 files changed, 159 insertions, 32 deletions
diff --git a/.travis.yml b/.travis.yml
index 4777f11..c242e62 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -19,8 +19,8 @@ install:
# command to run tests and coverage
script:
- coverage erase
- - coverage run -p manage.py test -v 2 yaksh
- - coverage run -p manage.py test -v 2 yaksh.live_server_tests.load_test
+ - coverage run -p manage.py test -v 2 --settings online_test.test_settings yaksh
+ - coverage run -p manage.py test -v 2 --settings online_test.test_settings yaksh.live_server_tests.load_test
after_success:
- coverage combine
diff --git a/online_test/test_settings.py b/online_test/test_settings.py
new file mode 100644
index 0000000..53f4901
--- /dev/null
+++ b/online_test/test_settings.py
@@ -0,0 +1,4 @@
+from online_test.settings import *
+
+
+MIGRATION_MODULES = {'yaksh': None} \ No newline at end of file
diff --git a/requirements/requirements-common.txt b/requirements/requirements-common.txt
index e04c5bd..53a44a4 100644
--- a/requirements/requirements-common.txt
+++ b/requirements/requirements-common.txt
@@ -5,3 +5,4 @@ python-social-auth==0.2.19
tornado
selenium==2.53.6
coverage
+psutil
diff --git a/yaksh/base_evaluator.py b/yaksh/base_evaluator.py
index 071008f..e702f68 100644
--- a/yaksh/base_evaluator.py
+++ b/yaksh/base_evaluator.py
@@ -7,6 +7,7 @@ from os.path import join, isfile
from os.path import isdir, dirname, abspath, join, isfile, exists
import subprocess
import stat
+import signal
# Local imports
@@ -30,11 +31,11 @@ class BaseEvaluator(object):
stdout and stderr.
"""
try:
- proc = subprocess.Popen(cmd_args, *args, **kw)
+ proc = subprocess.Popen(cmd_args,preexec_fn=os.setpgrp, *args, **kw)
stdout, stderr = proc.communicate()
except TimeoutException:
# Runaway code, so kill it.
- proc.kill()
+ os.killpg(os.getpgid(proc.pid), signal.SIGKILL)
# Re-raise exception.
raise
return proc, stdout.decode('utf-8'), stderr.decode('utf-8')
diff --git a/yaksh/bash_stdio_evaluator.py b/yaksh/bash_stdio_evaluator.py
index 334620d..1ce729a 100644
--- a/yaksh/bash_stdio_evaluator.py
+++ b/yaksh/bash_stdio_evaluator.py
@@ -49,7 +49,8 @@ class BashStdIOEvaluator(StdIOEvaluator):
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
- stderr=subprocess.PIPE
+ stderr=subprocess.PIPE,
+ preexec_fn=os.setpgrp
)
success, err = self.evaluate_stdio(self.user_answer, proc,
self.expected_input,
diff --git a/yaksh/cpp_stdio_evaluator.py b/yaksh/cpp_stdio_evaluator.py
index b302fa4..d211bb7 100644
--- a/yaksh/cpp_stdio_evaluator.py
+++ b/yaksh/cpp_stdio_evaluator.py
@@ -82,7 +82,8 @@ class CppStdIOEvaluator(StdIOEvaluator):
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
- stderr=subprocess.PIPE
+ stderr=subprocess.PIPE,
+ preexec_fn=os.setpgrp
)
success, err = self.evaluate_stdio(self.user_answer, proc,
self.expected_input,
diff --git a/yaksh/documentation/images/create_course.png b/yaksh/documentation/images/create_course.png
new file mode 100644
index 0000000..29c8783
--- /dev/null
+++ b/yaksh/documentation/images/create_course.png
Binary files differ
diff --git a/yaksh/documentation/moderator_docs/creating_course.rst b/yaksh/documentation/moderator_docs/creating_course.rst
index 69935fd..44ebe44 100644
--- a/yaksh/documentation/moderator_docs/creating_course.rst
+++ b/yaksh/documentation/moderator_docs/creating_course.rst
@@ -8,12 +8,23 @@ Setting up a new course
-----------------------
To create a course, click on the Add New Course button on the moderator's dashboard. This will lead you to a create add course page, where you need to fill in the following fields.
+ .. image:: ../images/create_course.png
+
* Name
Name of the Course
- * Active
- If the course should be active for students to take the quiz. The status of the course can be edited later.
* Enrollment
Open enrollment is open to all students. Enroll Request requires students to send a request which the moderator can accept or reject.
+ * Active
+ If the course should be active for students to take the quiz. The status of the course can be edited later.
+ * Code
+ If the course should be hidden and only accessible to students possessing the correct course code.
+ * Instructions
+ Instructions for the course
+ * Start Date and Time for enrollment of course
+ If the enrollment of the course should be available only after a set date and time
+ * End Date and Time for enrollment of course
+ If the enrollment of the course should be available only before a set date and time
+
Features in Courses
-------------------
diff --git a/yaksh/evaluator_tests/test_bash_evaluation.py b/yaksh/evaluator_tests/test_bash_evaluation.py
index 482d45e..8bb8c81 100644
--- a/yaksh/evaluator_tests/test_bash_evaluation.py
+++ b/yaksh/evaluator_tests/test_bash_evaluation.py
@@ -3,6 +3,8 @@ import unittest
import os
import shutil
import tempfile
+from psutil import Process, pid_exists
+# Local Imports
from yaksh.grader import Grader
from yaksh.bash_code_evaluator import BashCodeEvaluator
from yaksh.bash_stdio_evaluator import BashStdIOEvaluator
@@ -103,6 +105,10 @@ class BashAssertionEvaluationTestCases(EvaluatorBaseTest):
# Then
self.assertFalse(result.get("success"))
self.assert_correct_output(self.timeout_msg, result.get("error"))
+ parent_proc = Process(os.getpid()).children()
+ if parent_proc:
+ children_procs = Process(parent_proc[0].pid)
+ self.assertFalse(any(children_procs.children(recursive=True)))
def test_file_based_assert(self):
# Given
@@ -528,6 +534,10 @@ class BashHookEvaluationTestCases(EvaluatorBaseTest):
# Then
self.assertFalse(result.get('success'))
self.assert_correct_output(self.timeout_msg, result.get('error'))
+ parent_proc = Process(os.getpid()).children()
+ if parent_proc:
+ children_procs = Process(parent_proc[0].pid)
+ self.assertFalse(any(children_procs.children(recursive=True)))
if __name__ == '__main__':
diff --git a/yaksh/evaluator_tests/test_c_cpp_evaluation.py b/yaksh/evaluator_tests/test_c_cpp_evaluation.py
index 304f1cb..b15f766 100644
--- a/yaksh/evaluator_tests/test_c_cpp_evaluation.py
+++ b/yaksh/evaluator_tests/test_c_cpp_evaluation.py
@@ -4,6 +4,7 @@ import os
import shutil
import tempfile
from textwrap import dedent
+from psutil import Process
# Local import
from yaksh.grader import Grader
@@ -151,6 +152,10 @@ class CAssertionEvaluationTestCases(EvaluatorBaseTest):
# Then
self.assertFalse(result.get("success"))
self.assert_correct_output(self.timeout_msg, result.get("error"))
+ parent_proc = Process(os.getpid()).children()
+ if parent_proc:
+ children_procs = Process(parent_proc[0].pid)
+ self.assertFalse(any(children_procs.children(recursive=True)))
def test_file_based_assert(self):
# Given
@@ -401,6 +406,10 @@ class CppStdIOEvaluationTestCases(EvaluatorBaseTest):
# Then
self.assertFalse(result.get("success"))
self.assert_correct_output(self.timeout_msg, result.get("error"))
+ parent_proc = Process(os.getpid()).children()
+ if parent_proc:
+ children_procs = Process(parent_proc[0].pid)
+ self.assertFalse(any(children_procs.children(recursive=True)))
def test_only_stdout(self):
# Given
@@ -967,6 +976,10 @@ class CppHookEvaluationTestCases(EvaluatorBaseTest):
# Then
self.assertFalse(result.get('success'))
self.assert_correct_output(self.timeout_msg, result.get('error'))
+ parent_proc = Process(os.getpid()).children()
+ if parent_proc:
+ children_procs = Process(parent_proc[0].pid)
+ self.assertFalse(any(children_procs.children(recursive=True)))
if __name__ == '__main__':
diff --git a/yaksh/evaluator_tests/test_java_evaluation.py b/yaksh/evaluator_tests/test_java_evaluation.py
index 3d127af..ea558ed 100644
--- a/yaksh/evaluator_tests/test_java_evaluation.py
+++ b/yaksh/evaluator_tests/test_java_evaluation.py
@@ -4,6 +4,9 @@ import os
import shutil
import tempfile
from textwrap import dedent
+from psutil import Process, pid_exists
+import time
+
# Local Import
from yaksh import grader as gd
@@ -158,6 +161,10 @@ class JavaAssertionEvaluationTestCases(EvaluatorBaseTest):
# Then
self.assertFalse(result.get("success"))
self.assert_correct_output(self.timeout_msg, result.get("error"))
+ parent_proc = Process(os.getpid()).children()
+ if parent_proc:
+ children_procs = Process(parent_proc[0].pid)
+ self.assertFalse(any(children_procs.children(recursive=True)))
def test_file_based_assert(self):
# Given
@@ -398,6 +405,10 @@ class JavaStdIOEvaluationTestCases(EvaluatorBaseTest):
# Then
self.assertFalse(result.get("success"))
self.assert_correct_output(self.timeout_msg, result.get("error"))
+ parent_proc = Process(os.getpid()).children()
+ if parent_proc:
+ children_procs = Process(parent_proc[0].pid)
+ self.assertFalse(any(children_procs.children(recursive=True)))
def test_only_stdout(self):
# Given
@@ -832,8 +843,13 @@ class JavaHookEvaluationTestCases(EvaluatorBaseTest):
result = grader.evaluate(kwargs)
# Then
+
self.assertFalse(result.get('success'))
self.assert_correct_output(self.timeout_msg, result.get('error'))
+ parent_proc = Process(os.getpid()).children()
+ if parent_proc:
+ children_procs = Process(parent_proc[0].pid)
+ self.assertFalse(any(children_procs.children(recursive=True)))
if __name__ == '__main__':
diff --git a/yaksh/evaluator_tests/test_scilab_evaluation.py b/yaksh/evaluator_tests/test_scilab_evaluation.py
index 5a452a3..c3a1c83 100644
--- a/yaksh/evaluator_tests/test_scilab_evaluation.py
+++ b/yaksh/evaluator_tests/test_scilab_evaluation.py
@@ -3,13 +3,15 @@ import unittest
import os
import shutil
import tempfile
+from psutil import Process
from textwrap import dedent
+
+#Local Import
from yaksh import grader as gd
from yaksh.grader import Grader
from yaksh.scilab_code_evaluator import ScilabCodeEvaluator
from yaksh.evaluator_tests.test_python_evaluation import EvaluatorBaseTest
-
class ScilabEvaluationTestCases(EvaluatorBaseTest):
def setUp(self):
tmp_in_dir_path = tempfile.mkdtemp()
@@ -136,6 +138,11 @@ class ScilabEvaluationTestCases(EvaluatorBaseTest):
self.assertFalse(result.get("success"))
self.assert_correct_output(self.timeout_msg, result.get("error"))
+ parent_proc = Process(os.getpid()).children()
+ if parent_proc:
+ children_procs = Process(parent_proc[0].pid)
+ self.assertFalse(any(children_procs.children(recursive=True)))
+
if __name__ == '__main__':
unittest.main()
diff --git a/yaksh/forms.py b/yaksh/forms.py
index b34ad59..5dd56a2 100644
--- a/yaksh/forms.py
+++ b/yaksh/forms.py
@@ -289,10 +289,21 @@ class QuestionFilterForm(forms.Form):
class CourseForm(forms.ModelForm):
""" course form for moderators """
+ def save(self, commit=True, *args, **kwargs):
+ instance = super(CourseForm, self).save(commit=False)
+ if instance.code:
+ instance.hidden = True
+ else:
+ instance.hidden = False
+
+ if commit:
+ instance.save()
+ return instance
+
class Meta:
model = Course
exclude = ['creator', 'requests', 'students', 'rejected',
- 'created_on', 'is_trial', 'teachers']
+ 'created_on', 'is_trial', 'hidden', 'teachers']
class ProfileForm(forms.ModelForm):
diff --git a/yaksh/hook_evaluator.py b/yaksh/hook_evaluator.py
index 0819ec9..f5364d6 100644
--- a/yaksh/hook_evaluator.py
+++ b/yaksh/hook_evaluator.py
@@ -2,6 +2,8 @@
import sys
import traceback
import os
+import signal
+import psutil
# Local imports
from .file_utils import copy_files, delete_files
@@ -65,10 +67,12 @@ class HookEvaluator(BaseEvaluator):
check = hook_scope["check_answer"]
success, err, mark_fraction = check(self.user_answer)
except TimeoutException:
+ processes = psutil.Process(os.getpid()).children(recursive=True)
+ for process in processes:
+ process.kill()
raise
except Exception:
msg = traceback.format_exc(limit=0)
err = "Error in Hook code: {0}".format(msg)
del tb
return success, err, mark_fraction
- \ No newline at end of file
diff --git a/yaksh/java_stdio_evaluator.py b/yaksh/java_stdio_evaluator.py
index 48f265d..4e9238f 100644
--- a/yaksh/java_stdio_evaluator.py
+++ b/yaksh/java_stdio_evaluator.py
@@ -67,7 +67,8 @@ class JavaStdIOEvaluator(StdIOEvaluator):
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
- stderr=subprocess.PIPE
+ stderr=subprocess.PIPE,
+ preexec_fn=os.setpgrp
)
success, err = self.evaluate_stdio(self.user_answer, proc,
self.expected_input,
diff --git a/yaksh/models.py b/yaksh/models.py
index 77b5ec4..f6867f0 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -49,7 +49,7 @@ question_types = (
enrollment_methods = (
("default", "Enroll Request"),
- ("open", "Open Course"),
+ ("open", "Open Enrollment"),
)
test_case_types = (
@@ -112,6 +112,8 @@ class CourseManager(models.Manager):
trial_course.enroll(False, user)
return trial_course
+ def get_hidden_courses(self, code):
+ return self.filter(code=code, hidden=True)
###############################################################################
class Course(models.Model):
@@ -119,6 +121,8 @@ class Course(models.Model):
name = models.CharField(max_length=128)
enrollment = models.CharField(max_length=32, choices=enrollment_methods)
active = models.BooleanField(default=True)
+ code = models.CharField(max_length=128, null=True, blank=True)
+ hidden = models.BooleanField(default=False)
creator = models.ForeignKey(User, related_name='creator')
students = models.ManyToManyField(User, related_name='students')
requests = models.ManyToManyField(User, related_name='requests')
diff --git a/yaksh/stdio_evaluator.py b/yaksh/stdio_evaluator.py
index fa78a68..554d4c5 100644
--- a/yaksh/stdio_evaluator.py
+++ b/yaksh/stdio_evaluator.py
@@ -1,7 +1,10 @@
from __future__ import unicode_literals
+import os
+import signal
# Local imports
from .base_evaluator import BaseEvaluator
+from .grader import TimeoutException
class StdIOEvaluator(BaseEvaluator):
@@ -9,9 +12,13 @@ class StdIOEvaluator(BaseEvaluator):
success = False
ip = expected_input.replace(",", " ")
encoded_input = '{0}\n'.format(ip).encode('utf-8')
- user_output_bytes, output_err_bytes = proc.communicate(encoded_input)
- user_output = user_output_bytes.decode('utf-8')
- output_err = output_err_bytes.decode('utf-8')
+ try:
+ user_output_bytes, output_err_bytes = proc.communicate(encoded_input)
+ user_output = user_output_bytes.decode('utf-8')
+ output_err = output_err_bytes.decode('utf-8')
+ except TimeoutException:
+ os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
+ raise
expected_output = expected_output.replace("\r", "")
if not expected_input:
error_msg = "Expected Output is\n{0} ".\
diff --git a/yaksh/templates/yaksh/quizzes_user.html b/yaksh/templates/yaksh/quizzes_user.html
index ce74844..90d7f8e 100644
--- a/yaksh/templates/yaksh/quizzes_user.html
+++ b/yaksh/templates/yaksh/quizzes_user.html
@@ -1,6 +1,26 @@
{% extends "user.html" %}
{% block pagetitle %} {{ title }} {% endblock %}
{% block main %}
+ {% if 'Enrolled Courses' not in title%}
+ <div class="row well">
+ <form action="{{ URL_ROOT }}/exam/quizzes/" method="post" id="custom-search-form" class="form-search form-horizontal pull-right">
+ {% csrf_token %}
+ <div class="col-md-12">
+ <div class="input-group">
+ <span class="input-group-addon" id="basic-addon1">Search Course</span>
+ <input type="text" name="course_code" class="form-control" placeholder="Course Code">
+ <span class="input-group-btn">
+ <button class="btn btn-default" type="submit">Search</button>
+ <button class="btn btn-default" type="button" name="button" onClick='location.replace("{{URL_ROOT}}/exam/quizzes/");'>Cancel</button>
+ </span>
+ </div>
+ </div>
+ </form>
+ </div>
+ {% endif %}
+{% if not courses %}
+No Courses to display
+{% endif %}
{% for course in courses %}
<div class="row well">
<div class="col-md-12">
@@ -9,6 +29,8 @@
<h4><b><u> {{ course.name }} by {{ course.creator.get_full_name }}</u></b></h4>
</div>
<div class="col-md-4">
+ {% if course.hidden %}<span class="label label-info">Open Course</span>
+ {% endif %}
{% if user in course.requests.all %} <span class="label label-warning">Request Pending </span>
{% elif user in course.rejected.all %}<span class="label label-danger">Request Rejected</span>
{% elif user in course.students.all %}<span class="label label-info">Enrolled</span>
@@ -41,7 +63,7 @@
</td>
{% else %}
<td>
- {{ quiz.description }} <span class="label label-danger">INACTIVE</span><br>
+ {{ quiz.description }} <span class="label label-danger">Inactive</span><br>
</td>
{% endif %}
<td>
@@ -83,7 +105,7 @@
{% endif %}
</div>
</div><!--/row-->
- </br>
+</br>
{% endfor %}
{% endblock %}
diff --git a/yaksh/views.py b/yaksh/views.py
index 751efb5..35df9f9 100644
--- a/yaksh/views.py
+++ b/yaksh/views.py
@@ -76,14 +76,14 @@ def add_to_group(users):
user.groups.add(group)
@email_verified
-def index(request):
+def index(request, next_url=None):
"""The start page.
"""
user = request.user
if user.is_authenticated():
if is_moderator(user):
- return my_redirect('/exam/manage/')
- return my_redirect("/exam/quizzes/")
+ return my_redirect('/exam/manage/' if not next_url else next_url)
+ return my_redirect("/exam/quizzes/" if not next_url else next_url)
return my_redirect("/exam/login/")
@@ -131,14 +131,25 @@ def user_logout(request):
def quizlist_user(request, enrolled=None):
"""Show All Quizzes that is available to logged-in user."""
user = request.user
- if enrolled is not None:
+ ci = RequestContext(request)
+
+ if request.method == "POST":
+ course_code = request.POST.get('course_code')
+ hidden_courses = Course.objects.get_hidden_courses(code=course_code)
+ courses = hidden_courses if hidden_courses else None
+ title = 'Search'
+
+ elif enrolled is not None:
courses = user.students.all()
title = 'Enrolled Courses'
else:
- courses = Course.objects.filter(active=True, is_trial=False)
+ courses = Course.objects.filter(active=True, is_trial=False, hidden=False)
title = 'All Courses'
+
context = {'user': user, 'courses': courses, 'title': title}
- return my_render_to_response("yaksh/quizzes_user.html", context)
+
+ return my_render_to_response("yaksh/quizzes_user.html", context,
+ context_instance=ci)
@login_required
@@ -348,21 +359,23 @@ def user_login(request):
if user.is_authenticated():
return index(request)
+ next_url = request.GET.get('next')
+
if request.method == "POST":
form = UserLoginForm(request.POST)
if form.is_valid():
user = form.cleaned_data
login(request, user)
- return index(request)
+ return index(request, next_url)
else:
context = {"form": form}
- return my_render_to_response('yaksh/login.html', context,
- context_instance=ci)
+
else:
form = UserLoginForm()
context = {"form": form}
- return my_render_to_response('yaksh/login.html', context,
- context_instance=ci)
+
+ return my_render_to_response('yaksh/login.html', context,
+ context_instance=ci)
@login_required
@@ -658,8 +671,8 @@ def enroll_request(request, course_id):
user = request.user
ci = RequestContext(request)
course = get_object_or_404(Course, pk=course_id)
- if not course.is_active_enrollment:
- msg = 'Enrollment for this course has been closed, please contact your '\
+ if not course.is_active_enrollment and course.hidden:
+ msg = 'Unable to add enrollments for this course, please contact your '\
'instructor/administrator.'
return complete(request, msg, attempt_num=None, questionpaper_id=None)
@@ -1273,7 +1286,7 @@ def search_teacher(request, course_id):
if not is_moderator(user):
raise Http404('You are not allowed to view this page!')
- context = {}
+ context = {'success': False}
course = get_object_or_404(Course, pk=course_id)
context['course'] = course