예제 #1
0
 def test_private_rest_url(self):
     path_url = "/TEST_PATH"
     domain = "com"
     expected_url = CONSTANTS.REST_URL.format(
         domain) + CONSTANTS.PRIVATE_API_VERSION + path_url
     self.assertEqual(expected_url,
                      utils.private_rest_url(path_url, domain))
예제 #2
0
    def test_listen_for_user_stream_handle_ping_frame(self, mock_api, mock_ws):
        url = utils.private_rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_response = {"listenKey": self.listen_key}
        mock_api.post(regex_url, body=ujson.dumps(mock_response))

        mock_ws.return_value = self.mocking_assistant.create_websocket_mock()
        self.mocking_assistant.add_websocket_aiohttp_message(
            mock_ws.return_value, "", aiohttp.WSMsgType.PING)

        self.mocking_assistant.add_websocket_aiohttp_message(
            mock_ws.return_value, self._user_update_event())

        msg_queue = asyncio.Queue()
        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_user_stream(self.ev_loop, msg_queue))

        msg = self.ev_loop.run_until_complete(msg_queue.get())
        self.assertTrue(msg, self._user_update_event)
        self.assertTrue(
            self._is_logged("DEBUG",
                            "Received PING frame. Sending PONG frame..."))
    def test_listen_for_user_stream_iter_message_throws_exception(self, mock_api, mock_ws):
        url = utils.private_rest_url(path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL, domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?"))

        mock_response = {
            "listenKey": self.listen_key
        }
        mock_api.post(regex_url, body=json.dumps(mock_response))

        msg_queue: asyncio.Queue = asyncio.Queue()
        mock_ws.return_value = self.mocking_assistant.create_websocket_mock()
        mock_ws.return_value.receive.side_effect = (lambda *args, **kwargs:
                                                    self._create_exception_and_unlock_test_with_event(
                                                        Exception("TEST ERROR")))
        mock_ws.close.return_value = None

        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_user_stream(self.ev_loop, msg_queue)
        )

        self.async_run_with_timeout(self.resume_test_event.wait())

        self.assertTrue(
            self._is_logged(
                "ERROR",
                "Unexpected error while listening to user stream. Retrying after 5 seconds..."))
예제 #4
0
    def test_listen_for_user_stream_connection_failed(self, mock_api, mock_ws):
        url = utils.private_rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL,
            domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".",
                                                 r"\.").replace("?", r"\?"))

        mock_response = {"listenKey": self.listen_key}
        mock_api.post(regex_url, body=ujson.dumps(mock_response))

        mock_ws.side_effect = lambda **_: self._create_exception_and_unlock_test_with_event(
            Exception("TEST ERROR."))

        msg_queue = asyncio.Queue()
        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_user_stream(self.ev_loop, msg_queue))

        self.ev_loop.run_until_complete(self.resume_test_event.wait())

        self.assertTrue(
            self._is_logged(
                "NETWORK",
                "Unexpected error occured when connecting to WebSocket server. Error: TEST ERROR."
            ))
        self.assertTrue(
            self._is_logged(
                "ERROR",
                "Unexpected error while listening to user stream. Retrying after 5 seconds... Error: TEST ERROR."
            ))
    def test_ping_listen_key_successful(self, mock_api):
        url = utils.private_rest_url(path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL, domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?"))
        mock_api.put(regex_url, body=json.dumps({}))

        self.data_source._current_listen_key = self.listen_key
        result: bool = self.async_run_with_timeout(self.data_source._ping_listen_key())
        self.assertTrue(result)
    def test_get_listen_key_log_exception(self, mock_api):
        url = utils.private_rest_url(path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL, domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?"))

        mock_api.post(regex_url, status=400, body=json.dumps(self._error_response()))

        with self.assertRaises(IOError):
            self.async_run_with_timeout(self.data_source._get_listen_key())
    def test_ping_listen_key_log_exception(self, mock_api):
        url = utils.private_rest_url(path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL, domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?"))

        mock_api.put(regex_url, status=400, body=json.dumps(self._error_response()))

        self.data_source._current_listen_key = self.listen_key
        result: bool = self.async_run_with_timeout(self.data_source._ping_listen_key())

        self.assertTrue(self._is_logged("WARNING", f"Failed to refresh the listen key {self.listen_key}: {self._error_response()}"))
        self.assertFalse(result)
    def test_get_listen_key_successful(self, mock_api):
        url = utils.private_rest_url(path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL, domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?"))

        mock_response = {
            "listenKey": self.listen_key
        }
        mock_api.post(regex_url, body=json.dumps(mock_response))

        result: str = self.async_run_with_timeout(self.data_source._get_listen_key())

        self.assertEqual(self.listen_key, result)
예제 #9
0
    async def get_listen_key(self):
        async with aiohttp.ClientSession() as client:
            async with self._throttler.execute_task(
                    limit_id=CONSTANTS.BINANCE_USER_STREAM_PATH_URL):
                url = binance_utils.private_rest_url(
                    path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL,
                    domain=self._domain)
                response = await client.post(
                    url=url,
                    headers={"X-MBX-APIKEY": self._binance_client.API_KEY})

                if response.status != 200:
                    raise IOError(
                        f"Error fetching user stream listen key. Response: {response}"
                    )
                data: Dict[str, str] = await response.json()
                return data["listenKey"]
예제 #10
0
    async def _api_request(self,
                           method: RESTMethod,
                           path_url: str,
                           params: Optional[Dict[str, Any]] = None,
                           data: Optional[Dict[str, Any]] = None,
                           is_auth_required: bool = False) -> Dict[str, Any]:

        headers = {
            "Content-Type":
            "application/json" if method == RESTMethod.POST else
            "application/x-www-form-urlencoded"
        }
        client = await self._get_rest_assistant()

        if is_auth_required:
            url = binance_utils.private_rest_url(path_url, domain=self._domain)
        else:
            url = binance_utils.public_rest_url(path_url, domain=self._domain)

        request = RESTRequest(method=method,
                              url=url,
                              data=data,
                              params=params,
                              headers=headers,
                              is_auth_required=is_auth_required)

        async with self._throttler.execute_task(limit_id=path_url):
            response = await client.call(request)

            if response.status != 200:
                data = await response.text()
                raise IOError(
                    f"Error fetching data from {url}. HTTP status is {response.status} ({data})."
                )
            try:
                parsed_response = await response.json()
            except Exception:
                raise IOError(f"Error parsing data from {response}.")

            if "code" in parsed_response and "msg" in parsed_response:
                raise IOError(
                    f"The request to Binance failed. Error: {parsed_response}. Request: {request}"
                )

        return parsed_response
예제 #11
0
 async def ping_listen_key(self) -> bool:
     async with aiohttp.ClientSession() as client:
         async with self._throttler.execute_task(
                 limit_id=CONSTANTS.BINANCE_USER_STREAM_PATH_URL):
             url = binance_utils.private_rest_url(
                 path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL,
                 domain=self._domain)
             response = await client.put(
                 url=url,
                 headers={"X-MBX-APIKEY": self._binance_client.API_KEY},
                 params={"listenKey": self._current_listen_key})
             data: Tuple[str, any] = await response.json()
             if "code" in data:
                 self.logger().warning(
                     f"Failed to refresh the listen key {self._current_listen_key}: {data}"
                 )
                 return False
             return True
예제 #12
0
    async def _get_listen_key(self):
        rest_assistant = await self._get_rest_assistant()
        url = binance_utils.private_rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL,
            domain=self._domain)
        request = RESTRequest(method=RESTMethod.POST,
                              url=url,
                              headers=self._auth.header_for_authentication())

        async with self._throttler.execute_task(
                limit_id=CONSTANTS.BINANCE_USER_STREAM_PATH_URL):
            response: RESTResponse = await rest_assistant.call(request=request)

            if response.status != 200:
                raise IOError(
                    f"Error fetching user stream listen key. Response: {response}"
                )
            data: Dict[str, str] = await response.json()
            return data["listenKey"]
    def test_listen_for_user_stream_get_listen_key_successful_with_user_update_event(self, mock_api, mock_ws):
        url = utils.private_rest_url(path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL, domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?"))

        mock_response = {
            "listenKey": self.listen_key
        }
        mock_api.post(regex_url, body=json.dumps(mock_response))

        mock_ws.return_value = self.mocking_assistant.create_websocket_mock()
        self.mocking_assistant.add_websocket_aiohttp_message(mock_ws.return_value, self._user_update_event())

        msg_queue = asyncio.Queue()
        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_user_stream(self.ev_loop, msg_queue)
        )

        msg = self.async_run_with_timeout(msg_queue.get())
        self.assertTrue(msg, self._user_update_event)
    def test_listen_for_user_stream_does_not_queue_empty_payload(self, mock_api, mock_ws):
        url = utils.private_rest_url(path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL, domain=self.domain)
        regex_url = re.compile(f"^{url}".replace(".", r"\.").replace("?", r"\?"))

        mock_response = {
            "listenKey": self.listen_key
        }
        mock_api.post(regex_url, body=json.dumps(mock_response))

        mock_ws.return_value = self.mocking_assistant.create_websocket_mock()
        self.mocking_assistant.add_websocket_aiohttp_message(mock_ws.return_value, "")

        msg_queue = asyncio.Queue()
        self.listening_task = self.ev_loop.create_task(
            self.data_source.listen_for_user_stream(self.ev_loop, msg_queue)
        )

        self.mocking_assistant.run_until_all_aiohttp_messages_delivered(mock_ws.return_value)

        self.assertEqual(0, msg_queue.qsize())
예제 #15
0
    async def _ping_listen_key(self) -> bool:
        rest_assistant = await self._get_rest_assistant()
        url = binance_utils.private_rest_url(
            path_url=CONSTANTS.BINANCE_USER_STREAM_PATH_URL,
            domain=self._domain)
        request = RESTRequest(method=RESTMethod.PUT,
                              url=url,
                              headers=self._auth.header_for_authentication(),
                              params={"listenKey": self._current_listen_key})

        async with self._throttler.execute_task(
                limit_id=CONSTANTS.BINANCE_USER_STREAM_PATH_URL):
            response: RESTResponse = await rest_assistant.call(request=request)

            data: Tuple[str, any] = await response.json()
            if "code" in data:
                self.logger().warning(
                    f"Failed to refresh the listen key {self._current_listen_key}: {data}"
                )
                return False
            return True