def test_receive_messages_success(self): # Tests that a remote proxy player can successfully receive a message from a client server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_sock.bind(("localhost", self.port)) server_sock.listen() # run client on separate thread def thread_func(port): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(("localhost", port)) time.sleep(.1) sock.sendall(bytes('"void"', 'ascii')) if sock: sock.close() c_thread = threading.Thread(target=thread_func, args=(self.port, )) c_thread.start() client, address = server_sock.accept() rpp = RemotePlayerProxy('name', 1.0, client) response = rpp._RemotePlayerProxy__receive_messages() # close sockets if server_sock: server_sock.close() if rpp._RemotePlayerProxy__socket: rpp._RemotePlayerProxy__socket.close() self.assertEqual(response, ['void'])
def test_status_update(self): # Test that we simply return True for status_update rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) res = rpp.status_update(PlayerStatus.DISCONTINUED) self.assertEquals(res, True) res = rpp.status_update(PlayerStatus.WON_GAME) self.assertEquals(res, True)
def test_invalid_json_placement(self): # Tests that receiving invalid JSON results in a None placement rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'[' state = State(self.__b, players=[self.__p1, self.__p2, self.__p3]) pos = rpp.get_placement(state) self.assertEqual(pos, None)
def __init__(self, connection): """ This class implements a remote player proxy contract which has the same interface as the player, but checks the sent and received messages for validity. """ self.name = None self.remote_player_proxy = RemotePlayerProxy(connection)
def test_valid_json_invalid_message(self): # Tests that valid JSON but invalid message returns JsonDecodeException rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'["test"]' with self.assertRaises(JsonDecodeException): state = State(self.__b, players=[self.__p1, self.__p2, self.__p3]) pos = rpp.get_placement(state)
def test_tournament_start_success(self): # Test that RPP can successfully send a tournament start message and recieve ack rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'"void"' expected_client_request = f'["start", [true]]' with patch.object(rpp, '_RemotePlayerProxy__send_message') as mock: ack = rpp.tournament_has_started() mock.assert_called_with(expected_client_request) self.assertEqual(ack, True)
def test_playing_with_success(self): # Test that RPP can successfully send a color and receive ACK from client rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'"void"' expected_client_request = f'["playing-with", ["red", "brown"]]' with patch.object(rpp, '_RemotePlayerProxy__send_message') as mock: ack = rpp.notify_opponent_colors([Color.RED, Color.BROWN]) mock.assert_called_with(expected_client_request) self.assertEqual(ack, True)
def test_set_color_no_ack(self): # Test that RPP will return False if no ack received for set_color rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'[1, 2]' expected_client_request = f'["playing-as", ["white"]]' with patch.object(rpp, '_RemotePlayerProxy__send_message') as mock: ack = rpp.set_color(Color.WHITE) mock.assert_called_with(expected_client_request) self.assertEqual(ack, False)
def test_tournament_start_no_ack(self): # Test that RPP will return False if no ack received for tournament_start rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'[][]' expected_client_request = f'["start", [true]]' with patch.object(rpp, '_RemotePlayerProxy__send_message') as mock: ack = rpp.tournament_has_started() mock.assert_called_with(expected_client_request) self.assertEqual(ack, False)
def test_playing_with_no_ack(self): # Test that RPP will return False if no ack received for set_color rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'whoops' expected_client_request = f'["playing-with", ["white", "black"]]' with patch.object(rpp, '_RemotePlayerProxy__send_message') as mock: ack = rpp.notify_opponent_colors([Color.WHITE, Color.BLACK]) mock.assert_called_with(expected_client_request) self.assertEqual(ack, False)
def test_get_action_success(self): # Test that RPP can successfully request, receive, and decode an Action rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'[[0, 1], [2, 2]]' state = State(self.__b, players=[self.__p1, self.__p2, self.__p3]) json_state = _state_to_json(state) expected_client_request = f'["take-turn", [{json.dumps(json_state)}, []]]' with patch.object(rpp, '_RemotePlayerProxy__send_message') as mock: action = rpp.get_action(state) mock.assert_called_with(expected_client_request) self.assertEqual(action, Action(Position(0, 1), Position(2, 2)))
def test_get_action_returns_position(self): # Test that receiving a position when asking for an action throws JsonDecodeException and returns None rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'[0, 1]' state = State(self.__b, players=[self.__p1, self.__p2, self.__p3]) json_state = _state_to_json(state) expected_client_request = f'["take-turn", [{json.dumps(json_state)}, []]]' with patch.object(rpp, '_RemotePlayerProxy__send_message') as mock: with self.assertRaises(JsonDecodeException): action = rpp.get_action(state) mock.assert_called_with(expected_client_request) self.assertEqual(action, None)
def test_get_placement_success(self): # Test that RPP can successfully request, receive and decode a position # This is done to bypass the constructor type checking rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) rpp._RemotePlayerProxy__socket = self.mock_socket self.mock_socket.recv.return_value = b'[0, 1]' state = State(self.__b, players=[self.__p1, self.__p2, self.__p3]) json_state = _state_to_json(state) expected_client_request = f'["setup", [{json.dumps(json_state)}]]' with patch.object(rpp, '_RemotePlayerProxy__send_message') as mock: pos = rpp.get_placement(state) mock.assert_called_with(expected_client_request) self.assertEqual(pos, Position(0, 1))
def test_can_tournament_run(self): # Dummy socket can be used because we aren't running the tournament self.dummy_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.rp1 = RemotePlayerProxy('a', 1.0, self.dummy_sock) self.rp2 = RemotePlayerProxy('b', 2.0, self.dummy_sock) self.rp3 = RemotePlayerProxy('c', 3.0, self.dummy_sock) self.rp4 = RemotePlayerProxy('d', 4.0, self.dummy_sock) server = Server() server._Server__remote_player_proxies = [ self.rp1, self.rp2, self.rp3, self.rp4 ] self.assertFalse(server._Server__can_tournament_run()) self.rp5 = RemotePlayerProxy('e', 5.0, self.dummy_sock) server._Server__remote_player_proxies.append(self.rp5) self.assertTrue(server._Server__can_tournament_run()) self.__server_close(server)
class RemoteContractProxy(): def __init__(self, connection): """ This class implements a remote player proxy contract which has the same interface as the player, but checks the sent and received messages for validity. """ self.name = None self.remote_player_proxy = RemotePlayerProxy(connection) def register(self): p_name = self.remote_player_proxy.register() self.name = p_name return p_name def receive_stone(self, stone_type): self.remote_player_proxy.receive_stone(stone_type) def choose_move(self, boards): try: p_move = self.remote_player_proxy.choose_move(boards) p_move = p_move.replace("\"", "") if p_move == PASS: return PASS else: move_point = str_to_point(p_move) return (move_point.x, move_point.y) except PointException: raise PointException("Invalid move.") def game_over(self, end_tag): try: response = self.remote_player_proxy.game_over(end_tag) response = response.replace("\"", "") return (response == GAME_OVER_RESPONSE) except: return False
def __run_signup_period(self): """ This function conducts a single "waiting period" where we sign up players for a tournament throughn the server socket. It looks for new connections on our TCP server socket, and will add any client socket connections to our self._remote_player_proxies array. This function will wait for signups for self._signup_timeout seconds before returning. """ # get time in self._signup_timeout seconds from now time_end = time.time() + self.__signup_timeout # loop until we reach that time (i.e. this loop will run for signup_timeout seconds) while time.time() < time_end: client_sock = None try: (client_sock, address) = self.__server_socket.accept() client_sock.settimeout(self.NAME_TIMEOUT) # Receive name from client data = client_sock.recv(4096) name = data.decode('ascii') if name: # client timeout is now handled by the referee client_sock.settimeout(None) # Initialize the remote proxy player with the client socket curr_time = time.time() rpp = RemotePlayerProxy(name, curr_time, client_sock) self.__remote_player_proxies.append(rpp) else: # Either did not provide name, or provided a taken name, so we disconnect them client_sock.close() # If we have reached the max number of clients, stop listening if len(self.__remote_player_proxies) == self.__max_clients: break except Exception: if client_sock: client_sock.close() self.__signup_periods -= 1
def test_init_fail5(self): # Tests failing init due to name that is too long with self.assertRaises(ValueError): RemotePlayerProxy("thisstringistoolong", 2.0, self.sock1)
def test_init_fail4(self): # Tests failing init due to empty name with self.assertRaises(ValueError): RemotePlayerProxy("", 2.0, self.sock1)
def test_init_fail3(self): # Tests failing init due to invalid socket with self.assertRaises(TypeError): RemotePlayerProxy("name", 10.0, ["not a socket"])
def test_init_fail2(self): # Tests failing init due to invalid age with self.assertRaises(TypeError): RemotePlayerProxy("name", "not a float")
def test_init_fail1(self): # Tests failing init due to invalid name with self.assertRaises(TypeError): RemotePlayerProxy({'not a str': 'duh'})
def test_is_ack_false2(self): # Tests an invalid ack rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) is_ack = rpp._RemotePlayerProxy__is_ack([]) self.assertFalse(is_ack)
def test_is_ack_true(self): # Tests a valid ack rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) is_ack = rpp._RemotePlayerProxy__is_ack(['void']) self.assertTrue(is_ack)
def test_sync(self): # Tests that we simply return None for sync rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) state = State(self.__b, players=[self.__p1, self.__p2, self.__p3]) res = rpp.sync(state) self.assertEquals(res, None)
def test_game_over(self): # Test that we simply return None for game_over rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) res = rpp.game_over([], [], []) self.assertEquals(res, None)
def test_receive_messages_lost_connection(self): # Tests that a remote proxy player can successfully receive a message from a client rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) response = rpp._RemotePlayerProxy__receive_messages() self.assertEqual(response, [])
def test_kick_success(self): # Test that kicking the player sets their internal state to kicked, and returns None rpp = RemotePlayerProxy('name', 1.0, self.dummy_socket) res = rpp.kick('test') self.assertTrue(rpp.kicked) self.assertEquals(res, None)