Source code for oioioi.problems.tests.test_upload

import pytest
import urllib.parse
from django.core.files.base import ContentFile
from django.db import transaction
from django.test import TransactionTestCase
from django.test.utils import override_settings
from django.urls import reverse

from oioioi.base.tests import needs_linux
from oioioi.contests.models import Contest, ProblemInstance, Round
from oioioi.filetracker.tests import TestStreamingMixin
from oioioi.problems.models import Problem, ProblemPackage, ProblemSite
from oioioi.problems.tests.utilities import get_test_filename


[docs]def make_add_update_problem_url(contest, args): return '{}?{}'.format( reverse('add_or_update_problem', kwargs={'contest_id': contest.id}), urllib.parse.urlencode(args), )
@override_settings( PROBLEM_PACKAGE_BACKENDS=('oioioi.problems.tests.DummyPackageBackend',) )
[docs]class TestAPIProblemUpload(TransactionTestCase):
[docs] fixtures = ['test_users', 'test_contest']
[docs] def test_successful_upload(self): ProblemInstance.objects.all().delete() contest = Contest.objects.get() round = contest.round_set.all().first() self.assertTrue(self.client.login(username='test_admin')) data = { 'package_file': ContentFile('eloziom', name='foo'), 'contest_id': contest.id, 'round_name': round.name, } url = reverse('api_package_upload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 201) data = response.json() self.assertTrue('package_id' in data)
[docs] def test_successful_reupload(self): # first we upload single problem ProblemInstance.objects.all().delete() contest = Contest.objects.get() round = contest.round_set.all().first() self.assertTrue(self.client.login(username='test_admin')) data = { 'package_file': ContentFile('eloziom', name='foo'), 'contest_id': contest.id, 'round_name': round.name, } url = reverse('api_package_upload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 201) # then we reupload its package problem = Problem.objects.all().first() data = { 'package_file': ContentFile('eloziomReuploaded', name='foo'), 'problem_id': problem.id, } url = reverse('api_package_reupload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 201) data = response.json() self.assertTrue('package_id' in data)
[docs] def test_failed_upload_no_perm(self): ProblemInstance.objects.all().delete() contest = Contest.objects.get() round = contest.round_set.all().first() self.assertTrue(self.client.login(username='test_user')) data = { 'package_file': ContentFile('eloziom', name='foo'), 'contest_id': contest.id, 'round_name': round.name, } url = reverse('api_package_upload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 403)
[docs] def test_failed_reupload_no_perm(self): ProblemInstance.objects.all().delete() contest = Contest.objects.get() round = contest.round_set.all().first() self.assertTrue(self.client.login(username='test_admin')) data = { 'package_file': ContentFile('eloziom', name='foo'), 'contest_id': contest.id, 'round_name': round.name, } url = reverse('api_package_upload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 201) self.assertTrue(self.client.login(username='test_user')) problem = Problem.objects.all().first() data = { 'package_file': ContentFile('eloziomReuploaded', name='foo'), 'problem_id': problem.id, } url = reverse('api_package_reupload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 403)
[docs] def test_failed_upload_no_file(self): ProblemInstance.objects.all().delete() contest = Contest.objects.get() round = contest.round_set.all().first() self.assertTrue(self.client.login(username='test_admin')) data = {'contest_id': contest.id, 'round_name': round.name} url = reverse('api_package_upload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 400)
[docs] def test_failed_upload_no_contest_id(self): ProblemInstance.objects.all().delete() contest = Contest.objects.get() round = contest.round_set.all().first() self.assertTrue(self.client.login(username='test_admin')) data = { 'package_file': ContentFile('eloziom', name='foo'), 'round_name': round.name, } url = reverse('api_package_upload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 400)
[docs] def test_failed_upload_no_round_name(self): ProblemInstance.objects.all().delete() contest = Contest.objects.get() self.assertTrue(self.client.login(username='test_admin')) data = { 'package_file': ContentFile('eloziom', name='foo'), 'contest_id': contest.id, } url = reverse('api_package_upload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 400)
[docs] def test_failed_reupload_no_file(self): ProblemInstance.objects.all().delete() self.assertTrue(self.client.login(username='test_admin')) data = {'problem_id': 1} url = reverse('api_package_reupload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 400)
[docs] def test_failed_reupload_no_problem_id(self): ProblemInstance.objects.all().delete() self.assertTrue(self.client.login(username='test_admin')) data = {'package_file': ContentFile('eloziom', name='foo')} url = reverse('api_package_reupload') response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 400)
@override_settings( PROBLEM_PACKAGE_BACKENDS=('oioioi.problems.tests.DummyPackageBackend',) )
[docs]class TestAPIProblemUploadQuery(TransactionTestCase):
[docs] fixtures = ['test_users', 'test_contest', 'test_permissions']
[docs] def setUp(self): ProblemInstance.objects.all().delete() self.contest = Contest.objects.get() self.round = self.contest.round_set.all().first() self.data = { 'package_file': ContentFile('eloziom', name='foo'), 'contest_id': self.contest.id, 'round_name': self.round.name, }
[docs] def _test_successful_query(self, username): self.assertTrue(self.client.login(username=username)) url = reverse('api_package_upload') response = self.client.post(url, self.data, follow=True) self.assertEqual(response.status_code, 201) data = response.json() self.assertTrue('package_id' in data) package_id = data.get('package_id') url = reverse('api_package_upload_query', args=(package_id,)) response = self.client.get(url, follow=True) self.assertEqual(response.status_code, 200) data = response.json() self.assertTrue('package_status' in data)
[docs] def test_successful_query_as_admin(self): self._test_successful_query('test_admin')
[docs] def test_successful_query_as_contest_admin(self): self._test_successful_query('test_contest_admin')
[docs] def test_failed_query_no_perm(self): self.assertTrue(self.client.login(username='test_admin')) url = reverse('api_package_upload') response = self.client.post(url, self.data, follow=True) self.assertEqual(response.status_code, 201) self.assertTrue(self.client.login(username='test_user')) package_id = response.json().get('package_id') url = reverse('api_package_upload_query', args=(package_id,)) response = self.client.get(url, follow=True) self.assertEqual(response.status_code, 403)
@override_settings( PROBLEM_PACKAGE_BACKENDS=('oioioi.problems.tests.DummyPackageBackend',) )
[docs]class TestProblemUpload(TransactionTestCase):
[docs] fixtures = ['test_users', 'test_contest']
[docs] def test_successful_upload(self): ProblemInstance.objects.all().delete() contest = Contest.objects.get() self.assertTrue(self.client.login(username='test_admin')) data = { 'package_file': ContentFile('eloziom', name='foo'), 'visibility': Problem.VISIBILITY_FRIENDS, } url = make_add_update_problem_url(contest, {'key': 'upload'}) response = self.client.post(url, data, follow=True) self.assertContains(response, 'Package information') self.assertContains(response, 'Edit problem') self.assertNotContains(response, 'Error details') self.assertNotContains(response, 'Model solutions') package = ProblemPackage.objects.get() self.assertEqual(package.status, 'OK') self.assertEqual(package.problem_name, 'bar') problem = Problem.objects.get() self.assertEqual(problem.short_name, 'bar') problem_instance = ProblemInstance.objects.filter(contest__isnull=False).get() self.assertEqual(problem_instance.contest, contest) self.assertEqual(problem_instance.problem, problem)
[docs] def test_failed_upload(self): ProblemInstance.objects.all().delete() contest = Contest.objects.get() self.assertTrue(self.client.login(username='test_admin')) data = { 'package_file': ContentFile('eloziom', name='FAIL'), 'visibility': Problem.VISIBILITY_FRIENDS, } url = make_add_update_problem_url(contest, {'key': 'upload'}) response = self.client.post(url, data, follow=True) self.assertContains(response, 'DUMMY_FAILURE') self.assertContains(response, 'Error details') self.assertNotContains(response, 'Edit problem') self.assertNotContains(response, 'Model solutions') package = ProblemPackage.objects.get() self.assertEqual(package.problem_name, 'bar') self.assertEqual(package.status, 'ERR') problems = Problem.objects.all() self.assertEqual(len(problems), 0) problem_instances = ProblemInstance.objects.all() self.assertEqual(len(problem_instances), 0)
@override_settings(PROBLEM_SOURCES=('oioioi.problems.tests.DummySource',))
[docs] def test_handlers(self): contest = Contest.objects.get() self.assertTrue(self.client.login(username='test_admin')) data = { 'package_file': ContentFile('eloziom', name='foo'), 'visibility': Problem.VISIBILITY_FRIENDS, } url = make_add_update_problem_url(contest, {'key': 'upload'}) response = self.client.post(url, data, follow=True) self.assertContains(response, 'Package information') package = ProblemPackage.objects.get() self.assertEqual(package.status, 'OK') self.assertEqual(package.problem_name, 'handled')
[docs] def test_contest_controller_plugins(self): contest = Contest.objects.get() contest.controller_name = 'oioioi.problems.tests.DummyContestController' contest.save() self.assertTrue(self.client.login(username='test_admin')) data = { 'package_file': ContentFile('eloziom', name='foo'), 'visibility': Problem.VISIBILITY_FRIENDS, 'cc_rulez': True, } url = make_add_update_problem_url(contest, {'key': 'upload'}) response = self.client.post(url, data, follow=True) self.assertContains(response, 'Package information') package = ProblemPackage.objects.get() self.assertEqual(package.status, 'OK') self.assertEqual(package.problem_name, 'contest_controller_rulez')
[docs] def test_problem_submission_limit_changed(self): contest = Contest.objects.get() package_file = ContentFile('eloziom', name='foo') 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': package_file, 'visibility': Problem.VISIBILITY_FRIENDS}, follow=True, ) self.assertEqual(response.status_code, 200) self.assertEqual(Problem.objects.count(), 1) self.assertEqual(ProblemInstance.objects.count(), 2) problem = ProblemInstance.objects.filter(contest__isnull=False).get().problem contest.default_submissions_limit += 100 contest.save() url = make_add_update_problem_url(contest, {'problem': problem.id}) response = self.client.get(url, follow=True) url = response.redirect_chain[-1][0] self.assertEqual(response.status_code, 200) response = self.client.post( url, {'package_file': package_file, 'visibility': Problem.VISIBILITY_FRIENDS}, follow=True, ) self.assertEqual(response.status_code, 200) pis = ProblemInstance.objects.filter(problem=problem) self.assertEqual(pis.count(), 2) pi = ProblemInstance.objects.get(contest__isnull=False) self.assertEqual(pi.submissions_limit, contest.default_submissions_limit - 100)
@needs_linux
[docs]class TestProblemsetUploading(TransactionTestCase, TestStreamingMixin):
[docs] fixtures = ['test_users', 'test_contest']
[docs] def post_package_file(self, url, filename, visibility=Problem.VISIBILITY_PRIVATE): return self.client.post( url, { 'package_file': open(filename, 'rb'), 'visibility': visibility, }, follow=True, )
[docs] def check_models_for_simple_package(self, problem_instance): url = reverse('model_solutions', args=[problem_instance.id]) response = self.client.post(url, follow=True) self.assertEqual(response.status_code, 200) to_find = ["0", "1a", "1b", "1c", "2"] for test in to_find: self.assertContains(response, ">" + test + "</th>")
@pytest.mark.xfail(strict=True)
[docs] def test_upload_problem(self): filename = get_test_filename('test_simple_package.zip') self.assertTrue(self.client.login(username='test_admin')) # add problem to problemset url = reverse('problemset_add_or_update') # not possible from problemset :) response = self.client.get(url, {'key': "problemset_source"}, follow=True) self.assertEqual(response.status_code, 200) self.assertContains(response, "Option not available") self.assertContains(response, "Add problem") self.assertNotContains(response, "Select") # but ok by package response = self.client.get(url, follow=True) url = response.redirect_chain[-1][0] self.assertEqual(response.status_code, 200) self.assertContains(response, "Add problem") self.assertIn( 'problems/problemset/add-or-update.html', [getattr(t, 'name', None) for t in response.templates], ) response = self.post_package_file(url, filename) self.assertEqual(response.status_code, 200) self.assertEqual(Problem.objects.count(), 1) self.assertEqual(ProblemInstance.objects.count(), 1) self.assertEqual(ProblemSite.objects.count(), 1) # problem is not visible in "Public" url = reverse('problemset_main') response = self.client.post(url, follow=True) self.assertEqual(response.status_code, 200) self.assertNotContains(response, "Testowe") self.assertNotContains(response, "<td>tst</td>") # but visible in "My problems" url = reverse('problemset_my_problems') self.assertEqual(response.status_code, 200) response = self.client.post(url, follow=True) self.assertContains(response, "Testowe") self.assertContains(response, "<td>tst</td>") # and we are problem's author and problem_site exists problem = Problem.objects.get() url = '{}?key=settings'.format( reverse('problem_site', args=[problem.problemsite.url_key]) ) response = self.client.post(url, follow=True) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Edit problem') self.assertContains(response, 'Reupload problem') self.assertContains(response, 'Edit package') self.assertContains(response, 'Model solutions') # we can see model solutions of main_problem_instance self.check_models_for_simple_package(problem.main_problem_instance) # reuploading problem in problemset is not available from problemset url = reverse('problemset_add_or_update') response = self.client.get( url, {'key': "problemset_source", 'problem': problem.id}, follow=True ) self.assertEqual(response.status_code, 200) self.assertContains(response, "Option not available") self.assertNotContains(response, "Select")
@pytest.mark.xfail(strict=True)
[docs] def test_add_problem_to_contest(self): ProblemInstance.objects.all().delete() contest = Contest.objects.get() contest.default_submissions_limit = 42 contest.save() filename = get_test_filename('test_simple_package.zip') self.assertTrue(self.client.login(username='test_admin')) # Add problem to problemset url = reverse('problemset_add_or_update') response = self.client.get(url, follow=True) url = response.redirect_chain[-1][0] self.assertEqual(response.status_code, 200) response = self.post_package_file(url, filename) self.assertEqual(response.status_code, 200) self.assertEqual(Problem.objects.count(), 1) self.assertEqual(ProblemInstance.objects.count(), 1) problem = Problem.objects.get() url_key = problem.problemsite.url_key # now, add problem to the contest url = make_add_update_problem_url(contest, {'key': "problemset_source"}) response = self.client.post(url, follow=True) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Add from Problemset') self.assertContains(response, 'Enter problem') self.assertContains(response, 's secret key') self.assertContains(response, 'Choose problem from problemset') pi_number = 3 for i in range(pi_number): url = make_add_update_problem_url(contest, {'key': "problemset_source"}) response = self.client.get(url, {'url_key': url_key}, follow=True) self.assertEqual(response.status_code, 200) self.assertContains(response, str(url_key)) response = self.client.post(url, {'url_key': url_key}, follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(ProblemInstance.objects.count(), 2 + i) # check submissions limit for pi in ProblemInstance.objects.filter(contest__isnull=False): self.assertEqual(pi.submissions_limit, contest.default_submissions_limit) # add probleminstances to round with transaction.atomic(): for pi in ProblemInstance.objects.filter(contest__isnull=False): pi.round = Round.objects.get() pi.save() # we can see model solutions pi = ProblemInstance.objects.filter(contest__isnull=False)[0] self.check_models_for_simple_package(pi) # tests and models of every problem_instance are independent num_tests = pi.test_set.count() for test in pi.test_set.all(): test.delete() pi.save() url = reverse('model_solutions', args=[pi.id]) response = self.client.post(url, follow=True) self.assertEqual(response.status_code, 200) for test in ["0", "1a", "1b", "1c", "2"]: self.assertNotContains(response, ">" + test + "</th>") for pi2 in ProblemInstance.objects.all(): if pi2 != pi: self.assertEqual(pi2.test_set.count(), num_tests) self.check_models_for_simple_package(pi2) # reupload one ProblemInstance from problemset url = make_add_update_problem_url( contest, { 'key': "problemset_source", 'problem': problem.id, 'instance_id': pi.id, }, ) response = self.client.get(url, follow=True) self.assertEqual(response.status_code, 200) self.assertContains(response, str(url_key)) self.assertNotContains(response, "Select") response = self.client.post(url, {'url_key': url_key}, follow=True) self.assertEqual(response.status_code, 200) self.assertEqual(ProblemInstance.objects.count(), pi_number + 1) self.assertTrue(pi.round) self.assertEqual(pi.test_set.count(), num_tests) self.check_models_for_simple_package(pi) self.assertContains(response, "1 PROBLEM NEEDS REJUDGING") self.assertEqual( response.content.count("Rejudge all submissions for problem"), 1 ) # reupload problem in problemset url = '{}?{}'.format( reverse('problemset_add_or_update'), urllib.parse.urlencode({'problem': problem.id}), ) response = self.client.get(url, follow=True) url = response.redirect_chain[-1][0] self.assertEqual(response.status_code, 200) response = self.post_package_file(url, filename) self.assertEqual(response.status_code, 200) self.assertEqual(ProblemInstance.objects.count(), pi_number + 1) self.assertContains(response, "3 PROBLEMS NEED REJUDGING") self.check_models_for_simple_package(pi) # rejudge one problem url = reverse('rejudge_all_submissions_for_problem', args=[pi.id]) response = self.client.get(url, follow=True) self.assertEqual(response.status_code, 200) self.assertContains(response, "You are going to rejudge 1") response = self.client.post(url, {'submit': True}, follow=True) self.assertEqual(response.status_code, 200) self.assertEqual( response.content.count("Rejudge all submissions for problem"), pi_number - 1 ) self.assertContains(response, "1 rejudge request received.")
[docs] def test_uploading_to_contest(self): # we can add problem directly from contest 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], ) response = self.post_package_file(url, filename) self.assertEqual(response.status_code, 200) self.assertEqual(Problem.objects.count(), 1) self.assertEqual(ProblemInstance.objects.count(), 2) # many times response = self.post_package_file(url, filename) self.assertEqual(response.status_code, 200) self.assertEqual(Problem.objects.count(), 2) self.assertEqual(ProblemInstance.objects.count(), 4) # and nothing needs rejudging self.assertNotContains(response, 'REJUDGING')