checker works
This commit is contained in:
parent
7028ac37b6
commit
5518c34636
@ -6,6 +6,7 @@ urlpatterns = [
|
|||||||
path("status", views.status),
|
path("status", views.status),
|
||||||
path("available", views.available),
|
path("available", views.available),
|
||||||
path("get_dynamic", views.get_dynamic),
|
path("get_dynamic", views.get_dynamic),
|
||||||
path("set_result", views.set_result),
|
path("save_solution", views.save_solution),
|
||||||
path("current_test", views.current_test),
|
path("save_progress", views.save_progress),
|
||||||
|
path("notify", views.notify)
|
||||||
]
|
]
|
||||||
|
@ -9,8 +9,9 @@ from django.utils import timezone
|
|||||||
|
|
||||||
from Checker.models import Checker
|
from Checker.models import Checker
|
||||||
from FileStorage.sync import synchronized_method
|
from FileStorage.sync import synchronized_method
|
||||||
from Main.models import Solution, SolutionFile, ExtraFile
|
from Main.models import Solution, SolutionFile, ExtraFile, Progress
|
||||||
from SprintLib.utils import generate_token
|
from SprintLib.utils import generate_token
|
||||||
|
from SprintLib.queue import notify as notification
|
||||||
|
|
||||||
|
|
||||||
def get_dynamic(request):
|
def get_dynamic(request):
|
||||||
@ -50,7 +51,7 @@ def available(request):
|
|||||||
with TemporaryDirectory() as tempdir:
|
with TemporaryDirectory() as tempdir:
|
||||||
with ZipFile(join(tempdir, "package.zip"), 'w') as zip_file:
|
with ZipFile(join(tempdir, "package.zip"), 'w') as zip_file:
|
||||||
for sf in SolutionFile.objects.filter(solution=solution):
|
for sf in SolutionFile.objects.filter(solution=solution):
|
||||||
zip_file.writestr(sf.path, sf.bytes)
|
zip_file.writestr(join('solution', sf.path), sf.bytes)
|
||||||
for ef in ExtraFile.objects.filter(task=solution.task):
|
for ef in ExtraFile.objects.filter(task=solution.task):
|
||||||
zip_file.writestr(ef.filename, ef.bytes)
|
zip_file.writestr(ef.filename, ef.bytes)
|
||||||
response = HttpResponse(open(join(tempdir, 'package.zip'), 'rb').read(), content_type='application/octet-stream', status=201)
|
response = HttpResponse(open(join(tempdir, 'package.zip'), 'rb').read(), content_type='application/octet-stream', status=201)
|
||||||
@ -62,17 +63,22 @@ def available(request):
|
|||||||
return JsonResponse({"status": "incorrect token"}, status=403)
|
return JsonResponse({"status": "incorrect token"}, status=403)
|
||||||
|
|
||||||
|
|
||||||
def set_result(request):
|
def save_solution(request):
|
||||||
try:
|
try:
|
||||||
checker = Checker.objects.get(dynamic_token=request.GET['token'])
|
checker = Checker.objects.get(dynamic_token=request.GET['token'])
|
||||||
solution = Solution.objects.get(id=request.GET['solution_id'])
|
solution = Solution.objects.get(id=request.GET['solution_id'])
|
||||||
result = request.GET['result']
|
result = request.GET['result']
|
||||||
|
test = request.GET.get("test")
|
||||||
|
extras = request.GET.get('extras')
|
||||||
if checker.set != solution.set:
|
if checker.set != solution.set:
|
||||||
return JsonResponse({"status": "incorrect solution"}, status=403)
|
return JsonResponse({"status": "incorrect solution"}, status=403)
|
||||||
solution.result = result
|
solution.result = result
|
||||||
|
solution.test = test
|
||||||
|
solution.extras = extras
|
||||||
if result == 'OK':
|
if result == 'OK':
|
||||||
solution.test = None
|
solution.test = None
|
||||||
solution.save()
|
solution.save()
|
||||||
|
if not result.startswith('Testing'):
|
||||||
checker.testing_solution = None
|
checker.testing_solution = None
|
||||||
checker.save()
|
checker.save()
|
||||||
return JsonResponse({"status": True})
|
return JsonResponse({"status": True})
|
||||||
@ -80,15 +86,38 @@ def set_result(request):
|
|||||||
return JsonResponse({"status": "incorrect token"}, status=403)
|
return JsonResponse({"status": "incorrect token"}, status=403)
|
||||||
|
|
||||||
|
|
||||||
def current_test(request):
|
def notify(request):
|
||||||
try:
|
try:
|
||||||
checker = Checker.objects.get(dynamic_token=request.GET['token'])
|
checker = Checker.objects.get(dynamic_token=request.GET['token'])
|
||||||
solution = Solution.objects.get(id=request.GET['solution_id'])
|
solution = Solution.objects.get(id=request.GET['solution_id'])
|
||||||
if checker.set != solution.set:
|
if checker.set != solution.set:
|
||||||
return JsonResponse({"status": "incorrect solution"}, status=403)
|
return JsonResponse({"status": "incorrect solution"}, status=403)
|
||||||
test = int(request.GET['test'])
|
notification(
|
||||||
solution.test = test
|
solution.user,
|
||||||
solution.save()
|
"solution_result",
|
||||||
|
f"Задача: {solution.task.name}\n"
|
||||||
|
f"Результат: {solution.result}\n"
|
||||||
|
f"Очки решения: {Progress.by_solution(solution).score}\n"
|
||||||
|
f"Текущий рейтинг: {solution.user.userinfo.rating}")
|
||||||
|
return JsonResponse({"status": True})
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
return JsonResponse({"status": "incorrect token"}, status=403)
|
||||||
|
|
||||||
|
|
||||||
|
def save_progress(request):
|
||||||
|
try:
|
||||||
|
checker = Checker.objects.get(dynamic_token=request.GET['token'])
|
||||||
|
solution = Solution.objects.get(id=request.GET['solution_id'])
|
||||||
|
if checker.set != solution.set:
|
||||||
|
return JsonResponse({"status": "incorrect solution"}, status=403)
|
||||||
|
progress = Progress.objects.get(
|
||||||
|
user=solution.user, task=solution.task
|
||||||
|
)
|
||||||
|
if progress.finished_time is None:
|
||||||
|
progress.finished_time = solution.time_sent
|
||||||
|
progress.finished = True
|
||||||
|
progress.save()
|
||||||
|
progress.increment_rating()
|
||||||
return JsonResponse({"status": True})
|
return JsonResponse({"status": True})
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
return JsonResponse({"status": "incorrect token"}, status=403)
|
return JsonResponse({"status": "incorrect token"}, status=403)
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
FROM docker:dind
|
|
||||||
|
|
||||||
RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
|
|
||||||
RUN python3 -m ensurepip
|
|
||||||
RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev jpeg-dev zlib-dev libjpeg
|
|
||||||
RUN pip3 install --no-cache --upgrade pip setuptools
|
|
||||||
RUN addgroup -S docker
|
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
|
||||||
RUN mkdir -p /usr/src/app/
|
|
||||||
WORKDIR /usr/src/app/
|
|
||||||
|
|
||||||
RUN pip install requests
|
|
||||||
|
|
||||||
COPY . /usr/src/app/
|
|
||||||
|
|
||||||
CMD ["python", "main.py"]
|
|
@ -1,64 +0,0 @@
|
|||||||
from dataclasses import dataclass
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Language:
|
|
||||||
id: int
|
|
||||||
name: str
|
|
||||||
work_name: str
|
|
||||||
file_type: str
|
|
||||||
logo_url: str
|
|
||||||
image: str
|
|
||||||
highlight: str
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
|
|
||||||
languages = [
|
|
||||||
Language(
|
|
||||||
id=0,
|
|
||||||
name="Python3",
|
|
||||||
work_name="Python3",
|
|
||||||
file_type="py",
|
|
||||||
logo_url="https://entredatos.es/wp-content/uploads/2021/05/1200px-Python-logo-notext.svg.png",
|
|
||||||
image="python:3.6",
|
|
||||||
highlight="python",
|
|
||||||
),
|
|
||||||
Language(
|
|
||||||
id=1,
|
|
||||||
name="Kotlin",
|
|
||||||
work_name="Kotlin",
|
|
||||||
file_type="kt",
|
|
||||||
logo_url="https://upload.wikimedia.org/wikipedia/commons/0/06/Kotlin_Icon.svg",
|
|
||||||
image="zenika/kotlin",
|
|
||||||
highlight="kotlin",
|
|
||||||
),
|
|
||||||
Language(
|
|
||||||
id=2,
|
|
||||||
name="C++",
|
|
||||||
work_name="Cpp",
|
|
||||||
file_type="cpp",
|
|
||||||
logo_url="https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/ISO_C%2B%2B_Logo.svg/1822px-ISO_C%2B%2B_Logo.svg.png",
|
|
||||||
image="gcc",
|
|
||||||
highlight="cpp",
|
|
||||||
),
|
|
||||||
Language(
|
|
||||||
id=3,
|
|
||||||
name="Java",
|
|
||||||
work_name="Java",
|
|
||||||
file_type="java",
|
|
||||||
logo_url="https://upload.wikimedia.org/wikipedia/ru/thumb/3/39/Java_logo.svg/1200px-Java_logo.svg.png",
|
|
||||||
image="openjdk",
|
|
||||||
highlight="java",
|
|
||||||
),
|
|
||||||
Language(
|
|
||||||
id=4,
|
|
||||||
name="C#",
|
|
||||||
work_name="CSharp",
|
|
||||||
file_type="cs",
|
|
||||||
logo_url="https://cdn.worldvectorlogo.com/logos/c--4.svg",
|
|
||||||
image="mono",
|
|
||||||
highlight="csharp",
|
|
||||||
),
|
|
||||||
]
|
|
@ -1,84 +0,0 @@
|
|||||||
from multiprocessing import Process
|
|
||||||
from os import getenv, mkdir
|
|
||||||
from os.path import join, exists
|
|
||||||
from shutil import rmtree
|
|
||||||
from tempfile import TemporaryDirectory
|
|
||||||
from time import sleep
|
|
||||||
from zipfile import ZipFile
|
|
||||||
|
|
||||||
from requests import get
|
|
||||||
|
|
||||||
from language import languages
|
|
||||||
from testers import *
|
|
||||||
|
|
||||||
host = "http://dev.sprinthub.ru/"
|
|
||||||
|
|
||||||
|
|
||||||
def process_solution(path, data, language_id, solution_id, timeout, token, host):
|
|
||||||
with open(join(path, "package.zip"), 'wb') as fs:
|
|
||||||
fs.write(data)
|
|
||||||
with ZipFile(join(path, "package.zip"), 'r') as zip_ref:
|
|
||||||
zip_ref.extractall(path)
|
|
||||||
language = languages[language_id]
|
|
||||||
try:
|
|
||||||
result = eval(language.work_name + "Tester")(path, solution_id, language_id, timeout, token, host).execute()
|
|
||||||
except Exception as e:
|
|
||||||
print(str(e))
|
|
||||||
result = "TE"
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def poll(token):
|
|
||||||
correct_token = True
|
|
||||||
while correct_token:
|
|
||||||
code = get(f"{host}checker/status", params={"token": token}).status_code
|
|
||||||
if code != 200:
|
|
||||||
correct_token = False
|
|
||||||
else:
|
|
||||||
sleep(2)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
request = get(f"{host}checker/get_dynamic", params={"token": getenv("TOKEN")})
|
|
||||||
if request.status_code != 200:
|
|
||||||
print("Error happened: " + request.json()['status'])
|
|
||||||
exit(1)
|
|
||||||
dynamic_token = request.json()['token']
|
|
||||||
p = Process(target=poll, args=(dynamic_token,))
|
|
||||||
p.start()
|
|
||||||
while True:
|
|
||||||
data = get(f"{host}checker/available", params={"token": dynamic_token})
|
|
||||||
if data.status_code == 200:
|
|
||||||
sleep(2)
|
|
||||||
continue
|
|
||||||
elif data.status_code == 201:
|
|
||||||
tempdir = "/var/tmp/solution/"
|
|
||||||
try:
|
|
||||||
mkdir(tempdir)
|
|
||||||
result = process_solution(
|
|
||||||
tempdir,
|
|
||||||
data.content,
|
|
||||||
int(data.headers['language_id']),
|
|
||||||
int(data.headers['solution_id']),
|
|
||||||
int(data.headers['timeout']),
|
|
||||||
dynamic_token,
|
|
||||||
host
|
|
||||||
)
|
|
||||||
get(f"{host}checker/set_result", params={
|
|
||||||
"token": dynamic_token,
|
|
||||||
"solution_id": data.headers['solution_id'],
|
|
||||||
"result": result
|
|
||||||
})
|
|
||||||
finally:
|
|
||||||
if exists(tempdir):
|
|
||||||
rmtree(tempdir)
|
|
||||||
elif data.status_code == 403:
|
|
||||||
print("token removed")
|
|
||||||
exit(1)
|
|
||||||
else:
|
|
||||||
print("unknown status")
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
@ -1,120 +0,0 @@
|
|||||||
from os import listdir
|
|
||||||
from os.path import join, exists
|
|
||||||
from subprocess import call, TimeoutExpired
|
|
||||||
|
|
||||||
from SprintLib.language import *
|
|
||||||
from requests import get
|
|
||||||
|
|
||||||
|
|
||||||
class TestException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class BaseTester:
|
|
||||||
working_directory = "app"
|
|
||||||
checker_code = None
|
|
||||||
|
|
||||||
def exec_command(self, command, working_directory="app", timeout=None):
|
|
||||||
return call(
|
|
||||||
f'docker exec -i solution sh -c "cd {working_directory} && {command}"',
|
|
||||||
shell=True,
|
|
||||||
timeout=timeout,
|
|
||||||
)
|
|
||||||
|
|
||||||
def before_test(self):
|
|
||||||
files = [
|
|
||||||
file
|
|
||||||
for file in listdir(self.path)
|
|
||||||
if file.endswith("." + self.language.file_type)
|
|
||||||
]
|
|
||||||
code = self.exec_command(
|
|
||||||
f'{self.build_command} {" ".join(files)}',
|
|
||||||
working_directory=self.working_directory,
|
|
||||||
)
|
|
||||||
if code != 0:
|
|
||||||
raise TestException("CE")
|
|
||||||
|
|
||||||
def test(self, filename):
|
|
||||||
print('testing ' + filename)
|
|
||||||
code = self.exec_command(
|
|
||||||
f"< {filename} {self.command} > output.txt",
|
|
||||||
timeout=self.timeout / 1000,
|
|
||||||
)
|
|
||||||
if code != 0:
|
|
||||||
raise TestException("RE")
|
|
||||||
result = open(join(self.path, "output.txt"), "r").read().strip().replace('\r\n', '\n')
|
|
||||||
print("got result", result)
|
|
||||||
if self.checker_code is not None:
|
|
||||||
print('using checker')
|
|
||||||
with open(join(self.path, 'expected.txt'), 'w') as fs:
|
|
||||||
fs.write(self.predicted)
|
|
||||||
with open(join(self.path, 'checker.py'), 'w') as fs:
|
|
||||||
fs.write(self.checker_code)
|
|
||||||
code = call(f'docker exec -i checker sh -c "cd app && python checker.py"', shell=True, timeout=1)
|
|
||||||
if code != 0:
|
|
||||||
raise TestException("WA")
|
|
||||||
else:
|
|
||||||
print('using simple check')
|
|
||||||
if result != self.predicted:
|
|
||||||
print('incorrect')
|
|
||||||
raise TestException("WA")
|
|
||||||
print('correct')
|
|
||||||
|
|
||||||
def after_test(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@property
|
|
||||||
def command(self):
|
|
||||||
return "./executable.exe"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def build_command(self):
|
|
||||||
return ""
|
|
||||||
|
|
||||||
@property
|
|
||||||
def path(self):
|
|
||||||
return self._path
|
|
||||||
|
|
||||||
@property
|
|
||||||
def language(self):
|
|
||||||
return languages[self.language_id]
|
|
||||||
|
|
||||||
def __init__(self, path, solution_id, language_id, timeout, token, host):
|
|
||||||
self.solution_id = solution_id
|
|
||||||
self._path = path
|
|
||||||
self.language_id = language_id
|
|
||||||
self.timeout = timeout
|
|
||||||
self.token = token
|
|
||||||
self.host = host
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
docker_command = f"docker run --name solution --volume={self.path}:/{self.working_directory} -t -d {self.language.image}"
|
|
||||||
print(docker_command)
|
|
||||||
call(docker_command, shell=True)
|
|
||||||
checker = join(self.path, 'checker.py')
|
|
||||||
if exists(checker):
|
|
||||||
self.checker_code = open(checker, 'r').read()
|
|
||||||
call(f"docker run --name checker --volume={self.path}:/app -t -d python:3.6", shell=True)
|
|
||||||
print("Container created")
|
|
||||||
result = None
|
|
||||||
try:
|
|
||||||
self.before_test()
|
|
||||||
print("before test finished")
|
|
||||||
for file in listdir(self.path):
|
|
||||||
if not file.endswith(".a") and exists(join(self.path, file + '.a')):
|
|
||||||
self.predicted = open(join(self.path, file + '.a'), 'r').read().strip().replace('\r\n', '\n')
|
|
||||||
print('predicted:', self.predicted)
|
|
||||||
get(f"{self.host}checker/current_test", params={"token": self.token, 'test': file, 'solution_id': self.solution_id})
|
|
||||||
self.test(file)
|
|
||||||
self.after_test()
|
|
||||||
result = "OK"
|
|
||||||
except TestException as e:
|
|
||||||
result = str(e)
|
|
||||||
except TimeoutExpired:
|
|
||||||
result = "TL"
|
|
||||||
except Exception as e:
|
|
||||||
print(str(e))
|
|
||||||
result = "TE"
|
|
||||||
call(f"docker rm --force solution", shell=True)
|
|
||||||
call(f"docker rm --force checker", shell=True)
|
|
||||||
return result
|
|
@ -1,11 +0,0 @@
|
|||||||
from .BaseTester import BaseTester
|
|
||||||
|
|
||||||
|
|
||||||
class CSharpTester(BaseTester):
|
|
||||||
@property
|
|
||||||
def build_command(self):
|
|
||||||
return "csc /out:executable.exe"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def command(self):
|
|
||||||
return "mono executable.exe"
|
|
@ -1,7 +0,0 @@
|
|||||||
from .BaseTester import BaseTester
|
|
||||||
|
|
||||||
|
|
||||||
class CppTester(BaseTester):
|
|
||||||
@property
|
|
||||||
def build_command(self):
|
|
||||||
return "g++ -o executable.exe"
|
|
@ -1,8 +0,0 @@
|
|||||||
from .BaseTester import BaseTester
|
|
||||||
|
|
||||||
|
|
||||||
class GoTester(BaseTester):
|
|
||||||
working_directory = "../app"
|
|
||||||
|
|
||||||
def build_command(self):
|
|
||||||
return "go build -o executable.exe"
|
|
@ -1,27 +0,0 @@
|
|||||||
from os import listdir
|
|
||||||
|
|
||||||
from .BaseTester import BaseTester, TestException
|
|
||||||
|
|
||||||
|
|
||||||
class JavaTester(BaseTester):
|
|
||||||
_executable = None
|
|
||||||
|
|
||||||
def before_test(self):
|
|
||||||
files = [
|
|
||||||
file
|
|
||||||
for file in listdir(self.path)
|
|
||||||
if file.endswith(".java")
|
|
||||||
]
|
|
||||||
code = self.exec_command(f"javac {' '.join(files)}")
|
|
||||||
if code != 0:
|
|
||||||
raise TestException("CE")
|
|
||||||
for file in listdir(self.path):
|
|
||||||
if file.endswith(".class"):
|
|
||||||
self._executable = file.rstrip(".class")
|
|
||||||
break
|
|
||||||
if self._executable is None:
|
|
||||||
raise TestException("TE")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def command(self):
|
|
||||||
return f"java -classpath . {self._executable}"
|
|
@ -1,21 +0,0 @@
|
|||||||
from os import listdir
|
|
||||||
|
|
||||||
from .BaseTester import BaseTester, TestException
|
|
||||||
|
|
||||||
|
|
||||||
class KotlinTester(BaseTester):
|
|
||||||
def before_test(self):
|
|
||||||
files = [
|
|
||||||
file
|
|
||||||
for file in listdir(self.path)
|
|
||||||
if file.endswith(".kt")
|
|
||||||
]
|
|
||||||
code = self.exec_command(
|
|
||||||
f'kotlinc {" ".join(files)} -include-runtime -d solution.jar'
|
|
||||||
)
|
|
||||||
if code != 0:
|
|
||||||
raise TestException("CE")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def command(self):
|
|
||||||
return "java -jar solution.jar"
|
|
@ -1,19 +0,0 @@
|
|||||||
from os import listdir
|
|
||||||
|
|
||||||
from .BaseTester import BaseTester, TestException
|
|
||||||
|
|
||||||
|
|
||||||
class Python3Tester(BaseTester):
|
|
||||||
file = None
|
|
||||||
|
|
||||||
def before_test(self):
|
|
||||||
for file in listdir(self.path):
|
|
||||||
if file.endswith(".py") and file != 'checker.py':
|
|
||||||
self.file = file
|
|
||||||
break
|
|
||||||
if self.file is None:
|
|
||||||
raise TestException("TE")
|
|
||||||
|
|
||||||
@property
|
|
||||||
def command(self):
|
|
||||||
return f"python3 {self.file}"
|
|
@ -1,7 +0,0 @@
|
|||||||
from .BaseTester import BaseTester
|
|
||||||
from .Python3Tester import Python3Tester
|
|
||||||
from .CppTester import CppTester
|
|
||||||
from .GoTester import GoTester
|
|
||||||
from .JavaTester import JavaTester
|
|
||||||
from .CSharpTester import CSharpTester
|
|
||||||
from .KotlinTester import KotlinTester
|
|
@ -14,3 +14,5 @@ WORKDIR /usr/src/app/
|
|||||||
COPY . /usr/src/app/
|
COPY . /usr/src/app/
|
||||||
|
|
||||||
RUN pip3 install -r requirements.txt
|
RUN pip3 install -r requirements.txt
|
||||||
|
|
||||||
|
CMD ["./manage.py", "checker"]
|
||||||
|
@ -5,10 +5,18 @@ from SprintLib.utils import get_bytes, write_bytes, delete_file
|
|||||||
|
|
||||||
class FileStorageMixin:
|
class FileStorageMixin:
|
||||||
|
|
||||||
@cached_property
|
_bytes = None
|
||||||
|
|
||||||
|
@property
|
||||||
def bytes(self):
|
def bytes(self):
|
||||||
|
if self._bytes is not None:
|
||||||
|
return self._bytes
|
||||||
return get_bytes(self.fs_id)
|
return get_bytes(self.fs_id)
|
||||||
|
|
||||||
|
@bytes.setter
|
||||||
|
def bytes(self, value):
|
||||||
|
self._bytes = value
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def text(self):
|
def text(self):
|
||||||
try:
|
try:
|
||||||
|
@ -22,6 +22,8 @@ class Solution(models.Model):
|
|||||||
set = models.ForeignKey(Set, null=True, blank=True, on_delete=models.SET_NULL)
|
set = models.ForeignKey(Set, null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
extras = models.JSONField(default=dict)
|
extras = models.JSONField(default=dict)
|
||||||
|
|
||||||
|
_solutionfiles = None
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
indexes = [
|
indexes = [
|
||||||
models.Index(fields=['task', 'user', '-time_sent']),
|
models.Index(fields=['task', 'user', '-time_sent']),
|
||||||
@ -29,6 +31,16 @@ class Solution(models.Model):
|
|||||||
models.Index(fields=['set', '-time_sent']),
|
models.Index(fields=['set', '-time_sent']),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def solutionfiles(self):
|
||||||
|
if self._solutionfiles is not None:
|
||||||
|
return self._solutionfiles
|
||||||
|
return SolutionFile.objects.filter(solution=self)
|
||||||
|
|
||||||
|
@solutionfiles.setter
|
||||||
|
def solutionfiles(self, value):
|
||||||
|
self._solutionfiles = value
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def settask(self):
|
def settask(self):
|
||||||
return SetTask.objects.filter(set=self.set, task=self.task).first()
|
return SetTask.objects.filter(set=self.set, task=self.task).first()
|
||||||
@ -83,10 +95,6 @@ class Solution(models.Model):
|
|||||||
return "info"
|
return "info"
|
||||||
return "danger"
|
return "danger"
|
||||||
|
|
||||||
@property
|
|
||||||
def volume_directory(self):
|
|
||||||
return "/sprint-data/worker/" + str(self.id)
|
|
||||||
|
|
||||||
def exec_command(self, command, working_directory="app", timeout=None):
|
def exec_command(self, command, working_directory="app", timeout=None):
|
||||||
return call(
|
return call(
|
||||||
f'docker exec -i solution_{self.id} sh -c "cd {working_directory} && {command}"',
|
f'docker exec -i solution_{self.id} sh -c "cd {working_directory} && {command}"',
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
|
from cached_property import cached_property
|
||||||
from django.contrib.postgres.fields import ArrayField
|
from django.contrib.postgres.fields import ArrayField
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.db.models import JSONField
|
from django.db.models import JSONField
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
from Main.models.dump import Dump
|
from Main.models.dump import Dump
|
||||||
from Main.models.extrafile import ExtraFile
|
from Main.models.extrafile import ExtraFile
|
||||||
@ -22,6 +22,8 @@ class Task(models.Model):
|
|||||||
allow_sharing = models.BooleanField(default=False)
|
allow_sharing = models.BooleanField(default=False)
|
||||||
changes = JSONField(default=list)
|
changes = JSONField(default=list)
|
||||||
|
|
||||||
|
_extrafiles = None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@ -35,7 +37,32 @@ class Task(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def tests(self):
|
def tests(self):
|
||||||
return ExtraFile.objects.filter(task=self, is_test=True).order_by('filename')
|
for file in sorted(self.extrafiles, key=lambda x: x.filename):
|
||||||
|
if file.filename.isnumeric() or file.filename.endswith('.a') and file.filename[:-2].isnumeric():
|
||||||
|
yield file
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extrafiles(self):
|
||||||
|
if self._extrafiles is not None:
|
||||||
|
return self._extrafiles
|
||||||
|
return ExtraFile.objects.filter(task=self)
|
||||||
|
|
||||||
|
@extrafiles.setter
|
||||||
|
def extrafiles(self, value):
|
||||||
|
self._extrafiles = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dockerfiles(self):
|
||||||
|
for file in self.extrafiles:
|
||||||
|
if file.filename.startswith('Dockerfile_'):
|
||||||
|
yield file
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def checkerfile(self):
|
||||||
|
for file in self.extrafiles:
|
||||||
|
if file.filename == 'extrafile.py':
|
||||||
|
return file
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def tests_count(self):
|
def tests_count(self):
|
||||||
@ -44,7 +71,7 @@ class Task(models.Model):
|
|||||||
@property
|
@property
|
||||||
def samples(self):
|
def samples(self):
|
||||||
data = []
|
data = []
|
||||||
for test in self.tests.order_by("test_number"):
|
for test in self.tests:
|
||||||
if test.is_sample and test.readable:
|
if test.is_sample and test.readable:
|
||||||
data.append({"input": test.text, "output": test.answer.text})
|
data.append({"input": test.text, "output": test.answer.text})
|
||||||
count = 1
|
count = 1
|
||||||
|
@ -20,7 +20,7 @@ class SendCodeView(BaseView):
|
|||||||
"message": "Пользователя с таким именем не существует",
|
"message": "Пользователя с таким именем не существует",
|
||||||
}
|
}
|
||||||
code = randrange(10000, 100000)
|
code = randrange(10000, 100000)
|
||||||
print(code)
|
print(f"Отправлен код для {username}", code)
|
||||||
user.userinfo.code = code
|
user.userinfo.code = code
|
||||||
user.userinfo.save()
|
user.userinfo.save()
|
||||||
notify(user, "any", "Код для входа в сервис: " + str(code))
|
notify(user, "any", "Код для входа в сервис: " + str(code))
|
||||||
|
@ -3,11 +3,10 @@ from os.path import join, exists
|
|||||||
from subprocess import call, TimeoutExpired
|
from subprocess import call, TimeoutExpired
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
from SprintLib.queue import notify, send_to_queue
|
|
||||||
from Main.models import ExtraFile, SolutionFile
|
|
||||||
from Main.models.progress import Progress
|
from Main.models.progress import Progress
|
||||||
from Sprint.settings import CONSTS
|
from Sprint.settings import CONSTS
|
||||||
from SprintLib.utils import get_bytes, Timer
|
from SprintLib.queue import notify, send_to_queue
|
||||||
|
from SprintLib.utils import Timer
|
||||||
|
|
||||||
|
|
||||||
class TestException(Exception):
|
class TestException(Exception):
|
||||||
@ -70,21 +69,21 @@ class BaseTester:
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
def call(self, command):
|
def call(self, command):
|
||||||
|
print(f"Executing command: {command}")
|
||||||
|
if exists(self.path):
|
||||||
return call(f'cd {self.path} && {command}', shell=True)
|
return call(f'cd {self.path} && {command}', shell=True)
|
||||||
|
else:
|
||||||
|
return call(command, shell=True)
|
||||||
|
|
||||||
def __init__(self, solution):
|
def __init__(self, solution):
|
||||||
self.solution = solution
|
self.solution = solution
|
||||||
|
|
||||||
def set_test(self, num):
|
def save_solution(self):
|
||||||
self.solution.result = CONSTS["testing_status"] + f"({num})"
|
|
||||||
self.solution.save()
|
self.solution.save()
|
||||||
|
|
||||||
def _setup_networking(self):
|
def _setup_networking(self):
|
||||||
self.dockerfiles = sorted(
|
|
||||||
list(ExtraFile.objects.filter(filename__startswith="Dockerfile_", readable=True, task=self.solution.task)),
|
|
||||||
key=lambda x: x.filename)
|
|
||||||
self.call(f"docker network create solution_network_{self.solution.id}")
|
self.call(f"docker network create solution_network_{self.solution.id}")
|
||||||
for file in self.dockerfiles:
|
for file in self.solution.task.dockerfiles:
|
||||||
add_name = file.filename[11:]
|
add_name = file.filename[11:]
|
||||||
with open(join(self.path, 'Dockerfile'), 'w') as fs:
|
with open(join(self.path, 'Dockerfile'), 'w') as fs:
|
||||||
fs.write(file.text)
|
fs.write(file.text)
|
||||||
@ -97,11 +96,41 @@ class BaseTester:
|
|||||||
print('run command', run_command)
|
print('run command', run_command)
|
||||||
self.call(run_command)
|
self.call(run_command)
|
||||||
|
|
||||||
|
def notify(self):
|
||||||
|
self.solution.user.userinfo.refresh_from_db()
|
||||||
|
notify(
|
||||||
|
self.solution.user,
|
||||||
|
"solution_result",
|
||||||
|
f"Задача: {self.solution.task.name}\n"
|
||||||
|
f"Результат: {self.solution.result}\n"
|
||||||
|
f"Очки решения: {Progress.by_solution(self.solution).score}\n"
|
||||||
|
f"Текущий рейтинг: {self.solution.user.userinfo.rating}")
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
self.solution.save()
|
||||||
|
send_to_queue("cleaner", {"type": "container", "name": f"solution_{self.solution.id}"})
|
||||||
|
send_to_queue("cleaner", {"type": "container", "name": f"solution_{self.solution.id}_checker"})
|
||||||
|
for file in self.solution.task.dockerfiles:
|
||||||
|
add_name = file.filename[11:]
|
||||||
|
send_to_queue("cleaner", {"type": "container", "name": f"solution_container_{self.solution.id}_{add_name}"})
|
||||||
|
send_to_queue("cleaner", {"type": "image", "name": f"solution_image_{self.solution.id}_{add_name}"})
|
||||||
|
send_to_queue("cleaner", {"type": "network", "name": f"solution_network_{self.solution.id}"})
|
||||||
|
|
||||||
|
def save_progress(self):
|
||||||
|
progress = Progress.objects.get(
|
||||||
|
user=self.solution.user, task=self.solution.task
|
||||||
|
)
|
||||||
|
if progress.finished_time is None:
|
||||||
|
progress.finished_time = self.solution.time_sent
|
||||||
|
progress.finished = True
|
||||||
|
progress.save()
|
||||||
|
progress.increment_rating()
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
self.solution.result = CONSTS["testing_status"]
|
self.solution.result = CONSTS["testing_status"]
|
||||||
self.solution.save()
|
self.save_solution()
|
||||||
with TemporaryDirectory(dir='/tmp') as self.path:
|
with TemporaryDirectory(dir='/tmp') as self.path:
|
||||||
for file in SolutionFile.objects.filter(solution=self.solution):
|
for file in self.solution.solutionfiles:
|
||||||
dirs = file.path.split("/")
|
dirs = file.path.split("/")
|
||||||
for i in range(len(dirs) - 1):
|
for i in range(len(dirs) - 1):
|
||||||
name = join(
|
name = join(
|
||||||
@ -112,19 +141,19 @@ class BaseTester:
|
|||||||
with open(
|
with open(
|
||||||
join(self.path, file.path), "wb"
|
join(self.path, file.path), "wb"
|
||||||
) as fs:
|
) as fs:
|
||||||
fs.write(get_bytes(file.fs_id).replace(b"\r\n", b"\n"))
|
fs.write(file.bytes.replace(b"\r\n", b"\n"))
|
||||||
for file in ExtraFile.objects.filter(task=self.solution.task):
|
for file in self.solution.task.extrafiles:
|
||||||
with open(
|
with open(
|
||||||
join(self.path, file.filename), 'wb'
|
join(self.path, file.filename), 'wb'
|
||||||
) as fs:
|
) as fs:
|
||||||
bts = get_bytes(file.fs_id)
|
bts = file.bytes
|
||||||
fs.write(bts)
|
fs.write(bts)
|
||||||
print("Files copied")
|
print("Files copied")
|
||||||
self._setup_networking()
|
self._setup_networking()
|
||||||
docker_command = f"docker run --network solution_network_{self.solution.id} --name solution_{self.solution.id} --volume={self.path}:/{self.working_directory} -t -d {self.solution.language.image}"
|
docker_command = f"docker run --network solution_network_{self.solution.id} --name solution_{self.solution.id} --volume={self.path}:/{self.working_directory} -t -d {self.solution.language.image}"
|
||||||
print(docker_command)
|
print(docker_command)
|
||||||
call(docker_command, shell=True)
|
call(docker_command, shell=True)
|
||||||
checker = ExtraFile.objects.filter(task=self.solution.task, filename='checker.py').first()
|
checker = self.solution.task.checkerfile
|
||||||
if checker is not None:
|
if checker is not None:
|
||||||
self.checker_code = checker.text
|
self.checker_code = checker.text
|
||||||
call(f"docker run --network solution_network_{self.solution.id} --name solution_{self.solution.id}_checker --volume={self.path}:/app -t -d python:3.6", shell=True)
|
call(f"docker run --network solution_network_{self.solution.id} --name solution_{self.solution.id}_checker --volume={self.path}:/app -t -d python:3.6", shell=True)
|
||||||
@ -134,13 +163,11 @@ class BaseTester:
|
|||||||
print("before test finished")
|
print("before test finished")
|
||||||
for test in self.solution.task.tests:
|
for test in self.solution.task.tests:
|
||||||
if not test.filename.endswith(".a"):
|
if not test.filename.endswith(".a"):
|
||||||
self.predicted = ExtraFile.objects.get(
|
self.predicted = open(join(self.path, test.filename + '.a'), 'r').read().strip().replace('\r\n', '\n')
|
||||||
task=self.solution.task, filename=test.filename + ".a"
|
|
||||||
).text.strip().replace('\r\n', '\n')
|
|
||||||
print('predicted:', self.predicted)
|
print('predicted:', self.predicted)
|
||||||
self.solution.test = int(test.filename)
|
self.solution.test = int(test.filename)
|
||||||
self.solution.extras[test.filename] = {'predicted': self.predicted, 'output': ''}
|
self.solution.extras[test.filename] = {'predicted': self.predicted, 'output': ''}
|
||||||
self.solution.save()
|
self.save_solution()
|
||||||
try:
|
try:
|
||||||
self.test(test.filename)
|
self.test(test.filename)
|
||||||
finally:
|
finally:
|
||||||
@ -149,17 +176,12 @@ class BaseTester:
|
|||||||
self.solution.extras[test.filename]['output'] = open(join(self.path, 'output.txt'), 'r').read()
|
self.solution.extras[test.filename]['output'] = open(join(self.path, 'output.txt'), 'r').read()
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
self.solution.extras[test.filename]['output'] = ''
|
self.solution.extras[test.filename]['output'] = ''
|
||||||
|
self.save_solution()
|
||||||
self.after_test()
|
self.after_test()
|
||||||
self.solution.result = CONSTS["ok_status"]
|
self.solution.result = CONSTS["ok_status"]
|
||||||
self.solution.test = None
|
self.solution.test = None
|
||||||
progress = Progress.objects.get(
|
self.save_solution()
|
||||||
user=self.solution.user, task=self.solution.task
|
self.save_progress()
|
||||||
)
|
|
||||||
if progress.finished_time is None:
|
|
||||||
progress.finished_time = self.solution.time_sent
|
|
||||||
progress.finished = True
|
|
||||||
progress.save()
|
|
||||||
progress.increment_rating()
|
|
||||||
except TestException as e:
|
except TestException as e:
|
||||||
self.solution.result = str(e)
|
self.solution.result = str(e)
|
||||||
except TimeoutExpired:
|
except TimeoutExpired:
|
||||||
@ -167,19 +189,6 @@ class BaseTester:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.solution.result = "TE"
|
self.solution.result = "TE"
|
||||||
print(e)
|
print(e)
|
||||||
self.solution.save()
|
self.save_solution()
|
||||||
send_to_queue("cleaner", {"type": "container", "name": f"solution_{self.solution.id}"})
|
self.cleanup()
|
||||||
send_to_queue("cleaner", {"type": "container", "name": f"solution_{self.solution.id}_checker"})
|
self.notify()
|
||||||
for file in self.dockerfiles:
|
|
||||||
add_name = file.filename[11:]
|
|
||||||
send_to_queue("cleaner", {"type": "container", "name": f"solution_container_{self.solution.id}_{add_name}"})
|
|
||||||
send_to_queue("cleaner", {"type": "image", "name": f"solution_image_{self.solution.id}_{add_name}"})
|
|
||||||
send_to_queue("cleaner", {"type": "network", "name": f"solution_network_{self.solution.id}"})
|
|
||||||
self.solution.user.userinfo.refresh_from_db()
|
|
||||||
notify(
|
|
||||||
self.solution.user,
|
|
||||||
"solution_result",
|
|
||||||
f"Задача: {self.solution.task.name}\n"
|
|
||||||
f"Результат: {self.solution.result}\n"
|
|
||||||
f"Очки решения: {Progress.by_solution(self.solution).score}\n"
|
|
||||||
f"Текущий рейтинг: {self.solution.user.userinfo.rating}")
|
|
||||||
|
41
SprintLib/testers/DistantTester.py
Normal file
41
SprintLib/testers/DistantTester.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from requests import get
|
||||||
|
|
||||||
|
from SprintLib.testers import BaseTester
|
||||||
|
|
||||||
|
|
||||||
|
class DistantTester(BaseTester):
|
||||||
|
host = ""
|
||||||
|
token = ""
|
||||||
|
|
||||||
|
def request(self, method, params=None):
|
||||||
|
if params is None:
|
||||||
|
params = {}
|
||||||
|
return get(f'{self.host}checker/{method}', params={**{
|
||||||
|
"token": self.token,
|
||||||
|
"solution_id": self.solution.id,
|
||||||
|
}, **params})
|
||||||
|
|
||||||
|
def save_solution(self):
|
||||||
|
self.request("save_solution", {
|
||||||
|
"test": self.solution.test,
|
||||||
|
"result": self.solution.result,
|
||||||
|
"extras": json.dumps(self.solution.extras)
|
||||||
|
})
|
||||||
|
|
||||||
|
def notify(self):
|
||||||
|
self.request("notify")
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
self.save_solution()
|
||||||
|
self.call(f"docker rm --force solution_{self.solution.id}")
|
||||||
|
self.call(f"docker rm --force solution_{self.solution.id}_checker")
|
||||||
|
for file in self.solution.task.dockerfiles:
|
||||||
|
add_name = file.filename[11:]
|
||||||
|
self.call(f"docker rm --force solution_container_{self.solution.id}_{add_name}")
|
||||||
|
self.call(f"docker image rm solution_image_{self.solution.id}_{add_name}")
|
||||||
|
self.call(f"docker network rm solution_network_{self.solution.id}")
|
||||||
|
|
||||||
|
def save_progress(self):
|
||||||
|
self.request("save_progress")
|
@ -7,9 +7,8 @@ class Python3Tester(BaseTester):
|
|||||||
file = None
|
file = None
|
||||||
|
|
||||||
def before_test(self):
|
def before_test(self):
|
||||||
no_files = [file.filename for file in self.solution.task.files]
|
|
||||||
for file in listdir(self.path):
|
for file in listdir(self.path):
|
||||||
if file.endswith(".py") and file not in no_files:
|
if file == 'solution.py':
|
||||||
self.file = file
|
self.file = file
|
||||||
break
|
break
|
||||||
if self.file is None:
|
if self.file is None:
|
||||||
|
@ -6,3 +6,4 @@ from .JavaTester import JavaTester
|
|||||||
from .CSharpTester import CSharpTester
|
from .CSharpTester import CSharpTester
|
||||||
from .KotlinTester import KotlinTester
|
from .KotlinTester import KotlinTester
|
||||||
from .SwiftTester import SwiftTester
|
from .SwiftTester import SwiftTester
|
||||||
|
from .DistantTester import DistantTester
|
||||||
|
102
daemons/management/commands/checker.py
Normal file
102
daemons/management/commands/checker.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
from os import getenv, remove, listdir, walk
|
||||||
|
from os.path import join, isfile
|
||||||
|
from tempfile import TemporaryDirectory
|
||||||
|
from threading import Thread
|
||||||
|
from time import sleep
|
||||||
|
from zipfile import ZipFile
|
||||||
|
|
||||||
|
from django.core.management import BaseCommand
|
||||||
|
from requests import get
|
||||||
|
|
||||||
|
from Main.models import Solution, Task, ExtraFile, SolutionFile
|
||||||
|
from SprintLib.language import languages
|
||||||
|
from SprintLib.testers import *
|
||||||
|
|
||||||
|
|
||||||
|
host = 'http://192.168.0.146:8000/'
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Tests solution"
|
||||||
|
|
||||||
|
def poll(self, token):
|
||||||
|
correct_token = True
|
||||||
|
while correct_token:
|
||||||
|
code = get(f"{host}checker/status", params={"token": token}).status_code
|
||||||
|
if code != 200:
|
||||||
|
correct_token = False
|
||||||
|
else:
|
||||||
|
sleep(2)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
print("Starting checker")
|
||||||
|
request = get(f"{host}checker/get_dynamic", params={"token": getenv("TOKEN")})
|
||||||
|
if request.status_code != 200:
|
||||||
|
print("Error happened: " + request.json()['status'])
|
||||||
|
exit(1)
|
||||||
|
print("Got dynamic token")
|
||||||
|
dynamic_token = request.json()['token']
|
||||||
|
p = Thread(target=self.poll, args=(dynamic_token,))
|
||||||
|
p.start()
|
||||||
|
while True:
|
||||||
|
data = get(f"{host}checker/available", params={"token": dynamic_token})
|
||||||
|
if data.status_code == 200:
|
||||||
|
sleep(2)
|
||||||
|
continue
|
||||||
|
elif data.status_code == 201:
|
||||||
|
solution = self.create_solution(data)
|
||||||
|
print("handled solution", solution.id)
|
||||||
|
tester_class = eval(solution.language.work_name + "Tester")
|
||||||
|
|
||||||
|
class LocalTester(DistantTester, tester_class):
|
||||||
|
...
|
||||||
|
|
||||||
|
tester = LocalTester(solution)
|
||||||
|
tester.host = host
|
||||||
|
tester.token = dynamic_token
|
||||||
|
try:
|
||||||
|
tester.execute()
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
solution.result = "TE"
|
||||||
|
tester.save_solution()
|
||||||
|
elif data.status_code == 403:
|
||||||
|
print("token removed")
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
print("unknown status")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
def create_solution(self, data):
|
||||||
|
with TemporaryDirectory(dir='/tmp') as path:
|
||||||
|
with open(join(path, "package.zip"), 'wb') as fs:
|
||||||
|
fs.write(data.content)
|
||||||
|
with ZipFile(join(path, "package.zip"), 'r') as zip_ref:
|
||||||
|
zip_ref.extractall(path)
|
||||||
|
remove(join(path, "package.zip"))
|
||||||
|
|
||||||
|
solution = Solution(
|
||||||
|
id=int(data.headers['solution_id']),
|
||||||
|
language_id=int(data.headers['language_id']),
|
||||||
|
task=Task(
|
||||||
|
time_limit=int(data.headers['timeout']),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
solution.task.extrafiles = [ExtraFile(
|
||||||
|
filename=file,
|
||||||
|
task=solution.task
|
||||||
|
) for file in listdir(path) if isfile(join(path, file))]
|
||||||
|
for file in solution.task.extrafiles:
|
||||||
|
file.bytes = open(join(path, file.filename), 'rb').read()
|
||||||
|
solution.solutionfiles = [
|
||||||
|
SolutionFile(
|
||||||
|
path=join(directory, file)[len(join(path, 'solution')) + 1:],
|
||||||
|
solution=solution,
|
||||||
|
)
|
||||||
|
for directory, _, files in walk(join(path, 'solution')) for file in files
|
||||||
|
]
|
||||||
|
for file in solution.solutionfiles:
|
||||||
|
file.bytes = open(join(path, 'solution', file.path), 'rb').read()
|
||||||
|
|
||||||
|
return solution
|
@ -1,6 +1,3 @@
|
|||||||
from os.path import join, exists
|
|
||||||
from shutil import rmtree
|
|
||||||
|
|
||||||
from Main.models import Solution
|
from Main.models import Solution
|
||||||
from SprintLib.queue import MessagingSupport
|
from SprintLib.queue import MessagingSupport
|
||||||
from SprintLib.testers import *
|
from SprintLib.testers import *
|
||||||
@ -14,8 +11,9 @@ class Command(MessagingSupport):
|
|||||||
id = payload['id']
|
id = payload['id']
|
||||||
print(f"Received id {id}")
|
print(f"Received id {id}")
|
||||||
solution = Solution.objects.get(id=id)
|
solution = Solution.objects.get(id=id)
|
||||||
|
tester = eval(solution.language.work_name + "Tester")(solution)
|
||||||
try:
|
try:
|
||||||
eval(solution.language.work_name + "Tester")(solution).execute()
|
tester.execute()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
solution.result = "TE"
|
solution.result = "TE"
|
||||||
|
Loading…
Reference in New Issue
Block a user