mirror of https://github.com/caronc/apprise
improved test coverage
parent
8a18e6b6e4
commit
e483ffa130
|
@ -38,7 +38,7 @@ import pytest
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from apprise import Apprise, AppriseAttachment, NotifyType
|
from apprise import Apprise, AppriseAttachment, NotifyType
|
||||||
from apprise.plugins.slack import NotifySlack, SlackMode
|
from apprise.plugins.slack import NotifySlack
|
||||||
|
|
||||||
logging.disable(logging.CRITICAL)
|
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
|
# We'll fail now because of an internal exception
|
||||||
assert obj.send(body="test") is False
|
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")
|
@mock.patch("requests.request")
|
||||||
def test_plugin_slack_webhook_mode(mock_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(
|
assert loads(mock_request.call_args_list[1][1]["data"]).get(
|
||||||
"thread_ts"
|
"thread_ts"
|
||||||
) == str(thread_id_2)
|
) == 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
|
||||||
|
|
|
@ -35,11 +35,45 @@ import pytest
|
||||||
|
|
||||||
import apprise
|
import apprise
|
||||||
|
|
||||||
logging.disable(logging.CRITICAL)
|
try:
|
||||||
|
import syslog
|
||||||
|
|
||||||
# Skip tests when Python environment does not provide the `syslog` package.
|
except ImportError:
|
||||||
if "syslog" not in sys.modules:
|
# Shim so that test cases can run in environments that
|
||||||
pytest.skip("Skipping syslog based tests", allow_module_level=True)
|
# 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
|
from apprise.plugins.syslog import NotifySyslog # noqa E402
|
||||||
|
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -97,7 +97,7 @@ commands =
|
||||||
find . -type f -name "*.pyc" -delete
|
find . -type f -name "*.pyc" -delete
|
||||||
find . -type f -name "*.pyo" -delete
|
find . -type f -name "*.pyo" -delete
|
||||||
find . -type d -name "__pycache__" -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]
|
[testenv:i18n]
|
||||||
description = Extract and update .pot/.po files for translation
|
description = Extract and update .pot/.po files for translation
|
||||||
|
|
Loading…
Reference in New Issue