def __init__(self): self.__logger = Logger() self._request_exceptions = [type(item) for item in [requests.ConnectionError(), requests.HTTPError(), requests.TooManyRedirects(), requests.Timeout(), requests.TooManyRedirects(), requests.RequestException(), requests.ConnectTimeout(), requests.ReadTimeout()]] self._system_errors = [type(item) for item in [KeyError(), AttributeError(), IndexError(), ZeroDivisionError(), SystemError(), ValueError(), AssertionError()]] self._file_errors = [type(item) for item in [FileExistsError(), FileNotFoundError()]] self._database_errors = [type(item) for item in [sqlite3.Error(), sqlite3.DataError(), sqlite3.ProgrammingError(), sqlite3.DatabaseError(), sqlite3.NotSupportedError(), sqlite3.IntegrityError(), sqlite3.InterfaceError(), sqlite3.InternalError(), sqlite3.OperationalError()]] self._speech_recognizer_errors = [type(item) for item in [sr.RequestError(), sr.UnknownValueError(), sr.WaitTimeoutError(), sr.RequestError()]] self.__logger.info('ExceptionsHandler was successfully initialized.', __name__)
async def receive_event(self, timeout): event = self.state.next_event() while type(event) is h11.NEED_DATA: try: data = await asyncio.wait_for(self.reader.read(2048), timeout) except asyncio.TimeoutError: raise requests.ReadTimeout() self.state.receive_data(data) event = self.state.next_event() return event
from apprise.plugins import SCHEMA_MAP # Disable logging for a cleaner testing output import logging logging.disable(logging.CRITICAL) # Some exception handling we'll use REQUEST_EXCEPTIONS = ( requests.ConnectionError( 0, 'requests.ConnectionError() not handled'), requests.RequestException( 0, 'requests.RequestException() not handled'), requests.HTTPError( 0, 'requests.HTTPError() not handled'), requests.ReadTimeout( 0, 'requests.ReadTimeout() not handled'), requests.TooManyRedirects( 0, 'requests.TooManyRedirects() not handled'), ) @mock.patch('requests.get') @mock.patch('requests.post') def test_config_http(mock_post, mock_get): """ API: ConfigHTTP() object """ # Define our good:// url class GoodNotification(NotifyBase):
def _send(self, request, *args, **kwargs): response = None try: response = super().send(request, *args, **kwargs) except requests.ConnectionError as exc: retries_exhausted = False error = exc.args[0] if isinstance(error, urllib3.exceptions.MaxRetryError): # we need the original urllib3 exception base error error = error.reason try: request._retry = request._retry.increment( request.method, request.url, error=error, ) except urllib3.exceptions.MaxRetryError: retries_exhausted = True # we catch and flag to reraise the original exception. # This avoids confusing the already lengthy exception chain except Exception as urllib3_exc: if isinstance(urllib3_exc, error.__class__): # underlying urllib3 reraised, no more retries retries_exhausted = True else: raise if retries_exhausted: # An interesting bit of py2/3 differences here. We want to # reraise the original ConnectionError, with context unaltered. # A naked raise does exactly this in py3, it reraises the # exception that caused the current except: block. But in py2, # naked raise would raise the *last* error, MaxRetryError, # which we do not want. So we explicitly reraise the original # ConnectionError. In py3, this would not be desirable, as the # exception context would be confused, by py2 does not do # chained exceptions, so, erm, yay? if future.utils.PY3: raise # raises the original ConnectionError else: raise exc # we are going to retry, so backoff as appropriate request._retry.sleep() else: # We got a response, but perhaps we need to retry # # Note: urllib3 retry logic handles redirects here, but we do not # as requests explicitly does not use it (it calls urlopen with # redirect=False) # has_retry_after = 'Retry-After' in response.headers if request._retry.is_retry(request.method, response.status_code, has_retry_after): # response allows for retry, but perhaps we are exhausted try: request._retry = request._retry.increment( request.method, request.url, response=response.raw, ) except urllib3.exceptions.MaxRetryError as e: if request._retry.raise_on_status: # manually wrap it in a requests exception raise requests.exceptions.RetryError(e, request=request) return response request._retry.sleep(response.raw) else: return response # let's retry, with load balancing and adjusted timeouts self.select_backend(request) (connect, read) = self.calculate_timeouts(request, kwargs['timeout']) if read <= 0: raise requests.ReadTimeout(request=request, response=response) kwargs['timeout'] = (connect, read) return self._send(request, *args, **kwargs)
async def send( self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None ) -> requests.Response: urlparts = urlparse(request.url) hostname = urlparts.hostname port = urlparts.port if port is None: port = {"http": 80, "https": 443}[urlparts.scheme] target = urlparts.path if urlparts.query: target += "?" + urlparts.query headers = [("host", urlparts.netloc)] + list(request.headers.items()) conn_kwargs = {"ssl": no_verify()} if urlparts.scheme == "https" else {} if isinstance(timeout, tuple): connect_timeout, read_timeout = timeout else: connect_timeout = timeout read_timeout = timeout try: reader, writer = await asyncio.wait_for( asyncio.open_connection(hostname, port, **conn_kwargs), connect_timeout ) except asyncio.TimeoutError: raise requests.ConnectTimeout() conn = h11.Connection(our_role=h11.CLIENT) message = h11.Request(method=request.method, target=target, headers=headers) data = conn.send(message) writer.write(data) if request.body: message = h11.Data(data=request.body.encode("utf-8")) data = conn.send(message) writer.write(data) message = h11.EndOfMessage() data = conn.send(message) writer.write(data) status_code = 0 headers = [] reason = b"" buffer = io.BytesIO() while True: event = conn.next_event() event_type = type(event) if event_type is h11.NEED_DATA: try: data = await asyncio.wait_for(reader.read(2048), read_timeout) except asyncio.TimeoutError: raise requests.ReadTimeout() conn.receive_data(data) elif event_type is h11.Response: status_code = event.status_code headers = [ (key.decode(), value.decode()) for key, value in event.headers ] reason = event.reason elif event_type is h11.Data: buffer.write(event.data) elif event_type is h11.EndOfMessage: buffer.seek(0) break writer.close() if hasattr(writer, "wait_closed"): await writer.wait_closed() resp = urllib3.HTTPResponse( body=buffer, headers=headers, status=status_code, reason=reason, preload_content=False, ) return self.build_response(request, resp)
def callback(resp): raise requests.ReadTimeout()
class TestCanvasAPIError: @pytest.mark.parametrize( "status,expected_status,expected_exception_class,expected_exception_string", [ # A 401 Unauthorized response from Canvas, because our access token was # expired or deleted. ( 401, "401 Unauthorized", CanvasAPIAccessTokenError, "401 Client Error: Unauthorized for url: https://example.com/", ), # A 400 Bad Request response from Canvas, because we sent an invalid # parameter or something. ( 400, "400 Bad Request", CanvasAPIServerError, "400 Client Error: Bad Request for url: https://example.com/", ), # An unexpected error response from Canvas. ( 500, "500 Internal Server Error", CanvasAPIServerError, "500 Server Error: Internal Server Error for url: https://example.com/", ), ], ) def test_it_raises_the_right_subclass_for_different_Canvas_responses( self, status, expected_status, expected_exception_class, expected_exception_string, ): cause = self._requests_exception(status=status) raised_exception = self.assert_raises(cause, expected_exception_class) assert raised_exception.__cause__ == cause assert raised_exception.response == cause.response assert raised_exception.details == { "exception": expected_exception_string, "validation_errors": None, "response": {"status": expected_status, "body": '{"foo": "bar"}'}, } @pytest.mark.parametrize( "cause,expected_exception_string", [ (requests.RequestException(), "RequestException()"), (requests.ConnectionError(), "ConnectionError()"), (requests.TooManyRedirects(), "TooManyRedirects()"), (requests.ConnectTimeout(), "ConnectTimeout()"), (requests.ReadTimeout(), "ReadTimeout()"), ], ) def test_it_raises_CanvasAPIServerError_for_all_other_requests_errors( self, cause, expected_exception_string ): raised_exception = self.assert_raises(cause, CanvasAPIServerError) assert raised_exception.__cause__ == cause # For these kinds of errors no response (either successful or # unsuccessful) was ever received from Canvas (for example: the network # request timed out) so there's nothing to set as the response # property. assert raised_exception.response is None assert raised_exception.details == { "exception": expected_exception_string, "response": None, "validation_errors": None, } def test_it_raises_CanvasAPIServerError_for_a_successful_but_invalid_response( self, canvas_api_invalid_response ): cause = ValidationError("The response was invalid.") cause.response = canvas_api_invalid_response cause.response.body = "x" * 1000 # pylint:disable=no-member raised_exception = self.assert_raises(cause, CanvasAPIServerError) assert raised_exception.__cause__ == cause assert raised_exception.response == canvas_api_invalid_response assert raised_exception.details == { "exception": "Unable to process the contained instructions", "response": {"body": "Invalid", "status": "200 OK"}, "validation_errors": "The response was invalid.", } def test_it_raises_truncates_the_body_if_it_is_very_long( self, canvas_api_long_response ): # Make the response very long... cause = CanvasAPIServerError("The response was invalid.") cause.response = canvas_api_long_response raised_exception = self.assert_raises(cause, CanvasAPIServerError) body = raised_exception.details["response"]["body"] assert len(body) == 153 assert body.endswith("...") def assert_raises(self, cause, expected_exception_class): with pytest.raises( expected_exception_class, match="Calling the Canvas API failed" ) as exc_info: CanvasAPIError.raise_from(cause) return exc_info.value @pytest.fixture def canvas_api_long_response(self): """Return a successful (200 OK) response with a long body.""" httpretty.register_uri( httpretty.GET, "https://example.com", priority=1, status=200, body="x" * 2000, ) return requests.get("https://example.com") @pytest.fixture def canvas_api_invalid_response(self): """Return a successful (200 OK) response with an invalid body.""" httpretty.register_uri( httpretty.GET, "https://example.com", priority=1, status=200, body="Invalid" ) return requests.get("https://example.com") @staticmethod def _requests_exception(**kwargs): # pylint:disable=inconsistent-return-statements httpretty.register_uri( httpretty.GET, "https://example.com", priority=1, body=json.dumps({"foo": "bar"}), **kwargs ) response = requests.get("https://example.com") try: response.raise_for_status() except requests.RequestException as err: return err
class TestHTTPService: @pytest.mark.parametrize("method", ["GET", "PUT", "POST", "PATCH", "DELETE"]) def test_it_sends_the_request_and_returns_the_response(self, svc, method, url): httpretty.register_uri(method, url, body="test_response") response = svc.request(method, url) assert response.status_code == 200 assert response.text == "test_response" assert httpretty.last_request() == Any.object.with_attrs( {"url": url, "method": method} ) @pytest.mark.parametrize("method", ["GET", "PUT", "POST", "PATCH", "DELETE"]) def test_convenience_methods(self, svc, url, method): httpretty.register_uri(method, url, body="test_response") getattr(svc, method.lower())(url) assert httpretty.last_request() == Any.object.with_attrs( {"url": url, "method": method} ) def test_it_sends_request_params(self, svc, url): svc.request("GET", url, params={"test_param": "test_value"}) assert httpretty.last_request() == Any.object.with_attrs( {"url": f"{url}?test_param=test_value"} ) def test_it_sends_request_data(self, svc, url): svc.request("GET", url, data={"test_key": "test_value"}) assert httpretty.last_request() == Any.object.with_attrs( {"body": b"test_key=test_value"} ) def test_it_sends_request_json(self, svc, url): svc.request("GET", url, json={"test_key": "test_value"}) assert httpretty.last_request() == Any.object.with_attrs( {"body": b'{"test_key": "test_value"}'} ) def test_it_sends_request_headers(self, svc, url): svc.request("GET", url, headers={"HEADER_KEY": "HEADER_VALUE"}) assert httpretty.last_request().headers["HEADER_KEY"] == "HEADER_VALUE" def test_it_sends_request_auth(self, svc, url): svc.request("GET", url, auth=("user", "pass")) assert httpretty.last_request().headers["Authorization"] == "Basic dXNlcjpwYXNz" def test_it_uses_custom_timeouts(self, session): svc = HTTPService(session) svc.request("GET", "https://example.com", timeout=3) assert session.request.call_args[1]["timeout"] == 3 def test_it_passes_arbitrary_kwargs_to_requests(self, svc): session = Mock() svc = HTTPService(session) svc.request("GET", "https://example.com", foo="bar") assert session.request.call_args[1]["foo"] == "bar" @pytest.mark.parametrize( "exception", [ requests.ConnectionError(), requests.HTTPError(), requests.ReadTimeout(), requests.TooManyRedirects(), ], ) def test_it_raises_if_sending_the_request_fails(self, exception, session): session.request.side_effect = exception svc = HTTPService(session) with pytest.raises(UpstreamServiceError) as exc_info: svc.request("GET", "https://example.com") assert exc_info.value.response is None assert exc_info.value.__cause__ == exception @pytest.mark.parametrize("status", [400, 401, 403, 404, 500]) def test_it_raises_if_the_response_is_an_error(self, svc, url, status): httpretty.register_uri("GET", url, status=status) with pytest.raises(UnhandledUpstreamException) as exc_info: svc.request("GET", url) assert isinstance(exc_info.value.__cause__, requests.HTTPError) assert exc_info.value.response == Any.instance_of(requests.Response).with_attrs( {"status_code": status} ) @pytest.mark.parametrize("status", [400, 401, 403, 404, 500]) def test_it_doesnt_raise_if_the_response_is_an_error_when_disabled( self, svc, url, status ): httpretty.register_uri("GET", url, status=status) response = svc.request("GET", url, raise_for_status=False) assert response == Any.instance_of(requests.Response).with_attrs( {"status_code": status} ) @pytest.mark.parametrize("request_exception,expected_exception", EXCEPTION_MAP) def test_request_with_error_translator_defaults( self, error_translator, session, request_exception, expected_exception, url, ): svc = HTTPService(session, error_translator) session.request.side_effect = request_exception with pytest.raises(expected_exception): svc.request("GET", url) @pytest.mark.parametrize("generator_exception,expected_exception", EXCEPTION_MAP) def test_stream_with_error_translator_defaults( self, error_translator, session, generator_exception, expected_exception, url, ): svc = HTTPService(session, error_translator) def explode(): yield b"response-part-1" raise generator_exception session.request.return_value.iter_content.return_value = explode() with pytest.raises(expected_exception): list(svc.stream("GET", url)) def test_with_custom_exceptions(self, error_translator, session, url): svc = HTTPService(session, error_translator) session.request.side_effect = FileNotFoundError with pytest.raises(NotADirectoryError): svc.request("GET", url) def test_request_with_regular_exceptions(self, error_translator, session, url): svc = HTTPService(session, error_translator) session.request.side_effect = ValueError with pytest.raises(ValueError): svc.request("GET", url) def test_stream_with_regular_exceptions(self, error_translator, session, url): svc = HTTPService(session, error_translator) session.request.return_value.iter_content.side_effect = ValueError with pytest.raises(ValueError): list(svc.stream("GET", url)) @pytest.mark.parametrize( "input_bytes,output", ( ([b"longer_than_chunk_size"], [b"longer_than_chunk_size"]), ([b"chunksize"], [b"chunksize"]), ([b"chunk", b"size"], [b"chunksize"]), ([b"too", b"smol"], [b"toosmol"]), ), ) def test_stream_bytes(self, svc, response, input_bytes, output): # pylint:disable=protected-access response.iter_content.return_value = input_bytes results = svc._stream_bytes(response, min_chunk_size=9) assert list(results) == output response.iter_content.assert_called_once_with(chunk_size=9) @pytest.fixture def url(self): """Return the URL that we'll be sending test requests to.""" return "https://example.com/example" @pytest.fixture(autouse=True) def test_response(self, url): httpretty.register_uri( "GET", url, body='{"test_response_key": "test_response_value"}', priority=-1 ) @pytest.fixture def session(self): return create_autospec(requests.Session, instance=True, spec_set=True) @pytest.fixture def error_translator(self, session): def error_mapper_callable(err): if isinstance(err, FileNotFoundError): return NotADirectoryError("Translated") return None return error_mapper_callable @pytest.fixture def svc(self): return HTTPService() @pytest.fixture def response(self): return create_autospec(Response, instance=True, spec_set=True)
class AppriseURLTester(object): # Some exception handling we'll use req_exceptions = ( requests.ConnectionError(0, 'requests.ConnectionError() not handled'), requests.RequestException(0, 'requests.RequestException() not handled'), requests.HTTPError(0, 'requests.HTTPError() not handled'), requests.ReadTimeout(0, 'requests.ReadTimeout() not handled'), requests.TooManyRedirects(0, 'requests.TooManyRedirects() not handled'), ) # Attachment Testing Directory __test_var_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'var') # Our URLs we'll test against __tests = [] # Define how many characters exist per line row = 80 # Some variables we use to control the data we work with body_len = 1024 title_len = 1024 def __init__(self, tests=None, *args, **kwargs): """ Our initialization """ # Create a large body and title with random data self.body = ''.join( choice(str_alpha + str_num + ' ') for _ in range(self.body_len)) self.body = '\r\n'.join([ self.body[i:i + self.row] for i in range(0, len(self.body), self.row) ]) # Create our title using random data self.title = ''.join( choice(str_alpha + str_num) for _ in range(self.title_len)) if tests: self.__tests = tests def add(self, url, meta): """ Adds a test suite to our object """ self.__tests.append({ 'url': url, 'meta': meta, }) def run_all(self): """ Run all of our tests """ # iterate over our dictionary and test it out for (url, meta) in self.__tests: self.run(url, meta) @mock.patch('requests.get') @mock.patch('requests.post') def run(self, url, meta, mock_post, mock_get): """ Run a specific test """ # Disable Throttling to speed testing plugins.NotifyBase.request_rate_per_sec = 0 # Our expected instance instance = meta.get('instance', None) # Our expected server objects _self = meta.get('self', None) # Our expected Query response (True, False, or exception type) response = meta.get('response', True) # Our expected privacy url # Don't set this if don't need to check it's value privacy_url = meta.get('privacy_url') # Our regular expression url_matches = meta.get('url_matches') # Allow us to force the server response code to be something other then # the defaults requests_response_code = meta.get( 'requests_response_code', requests.codes.ok if response else requests.codes.not_found, ) # Allow us to force the server response text to be something other then # the defaults requests_response_text = meta.get('requests_response_text') if not isinstance(requests_response_text, six.string_types): # Convert to string requests_response_text = dumps(requests_response_text) # Whether or not we should include an image with our request; unless # otherwise specified, we assume that images are to be included include_image = meta.get('include_image', True) if include_image: # a default asset asset = AppriseAsset() else: # Disable images asset = AppriseAsset(image_path_mask=False, image_url_mask=False) asset.image_url_logo = None test_requests_exceptions = meta.get('test_requests_exceptions', False) # Mock our request object robj = mock.Mock() robj.content = u'' mock_get.return_value = robj mock_post.return_value = robj if test_requests_exceptions is False: # Handle our default response mock_post.return_value.status_code = requests_response_code mock_get.return_value.status_code = requests_response_code # Handle our default text response mock_get.return_value.content = requests_response_text mock_post.return_value.content = requests_response_text mock_get.return_value.text = requests_response_text mock_post.return_value.text = requests_response_text # Ensure there is no side effect set mock_post.side_effect = None mock_get.side_effect = None else: # Handle exception testing; first we turn the boolean flag # into a list of exceptions test_requests_exceptions = self.req_exceptions try: # We can now instantiate our object: obj = Apprise.instantiate(url, asset=asset, suppress_exceptions=False) except Exception as e: # Handle our exception if instance is None: print('%s %s' % (url, str(e))) raise e if not isinstance(e, instance): print('%s %s' % (url, str(e))) raise e # We're okay if we get here return if obj is None: if instance is not None: # We're done (assuming this is what we were # expecting) print("{} didn't instantiate itself " "(we expected it to be a {})".format(url, instance)) assert False # We're done because we got the results we expected return if instance is None: # Expected None but didn't get it print('%s instantiated %s (but expected None)' % (url, str(obj))) assert False if not isinstance(obj, instance): print('%s instantiated %s (but expected %s)' % (url, type(instance), str(obj))) assert False if isinstance(obj, plugins.NotifyBase): # Ensure we are not performing any type of thorttling obj.request_rate_per_sec = 0 # We loaded okay; now lets make sure we can reverse # this url assert isinstance(obj.url(), six.string_types) is True # Test url() with privacy=True assert isinstance(obj.url(privacy=True), six.string_types) is True # Some Simple Invalid Instance Testing assert instance.parse_url(None) is None assert instance.parse_url(object) is None assert instance.parse_url(42) is None if privacy_url: # Assess that our privacy url is as expected if not obj.url(privacy=True).startswith(privacy_url): raise AssertionError( "Privacy URL: '{}' != expected '{}'".format( obj.url(privacy=True)[:len(privacy_url)], privacy_url)) if url_matches: # Assess that our URL matches a set regex assert re.search(url_matches, obj.url()) # Instantiate the exact same object again using the URL # from the one that was already created properly obj_cmp = Apprise.instantiate(obj.url()) # Our object should be the same instance as what we had # originally expected above. if not isinstance(obj_cmp, plugins.NotifyBase): # Assert messages are hard to trace back with the # way these tests work. Just printing before # throwing our assertion failure makes things # easier to debug later on print('TEST FAIL: {} regenerated as {}'.format(url, obj.url())) assert False # Tidy our object del obj_cmp if _self: # Iterate over our expected entries inside of our # object for key, val in self.items(): # Test that our object has the desired key assert hasattr(key, obj) is True assert getattr(key, obj) == val try: self.__notify(url, obj, meta, asset) except AssertionError: # Don't mess with these entries print('%s AssertionError' % url) raise # Tidy our object and allow any possible defined deconstructors to # be executed. del obj @mock.patch('requests.get') @mock.patch('requests.post') @mock.patch('requests.head') @mock.patch('requests.put') @mock.patch('requests.delete') def __notify(self, url, obj, meta, asset, mock_del, mock_put, mock_head, mock_post, mock_get): """ Perform notification testing against object specified """ # # Prepare our options # # Allow notification type override, otherwise default to INFO notify_type = meta.get('notify_type', NotifyType.INFO) # Whether or not we're testing exceptions or not test_requests_exceptions = meta.get('test_requests_exceptions', False) # Our expected Query response (True, False, or exception type) response = meta.get('response', True) # Our expected Notify response (True or False) notify_response = meta.get('notify_response', response) # Our expected Notify Attachment response (True or False) attach_response = meta.get('attach_response', notify_response) # Test attachments # Don't set this if don't need to check it's value check_attachments = meta.get('check_attachments', True) # Allow us to force the server response code to be something other then # the defaults requests_response_code = meta.get( 'requests_response_code', requests.codes.ok if response else requests.codes.not_found, ) # Allow us to force the server response text to be something other then # the defaults requests_response_text = meta.get('requests_response_text') if not isinstance(requests_response_text, six.string_types): # Convert to string requests_response_text = dumps(requests_response_text) # A request robj = mock.Mock() robj.content = u'' mock_get.return_value = robj mock_post.return_value = robj mock_head.return_value = robj mock_del.return_value = robj mock_put.return_value = robj if test_requests_exceptions is False: # Handle our default response mock_put.return_value.status_code = requests_response_code mock_head.return_value.status_code = requests_response_code mock_del.return_value.status_code = requests_response_code mock_post.return_value.status_code = requests_response_code mock_get.return_value.status_code = requests_response_code # Handle our default text response mock_get.return_value.content = requests_response_text mock_post.return_value.content = requests_response_text mock_del.return_value.content = requests_response_text mock_put.return_value.content = requests_response_text mock_head.return_value.content = requests_response_text mock_get.return_value.text = requests_response_text mock_post.return_value.text = requests_response_text mock_put.return_value.text = requests_response_text mock_del.return_value.text = requests_response_text mock_head.return_value.text = requests_response_text # Ensure there is no side effect set mock_post.side_effect = None mock_del.side_effect = None mock_put.side_effect = None mock_head.side_effect = None mock_get.side_effect = None else: # Handle exception testing; first we turn the boolean flag # into a list of exceptions test_requests_exceptions = self.req_exceptions try: if test_requests_exceptions is False: # Disable throttling obj.request_rate_per_sec = 0 # check that we're as expected assert obj.notify(body=self.body, title=self.title, notify_type=notify_type) == notify_response # check that this doesn't change using different overflow # methods assert obj.notify( body=self.body, title=self.title, notify_type=notify_type, overflow=OverflowMode.UPSTREAM) == notify_response assert obj.notify( body=self.body, title=self.title, notify_type=notify_type, overflow=OverflowMode.TRUNCATE) == notify_response assert obj.notify( body=self.body, title=self.title, notify_type=notify_type, overflow=OverflowMode.SPLIT) == notify_response # # Handle varations of the Asset Object missing fields # # First make a backup app_id = asset.app_id app_desc = asset.app_desc # now clear records asset.app_id = None asset.app_desc = None # Notify should still work assert obj.notify(body=self.body, title=self.title, notify_type=notify_type) == notify_response # App ID only asset.app_id = app_id asset.app_desc = None # Notify should still work assert obj.notify(body=self.body, title=self.title, notify_type=notify_type) == notify_response # App Desc only asset.app_id = None asset.app_desc = app_desc # Notify should still work assert obj.notify(body=self.body, title=self.title, notify_type=notify_type) == notify_response # Restore asset.app_id = app_id asset.app_desc = app_desc if check_attachments: # Test single attachment support; even if the service # doesn't support attachments, it should still # gracefully ignore the data attach = os.path.join(self.__test_var_dir, 'apprise-test.gif') assert obj.notify(body=self.body, title=self.title, notify_type=notify_type, attach=attach) == attach_response # Same results should apply to a list of attachments attach = AppriseAttachment(( os.path.join(self.__test_var_dir, 'apprise-test.gif'), os.path.join(self.__test_var_dir, 'apprise-test.png'), os.path.join(self.__test_var_dir, 'apprise-test.jpeg'), )) assert obj.notify(body=self.body, title=self.title, notify_type=notify_type, attach=attach) == attach_response else: # Disable throttling obj.request_rate_per_sec = 0 for _exception in self.req_exceptions: mock_post.side_effect = _exception mock_head.side_effect = _exception mock_del.side_effect = _exception mock_put.side_effect = _exception mock_get.side_effect = _exception try: assert obj.notify(body=self.body, title=self.title, notify_type=NotifyType.INFO) is False except AssertionError: # Don't mess with these entries raise except Exception: # We can't handle this exception type raise except AssertionError: # Don't mess with these entries raise except Exception as e: # Check that we were expecting this exception to happen try: if not isinstance(e, response): raise e except TypeError: print('%s Unhandled response %s' % (url, type(e))) raise e # # Do the test again but without a title defined # try: if test_requests_exceptions is False: # check that we're as expected assert obj.notify(body='body', notify_type=notify_type) \ == notify_response else: for _exception in self.req_exceptions: mock_post.side_effect = _exception mock_del.side_effect = _exception mock_put.side_effect = _exception mock_head.side_effect = _exception mock_get.side_effect = _exception try: assert obj.notify(body=self.body, notify_type=NotifyType.INFO) is False except AssertionError: # Don't mess with these entries raise except Exception: # We can't handle this exception type raise except AssertionError: # Don't mess with these entries raise except Exception as e: # Check that we were expecting this exception to happen if not isinstance(e, response): raise e return True
def raise_retry(*args, **kwargs): raise requests.ReadTimeout()