summaryrefslogtreecommitdiff
path: root/exam
diff options
context:
space:
mode:
authorPrabhu Ramachandran2011-11-24 02:11:40 +0530
committerPrabhu Ramachandran2011-11-24 02:11:40 +0530
commit11a2eaefaba6d2b547d35afbee3e85b18520afd2 (patch)
treef05aef4423f613c4d38232569df77a88c66978e7 /exam
parent30f56443790841901f15b5ab435f97fba1c81d85 (diff)
downloadonline_test-11a2eaefaba6d2b547d35afbee3e85b18520afd2.tar.gz
online_test-11a2eaefaba6d2b547d35afbee3e85b18520afd2.tar.bz2
online_test-11a2eaefaba6d2b547d35afbee3e85b18520afd2.zip
ENH/TMP: Preliminary support for bash scripts.
- Changing the Question model to add a language attribute. - Moving python_server.py -> code_server.py. - Adding functionality to test for Shell scripts. This is still incomplete since the shell code checker seems to have some problems. - Modified the xmlrpc_clients to support multiple languages and right now two. - Using setgid/setuid instead of setegid/seteuid in the code_server.py.. - Adding a bash example to the sample_questions.py. The shell script support doesn't quite work yet but this is really a code_server/checking issue.
Diffstat (limited to 'exam')
-rw-r--r--exam/management/commands/load_questions_xml.py4
-rw-r--r--exam/models.py8
-rw-r--r--exam/views.py5
-rw-r--r--exam/xmlrpc_clients.py37
4 files changed, 45 insertions, 9 deletions
diff --git a/exam/management/commands/load_questions_xml.py b/exam/management/commands/load_questions_xml.py
index aa403dd..b4151ae 100644
--- a/exam/management/commands/load_questions_xml.py
+++ b/exam/management/commands/load_questions_xml.py
@@ -35,6 +35,9 @@ def load_questions_xml(filename):
desc_node = question.getElementsByTagName("description")[0]
description = (desc_node.childNodes[0].data).strip()
+ lang_node = question.getElementsByTagName("language")[0]
+ language = (lang_node.childNodes[0].data).strip()
+
points_node = question.getElementsByTagName("points")[0]
points = int((points_node.childNodes[0].data).strip()) \
if points_node else 1
@@ -45,6 +48,7 @@ def load_questions_xml(filename):
new_question = Question(summary=summary,
description=description,
points=points,
+ language=language,
test=test)
new_question.save()
diff --git a/exam/models.py b/exam/models.py
index d433c7c..ef4312f 100644
--- a/exam/models.py
+++ b/exam/models.py
@@ -12,6 +12,11 @@ class Profile(models.Model):
position = models.CharField(max_length=64)
+LANGUAGE_CHOICES = (
+ ("python", "Python"),
+ ("bash", "Bash"),
+ )
+
################################################################################
class Question(models.Model):
"""A question in the database."""
@@ -29,6 +34,9 @@ class Question(models.Model):
# This is simple Python code.
test = models.TextField()
+ # The language being tested.
+ language = models.CharField(max_length=10, choices=LANGUAGE_CHOICES)
+
# Is this question active or not. If it is inactive it will not be used
# when creating a QuestionPaper.
active = models.BooleanField(default=True)
diff --git a/exam/views.py b/exam/views.py
index bafd0be..1f92553 100644
--- a/exam/views.py
+++ b/exam/views.py
@@ -13,7 +13,7 @@ from django.http import Http404
# Local imports.
from exam.models import Quiz, Question, QuestionPaper, Profile, Answer, User
from exam.forms import UserRegisterForm, UserLoginForm
-from exam.xmlrpc_clients import python_server
+from exam.xmlrpc_clients import code_server
from settings import URL_ROOT
# The directory where user data can be saved.
@@ -203,7 +203,8 @@ def check(request, q_id):
# with the code executed safely in a separate process (the python_server.py)
# running as nobody.
user_dir = get_user_dir(user)
- success, err_msg = python_server.run_code(answer, question.test, user_dir)
+ success, err_msg = code_server.run_code(answer, question.test,
+ user_dir, question.language)
new_answer.error = err_msg
if success:
diff --git a/exam/xmlrpc_clients.py b/exam/xmlrpc_clients.py
index 115ee6e..01172d7 100644
--- a/exam/xmlrpc_clients.py
+++ b/exam/xmlrpc_clients.py
@@ -4,7 +4,7 @@ import random
import socket
-class PythonServer(object):
+class CodeServer(object):
"""A class that manages accesing the farm of Python servers and making
calls to them such that no one XMLRPC server is overloaded.
"""
@@ -12,19 +12,41 @@ class PythonServer(object):
servers = [ServerProxy('http://localhost:%d'%(x)) for x in SERVER_PORTS]
self.servers = servers
self.indices = range(len(SERVER_PORTS))
+ self.methods = {"python": 'run_python_code',
+ "bash": 'run_bash_code'}
- def run_code(self, answer, test_code, user_dir):
- """See the documentation of the method of the same name in
- python_server.py.
+ def run_code(self, answer, test_code, user_dir, language):
+ """Tests given code (`answer`) with the `test_code` supplied. If the
+ optional `in_dir` keyword argument is supplied it changes the directory
+ to that directory (it does not change it back to the original when
+ done). The parameter language specifies which language to use for the
+ tests.
+
+ Parameters
+ ----------
+ answer : str
+ The user's answer for the question.
+ test_code : str
+ The test code to check the user code with.
+ user_dir : str (directory)
+ The directory to run the tests inside.
+ language : str
+ The programming language to use.
+
+ Returns
+ -------
+ A tuple: (success, error message).
"""
+ method_name = self.methods[language]
done = False
- result = [False, 'Unable to connect to any Python servers!']
+ result = [False, 'Unable to connect to any code servers!']
# Try to connect a few times if not, quit.
count = 5
while (not done) and (count > 0):
try:
server = self._get_server()
- result = server.run_code(answer, test_code, user_dir)
+ method = getattr(server, method_name)
+ result = method(answer, test_code, user_dir)
except socket.error:
count -= 1
else:
@@ -38,4 +60,5 @@ class PythonServer(object):
# views.py calls this Python server which forwards the request to one
# of the running servers.
-python_server = PythonServer()
+code_server = CodeServer()
+