2017-12-04 03:48:23 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
2019-02-01 03:05:56 +01:00
|
|
|
# Copyright (C) 2019 Chris Caron <lead2gold@gmail.com>
|
|
|
|
# All rights reserved.
|
2017-12-04 03:48:23 +01:00
|
|
|
#
|
2019-02-01 03:05:56 +01:00
|
|
|
# This code is licensed under the MIT License.
|
2017-12-04 03:48:23 +01:00
|
|
|
#
|
2019-02-01 03:05:56 +01:00
|
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
# of this software and associated documentation files(the "Software"), to deal
|
|
|
|
# in the Software without restriction, including without limitation the rights
|
|
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
|
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
|
|
# furnished to do so, subject to the following conditions :
|
2017-12-04 03:48:23 +01:00
|
|
|
#
|
2019-02-01 03:05:56 +01:00
|
|
|
# The above copyright notice and this permission notice shall be included in
|
|
|
|
# all copies or substantial portions of the Software.
|
2017-12-04 03:48:23 +01:00
|
|
|
#
|
2019-02-01 03:05:56 +01:00
|
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
# THE SOFTWARE.
|
2017-12-04 03:48:23 +01:00
|
|
|
|
2020-08-07 21:27:58 +02:00
|
|
|
import re
|
2019-11-15 01:41:12 +01:00
|
|
|
import os
|
2019-02-25 07:02:29 +01:00
|
|
|
import six
|
2019-10-09 18:39:31 +02:00
|
|
|
import pytest
|
2019-02-25 07:02:29 +01:00
|
|
|
import requests
|
|
|
|
import mock
|
|
|
|
from json import dumps
|
|
|
|
from random import choice
|
|
|
|
from string import ascii_uppercase as str_alpha
|
|
|
|
from string import digits as str_num
|
|
|
|
|
2017-12-04 03:48:23 +01:00
|
|
|
from apprise import plugins
|
|
|
|
from apprise import NotifyType
|
2019-02-16 06:26:33 +01:00
|
|
|
from apprise import NotifyBase
|
2017-12-04 03:48:23 +01:00
|
|
|
from apprise import Apprise
|
2017-12-11 03:28:00 +01:00
|
|
|
from apprise import AppriseAsset
|
2019-11-15 01:41:12 +01:00
|
|
|
from apprise import AppriseAttachment
|
2018-03-25 04:44:18 +02:00
|
|
|
from apprise.common import NotifyFormat
|
2019-02-16 06:26:33 +01:00
|
|
|
from apprise.common import OverflowMode
|
2018-03-25 04:44:18 +02:00
|
|
|
|
2019-02-25 07:02:29 +01:00
|
|
|
# Disable logging for a cleaner testing output
|
|
|
|
import logging
|
|
|
|
logging.disable(logging.CRITICAL)
|
2017-12-04 03:48:23 +01:00
|
|
|
|
2019-04-04 04:39:51 +02:00
|
|
|
# a test UUID we can use
|
|
|
|
UUID4 = '8b799edf-6f98-4d3a-9be7-2862fb4e5752'
|
|
|
|
|
2018-03-05 03:06:41 +01:00
|
|
|
# Some exception handling we'll use
|
|
|
|
REQUEST_EXCEPTIONS = (
|
|
|
|
requests.ConnectionError(
|
|
|
|
0, 'requests.ConnectionError() not handled'),
|
|
|
|
requests.RequestException(
|
|
|
|
0, 'requests.RequestException() not handled'),
|
|
|
|
requests.HTTPError(
|
|
|
|
0, 'requests.HTTPError() not handled'),
|
|
|
|
requests.ReadTimeout(
|
|
|
|
0, 'requests.ReadTimeout() not handled'),
|
|
|
|
requests.TooManyRedirects(
|
|
|
|
0, 'requests.TooManyRedirects() not handled'),
|
|
|
|
)
|
|
|
|
|
2019-11-15 01:41:12 +01:00
|
|
|
# Attachment Directory
|
|
|
|
TEST_VAR_DIR = os.path.join(os.path.dirname(__file__), 'var')
|
|
|
|
|
2017-12-11 03:28:00 +01:00
|
|
|
TEST_URLS = (
|
|
|
|
##################################
|
|
|
|
# NotifyBoxcar
|
|
|
|
##################################
|
|
|
|
('boxcar://', {
|
2019-06-30 21:32:12 +02:00
|
|
|
# invalid secret key
|
|
|
|
'instance': TypeError,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
# A a bad url
|
|
|
|
('boxcar://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2017-12-11 03:28:00 +01:00
|
|
|
# No secret specified
|
|
|
|
('boxcar://%s' % ('a' * 64), {
|
2019-03-27 04:06:20 +01:00
|
|
|
'instance': TypeError,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# No access specified (whitespace is trimmed)
|
|
|
|
('boxcar://%%20/%s' % ('a' * 64), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# No secret specified (whitespace is trimmed)
|
|
|
|
('boxcar://%s/%%20' % ('a' * 64), {
|
2017-12-25 21:07:41 +01:00
|
|
|
'instance': TypeError,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
# Provide both an access and a secret
|
|
|
|
('boxcar://%s/%s' % ('a' * 64, 'b' * 64), {
|
|
|
|
'instance': plugins.NotifyBoxcar,
|
|
|
|
'requests_response_code': requests.codes.created,
|
2019-09-29 23:17:25 +02:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'boxcar://a...a/****/',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
# Test without image set
|
2019-03-27 04:06:20 +01:00
|
|
|
('boxcar://%s/%s?image=True' % ('a' * 64, 'b' * 64), {
|
2017-12-11 03:28:00 +01:00
|
|
|
'instance': plugins.NotifyBoxcar,
|
|
|
|
'requests_response_code': requests.codes.created,
|
2019-03-27 04:06:20 +01:00
|
|
|
# don't include an image in Asset by default
|
2017-12-11 03:28:00 +01:00
|
|
|
'include_image': False,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('boxcar://%s/%s?image=False' % ('a' * 64, 'b' * 64), {
|
|
|
|
'instance': plugins.NotifyBoxcar,
|
|
|
|
'requests_response_code': requests.codes.created,
|
|
|
|
}),
|
2017-12-11 03:28:00 +01:00
|
|
|
# our access, secret and device are all 64 characters
|
|
|
|
# which is what we're doing here
|
2019-03-27 04:06:20 +01:00
|
|
|
('boxcar://%s/%s/@tag1/tag2///%s/?to=tag3' % (
|
2017-12-11 03:28:00 +01:00
|
|
|
'a' * 64, 'b' * 64, 'd' * 64), {
|
|
|
|
'instance': plugins.NotifyBoxcar,
|
|
|
|
'requests_response_code': requests.codes.created,
|
|
|
|
}),
|
|
|
|
# An invalid tag
|
|
|
|
('boxcar://%s/%s/@%s' % ('a' * 64, 'b' * 64, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyBoxcar,
|
|
|
|
'requests_response_code': requests.codes.created,
|
|
|
|
}),
|
|
|
|
('boxcar://%s/%s/' % ('a' * 64, 'b' * 64), {
|
|
|
|
'instance': plugins.NotifyBoxcar,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('boxcar://%s/%s/' % ('a' * 64, 'b' * 64), {
|
|
|
|
'instance': plugins.NotifyBoxcar,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('boxcar://%s/%s/' % ('a' * 64, 'b' * 64), {
|
|
|
|
'instance': plugins.NotifyBoxcar,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
2019-09-07 01:41:23 +02:00
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
|
|
|
##################################
|
|
|
|
# NotifyClickSend
|
|
|
|
##################################
|
|
|
|
('clicksend://', {
|
2019-10-09 18:39:31 +02:00
|
|
|
# We failed to identify any valid authentication
|
2019-09-07 01:41:23 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('clicksend://:@/', {
|
2019-10-09 18:39:31 +02:00
|
|
|
# We failed to identify any valid authentication
|
2019-09-07 01:41:23 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('clicksend://user:pass@{}/{}/{}'.format('1' * 10, '2' * 15, 'a' * 13), {
|
|
|
|
# invalid target numbers; we'll fail to notify anyone
|
|
|
|
'instance': plugins.NotifyClickSend,
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('clicksend://user:pass@{}?batch=yes'.format('3' * 14), {
|
|
|
|
# valid number
|
|
|
|
'instance': plugins.NotifyClickSend,
|
|
|
|
}),
|
|
|
|
('clicksend://user:pass@{}?batch=yes&to={}'.format('3' * 14, '6' * 14), {
|
|
|
|
# valid number but using the to= variable
|
|
|
|
'instance': plugins.NotifyClickSend,
|
2019-09-29 23:17:25 +02:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'clicksend://user:****',
|
2019-09-07 01:41:23 +02:00
|
|
|
}),
|
|
|
|
('clicksend://user:pass@{}?batch=no'.format('3' * 14), {
|
|
|
|
# valid number - no batch
|
|
|
|
'instance': plugins.NotifyClickSend,
|
|
|
|
}),
|
|
|
|
('clicksend://user:pass@{}'.format('3' * 14), {
|
|
|
|
'instance': plugins.NotifyClickSend,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('clicksend://user:pass@{}'.format('3' * 14), {
|
|
|
|
'instance': plugins.NotifyClickSend,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
2017-12-11 03:28:00 +01:00
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-06-27 02:34:30 +02:00
|
|
|
##################################
|
|
|
|
# NotifyD7Networks
|
|
|
|
##################################
|
|
|
|
('d7sms://', {
|
2019-10-09 18:39:31 +02:00
|
|
|
# We failed to identify any valid authentication
|
2019-06-30 21:32:12 +02:00
|
|
|
'instance': TypeError,
|
2019-06-27 02:34:30 +02:00
|
|
|
}),
|
|
|
|
('d7sms://:@/', {
|
2019-10-09 18:39:31 +02:00
|
|
|
# We failed to identify any valid authentication
|
2019-06-27 02:34:30 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}/{}/{}'.format('1' * 10, '2' * 15, 'a' * 13), {
|
2019-10-09 18:39:31 +02:00
|
|
|
# No valid targets to notify
|
2019-06-27 02:34:30 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}?batch=yes'.format('3' * 14), {
|
|
|
|
# valid number
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
2019-09-29 23:17:25 +02:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'd7sms://user:****@',
|
2019-06-27 02:34:30 +02:00
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}?batch=yes'.format('7' * 14), {
|
|
|
|
# valid number
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
# Test what happens if a batch send fails to return a messageCount
|
|
|
|
'requests_response_text': {
|
|
|
|
'data': {
|
|
|
|
'messageCount': 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
# Expected notify() response
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}?batch=yes&to={}'.format('3' * 14, '6' * 14), {
|
|
|
|
# valid number
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}?batch=yes&from=apprise'.format('3' * 14), {
|
|
|
|
# valid number, utilizing the optional from= variable
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}?batch=yes&source=apprise'.format('3' * 14), {
|
|
|
|
# valid number, utilizing the optional source= variable (same as from)
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}?priority=invalid'.format('3' * 14), {
|
|
|
|
# valid number; invalid priority
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}?priority=3'.format('3' * 14), {
|
|
|
|
# valid number; adjusted priority
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}?priority=high'.format('3' * 14), {
|
|
|
|
# valid number; adjusted priority (string supported)
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}?batch=no'.format('3' * 14), {
|
|
|
|
# valid number - no batch
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}'.format('3' * 14), {
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('d7sms://user:pass@{}'.format('3' * 14), {
|
|
|
|
'instance': plugins.NotifyD7Networks,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2018-02-26 01:59:37 +01:00
|
|
|
##################################
|
|
|
|
# NotifyDiscord
|
|
|
|
##################################
|
|
|
|
('discord://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# An invalid url
|
|
|
|
('discord://:@/', {
|
|
|
|
'instance': TypeError,
|
2018-02-26 01:59:37 +01:00
|
|
|
}),
|
|
|
|
# No webhook_token specified
|
|
|
|
('discord://%s' % ('i' * 24), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Provide both an webhook id and a webhook token
|
|
|
|
('discord://%s/%s' % ('i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
}),
|
|
|
|
# Provide a temporary username
|
|
|
|
('discord://l2g@%s/%s' % ('i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
}),
|
2020-08-28 22:49:09 +02:00
|
|
|
# test image= field
|
|
|
|
('discord://%s/%s?format=markdown&footer=Yes&image=Yes' % (
|
2019-02-06 05:11:45 +01:00
|
|
|
'i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
2020-08-28 22:49:09 +02:00
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
2018-02-26 01:59:37 +01:00
|
|
|
}),
|
2020-09-14 05:06:41 +02:00
|
|
|
('discord://%s/%s?format=markdown&footer=Yes&image=No&fields=no' % (
|
2019-03-27 04:06:20 +01:00
|
|
|
'i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
}),
|
|
|
|
('discord://%s/%s?format=markdown&footer=Yes&image=Yes' % (
|
2019-02-25 07:02:29 +01:00
|
|
|
'i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
2019-03-27 04:06:20 +01:00
|
|
|
}),
|
2020-07-19 17:08:41 +02:00
|
|
|
('https://discord.com/api/webhooks/{}/{}'.format(
|
|
|
|
'0' * 10, 'B' * 40), {
|
|
|
|
# Native URL Support, support the provided discord URL from their
|
|
|
|
# webpage.
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
}),
|
2019-06-01 02:56:54 +02:00
|
|
|
('https://discordapp.com/api/webhooks/{}/{}'.format(
|
|
|
|
'0' * 10, 'B' * 40), {
|
2020-07-19 17:08:41 +02:00
|
|
|
# Legacy Native URL Support, support the older URL (to be
|
|
|
|
# decomissioned on Nov 7th 2020)
|
2019-06-01 02:56:54 +02:00
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
}),
|
2019-10-13 00:02:05 +02:00
|
|
|
('https://discordapp.com/api/webhooks/{}/{}?footer=yes'.format(
|
|
|
|
'0' * 10, 'B' * 40), {
|
|
|
|
# Native URL Support with arguments
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
}),
|
2019-02-06 05:11:45 +01:00
|
|
|
('discord://%s/%s?format=markdown&avatar=No&footer=No' % (
|
|
|
|
'i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
2018-02-26 01:59:37 +01:00
|
|
|
}),
|
2019-02-06 04:02:42 +01:00
|
|
|
# different format support
|
|
|
|
('discord://%s/%s?format=markdown' % ('i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
}),
|
|
|
|
('discord://%s/%s?format=text' % ('i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
}),
|
2020-06-07 20:08:57 +02:00
|
|
|
# Test with avatar URL
|
|
|
|
('discord://%s/%s?avatar_url=http://localhost/test.jpg' % (
|
|
|
|
'i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
}),
|
2018-02-26 01:59:37 +01:00
|
|
|
# Test without image set
|
|
|
|
('discord://%s/%s' % ('i' * 24, 't' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
'requests_response_code': requests.codes.no_content,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
('discord://%s/%s/' % ('a' * 24, 'b' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('discord://%s/%s/' % ('a' * 24, 'b' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('discord://%s/%s/' % ('a' * 24, 'b' * 64), {
|
|
|
|
'instance': plugins.NotifyDiscord,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2018-03-05 03:06:41 +01:00
|
|
|
##################################
|
|
|
|
# NotifyEmby
|
|
|
|
##################################
|
|
|
|
# Insecure Request; no hostname specified
|
|
|
|
('emby://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
# Secure Emby Request; no hostname specified
|
|
|
|
('embys://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
# No user specified
|
|
|
|
('emby://localhost', {
|
|
|
|
# Missing a username
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('emby://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
# Valid Authentication
|
|
|
|
('emby://l2g@localhost', {
|
|
|
|
'instance': plugins.NotifyEmby,
|
|
|
|
# our response will be False because our authentication can't be
|
|
|
|
# tested very well using this matrix. It will resume in
|
|
|
|
# in test_notify_emby_plugin()
|
|
|
|
'response': False,
|
|
|
|
}),
|
|
|
|
('embys://l2g:password@localhost', {
|
|
|
|
'instance': plugins.NotifyEmby,
|
|
|
|
# our response will be False because our authentication can't be
|
|
|
|
# tested very well using this matrix. It will resume in
|
|
|
|
# in test_notify_emby_plugin()
|
|
|
|
'response': False,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'embys://l2g:****@localhost',
|
2018-03-05 03:06:41 +01:00
|
|
|
}),
|
|
|
|
# The rest of the emby tests are in test_notify_emby_plugin()
|
|
|
|
|
2019-11-29 01:12:23 +01:00
|
|
|
##################################
|
|
|
|
# NotifyEnigma2
|
|
|
|
##################################
|
|
|
|
('enigma2://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('enigma2://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('enigma2s://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('enigma2://localhost', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
# This will fail because we're also expecting a server acknowledgement
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('enigma2://localhost', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
# invalid JSON response
|
|
|
|
'requests_response_text': '{',
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('enigma2://localhost', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
# False is returned
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': False
|
|
|
|
},
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('enigma2://localhost', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
# With the right content, this will succeed
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
('enigma2://user@localhost', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
# Set timeout
|
|
|
|
('enigma2://user@localhost?timeout=-1', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
# Set timeout
|
|
|
|
('enigma2://user@localhost?timeout=-1000', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
# Set invalid timeout (defaults to a set value)
|
|
|
|
('enigma2://user@localhost?timeout=invalid', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
('enigma2://user:pass@localhost', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'enigma2://user:****@localhost',
|
|
|
|
}),
|
|
|
|
('enigma2://localhost:8080', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('enigma2://user:pass@localhost:8080', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('enigma2s://localhost', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('enigma2s://user:pass@localhost', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'enigma2s://user:****@localhost',
|
|
|
|
}),
|
|
|
|
('enigma2s://localhost:8080/path/', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'enigma2s://localhost:8080/path/',
|
|
|
|
}),
|
|
|
|
('enigma2s://user:pass@localhost:8080', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('enigma2://localhost:8080/path?-HeaderKey=HeaderValue', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('enigma2://user:pass@localhost:8081', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('enigma2://user:pass@localhost:8082', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('enigma2://user:pass@localhost:8083', {
|
|
|
|
'instance': plugins.NotifyEnigma2,
|
|
|
|
'requests_response_text': {
|
|
|
|
'result': True
|
|
|
|
},
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-14 03:35:59 +01:00
|
|
|
##################################
|
|
|
|
# NotifyFaast
|
|
|
|
##################################
|
|
|
|
('faast://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('faast://:@/', {
|
|
|
|
'instance': TypeError,
|
2017-12-14 03:35:59 +01:00
|
|
|
}),
|
|
|
|
# Auth Token specified
|
|
|
|
('faast://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyFaast,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'faast://a...a',
|
2017-12-14 03:35:59 +01:00
|
|
|
}),
|
|
|
|
('faast://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyFaast,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
('faast://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyFaast,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('faast://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyFaast,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('faast://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyFaast,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2020-12-23 20:56:28 +01:00
|
|
|
##################################
|
|
|
|
# NotifyFCM
|
|
|
|
##################################
|
|
|
|
('fcm://', {
|
|
|
|
# We failed to identify any valid authentication
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('fcm://:@/', {
|
|
|
|
# We failed to identify any valid authentication
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('fcm://project@%20%20/', {
|
|
|
|
# invalid apikey
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2021-02-14 20:03:12 +01:00
|
|
|
('fcm://apikey/', {
|
|
|
|
# no project id specified so we operate in legacy mode
|
2020-12-23 20:56:28 +01:00
|
|
|
'instance': plugins.NotifyFCM,
|
2021-02-14 20:03:12 +01:00
|
|
|
# but there are no targets specified so we return False
|
2020-12-23 20:56:28 +01:00
|
|
|
'notify_response': False,
|
|
|
|
}),
|
2021-02-14 20:03:12 +01:00
|
|
|
('fcm://apikey/device', {
|
2020-12-23 20:56:28 +01:00
|
|
|
# Valid device
|
|
|
|
'instance': plugins.NotifyFCM,
|
2021-02-14 20:03:12 +01:00
|
|
|
'privacy_url': 'fcm://a...y/device',
|
2020-12-23 20:56:28 +01:00
|
|
|
}),
|
2021-02-14 20:03:12 +01:00
|
|
|
('fcm://apikey/#topic', {
|
2020-12-23 20:56:28 +01:00
|
|
|
# Valid topic
|
|
|
|
'instance': plugins.NotifyFCM,
|
2021-02-14 20:03:12 +01:00
|
|
|
'privacy_url': 'fcm://a...y/%23topic',
|
|
|
|
}),
|
|
|
|
('fcm://apikey/device?mode=invalid', {
|
|
|
|
# Valid device, invalid mode
|
|
|
|
'instance': TypeError,
|
2020-12-23 20:56:28 +01:00
|
|
|
}),
|
2021-02-14 20:03:12 +01:00
|
|
|
('fcm://apikey/#topic1/device/%20/', {
|
2020-12-23 20:56:28 +01:00
|
|
|
# Valid topic, valid device, and invalid entry
|
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
}),
|
2021-02-14 20:03:12 +01:00
|
|
|
('fcm://apikey?to=#topic1,device', {
|
2020-12-23 20:56:28 +01:00
|
|
|
# Test to=
|
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
}),
|
2021-02-14 20:03:12 +01:00
|
|
|
('fcm://?apikey=abc123&to=device', {
|
|
|
|
# Test apikey= to=
|
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
}),
|
|
|
|
('fcm://%20?to=device&keyfile=/invalid/path', {
|
|
|
|
# invalid Project ID
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('fcm://project_id?to=device&keyfile=/invalid/path', {
|
|
|
|
# Test to= and auto detection of oauth mode
|
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
# we'll fail to send our notification as a result
|
|
|
|
'response': False,
|
|
|
|
}),
|
|
|
|
('fcm://?to=device&project=project_id&keyfile=/invalid/path', {
|
|
|
|
# Test project= & to= and auto detection of oauth mode
|
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
# we'll fail to send our notification as a result
|
|
|
|
'response': False,
|
|
|
|
}),
|
|
|
|
('fcm://project_id?to=device&mode=oauth2', {
|
|
|
|
# no keyfile was specified
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('fcm://project_id?to=device&mode=oauth2&keyfile=/invalid/path', {
|
|
|
|
# Same test as above except we explicitly set our oauth2 mode
|
|
|
|
# Test to= and auto detection of oauth mode
|
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
# we'll fail to send our notification as a result
|
|
|
|
'response': False,
|
|
|
|
}),
|
|
|
|
('fcm://apikey/#topic1/device/?mode=legacy', {
|
2020-12-23 20:56:28 +01:00
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
2021-02-14 20:03:12 +01:00
|
|
|
('fcm://apikey/#topic1/device/?mode=legacy', {
|
2020-12-23 20:56:28 +01:00
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2021-02-14 20:03:12 +01:00
|
|
|
('fcm://project/#topic1/device/?mode=oauth2&keyfile=file://{}'.format(
|
|
|
|
os.path.join(
|
|
|
|
os.path.dirname(__file__), 'var', 'fcm',
|
|
|
|
'service_account.json')), {
|
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('fcm://projectid/#topic1/device/?mode=oauth2&keyfile=file://{}'.format(
|
|
|
|
os.path.join(
|
|
|
|
os.path.dirname(__file__), 'var', 'fcm',
|
|
|
|
'service_account.json')), {
|
|
|
|
'instance': plugins.NotifyFCM,
|
|
|
|
# Throws a series of connection and transfer exceptions when
|
|
|
|
# this flag is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2019-03-12 02:17:55 +01:00
|
|
|
##################################
|
2019-03-18 00:27:34 +01:00
|
|
|
# NotifyFlock
|
|
|
|
##################################
|
|
|
|
# No token specified
|
|
|
|
('flock://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# An invalid url
|
|
|
|
('flock://:@/', {
|
|
|
|
'instance': TypeError,
|
2019-03-18 00:27:34 +01:00
|
|
|
}),
|
|
|
|
# Provide a token
|
|
|
|
('flock://%s' % ('t' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
# Image handling
|
|
|
|
('flock://%s?image=True' % ('t' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'flock://t...t',
|
2019-03-27 04:06:20 +01:00
|
|
|
}),
|
|
|
|
('flock://%s?image=False' % ('t' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
|
|
|
('flock://%s?image=True' % ('t' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
# Run test when image is set to True, but one couldn't actually be
|
|
|
|
# loaded from the Asset Object.
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
# Test to=
|
|
|
|
('flock://%s?to=u:%s&format=markdown' % ('i' * 24, 'u' * 12), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
2019-03-18 00:27:34 +01:00
|
|
|
# Provide markdown format
|
|
|
|
('flock://%s?format=markdown' % ('i' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
|
|
|
# Provide text format
|
|
|
|
('flock://%s?format=text' % ('i' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
2019-06-01 02:56:54 +02:00
|
|
|
# Native URL Support, take the slack URL and still build from it
|
|
|
|
('https://api.flock.com/hooks/sendMessage/{}/'.format('i' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
2019-10-13 00:02:05 +02:00
|
|
|
# Native URL Support with arguments
|
|
|
|
('https://api.flock.com/hooks/sendMessage/{}/?format=markdown'.format(
|
|
|
|
'i' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
2019-03-18 00:27:34 +01:00
|
|
|
# Bot API presumed if one or more targets are specified
|
|
|
|
# Provide markdown format
|
|
|
|
('flock://%s/u:%s?format=markdown' % ('i' * 24, 'u' * 12), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
|
|
|
# Bot API presumed if one or more targets are specified
|
|
|
|
# Provide text format
|
|
|
|
('flock://%s/u:%s?format=html' % ('i' * 24, 'u' * 12), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
|
|
|
# Bot API presumed if one or more targets are specified
|
|
|
|
# u: is optional
|
|
|
|
('flock://%s/%s?format=text' % ('i' * 24, 'u' * 12), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
|
|
|
# Bot API presumed if one or more targets are specified
|
|
|
|
# Multi-entries
|
|
|
|
('flock://%s/g:%s/u:%s?format=text' % ('i' * 24, 'g' * 12, 'u' * 12), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
|
|
|
# Bot API presumed if one or more targets are specified
|
|
|
|
# Multi-entries using @ for user and # for channel
|
|
|
|
('flock://%s/#%s/@%s?format=text' % ('i' * 24, 'g' * 12, 'u' * 12), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
|
|
|
# Bot API presumed if one or more targets are specified
|
|
|
|
# has bad entry
|
|
|
|
('flock://%s/g:%s/u:%s?format=text' % ('i' * 24, 'g' * 12, 'u' * 10), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# Invalid user/group defined
|
|
|
|
('flock://%s/g:/u:?format=text' % ('i' * 24), {
|
2019-03-18 00:27:34 +01:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# we don't focus on the invalid length of the user/group fields.
|
|
|
|
# As a result, the following will load and pass the data upstream
|
|
|
|
('flock://%s/g:%s/u:%s?format=text' % ('i' * 24, 'g' * 14, 'u' * 10), {
|
|
|
|
# We will still instantiate the object
|
|
|
|
'instance': plugins.NotifyFlock,
|
2019-03-18 00:27:34 +01:00
|
|
|
}),
|
|
|
|
# Error Testing
|
|
|
|
('flock://%s/g:%s/u:%s?format=text' % ('i' * 24, 'g' * 12, 'u' * 10), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('flock://%s/' % ('t' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('flock://%s/' % ('t' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('flock://%s/' % ('t' * 24), {
|
|
|
|
'instance': plugins.NotifyFlock,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-03-25 03:45:44 +01:00
|
|
|
##################################
|
|
|
|
# NotifyGitter
|
|
|
|
##################################
|
|
|
|
('gitter://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-03-25 03:45:44 +01:00
|
|
|
}),
|
|
|
|
('gitter://:@/', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-03-25 03:45:44 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# Invalid Token Length
|
2019-03-25 03:45:44 +01:00
|
|
|
('gitter://%s' % ('a' * 12), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# Token specified but no channel
|
2019-03-25 03:45:44 +01:00
|
|
|
('gitter://%s' % ('a' * 40), {
|
2019-10-09 18:39:31 +02:00
|
|
|
'instance': TypeError,
|
2019-03-25 03:45:44 +01:00
|
|
|
}),
|
|
|
|
# Token + channel
|
2019-10-09 18:39:31 +02:00
|
|
|
('gitter://%s/apprise' % ('b' * 40), {
|
2019-03-25 03:45:44 +01:00
|
|
|
'instance': plugins.NotifyGitter,
|
|
|
|
'response': False,
|
|
|
|
}),
|
|
|
|
# include image in post
|
2019-10-09 18:39:31 +02:00
|
|
|
('gitter://%s/apprise?image=Yes' % ('c' * 40), {
|
2019-03-25 03:45:44 +01:00
|
|
|
'instance': plugins.NotifyGitter,
|
|
|
|
'response': False,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
2019-10-09 18:39:31 +02:00
|
|
|
'privacy_url': 'gitter://c...c/apprise',
|
2019-03-25 03:45:44 +01:00
|
|
|
}),
|
|
|
|
# Don't include image in post (this is the default anyway)
|
2019-10-09 18:39:31 +02:00
|
|
|
('gitter://%s/apprise?image=Yes' % ('d' * 40), {
|
2019-03-25 03:45:44 +01:00
|
|
|
'instance': plugins.NotifyGitter,
|
|
|
|
'response': False,
|
2019-10-09 18:39:31 +02:00
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
2019-03-25 03:45:44 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# Don't include image in post (this is the default anyway)
|
|
|
|
('gitter://%s/apprise?image=No' % ('e' * 40), {
|
|
|
|
'instance': plugins.NotifyGitter,
|
|
|
|
'response': False,
|
|
|
|
}),
|
|
|
|
('gitter://%s/apprise' % ('f' * 40), {
|
2019-03-25 03:45:44 +01:00
|
|
|
'instance': plugins.NotifyGitter,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('gitter://%s/apprise' % ('g' * 40), {
|
2019-03-25 03:45:44 +01:00
|
|
|
'instance': plugins.NotifyGitter,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('gitter://%s/apprise' % ('h' * 40), {
|
2019-03-25 03:45:44 +01:00
|
|
|
'instance': plugins.NotifyGitter,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2021-01-11 20:23:52 +01:00
|
|
|
##################################
|
|
|
|
# NotifyGoogleChat
|
|
|
|
##################################
|
|
|
|
('gchat://', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('gchat://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Workspace, but not Key or Token
|
|
|
|
('gchat://workspace', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Workspace and key, but no Token
|
|
|
|
('gchat://workspace/key/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Credentials are good
|
|
|
|
('gchat://workspace/key/token', {
|
|
|
|
'instance': plugins.NotifyGoogleChat,
|
|
|
|
'privacy_url': 'gchat://w...e/k...y/t...n',
|
|
|
|
}),
|
|
|
|
# Test arguments
|
|
|
|
('gchat://?workspace=ws&key=mykey&token=mytoken', {
|
|
|
|
'instance': plugins.NotifyGoogleChat,
|
|
|
|
'privacy_url': 'gchat://w...s/m...y/m...n',
|
|
|
|
}),
|
|
|
|
# Google Native Webhohok URL
|
|
|
|
('https://chat.googleapis.com/v1/spaces/myworkspace/messages'
|
|
|
|
'?key=mykey&token=mytoken', {
|
|
|
|
'instance': plugins.NotifyGoogleChat,
|
|
|
|
'privacy_url': 'gchat://m...e/m...y/m...n'}),
|
|
|
|
|
|
|
|
('gchat://workspace/key/token', {
|
|
|
|
'instance': plugins.NotifyGoogleChat,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('gchat://workspace/key/token', {
|
|
|
|
'instance': plugins.NotifyGoogleChat,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('gchat://workspace/key/token', {
|
|
|
|
'instance': plugins.NotifyGoogleChat,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-03-18 00:27:34 +01:00
|
|
|
##################################
|
2019-03-12 02:17:55 +01:00
|
|
|
# NotifyGotify
|
|
|
|
##################################
|
|
|
|
('gotify://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
# No token specified
|
|
|
|
('gotify://hostname', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Provide a hostname and token
|
|
|
|
('gotify://hostname/%s' % ('t' * 16), {
|
|
|
|
'instance': plugins.NotifyGotify,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'gotify://hostname/t...t',
|
2019-03-12 02:17:55 +01:00
|
|
|
}),
|
2020-07-27 17:10:54 +02:00
|
|
|
# Provide a hostname, path, and token
|
|
|
|
('gotify://hostname/a/path/ending/in/a/slash/%s' % ('u' * 16), {
|
|
|
|
'instance': plugins.NotifyGotify,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'gotify://hostname/a/path/ending/in/a/slash/u...u/',
|
|
|
|
}),
|
2021-02-17 23:44:10 +01:00
|
|
|
# Markdown test
|
|
|
|
('gotify://hostname/%s?format=markdown' % ('t' * 16), {
|
|
|
|
'instance': plugins.NotifyGotify,
|
|
|
|
}),
|
2020-07-27 17:10:54 +02:00
|
|
|
# Provide a hostname, path, and token
|
|
|
|
('gotify://hostname/a/path/not/ending/in/a/slash/%s' % ('v' * 16), {
|
|
|
|
'instance': plugins.NotifyGotify,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'gotify://hostname/a/path/not/ending/in/a/slash/v...v/',
|
|
|
|
}),
|
2019-03-12 02:17:55 +01:00
|
|
|
# Provide a priority
|
|
|
|
('gotify://hostname/%s?priority=high' % ('i' * 16), {
|
|
|
|
'instance': plugins.NotifyGotify,
|
|
|
|
}),
|
|
|
|
# Provide an invalid priority
|
|
|
|
('gotify://hostname:8008/%s?priority=invalid' % ('i' * 16), {
|
|
|
|
'instance': plugins.NotifyGotify,
|
|
|
|
}),
|
|
|
|
# An invalid url
|
|
|
|
('gotify://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('gotify://hostname/%s/' % ('t' * 16), {
|
|
|
|
'instance': plugins.NotifyGotify,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('gotifys://localhost/%s/' % ('t' * 16), {
|
|
|
|
'instance': plugins.NotifyGotify,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('gotify://localhost/%s/' % ('t' * 16), {
|
|
|
|
'instance': plugins.NotifyGotify,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2021-02-14 20:01:30 +01:00
|
|
|
##################################
|
|
|
|
# NotifyHomeAssistant
|
|
|
|
##################################
|
|
|
|
('hassio://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('hassio://', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('hassios://', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# No Long Lived Access Token specified
|
|
|
|
('hassio://user@localhost', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('hassio://localhost/long-lived-access-token', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
}),
|
|
|
|
('hassio://user:pass@localhost/long-lived-access-token/', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'hassio://user:****@localhost/l...n',
|
|
|
|
}),
|
|
|
|
('hassio://localhost:80/long-lived-access-token', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
}),
|
|
|
|
('hassio://user@localhost:8123/llat', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
'privacy_url': 'hassio://user@localhost/l...t',
|
|
|
|
}),
|
|
|
|
('hassios://localhost/llat?nid=!%', {
|
|
|
|
# Invalid notification_id
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('hassios://localhost/llat?nid=abcd', {
|
|
|
|
# Valid notification_id
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
}),
|
|
|
|
('hassios://user:pass@localhost/llat', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
'privacy_url': 'hassios://user:****@localhost/l...t',
|
|
|
|
}),
|
|
|
|
('hassios://localhost:8443/path/llat/', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
'privacy_url': 'hassios://localhost:8443/path/l...t',
|
|
|
|
}),
|
|
|
|
('hassio://localhost:8123/a/path?accesstoken=llat', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
# Default port; so it's stripped off
|
|
|
|
# accesstoken was specified as kwarg
|
|
|
|
'privacy_url': 'hassio://localhost/a/path/l...t',
|
|
|
|
}),
|
|
|
|
('hassios://user:password@localhost:80/llat/', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
|
|
|
|
'privacy_url': 'hassios://user:****@localhost:80',
|
|
|
|
}),
|
|
|
|
('hassio://user:pass@localhost:8123/llat', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('hassio://user:pass@localhost/llat', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('hassio://user:pass@localhost/llat', {
|
|
|
|
'instance': plugins.NotifyHomeAssistant,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2018-03-09 02:20:51 +01:00
|
|
|
##################################
|
|
|
|
# NotifyIFTTT - If This Than That
|
|
|
|
##################################
|
|
|
|
('ifttt://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('ifttt://:@/', {
|
|
|
|
'instance': TypeError,
|
2018-03-09 02:20:51 +01:00
|
|
|
}),
|
|
|
|
# No User
|
|
|
|
('ifttt://EventID/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-02-17 19:45:48 +01:00
|
|
|
# A nicely formed ifttt url with 1 event and a new key/value store
|
|
|
|
('ifttt://WebHookID@EventID/?+TemplateKey=TemplateVal', {
|
|
|
|
'instance': plugins.NotifyIFTTT,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'ifttt://W...D',
|
2019-02-17 19:45:48 +01:00
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
# Test to= in which case we set the host to the webhook id
|
|
|
|
('ifttt://WebHookID?to=EventID,EventID2', {
|
|
|
|
'instance': plugins.NotifyIFTTT,
|
|
|
|
}),
|
2019-02-17 19:45:48 +01:00
|
|
|
# Removing certain keys:
|
|
|
|
('ifttt://WebHookID@EventID/?-Value1=&-Value2', {
|
|
|
|
'instance': plugins.NotifyIFTTT,
|
|
|
|
}),
|
2019-02-13 23:48:09 +01:00
|
|
|
# A nicely formed ifttt url with 2 events defined:
|
|
|
|
('ifttt://WebHookID@EventID/EventID2/', {
|
|
|
|
'instance': plugins.NotifyIFTTT,
|
|
|
|
}),
|
2019-10-13 00:02:05 +02:00
|
|
|
# Support Native URL references
|
2019-06-01 02:56:54 +02:00
|
|
|
('https://maker.ifttt.com/use/WebHookID/', {
|
|
|
|
# No EventID specified
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('https://maker.ifttt.com/use/WebHookID/EventID/', {
|
|
|
|
'instance': plugins.NotifyIFTTT,
|
|
|
|
}),
|
2019-10-13 00:02:05 +02:00
|
|
|
# Native URL with arguments
|
|
|
|
('https://maker.ifttt.com/use/WebHookID/EventID/?-Value1=', {
|
|
|
|
'instance': plugins.NotifyIFTTT,
|
|
|
|
}),
|
2018-03-09 02:20:51 +01:00
|
|
|
# Test website connection failures
|
|
|
|
('ifttt://WebHookID@EventID', {
|
|
|
|
'instance': plugins.NotifyIFTTT,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('ifttt://WebHookID@EventID', {
|
|
|
|
'instance': plugins.NotifyIFTTT,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('ifttt://WebHookID@EventID', {
|
|
|
|
'instance': plugins.NotifyIFTTT,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-14 03:35:59 +01:00
|
|
|
##################################
|
|
|
|
# NotifyJoin
|
|
|
|
##################################
|
|
|
|
('join://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# API Key + bad url
|
|
|
|
('join://:@/', {
|
|
|
|
'instance': TypeError,
|
2017-12-14 03:35:59 +01:00
|
|
|
}),
|
|
|
|
# APIkey; no device
|
|
|
|
('join://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + device (using to=)
|
2019-03-27 04:06:20 +01:00
|
|
|
('join://%s?to=%s' % ('a' * 32, 'd' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'join://a...a/',
|
2019-03-27 04:06:20 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + priority setting
|
|
|
|
('join://%s?priority=high' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
}),
|
|
|
|
# API Key + invalid priority setting
|
|
|
|
('join://%s?priority=invalid' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
}),
|
|
|
|
# API Key + priority setting (empty)
|
|
|
|
('join://%s?priority=' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
}),
|
|
|
|
# API Key + device
|
2019-03-27 04:06:20 +01:00
|
|
|
('join://%s@%s?image=True' % ('a' * 32, 'd' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
}),
|
|
|
|
# No image
|
|
|
|
('join://%s@%s?image=False' % ('a' * 32, 'd' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
}),
|
2020-02-21 00:48:10 +01:00
|
|
|
# API Key + Device Name
|
|
|
|
('join://%s/%s' % ('a' * 32, 'My Device'), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
2019-10-09 18:39:31 +02:00
|
|
|
}),
|
|
|
|
# API Key + device
|
2017-12-14 03:35:59 +01:00
|
|
|
('join://%s/%s' % ('a' * 32, 'd' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + 2 devices
|
2017-12-14 03:35:59 +01:00
|
|
|
('join://%s/%s/%s' % ('a' * 32, 'd' * 32, 'e' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + 1 device and 1 group
|
2017-12-14 03:35:59 +01:00
|
|
|
('join://%s/%s/%s' % ('a' * 32, 'd' * 32, 'group.chrome'), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
}),
|
|
|
|
('join://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('join://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('join://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyJoin,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-04 03:48:23 +01:00
|
|
|
##################################
|
|
|
|
# NotifyJSON
|
|
|
|
##################################
|
2019-10-27 19:32:51 +01:00
|
|
|
('json://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
2017-12-04 03:48:23 +01:00
|
|
|
('json://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
2017-12-04 04:28:46 +01:00
|
|
|
('jsons://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
2017-12-04 03:48:23 +01:00
|
|
|
('json://localhost', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
|
|
|
}),
|
|
|
|
('json://user:pass@localhost', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'json://user:****@localhost',
|
2017-12-04 03:48:23 +01:00
|
|
|
}),
|
2019-02-13 23:48:09 +01:00
|
|
|
('json://user@localhost', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
|
|
|
}),
|
2017-12-04 03:48:23 +01:00
|
|
|
('json://localhost:8080', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
|
|
|
}),
|
|
|
|
('json://user:pass@localhost:8080', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
|
|
|
}),
|
|
|
|
('jsons://localhost', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
|
|
|
}),
|
|
|
|
('jsons://user:pass@localhost', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
|
|
|
}),
|
|
|
|
('jsons://localhost:8080/path/', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
2019-10-27 19:32:51 +01:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'jsons://localhost:8080/path/',
|
2017-12-04 03:48:23 +01:00
|
|
|
}),
|
2019-09-29 23:17:25 +02:00
|
|
|
('jsons://user:password@localhost:8080', {
|
2017-12-04 03:48:23 +01:00
|
|
|
'instance': plugins.NotifyJSON,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'jsons://user:****@localhost:8080',
|
2017-12-04 03:48:23 +01:00
|
|
|
}),
|
2019-10-27 19:32:51 +01:00
|
|
|
('json://localhost:8080/path?-HeaderKey=HeaderValue', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
2017-12-06 06:35:03 +01:00
|
|
|
}),
|
2017-12-04 03:48:23 +01:00
|
|
|
('json://user:pass@localhost:8081', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
2017-12-11 03:28:00 +01:00
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
2017-12-04 03:48:23 +01:00
|
|
|
}),
|
|
|
|
('json://user:pass@localhost:8082', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('json://user:pass@localhost:8083', {
|
|
|
|
'instance': plugins.NotifyJSON,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
2017-12-04 04:28:46 +01:00
|
|
|
}),
|
2019-02-15 23:37:55 +01:00
|
|
|
|
2020-01-29 19:08:19 +01:00
|
|
|
##################################
|
|
|
|
# NotifyKavenegar
|
|
|
|
##################################
|
|
|
|
('kavenegar://', {
|
|
|
|
# We failed to identify any valid authentication
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('kavenegar://:@/', {
|
|
|
|
# We failed to identify any valid authentication
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('kavenegar://{}/{}/{}'.format('1' * 10, '2' * 15, 'a' * 13), {
|
|
|
|
# No valid targets to notify
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('kavenegar://{}/{}'.format('a' * 24, '3' * 14), {
|
|
|
|
# valid api key and valid number
|
|
|
|
'instance': plugins.NotifyKavenegar,
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'kavenegar://a...a/',
|
|
|
|
}),
|
|
|
|
('kavenegar://{}?to={}'.format('a' * 24, '3' * 14), {
|
|
|
|
# valid api key and valid number
|
|
|
|
'instance': plugins.NotifyKavenegar,
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'kavenegar://a...a/',
|
|
|
|
}),
|
|
|
|
('kavenegar://{}@{}/{}'.format('1' * 14, 'b' * 24, '3' * 14), {
|
|
|
|
# valid api key and valid number
|
|
|
|
'instance': plugins.NotifyKavenegar,
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'kavenegar://{}@b...b/'.format('1' * 14),
|
|
|
|
}),
|
|
|
|
('kavenegar://{}@{}/{}'.format('a' * 14, 'b' * 24, '3' * 14), {
|
|
|
|
# invalid from number
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('kavenegar://{}@{}/{}'.format('3' * 4, 'b' * 24, '3' * 14), {
|
|
|
|
# invalid from number
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('kavenegar://{}/{}?from={}'.format('b' * 24, '3' * 14, '1' * 14), {
|
|
|
|
# valid api key and valid number
|
|
|
|
'instance': plugins.NotifyKavenegar,
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'kavenegar://{}@b...b/'.format('1' * 14),
|
|
|
|
}),
|
|
|
|
('kavenegar://{}/{}'.format('b' * 24, '4' * 14), {
|
|
|
|
'instance': plugins.NotifyKavenegar,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('kavenegar://{}/{}'.format('c' * 24, '5' * 14), {
|
|
|
|
'instance': plugins.NotifyKavenegar,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-11 03:28:00 +01:00
|
|
|
##################################
|
|
|
|
# NotifyKODI
|
|
|
|
##################################
|
|
|
|
('kodi://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('kodis://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('kodi://localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
2020-08-08 15:08:49 +02:00
|
|
|
('kodi://192.168.4.1', {
|
|
|
|
# Support IPv4 Addresses
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
|
|
|
('kodi://[2001:db8:002a:3256:adfe:05c0:0003:0006]', {
|
|
|
|
# Support IPv6 Addresses
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
2017-12-11 03:28:00 +01:00
|
|
|
('kodi://user:pass@localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'kodi://user:****@localhost',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('kodi://localhost:8080', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
|
|
|
('kodi://user:pass@localhost:8080', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
|
|
|
('kodis://localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
|
|
|
('kodis://user:pass@localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
|
|
|
('kodis://localhost:8080/path/', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
2019-09-29 23:17:25 +02:00
|
|
|
('kodis://user:password@localhost:8080', {
|
2017-12-11 03:28:00 +01:00
|
|
|
'instance': plugins.NotifyXBMC,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'kodis://user:****@localhost:8080',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('kodi://localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# Experement with different notification types
|
|
|
|
'notify_type': NotifyType.WARNING,
|
|
|
|
}),
|
|
|
|
('kodi://localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# Experement with different notification types
|
|
|
|
'notify_type': NotifyType.FAILURE,
|
|
|
|
}),
|
|
|
|
('kodis://localhost:443', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
('kodi://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('kodi://user:pass@localhost:8081', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('kodi://user:pass@localhost:8082', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('kodi://user:pass@localhost:8083', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-09-12 04:10:32 +02:00
|
|
|
##################################
|
|
|
|
# NotifyKumulos
|
|
|
|
##################################
|
|
|
|
('kumulos://', {
|
|
|
|
# No API or Server Key specified
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-09-12 04:10:32 +02:00
|
|
|
}),
|
|
|
|
('kumulos://:@/', {
|
|
|
|
# No API or Server Key specified
|
|
|
|
# We don't have strict host checking on for kumulos, so this URL
|
|
|
|
# actually becomes parseable and :@ becomes a hostname.
|
|
|
|
# The below errors because a second token wasn't found
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-09-12 04:10:32 +02:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('kumulos://{}/'.format(UUID4), {
|
|
|
|
# No server key was specified
|
2019-09-12 04:10:32 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('kumulos://{}/{}/'.format(UUID4, 'w' * 36), {
|
|
|
|
# Everything is okay
|
|
|
|
'instance': plugins.NotifyKumulos,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'kumulos://8...2/w...w/',
|
2019-09-12 04:10:32 +02:00
|
|
|
}),
|
|
|
|
('kumulos://{}/{}/'.format(UUID4, 'x' * 36), {
|
|
|
|
'instance': plugins.NotifyKumulos,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'kumulos://8...2/x...x/',
|
2019-09-12 04:10:32 +02:00
|
|
|
}),
|
|
|
|
('kumulos://{}/{}/'.format(UUID4, 'y' * 36), {
|
|
|
|
'instance': plugins.NotifyKumulos,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'kumulos://8...2/y...y/',
|
2019-09-12 04:10:32 +02:00
|
|
|
}),
|
|
|
|
('kumulos://{}/{}/'.format(UUID4, 'z' * 36), {
|
|
|
|
'instance': plugins.NotifyKumulos,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2020-08-07 21:27:58 +02:00
|
|
|
##################################
|
|
|
|
# NotifyLametric
|
|
|
|
##################################
|
|
|
|
('lametric://', {
|
2020-09-14 04:13:27 +02:00
|
|
|
# No APIKey or App ID specified
|
2020-08-07 21:27:58 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('lametric://:@/', {
|
2020-09-14 04:13:27 +02:00
|
|
|
# No APIKey or App ID specified
|
2020-08-07 21:27:58 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2020-09-14 04:13:27 +02:00
|
|
|
('lametric://{}/'.format(
|
|
|
|
'com.lametric.941c51dff3135bd87aa72db9d855dd50'), {
|
|
|
|
# No APIKey specified
|
|
|
|
'instance': TypeError,
|
2020-08-07 21:27:58 +02:00
|
|
|
}),
|
|
|
|
('lametric://root:{}@192.168.0.5:8080/'.format(UUID4), {
|
|
|
|
# Everything is okay; this would be picked up in Device Mode
|
|
|
|
# We're using a default port and enforcing a special user
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametric://root:8...2@192.168.0.5/',
|
|
|
|
}),
|
|
|
|
('lametric://{}@192.168.0.4:8000/'.format(UUID4), {
|
|
|
|
# Everything is okay; this would be picked up in Device Mode
|
|
|
|
# Port is enforced
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametric://8...2@192.168.0.4:8000/',
|
|
|
|
}),
|
|
|
|
('lametric://{}@192.168.0.5/'.format(UUID4), {
|
|
|
|
# Everything is okay; this would be picked up in Device Mode
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametric://8...2@192.168.0.5/',
|
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.0.6/?mode=device'.format(UUID4), {
|
|
|
|
# Everything is okay; Device mode forced
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametrics://8...2@192.168.0.6/',
|
|
|
|
}),
|
2020-09-14 04:13:27 +02:00
|
|
|
# Support Native URL (with Access Token Argument)
|
|
|
|
('https://developer.lametric.com/api/v1/dev/widget/update/'
|
|
|
|
'com.lametric.ABCD123/1?token={}=='.format('D' * 88), {
|
|
|
|
# Everything is okay; Device mode forced
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametric://D...=@A...3/1/',
|
|
|
|
}),
|
|
|
|
|
2020-08-07 21:27:58 +02:00
|
|
|
('lametric://192.168.2.8/?mode=device&apikey=abc123', {
|
|
|
|
# Everything is okay; Device mode forced
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametric://a...3@192.168.2.8/',
|
|
|
|
}),
|
2020-09-14 04:13:27 +02:00
|
|
|
('lametrics://{}==@com.lametric.941c51dff3135bd87aa72db9d855dd50/'
|
|
|
|
'?mode=cloud&app_ver=2'.format('A' * 88), {
|
|
|
|
# Everything is okay; Cloud mode forced
|
|
|
|
# We gracefully strip off the com.lametric. part as well
|
|
|
|
# We also set an application version of 2
|
|
|
|
'instance': plugins.NotifyLametric,
|
2020-08-07 21:27:58 +02:00
|
|
|
|
2020-09-14 04:13:27 +02:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametric://A...=@9...0/',
|
|
|
|
}),
|
|
|
|
('lametrics://{}==@com.lametric.941c51dff3135bd87aa72db9d855dd50/'
|
|
|
|
'?app_ver=invalid'.format('A' * 88), {
|
|
|
|
# We set invalid app version
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# our lametric object initialized via argument
|
|
|
|
('lametric://?app=com.lametric.941c51dff3135bd87aa72db9d855dd50&token={}=='
|
|
|
|
'&mode=cloud'.format('B' * 88), {
|
|
|
|
# Everything is okay; Cloud mode forced
|
|
|
|
'instance': plugins.NotifyLametric,
|
2020-08-07 21:27:58 +02:00
|
|
|
|
2020-09-14 04:13:27 +02:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametric://B...=@9...0/',
|
|
|
|
}),
|
|
|
|
('lametrics://{}==@abcd/?mode=cloud&sound=knock&icon_type=info'
|
|
|
|
'&priority=critical&cycles=10'.format('C' * 88), {
|
2020-08-07 21:27:58 +02:00
|
|
|
# Cloud mode forced, sound, icon_type, and priority not supported
|
|
|
|
# with cloud mode so warnings are created
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
2020-09-14 04:13:27 +02:00
|
|
|
'privacy_url': 'lametric://C...=@a...d/',
|
2020-08-07 21:27:58 +02:00
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.0.7/?mode=invalid'.format(UUID4), {
|
|
|
|
# Invalid Mode
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.0.6/?sound=alarm1'.format(UUID4), {
|
|
|
|
# Device mode with sound set to alarm1
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.0.7/?sound=bike'.format(UUID4), {
|
|
|
|
# Device mode with sound set to bicycle using alias
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
# Bike is an alias,
|
|
|
|
'url_matches': r'sound=bicycle',
|
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.0.8/?sound=invalid!'.format(UUID4), {
|
|
|
|
# Invalid sounds just produce warnings... object still loads
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.0.9/?icon_type=alert'.format(UUID4), {
|
|
|
|
# Icon Type Changed
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
# icon=alert exists somewhere on our generated URL
|
|
|
|
'url_matches': r'icon_type=alert',
|
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.0.10/?icon_type=invalid'.format(UUID4), {
|
|
|
|
# Invalid icon types just produce warnings... object still loads
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametric://{}@192.168.1.1/?priority=warning'.format(UUID4), {
|
|
|
|
# Priority changed
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.1.2/?priority=invalid'.format(UUID4), {
|
|
|
|
# Invalid priority just produce warnings... object still loads
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
2020-09-02 03:46:21 +02:00
|
|
|
('lametric://{}@192.168.1.2/?icon=230'.format(UUID4), {
|
|
|
|
# Our custom icon by it's ID
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.1.2/?icon=#230'.format(UUID4), {
|
|
|
|
# Our custom icon by it's ID; the hashtag at the front is ignored
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametric://{}@192.168.1.2/?icon=Heart'.format(UUID4), {
|
|
|
|
# Our custom icon; the hashtag at the front is ignored
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametric://{}@192.168.1.2/?icon=#'.format(UUID4), {
|
|
|
|
# a hashtag and nothing else
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametric://{}@192.168.1.2/?icon=#%20%20%20'.format(UUID4), {
|
|
|
|
# a hashtag and some spaces
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
2020-08-07 21:27:58 +02:00
|
|
|
('lametric://{}@192.168.1.3/?cycles=2'.format(UUID4), {
|
|
|
|
# Cycles changed
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametric://{}@192.168.1.4/?cycles=-1'.format(UUID4), {
|
|
|
|
# Cycles changed (out of range)
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametrics://{}@192.168.1.5/?cycles=invalid'.format(UUID4), {
|
|
|
|
# Invalid priority just produce warnings... object still loads
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
}),
|
|
|
|
('lametric://{}@example.com/'.format(UUID4), {
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametric://8...2@example.com/',
|
|
|
|
}),
|
|
|
|
('lametrics://{}@example.ca/'.format(UUID4), {
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'lametrics://8...2@example.ca/',
|
|
|
|
}),
|
|
|
|
('lametrics://{}@example.net/'.format(UUID4), {
|
|
|
|
'instance': plugins.NotifyLametric,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-04-27 23:41:20 +02:00
|
|
|
##################################
|
|
|
|
# NotifyMailgun
|
|
|
|
##################################
|
|
|
|
('mailgun://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-04-27 23:41:20 +02:00
|
|
|
}),
|
|
|
|
('mailgun://:@/', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-04-27 23:41:20 +02:00
|
|
|
}),
|
|
|
|
# No Token specified
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain', {
|
2019-04-27 23:41:20 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Token is valid, but no user name specified
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://localhost.localdomain/{}-{}-{}'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
2019-04-27 23:41:20 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Invalid from email address
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://!@localhost.localdomain/{}-{}-{}'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
2019-04-27 23:41:20 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# No To email address, but everything else is valid
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
2019-04-27 23:41:20 +02:00
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
2020-10-06 16:43:46 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}?format=markdown'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}?format=html'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}?format=text'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
2019-04-27 23:41:20 +02:00
|
|
|
# valid url with region specified (case insensitve)
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}?region=uS'.format(
|
2019-04-27 23:41:20 +02:00
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
|
|
|
# valid url with region specified (case insensitve)
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}?region=EU'.format(
|
2019-04-27 23:41:20 +02:00
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
|
|
|
# invalid url with region specified (case insensitve)
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}?region=invalid'.format(
|
2019-04-27 23:41:20 +02:00
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2020-10-06 16:43:46 +02:00
|
|
|
# headers
|
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}'
|
|
|
|
'?+X-Customer-Campaign-ID=Apprise'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
|
|
|
# template tokens
|
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}'
|
|
|
|
'?:name=Chris&:status=admin'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
|
|
|
# bcc and cc
|
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}'
|
|
|
|
'?bcc=user@example.com&cc=user2@example.com'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
2019-04-27 23:41:20 +02:00
|
|
|
# One To Email address
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}/test@example.com'.format(
|
2019-04-27 23:41:20 +02:00
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/'
|
|
|
|
'{}-{}-{}?to=test@example.com'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun}),
|
2019-04-27 23:41:20 +02:00
|
|
|
# One To Email address, a from name specified too
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}/'
|
|
|
|
'test@example.com?name="Frodo"'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun}),
|
2020-10-06 16:43:46 +02:00
|
|
|
# Invalid 'To' Email address
|
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}/invalid'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
# Expected notify() response
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
# Multiple 'To', 'Cc', and 'Bcc' addresses (with invalid ones)
|
|
|
|
('mailgun://user@example.com/{}-{}-{}/{}?bcc={}&cc={}'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8,
|
|
|
|
'/'.join(('user1@example.com', 'invalid', 'User2:user2@example.com')),
|
|
|
|
','.join(('user3@example.com', 'i@v', 'User1:user1@example.com')),
|
|
|
|
','.join(('user4@example.com', 'g@r@b', 'Da:user5@example.com'))), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
}),
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}'.format(
|
2019-04-27 23:41:20 +02:00
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
2019-04-27 23:41:20 +02:00
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
2020-05-04 03:34:15 +02:00
|
|
|
('mailgun://user@localhost.localdomain/{}-{}-{}'.format(
|
|
|
|
'a' * 32, 'b' * 8, 'c' * 8), {
|
2019-04-27 23:41:20 +02:00
|
|
|
'instance': plugins.NotifyMailgun,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-01-02 20:25:53 +01:00
|
|
|
##################################
|
|
|
|
# NotifyMatrix
|
|
|
|
##################################
|
|
|
|
('matrix://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('matrixs://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
2019-12-23 01:10:54 +01:00
|
|
|
('matrix://localhost?mode=off', {
|
2019-03-10 00:35:15 +01:00
|
|
|
# treats it as a anonymous user to register
|
2019-01-02 20:25:53 +01:00
|
|
|
'instance': plugins.NotifyMatrix,
|
2019-03-10 00:35:15 +01:00
|
|
|
# response is false because we have nothing to notify
|
|
|
|
'response': False,
|
2019-01-02 20:25:53 +01:00
|
|
|
}),
|
2019-12-23 01:10:54 +01:00
|
|
|
('matrix://localhost', {
|
|
|
|
# response is TypeError because we'll try to initialize as
|
|
|
|
# a t2bot and fail (localhost is too short of a api key)
|
|
|
|
'instance': TypeError
|
|
|
|
}),
|
2019-03-10 00:35:15 +01:00
|
|
|
('matrix://user:pass@localhost/#room1/#room2/#room3', {
|
2019-01-02 20:25:53 +01:00
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
2019-03-10 00:35:15 +01:00
|
|
|
('matrix://user:pass@localhost/#room1/#room2/!room1', {
|
2019-01-02 20:25:53 +01:00
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
2019-03-10 00:35:15 +01:00
|
|
|
('matrix://user:pass@localhost:1234/#room', {
|
2019-01-02 20:25:53 +01:00
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'matrix://user:****@localhost:1234/',
|
2019-01-02 20:25:53 +01:00
|
|
|
}),
|
|
|
|
|
2019-03-17 19:20:51 +01:00
|
|
|
# Matrix supports webhooks too; the following tests this now:
|
2019-03-27 04:06:20 +01:00
|
|
|
('matrix://user:token@localhost?mode=matrix&format=text', {
|
|
|
|
# user and token correctly specified with webhook
|
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
'response': False,
|
|
|
|
}),
|
|
|
|
('matrix://user:token@localhost?mode=matrix&format=html', {
|
|
|
|
# user and token correctly specified with webhook
|
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
}),
|
|
|
|
('matrix://user:token@localhost?mode=slack&format=text', {
|
|
|
|
# user and token correctly specified with webhook
|
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
}),
|
|
|
|
('matrixs://user:token@localhost?mode=SLACK&format=markdown', {
|
2019-03-17 19:20:51 +01:00
|
|
|
# user and token specified; slack webhook still detected
|
|
|
|
# despite uppercase characters
|
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
# Image Reference
|
|
|
|
('matrixs://user:token@localhost?mode=slack&format=markdown&image=True', {
|
|
|
|
# user and token specified; image set to True
|
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
}),
|
|
|
|
('matrixs://user:token@localhost?mode=slack&format=markdown&image=False', {
|
|
|
|
# user and token specified; image set to True
|
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
}),
|
2019-12-23 01:10:54 +01:00
|
|
|
('matrixs://user@{}?mode=t2bot&format=markdown&image=True'
|
|
|
|
.format('a' * 64), {
|
|
|
|
# user and token specified; image set to True
|
|
|
|
'instance': plugins.NotifyMatrix}),
|
|
|
|
('matrix://user@{}?mode=t2bot&format=markdown&image=False'
|
|
|
|
.format('z' * 64), {
|
|
|
|
# user and token specified; image set to True
|
|
|
|
'instance': plugins.NotifyMatrix}),
|
|
|
|
# This will default to t2bot because no targets were specified and no
|
|
|
|
# password
|
|
|
|
('matrixs://{}'.format('c' * 64), {
|
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
# Test Native URL
|
|
|
|
('https://webhooks.t2bot.io/api/v1/matrix/hook/{}/'.format('d' * 64), {
|
|
|
|
# user and token specified; image set to True
|
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('matrix://user:token@localhost?mode=On', {
|
2019-03-17 19:20:51 +01:00
|
|
|
# invalid webhook specified (unexpected boolean)
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('matrix://token@localhost/?mode=Matrix', {
|
2019-03-17 19:20:51 +01:00
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('matrix://user:token@localhost/mode=matrix', {
|
2019-03-17 19:20:51 +01:00
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('matrix://token@localhost:8080/?mode=slack', {
|
2019-03-17 19:20:51 +01:00
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2019-12-23 01:10:54 +01:00
|
|
|
('matrix://{}/?mode=t2bot'.format('b' * 64), {
|
|
|
|
'instance': plugins.NotifyMatrix,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2019-03-17 19:20:51 +01:00
|
|
|
|
2017-12-04 04:28:46 +01:00
|
|
|
##################################
|
2021-02-06 20:55:49 +01:00
|
|
|
# NotifyMattermost
|
2017-12-04 04:28:46 +01:00
|
|
|
##################################
|
|
|
|
('mmost://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('mmosts://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('mmost://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('mmosts://localhost', {
|
|
|
|
# Thrown because there was no webhook id specified
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2017-12-04 04:28:46 +01:00
|
|
|
('mmost://localhost/3ccdd113474722377935511fc85d3dd4', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2017-12-04 04:28:46 +01:00
|
|
|
}),
|
|
|
|
('mmost://user@localhost/3ccdd113474722377935511fc85d3dd4?channel=test', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2017-12-04 04:28:46 +01:00
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('mmost://user@localhost/3ccdd113474722377935511fc85d3dd4?to=test', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'mmost://user@localhost/3...4/',
|
2019-03-27 04:06:20 +01:00
|
|
|
}),
|
|
|
|
('mmost://localhost/3ccdd113474722377935511fc85d3dd4'
|
|
|
|
'?to=test&image=True', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('mmost://localhost/3ccdd113474722377935511fc85d3dd4' \
|
|
|
|
'?to=test&image=False', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('mmost://localhost/3ccdd113474722377935511fc85d3dd4' \
|
|
|
|
'?to=test&image=True', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2019-03-27 04:06:20 +01:00
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False}),
|
2017-12-04 04:28:46 +01:00
|
|
|
('mmost://localhost:8080/3ccdd113474722377935511fc85d3dd4', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'mmost://localhost:8080/3...4/',
|
2017-12-04 04:28:46 +01:00
|
|
|
}),
|
2020-08-08 15:08:49 +02:00
|
|
|
('mmost://localhost:8080/3ccdd113474722377935511fc85d3dd4', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2017-12-04 04:28:46 +01:00
|
|
|
}),
|
|
|
|
('mmost://localhost:invalid-port/3ccdd113474722377935511fc85d3dd4', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('mmosts://localhost/3ccdd113474722377935511fc85d3dd4', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2017-12-04 04:28:46 +01:00
|
|
|
}),
|
2019-06-06 18:40:14 +02:00
|
|
|
# Test our paths
|
|
|
|
('mmosts://localhost/a/path/3ccdd113474722377935511fc85d3dd4', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2019-06-06 18:40:14 +02:00
|
|
|
}),
|
|
|
|
('mmosts://localhost/////3ccdd113474722377935511fc85d3dd4///', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2019-06-06 18:40:14 +02:00
|
|
|
}),
|
2017-12-04 04:28:46 +01:00
|
|
|
('mmost://localhost/3ccdd113474722377935511fc85d3dd4', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2017-12-04 04:28:46 +01:00
|
|
|
# force a failure
|
|
|
|
'response': False,
|
2017-12-11 03:28:00 +01:00
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
2017-12-04 04:28:46 +01:00
|
|
|
}),
|
|
|
|
('mmost://localhost/3ccdd113474722377935511fc85d3dd4', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2017-12-04 04:28:46 +01:00
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('mmost://localhost/3ccdd113474722377935511fc85d3dd4', {
|
2021-02-06 20:55:49 +01:00
|
|
|
'instance': plugins.NotifyMattermost,
|
2017-12-04 04:28:46 +01:00
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2017-12-11 03:28:00 +01:00
|
|
|
|
2019-04-04 04:39:51 +02:00
|
|
|
##################################
|
|
|
|
# NotifyMSTeams
|
|
|
|
##################################
|
|
|
|
('msteams://', {
|
2019-06-30 21:32:12 +02:00
|
|
|
# First API Token not specified
|
|
|
|
'instance': TypeError,
|
2019-04-04 04:39:51 +02:00
|
|
|
}),
|
|
|
|
('msteams://:@/', {
|
|
|
|
# We don't have strict host checking on for msteams, so this URL
|
|
|
|
# actually becomes parseable and :@ becomes a hostname.
|
|
|
|
# The below errors because a second token wasn't found
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msteams://{}'.format(UUID4), {
|
|
|
|
# Just half of one token 1 provided
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msteams://{}@{}/'.format(UUID4, UUID4), {
|
|
|
|
# Just 1 tokens provided
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msteams://{}@{}/{}'.format(UUID4, UUID4, 'a' * 32), {
|
|
|
|
# Just 2 tokens provided
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msteams://{}@{}/{}/{}?t1'.format(UUID4, UUID4, 'a' * 32, UUID4), {
|
|
|
|
# All tokens provided - we're good
|
|
|
|
'instance': plugins.NotifyMSTeams,
|
|
|
|
}),
|
2019-06-01 02:56:54 +02:00
|
|
|
# Support native URLs
|
|
|
|
('https://outlook.office.com/webhook/{}@{}/IncomingWebhook/{}/{}'
|
|
|
|
.format(UUID4, UUID4, 'a' * 32, UUID4), {
|
|
|
|
# All tokens provided - we're good
|
|
|
|
'instance': plugins.NotifyMSTeams}),
|
|
|
|
|
2021-02-22 20:35:28 +01:00
|
|
|
# Legacy URL Formatting
|
2019-04-04 04:39:51 +02:00
|
|
|
('msteams://{}@{}/{}/{}?t2'.format(UUID4, UUID4, 'a' * 32, UUID4), {
|
|
|
|
# All tokens provided - we're good
|
|
|
|
'instance': plugins.NotifyMSTeams,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
2021-02-22 20:35:28 +01:00
|
|
|
# Legacy URL Formatting
|
2019-04-04 04:39:51 +02:00
|
|
|
('msteams://{}@{}/{}/{}?image=No'.format(UUID4, UUID4, 'a' * 32, UUID4), {
|
|
|
|
# All tokens provided - we're good no image
|
|
|
|
'instance': plugins.NotifyMSTeams,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
2021-02-22 20:35:28 +01:00
|
|
|
'privacy_url': 'msteams://outlook/8...2/a...a/8...2/',
|
|
|
|
}),
|
|
|
|
# New 2021 URL formatting
|
|
|
|
('msteams://apprise/{}@{}/{}/{}'.format(
|
|
|
|
UUID4, UUID4, 'a' * 32, UUID4), {
|
|
|
|
# All tokens provided - we're good no image
|
|
|
|
'instance': plugins.NotifyMSTeams,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'msteams://apprise/8...2/a...a/8...2/',
|
|
|
|
}),
|
|
|
|
# New 2021 URL formatting; support team= argument
|
|
|
|
('msteams://{}@{}/{}/{}?team=teamname'.format(
|
|
|
|
UUID4, UUID4, 'a' * 32, UUID4), {
|
|
|
|
# All tokens provided - we're good no image
|
|
|
|
'instance': plugins.NotifyMSTeams,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'msteams://teamname/8...2/a...a/8...2/',
|
2019-04-04 04:39:51 +02:00
|
|
|
}),
|
|
|
|
('msteams://{}@{}/{}/{}?tx'.format(UUID4, UUID4, 'a' * 32, UUID4), {
|
|
|
|
'instance': plugins.NotifyMSTeams,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('msteams://{}@{}/{}/{}?ty'.format(UUID4, UUID4, 'a' * 32, UUID4), {
|
|
|
|
'instance': plugins.NotifyMSTeams,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('msteams://{}@{}/{}/{}?tz'.format(UUID4, UUID4, 'a' * 32, UUID4), {
|
|
|
|
'instance': plugins.NotifyMSTeams,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2017-12-14 03:35:59 +01:00
|
|
|
|
2019-09-29 23:17:25 +02:00
|
|
|
##################################
|
|
|
|
# NotifyNexmo
|
|
|
|
##################################
|
|
|
|
('nexmo://', {
|
|
|
|
# No API Key specified
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('nexmo://:@/', {
|
|
|
|
# invalid Auth key
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://AC{}@12345678'.format('a' * 8), {
|
2019-09-29 23:17:25 +02:00
|
|
|
# Just a key provided
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://AC{}:{}@{}'.format('a' * 8, 'b' * 16, '3' * 9), {
|
2019-09-29 23:17:25 +02:00
|
|
|
# key and secret provided and from but invalid from no
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://AC{}:{}@{}/?ttl=0'.format('b' * 8, 'c' * 16, '3' * 11), {
|
2019-09-29 23:17:25 +02:00
|
|
|
# Invalid ttl defined
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://AC{}:{}@{}'.format('d' * 8, 'e' * 16, 'a' * 11), {
|
|
|
|
# Invalid source number
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('nexmo://AC{}:{}@{}/123/{}/abcd/'.format(
|
|
|
|
'f' * 8, 'g' * 16, '3' * 11, '9' * 15), {
|
2019-09-29 23:17:25 +02:00
|
|
|
# valid everything but target numbers
|
|
|
|
'instance': plugins.NotifyNexmo,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
2019-10-09 18:39:31 +02:00
|
|
|
'privacy_url': 'nexmo://A...f:****@',
|
2019-09-29 23:17:25 +02:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://AC{}:{}@{}'.format('h' * 8, 'i' * 16, '5' * 11), {
|
2019-09-29 23:17:25 +02:00
|
|
|
# using phone no with no target - we text ourselves in
|
|
|
|
# this case
|
|
|
|
'instance': plugins.NotifyNexmo,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://_?key=AC{}&secret={}&from={}'.format(
|
2019-09-29 23:17:25 +02:00
|
|
|
'a' * 8, 'b' * 16, '5' * 11), {
|
|
|
|
# use get args to acomplish the same thing
|
|
|
|
'instance': plugins.NotifyNexmo,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://_?key=AC{}&secret={}&source={}'.format(
|
2019-09-29 23:17:25 +02:00
|
|
|
'a' * 8, 'b' * 16, '5' * 11), {
|
|
|
|
# use get args to acomplish the same thing (use source instead of from)
|
|
|
|
'instance': plugins.NotifyNexmo,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://_?key=AC{}&secret={}&from={}&to={}'.format(
|
2019-09-29 23:17:25 +02:00
|
|
|
'a' * 8, 'b' * 16, '5' * 11, '7' * 13), {
|
|
|
|
# use to=
|
|
|
|
'instance': plugins.NotifyNexmo,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://AC{}:{}@{}'.format('a' * 8, 'b' * 16, '6' * 11), {
|
2019-09-29 23:17:25 +02:00
|
|
|
'instance': plugins.NotifyNexmo,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('nexmo://AC{}:{}@{}'.format('a' * 8, 'b' * 16, '6' * 11), {
|
2019-09-29 23:17:25 +02:00
|
|
|
'instance': plugins.NotifyNexmo,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-10-19 15:28:31 +02:00
|
|
|
##################################
|
|
|
|
# NotifyNotica
|
|
|
|
##################################
|
|
|
|
('notica://', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('notica://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Native URL
|
|
|
|
('https://notica.us/?%s' % ('z' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
2019-10-27 19:07:47 +01:00
|
|
|
'privacy_url': 'notica://z...z/',
|
|
|
|
}),
|
|
|
|
# Native URL with additional arguments
|
|
|
|
('https://notica.us/?%s&overflow=upstream' % ('z' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'notica://z...z/',
|
2019-10-19 15:28:31 +02:00
|
|
|
}),
|
|
|
|
# Token specified
|
|
|
|
('notica://%s' % ('a' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
2019-10-27 19:07:47 +01:00
|
|
|
'privacy_url': 'notica://a...a/',
|
|
|
|
}),
|
|
|
|
# Self-Hosted configuration
|
|
|
|
('notica://localhost/%s' % ('b' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
}),
|
|
|
|
('notica://user@localhost/%s' % ('c' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
}),
|
|
|
|
('notica://user:pass@localhost/%s/' % ('d' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'notica://user:****@localhost/d...d',
|
|
|
|
}),
|
|
|
|
('notica://user:pass@localhost/a/path/%s/' % ('r' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'notica://user:****@localhost/a/path/r...r',
|
|
|
|
}),
|
|
|
|
('notica://localhost:8080/%s' % ('a' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
}),
|
|
|
|
('notica://user:pass@localhost:8080/%s' % ('b' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
}),
|
|
|
|
('noticas://localhost/%s' % ('j' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
'privacy_url': 'noticas://localhost/j...j',
|
|
|
|
}),
|
|
|
|
('noticas://user:pass@localhost/%s' % ('e' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'noticas://user:****@localhost/e...e',
|
|
|
|
}),
|
|
|
|
('noticas://localhost:8080/path/%s' % ('5' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
'privacy_url': 'noticas://localhost:8080/path/5...5',
|
|
|
|
}),
|
|
|
|
('noticas://user:pass@localhost:8080/%s' % ('6' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
2019-10-19 15:28:31 +02:00
|
|
|
}),
|
|
|
|
('notica://%s' % ('b' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
2019-10-27 19:07:47 +01:00
|
|
|
# Test Header overrides
|
|
|
|
('notica://localhost:8080//%s/?+HeaderKey=HeaderValue' % ('7' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
}),
|
2020-09-27 02:14:55 +02:00
|
|
|
# Test Depricated Header overrides
|
|
|
|
('notica://localhost:8080//%s/?-HeaderKey=HeaderValue' % ('7' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
}),
|
2019-10-19 15:28:31 +02:00
|
|
|
('notica://%s' % ('c' * 6), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('notica://%s' % ('d' * 7), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('notica://%s' % ('e' * 8), {
|
|
|
|
'instance': plugins.NotifyNotica,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-10-13 19:59:02 +02:00
|
|
|
##################################
|
|
|
|
# NotifyNotifico
|
|
|
|
##################################
|
|
|
|
('notifico://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-10-13 19:59:02 +02:00
|
|
|
}),
|
|
|
|
('notifico://:@/', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-10-13 19:59:02 +02:00
|
|
|
}),
|
|
|
|
('notifico://1234', {
|
|
|
|
# Just a project id provided (no message token)
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('notifico://abcd/ckhrjW8w672m6HG', {
|
|
|
|
# an invalid project id provided
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG', {
|
|
|
|
# A project id and message hook provided
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG?prefix=no', {
|
|
|
|
# Disable our prefix
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG?color=yes', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
'notify_type': 'info',
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG?color=yes', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
'notify_type': 'success',
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG?color=yes', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
'notify_type': 'warning',
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG?color=yes', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
'notify_type': 'failure',
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG?color=yes', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
'notify_type': 'invalid',
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG?color=no', {
|
|
|
|
# Test our color flag by having it set to off
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'notifico://1...4/c...G',
|
|
|
|
}),
|
|
|
|
# Support Native URLs
|
|
|
|
('https://n.tkte.ch/h/2144/uJmKaBW9WFk42miB146ci3Kj', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('notifico://1234/ckhrjW8w672m6HG', {
|
|
|
|
'instance': plugins.NotifyNotifico,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-12-13 01:37:05 +01:00
|
|
|
##################################
|
|
|
|
# NotifyNextcloud
|
|
|
|
##################################
|
|
|
|
('ncloud://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('ncloud://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('nclouds://', {
|
|
|
|
# No hostname
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('ncloud://localhost', {
|
|
|
|
# No user specified
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('ncloud://localhost/admin', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
}),
|
|
|
|
('ncloud://user@localhost/admin', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
}),
|
|
|
|
('ncloud://user@localhost?to=user1,user2', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
}),
|
|
|
|
('ncloud://user:pass@localhost/user1/user2', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'ncloud://user:****@localhost/user1/user2',
|
|
|
|
}),
|
|
|
|
('ncloud://user:pass@localhost:8080/admin', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
}),
|
|
|
|
('nclouds://user:pass@localhost/admin', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'nclouds://user:****@localhost/admin',
|
|
|
|
}),
|
|
|
|
('nclouds://user:pass@localhost:8080/admin/', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
}),
|
|
|
|
('ncloud://localhost:8080/admin?-HeaderKey=HeaderValue', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
}),
|
|
|
|
('ncloud://user:pass@localhost:8081/admin', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('ncloud://user:pass@localhost:8082/admin', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('ncloud://user:pass@localhost:8083/user1/user2/user3', {
|
|
|
|
'instance': plugins.NotifyNextcloud,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2020-05-04 03:34:15 +02:00
|
|
|
##################################
|
|
|
|
# NotifyOffice365
|
|
|
|
##################################
|
|
|
|
('o365://', {
|
|
|
|
# Missing tenant, client_id, secret, and targets!
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('o365://:@/', {
|
|
|
|
# invalid url
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('o365://{tenant}:{aid}/{cid}/{secret}/{targets}'.format(
|
|
|
|
# invalid tenant
|
|
|
|
tenant=',',
|
|
|
|
cid='ab-cd-ef-gh',
|
|
|
|
aid='user@example.com',
|
|
|
|
secret='abcd/123/3343/@jack/test',
|
|
|
|
targets='/'.join(['email1@test.ca'])), {
|
|
|
|
|
|
|
|
# We're valid and good to go
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('o365://{tenant}:{aid}/{cid}/{secret}/{targets}'.format(
|
|
|
|
tenant='tenant',
|
|
|
|
# invalid client id
|
|
|
|
cid='ab.',
|
|
|
|
aid='user@example.com',
|
|
|
|
secret='abcd/123/3343/@jack/test',
|
|
|
|
targets='/'.join(['email1@test.ca'])), {
|
|
|
|
|
|
|
|
# We're valid and good to go
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('o365://{tenant}:{aid}/{cid}/{secret}/{targets}'.format(
|
|
|
|
tenant='tenant',
|
|
|
|
cid='ab-cd-ef-gh',
|
|
|
|
aid='user@example.com',
|
|
|
|
secret='abcd/123/3343/@jack/test',
|
|
|
|
targets='/'.join(['email1@test.ca'])), {
|
|
|
|
|
|
|
|
# We're valid and good to go
|
|
|
|
'instance': plugins.NotifyOffice365,
|
|
|
|
|
|
|
|
# Test what happens if a batch send fails to return a messageCount
|
|
|
|
'requests_response_text': {
|
|
|
|
'expires_in': 2000,
|
|
|
|
'access_token': 'abcd1234',
|
|
|
|
},
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'o365://t...t:user@example.com/a...h/' \
|
|
|
|
'****/email1%40test.ca/'}),
|
|
|
|
# test our arguments
|
|
|
|
('o365://_/?oauth_id={cid}&oauth_secret={secret}&tenant={tenant}'
|
|
|
|
'&to={targets}&from={aid}'.format(
|
|
|
|
tenant='tenant',
|
|
|
|
cid='ab-cd-ef-gh',
|
|
|
|
aid='user@example.com',
|
|
|
|
secret='abcd/123/3343/@jack/test',
|
|
|
|
targets='email1@test.ca'),
|
|
|
|
{
|
|
|
|
# We're valid and good to go
|
|
|
|
'instance': plugins.NotifyOffice365,
|
|
|
|
|
|
|
|
# Test what happens if a batch send fails to return a messageCount
|
|
|
|
'requests_response_text': {
|
|
|
|
'expires_in': 2000,
|
|
|
|
'access_token': 'abcd1234',
|
|
|
|
},
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'o365://t...t:user@example.com/a...h/' \
|
|
|
|
'****/email1%40test.ca/'}),
|
|
|
|
# Test invalid JSON (no tenant defaults to email domain)
|
|
|
|
('o365://{tenant}:{aid}/{cid}/{secret}/{targets}'.format(
|
|
|
|
tenant='tenant',
|
|
|
|
cid='ab-cd-ef-gh',
|
|
|
|
aid='user@example.com',
|
|
|
|
secret='abcd/123/3343/@jack/test',
|
|
|
|
targets='/'.join(['email1@test.ca'])), {
|
|
|
|
|
|
|
|
# We're valid and good to go
|
|
|
|
'instance': plugins.NotifyOffice365,
|
|
|
|
|
|
|
|
# invalid JSON response
|
|
|
|
'requests_response_text': '{',
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
# No Targets specified
|
|
|
|
('o365://{tenant}:{aid}/{cid}/{secret}'.format(
|
|
|
|
tenant='tenant',
|
|
|
|
cid='ab-cd-ef-gh',
|
|
|
|
aid='user@example.com',
|
|
|
|
secret='abcd/123/3343/@jack/test'), {
|
|
|
|
|
|
|
|
# We're valid and good to go
|
|
|
|
'instance': plugins.NotifyOffice365,
|
|
|
|
|
|
|
|
# There were no targets to notify; so we use our own email
|
|
|
|
'requests_response_text': {
|
|
|
|
'expires_in': 2000,
|
|
|
|
'access_token': 'abcd1234',
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('o365://{tenant}:{aid}/{cid}/{secret}/{targets}'.format(
|
|
|
|
tenant='tenant',
|
|
|
|
cid='zz-zz-zz-zz',
|
|
|
|
aid='user@example.com',
|
|
|
|
secret='abcd/abc/dcba/@john/test',
|
|
|
|
targets='/'.join(['email1@test.ca'])), {
|
|
|
|
'instance': plugins.NotifyOffice365,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('o365://{tenant}:{aid}/{cid}/{secret}/{targets}'.format(
|
|
|
|
tenant='tenant',
|
|
|
|
cid='01-12-23-34',
|
|
|
|
aid='user@example.com',
|
|
|
|
secret='abcd/321/4321/@test/test',
|
|
|
|
targets='/'.join(['email1@test.ca'])), {
|
|
|
|
'instance': plugins.NotifyOffice365,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2020-12-29 16:49:33 +01:00
|
|
|
##################################
|
|
|
|
# NotifyOneSignal
|
|
|
|
##################################
|
|
|
|
('onesignal://', {
|
|
|
|
# We failed to identify any valid authentication
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('onesignal://:@/', {
|
|
|
|
# We failed to identify any valid authentication
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('onesignal://apikey/', {
|
|
|
|
# no app id specified
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('onesignal://appid@%20%20/', {
|
|
|
|
# invalid apikey
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('onesignal://appid@apikey/playerid/?lang=X', {
|
|
|
|
# invalid language id (must be 2 characters)
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('onesignal://appid@apikey/', {
|
|
|
|
# No targets specified; we will initialize but not notify anything
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('onesignal://appid@apikey/playerid', {
|
|
|
|
# Valid playerid
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
'privacy_url': 'onesignal://a...d@a...y/playerid',
|
|
|
|
}),
|
|
|
|
('onesignal://appid@apikey/player', {
|
|
|
|
# Valid player id
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
('onesignal://appid@apikey/@user?image=no', {
|
|
|
|
# Valid userid, no image
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
}),
|
|
|
|
('onesignal://appid@apikey/user@email.com/#seg/player/@user/%20/a', {
|
|
|
|
# Valid email, valid playerid, valid user, invalid entry (%20),
|
|
|
|
# and too short of an entry (a)
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
}),
|
|
|
|
('onesignal://appid@apikey?to=#segment,playerid', {
|
|
|
|
# Test to=
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
}),
|
2020-12-30 22:29:23 +01:00
|
|
|
('onesignal://appid@apikey/#segment/@user/?batch=yes', {
|
|
|
|
# Test batch=
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
}),
|
|
|
|
('onesignal://appid@apikey/#segment/@user/?batch=no', {
|
|
|
|
# Test batch=
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
}),
|
2020-12-29 16:49:33 +01:00
|
|
|
('onesignal://templateid:appid@apikey/playerid', {
|
|
|
|
# Test Template ID
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
}),
|
|
|
|
('onesignal://appid@apikey/playerid/?lang=es&subtitle=Sub', {
|
|
|
|
# Test Language and Subtitle Over-ride
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
}),
|
|
|
|
('onesignal://?apikey=abc&template=tp&app=123&to=playerid', {
|
|
|
|
# Test Kwargs
|
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
}),
|
2020-12-30 21:55:16 +01:00
|
|
|
('onesignal://appid@apikey/#segment/playerid/', {
|
2020-12-29 16:49:33 +01:00
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
2020-12-30 21:55:16 +01:00
|
|
|
('onesignal://appid@apikey/#segment/playerid/', {
|
2020-12-29 16:49:33 +01:00
|
|
|
'instance': plugins.NotifyOneSignal,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2020-12-30 21:55:16 +01:00
|
|
|
##################################
|
|
|
|
# NotifyOpsgenie
|
|
|
|
##################################
|
|
|
|
('opsgenie://', {
|
|
|
|
# We failed to identify any valid authentication
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('opsgenie://:@/', {
|
|
|
|
# We failed to identify any valid authentication
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('opsgenie://%20%20/', {
|
|
|
|
# invalid apikey specified
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/user/?region=xx', {
|
|
|
|
# invalid region id
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/', {
|
|
|
|
# No targets specified; this is allowed
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/user', {
|
|
|
|
# Valid user
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
'privacy_url': 'opsgenie://a...y/%40user',
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/@user?region=eu', {
|
|
|
|
# European Region
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/@user?entity=A%20Entity', {
|
|
|
|
# Assign an entity
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/@user?alias=An%20Alias', {
|
|
|
|
# Assign an alias
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/@user?priority=p3', {
|
|
|
|
# Assign our priority
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/?tags=comma,separated', {
|
|
|
|
# Test our our 'tags' (tag is reserved in Apprise) but not 'tags'
|
|
|
|
# Also test the fact we do not need to define a target
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/@user?priority=invalid', {
|
|
|
|
# Invalid priority (loads using default)
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/user@email.com/#team/*sche/^esc/%20/a', {
|
|
|
|
# Valid user (email), valid schedule, Escalated ID,
|
|
|
|
# an invalid entry (%20), and too short of an entry (a)
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/{}/@{}/#{}/*{}/^{}/'.format(
|
|
|
|
UUID4, UUID4, UUID4, UUID4, UUID4), {
|
|
|
|
# similar to the above, except we use the UUID's
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey?to=#team,user&+key=value&+type=override', {
|
|
|
|
# Test to= and details (key/value pair) also override 'type'
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/#team/@user/?batch=yes', {
|
|
|
|
# Test batch=
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/#team/@user/?batch=no', {
|
|
|
|
# Test batch=
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://?apikey=abc&to=user', {
|
|
|
|
# Test Kwargs
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/#team/user/', {
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('opsgenie://apikey/#topic1/device/', {
|
|
|
|
'instance': plugins.NotifyOpsgenie,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2020-10-20 02:01:06 +02:00
|
|
|
##################################
|
|
|
|
# NotifyParsePlatform
|
|
|
|
##################################
|
|
|
|
('parsep://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
# API Key + bad url
|
|
|
|
('parsep://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
# APIkey; no app_id or master_key
|
|
|
|
('parsep://%s' % ('a' * 32), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# APIkey; no master_key
|
|
|
|
('parsep://app_id@%s' % ('a' * 32), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# APIkey; no app_id
|
|
|
|
('parseps://:master_key@%s' % ('a' * 32), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# app_id + master_key (using arguments=)
|
|
|
|
('parseps://localhost?app_id=%s&master_key=%s' % ('a' * 32, 'd' * 32), {
|
|
|
|
'instance': plugins.NotifyParsePlatform,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'parseps://a...a:d...d@localhost',
|
|
|
|
}),
|
|
|
|
# Set a device id + custom port
|
|
|
|
('parsep://app_id:master_key@localhost:8080?device=ios', {
|
|
|
|
'instance': plugins.NotifyParsePlatform,
|
|
|
|
}),
|
|
|
|
# invalid device id
|
|
|
|
('parsep://app_id:master_key@localhost?device=invalid', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Normal Query
|
|
|
|
('parseps://app_id:master_key@localhost', {
|
|
|
|
'instance': plugins.NotifyParsePlatform,
|
|
|
|
}),
|
|
|
|
('parseps://app_id:master_key@localhost', {
|
|
|
|
'instance': plugins.NotifyParsePlatform,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('parseps://app_id:master_key@localhost', {
|
|
|
|
'instance': plugins.NotifyParsePlatform,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('parseps://app_id:master_key@localhost', {
|
|
|
|
'instance': plugins.NotifyParsePlatform,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-23 04:47:46 +01:00
|
|
|
##################################
|
|
|
|
# NotifyProwl
|
|
|
|
##################################
|
|
|
|
('prowl://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# bad url
|
|
|
|
('prowl://:@/', {
|
|
|
|
'instance': TypeError,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# Invalid API Key
|
|
|
|
('prowl://%s' % ('a' * 20), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Provider Key
|
|
|
|
('prowl://%s/%s' % ('a' * 40, 'b' * 40), {
|
2017-12-23 04:47:46 +01:00
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# Invalid Provider Key
|
|
|
|
('prowl://%s/%s' % ('a' * 40, 'b' * 20), {
|
2017-12-25 21:07:41 +01:00
|
|
|
'instance': TypeError,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# APIkey; no device
|
|
|
|
('prowl://%s' % ('a' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
}),
|
|
|
|
# API Key
|
2017-12-23 04:47:46 +01:00
|
|
|
('prowl://%s' % ('a' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + priority setting
|
2017-12-23 04:47:46 +01:00
|
|
|
('prowl://%s?priority=high' % ('a' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + invalid priority setting
|
2017-12-23 04:47:46 +01:00
|
|
|
('prowl://%s?priority=invalid' % ('a' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + priority setting (empty)
|
2017-12-23 04:47:46 +01:00
|
|
|
('prowl://%s?priority=' % ('a' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + No Provider Key (empty)
|
2019-09-29 23:17:25 +02:00
|
|
|
('prowl://%s///' % ('w' * 40), {
|
2017-12-23 04:47:46 +01:00
|
|
|
'instance': plugins.NotifyProwl,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'prowl://w...w/',
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + Provider Key
|
2017-12-23 04:47:46 +01:00
|
|
|
('prowl://%s/%s' % ('a' * 40, 'b' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'prowl://a...a/b...b',
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + with image
|
2017-12-23 04:47:46 +01:00
|
|
|
('prowl://%s' % ('a' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
}),
|
|
|
|
('prowl://%s' % ('a' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('prowl://%s' % ('a' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('prowl://%s' % ('a' * 40), {
|
|
|
|
'instance': plugins.NotifyProwl,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
|
|
|
##################################
|
|
|
|
# NotifyPushBullet
|
|
|
|
##################################
|
|
|
|
('pbul://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-11-22 04:12:47 +01:00
|
|
|
('pbul://:@/', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-11-22 04:12:47 +01:00
|
|
|
}),
|
2017-12-23 04:47:46 +01:00
|
|
|
# APIkey
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
|
|
|
}),
|
|
|
|
# APIkey; but support attachment response
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
|
|
|
|
|
|
|
# Test what happens if a batch send fails to return a messageCount
|
|
|
|
'requests_response_text': {
|
|
|
|
'file_name': 'cat.jpeg',
|
|
|
|
'file_type': 'image/jpeg',
|
|
|
|
'file_url': 'http://file_url',
|
|
|
|
'upload_url': 'http://upload_url',
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# APIkey; attachment testing that isn't an image type
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
|
|
|
|
|
|
|
# Test what happens if a batch send fails to return a messageCount
|
|
|
|
'requests_response_text': {
|
|
|
|
'file_name': 'test.pdf',
|
|
|
|
'file_type': 'application/pdf',
|
|
|
|
'file_url': 'http://file_url',
|
|
|
|
'upload_url': 'http://upload_url',
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# APIkey; attachment testing were expected entry in payload is missing
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
|
|
|
|
|
|
|
# Test what happens if a batch send fails to return a messageCount
|
|
|
|
'requests_response_text': {
|
|
|
|
'file_name': 'test.pdf',
|
|
|
|
'file_type': 'application/pdf',
|
|
|
|
'file_url': 'http://file_url',
|
|
|
|
# upload_url missing
|
|
|
|
},
|
|
|
|
# Our Notification calls associated with attachments will fail:
|
|
|
|
'attach_response': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + channel
|
2017-12-23 04:47:46 +01:00
|
|
|
('pbul://%s/#channel/' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + channel (via to=
|
2019-03-27 04:06:20 +01:00
|
|
|
('pbul://%s/?to=#channel' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2019-03-27 04:06:20 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + 2 channels
|
2017-12-23 04:47:46 +01:00
|
|
|
('pbul://%s/#channel1/#channel2' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'pbul://a...a/',
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + device
|
2017-12-23 04:47:46 +01:00
|
|
|
('pbul://%s/device/' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + 2 devices
|
2017-12-23 04:47:46 +01:00
|
|
|
('pbul://%s/device1/device2/' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + email
|
2017-12-23 04:47:46 +01:00
|
|
|
('pbul://%s/user@example.com/' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + 2 emails
|
2017-12-23 04:47:46 +01:00
|
|
|
('pbul://%s/user@example.com/abc@def.com/' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + Combo
|
2017-12-23 04:47:46 +01:00
|
|
|
('pbul://%s/device/#channel/user@example.com/' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-01-31 06:15:50 +01:00
|
|
|
# ,
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2019-01-31 06:15:50 +01:00
|
|
|
}),
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2019-01-31 06:15:50 +01:00
|
|
|
}),
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
|
|
|
('pbul://%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushBullet,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
2019-11-22 04:12:47 +01:00
|
|
|
'check_attachments': False,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
|
|
|
|
2019-12-09 02:34:34 +01:00
|
|
|
##################################
|
|
|
|
# NotifyPushSafer
|
|
|
|
##################################
|
|
|
|
('psafer://:@/', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-12-09 02:34:34 +01:00
|
|
|
}),
|
|
|
|
('psafer://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-12-09 02:34:34 +01:00
|
|
|
}),
|
|
|
|
('psafers://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-12-09 02:34:34 +01:00
|
|
|
}),
|
|
|
|
('psafer://{}'.format('a' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# This will fail because we're also expecting a server acknowledgement
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('psafer://{}'.format('b' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# invalid JSON response
|
|
|
|
'requests_response_text': '{',
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('psafer://{}'.format('c' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# A failure has status set to zero
|
|
|
|
# We also expect an 'error' flag to be set
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 0,
|
|
|
|
'error': 'we failed'
|
|
|
|
},
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('psafers://{}'.format('d' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# A failure has status set to zero
|
|
|
|
# Test without an 'error' flag
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 0,
|
|
|
|
},
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
# This will notify all users ('a')
|
|
|
|
('psafer://{}'.format('e' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# A status of 1 is a success
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 1,
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
# This will notify a selected set of devices
|
|
|
|
('psafer://{}/12/24/53'.format('e' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# A status of 1 is a success
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 1,
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
# Same as above, but exercises the to= argument
|
|
|
|
('psafer://{}?to=12,24,53'.format('e' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# A status of 1 is a success
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 1,
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
# Set priority
|
|
|
|
('psafer://{}?priority=emergency'.format('f' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 1,
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
# Support integer value too
|
|
|
|
('psafer://{}?priority=-1'.format('f' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 1,
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
# Invalid priority
|
|
|
|
('psafer://{}?priority=invalid'.format('f' * 20), {
|
|
|
|
# Invalid Priority
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Invalid priority
|
|
|
|
('psafer://{}?priority=25'.format('f' * 20), {
|
|
|
|
# Invalid Priority
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Set sound
|
|
|
|
('psafer://{}?sound=ok'.format('g' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 1,
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
# Support integer value too
|
|
|
|
('psafers://{}?sound=14'.format('g' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 1,
|
|
|
|
},
|
|
|
|
'privacy_url': 'psafers://g...g',
|
|
|
|
}),
|
|
|
|
# Invalid sound
|
|
|
|
('psafer://{}?sound=invalid'.format('h' * 20), {
|
|
|
|
# Invalid Sound
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('psafer://{}?sound=94000'.format('h' * 20), {
|
|
|
|
# Invalid Sound
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Set vibration (integer only)
|
|
|
|
('psafers://{}?vibration=1'.format('h' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 1,
|
|
|
|
},
|
|
|
|
'privacy_url': 'psafers://h...h',
|
|
|
|
}),
|
|
|
|
# Invalid sound
|
|
|
|
('psafer://{}?vibration=invalid'.format('h' * 20), {
|
|
|
|
# Invalid Vibration
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Invalid vibration
|
|
|
|
('psafer://{}?vibration=25000'.format('h' * 20), {
|
|
|
|
# Invalid Vibration
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('psafers://{}'.format('d' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# A failure has status set to zero
|
|
|
|
# Test without an 'error' flag
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 0,
|
|
|
|
},
|
|
|
|
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('psafer://{}'.format('d' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# A failure has status set to zero
|
|
|
|
# Test without an 'error' flag
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 0,
|
|
|
|
},
|
|
|
|
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('psafers://{}'.format('d' * 20), {
|
|
|
|
'instance': plugins.NotifyPushSafer,
|
|
|
|
# A failure has status set to zero
|
|
|
|
# Test without an 'error' flag
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 0,
|
|
|
|
},
|
|
|
|
# Throws a series of connection and transfer exceptions when this
|
|
|
|
# flag is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-07-20 04:42:41 +02:00
|
|
|
##################################
|
|
|
|
# NotifyTechulusPush
|
|
|
|
##################################
|
|
|
|
('push://', {
|
2019-10-09 18:39:31 +02:00
|
|
|
# Missing API Key
|
2019-07-20 04:42:41 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# Invalid API Key
|
2019-07-20 04:42:41 +02:00
|
|
|
('push://%s' % ('+' * 24), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# APIkey
|
|
|
|
('push://%s' % UUID4, {
|
|
|
|
'instance': plugins.NotifyTechulusPush,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'push://8...2/',
|
2019-07-20 04:42:41 +02:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + bad url
|
2019-07-20 04:42:41 +02:00
|
|
|
('push://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('push://%s' % UUID4, {
|
|
|
|
'instance': plugins.NotifyTechulusPush,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('push://%s' % UUID4, {
|
|
|
|
'instance': plugins.NotifyTechulusPush,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('push://%s' % UUID4, {
|
|
|
|
'instance': plugins.NotifyTechulusPush,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2019-01-31 06:15:50 +01:00
|
|
|
|
|
|
|
##################################
|
|
|
|
# NotifyPushed
|
|
|
|
##################################
|
|
|
|
('pushed://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-01-31 06:15:50 +01:00
|
|
|
}),
|
|
|
|
# Application Key Only
|
|
|
|
('pushed://%s' % ('a' * 32), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2020-08-08 15:08:49 +02:00
|
|
|
# Invalid URL
|
|
|
|
('pushed://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-01-31 06:15:50 +01:00
|
|
|
# Application Key+Secret
|
|
|
|
('pushed://%s/%s' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
}),
|
|
|
|
# Application Key+Secret + channel
|
|
|
|
('pushed://%s/%s/#channel/' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
# Application Key+Secret + channel (via to=)
|
|
|
|
('pushed://%s/%s?to=channel' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
2019-09-29 23:17:25 +02:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'pushed://a...a/****/',
|
2019-01-31 06:15:50 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# Application Key+Secret + dropped entry
|
|
|
|
('pushed://%s/%s/dropped_value/' % ('a' * 32, 'a' * 64), {
|
|
|
|
# No entries validated is a fail
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-01-31 06:15:50 +01:00
|
|
|
# Application Key+Secret + 2 channels
|
|
|
|
('pushed://%s/%s/#channel1/#channel2' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
}),
|
|
|
|
# Application Key+Secret + User Pushed ID
|
|
|
|
('pushed://%s/%s/@ABCD/' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
}),
|
|
|
|
# Application Key+Secret + 2 devices
|
|
|
|
('pushed://%s/%s/@ABCD/@DEFG/' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
}),
|
|
|
|
# Application Key+Secret + Combo
|
|
|
|
('pushed://%s/%s/@ABCD/#channel' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
}),
|
|
|
|
# ,
|
|
|
|
('pushed://%s/%s' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('pushed://%s/%s' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('pushed://%s/%s' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
('pushed://%s/%s' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('pushed://%s/%s' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('pushed://%s/%s/#channel' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('pushed://%s/%s/@user' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('pushed://%s/%s' % ('a' * 32, 'a' * 64), {
|
|
|
|
'instance': plugins.NotifyPushed,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-09-08 00:39:18 +02:00
|
|
|
##################################
|
|
|
|
# NotifyPushjet
|
|
|
|
##################################
|
|
|
|
('pjet://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('pjets://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('pjet://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
# You must specify a secret key
|
|
|
|
('pjet://%s' % ('a' * 32), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# The proper way to log in
|
|
|
|
('pjet://user:pass@localhost/%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushjet,
|
|
|
|
}),
|
|
|
|
# The proper way to log in
|
|
|
|
('pjets://localhost/%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushjet,
|
|
|
|
}),
|
|
|
|
# Specify your own server with login (secret= MUST be provided)
|
|
|
|
('pjet://user:pass@localhost?secret=%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushjet,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'pjet://user:****@localhost',
|
2019-09-08 00:39:18 +02:00
|
|
|
}),
|
|
|
|
# Specify your own server with port
|
|
|
|
('pjets://localhost:8080/%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushjet,
|
|
|
|
}),
|
|
|
|
('pjets://localhost:8080/%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushjet,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('pjets://localhost:4343/%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushjet,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('pjet://localhost:8081/%s' % ('a' * 32), {
|
|
|
|
'instance': plugins.NotifyPushjet,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-23 04:47:46 +01:00
|
|
|
##################################
|
|
|
|
# NotifyPushover
|
|
|
|
##################################
|
|
|
|
('pover://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# bad url
|
|
|
|
('pover://:@/', {
|
|
|
|
'instance': TypeError,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
|
|
|
# APIkey; no user
|
|
|
|
('pover://%s' % ('a' * 30), {
|
2017-12-25 21:07:41 +01:00
|
|
|
'instance': TypeError,
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + invalid sound setting
|
2019-05-28 22:38:26 +02:00
|
|
|
('pover://%s@%s?sound=invalid' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + valid alternate sound picked
|
2019-06-19 19:04:35 +02:00
|
|
|
('pover://%s@%s?sound=spacealarm' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + Valid User
|
2017-12-23 04:47:46 +01:00
|
|
|
('pover://%s@%s' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + Valid User + 1 Device
|
2017-12-23 04:47:46 +01:00
|
|
|
('pover://%s@%s/DEVICE' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + Valid User + 1 Device (via to=)
|
2019-03-27 04:06:20 +01:00
|
|
|
('pover://%s@%s?to=DEVICE' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + Valid User + 2 Devices
|
2017-12-23 04:47:46 +01:00
|
|
|
('pover://%s@%s/DEVICE1/DEVICE2/' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'pover://u...u@a...a',
|
2017-12-23 04:47:46 +01:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + Valid User + invalid device
|
2017-12-23 04:47:46 +01:00
|
|
|
('pover://%s@%s/%s/' % ('u' * 30, 'a' * 30, 'd' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
# Notify will return False since there is a bad device in our list
|
|
|
|
'response': False,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + Valid User + device + invalid device
|
2017-12-23 04:47:46 +01:00
|
|
|
('pover://%s@%s/DEVICE1/%s/' % ('u' * 30, 'a' * 30, 'd' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
# Notify will return False since there is a bad device in our list
|
|
|
|
'response': False,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + priority setting
|
2017-12-23 04:47:46 +01:00
|
|
|
('pover://%s@%s?priority=high' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + invalid priority setting
|
2017-12-23 04:47:46 +01:00
|
|
|
('pover://%s@%s?priority=invalid' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + emergency(2) priority setting
|
2019-06-19 19:04:35 +02:00
|
|
|
('pover://%s@%s?priority=emergency' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + emergency priority setting with retry and expire
|
2019-06-19 19:04:35 +02:00
|
|
|
('pover://%s@%s?priority=emergency&%s&%s' % ('u' * 30,
|
|
|
|
'a' * 30,
|
|
|
|
'retry=30',
|
|
|
|
'expire=300'), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + emergency priority setting with text retry
|
2019-06-19 19:04:35 +02:00
|
|
|
('pover://%s@%s?priority=emergency&%s&%s' % ('u' * 30,
|
|
|
|
'a' * 30,
|
|
|
|
'retry=invalid',
|
|
|
|
'expire=300'), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + emergency priority setting with text expire
|
2019-06-19 19:04:35 +02:00
|
|
|
('pover://%s@%s?priority=emergency&%s&%s' % ('u' * 30,
|
|
|
|
'a' * 30,
|
|
|
|
'retry=30',
|
|
|
|
'expire=invalid'), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + emergency priority setting with invalid expire
|
2019-06-19 19:04:35 +02:00
|
|
|
('pover://%s@%s?priority=emergency&%s' % ('u' * 30,
|
|
|
|
'a' * 30,
|
|
|
|
'expire=100000'), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + emergency priority setting with invalid retry
|
2019-06-19 19:04:35 +02:00
|
|
|
('pover://%s@%s?priority=emergency&%s' % ('u' * 30,
|
|
|
|
'a' * 30,
|
|
|
|
'retry=15'), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
# API Key + priority setting (empty)
|
2017-12-23 04:47:46 +01:00
|
|
|
('pover://%s@%s?priority=' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
}),
|
|
|
|
('pover://%s@%s' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('pover://%s@%s' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('pover://%s@%s' % ('u' * 30, 'a' * 30), {
|
|
|
|
'instance': plugins.NotifyPushover,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2021-03-04 16:02:26 +01:00
|
|
|
##################################
|
|
|
|
# NotifyReddit
|
|
|
|
##################################
|
|
|
|
('reddit://', {
|
|
|
|
# Missing all credentials
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('reddit://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('reddit://user@app_id/app_secret/', {
|
|
|
|
# No password
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('reddit://user:password@app_id/', {
|
|
|
|
# No app secret
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('reddit://user:password@app_id/appsecret/apprise', {
|
|
|
|
# No invalid app_id (has underscore)
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('reddit://user:password@app-id/app_secret/apprise', {
|
|
|
|
# No invalid app_secret (has underscore)
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('reddit://user:password@app-id/app-secret/apprise?kind=invalid', {
|
|
|
|
# An Invalid Kind
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('reddit://user:password@app-id/app-secret/apprise', {
|
|
|
|
# Login failed
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
# Expected notify() response is False because internally we would
|
|
|
|
# have failed to login
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('reddit://user:password@app-id/app-secret', {
|
|
|
|
# Login successful, but there was no subreddit to notify
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
'requests_response_text': {
|
|
|
|
"access_token": 'abc123',
|
|
|
|
"token_type": "bearer",
|
|
|
|
"expires_in": 100000,
|
|
|
|
"scope": '*',
|
|
|
|
"refresh_token": 'def456',
|
|
|
|
# The below is used in the response:
|
|
|
|
"json": {
|
|
|
|
# No errors during post
|
|
|
|
"errors": [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
# Expected notify() response is False
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('reddit://user:password@app-id/app-secret/apprise', {
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
'requests_response_text': {
|
|
|
|
"access_token": 'abc123',
|
|
|
|
"token_type": "bearer",
|
|
|
|
"expires_in": 100000,
|
|
|
|
"scope": '*',
|
|
|
|
"refresh_token": 'def456',
|
|
|
|
# The below is used in the response:
|
|
|
|
"json": {
|
|
|
|
# Identify an error
|
|
|
|
"errors": [('KEY', 'DESC', 'INFO'), ],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
# Expected notify() response is False because the
|
|
|
|
# reddit server provided us errors
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
|
|
|
|
('reddit://user:password@app-id/app-secret/apprise', {
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
'requests_response_text': {
|
|
|
|
"access_token": 'abc123',
|
|
|
|
"token_type": "bearer",
|
|
|
|
# Test case where 'expires_in' entry is missing
|
|
|
|
"scope": '*',
|
|
|
|
"refresh_token": 'def456',
|
|
|
|
# The below is used in the response:
|
|
|
|
"json": {
|
|
|
|
# No errors during post
|
|
|
|
"errors": [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'reddit://user:****@****/****/apprise',
|
|
|
|
}),
|
|
|
|
('reddit://user:password@app-id/app-secret/apprise/subreddit2', {
|
|
|
|
# password:login acceptable
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
'requests_response_text': {
|
|
|
|
"access_token": 'abc123',
|
|
|
|
"token_type": "bearer",
|
|
|
|
"expires_in": 100000,
|
|
|
|
"scope": '*',
|
|
|
|
"refresh_token": 'def456',
|
|
|
|
# The below is used in the response:
|
|
|
|
"json": {
|
|
|
|
# No errors during post
|
|
|
|
"errors": [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url':
|
|
|
|
'reddit://user:****@****/****/apprise/subreddit2',
|
|
|
|
}),
|
|
|
|
# Pass in some arguments to over-ride defaults
|
|
|
|
('reddit://user:pass@id/secret/sub/'
|
|
|
|
'?ad=yes&nsfw=yes&replies=no&resubmit=yes&spoiler=yes&kind=self', {
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
'requests_response_text': {
|
|
|
|
"access_token": 'abc123',
|
|
|
|
"token_type": "bearer",
|
|
|
|
"expires_in": 100000,
|
|
|
|
"scope": '*',
|
|
|
|
"refresh_token": 'def456',
|
|
|
|
# The below is used in the response:
|
|
|
|
"json": {
|
|
|
|
# No errors during post
|
|
|
|
"errors": [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'reddit://user:****@****/****/sub'}),
|
|
|
|
# Pass in more arguments
|
|
|
|
('reddit://'
|
|
|
|
'?user=l2g&pass=pass&app_secret=abc123&app_id=54321&to=sub1,sub2', {
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
'requests_response_text': {
|
|
|
|
"access_token": 'abc123',
|
|
|
|
"token_type": "bearer",
|
|
|
|
"expires_in": 100000,
|
|
|
|
"scope": '*',
|
|
|
|
"refresh_token": 'def456',
|
|
|
|
# The below is used in the response:
|
|
|
|
"json": {
|
|
|
|
# No errors during post
|
|
|
|
"errors": [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'reddit://l2g:****@****/****/sub1/sub2'}),
|
|
|
|
# More arguments ...
|
|
|
|
('reddit://user:pass@id/secret/sub7/sub6/sub5/'
|
|
|
|
'?flair_id=wonder&flair_text=not%20for%20you', {
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
'requests_response_text': {
|
|
|
|
"access_token": 'abc123',
|
|
|
|
"token_type": "bearer",
|
|
|
|
"expires_in": 100000,
|
|
|
|
"scope": '*',
|
|
|
|
"refresh_token": 'def456',
|
|
|
|
# The below is used in the response:
|
|
|
|
"json": {
|
|
|
|
# No errors during post
|
|
|
|
"errors": [],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'reddit://user:****@****/****/sub'}),
|
|
|
|
('reddit://user:password@app-id/app-secret/apprise', {
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('reddit://user:password@app-id/app-secret/apprise', {
|
|
|
|
'instance': plugins.NotifyReddit,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-25 21:07:41 +01:00
|
|
|
##################################
|
|
|
|
# NotifyRocketChat
|
|
|
|
##################################
|
|
|
|
('rocket://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('rockets://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
2019-05-22 03:50:50 +02:00
|
|
|
('rocket://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
2017-12-25 21:07:41 +01:00
|
|
|
# No username or pass
|
|
|
|
('rocket://localhost', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# No room or channel
|
|
|
|
('rocket://user:pass@localhost', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# No valid rooms or channels
|
|
|
|
('rocket://user:pass@localhost/#/!/@', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-02-13 23:48:09 +01:00
|
|
|
# No user/pass combo
|
|
|
|
('rocket://user@localhost/room/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# No user/pass combo
|
|
|
|
('rocket://localhost/room/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2017-12-25 21:07:41 +01:00
|
|
|
# A room and port identifier
|
|
|
|
('rocket://user:pass@localhost:8080/room/', {
|
|
|
|
'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',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
# A channel (using the to=)
|
|
|
|
('rockets://user:pass@localhost?to=#channel', {
|
|
|
|
'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',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}),
|
2017-12-25 21:07:41 +01:00
|
|
|
# A channel
|
|
|
|
('rockets://user:pass@localhost/#channel', {
|
|
|
|
'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',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# Several channels
|
2019-05-22 03:50:50 +02:00
|
|
|
('rocket://user:pass@localhost/#channel1/#channel2/?avatar=No', {
|
2017-12-25 21:07:41 +01:00
|
|
|
'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',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# Several Rooms
|
|
|
|
('rocket://user:pass@localhost/room1/room2', {
|
|
|
|
'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
|
2019-05-22 03:50:50 +02:00
|
|
|
('rocket://user:pass@localhost/room/#channel?mode=basic', {
|
2017-12-25 21:07:41 +01:00
|
|
|
'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',
|
|
|
|
},
|
|
|
|
},
|
2019-09-29 23:17:25 +02:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'rocket://user:****@localhost',
|
2017-12-25 21:07:41 +01:00
|
|
|
}),
|
2019-05-22 03:50:50 +02:00
|
|
|
# A user/pass where the pass matches a webtoken
|
|
|
|
# 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',
|
|
|
|
},
|
|
|
|
},
|
2017-12-25 21:07:41 +01:00
|
|
|
}),
|
|
|
|
# A room and channel
|
|
|
|
('rockets://user:pass@localhost/rooma/#channela', {
|
|
|
|
# The response text is expected to be the following on a success
|
|
|
|
'requests_response_code': requests.codes.ok,
|
|
|
|
'requests_response_text': {
|
|
|
|
# return something other then a success message type
|
|
|
|
'status': 'failure',
|
|
|
|
},
|
|
|
|
# Exception is thrown in this case
|
|
|
|
'instance': plugins.NotifyRocketChat,
|
|
|
|
# Notifications will fail in this event
|
|
|
|
'response': False,
|
|
|
|
}),
|
2019-05-22 03:50:50 +02:00
|
|
|
# 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,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'rockets://w...n@localhost',
|
2019-05-22 03:50:50 +02:00
|
|
|
}),
|
|
|
|
('rockets://localhost/@user/?mode=webhook&webhook=web/token', {
|
|
|
|
'instance': plugins.NotifyRocketChat,
|
|
|
|
}),
|
|
|
|
('rockets://user:web/token@localhost/@user/?mode=invalid', {
|
|
|
|
# invalid mode
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2017-12-25 21:07:41 +01:00
|
|
|
('rocket://user:pass@localhost:8081/room1/room2', {
|
|
|
|
'instance': plugins.NotifyRocketChat,
|
2019-05-22 03:50:50 +02:00
|
|
|
# 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
|
2017-12-25 21:07:41 +01:00
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('rocket://user:pass@localhost:8082/#channel', {
|
|
|
|
'instance': plugins.NotifyRocketChat,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('rocket://user:pass@localhost:8083/#chan1/#chan2/room', {
|
|
|
|
'instance': plugins.NotifyRocketChat,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-02-09 23:24:32 +01:00
|
|
|
##################################
|
|
|
|
# NotifyRyver
|
|
|
|
##################################
|
|
|
|
('ryver://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-02-09 23:24:32 +01:00
|
|
|
}),
|
|
|
|
('ryver://:@/', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-02-09 23:24:32 +01:00
|
|
|
}),
|
|
|
|
('ryver://apprise', {
|
|
|
|
# Just org provided (no token)
|
2019-03-27 04:06:20 +01:00
|
|
|
'instance': TypeError,
|
2019-02-09 23:24:32 +01:00
|
|
|
}),
|
2020-08-28 22:49:09 +02:00
|
|
|
('ryver://apprise/ckhrjW8w672m6HG?mode=invalid', {
|
|
|
|
# invalid mode provided
|
2019-02-09 23:24:32 +01:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('ryver://x/ckhrjW8w672m6HG?mode=slack', {
|
|
|
|
# Invalid org
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('ryver://apprise/ckhrjW8w672m6HG?mode=slack', {
|
|
|
|
# No username specified; this is still okay as we use whatever
|
|
|
|
# the user told the webhook to use; set our slack mode
|
|
|
|
'instance': plugins.NotifyRyver,
|
|
|
|
}),
|
|
|
|
('ryver://apprise/ckhrjW8w672m6HG?mode=ryver', {
|
|
|
|
# No username specified; this is still okay as we use whatever
|
|
|
|
# the user told the webhook to use; set our ryver mode
|
|
|
|
'instance': plugins.NotifyRyver,
|
|
|
|
}),
|
|
|
|
# Legacy webhook mode setting:
|
|
|
|
# Legacy webhook mode setting:
|
2019-02-09 23:24:32 +01:00
|
|
|
('ryver://apprise/ckhrjW8w672m6HG?webhook=slack', {
|
|
|
|
# No username specified; this is still okay as we use whatever
|
|
|
|
# the user told the webhook to use; set our slack mode
|
|
|
|
'instance': plugins.NotifyRyver,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('ryver://apprise/ckhrjW8w672m6HG?webhook=ryver', {
|
|
|
|
# No username specified; this is still okay as we use whatever
|
|
|
|
# the user told the webhook to use; set our ryver mode
|
|
|
|
'instance': plugins.NotifyRyver,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'ryver://apprise/c...G',
|
2019-03-27 04:06:20 +01:00
|
|
|
}),
|
2019-06-01 02:56:54 +02:00
|
|
|
# Support Native URLs
|
|
|
|
('https://apprise.ryver.com/application/webhook/ckhrjW8w672m6HG', {
|
|
|
|
'instance': plugins.NotifyRyver,
|
|
|
|
}),
|
2019-10-13 00:02:05 +02:00
|
|
|
# Support Native URLs with arguments
|
|
|
|
('https://apprise.ryver.com/application/webhook/ckhrjW8w672m6HG'
|
|
|
|
'?webhook=ryver',
|
|
|
|
{
|
|
|
|
'instance': plugins.NotifyRyver,
|
|
|
|
}),
|
2019-02-09 23:24:32 +01:00
|
|
|
('ryver://caronc@apprise/ckhrjW8w672m6HG', {
|
|
|
|
'instance': plugins.NotifyRyver,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
('ryver://apprise/ckhrjW8w672m6HG', {
|
|
|
|
'instance': plugins.NotifyRyver,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('ryver://apprise/ckhrjW8w672m6HG', {
|
|
|
|
'instance': plugins.NotifyRyver,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('ryver://apprise/ckhrjW8w672m6HG', {
|
|
|
|
'instance': plugins.NotifyRyver,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-08-18 06:39:21 +02:00
|
|
|
##################################
|
|
|
|
# NotifySendGrid
|
|
|
|
##################################
|
|
|
|
('sendgrid://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('sendgrid://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd', {
|
|
|
|
# Just an broken email (no api key or email)
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd@host', {
|
|
|
|
# Just an Email specified, no API Key
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('sendgrid://invalid-api-key+*-d:user@example.com', {
|
|
|
|
# An invalid API Key
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.com', {
|
|
|
|
# No To/Target Address(es) specified; so we sub in the same From
|
|
|
|
# address
|
|
|
|
'instance': plugins.NotifySendGrid,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.com/newuser@example.com', {
|
|
|
|
# A good email
|
|
|
|
'instance': plugins.NotifySendGrid,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.com/newuser@example.com'
|
|
|
|
'?bcc=l2g@nuxref.com', {
|
|
|
|
# A good email with Blind Carbon Copy
|
|
|
|
'instance': plugins.NotifySendGrid,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.com/newuser@example.com'
|
|
|
|
'?cc=l2g@nuxref.com', {
|
|
|
|
# A good email with Carbon Copy
|
|
|
|
'instance': plugins.NotifySendGrid,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.com/newuser@example.com'
|
|
|
|
'?to=l2g@nuxref.com', {
|
|
|
|
# A good email with Carbon Copy
|
|
|
|
'instance': plugins.NotifySendGrid,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.com/newuser@example.com'
|
|
|
|
'?template={}'.format(UUID4), {
|
|
|
|
# A good email with a template + no substitutions
|
|
|
|
'instance': plugins.NotifySendGrid,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.com/newuser@example.com'
|
|
|
|
'?template={}&+sub=value&+sub2=value2'.format(UUID4), {
|
|
|
|
# A good email with a template + substitutions
|
|
|
|
'instance': plugins.NotifySendGrid,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'sendgrid://a...d:user@example.com/',
|
2019-08-18 06:39:21 +02:00
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.ca/newuser@example.ca', {
|
|
|
|
'instance': plugins.NotifySendGrid,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.uk/newuser@example.uk', {
|
|
|
|
'instance': plugins.NotifySendGrid,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('sendgrid://abcd:user@example.au/newuser@example.au', {
|
|
|
|
'instance': plugins.NotifySendGrid,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2020-01-15 02:57:14 +01:00
|
|
|
##################################
|
|
|
|
# NotifySinch
|
|
|
|
##################################
|
|
|
|
('sinch://', {
|
|
|
|
# No Account SID specified
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sinch://:@/', {
|
|
|
|
# invalid Auth token
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sinch://{}@12345678'.format('a' * 32), {
|
|
|
|
# Just spi provided
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@_'.format('a' * 32, 'b' * 32), {
|
|
|
|
# spi and token provided but invalid from
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@{}'.format('a' * 32, 'b' * 32, '3' * 5), {
|
|
|
|
# using short-code (5 characters) without a target
|
|
|
|
# We can still instantiate ourselves with a valid short code
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@{}'.format('a' * 32, 'b' * 32, '3' * 9), {
|
|
|
|
# spi and token provided and from but invalid from no
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@{}/123/{}/abcd/'.format(
|
|
|
|
'a' * 32, 'b' * 32, '3' * 11, '9' * 15), {
|
|
|
|
# valid everything but target numbers
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@12345/{}'.format('a' * 32, 'b' * 32, '4' * 11), {
|
|
|
|
# using short-code (5 characters)
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'sinch://...aaaa:b...b@12345',
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@123456/{}'.format('a' * 32, 'b' * 32, '4' * 11), {
|
|
|
|
# using short-code (6 characters)
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@{}'.format('a' * 32, 'b' * 32, '5' * 11), {
|
|
|
|
# using phone no with no target - we text ourselves in
|
|
|
|
# this case
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@{}?region=eu'.format('a' * 32, 'b' * 32, '5' * 11), {
|
|
|
|
# Specify a region
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@{}?region=invalid'.format('a' * 32, 'b' * 32, '5' * 11), {
|
|
|
|
# Invalid region
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sinch://_?spi={}&token={}&from={}'.format(
|
|
|
|
'a' * 32, 'b' * 32, '5' * 11), {
|
|
|
|
# use get args to acomplish the same thing
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
}),
|
|
|
|
('sinch://_?spi={}&token={}&source={}'.format(
|
|
|
|
'a' * 32, 'b' * 32, '5' * 11), {
|
|
|
|
# use get args to acomplish the same thing (use source instead of from)
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
}),
|
|
|
|
('sinch://_?spi={}&token={}&from={}&to={}'.format(
|
|
|
|
'a' * 32, 'b' * 32, '5' * 11, '7' * 13), {
|
|
|
|
# use to=
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@{}'.format('a' * 32, 'b' * 32, '6' * 11), {
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('sinch://{}:{}@{}'.format('a' * 32, 'b' * 32, '6' * 11), {
|
|
|
|
'instance': plugins.NotifySinch,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2020-10-04 17:14:09 +02:00
|
|
|
##################################
|
|
|
|
# NotifySparkPost
|
|
|
|
##################################
|
|
|
|
('sparkpost://', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sparkpost://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# No Token specified
|
|
|
|
('sparkpost://user@localhost.localdomain', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Token is valid, but no user name specified
|
|
|
|
('sparkpost://localhost.localdomain/{}'.format('a' * 32), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Invalid from email address
|
|
|
|
('sparkpost://!@localhost.localdomain/{}'.format('b' * 32), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# No To email address, but everything else is valid
|
|
|
|
('sparkpost://user@localhost.localdomain/{}'.format('c' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('sparkpost://user@localhost.localdomain/{}?format=markdown'
|
|
|
|
.format('d' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('sparkpost://user@localhost.localdomain/{}?format=html'
|
|
|
|
.format('d' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('sparkpost://user@localhost.localdomain/{}?format=text'
|
|
|
|
.format('d' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# valid url with region specified (case insensitve)
|
|
|
|
('sparkpost://user@localhost.localdomain/{}?region=uS'.format('d' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# valid url with region specified (case insensitve)
|
|
|
|
('sparkpost://user@localhost.localdomain/{}?region=EU'.format('e' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# headers
|
|
|
|
('sparkpost://user@localhost.localdomain/{}'
|
|
|
|
'?+X-Customer-Campaign-ID=Apprise'.format('f' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# template tokens
|
|
|
|
('sparkpost://user@localhost.localdomain/{}'
|
|
|
|
'?:name=Chris&:status=admin'.format('g' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# bcc and cc
|
|
|
|
('sparkpost://user@localhost.localdomain/{}'
|
|
|
|
'?bcc=user@example.com&cc=user2@example.com'.format('h' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# invalid url with region specified (case insensitve)
|
|
|
|
('sparkpost://user@localhost.localdomain/{}?region=invalid'.format(
|
|
|
|
'a' * 32), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# One 'To' Email address
|
|
|
|
('sparkpost://user@localhost.localdomain/{}/test@example.com'.format(
|
|
|
|
'a' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# Invalid 'To' Email address
|
|
|
|
('sparkpost://user@localhost.localdomain/{}/invalid'.format(
|
|
|
|
'i' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
# Expected notify() response
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
# Multiple 'To', 'Cc', and 'Bcc' addresses (with invalid ones)
|
|
|
|
('sparkpost://user@example.com/{}/{}?bcc={}&cc={}'.format(
|
|
|
|
'j' * 32,
|
|
|
|
'/'.join(('user1@example.com', 'invalid', 'User2:user2@example.com')),
|
|
|
|
','.join(('user3@example.com', 'i@v', 'User1:user1@example.com')),
|
|
|
|
','.join(('user4@example.com', 'g@r@b', 'Da:user5@example.com'))), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('sparkpost://user@localhost.localdomain/'
|
|
|
|
'{}?to=test@example.com'.format('k' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# One To Email address, a from name specified too
|
|
|
|
('sparkpost://user@localhost.localdomain/{}/'
|
|
|
|
'test@example.com?name="Frodo"'.format('l' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': {
|
|
|
|
"results": {
|
|
|
|
"total_rejected_recipients": 0,
|
|
|
|
"total_accepted_recipients": 1,
|
|
|
|
"id": "11668787484950529"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# Test invalid JSON response
|
|
|
|
('sparkpost://user@localhost.localdomain/{}'.format('m' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
'requests_response_text': "{",
|
|
|
|
}),
|
|
|
|
('sparkpost://user@localhost.localdomain/{}'.format('n' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('sparkpost://user@localhost.localdomain/{}'.format('o' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('sparkpost://user@localhost.localdomain/{}'.format('p' * 32), {
|
|
|
|
'instance': plugins.NotifySparkPost,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2020-08-01 15:36:34 +02:00
|
|
|
##################################
|
|
|
|
# NotifySpontit
|
|
|
|
##################################
|
|
|
|
('spontit://', {
|
|
|
|
# invalid url
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Another bad url
|
|
|
|
('spontit://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# No user specified
|
|
|
|
('spontit://%s' % ('a' * 100), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Invalid API Key specified
|
|
|
|
('spontit://user@%%20_', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Provide a valid user and API Key
|
|
|
|
('spontit://%s@%s' % ('u' * 11, 'b' * 100), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'spontit://{}@b...b/'.format('u' * 11),
|
|
|
|
}),
|
|
|
|
# Provide a valid user and API Key, but provide an invalid channel
|
|
|
|
('spontit://%s@%s/#!!' % ('u' * 11, 'b' * 100), {
|
|
|
|
# An instance is still created, but the channel won't be notified
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
}),
|
|
|
|
# Provide a valid user, API Key and a valid channel
|
|
|
|
('spontit://%s@%s/#abcd' % ('u' * 11, 'b' * 100), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
}),
|
|
|
|
# Provide a valid user, API Key, and a subtitle
|
|
|
|
('spontit://%s@%s/?subtitle=Test' % ('u' * 11, 'b' * 100), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
}),
|
|
|
|
# Provide a valid user, API Key, and a lengthy subtitle
|
|
|
|
('spontit://%s@%s/?subtitle=%s' % ('u' * 11, 'b' * 100, 'c' * 300), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
}),
|
|
|
|
# Provide a valid user and API Key, but provide a valid channel (that is
|
|
|
|
# not ours).
|
|
|
|
# Spontit uses a slash (/) to delimite the user from the channel id when
|
|
|
|
# specifying channel entries. For Apprise we need to encode this
|
|
|
|
# so we convert the slash (/) into %2F
|
|
|
|
('spontit://{}@{}/#1245%2Fabcd'.format('u' * 11, 'b' * 100), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
}),
|
|
|
|
# Provide multipe channels
|
|
|
|
('spontit://{}@{}/#1245%2Fabcd/defg'.format('u' * 11, 'b' * 100), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
}),
|
|
|
|
# Provide multipe channels through the use of the to= variable
|
|
|
|
('spontit://{}@{}/?to=#1245/abcd'.format('u' * 11, 'b' * 100), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
}),
|
|
|
|
('spontit://%s@%s' % ('u' * 11, 'b' * 100), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('spontit://%s@%s' % ('u' * 11, 'b' * 100), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('spontit://%s@%s' % ('u' * 11, 'b' * 100), {
|
|
|
|
'instance': plugins.NotifySpontit,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-09-08 00:57:02 +02:00
|
|
|
##################################
|
|
|
|
# NotifySimplePush
|
|
|
|
##################################
|
|
|
|
('spush://', {
|
|
|
|
# No api key
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-09-08 00:57:02 +02:00
|
|
|
}),
|
|
|
|
('spush://{}'.format('A' * 14), {
|
|
|
|
# API Key specified however expected server response
|
|
|
|
# didn't have 'OK' in JSON response
|
|
|
|
'instance': plugins.NotifySimplePush,
|
|
|
|
# Expected notify() response
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
2019-09-29 23:17:25 +02:00
|
|
|
('spush://{}'.format('Y' * 14), {
|
2019-09-08 00:57:02 +02:00
|
|
|
# API Key valid and expected response was valid
|
|
|
|
'instance': plugins.NotifySimplePush,
|
|
|
|
# Set our response to OK
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 'OK',
|
|
|
|
},
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'spush://Y...Y/',
|
2019-09-08 00:57:02 +02:00
|
|
|
}),
|
|
|
|
('spush://{}?event=Not%20So%20Good'.format('X' * 14), {
|
|
|
|
# API Key valid and expected response was valid
|
|
|
|
'instance': plugins.NotifySimplePush,
|
|
|
|
# Set our response to something that is not okay
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 'NOT-OK',
|
|
|
|
},
|
|
|
|
# Expected notify() response
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
2020-06-07 19:37:07 +02:00
|
|
|
('spush://salt:pass@{}'.format('X' * 14), {
|
2019-09-08 00:57:02 +02:00
|
|
|
# Now we'll test encrypted messages with new salt
|
|
|
|
'instance': plugins.NotifySimplePush,
|
|
|
|
# Set our response to OK
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 'OK',
|
|
|
|
},
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'spush://****:****@X...X/',
|
2019-09-08 00:57:02 +02:00
|
|
|
}),
|
|
|
|
('spush://{}'.format('Y' * 14), {
|
|
|
|
'instance': plugins.NotifySimplePush,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
# Set a failing message too
|
|
|
|
'requests_response_text': {
|
|
|
|
'status': 'BadRequest',
|
|
|
|
'message': 'Title or message too long',
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('spush://{}'.format('Z' * 14), {
|
|
|
|
'instance': plugins.NotifySimplePush,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-11 03:28:00 +01:00
|
|
|
##################################
|
|
|
|
# NotifySlack
|
|
|
|
##################################
|
|
|
|
('slack://', {
|
2019-11-15 01:41:12 +01:00
|
|
|
'instance': TypeError,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('slack://:@/', {
|
2019-11-15 01:41:12 +01:00
|
|
|
'instance': TypeError,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('slack://T1JJ3T3L2', {
|
|
|
|
# Just Token 1 provided
|
2019-03-27 04:06:20 +01:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('slack://T1JJ3T3L2/A1BRTD4JD/', {
|
|
|
|
# Just 2 tokens provided
|
|
|
|
'instance': TypeError,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('slack://T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#hmm/#-invalid-', {
|
|
|
|
# No username specified; this is still okay as we sub in
|
|
|
|
# default; The one invalid channel is skipped when sending a message
|
|
|
|
'instance': plugins.NotifySlack,
|
2019-02-25 07:02:29 +01:00
|
|
|
# There is an invalid channel that we will fail to deliver to
|
|
|
|
# as a result the response type will be false
|
|
|
|
'response': False,
|
2019-11-15 01:41:12 +01:00
|
|
|
'requests_response_text': {
|
|
|
|
'ok': False,
|
|
|
|
'message': 'Bad Channel',
|
|
|
|
},
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('slack://T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#channel', {
|
|
|
|
# No username specified; this is still okay as we sub in
|
|
|
|
# default; The one invalid channel is skipped when sending a message
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
2021-01-10 21:55:59 +01:00
|
|
|
'requests_response_text': 'ok'
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('slack://T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/+id/@id/', {
|
2017-12-11 03:28:00 +01:00
|
|
|
# + encoded id,
|
|
|
|
# @ userid
|
|
|
|
'instance': plugins.NotifySlack,
|
2021-01-10 21:55:59 +01:00
|
|
|
'requests_response_text': 'ok',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
2020-05-04 03:34:15 +02:00
|
|
|
('slack://username@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/'
|
2019-03-27 04:06:20 +01:00
|
|
|
'?to=#nuxref', {
|
|
|
|
'instance': plugins.NotifySlack,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'slack://username@T...2/A...D/T...Q/',
|
2021-01-10 21:55:59 +01:00
|
|
|
'requests_response_text': 'ok',
|
2019-03-27 04:06:20 +01:00
|
|
|
}),
|
2017-12-11 03:28:00 +01:00
|
|
|
('slack://username@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#nuxref', {
|
2021-01-10 21:55:59 +01:00
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
'requests_response_text': 'ok',
|
|
|
|
}),
|
|
|
|
# You can't send to email using webhook
|
|
|
|
('slack://T1JJ3T3L2/A1BRTD4JD/TIiajkdnl/user@gmail.com', {
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
'requests_response_text': 'ok',
|
|
|
|
# we'll have a notify response failure in this case
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
# Specify Token on argument string (with username)
|
|
|
|
('slack://bot@_/#nuxref?token=T1JJ3T3L2/A1BRTD4JD/TIiajkdnadfdajkjkfl/', {
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
'requests_response_text': 'ok',
|
|
|
|
}),
|
|
|
|
# Specify Token and channels on argument string (no username)
|
|
|
|
('slack://?token=T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/&to=#chan', {
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
'requests_response_text': 'ok',
|
|
|
|
}),
|
|
|
|
# Test webhook that doesn't have a proper response
|
|
|
|
('slack://username@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#nuxref', {
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
'requests_response_text': 'fail',
|
|
|
|
# we'll have a notify response failure in this case
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
# Test using a bot-token (also test footer set to no flag)
|
|
|
|
('slack://username@xoxb-1234-1234-abc124/#nuxref?footer=no', {
|
2017-12-11 03:28:00 +01:00
|
|
|
'instance': plugins.NotifySlack,
|
2019-11-15 01:41:12 +01:00
|
|
|
'requests_response_text': {
|
|
|
|
'ok': True,
|
|
|
|
'message': '',
|
2021-01-10 21:55:59 +01:00
|
|
|
# support attachments
|
|
|
|
'file': {
|
|
|
|
'url_private': 'http://localhost/',
|
|
|
|
},
|
2019-11-15 01:41:12 +01:00
|
|
|
},
|
|
|
|
}),
|
2021-01-10 21:55:59 +01:00
|
|
|
# Test using a bot-token as argument
|
|
|
|
('slack://?token=xoxb-1234-1234-abc124&to=#nuxref&footer=no&user=test', {
|
2019-11-15 01:41:12 +01:00
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
'requests_response_text': {
|
|
|
|
'ok': True,
|
|
|
|
'message': '',
|
|
|
|
# support attachments
|
|
|
|
'file': {
|
|
|
|
'url_private': 'http://localhost/',
|
|
|
|
},
|
|
|
|
},
|
2021-01-10 21:55:59 +01:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'slack://test@x...4/nuxref/',
|
|
|
|
}),
|
|
|
|
# We contain 1 or more invalid channels, so we'll fail on our notify call
|
|
|
|
('slack://?token=xoxb-1234-1234-abc124&to=#nuxref,#$,#-&footer=no', {
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
'requests_response_text': {
|
|
|
|
'ok': True,
|
|
|
|
'message': '',
|
|
|
|
# support attachments
|
|
|
|
'file': {
|
|
|
|
'url_private': 'http://localhost/',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
# We fail because of the empty channel #$ and #-
|
|
|
|
'notify_response': False,
|
2019-11-15 01:41:12 +01:00
|
|
|
}),
|
|
|
|
('slack://username@xoxb-1234-1234-abc124/#nuxref', {
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
'requests_response_text': {
|
|
|
|
'ok': True,
|
|
|
|
'message': '',
|
|
|
|
},
|
|
|
|
# we'll fail to send attachments because we had no 'file' response in
|
|
|
|
# our object
|
|
|
|
'response': False,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
2019-11-15 01:41:12 +01:00
|
|
|
|
2017-12-11 03:28:00 +01:00
|
|
|
('slack://username@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ', {
|
2019-05-11 21:02:56 +02:00
|
|
|
# Missing a channel, falls back to webhook channel bindings
|
|
|
|
'instance': plugins.NotifySlack,
|
2021-01-10 21:55:59 +01:00
|
|
|
'requests_response_text': 'ok',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
2019-06-01 02:56:54 +02:00
|
|
|
# Native URL Support, take the slack URL and still build from it
|
|
|
|
('https://hooks.slack.com/services/{}/{}/{}'.format(
|
|
|
|
'A' * 9, 'B' * 9, 'c' * 24), {
|
|
|
|
'instance': plugins.NotifySlack,
|
2021-01-10 21:55:59 +01:00
|
|
|
'requests_response_text': 'ok',
|
2019-06-01 02:56:54 +02:00
|
|
|
}),
|
2019-10-13 00:02:05 +02:00
|
|
|
# Native URL Support with arguments
|
|
|
|
('https://hooks.slack.com/services/{}/{}/{}?format=text'.format(
|
|
|
|
'A' * 9, 'B' * 9, 'c' * 24), {
|
|
|
|
'instance': plugins.NotifySlack,
|
2021-01-10 21:55:59 +01:00
|
|
|
'requests_response_text': 'ok',
|
2019-10-13 00:02:05 +02:00
|
|
|
}),
|
2020-03-20 18:05:01 +01:00
|
|
|
('slack://username@-INVALID-/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#cool', {
|
2017-12-11 03:28:00 +01:00
|
|
|
# invalid 1st Token
|
2017-12-25 21:07:41 +01:00
|
|
|
'instance': TypeError,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
2020-03-20 18:05:01 +01:00
|
|
|
('slack://username@T1JJ3T3L2/-INVALID-/TIiajkdnlazkcOXrIdevi7FQ/#great', {
|
2017-12-11 03:28:00 +01:00
|
|
|
# invalid 2rd Token
|
2017-12-25 21:07:41 +01:00
|
|
|
'instance': TypeError,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
2020-03-20 18:05:01 +01:00
|
|
|
('slack://username@T1JJ3T3L2/A1BRTD4JD/-INVALID-/#channel', {
|
2017-12-11 03:28:00 +01:00
|
|
|
# invalid 3rd Token
|
2017-12-25 21:07:41 +01:00
|
|
|
'instance': TypeError,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('slack://l2g@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#usenet', {
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
2021-01-10 21:55:59 +01:00
|
|
|
'requests_response_text': 'ok',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('slack://respect@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#a', {
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
2021-01-10 21:55:59 +01:00
|
|
|
'requests_response_text': 'ok',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('slack://notify@T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/#b', {
|
|
|
|
'instance': plugins.NotifySlack,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
2021-01-10 21:55:59 +01:00
|
|
|
'requests_response_text': 'ok',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
|
2019-02-10 05:36:27 +01:00
|
|
|
##################################
|
|
|
|
# NotifySNS (AWS)
|
|
|
|
##################################
|
|
|
|
('sns://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-02-10 05:36:27 +01:00
|
|
|
}),
|
|
|
|
('sns://:@/', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-02-10 05:36:27 +01:00
|
|
|
}),
|
|
|
|
('sns://T1JJ3T3L2', {
|
|
|
|
# Just Token 1 provided
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sns://T1JJ3TD4JD/TIiajkdnlazk7FQ/', {
|
|
|
|
# Missing a region
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('sns://T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcevi7FQ/us-west-2/12223334444', {
|
2019-10-09 18:39:31 +02:00
|
|
|
# we have a valid URL and one number to text
|
2019-02-10 05:36:27 +01:00
|
|
|
'instance': plugins.NotifySNS,
|
|
|
|
}),
|
|
|
|
('sns://T1JJ3TD4JD/TIiajkdnlazk7FQ/us-west-2/12223334444/12223334445', {
|
|
|
|
# Multi SNS Suppport
|
|
|
|
'instance': plugins.NotifySNS,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
2019-10-09 18:39:31 +02:00
|
|
|
'privacy_url': 'sns://T...D/****/us-west-2',
|
2019-02-10 05:36:27 +01:00
|
|
|
}),
|
2020-05-04 03:34:15 +02:00
|
|
|
('sns://T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcOXrIdevi7FQ/us-east-1'
|
2019-03-27 04:06:20 +01:00
|
|
|
'?to=12223334444', {
|
|
|
|
# Missing a topic and/or phone No
|
|
|
|
'instance': plugins.NotifySNS,
|
|
|
|
}),
|
2019-02-10 05:36:27 +01:00
|
|
|
('sns://T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcevi7FQ/us-west-2/12223334444', {
|
|
|
|
'instance': plugins.NotifySNS,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('sns://T1JJ3T3L2/A1BRTD4JD/TIiajkdnlazkcevi7FQ/us-west-2/15556667777', {
|
|
|
|
'instance': plugins.NotifySNS,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-23 04:47:46 +01:00
|
|
|
##################################
|
|
|
|
# NotifyTelegram
|
|
|
|
##################################
|
|
|
|
('tgram://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
# Simple Message
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
|
|
|
# Simple Message (no images)
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
# Simple Message with multiple chat names
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/id1/id2/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
# Simple Message with multiple chat names
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/?to=id1,id2', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
2017-12-23 04:47:46 +01:00
|
|
|
# Simple Message with an invalid chat ID
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/%$/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# Notify will fail
|
|
|
|
'response': False,
|
|
|
|
}),
|
|
|
|
# Simple Message with multiple chat ids
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/id1/id2/23423/-30/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
|
|
|
# Simple Message with multiple chat ids (no images)
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/id1/id2/23423/-30/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
# Support bot keyword prefix
|
|
|
|
('tgram://bottest@123456789:abcdefg_hijklmnop/lead2gold/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
2018-03-03 23:34:10 +01:00
|
|
|
# Testing image
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?image=Yes', {
|
2017-12-23 04:47:46 +01:00
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
2018-03-03 23:34:10 +01:00
|
|
|
# Testing invalid format (fall's back to html)
|
2017-12-23 04:47:46 +01:00
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=invalid', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
2018-03-03 23:34:10 +01:00
|
|
|
# Testing empty format (falls back to html)
|
2017-12-23 04:47:46 +01:00
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
2019-02-06 04:02:42 +01:00
|
|
|
# Testing valid formats
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=markdown', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=html', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?format=text', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
}),
|
2017-12-23 04:47:46 +01:00
|
|
|
# Simple Message without image
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
# Invalid Bot Token
|
|
|
|
('tgram://alpha:abcdefg_hijklmnop/lead2gold/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
# AuthToken + bad url
|
|
|
|
('tgram://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
2018-03-03 23:34:10 +01:00
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?image=Yes', {
|
2017-12-23 04:47:46 +01:00
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# force a failure without an image specified
|
|
|
|
'include_image': False,
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/id1/id2/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# force a failure with multiple chat_ids
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/id1/id2/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# force a failure without an image specified
|
|
|
|
'include_image': False,
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up without
|
|
|
|
# having an image included
|
|
|
|
'include_image': False,
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
2018-03-03 23:34:10 +01:00
|
|
|
# Test with image set
|
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?image=Yes', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up without
|
|
|
|
# having an image included
|
|
|
|
'include_image': True,
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
2017-12-23 04:47:46 +01:00
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/', {
|
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2018-03-03 23:34:10 +01:00
|
|
|
('tgram://123456789:abcdefg_hijklmnop/lead2gold/?image=Yes', {
|
2017-12-23 04:47:46 +01:00
|
|
|
'instance': plugins.NotifyTelegram,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them without images set
|
2018-03-03 23:34:10 +01:00
|
|
|
'include_image': True,
|
2017-12-23 04:47:46 +01:00
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-05-09 16:06:20 +02:00
|
|
|
##################################
|
|
|
|
# NotifyTwilio
|
|
|
|
##################################
|
|
|
|
('twilio://', {
|
2019-06-30 21:32:12 +02:00
|
|
|
# No Account SID specified
|
|
|
|
'instance': TypeError,
|
2019-05-09 16:06:20 +02:00
|
|
|
}),
|
|
|
|
('twilio://:@/', {
|
|
|
|
# invalid Auth token
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twilio://AC{}@12345678'.format('a' * 32), {
|
|
|
|
# Just sid provided
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twilio://AC{}:{}@_'.format('a' * 32, 'b' * 32), {
|
|
|
|
# sid and token provided but invalid from
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twilio://AC{}:{}@{}'.format('a' * 32, 'b' * 32, '3' * 5), {
|
|
|
|
# using short-code (5 characters) without a target
|
2019-10-09 18:39:31 +02:00
|
|
|
# We can still instantiate ourselves with a valid short code
|
2019-05-09 16:06:20 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twilio://AC{}:{}@{}'.format('a' * 32, 'b' * 32, '3' * 9), {
|
|
|
|
# sid and token provided and from but invalid from no
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twilio://AC{}:{}@{}/123/{}/abcd/'.format(
|
|
|
|
'a' * 32, 'b' * 32, '3' * 11, '9' * 15), {
|
|
|
|
# valid everything but target numbers
|
|
|
|
'instance': plugins.NotifyTwilio,
|
|
|
|
}),
|
|
|
|
('twilio://AC{}:{}@12345/{}'.format('a' * 32, 'b' * 32, '4' * 11), {
|
|
|
|
# using short-code (5 characters)
|
|
|
|
'instance': plugins.NotifyTwilio,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'twilio://...aaaa:b...b@12345',
|
2019-05-09 16:06:20 +02:00
|
|
|
}),
|
|
|
|
('twilio://AC{}:{}@123456/{}'.format('a' * 32, 'b' * 32, '4' * 11), {
|
|
|
|
# using short-code (6 characters)
|
|
|
|
'instance': plugins.NotifyTwilio,
|
|
|
|
}),
|
|
|
|
('twilio://AC{}:{}@{}'.format('a' * 32, 'b' * 32, '5' * 11), {
|
|
|
|
# using phone no with no target - we text ourselves in
|
|
|
|
# this case
|
|
|
|
'instance': plugins.NotifyTwilio,
|
|
|
|
}),
|
|
|
|
('twilio://_?sid=AC{}&token={}&from={}'.format(
|
|
|
|
'a' * 32, 'b' * 32, '5' * 11), {
|
|
|
|
# use get args to acomplish the same thing
|
|
|
|
'instance': plugins.NotifyTwilio,
|
|
|
|
}),
|
|
|
|
('twilio://_?sid=AC{}&token={}&source={}'.format(
|
|
|
|
'a' * 32, 'b' * 32, '5' * 11), {
|
|
|
|
# use get args to acomplish the same thing (use source instead of from)
|
|
|
|
'instance': plugins.NotifyTwilio,
|
|
|
|
}),
|
|
|
|
('twilio://_?sid=AC{}&token={}&from={}&to={}'.format(
|
|
|
|
'a' * 32, 'b' * 32, '5' * 11, '7' * 13), {
|
|
|
|
# use to=
|
|
|
|
'instance': plugins.NotifyTwilio,
|
|
|
|
}),
|
|
|
|
('twilio://AC{}:{}@{}'.format('a' * 32, 'b' * 32, '6' * 11), {
|
|
|
|
'instance': plugins.NotifyTwilio,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('twilio://AC{}:{}@{}'.format('a' * 32, 'b' * 32, '6' * 11), {
|
|
|
|
'instance': plugins.NotifyTwilio,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-07-19 04:41:10 +02:00
|
|
|
##################################
|
|
|
|
# NotifyTwist
|
|
|
|
##################################
|
|
|
|
('twist://', {
|
|
|
|
# Missing Email and Login
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('twist://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('twist://user@example.com/', {
|
|
|
|
# No password
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('twist://user@example.com/password', {
|
|
|
|
# Password acceptable as first entry in path
|
|
|
|
'instance': plugins.NotifyTwist,
|
|
|
|
# Expected notify() response is False because internally we would
|
|
|
|
# have failed to login
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('twist://password:user1@example.com', {
|
|
|
|
# password:login acceptable
|
|
|
|
'instance': plugins.NotifyTwist,
|
|
|
|
# Expected notify() response is False because internally we would
|
|
|
|
# have failed to login
|
|
|
|
'notify_response': False,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'twist://****:user1@example.com',
|
2019-07-19 04:41:10 +02:00
|
|
|
}),
|
|
|
|
('twist://password:user2@example.com', {
|
|
|
|
# password:login acceptable
|
|
|
|
'instance': plugins.NotifyTwist,
|
|
|
|
# Expected notify() response is False because internally we would
|
|
|
|
# have logged in, but we would have failed to look up the #General
|
|
|
|
# channel and workspace.
|
|
|
|
'requests_response_text': {
|
|
|
|
# Login expected response
|
|
|
|
'id': 1234,
|
|
|
|
'default_workspace': 9876,
|
|
|
|
},
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('twist://password:user2@example.com', {
|
|
|
|
'instance': plugins.NotifyTwist,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('twist://password:user2@example.com', {
|
|
|
|
'instance': plugins.NotifyTwist,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2021-03-04 16:02:26 +01:00
|
|
|
|
2019-06-30 00:27:59 +02:00
|
|
|
##################################
|
|
|
|
# NotifyTwitter
|
|
|
|
##################################
|
|
|
|
('twitter://', {
|
2019-06-30 21:32:12 +02:00
|
|
|
# Missing Consumer API Key
|
|
|
|
'instance': TypeError,
|
2019-06-30 00:27:59 +02:00
|
|
|
}),
|
|
|
|
('twitter://:@/', {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twitter://consumer_key', {
|
|
|
|
# Missing Keys
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twitter://consumer_key/consumer_secret/', {
|
|
|
|
# Missing Keys
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twitter://consumer_key/consumer_secret/access_token/', {
|
|
|
|
# Missing Access Secret
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twitter://consumer_key/consumer_secret/access_token/access_secret', {
|
|
|
|
# No user mean's we message ourselves
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
# Expected notify() response False (because we won't be able
|
|
|
|
# to detect our user)
|
|
|
|
'notify_response': False,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'twitter://c...y/****/a...n/****',
|
2019-06-30 00:27:59 +02:00
|
|
|
}),
|
|
|
|
('twitter://consumer_key/consumer_secret/access_token/access_secret'
|
|
|
|
'?cache=no', {
|
|
|
|
# No user mean's we message ourselves
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
# However we'll be okay if we return a proper response
|
|
|
|
'requests_response_text': {
|
|
|
|
'id': 12345,
|
|
|
|
'screen_name': 'test'
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
('twitter://consumer_key/consumer_secret/access_token/access_secret', {
|
|
|
|
# No user mean's we message ourselves
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
# However we'll be okay if we return a proper response
|
|
|
|
'requests_response_text': {
|
|
|
|
'id': 12345,
|
|
|
|
'screen_name': 'test'
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# A duplicate of the entry above, this will cause cache to be referenced
|
|
|
|
('twitter://consumer_key/consumer_secret/access_token/access_secret', {
|
|
|
|
# No user mean's we message ourselves
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
# However we'll be okay if we return a proper response
|
|
|
|
'requests_response_text': {
|
|
|
|
'id': 12345,
|
|
|
|
'screen_name': 'test'
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
# handle cases where the screen_name is missing from the response causing
|
|
|
|
# an exception during parsing
|
|
|
|
('twitter://consumer_key/consumer_secret2/access_token/access_secret', {
|
|
|
|
# No user mean's we message ourselves
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
# However we'll be okay if we return a proper response
|
|
|
|
'requests_response_text': {
|
|
|
|
'id': 12345,
|
|
|
|
},
|
|
|
|
# due to a mangled response_text we'll fail
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('twitter://user@consumer_key/csecret2/access_token/access_secret/-/%/', {
|
|
|
|
# One Invalid User
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
# Expected notify() response False (because we won't be able
|
|
|
|
# to detect our user)
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('twitter://user@consumer_key/csecret/access_token/access_secret'
|
|
|
|
'?cache=No', {
|
|
|
|
# No Cache
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
'requests_response_text': [{
|
|
|
|
'id': 12345,
|
|
|
|
'screen_name': 'user'
|
|
|
|
}],
|
|
|
|
}),
|
|
|
|
('twitter://user@consumer_key/csecret/access_token/access_secret', {
|
|
|
|
# We're good!
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
'requests_response_text': [{
|
|
|
|
'id': 12345,
|
|
|
|
'screen_name': 'user'
|
|
|
|
}],
|
|
|
|
}),
|
|
|
|
# A duplicate of the entry above, this will cause cache to be referenced
|
|
|
|
# for this reason, we don't even need to return a valid response
|
|
|
|
('twitter://user@consumer_key/csecret/access_token/access_secret', {
|
|
|
|
# We're identifying the same user we already sent to
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
}),
|
|
|
|
('twitter://ckey/csecret/access_token/access_secret?mode=tweet', {
|
|
|
|
# A Public Tweet
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
}),
|
|
|
|
('twitter://user@ckey/csecret/access_token/access_secret?mode=invalid', {
|
|
|
|
# An invalid mode
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('twitter://usera@consumer_key/consumer_secret/access_token/'
|
|
|
|
'access_secret/user/?to=userb', {
|
|
|
|
# We're good!
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
'requests_response_text': [{
|
|
|
|
'id': 12345,
|
|
|
|
'screen_name': 'usera'
|
|
|
|
}, {
|
|
|
|
'id': 12346,
|
|
|
|
'screen_name': 'userb'
|
|
|
|
}, {
|
|
|
|
# A garbage entry we can test exception handling on
|
|
|
|
'id': 123,
|
|
|
|
}],
|
|
|
|
}),
|
|
|
|
('twitter://ckey/csecret/access_token/access_secret', {
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('twitter://ckey/csecret/access_token/access_secret', {
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
('twitter://ckey/csecret/access_token/access_secret?mode=tweet', {
|
|
|
|
'instance': plugins.NotifyTwitter,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2019-08-18 21:30:38 +02:00
|
|
|
|
|
|
|
##################################
|
|
|
|
# NotifyMSG91
|
|
|
|
##################################
|
|
|
|
('msg91://', {
|
|
|
|
# No hostname/authkey specified
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-08-18 21:30:38 +02:00
|
|
|
}),
|
|
|
|
('msg91://-', {
|
|
|
|
# Invalid AuthKey
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-08-18 21:30:38 +02:00
|
|
|
}),
|
|
|
|
('msg91://{}'.format('a' * 23), {
|
2019-10-09 18:39:31 +02:00
|
|
|
# No number specified
|
|
|
|
'instance': TypeError,
|
2019-08-18 21:30:38 +02:00
|
|
|
}),
|
|
|
|
('msg91://{}/123'.format('a' * 23), {
|
|
|
|
# invalid phone number
|
2019-10-09 18:39:31 +02:00
|
|
|
'instance': TypeError,
|
2019-08-18 21:30:38 +02:00
|
|
|
}),
|
|
|
|
('msg91://{}/abcd'.format('a' * 23), {
|
2019-10-09 18:39:31 +02:00
|
|
|
# No number to notify
|
|
|
|
'instance': TypeError,
|
2019-08-18 21:30:38 +02:00
|
|
|
}),
|
|
|
|
('msg91://{}/15551232000/?country=invalid'.format('a' * 23), {
|
|
|
|
# invalid country
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msg91://{}/15551232000/?country=99'.format('a' * 23), {
|
|
|
|
# invalid country
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msg91://{}/15551232000/?route=invalid'.format('a' * 23), {
|
|
|
|
# invalid route
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msg91://{}/15551232000/?route=99'.format('a' * 23), {
|
|
|
|
# invalid route
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msg91://{}/15551232000'.format('a' * 23), {
|
|
|
|
# a valid message
|
|
|
|
'instance': plugins.NotifyMSG91,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'msg91://a...a/15551232000',
|
2019-08-18 21:30:38 +02:00
|
|
|
}),
|
|
|
|
('msg91://{}/?to=15551232000'.format('a' * 23), {
|
|
|
|
# a valid message
|
|
|
|
'instance': plugins.NotifyMSG91,
|
|
|
|
}),
|
|
|
|
('msg91://{}/15551232000?country=91&route=1'.format('a' * 23), {
|
|
|
|
# using phone no with no target - we text ourselves in
|
|
|
|
# this case
|
|
|
|
'instance': plugins.NotifyMSG91,
|
|
|
|
}),
|
|
|
|
('msg91://{}/15551232000'.format('a' * 23), {
|
|
|
|
# use get args to acomplish the same thing
|
|
|
|
'instance': plugins.NotifyMSG91,
|
|
|
|
}),
|
|
|
|
('msg91://{}/15551232000'.format('a' * 23), {
|
|
|
|
'instance': plugins.NotifyMSG91,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('msg91://{}/15551232000'.format('a' * 23), {
|
|
|
|
'instance': plugins.NotifyMSG91,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-08-23 02:01:20 +02:00
|
|
|
##################################
|
|
|
|
# NotifyMessageBird
|
|
|
|
##################################
|
|
|
|
('msgbird://', {
|
|
|
|
# No hostname/apikey specified
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-08-23 02:01:20 +02:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('msgbird://{}/abcd'.format('a' * 25), {
|
|
|
|
# invalid characters in source phone number
|
2019-08-23 02:01:20 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msgbird://{}/123'.format('a' * 25), {
|
2019-10-09 18:39:31 +02:00
|
|
|
# invalid source phone number
|
2019-08-23 02:01:20 +02:00
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('msgbird://{}/15551232000'.format('a' * 25), {
|
|
|
|
# target phone number becomes who we text too; all is good
|
|
|
|
'instance': plugins.NotifyMessageBird,
|
2019-09-29 23:17:25 +02:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'msgbird://a...a/15551232000',
|
2019-08-23 02:01:20 +02:00
|
|
|
}),
|
2019-10-09 18:39:31 +02:00
|
|
|
('msgbird://{}/15551232000/abcd'.format('a' * 25), {
|
|
|
|
# invalid target phone number; we have no one to notify
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
2019-08-23 02:01:20 +02:00
|
|
|
('msgbird://{}/15551232000/123'.format('a' * 25), {
|
2019-10-09 18:39:31 +02:00
|
|
|
# invalid target phone number
|
|
|
|
'instance': TypeError,
|
2019-08-23 02:01:20 +02:00
|
|
|
}),
|
|
|
|
('msgbird://{}/?from=15551233000&to=15551232000'.format('a' * 25), {
|
2019-10-09 18:39:31 +02:00
|
|
|
# reference to to= and from=
|
2019-08-23 02:01:20 +02:00
|
|
|
'instance': plugins.NotifyMessageBird,
|
|
|
|
}),
|
2019-09-21 02:56:00 +02:00
|
|
|
('msgbird://{}/15551232000'.format('a' * 25), {
|
|
|
|
'instance': plugins.NotifyMessageBird,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
2019-08-23 02:01:20 +02:00
|
|
|
('msgbird://{}/15551232000'.format('a' * 25), {
|
|
|
|
'instance': plugins.NotifyMessageBird,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('msgbird://{}/15551232000'.format('a' * 25), {
|
|
|
|
'instance': plugins.NotifyMessageBird,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2019-04-06 06:33:44 +02:00
|
|
|
##################################
|
2020-07-23 16:04:59 +02:00
|
|
|
# NotifyPopcorn (PopcornNotify)
|
|
|
|
##################################
|
|
|
|
('popcorn://', {
|
|
|
|
# No hostname/apikey specified
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2020-07-23 16:04:59 +02:00
|
|
|
}),
|
|
|
|
('popcorn://{}/18001231234'.format('_' * 9), {
|
|
|
|
# invalid apikey
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('popcorn://{}/1232348923489234923489234289-32423'.format('a' * 9), {
|
|
|
|
# invalid phone number
|
|
|
|
'instance': plugins.NotifyPopcornNotify,
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('popcorn://{}/abc'.format('b' * 9), {
|
|
|
|
# invalid email
|
|
|
|
'instance': plugins.NotifyPopcornNotify,
|
|
|
|
'notify_response': False,
|
|
|
|
}),
|
|
|
|
('popcorn://{}/15551232000/user@example.com'.format('c' * 9), {
|
|
|
|
# value phone and email
|
|
|
|
'instance': plugins.NotifyPopcornNotify,
|
|
|
|
}),
|
|
|
|
('popcorn://{}/15551232000/user@example.com?batch=yes'.format('w' * 9), {
|
|
|
|
# value phone and email with batch mode set
|
|
|
|
'instance': plugins.NotifyPopcornNotify,
|
|
|
|
}),
|
|
|
|
('popcorn://{}/?to=15551232000'.format('w' * 9), {
|
|
|
|
# reference to to=
|
|
|
|
'instance': plugins.NotifyPopcornNotify,
|
|
|
|
}),
|
|
|
|
('popcorn://{}/15551232000'.format('x' * 9), {
|
|
|
|
'instance': plugins.NotifyPopcornNotify,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('popcorn://{}/15551232000'.format('y' * 9), {
|
|
|
|
'instance': plugins.NotifyPopcornNotify,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('popcorn://{}/15551232000'.format('z' * 9), {
|
|
|
|
'instance': plugins.NotifyPopcornNotify,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
|
|
|
##################################
|
2019-04-06 06:33:44 +02:00
|
|
|
# NotifyWebexTeams
|
|
|
|
##################################
|
|
|
|
('wxteams://', {
|
2019-06-30 21:32:12 +02:00
|
|
|
# Teams Token missing
|
|
|
|
'instance': TypeError,
|
2019-04-06 06:33:44 +02:00
|
|
|
}),
|
|
|
|
('wxteams://:@/', {
|
|
|
|
# We don't have strict host checking on for wxteams, so this URL
|
|
|
|
# actually becomes parseable and :@ becomes a hostname.
|
|
|
|
# The below errors because a second token wasn't found
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('wxteams://{}'.format('a' * 80), {
|
|
|
|
# token provided - we're good
|
|
|
|
'instance': plugins.NotifyWebexTeams,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'wxteams://a...a/',
|
2019-04-06 06:33:44 +02:00
|
|
|
}),
|
2019-06-01 02:56:54 +02:00
|
|
|
# Support Native URLs
|
|
|
|
('https://api.ciscospark.com/v1/webhooks/incoming/{}'.format('a' * 80), {
|
|
|
|
# token provided - we're good
|
|
|
|
'instance': plugins.NotifyWebexTeams,
|
|
|
|
}),
|
2019-10-13 00:02:05 +02:00
|
|
|
# Support Native URLs with arguments
|
|
|
|
('https://api.ciscospark.com/v1/webhooks/incoming/{}?format=text'.format(
|
|
|
|
'a' * 80), {
|
|
|
|
# token provided - we're good
|
|
|
|
'instance': plugins.NotifyWebexTeams,
|
|
|
|
}),
|
2019-04-06 06:33:44 +02:00
|
|
|
('wxteams://{}'.format('a' * 80), {
|
|
|
|
'instance': plugins.NotifyWebexTeams,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('wxteams://{}'.format('a' * 80), {
|
|
|
|
'instance': plugins.NotifyWebexTeams,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('wxteams://{}'.format('a' * 80), {
|
|
|
|
'instance': plugins.NotifyWebexTeams,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
2017-12-11 03:28:00 +01:00
|
|
|
##################################
|
|
|
|
# NotifyKODI
|
|
|
|
##################################
|
|
|
|
('xbmc://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('xbmc://localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
2019-03-27 04:06:20 +01:00
|
|
|
('xbmc://localhost?duration=14', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
|
|
|
('xbmc://localhost?duration=invalid', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
|
|
|
('xbmc://localhost?duration=-1', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
2017-12-11 03:28:00 +01:00
|
|
|
('xbmc://user:pass@localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
|
|
|
('xbmc://localhost:8080', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
|
|
|
('xbmc://user:pass@localhost:8080', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
}),
|
2019-02-13 23:48:09 +01:00
|
|
|
('xbmc://user@localhost', {
|
2017-12-11 03:28:00 +01:00
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
('xbmc://localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# Experement with different notification types
|
|
|
|
'notify_type': NotifyType.WARNING,
|
|
|
|
}),
|
|
|
|
('xbmc://localhost', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# Experement with different notification types
|
|
|
|
'notify_type': NotifyType.FAILURE,
|
|
|
|
}),
|
|
|
|
('xbmc://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('xbmc://user:pass@localhost:8081', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('xbmc://user:pass@localhost:8082', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('xbmc://user:pass@localhost:8083', {
|
|
|
|
'instance': plugins.NotifyXBMC,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
|
|
|
|
|
|
|
##################################
|
|
|
|
# NotifyXML
|
|
|
|
##################################
|
2019-10-27 19:32:51 +01:00
|
|
|
('xml://:@/', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
2017-12-11 03:28:00 +01:00
|
|
|
('xml://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('xmls://', {
|
|
|
|
'instance': None,
|
|
|
|
}),
|
|
|
|
('xml://localhost', {
|
|
|
|
'instance': plugins.NotifyXML,
|
|
|
|
}),
|
2019-02-13 23:48:09 +01:00
|
|
|
('xml://user@localhost', {
|
|
|
|
'instance': plugins.NotifyXML,
|
|
|
|
}),
|
2017-12-11 03:28:00 +01:00
|
|
|
('xml://user:pass@localhost', {
|
|
|
|
'instance': plugins.NotifyXML,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'xml://user:****@localhost',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('xml://localhost:8080', {
|
|
|
|
'instance': plugins.NotifyXML,
|
|
|
|
}),
|
|
|
|
('xml://user:pass@localhost:8080', {
|
|
|
|
'instance': plugins.NotifyXML,
|
|
|
|
}),
|
|
|
|
('xmls://localhost', {
|
|
|
|
'instance': plugins.NotifyXML,
|
|
|
|
}),
|
|
|
|
('xmls://user:pass@localhost', {
|
|
|
|
'instance': plugins.NotifyXML,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'xmls://user:****@localhost',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('xmls://localhost:8080/path/', {
|
|
|
|
'instance': plugins.NotifyXML,
|
2019-10-27 19:32:51 +01:00
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'xmls://localhost:8080/path/',
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('xmls://user:pass@localhost:8080', {
|
|
|
|
'instance': plugins.NotifyXML,
|
|
|
|
}),
|
2019-10-27 19:32:51 +01:00
|
|
|
('xml://localhost:8080/path?-HeaderKey=HeaderValue', {
|
|
|
|
'instance': plugins.NotifyXML,
|
2017-12-11 03:28:00 +01:00
|
|
|
}),
|
|
|
|
('xml://user:pass@localhost:8081', {
|
|
|
|
'instance': plugins.NotifyXML,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('xml://user:pass@localhost:8082', {
|
|
|
|
'instance': plugins.NotifyXML,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('xml://user:pass@localhost:8083', {
|
|
|
|
'instance': plugins.NotifyXML,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2019-06-23 20:03:45 +02:00
|
|
|
|
|
|
|
##################################
|
|
|
|
# NotifyZulip
|
|
|
|
##################################
|
|
|
|
('zulip://', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-06-23 20:03:45 +02:00
|
|
|
}),
|
|
|
|
('zulip://:@/', {
|
2020-08-08 15:08:49 +02:00
|
|
|
'instance': TypeError,
|
2019-06-23 20:03:45 +02:00
|
|
|
}),
|
|
|
|
('zulip://apprise', {
|
|
|
|
# Just org provided (no token or botname)
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
('zulip://botname@apprise', {
|
|
|
|
# Just org and botname provided (no token)
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# invalid token
|
|
|
|
('zulip://botname@apprise/{}'.format('a' * 24), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# invalid botname
|
|
|
|
('zulip://....@apprise/{}'.format('a' * 32), {
|
|
|
|
'instance': TypeError,
|
|
|
|
}),
|
|
|
|
# Valid everything - no target so default is used
|
|
|
|
('zulip://botname@apprise/{}'.format('a' * 32), {
|
|
|
|
'instance': plugins.NotifyZulip,
|
2019-09-29 23:17:25 +02:00
|
|
|
|
|
|
|
# Our expected url(privacy=True) startswith() response:
|
|
|
|
'privacy_url': 'zulip://botname@apprise/a...a/',
|
2019-06-23 20:03:45 +02:00
|
|
|
}),
|
|
|
|
# Valid everything - organization as hostname
|
|
|
|
('zulip://botname@apprise.zulipchat.com/{}'.format('a' * 32), {
|
|
|
|
'instance': plugins.NotifyZulip,
|
|
|
|
}),
|
2020-12-15 00:45:54 +01:00
|
|
|
# Valid everything - 2 streams specified
|
2019-06-23 20:03:45 +02:00
|
|
|
('zulip://botname@apprise/{}/channel1/channel2'.format('a' * 32), {
|
|
|
|
'instance': plugins.NotifyZulip,
|
|
|
|
}),
|
2020-12-15 00:45:54 +01:00
|
|
|
# Valid everything - 2 streams specified (using to=)
|
2019-06-23 20:03:45 +02:00
|
|
|
('zulip://botname@apprise/{}/?to=channel1/channel2'.format('a' * 32), {
|
|
|
|
'instance': plugins.NotifyZulip,
|
|
|
|
}),
|
|
|
|
# Valid everything - 2 emails specified
|
|
|
|
('zulip://botname@apprise/{}/user@example.com/user2@example.com'.format(
|
|
|
|
'a' * 32), {
|
|
|
|
'instance': plugins.NotifyZulip,
|
|
|
|
}),
|
|
|
|
('zulip://botname@apprise/{}'.format('a' * 32), {
|
|
|
|
'instance': plugins.NotifyZulip,
|
|
|
|
# don't include an image by default
|
|
|
|
'include_image': False,
|
|
|
|
}),
|
|
|
|
('zulip://botname@apprise/{}'.format('a' * 32), {
|
|
|
|
'instance': plugins.NotifyZulip,
|
|
|
|
# force a failure
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': requests.codes.internal_server_error,
|
|
|
|
}),
|
|
|
|
('zulip://botname@apprise/{}'.format('a' * 32), {
|
|
|
|
'instance': plugins.NotifyZulip,
|
|
|
|
# throw a bizzare code forcing us to fail to look it up
|
|
|
|
'response': False,
|
|
|
|
'requests_response_code': 999,
|
|
|
|
}),
|
|
|
|
('zulip://botname@apprise/{}'.format('a' * 32), {
|
|
|
|
'instance': plugins.NotifyZulip,
|
|
|
|
# Throws a series of connection and transfer exceptions when this flag
|
|
|
|
# is set and tests that we gracfully handle them
|
|
|
|
'test_requests_exceptions': True,
|
|
|
|
}),
|
2017-12-04 03:48:23 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
2017-12-06 06:35:03 +01:00
|
|
|
def test_rest_plugins(mock_post, mock_get):
|
2017-12-04 03:48:23 +01:00
|
|
|
"""
|
2017-12-06 06:35:03 +01:00
|
|
|
API: REST Based Plugins()
|
2017-12-04 03:48:23 +01:00
|
|
|
|
|
|
|
"""
|
2019-02-13 23:48:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2017-12-04 03:48:23 +01:00
|
|
|
|
2019-02-18 04:21:59 +01:00
|
|
|
# Define how many characters exist per line
|
|
|
|
row = 80
|
|
|
|
|
|
|
|
# Some variables we use to control the data we work with
|
|
|
|
body_len = 1024
|
|
|
|
title_len = 1024
|
|
|
|
|
|
|
|
# Create a large body and title with random data
|
|
|
|
body = ''.join(choice(str_alpha + str_num + ' ') for _ in range(body_len))
|
|
|
|
body = '\r\n'.join([body[i: i + row] for i in range(0, len(body), row)])
|
|
|
|
|
|
|
|
# Create our title using random data
|
|
|
|
title = ''.join(choice(str_alpha + str_num) for _ in range(title_len))
|
|
|
|
|
2017-12-04 03:48:23 +01:00
|
|
|
# iterate over our dictionary and test it out
|
2017-12-11 03:28:00 +01:00
|
|
|
for (url, meta) in TEST_URLS:
|
2017-12-04 03:48:23 +01:00
|
|
|
# Our expected instance
|
|
|
|
instance = meta.get('instance', None)
|
|
|
|
|
|
|
|
# Our expected server objects
|
|
|
|
self = meta.get('self', None)
|
|
|
|
|
|
|
|
# Our expected Query response (True, False, or exception type)
|
|
|
|
response = meta.get('response', True)
|
|
|
|
|
2019-06-27 02:34:30 +02:00
|
|
|
# Our expected Notify response (True or False)
|
|
|
|
notify_response = meta.get('notify_response', response)
|
|
|
|
|
2019-11-22 04:12:47 +01:00
|
|
|
# Our expected Notify Attachment response (True or False)
|
|
|
|
attach_response = meta.get('attach_response', notify_response)
|
|
|
|
|
2019-09-29 23:17:25 +02:00
|
|
|
# Our expected privacy url
|
|
|
|
# Don't set this if don't need to check it's value
|
|
|
|
privacy_url = meta.get('privacy_url')
|
|
|
|
|
2020-08-07 21:27:58 +02:00
|
|
|
# Our regular expression
|
|
|
|
url_matches = meta.get('url_matches')
|
|
|
|
|
2019-11-22 04:12:47 +01:00
|
|
|
# Test attachments
|
|
|
|
# Don't set this if don't need to check it's value
|
|
|
|
check_attachments = meta.get('check_attachments', True)
|
|
|
|
|
2017-12-04 03:48:23 +01:00
|
|
|
# Allow us to force the server response code to be something other then
|
|
|
|
# the defaults
|
|
|
|
requests_response_code = meta.get(
|
2017-12-11 03:28:00 +01:00
|
|
|
'requests_response_code',
|
|
|
|
requests.codes.ok if response else requests.codes.not_found,
|
|
|
|
)
|
|
|
|
|
2017-12-25 21:07:41 +01:00
|
|
|
# Allow us to force the server response text to be something other then
|
|
|
|
# the defaults
|
|
|
|
requests_response_text = meta.get('requests_response_text')
|
2019-02-25 07:02:29 +01:00
|
|
|
if not isinstance(requests_response_text, six.string_types):
|
2017-12-25 21:07:41 +01:00
|
|
|
# Convert to string
|
|
|
|
requests_response_text = dumps(requests_response_text)
|
|
|
|
|
2017-12-11 03:28:00 +01:00
|
|
|
# Allow notification type override, otherwise default to INFO
|
|
|
|
notify_type = meta.get('notify_type', NotifyType.INFO)
|
|
|
|
|
|
|
|
# Whether or not we should include an image with our request; unless
|
|
|
|
# otherwise specified, we assume that images are to be included
|
|
|
|
include_image = meta.get('include_image', True)
|
|
|
|
if include_image:
|
|
|
|
# a default asset
|
|
|
|
asset = AppriseAsset()
|
|
|
|
|
|
|
|
else:
|
|
|
|
# Disable images
|
|
|
|
asset = AppriseAsset(image_path_mask=False, image_url_mask=False)
|
2019-02-25 07:02:29 +01:00
|
|
|
asset.image_url_logo = None
|
2017-12-04 03:48:23 +01:00
|
|
|
|
|
|
|
test_requests_exceptions = meta.get(
|
|
|
|
'test_requests_exceptions', False)
|
|
|
|
|
2017-12-14 03:35:59 +01:00
|
|
|
# A request
|
|
|
|
robj = mock.Mock()
|
2019-02-25 07:02:29 +01:00
|
|
|
robj.content = u''
|
2017-12-14 03:35:59 +01:00
|
|
|
mock_get.return_value = robj
|
|
|
|
mock_post.return_value = robj
|
|
|
|
|
2017-12-04 03:48:23 +01:00
|
|
|
if test_requests_exceptions is False:
|
|
|
|
# Handle our default response
|
|
|
|
mock_post.return_value.status_code = requests_response_code
|
|
|
|
mock_get.return_value.status_code = requests_response_code
|
2017-12-25 21:07:41 +01:00
|
|
|
|
|
|
|
# Handle our default text response
|
2019-02-25 07:02:29 +01:00
|
|
|
mock_get.return_value.content = requests_response_text
|
|
|
|
mock_post.return_value.content = requests_response_text
|
2021-01-10 21:55:59 +01:00
|
|
|
mock_get.return_value.text = requests_response_text
|
|
|
|
mock_post.return_value.text = requests_response_text
|
2017-12-25 21:07:41 +01:00
|
|
|
|
|
|
|
# Ensure there is no side effect set
|
2017-12-04 03:48:23 +01:00
|
|
|
mock_post.side_effect = None
|
|
|
|
mock_get.side_effect = None
|
|
|
|
|
|
|
|
else:
|
|
|
|
# Handle exception testing; first we turn the boolean flag ito
|
|
|
|
# a list of exceptions
|
2018-03-05 03:06:41 +01:00
|
|
|
test_requests_exceptions = REQUEST_EXCEPTIONS
|
2017-12-04 03:48:23 +01:00
|
|
|
|
|
|
|
try:
|
2017-12-11 03:28:00 +01:00
|
|
|
obj = Apprise.instantiate(
|
|
|
|
url, asset=asset, suppress_exceptions=False)
|
2017-12-04 03:48:23 +01:00
|
|
|
|
|
|
|
if obj is None:
|
2019-03-17 04:35:06 +01:00
|
|
|
if instance is not None:
|
|
|
|
# We're done (assuming this is what we were expecting)
|
|
|
|
print("{} didn't instantiate itself "
|
2019-05-09 16:06:20 +02:00
|
|
|
"(we expected it to be a {})".format(url, instance))
|
2019-03-17 04:35:06 +01:00
|
|
|
assert False
|
2017-12-04 03:48:23 +01:00
|
|
|
continue
|
|
|
|
|
2019-02-13 23:48:09 +01:00
|
|
|
if instance is None:
|
|
|
|
# Expected None but didn't get it
|
|
|
|
print('%s instantiated %s (but expected None)' % (
|
|
|
|
url, str(obj)))
|
2019-03-27 04:06:20 +01:00
|
|
|
assert False
|
2019-02-13 23:48:09 +01:00
|
|
|
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, instance) is True
|
2017-12-04 03:48:23 +01:00
|
|
|
|
2019-05-30 02:07:05 +02:00
|
|
|
if isinstance(obj, plugins.NotifyBase):
|
2019-02-13 23:48:09 +01:00
|
|
|
# We loaded okay; now lets make sure we can reverse this url
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj.url(), six.string_types) is True
|
2019-02-13 23:48:09 +01:00
|
|
|
|
2019-09-29 23:17:25 +02:00
|
|
|
# Test url() with privacy=True
|
|
|
|
assert isinstance(
|
|
|
|
obj.url(privacy=True), six.string_types) is True
|
|
|
|
|
2019-06-30 21:32:12 +02:00
|
|
|
# Some Simple Invalid Instance Testing
|
|
|
|
assert instance.parse_url(None) is None
|
|
|
|
assert instance.parse_url(object) is None
|
|
|
|
assert instance.parse_url(42) is None
|
|
|
|
|
2019-09-29 23:17:25 +02:00
|
|
|
if privacy_url:
|
|
|
|
# Assess that our privacy url is as expected
|
|
|
|
assert obj.url(privacy=True).startswith(privacy_url)
|
|
|
|
|
2020-08-07 21:27:58 +02:00
|
|
|
if url_matches:
|
|
|
|
# Assess that our URL matches a set regex
|
|
|
|
assert re.search(url_matches, obj.url())
|
|
|
|
|
2019-02-13 23:48:09 +01:00
|
|
|
# Instantiate the exact same object again using the URL from
|
|
|
|
# the one that was already created properly
|
|
|
|
obj_cmp = Apprise.instantiate(obj.url())
|
|
|
|
|
|
|
|
# Our object should be the same instance as what we had
|
|
|
|
# originally expected above.
|
2019-05-30 02:07:05 +02:00
|
|
|
if not isinstance(obj_cmp, plugins.NotifyBase):
|
2019-02-13 23:48:09 +01:00
|
|
|
# Assert messages are hard to trace back with the way
|
|
|
|
# these tests work. Just printing before throwing our
|
|
|
|
# assertion failure makes things easier to debug later on
|
|
|
|
print('TEST FAIL: {} regenerated as {}'.format(
|
|
|
|
url, obj.url()))
|
2019-03-27 04:06:20 +01:00
|
|
|
assert False
|
2017-12-23 04:47:46 +01:00
|
|
|
|
2019-06-30 21:32:12 +02:00
|
|
|
# Tidy our object
|
|
|
|
del obj_cmp
|
|
|
|
|
2017-12-04 03:48:23 +01:00
|
|
|
if self:
|
|
|
|
# Iterate over our expected entries inside of our object
|
|
|
|
for key, val in self.items():
|
|
|
|
# Test that our object has the desired key
|
2019-03-27 04:06:20 +01:00
|
|
|
assert hasattr(key, obj) is True
|
|
|
|
assert getattr(key, obj) == val
|
2017-12-04 03:48:23 +01:00
|
|
|
|
2019-02-06 04:02:42 +01:00
|
|
|
#
|
|
|
|
# Stage 1: with title defined
|
|
|
|
#
|
2017-12-04 03:48:23 +01:00
|
|
|
try:
|
|
|
|
if test_requests_exceptions is False:
|
2019-02-17 22:35:09 +01:00
|
|
|
# Disable throttling
|
|
|
|
obj.request_rate_per_sec = 0
|
|
|
|
|
2017-12-06 06:35:03 +01:00
|
|
|
# check that we're as expected
|
2017-12-04 03:48:23 +01:00
|
|
|
assert obj.notify(
|
2019-02-18 04:21:59 +01:00
|
|
|
body=body, title=title,
|
2019-06-27 02:34:30 +02:00
|
|
|
notify_type=notify_type) == notify_response
|
2017-12-04 03:48:23 +01:00
|
|
|
|
2019-02-18 04:21:59 +01:00
|
|
|
# check that this doesn't change using different overflow
|
|
|
|
# methods
|
|
|
|
assert obj.notify(
|
|
|
|
body=body, title=title,
|
|
|
|
notify_type=notify_type,
|
2019-06-27 02:34:30 +02:00
|
|
|
overflow=OverflowMode.UPSTREAM) == notify_response
|
2019-02-18 04:21:59 +01:00
|
|
|
assert obj.notify(
|
|
|
|
body=body, title=title,
|
|
|
|
notify_type=notify_type,
|
2019-06-27 02:34:30 +02:00
|
|
|
overflow=OverflowMode.TRUNCATE) == notify_response
|
2019-02-18 04:21:59 +01:00
|
|
|
assert obj.notify(
|
|
|
|
body=body, title=title,
|
|
|
|
notify_type=notify_type,
|
2019-06-27 02:34:30 +02:00
|
|
|
overflow=OverflowMode.SPLIT) == notify_response
|
2019-02-18 04:21:59 +01:00
|
|
|
|
2020-08-01 15:36:34 +02:00
|
|
|
#
|
|
|
|
# Handle varations of the Asset Object missing fields
|
|
|
|
#
|
|
|
|
|
|
|
|
# First make a backup
|
|
|
|
app_id = asset.app_id
|
|
|
|
app_desc = asset.app_desc
|
|
|
|
|
|
|
|
# now clear records
|
|
|
|
asset.app_id = None
|
|
|
|
asset.app_desc = None
|
|
|
|
|
|
|
|
# Notify should still work
|
|
|
|
assert obj.notify(
|
|
|
|
body=body, title=title,
|
|
|
|
notify_type=notify_type) == notify_response
|
|
|
|
|
|
|
|
# App ID only
|
|
|
|
asset.app_id = app_id
|
|
|
|
asset.app_desc = None
|
|
|
|
|
|
|
|
# Notify should still work
|
|
|
|
assert obj.notify(
|
|
|
|
body=body, title=title,
|
|
|
|
notify_type=notify_type) == notify_response
|
|
|
|
|
|
|
|
# App Desc only
|
|
|
|
asset.app_id = None
|
|
|
|
asset.app_desc = app_desc
|
|
|
|
|
|
|
|
# Notify should still work
|
|
|
|
assert obj.notify(
|
|
|
|
body=body, title=title,
|
|
|
|
notify_type=notify_type) == notify_response
|
|
|
|
|
|
|
|
# Restore
|
|
|
|
asset.app_id = app_id
|
|
|
|
asset.app_desc = app_desc
|
|
|
|
|
2019-11-22 04:12:47 +01:00
|
|
|
if check_attachments:
|
|
|
|
# Test single attachment support; even if the service
|
|
|
|
# doesn't support attachments, it should still
|
|
|
|
# gracefully ignore the data
|
|
|
|
attach = os.path.join(TEST_VAR_DIR, 'apprise-test.gif')
|
|
|
|
assert obj.notify(
|
|
|
|
body=body, title=title,
|
|
|
|
notify_type=notify_type,
|
|
|
|
attach=attach) == attach_response
|
|
|
|
|
|
|
|
# Same results should apply to a list of attachments
|
|
|
|
attach = AppriseAttachment((
|
|
|
|
os.path.join(TEST_VAR_DIR, 'apprise-test.gif'),
|
|
|
|
os.path.join(TEST_VAR_DIR, 'apprise-test.png'),
|
|
|
|
os.path.join(TEST_VAR_DIR, 'apprise-test.jpeg'),
|
|
|
|
))
|
|
|
|
assert obj.notify(
|
|
|
|
body=body, title=title,
|
|
|
|
notify_type=notify_type,
|
|
|
|
attach=attach) == attach_response
|
2019-11-15 01:41:12 +01:00
|
|
|
|
2017-12-04 03:48:23 +01:00
|
|
|
else:
|
2019-02-17 22:35:09 +01:00
|
|
|
# Disable throttling
|
|
|
|
obj.request_rate_per_sec = 0
|
|
|
|
|
2018-03-05 03:06:41 +01:00
|
|
|
for _exception in REQUEST_EXCEPTIONS:
|
2017-12-23 04:47:46 +01:00
|
|
|
mock_post.side_effect = _exception
|
|
|
|
mock_get.side_effect = _exception
|
2017-12-25 21:07:41 +01:00
|
|
|
|
2017-12-04 03:48:23 +01:00
|
|
|
try:
|
|
|
|
assert obj.notify(
|
2019-02-18 04:21:59 +01:00
|
|
|
body=body, title=title,
|
2017-12-04 03:48:23 +01:00
|
|
|
notify_type=NotifyType.INFO) is False
|
|
|
|
|
|
|
|
except AssertionError:
|
|
|
|
# Don't mess with these entries
|
|
|
|
raise
|
|
|
|
|
2019-02-18 05:28:37 +01:00
|
|
|
except Exception:
|
2017-12-04 03:48:23 +01:00
|
|
|
# We can't handle this exception type
|
2019-02-13 23:48:09 +01:00
|
|
|
raise
|
2017-12-04 03:48:23 +01:00
|
|
|
|
|
|
|
except AssertionError:
|
|
|
|
# Don't mess with these entries
|
2019-02-06 04:02:42 +01:00
|
|
|
raise
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
# Check that we were expecting this exception to happen
|
2019-02-25 07:02:29 +01:00
|
|
|
try:
|
|
|
|
if not isinstance(e, response):
|
2020-01-12 00:39:53 +01:00
|
|
|
raise e
|
2019-02-25 07:02:29 +01:00
|
|
|
|
|
|
|
except TypeError:
|
|
|
|
print('%s Unhandled response %s' % (url, type(e)))
|
2020-01-12 00:39:53 +01:00
|
|
|
raise e
|
2019-02-06 04:02:42 +01:00
|
|
|
|
|
|
|
#
|
2019-02-10 05:36:27 +01:00
|
|
|
# Stage 2: without title defined
|
2019-02-06 04:02:42 +01:00
|
|
|
#
|
|
|
|
try:
|
|
|
|
if test_requests_exceptions is False:
|
|
|
|
# check that we're as expected
|
2019-06-27 02:34:30 +02:00
|
|
|
assert obj.notify(body='body', notify_type=notify_type) \
|
|
|
|
== notify_response
|
2019-02-06 04:02:42 +01:00
|
|
|
|
|
|
|
else:
|
|
|
|
for _exception in REQUEST_EXCEPTIONS:
|
|
|
|
mock_post.side_effect = _exception
|
|
|
|
mock_get.side_effect = _exception
|
|
|
|
|
|
|
|
try:
|
|
|
|
assert obj.notify(
|
2019-02-18 04:21:59 +01:00
|
|
|
body=body,
|
2019-02-06 04:02:42 +01:00
|
|
|
notify_type=NotifyType.INFO) is False
|
|
|
|
|
|
|
|
except AssertionError:
|
|
|
|
# Don't mess with these entries
|
|
|
|
raise
|
|
|
|
|
2019-02-18 05:28:37 +01:00
|
|
|
except Exception:
|
2019-02-06 04:02:42 +01:00
|
|
|
# We can't handle this exception type
|
2019-02-13 23:48:09 +01:00
|
|
|
raise
|
2019-02-06 04:02:42 +01:00
|
|
|
|
|
|
|
except AssertionError:
|
|
|
|
# Don't mess with these entries
|
2017-12-04 03:48:23 +01:00
|
|
|
raise
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
# Check that we were expecting this exception to happen
|
2019-02-13 23:48:09 +01:00
|
|
|
if not isinstance(e, response):
|
2020-01-12 00:39:53 +01:00
|
|
|
raise e
|
2017-12-04 03:48:23 +01:00
|
|
|
|
2019-06-30 21:32:12 +02:00
|
|
|
# Tidy our object and allow any possible defined deconstructors to
|
|
|
|
# be executed.
|
|
|
|
del obj
|
|
|
|
|
2017-12-04 03:48:23 +01:00
|
|
|
except AssertionError:
|
|
|
|
# Don't mess with these entries
|
2017-12-11 03:28:00 +01:00
|
|
|
print('%s AssertionError' % url)
|
2017-12-04 03:48:23 +01:00
|
|
|
raise
|
|
|
|
|
|
|
|
except Exception as e:
|
|
|
|
# Handle our exception
|
2019-10-09 18:39:31 +02:00
|
|
|
if instance is None:
|
2019-03-27 04:06:20 +01:00
|
|
|
print('%s %s' % (url, str(e)))
|
2020-01-12 00:39:53 +01:00
|
|
|
raise e
|
2019-02-13 23:48:09 +01:00
|
|
|
|
|
|
|
if not isinstance(e, instance):
|
2019-03-27 04:06:20 +01:00
|
|
|
print('%s %s' % (url, str(e)))
|
2020-01-12 00:39:53 +01:00
|
|
|
raise e
|
2017-12-11 03:28:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_boxcar_plugin(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifyBoxcar() Extra Checks
|
|
|
|
|
|
|
|
"""
|
2019-02-13 23:48:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2019-02-13 23:48:09 +01:00
|
|
|
|
2017-12-11 03:28:00 +01:00
|
|
|
# Generate some generic message types
|
|
|
|
device = 'A' * 64
|
|
|
|
tag = '@B' * 63
|
|
|
|
|
|
|
|
access = '-' * 64
|
|
|
|
secret = '_' * 64
|
|
|
|
|
|
|
|
# Initializes the plugin with recipients set to None
|
2019-03-27 04:06:20 +01:00
|
|
|
plugins.NotifyBoxcar(access=access, secret=secret, targets=None)
|
2017-12-11 03:28:00 +01:00
|
|
|
|
|
|
|
# Initializes the plugin with a valid access, but invalid access key
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
2019-03-27 04:06:20 +01:00
|
|
|
plugins.NotifyBoxcar(access=None, secret=secret, targets=None)
|
2017-12-11 03:28:00 +01:00
|
|
|
|
|
|
|
# Initializes the plugin with a valid access, but invalid secret
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
2019-03-27 04:06:20 +01:00
|
|
|
plugins.NotifyBoxcar(access=access, secret=None, targets=None)
|
2017-12-11 03:28:00 +01:00
|
|
|
|
|
|
|
# Initializes the plugin with recipients list
|
|
|
|
# the below also tests our the variation of recipient types
|
|
|
|
plugins.NotifyBoxcar(
|
2019-03-27 04:06:20 +01:00
|
|
|
access=access, secret=secret, targets=[device, tag])
|
2017-12-11 03:28:00 +01:00
|
|
|
|
|
|
|
mock_get.return_value = requests.Request()
|
|
|
|
mock_post.return_value = requests.Request()
|
|
|
|
mock_post.return_value.status_code = requests.codes.created
|
|
|
|
mock_get.return_value.status_code = requests.codes.created
|
2017-12-14 03:35:59 +01:00
|
|
|
|
2017-12-11 03:28:00 +01:00
|
|
|
# Test notifications without a body or a title
|
2019-03-27 04:06:20 +01:00
|
|
|
p = plugins.NotifyBoxcar(access=access, secret=secret, targets=None)
|
|
|
|
|
|
|
|
assert p.notify(body=None, title=None, notify_type=NotifyType.INFO) is True
|
2017-12-23 04:47:46 +01:00
|
|
|
|
2019-03-27 04:06:20 +01:00
|
|
|
# Test comma, separate values
|
|
|
|
device = 'a' * 64
|
|
|
|
|
|
|
|
p = plugins.NotifyBoxcar(
|
|
|
|
access=access, secret=secret,
|
|
|
|
targets=','.join([device, device, device]))
|
|
|
|
assert len(p.device_tokens) == 3
|
2017-12-11 03:28:00 +01:00
|
|
|
|
|
|
|
|
2018-03-05 03:06:41 +01:00
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_emby_plugin_login(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifyEmby.login()
|
|
|
|
|
|
|
|
"""
|
2019-02-17 22:35:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2018-03-05 03:06:41 +01:00
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_get.return_value = requests.Request()
|
|
|
|
mock_post.return_value = requests.Request()
|
|
|
|
|
|
|
|
obj = Apprise.instantiate('emby://l2g:l2gpass@localhost')
|
|
|
|
assert isinstance(obj, plugins.NotifyEmby)
|
|
|
|
|
|
|
|
# Test our exception handling
|
|
|
|
for _exception in REQUEST_EXCEPTIONS:
|
|
|
|
mock_post.side_effect = _exception
|
|
|
|
mock_get.side_effect = _exception
|
|
|
|
# We'll fail to log in each time
|
|
|
|
assert obj.login() is False
|
|
|
|
|
|
|
|
# Disable Exceptions
|
|
|
|
mock_post.side_effect = None
|
|
|
|
mock_get.side_effect = None
|
|
|
|
|
|
|
|
# Our login flat out fails if we don't have proper parseable content
|
|
|
|
mock_post.return_value.content = u''
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
# KeyError handling
|
|
|
|
mock_post.return_value.status_code = 999
|
|
|
|
mock_get.return_value.status_code = 999
|
|
|
|
assert obj.login() is False
|
|
|
|
|
|
|
|
# General Internal Server Error
|
|
|
|
mock_post.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
mock_get.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
assert obj.login() is False
|
|
|
|
|
|
|
|
mock_post.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.status_code = requests.codes.ok
|
|
|
|
|
2020-08-08 15:08:49 +02:00
|
|
|
obj = Apprise.instantiate('emby://l2g:l2gpass@localhost:1234')
|
|
|
|
# Set a different port (outside of default)
|
2018-03-05 03:06:41 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyEmby)
|
2020-08-08 15:08:49 +02:00
|
|
|
assert obj.port == 1234
|
2018-03-05 03:06:41 +01:00
|
|
|
|
|
|
|
# The login will fail because '' is not a parseable JSON response
|
|
|
|
assert obj.login() is False
|
|
|
|
|
|
|
|
# Disable the port completely
|
|
|
|
obj.port = None
|
|
|
|
assert obj.login() is False
|
|
|
|
|
2020-08-08 15:08:49 +02:00
|
|
|
# Default port assignments
|
2018-03-05 03:06:41 +01:00
|
|
|
obj = Apprise.instantiate('emby://l2g:l2gpass@localhost')
|
|
|
|
assert isinstance(obj, plugins.NotifyEmby)
|
2020-08-08 15:08:49 +02:00
|
|
|
assert obj.port == 8096
|
2018-03-05 03:06:41 +01:00
|
|
|
|
|
|
|
# The login will (still) fail because '' is not a parseable JSON response
|
|
|
|
assert obj.login() is False
|
|
|
|
|
|
|
|
# Our login flat out fails if we don't have proper parseable content
|
|
|
|
mock_post.return_value.content = dumps({
|
|
|
|
u'AccessToken': u'0000-0000-0000-0000',
|
|
|
|
})
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
obj = Apprise.instantiate('emby://l2g:l2gpass@localhost')
|
|
|
|
assert isinstance(obj, plugins.NotifyEmby)
|
|
|
|
|
|
|
|
# The login will fail because the 'User' or 'Id' field wasn't parsed
|
|
|
|
assert obj.login() is False
|
|
|
|
|
|
|
|
# Our text content (we intentionally reverse the 2 locations
|
|
|
|
# that store the same thing; we do this so we can test which
|
|
|
|
# one it defaults to if both are present
|
|
|
|
mock_post.return_value.content = dumps({
|
|
|
|
u'User': {
|
|
|
|
u'Id': u'abcd123',
|
|
|
|
},
|
|
|
|
u'Id': u'123abc',
|
|
|
|
u'AccessToken': u'0000-0000-0000-0000',
|
|
|
|
})
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
obj = Apprise.instantiate('emby://l2g:l2gpass@localhost')
|
|
|
|
assert isinstance(obj, plugins.NotifyEmby)
|
|
|
|
|
|
|
|
# Login
|
|
|
|
assert obj.login() is True
|
|
|
|
assert obj.user_id == '123abc'
|
|
|
|
assert obj.access_token == '0000-0000-0000-0000'
|
|
|
|
|
|
|
|
# We're going to log in a second time which checks that we logout
|
|
|
|
# first before logging in again. But this time we'll scrap the
|
|
|
|
# 'Id' area and use the one found in the User area if detected
|
|
|
|
mock_post.return_value.content = dumps({
|
|
|
|
u'User': {
|
|
|
|
u'Id': u'abcd123',
|
|
|
|
},
|
|
|
|
u'AccessToken': u'0000-0000-0000-0000',
|
|
|
|
})
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
# Login
|
|
|
|
assert obj.login() is True
|
|
|
|
assert obj.user_id == 'abcd123'
|
|
|
|
assert obj.access_token == '0000-0000-0000-0000'
|
|
|
|
|
|
|
|
|
|
|
|
@mock.patch('apprise.plugins.NotifyEmby.login')
|
|
|
|
@mock.patch('apprise.plugins.NotifyEmby.logout')
|
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_emby_plugin_sessions(mock_post, mock_get, mock_logout,
|
|
|
|
mock_login):
|
|
|
|
"""
|
|
|
|
API: NotifyEmby.sessions()
|
|
|
|
|
|
|
|
"""
|
2019-02-17 22:35:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2018-03-05 03:06:41 +01:00
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_get.return_value = requests.Request()
|
|
|
|
mock_post.return_value = requests.Request()
|
|
|
|
|
|
|
|
# This is done so we don't obstruct our access_token and user_id values
|
|
|
|
mock_login.return_value = True
|
|
|
|
mock_logout.return_value = True
|
|
|
|
|
|
|
|
obj = Apprise.instantiate('emby://l2g:l2gpass@localhost')
|
|
|
|
assert isinstance(obj, plugins.NotifyEmby)
|
|
|
|
obj.access_token = 'abc'
|
|
|
|
obj.user_id = '123'
|
|
|
|
|
|
|
|
# Test our exception handling
|
|
|
|
for _exception in REQUEST_EXCEPTIONS:
|
|
|
|
mock_post.side_effect = _exception
|
|
|
|
mock_get.side_effect = _exception
|
|
|
|
# We'll fail to log in each time
|
|
|
|
sessions = obj.sessions()
|
|
|
|
assert isinstance(sessions, dict) is True
|
|
|
|
assert len(sessions) == 0
|
|
|
|
|
|
|
|
# Disable Exceptions
|
|
|
|
mock_post.side_effect = None
|
|
|
|
mock_get.side_effect = None
|
|
|
|
|
|
|
|
# Our login flat out fails if we don't have proper parseable content
|
|
|
|
mock_post.return_value.content = u''
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
# KeyError handling
|
|
|
|
mock_post.return_value.status_code = 999
|
|
|
|
mock_get.return_value.status_code = 999
|
|
|
|
sessions = obj.sessions()
|
|
|
|
assert isinstance(sessions, dict) is True
|
|
|
|
assert len(sessions) == 0
|
|
|
|
|
|
|
|
# General Internal Server Error
|
|
|
|
mock_post.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
mock_get.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
sessions = obj.sessions()
|
|
|
|
assert isinstance(sessions, dict) is True
|
|
|
|
assert len(sessions) == 0
|
|
|
|
|
|
|
|
mock_post.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
# Disable the port completely
|
|
|
|
obj.port = None
|
|
|
|
|
|
|
|
sessions = obj.sessions()
|
|
|
|
assert isinstance(sessions, dict) is True
|
|
|
|
assert len(sessions) == 0
|
|
|
|
|
|
|
|
# Let's get some results
|
|
|
|
mock_post.return_value.content = dumps([
|
|
|
|
{
|
|
|
|
u'Id': u'abc123',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
u'Id': u'def456',
|
|
|
|
},
|
|
|
|
{
|
|
|
|
u'InvalidEntry': None,
|
|
|
|
},
|
|
|
|
])
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
sessions = obj.sessions(user_controlled=True)
|
|
|
|
assert isinstance(sessions, dict) is True
|
|
|
|
assert len(sessions) == 2
|
|
|
|
|
|
|
|
# Test it without setting user-controlled sessions
|
|
|
|
sessions = obj.sessions(user_controlled=False)
|
|
|
|
assert isinstance(sessions, dict) is True
|
|
|
|
assert len(sessions) == 2
|
|
|
|
|
|
|
|
# Triggers an authentication failure
|
|
|
|
obj.user_id = None
|
|
|
|
mock_login.return_value = False
|
|
|
|
sessions = obj.sessions()
|
|
|
|
assert isinstance(sessions, dict) is True
|
|
|
|
assert len(sessions) == 0
|
|
|
|
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_flock_plugin(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifyFlock() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# Initializes the plugin with an invalid token
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyFlock(token=None)
|
|
|
|
# Whitespace also acts as an invalid token value
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyFlock(token=" ")
|
|
|
|
|
|
|
|
|
|
|
|
def test_notify_gitter_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifyGitter() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Define our channels
|
|
|
|
targets = ['apprise']
|
|
|
|
|
|
|
|
# Initializes the plugin with an invalid token
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyGitter(token=None, targets=targets)
|
|
|
|
# Whitespace also acts as an invalid token value
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyGitter(token=" ", targets=targets)
|
|
|
|
|
|
|
|
|
|
|
|
def test_notify_gotify_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifyGotify() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Initializes the plugin with an invalid token
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyGotify(token=None)
|
|
|
|
# Whitespace also acts as an invalid token value
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyGotify(token=" ")
|
|
|
|
|
|
|
|
|
2020-08-07 21:27:58 +02:00
|
|
|
def test_notify_lametric_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifyLametric() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Initializes the plugin with an invalid API Key
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyLametric(apikey=None, mode="device")
|
|
|
|
|
|
|
|
# Initializes the plugin with an invalid Client Secret
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyLametric(client_id='valid', secret=None, mode="cloud")
|
|
|
|
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_msg91_plugin(mock_post):
|
|
|
|
"""
|
|
|
|
API: NotifyMSG91() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# Prepare our response
|
|
|
|
response = requests.Request()
|
|
|
|
response.status_code = requests.codes.ok
|
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_post.return_value = response
|
|
|
|
|
|
|
|
# Initialize some generic (but valid) tokens
|
|
|
|
# authkey = '{}'.format('a' * 24)
|
|
|
|
target = '+1 (555) 123-3456'
|
|
|
|
|
|
|
|
# No authkey specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyMSG91(authkey=None, targets=target)
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyMSG91(authkey=" ", targets=target)
|
|
|
|
|
|
|
|
|
|
|
|
def test_notify_prowl_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifyProwl() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Initializes the plugin with an invalid apikey
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyProwl(apikey=None)
|
|
|
|
# Whitespace also acts as an invalid apikey value
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyProwl(apikey=' ')
|
|
|
|
|
|
|
|
# Whitespace also acts as an invalid provider key
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyProwl(apikey='abcd', providerkey=object())
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyProwl(apikey='abcd', providerkey=' ')
|
|
|
|
|
|
|
|
|
2020-01-15 02:57:14 +01:00
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_sinch_plugin(mock_post):
|
|
|
|
"""
|
|
|
|
API: NotifySinch() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# Prepare our response
|
|
|
|
response = requests.Request()
|
|
|
|
response.status_code = requests.codes.ok
|
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_post.return_value = response
|
|
|
|
|
|
|
|
# Initialize some generic (but valid) tokens
|
|
|
|
service_plan_id = '{}'.format('b' * 32)
|
|
|
|
api_token = '{}'.format('b' * 32)
|
|
|
|
source = '+1 (555) 123-3456'
|
|
|
|
|
|
|
|
# No service_plan_id specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifySinch(
|
|
|
|
service_plan_id=None, api_token=api_token, source=source)
|
|
|
|
|
|
|
|
# No api_token specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifySinch(
|
|
|
|
service_plan_id=service_plan_id, api_token=None, 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 = plugins.NotifySinch(
|
|
|
|
service_plan_id=service_plan_id, api_token=api_token, source=source)
|
|
|
|
|
|
|
|
# We will fail with the above error code
|
|
|
|
assert obj.notify('title', 'body', 'info') is False
|
|
|
|
|
|
|
|
|
2019-05-09 16:06:20 +02:00
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_twilio_plugin(mock_post):
|
|
|
|
"""
|
|
|
|
API: NotifyTwilio() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2019-05-09 16:06:20 +02:00
|
|
|
|
|
|
|
# Prepare our response
|
|
|
|
response = requests.Request()
|
|
|
|
response.status_code = requests.codes.ok
|
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_post.return_value = response
|
|
|
|
|
|
|
|
# Initialize some generic (but valid) tokens
|
|
|
|
account_sid = 'AC{}'.format('b' * 32)
|
|
|
|
auth_token = '{}'.format('b' * 32)
|
|
|
|
source = '+1 (555) 123-3456'
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No account_sid specified
|
|
|
|
with pytest.raises(TypeError):
|
2019-05-09 16:06:20 +02:00
|
|
|
plugins.NotifyTwilio(
|
|
|
|
account_sid=None, auth_token=auth_token, source=source)
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No auth_token specified
|
|
|
|
with pytest.raises(TypeError):
|
2019-05-09 16:06:20 +02:00
|
|
|
plugins.NotifyTwilio(
|
|
|
|
account_sid=account_sid, auth_token=None, 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 = plugins.NotifyTwilio(
|
|
|
|
account_sid=account_sid, auth_token=auth_token, source=source)
|
|
|
|
|
|
|
|
# We will fail with the above error code
|
|
|
|
assert obj.notify('title', 'body', 'info') is False
|
|
|
|
|
|
|
|
|
2019-06-07 04:59:05 +02:00
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_nexmo_plugin(mock_post):
|
|
|
|
"""
|
|
|
|
API: NotifyNexmo() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# Prepare our response
|
|
|
|
response = requests.Request()
|
|
|
|
response.status_code = requests.codes.ok
|
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_post.return_value = response
|
|
|
|
|
|
|
|
# Initialize some generic (but valid) tokens
|
2019-10-09 18:39:31 +02:00
|
|
|
apikey = 'AC{}'.format('b' * 8)
|
2019-06-07 04:59:05 +02:00
|
|
|
secret = '{}'.format('b' * 16)
|
|
|
|
source = '+1 (555) 123-3456'
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No apikey specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyNexmo(apikey=None, secret=secret, source=source)
|
2019-06-07 04:59:05 +02:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyNexmo(apikey=" ", secret=secret, source=source)
|
2019-06-07 04:59:05 +02:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No secret specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyNexmo(apikey=apikey, secret=None, source=source)
|
2019-06-07 04:59:05 +02:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyNexmo(apikey=apikey, secret=" ", source=source)
|
2019-06-07 04:59:05 +02:00
|
|
|
|
|
|
|
# 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 = plugins.NotifyNexmo(
|
|
|
|
apikey=apikey, secret=secret, source=source)
|
|
|
|
|
|
|
|
# We will fail with the above error code
|
|
|
|
assert obj.notify('title', 'body', 'info') is False
|
|
|
|
|
|
|
|
|
2018-03-05 03:06:41 +01:00
|
|
|
@mock.patch('apprise.plugins.NotifyEmby.login')
|
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_emby_plugin_logout(mock_post, mock_get, mock_login):
|
|
|
|
"""
|
|
|
|
API: NotifyEmby.sessions()
|
|
|
|
|
|
|
|
"""
|
2019-02-17 22:35:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2018-03-05 03:06:41 +01:00
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_get.return_value = requests.Request()
|
|
|
|
mock_post.return_value = requests.Request()
|
|
|
|
|
|
|
|
# This is done so we don't obstruct our access_token and user_id values
|
|
|
|
mock_login.return_value = True
|
|
|
|
|
|
|
|
obj = Apprise.instantiate('emby://l2g:l2gpass@localhost')
|
|
|
|
assert isinstance(obj, plugins.NotifyEmby)
|
|
|
|
obj.access_token = 'abc'
|
|
|
|
obj.user_id = '123'
|
|
|
|
|
|
|
|
# Test our exception handling
|
|
|
|
for _exception in REQUEST_EXCEPTIONS:
|
|
|
|
mock_post.side_effect = _exception
|
|
|
|
mock_get.side_effect = _exception
|
|
|
|
# We'll fail to log in each time
|
|
|
|
obj.logout()
|
|
|
|
obj.access_token = 'abc'
|
|
|
|
obj.user_id = '123'
|
|
|
|
|
|
|
|
# Disable Exceptions
|
|
|
|
mock_post.side_effect = None
|
|
|
|
mock_get.side_effect = None
|
|
|
|
|
|
|
|
# Our login flat out fails if we don't have proper parseable content
|
|
|
|
mock_post.return_value.content = u''
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
# KeyError handling
|
|
|
|
mock_post.return_value.status_code = 999
|
|
|
|
mock_get.return_value.status_code = 999
|
|
|
|
obj.logout()
|
|
|
|
obj.access_token = 'abc'
|
|
|
|
obj.user_id = '123'
|
|
|
|
|
|
|
|
# General Internal Server Error
|
|
|
|
mock_post.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
mock_get.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
obj.logout()
|
|
|
|
obj.access_token = 'abc'
|
|
|
|
obj.user_id = '123'
|
|
|
|
|
|
|
|
mock_post.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
# Disable the port completely
|
|
|
|
obj.port = None
|
2019-06-30 21:32:12 +02:00
|
|
|
|
|
|
|
# Perform logout
|
|
|
|
obj.logout()
|
|
|
|
|
|
|
|
# Calling logout on an object already logged out
|
2018-03-05 03:06:41 +01:00
|
|
|
obj.logout()
|
|
|
|
|
2019-06-30 21:32:12 +02:00
|
|
|
# Test Python v3.5 LookupError Bug: https://bugs.python.org/issue29288
|
|
|
|
mock_post.side_effect = LookupError()
|
|
|
|
mock_get.side_effect = LookupError()
|
|
|
|
obj.access_token = 'abc'
|
|
|
|
obj.user_id = '123'
|
|
|
|
|
|
|
|
# Tidy object
|
|
|
|
del obj
|
|
|
|
|
2018-03-05 03:06:41 +01:00
|
|
|
|
|
|
|
@mock.patch('apprise.plugins.NotifyEmby.sessions')
|
|
|
|
@mock.patch('apprise.plugins.NotifyEmby.login')
|
|
|
|
@mock.patch('apprise.plugins.NotifyEmby.logout')
|
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_emby_plugin_notify(mock_post, mock_get, mock_logout,
|
|
|
|
mock_login, mock_sessions):
|
|
|
|
"""
|
|
|
|
API: NotifyEmby.notify()
|
|
|
|
|
|
|
|
"""
|
2019-02-17 22:35:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2018-03-05 03:06:41 +01:00
|
|
|
|
2019-02-25 07:02:29 +01:00
|
|
|
req = requests.Request()
|
|
|
|
req.status_code = requests.codes.ok
|
|
|
|
req.content = ''
|
|
|
|
mock_get.return_value = req
|
|
|
|
mock_post.return_value = req
|
2018-03-05 03:06:41 +01:00
|
|
|
|
|
|
|
# This is done so we don't obstruct our access_token and user_id values
|
|
|
|
mock_login.return_value = True
|
|
|
|
mock_logout.return_value = True
|
|
|
|
mock_sessions.return_value = {'abcd': {}}
|
|
|
|
|
|
|
|
obj = Apprise.instantiate('emby://l2g:l2gpass@localhost?modal=False')
|
|
|
|
assert isinstance(obj, plugins.NotifyEmby)
|
|
|
|
assert obj.notify('title', 'body', 'info') is True
|
|
|
|
obj.access_token = 'abc'
|
|
|
|
obj.user_id = '123'
|
|
|
|
|
|
|
|
# Test Modal support
|
|
|
|
obj = Apprise.instantiate('emby://l2g:l2gpass@localhost?modal=True')
|
|
|
|
assert isinstance(obj, plugins.NotifyEmby)
|
|
|
|
assert obj.notify('title', 'body', 'info') is True
|
|
|
|
obj.access_token = 'abc'
|
|
|
|
obj.user_id = '123'
|
|
|
|
|
|
|
|
# Test our exception handling
|
|
|
|
for _exception in REQUEST_EXCEPTIONS:
|
|
|
|
mock_post.side_effect = _exception
|
|
|
|
mock_get.side_effect = _exception
|
|
|
|
# We'll fail to log in each time
|
|
|
|
assert obj.notify('title', 'body', 'info') is False
|
|
|
|
|
|
|
|
# Disable Exceptions
|
|
|
|
mock_post.side_effect = None
|
|
|
|
mock_get.side_effect = None
|
|
|
|
|
|
|
|
# Our login flat out fails if we don't have proper parseable content
|
|
|
|
mock_post.return_value.content = u''
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
# KeyError handling
|
|
|
|
mock_post.return_value.status_code = 999
|
|
|
|
mock_get.return_value.status_code = 999
|
|
|
|
assert obj.notify('title', 'body', 'info') is False
|
|
|
|
|
|
|
|
# General Internal Server Error
|
|
|
|
mock_post.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
mock_get.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
assert obj.notify('title', 'body', 'info') is False
|
|
|
|
|
|
|
|
mock_post.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.content = mock_post.return_value.content
|
|
|
|
|
|
|
|
# Disable the port completely
|
|
|
|
obj.port = None
|
|
|
|
assert obj.notify('title', 'body', 'info') is True
|
|
|
|
|
|
|
|
# An Empty return set (no query is made, but notification will still
|
|
|
|
# succeed
|
|
|
|
mock_sessions.return_value = {}
|
|
|
|
assert obj.notify('title', 'body', 'info') is True
|
|
|
|
|
2019-06-30 21:32:12 +02:00
|
|
|
# Tidy our object
|
|
|
|
del obj
|
|
|
|
|
2018-03-05 03:06:41 +01:00
|
|
|
|
2018-03-09 02:20:51 +01:00
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_ifttt_plugin(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifyIFTTT() Extra Checks
|
|
|
|
|
|
|
|
"""
|
2019-02-13 23:48:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2018-03-09 02:20:51 +01:00
|
|
|
|
|
|
|
# Initialize some generic (but valid) tokens
|
2019-03-27 04:06:20 +01:00
|
|
|
webhook_id = 'webhook_id'
|
2019-02-13 23:48:09 +01:00
|
|
|
events = ['event1', 'event2']
|
2018-03-09 02:20:51 +01:00
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_get.return_value = requests.Request()
|
|
|
|
mock_post.return_value = requests.Request()
|
|
|
|
mock_post.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.content = '{}'
|
|
|
|
mock_post.return_value.content = '{}'
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No webhook_id specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyIFTTT(webhook_id=None, events=None)
|
2019-03-27 04:06:20 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# Initializes the plugin with an invalid webhook id
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyIFTTT(webhook_id=None, events=events)
|
2019-03-27 04:06:20 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# Whitespace also acts as an invalid webhook id
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyIFTTT(webhook_id=" ", events=events)
|
2018-03-09 02:20:51 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No events specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyIFTTT(webhook_id=webhook_id, events=None)
|
2018-03-09 02:20:51 +01:00
|
|
|
|
2019-02-13 23:48:09 +01:00
|
|
|
obj = plugins.NotifyIFTTT(webhook_id=webhook_id, events=events)
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyIFTTT) is True
|
2018-03-09 02:20:51 +01:00
|
|
|
|
2019-02-18 04:21:59 +01:00
|
|
|
assert obj.notify(
|
|
|
|
body='body', title='title', notify_type=NotifyType.INFO) is True
|
2018-03-09 02:20:51 +01:00
|
|
|
|
2019-02-17 19:45:48 +01:00
|
|
|
# Test the addition of tokens
|
|
|
|
obj = plugins.NotifyIFTTT(
|
|
|
|
webhook_id=webhook_id, events=events,
|
2019-02-17 22:35:09 +01:00
|
|
|
add_tokens={'Test': 'ValueA', 'Test2': 'ValueB'})
|
2019-02-17 19:45:48 +01:00
|
|
|
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyIFTTT) is True
|
2019-02-17 19:45:48 +01:00
|
|
|
|
2019-02-18 04:21:59 +01:00
|
|
|
assert obj.notify(
|
|
|
|
body='body', title='title', notify_type=NotifyType.INFO) is True
|
2019-02-17 19:45:48 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# Invalid del_tokens entry
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyIFTTT(
|
2019-02-17 19:45:48 +01:00
|
|
|
webhook_id=webhook_id, events=events,
|
|
|
|
del_tokens=plugins.NotifyIFTTT.ifttt_default_title_key)
|
|
|
|
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyIFTTT) is True
|
2019-02-17 19:45:48 +01:00
|
|
|
|
2019-02-18 04:21:59 +01:00
|
|
|
assert obj.notify(
|
|
|
|
body='body', title='title', notify_type=NotifyType.INFO) is True
|
2019-02-17 19:45:48 +01:00
|
|
|
|
|
|
|
# Test removal of tokens by a list
|
|
|
|
obj = plugins.NotifyIFTTT(
|
|
|
|
webhook_id=webhook_id, events=events,
|
|
|
|
add_tokens={
|
|
|
|
'MyKey': 'MyValue'
|
|
|
|
},
|
|
|
|
del_tokens=(
|
|
|
|
plugins.NotifyIFTTT.ifttt_default_title_key,
|
|
|
|
plugins.NotifyIFTTT.ifttt_default_body_key,
|
2019-02-17 22:35:09 +01:00
|
|
|
plugins.NotifyIFTTT.ifttt_default_type_key))
|
2019-02-17 19:45:48 +01:00
|
|
|
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyIFTTT) is True
|
2019-02-17 19:45:48 +01:00
|
|
|
|
2019-02-18 04:21:59 +01:00
|
|
|
assert obj.notify(
|
|
|
|
body='body', title='title', notify_type=NotifyType.INFO) is True
|
2019-02-17 19:45:48 +01:00
|
|
|
|
2019-05-30 02:07:05 +02:00
|
|
|
# Test removal of tokens as dict
|
|
|
|
obj = plugins.NotifyIFTTT(
|
|
|
|
webhook_id=webhook_id, events=events,
|
|
|
|
add_tokens={
|
|
|
|
'MyKey': 'MyValue'
|
|
|
|
},
|
|
|
|
del_tokens={
|
|
|
|
plugins.NotifyIFTTT.ifttt_default_title_key: None,
|
|
|
|
plugins.NotifyIFTTT.ifttt_default_body_key: None,
|
|
|
|
plugins.NotifyIFTTT.ifttt_default_type_key: None})
|
|
|
|
|
|
|
|
assert isinstance(obj, plugins.NotifyIFTTT) is True
|
|
|
|
|
2019-02-17 22:35:09 +01:00
|
|
|
|
2017-12-14 03:35:59 +01:00
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_join_plugin(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifyJoin() Extra Checks
|
|
|
|
|
|
|
|
"""
|
2019-02-13 23:48:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2019-02-13 23:48:09 +01:00
|
|
|
|
2017-12-14 03:35:59 +01:00
|
|
|
# Generate some generic message types
|
|
|
|
device = 'A' * 32
|
|
|
|
group = 'group.chrome'
|
|
|
|
apikey = 'a' * 32
|
|
|
|
|
|
|
|
# Initializes the plugin with devices set to a string
|
2019-03-27 04:06:20 +01:00
|
|
|
plugins.NotifyJoin(apikey=apikey, targets=group)
|
2017-12-14 03:35:59 +01:00
|
|
|
|
|
|
|
# Initializes the plugin with devices set to None
|
2019-03-27 04:06:20 +01:00
|
|
|
plugins.NotifyJoin(apikey=apikey, targets=None)
|
2017-12-14 03:35:59 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# Initializes the plugin with an invalid apikey
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyJoin(apikey=None)
|
|
|
|
|
|
|
|
# Whitespace also acts as an invalid apikey
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyJoin(apikey=" ")
|
|
|
|
|
2017-12-14 03:35:59 +01:00
|
|
|
# Initializes the plugin with devices set to a set
|
2019-03-27 04:06:20 +01:00
|
|
|
p = plugins.NotifyJoin(apikey=apikey, targets=[group, device])
|
2017-12-14 03:35:59 +01:00
|
|
|
|
|
|
|
# Prepare our mock responses
|
2019-02-25 07:02:29 +01:00
|
|
|
req = requests.Request()
|
|
|
|
req.status_code = requests.codes.created
|
|
|
|
req.content = ''
|
|
|
|
mock_get.return_value = req
|
|
|
|
mock_post.return_value = req
|
2017-12-14 03:35:59 +01:00
|
|
|
|
|
|
|
# Test notifications without a body or a title; nothing to send
|
|
|
|
# so we return False
|
|
|
|
p.notify(body=None, title=None, notify_type=NotifyType.INFO) is False
|
|
|
|
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
def test_notify_kumulos_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifyKumulos() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# Invalid API Key
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyKumulos(None, None)
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyKumulos(" ", None)
|
|
|
|
|
|
|
|
# Invalid Server Key
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyKumulos("abcd", None)
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyKumulos("abcd", " ")
|
|
|
|
|
|
|
|
|
|
|
|
def test_notify_mattermost_plugin():
|
|
|
|
"""
|
2021-02-06 20:55:49 +01:00
|
|
|
API: NotifyMattermost() Extra Checks
|
2019-10-09 18:39:31 +02:00
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# Invalid Authorization Token
|
|
|
|
with pytest.raises(TypeError):
|
2021-02-06 20:55:49 +01:00
|
|
|
plugins.NotifyMattermost(None)
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
2021-02-06 20:55:49 +01:00
|
|
|
plugins.NotifyMattermost(" ")
|
2019-10-09 18:39:31 +02:00
|
|
|
|
|
|
|
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_messagebird_plugin(mock_post):
|
|
|
|
"""
|
|
|
|
API: NotifyMessageBird() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# Prepare our response
|
|
|
|
response = requests.Request()
|
|
|
|
response.status_code = requests.codes.ok
|
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_post.return_value = response
|
|
|
|
|
|
|
|
# Initialize some generic (but valid) tokens
|
|
|
|
# authkey = '{}'.format('a' * 24)
|
|
|
|
source = '+1 (555) 123-3456'
|
|
|
|
|
|
|
|
# No apikey specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyMessageBird(apikey=None, source=source)
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyMessageBird(apikey=" ", source=source)
|
|
|
|
|
|
|
|
|
2019-03-27 04:06:20 +01:00
|
|
|
def test_notify_pover_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifyPushover() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2019-03-27 04:06:20 +01:00
|
|
|
|
|
|
|
# No token
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
2019-03-27 04:06:20 +01:00
|
|
|
plugins.NotifyPushover(token=None)
|
|
|
|
|
|
|
|
|
|
|
|
def test_notify_ryver_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifyRyver() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2019-03-27 04:06:20 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No token
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyRyver(organization="abc", token=None)
|
|
|
|
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyRyver(organization="abc", token=" ")
|
2019-03-27 04:06:20 +01:00
|
|
|
|
|
|
|
# No organization
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyRyver(organization=None, token="abc")
|
2019-03-27 04:06:20 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyRyver(organization=" ", token="abc")
|
|
|
|
|
|
|
|
|
|
|
|
def test_notify_simplepush_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifySimplePush() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# No token
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifySimplePush(apikey=None)
|
|
|
|
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifySimplePush(apikey=" ")
|
|
|
|
|
|
|
|
# Bad event
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifySimplePush(apikey="abc", event=object)
|
|
|
|
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifySimplePush(apikey="abc", event=" ")
|
2019-03-27 04:06:20 +01:00
|
|
|
|
|
|
|
|
2019-06-23 20:03:45 +02:00
|
|
|
def test_notify_zulip_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifyZulip() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# must be 32 characters long
|
|
|
|
token = 'a' * 32
|
|
|
|
|
|
|
|
# Invalid organization
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
2019-06-23 20:03:45 +02:00
|
|
|
plugins.NotifyZulip(
|
|
|
|
botname='test', organization='#', token=token)
|
|
|
|
|
|
|
|
|
2019-08-18 06:39:21 +02:00
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_sendgrid_plugin(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifySendGrid() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# no apikey
|
|
|
|
with pytest.raises(TypeError):
|
2019-08-18 06:39:21 +02:00
|
|
|
plugins.NotifySendGrid(
|
|
|
|
apikey=None, from_email='user@example.com')
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# invalid from email
|
|
|
|
with pytest.raises(TypeError):
|
2019-08-18 06:39:21 +02:00
|
|
|
plugins.NotifySendGrid(
|
|
|
|
apikey='abcd', from_email='!invalid')
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# no email
|
|
|
|
with pytest.raises(TypeError):
|
2019-08-18 06:39:21 +02:00
|
|
|
plugins.NotifySendGrid(apikey='abcd', from_email=None)
|
|
|
|
|
|
|
|
# Invalid To email address
|
|
|
|
plugins.NotifySendGrid(
|
|
|
|
apikey='abcd', from_email='user@example.com', targets="!invalid")
|
|
|
|
|
|
|
|
# Test invalid bcc/cc entries mixed with good ones
|
|
|
|
assert isinstance(plugins.NotifySendGrid(
|
|
|
|
apikey='abcd',
|
|
|
|
from_email='l2g@example.com',
|
|
|
|
bcc=('abc@def.com', '!invalid'),
|
|
|
|
cc=('abc@test.org', '!invalid')), plugins.NotifySendGrid)
|
|
|
|
|
|
|
|
|
2017-12-23 04:47:46 +01:00
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_pushbullet_plugin(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifyPushBullet() Extra Checks
|
|
|
|
|
|
|
|
"""
|
2019-02-17 22:35:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2017-12-23 04:47:46 +01:00
|
|
|
|
|
|
|
# Initialize some generic (but valid) tokens
|
|
|
|
accesstoken = 'a' * 32
|
|
|
|
|
|
|
|
# Support strings
|
|
|
|
recipients = '#chan1,#chan2,device,user@example.com,,,'
|
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_get.return_value = requests.Request()
|
|
|
|
mock_post.return_value = requests.Request()
|
|
|
|
mock_post.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.status_code = requests.codes.ok
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# Invalid Access Token
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushBullet(accesstoken=None)
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushBullet(accesstoken=" ")
|
|
|
|
|
2017-12-23 04:47:46 +01:00
|
|
|
obj = plugins.NotifyPushBullet(
|
2019-03-27 04:06:20 +01:00
|
|
|
accesstoken=accesstoken, targets=recipients)
|
|
|
|
assert isinstance(obj, plugins.NotifyPushBullet) is True
|
|
|
|
assert len(obj.targets) == 4
|
2017-12-23 04:47:46 +01:00
|
|
|
|
|
|
|
obj = plugins.NotifyPushBullet(accesstoken=accesstoken)
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyPushBullet) is True
|
2017-12-23 04:47:46 +01:00
|
|
|
# Default is to send to all devices, so there will be a
|
|
|
|
# recipient here
|
2019-03-27 04:06:20 +01:00
|
|
|
assert len(obj.targets) == 1
|
2017-12-23 04:47:46 +01:00
|
|
|
|
2019-03-27 04:06:20 +01:00
|
|
|
obj = plugins.NotifyPushBullet(accesstoken=accesstoken, targets=set())
|
|
|
|
assert isinstance(obj, plugins.NotifyPushBullet) is True
|
2017-12-23 04:47:46 +01:00
|
|
|
# Default is to send to all devices, so there will be a
|
|
|
|
# recipient here
|
2019-03-27 04:06:20 +01:00
|
|
|
assert len(obj.targets) == 1
|
2017-12-23 04:47:46 +01:00
|
|
|
|
|
|
|
|
2019-01-31 06:15:50 +01:00
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_pushed_plugin(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifyPushed() Extra Checks
|
|
|
|
|
|
|
|
"""
|
2019-02-13 23:48:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2019-02-13 23:48:09 +01:00
|
|
|
|
2019-01-31 06:15:50 +01:00
|
|
|
# Chat ID
|
|
|
|
recipients = '@ABCDEFG, @DEFGHIJ, #channel, #channel2'
|
|
|
|
|
|
|
|
# Some required input
|
|
|
|
app_key = 'ABCDEFG'
|
|
|
|
app_secret = 'ABCDEFG'
|
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_get.return_value = requests.Request()
|
|
|
|
mock_post.return_value = requests.Request()
|
|
|
|
mock_post.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.status_code = requests.codes.ok
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No application Key specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushed(
|
|
|
|
app_key=None,
|
|
|
|
app_secret=app_secret,
|
|
|
|
recipients=None,
|
|
|
|
)
|
|
|
|
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushed(
|
|
|
|
app_key=" ",
|
|
|
|
app_secret=app_secret,
|
|
|
|
recipients=None,
|
|
|
|
)
|
|
|
|
# No application Secret specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushed(
|
2019-01-31 06:15:50 +01:00
|
|
|
app_key=app_key,
|
|
|
|
app_secret=None,
|
|
|
|
recipients=None,
|
|
|
|
)
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushed(
|
2019-01-31 06:15:50 +01:00
|
|
|
app_key=app_key,
|
2019-10-09 18:39:31 +02:00
|
|
|
app_secret=" ",
|
2019-01-31 06:15:50 +01:00
|
|
|
)
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# recipients list set to (None) is perfectly fine; in this case it will
|
|
|
|
# notify the App
|
|
|
|
obj = plugins.NotifyPushed(
|
|
|
|
app_key=app_key,
|
|
|
|
app_secret=app_secret,
|
|
|
|
recipients=None,
|
|
|
|
)
|
|
|
|
assert isinstance(obj, plugins.NotifyPushed) is True
|
|
|
|
assert len(obj.channels) == 0
|
|
|
|
assert len(obj.users) == 0
|
2019-01-31 06:15:50 +01:00
|
|
|
|
|
|
|
obj = plugins.NotifyPushed(
|
|
|
|
app_key=app_key,
|
|
|
|
app_secret=app_secret,
|
2019-03-27 04:06:20 +01:00
|
|
|
targets=recipients,
|
2019-01-31 06:15:50 +01:00
|
|
|
)
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyPushed) is True
|
|
|
|
assert len(obj.channels) == 2
|
|
|
|
assert len(obj.users) == 2
|
2019-01-31 06:15:50 +01:00
|
|
|
|
|
|
|
# Prepare Mock to fail
|
|
|
|
mock_post.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
mock_get.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
def test_notify_pushjet_plugin():
|
|
|
|
"""
|
|
|
|
API: NotifyPushjet() Extra Checks
|
|
|
|
|
|
|
|
"""
|
|
|
|
# Disable Throttling to speed testing
|
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
|
|
|
|
|
|
|
# No application Key specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushjet(secret_key=None)
|
|
|
|
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushjet(secret_key=" ")
|
|
|
|
|
|
|
|
|
2017-12-23 04:47:46 +01:00
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_pushover_plugin(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifyPushover() Extra Checks
|
|
|
|
|
|
|
|
"""
|
2019-02-13 23:48:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2017-12-23 04:47:46 +01:00
|
|
|
|
|
|
|
# Initialize some generic (but valid) tokens
|
|
|
|
token = 'a' * 30
|
2019-10-09 18:39:31 +02:00
|
|
|
user_key = 'u' * 30
|
2017-12-23 04:47:46 +01:00
|
|
|
|
|
|
|
invalid_device = 'd' * 35
|
|
|
|
|
|
|
|
# Support strings
|
|
|
|
devices = 'device1,device2,,,,%s' % invalid_device
|
|
|
|
|
|
|
|
# Prepare Mock
|
|
|
|
mock_get.return_value = requests.Request()
|
|
|
|
mock_post.return_value = requests.Request()
|
|
|
|
mock_post.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.status_code = requests.codes.ok
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No webhook id specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushover(user_key=user_key, webhook_id=None)
|
2017-12-23 04:47:46 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
obj = plugins.NotifyPushover(
|
|
|
|
user_key=user_key, token=token, targets=devices)
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyPushover) is True
|
|
|
|
assert len(obj.targets) == 3
|
2017-12-23 04:47:46 +01:00
|
|
|
|
|
|
|
# This call fails because there is 1 invalid device
|
2019-02-18 04:21:59 +01:00
|
|
|
assert obj.notify(
|
2019-10-09 18:39:31 +02:00
|
|
|
body='body', title='title',
|
|
|
|
notify_type=NotifyType.INFO) is False
|
2017-12-23 04:47:46 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
obj = plugins.NotifyPushover(user_key=user_key, token=token)
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyPushover) is True
|
2017-12-23 04:47:46 +01:00
|
|
|
# Default is to send to all devices, so there will be a
|
|
|
|
# device defined here
|
2019-03-27 04:06:20 +01:00
|
|
|
assert len(obj.targets) == 1
|
2017-12-23 04:47:46 +01:00
|
|
|
|
|
|
|
# This call succeeds because all of the devices are valid
|
2019-02-18 04:21:59 +01:00
|
|
|
assert obj.notify(
|
|
|
|
body='body', title='title', notify_type=NotifyType.INFO) is True
|
2017-12-23 04:47:46 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
obj = plugins.NotifyPushover(user_key=user_key, token=token, targets=set())
|
2019-03-27 04:06:20 +01:00
|
|
|
assert isinstance(obj, plugins.NotifyPushover) is True
|
2017-12-23 04:47:46 +01:00
|
|
|
# Default is to send to all devices, so there will be a
|
|
|
|
# device defined here
|
2019-03-27 04:06:20 +01:00
|
|
|
assert len(obj.targets) == 1
|
2017-12-23 04:47:46 +01:00
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# No User Key specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushover(user_key=None, token="abcd")
|
|
|
|
|
|
|
|
# No Access Token specified
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushover(user_key="abcd", token=None)
|
|
|
|
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
plugins.NotifyPushover(user_key="abcd", token=" ")
|
|
|
|
|
2017-12-23 04:47:46 +01:00
|
|
|
|
2017-12-25 21:07:41 +01:00
|
|
|
@mock.patch('requests.get')
|
|
|
|
@mock.patch('requests.post')
|
|
|
|
def test_notify_rocketchat_plugin(mock_post, mock_get):
|
|
|
|
"""
|
|
|
|
API: NotifyRocketChat() Extra Checks
|
|
|
|
|
|
|
|
"""
|
2019-02-13 23:48:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2019-02-13 23:48:09 +01:00
|
|
|
|
2017-12-25 21:07:41 +01:00
|
|
|
# Chat ID
|
2019-05-22 03:50:50 +02:00
|
|
|
recipients = 'AbcD1245, @l2g, @lead2gold, #channel, #channel2'
|
2017-12-25 21:07:41 +01:00
|
|
|
|
2019-02-13 23:48:09 +01:00
|
|
|
# Authentication
|
|
|
|
user = 'myuser'
|
|
|
|
password = 'mypass'
|
|
|
|
|
2017-12-25 21:07:41 +01:00
|
|
|
# Prepare Mock
|
|
|
|
mock_get.return_value = requests.Request()
|
|
|
|
mock_post.return_value = requests.Request()
|
|
|
|
mock_post.return_value.status_code = requests.codes.ok
|
|
|
|
mock_get.return_value.status_code = requests.codes.ok
|
2019-02-25 07:02:29 +01:00
|
|
|
mock_post.return_value.content = ''
|
|
|
|
mock_get.return_value.content = ''
|
2017-12-25 21:07:41 +01:00
|
|
|
|
2019-02-13 23:48:09 +01:00
|
|
|
obj = plugins.NotifyRocketChat(
|
2019-03-27 04:06:20 +01:00
|
|
|
user=user, password=password, targets=recipients)
|
|
|
|
assert isinstance(obj, plugins.NotifyRocketChat) is True
|
|
|
|
assert len(obj.channels) == 2
|
2019-05-22 03:50:50 +02:00
|
|
|
assert len(obj.users) == 2
|
|
|
|
assert len(obj.rooms) == 1
|
|
|
|
|
|
|
|
# No Webhook specified
|
2019-10-09 18:39:31 +02:00
|
|
|
with pytest.raises(TypeError):
|
2019-05-22 03:50:50 +02:00
|
|
|
obj = plugins.NotifyRocketChat(webhook=None, mode='webhook')
|
2017-12-25 21:07:41 +01:00
|
|
|
|
|
|
|
#
|
|
|
|
# Logout
|
|
|
|
#
|
|
|
|
assert obj.logout() is True
|
|
|
|
|
2019-11-24 22:26:11 +01:00
|
|
|
# Invalid JSON during Login
|
|
|
|
mock_post.return_value.content = '{'
|
|
|
|
mock_get.return_value.content = '}'
|
|
|
|
assert obj.login() is False
|
|
|
|
|
2017-12-25 21:07:41 +01:00
|
|
|
# Prepare Mock to fail
|
2019-11-24 22:26:11 +01:00
|
|
|
mock_post.return_value.content = ''
|
|
|
|
mock_get.return_value.content = ''
|
2017-12-25 21:07:41 +01:00
|
|
|
mock_post.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
mock_get.return_value.status_code = requests.codes.internal_server_error
|
|
|
|
|
|
|
|
#
|
|
|
|
# Send Notification
|
|
|
|
#
|
|
|
|
assert obj.notify(
|
2019-02-18 04:21:59 +01:00
|
|
|
body='body', title='title', notify_type=NotifyType.INFO) is False
|
|
|
|
assert obj._send(payload='test', notify_type=NotifyType.INFO) is False
|
2017-12-25 21:07:41 +01:00
|
|
|
|
|
|
|
#
|
|
|
|
# Logout
|
|
|
|
#
|
|
|
|
assert obj.logout() is False
|
|
|
|
|
|
|
|
# KeyError handling
|
|
|
|
mock_post.return_value.status_code = 999
|
|
|
|
mock_get.return_value.status_code = 999
|
|
|
|
|
|
|
|
#
|
|
|
|
# Send Notification
|
|
|
|
#
|
|
|
|
assert obj.notify(
|
2019-02-18 04:21:59 +01:00
|
|
|
body='body', title='title', notify_type=NotifyType.INFO) is False
|
|
|
|
assert obj._send(payload='test', notify_type=NotifyType.INFO) is False
|
2017-12-25 21:07:41 +01:00
|
|
|
|
|
|
|
#
|
|
|
|
# Logout
|
|
|
|
#
|
|
|
|
assert obj.logout() is False
|
|
|
|
|
|
|
|
# Generate exceptions
|
|
|
|
mock_get.side_effect = requests.ConnectionError(
|
|
|
|
0, 'requests.ConnectionError() not handled')
|
|
|
|
mock_post.side_effect = mock_get.side_effect
|
|
|
|
|
|
|
|
#
|
|
|
|
# Send Notification
|
|
|
|
#
|
2019-02-18 04:21:59 +01:00
|
|
|
assert obj._send(payload='test', notify_type=NotifyType.INFO) is False
|
2017-12-25 21:07:41 +01:00
|
|
|
|
|
|
|
# Attempt the check again but fake a successful login
|
|
|
|
obj.login = mock.Mock()
|
|
|
|
obj.login.return_value = True
|
|
|
|
assert obj.notify(
|
2019-02-18 04:21:59 +01:00
|
|
|
body='body', title='title', notify_type=NotifyType.INFO) is False
|
2017-12-25 21:07:41 +01:00
|
|
|
#
|
|
|
|
# Logout
|
|
|
|
#
|
|
|
|
assert obj.logout() is False
|
|
|
|
|
|
|
|
|
2019-02-16 06:26:33 +01:00
|
|
|
def test_notify_overflow_truncate():
|
|
|
|
"""
|
|
|
|
API: Overflow Truncate Functionality Testing
|
|
|
|
|
|
|
|
"""
|
|
|
|
#
|
|
|
|
# A little preparation
|
|
|
|
#
|
|
|
|
|
2019-02-17 22:35:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2019-02-17 22:35:09 +01:00
|
|
|
|
2019-02-16 06:26:33 +01:00
|
|
|
# Number of characters per line
|
|
|
|
row = 24
|
|
|
|
|
|
|
|
# Some variables we use to control the data we work with
|
|
|
|
body_len = 1024
|
|
|
|
title_len = 1024
|
|
|
|
|
|
|
|
# Create a large body and title with random data
|
|
|
|
body = ''.join(choice(str_alpha + str_num + ' ') for _ in range(body_len))
|
|
|
|
body = '\r\n'.join([body[i: i + row] for i in range(0, len(body), row)])
|
|
|
|
|
|
|
|
# the new lines add a large amount to our body; lets force the content
|
|
|
|
# back to being 1024 characters.
|
|
|
|
body = body[0:1024]
|
|
|
|
|
|
|
|
# Create our title using random data
|
|
|
|
title = ''.join(choice(str_alpha + str_num) for _ in range(title_len))
|
|
|
|
|
|
|
|
#
|
|
|
|
# First Test: Truncated Title
|
|
|
|
#
|
|
|
|
class TestNotification(NotifyBase):
|
|
|
|
|
|
|
|
# Test title max length
|
|
|
|
title_maxlen = 10
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(TestNotification, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
def notify(self, *args, **kwargs):
|
|
|
|
# Pretend everything is okay
|
|
|
|
return True
|
|
|
|
|
2019-10-09 18:39:31 +02:00
|
|
|
# We should throw an exception because our specified overflow is wrong.
|
|
|
|
with pytest.raises(TypeError):
|
2019-02-16 06:26:33 +01:00
|
|
|
# Load our object
|
|
|
|
obj = TestNotification(overflow='invalid')
|
|
|
|
|
|
|
|
# Load our object
|
|
|
|
obj = TestNotification(overflow=OverflowMode.TRUNCATE)
|
|
|
|
assert obj is not None
|
|
|
|
|
|
|
|
# Verify that we break the title to a max length of our title_max
|
|
|
|
# and that the body remains untouched
|
2019-02-18 04:21:59 +01:00
|
|
|
chunks = obj._apply_overflow(body=body, title=title, overflow=None)
|
|
|
|
chunks = obj._apply_overflow(
|
|
|
|
body=body, title=title, overflow=OverflowMode.SPLIT)
|
2019-02-16 06:26:33 +01:00
|
|
|
assert len(chunks) == 1
|
2019-02-25 07:02:29 +01:00
|
|
|
assert body.rstrip() == chunks[0].get('body')
|
2019-02-16 06:26:33 +01:00
|
|
|
assert title[0:TestNotification.title_maxlen] == chunks[0].get('title')
|
|
|
|
|
|
|
|
#
|
|
|
|
# Next Test: Line Count Control
|
|
|
|
#
|
|
|
|
|
|
|
|
class TestNotification(NotifyBase):
|
|
|
|
|
|
|
|
# Test title max length
|
|
|
|
title_maxlen = 5
|
|
|
|
|
|
|
|
# Maximum number of lines
|
|
|
|
body_max_line_count = 5
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(TestNotification, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
def notify(self, *args, **kwargs):
|
|
|
|
# Pretend everything is okay
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Load our object
|
|
|
|
obj = TestNotification(overflow=OverflowMode.TRUNCATE)
|
|
|
|
assert obj is not None
|
|
|
|
|
|
|
|
# Verify that we break the title to a max length of our title_max
|
|
|
|
# and that the body remains untouched
|
|
|
|
chunks = obj._apply_overflow(body=body, title=title)
|
|
|
|
assert len(chunks) == 1
|
|
|
|
assert len(chunks[0].get('body').split('\n')) == \
|
|
|
|
TestNotification.body_max_line_count
|
|
|
|
assert title[0:TestNotification.title_maxlen] == chunks[0].get('title')
|
|
|
|
|
|
|
|
#
|
|
|
|
# Next Test: Truncated body
|
|
|
|
#
|
|
|
|
|
|
|
|
class TestNotification(NotifyBase):
|
|
|
|
|
|
|
|
# Test title max length
|
|
|
|
title_maxlen = title_len
|
|
|
|
|
|
|
|
# Enforce a body length of just 10
|
|
|
|
body_maxlen = 10
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(TestNotification, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
def notify(self, *args, **kwargs):
|
|
|
|
# Pretend everything is okay
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Load our object
|
|
|
|
obj = TestNotification(overflow=OverflowMode.TRUNCATE)
|
|
|
|
assert obj is not None
|
|
|
|
|
|
|
|
# Verify that we break the title to a max length of our title_max
|
|
|
|
# and that the body remains untouched
|
|
|
|
chunks = obj._apply_overflow(body=body, title=title)
|
|
|
|
assert len(chunks) == 1
|
|
|
|
assert body[0:TestNotification.body_maxlen] == chunks[0].get('body')
|
|
|
|
assert title == chunks[0].get('title')
|
|
|
|
|
|
|
|
#
|
|
|
|
# Next Test: Append title to body + Truncated body
|
|
|
|
#
|
|
|
|
|
|
|
|
class TestNotification(NotifyBase):
|
|
|
|
|
|
|
|
# Enforce no title
|
|
|
|
title_maxlen = 0
|
|
|
|
|
|
|
|
# Enforce a body length of just 100
|
|
|
|
body_maxlen = 100
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(TestNotification, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
def notify(self, *args, **kwargs):
|
|
|
|
# Pretend everything is okay
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Load our object
|
|
|
|
obj = TestNotification(overflow=OverflowMode.TRUNCATE)
|
|
|
|
assert obj is not None
|
|
|
|
|
|
|
|
# Verify that we break the title to a max length of our title_max
|
|
|
|
# and that the body remains untouched
|
2019-03-10 17:10:01 +01:00
|
|
|
|
|
|
|
obj.notify_format = NotifyFormat.HTML
|
|
|
|
chunks = obj._apply_overflow(body=body, title=title)
|
|
|
|
assert len(chunks) == 1
|
|
|
|
|
|
|
|
obj.notify_format = NotifyFormat.MARKDOWN
|
|
|
|
chunks = obj._apply_overflow(body=body, title=title)
|
|
|
|
assert len(chunks) == 1
|
|
|
|
|
|
|
|
obj.notify_format = NotifyFormat.TEXT
|
2019-02-16 06:26:33 +01:00
|
|
|
chunks = obj._apply_overflow(body=body, title=title)
|
|
|
|
assert len(chunks) == 1
|
|
|
|
|
|
|
|
# The below line should be read carefully... We're actually testing to see
|
|
|
|
# that our title is matched against our body. Behind the scenes, the title
|
|
|
|
# was appended to the body. The body was then truncated to the maxlen.
|
|
|
|
# The thing is, since the title is so large, all of the body was lost
|
|
|
|
# and a good chunk of the title was too. The message sent will just be a
|
|
|
|
# small portion of the title
|
|
|
|
assert len(chunks[0].get('body')) == TestNotification.body_maxlen
|
|
|
|
assert title[0:TestNotification.body_maxlen] == chunks[0].get('body')
|
|
|
|
|
|
|
|
|
|
|
|
def test_notify_overflow_split():
|
|
|
|
"""
|
|
|
|
API: Overflow Split Functionality Testing
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
#
|
|
|
|
# A little preparation
|
|
|
|
#
|
|
|
|
|
2019-02-17 22:35:09 +01:00
|
|
|
# Disable Throttling to speed testing
|
2019-05-30 02:07:05 +02:00
|
|
|
plugins.NotifyBase.request_rate_per_sec = 0
|
2019-02-17 22:35:09 +01:00
|
|
|
|
2019-02-16 06:26:33 +01:00
|
|
|
# Number of characters per line
|
|
|
|
row = 24
|
|
|
|
|
|
|
|
# Some variables we use to control the data we work with
|
|
|
|
body_len = 1024
|
|
|
|
title_len = 1024
|
|
|
|
|
|
|
|
# Create a large body and title with random data
|
2019-02-19 03:24:30 +01:00
|
|
|
body = ''.join(choice(str_alpha + str_num) for _ in range(body_len))
|
2019-02-16 06:26:33 +01:00
|
|
|
body = '\r\n'.join([body[i: i + row] for i in range(0, len(body), row)])
|
|
|
|
|
|
|
|
# the new lines add a large amount to our body; lets force the content
|
|
|
|
# back to being 1024 characters.
|
|
|
|
body = body[0:1024]
|
|
|
|
|
|
|
|
# Create our title using random data
|
|
|
|
title = ''.join(choice(str_alpha + str_num) for _ in range(title_len))
|
|
|
|
|
|
|
|
#
|
|
|
|
# First Test: Truncated Title
|
|
|
|
#
|
|
|
|
class TestNotification(NotifyBase):
|
|
|
|
|
|
|
|
# Test title max length
|
|
|
|
title_maxlen = 10
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(TestNotification, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
def notify(self, *args, **kwargs):
|
|
|
|
# Pretend everything is okay
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Load our object
|
|
|
|
obj = TestNotification(overflow=OverflowMode.SPLIT)
|
|
|
|
assert obj is not None
|
|
|
|
|
|
|
|
# Verify that we break the title to a max length of our title_max
|
|
|
|
# and that the body remains untouched
|
|
|
|
chunks = obj._apply_overflow(body=body, title=title)
|
|
|
|
assert len(chunks) == 1
|
|
|
|
assert body == chunks[0].get('body')
|
|
|
|
assert title[0:TestNotification.title_maxlen] == chunks[0].get('title')
|
|
|
|
|
|
|
|
#
|
|
|
|
# Next Test: Line Count Control
|
|
|
|
#
|
|
|
|
|
|
|
|
class TestNotification(NotifyBase):
|
|
|
|
|
|
|
|
# Test title max length
|
|
|
|
title_maxlen = 5
|
|
|
|
|
|
|
|
# Maximum number of lines
|
|
|
|
body_max_line_count = 5
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(TestNotification, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
def notify(self, *args, **kwargs):
|
|
|
|
# Pretend everything is okay
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Load our object
|
|
|
|
obj = TestNotification(overflow=OverflowMode.SPLIT)
|
|
|
|
assert obj is not None
|
|
|
|
|
|
|
|
# Verify that we break the title to a max length of our title_max
|
|
|
|
# and that the body remains untouched
|
|
|
|
chunks = obj._apply_overflow(body=body, title=title)
|
|
|
|
assert len(chunks) == 1
|
|
|
|
assert len(chunks[0].get('body').split('\n')) == \
|
|
|
|
TestNotification.body_max_line_count
|
|
|
|
assert title[0:TestNotification.title_maxlen] == chunks[0].get('title')
|
|
|
|
|
|
|
|
#
|
|
|
|
# Next Test: Split body
|
|
|
|
#
|
|
|
|
|
|
|
|
class TestNotification(NotifyBase):
|
|
|
|
|
|
|
|
# Test title max length
|
|
|
|
title_maxlen = title_len
|
|
|
|
|
|
|
|
# Enforce a body length
|
2019-02-17 19:45:48 +01:00
|
|
|
# Wrap in int() so Python v3 doesn't convert the response into a float
|
|
|
|
body_maxlen = int(body_len / 4)
|
2019-02-16 06:26:33 +01:00
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(TestNotification, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
def notify(self, *args, **kwargs):
|
|
|
|
# Pretend everything is okay
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Load our object
|
|
|
|
obj = TestNotification(overflow=OverflowMode.SPLIT)
|
|
|
|
assert obj is not None
|
|
|
|
|
|
|
|
# Verify that we break the title to a max length of our title_max
|
|
|
|
# and that the body remains untouched
|
|
|
|
chunks = obj._apply_overflow(body=body, title=title)
|
|
|
|
offset = 0
|
|
|
|
assert len(chunks) == 4
|
|
|
|
for chunk in chunks:
|
|
|
|
# Our title never changes
|
|
|
|
assert title == chunk.get('title')
|
|
|
|
|
|
|
|
# Our body is only broken up; not lost
|
|
|
|
_body = chunk.get('body')
|
2019-02-22 03:13:31 +01:00
|
|
|
assert body[offset: len(_body) + offset].rstrip() == _body
|
2019-02-16 06:26:33 +01:00
|
|
|
offset += len(_body)
|
|
|
|
|
|
|
|
#
|
|
|
|
# Next Test: Append title to body + split body
|
|
|
|
#
|
|
|
|
|
|
|
|
class TestNotification(NotifyBase):
|
|
|
|
|
|
|
|
# Enforce no title
|
|
|
|
title_maxlen = 0
|
|
|
|
|
2019-02-17 19:45:48 +01:00
|
|
|
# Enforce a body length based on the title
|
|
|
|
# Wrap in int() so Python v3 doesn't convert the response into a float
|
|
|
|
body_maxlen = int(title_len / 4)
|
2019-02-16 06:26:33 +01:00
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(TestNotification, self).__init__(**kwargs)
|
|
|
|
|
|
|
|
def notify(self, *args, **kwargs):
|
|
|
|
# Pretend everything is okay
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Load our object
|
|
|
|
obj = TestNotification(overflow=OverflowMode.SPLIT)
|
|
|
|
assert obj is not None
|
|
|
|
|
|
|
|
# Verify that we break the title to a max length of our title_max
|
|
|
|
# and that the body remains untouched
|
|
|
|
chunks = obj._apply_overflow(body=body, title=title)
|
|
|
|
|
|
|
|
# Our final product is that our title has been appended to our body to
|
|
|
|
# create one great big body. As a result we'll get quite a few lines back
|
|
|
|
# now.
|
|
|
|
offset = 0
|
|
|
|
|
|
|
|
# Our body will look like this in small chunks at the end of the day
|
|
|
|
bulk = title + '\r\n' + body
|
|
|
|
|
|
|
|
# Due to the new line added to the end
|
|
|
|
assert len(chunks) == (
|
2019-02-17 19:45:48 +01:00
|
|
|
# wrap division in int() so Python 3 doesn't convert it to a float on
|
|
|
|
# us
|
|
|
|
int(len(bulk) / TestNotification.body_maxlen) +
|
2019-02-16 06:26:33 +01:00
|
|
|
(1 if len(bulk) % TestNotification.body_maxlen else 0))
|
|
|
|
|
|
|
|
for chunk in chunks:
|
|
|
|
# Our title is empty every time
|
|
|
|
assert chunk.get('title') == ''
|
|
|
|
|
|
|
|
_body = chunk.get('body')
|
2019-02-17 22:35:09 +01:00
|
|
|
assert bulk[offset: len(_body) + offset] == _body
|
2019-02-16 06:26:33 +01:00
|
|
|
offset += len(_body)
|