diff --git a/plugins/twilio/.CHECKSUM b/plugins/twilio/.CHECKSUM index 0b7c6c768b..614a78ab4d 100644 --- a/plugins/twilio/.CHECKSUM +++ b/plugins/twilio/.CHECKSUM @@ -1,15 +1,15 @@ { - "spec": "c44c0f5ab7e3a322044a83acfb10b817", - "manifest": "621d693d051b5c4549806163cea779b7", - "setup": "50e952cec8d2c9a5404f295fcf472b33", + "spec": "68d29af89c0c697f4c1427ebb692e3bd", + "manifest": "dbaf53402693f5664b6cc0432d4d16aa", + "setup": "fb84ae8d956792b7ff02d9b1a06fb99b", "schemas": [ { "identifier": "send_sms/schema.py", - "hash": "af20fb89e065530bc9ca6b92313cf3dc" + "hash": "d2bd4c43600e8995db3526323e37d446" }, { "identifier": "connection/schema.py", - "hash": "08ac8deb36b6dc3f3430221f8c2a20c8" + "hash": "f43143c7fef8d5dff52d63bbff8ece45" } ] } \ No newline at end of file diff --git a/plugins/twilio/Dockerfile b/plugins/twilio/Dockerfile index 5013ee916e..d7fccbd13d 100755 --- a/plugins/twilio/Dockerfile +++ b/plugins/twilio/Dockerfile @@ -1,25 +1,20 @@ -FROM komand/python-2-plugin:2 -# The three supported python parent images are: -# - komand/python-2-plugin -# - komand/python-3-plugin -# - komand/python-pypy3-plugin -# -# Update the tag to a full semver version +FROM --platform=linux/amd64 rapid7/insightconnect-python-3-slim-plugin:6.2.2 -# Add any custom package dependencies here -# NOTE: Add pip packages to requirements.txt +LABEL organization=rapid7 +LABEL sdk=python -# End package dependencies - -# Add source code WORKDIR /python/src + ADD ./plugin.spec.yaml /plugin.spec.yaml -ADD . /python/src +ADD ./requirements.txt /python/src/requirements.txt -# Install pip dependencies RUN if [ -f requirements.txt ]; then pip install -r requirements.txt; fi -# Install plugin +ADD . /python/src + RUN python setup.py build && python setup.py install -ENTRYPOINT ["/usr/local/bin/komand_twilio"] \ No newline at end of file +# User to run plugin code. The two supported users are: root, nobody +USER nobody + +ENTRYPOINT ["/usr/local/bin/komand_twilio"] diff --git a/plugins/twilio/bin/komand_twilio b/plugins/twilio/bin/komand_twilio index b090e4171d..50818be410 100755 --- a/plugins/twilio/bin/komand_twilio +++ b/plugins/twilio/bin/komand_twilio @@ -1,30 +1,44 @@ #!/usr/bin/env python -# GENERATED BY KOMAND SDK - DO NOT EDIT -import komand -from komand_twilio import connection, actions, triggers +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +import os +import json +from sys import argv +Name = "Twilio" +Vendor = "rapid7" +Version = "1.0.3" +Description = "[Twilio](https://www.twilio.com/) is a cloud communications platform for building SMS, voice, and messaging applicationson an API built for global scale. Users can send SMS using the Twilio plugin for Rapid7 for notification or other purposes." -Name = 'Twilio' -Vendor = 'rapid7' -Version = '1.0.2' -Description = 'Send SMS directly from a workflow using Twilio' - -class ICONTwilio(komand.Plugin): - def __init__(self): - super(self.__class__, self).__init__( +def main(): + if 'http' in argv: + if os.environ.get("GUNICORN_CONFIG_FILE"): + with open(os.environ.get("GUNICORN_CONFIG_FILE")) as gf: + gunicorn_cfg = json.load(gf) + if gunicorn_cfg.get("worker_class", "sync") == "gevent": + from gevent import monkey + monkey.patch_all() + elif 'gevent' in argv: + from gevent import monkey + monkey.patch_all() + + import insightconnect_plugin_runtime + from komand_twilio import connection, actions, triggers, tasks + + class ICONTwilio(insightconnect_plugin_runtime.Plugin): + def __init__(self): + super(self.__class__, self).__init__( name=Name, vendor=Vendor, version=Version, description=Description, connection=connection.Connection() - ) - self.add_action(actions.SendSms()) + ) + self.add_action(actions.SendSms()) + - -def main(): """Run plugin""" - cli = komand.CLI(ICONTwilio()) + cli = insightconnect_plugin_runtime.CLI(ICONTwilio()) cli.run() diff --git a/plugins/twilio/help.md b/plugins/twilio/help.md index be995b3cba..d6f981e5be 100644 --- a/plugins/twilio/help.md +++ b/plugins/twilio/help.md @@ -1,8 +1,7 @@ # Description [Twilio](https://www.twilio.com/) is a cloud communications platform for building SMS, voice, and messaging applications -on an API built for global scale. Users can send SMS using the Twilio plugin for Rapid7 for notification or other -purposes. +on an API built for global scale. Users can send SMS using the Twilio plugin for Rapid7 for notification or other purposes. # Key Features @@ -14,6 +13,10 @@ purposes. * Authentication token * Account ID +# Supported Product Versions + +* Twilio Client 9.4.1 + # Documentation ## Setup @@ -23,47 +26,79 @@ The account SID and Auth Token are viewable in your [console](https://www.twilio The connection configuration accepts the following parameters: -|Name|Type|Default|Required|Description|Enum| -|----|----|-------|--------|-----------|----| -|twilio_phone_number|string|None|True|Twilio phone number|None| -|auth_token|string|None|True|Twilio Auth Token|None| -|account_id|string|None|True|Twilio Account SID|None| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|credentials|credential_username_password|None|True|Username should be your account ID, and your password should be your auth token|None|{"username": "ExampleUsername", "password": "ExamplePassword"}|None|None| +|twilio_phone_number|string|None|True|The phone number of a Twilio user from which the SMS will be sent|None|+00000111222|None|None| + +Example input: + +``` +{ + "credentials": { + "password": "ExamplePassword", + "username": "ExampleUsername" + }, + "twilio_phone_number": "+00000111222" +} +``` ## Technical Details ### Actions + #### Send SMS -This action is used to send an SMS message to a phone number. +This action is used to send an SMS message to a phone number ##### Input -|Name|Type|Default|Required|Description|Enum| -|----|----|-------|--------|-----------|----| -|message|string|None|True|Message to send|None| -|to_number|string|None|True|Phone number to send SMS message|None| +|Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| +| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | +|message|string|None|True|Message to send|None|ExampleMessage|None|None| +|to_number|string|None|True|Phone number to send SMS message|None|+00000111222|None|None| + +Example input: -##### Output +``` +{ + "message": "ExampleMessage", + "to_number": "+00000111222" +} +``` -|Name|Type|Required|Description| -|----|----|--------|-----------| -|message_sid|string|False|Message SID| +##### Output +|Name|Type|Required|Description|Example| +| :--- | :--- | :--- | :--- | :--- | +|message_sid|string|False|Message SID|ExampleMessageSID| + +Example output: + +``` +{ + "message_sid": "ExampleMessageSID" +} +``` ### Triggers + +*This plugin does not contain any triggers.* +### Tasks + +*This plugin does not contain any tasks.* -_This plugin does not contain any triggers._ - -### Custom Output Types - -_This plugin does not contain any custom output types._ +### Custom Types + +*This plugin does not contain any custom output types.* ## Troubleshooting -Before sending the SMS make sure that the country you're sending the message to is enabled [here](https://www.twilio.com/console/sms/settings/geo-permissions). +* Before sending the SMS make sure that the country you're sending the message to is enabled [here](https://www.twilio.com/console/sms/settings/geo-permissions). # Version History +* 1.0.3 - Updated dependencies | Updated SDK to the latest version * 1.0.2 - New spec and help.md format for the Extension Library * 1.0.1 - Update Twilio dependency to 6.19.1 * 1.0.0 - Update to v2 Python plugin architecture | Support web server mode | Update to new credential types @@ -72,8 +107,10 @@ Before sending the SMS make sure that the country you're sending the message to # Links +* [Twilio](https://www.twilio.com/) +* [SMS Geo-permissions](https://www.twilio.com/console/sms/settings/geo-permissions) + ## References * [Twilio](https://www.twilio.com/) -* [Twilio Python Library](https://www.twilio.com/docs/libraries/python) - +* [Twilio Python Library](https://www.twilio.com/docs/libraries/python) \ No newline at end of file diff --git a/plugins/twilio/komand_twilio/actions/__init__.py b/plugins/twilio/komand_twilio/actions/__init__.py index 5decc19c2c..fae210d017 100755 --- a/plugins/twilio/komand_twilio/actions/__init__.py +++ b/plugins/twilio/komand_twilio/actions/__init__.py @@ -1,2 +1,4 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT + from .send_sms.action import SendSms + diff --git a/plugins/twilio/komand_twilio/actions/send_sms/__init__.py b/plugins/twilio/komand_twilio/actions/send_sms/__init__.py index 27d7629c5c..a0044851da 100755 --- a/plugins/twilio/komand_twilio/actions/send_sms/__init__.py +++ b/plugins/twilio/komand_twilio/actions/send_sms/__init__.py @@ -1,2 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from .action import SendSms diff --git a/plugins/twilio/komand_twilio/actions/send_sms/action.py b/plugins/twilio/komand_twilio/actions/send_sms/action.py index 5bebf69f53..900bd52220 100755 --- a/plugins/twilio/komand_twilio/actions/send_sms/action.py +++ b/plugins/twilio/komand_twilio/actions/send_sms/action.py @@ -1,23 +1,29 @@ -import komand -from .schema import SendSmsInput, SendSmsOutput +import insightconnect_plugin_runtime +from insightconnect_plugin_runtime.exceptions import PluginException +from .schema import SendSmsInput, SendSmsOutput, Input, Output, Component -class SendSms(komand.Action): +class SendSms(insightconnect_plugin_runtime.Action): def __init__(self): super(self.__class__, self).__init__( name="send_sms", - description="Send an SMS message to a phone number", + description=Component.DESCRIPTION, input=SendSmsInput(), output=SendSmsOutput(), ) def run(self, params={}): - message = self.connection.client.messages.create( - body=params.get("message"), - to=params.get("to_number"), - from_=self.connection.twilio_phone_number, - ) - return {"message_sid": message.sid} + # START INPUT BINDING - DO NOT REMOVE - ANY INPUTS BELOW WILL UPDATE WITH YOUR PLUGIN SPEC AFTER REGENERATION + message = params.get(Input.MESSAGE, "") + send_to_number = params.get(Input.TO_NUMBER, "").strip() + # END INPUT BINDING - DO NOT REMOVE - def test(self): - return {"message_sid": "SM91b89296d763426db7b50d165f6eadfb"} + try: + message = self.connection.client.messages.create( + body=message, + to=send_to_number, + from_=self.connection.twilio_phone_number, + ) + return {Output.MESSAGE_SID: message.sid} + except Exception as error: + raise PluginException(preset=PluginException.Preset.UNKNOWN, data=error) diff --git a/plugins/twilio/komand_twilio/actions/send_sms/schema.py b/plugins/twilio/komand_twilio/actions/send_sms/schema.py index b887344f04..a37c9cccdd 100755 --- a/plugins/twilio/komand_twilio/actions/send_sms/schema.py +++ b/plugins/twilio/komand_twilio/actions/send_sms/schema.py @@ -1,5 +1,5 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT -import komand +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +import insightconnect_plugin_runtime import json @@ -10,14 +10,14 @@ class Component: class Input: MESSAGE = "message" TO_NUMBER = "to_number" - + class Output: MESSAGE_SID = "message_sid" - -class SendSmsInput(komand.Input): - schema = json.loads(""" + +class SendSmsInput(insightconnect_plugin_runtime.Input): + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -38,7 +38,8 @@ class SendSmsInput(komand.Input): "required": [ "message", "to_number" - ] + ], + "definitions": {} } """) @@ -46,8 +47,8 @@ def __init__(self): super(self.__class__, self).__init__(self.schema) -class SendSmsOutput(komand.Output): - schema = json.loads(""" +class SendSmsOutput(insightconnect_plugin_runtime.Output): + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -58,7 +59,8 @@ class SendSmsOutput(komand.Output): "description": "Message SID", "order": 1 } - } + }, + "definitions": {} } """) diff --git a/plugins/twilio/komand_twilio/connection/__init__.py b/plugins/twilio/komand_twilio/connection/__init__.py index a515dcf6b0..c78d3356be 100755 --- a/plugins/twilio/komand_twilio/connection/__init__.py +++ b/plugins/twilio/komand_twilio/connection/__init__.py @@ -1,2 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from .connection import Connection diff --git a/plugins/twilio/komand_twilio/connection/connection.py b/plugins/twilio/komand_twilio/connection/connection.py index 0192d7db3d..ac7db22e05 100755 --- a/plugins/twilio/komand_twilio/connection/connection.py +++ b/plugins/twilio/komand_twilio/connection/connection.py @@ -1,18 +1,32 @@ -import komand -from .schema import ConnectionSchema +import insightconnect_plugin_runtime +from insightconnect_plugin_runtime.exceptions import ConnectionTestException +from typing import Dict, Any +from .schema import ConnectionSchema, Input # Custom imports below from twilio.rest import Client +from twilio.http.http_client import TwilioHttpClient -class Connection(komand.Connection): +class Connection(insightconnect_plugin_runtime.Connection): def __init__(self): super(self.__class__, self).__init__(input=ConnectionSchema()) + self.twilio_phone_number = None + self.client = None - def connect(self, params): - account_sid = params.get("credentials").get("username") - auth_token = params.get("credentials").get("password") + def connect(self, params={}) -> None: + self.logger.info("Connect: Connecting...") + account_sid = params.get(Input.CREDENTIALS, {}).get("username").strip() + auth_token = params.get(Input.CREDENTIALS, {}).get("password").strip() + self.twilio_phone_number = params.get(Input.TWILIO_PHONE_NUMBER, "").strip() self.client = Client(account_sid, auth_token) - self.twilio_phone_number = params.get("twilio_phone_number") - self.logger.info("connecting") + def test(self) -> Dict[str, Any]: + try: + self.logger.info("Running TLS test over twilio...") + TwilioHttpClient().request("GET", "https://tls-test.twilio.com") + self.logger.info("TLS test passed.") + self.client.messages.list(limit=1) + return {"success": True} + except Exception as error: + raise ConnectionTestException(preset=ConnectionTestException.Preset.UNKNOWN, data=error) diff --git a/plugins/twilio/komand_twilio/connection/schema.py b/plugins/twilio/komand_twilio/connection/schema.py index 3bf4ef5d44..a969ba107a 100755 --- a/plugins/twilio/komand_twilio/connection/schema.py +++ b/plugins/twilio/komand_twilio/connection/schema.py @@ -1,15 +1,15 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT -import komand +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +import insightconnect_plugin_runtime import json class Input: CREDENTIALS = "credentials" TWILIO_PHONE_NUMBER = "twilio_phone_number" - -class ConnectionSchema(komand.Input): - schema = json.loads(""" + +class ConnectionSchema(insightconnect_plugin_runtime.Input): + schema = json.loads(r""" { "type": "object", "title": "Variables", @@ -22,8 +22,7 @@ class ConnectionSchema(komand.Input): }, "twilio_phone_number": { "type": "string", - "title": "Twilio Phone Number", - "description": "Twilio phone number", + "description": "The phone number of a Twilio user from which the SMS will be sent", "order": 1 } }, @@ -34,21 +33,23 @@ class ConnectionSchema(komand.Input): "definitions": { "credential_username_password": { "id": "credential_username_password", - "type": "object", "title": "Credential: Username and Password", "description": "A username and password combination", + "type": "object", "properties": { + "username": { + "type": "string", + "title": "Username", + "description": "The username to log in with", + "order": 1 + }, "password": { "type": "string", "title": "Password", - "displayType": "password", "description": "The password", - "format": "password" - }, - "username": { - "type": "string", - "title": "Username", - "description": "The username to log in with" + "format": "password", + "displayType": "password", + "order": 2 } }, "required": [ diff --git a/plugins/twilio/komand_twilio/tasks/__init__.py b/plugins/twilio/komand_twilio/tasks/__init__.py new file mode 100644 index 0000000000..7020c9a4ad --- /dev/null +++ b/plugins/twilio/komand_twilio/tasks/__init__.py @@ -0,0 +1,2 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT + diff --git a/plugins/twilio/komand_twilio/triggers/__init__.py b/plugins/twilio/komand_twilio/triggers/__init__.py index bace8db897..7020c9a4ad 100755 --- a/plugins/twilio/komand_twilio/triggers/__init__.py +++ b/plugins/twilio/komand_twilio/triggers/__init__.py @@ -1 +1,2 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT + diff --git a/plugins/twilio/plugin.spec.yaml b/plugins/twilio/plugin.spec.yaml index c92bf2fb39..34c82b4d9c 100644 --- a/plugins/twilio/plugin.spec.yaml +++ b/plugins/twilio/plugin.spec.yaml @@ -3,32 +3,61 @@ extension: plugin products: [insightconnect] name: twilio title: Twilio -description: Send SMS directly from a workflow using Twilio -version: 1.0.2 +description: "[Twilio](https://www.twilio.com/) is a cloud communications platform for building SMS, voice, and messaging applications\non an API built for global scale. Users can send SMS using the Twilio plugin for Rapid7 for notification or other purposes." +version: 1.0.3 +connection_version: 1 vendor: rapid7 support: community +supported_versions: ["Twilio Client 9.4.1"] status: [] resources: source_url: https://github.com/rapid7/insightconnect-plugins/tree/master/plugins/twilio license_url: https://github.com/rapid7/insightconnect-plugins/blob/master/LICENSE tags: -- twilio -- SMS + - twilio + - SMS hub_tags: use_cases: [alerting_and_notifications] keywords: [twilio, SMS] features: [] +sdk: + type: slim + version: 6.2.2 + user: nobody +key_features: + - Send SMS +requirements: + - Twilio phone number + - Authentication token + - Account ID +troubleshooting: + - Before sending the SMS make sure that the country you're sending the message to is enabled [here](https://www.twilio.com/console/sms/settings/geo-permissions). +version_history: + - "1.0.3 - Updated dependencies | Updated SDK to the latest version" + - "1.0.2 - New spec and help.md format for the Extension Library" + - "1.0.1 - Update Twilio dependency to 6.19.1" + - "1.0.0 - Update to v2 Python plugin architecture | Support web server mode | Update to new credential types" + - "0.1.1 - SSL bug fix in SDK" + - "0.1.0 - Initial plugin" +links: + - "[Twilio](https://www.twilio.com/)" + - "[SMS Geo-permissions](https://www.twilio.com/console/sms/settings/geo-permissions)" +references: + - "[Twilio](https://www.twilio.com/)" + - "[Twilio Python Library](https://www.twilio.com/docs/libraries/python)" connection: twilio_phone_number: + description: The phone number of a Twilio user from which the SMS will be sent type: string - description: Twilio phone number required: true + example: "+00000111222" credentials: title: Account SID and Auth Token description: Username should be your account ID, and your password should be your auth token - required: true type: credential_username_password + required: true + example: '{"username": "ExampleUsername", "password": "ExamplePassword"}' actions: send_sms: title: Send SMS @@ -36,17 +65,20 @@ actions: input: message: title: Message - type: string description: Message to send + type: string required: true + example: ExampleMessage to_number: title: Number - type: string description: Phone number to send SMS message + type: string required: true + example: "+00000111222" output: message_sid: title: Message SID - type: string description: Message SID + type: string required: false + example: ExampleMessageSID diff --git a/plugins/twilio/requirements.txt b/plugins/twilio/requirements.txt index 2798fa1473..3cbde839de 100755 --- a/plugins/twilio/requirements.txt +++ b/plugins/twilio/requirements.txt @@ -1,4 +1,4 @@ # List third-party dependencies here, separated by newlines. # All dependencies must be version-pinned, eg. requests==1.2.0 # See: https://pip.pypa.io/en/stable/user_guide/#requirements-files -twilio==6.19.1 +twilio==9.4.1 diff --git a/plugins/twilio/setup.py b/plugins/twilio/setup.py index c8096ff78a..c8083323f6 100755 --- a/plugins/twilio/setup.py +++ b/plugins/twilio/setup.py @@ -1,14 +1,14 @@ -# GENERATED BY KOMAND SDK - DO NOT EDIT +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT from setuptools import setup, find_packages -setup(name='twilio-rapid7-plugin', - version='1.0.2', - description='Send SMS directly from a workflow using Twilio', - author='rapid7', - author_email='', - url='', +setup(name="twilio-rapid7-plugin", + version="1.0.3", + description="[Twilio](https://www.twilio.com/) is a cloud communications platform for building SMS, voice, and messaging applicationson an API built for global scale. Users can send SMS using the Twilio plugin for Rapid7 for notification or other purposes.", + author="rapid7", + author_email="", + url="", packages=find_packages(), - install_requires=['komand'], # Add third-party dependencies to requirements.txt, not here! + install_requires=['insightconnect-plugin-runtime'], # Add third-party dependencies to requirements.txt, not here! scripts=['bin/komand_twilio'] ) diff --git a/plugins/twilio/unit_test/__init__.py b/plugins/twilio/unit_test/__init__.py new file mode 100644 index 0000000000..d9ae09fc16 --- /dev/null +++ b/plugins/twilio/unit_test/__init__.py @@ -0,0 +1,4 @@ +# GENERATED BY INSIGHT-PLUGIN - DO NOT EDIT +import sys + +sys.path.append("../") \ No newline at end of file diff --git a/plugins/twilio/unit_test/responses/send_sms.json.resp b/plugins/twilio/unit_test/responses/send_sms.json.resp new file mode 100644 index 0000000000..bf969b6f29 --- /dev/null +++ b/plugins/twilio/unit_test/responses/send_sms.json.resp @@ -0,0 +1,24 @@ +{ + "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", + "api_version": "2010-04-01", + "body": "Hi there", + "date_created": "Thu, 24 Aug 2023 05:01:45 +0000", + "date_sent": "Thu, 24 Aug 2023 05:01:45 +0000", + "date_updated": "Thu, 24 Aug 2023 05:01:45 +0000", + "direction": "outbound-api", + "error_code": null, + "error_message": null, + "from": "+15557122661", + "num_media": "0", + "num_segments": "1", + "price": null, + "price_unit": null, + "messaging_service_sid": "ExampleSSID", + "sid": "ExampleMessageSID", + "status": "queued", + "subresource_uris": { + "media": "/2010-04-01/Accounts/ExampleUsername/Messages/ExampleSID/Media.json" + }, + "to": "+15558675310", + "uri": "/2010-04-01/Accounts/ExampleUsername/Messages/ExampleSID.json" +} diff --git a/plugins/twilio/unit_test/test_send_sms.py b/plugins/twilio/unit_test/test_send_sms.py new file mode 100644 index 0000000000..1a28c7af3f --- /dev/null +++ b/plugins/twilio/unit_test/test_send_sms.py @@ -0,0 +1,42 @@ +import os +import sys + +from insightconnect_plugin_runtime.exceptions import PluginException + +sys.path.append(os.path.abspath("../")) + +from unittest import TestCase +from unittest.mock import MagicMock, patch + +from jsonschema import validate +from komand_twilio.actions.send_sms import SendSms +from komand_twilio.actions.send_sms.schema import Input, Output + +from utils import MockResponse, Util + +STUB_RESPONSE_FILENAME = "send_sms" + + +class TestSendSms(TestCase): + def setUp(self) -> None: + self.action = Util.default_connector(SendSms()) + + @patch( + "requests.sessions.Session.send", return_value=MockResponse(filename=STUB_RESPONSE_FILENAME, status_code=200) + ) + def test_send_sms(self, mock_requests: MagicMock) -> None: + response = self.action.run({Input.TO_NUMBER: "000111222", Input.MESSAGE: "ExampleMessage"}) + expected = {Output.MESSAGE_SID: "ExampleMessageSID"} + validate(response, self.action.output.schema) + self.assertEqual(response, expected) + mock_requests.assert_called() + + @patch( + "requests.sessions.Session.send", return_value=MockResponse(filename=STUB_RESPONSE_FILENAME, status_code=400) + ) + def test_send_sms_error(self, mock_requests: MagicMock) -> None: + with self.assertRaises(PluginException) as context: + self.action.run({}) + self.assertEqual(context.exception.cause, PluginException.causes[PluginException.Preset.UNKNOWN]) + self.assertEqual(context.exception.assistance, PluginException.assistances[PluginException.Preset.UNKNOWN]) + mock_requests.assert_called() diff --git a/plugins/twilio/unit_test/utils.py b/plugins/twilio/unit_test/utils.py new file mode 100644 index 0000000000..a397236f75 --- /dev/null +++ b/plugins/twilio/unit_test/utils.py @@ -0,0 +1,39 @@ +import json +import logging +import os +from unittest.mock import MagicMock + +from insightconnect_plugin_runtime.action import Action +from komand_twilio.connection.connection import Connection +from komand_twilio.connection.schema import Input + +STUB_CONNECTION = { + Input.TWILIO_PHONE_NUMBER: "000111222", + Input.CREDENTIALS: {"username": "ExampleUsername", "password": "ExamplePassword"}, +} + + +class Util: + @staticmethod + def default_connector(action: Action) -> Action: + default_connection = Connection() + default_connection.logger = logging.getLogger("connection logger") + default_connection.connect(STUB_CONNECTION) + action.connection = default_connection + action.logger = logging.getLogger("action logger") + return action + + +class MockResponse: + def __init__(self, filename: str, status_code: int) -> None: + self.filename = filename + self.status_code = status_code + self.text = json.dumps(self.json(), sort_keys=True) + self.request = MagicMock() + self.headers = MagicMock() + + def json(self): + with open( + os.path.join(os.path.dirname(os.path.realpath(__file__)), f"responses/{self.filename}.json.resp") + ) as file: + return json.load(file)