Skip to content

Commit

Permalink
Added support to process text files
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinXPN committed Oct 9, 2023
1 parent 942ced0 commit 3451a8e
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 1 deletion.
11 changes: 11 additions & 0 deletions bouncer/coderunners.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ def name(self) -> str:
@staticmethod
def from_language(language: str) -> 'CodeRunner':
language = language.lower()
if language in TxtRunner.supported_standards:
return TxtRunner()
if language in CppRunner.supported_standards:
return CppRunner()
if language in PythonRunner.supported_standards:
Expand All @@ -37,6 +39,15 @@ def invoke(self, aws_lambda_client, request: SubmissionRequest) -> SubmissionRes
return SubmissionResult.from_json(res)


@dataclass
class TxtRunner(CodeRunner):
supported_standards = {'txt', 'text'}

@property
def name(self) -> str:
return 'CodeRunnerTxt'


@dataclass
class CppRunner(CodeRunner):
supported_standards = {'c++11', 'c++14', 'c++17', 'c++20'}
Expand Down
18 changes: 17 additions & 1 deletion coderunners/compilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from typing import ClassVar

from coderunners.process import Process
from models import RunResult
from models import RunResult, Status


class Compiler(ABC):
Expand All @@ -24,6 +24,8 @@ def find_main_file_path(cls, submission_paths: list[Path], main_file_name: str)
@staticmethod
def from_language(language: str) -> 'Compiler':
language = language.lower()
if language in TxtCompiler.supported_standards:
return TxtCompiler()
if language in CppCompiler.supported_standards:
return CppCompiler(language_standard=language)
if language in PythonCompiler.supported_standards:
Expand All @@ -39,6 +41,20 @@ def from_language(language: str) -> 'Compiler':
raise ValueError(f'{language} does not have a compiler yet')


@dataclass
class TxtCompiler(Compiler):
MAIN_FILE_NAME: ClassVar[str] = 'main.txt'
supported_standards = {'txt', 'text'}

def compile(self, submission_paths: list[Path]):
if len(submission_paths) != 1:
raise ValueError('Only one file is allowed for txt submissions')

executable_path = f'cat {submission_paths[0]}'
compile_res = RunResult(status=Status.OK, memory=0, time=0, return_code=0, outputs=None, errors=None)
return executable_path, compile_res


@dataclass
class CppCompiler(Compiler):
MAIN_FILE_NAME: ClassVar[str] = 'main.cpp'
Expand Down
17 changes: 17 additions & 0 deletions coderunners/lang/txt.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM public.ecr.aws/lambda/python:3.11

# Initial setup
RUN pip install --upgrade pip
RUN pip install awslambdaric -t "${LAMBDA_TASK_ROOT}"

# Install dependencies
COPY coderunners/requirements.txt ./
RUN pip install -r requirements.txt -t "${LAMBDA_TASK_ROOT}"

# Setup source files
COPY coderunners/*.py ${LAMBDA_TASK_ROOT}/coderunners/
COPY models.py ${LAMBDA_TASK_ROOT}/

# Run the lambda function handler
ENTRYPOINT [ "python", "-m", "awslambdaric" ]
CMD [ "coderunners.app.run_code_lambda" ]
23 changes: 23 additions & 0 deletions template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,26 @@ Resources:
DockerContext: ./
Dockerfile: bouncer/Dockerfile

CodeRunnerTxt:
Type: AWS::Serverless::Function
DependsOn: CodeRunnerMountTarget
Properties:
FunctionName: CodeRunnerTxt
PackageType: Image
Role: !GetAtt ContestantRole.Arn
VpcConfig:
SecurityGroupIds:
- !GetAtt JudgeVPC.DefaultSecurityGroup
SubnetIds:
- !Ref CodeRunnerPrivateSubnet
FileSystemConfigs:
- Arn: !GetAtt AccessPointResource.Arn
LocalMountPath: '/mnt/efs'
Metadata:
DockerTag: txt-v1
DockerContext: ./
Dockerfile: coderunners/lang/txt.Dockerfile

CodeRunnerPython:
Type: AWS::Serverless::Function
DependsOn: CodeRunnerMountTarget
Expand Down Expand Up @@ -497,6 +517,9 @@ Outputs:
Description: 'AWS Lambda checker for determining if the output of a code is exactly the same es the target'
Value: !GetAtt Bouncer.Arn

CodeRunnerTxt:
Description: 'AWS Lambda for checking textual outputs'
Value: !GetAtt CodeRunnerTxt.Arn
CodeRunnerPython:
Description: 'AWS Lambda for executing a python code and getting the outputs'
Value: !GetAtt CodeRunnerPython.Arn
Expand Down
86 changes: 86 additions & 0 deletions tests/integration/coderunners/test_escape_characters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from bouncer.coderunners import CodeRunner
from models import Status, SubmissionRequest, TestCase
from tests.integration.config import lambda_client


class TestEscapeCharacters:

def test_plain_text(self):
request = SubmissionRequest(test_cases=[TestCase(input='', target='hello')], language='txt', code={
'main.txt': 'hello',
})

res = CodeRunner.from_language(language=request.language).invoke(lambda_client, request=request)
print(res)
assert res.overall.status == Status.OK
assert len(res.test_results) == 1 and res.test_results[0].status == Status.OK

def test_escape_text(self):
request = SubmissionRequest(test_cases=[TestCase(input='', target='h\'ell"o')], language='txt', code={
'main.txt': 'h\'ell"o',
})

res = CodeRunner.from_language(language=request.language).invoke(lambda_client, request=request)
print(res)
assert res.overall.status == Status.OK
assert len(res.test_results) == 1 and res.test_results[0].status == Status.OK

def test_program(self):
request = SubmissionRequest(test_cases=[
TestCase(input='', target="""'import os; os.system("rm -rf /")"""),
], language='txt', code={
'main.txt': """'import os; os.system("rm -rf /")""",
})

res = CodeRunner.from_language(language=request.language).invoke(lambda_client, request=request)
print(res)
assert res.overall.status == Status.OK
assert len(res.test_results) == 1 and res.test_results[0].status == Status.OK

def test_multiline_text(self):
request = SubmissionRequest(test_cases=[
TestCase(input='', target='line1\nline2\nline3\n')
], language='txt', code={'main.txt': 'line1\nline2\nline3\n'})

res = CodeRunner.from_language(language=request.language).invoke(lambda_client, request=request)
print(res)
assert res.overall.status == Status.OK
assert len(res.test_results) == 1 and res.test_results[0].status == Status.OK

def test_empty_target(self):
request = SubmissionRequest(test_cases=[TestCase(input='', target='')], language='txt', code={'main.txt': ''})

res = CodeRunner.from_language(language=request.language).invoke(lambda_client, request=request)
print(res)
assert res.overall.status == Status.OK
assert len(res.test_results) == 1 and res.test_results[0].status == Status.OK

def test_whitespace(self):
request = SubmissionRequest(test_cases=[
TestCase(input='', target=' \t\n \t\t\n')
], language='txt', code={'main.txt': ' \t\n \t\t\n'})

res = CodeRunner.from_language(language=request.language).invoke(lambda_client, request=request)
print(res)
assert res.overall.status == Status.OK
assert len(res.test_results) == 1 and res.test_results[0].status == Status.OK

def test_special_chars(self):
request = SubmissionRequest(test_cases=[TestCase(input='', target='\\ \n ❤️🚀')], language='txt', code={
'main.txt': '\\ \n ❤️🚀',
})

res = CodeRunner.from_language(language=request.language).invoke(lambda_client, request=request)
print(res)
assert res.overall.status == Status.OK
assert len(res.test_results) == 1 and res.test_results[0].status == Status.OK

def test_mismatch(self):
request = SubmissionRequest(test_cases=[TestCase(input='', target='helloo')], language='txt', code={
'main.txt': 'hello',
})

res = CodeRunner.from_language(language=request.language).invoke(lambda_client, request=request)
print(res)
assert res.overall.status == Status.WA
assert len(res.test_results) == 1 and res.test_results[0].status == Status.WA
5 changes: 5 additions & 0 deletions tests/integration/coderunners/test_hello_world.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ def run_test(request: SubmissionRequest) -> SubmissionResult:
assert len(res.test_results) == 1 and res.test_results[0].status == Status.OK
return res

def test_txt(self):
self.run_test(SubmissionRequest(test_cases=self.test_cases, language='txt', code={
'main.txt': 'Hello World!',
}))

def test_python(self):
self.run_test(SubmissionRequest(test_cases=self.test_cases, language='python', code={
'main.py': 'print("Hello World!")',
Expand Down

0 comments on commit 3451a8e

Please sign in to comment.