import asyncio import json import pytest from fastapi import status from fastapi.testclient import TestClient from cooperative_cuisine import ROOT_DIR from cooperative_cuisine.action import ActionType from cooperative_cuisine.game_server import ( app, environment_handler, CreateEnvironmentConfig, ManageEnv, ) from cooperative_cuisine.server_results import CreateEnvResult from cooperative_cuisine.state_representation import StateRepresentation environment_handler.extend_allowed_manager(["123"]) @pytest.fixture def create_env_config(): layout_path = ROOT_DIR / "configs" / "layouts" / "tutorial.layout" environment_config_path = ROOT_DIR / "configs" / "tutorial_env_config.yaml" item_info_path = ROOT_DIR / "configs" / "item_info.yaml" with open(item_info_path, "r") as file: item_info = file.read() with open(layout_path, "r") as file: layout = file.read() with open(environment_config_path, "r") as file: environment_config = file.read() return CreateEnvironmentConfig( manager_id="123", number_players=1, environment_settings={"all_player_can_pause_game": False}, item_info_config=item_info, layout_config=layout, environment_config=environment_config, seed=123, ) def test_create_env(create_env_config): with TestClient(app) as client: res = client.post( "/manage/create_env/", json=create_env_config.model_dump(mode="json"), ) assert res.status_code == status.HTTP_200_OK create_env_result = CreateEnvResult(**res.json()) assert len(create_env_result["player_info"]) == 1 assert isinstance(create_env_result["env_id"], str) def test_invalid_manager_id_create_env(create_env_config): create_env_config.manager_id = "!" with TestClient(app) as client: res = client.post( "/manage/create_env/", json=create_env_config.model_dump(mode="json"), ) assert res.status_code == status.HTTP_403_FORBIDDEN assert res.json() == {"detail": "Manager ID not known/registered."} def test_invalid_create_env_config(create_env_config): create_env_config.number_players = -1 with TestClient(app) as client: res = client.post( "/manage/create_env/", json=create_env_config.model_dump(mode="json"), ) assert res.status_code == status.HTTP_409_CONFLICT assert res.json() == {"detail": "Number players need to be positive."} def test_stop_env(create_env_config): with TestClient(app) as client: res = client.post( "/manage/create_env/", json=create_env_config.model_dump(mode="json"), ) with TestClient(app) as client: res = client.post( "/manage/stop_env/", json=ManageEnv( manager_id="123", env_id=res.json()["env_id"], reason="test" ).model_dump(mode="json"), ) assert res.status_code == status.HTTP_200_OK with TestClient(app) as client: res = client.post( "/manage/stop_env/", json=ManageEnv(manager_id="123", env_id="123456", reason="test").model_dump( mode="json" ), ) assert res.status_code == status.HTTP_403_FORBIDDEN def test_websocket(create_env_config): with TestClient(app) as client: environment_handler.envs = {} res = client.post( "/manage/create_env/", json=create_env_config.model_dump(mode="json"), ) player_hash = res.json()["player_info"]["0"]["player_hash"] loop = asyncio.new_event_loop() task = loop.create_task(environment_handler.environment_steps()) try: with client.websocket_connect( f"/ws/player/{res.json()['player_info']['0']['client_id']}" ) as websocket: assert environment_handler.check_all_players_connected( res.json()["env_id"] ) websocket.send_json({"player_hash": player_hash, "type": "ready"}) assert websocket.receive_json() == { "request_type": "ready", "msg": f"ready accepted", "status": 200, "player_hash": player_hash, } loop.run_until_complete(asyncio.sleep(0.001)) websocket.send_json({"player_hash": player_hash, "type": "get_state"}) state = websocket.receive_json() assert state["all_players_ready"] del state["all_players_ready"] StateRepresentation.model_validate_json(json_data=json.dumps(state)) websocket.send_json( { "player_hash": player_hash, "type": "action", "action": { "player": "0", "action_type": ActionType.PICK_UP_DROP.value, "action_data": None, }, } ) assert websocket.receive_json() == { "request_type": "action", "status": 200, "msg": f"action accepted", "player_hash": player_hash, } assert ( len( environment_handler.list_not_ready_players(res.json()["env_id"]) ) == 0 ) assert ( len( environment_handler.list_not_connected_players( res.json()["env_id"] ) ) == 0 ) finally: task.cancel() loop.close() def test_websocket_wrong_inputs(create_env_config): with TestClient(app) as client: environment_handler.envs = {} res = client.post( "/manage/create_env/", json=create_env_config.model_dump(mode="json"), ) player_hash = res.json()["player_info"]["0"]["player_hash"] wrong_player_hash = player_hash + "-------" loop = asyncio.new_event_loop() task = loop.create_task(environment_handler.environment_steps()) assert ( len(environment_handler.list_not_connected_players(res.json()["env_id"])) == 1 ) try: with client.websocket_connect( f"/ws/player/{res.json()['player_info']['0']['client_id']}" ) as websocket: assert ( len( environment_handler.list_not_ready_players(res.json()["env_id"]) ) == 1 ) assert ( len( environment_handler.list_not_connected_players( res.json()["env_id"] ) ) == 0 ) websocket.send_json({"player_hash": wrong_player_hash, "type": "ready"}) assert websocket.receive_json() == { "request_type": "ready", "msg": f"ready not accepted", "status": 400, "player_hash": wrong_player_hash, } loop.run_until_complete(asyncio.sleep(0.001)) websocket.send_json( {"player_hash": wrong_player_hash, "type": "get_state"} ) state = websocket.receive_json() assert state == { "request_type": "get_state", "status": 400, "msg": "player hash unknown", "player_hash": None, } websocket.send_json( { "player_hash": wrong_player_hash, "type": "action", "action": { "player": "0", "action_type": ActionType.PICK_UP_DROP.value, "action_data": None, }, } ) assert websocket.receive_json() == { "request_type": "action", "status": 400, "msg": f"action not accepted", "player_hash": wrong_player_hash, } websocket.send_json( { "player_hash": wrong_player_hash, "type": "delta_v", "action": { "player": "0", "action_type": ActionType.PICK_UP_DROP.value, "action_data": None, }, } ) assert websocket.receive_json()["status"] == 400 websocket.send_json( { "player_hash": wrong_player_hash, "type": "action", } ) assert websocket.receive_json()["status"] == 400 assert ( len( environment_handler.list_not_ready_players(res.json()["env_id"]) ) == 1 ) assert ( len( environment_handler.list_not_connected_players( res.json()["env_id"] ) ) == 0 ) finally: task.cancel() loop.close() def test_root(): with TestClient(app) as client: res = client.get("/") assert res.status_code == status.HTTP_200_OK assert res.json() == {"Cooperative": "Cuisine"}