sprint/Main/Tester.py
Egor Matveev 9c0123cbf2 initial
2021-07-11 10:28:12 +03:00

244 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)