improved test coverage

pull/1368/head
Chris Caron 2025-07-20 14:18:34 -04:00
parent 8a18e6b6e4
commit e483ffa130
3 changed files with 142 additions and 48 deletions

View File

@ -38,7 +38,7 @@ import pytest
import requests
from apprise import Apprise, AppriseAttachment, NotifyType
from apprise.plugins.slack import NotifySlack, SlackMode
from apprise.plugins.slack import NotifySlack
logging.disable(logging.CRITICAL)
@ -565,48 +565,6 @@ def test_plugin_slack_oauth_access_token(mock_request):
# We'll fail now because of an internal exception
assert obj.send(body="test") is False
# --- Simulate failure to send file to channel (missing 'files') ---
mock_request.reset_mock()
mock_request.side_effect = [
request, # chat.postMessage
mock.Mock(**{ # getUploadURLExternal
"content": dumps({
"ok": True,
"upload_url": "https://files.slack.com/upload/v1/ABC123",
"file_id": "F123ABC456",
}),
"status_code": requests.codes.ok,
}),
mock.Mock(**{ # File upload
"content": b"OK - 123",
"status_code": requests.codes.ok,
}),
mock.Mock(**{ # completeUploadExternal returns invalid response
"content": dumps({
"ok": True,
"files": [], # <== This triggers the unhit block
}),
"status_code": requests.codes.ok,
}),
]
path = os.path.join(TEST_VAR_DIR, "apprise-test.gif")
attach = AppriseAttachment(path)
# Test via BOT Mode
obj.mode = SlackMode.BOT
# This will now fail on 'response.get("files")' being empty
assert (
obj.notify(
body="body",
title="title",
notify_type=NotifyType.INFO,
attach=attach,
)
is False
)
@mock.patch("requests.request")
def test_plugin_slack_webhook_mode(mock_request):
@ -1040,3 +998,105 @@ def test_plugin_slack_multiple_thread_reply(mock_request):
assert loads(mock_request.call_args_list[1][1]["data"]).get(
"thread_ts"
) == str(thread_id_2)
@mock.patch("requests.request")
def test_plugin_slack_file_upload_success(mock_request):
"""Test Slack BOT attachment upload success path."""
token = "xoxb-1234-1234-abc124"
path = os.path.join(TEST_VAR_DIR, "apprise-test.gif")
attach = AppriseAttachment(path)
# Simulate all successful Slack API responses
mock_request.side_effect = [
mock.Mock(**{
"content": dumps({
"ok": True,
"channel": "C123456",
}),
"status_code": requests.codes.ok,
}),
mock.Mock(**{
"content": dumps({
"ok": True,
"upload_url": "https://files.slack.com/upload/v1/ABC123",
"file_id": "F123ABC456",
}),
"status_code": requests.codes.ok,
}),
mock.Mock(**{
"content": b"OK - 123",
"status_code": requests.codes.ok,
}),
mock.Mock(**{
"content": dumps({
"ok": True,
"files": [{"id": "F123ABC456", "title": "apprise-test"}],
}),
"status_code": requests.codes.ok,
}),
]
obj = NotifySlack(access_token=token, targets=["#general"])
assert obj.notify(
body="Success path test",
title="Slack Upload OK",
notify_type=NotifyType.INFO,
attach=attach,
) is True
@mock.patch("requests.request")
def test_plugin_slack_file_upload_fails_missing_files(mock_request):
"""Test that file upload fails when 'files' is missing or empty."""
token = "xoxb-1234-1234-abc124"
path = os.path.join(TEST_VAR_DIR, "apprise-test.gif")
attach = AppriseAttachment(path)
# Mock sequence:
# 1. chat.postMessage returns valid channel
# 2. files.getUploadURLExternal returns file_id and upload_url
# 3. Upload returns 'OK'
# 4. files.completeUploadExternal returns missing/empty 'files'
mock_request.side_effect = [
mock.Mock(**{
"content": dumps({
"ok": True,
"channel": "C555555",
}),
"status_code": requests.codes.ok,
}),
mock.Mock(**{
"content": dumps({
"ok": True,
"upload_url": "https://files.slack.com/upload/v1/X99999",
"file_id": "F999XYZ888",
}),
"status_code": requests.codes.ok,
}),
mock.Mock(**{
"content": b"OK - 2048",
"status_code": requests.codes.ok,
}),
# <== This response will trigger the error condition
mock.Mock(**{
"content": dumps({
"ok": True,
"files": [],
}),
"status_code": requests.codes.ok,
}),
]
obj = NotifySlack(access_token=token, targets=["#fail-channel"])
result = obj.notify(
body="This should trigger a failed file upload",
title="Trigger failure",
notify_type=NotifyType.INFO,
attach=attach,
)
assert result is False

View File

@ -35,11 +35,45 @@ import pytest
import apprise
logging.disable(logging.CRITICAL)
try:
import syslog
# Skip tests when Python environment does not provide the `syslog` package.
if "syslog" not in sys.modules:
pytest.skip("Skipping syslog based tests", allow_module_level=True)
except ImportError:
# Shim so that test cases can run in environments that
# do not have syslog
import types
syslog = types.SimpleNamespace(
LOG_PID=0x01,
LOG_PERROR=0x02,
LOG_INFO=6,
LOG_NOTICE=5,
LOG_CRIT=2,
LOG_WARNING=4,
LOG_KERN=0,
LOG_USER=1,
LOG_MAIL=2,
LOG_DAEMON=3,
LOG_AUTH=4,
LOG_SYSLOG=5,
LOG_LPR=6,
LOG_NEWS=7,
LOG_UUCP=8,
LOG_CRON=9,
LOG_LOCAL0=16,
LOG_LOCAL1=17,
LOG_LOCAL2=18,
LOG_LOCAL3=19,
LOG_LOCAL4=20,
LOG_LOCAL5=21,
LOG_LOCAL6=22,
LOG_LOCAL7=23,
openlog=lambda *a, **kw: None,
syslog=lambda *a, **kw: None,
)
sys.modules["syslog"] = syslog
logging.disable(logging.CRITICAL)
from apprise.plugins.syslog import NotifySyslog # noqa E402

View File

@ -97,7 +97,7 @@ commands =
find . -type f -name "*.pyc" -delete
find . -type f -name "*.pyo" -delete
find . -type d -name "__pycache__" -delete
rm -rf BUILD SOURCES SRPMS BUILDROOT .ruff_cache .coverage-reports .coverage coverage.xml dist build apprise.egg-info .mypy_cache .pytest_cache
rm -rf BUILD SOURCES SRPMS BUILDROOT .cache .ruff_cache .coverage-reports .coverage coverage.xml dist build apprise.egg-info .mypy_cache .pytest_cache
[testenv:i18n]
description = Extract and update .pot/.po files for translation