improved test coverage

This commit is contained in:
Chris Caron 2021-01-23 17:35:04 -05:00
parent b69ed1dfa9
commit c7f015bf7c
8 changed files with 179 additions and 124 deletions

View File

@ -636,11 +636,11 @@ class NotifyEmail(NotifyBase):
except TypeError: except TypeError:
# Python v2.x Support (no charset keyword) # Python v2.x Support (no charset keyword)
# Format our cc addresses to support the Name field # Format our cc addresses to support the Name field
cc = [formataddr( cc = [formataddr( # pragma: no branch
(self.names.get(addr, False), addr)) for addr in cc] (self.names.get(addr, False), addr)) for addr in cc]
# Format our bcc addresses to support the Name field # Format our bcc addresses to support the Name field
bcc = [formataddr( bcc = [formataddr( # pragma: no branch
(self.names.get(addr, False), addr)) for addr in bcc] (self.names.get(addr, False), addr)) for addr in bcc]
self.logger.debug( self.logger.debug(

View File

@ -485,7 +485,7 @@ class NotifyMailgun(NotifyBase):
except TypeError: except TypeError:
# Python v2.x Support (no charset keyword) # Python v2.x Support (no charset keyword)
# Format our cc addresses to support the Name field # Format our cc addresses to support the Name field
payload['cc'] = ','.join([formataddr( payload['cc'] = ','.join([formataddr( # pragma: no branch
(self.names.get(addr, False), addr)) (self.names.get(addr, False), addr))
for addr in cc]) for addr in cc])

View File

@ -367,8 +367,9 @@ class NotifyPushBullet(NotifyBase):
except (OSError, IOError) as e: except (OSError, IOError) as e:
self.logger.warning( self.logger.warning(
'An I/O error occurred while reading {}.'.format( 'An I/O error occurred while handling {}.'.format(
payload.name if payload else 'attachment')) payload.name if isinstance(payload, AttachBase)
else payload))
self.logger.debug('I/O Exception: %s' % str(e)) self.logger.debug('I/O Exception: %s' % str(e))
return False, response return False, response

View File

@ -30,8 +30,6 @@ import six
import pytest import pytest
import requests import requests
import mock import mock
from os import chmod
from os import getuid
from os.path import dirname from os.path import dirname
from os.path import join from os.path import join
@ -846,48 +844,21 @@ def test_apprise_asset(tmpdir):
NotifyImageSize.XY_256, NotifyImageSize.XY_256,
must_exist=True) is not None must_exist=True) is not None
# If we make the file un-readable however, we won't be able to read it # Test case where we can't access the image file
# This test is just showing that we won't throw an exception if sys.version_info.major <= 2:
if getuid() == 0: # Python v2.x
# Root always over-rides 0x000 permission settings making the below with mock.patch('__builtin__.open', side_effect=OSError()):
# tests futile
pytest.skip('The Root user can not run file permission tests.')
chmod(dirname(sub.strpath), 0o000)
assert a.image_raw(NotifyType.INFO, NotifyImageSize.XY_256) is None assert a.image_raw(NotifyType.INFO, NotifyImageSize.XY_256) is None
# Our path doesn't exist anymore using this logic
assert a.image_path(
NotifyType.INFO,
NotifyImageSize.XY_256,
must_exist=True) is None
# Return our permission so we don't have any problems with our cleanup
chmod(dirname(sub.strpath), 0o700)
# Our content is retrivable again # Our content is retrivable again
assert a.image_raw(NotifyType.INFO, NotifyImageSize.XY_256) is not None assert a.image_raw(NotifyType.INFO, NotifyImageSize.XY_256) is not None
else:
# our file path is accessible again too # Python >= v3.x
assert a.image_path( with mock.patch('builtins.open', side_effect=OSError()):
NotifyType.INFO,
NotifyImageSize.XY_256,
must_exist=True) is not None
# We do the same test, but set the permission on the file
chmod(a.image_path(NotifyType.INFO, NotifyImageSize.XY_256), 0o000)
# our path will still exist in this case
assert a.image_path(
NotifyType.INFO,
NotifyImageSize.XY_256,
must_exist=True) is not None
# but we will not be able to open it
assert a.image_raw(NotifyType.INFO, NotifyImageSize.XY_256) is None assert a.image_raw(NotifyType.INFO, NotifyImageSize.XY_256) is None
# Restore our permissions # Our content is retrivable again
chmod(a.image_path(NotifyType.INFO, NotifyImageSize.XY_256), 0o640) assert a.image_raw(NotifyType.INFO, NotifyImageSize.XY_256) is not None
# Disable all image references # Disable all image references
a = AppriseAsset(image_path_mask=False, image_url_mask=False) a = AppriseAsset(image_path_mask=False, image_url_mask=False)

View File

@ -251,9 +251,16 @@ def test_discord_attachments(mock_post):
webhook_id = 'C' * 24 webhook_id = 'C' * 24
webhook_token = 'D' * 64 webhook_token = 'D' * 64
# Prepare a good response
response = mock.Mock()
response.status_code = requests.codes.ok
# Prepare a bad response
bad_response = mock.Mock()
bad_response.status_code = requests.codes.internal_server_error
# Prepare Mock return object # Prepare Mock return object
mock_post.return_value = requests.Request() mock_post.return_value = response
mock_post.return_value.status_code = requests.codes.ok
# Test our markdown # Test our markdown
obj = Apprise.instantiate( obj = Apprise.instantiate(
@ -266,6 +273,15 @@ def test_discord_attachments(mock_post):
body='body', title='title', notify_type=NotifyType.INFO, body='body', title='title', notify_type=NotifyType.INFO,
attach=attach) is True attach=attach) is True
# Test our call count
assert mock_post.call_count == 2
assert mock_post.call_args_list[0][0][0] == \
'https://discord.com/api/webhooks/{}/{}'.format(
webhook_id, webhook_token)
assert mock_post.call_args_list[1][0][0] == \
'https://discord.com/api/webhooks/{}/{}'.format(
webhook_id, webhook_token)
# An invalid attachment will cause a failure # An invalid attachment will cause a failure
path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg') path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg')
attach = AppriseAttachment(path) attach = AppriseAttachment(path)
@ -273,15 +289,28 @@ def test_discord_attachments(mock_post):
body='body', title='title', notify_type=NotifyType.INFO, body='body', title='title', notify_type=NotifyType.INFO,
attach=path) is False attach=path) is False
# Throw an exception on the second call to requests.post()
mock_post.return_value = None
response = mock.Mock()
response.status_code = requests.codes.ok
mock_post.side_effect = [response, OSError()]
# update our attachment to be valid # update our attachment to be valid
attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif')) attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
# Test our markdown
mock_post.return_value = None
# Throw an exception on the first call to requests.post()
for side_effect in (requests.RequestException(), OSError(), bad_response):
mock_post.side_effect = [side_effect]
# We'll fail now because of our error handling
assert obj.send(body="test", attach=attach) is False
# Throw an exception on the second call to requests.post()
for side_effect in (requests.RequestException(), OSError(), bad_response):
mock_post.side_effect = [response, side_effect]
# We'll fail now because of our error handling
assert obj.send(body="test", attach=attach) is False
# handle a bad response
bad_response = mock.Mock()
bad_response.status_code = requests.codes.internal_server_error
mock_post.side_effect = [response, bad_response]
# We'll fail now because of an internal exception # We'll fail now because of an internal exception
assert obj.send(body="test", attach=attach) is False assert obj.send(body="test", attach=attach) is False

View File

@ -72,6 +72,23 @@ def test_pushbullet_attachments(mock_post):
# Send a good attachment # Send a good attachment
assert obj.notify(body="test", attach=attach) is True assert obj.notify(body="test", attach=attach) is True
# Test our call count
assert mock_post.call_count == 4
# Image Prep
assert mock_post.call_args_list[0][0][0] == \
'https://api.pushbullet.com/v2/upload-request'
assert mock_post.call_args_list[1][0][0] == \
'https://upload.pushbullet.com/abcd123'
# Message
assert mock_post.call_args_list[2][0][0] == \
'https://api.pushbullet.com/v2/pushes'
# Image Send
assert mock_post.call_args_list[3][0][0] == \
'https://api.pushbullet.com/v2/pushes'
# Reset our mock object
mock_post.reset_mock()
# Add another attachment so we drop into the area of the PushBullet code # Add another attachment so we drop into the area of the PushBullet code
# that sends remaining attachments (if more detected) # that sends remaining attachments (if more detected)
attach.add(os.path.join(TEST_VAR_DIR, 'apprise-test.gif')) attach.add(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
@ -79,85 +96,86 @@ def test_pushbullet_attachments(mock_post):
# Send our attachments # Send our attachments
assert obj.notify(body="test", attach=attach) is True assert obj.notify(body="test", attach=attach) is True
# Test our call count
assert mock_post.call_count == 7
# Image Prep
assert mock_post.call_args_list[0][0][0] == \
'https://api.pushbullet.com/v2/upload-request'
assert mock_post.call_args_list[1][0][0] == \
'https://upload.pushbullet.com/abcd123'
assert mock_post.call_args_list[2][0][0] == \
'https://api.pushbullet.com/v2/upload-request'
assert mock_post.call_args_list[3][0][0] == \
'https://upload.pushbullet.com/abcd123'
# Message
assert mock_post.call_args_list[4][0][0] == \
'https://api.pushbullet.com/v2/pushes'
# Image Send
assert mock_post.call_args_list[5][0][0] == \
'https://api.pushbullet.com/v2/pushes'
assert mock_post.call_args_list[6][0][0] == \
'https://api.pushbullet.com/v2/pushes'
# Reset our mock object
mock_post.reset_mock()
# An invalid attachment will cause a failure # An invalid attachment will cause a failure
path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg') path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg')
attach = AppriseAttachment(path) attach = AppriseAttachment(path)
assert obj.notify(body="test", attach=attach) is False assert obj.notify(body="test", attach=attach) is False
# Throw an exception on the first call to requests.post() # Test our call count
mock_post.return_value = None assert mock_post.call_count == 0
mock_post.side_effect = requests.RequestException()
# We'll fail now because of an internal exception # prepare our attachment
assert obj.send(body="test", attach=attach) is False attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
# Throw an exception on the second call to requests.post()
mock_post.side_effect = [response, OSError()]
# We'll fail now because of an internal exception
assert obj.send(body="test", attach=attach) is False
# Throw an exception on the third call to requests.post()
mock_post.side_effect = [
response, response, requests.RequestException()]
# We'll fail now because of an internal exception
assert obj.send(body="test", attach=attach) is False
# Throw an exception on the forth call to requests.post()
mock_post.side_effect = [
response, response, response, requests.RequestException()]
# We'll fail now because of an internal exception
assert obj.send(body="test", attach=attach) is False
# Test case where we don't get a valid response back
response.content = '}'
mock_post.side_effect = response
# We'll fail because of an invalid json object
assert obj.send(body="test", attach=attach) is False
#
# Test bad responses
#
# Prepare a bad response # Prepare a bad response
response.content = dumps({ bad_response = mock.Mock()
bad_response.content = dumps({
"file_name": "cat.jpg", "file_name": "cat.jpg",
"file_type": "image/jpeg", "file_type": "image/jpeg",
"file_url": "https://dl.pushb.com/abc/cat.jpg", "file_url": "https://dl.pushb.com/abc/cat.jpg",
"upload_url": "https://upload.pushbullet.com/abcd123", "upload_url": "https://upload.pushbullet.com/abcd123",
}) })
bad_response = mock.Mock() bad_response.status_code = requests.codes.internal_server_error
bad_response.content = response.content
bad_response.status_code = 400 # Prepare a bad response
bad_json_response = mock.Mock()
bad_json_response.content = '}'
bad_json_response.status_code = requests.codes.ok
# Throw an exception on the first call to requests.post()
mock_post.return_value = None
for side_effect in (requests.RequestException(), OSError(), bad_response):
mock_post.side_effect = side_effect
# We'll fail now because of our error handling
assert obj.send(body="test", attach=attach) is False
# Throw an exception on the second call to requests.post()
for side_effect in (requests.RequestException(), OSError(), bad_response):
mock_post.side_effect = [response, side_effect]
# We'll fail now because of our error handling
assert obj.send(body="test", attach=attach) is False
# Throw an exception on the third call to requests.post() # Throw an exception on the third call to requests.post()
mock_post.return_value = bad_response for side_effect in (requests.RequestException(), OSError(), bad_response):
mock_post.side_effect = [response, response, side_effect]
# prepare our attachment # We'll fail now because of our error handling
attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
# We'll fail now because we were unable to send the attachment
assert obj.send(body="test", attach=attach) is False assert obj.send(body="test", attach=attach) is False
# Throw an exception on the second call # Throw an exception on the forth call to requests.post()
mock_post.side_effect = [response, bad_response, response] for side_effect in (requests.RequestException(), OSError(), bad_response):
mock_post.side_effect = [response, response, response, side_effect]
# We'll fail now because of our error handling
assert obj.send(body="test", attach=attach) is False assert obj.send(body="test", attach=attach) is False
# Throw an OSError # Test case where we don't get a valid response back
mock_post.side_effect = [response, OSError()] mock_post.side_effect = bad_json_response
assert obj.send(body="test", attach=attach) is False
# Throw an exception on the third call # We'll fail because of an invalid json object
mock_post.side_effect = [response, response, bad_response]
assert obj.send(body="test", attach=attach) is False assert obj.send(body="test", attach=attach) is False
# Throw an exception on the fourth call
mock_post.side_effect = [response, response, response, bad_response]
assert obj.send(body="test", attach=attach) is False
# A good message
mock_post.side_effect = [response, response, response, response]
assert obj.send(body="test", attach=attach) is True

View File

@ -52,11 +52,19 @@ def test_pushover_attachments(mock_post, tmpdir):
user_key = 'u' * 30 user_key = 'u' * 30
api_token = 'a' * 30 api_token = 'a' * 30
# Prepare Mock return object # Prepare a good response
response = mock.Mock() response = mock.Mock()
response.content = dumps( response.content = dumps(
{"status": 1, "request": "647d2300-702c-4b38-8b2f-d56326ae460b"}) {"status": 1, "request": "647d2300-702c-4b38-8b2f-d56326ae460b"})
response.status_code = requests.codes.ok response.status_code = requests.codes.ok
# Prepare a bad response
bad_response = mock.Mock()
response.content = dumps(
{"status": 1, "request": "647d2300-702c-4b38-8b2f-d56326ae460b"})
bad_response.status_code = requests.codes.internal_server_error
# Assign our good response
mock_post.return_value = response mock_post.return_value = response
# prepare our attachment # prepare our attachment
@ -70,6 +78,11 @@ def test_pushover_attachments(mock_post, tmpdir):
# Test our attachment # Test our attachment
assert obj.notify(body="test", attach=attach) is True assert obj.notify(body="test", attach=attach) is True
# Test our call count
assert mock_post.call_count == 1
assert mock_post.call_args_list[0][0][0] == \
'https://api.pushover.net/1/messages.json'
# Test multiple attachments # Test multiple attachments
assert attach.add(os.path.join(TEST_VAR_DIR, 'apprise-test.gif')) assert attach.add(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
assert obj.notify(body="test", attach=attach) is True assert obj.notify(body="test", attach=attach) is True
@ -101,8 +114,12 @@ def test_pushover_attachments(mock_post, tmpdir):
# Content is silently ignored # Content is silently ignored
assert obj.notify(body="test", attach=attach) is True assert obj.notify(body="test", attach=attach) is True
# Throw an exception on the second call to requests.post()
mock_post.side_effect = OSError()
# prepare our attachment # prepare our attachment
attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif')) attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
assert obj.notify(body="test", attach=attach) is False
# Throw an exception on the first call to requests.post()
for side_effect in (requests.RequestException(), OSError(), bad_response):
mock_post.side_effect = [side_effect]
# We'll fail now because of our error handling
assert obj.send(body="test", attach=attach) is False

View File

@ -522,6 +522,25 @@ def test_parse_bool():
assert utils.parse_bool('OhYeah', True) is True assert utils.parse_bool('OhYeah', True) is True
def test_is_uuid():
"""
API: is_uuid() function
"""
# Invalid Entries
assert utils.is_uuid('invalid') is False
assert utils.is_uuid(None) is False
assert utils.is_uuid(5) is False
assert utils.is_uuid(object) is False
# A slightly invalid uuid4 entry
assert utils.is_uuid('591ed387-fa65-ac97-9712-b9d2a15e42a9') is False
assert utils.is_uuid('591ed387-fa65-Jc97-9712-b9d2a15e42a9') is False
# Valid UUID4 Entries
assert utils.is_uuid('591ed387-fa65-4c97-9712-b9d2a15e42a9') is True
assert utils.is_uuid('32b0b447-fe84-4df1-8368-81925e729265') is True
def test_is_hostname(): def test_is_hostname():
""" """
API: is_hostname() function API: is_hostname() function