Skip to content

Commit

Permalink
Merge pull request #470 from Whist-Team/feature/room_error_handling
Browse files Browse the repository at this point in the history
FEATURE: error handling
  • Loading branch information
Segelzwerg authored Sep 16, 2023
2 parents be6860e + 27408c5 commit dea8428
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 20 deletions.
32 changes: 25 additions & 7 deletions tests/whist_server/api/room/test_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ def test_start_not_creator(self):
self.room_mock.start.assert_called_once()
self.assertEqual(403, response.status_code, msg=response.content)

def test_start_no_room(self):
self.room_service_mock.get = MagicMock(side_effect=RoomNotFoundError('999'))
response = self.client.post(url='/room/action/start/999', headers=self.headers,
json={'matcher_type': 'robin'})
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)

def test_start_table_not_ready(self):
self.room_mock.start = MagicMock(side_effect=TableNotReadyError)
# Request to start table.
Expand All @@ -57,6 +64,12 @@ def test_ready_not_joined(self):
self.room_mock.ready_player.assert_called_once()
self.assertEqual(403, response.status_code, msg=response.content)

def test_ready_no_room(self):
self.room_service_mock.get = MagicMock(side_effect=RoomNotFoundError('999'))
response = self.client.post(url='/room/action/ready/999', headers=self.headers)
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)

def test_unready(self):
response = self.client.post(url=f'/room/action/unready/{self.room_mock.id}',
headers=self.headers)
Expand All @@ -70,16 +83,21 @@ def test_unready_not_joined(self):
self.room_mock.unready_player.assert_called_once()
self.assertEqual(403, response.status_code, msg=response.content)

def test_unready_game_not_found(self):
self.room_mock.unready_player = MagicMock(side_effect=RoomNotFoundError)
response = self.client.post(url=f'/room/action/unready/{self.room_mock.id}',
headers=self.second_player)
self.room_mock.unready_player.assert_called_once()
self.assertEqual(404, response.status_code, msg=response.content)

def test_unready_player_not_ready(self):
self.room_mock.unready_player = MagicMock(side_effect=UserNotReadyError)
response = self.client.post(url=f'/room/action/unready/{self.room_mock.id}',
headers=self.second_player)
self.room_mock.unready_player.assert_called_once()
self.assertEqual(400, response.status_code, msg=response.content)

def test_unready_no_room(self):
self.room_service_mock.get = MagicMock(side_effect=RoomNotFoundError('998'))
response = self.client.post(url='/room/action/unready/998', headers=self.headers)
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)

def test_unready_no_room_save(self):
self.room_service_mock.save = MagicMock(side_effect=RoomNotFoundError('999'))
response = self.client.post(url='/room/action/unready/999', headers=self.headers)
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)
7 changes: 7 additions & 0 deletions tests/whist_server/api/room/test_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from tests.whist_server.api.room.base_created_case import BaseCreateGameTestCase
from whist_server import app
from whist_server.services.error import RoomNotFoundError


class GameTestCase(BaseCreateGameTestCase):
Expand Down Expand Up @@ -39,3 +40,9 @@ def test_next_hand_not_done(self):
headers=self.headers)
self.room_mock.next_hand.assert_called_once()
self.assertEqual(400, response.status_code)

def test_next_hand_no_room(self):
self.room_service_mock.get = MagicMock(side_effect=RoomNotFoundError('999'))
response = self.client.post(url='/room/next_hand/999', headers=self.headers)
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)
5 changes: 5 additions & 0 deletions tests/whist_server/api/room/test_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def test_get_all_ids_require_login(self):
response = self.client.get('/room/info/ids')
self.assertEqual(401, response.status_code, msg=response.content)

def test_get_all_no_room(self):
self.room_service_mock.all = MagicMock(return_value=[])
response = self.client.get('/room/info/ids')
self.assertEqual(200, response.status_code, msg=response.content)

def test_get_room_info(self):
expected_info = RoomInfo(name='test', password=True, phase=RoomPhase.LOBBY, rubber_number=0,
game_number=0, hand_number=0, trick_number=0, min_player=2,
Expand Down
13 changes: 13 additions & 0 deletions tests/whist_server/api/room/test_join.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ def test_host_join(self):
self.assertEqual(200, response.status_code, msg=response.content)
self.assertEqual('already joined', response.json()['status'])

def test_join_no_room(self):
self.room_service_mock.get = MagicMock(side_effect=RoomNotFoundError('999'))
response = self.client.post(url='/room/join/999', json={'password': 'abc'},
headers=self.headers)
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)

def test_leave(self):
headers = self.create_and_auth_user()
self.password_service_mock.verify = MagicMock(return_value=True)
Expand All @@ -107,6 +114,12 @@ def test_leave_not_joined(self):
self.room_mock.leave.assert_called_once()
self.assertEqual(403, response.status_code, msg=response.content)

def test_leave_no_room(self):
self.room_service_mock.get = MagicMock(side_effect=RoomNotFoundError('999'))
response = self.client.post(url='/room/leave/999', headers=self.headers)
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)


class IntegrationTestJoinGame(TestCase):
def create_and_auth_user(self, user: str, password):
Expand Down
20 changes: 20 additions & 0 deletions tests/whist_server/api/room/test_trick.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from tests.whist_server.api.room.base_created_case import BaseCreateGameTestCase
from whist_server import app
from whist_server.services.error import RoomNotFoundError


class TrickTestCase(BaseCreateGameTestCase):
Expand All @@ -32,6 +33,12 @@ def test_player_hand(self):
headers=self.headers)
self.assertEqual(UnorderedCardContainer(**response.json()), self.hand)

def test_hand_no_room(self):
self.room_service_mock.get = MagicMock(side_effect=RoomNotFoundError('999'))
response = self.client.get(url='/room/trick/hand/999', headers=self.headers)
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)

def test_play_card(self):
response = self.client.post(url=f'/room/trick/play_card/{self.room_mock.id}',
headers=self.headers, json=self.first_card.dict())
Expand All @@ -40,6 +47,13 @@ def test_play_card(self):
response_stack = OrderedCardContainer(**response.json())
self.assertEqual(self.stack, response_stack)

def test_play_card_no_room(self):
self.room_service_mock.get = MagicMock(side_effect=RoomNotFoundError('999'))
response = self.client.post(url='/room/trick/play_card/999', headers=self.headers,
json=self.first_card.dict())
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)

def test_not_players_turn(self):
self.trick_mock.play_card = MagicMock(
side_effect=NotPlayersTurnError(player=MagicMock(),
Expand Down Expand Up @@ -69,6 +83,12 @@ def test_not_joined_winner(self):
headers=self.headers)
self.assertEqual(403, response.status_code, msg=response.content)

def test_winner_no_room(self):
self.room_service_mock.get = MagicMock(side_effect=RoomNotFoundError('999'))
response = self.client.get(url='/room/trick/winner/999', headers=self.headers)
self.room_mock.assert_not_called()
self.assertEqual(404, response.status_code, msg=response.content)

def test_next_trick(self):
response = self.client.post(url=f'/room/next_trick/{self.room_mock.id}',
headers=self.headers)
Expand Down
21 changes: 16 additions & 5 deletions whist_server/api/room/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ def start_room(room_id: str, background_tasks: BackgroundTasks,
:return: dictionary containing the status of whether the table has been started or not.
Raises 403 exception if the user has not the appropriate privileges.
"""
room: RoomInDb = room_service.get(room_id)
try:
room: RoomInDb = room_service.get(room_id)
except RoomNotFoundError as not_found_error:
message = f'The room with id "{not_found_error}" was not found.'
raise create_http_error(message, status.HTTP_404_NOT_FOUND) from not_found_error

try:
room.start(user)
Expand All @@ -64,16 +68,19 @@ def start_room(room_id: str, background_tasks: BackgroundTasks,
def ready_player(room_id: str, user: UserInDb = Security(get_current_user),
room_service=Depends(RoomDatabaseService)) -> dict:
"""
A player can mark theyself to be ready.
A player can mark themself to be ready.
:param room_id: unique identifier of the room
:param user: Required to identify the user.
:param room_service: Injection of the room database service. Requires to interact with the
database.
:return: dictionary containing the status of whether the action was successful.
Raises 403 exception if the user has not be joined yet.
"""
room = room_service.get(room_id)

try:
room: RoomInDb = room_service.get(room_id)
except RoomNotFoundError as not_found_error:
message = f'The room with id "{not_found_error}" was not found.'
raise create_http_error(message, status.HTTP_404_NOT_FOUND) from not_found_error
try:
room.ready_player(user)
room_service.save(room)
Expand All @@ -97,7 +104,11 @@ def unready_player(room_id: str, user: UserInDb = Security(get_current_user),
Raises 404 exception if room_id is not found
Raises 400 exception if player is not ready
"""
room = room_service.get(room_id)
try:
room: RoomInDb = room_service.get(room_id)
except RoomNotFoundError as not_found_error:
message = f'The room with id "{not_found_error}" was not found.'
raise create_http_error(message, status.HTTP_404_NOT_FOUND) from not_found_error

try:
room.unready_player(user)
Expand Down
8 changes: 7 additions & 1 deletion whist_server/api/room/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from whist_server.database.user import UserInDb
from whist_server.services.authentication import get_current_user
from whist_server.services.channel_service import ChannelService
from whist_server.services.error import RoomNotFoundError
from whist_server.services.room_db_service import RoomDatabaseService
from whist_server.web_socket.events.event import NextHandEvent, NextTrickEvent

Expand All @@ -29,7 +30,12 @@ def next_hand(room_id: str, background_tasks: BackgroundTasks,
database.
:return: Status: 'Success' if next hand is created else raises error.
"""
room: RoomInDb = room_service.get(room_id)
try:
room: RoomInDb = room_service.get(room_id)
except RoomNotFoundError as not_found_error:
message = f'The room with id "{not_found_error}" was not found.'
raise create_http_error(message, status.HTTP_404_NOT_FOUND) from not_found_error

if user not in room.players:
message = f'Player: {user} has not joined {room}, yet.'
raise create_http_error(message, status.HTTP_403_FORBIDDEN)
Expand Down
2 changes: 1 addition & 1 deletion whist_server/api/room/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def all_rooms(room_service=Depends(RoomDatabaseService),
Returns all room id.
:param room_service: Dependency injection of the room service
:param _: not required for logic, but authentication
:return: a list of all room ids as strings.
:return: a list of all room ids as strings. Empty list if no rooms are found.
"""
rooms = room_service.all()
return {'rooms': [str(room.id) for room in rooms]}
Expand Down
15 changes: 12 additions & 3 deletions whist_server/api/room/join.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from whist_server.api.util import create_http_error
from whist_server.database.error import PlayerNotJoinedError
from whist_server.database.room import RoomInfo
from whist_server.database.room import RoomInDb, RoomInfo
from whist_server.database.user import UserInDb
from whist_server.database.warning import PlayerAlreadyJoinedWarning
from whist_server.services.authentication import get_current_user
Expand Down Expand Up @@ -47,7 +47,12 @@ def join_game(room_id: str, request: JoinRoomArgs, background_tasks: BackgroundT
:param channel_service: Injection of the websocket channel manager.
:return: the status of the join request. 'joined' for successful join
"""
room = room_service.get(room_id)
try:
room: RoomInDb = room_service.get(room_id)
except RoomNotFoundError as not_found_error:
message = f'The room with id "{not_found_error}" was not found.'
raise create_http_error(message, status.HTTP_404_NOT_FOUND) from not_found_error

if room.hashed_password is not None and (
request.password is None or not pwd_service.verify(request.password,
room.hashed_password)):
Expand Down Expand Up @@ -80,7 +85,11 @@ def leave_game(room_id: str, background_tasks: BackgroundTasks,
:param channel_service: Injection of the websocket channel manager.
:return: the status of the leave request. 'left' for successful join
"""
room = room_service.get(room_id)
try:
room: RoomInDb = room_service.get(room_id)
except RoomNotFoundError as not_found_error:
message = f'The room with id "{not_found_error}" was not found.'
raise create_http_error(message, status.HTTP_404_NOT_FOUND) from not_found_error

try:
room.leave(user)
Expand Down
22 changes: 19 additions & 3 deletions whist_server/api/room/trick.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
from whist_core.game.warnings import TrickNotDoneWarning

from whist_server.api.util import create_http_error
from whist_server.database.room import RoomInDb
from whist_server.database.user import UserInDb
from whist_server.services.authentication import get_current_user
from whist_server.services.channel_service import ChannelService
from whist_server.services.error import RoomNotFoundError
from whist_server.services.room_db_service import RoomDatabaseService
from whist_server.web_socket.events.event import CardPlayedEvent, TrickDoneEvent

Expand All @@ -31,7 +33,11 @@ def hand(room_id: str, user: UserInDb = Security(get_current_user),
database.
:return: UnorderedCardContainer containing all cards of the player
"""
room = room_service.get(room_id)
try:
room: RoomInDb = room_service.get(room_id)
except RoomNotFoundError as not_found_error:
message = f'The room with id "{not_found_error}" was not found.'
raise create_http_error(message, status.HTTP_404_NOT_FOUND) from not_found_error

player = room.get_player(user)
return player.hand
Expand All @@ -55,7 +61,12 @@ def play_card(room_id: str, card: Card, background_tasks: BackgroundTasks,
:param channel_service: Injection of the websocket channel manager.
:return: the stack after card being played if successful. If not the players turn raises error.
"""
room = room_service.get(room_id)
try:
room: RoomInDb = room_service.get(room_id)
except RoomNotFoundError as not_found_error:
message = f'The room with id "{not_found_error}" was not found.'
raise create_http_error(message, status.HTTP_404_NOT_FOUND) from not_found_error

trick = room.current_trick()

try:
Expand Down Expand Up @@ -86,7 +97,12 @@ def get_winner(room_id: str, user: UserInDb = Security(get_current_user),
:return: The PlayerAtTable object of the winner. Raises Exception if the user has not joined
the room yet. Replies with a warning if the trick has not be done.
"""
room = room_service.get(room_id)
try:
room: RoomInDb = room_service.get(room_id)
except RoomNotFoundError as not_found_error:
message = f'The room with id "{not_found_error}" was not found.'
raise create_http_error(message, status.HTTP_404_NOT_FOUND) from not_found_error

if user not in room.players:
message = 'You have not joined the table.'
raise create_http_error(message, status.HTTP_403_FORBIDDEN)
Expand Down

0 comments on commit dea8428

Please sign in to comment.