async def test_initialized_game_not_allowed_to_end(game: Game): await game.clear_data() game.state = GameState.INITIALIZING game.on_game_end() assert game.state is GameState.INITIALIZING
async def test_compute_rating_balanced_teamgame(game: Game, create_player): await game.clear_data() game.state = GameState.LOBBY players = [( create_player(**info), result, team ) for info, result, team in [ (dict(login='******', id=1, global_rating=Rating(1500, 250.7)), 0, 1), (dict(login='******', id=2, global_rating=Rating(1700, 120.1)), 0, 1), (dict(login='******', id=3, global_rating=Rating(1200, 72.02)), 0, 2), (dict(login='******', id=4, global_rating=Rating(1200, 72.02)), 0, 2), ]] add_connected_players(game, [player for player, _, _ in players]) for player, _, team in players: game.set_player_option(player.id, 'Team', team) game.set_player_option(player.id, 'Army', player.id - 1) await game.launch() for player, result, _ in players: await game.add_result(player, player.id - 1, 'score', result) result = game.compute_rating() for team in result: for player, new_rating in team.items(): assert player in game.players assert new_rating != Rating(*player.global_rating)
async def test_remove_game_connection(game: Game, players, mock_game_connection): game.state = GameState.LOBBY mock_game_connection.player = players.hosting mock_game_connection.state = GameConnectionState.CONNECTED_TO_HOST game.add_game_connection(mock_game_connection) await game.remove_game_connection(mock_game_connection) assert players.hosting not in game.players
async def test_add_game_connection_twice(game: Game, players, mock_game_connection): """ When a player disconnects and reconnects to the same game, they should not be considered as 'in-lobby' until the new PlayerOptions are received. """ game.state = GameState.LOBBY mock_game_connection.player = players.hosting mock_game_connection.state = GameConnectionState.CONNECTED_TO_HOST # Connect the host game.add_game_connection(mock_game_connection) game.set_player_option(players.hosting.id, 'Team', 1) assert game.players == {players.hosting} # Join a new player join_conn = add_connected_player(game, players.joining) assert game.players == {players.hosting, players.joining} # Player leaves await game.remove_game_connection(join_conn) assert game.players == {players.hosting} # Player joins again game.add_game_connection(join_conn) assert game.to_dict()["num_players"] == 1 assert game.players == {players.hosting} game.set_player_option(players.joining.id, 'Team', 1) assert game.players == {players.hosting, players.joining} assert game.to_dict()["num_players"] == 2
async def test_compute_rating_balanced_teamgame(game: Game, player_factory): game.state = GameState.LOBBY players = [(player_factory(login=f"{i}", player_id=i, global_rating=rating, with_lobby_connection=False), result, team) for i, (rating, result, team) in enumerate([ (Rating(1500, 250), 0, 2), (Rating(1700, 120), 0, 2), (Rating(1200, 72), 0, 3), (Rating(1200, 72), 0, 3), ], 1)] add_connected_players(game, [player for player, _, _ in players]) for player, _, team in players: game.set_player_option(player.id, 'Team', team) game.set_player_option(player.id, 'Army', player.id - 1) await game.launch() for player, result, team in players: await game.add_result(player, player.id - 1, 'victory' if team == 2 else 'defeat', result) result = game.compute_rating() for team in result: for player, new_rating in team.items(): assert player in game.players assert new_rating != Rating(*player.ratings[RatingType.GLOBAL])
def test_add_game_connection_throws_if_not_connected_to_host(game: Game, players, mock_game_connection): game.state = GameState.LOBBY mock_game_connection.player = players.hosting mock_game_connection.state = GameConnectionState.INITIALIZED with pytest.raises(GameError): game.add_game_connection(mock_game_connection) assert players.hosting not in game.players
def test_add_game_connection_throws_if_not_lobby_state(game: Game, players, mock_game_connection): game.state = GameState.INITIALIZING mock_game_connection.player = players.hosting mock_game_connection.state = GameConnectionState.CONNECTED_TO_HOST with pytest.raises(GameError): game.add_game_connection(mock_game_connection) assert players.hosting not in game.players
async def test_game_end_when_no_more_connections(game: Game, mock_game_connection): game.state = GameState.LOBBY game.on_game_end = CoroMock() mock_game_connection.state = GameConnectionState.CONNECTED_TO_HOST game.add_game_connection(mock_game_connection) await game.remove_game_connection(mock_game_connection) game.on_game_end.assert_any_call()
async def test_game_is_invalid_due_to_desyncs(game: Game, players): game.state = GameState.LOBBY add_connected_players(game, [players.hosting, players.joining]) game.host = players.hosting await game.launch() game.desyncs = 30 await game.on_game_end() assert game.validity is ValidityState.TOO_MANY_DESYNCS
async def test_compute_rating_raises_game_error(game: Game, players): game.state = GameState.LOBBY add_connected_players(game, [players.hosting, players.joining]) # add_connected_players sets this, so we need to unset it again del game._player_options[players.hosting.id]["Team"] game.set_player_option(players.joining.id, "Team", 1) await game.launch() with pytest.raises(GameError): game.compute_rating(rating=RatingType.LADDER_1V1)
async def test_add_game_connection(game: Game, players, mock_game_connection): game.state = GameState.LOBBY mock_game_connection.player = players.hosting mock_game_connection.state = GameConnectionState.CONNECTED_TO_HOST game.add_game_connection(mock_game_connection) # Players should not be considered as 'in lobby' until the host has sent # "PlayerOption" configuration for them assert game.to_dict()["num_players"] == 0 assert game.players == set() game.set_player_option(players.hosting.id, 'Team', 1) assert players.hosting in game.players
async def test_game_sim_ends_when_no_more_connections(game: Game, players): game.state = GameState.LOBBY host_conn = add_connected_player(game, players.hosting) join_conn = add_connected_player(game, players.joining) game.host = players.hosting await game.launch() await game.remove_game_connection(host_conn) await game.remove_game_connection(join_conn) assert game.ended
async def test_game_is_invalid_due_to_desyncs(game: Game, players): await game.clear_data() game.state = GameState.LOBBY add_connected_players(game, [players.hosting, players.joining]) game.host = players.hosting await game.launch() game.desyncs = 30 await game.on_game_end() assert game.validity is ValidityState.TOO_MANY_DESYNCS
async def test_game_ends_in_mutually_agreed_draw(game: Game): game.state = GameState.LOBBY players = add_players(game, 2) await game.launch() game.launched_at = time.time() - 60 * 60 await game.add_result(players[0], 0, 'mutual_draw', 0) await game.add_result(players[1], 1, 'mutual_draw', 0) await game.on_game_end() assert game.validity is ValidityState.MUTUAL_DRAW
async def test_game_sim_ends_when_no_more_connections(game: Game, players): await game.clear_data() game.state = GameState.LOBBY host_conn = add_connected_player(game, players.hosting) join_conn = add_connected_player(game, players.joining) game.host = players.hosting await game.launch() await game.remove_game_connection(host_conn) await game.remove_game_connection(join_conn) assert game.ended
async def test_game_ends_in_mutually_agreed_draw(game: Game): game.state = GameState.LOBBY players = add_players(game, 2) await game.launch() game.launched_at = time.time()-60*60 await game.add_result(players[0], 0, 'mutual_draw', 0) await game.add_result(players[1], 1, 'mutual_draw', 0) await game.on_game_end() assert game.validity is ValidityState.MUTUAL_DRAW
async def test_game_not_ends_in_unilatery_agreed_draw(game: Game, players): game.state = GameState.LOBBY add_players(game, 2) await game.launch() game.launched_at = time.time()-60*60 await game.add_result(players.hosting, 0, 'mutual_draw', 0) await game.add_result(players.joining, 1, 'victory', 10) await game.on_game_end() assert game.validity is not ValidityState.MUTUAL_DRAW
async def test_game_sim_ends_when_connections_ended_sim(game: Game, players): game.state = GameState.LOBBY host_conn = add_connected_player(game, players.hosting) join_conn = add_connected_player(game, players.joining) game.host = players.hosting await game.launch() host_conn.finished_sim = True join_conn.finished_sim = True await game.check_sim_end() assert game.ended
async def test_game_not_ends_in_unilatery_agreed_draw(game: Game, players): game.state = GameState.LOBBY add_players(game, 2) await game.launch() game.launched_at = time.time() - 60 * 60 await game.add_result(players.hosting, 0, 'mutual_draw', 0) await game.add_result(players.joining, 1, 'victory', 10) await game.on_game_end() assert game.validity is not ValidityState.MUTUAL_DRAW
async def test_report_army_stats_sends_stats_for_defeated_player(game: Game): game.state = GameState.LOBBY players = add_players(game, 2) await game.launch() await game.add_result(0, 1, 'defeat', -1) with open("tests/data/game_stats_simple_win.json", "r") as stats_file: stats = stats_file.read() await game.report_army_stats(stats) game._game_stats_service.process_game_stats.assert_called_once_with(players[1], game, stats)
async def test_game_sim_ends_when_connections_ended_sim(game: Game, players): await game.clear_data() game.state = GameState.LOBBY host_conn = add_connected_player(game, players.hosting) join_conn = add_connected_player(game, players.joining) game.host = players.hosting await game.launch() host_conn.finished_sim = True join_conn.finished_sim = True await game.check_sim_end() assert game.ended
async def test_compute_rating_computes_ladder_ratings(game: Game, players): game.state = GameState.LOBBY players.hosting.ratings[RatingType.LADDER_1V1] = Rating(1500, 250) players.joining.ratings[RatingType.LADDER_1V1] = Rating(1500, 250) add_connected_players(game, [players.hosting, players.joining]) await game.launch() await game.add_result(players.hosting.id, 0, 'victory', 1) await game.add_result(players.joining.id, 1, 'defeat', 0) game.set_player_option(players.hosting.id, 'Team', 1) game.set_player_option(players.joining.id, 'Team', 1) groups = game.compute_rating(rating=RatingType.LADDER_1V1) assert players.hosting in groups[0] assert players.joining in groups[1]
async def test_game_ends_in_mutually_agreed_draw(game: Game): await game.clear_data() game.state = GameState.LOBBY players = [ Player(id=1, login='******', global_rating=(1500, 500)), Player(id=2, login='******', global_rating=(1500, 500)) ] add_connected_players(game, players) await game.launch() for player in players: game.set_player_option(player.id, 'Team', 1) game.set_player_option(player.id, 'Army', player.id - 1) game.state = GameState.LIVE game.launched_at = time.time() - 60 * 60 await game.add_result(players[0], 0, 'mutual_draw', 0) await game.add_result(players[1], 1, 'mutual_draw', 0) await game.on_game_end() assert game.validity is ValidityState.MUTUAL_DRAW
async def test_game_launch_freezes_players(game: Game, players): game.state = GameState.LOBBY host_conn = add_connected_player(game, players.hosting) game.host = players.hosting add_connected_player(game, players.joining) await game.launch() assert game.state is GameState.LIVE assert game.players == {players.hosting, players.joining} await game.remove_game_connection(host_conn) assert game.players == {players.hosting, players.joining}
async def test_clear_slot(game: Game, game_connection: GameConnection): game.state = GameState.LOBBY players = [ Player(id=1, login='******', global_rating=(1500, 500)), Player(id=2, login='******', global_rating=(1500, 500)) ] add_connected_players(game, players) game.clear_slot(0) assert game.get_player_option(1, 'StartSpot') == -1 assert game.get_player_option(1, 'Team') == -1 assert game.get_player_option(1, 'Army') == -1 assert game.get_player_option(2, 'StartSpot') == 1
async def test_game_launch_freezes_players(game: Game, players): await game.clear_data() game.state = GameState.LOBBY host_conn = add_connected_player(game, players.hosting) game.host = players.hosting add_connected_player(game, players.joining) await game.launch() assert game.state == GameState.LIVE assert game.players == {players.hosting, players.joining} await game.remove_game_connection(host_conn) assert game.players == {players.hosting, players.joining}
async def test_game_outcomes_no_results(game: Game, players): await game.clear_data() game.state = GameState.LOBBY players.hosting.ladder_rating = Rating(1500, 250) players.joining.ladder_rating = Rating(1500, 250) add_connected_players(game, [players.hosting, players.joining]) await game.launch() game.set_player_option(players.hosting.id, 'Team', 1) game.set_player_option(players.joining.id, 'Team', 1) host_outcome = game.outcome(players.hosting) guest_outcome = game.outcome(players.joining) assert host_outcome is None assert guest_outcome is None
async def test_compute_rating_computes_ladder_ratings(game: Game, players): await game.clear_data() game.state = GameState.LOBBY players.hosting.ladder_rating = Rating(1500, 250) players.joining.ladder_rating = Rating(1500, 250) add_connected_players(game, [players.hosting, players.joining]) await game.launch() await game.add_result(players.hosting, 0, 'victory', 1) await game.add_result(players.joining, 1, 'defeat', 0) game.set_player_option(players.hosting.id, 'Team', 1) game.set_player_option(players.joining.id, 'Team', 1) groups = game.compute_rating(rating='ladder') assert players.hosting in groups[0] assert players.joining in groups[1]
async def test_compute_rating_computes_global_ratings(game: Game, players): await game.clear_data() game.state = GameState.LOBBY players.hosting.global_rating = Rating(1500, 250) players.joining.global_rating = Rating(1500, 250) add_connected_players(game, [players.hosting, players.joining]) await game.launch() await game.add_result(players.hosting, 0, 'victory', 1) await game.add_result(players.joining, 1, 'defeat', 0) game.set_player_option(players.hosting.id, 'Team', 2) game.set_player_option(players.joining.id, 'Team', 3) groups = game.compute_rating() assert players.hosting in groups[0] assert players.joining in groups[1]
async def test_game_outcomes_conflicting(game: Game, database, players): game.state = GameState.LOBBY players.hosting.ratings[RatingType.LADDER_1V1] = Rating(1500, 250) players.joining.ratings[RatingType.LADDER_1V1] = Rating(1500, 250) add_connected_players(game, [players.hosting, players.joining]) await game.launch() await game.add_result(players.hosting.id, 0, 'victory', 1) await game.add_result(players.joining.id, 1, 'victory', 0) await game.add_result(players.hosting.id, 0, 'defeat', 1) await game.add_result(players.joining.id, 1, 'defeat', 0) game.set_player_option(players.hosting.id, 'Team', 1) game.set_player_option(players.joining.id, 'Team', 1) host_outcome = game.get_player_outcome(players.hosting) guest_outcome = game.get_player_outcome(players.joining) assert host_outcome is GameOutcome.CONFLICTING assert guest_outcome is GameOutcome.CONFLICTING
async def test_players_exclude_observers(game: Game): game.state = GameState.LOBBY players = add_players(game, 2) obs = Player(id=3, login='******', global_rating=(1500, 500)) game.game_service.player_service[obs.id] = obs gc = make_mock_game_connection(state=GameConnectionState.CONNECTED_TO_HOST, player=obs) game.set_player_option(obs.id, 'Army', -1) game.set_player_option(obs.id, 'StartSpot', -1) game.set_player_option(obs.id, 'Team', 0) game.set_player_option(obs.id, 'Faction', 0) game.set_player_option(obs.id, 'Color', 0) game.add_game_connection(gc) await game.launch() assert game.players == frozenset(players)
async def test_game_outcomes_no_results(game: Game, database, players): game.state = GameState.LOBBY players.hosting.ratings[RatingType.LADDER_1V1] = Rating(1500, 250) players.joining.ratings[RatingType.LADDER_1V1] = Rating(1500, 250) add_connected_players(game, [players.hosting, players.joining]) await game.launch() game.set_player_option(players.hosting.id, 'Team', 1) game.set_player_option(players.joining.id, 'Team', 1) host_outcome = game.get_player_outcome(players.hosting) guest_outcome = game.get_player_outcome(players.joining) assert host_outcome is GameOutcome.UNKNOWN assert guest_outcome is GameOutcome.UNKNOWN await game.on_game_end() expected_scores = {(players.hosting.id, 0), (players.joining.id, 0)} assert await game_player_scores(database, game) == expected_scores
async def test_game_outcomes(game: Game, players): await game.clear_data() game.state = GameState.LOBBY players.hosting.ladder_rating = Rating(1500, 250) players.joining.ladder_rating = Rating(1500, 250) add_connected_players(game, [players.hosting, players.joining]) await game.launch() await game.add_result(players.hosting, 0, 'victory', 1) await game.add_result(players.joining, 1, 'defeat', 0) game.set_player_option(players.hosting.id, 'Team', 1) game.set_player_option(players.joining.id, 'Team', 1) host_outcome = game.outcome(players.hosting) guest_outcome = game.outcome(players.joining) assert host_outcome is GameOutcome.VICTORY assert guest_outcome is GameOutcome.DEFEAT
async def test_players_exclude_observers(game: Game): game.state = GameState.LOBBY players = add_players(game, 2) obs = Player(id=3, login='******', global_rating=(1500, 500)) game.game_service.player_service[obs.id] = obs gc = mock_game_connection(state=GameConnectionState.CONNECTED_TO_HOST, player=obs) game.set_player_option(obs.id, 'Army', -1) game.set_player_option(obs.id, 'StartSpot', -1) game.set_player_option(obs.id, 'Team', 0) game.set_player_option(obs.id, 'Faction', 0) game.set_player_option(obs.id, 'Color', 0) game.add_game_connection(gc) await game.launch() assert game.players == frozenset(players)
async def test_clear_slot(game: Game, mock_game_connection: GameConnection, player_factory): game.state = GameState.LOBBY players = [ player_factory("Dostya", player_id=1, global_rating=(1500, 500)), player_factory("Rhiza", player_id=2, global_rating=(1500, 500)) ] add_connected_players(game, players) game.set_ai_option('rush', 'StartSpot', 3) game.clear_slot(0) game.clear_slot(3) assert game.get_player_option(1, 'StartSpot') == -1 assert game.get_player_option(1, 'Team') == -1 assert game.get_player_option(1, 'Army') == -1 assert game.get_player_option(2, 'StartSpot') == 1 assert 'rush' not in game.AIs
async def test_report_army_stats_sends_stats_for_defeated_player(game: Game): game.state = GameState.LOBBY players = [ Player(id=1, login='******', global_rating=(1500, 500)), Player(id=2, login='******', global_rating=(1500, 500)) ] add_connected_players(game, players) await game.launch() await game.add_result(0, 1, 'defeat', -1) with open("tests/data/game_stats_simple_win.json", "r") as stats_file: stats = stats_file.read() await game.report_army_stats(stats) game._game_stats_service.process_game_stats.assert_called_once_with( players[1], game, stats)
async def test_report_army_stats_sends_stats_for_defeated_player(game: Game): game.id = 43 game.state = GameState.LOBBY players = [ Player(id=1, login='******', global_rating=(1500, 500)), Player(id=2, login='******', global_rating=(1500, 500)) ] add_connected_players(game, players) await game.launch() await game.add_result(0, 1, 'defeat', -1) with open("tests/data/game_stats_simple_win.json", "r") as stats_file: stats = stats_file.read() await game.report_army_stats(stats) game._game_stats_service.process_game_stats.assert_called_once_with(players[1], game, stats)
async def test_compute_rating_does_not_rate_double_win(game: Game, player_factory): game.state = GameState.LOBBY players = [(player_factory(f"{i}", player_id=i, global_rating=rating), result, team) for i, (rating, result, team) in enumerate([ (Rating(1500, 250), 10, 2), (Rating(1700, 120), 0, 3), ], 1)] add_connected_players(game, [player for player, _, _ in players]) for player, _, team in players: game.set_player_option(player.id, 'Team', team) game.set_player_option(player.id, 'Army', player.id - 1) await game.launch() for player, result, _ in players: await game.add_result(player, player.id - 1, 'victory', result) with pytest.raises(GameRatingError): game.compute_rating()
async def test_validate_game_settings(game: Game): settings = [ ('Victory', Victory.SANDBOX, ValidityState.WRONG_VICTORY_CONDITION), ('FogOfWar', 'none', ValidityState.NO_FOG_OF_WAR), ('CheatsEnabled', 'true', ValidityState.CHEATS_ENABLED), ('PrebuiltUnits', 'On', ValidityState.PREBUILT_ENABLED), ('NoRushOption', 20, ValidityState.NORUSH_ENABLED), ('RestrictedCategories', 1, ValidityState.BAD_UNIT_RESTRICTIONS), ('TeamLock', 'unlocked', ValidityState.UNLOCKED_TEAMS) ] game.state = GameState.LOBBY add_players(game, 2) await check_game_settings(game, settings) game.validity = ValidityState.VALID await game.validate_game_settings() assert game.validity is ValidityState.VALID
async def test_compute_rating_balanced_teamgame(game: Game, create_player): await game.clear_data() game.state = GameState.LOBBY players = [ (create_player(**info), result, team) for info, result, team in [ (dict(login='******', id=1, global_rating=Rating(1500, 250.7)), 0, 1), (dict(login='******', id=2, global_rating=Rating(1700, 120.1)), 0, 1), (dict(login='******', id=3, global_rating=Rating(1200, 72.02)), 0, 2), (dict(login='******', id=4, global_rating=Rating(1200, 72.02)), 0, 2), ] ] add_connected_players(game, [player for player, _, _ in players]) for player, _, team in players: game.set_player_option(player.id, 'Team', team) game.set_player_option(player.id, 'Army', player.id - 1) await game.launch() for player, result, _ in players: await game.add_result(player, player.id - 1, 'score', result) result = game.compute_rating() for team in result: for player, new_rating in team.items(): assert player in game.players assert new_rating != Rating(*player.global_rating)
def test_add_game_connection(game: Game, players, game_connection): game.state = GameState.LOBBY game_connection.player = players.hosting game_connection.state = GameConnectionState.CONNECTED_TO_HOST game.add_game_connection(game_connection) assert players.hosting in game.players
async def test_update_ratings(game: Game, players, db_pool, player_service, game_service): player_service.players[players.hosting.id] = players.hosting game.state = GameState.LOBBY add_connected_player(game, players.hosting) await game.update_ratings() assert players.hosting.global_rating == (2000, 125)
async def test_game_marked_dirty_when_timed_out(game: Game): game.state = GameState.INITIALIZING game.sleep = CoroMock() await game.timeout_game() assert game.state == GameState.ENDED assert game in game.game_service.dirty_games
def test_game_teams_represents_active_teams(game: Game, players): game.state = GameState.LOBBY add_connected_players(game, [players.hosting, players.joining]) game.set_player_option(players.hosting.id, 'Team', 1) game.set_player_option(players.joining.id, 'Team', 2) assert game.teams == {1, 2}