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 += ( "
" + get_node_value(el.getElementsByTagName("MethodName")) + "
" ) r = get_node_value(el.getElementsByTagName("Successful")) if r == "true": self.solution.details += '
Passed
' else: self.solution.details += '
Failed
' mes = get_node_value(el.getElementsByTagName("Message")) self.solution.details += "
{}
".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)