From 52a53d6f33d39164ab7ee161da26d113a760531c Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Sun, 29 Jun 2025 15:26:13 -0400 Subject: [PATCH] smpp dependency cleanup and test case prep --- all-plugin-requirements.txt | 3 ++ apprise/plugins/smpp.py | 40 ++++++++++++++----- test/test_plugin_smpp.py | 80 ++++++++++++++----------------------- 3 files changed, 63 insertions(+), 60 deletions(-) diff --git a/all-plugin-requirements.txt b/all-plugin-requirements.txt index 826901be..372c27fc 100644 --- a/all-plugin-requirements.txt +++ b/all-plugin-requirements.txt @@ -14,3 +14,6 @@ paho-mqtt != 2.0.* # Pretty Good Privacy (PGP) Provides mailto:// and deltachat:// support PGPy + +# Provides smpp:// support +python-smpp diff --git a/apprise/plugins/smpp.py b/apprise/plugins/smpp.py index 39f9ccd4..4ae9fcf3 100644 --- a/apprise/plugins/smpp.py +++ b/apprise/plugins/smpp.py @@ -28,9 +28,18 @@ from itertools import chain -import smpplib -import smpplib.consts -import smpplib.gsm +try: + import smpplib + import smpplib.consts + import smpplib.gsm + + # We're good to go! + NOTIFY_SMPP_ENABLED = True + +except ImportError: + # cryptography is required in order for this package to work + NOTIFY_SMPP_ENABLED = False + from .base import NotifyBase from ..common import NotifyType @@ -38,18 +47,29 @@ from ..locale import gettext_lazy as _ from ..utils.parse import is_phone_no, parse_phone_no -class NotifySmpp(NotifyBase): +class NotifySMPP(NotifyBase): """ A wrapper for SMPP Notifications """ + # Set our global enabled flag + enabled = NOTIFY_SMPP_ENABLED + + requirements = { + # Define our required packaging in order to work + 'packages_required': 'python-snpp' + } + # The default descriptive name associated with the Notification service_name = _('SMPP') # The services URL service_url = 'https://smpp.org/' + # The default protocol protocol = 'smpp' + + # The default secure protocol secure_protocol = 'smpps' # A URL that takes you to the setup/help of the specific protocol @@ -175,7 +195,7 @@ class NotifySmpp(NotifyBase): port=self.port, source=self.source, targets='/'.join( - [NotifySmpp.quote(t, safe='') + [NotifySMPP.quote(t, safe='') for t in chain(self.targets, self._invalid_targets)]), params=self.urlencode(params), ) @@ -249,27 +269,27 @@ class NotifySmpp(NotifyBase): # We're done early as we couldn't load the results return results - results['targets'] = NotifySmpp.split_path(results['fullpath']) + results['targets'] = NotifySMPP.split_path(results['fullpath']) # Support the 'to' variable so that we can support targets this way too # 'to' makes it easier to use yaml configuration if 'to' in results['qsd'] and len(results['qsd']['to']): results['targets'] += \ - NotifySmpp.parse_phone_no(results['qsd']['to']) + NotifySMPP.parse_phone_no(results['qsd']['to']) # store any additional payload extras defined - results['payload'] = {NotifySmpp.unquote(x): NotifySmpp.unquote(y) + results['payload'] = {NotifySMPP.unquote(x): NotifySMPP.unquote(y) for x, y in results['qsd:'].items()} # Add our GET parameters in the event the user wants to pass them - results['params'] = {NotifySmpp.unquote(x): NotifySmpp.unquote(y) + results['params'] = {NotifySMPP.unquote(x): NotifySMPP.unquote(y) for x, y in results['qsd-'].items()} # Support the 'from' and 'source' variable so that we can support # targets this way too. # 'from' makes it easier to use yaml configuration if 'from' in results['qsd'] and len(results['qsd']['from']): - results['source'] = NotifySmpp.unquote(results['qsd']['from']) + results['source'] = NotifySMPP.unquote(results['qsd']['from']) elif results['targets']: # from phone number is the first entry in the list otherwise results['source'] = results['targets'].pop(0) diff --git a/test/test_plugin_smpp.py b/test/test_plugin_smpp.py index 5cab7461..2f2f0232 100644 --- a/test/test_plugin_smpp.py +++ b/test/test_plugin_smpp.py @@ -27,13 +27,11 @@ # POSSIBILITY OF SUCH DAMAGE. import logging -from json import dumps -from unittest import mock +import sys import pytest -import requests - -from apprise.plugins.smpp import NotifySmpp +from apprise import Apprise +from apprise.plugins.smpp import NotifySMPP from helpers import AppriseURLTester logging.disable(logging.CRITICAL) @@ -66,32 +64,32 @@ apprise_url_tests = ( }), ('smpp://user:pass@host:port/{}/{}'.format('1' * 10, 'a' * 32), { # valid everything but target numbers - 'instance': NotifySmpp, + 'instance': NotifySMPP, # We have no one to notify 'notify_response': False, }), ('smpp://user:pass@host:port/{}'.format('1' * 10), { # everything valid - 'instance': NotifySmpp, + 'instance': NotifySMPP, # We have no one to notify 'notify_response': False, }), ('smpp://user:pass@host:port/{}/{}'.format('1' * 10, '1' * 10), { - 'instance': NotifySmpp, + 'instance': NotifySMPP, }), ('smpp://_?&from={}&to={},{}'.format( '1' * 10, '1' * 10, '1' * 10), { - # use get args to accomplish the same thing - 'instance': NotifySmpp, - }), + # use get args to accomplish the same thing + 'instance': NotifySMPP, + }), ('smpp://user:pass@host:port/{}/{}'.format('1' * 10, '1' * 10), { - 'instance': NotifySmpp, + 'instance': NotifySMPP, # throw a bizarre code forcing us to fail to look it up 'response': False, 'requests_response_code': 999, }), ('smpp://user:pass@host:port/{}/{}'.format('1' * 10, '1' * 10), { - 'instance': NotifySmpp, + 'instance': NotifySMPP, # Throws a series of connection and transfer exceptions when this flag # is set and tests that we gracefully handle them 'test_requests_exceptions': True, @@ -99,46 +97,28 @@ apprise_url_tests = ( ) +@pytest.mark.skipif( + 'python-smpp' in sys.modules, + reason="Requires that python-smpp NOT be installed") +def test_plugin_fcm_cryptography_import_error(): + """ + NotifySimplePush() python-smpp loading failure + """ + + # Attempt to instantiate our object + obj = Apprise.instantiate( + 'smpp://user:pass@host:port/{}/{}'.format('1' * 10, '1' * 10)) + + # It's not possible because our cryptography depedancy is missing + assert obj is None + + +@pytest.mark.skipif( + 'python-smpp' not in sys.modules, reason="Requires python-smpp") def test_plugin_smpp_urls(): """ - NotifySmpp() Apprise URLs + NotifySMPP() Apprise URLs """ # Run our general tests AppriseURLTester(tests=apprise_url_tests).run_all() - - -@mock.patch('requests.post') -def test_plugin_smpp_edge_cases(mock_post): - """ - NotifySmpp() Edge Cases - """ - - # Prepare our response - response = requests.Request() - response.status_code = requests.codes.ok - - # Prepare Mock - mock_post.return_value = response - - # Initialize some generic (but valid) apikeys - apikey = 'b' * 32 - source = '+1 (555) 123-3456' - - # No apikey specified - with pytest.raises(TypeError): - NotifySmpp(source=source) - - # a error response - response.status_code = 400 - response.content = dumps({ - 'code': 21211, - 'message': "The 'To' number +1234567 is not a valid phone number.", - }) - mock_post.return_value = response - - # Initialize our object - obj = NotifySmpp(source=source) - - # We will fail with the above error code - assert obj.notify('title', 'body', 'info') is False