Implimented overflow support (upstream, truncate, and split)

This commit is contained in:
Chris Caron 2019-02-16 00:26:33 -05:00
parent 0d56da9ac8
commit cdd72086ee
31 changed files with 551 additions and 67 deletions

View File

@ -363,26 +363,30 @@ class Apprise(object):
# Store entry directly
conversion_map[server.notify_format] = body
try:
# Send notification
if not server.notify(
title=title,
body=conversion_map[server.notify_format],
notify_type=notify_type):
# Apply our overflow (if defined)
for chunk in server._apply_overflow(
body=conversion_map[server.notify_format], title=title):
try:
# Send notification
if not server.notify(
title=chunk['title'],
body=chunk['body'],
notify_type=notify_type):
# Toggle our return status flag
# Toggle our return status flag
status = False
except TypeError:
# These our our internally thrown notifications
# TODO: Change this to a custom one such as
# AppriseNotifyError
status = False
except TypeError:
# These our our internally thrown notifications
# TODO: Change this to a custom one such as AppriseNotifyError
status = False
except Exception:
# A catch all so we don't have to abort early
# just because one of our plugins has a bug in it.
logging.exception("Notification Exception")
status = False
except Exception:
# A catch all so we don't have to abort early
# just because one of our plugins has a bug in it.
logging.exception("Notification Exception")
status = False
return status

View File

@ -37,6 +37,8 @@ from .common import NotifyImageSize
from .common import NOTIFY_IMAGE_SIZES
from .common import NotifyFormat
from .common import NOTIFY_FORMATS
from .common import OverflowMode
from .common import OVERFLOW_MODES
from .plugins.NotifyBase import NotifyBase
from .Apprise import Apprise
@ -52,6 +54,6 @@ __all__ = [
'Apprise', 'AppriseAsset', 'NotifyBase',
# Reference
'NotifyType', 'NotifyImageSize', 'NotifyFormat', 'NOTIFY_TYPES',
'NOTIFY_IMAGE_SIZES', 'NOTIFY_FORMATS',
'NotifyType', 'NotifyImageSize', 'NotifyFormat', 'OverflowMode',
'NOTIFY_TYPES', 'NOTIFY_IMAGE_SIZES', 'NOTIFY_FORMATS', 'OVERFLOW_MODES',
]

View File

@ -77,3 +77,31 @@ NOTIFY_FORMATS = (
NotifyFormat.HTML,
NotifyFormat.MARKDOWN,
)
class OverflowMode(object):
"""
A list of pre-defined modes of how to handle the text when it exceeds the
defined maximum message size.
"""
# Send the data as is; untouched. Let the upstream server decide how the
# content is handled. Some upstream services might gracefully handle this
# with expected intentions; others might not.
UPSTREAM = 'upstream'
# Always truncate the text when it exceeds the maximum message size and
# send it anyway
TRUNCATE = 'truncate'
# Split the message into multiple smaller messages that fit within the
# limits of what is expected. The smaller messages are sent
SPLIT = 'split'
# Define our modes so we can verify if we need to
OVERFLOW_MODES = (
OverflowMode.UPSTREAM,
OverflowMode.TRUNCATE,
OverflowMode.SPLIT,
)

View File

@ -45,6 +45,8 @@ from ..utils import is_hostname
from ..common import NOTIFY_TYPES
from ..common import NotifyFormat
from ..common import NOTIFY_FORMATS
from ..common import OverflowMode
from ..common import OVERFLOW_MODES
from ..AppriseAsset import AppriseAsset
@ -120,14 +122,26 @@ class NotifyBase(object):
image_size = None
# The maximum allowable characters allowed in the body per message
body_maxlen = 32768
# We set it to what would virtually be an infinite value really
# 2^63 - 1 = 9223372036854775807
body_maxlen = 9223372036854775807
# Defines the maximum allowable characters in the title
# Defines the maximum allowable characters in the title; set this to zero
# if a title can't be used. Titles that are not used but are defined are
# automatically placed into the body
title_maxlen = 250
# Set the maximum line count; if this is set to anything larger then zero
# the message (prior to it being sent) will be truncated to this number
# of lines. Setting this to zero disables this feature.
body_max_line_count = 0
# Default Notify Format
notify_format = NotifyFormat.TEXT
# Default Overflow Mode
overflow_mode = OverflowMode.UPSTREAM
# Maintain a set of tags to associate with this specific notification
tags = set()
@ -177,6 +191,19 @@ class NotifyBase(object):
# Provide override
self.notify_format = notify_format
if 'overflow' in kwargs:
# Store the specified format if specified
overflow_mode = kwargs.get('overflow', '')
if overflow_mode.lower() not in OVERFLOW_MODES:
self.logger.error(
'Invalid overflow method %s' % overflow_mode,
)
raise TypeError(
'Invalid overflow method %s' % overflow_mode,
)
# Provide override
self.overflow_mode = overflow_mode
if 'tag' in kwargs:
# We want to associate some tags with our notification service.
# the code below gets the 'tag' argument if defined, otherwise
@ -260,6 +287,78 @@ class NotifyBase(object):
color_type=color_type,
)
def _apply_overflow(self, body, title=None):
"""
Takes the message body and title as input. This function then
applies any defined overflow restrictions associated with the
notification service and may alter the message if/as required.
The function will always return a list object in the following
structure:
[
{
title: 'the title goes here',
body: 'the message body goes here',
},
{
title: 'the title goes here',
body: 'the message body goes here',
},
]
"""
response = list()
if self.title_maxlen <= 0:
# Content is appended to body
body = '{}\r\n{}'.format(title, body)
title = ''
# Enforce the line count first always
if self.body_max_line_count > 0:
# Limit results to just the first 2 line otherwise
# there is just to much content to display
body = re.split('\r*\n', body)
body = '\r\n'.join(body[0:self.body_max_line_count])
if self.overflow_mode == OverflowMode.UPSTREAM:
# Nothing to do
response.append({
'body': body,
'title': title,
})
return response
elif len(title) > self.title_maxlen:
# Truncate our Title
title = title[:self.title_maxlen]
if self.body_maxlen > 0 and len(body) <= self.body_maxlen:
response.append({
'body': body,
'title': title,
})
return response
if self.overflow_mode == OverflowMode.TRUNCATE:
# Truncate our body and return
response.append({
'body': body[:self.body_maxlen],
'title': title,
})
# For truncate mode, we're done now
return response
# If we reach here, then we are in SPLIT mode.
# For here, we want to split the message as many times as we have to
# in order to fit it within the designated limits.
response = [{
'body': body[i: i + self.body_maxlen],
'title': title} for i in range(0, len(body), self.body_maxlen)]
return response
def url(self):
"""
Assembles the URL associated with the notification based on the

View File

@ -280,7 +280,8 @@ class NotifyBoxcar(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format
'format': self.notify_format,
'overflow': self.overflow_mode,
}
return '{schema}://{access}/{secret}/{recipients}/?{args}'.format(

View File

@ -148,6 +148,14 @@ class NotifyDBus(NotifyBase):
# The number of seconds to keep the message present for
message_timeout_ms = 13000
# Limit results to just the first 10 line otherwise there is just to much
# content to display
body_max_line_count = 10
# A title can not be used for SMS Messages. Setting this to zero will
# cause any title (if defined) to get placed into the message body.
title_maxlen = 0
# This entry is a bit hacky, but it allows us to unit-test this library
# in an environment that simply doesn't have the gnome packages
# available to us. It also allows us to handle situations where the
@ -249,15 +257,6 @@ class NotifyDBus(NotifyBase):
"Could not load Gnome notification icon ({}): {}"
.format(icon_path, e))
# Limit results to just the first 10 line otherwise
# there is just to much content to display
body = re.split('[\r\n]+', body)
if title:
# Place title on first line if it exists
body.insert(0, title)
body = '\r\n'.join(body[0:10])
try:
dbus_iface.Notify(
# Application Identifier

View File

@ -249,6 +249,7 @@ class NotifyDiscord(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
'tts': 'yes' if self.tts else 'no',
'avatar': 'yes' if self.avatar else 'no',
'footer': 'yes' if self.footer else 'no',

View File

@ -429,6 +429,7 @@ class NotifyEmail(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
'to': self.to_addr,
'from': self.from_addr,
'name': self.from_name,

View File

@ -543,6 +543,7 @@ class NotifyEmby(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
'modal': 'yes' if self.modal else 'no',
}

View File

@ -132,6 +132,7 @@ class NotifyFaast(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
return '{schema}://{authtoken}/?{args}'.format(

View File

@ -26,8 +26,6 @@
from __future__ import absolute_import
from __future__ import print_function
import re
from .NotifyBase import NotifyBase
from ..common import NotifyImageSize
@ -86,6 +84,14 @@ class NotifyGnome(NotifyBase):
# Allows the user to specify the NotifyImageSize object
image_size = NotifyImageSize.XY_128
# Limit results to just the first 10 line otherwise there is just to much
# content to display
body_max_line_count = 10
# A title can not be used for SMS Messages. Setting this to zero will
# cause any title (if defined) to get placed into the message body.
title_maxlen = 0
# This entry is a bit hacky, but it allows us to unit-test this library
# in an environment that simply doesn't have the gnome packages
# available to us. It also allows us to handle situations where the
@ -119,15 +125,6 @@ class NotifyGnome(NotifyBase):
"Gnome Notifications are not supported by this system.")
return False
# Limit results to just the first 10 line otherwise
# there is just to much content to display
body = re.split('[\r\n]+', body)
if title:
# Place title on first line if it exists
body.insert(0, title)
body = '\r\n'.join(body[0:10])
try:
# App initialization
Notify.init(self.app_id)

View File

@ -223,6 +223,7 @@ class NotifyGrowl(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
'priority':
_map[GrowlPriority.NORMAL] if self.priority not in _map
else _map[self.priority],

View File

@ -214,6 +214,7 @@ class NotifyIFTTT(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
return '{schema}://{webhook_id}@{events}/?{args}'.format(

View File

@ -78,6 +78,7 @@ class NotifyJSON(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
# Determine Authentication

View File

@ -90,6 +90,10 @@ class NotifyJoin(NotifyBase):
# Allows the user to specify the NotifyImageSize object
image_size = NotifyImageSize.XY_72
# Limit results to just the first 2 line otherwise there is just to much
# content to display
body_max_line_count = 2
# The maximum allowable characters allowed in the body per message
body_maxlen = 1000
@ -131,17 +135,6 @@ class NotifyJoin(NotifyBase):
Perform Join Notification
"""
try:
# Limit results to just the first 2 line otherwise
# there is just to much content to display
body = re.split('[\r\n]+', body)
body[0] = body[0].strip('#').strip()
body = '\r\n'.join(body[0:2])
except (AttributeError, TypeError):
# body was None or not of a type string
body = ''
headers = {
'User-Agent': self.app_id,
'Content-Type': 'application/x-www-form-urlencoded',
@ -241,6 +234,7 @@ class NotifyJoin(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
return '{schema}://{apikey}/{devices}/?{args}'.format(

View File

@ -244,6 +244,7 @@ class NotifyMatrix(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
'mode': self.mode,
}

View File

@ -187,6 +187,7 @@ class NotifyMatterMost(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
default_port = 443 if self.secure else self.default_port

View File

@ -206,6 +206,7 @@ class NotifyProwl(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
'priority': 'normal' if self.priority not in _map
else _map[self.priority]
}

View File

@ -190,6 +190,7 @@ class NotifyPushBullet(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
recipients = '/'.join([self.quote(x) for x in self.recipients])

View File

@ -265,6 +265,7 @@ class NotifyPushed(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
return '{schema}://{app_key}/{app_secret}/{targets}/?{args}'.format(

View File

@ -95,6 +95,7 @@ class NotifyPushjet(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
default_port = 443 if self.secure else 80

View File

@ -253,6 +253,7 @@ class NotifyPushover(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
'priority':
_map[PushoverPriority.NORMAL] if self.priority not in _map
else _map[self.priority],

View File

@ -148,6 +148,7 @@ class NotifyRocketChat(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
# Determine Authentication

View File

@ -229,6 +229,7 @@ class NotifyRyver(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
'webhook': self.webhook,
}

View File

@ -90,6 +90,10 @@ class NotifySNS(NotifyBase):
# Source: https://docs.aws.amazon.com/sns/latest/api/API_Publish.html
body_maxlen = 140
# A title can not be used for SMS Messages. Setting this to zero will
# cause any title (if defined) to get placed into the message body.
title_maxlen = 0
def __init__(self, access_key_id, secret_access_key, region_name,
recipients=None, **kwargs):
"""
@ -530,6 +534,7 @@ class NotifySNS(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
return '{schema}://{key_id}/{key_secret}/{region}/{targets}/'\

View File

@ -304,6 +304,7 @@ class NotifySlack(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
# Determine if there is a botname present

View File

@ -498,6 +498,7 @@ class NotifyTelegram(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
# No need to check the user token because the user automatically gets

View File

@ -26,7 +26,6 @@
from __future__ import absolute_import
from __future__ import print_function
import re
from time import sleep
from .NotifyBase import NotifyBase
@ -67,6 +66,10 @@ class NotifyWindows(NotifyBase):
# Allows the user to specify the NotifyImageSize object
image_size = NotifyImageSize.XY_128
# Limit results to just the first 2 line otherwise there is just to much
# content to display
body_max_line_count = 2
# This entry is a bit hacky, but it allows us to unit-test this library
# in an environment that simply doesn't have the windows packages
# available to us. It also allows us to handle situations where the
@ -110,12 +113,6 @@ class NotifyWindows(NotifyBase):
"Windows Notifications are not supported by this system.")
return False
# Limit results to just the first 2 line otherwise
# there is just to much content to display
body = re.split('[\r\n]+', body)
body[0] = body[0].strip('#').strip()
body = '\r\n'.join(body[0:2])
try:
# Register destruction callback
message_map = {win32con.WM_DESTROY: self._on_destroy, }

View File

@ -23,7 +23,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import re
import requests
from json import dumps
@ -58,6 +57,10 @@ class NotifyXBMC(NotifyBase):
# A URL that takes you to the setup/help of the specific protocol
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_kodi'
# Limit results to just the first 2 line otherwise there is just to much
# content to display
body_max_line_count = 2
# XBMC uses the http protocol with JSON requests
xbmc_default_port = 8080
@ -159,12 +162,6 @@ class NotifyXBMC(NotifyBase):
Perform XBMC/KODI Notification
"""
# Limit results to just the first 2 line otherwise
# there is just to much content to display
body = re.split('[\r\n]+', body)
body[0] = body[0].strip('#').strip()
body = '\r\n'.join(body[0:2])
if self.protocol == self.xbmc_remote_protocol:
# XBMC v2.0
(headers, payload) = self._payload_20(
@ -237,6 +234,7 @@ class NotifyXBMC(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
# Determine Authentication

View File

@ -93,6 +93,7 @@ class NotifyXML(NotifyBase):
# Define any arguments set
args = {
'format': self.notify_format,
'overflow': self.overflow_mode,
}
# Determine Authentication

View File

@ -25,12 +25,18 @@
from apprise import plugins
from apprise import NotifyType
from apprise import NotifyBase
from apprise import Apprise
from apprise import AppriseAsset
from apprise.utils import compat_is_basestring
from apprise.common import NotifyFormat
from apprise.common import OverflowMode
from json import dumps
from random import choice
from string import ascii_uppercase as str_alpha
from string import digits as str_num
import requests
import mock
@ -2883,3 +2889,338 @@ def test_notify_telegram_plugin(mock_post, mock_get):
except TypeError:
# Exception should be thrown about the fact no token was specified
assert(True)
def test_notify_overflow_truncate():
"""
API: Overflow Truncate Functionality Testing
"""
#
# A little preparation
#
# 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
try:
# Load our object
obj = TestNotification(overflow='invalid')
# We should have thrown an exception because our specified overflow
# is wrong.
assert False
except TypeError:
# Expected to be here
assert 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 == 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.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
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
#
# 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
# 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
body_maxlen = (body_len / 4)
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')
assert body[offset: len(_body) + offset] == _body
offset += len(_body)
#
# Next Test: Append title to body + split body
#
class TestNotification(NotifyBase):
# Enforce no title
title_maxlen = 0
# Enforce a body length
body_maxlen = (title_len / 4)
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) == (
(len(bulk) / TestNotification.body_maxlen) +
(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')
assert bulk[offset:len(_body)+offset] == _body
offset += len(_body)