diff options
Diffstat (limited to 'testapp/exam')
38 files changed, 1196 insertions, 237 deletions
diff --git a/testapp/exam/c_cpp_files/main.cpp b/testapp/exam/c_cpp_files/main.cpp new file mode 100755 index 0000000..ebe1f08 --- /dev/null +++ b/testapp/exam/c_cpp_files/main.cpp @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int add(int, int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + int result; + result = add(0,0); + printf("Input submitted to the function: 0, 0"); + check(0, result); + result = add(2,3); + printf("Input submitted to the function: 2 3"); + check(5,result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main2.c b/testapp/exam/c_cpp_files/main2.c new file mode 100755 index 0000000..ccd1768 --- /dev/null +++ b/testapp/exam/c_cpp_files/main2.c @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int add(int, int, int); + +template <class T> +void check(T expect,T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (0); + } +} + +int main(void) +{ + int result; + result = add(0,0,0); + printf("Input submitted to the function: 0, 0, 0"); + check(0, result); + result = add(2,3,3); + printf("Input submitted to the function: 2, 3, 3"); + check(8,result); + printf("All Correct\n"); +} diff --git a/testapp/exam/c_cpp_files/main_array_check.cpp b/testapp/exam/c_cpp_files/main_array_check.cpp new file mode 100755 index 0000000..ea34fdd --- /dev/null +++ b/testapp/exam/c_cpp_files/main_array_check.cpp @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <stdlib.h> + +extern bool array_check(int [], int); + +template <class T> + +void check(T expect,T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + bool result; + int a[] = {1,2,3,0,0}; + result = array_check(a, 2); + printf("Input submitted to the function: {1, 2, 3, 0, 0} and index 2"); + check(false, result); + int b[] = {1,2,3,4,5}; + result = array_check(b, 3); + printf("Input submitted to the function: {1, 2, 3, 4, 5} and index 3"); + check(true, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_array_check_all.cpp b/testapp/exam/c_cpp_files/main_array_check_all.cpp new file mode 100755 index 0000000..140578e --- /dev/null +++ b/testapp/exam/c_cpp_files/main_array_check_all.cpp @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <stdlib.h> + +extern bool array_check_all(int []); + +template <class T> + +void check(T expect,T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + bool result; + int a[] = {1,2,3,2,8}; + result = array_check_all(a); + printf("Input submitted to the function: {1, 2, 3, 2, 8}"); + check(false, result); + int b[] = {4,2,32,4,56}; + result = array_check_all(b); + printf("Input submitted to the function: {4, 2, 32, 4, 56}"); + check(true, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_array_sum.cpp b/testapp/exam/c_cpp_files/main_array_sum.cpp new file mode 100755 index 0000000..55b2ebf --- /dev/null +++ b/testapp/exam/c_cpp_files/main_array_sum.cpp @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int array_sum(int []); + +template <class T> + +void check(T expect,T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + int result; + int a[] = {1,2,3,0,0}; + result = array_sum(a); + printf("Input submitted to the function: {1, 2, 3, 0, 0}"); + check(6, result); + int b[] = {1,2,3,4,5}; + result = array_sum(b); + printf("Input submitted to the function: {1, 2, 3, 4, 5}"); + check(15,result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_blackJack.cpp b/testapp/exam/c_cpp_files/main_blackJack.cpp new file mode 100755 index 0000000..cc54e78 --- /dev/null +++ b/testapp/exam/c_cpp_files/main_blackJack.cpp @@ -0,0 +1,41 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int blackJack(int, int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + int result; + result = blackJack(11, 12); + printf("Input submitted to the function: 11, 12"); + check(12, result); + result = blackJack(15, 19); + printf("Input submitted to the function: 15, 19"); + check(19, result); + result = blackJack(10, 21); + printf("Input submitted to the function: 10, 21"); + check(21, result); + result = blackJack(31, 22); + printf("Input submitted to the function: 31, 22"); + check(0, result); + result = blackJack(91, 61); + printf("Input submitted to the function: 91, 61"); + check(0, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_check_digit.cpp b/testapp/exam/c_cpp_files/main_check_digit.cpp new file mode 100755 index 0000000..d3bf3d6 --- /dev/null +++ b/testapp/exam/c_cpp_files/main_check_digit.cpp @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <stdlib.h> + +extern bool check_digit(int, int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + bool result; + result = check_digit(12, 23); + printf("Input submitted to the function: 12, 23"); + check(true, result); + result = check_digit(22, 11); + printf("Input submitted to the function: 121"); + check(false, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_count667.cpp b/testapp/exam/c_cpp_files/main_count667.cpp new file mode 100755 index 0000000..f146e8c --- /dev/null +++ b/testapp/exam/c_cpp_files/main_count667.cpp @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int count667(int[]); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + int result; + int arr[5] = {2,6,4,5,6}; + result = count667(arr); + printf("Input submitted to the function: [2, 6, 4, 5,6]"); + check(0, result); + int arr2[5] = {6,6,2,17,9}; + result = count667(arr2); + printf("Input submitted to the function: [6, 6, 2, 17, 9]"); + check(1, result); + int arr3[5] = {6,6,6,7,1}; + result = count667(arr3); + printf("Input submitted to the function: [6, 6, 7, 2, 1]"); + check(3, result); + int arr4[5] = {6,7,7,6,6}; + result = count667(arr4); + printf("Input submitted to the function: [6, 7, 7, 6, 6]"); + check(2, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_count7.cpp b/testapp/exam/c_cpp_files/main_count7.cpp new file mode 100755 index 0000000..982e930 --- /dev/null +++ b/testapp/exam/c_cpp_files/main_count7.cpp @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int count7(int[]); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + int result; + int arr[4] = {2,3,4,5}; + result = count7(arr); + printf("Input submitted to the function: [2, 3, 4, 5]"); + check(0, result); + int arr2[4] = {1,2,17,9}; + result = count7(arr2); + printf("Input submitted to the function: [1, 2, 17, 9]"); + check(0, result); + int arr3[4] = {7,9,2,1}; + result = count7(arr3); + printf("Input submitted to the function: [7, 9, 2, 1]"); + check(1, result); + int arr4[4] = {1,7,7,7}; + result = count7(arr4); + printf("Input submitted to the function: [1, 7, 7, 7]"); + check(3, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_fact.cpp b/testapp/exam/c_cpp_files/main_fact.cpp new file mode 100755 index 0000000..a4ff230 --- /dev/null +++ b/testapp/exam/c_cpp_files/main_fact.cpp @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int factorial(int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + int result; + result = factorial(0); + printf("Input submitted to the function: 0"); + check(1, result); + result = factorial(3); + printf("Input submitted to the function: 3"); + check(6, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_greatest.cpp b/testapp/exam/c_cpp_files/main_greatest.cpp new file mode 100755 index 0000000..6d0a7c2 --- /dev/null +++ b/testapp/exam/c_cpp_files/main_greatest.cpp @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int greatest(int, int, int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + int result; + result = greatest(1, 2, 3); + printf("Input submitted to the function: 1, 2, 3"); + check(3, result); + result = greatest(5, 9, 2); + printf("Input submitted to the function: 5, 9, 2"); + check(9, result); + result = greatest(7, 2, 4); + printf("Input submitted to the function: 7, 2, 4"); + check(7, result); + result = greatest(11, 2, 45); + printf("Input submitted to the function: 11, 2, 45"); + check(45, result); + result = greatest(2, 7, 0); + printf("Input submitted to the function: 2, 7, 0"); + check(7, result); + result = greatest(9, 6, 5); + printf("Input submitted to the function: 9, 6, 5"); + check(9, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_hello_name.c b/testapp/exam/c_cpp_files/main_hello_name.c new file mode 100755 index 0000000..71b83a2 --- /dev/null +++ b/testapp/exam/c_cpp_files/main_hello_name.c @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <stdlib.h> + + +void check(char expect[], char result[]) +{ + if (expect == result) + { + printf("Correct:expected %s got %s \n",expect,result); + } + else + { + printf("ERROR:expected %s got %s \n",expect,result); + exit (0); + } +} + +int main(void) +{ + char result[20]; + char A[20]=" pratham"; + char B[20]=" sir"; + result[20] = message(A); + printf("%s",result); + check("hello pratham", result); + result[20] = message(B); + check("hello sir",result); + printf("All Correct\n"); +} diff --git a/testapp/exam/c_cpp_files/main_lessThan9.cpp b/testapp/exam/c_cpp_files/main_lessThan9.cpp new file mode 100755 index 0000000..722b4bb --- /dev/null +++ b/testapp/exam/c_cpp_files/main_lessThan9.cpp @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdlib.h> + +extern bool lessThan9(int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + bool result; + result = lessThan9(10); + printf("Input submitted to the function: 10"); + check(false, result); + result = lessThan9(17); + printf("Input submitted to the function: 17"); + check(true, result); + result = lessThan9(16); + printf("Input submitted to the function: 16"); + check(true, result); + result = lessThan9(15); + printf("Input submitted to the function: 15"); + check(false, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_mean.cpp b/testapp/exam/c_cpp_files/main_mean.cpp new file mode 100755 index 0000000..21a4b1a --- /dev/null +++ b/testapp/exam/c_cpp_files/main_mean.cpp @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdlib.h> + +extern bool mean(int, int , int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + bool result; + result = mean(11, 11, 11); + printf("Input submitted to the function: 11, 121, 11"); + check(true, result); + result = mean(16, 12, 9); + printf("Input submitted to the function: 16, 144, 9"); + check(true, result); + result = mean(19, 221, 9); + printf("Input submitted to the function: 19, 221, 9"); + check(false, result); + result = mean(34, 12, 3); + printf("Input submitted to the function: 11, 121, 11"); + check(false, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_palindrome.cpp b/testapp/exam/c_cpp_files/main_palindrome.cpp new file mode 100755 index 0000000..0e66928 --- /dev/null +++ b/testapp/exam/c_cpp_files/main_palindrome.cpp @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <stdlib.h> + +extern bool palindrome(int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + bool result; + result = palindrome(123); + printf("Input submitted to the function: 123"); + check(false, result); + result = palindrome(121); + printf("Input submitted to the function: 121"); + check(true, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_roundTo10.cpp b/testapp/exam/c_cpp_files/main_roundTo10.cpp new file mode 100755 index 0000000..12c961d --- /dev/null +++ b/testapp/exam/c_cpp_files/main_roundTo10.cpp @@ -0,0 +1,41 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int roundTo10(int,int,int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + int result; + result = roundTo10(10, 22, 39); + printf("Input submitted to the function: 10, 22, 39"); + check(70, result); + result = roundTo10(45, 42, 39); + printf("Input submitted to the function: 45, 42, 39"); + check(130, result); + result = roundTo10(7, 3, 9); + printf("Input submitted to the function: 7, 3, 9"); + check(20, result); + result = roundTo10(1, 2, 3); + printf("Input submitted to the function: 1, 2, 3"); + check(0, result); + result = roundTo10(30, 40, 50); + printf("Input submitted to the function: 30, 40, 50"); + check(120, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_specialSum.cpp b/testapp/exam/c_cpp_files/main_specialSum.cpp new file mode 100755 index 0000000..d614536 --- /dev/null +++ b/testapp/exam/c_cpp_files/main_specialSum.cpp @@ -0,0 +1,41 @@ +#include <stdio.h> +#include <stdlib.h> + +extern int specialSum(int,int,int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + int result; + result = specialSum(10, 2, 9); + printf("Input submitted to the function: 10, 2, 9"); + check(21, result); + result = specialSum(1, 21, 9); + printf("Input submitted to the function: 1, 21, 9"); + check(1, result); + result = specialSum(21, 2, 3); + printf("Input submitted to the function: 21, 2, 3"); + check(0, result); + result = specialSum(10, 2, 21); + printf("Input submitted to the function: 10, 2, 21"); + check(12, result); + result = specialSum(10, 2, 6); + printf("Input submitted to the function: 10, 2, 6"); + check(18, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/c_cpp_files/main_within.cpp b/testapp/exam/c_cpp_files/main_within.cpp new file mode 100755 index 0000000..50f9ad0 --- /dev/null +++ b/testapp/exam/c_cpp_files/main_within.cpp @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdlib.h> + +extern bool within(int, int, int); + +template <class T> + +void check(T expect, T result) +{ + if (expect == result) + { + printf("\nCorrect:\n Expected %d got %d \n",expect,result); + } + else + { + printf("\nIncorrect:\n Expected %d got %d \n",expect,result); + exit (1); + } +} + +int main(void) +{ + bool result; + result = within(12, 3, 20); + printf("Input submitted to the function: 12, 3, 20"); + check(true, result); + result = within(12, 13, 20); + printf("Input submitted to the function: 12, 13, 20"); + check(false, result); + result = within(29, 13, 120); + printf("Input submitted to the function: 29, 13, 120"); + check(true, result); + result = within(12, 12, 20); + printf("Input submitted to the function: 12, 3, 20"); + check(false, result); + printf("All Correct\n"); + return 0; +} diff --git a/testapp/exam/code_server.py b/testapp/exam/code_server.py index f5c5698..db30798 100755 --- a/testapp/exam/code_server.py +++ b/testapp/exam/code_server.py @@ -19,7 +19,6 @@ settings.py:SERVER_POOL_PORT. This port exposes a `get_server_port` function that returns an available server. """ import sys -import traceback from SimpleXMLRPCServer import SimpleXMLRPCServer import pwd import os @@ -34,13 +33,15 @@ import importlib # Local imports. from settings import SERVER_PORTS, SERVER_TIMEOUT, SERVER_POOL_PORT from registry import registry - +from evaluate_python import EvaluatePython +from evaluate_c import EvaluateC +from evaluate_cpp import EvaluateCpp +from evaluate_java import EvaluateJava +from evaluate_scilab import EvaluateScilab +from evaluate_bash import EvaluateBash MY_DIR = abspath(dirname(__file__)) -registry.register('python', ) -registry.register('py', MyTestCode) - def run_as_nobody(): """Runs the current process as nobody.""" # Set the effective uid and to that of nobody. @@ -48,166 +49,6 @@ def run_as_nobody(): os.setegid(nobody.pw_gid) os.seteuid(nobody.pw_uid) - -# Raised when the code times-out. -# c.f. http://pguides.net/python/timeout-a-function -class TimeoutException(Exception): - pass - - -def timeout_handler(signum, frame): - """A handler for the ALARM signal.""" - raise TimeoutException('Code took too long to run.') - -def create_signal_handler(): - """Add a new signal handler for the execution of this code.""" - prev_handler = signal.signal(signal.SIGALRM, timeout_handler) - signal.alarm(SERVER_TIMEOUT) - return prev_handler - -def set_original_signal_handler(old_handler=None): - """Set back any original signal handler.""" - if old_handler is not None: - signal.signal(signal.SIGALRM, old_handler) - return - else: - raise Exception("Signal Handler: object cannot be NoneType") - -def delete_signal_handler(): - signal.alarm(0) - return - - - -############################################################################### -# `TestCode` class. -############################################################################### -class TestCode(object): - """Tests the code obtained from Code Server""" - def __init__(self, test_parameter, language, user_answer, ref_code_path=None, in_dir=None): - msg = 'Code took more than %s seconds to run. You probably '\ - 'have an infinite loop in your code.' % SERVER_TIMEOUT - self.timeout_msg = msg - self.test_parameter = test_parameter - self.language = language.lower() - self.user_answer = user_answer - self.ref_code_path = ref_code_path - self.in_dir = in_dir - - def run_code(self): - """Tests given code (`answer`) with the test cases based on - given arguments. - - The ref_code_path is a path to the reference code. - The reference code will call the function submitted by the student. - The reference code will check for the expected output. - - If the path's start with a "/" then we assume they are absolute paths. - If not, we assume they are relative paths w.r.t. the location of this - code_server script. - - 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). - - Returns - ------- - - A tuple: (success, error message). - """ - self._change_dir(self.in_dir) - - # Add a new signal handler for the execution of this code. - prev_handler = create_signal_handler() - success = False - - # Do whatever testing needed. - try: - success, err = self.evaluate_code() - - except TimeoutException: - err = self.timeout_msg - except: - type, value = sys.exc_info()[:2] - err = "Error: {0}".format(repr(value)) - finally: - # Set back any original signal handler. - set_original_signal_handler(prev_handler) - - # Cancel the signal - delete_signal_handler() - - result = {'success': success, 'error': err} - return result - - def evaluate_code(self): - raise NotImplementedError("evaluate_code method not implemented") - - def _create_submit_code_file(self, file_name): - """ Write the code (`answer`) to a file and set the file path""" - # File name/extension depending on the question language - submit_f = open(file_name, 'w') - submit_f.write(self.user_answer.lstrip()) - submit_f.close() - submit_path = abspath(submit_f.name) - if sfile_elf.language == "bash": - self._set_file_as_executable(submit_path) - - return submit_path - - def _set_file_as_executable(self, fname): - os.chmod(fname, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR - | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP - | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) - - def _set_test_code_file_path(self, ref_path=None, test_case_path=None): - # ref_path, test_case_path = self.ref_code_path.split(',') - - if ref_path and not ref_path.startswith('/'): - ref_path = join(MY_DIR, ref_path) - if test_case_path and not test_case_path.startswith('/'): - test_case_path = join(MY_DIR, test_case_path) - - return ref_path, test_case_path - - def _run_command(self, cmd_args, *args, **kw): - """Run a command in a subprocess while blocking, the process is killed - if it takes more than 2 seconds to run. Return the Popen object, the - stdout and stderr. - """ - try: - proc = subprocess.Popen(cmd_args, *args, **kw) - stdout, stderr = proc.communicate() - except TimeoutException: - # Runaway code, so kill it. - proc.kill() - # Re-raise exception. - raise - return proc, stdout, stderr - - def _compile_command(self, cmd, *args, **kw): - """Compiles C/C++/java code and returns errors if any. - Run a command in a subprocess while blocking, the process is killed - if it takes more than 2 seconds to run. Return the Popen object, the - stderr. - """ - try: - proc_compile = subprocess.Popen(cmd, shell=True, stdin=None, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out, err = proc_compile.communicate() - except TimeoutException: - # Runaway code, so kill it. - proc_compile.kill() - # Re-raise exception. - raise - return proc_compile, err - - def _change_dir(self, in_dir): - if in_dir is not None and isdir(in_dir): - os.chdir(in_dir) - - ############################################################################### # `CodeServer` class. ############################################################################### @@ -219,34 +60,17 @@ class CodeServer(object): self.port = port self.queue = queue - def check_code(self, info_parameter, in_dir=None): - """Calls the TestCode Class to test the current code""" - info_parameter = json.loads(info_parameter) - test_parameter = info_parameter.get("test_parameter") - language = info_parameter.get("language") - user_answer = info_parameter.get("user_answer") - ref_code_path = info_parameter.get("ref_code_path") - - eval_module_name = "evaluate_{0}".format(language.lower()) - eval_class_name = "Evaluate{0}".format(language.capitalize()) - - get_class = self._sub_class_factory(eval_module_name, eval_class_name) + def check_code(self, info_parameter, language, in_dir=None): + """Calls the TestCode SUb Class based on language to test the current code""" + evaluate_code_class = registry.get_class(language) + evaluate_code_instance = evaluate_code_class.from_json(info_parameter, language, in_dir) + result = evaluate_code_instance.run_code() - test_code_class = get_class(test_parameter, language, user_answer, ref_code_path, in_dir) - result = test_code_class.run_code() # Put us back into the server pool queue since we are free now. self.queue.put(self.port) return json.dumps(result) - def _sub_class_factory(self, module_name, class_name): - # load the module, will raise ImportError if module cannot be loaded - get_module = importlib.import_module(module_name) - # get the class, will raise AttributeError if class cannot be found - get_class = getattr(get_module, class_name) - - return get_class - def run(self): """Run XMLRPC server, serving our methods.""" server = SimpleXMLRPCServer(("localhost", self.port)) diff --git a/testapp/exam/evaluate_bash.py b/testapp/exam/evaluate_bash.py index 57c89ae..fd769cd 100644 --- a/testapp/exam/evaluate_bash.py +++ b/testapp/exam/evaluate_bash.py @@ -7,16 +7,17 @@ import subprocess import importlib # local imports -from code_server import TestCode +from test_code import TestCode from registry import registry class EvaluateBash(TestCode): """Tests the Bash code obtained from Code Server""" def evaluate_code(self): - submit_path = self._create_submit_code_file('submit.sh') + fpath = self.create_submit_code_file('submit.sh') + submit_path = self.set_file_as_executable(fpath) get_ref_path, get_test_case_path = self.ref_code_path.strip().split(',') - ref_path, test_case_path = self._set_test_code_file_path(get_ref_path, get_test_case_path) + ref_path, test_case_path = self.set_test_code_file_path(get_ref_path, get_test_case_path) success = False success, err = self.check_bash_script(ref_path, submit_path, @@ -61,11 +62,11 @@ class EvaluateBash(TestCode): return False, "Script %s is not executable" % submit_path if test_case_path is None or "": - ret = self._run_command(ref_path, stdin=None, + ret = self.run_command(ref_path, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc, inst_stdout, inst_stderr = ret - ret = self._run_command(submit_path, stdin=None, + ret = self.run_command(submit_path, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc, stdnt_stdout, stdnt_stderr = ret @@ -92,12 +93,12 @@ class EvaluateBash(TestCode): loop_count += 1 if valid_answer: args = [ref_path] + [x for x in test_case.split()] - ret = self._run_command(args, stdin=None, + ret = self.run_command(args, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc, inst_stdout, inst_stderr = ret args = [submit_path]+[x for x in test_case.split()] - ret = self._run_command(args, stdin=None, + ret = self.run_command(args, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc, stdnt_stdout, stdnt_stderr = ret @@ -109,4 +110,4 @@ class EvaluateBash(TestCode): stdnt_stdout+stdnt_stderr) return False, err -registry.register('bash', evaluate_bash, EvaluateBash)
\ No newline at end of file +registry.register('bash', EvaluateBash)
\ No newline at end of file diff --git a/testapp/exam/evaluate_c.py b/testapp/exam/evaluate_c.py index bbe0e87..0700daa 100644 --- a/testapp/exam/evaluate_c.py +++ b/testapp/exam/evaluate_c.py @@ -7,29 +7,29 @@ import subprocess import importlib # local imports -from code_server import TestCode +from test_code import TestCode from registry import registry class EvaluateC(TestCode): """Tests the C code obtained from Code Server""" def evaluate_code(self): - submit_path = self._create_submit_code_file('submit.c') + submit_path = self.create_submit_code_file('submit.c') get_ref_path = self.ref_code_path - ref_path, test_case_path = self._set_test_code_file_path(get_ref_path) + ref_path, test_case_path = self.set_test_code_file_path(get_ref_path) success = False # Set file paths - c_user_output_path = os.getcwd() + '/output', - c_ref_output_path = os.getcwd() + '/executable', + c_user_output_path = os.getcwd() + '/output' + c_ref_output_path = os.getcwd() + '/executable' # Set command variables - compile_command = 'g++ {0} -c -o {1}'.format(submit_path, - c_user_output_path), + compile_command = 'g++ {0} -c -o {1}'.format(submit_path, + c_user_output_path) compile_main = 'g++ {0} {1} -o {2}'.format(ref_path, c_user_output_path, - c_ref_output_path), - run_command_args = c_ref_output_path + c_ref_output_path) + run_command_args = [c_ref_output_path] remove_user_output = c_user_output_path remove_ref_output = c_ref_output_path @@ -72,21 +72,21 @@ class EvaluateC(TestCode): success = False # output_path = os.getcwd() + '/output' - ret = self._compile_command(compile_command) + ret = self.compile_command(compile_command) proc, stdnt_stderr = ret # if self.language == "java": - stdnt_stderr = self._remove_null_substitute_char(stdnt_stderr) + stdnt_stderr = self.remove_null_substitute_char(stdnt_stderr) # Only if compilation is successful, the program is executed # And tested with testcases if stdnt_stderr == '': - ret = self._compile_command(compile_main) + ret = self.compile_command(compile_main) proc, main_err = ret # if self.language == "java": - # main_err = self._remove_null_substitute_char(main_err) + main_err = self.remove_null_substitute_char(main_err) if main_err == '': - ret = self._run_command(run_command_args, stdin=None, + ret = self.run_command(run_command_args, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc, stdout, stderr = ret @@ -121,7 +121,8 @@ class EvaluateC(TestCode): return success, err - def _remove_null_substitute_char(self, string): + + def remove_null_substitute_char(self, string): """Returns a string without any null and substitute characters""" stripped = "" for c in string: @@ -129,4 +130,4 @@ class EvaluateC(TestCode): stripped = stripped + c return ''.join(stripped) -registry.register('c', evaluate_c, EvaluateC)
\ No newline at end of file +registry.register('c', EvaluateC)
\ No newline at end of file diff --git a/testapp/exam/evaluate_cpp.py b/testapp/exam/evaluate_cpp.py index 87bd7a3..cffe744 100644 --- a/testapp/exam/evaluate_cpp.py +++ b/testapp/exam/evaluate_cpp.py @@ -8,7 +8,7 @@ import importlib # local imports from evaluate_c import EvaluateC -from code_server import TestCode +from test_code import TestCode from registry import registry @@ -16,21 +16,21 @@ from registry import registry class EvaluateCpp(EvaluateC, TestCode): """Tests the C code obtained from Code Server""" def evaluate_code(self): - submit_path = self._create_submit_code_file('submitstd.cpp') + submit_path = self.create_submit_code_file('submitstd.cpp') get_ref_path = self.ref_code_path - ref_path, test_case_path = self._set_test_code_file_path(get_ref_path) + ref_path, test_case_path = self.set_test_code_file_path(get_ref_path) success = False # Set file paths - c_user_output_path = os.getcwd() + '/output', - c_ref_output_path = os.getcwd() + '/executable', + c_user_output_path = os.getcwd() + '/output' + c_ref_output_path = os.getcwd() + '/executable' # Set command variables compile_command = 'g++ {0} -c -o {1}'.format(submit_path, - c_user_output_path), + c_user_output_path) compile_main = 'g++ {0} {1} -o {2}'.format(ref_path, c_user_output_path, - c_ref_output_path), + c_ref_output_path) run_command_args = c_ref_output_path remove_user_output = c_user_output_path remove_ref_output = c_ref_output_path @@ -44,4 +44,4 @@ class EvaluateCpp(EvaluateC, TestCode): return success, err -registry.register('cpp', evaluate_cpp, EvaluateCpp)
\ No newline at end of file +registry.register('cpp', EvaluateCpp)
\ No newline at end of file diff --git a/testapp/exam/evaluate_java.py b/testapp/exam/evaluate_java.py index f908102..d3d4e2a 100644 --- a/testapp/exam/evaluate_java.py +++ b/testapp/exam/evaluate_java.py @@ -8,7 +8,7 @@ import importlib # local imports from evaluate_c import EvaluateC -from code_server import TestCode +from test_code import TestCode from registry import registry @@ -16,14 +16,14 @@ from registry import registry class EvaluateJava(EvaluateC, TestCode): """Tests the C code obtained from Code Server""" def evaluate_code(self): - submit_path = self._create_submit_code_file('Test.java') + submit_path = self.create_submit_code_file('Test.java') get_ref_path = self.ref_code_path - ref_path, test_case_path = self._set_test_code_file_path(get_ref_path) + ref_path, test_case_path = self.set_test_code_file_path(get_ref_path) success = False # Set file paths java_student_directory = os.getcwd() + '/' - java_ref_file_name = (ref_code_path.split('/')[-1]).split('.')[0], + java_ref_file_name = (ref_code_path.split('/')[-1]).split('.')[0] # Set command variables compile_command = 'javac {0}'.format(submit_code_path), @@ -46,4 +46,4 @@ class EvaluateJava(EvaluateC, TestCode): return success, err -registry.register('java', evaluate_java, EvaluateJava)
\ No newline at end of file +registry.register('java', EvaluateJava)
\ No newline at end of file diff --git a/testapp/exam/evaluate_python.py b/testapp/exam/evaluate_python.py index 18fde43..3af82b6 100644 --- a/testapp/exam/evaluate_python.py +++ b/testapp/exam/evaluate_python.py @@ -6,7 +6,7 @@ from os.path import join import importlib # local imports -from code_server import TestCode +from test_code import TestCode from registry import registry class EvaluatePython(TestCode): @@ -36,6 +36,7 @@ class EvaluatePython(TestCode): del tb return success, err + # Private Protocol def _create_test_case(self): """ Create assert based test cases in python @@ -52,4 +53,4 @@ class EvaluatePython(TestCode): test_code += tcode + "\n" return test_code -registry.register('python', evaluate_python, EvaluatePython)
\ No newline at end of file +registry.register('python', EvaluatePython)
\ No newline at end of file diff --git a/testapp/exam/evaluate_scilab.py b/testapp/exam/evaluate_scilab.py index 1874cf6..f4253ff 100644 --- a/testapp/exam/evaluate_scilab.py +++ b/testapp/exam/evaluate_scilab.py @@ -7,21 +7,21 @@ import re import importlib # local imports -from code_server import TestCode -from registry import registryz +from test_code import TestCode +from registry import registry class EvaluateScilab(TestCode): """Tests the Scilab code obtained from Code Server""" # def evaluate_scilab_code(self): def evaluate_code(self): - submit_path = self._create_submit_code_file('function.sci') - ref_path, test_case_path = self._set_test_code_file_path() + submit_path = self.create_submit_code_file('function.sci') + ref_path, test_case_path = self.set_test_code_file_path() success = False cmd = 'printf "lines(0)\nexec(\'{0}\',2);\nquit();"'.format(ref_path) cmd += ' | timeout 8 scilab-cli -nb' - ret = self._run_command(cmd, + ret = self.run_command(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -44,6 +44,7 @@ class EvaluateScilab(TestCode): return success, err + # Private Protocol def _remove_scilab_exit(self, string): """ Removes exit, quit and abort from the scilab code @@ -79,4 +80,4 @@ class EvaluateScilab(TestCode): strip_out = strip_out+"\n"+l.strip() return strip_out -registry.register('scilab', evaluate_scilab, EvaluateScilab)
\ No newline at end of file +registry.register('scilab', EvaluateScilab)
\ No newline at end of file diff --git a/testapp/exam/java_files/main_array_sum.java b/testapp/exam/java_files/main_array_sum.java new file mode 100644 index 0000000..5eae299 --- /dev/null +++ b/testapp/exam/java_files/main_array_sum.java @@ -0,0 +1,36 @@ +class main_array_sum +{ + public static <E> void check(E expect, E result) + { + if(result.equals(expect)) + { + System.out.println("Correct:\nOutput expected "+expect+" and got "+result); + } + else + { + System.out.println("Incorrect:\nOutput expected "+expect+" but got "+result); + System.exit(1); + } + } + public static void main(String arg[]) + { + int result; + Test t = new Test(); + int x[] = {0,0,0,0,0}; + result = t.array_sum(x); + System.out.println("Input submitted to the function: {0,0,0,0,0}"); + check(0, result); + int a[] = {1,2,3,4,5}; + result = t.array_sum(a); + System.out.println("Input submitted to the function: {1,2,3,4,5}"); + check(15, result); + int b[] = {1,2,3,0,0}; + result = t.array_sum(b); + System.out.println("Input submitted to the function: {1,2,3,0,0}"); + check(6, result); + int c[] = {1,1,1,1,1}; + result = t.array_sum(c); + System.out.println("Input submitted to the function: {1,1,1,1,1}"); + check(5, result); + } +} diff --git a/testapp/exam/java_files/main_fact.java b/testapp/exam/java_files/main_fact.java new file mode 100644 index 0000000..325dab6 --- /dev/null +++ b/testapp/exam/java_files/main_fact.java @@ -0,0 +1,29 @@ +class main_fact +{ + public static <E> void check(E expect, E result) + { + if(result.equals(expect)) + { + System.out.println("Correct:\nOutput expected "+expect+" and got "+result); + } + else + { + System.out.println("Incorrect:\nOutput expected "+expect+" but got "+result); + System.exit(1); + } + } + public static void main(String arg[]) + { + Test t = new Test(); + int result; + result = t.factorial(0); + System.out.println("Input submitted to the function: 0"); + check(1, result); + result = t.factorial(3); + System.out.println("Input submitted to the function: 3"); + check(6, result); + result = t.factorial(4); + System.out.println("Input submitted to the function: 4"); + check(24, result); + } +} diff --git a/testapp/exam/java_files/main_great.java b/testapp/exam/java_files/main_great.java new file mode 100644 index 0000000..4bfcb1f --- /dev/null +++ b/testapp/exam/java_files/main_great.java @@ -0,0 +1,39 @@ +class main_great +{ + public static <E> void check(E expect, E result) + { + if(result.equals(expect)) + { + System.out.println("Correct:\nOutput expected "+expect+" and got "+result); + } + else + { + System.out.println("Incorrect:\nOutput expected "+expect+" but got "+result); + System.exit(1); + } + } + public static void main(String arg[]) + { + Test t = new Test(); + int result; + result = t.greatest(1, 3, 4); + System.out.println("Input submitted to the function: 1, 3, 4"); + check(4, result); + result = t.greatest(5, 10, 3); + System.out.println("Input submitted to the function: 5, 10, 3"); + check(10, result); + result = t.greatest(6, 1, 4); + System.out.println("Input submitted to the function: 6, 1, 4"); + check(6, result); + result = t.greatest(6, 11, 14); + System.out.println("Input submitted to the function: 6, 11, 14"); + check(14, result); + result = t.greatest(3, 31, 4); + System.out.println("Input submitted to the function: 3, 31, 4"); + check(31, result); + result = t.greatest(26, 13, 3); + System.out.println("Input submitted to the function: 26, 13, 3"); + check(26, result); + + } +} diff --git a/testapp/exam/java_files/main_hello_name.java b/testapp/exam/java_files/main_hello_name.java new file mode 100644 index 0000000..84bb282 --- /dev/null +++ b/testapp/exam/java_files/main_hello_name.java @@ -0,0 +1,29 @@ +class main_hello_name +{ + public static <E> void check(E expect, E result) + { + if(result.equals(expect)) + { + System.out.println("Correct:\nOutput expected "+expect+" and got "+result); + } + else + { + System.out.println("Incorrect:\nOutput expected "+expect+" but got "+result); + System.exit(1); + } + } + public static void main(String arg[]) + { + Test t = new Test(); + String result; + result = t.hello_name("Raj"); + System.out.println("Input submitted to the function: 'Raj'"); + check("hello Raj", result); + result = t.hello_name("Pratham"); + System.out.println("Input submitted to the function: 'Pratham'"); + check("hello Pratham", result); + result = t.hello_name("Ram"); + System.out.println("Input submitted to the function: 'Ram'"); + check("hello Ram", result); + } +} diff --git a/testapp/exam/java_files/main_lastDigit.java b/testapp/exam/java_files/main_lastDigit.java new file mode 100644 index 0000000..05439e2 --- /dev/null +++ b/testapp/exam/java_files/main_lastDigit.java @@ -0,0 +1,36 @@ +class main_lastDigit +{ + public static <E> void check(E expect, E result) + { + if(result.equals(expect)) + { + System.out.println("Correct:\nOutput expected "+expect+" and got "+result+"\n"); + } + else + { + System.out.println("Incorrect:\nOutput expected "+expect+" but got "+result+"\n"); + System.exit(1); + } + } + public static void main(String arg[]) + { + Test t = new Test(); + boolean result; + result= t.lastDigit(12, 2, 13); + System.out.println("Input submitted to the function: 12, 2, 13"); + check(true, result); + result = t.lastDigit(11, 52, 32); + System.out.println("Input submitted to the function: 11, 52, 32"); + check(true, result); + result = t.lastDigit(6, 34, 22); + System.out.println("Input submitted to the function: 6, 34, 22"); + check(false, result); + result = t.lastDigit(6, 46, 26); + System.out.println("Input submitted to the function: 63"); + check(true, result); + result = t.lastDigit(91, 90, 92); + System.out.println("Input submitted to the function: 91"); + check(false, result); + + } +} diff --git a/testapp/exam/java_files/main_moreThan30.java b/testapp/exam/java_files/main_moreThan30.java new file mode 100644 index 0000000..7da31cb --- /dev/null +++ b/testapp/exam/java_files/main_moreThan30.java @@ -0,0 +1,36 @@ +class main_moreThan30 +{ + public static <E> void check(E expect, E result) + { + if(result.equals(expect)) + { + System.out.println("Correct:\nOutput expected "+expect+" and got "+result+"\n"); + } + else + { + System.out.println("Incorrect:\nOutput expected "+expect+" but got "+result+"\n"); + System.exit(1); + } + } + public static void main(String arg[]) + { + Test t = new Test(); + boolean result; + result= t.moreThan30(30); + System.out.println("Input submitted to the function: 30"); + check(false, result); + result = t.moreThan30(151); + System.out.println("Input submitted to the function: 151"); + check(true, result); + result = t.moreThan30(66); + System.out.println("Input submitted to the function: 66"); + check(false, result); + result = t.moreThan30(63); + System.out.println("Input submitted to the function: 63"); + check(true, result); + result = t.moreThan30(91); + System.out.println("Input submitted to the function: 91"); + check(true, result); + + } +} diff --git a/testapp/exam/java_files/main_palindrome.java b/testapp/exam/java_files/main_palindrome.java new file mode 100644 index 0000000..c0745f9 --- /dev/null +++ b/testapp/exam/java_files/main_palindrome.java @@ -0,0 +1,29 @@ +class main_palindrome +{ + public static <E> void check(E expect, E result) + { + if(result.equals(expect)) + { + System.out.println("Correct:\nOutput expected "+expect+" and got "+result+"\n"); + } + else + { + System.out.println("Incorrect:\nOutput expected "+expect+" but got "+result+"\n"); + System.exit(1); + } + } + public static void main(String arg[]) + { + Test t = new Test(); + boolean result; + result= t.palindrome(123); + System.out.println("Input submitted to the function: 123"); + check(false, result); + result = t.palindrome(151); + System.out.println("Input submitted to the function: 151"); + check(true, result); + result = t.palindrome(23432); + System.out.println("Input submitted to the function: 23432"); + check(true, result); + } +} diff --git a/testapp/exam/java_files/main_square.java b/testapp/exam/java_files/main_square.java new file mode 100644 index 0000000..5cb8c35 --- /dev/null +++ b/testapp/exam/java_files/main_square.java @@ -0,0 +1,32 @@ +class main_square +{ + public static <E> void check(E expect, E result) + { + if(result.equals(expect)) + { + System.out.println("Correct:\nOutput expected "+expect+" and got "+result); + } + else + { + System.out.println("Incorrect:\nOutput expected "+expect+" but got "+result); + System.exit(1); + } + } + public static void main(String arg[]) + { + Test t = new Test(); + int result, input, output; + input = 0; output = 0; + result = t.square_num(input); + System.out.println("Input submitted to the function: "+input); + check(output, result); + input = 5; output = 25; + result = t.square_num(input); + System.out.println("Input submitted to the function: "+input); + check(output, result); + input = 6; output = 36; + result = t.square_num(input); + System.out.println("Input submitted to the function: "+input); + check(output, result); + } +} diff --git a/testapp/exam/models.py b/testapp/exam/models.py index 874c81c..d0c9cc2 100644 --- a/testapp/exam/models.py +++ b/testapp/exam/models.py @@ -87,7 +87,7 @@ class Question(models.Model): # Tags for the Question. tags = TaggableManager() - def consolidate_answer_data(self, test_cases, user_answer): #test + def consolidate_answer_data(self, test_cases, user_answer): test_case_parameter = [] info_parameter = {} @@ -113,7 +113,7 @@ class Question(models.Model): parameter_dict['pos_args'] = pos_args_list test_case_parameter.append(parameter_dict) - info_parameter['language'] = self.language + # info_parameter['language'] = self.language info_parameter['id'] = self.id info_parameter['user_answer'] = user_answer info_parameter['test_parameter'] = test_case_parameter diff --git a/testapp/exam/scilab_files/test_add.sce b/testapp/exam/scilab_files/test_add.sce new file mode 100644 index 0000000..a317cdb --- /dev/null +++ b/testapp/exam/scilab_files/test_add.sce @@ -0,0 +1,29 @@ +mode(-1) +exec("function.sci",-1); +i = 0 +p = add(3,5); +correct = (p == 8); +if correct then + i=i+1 +end +disp("Input submitted 3 and 5") +disp("Expected output 8 got " + string(p)) +p = add(22,-20); +correct = (p==2); +if correct then + i=i+1 +end +disp("Input submitted 22 and -20") +disp("Expected output 2 got " + string(p)) +p =add(91,0); +correct = (p==91); +if correct then + i=i+1 +end +disp("Input submitted 91 and 0") +disp("Expected output 91 got " + string(p)) +if i==3 then + exit(5); +else + exit(3); +end diff --git a/testapp/exam/test_code.py b/testapp/exam/test_code.py new file mode 100644 index 0000000..8930f55 --- /dev/null +++ b/testapp/exam/test_code.py @@ -0,0 +1,182 @@ +import sys +from SimpleXMLRPCServer import SimpleXMLRPCServer +import pwd +import os +import stat +from os.path import isdir, dirname, abspath, join, isfile +import signal +from multiprocessing import Process, Queue +import subprocess +import re +import json +import importlib +# Local imports. +from settings import SERVER_PORTS, SERVER_TIMEOUT, SERVER_POOL_PORT + + +MY_DIR = abspath(dirname(__file__)) + +# Raised when the code times-out. +# c.f. http://pguides.net/python/timeout-a-function +class TimeoutException(Exception): + pass + + +def timeout_handler(signum, frame): + """A handler for the ALARM signal.""" + raise TimeoutException('Code took too long to run.') + +def create_signal_handler(): + """Add a new signal handler for the execution of this code.""" + prev_handler = signal.signal(signal.SIGALRM, timeout_handler) + signal.alarm(SERVER_TIMEOUT) + return prev_handler + +def set_original_signal_handler(old_handler=None): + """Set back any original signal handler.""" + if old_handler is not None: + signal.signal(signal.SIGALRM, old_handler) + return + else: + raise Exception("Signal Handler: object cannot be NoneType") + +def delete_signal_handler(): + signal.alarm(0) + return + + + +############################################################################### +# `TestCode` class. +############################################################################### +class TestCode(object): + """Tests the code obtained from Code Server""" + def __init__(self, test_parameter, language, user_answer, ref_code_path=None, in_dir=None): + msg = 'Code took more than %s seconds to run. You probably '\ + 'have an infinite loop in your code.' % SERVER_TIMEOUT + self.timeout_msg = msg + self.test_parameter = test_parameter + self.language = language.lower() + self.user_answer = user_answer + self.ref_code_path = ref_code_path + self.in_dir = in_dir + + @classmethod + def from_json(cls, blob, language, in_dir): + info_parameter = json.loads(blob) + test_parameter = info_parameter.get("test_parameter") + user_answer = info_parameter.get("user_answer") + ref_code_path = info_parameter.get("ref_code_path") + + instance = cls(test_parameter, language, user_answer, ref_code_path, in_dir) + return instance + + def run_code(self): + """Tests given code (`answer`) with the test cases based on + given arguments. + + The ref_code_path is a path to the reference code. + The reference code will call the function submitted by the student. + The reference code will check for the expected output. + + If the path's start with a "/" then we assume they are absolute paths. + If not, we assume they are relative paths w.r.t. the location of this + code_server script. + + 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). + + Returns + ------- + + A tuple: (success, error message). + """ + self._change_dir(self.in_dir) + + # Add a new signal handler for the execution of this code. + prev_handler = create_signal_handler() + success = False + + # Do whatever testing needed. + try: + success, err = self.evaluate_code() + + except TimeoutException: + err = self.timeout_msg + except: + type, value = sys.exc_info()[:2] + err = "Error: {0}".format(repr(value)) + finally: + # Set back any original signal handler. + set_original_signal_handler(prev_handler) + + # Cancel the signal + delete_signal_handler() + + result = {'success': success, 'error': err} + return result + + def evaluate_code(self): + raise NotImplementedError("evaluate_code method not implemented") + + def create_submit_code_file(self, file_name): + """ Write the code (`answer`) to a file and set the file path""" + # File name/extension depending on the question language + submit_f = open(file_name, 'w') + submit_f.write(self.user_answer.lstrip()) + submit_f.close() + submit_path = abspath(submit_f.name) + + return submit_path + + def set_file_as_executable(self, fname): + os.chmod(fname, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR + | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP + | stat.S_IROTH | stat.S_IWOTH | stat.S_IXOTH) + + def set_test_code_file_path(self, ref_path=None, test_case_path=None): + if ref_path and not ref_path.startswith('/'): + ref_path = join(MY_DIR, ref_path) + + if test_case_path and not test_case_path.startswith('/'): + test_case_path = join(MY_DIR, test_case_path) + + return ref_path, test_case_path + + def run_command(self, cmd_args, *args, **kw): + """Run a command in a subprocess while blocking, the process is killed + if it takes more than 2 seconds to run. Return the Popen object, the + stdout and stderr. + """ + try: + proc = subprocess.Popen(cmd_args, *args, **kw) + stdout, stderr = proc.communicate() + except TimeoutException: + # Runaway code, so kill it. + proc.kill() + # Re-raise exception. + raise + return proc, stdout, stderr + + def compile_command(self, cmd, *args, **kw): + """Compiles C/C++/java code and returns errors if any. + Run a command in a subprocess while blocking, the process is killed + if it takes more than 2 seconds to run. Return the Popen object, the + stderr. + """ + try: + proc_compile = subprocess.Popen(cmd, shell=True, stdin=None, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = proc_compile.communicate() + except TimeoutException: + # Runaway code, so kill it. + proc_compile.kill() + # Re-raise exception. + raise + return proc_compile, err + + def _change_dir(self, in_dir): + if in_dir is not None and isdir(in_dir): + os.chdir(in_dir)
\ No newline at end of file diff --git a/testapp/exam/views.py b/testapp/exam/views.py index 840f30a..508b623 100644 --- a/testapp/exam/views.py +++ b/testapp/exam/views.py @@ -1025,7 +1025,7 @@ def validate_answer(user, user_answer, question, info_parameter=None): message = 'Correct answer' elif question.type == 'code': user_dir = get_user_dir(user) - json_result = code_server.run_code(info_parameter, user_dir) + json_result = code_server.run_code(info_parameter, question.language, user_dir) result = json.loads(json_result) if result.get('success'): correct = True diff --git a/testapp/exam/xmlrpc_clients.py b/testapp/exam/xmlrpc_clients.py index 33fbc57..5d95cae 100644 --- a/testapp/exam/xmlrpc_clients.py +++ b/testapp/exam/xmlrpc_clients.py @@ -22,7 +22,7 @@ class CodeServerProxy(object): pool_url = 'http://localhost:%d' % (SERVER_POOL_PORT) self.pool_server = ServerProxy(pool_url) - def run_code(self, info_parameter, user_dir): + def run_code(self, info_parameter, language, user_dir): """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 @@ -50,7 +50,7 @@ class CodeServerProxy(object): try: server = self._get_server() - result = server.check_code(info_parameter, user_dir) + result = server.check_code(info_parameter, language, user_dir) except ConnectionError: result = json.dumps({'success': False, 'error': 'Unable to connect to any code servers!'}) return result |