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_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 check_game_settings(game: Game, settings: List[Tuple[str, Any, ValidityState]]): for key, value, expected in settings: old = game.gameOptions.get(key) game.gameOptions[key] = value await game.validate_game_settings() assert game.validity is expected game.gameOptions[key] = old
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
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
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_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_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_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_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_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_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_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_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_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_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_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_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_report_army_stats_sends_stats_for_defeated_player( game: Game, game_add_players): game.state = GameState.LOBBY players = game_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() game.report_army_stats(stats) game._game_stats_service.process_game_stats.assert_called_once_with( players[1], game, stats)
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_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_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]
def add_connected_players(game: Game, players): """ Utility to add players with army and StartSpot indexed by a list """ for army, player in enumerate(players): add_connected_player(game, player) game.set_player_option(player.id, 'Army', army) game.set_player_option(player.id, 'StartSpot', army) game.set_player_option(player.id, 'Team', army) game.set_player_option(player.id, 'Faction', 0) game.set_player_option(player.id, 'Color', 0) game.host = players[0]
def create_game(self, visibility=VisibilityState.PUBLIC, game_mode: str=None, host: Player=None, name: str=None, mapname: str=None, password: str=None): """ Main entrypoint for creating new games """ id = self.createUuid() args = { "id": id, "host": host, "name": name, "map": mapname, "game_mode": game_mode, "game_service": self, "game_stats_service": self.game_stats_service } if game_mode == 'ladder1v1': game = LadderGame(**args) elif game_mode == 'coop': game = CoopGame(**args) elif game_mode == 'faf' or game_mode == 'fafbeta' or game_mode == 'equilibrium': game = CustomGame(**args) else: game = Game(**args) self.games[id] = game game.visibility = visibility game.password = password self.mark_dirty(game) return game
async def test_hashing(game): assert { game: 1, Game(game.id, mock.Mock(), mock.Mock(), mock.Mock()): 1 } == { game: 1 }
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_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_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_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_validate_game_settings(game: Game): settings = [ ('Victory', Victory.SANDBOX, Victory.DEMORALIZATION, ValidityState.WRONG_VICTORY_CONDITION), ('FogOfWar', 'none', 'explored', ValidityState.NO_FOG_OF_WAR), ('CheatsEnabled', 'true', 'false', ValidityState.CHEATS_ENABLED), ('PrebuiltUnits', 'On', 'Off', ValidityState.PREBUILT_ENABLED), ('NoRushOption', 20, 'Off', ValidityState.NORUSH_ENABLED), ('RestrictedCategories', 1, 0, ValidityState.BAD_UNIT_RESTRICTIONS) ] for data in settings: key, value, default, expected = data game.gameOptions[key] = value await game.validate_game_settings() assert game.validity is expected game.gameOptions[key] = default game.validity = ValidityState.VALID await game.validate_game_settings() assert game.validity is ValidityState.VALID
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])
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_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_validate_game_settings_coop(coop_game: Game): settings = [ ('Victory', Victory.DEMORALIZATION, ValidityState.WRONG_VICTORY_CONDITION), ('TeamSpawn', 'open', ValidityState.SPAWN_NOT_FIXED), ('RevealedCivilians', 'Yes', ValidityState.CIVILIANS_REVEALED), ('Difficulty', 1, ValidityState.WRONG_DIFFICULTY), ('Expansion', 0, ValidityState.EXPANSION_DISABLED), ] await check_game_settings(coop_game, settings) coop_game.validity = ValidityState.VALID await coop_game.validate_game_settings() assert coop_game.validity is ValidityState.VALID
async def test_clear_slot(game: Game, mock_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.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_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_invalid_get_player_option_key(game: Game, players): assert game.get_player_option(players.hosting.id, -1) is None
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)
def add_connected_player(game: Game, player): game.game_service.player_service[player.id] = player gc = game_connection(state=GameConnectionState.CONNECTED_TO_HOST, player=player) game.set_player_option(player.id, 'Army', 0) game.set_player_option(player.id, 'StartSpot', 0) game.set_player_option(player.id, 'Team', 0) game.set_player_option(player.id, 'Faction', 0) game.set_player_option(player.id, 'Color', 0) game.add_game_connection(gc) return gc
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
def game(loop, game_service, game_stats_service): game = Game(42, game_service, game_stats_service) yield game loop.run_until_complete(game.clear_data())
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_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}