def test_client_retries_and_returns_data_if_successful(self, _make_request, from_httplib, base_client): # The third response here would normally be a httplib response object. It's only use is to be passed in to # `from_httplib`, which we're mocking the return of below. `from_httplib` converts a httplib response into a # urllib3 response. The mock object we're returning is a mock for that urllib3 response. _make_request.side_effect = [ ProtocolError(mock.Mock(), '1st error'), ProtocolError(mock.Mock(), '2nd error'), ProtocolError(mock.Mock(), '3nd error'), 'httplib_response - success!', ] from_httplib.return_value = self._from_httplib_response_mock(200, response_data=b'{"Success?": "Yes!"}') response = base_client._request("GET", '/') requests = _make_request.call_args_list assert len(requests) == 4 assert all((request[0][1], request[0][2]) == ('GET', '/') for request in requests) assert response == {'Success?': 'Yes!'}
def test_do_request_exception_args_2(self): self.mock_requests( ).put.side_effect = requests.exceptions.ConnectionError( ProtocolError('Connection broken: xyz')) with self.assertRaises(RequestException) as context: self.rest_client.do_request('PUT', '/test') self.assertEqual( 'UnitTest REST API cannot be reached. Please ' 'check your configuration and that the API ' 'endpoint is accessible', context.exception.message)
def _error_catcher(self): """ Catch low-level python exceptions, instead re-raising urllib3 variants, so that low-level exceptions are not leaked in the high-level api. On exit, release the connection back to the pool. """ try: try: yield except SocketTimeout: # FIXME: Ideally we'd like to include the url in the # ReadTimeoutError but there is yet no clean way to # get at it from this context. raise ReadTimeoutError(self._pool, None, 'Read timed out.') except BaseSSLError as e: # FIXME: Is there a better way to differentiate between SSLErrors? if 'read operation timed out' not in str(e): # Defensive: # This shouldn't happen but just in case we're missing an edge # case, let's avoid swallowing SSL errors. raise raise ReadTimeoutError(self._pool, None, 'Read timed out.') except HTTPException as e: # This includes IncompleteRead. raise ProtocolError('Connection broken: %r' % e, e) except Exception: # The response may not be closed but we're not going to use it anymore # so close it now to ensure that the connection is released back to the # pool. if self._original_response and not self._original_response.isclosed(): self._original_response.close() # Before returning the socket, close it. From the server's # point of view, # this socket is in the middle of handling an SSL handshake/HTTP # request so it we were to try and re-use the connection later, # we'd see undefined behaviour. # # Still return the connection to the pool (it will be # re-established next time it is used). self._connection.close() raise finally: if self._original_response and self._original_response.isclosed(): self.release_conn()
def exec(self, name, *args, api=None, return_with_args=None, _ret_cnt=0): """ Execute a method against steemd RPC. Warnings: This command will auto-retry in case of node failure, as well as handle node fail-over, unless we are broadcasting a transaction. In latter case, the exception is **re-raised**. """ body = HttpClient.json_rpc_body(name, *args, api=api) response = None try: response = self.request(body=body) if response.status in (502, 503, 504): raise ProtocolError('Bad status code: %s' % response.status) except (MaxRetryError, ConnectionResetError, ReadTimeoutError, RemoteDisconnected, ProtocolError) as e: # if we broadcasted a transaction, always raise # this is to prevent potential for double spend scenario if api == 'network_broadcast_api': raise e # try switching nodes before giving up if _ret_cnt > 2: time.sleep(5 * _ret_cnt) elif _ret_cnt > 10: raise e self.next_node() logging.debug('Switched node to %s due to exception: %s' % (self.hostname, e.__class__.__name__)) return self.exec(name, *args, return_with_args=return_with_args, _ret_cnt=_ret_cnt + 1) except Exception as e: if self.re_raise: raise e else: extra = dict(err=e, request=self.request) logger.info('Request error', extra=extra) return self._return(response=response, args=args, return_with_args=return_with_args) else: if response.status not in tuple([*response.REDIRECT_STATUSES, 200]): logger.info('non 200 response:%s', response.status) return self._return(response=response, args=args, return_with_args=return_with_args)
def _mock_incomplete_read_session_response(data: bytes): data_stream = BytesIO(data) mock = MagicMock(name='session_response') mock.raw.read.side_effect = _sequential_side_effects( [data_stream.read, ProtocolError('IncompleteRead')]) return mock
def urlopen(self, method, url, redirect=True, **kw): """ Same as :meth:`urllib3.connectionpool.HTTPConnectionPool.urlopen` with custom cross-host redirect logic and only sends the request-uri portion of the ``url``. The given ``url`` parameter must be absolute, such that an appropriate :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. """ #=============================================================================================================== # add by mz error_type = kw.get('error_type') if error_type: from urllib3.exceptions import LocationValueError, HostChangedError, LocationParseError, ConnectTimeoutError from urllib3.exceptions import ProxyError, TimeoutError, ReadTimeoutError, ProtocolError, DecodeError from urllib3.exceptions import ResponseError, ResponseNotChunked, SSLError, HTTPError, HTTPWarning, PoolError from urllib3.exceptions import RequestError, MaxRetryError, TimeoutStateError, NewConnectionError from urllib3.exceptions import EmptyPoolError, ClosedPoolError, SecurityWarning, SubjectAltNameWarning from urllib3.exceptions import InsecureRequestWarning, SystemTimeWarning, InsecurePlatformWarning from urllib3.exceptions import SNIMissingWarning, DependencyWarning, ProxySchemeUnknown, HeaderParsingError get_error = { "LocationValueError": LocationValueError(), "HostChangedError": HostChangedError(pool=1, url=2), "LocationParseError": LocationParseError(url), "ConnectTimeoutError": ConnectTimeoutError(), "ProxyError": ProxyError(), "TimeoutError": TimeoutError(), "ReadTimeoutError": ReadTimeoutError(pool=1, url=2, message="ReadTimeoutError"), "ProtocolError": ProtocolError(), "DecodeError": DecodeError(), "ResponseError": ResponseError(), "ResponseNotChunked": ResponseNotChunked(), "SSLError": SSLError(), "HTTPError": HTTPError(), "HTTPWarning": HTTPWarning(), "PoolError": PoolError(pool=1, message=2), "RequestError": RequestError(pool=1, url=2, message="RequestError"), "MaxRetryError": MaxRetryError(pool=1, url=2, reason=None), "TimeoutStateError": TimeoutStateError(), "NewConnectionError": NewConnectionError(pool=1, message="NewConnectionError"), "EmptyPoolError": EmptyPoolError(pool=1, message="EmptyPoolError"), "ClosedPoolError": ClosedPoolError(pool=1, message="ClosedPoolError"), "SecurityWarning": SecurityWarning(), "SubjectAltNameWarning": SubjectAltNameWarning(), "InsecureRequestWarning": InsecureRequestWarning(), "SystemTimeWarning": SystemTimeWarning(), "InsecurePlatformWarning": InsecurePlatformWarning(), "SNIMissingWarning": SNIMissingWarning(), "DependencyWarning": DependencyWarning(), "ProxySchemeUnknown": ProxySchemeUnknown(scheme=1), "HeaderParsingError": HeaderParsingError(defects=1, unparsed_data=2) } error_ = get_error[error_type] raise error_ #=============================================================================================================== u = parse_url(url) conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) kw['assert_same_host'] = False kw['redirect'] = False if 'headers' not in kw: kw['headers'] = self.headers if self.proxy is not None and u.scheme == "http": response = conn.urlopen(method, url, **kw) else: response = conn.urlopen(method, u.request_uri, **kw) redirect_location = redirect and response.get_redirect_location() if not redirect_location: return response # Support relative URLs for redirecting. redirect_location = urljoin(url, redirect_location) # RFC 2616, Section 10.3.4 if response.status == 303: method = 'GET' log.info("Redirecting %s -> %s" % (url, redirect_location)) kw['retries'] = kw.get('retries', 3) - 1 # Persist retries countdown kw['redirect'] = redirect return self.urlopen(method, redirect_location, **kw)
def test_catches_bad_status_line(self): error = ProtocolError(None) self.make_request_with_error(error)
class TestBaseApiClient(object): def _from_httplib_response_mock(self, status, response_data=None): response_mock = mock.Mock(status=status, headers={}, spec=[ 'get_redirect_location', 'getheader', 'read', 'reason', 'drain_conn' ]) response_mock.get_redirect_location.return_value = None response_mock.getheader.return_value = None response_mock.read.side_effect = [response_data, None, None, None] response_mock.reason = f'Mocked {status} response' return response_mock @pytest.mark.parametrize( "method,exc_factory", chain( ((m, lambda: NewConnectionError(mock.Mock(), "I'm a message")) for m in ( "GET", "PUT", "POST", "PATCH", )), ((m, lambda: ProtocolError(mock.Mock(), "I'm a message")) for m in ( "GET", "PUT", )), ((m, lambda: ReadTimeoutError(mock.Mock(), mock.Mock(), "I'm a message")) for m in ( "GET", "PUT", )), )) @pytest.mark.parametrize('retry_count', range(1, 4)) @mock.patch('urllib3.connectionpool.HTTPConnectionPool._make_request') @mock.patch('dmapiclient.base.BaseAPIClient._RETRIES_BACKOFF_FACTOR', 0) def test_client_retries_on_httperror_and_raises_api_error( self, _make_request, base_client, retry_count, exc_factory, method, ): _make_request.side_effect = exc_factory() with mock.patch('dmapiclient.base.BaseAPIClient._RETRIES', retry_count): with pytest.raises(HTTPError) as e: base_client._request(method, '/') requests = _make_request.call_args_list assert len(requests) == retry_count + 1 assert all((request[0][1], request[0][2]) == (method, '/') for request in requests) assert type(_make_request.side_effect).__name__ in e.value.message assert e.value.status_code == REQUEST_ERROR_STATUS_CODE @pytest.mark.parametrize("exc_factory", ( lambda: ProtocolError(mock.Mock(), "I'm a message"), lambda: ReadTimeoutError(mock.Mock(), mock.Mock(), "I'm a message"), )) @pytest.mark.parametrize("method", ( "POST", "PATCH", )) @pytest.mark.parametrize('retry_count', range(1, 4)) @mock.patch('urllib3.connectionpool.HTTPConnectionPool._make_request') @mock.patch('dmapiclient.base.BaseAPIClient._RETRIES_BACKOFF_FACTOR', 0) def test_client_doesnt_retry_non_whitelisted_methods_on_unsafe_errors( self, _make_request, base_client, retry_count, exc_factory, method, ): _make_request.side_effect = exc_factory() with mock.patch('dmapiclient.base.BaseAPIClient._RETRIES', retry_count): with pytest.raises(HTTPError) as e: base_client._request(method, '/') requests = _make_request.call_args_list assert len(requests) == 1 assert requests[0][0][1] == method assert requests[0][0][2] == "/" assert type(_make_request.side_effect).__name__ in e.value.message assert e.value.status_code == REQUEST_ERROR_STATUS_CODE @pytest.mark.parametrize(('retry_count'), range(1, 4)) @pytest.mark.parametrize(('status'), BaseAPIClient.RETRIES_FORCE_STATUS_CODES) @mock.patch( 'urllib3.connectionpool.HTTPConnectionPool.ResponseCls.from_httplib') @mock.patch('urllib3.connectionpool.HTTPConnectionPool._make_request') @mock.patch('dmapiclient.base.BaseAPIClient._RETRIES_BACKOFF_FACTOR', 0) def test_client_retries_on_status_error_and_raises_api_error( self, _make_request, from_httplib, base_client, status, retry_count): response_mock = self._from_httplib_response_mock(status) from_httplib.return_value = response_mock with mock.patch('dmapiclient.base.BaseAPIClient._RETRIES', retry_count): with pytest.raises(HTTPError) as e: base_client._request("GET", '/') requests = _make_request.call_args_list assert len(requests) == retry_count + 1 assert all((request[0][1], request[0][2]) == ('GET', '/') for request in requests) assert f'{status} Server Error: {response_mock.reason} for url: http://baseurl/\n' in e.value.message assert e.value.status_code == status @mock.patch( 'urllib3.connectionpool.HTTPConnectionPool.ResponseCls.from_httplib') @mock.patch('urllib3.connectionpool.HTTPConnectionPool._make_request') @mock.patch('dmapiclient.base.BaseAPIClient._RETRIES_BACKOFF_FACTOR', 0) def test_client_retries_and_returns_data_if_successful( self, _make_request, from_httplib, base_client): # The third response here would normally be a httplib response object. It's only use is to be passed in to # `from_httplib`, which we're mocking the return of below. `from_httplib` converts a httplib response into a # urllib3 response. The mock object we're returning is a mock for that urllib3 response. _make_request.side_effect = [ ProtocolError(mock.Mock(), '1st error'), ProtocolError(mock.Mock(), '2nd error'), ProtocolError(mock.Mock(), '3nd error'), 'httplib_response - success!', ] from_httplib.return_value = self._from_httplib_response_mock( 200, response_data=b'{"Success?": "Yes!"}') response = base_client._request("GET", '/') requests = _make_request.call_args_list assert len(requests) == 4 assert all((request[0][1], request[0][2]) == ('GET', '/') for request in requests) assert response == {'Success?': 'Yes!'} def test_non_2xx_response_raises_api_error(self, base_client, rmock): rmock.request("GET", "http://baseurl/", json={"error": "Not found"}, status_code=404) with pytest.raises(HTTPError) as e: base_client._request("GET", '/') assert e.value.message == "Not found" assert e.value.status_code == 404 def test_base_error_is_logged(self, base_client): with requests_mock.Mocker() as m: m.register_uri('GET', '/', exc=requests.RequestException()) with pytest.raises(HTTPError) as e: base_client._request("GET", "/") assert e.value.message == "\nRequestException()" assert e.value.status_code == 503 def test_invalid_json_raises_api_error(self, base_client, rmock): rmock.request("GET", "http://baseurl/", text="Internal Error", status_code=200) with pytest.raises(InvalidResponse) as e: base_client._request("GET", '/') assert e.value.message == "No JSON object could be decoded" assert e.value.status_code == 200 def test_user_agent_is_set(self, base_client, rmock): rmock.request("GET", "http://baseurl/", json={}, status_code=200) base_client._request('GET', '/') assert rmock.last_request.headers.get("User-Agent").startswith( "DM-API-Client/") def test_request_always_uses_base_url_scheme(self, base_client, rmock): rmock.request("GET", "http://baseurl/path/", json={}, status_code=200) base_client._request('GET', 'https://host/path/') assert rmock.called def test_null_api_throws(self): bad_client = BaseAPIClient(None, 'auth-token', True) with pytest.raises(ImproperlyConfigured): bad_client._request('GET', '/anything') def test_onwards_request_headers_added_if_available( self, base_client, rmock, app): rmock.get("http://baseurl/_status", json={"status": "ok"}, status_code=200) with app.test_request_context('/'): # add a simple mock callable instead of using a full request implementation request.get_onwards_request_headers = mock.Mock() request.get_onwards_request_headers.return_value = { "Douce": "bronze", "Kennedy": "gold", } base_client.get_status() assert rmock.last_request.headers["Douce"] == "bronze" assert rmock.last_request.headers["kennedy"] == "gold" assert request.get_onwards_request_headers.call_args_list == [ # just a single, arg-less call (), ] def test_onwards_request_headers_not_available(self, base_client, rmock, app): rmock.get("http://baseurl/_status", json={"status": "ok"}, status_code=200) with app.test_request_context('/'): # really just asserting no exception arose from performing a call without get_onwards_request_headers being # available base_client.get_status() def test_request_id_fallback(self, base_client, rmock, app): # request.request_id is an old interface which we're still supporting here just for compatibility rmock.get("http://baseurl/_status", json={"status": "ok"}, status_code=200) app.config["DM_REQUEST_ID_HEADER"] = "Bar" with app.test_request_context('/'): request.request_id = "Ormond" base_client.get_status() assert rmock.last_request.headers["bar"] == "Ormond" @pytest.mark.parametrize("dm_span_id_headers_setting", ( None, ( "X-Brian-Tweedy", "Major-Tweedy", ), )) @pytest.mark.parametrize( "has_request_context", (False, True), ) @mock.patch("dmapiclient.base.logger") def test_child_span_id_not_provided( self, logger, dm_span_id_headers_setting, has_request_context, base_client, rmock, app, ): rmock.get("http://baseurl/_status", json={"status": "ok"}, status_code=200) app.config["DM_SPAN_ID_HEADERS"] = dm_span_id_headers_setting with (app.test_request_context('/') if has_request_context else _empty_context_manager()): if has_request_context: request.get_onwards_request_headers = mock.Mock( return_value={ "impression": "arrested", }) base_client.get_status() assert rmock.called assert logger.log.call_args_list == [ mock.call( logging.DEBUG, "API request {method} {url}", extra={ "method": "GET", "url": "http://baseurl/_status", # childSpanId NOT provided }), mock.call( logging.INFO, "API {api_method} request on {api_url} finished in {api_time}", extra={ "api_method": "GET", "api_url": "http://baseurl/_status", "api_status": 200, "api_time": mock.ANY, # childSpanId NOT provided }), ] @pytest.mark.parametrize( "onwards_request_headers", ( { "X-Brian-Tweedy": "Amiens Street", }, { "major-TWEEDY": "Amiens Street", }, { "Major-Tweedy": "terminus", "x-brian-tweedy": "Amiens Street", }, { # note same header name, different capitalizations "X-BRIAN-TWEEDY": "great northern", "x-brian-tweedy": "Amiens Street", }, )) @pytest.mark.parametrize("response_status", ( 200, 500, )) @mock.patch("dmapiclient.base.logger") def test_child_span_id_provided( self, mock_logger, onwards_request_headers, response_status, base_client, rmock, app, ): rmock.get("http://baseurl/_status", json={"status": "foobar"}, status_code=response_status) app.config["DM_SPAN_ID_HEADERS"] = ( "X-Brian-Tweedy", "major-tweedy", ) with app.test_request_context('/'): request.get_onwards_request_headers = mock.Mock( return_value=onwards_request_headers) try: base_client.get_status() except HTTPError: # it is tested elsewhere whether this exception is raised in the *right* circumstances or not pass assert rmock.called # some of our scenarios test multiple header names differing only by capitalization - we care that the same # span id that was chosen for the log message is the same one that was sent in the onwards request header, # so we need two distinct values which are acceptable either_span_id = RestrictedAny( lambda value: value == "Amiens Street" or value == "great northern") assert mock_logger.log.call_args_list == [ mock.call(logging.DEBUG, "API request {method} {url}", extra={ "method": "GET", "url": "http://baseurl/_status", "childSpanId": either_span_id, }), (mock.call( logging.INFO, "API {api_method} request on {api_url} finished in {api_time}", extra={ "api_method": "GET", "api_url": "http://baseurl/_status", "api_status": response_status, "api_time": mock.ANY, "childSpanId": either_span_id, } ) if response_status == 200 else mock.call( logging.WARNING, "API {api_method} request on {api_url} failed with {api_status} '{api_error}'", extra={ "api_method": "GET", "api_url": "http://baseurl/_status", "api_status": response_status, "api_time": mock.ANY, "api_error": mock.ANY, "childSpanId": either_span_id, }, )) ] # both logging calls should have had the *same* childSpanId value assert mock_logger.log.call_args_list[0][1]["extra"]["childSpanId"] \ == mock_logger.log.call_args_list[1][1]["extra"]["childSpanId"] # that value should be the same one that was sent in the onwards request header assert ( rmock.last_request.headers.get("x-brian-tweedy") or rmock.last_request.headers.get("major-tweedy") ) == mock_logger.log.call_args_list[0][1]["extra"]["childSpanId"] @pytest.mark.parametrize( "thrown_exception", ( # requests can be slightly unpredictable in the exceptions it raises requests.exceptions.ConnectionError( MaxRetryError( mock.Mock(), "http://abc.net", ReadTimeoutError(mock.Mock(), mock.Mock(), mock.Mock()))), requests.exceptions.ConnectionError( ReadTimeoutError(mock.Mock(), mock.Mock(), mock.Mock())), requests.exceptions.ReadTimeout, )) @mock.patch("dmapiclient.base.logger") def test_nowait_times_out( self, mock_logger, base_client, rmock, app, thrown_exception, ): "test the case when a request with client_wait_for_response=False does indeed time out" rmock.post("http://baseurl/services/10000", exc=thrown_exception) retval = base_client._request( "POST", "/services/10000", {"serviceName": "Postcard"}, client_wait_for_response=False, ) assert retval is None assert rmock.called assert tuple( req.timeout for req in rmock.request_history) == (base_client.nowait_timeout, ) assert mock_logger.log.call_args_list == [ mock.call(logging.DEBUG, "API request {method} {url}", extra={ "method": "POST", "url": "http://baseurl/services/10000", }), mock.call( logging.INFO, "API {api_method} request on {api_url} dispatched but ignoring response", extra={ "api_method": "POST", "api_url": "http://baseurl/services/10000", "api_time": mock.ANY, "api_time_incomplete": True, }), ] @mock.patch("dmapiclient.base.logger") def test_nowait_completes( self, mock_logger, base_client, rmock, app, ): "test the case when a request with client_wait_for_response=False completes before it can time out" rmock.post("http://baseurl/services/10000", json={"services": { "id": "10000" }}, status_code=200) retval = base_client._request( "POST", "/services/10000", {"serviceName": "Postcard"}, client_wait_for_response=False, ) assert retval == {"services": {"id": "10000"}} assert rmock.called assert tuple( req.timeout for req in rmock.request_history) == (base_client.nowait_timeout, ) assert mock_logger.log.call_args_list == [ mock.call(logging.DEBUG, "API request {method} {url}", extra={ "method": "POST", "url": "http://baseurl/services/10000", }), mock.call( logging.INFO, "API {api_method} request on {api_url} finished in {api_time}", extra={ "api_method": "POST", "api_url": "http://baseurl/services/10000", "api_time": mock.ANY, "api_status": 200, }), ]
def test_download_raises_retriable_exception(bucket): with mock.patch('google.cloud.storage.blob.RawDownload') as download_mock: # Some random urllib3 exception download_mock.return_value.consume.side_effect = ProtocolError() with pytest.raises(RetriableError): ret = download_file(bucket, 'foo')
def test_monitor_sends_exception_data_and_hb_on_expected_exceptions( self, mock_get_data) -> None: json_decode_error = json.JSONDecodeError(msg='test error', doc='test', pos=2) errors_exceptions_dict = { ReqConnectionError('test'): CannotAccessGitHubPageException(self.repo_config.releases_page), ReadTimeout('test'): CannotAccessGitHubPageException(self.repo_config.releases_page), IncompleteRead('test'): DataReadingException(self.monitor_name, self.repo_config.releases_page), ChunkedEncodingError('test'): DataReadingException(self.monitor_name, self.repo_config.releases_page), ProtocolError('test'): DataReadingException(self.monitor_name, self.repo_config.releases_page), json_decode_error: JSONDecodeException(json_decode_error) } try: self.test_monitor._initialise_rabbitmq() for error, data_ret_exception in errors_exceptions_dict.items(): mock_get_data.side_effect = error expected_output_data = { 'error': { 'meta_data': { 'monitor_name': self.test_monitor.monitor_name, 'repo_name': self.test_monitor.repo_config.repo_name, 'repo_id': self.test_monitor.repo_config.repo_id, 'repo_parent_id': self.test_monitor.repo_config.parent_id, 'time': datetime(2012, 1, 1).timestamp() }, 'message': data_ret_exception.message, 'code': data_ret_exception.code, } } expected_output_hb = { 'component_name': self.test_monitor.monitor_name, 'is_alive': True, 'timestamp': datetime(2012, 1, 1).timestamp() } # Delete the queue before to avoid messages in the queue on # error. self.test_monitor.rabbitmq.queue_delete(self.test_queue_name) res = self.test_monitor.rabbitmq.queue_declare( queue=self.test_queue_name, durable=True, exclusive=False, auto_delete=False, passive=False) self.assertEqual(0, res.method.message_count) self.test_monitor.rabbitmq.queue_bind( queue=self.test_queue_name, exchange=RAW_DATA_EXCHANGE, routing_key='github') self.test_monitor.rabbitmq.queue_bind( queue=self.test_queue_name, exchange=HEALTH_CHECK_EXCHANGE, routing_key='heartbeat.worker') self.test_monitor._monitor() # By re-declaring the queue again we can get the number of # messages in the queue. res = self.test_monitor.rabbitmq.queue_declare( queue=self.test_queue_name, durable=True, exclusive=False, auto_delete=False, passive=True) # There must be 2 messages in the queue, the heartbeat and the # processed data self.assertEqual(2, res.method.message_count) # Check that the message received is actually the processed data _, _, body = self.test_monitor.rabbitmq.basic_get( self.test_queue_name) self.assertEqual(expected_output_data, json.loads(body)) # Check that the message received is actually the HB _, _, body = self.test_monitor.rabbitmq.basic_get( self.test_queue_name) self.assertEqual(expected_output_hb, json.loads(body)) except Exception as e: self.fail("Test failed: {}".format(e))
def test_catches_bad_status_line(self): error = ProtocolError(None) with pytest.raises(ConnectionClosedError): self.make_request_with_error(error)