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
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
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}
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}
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
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())
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
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'] == []
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())
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}', }
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
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}
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
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
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
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
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
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)
def test_tournament_serializers(self): tournament = TournamentFactory() expected = {"name": tournament.name, "slug": tournament.slug} serializer = TournamentSerializerSmall(tournament) assert serializer.data == expected
def test_delete_competitors_none_exist_noop(self, db): tournament: Tournament = TournamentFactory() tournament.delete_competitors(db) assert len(tournament.competitors) == 0
def test_delete_competitors(self, db): tournament: Tournament = TournamentFactory(competitors=10) tournament.delete_competitors(db) assert len(tournament.competitors) == 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