276 lines
10 KiB
Python
276 lines
10 KiB
Python
from os import listdir, mkdir
|
|
from os.path import basename, isdir
|
|
from shutil import rmtree, copyfile
|
|
from threading import Thread
|
|
from xml.dom.minidom import parse
|
|
|
|
from Main.models import *
|
|
from .main import solution_path
|
|
|
|
|
|
def start_new(host):
|
|
in_queue = list(Solution.objects.filter(result="IN QUEUE"))
|
|
if in_queue:
|
|
sol = in_queue[0]
|
|
for s in in_queue:
|
|
dif = (
|
|
s.task.block.priority * 10
|
|
+ s.task.priority
|
|
- sol.task.block.priority * 10
|
|
- sol.task.priority
|
|
)
|
|
if dif > 0:
|
|
sol = s
|
|
elif dif == 0 and s.id < sol.id:
|
|
sol = s
|
|
Tester(sol, host).test()
|
|
|
|
|
|
def is_project(path):
|
|
return any([x.endswith(".csproj") for x in listdir(path)])
|
|
|
|
|
|
def get_node_value(element):
|
|
return element[0].firstChild.nodeValue
|
|
|
|
|
|
def nunit_path(working_dir):
|
|
return "..{}".format(sep) * len(
|
|
working_dir.split(sep)
|
|
) + "nunit_console{}nunit3-console.exe".format(sep)
|
|
|
|
|
|
class Tester:
|
|
def __init__(self, solution, host):
|
|
self.solution = solution
|
|
self.host = host
|
|
self.working_dir = ""
|
|
self.files = []
|
|
|
|
# функция компиляции
|
|
def build(self, path):
|
|
# решение для UNIX
|
|
# shell('msbuild ' + path + ' /p:Configuration=Debug')
|
|
|
|
# решение для Windows
|
|
cmd = "dotnet build {} -o {}\\bin\\Debug".format(path, path)
|
|
with self.solution.log_fs as fs:
|
|
shell(cmd, fs)
|
|
|
|
def build_and_copy(self, path, working_dir):
|
|
if exists(join(path, "bin", "Debug")):
|
|
rmtree(join(path, "bin", "Debug"))
|
|
self.build(path)
|
|
name = basename(path)
|
|
if not exists(join(path, "bin", "Debug")) or not any(
|
|
x.endswith(".exe") for x in listdir(join(path, "bin", "Debug"))
|
|
):
|
|
return False
|
|
self.files.append(basename(path))
|
|
for file in listdir(join(path, "bin", "Debug")):
|
|
if exists(join(path, "bin", "Debug", file)):
|
|
new_file = join(working_dir, basename(file))
|
|
try:
|
|
copyfile(join(path, "bin", "Debug", file), new_file)
|
|
except:
|
|
pass
|
|
else:
|
|
return False
|
|
return True
|
|
|
|
def push(self):
|
|
solution = self.solution
|
|
if solution.result == "SOLUTION ERROR":
|
|
return
|
|
solution.result = "IN QUEUE"
|
|
solution.save()
|
|
from Main.models import System
|
|
|
|
if len(Solution.objects.filter(result="TESTING")) < int(
|
|
System.objects.get(key="queue_size").value
|
|
):
|
|
self.test()
|
|
|
|
def delete_everything(self):
|
|
ssp = solution_path(self.solution.path())
|
|
sln_path = join(ssp, ".idea")
|
|
if exists(sln_path):
|
|
rmtree(sln_path)
|
|
sln_path = join(ssp, ".vs")
|
|
if exists(sln_path):
|
|
rmtree(sln_path)
|
|
sln_path = ssp
|
|
for p in listdir(sln_path):
|
|
if isdir(join(sln_path, p)):
|
|
if exists(join(sln_path, p, "bin")):
|
|
rmtree(join(sln_path, p, "bin"))
|
|
if exists(join(sln_path, p, "obj")):
|
|
rmtree(join(sln_path, p, "obj"))
|
|
if exists(self.working_dir):
|
|
rmtree(self.working_dir)
|
|
if exists(join(self.solution.path(), "solution.zip")):
|
|
remove(join(self.solution.path(), "solution.zip"))
|
|
if exists(join(self.solution.path(), "__MACOSX")):
|
|
rmtree(join(self.solution.path(), "__MACOSX"))
|
|
if exists(join(sln_path, ".DS_Store")):
|
|
remove(join(sln_path, ".DS_Store"))
|
|
if exists(join(sln_path, "test_folder")):
|
|
rmtree(join(sln_path, "test_folder"))
|
|
|
|
def nunit_testing(self):
|
|
solution = self.solution
|
|
with self.solution.log_fs as fs:
|
|
fs.write(b"Building image\n")
|
|
shell(
|
|
"docker build -t solution_{} {}".format(self.solution.id, self.working_dir)
|
|
)
|
|
with self.solution.log_fs as fs:
|
|
fs.write(b"Image built successfully\n")
|
|
|
|
def execute():
|
|
with self.solution.log_fs as fs:
|
|
shell(
|
|
"docker run --name solution_container_{} solution_{}".format(
|
|
self.solution.id, self.solution.id
|
|
),
|
|
output=fs,
|
|
)
|
|
|
|
solution.write_log("Running container")
|
|
t = Thread(target=execute)
|
|
t.start()
|
|
t.join(self.solution.task.time_limit / 1000)
|
|
solution.write_log("Running finished")
|
|
with self.solution.log_fs as fs:
|
|
shell(
|
|
"docker cp solution_container_{}:/app/TestResults.xml {}".format(
|
|
self.solution.id, self.working_dir
|
|
),
|
|
fs,
|
|
)
|
|
with self.solution.log_fs as fs:
|
|
shell(
|
|
"docker rm --force solution_container_{}".format(self.solution.id), fs
|
|
)
|
|
with self.solution.log_fs as fs:
|
|
shell("docker image rm solution_{}".format(self.solution.id), fs)
|
|
if not exists(join(self.working_dir, "TestResults.xml")):
|
|
self.solution.set_result("Time limit")
|
|
solution.write_log("Result file not found in container")
|
|
return
|
|
solution.write_log("Result file found in container")
|
|
try:
|
|
doc = parse(join(self.working_dir, "TestResults.xml"))
|
|
res = (
|
|
get_node_value(doc.getElementsByTagName("Passed"))
|
|
+ "/"
|
|
+ get_node_value(doc.getElementsByTagName("Total"))
|
|
)
|
|
self.solution.details = ""
|
|
for el in doc.getElementsByTagName("Result"):
|
|
self.solution.details += (
|
|
"<h5><b>"
|
|
+ get_node_value(el.getElementsByTagName("MethodName"))
|
|
+ "</b></h5>"
|
|
)
|
|
r = get_node_value(el.getElementsByTagName("Successful"))
|
|
if r == "true":
|
|
self.solution.details += '<div style="color: green;">Passed</div>'
|
|
else:
|
|
self.solution.details += '<div style="color: red;">Failed</div>'
|
|
mes = get_node_value(el.getElementsByTagName("Message"))
|
|
self.solution.details += "<pre>{}</pre>".format(mes)
|
|
except:
|
|
solution.write_log("Unknown error")
|
|
res = "TEST ERROR"
|
|
self.solution.set_result(res)
|
|
|
|
def test(self):
|
|
solution = self.solution
|
|
solution.result = "TESTING"
|
|
solution.save()
|
|
try:
|
|
if not exists(self.solution.task.tests_path()):
|
|
with self.solution.log_fs as fs:
|
|
fs.write(b"No test file found\n")
|
|
solution.set_result("TEST ERROR")
|
|
solution.save()
|
|
self.delete_everything()
|
|
start_new(self.host)
|
|
return
|
|
sln_path = solution_path(join(MEDIA_ROOT, "solutions", str(solution.id)))
|
|
if sln_path == "":
|
|
solution.set_result("TEST ERROR")
|
|
solution.save()
|
|
self.delete_everything()
|
|
start_new(self.host)
|
|
return
|
|
working_dir = join(sln_path, "test_folder")
|
|
if exists(working_dir):
|
|
try:
|
|
rmtree(working_dir)
|
|
except:
|
|
remove(working_dir)
|
|
mkdir(working_dir)
|
|
with self.solution.log_fs as fs:
|
|
fs.write(b"Testing directory created\n")
|
|
for project in listdir(sln_path):
|
|
solution.write_log("Checking if {} is project".format(project))
|
|
prj = project
|
|
project = join(sln_path, project)
|
|
if (
|
|
isdir(project)
|
|
and is_project(project)
|
|
and basename(project) != "TestsProject"
|
|
):
|
|
if not self.build_and_copy(project, working_dir):
|
|
solution.set_result("Compilation error")
|
|
solution.write_log("Failed to compile project {}".format(prj))
|
|
solution.save()
|
|
self.delete_everything()
|
|
start_new(self.host)
|
|
return
|
|
dll_path = solution.task.tests_path()
|
|
solution.write_log("Copying test file to working directory")
|
|
copyfile(dll_path, join(working_dir, str(solution.task.id) + ".cs"))
|
|
solution.write_log("Test file copied")
|
|
for file in listdir("SprintTest"):
|
|
try:
|
|
copyfile(join("SprintTest", file), join(working_dir, file))
|
|
except:
|
|
pass
|
|
self.working_dir = working_dir
|
|
build_tests_cmd = "csc -out:{} -t:library /r:{} /r:{} /r:{} ".format(
|
|
join(self.working_dir, "tests.dll"),
|
|
join(self.working_dir, "SprintTest.dll"),
|
|
join(working_dir, "System.Runtime.dll"),
|
|
join(working_dir, "System.Reflection.dll"),
|
|
)
|
|
for file in self.files:
|
|
build_tests_cmd += "/r:{}.dll ".format(join(self.working_dir, file))
|
|
build_tests_cmd += self.solution.task.tests_path()
|
|
if exists(join(self.working_dir, "tests.dll")):
|
|
remove(join(self.working_dir, "tests.dll"))
|
|
solution.write_log("Building tests file started")
|
|
with self.solution.log_fs as fs:
|
|
shell(build_tests_cmd, fs)
|
|
with self.solution.log_fs as fs:
|
|
fs.write(b"Building tests file finished\n")
|
|
if exists(join(self.working_dir, "tests.dll")):
|
|
with self.solution.log_fs as fs:
|
|
fs.write(b"Got .dll tests file\n")
|
|
for file in ExtraFile.objects.filter(task=self.solution.task):
|
|
copyfile(file.path, join(working_dir, file.filename))
|
|
self.nunit_testing()
|
|
else:
|
|
solution.set_result("TEST ERROR")
|
|
solution.write_log("Failed to compile tests")
|
|
except:
|
|
solution.set_result("TEST ERROR")
|
|
raise
|
|
with self.solution.log_fs as fs:
|
|
fs.write(b"Unknown error\n")
|
|
solution.save()
|
|
self.delete_everything()
|
|
start_new(self.host)
|