-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun_tests.py
More file actions
133 lines (107 loc) · 4.04 KB
/
run_tests.py
File metadata and controls
133 lines (107 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import os
import subprocess
import json
import shutil
import xml.etree.ElementTree as ET
import re
DEBUG = 'N'
def log(message):
if DEBUG == 'S':
print(message)
# Set the classpath to include all dependencies and compiled classes
classpath = ':'.join(
[os.path.join(dp, f) for dp, dn, filenames in os.walk('/app/dependency') for f in filenames if f.endswith('.jar')]
) + ':/app/classes:/app/test-classes:/app'
log("Copying the student's code...")
# Copy the student's code to the correct directory
PACKAGE = 'empleados'
FILE_PATH = f'/app/classes/{PACKAGE}'
os.makedirs(FILE_PATH, exist_ok=True)
result = subprocess.run(['cp', '/tmp/exercise', f'{FILE_PATH}/EmpleadoBR.java'], check=True)
if result.returncode != 0:
error_message = {
"success": False,
"error": "Failed to copy the student's code"
}
print(json.dumps(error_message))
# Exit with an error code, the correction failed
exit(1)
log("Compiling the student's code...")
# Compile the student's code, replacing the stubs
compile_error_file = '/tmp/compile_errors.txt'
compile_command = [
'javac', '-cp', classpath, f'{FILE_PATH}/EmpleadoBR.java',
'-sourcepath', '/app/classes'
]
compile_result = subprocess.run(compile_command, stderr=subprocess.PIPE, text=True)
if compile_result.returncode != 0:
compile_errors = compile_result.stderr.replace(f'{FILE_PATH}/', '')
error_message = {
"success": False,
"error": f"Compilation failed: {compile_errors}"
}
print(json.dumps(error_message))
# Exit with an OK code, since the container succeeded but the correction failed
exit(0)
log("Compilation successful!")
log("Running the tests...")
# Run the JUnit Console Launcher to execute the tests
REPORTS_DIR = 'test-reports'
REPORTS_FILE = f'{REPORTS_DIR}/TEST-junit-jupiter.xml'
RESULT_FILE = '/tmp/test_results.txt'
ERROR_FILE = '/tmp/test_errors.txt'
# Remove the reports directory if it exists
shutil.rmtree(REPORTS_DIR, ignore_errors=True)
test_command = [
'java', '-jar', 'junit-platform-console-standalone.jar',
'--class-path', classpath,
'--scan-class-path',
'--details=tree',
f'--reports-dir={REPORTS_DIR}',
]
# We don't need the stdout, because it will generate report files
with open(os.devnull, 'w') as devnull:
run_result = subprocess.run(test_command, stdout=devnull, stderr=subprocess.PIPE, text=True)
# If junit console launcher returns 0, all tests passed
if run_result.returncode == 0:
log('All tests passed')
success_message = {
'success': True,
'grade': 10,
'comments': [ 'The code is working properly' ]
}
print(json.dumps(success_message))
# Exit with an OK code, the container succeeded and the correction passed
exit(0)
# The console launcher failed. We need to tell apart if the tests failed or the execution failed
# Content in stderr means that the execution failed
if run_result.stderr:
log(f'Failed to run the tests: {run_result.stderr}')
error_message = {
'success': False,
'error': f'Failed to run the tests: {run_result.stderr}'
}
print(json.dumps(error_message))
# The correction failed, probably because of something wrong in the container
exit(1)
# If we reach this point, everything went OK but some tests failed
# We will parse the JUnit XML file to get the failed tests
# and return the results as a success correction with errors
log('Some tests failed, parsing the results...')
def get_failed_tests(file_path):
tree = ET.parse(file_path)
root = tree.getroot()
def extract_display_name(text):
pattern = re.compile(r"display-name: (.+)")
match = pattern.search(text)
return match.group(1) if match else None
failure_errors = root.findall('.//testcase[failure]/system-out')
failure_descriptions = map(lambda x: extract_display_name(x.text), failure_errors)
return list(set(failure_descriptions))
# Create the JSON output
success_message = {
'success': True,
'grade': 0,
'comments': get_failed_tests(REPORTS_FILE)
}
print(json.dumps(success_message))