# coding: utf-8
import os.path
import zipfile
import pytest
import urllib.parse
from io import BytesIO
from django.conf import settings
from django.core.files import File
from django.core.management import call_command
from django.core.management.base import CommandError
from django.test import TransactionTestCase
from django.test.utils import override_settings
from django.urls import reverse
from django.utils.html import escape
from django.utils.module_loading import import_string
from oioioi.base.tests import TestCase, needs_linux
from oioioi.contests.current_contest import ContestMode
from oioioi.contests.models import (
Contest,
ProblemInstance,
Submission,
UserResultForContest,
)
from oioioi.contests.scores import IntegerScore
from oioioi.filetracker.tests import TestStreamingMixin
from oioioi.problems.models import (
Problem,
ProblemName,
ProblemPackage,
ProblemStatement,
)
from oioioi.problems.package import NoBackend, backend_for_package
from oioioi.programs.models import (
LanguageOverrideForTest,
ModelSolution,
OutputChecker,
Test,
TestReport,
)
from oioioi.sinolpack.models import ExtraConfig, ExtraFile
from oioioi.sinolpack.package import (
DEFAULT_MEMORY_LIMIT,
DEFAULT_TIME_LIMIT,
SinolPackageBackend,
)
[docs]def get_test_filename(name):
return os.path.join(os.path.dirname(__file__), 'files', name)
[docs]BOTH_CONFIGURATIONS = '%test_both_configurations'
[docs]def use_makefiles(fn):
return override_settings(USE_SINOLPACK_MAKEFILES=True)((fn))
[docs]def no_makefiles(fn):
return override_settings(USE_SINOLPACK_MAKEFILES=False)(fn)
# When a class inheriting from django.test.TestCase is decorated with
# enable_both_unpack_configurations, all its methods decorated with
# both_configurations will be run twice. Once in safe and once in unsafe unpack
# mode.
# Unfortunately, you won't be able run such a decorated method as a single
# test, that is:
# ./test.sh oioioi.sinolpack.tests:TestSinolPackage.test_huge_unpack_update
# will NOT work.
[docs]def enable_both_unpack_configurations(cls):
for name, fn in list(cls.__dict__.items()):
if getattr(fn, BOTH_CONFIGURATIONS, False):
setattr(cls, '%s_safe' % (name), no_makefiles(fn))
setattr(cls, '%s_unsafe' % (name), use_makefiles(fn))
delattr(cls, name)
return cls
[docs]def both_configurations(fn):
setattr(fn, BOTH_CONFIGURATIONS, True)
return fn
[docs]class TestSinolPackageIdentify(TestCase):
[docs] def test_identify_zip(self):
filename = get_test_filename('test_simple_package.zip')
self.assertTrue(SinolPackageBackend().identify(filename))
[docs] def test_identify_tgz(self):
filename = get_test_filename('test_full_package.tgz')
self.assertTrue(SinolPackageBackend().identify(filename))
@enable_both_unpack_configurations
@needs_linux
[docs]class TestSinolPackage(TestCase, TestStreamingMixin):
[docs] fixtures = ['test_users', 'test_contest']
[docs] def test_title_in_config_yml(self):
filename = get_test_filename('test_simple_package.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
self.assertEqual(problem.name, 'Testowe')
@override_settings(CONTEST_MODE=ContestMode.neutral)
[docs] def test_single_file_replacement(self):
filename = get_test_filename('test_simple_package.zip')
old_statement = 'tst/doc/tstzad.pdf'
bad_statement = get_test_filename('blank.pdf')
good_statement = get_test_filename('tstzad.pdf') # copy of blank
call_command('addproblem', filename)
problem = Problem.objects.get()
site_key = problem.problemsite.url_key
url = (
reverse('problem_site', kwargs={'site_key': site_key})
+ '?key=manage_files_problem_package'
)
self.assertTrue(self.client.login(username='test_user'))
response = self.client.get(url)
self.assertNotEqual(response.status_code, 200)
self.assertTrue(self.client.login(username='test_admin'))
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, old_statement)
post_data = {
'file_name': old_statement,
'file_replacement': open(bad_statement, 'rb'),
'upload_button': '',
}
response = self.client.post(url, post_data, follow=True)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'must have the same name') # error
post_data['file_replacement'] = open(good_statement, 'rb')
response = self.client.post(url, post_data, follow=True)
self.assertEqual(response.status_code, 200)
# It is in the old and modified packages' rows and also in a filter
self.assertContains(response, 'Uploaded', 3)
statement = ProblemStatement.objects.get(problem=problem)
url = reverse('show_statement', kwargs={'statement_id': statement.id})
response = self.client.get(url)
content = self.streamingContent(response)
self.assertEqual(content, open(good_statement, 'rb').read())
[docs] def test_title_translations_in_config_yml(self):
filename = get_test_filename('test_simple_package_translations.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
problem_names = ProblemName.objects.filter(problem=problem)
self.assertEqual(problem_names.count(), 2)
self.assertTrue(
problem_names.filter(
name='Problem with translations', language='en'
).exists()
)
self.assertTrue(
problem_names.filter(
name=u'Zadanie z tłumaczeniami', language='pl'
).exists()
)
[docs] def test_title_from_doc(self):
filename = get_test_filename('test_simple_package_no_config.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
self.assertNotEqual(problem.name, 'Not this one')
self.assertEqual(problem.name, 'Testowe')
[docs] def test_latin2_title_from_doc(self):
filename = get_test_filename('test_simple_package_latin2_title_from_doc.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
self.assertEqual(problem.name, u'Łąka')
[docs] def test_utf8_title_from_doc(self):
filename = get_test_filename('test_simple_package_utf8_title_from_doc.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
self.assertEqual(problem.name, u'Łąka')
[docs] def test_utf8_title_from_config(self):
filename = get_test_filename('test_simple_package_utf8_title_from_config.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
self.assertEqual(problem.name, u'ĄąĆćĘꣳÓ󌜯żŹź')
[docs] def test_memory_limit_from_doc(self):
filename = get_test_filename('test_simple_package_no_config.zip')
call_command('addproblem', filename)
test = Test.objects.filter(memory_limit=132000)
self.assertEqual(test.count(), 5)
[docs] def test_attachments(self):
filename = get_test_filename('test_simple_package_attachments.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
self.assertEqual(problem.attachments.all().count(), 1)
[docs] def test_attachments_no_directory(self):
filename = get_test_filename('test_simple_package.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
self.assertEqual(problem.attachments.all().count(), 0)
[docs] def test_attachments_empty_directory(self):
filename = get_test_filename('test_simple_package_attachments_empty.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
self.assertEqual(problem.attachments.all().count(), 0)
[docs] def test_attachments_reupload_same_attachments(self):
filename = get_test_filename('test_simple_package_attachments.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
filename = get_test_filename('test_simple_package_attachments.zip')
call_command('updateproblem', str(problem.id), filename)
problem = Problem.objects.get()
self.assertEqual(problem.attachments.all().count(), 1)
[docs] def test_attachments_reupload_no_attachments(self):
filename = get_test_filename('test_simple_package_attachments.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
filename = get_test_filename('test_simple_package_attachments_empty.zip')
call_command('updateproblem', str(problem.id), filename)
problem = Problem.objects.get()
self.assertEqual(problem.attachments.all().count(), 0)
[docs] def test_assign_points_from_file(self):
filename = get_test_filename('test_scores.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
self.assertEqual(tests.get(name='1a').max_score, 42)
self.assertEqual(tests.get(name='1b').max_score, 42)
self.assertEqual(tests.get(name='1c').max_score, 42)
self.assertEqual(tests.get(name='2').max_score, 23)
[docs] def test_assign_global_time_limit_from_file(self):
filename = get_test_filename('test_global_time_limit.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
self.assertEqual(tests.get(name='1a').time_limit, 7000)
self.assertEqual(tests.get(name='1b').time_limit, 7000)
self.assertEqual(tests.get(name='1c').time_limit, 7000)
self.assertEqual(tests.get(name='2').time_limit, 7000)
[docs] def test_assign_time_limits_for_groups_from_file(self):
filename = get_test_filename('test_time_limits_for_group.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
self.assertEqual(tests.get(name='1a').time_limit, 2000)
self.assertEqual(tests.get(name='1b').time_limit, 2000)
self.assertEqual(tests.get(name='1c').time_limit, 2000)
self.assertEqual(tests.get(name='2').time_limit, 3000)
@pytest.mark.xfail(strict=True)
[docs] def test_assign_time_limits_for_groups_nonexistent(self):
filename = get_test_filename('test_time_limits_for_nonexisting_group.zip')
self.assertRaises(CommandError, call_command, 'addproblem', filename)
call_command('addproblem', filename, "nothrow")
self.assertEqual(Problem.objects.count(), 0)
package = ProblemPackage.objects.get()
self.assertEqual(package.status, "ERR")
# Check if error message is relevant to the issue
self.assertIn("no such test group exists", package.info)
[docs] def test_assign_time_limits_for_different_levels(self):
filename = get_test_filename('test_time_limit_levels.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
self.assertEqual(tests.get(name='1a').time_limit, 3000)
self.assertEqual(tests.get(name='1b').time_limit, 5000)
self.assertEqual(tests.get(name='1c').time_limit, 5000)
self.assertEqual(tests.get(name='2').time_limit, 7000)
[docs] def test_assign_points_nonexistent(self):
filename = get_test_filename('test_scores_nonexistent_fail.zip')
self.assertRaises(CommandError, call_command, 'addproblem', filename)
call_command('addproblem', filename, "nothrow")
self.assertEqual(Problem.objects.count(), 0)
package = ProblemPackage.objects.get()
self.assertEqual(package.status, "ERR")
# Check if error message is relevant to the issue
self.assertIn("no such test group exists", package.info)
[docs] def test_assign_points_not_exhaustive(self):
filename = get_test_filename('test_scores_notexhaustive_fail.zip')
self.assertRaises(CommandError, call_command, 'addproblem', filename)
call_command('addproblem', filename, "nothrow")
self.assertEqual(Problem.objects.count(), 0)
package = ProblemPackage.objects.get()
self.assertEqual(package.status, "ERR")
# Check if error message is relevant to the issue
self.assertIn("Score for group", package.info)
self.assertIn("not found", package.info)
@pytest.mark.slow
@both_configurations
@override_settings(CONTEST_MODE=ContestMode.neutral)
[docs] def test_huge_unpack_update(self):
self.assertTrue(self.client.login(username='test_admin'))
filename = get_test_filename('test_huge_package.tgz')
call_command('addproblem', filename)
problem = Problem.objects.get()
# Rudimentary test of package updating
url = (
reverse('add_or_update_problem')
+ '?'
+ urllib.parse.urlencode({'problem': problem.id})
)
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 200)
url = response.redirect_chain[-1][0]
response = self.client.post(
url,
{
'package_file': open(filename, 'rb'),
'visibility': Problem.VISIBILITY_PRIVATE,
},
follow=True,
)
self.assertEqual(response.status_code, 200)
url = reverse('oioioiadmin:problems_problempackage_changelist')
self.assertRedirects(response, url)
[docs] def _check_no_ingen_package(self, problem, doc=True):
self.assertEqual(problem.short_name, 'test')
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
t0 = tests.get(name='0')
self.assertEqual(t0.input_file.read(), b'0 0\n')
self.assertEqual(t0.output_file.read(), b'0\n')
self.assertEqual(t0.kind, 'EXAMPLE')
self.assertEqual(t0.group, '0')
self.assertEqual(t0.max_score, 0)
self.assertEqual(t0.time_limit, DEFAULT_TIME_LIMIT)
self.assertEqual(t0.memory_limit, DEFAULT_MEMORY_LIMIT)
t1a = tests.get(name='1a')
self.assertEqual(t1a.input_file.read(), b'0 0\n')
self.assertEqual(t1a.output_file.read(), b'0\n')
self.assertEqual(t1a.kind, 'NORMAL')
self.assertEqual(t1a.group, '1')
self.assertEqual(t1a.max_score, 100)
self.assertEqual(t1a.time_limit, DEFAULT_TIME_LIMIT)
self.assertEqual(t1a.memory_limit, DEFAULT_MEMORY_LIMIT)
t1b = tests.get(name='1b')
self.assertEqual(t1b.input_file.read(), b'0 0\n')
self.assertEqual(t1b.output_file.read(), b'0\n')
self.assertEqual(t1b.kind, 'NORMAL')
self.assertEqual(t1b.group, '1')
self.assertEqual(t1b.max_score, 100)
self.assertEqual(t1b.time_limit, DEFAULT_TIME_LIMIT)
self.assertEqual(t1b.memory_limit, DEFAULT_MEMORY_LIMIT)
model_solutions = ModelSolution.objects.filter(problem=problem)
sol = model_solutions.get(name='test.c')
self.assertEqual(sol.kind, 'NORMAL')
self.assertEqual(model_solutions.count(), 1)
@both_configurations
[docs] def test_no_ingen_package(self):
filename = get_test_filename('test_no_ingen_package.tgz')
call_command('addproblem', filename)
problem = Problem.objects.get()
self._check_no_ingen_package(problem)
# Rudimentary test of package updating
call_command('updateproblem', str(problem.id), filename)
problem = Problem.objects.get()
self._check_no_ingen_package(problem)
[docs] def _check_full_package(self, problem, doc=True):
self.assertEqual(problem.short_name, 'sum')
config = ExtraConfig.objects.get(problem=problem)
assert 'extra_compilation_args' in config.parsed_config
if doc:
self.assertEqual(problem.name, u'Sumżyce')
if settings.USE_SINOLPACK_MAKEFILES:
statements = ProblemStatement.objects.filter(problem=problem)
self.assertEqual(statements.count(), 1)
self.assertTrue(statements.get().content.read().startswith(b'%PDF'))
else:
self.assertEqual(problem.name, u'sum')
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
t0 = tests.get(name='0')
self.assertEqual(t0.input_file.read(), b'1 2\n')
self.assertEqual(t0.output_file.read(), b'3\n')
self.assertEqual(t0.kind, 'EXAMPLE')
self.assertEqual(t0.group, '0')
self.assertEqual(t0.max_score, 0)
self.assertEqual(t0.time_limit, DEFAULT_TIME_LIMIT)
self.assertEqual(t0.memory_limit, 133000)
t1a = tests.get(name='1a')
self.assertEqual(t1a.kind, 'NORMAL')
self.assertEqual(t1a.group, '1')
self.assertEqual(t1a.max_score, 33)
t1b = tests.get(name='1b')
self.assertEqual(t1b.kind, 'NORMAL')
self.assertEqual(t1b.group, '1')
self.assertEqual(t1b.max_score, 33)
self.assertEqual(t1b.time_limit, 100)
t1ocen = tests.get(name='1ocen')
self.assertEqual(t1ocen.kind, 'EXAMPLE')
self.assertEqual(t1ocen.group, '1ocen')
self.assertEqual(t1ocen.max_score, 0)
t2 = tests.get(name='2')
self.assertEqual(t2.kind, 'NORMAL')
self.assertEqual(t2.group, '2')
self.assertEqual(t2.max_score, 33)
t3 = tests.get(name='3')
self.assertEqual(t3.kind, 'NORMAL')
self.assertEqual(t3.group, '3')
self.assertEqual(t3.max_score, 34)
self.assertEqual(tests.count(), 6)
checker = OutputChecker.objects.get(problem=problem)
self.assertTrue(bool(checker.exe_file))
extra_files = ExtraFile.objects.filter(problem=problem)
self.assertEqual(extra_files.count(), 1)
self.assertEqual(extra_files.get().name, 'makra.h')
model_solutions = ModelSolution.objects.filter(problem=problem).order_by(
'order_key'
)
sol = model_solutions.get(name='sum.c')
self.assertEqual(sol.kind, 'NORMAL')
sol1 = model_solutions.get(name='sums1.cpp')
self.assertEqual(sol1.kind, 'SLOW')
solb0 = model_solutions.get(name='sumb0.c')
self.assertEqual(solb0.kind, 'INCORRECT')
self.assertEqual(model_solutions.count(), 3)
self.assertEqual(list(model_solutions), [sol, sol1, solb0])
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
@pytest.mark.slow
@both_configurations
[docs] def test_full_unpack_update(self):
filename = get_test_filename('test_full_package.tgz')
call_command('addproblem', filename)
problem = Problem.objects.get()
self._check_full_package(problem)
# Rudimentary test of package updating
call_command('updateproblem', str(problem.id), filename)
problem = Problem.objects.get()
self._check_full_package(problem)
[docs] def _check_interactive_package(self, problem):
self.assertEqual(problem.short_name, 'arc')
config = ExtraConfig.objects.get(problem=problem)
assert len(config.parsed_config['extra_compilation_args']) == 2
assert len(config.parsed_config['extra_compilation_files']) == 2
self.assertEqual(problem.name, u'arc')
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
t0 = tests.get(name='0')
self.assertEqual(t0.input_file.read(), b'3\n12\n5\n8\n3\n15\n8\n0\n')
self.assertEqual(t0.output_file.read(), b'12\n15\n8\n')
self.assertEqual(t0.kind, 'EXAMPLE')
self.assertEqual(t0.group, '0')
self.assertEqual(t0.max_score, 0)
self.assertEqual(t0.time_limit, DEFAULT_TIME_LIMIT)
self.assertEqual(t0.memory_limit, 66000)
t1a = tests.get(name='1a')
self.assertEqual(
t1a.input_file.read(), b'0\n-435634223 1 30 23 130 0 -324556462\n'
)
self.assertEqual(
t1a.output_file.read(),
b"""126\n126\n82\n85\n80\n64\n84\n5\n128\n66\n4\n79\n64\n96
22\n107\n84\n112\n92\n63\n125\n82\n1\n""",
)
self.assertEqual(t1a.kind, 'NORMAL')
self.assertEqual(t1a.group, '1')
self.assertEqual(t1a.max_score, 50)
t2a = tests.get(name='2a')
self.assertEqual(
t2a.input_file.read(), b'0\n-435634223 1 14045 547 60000 0 -324556462\n'
)
self.assertEqual(t2a.kind, 'NORMAL')
self.assertEqual(t2a.group, '2')
self.assertEqual(t2a.max_score, 50)
checker = OutputChecker.objects.get(problem=problem)
self.assertIsNotNone(checker.exe_file)
extra_files = ExtraFile.objects.filter(problem=problem)
self.assertEqual(extra_files.count(), 2)
model_solutions = ModelSolution.objects.filter(problem=problem).order_by(
'order_key'
)
solc = model_solutions.get(name='arc.c')
self.assertEqual(solc.kind, 'NORMAL')
solcpp = model_solutions.get(name='arc1.cpp')
self.assertEqual(solcpp.kind, 'NORMAL')
self.assertEqual(list(model_solutions), [solc, solcpp])
submissions = Submission.objects.all()
for s in submissions:
self.assertEqual(s.status, 'INI_OK')
self.assertEqual(s.score, IntegerScore(100))
@pytest.mark.slow
@both_configurations
[docs] def test_interactive_task(self):
filename = get_test_filename('test_interactive_package.tgz')
call_command('addproblem', filename)
problem = Problem.objects.get()
self._check_interactive_package(problem)
[docs] def _add_problem_with_author(self, filename, author, nothrow=False):
try:
backend = import_string(backend_for_package(filename))()
except NoBackend:
raise ValueError("Package format not recognized")
pp = ProblemPackage(problem=None)
pp.package_file.save(filename, File(open(filename, 'rb')))
env = {'author': author}
pp.problem_name = backend.get_short_name(filename)
pp.save()
env['package_id'] = pp.id
problem = None
with pp.save_operation_status():
backend.unpack(env)
problem = Problem.objects.get(id=env['problem_id'])
pp.problem = problem
pp.save()
if problem is None and not nothrow:
raise ValueError("Error during unpacking the given package")
[docs] def test_restrict_html(self):
self.assertTrue(self.client.login(username='test_user'))
filename = get_test_filename(
'test_simple_package_with_malicious_html_statement.zip'
)
with self.settings(USE_SINOLPACK_MAKEFILES=False):
with self.settings(SINOLPACK_RESTRICT_HTML=True):
self._add_problem_with_author(filename, 'test_user', True)
self.assertEqual(Problem.objects.count(), 0)
package = ProblemPackage.objects.get()
self.assertEqual(package.status, "ERR")
# Check if error message is relevant to the issue
self.assertIn("problem statement in HTML", package.info)
self._add_problem_with_author(filename, 'test_admin')
self._add_problem_with_author(filename, 'test_user')
with self.settings(SINOLPACK_RESTRICT_HTML=True):
self._add_problem_with_author(filename, 'test_user')
self.assertEqual(Problem.objects.count(), 3)
@pytest.mark.slow
@both_configurations
[docs] def test_overriden_limits_with_reupload(self):
filename = get_test_filename('test_limits_overriden_for_cpp.zip')
call_command('addproblem', filename)
problem = Problem.objects.get()
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
overriden_tests = LanguageOverrideForTest.objects.filter(test__in=tests)
self.assertEqual(len(overriden_tests), 5)
self.assertTrue(all([t.language == 'cpp' for t in overriden_tests]))
# New global time limit
self.assertTrue(all([t.time_limit == 1000 for t in overriden_tests]))
# New group-specific memory limits
overriden_memory_group = overriden_tests.filter(test__group=1)
self.assertTrue(all([t.memory_limit == 6000 for t in overriden_memory_group]))
overriden_memory_group2 = overriden_tests.filter(test__group=2)
self.assertTrue(all([t.memory_limit == 2000 for t in overriden_memory_group2]))
filename = get_test_filename('test_limits_overriden_for_cpp_and_py.zip')
call_command('updateproblem', str(problem.id),filename)
tests = Test.objects.filter(problem_instance=problem.main_problem_instance)
overriden_tests = LanguageOverrideForTest.objects.filter(test__in=tests)
for lang in ('cpp', 'py'):
self.assertEqual(overriden_tests.filter(language=lang).count(), 5)
# New and halved global time limit
self.assertTrue(all([t.time_limit == 500 for t in overriden_tests]))
# New and halved memory limits for a different set of groups
overriden_memory_group = overriden_tests.filter(test__group=0)
self.assertTrue(all([t.memory_limit == 3000 for t in overriden_memory_group]))
overriden_memory_group2 = overriden_tests.filter(test__group=2)
self.assertTrue(all([t.memory_limit == 1000 for t in overriden_memory_group2]))
@enable_both_unpack_configurations
@needs_linux
[docs]class TestSinolPackageInContest(TransactionTestCase, TestStreamingMixin):
[docs] fixtures = ['test_users', 'test_contest']
@both_configurations
[docs] def test_upload_and_download_package(self):
ProblemInstance.objects.all().delete()
contest = Contest.objects.get()
contest.default_submissions_limit = 123
contest.save()
filename = get_test_filename('test_simple_package.zip')
self.assertTrue(self.client.login(username='test_admin'))
url = reverse('oioioiadmin:problems_problem_add')
response = self.client.get(url, {'contest_id': contest.id}, follow=True)
url = response.redirect_chain[-1][0]
self.assertEqual(response.status_code, 200)
self.assertIn(
'problems/add-or-update.html',
[getattr(t, 'name', None) for t in response.templates],
)
response = self.client.post(
url,
{
'package_file': open(filename, 'rb'),
'visibility': Problem.VISIBILITY_PRIVATE,
},
follow=True,
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Problem.objects.count(), 1)
self.assertEqual(ProblemInstance.objects.count(), 2)
self.assertEqual(
ProblemInstance.objects.get(contest=contest).submissions_limit, 123
)
contest.default_submissions_limit = 124
contest.save()
# Delete tests and check if re-uploading will fix it.
problem = Problem.objects.get()
problem_instance = ProblemInstance.objects.filter(contest__isnull=False).get()
num_tests = problem_instance.test_set.count()
for test in problem_instance.test_set.all():
test.delete()
problem_instance.save()
# problem instances are independent
problem_instance = problem.main_problem_instance
self.assertEqual(problem_instance.test_set.count(), num_tests)
num_tests = problem_instance.test_set.count()
for test in problem_instance.test_set.all():
test.delete()
problem_instance.save()
url = (
reverse('add_or_update_problem', kwargs={'contest_id': contest.id})
+ '?'
+ urllib.parse.urlencode({'problem': problem_instance.problem.id})
)
response = self.client.get(url, follow=True)
url = response.redirect_chain[-1][0]
self.assertEqual(response.status_code, 200)
self.assertIn(
'problems/add-or-update.html',
[getattr(t, 'name', None) for t in response.templates],
)
response = self.client.post(
url,
{
'package_file': open(filename, 'rb'),
'visibility': Problem.VISIBILITY_PRIVATE,
},
follow=True,
)
self.assertEqual(response.status_code, 200)
problem_instance = ProblemInstance.objects.filter(contest__isnull=False).get()
self.assertEqual(problem_instance.test_set.count(), num_tests)
self.assertEqual(problem_instance.submissions_limit, 123)
problem_instance = problem.main_problem_instance
self.assertEqual(problem_instance.test_set.count(), num_tests)
response = self.client.get(
reverse(
'oioioiadmin:problems_problem_download',
args=(problem_instance.problem.id,),
)
)
self.assertStreamingEqual(response, open(filename, 'rb').read())
@both_configurations
[docs] def test_inwer_failure_package(self):
ProblemInstance.objects.all().delete()
contest = Contest.objects.get()
filename = get_test_filename('test_inwer_failure.zip')
self.assertTrue(self.client.login(username='test_admin'))
url = reverse('oioioiadmin:problems_problem_add')
response = self.client.get(url, {'contest_id': contest.id}, follow=True)
url = response.redirect_chain[-1][0]
self.assertEqual(response.status_code, 200)
response = self.client.post(
url,
{
'package_file': open(filename, 'rb'),
'visibility': Problem.VISIBILITY_PRIVATE,
},
follow=True,
)
self.assertEqual(response.status_code, 200)
self.assertEqual(Problem.objects.count(), 0)
self.assertEqual(ProblemInstance.objects.count(), 0)
# Bad packages need to be left over for the error messages
self.assertEqual(ProblemPackage.objects.count(), 1)
[docs]class TestSinolPackageCreator(TestCase, TestStreamingMixin):
[docs] fixtures = [
'test_users',
'test_full_package',
'test_problem_instance_with_no_contest',
]
[docs] def test_sinol_package_creator(self):
problem = Problem.objects.get()
self.assertTrue(self.client.login(username='test_admin'))
response = self.client.get(
reverse('oioioiadmin:problems_problem_download', args=(problem.id,))
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Content-Type'], 'application/zip')
stream = BytesIO(self.streamingContent(response))
zip = zipfile.ZipFile(stream, 'r')
self.assertEqual(
sorted(zip.namelist()),
[
'sum/doc/sumzad.pdf',
'sum/in/sum0.in',
'sum/in/sum1a.in',
'sum/in/sum1b.in',
'sum/in/sum1ocen.in',
'sum/in/sum2.in',
'sum/in/sum3.in',
'sum/out/sum0.out',
'sum/out/sum1a.out',
'sum/out/sum1b.out',
'sum/out/sum1ocen.out',
'sum/out/sum2.out',
'sum/out/sum3.out',
'sum/prog/sum.c',
'sum/prog/sumb0.c',
'sum/prog/sums1.cpp',
],
)
[docs]class TestJudging(TestCase):
[docs] fixtures = [
'test_users',
'test_contest',
'test_full_package',
'test_problem_instance',
]
[docs] def test_judging(self):
self.assertTrue(self.client.login(username='test_user'))
contest = Contest.objects.get()
url = reverse('submit', kwargs={'contest_id': contest.id})
# Show submission form
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertIn(
'contests/submit.html',
[getattr(t, 'name', None) for t in response.templates],
)
form = response.context['form']
self.assertEqual(len(form.fields['problem_instance_id'].choices), 1)
pi_id = form.fields['problem_instance_id'].choices[0][0]
# Submit
filename = get_test_filename('sum-various-results.cpp')
response = self.client.post(
url, {'problem_instance_id': pi_id, 'file': open(filename, 'rb')}
)
self.assertEqual(response.status_code, 302)
self.assertEqual(Submission.objects.count(), 1)
self.assertEqual(TestReport.objects.count(), 6)
self.assertEqual(TestReport.objects.filter(status='OK').count(), 4)
self.assertEqual(TestReport.objects.filter(status='WA').count(), 1)
self.assertEqual(TestReport.objects.filter(status='RE').count(), 1)
submission = Submission.objects.get()
self.assertEqual(submission.status, 'INI_OK')
self.assertEqual(submission.score, IntegerScore(34))
urc = UserResultForContest.objects.get()
self.assertEqual(urc.score, IntegerScore(34))
@needs_linux
[docs]class TestLimits(TestCase):
[docs] fixtures = ['test_users', 'test_contest']
[docs] def upload_package(self):
ProblemInstance.objects.all().delete()
contest = Contest.objects.get()
filename = get_test_filename('test_simple_package.zip')
self.assertTrue(self.client.login(username='test_admin'))
url = reverse('oioioiadmin:problems_problem_add')
response = self.client.get(url, {'contest_id': contest.id}, follow=True)
url = response.redirect_chain[-1][0]
self.assertEqual(response.status_code, 200)
self.assertIn(
'problems/add-or-update.html',
[getattr(t, 'name', None) for t in response.templates],
)
return self.client.post(
url,
{
'package_file': open(filename, 'rb'),
'visibility': Problem.VISIBILITY_PRIVATE,
},
follow=True,
)
@override_settings(MAX_TEST_TIME_LIMIT_PER_PROBLEM=2000)
[docs] def test_time_limit(self):
response = self.upload_package()
self.assertContains(
response,
escape(
"Sum of time limits for all tests is too big. It's "
"50s, but it shouldn't exceed 2s."
),
)
@override_settings(MAX_MEMORY_LIMIT_FOR_TEST=10)
[docs] def test_memory_limit(self):
response = self.upload_package()
self.assertContains(
response,
escape(
"Memory limit mustn't be greater than %dKiB"
% settings.MAX_MEMORY_LIMIT_FOR_TEST
),
)