예제 #1
0
    def test_progress_tournament_active_on_final_stage_completes_it_and_sets_status_to_complete(
            self, db):
        tournament: Tournament = TournamentFactory(
            status=Tournament.TournamentStatus.ACTIVE)
        stages: List[Stage] = [
            StageFactory(
                tournament=tournament,
                status=Stage.StageStatus.COMPLETE
                if idx < 2 else Stage.StageStatus.PENDING,
                ordinal=idx,
                params={'minimum_pool_size': 2},
            ) for idx in range(3)
        ]
        CompetitorFactory.create_batch(2, tournament=tournament)
        stages[2].progress(db, autocommit=True)
        db.query(Match).filter(Match.pool == stages[2].pools[0]).update(
            {Match.status: Match.MatchStatus.COMPLETE})

        tournament.progress(db, autocommit=True)

        # Verify that the tournament is now complete
        assert tournament.status == Tournament.TournamentStatus.COMPLETE

        # Verify that all stages are complete
        for stage in stages:
            assert stage.status == Stage.StageStatus.COMPLETE
예제 #2
0
    def test_extra_stages_are_deleted(self, client, test_user, db):
        tournament = TournamentFactory(stages=3, owner=test_user['user'])

        response = client.put(f'/tournaments/{tournament.id}/stages/',
                              json=[{
                                  'type':
                                  Stage.StageType.BRACKET_SINGLE_ELIMINATION,
                                  'params': {
                                      'seeded': True
                                  },
                              }],
                              headers={
                                  'Authorization':
                                  f'Bearer {test_user["auth_token"]}',
                              })

        # Verify the response
        assert response.status_code == 200
        response_json = response.json()
        assert len(response_json) == 1
        assert response_json[0][
            'type'] == Stage.StageType.BRACKET_SINGLE_ELIMINATION
        assert response_json[0]['ordinal'] == 0
        assert response_json[0]['status'] == Stage.StageStatus.PENDING
        assert response_json[0]['params'] == {'seeded': True}

        # Verify the DB looks ok
        stages: Sequence[Stage] = db.query(Stage).all()
        assert len(stages) == 1
        assert stages[0].tournament == tournament
        assert stages[0].ordinal == 0
        assert stages[0].type == Stage.StageType.BRACKET_SINGLE_ELIMINATION
예제 #3
0
    def test_progress_tournament_active_with_no_active_stages_raises_error(
            self, db):
        tournament: Tournament = TournamentFactory(
            status=Tournament.TournamentStatus.ACTIVE)
        stages: List[Stage] = [
            StageFactory(tournament=tournament,
                         status=Stage.StageStatus.PENDING,
                         ordinal=0),
            StageFactory(tournament=tournament,
                         status=Stage.StageStatus.PENDING,
                         ordinal=1),
            StageFactory(tournament=tournament,
                         status=Stage.StageStatus.PENDING,
                         ordinal=2),
        ]

        with pytest.raises(TournamentError):
            tournament.progress(db, autocommit=True)

        # Make sure the tournament status is unchanged
        assert tournament.status == Tournament.TournamentStatus.ACTIVE

        # Make sure the stage statuses are unchanged
        assert {stage.status
                for stage in stages} == {Stage.StageStatus.PENDING}
예제 #4
0
    def test_returns_error_if_user_does_not_own_tournament(
            self, client, test_user, db):
        tournament = TournamentFactory(stages=3)

        response = client.put(f'/tournaments/{tournament.id}/stages/',
                              json=[{
                                  'type': stage.type,
                                  'params': {
                                      'minimum_pool_size': 7
                                  },
                              } for stage in tournament.stages],
                              headers={
                                  'Authorization':
                                  f'Bearer {test_user["auth_token"]}',
                              })

        # Verify the response
        assert response.status_code == 404
        response_body = response.json()
        assert response_body == {
            'detail': f'No tournament found with id {tournament.id}',
        }

        # Verify that the stages were not altered
        db.refresh(tournament)
        for stage in tournament.stages:
            assert stage.params == {'minimum_pool_size': 5}
예제 #5
0
    def test_delete_stages_no_commit_when_autocommit_is_false(self, db):
        tournament: Tournament = TournamentFactory(stages=3)
        existing_stage_ids = [stage.id for stage in tournament.stages]
        tournament.delete_stages(db, autocommit=False)

        db.refresh(tournament)
        assert len(tournament.stages) == 3
        assert [stage.id for stage in tournament.stages] == existing_stage_ids
예제 #6
0
    def test_get_tournaments_not_filtered_and_some_tournaments_returns_public_tourneys(self, client, test_user, db):
        # Create some private and two public tournaments from different users
        TournamentFactory()
        private_tournament = TournamentFactory(owner=test_user['user'], start_date=datetime.now() + timedelta(days=3))
        public_tournaments = [
            TournamentFactory(public=True, start_date=datetime.now() + timedelta(days=2)),
            TournamentFactory(public=True),
        ]

        response = client.get('/tournaments/', headers={
            'Authorization': f'Bearer {test_user["auth_token"]}'
        })

        assert response.status_code == 200
        response_body = response.json()
        assert response_body == json.loads(TournamentList(**{
            'total': 3,
            'items': [private_tournament] + public_tournaments,
        }).json())
예제 #7
0
 def test_tournament_serializers(self):
     tournament = TournamentFactory()
     expected = {
         "banner": tournament.banner,
         "icon": tournament.icon,
         "name": tournament.name,
         "prize": tournament.prize,
         "slug": tournament.slug,
         "web": tournament.web,
     }
     serializer = TournamentSerializer(tournament)
     assert serializer.data == expected
예제 #8
0
    def test_get_tournaments_filtered_and_no_public_tournaments_returns_nothing(self, client, test_user, db):
        # Create a private factory from a different user
        TournamentFactory()

        response = client.get('/tournaments/?is_filtered_by_user=true', headers={
            'Authorization': f'Bearer {test_user["auth_token"]}'
        })

        # Verify the response
        assert response.status_code == 200
        response_body = response.json()
        assert response_body['total'] == 0
        assert response_body['items'] == []
예제 #9
0
    def test_get_tournaments_pagination_limits_result_set(self, client, test_user, db):
        test_tournaments = [
            TournamentFactory.create(
                public=True,
                start_date=datetime.now() + timedelta(days=i),
            ) for i in range(25)
        ]
        test_tournaments.reverse()

        # Grab the first page for a page size of 10
        response = client.get('/tournaments/?skip=0&limit=10', headers={
            'Authorization': f'Bearer {test_user["auth_token"]}'
        })

        # Verify the response
        assert response.status_code == 200
        response_body = response.json()
        assert response_body == json.loads(TournamentList(**{
            'total': 25,
            'items': test_tournaments[0:10],
        }).json())

        # Grab the second page for a page size of 10
        response = client.get('/tournaments/?skip=10&limit=10', headers={
            'Authorization': f'Bearer {test_user["auth_token"]}'
        })

        # Verify the response
        assert response.status_code == 200
        response_body = response.json()
        assert response_body == json.loads(TournamentList(**{
            'total': 25,
            'items': test_tournaments[10:20],
        }).json())

        # Grab the third page for a page size of 10, which will be a partial page
        response = client.get('/tournaments/?skip=20&limit=10', headers={
            'Authorization': f'Bearer {test_user["auth_token"]}'
        })

        # Verify the response
        assert response.status_code == 200
        response_body = response.json()
        assert response_body == json.loads(TournamentList(**{
            'total': 25,
            'items': test_tournaments[20:],
        }).json())
예제 #10
0
    def test_wrong_owner_gets_404(self, client, test_user, db):
        tournament = TournamentFactory()

        response = client.put(f'/tournaments/{tournament.id}/competitors/', json=[{
            'organization': 'Org 1',
        }, {
            'organization': 'Org 2',
        }], headers={
            'Authorization': f'Bearer {test_user["auth_token"]}',
        })

        # Verify the response
        assert response.status_code == 404
        response_body = response.json()
        assert response_body == {
            'detail': f'No tournament found with id {tournament.id}',
        }
예제 #11
0
    def test_new_stages_are_created_if_necessary(self, client, test_user, db):
        tournament = TournamentFactory(stages=1, owner=test_user['user'])

        response = client.put(f'/tournaments/{tournament.id}/stages/',
                              json=[{
                                  'type': Stage.StageType.POOL,
                                  'params': {
                                      'minimum_pool_size': 5
                                  },
                              }, {
                                  'type':
                                  Stage.StageType.BRACKET_SINGLE_ELIMINATION,
                                  'params': {
                                      'seeded': True
                                  },
                              }],
                              headers={
                                  'Authorization':
                                  f'Bearer {test_user["auth_token"]}',
                              })

        # Verify the response
        assert response.status_code == 200
        response_json = response.json()
        assert len(response_json) == 2
        assert response_json[0]['type'] == Stage.StageType.POOL
        assert response_json[0]['ordinal'] == 0
        assert response_json[0]['status'] == Stage.StageStatus.PENDING
        assert response_json[0]['params'] == {'minimum_pool_size': 5}
        assert response_json[1][
            'type'] == Stage.StageType.BRACKET_SINGLE_ELIMINATION
        assert response_json[1]['ordinal'] == 1
        assert response_json[1]['status'] == Stage.StageStatus.PENDING
        assert response_json[1]['params'] == {'seeded': True}

        # Make sure the DB looks ok
        stages: Sequence[Stage] = db.query(Stage).order_by(Stage.ordinal).all()
        assert len(stages) == 2
        assert stages[0].tournament == tournament
        assert stages[0].ordinal == 0
        assert stages[0].type == Stage.StageType.POOL
        assert stages[1].tournament == tournament
        assert stages[1].ordinal == 1
        assert stages[1].type == Stage.StageType.BRACKET_SINGLE_ELIMINATION
예제 #12
0
    def test_updates_without_length_changes_work(self, client, test_user, db):
        tournament = TournamentFactory(stages=2, owner=test_user['user'])

        response = client.put(f'/tournaments/{tournament.id}/stages/',
                              json=[{
                                  'type': Stage.StageType.POOL,
                                  'params': {
                                      'minimum_pool_size': 7
                                  },
                              }, {
                                  'type': Stage.StageType.POOL,
                                  'params': {
                                      'minimum_pool_size': 10
                                  },
                              }],
                              headers={
                                  'Authorization':
                                  f'Bearer {test_user["auth_token"]}',
                              })

        # Verify the response
        assert response.status_code == 200
        response_json = response.json()
        assert len(response_json) == 2
        assert response_json[0]['type'] == Stage.StageType.POOL
        assert response_json[0]['ordinal'] == 0
        assert response_json[0]['status'] == Stage.StageStatus.PENDING
        assert response_json[0]['params'] == {'minimum_pool_size': 7}
        assert response_json[1]['type'] == Stage.StageType.POOL
        assert response_json[1]['ordinal'] == 1
        assert response_json[1]['status'] == Stage.StageStatus.PENDING
        assert response_json[1]['params'] == {'minimum_pool_size': 10}

        # Make sure the DB looks ok
        stages: Sequence[Stage] = db.query(Stage).order_by(Stage.ordinal).all()
        assert len(stages) == 2
        assert stages[0].tournament == tournament
        assert stages[0].ordinal == 0
        assert stages[0].type == Stage.StageType.POOL
        assert stages[0].params == {'minimum_pool_size': 7}
        assert stages[1].tournament == tournament
        assert stages[1].ordinal == 1
        assert stages[1].type == Stage.StageType.POOL
        assert stages[1].params == {'minimum_pool_size': 10}
예제 #13
0
    def test_integrity_error_rollsback_all_changes(self, client, test_user, db):
        tournament = TournamentFactory(owner=test_user['user'], competitors=10)

        response = client.put(f'/tournaments/{tournament.id}/competitors/', json=[{
            'organization': 'Org 1',
        }, {
            'organization': 'Org 2',
        }, {
            'first_name': 'test_user',
        }], headers={
            'Authorization': f'Bearer {test_user["auth_token"]}',
        })

        # Verify the response
        assert response.status_code == 409
        assert response.json() == {'detail': 'Competitors must have at least a last name or an organization'}

        # Verify the DB
        competitors: Sequence[Competitor] = db.query(Competitor).filter(Competitor.tournament == tournament).all()
        assert len(competitors) == 10
예제 #14
0
    def test_old_ones_deleted_new_ones_created(self, client, test_user, db):
        tournament = TournamentFactory(owner=test_user['user'], competitors=10)

        response = client.put(f'/tournaments/{tournament.id}/competitors/', json=[{
            'organization': 'Org 1',
        }, {
            'organization': 'Org 2',
        }], headers={
            'Authorization': f'Bearer {test_user["auth_token"]}',
        })

        # Verify the response
        assert response.status_code == 200
        response_body = response.json()
        assert len(response_body) == 2
        assert response_body[0]['first_name'] is None
        assert response_body[0]['last_name'] is None
        assert response_body[0]['organization'] == 'Org 1'
        assert response_body[0]['location'] is None
        assert response_body[1]['first_name'] is None
        assert response_body[1]['last_name'] is None
        assert response_body[1]['organization'] == 'Org 2'
        assert response_body[1]['location'] is None

        # Verify the DB
        competitors: Sequence[Competitor] = db.query(Competitor).order_by(Competitor.organization).all()
        assert len(competitors) == 2
        assert competitors[0].tournament == tournament
        assert competitors[0].first_name is None
        assert competitors[0].last_name is None
        assert competitors[0].organization == 'Org 1'
        assert competitors[0].location is None
        assert competitors[1].tournament == tournament
        assert competitors[1].first_name is None
        assert competitors[1].last_name is None
        assert competitors[1].organization == 'Org 2'
        assert competitors[1].location is None
예제 #15
0
    def test_progress_tournament_active_progresses_the_active_stage_and_starts_the_next_one(
            self, db):
        tournament: Tournament = TournamentFactory(
            status=Tournament.TournamentStatus.ACTIVE)
        stages: List[Stage] = [
            StageFactory(
                tournament=tournament,
                status=Stage.StageStatus.PENDING,
                ordinal=idx,
                params={'minimum_pool_size': 2},
            ) for idx in range(3)
        ]
        CompetitorFactory.create_batch(2, tournament=tournament)

        # Start the first stage and finish all of its matches
        stages[0].progress(db, autocommit=True)
        db.query(Match).filter(Match.pool == stages[0].pools[0]).update(
            {Match.status: Match.MatchStatus.COMPLETE})

        tournament.progress(db, autocommit=True)

        # Verify that the tournament is still active
        assert tournament.status == Tournament.TournamentStatus.ACTIVE

        # Verify that the first stage is complete
        assert stages[0].status == Stage.StageStatus.COMPLETE

        # Verify that the second stage is active and has pools/matches
        assert stages[1].status == Stage.StageStatus.ACTIVE
        assert len(stages[1].pools) == 1
        assert len(stages[1].pools[0].matches) == 1
        assert stages[1].pools[0].matches[
            0].status == Match.MatchStatus.PENDING

        # Verify that the third stage is still pending
        assert stages[2].status == Stage.StageStatus.PENDING
예제 #16
0
    def test_delete_stages_no_stages_is_a_noop(self, db):
        tournament: Tournament = TournamentFactory()
        tournament.delete_stages(db)

        assert len(tournament.stages) == 0
        assert len(db.query(Stage).all()) == 0
예제 #17
0
    def test_delete_stages_all_are_removed(self, db):
        tournament: Tournament = TournamentFactory(stages=3)
        tournament.delete_stages(db)

        assert len(tournament.stages) == 0
        assert len(db.query(Stage).all()) == 0
예제 #18
0
    def test_progress_tournament_invalid_status_raises_error(self, db, status):
        tournament: Tournament = TournamentFactory(status=status)

        with pytest.raises(TournamentError):
            tournament.progress(db, autocommit=True)
예제 #19
0
 def test_tournament_serializers(self):
     tournament = TournamentFactory()
     expected = {"name": tournament.name, "slug": tournament.slug}
     serializer = TournamentSerializerSmall(tournament)
     assert serializer.data == expected
예제 #20
0
    def test_delete_competitors_none_exist_noop(self, db):
        tournament: Tournament = TournamentFactory()
        tournament.delete_competitors(db)

        assert len(tournament.competitors) == 0
예제 #21
0
    def test_delete_competitors(self, db):
        tournament: Tournament = TournamentFactory(competitors=10)
        tournament.delete_competitors(db)

        assert len(tournament.competitors) == 0
예제 #22
0
    def test_delete_competitors_autocommit_is_false_no_changes(self, db):
        tournament: Tournament = TournamentFactory(competitors=10)
        tournament.delete_competitors(db, autocommit=False)

        assert len(tournament.competitors) == 10