def test_close(self):
        ws = AsyncMock()

        adaptor = BybitPerpetualWebSocketAdaptor(websocket=ws)
        asyncio.get_event_loop().run_until_complete(adaptor.close())

        self.assertEquals(1, ws.close.await_count)
    def test_subscribe_to_instruments_info_for_two_symbols(self):
        sent_messages = []
        ws = AsyncMock()
        ws.send_json.side_effect = lambda sent_message: sent_messages.append(sent_message)

        adaptor = BybitPerpetualWebSocketAdaptor(websocket=ws)
        asyncio.get_event_loop().run_until_complete(adaptor.subscribe_to_instruments_info(["BTCUSD", "ETHUSD"]))

        self.assertEqual(1, len(sent_messages))
        message = sent_messages[0]
        expected_message = {"op": "subscribe",
                            "args": ["instrument_info.100ms.BTCUSD|ETHUSD"]}
        self.assertEqual(expected_message, message)
    def test_subscribe_to_trades_for_all_symbols(self):
        sent_messages = []
        ws = AsyncMock()
        ws.send_json.side_effect = lambda sent_message: sent_messages.append(sent_message)

        adaptor = BybitPerpetualWebSocketAdaptor(websocket=ws)
        asyncio.get_event_loop().run_until_complete(adaptor.subscribe_to_trades())

        self.assertEqual(1, len(sent_messages))
        message = sent_messages[0]
        expected_message = {"op": "subscribe",
                            "args": ["trade.*"]}
        self.assertEqual(expected_message, message)
    def test_request_message_structure(self):
        sent_messages = []
        ws = AsyncMock()
        ws.send_json.side_effect = lambda sent_message: sent_messages.append(sent_message)

        adaptor = BybitPerpetualWebSocketAdaptor(websocket=ws)
        payload = {"TestElement1": "Value1", "TestElement2": "Value2"}
        asyncio.get_event_loop().run_until_complete(adaptor.send_request(payload=payload))

        self.assertEqual(1, len(sent_messages))
        message = sent_messages[0]

        self.assertEqual(payload, message)
    def test_adaptor_sends_ping_heartbeat_when_receive_times_out(self):
        sent_messages = asyncio.Queue()
        messages_to_receive = asyncio.Queue()
        ws = AsyncMock()
        ws.send_json.side_effect = lambda sent_message: sent_messages.put_nowait(sent_message)
        ws.receive_json.side_effect = lambda timeout: (self._raise_asyncio_timeout_exception()
                                                       if sent_messages.empty()
                                                       else messages_to_receive.get())

        adaptor = BybitPerpetualWebSocketAdaptor(websocket=ws)
        task = asyncio.get_event_loop().create_task(self._iterate_messages(adaptor))

        messages_to_receive.put_nowait({"topic": "dummyMessage"})

        sent_message = asyncio.get_event_loop().run_until_complete(sent_messages.get())

        task.cancel()
        try:
            asyncio.get_event_loop().run_until_complete(task)
        except asyncio.CancelledError:
            # Ignore the cancelled error
            pass

        expected_message = {"op": "ping"}
        self.assertEqual(expected_message, sent_message)
 async def _create_websocket_connection(self, url: str) -> BybitPerpetualWebSocketAdaptor:
     """
     Initialize WebSocket client for UserStreamDataSource
     """
     try:
         if self._session is None:
             self._session = aiohttp.ClientSession()
         ws = await self._session.ws_connect(url)
         return BybitPerpetualWebSocketAdaptor(websocket=ws)
     except asyncio.CancelledError:
         raise
     except Exception as ex:
         self.logger().network(f"Unexpected error occurred during {CONSTANTS.EXCHANGE_NAME} WebSocket Connection"
                               f" on {url} ({ex})")
         raise
    def test_listening_process_authenticates_and_subscribes_to_events(
            self, ws_connect_mock):
        messages = asyncio.Queue()
        ws_connect_mock.return_value = self.mocking_assistant.create_websocket_mock(
        )
        initial_last_recv_time = self.data_source.last_recv_time

        self.listening_task = asyncio.get_event_loop().create_task(
            self.data_source._listen_for_user_stream_on_url(
                "test_url", messages))
        # Add the authentication response for the websocket
        self.mocking_assistant.add_websocket_json_message(
            ws_connect_mock.return_value, self._authentication_response(True))
        self.mocking_assistant.add_websocket_json_message(
            ws_connect_mock.return_value,
            self._subscription_response(
                True, CONSTANTS.WS_SUBSCRIPTION_POSITIONS_ENDPOINT_NAME))
        self.mocking_assistant.add_websocket_json_message(
            ws_connect_mock.return_value,
            self._subscription_response(
                True, CONSTANTS.WS_SUBSCRIPTION_ORDERS_ENDPOINT_NAME))
        self.mocking_assistant.add_websocket_json_message(
            ws_connect_mock.return_value,
            self._subscription_response(
                True, CONSTANTS.WS_SUBSCRIPTION_EXECUTIONS_ENDPOINT_NAME))

        # Add a dummy message for the websocket to read and include in the "messages" queue
        self.mocking_assistant.add_websocket_json_message(
            ws_connect_mock.return_value, json.dumps('dummyMessage'))

        asyncio.get_event_loop().run_until_complete(messages.get())

        self.assertTrue(
            self._is_logged('INFO', "Authenticating to User Stream..."))
        self.assertTrue(
            self._is_logged('INFO',
                            "Successfully authenticated to User Stream."))
        self.assertTrue(
            self._is_logged(
                'INFO',
                "Successful subscription to the topic ['position'] on test_url"
            ))
        self.assertTrue(
            self._is_logged(
                "INFO",
                "Successful subscription to the topic ['order'] on test_url"))
        self.assertTrue(
            self._is_logged(
                "INFO",
                "Successful subscription to the topic ['execution'] on test_url"
            ))

        sent_messages = self.mocking_assistant.json_messages_sent_through_websocket(
            ws_connect_mock.return_value)
        self.assertEqual(4, len(sent_messages))
        authentication_request = sent_messages[0]
        subscription_positions_request = sent_messages[1]
        subscription_orders_request = sent_messages[2]
        subscription_executions_request = sent_messages[3]

        self.assertEqual(
            CONSTANTS.WS_AUTHENTICATE_USER_ENDPOINT_NAME,
            BybitPerpetualWebSocketAdaptor.endpoint_from_message(
                authentication_request))
        self.assertEqual(
            CONSTANTS.WS_SUBSCRIPTION_POSITIONS_ENDPOINT_NAME,
            BybitPerpetualWebSocketAdaptor.endpoint_from_message(
                subscription_positions_request))
        self.assertEqual(
            CONSTANTS.WS_SUBSCRIPTION_ORDERS_ENDPOINT_NAME,
            BybitPerpetualWebSocketAdaptor.endpoint_from_message(
                subscription_orders_request))
        self.assertEqual(
            CONSTANTS.WS_SUBSCRIPTION_EXECUTIONS_ENDPOINT_NAME,
            BybitPerpetualWebSocketAdaptor.endpoint_from_message(
                subscription_executions_request))

        subscription_positions_payload = BybitPerpetualWebSocketAdaptor.payload_from_message(
            subscription_positions_request)
        expected_payload = {"op": "subscribe", "args": ["position"]}
        self.assertEqual(expected_payload, subscription_positions_payload)

        subscription_orders_payload = BybitPerpetualWebSocketAdaptor.payload_from_message(
            subscription_orders_request)
        expected_payload = {"op": "subscribe", "args": ["order"]}
        self.assertEqual(expected_payload, subscription_orders_payload)

        subscription_executions_payload = BybitPerpetualWebSocketAdaptor.payload_from_message(
            subscription_executions_request)
        expected_payload = {"op": "subscribe", "args": ["execution"]}
        self.assertEqual(expected_payload, subscription_executions_payload)

        self.assertGreater(self.data_source.last_recv_time,
                           initial_last_recv_time)