Rocket.Chat Refactored for Webhook Support; refs #107

This commit is contained in:
Chris Caron 2019-05-21 21:50:50 -04:00 committed by GitHub
parent ac56a409a0
commit 554c7f0b10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 323 additions and 51 deletions

View File

@ -55,7 +55,7 @@ The table below identifies the services this tool supports and some example serv
| [Pushjet](https://github.com/caronc/apprise/wiki/Notify_pushjet) | pjet:// or pjets:// | (TCP) 80 or 443 | pjet://secret@hostname<br />pjet://secret@hostname:port<br />pjets://secret@hostname<br />pjets://secret@hostname:port | [Pushjet](https://github.com/caronc/apprise/wiki/Notify_pushjet) | pjet:// or pjets:// | (TCP) 80 or 443 | pjet://secret@hostname<br />pjet://secret@hostname:port<br />pjets://secret@hostname<br />pjets://secret@hostname:port
| [Pushed](https://github.com/caronc/apprise/wiki/Notify_pushed) | pushed:// | (TCP) 443 | pushed://appkey/appsecret/<br/>pushed://appkey/appsecret/#ChannelAlias<br/>pushed://appkey/appsecret/#ChannelAlias1/#ChannelAlias2/#ChannelAliasN<br/>pushed://appkey/appsecret/@UserPushedID<br/>pushed://appkey/appsecret/@UserPushedID1/@UserPushedID2/@UserPushedIDN | [Pushed](https://github.com/caronc/apprise/wiki/Notify_pushed) | pushed:// | (TCP) 443 | pushed://appkey/appsecret/<br/>pushed://appkey/appsecret/#ChannelAlias<br/>pushed://appkey/appsecret/#ChannelAlias1/#ChannelAlias2/#ChannelAliasN<br/>pushed://appkey/appsecret/@UserPushedID<br/>pushed://appkey/appsecret/@UserPushedID1/@UserPushedID2/@UserPushedIDN
| [Pushover](https://github.com/caronc/apprise/wiki/Notify_pushover) | pover:// | (TCP) 443 | pover://user@token<br />pover://user@token/DEVICE<br />pover://user@token/DEVICE1/DEVICE2/DEVICEN<br />**Note**: you must specify both your user_id and token | [Pushover](https://github.com/caronc/apprise/wiki/Notify_pushover) | pover:// | (TCP) 443 | pover://user@token<br />pover://user@token/DEVICE<br />pover://user@token/DEVICE1/DEVICE2/DEVICEN<br />**Note**: you must specify both your user_id and token
| [Rocket.Chat](https://github.com/caronc/apprise/wiki/Notify_rocketchat) | rocket:// or rockets:// | (TCP) 80 or 443 | rocket://user:password@hostname/RoomID/Channel<br />rockets://user:password@hostname:443/Channel1/Channel1/RoomID<br />rocket://user:password@hostname/Channel | [Rocket.Chat](https://github.com/caronc/apprise/wiki/Notify_rocketchat) | rocket:// or rockets:// | (TCP) 80 or 443 | rocket://user:password@hostname/RoomID/Channel<br />rockets://user:password@hostname:443/#Channel1/#Channel1/RoomID<br />rocket://user:password@hostname/#Channel<br />rocket://webhook@hostname<br />rockets://webhook@hostname/@User/#Channel
| [Ryver](https://github.com/caronc/apprise/wiki/Notify_ryver) | ryver:// | (TCP) 443 | ryver://Organization/Token<br />ryver://botname@Organization/Token | [Ryver](https://github.com/caronc/apprise/wiki/Notify_ryver) | ryver:// | (TCP) 443 | ryver://Organization/Token<br />ryver://botname@Organization/Token
| [Slack](https://github.com/caronc/apprise/wiki/Notify_slack) | slack:// | (TCP) 443 | slack://TokenA/TokenB/TokenC/<br />slack://TokenA/TokenB/TokenC/Channel<br />slack://botname@TokenA/TokenB/TokenC/Channel<br />slack://user@TokenA/TokenB/TokenC/Channel1/Channel2/ChannelN | [Slack](https://github.com/caronc/apprise/wiki/Notify_slack) | slack:// | (TCP) 443 | slack://TokenA/TokenB/TokenC/<br />slack://TokenA/TokenB/TokenC/Channel<br />slack://botname@TokenA/TokenB/TokenC/Channel<br />slack://user@TokenA/TokenB/TokenC/Channel1/Channel2/ChannelN
| [Telegram](https://github.com/caronc/apprise/wiki/Notify_telegram) | tgram:// | (TCP) 443 | tgram://bottoken/ChatID<br />tgram://bottoken/ChatID1/ChatID2/ChatIDN | [Telegram](https://github.com/caronc/apprise/wiki/Notify_telegram) | tgram:// | (TCP) 443 | tgram://bottoken/ChatID<br />tgram://bottoken/ChatID1/ChatID2/ChatIDN

View File

@ -24,15 +24,21 @@
# THE SOFTWARE. # THE SOFTWARE.
import re import re
import six
import requests import requests
from json import loads from json import loads
from json import dumps
from itertools import chain from itertools import chain
from .NotifyBase import NotifyBase from .NotifyBase import NotifyBase
from ..common import NotifyImageSize
from ..common import NotifyFormat
from ..common import NotifyType from ..common import NotifyType
from ..utils import parse_list from ..utils import parse_list
from ..utils import parse_bool
IS_CHANNEL = re.compile(r'^#(?P<name>[A-Za-z0-9]+)$') IS_CHANNEL = re.compile(r'^#(?P<name>[A-Za-z0-9_-]+)$')
IS_USER = re.compile(r'^@(?P<name>[A-Za-z0-9._-]+)$')
IS_ROOM_ID = re.compile(r'^(?P<name>[A-Za-z0-9]+)$') IS_ROOM_ID = re.compile(r'^(?P<name>[A-Za-z0-9]+)$')
# Extend HTTP Error Messages # Extend HTTP Error Messages
@ -46,6 +52,24 @@ RC_HTTP_ERROR_MAP = {
LIST_DELIM = re.compile(r'[ \t\r\n,\\/]+') LIST_DELIM = re.compile(r'[ \t\r\n,\\/]+')
class RocketChatAuthMode(object):
"""
The Chat Authentication mode is detected
"""
# providing a webhook
WEBHOOK = "webhook"
# Providing a username and password (default)
BASIC = "basic"
# Define our authentication modes
ROCKETCHAT_AUTH_MODES = (
RocketChatAuthMode.WEBHOOK,
RocketChatAuthMode.BASIC,
)
class NotifyRocketChat(NotifyBase): class NotifyRocketChat(NotifyBase):
""" """
A wrapper for Notify Rocket.Chat Notifications A wrapper for Notify Rocket.Chat Notifications
@ -66,13 +90,21 @@ class NotifyRocketChat(NotifyBase):
# A URL that takes you to the setup/help of the specific protocol # A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_rocketchat' setup_url = 'https://github.com/caronc/apprise/wiki/Notify_rocketchat'
# Allows the user to specify the NotifyImageSize object; this is supported
# through the webhook
image_size = NotifyImageSize.XY_128
# The title is not used # The title is not used
title_maxlen = 0 title_maxlen = 0
# The maximum size of the message # The maximum size of the message
body_maxlen = 200 body_maxlen = 1000
def __init__(self, targets=None, **kwargs): # Default to markdown
notify_format = NotifyFormat.MARKDOWN
def __init__(self, webhook=None, targets=None, mode=None,
include_avatar=True, **kwargs):
""" """
Initialize Notify Rocket.Chat Object Initialize Notify Rocket.Chat Object
""" """
@ -87,19 +119,55 @@ class NotifyRocketChat(NotifyBase):
if isinstance(self.port, int): if isinstance(self.port, int):
self.api_url += ':%d' % self.port self.api_url += ':%d' % self.port
self.api_url += '/api/v1/'
# Initialize channels list # Initialize channels list
self.channels = list() self.channels = list()
# Initialize room list # Initialize room list
self.rooms = list() self.rooms = list()
if not (self.user and self.password): # Initialize user list (webhook only)
self.users = list()
# Assign our webhook (if defined)
self.webhook = webhook
# Place an avatar image to associate with our content
self.include_avatar = include_avatar
# Used to track token headers upon authentication (if successful)
# This is only used if not on webhook mode
self.headers = {}
# Authentication mode
self.mode = None \
if not isinstance(mode, six.string_types) \
else mode.lower()
if self.mode and self.mode not in ROCKETCHAT_AUTH_MODES:
msg = 'The authentication mode specified ({}) is invalid.'.format(
mode)
self.logger.warning(msg)
raise TypeError(msg)
# Detect our mode if it wasn't specified
if not self.mode:
if self.webhook is not None:
# Just a username was specified, we treat this as a webhook
self.mode = RocketChatAuthMode.WEBHOOK
else:
self.mode = RocketChatAuthMode.BASIC
if self.mode == RocketChatAuthMode.BASIC \
and not (self.user and self.password):
# Username & Password is required for Rocket Chat to work # Username & Password is required for Rocket Chat to work
raise TypeError( msg = 'No Rocket.Chat user/pass combo was specified.'
'No Rocket.Chat user/pass combo specified.' self.logger.warning(msg)
) raise TypeError(msg)
elif self.mode == RocketChatAuthMode.WEBHOOK and not self.webhook:
msg = 'No Rocket.Chat Incoming Webhook was specified.'
self.logger.warning(msg)
raise TypeError(msg)
# Validate recipients and drop bad ones: # Validate recipients and drop bad ones:
for recipient in parse_list(targets): for recipient in parse_list(targets):
@ -115,18 +183,24 @@ class NotifyRocketChat(NotifyBase):
self.rooms.append(result.group('name')) self.rooms.append(result.group('name'))
continue continue
result = IS_USER.match(recipient)
if result:
# store valid room
self.users.append(result.group('name'))
continue
self.logger.warning( self.logger.warning(
'Dropped invalid channel/room ' 'Dropped invalid channel/room/user '
'(%s) specified.' % recipient, '({}) specified.'.format(recipient),
) )
if len(self.rooms) == 0 and len(self.channels) == 0: if self.mode == RocketChatAuthMode.BASIC and \
len(self.rooms) == 0 and len(self.channels) == 0:
msg = 'No Rocket.Chat room and/or channels specified to notify.' msg = 'No Rocket.Chat room and/or channels specified to notify.'
self.logger.warning(msg) self.logger.warning(msg)
raise TypeError(msg) raise TypeError(msg)
# Used to track token headers upon authentication (if successful) return
self.headers = {}
def url(self): def url(self):
""" """
@ -138,13 +212,22 @@ class NotifyRocketChat(NotifyBase):
'format': self.notify_format, 'format': self.notify_format,
'overflow': self.overflow_mode, 'overflow': self.overflow_mode,
'verify': 'yes' if self.verify_certificate else 'no', 'verify': 'yes' if self.verify_certificate else 'no',
'avatar': 'yes' if self.include_avatar else 'no',
'mode': self.mode,
} }
# Determine Authentication # Determine Authentication
if self.mode == RocketChatAuthMode.BASIC:
auth = '{user}:{password}@'.format( auth = '{user}:{password}@'.format(
user=NotifyRocketChat.quote(self.user, safe=''), user=NotifyRocketChat.quote(self.user, safe=''),
password=NotifyRocketChat.quote(self.password, safe=''), password=NotifyRocketChat.quote(self.password, safe=''),
) )
else:
auth = '{user}{webhook}@'.format(
user='{}:'.format(NotifyRocketChat.quote(self.user, safe=''))
if self.user else '',
webhook=NotifyRocketChat.quote(self.webhook, safe=''),
)
default_port = 443 if self.secure else 80 default_port = 443 if self.secure else 80
@ -160,6 +243,8 @@ class NotifyRocketChat(NotifyBase):
['#{}'.format(x) for x in self.channels], ['#{}'.format(x) for x in self.channels],
# Rooms are as is # Rooms are as is
self.rooms, self.rooms,
# Users
['@{}'.format(x) for x in self.users],
)]), )]),
args=NotifyRocketChat.urlencode(args), args=NotifyRocketChat.urlencode(args),
) )
@ -169,44 +254,103 @@ class NotifyRocketChat(NotifyBase):
wrapper to _send since we can alert more then one channel wrapper to _send since we can alert more then one channel
""" """
# Call the _send_ function applicable to whatever mode we're in
# - calls _send_webhook_notification if the mode variable is set
# - calls _send_basic_notification if the mode variable is not set
return getattr(self, '_send_{}_notification'.format(self.mode))(
body=body, title=title, notify_type=notify_type, **kwargs)
def _send_webhook_notification(self, body, title='',
notify_type=NotifyType.INFO, **kwargs):
"""
Sends a webhook notification
"""
# Our payload object
payload = self._payload(body, title, notify_type)
# Assemble our webhook URL
path = 'hooks/{}'.format(self.webhook)
# Build our list of channels/rooms/users (if any identified)
targets = ['@{}'.format(u) for u in self.users]
targets.extend(['#{}'.format(c) for c in self.channels])
targets.extend(['{}'.format(r) for r in self.rooms])
if len(targets) == 0:
# We can take an early exit
return self._send(
payload, notify_type=notify_type, path=path, **kwargs)
# Otherwise we want to iterate over each of the targets
# Initiaize our error tracking
has_error = False
headers = {
'User-Agent': self.app_id,
'Content-Type': 'application/json',
}
while len(targets):
# Retrieve our target
target = targets.pop(0)
# Assign our channel/room/user
payload['channel'] = target
if not self._send(
dumps(payload), notify_type=notify_type, path=path,
headers=headers, **kwargs):
# toggle flag
has_error = True
return not has_error
def _send_basic_notification(self, body, title='',
notify_type=NotifyType.INFO, **kwargs):
"""
Authenticates with the server using a user/pass combo for
notifications.
"""
# Track whether we authenticated okay # Track whether we authenticated okay
if not self.login(): if not self.login():
return False return False
# Prepare our message using the body only # prepare JSON Object
text = body payload = self._payload(body, title, notify_type)
# Initiaize our error tracking # Initiaize our error tracking
has_error = False has_error = False
# Create a copy of our rooms and channels to notify against # Create a copy of our channels to notify against
channels = list(self.channels) channels = list(self.channels)
rooms = list(self.rooms) _payload = payload.copy()
while len(channels) > 0: while len(channels) > 0:
# Get Channel # Get Channel
channel = channels.pop(0) channel = channels.pop(0)
_payload['channel'] = channel
if not self._send( if not self._send(
{ _payload, notify_type=notify_type, headers=self.headers,
'text': text, **kwargs):
'channel': channel,
}, notify_type=notify_type, **kwargs):
# toggle flag # toggle flag
has_error = True has_error = True
# Send all our defined room id's # Create a copy of our room id's to notify against
rooms = list(self.rooms)
_payload = payload.copy()
while len(rooms): while len(rooms):
# Get Room # Get Room
room = rooms.pop(0) room = rooms.pop(0)
_payload['roomId'] = room
if not self._send( if not self._send(
{ payload, notify_type=notify_type, headers=self.headers,
'text': text, **kwargs):
'roomId': room,
}, notify_type=notify_type, **kwargs):
# toggle flag # toggle flag
has_error = True has_error = True
@ -216,14 +360,32 @@ class NotifyRocketChat(NotifyBase):
return not has_error return not has_error
def _send(self, payload, notify_type, **kwargs): def _payload(self, body, title='', notify_type=NotifyType.INFO):
"""
Prepares a payload object
"""
# prepare JSON Object
payload = {
"text": body,
}
# apply our images if they're set to be displayed
image_url = self.image_url(notify_type)
if self.include_avatar:
payload['avatar'] = image_url
return payload
def _send(self, payload, notify_type, path='api/v1/chat.postMessage',
headers=None, **kwargs):
""" """
Perform Notify Rocket.Chat Notification Perform Notify Rocket.Chat Notification
""" """
api_url = '{}/{}'.format(self.api_url, path)
self.logger.debug('Rocket.Chat POST URL: %s (cert_verify=%r)' % ( self.logger.debug('Rocket.Chat POST URL: %s (cert_verify=%r)' % (
self.api_url + 'chat.postMessage', self.verify_certificate, api_url, self.verify_certificate))
))
self.logger.debug('Rocket.Chat Payload: %s' % str(payload)) self.logger.debug('Rocket.Chat Payload: %s' % str(payload))
# Always call throttle before any remote server i/o is made # Always call throttle before any remote server i/o is made
@ -231,9 +393,9 @@ class NotifyRocketChat(NotifyBase):
try: try:
r = requests.post( r = requests.post(
self.api_url + 'chat.postMessage', api_url,
data=payload, data=payload,
headers=self.headers, headers=headers,
verify=self.verify_certificate, verify=self.verify_certificate,
) )
if r.status_code != requests.codes.ok: if r.status_code != requests.codes.ok:
@ -243,8 +405,9 @@ class NotifyRocketChat(NotifyBase):
r.status_code, RC_HTTP_ERROR_MAP) r.status_code, RC_HTTP_ERROR_MAP)
self.logger.warning( self.logger.warning(
'Failed to send Rocket.Chat notification: ' 'Failed to send Rocket.Chat {}:notification: '
'{}{}error={}.'.format( '{}{}error={}.'.format(
self.mode,
status_str, status_str,
', ' if status_str else '', ', ' if status_str else '',
r.status_code)) r.status_code))
@ -255,12 +418,13 @@ class NotifyRocketChat(NotifyBase):
return False return False
else: else:
self.logger.info('Sent Rocket.Chat notification.') self.logger.info(
'Sent Rocket.Chat {}:notification.'.format(self.mode))
except requests.RequestException as e: except requests.RequestException as e:
self.logger.warning( self.logger.warning(
'A Connection error occured sending Rocket.Chat ' 'A Connection error occured sending Rocket.Chat '
'notification.') '{}:notification.'.format(self.mode))
self.logger.debug('Socket Exception: %s' % str(e)) self.logger.debug('Socket Exception: %s' % str(e))
# Return; we're done # Return; we're done
@ -273,14 +437,17 @@ class NotifyRocketChat(NotifyBase):
login to our server login to our server
""" """
payload = { payload = {
'username': self.user, 'username': self.user,
'password': self.password, 'password': self.password,
} }
api_url = '{}/{}'.format(self.api_url, 'api/v1/login')
try: try:
r = requests.post( r = requests.post(
self.api_url + 'login', api_url,
data=payload, data=payload,
verify=self.verify_certificate, verify=self.verify_certificate,
) )
@ -331,9 +498,12 @@ class NotifyRocketChat(NotifyBase):
""" """
logout of our server logout of our server
""" """
api_url = '{}/{}'.format(self.api_url, 'api/v1/logout')
try: try:
r = requests.post( r = requests.post(
self.api_url + 'logout', api_url,
headers=self.headers, headers=self.headers,
verify=self.verify_certificate, verify=self.verify_certificate,
) )
@ -377,18 +547,69 @@ class NotifyRocketChat(NotifyBase):
us to substantiate this object. us to substantiate this object.
""" """
try:
# Attempt to detect the webhook (if specified in the URL)
# If no webhook is specified, then we just pass along as if nothing
# happened. However if we do find a webhook, we want to rebuild our
# URL without it since it conflicts with standard URLs. Support
# %2F since that is a forward slash escaped
# rocket://webhook@host
# rocket://user:webhook@host
match = re.match(
r'^\s*(?P<schema>[^:]+://)((?P<user>[^:]+):)?'
r'(?P<webhook>[a-z0-9]+(/|%2F)'
r'[a-z0-9]+)\@(?P<url>.+)$', url, re.I)
except TypeError:
# Not a string
return None
if match:
# Re-assemble our URL without the webhook
url = '{schema}{user}{url}'.format(
schema=match.group('schema'),
user='{}@'.format(match.group('user'))
if match.group('user') else '',
url=match.group('url'),
)
results = NotifyBase.parse_url(url) results = NotifyBase.parse_url(url)
if not results: if not results:
# We're done early as we couldn't load the results # We're done early as we couldn't load the results
return results return results
if match:
# store our webhook
results['webhook'] = \
NotifyRocketChat.unquote(match.group('webhook'))
# Take on the password too in the event we're in basic mode
# We do not unquote() as this is done at a later state
results['password'] = match.group('webhook')
# Apply our targets # Apply our targets
results['targets'] = NotifyRocketChat.split_path(results['fullpath']) results['targets'] = NotifyRocketChat.split_path(results['fullpath'])
# The user may have forced the mode
if 'mode' in results['qsd'] and len(results['qsd']['mode']):
results['mode'] = \
NotifyRocketChat.unquote(results['qsd']['mode'])
# avatar icon
results['include_avatar'] = \
parse_bool(results['qsd'].get('avatar', True))
# The 'to' makes it easier to use yaml configuration # The 'to' makes it easier to use yaml configuration
if 'to' in results['qsd'] and len(results['qsd']['to']): if 'to' in results['qsd'] and len(results['qsd']['to']):
results['targets'] += \ results['targets'] += \
NotifyRocketChat.parse_list(results['qsd']['to']) NotifyRocketChat.parse_list(results['qsd']['to'])
# The 'webhook' over-ride (if specified)
if 'webhook' in results['qsd'] and len(results['qsd']['webhook']):
results['webhook'] = \
NotifyRocketChat.unquote(results['qsd']['webhook'])
return results return results

View File

@ -1423,6 +1423,9 @@ TEST_URLS = (
('rockets://', { ('rockets://', {
'instance': None, 'instance': None,
}), }),
('rocket://:@/', {
'instance': None,
}),
# No username or pass # No username or pass
('rocket://localhost', { ('rocket://localhost', {
'instance': TypeError, 'instance': TypeError,
@ -1480,7 +1483,7 @@ TEST_URLS = (
}, },
}), }),
# Several channels # Several channels
('rocket://user:pass@localhost/#channel1/#channel2/', { ('rocket://user:pass@localhost/#channel1/#channel2/?avatar=No', {
'instance': plugins.NotifyRocketChat, 'instance': plugins.NotifyRocketChat,
# The response text is expected to be the following on a success # The response text is expected to be the following on a success
'requests_response_text': { 'requests_response_text': {
@ -1504,7 +1507,7 @@ TEST_URLS = (
}, },
}), }),
# A room and channel # A room and channel
('rocket://user:pass@localhost/room/#channel', { ('rocket://user:pass@localhost/room/#channel?mode=basic', {
'instance': plugins.NotifyRocketChat, 'instance': plugins.NotifyRocketChat,
# The response text is expected to be the following on a success # The response text is expected to be the following on a success
'requests_response_text': { 'requests_response_text': {
@ -1515,8 +1518,19 @@ TEST_URLS = (
}, },
}, },
}), }),
('rocket://:@/', { # A user/pass where the pass matches a webtoken
'instance': None, # to ensure we get the right mode, we enforce basic mode
# so that web/token gets interpreted as a password
('rockets://user:pass%2Fwithslash@localhost/#channel/?mode=basic', {
'instance': plugins.NotifyRocketChat,
# The response text is expected to be the following on a success
'requests_response_text': {
'status': 'success',
'data': {
'authToken': 'abcd',
'userId': 'user',
},
},
}), }),
# A room and channel # A room and channel
('rockets://user:pass@localhost/rooma/#channela', { ('rockets://user:pass@localhost/rooma/#channela', {
@ -1531,9 +1545,36 @@ TEST_URLS = (
# Notifications will fail in this event # Notifications will fail in this event
'response': False, 'response': False,
}), }),
# A web token
('rockets://web/token@localhost/@user/#channel/roomid', {
'instance': plugins.NotifyRocketChat,
}),
('rockets://user:web/token@localhost/@user/?mode=webhook', {
'instance': plugins.NotifyRocketChat,
}),
('rockets://user:web/token@localhost?to=@user2,#channel2', {
'instance': plugins.NotifyRocketChat,
}),
('rockets://web/token@localhost/?avatar=No', {
# a simple webhook token with default values
'instance': plugins.NotifyRocketChat,
}),
('rockets://localhost/@user/?mode=webhook&webhook=web/token', {
'instance': plugins.NotifyRocketChat,
}),
('rockets://user:web/token@localhost/@user/?mode=invalid', {
# invalid mode
'instance': TypeError,
}),
('rocket://user:pass@localhost:8081/room1/room2', { ('rocket://user:pass@localhost:8081/room1/room2', {
'instance': plugins.NotifyRocketChat, 'instance': plugins.NotifyRocketChat,
# force a failure # force a failure using basic mode
'response': False,
'requests_response_code': requests.codes.internal_server_error,
}),
('rockets://user:web/token@localhost?to=@user3,#channel3', {
'instance': plugins.NotifyRocketChat,
# force a failure using webhook mode
'response': False, 'response': False,
'requests_response_code': requests.codes.internal_server_error, 'requests_response_code': requests.codes.internal_server_error,
}), }),
@ -2370,7 +2411,6 @@ def test_rest_plugins(mock_post, mock_get):
except AssertionError: except AssertionError:
# Don't mess with these entries # Don't mess with these entries
print('%s AssertionError' % url)
raise raise
except Exception as e: except Exception as e:
@ -3367,7 +3407,7 @@ def test_notify_rocketchat_plugin(mock_post, mock_get):
plugins.NotifyBase.NotifyBase.request_rate_per_sec = 0 plugins.NotifyBase.NotifyBase.request_rate_per_sec = 0
# Chat ID # Chat ID
recipients = 'l2g, lead2gold, #channel, #channel2' recipients = 'AbcD1245, @l2g, @lead2gold, #channel, #channel2'
# Authentication # Authentication
user = 'myuser' user = 'myuser'
@ -3385,7 +3425,18 @@ def test_notify_rocketchat_plugin(mock_post, mock_get):
user=user, password=password, targets=recipients) user=user, password=password, targets=recipients)
assert isinstance(obj, plugins.NotifyRocketChat) is True assert isinstance(obj, plugins.NotifyRocketChat) is True
assert len(obj.channels) == 2 assert len(obj.channels) == 2
assert len(obj.rooms) == 2 assert len(obj.users) == 2
assert len(obj.rooms) == 1
# No Webhook specified
try:
obj = plugins.NotifyRocketChat(webhook=None, mode='webhook')
# We should have thrown an exception before we get to the next
# assert line:
assert False
except TypeError:
# We're in good shape if we reach here as we got the expected error
assert True
# #
# Logout # Logout