diff --git a/tournaments/frontend/tests.py b/tournaments/frontend/tests.py index a24c9e9..6d1fb12 100644 --- a/tournaments/frontend/tests.py +++ b/tournaments/frontend/tests.py @@ -6,7 +6,7 @@ from . import views from tournaments import models -from tournaments.tests import test_tournament1_yml +from tournaments.tests import test_tournament1_yml, _confirm_fixture password1 = 'Xz23#!sZ' @@ -321,15 +321,21 @@ def test(self): self.assertTrue(self.user1_tournament.published) -def start_tournament(tournament): +def add_participators(tournament, number = 10): if not tournament.published: tournament.published = True tournament.save() - users = [models.User.objects.create(username = f'user{idx}') for idx in range(10)] + users = [models.User.objects.get_or_create(username = f'user{idx}')[0] for idx in range(number)] for user in users: models.Participation.objects.create(tournament = tournament, user = user, slot_id = models.Participation.next_slot_id(tournament)) + return users + + +def start_tournament(tournament, **kwargs): + users = add_participators(tournament, **kwargs) tournament.update_state() assert tournament.state == 'active' + return users class DraftTournamentViewTests(TestCase): @@ -587,3 +593,198 @@ def test(self): self.assertEqual(response.status_code, 200) self.assertIs(response.resolver_match.func.view_class, views.UpdateTournamentView) self.assertEqual(clone.definition, self.user1_tournament.definition) + + +class TournamentProgressViewTests(TestCase): + + def setUp(self): + self.user1 = models.User.objects.create(username = 'test1') + self.user2 = models.User.objects.create(username = 'test2') + self.client.force_login(self.user1) + + self.tournament1 = models.Tournament.load(definition = test_tournament1_yml, name = 'Test1', creator = self.user1, published = True) + self.tournament2 = models.Tournament.load(definition = test_tournament1_yml, name = 'Test2', creator = self.user2, published = True) + + self.users = add_participators(self.tournament1, number = 10) + + def test_unauthenticated_open(self): + """ + Starting a tournament as an authenticated user yields 403 (forbidden). + """ + self.client.logout() + + response = self.client.get(reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id))) + self.assertEqual(response.status_code, 403) + + def test_foreign_open(self): + """ + Starting a tournament created by a different user yields 403 (forbidden). + """ + response = self.client.get(reverse('tournament-progress', kwargs = dict(pk = self.tournament2.id))) + self.assertEqual(response.status_code, 403) + + def test_unauthenticated_active(self): + self.test_open() + self.client.logout() + + response = self.client.get(reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id))) + self.assertEqual(response.status_code, 200) + self.assertContains(response, '

Preliminaries Current Stage

') + + def test_not_found(self): + response = self.client.get(reverse('tournament-progress', kwargs = dict(pk = 0))) + self.assertEqual(response.status_code, 404) + + def test_drafted(self): + self.tournament1.published = False + self.tournament1.save() + response = self.client.get(reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id))) + self.assertEqual(response.status_code, 412) + + def test_less_than_3_participators(self): + """ + Starting a tournament created by the user yields 412 (precondition failed) if there are fewer than 3 participators. + """ + self.client.force_login(self.user2) + add_participators(self.tournament2, number = 2) + response = self.client.get(reverse('tournament-progress', kwargs = dict(pk = self.tournament2.id))) + self.assertEqual(response.status_code, 412) + + def test_less_than_5_participators(self): + """ + Starting a tournament created by the user fails if `Tournament.test` checking fails. + """ + self.client.force_login(self.user2) + add_participators(self.tournament2, number = 4) + response = self.client.get(reverse('tournament-progress', kwargs = dict(pk = self.tournament2.id)), follow = True) + self.assertEqual(response.status_code, 200) + self.assertIs(response.resolver_match.func.view_class, views.UpdateTournamentView) + self.assertContains(response, 'insufficient participants: main_round[2] is out of range') + + def test_less_than_6_participators(self): + """ + Starting a tournament created by the user fails if `Tournament.test` checking fails. + """ + self.client.force_login(self.user2) + add_participators(self.tournament2, number = 5) + response = self.client.get(reverse('tournament-progress', kwargs = dict(pk = self.tournament2.id)), follow = True) + self.assertEqual(response.status_code, 200) + self.assertIs(response.resolver_match.func.view_class, views.UpdateTournamentView) + self.assertContains(response, 'Error while initializing tournament (insufficient participants).') + + def test_open(self): + """ + Successfulls starts an open tournament. + """ + response = self.client.get(reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id))) + self.assertEqual(response.status_code, 200) + self.assertEqual(self.tournament1.state, 'active') + self.assertContains(response, '

Preliminaries Current Stage

') + + def test_post_open(self): + fixture = models.Fixture.objects.create(mode = self.tournament1.stages.all()[0], level = 0, position = 0) + response = self.client.post( + reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id)), + dict( + fixture_id = fixture.id, + score1 = '10', + score2 = '12', + ), + ) + self.assertEqual(response.status_code, 403) + + def test_post_not_participating(self): + self.test_open() ## start the tournament + fixture = self.tournament1.current_stage.fixtures.filter(level = self.tournament1.current_stage.current_level)[0] + response = self.client.post( + reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id)), + dict( + fixture_id = fixture.id, + score1 = '10', + score2 = '12', + ), + ) + self.assertEqual(response.status_code, 403) + + def test_post_wrong_level(self): + self.test_open() ## start the tournament + self.client.force_login(self.users[0]) + fixture = self.tournament1.current_stage.fixtures.filter(level = self.tournament1.current_stage.current_level + 1)[0] + response = self.client.post( + reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id)), + dict( + fixture_id = fixture.id, + score1 = '10', + score2 = '12', + ), + ) + self.assertEqual(response.status_code, 412) + + def test_post_wrong_stage(self): + self.test_open() ## start the tournament + self.client.force_login(self.users[0]) + next_stage = self.tournament1.stages.all()[1] + fixture = models.Fixture.objects.create(mode = next_stage, level = 0, position = 0) + response = self.client.post( + reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id)), + dict( + fixture_id = fixture.id, + score1 = '10', + score2 = '12', + ), + ) + self.assertEqual(response.status_code, 412) + + def test_post_already_confirmed(self): + self.test_open() ## start the tournament + self.client.force_login(self.users[0]) + fixture = self.tournament1.current_stage.fixtures.filter(level = self.tournament1.current_stage.current_level)[0] + _confirm_fixture(self.tournament1.participants, fixture) + response = self.client.post( + reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id)), + dict( + fixture_id = fixture.id, + score1 = '10', + score2 = '12', + ), + follow = True + ) + self.assertEqual(response.status_code, 412) + + def test_post_invalid_score(self): + self.test_open() ## start the tournament + self.client.force_login(self.users[0]) + fixture = self.tournament1.current_stage.fixtures.filter(level = self.tournament1.current_stage.current_level)[0] + response = self.client.post( + reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id)), + dict( + fixture_id = fixture.id, + score1 = '', + score2 = '12', + ), + follow = True + ) + fixture.refresh_from_db() + self.assertEqual(response.status_code, 200) + self.assertEqual(fixture.score, (None, None)) + self.assertContains(response, 'You have not entered a valid score.') + + def test_post(self): + self.test_open() ## start the tournament + self.client.force_login(self.users[0]) + fixture = self.tournament1.current_stage.fixtures.filter(level = self.tournament1.current_stage.current_level)[0] + response = self.client.post( + reverse('tournament-progress', kwargs = dict(pk = self.tournament1.id)), + dict( + fixture_id = fixture.id, + score1 = '10', + score2 = '12', + ), + follow = True + ) + fixture.refresh_from_db() + self.assertEqual(response.status_code, 200) + self.assertEqual(fixture.score, (10, 12)) + self.assertContains(response, 'Your confirmation has been saved.') + self.assertContains(response, 'Confirmations: 1 / 6') + self.assertContains(response, 'You have confirmed.') diff --git a/tournaments/frontend/views.py b/tournaments/frontend/views.py index 404b526..723e7da 100644 --- a/tournaments/frontend/views.py +++ b/tournaments/frontend/views.py @@ -261,6 +261,11 @@ class TournamentProgressView(SingleObjectMixin, VersionInfoMixin, AlertMixin, Vi def get(self, request, *args, **kwargs): self.object = self.get_object() + + # Drafted tournaments cannot be started. + if self.object.state == 'draft': + return HttpResponse(status = 412) + if self.object.state == 'open': # Tournament can only be started by the creator.