Beispiel #1
0
def test_smtplib_send_okay(mock_smtplib):
    """
    API: Test a successfully sent email

    """
    # Disable Throttling to speed testing
    plugins.NotifyBase.NotifyBase.request_rate_per_sec = 0

    # Defaults to HTML
    obj = Apprise.instantiate('mailto://*****:*****@gmail.com',
                              suppress_exceptions=False)
    assert (isinstance(obj, plugins.NotifyEmail))

    # Support an email simulation where we can correctly quit
    mock_smtplib.starttls.return_value = True
    mock_smtplib.login.return_value = True
    mock_smtplib.sendmail.return_value = True
    mock_smtplib.quit.return_value = True

    assert (obj.notify(body='body', title='test', notify_type=NotifyType.INFO)
            is True)

    # Set Text
    obj = Apprise.instantiate('mailto://*****:*****@gmail.com?format=text',
                              suppress_exceptions=False)
    assert (isinstance(obj, plugins.NotifyEmail))

    assert (obj.notify(body='body', title='test', notify_type=NotifyType.INFO)
            is True)
Beispiel #2
0
def main():
    """
    Loops over all the Swarm services, checking if they need updates.

    :raises Exception when Docker Engine is not in Swarm Mode
    """
    update_delay = getenv('UPDATE_DELAY', '300')
    notification_url = getenv('NOTIFICATION_URL', '')

    try:
        client = docker.from_env()
    except ConnectionError:
        logger.error(
            'Could not connect to Docker Engine. Check https://git.io/JJujV for possible solutions'
        )
        return

    logger.info('Started checking for updates')
    apprise = Apprise()
    if len(notification_url) > 0:
        # Add notification provider from URL if provided
        apprise.add(notification_url)

    if not is_swarm_manager(client):
        raise Exception('Docker Engine is not in Swarm Mode')
    while True:
        update_services(client, apprise)
        time.sleep(float(update_delay))
Beispiel #3
0
def test_twist_plugin_init():
    """
    API: NotifyTwist init()

    """
    try:
        plugins.NotifyTwist(email='invalid', targets=None)
        assert False
    except TypeError:
        # Invalid email address
        assert True

    try:
        plugins.NotifyTwist(email='user@domain', targets=None)
        assert False
    except TypeError:
        # No password was specified
        assert True

    # Simple object initialization
    result = plugins.NotifyTwist(password='******',
                                 email='*****@*****.**',
                                 targets=None)
    assert result.user == 'user'
    assert result.host == 'domain.com'
    assert result.password == 'abc123'

    # Channel Instantiation by name
    obj = Apprise.instantiate('twist://*****:*****@example.com/#Channel')
    assert isinstance(obj, plugins.NotifyTwist)

    # Channel Instantiation by id (faster if you know the translation)
    obj = Apprise.instantiate('twist://*****:*****@example.com/12345')
    assert isinstance(obj, plugins.NotifyTwist)

    # Invalid Channel - (max characters is 64), the below drops it
    obj = Apprise.instantiate('twist://*****:*****@example.com/{}'.format(
        'a' * 65))
    assert isinstance(obj, plugins.NotifyTwist)

    # No User detect
    result = plugins.NotifyTwist.parse_url('twist://example.com')
    assert result is None

    # test usage of to=
    result = plugins.NotifyTwist.parse_url(
        'twist://*****:*****@example.com?to=#channel')
    assert isinstance(result, dict)
    assert 'user' in result
    assert result['user'] == 'user'
    assert 'host' in result
    assert result['host'] == 'example.com'
    assert 'password' in result
    assert result['password'] == 'password'
    assert 'targets' in result
    assert isinstance(result['targets'], list) is True
    assert len(result['targets']) == 1
    assert '#channel' in result['targets']
def test_fcm_plugin(mock_post):
    """
    API: NotifyFCM() General Checks

    """
    # Valid Keyfile
    path = os.path.join(PRIVATE_KEYFILE_DIR, 'service_account.json')

    # Disable Throttling to speed testing
    plugins.NotifyBase.request_rate_per_sec = 0

    # Prepare a good response
    response = mock.Mock()
    response.content = json.dumps({
        "access_token": "ya29.c.abcd",
        "expires_in": 3599,
        "token_type": "Bearer",
    })
    response.status_code = requests.codes.ok
    mock_post.return_value = response

    # Test having a valid keyfile, but not a valid project id match
    obj = Apprise.instantiate(
        'fcm://invalid_project_id/device/?keyfile={}'.format(str(path)))
    # we'll fail as a result
    assert obj.notify("test") is False

    # Test our call count
    assert mock_post.call_count == 0

    # Now we test using a valid Project ID but we can't open our file
    obj = Apprise.instantiate(
        'fcm://mock-project-id/device/?keyfile={}'.format(str(path)))

    with mock.patch('io.open', side_effect=OSError):
        # we'll fail as a result
        assert obj.notify("test") is False

    # Test our call count
    assert mock_post.call_count == 0

    # Now we test using a valid Project ID
    obj = Apprise.instantiate(
        'fcm://mock-project-id/device/#topic/?keyfile={}'.format(str(path)))

    # we'll fail as a result
    assert obj.notify("test") is True

    # Test our call count
    assert mock_post.call_count == 3
    assert mock_post.call_args_list[0][0][0] == \
        'https://accounts.google.com/o/oauth2/token'
    assert mock_post.call_args_list[1][0][0] == \
        'https://fcm.googleapis.com/v1/projects/mock-project-id/messages:send'
    assert mock_post.call_args_list[2][0][0] == \
        'https://fcm.googleapis.com/v1/projects/mock-project-id/messages:send'
def run_server(apprise: Apprise):
    apprise.notify("Starting notification service")
    public_ip = ""

    while True:
        current_ip = get_public_ip()
        if public_ip != current_ip:
            apprise.notify(f"Public IP changed to '{current_ip}'")
            public_ip = current_ip
        sleep(CHECK_INTERVAL_IN_SECONDS)
Beispiel #6
0
def update_services(client: DockerClient, apprise: Apprise):
    """
    Update all the services found on the Docker Swarm.

    :param client: Docker Client that is connected to a Docker Swarm Manager
    :param apprise: Apprise notification service
    """
    services = client.services.list()
    logger.info(f'Checking for updates on {len(services)} service(s).')
    for service in services:
        name = service.name
        outdated, tag, digest = is_service_outdated(client, service)
        if outdated:
            update_message = f'Found update for `{tag}`, updating.'
            mode = service.attrs['Spec']['Mode']
            replicated = 'Replicated' in mode
            if replicated:
                replicas = mode['Replicated']['Replicas']
                plural = 's' if replicas > 1 else ''
                update_message = f"Found update for `{tag}`, updating {replicas} replica{plural}."

            apprise.notify(title=f'Service: `{name}`',
                           body=update_message,
                           notify_type=NotifyType.INFO)

            logger.info(
                f'Found update for service \'{name}\', updating using image {tag}'
            )
            start = time.time()
            full_image = f"{tag}@{digest}"
            service.update(image=full_image,
                           force_update=True)  # Update the service
            end = time.time()
            elapsed = str((
                end -
                start))[:4]  # Calculate the time it took to update the service
            logger.info(
                f'Update for service \'{name}\' successful, took {elapsed} seconds ({full_image})'
            )

            success_message = f'Update successful. Took {elapsed} seconds.'
            apprise.notify(title=f'Service: `{name}`',
                           body=success_message,
                           notify_type=NotifyType.SUCCESS)
            if getenv('PARALLEL_UPDATES',
                      '').lower() in ['false', 'no', 'off', '0']:
                # When there are more images to update in one pass then update them one by one
                return
        else:
            logger.debug(f'No update found for service \'{name}\'')
def test_object_parsing():
    """
    API: NotifySNS Plugin() Object Parsing

    """

    # Create our object
    a = Apprise()

    # Now test failing variations of our URL
    assert a.add('sns://') is False
    assert a.add('sns://nosecret') is False
    assert a.add('sns://nosecret/noregion/') is False

    # This is valid but without valid recipients; while it's still a valid URL
    # it won't do much when the user goes to send a notification
    assert a.add('sns://norecipient/norecipient/us-west-2') is True
    assert len(a) == 1

    # Parse a good one
    assert a.add('sns://oh/yeah/us-west-2/abcdtopic/+12223334444') is True
    assert len(a) == 2

    assert a.add('sns://oh/yeah/us-west-2/12223334444') is True
    assert len(a) == 3
def test_plugin_homeassistant_general(mock_post):
    """
    NotifyHomeAssistant() General Checks

    """
    # Disable Throttling to speed testing
    plugins.NotifyBase.request_rate_per_sec = 0

    response = mock.Mock()
    response.content = ''
    response.status_code = requests.codes.ok

    # Prepare Mock
    mock_post.return_value = response

    # Variation Initializations
    obj = Apprise.instantiate('hassio://localhost/accesstoken')
    assert isinstance(obj, plugins.NotifyHomeAssistant) is True
    assert isinstance(obj.url(), six.string_types) is True

    # Send Notification
    assert obj.send(body="test") is True

    assert mock_post.call_count == 1
    assert mock_post.call_args_list[0][0][0] == \
        'http://localhost:8123/api/services/persistent_notification/create'
def test_smtplib_init_fail(mock_smtplib):
    """
    API: Test exception handling when calling smtplib.SMTP()

    """

    from apprise.plugins import NotifyEmailBase

    obj = Apprise.instantiate('mailto://*****:*****@gmail.com',
                              suppress_exceptions=False)
    assert (isinstance(obj, plugins.NotifyEmail))

    # Support Exception handling of smtplib.SMTP
    mock_smtplib.side_effect = TypeError('Test')

    try:
        obj.notify(title='test', body='body', notify_type=NotifyType.INFO)

        # We should have thrown an exception
        assert False

    except TypeError:
        # Exception thrown as expected
        assert True

    except Exception:
        # Un-Expected
        assert False

    # A handled and expected exception
    mock_smtplib.side_effect = smtplib.SMTPException('Test')
    assert obj.notify(title='test', body='body',
                      notify_type=NotifyType.INFO) is False
def test_discord_attachments(mock_post):
    """
    API: NotifyDiscord() Attachment Checks

    """
    # Disable Throttling to speed testing
    plugins.NotifyBase.request_rate_per_sec = 0

    # Initialize some generic (but valid) tokens
    webhook_id = 'C' * 24
    webhook_token = 'D' * 64

    # Prepare Mock return object
    response = mock.Mock()
    response.status_code = requests.codes.ok

    # Throw an exception on the second call to requests.post()
    mock_post.side_effect = [response, OSError()]

    # Test our markdown
    obj = Apprise.instantiate('discord://{}/{}/?format=markdown'.format(
        webhook_id, webhook_token))

    # attach our content
    attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))

    # We'll fail now because of an internal exception
    assert obj.send(body="test", attach=attach) is False
Beispiel #11
0
def test_email_url_escaping():
    """
    API: Test that user/passwords are properly escaped from URL

    """
    # quote(' %20')
    passwd = '%20%2520'

    # Basically we want to check that ' ' equates to %20 and % equates to %25
    # So the above translates to ' %20' (a space in front of %20).  We want
    # to verify the handling of the password escaping and when it happens.
    # a very bad response would be '  ' (double space)
    obj = plugins.NotifyEmail.parse_url(
        'mailto://*****:*****@gmail.com?format=text'.format(passwd))

    assert isinstance(obj, dict) is True
    assert 'password' in obj

    # Escaping doesn't happen at this stage because we want to leave this to
    # the plugins discretion
    assert obj.get('password') == '%20%2520'

    obj = Apprise.instantiate(
        'mailto://*****:*****@gmail.com?format=text'.format(passwd),
        suppress_exceptions=False)
    assert isinstance(obj, plugins.NotifyEmail) is True

    # The password is escapped 'once' at this point
    assert obj.password == ' %20'
Beispiel #12
0
def test_webbase_lookup(mock_smtp, mock_smtpssl):
    """
    API: Web Based Lookup Tests

    """

    # Insert a test email at the head of our table
    NotifyEmailBase.WEBBASE_LOOKUP_TABLE = (
        (
            # Testing URL
            'Testing Lookup',
            re.compile(r'^(?P<id>[^@]+)@(?P<domain>l2g\.com)$', re.I),
            {
                'port': 123,
                'smtp_host': 'smtp.l2g.com',
                'secure': True,
                'login_type': (NotifyEmailBase.WebBaseLogin.USERID, )
            },
        ), ) + NotifyEmailBase.WEBBASE_LOOKUP_TABLE

    obj = Apprise.instantiate('mailto://*****:*****@l2g.com',
                              suppress_exceptions=True)

    assert (isinstance(obj, plugins.NotifyEmail))
    assert obj.to_addr == '*****@*****.**'
    assert obj.from_addr == '*****@*****.**'
    assert obj.password == 'pass'
    assert obj.user == 'user'
    assert obj.secure is True
    assert obj.port == 123
    assert obj.smtp_host == 'smtp.l2g.com'
Beispiel #13
0
def test_apprise_schemas(tmpdir):
    """
    API: Apprise().schema() tests

    """
    # Caling load matix a second time which is an internal function causes it
    # to skip over content already loaded into our matrix and thefore accesses
    # other if/else parts of the code that aren't otherwise called
    __load_matrix()

    a = Apprise()

    # no items
    assert len(a) == 0

    class TextNotification(NotifyBase):
        # set our default notification format
        notify_format = NotifyFormat.TEXT

        # Garbage Protocol Entries
        protocol = None

        secure_protocol = (None, object)

    class HtmlNotification(NotifyBase):

        protocol = ('html', 'htm')

        secure_protocol = ('htmls', 'htms')

    class MarkDownNotification(NotifyBase):

        protocol = 'markdown'

        secure_protocol = 'markdowns'

    # Store our notifications into our schema map
    SCHEMA_MAP['text'] = TextNotification
    SCHEMA_MAP['html'] = HtmlNotification
    SCHEMA_MAP['markdown'] = MarkDownNotification

    schemas = URLBase.schemas(TextNotification)
    assert isinstance(schemas, set) is True
    # We didn't define a protocol or secure protocol
    assert len(schemas) == 0

    schemas = URLBase.schemas(HtmlNotification)
    assert isinstance(schemas, set) is True
    assert len(schemas) == 4
    assert 'html' in schemas
    assert 'htm' in schemas
    assert 'htmls' in schemas
    assert 'htms' in schemas

    # Invalid entries do not disrupt schema calls
    for garbage in (object(), None, 42):
        schemas = URLBase.schemas(garbage)
        assert isinstance(schemas, set) is True
        assert len(schemas) == 0
Beispiel #14
0
def test_config_base_parse_yaml_file03(tmpdir):
    """
    API: ConfigBase.parse_yaml_file (#3)

    """

    t = tmpdir.mkdir("bad-first-entry").join("apprise.yml")
    # The first entry is -tag and not <dash><space>tag
    # The element is therefore not picked up; This causes us to display
    # some warning messages to the screen complaining of this typo yet
    # still allowing us to load the URL since it is valid
    t.write("""urls:
  - pover://nsisxnvnqixq39t0cw54pxieyvtdd9@2jevtmstfg5a7hfxndiybasttxxfku:
    -tag: test1
  - pover://rg8ta87qngcrkc6t4qbykxktou0uug@tqs3i88xlufexwl8t4asglt4zp5wfn:
    - tag: test2
  - pover://jcqgnlyq2oetea4qg3iunahj8d5ijm@evalvutkhc8ipmz2lcgc70wtsm0qpb:
    - tag: test3""")

    # Create ourselves a config object
    ac = AppriseConfig(paths=str(t))

    # The number of configuration files that exist
    assert len(ac) == 1

    # no notifications lines processed is 3
    assert len(ac.servers()) == 3

    # Test our ability to add Config objects to our apprise object
    a = Apprise()

    # Add our configuration object
    assert a.add(servers=ac) is True

    # Detect our 3 entry as they should have loaded successfully
    assert len(a) == 3

    # No match
    assert sum(1 for _ in a.find('no-match')) == 0
    # Match everything
    assert sum(1 for _ in a.find('all')) == 3
    # No match for bad entry
    assert sum(1 for _ in a.find('test1')) == 0
    # Match test2 entry
    assert sum(1 for _ in a.find('test2')) == 1
    # Match test3 entry
    assert sum(1 for _ in a.find('test3')) == 1
    # Match test1 or test3 entry; (only matches test3)
    assert sum(1 for _ in a.find('test1, test3')) == 1
Beispiel #15
0
def test_apprise_details():
    """
    API: Apprise() Details

    """

    # Caling load matix a second time which is an internal function causes it
    # to skip over content already loaded into our matrix and thefore accesses
    # other if/else parts of the code that aren't otherwise called
    __load_matrix()

    a = Apprise()

    # Details object
    details = a.details()

    # Dictionary response
    assert isinstance(details, dict)

    # Apprise version
    assert 'version' in details
    assert details.get('version') == __version__

    # Defined schemas identify each plugin
    assert 'schemas' in details
    assert isinstance(details.get('schemas'), list)

    # We have an entry per defined plugin
    assert 'asset' in details
    assert isinstance(details.get('asset'), dict)
    assert 'app_id' in details['asset']
    assert 'app_desc' in details['asset']
    assert 'default_extension' in details['asset']
    assert 'theme' in details['asset']
    assert 'image_path_mask' in details['asset']
    assert 'image_url_mask' in details['asset']
    assert 'image_url_logo' in details['asset']

    # All plugins must have a name defined; the below generates
    # a list of entrys that do not have a string defined.
    assert (not len([
        x['service_name'] for x in details['schemas']
        if not isinstance(x['service_name'], six.string_types)
    ]))
def test_plugin_fcm_cryptography_import_error():
    """
    NotifySimplePush() Cryptography loading failure
    """

    # Attempt to instantiate our object
    obj = Apprise.instantiate('spush://{}'.format('Y' * 14))

    # It's not possible because our cryptography depedancy is missing
    assert obj is None
def test_plugin_signal_edge_cases(mock_post):
    """
    NotifySignalAPI() Edge Cases

    """
    # 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
    source = '+1 (555) 123-3456'
    target = '+1 (555) 987-5432'
    body = "test body"
    title = "My Title"

    # No apikey specified
    with pytest.raises(TypeError):
        plugins.NotifySignalAPI(source=None)

    aobj = Apprise()
    assert aobj.add("signals://*****:*****@localhost:231/{}/{}?status=True".format(
            source, target))
    assert aobj.notify(title=title, body=body)

    assert mock_post.call_count == 1

    details = mock_post.call_args_list[0]
    assert details[0][0] == 'https://localhost:231/v2/send'
    payload = loads(details[1]['data'])
    # Status flag is set
    assert payload['message'] == '[i] My Title\r\ntest body'
def test_plugin(mock_oauth, mock_api):
    """
    API: NotifyTwitter Plugin() (pt1)

    """

    # iterate over our dictionary and test it out
    for (url, meta) in TEST_URLS:

        # 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)

        # Allow us to force the server response code to be something other then
        # the defaults
        response = meta.get(
            'response', True if response else False)

        try:
            obj = Apprise.instantiate(url, suppress_exceptions=False)

            if instance is None:
                # Check that we got what we came for
                assert obj is instance
                continue

            assert(isinstance(obj, instance))

            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
                    assert(hasattr(key, obj))
                    assert(getattr(key, obj) == val)

            # check that we're as expected
            assert obj.notify(
                title='test', body='body',
                notify_type=NotifyType.INFO) == response

        except AssertionError:
            # Don't mess with these entries
            raise

        except Exception as e:
            # Handle our exception
            assert(instance is not None)
            assert(isinstance(e, instance))
def test_email_dict_variations():
    """
    API: Test email dictionary variations to ensure parsing is correct

    """
    # Test variations of username required to be an email address
    # [email protected]
    obj = Apprise.instantiate({
        'schema': 'mailto',
        'user': '******',
        'password': '******',
        'host': 'example.com'}, suppress_exceptions=False)
    assert isinstance(obj, plugins.NotifyEmail) is True
def test_webbase_lookup(mock_smtp, mock_smtpssl):
    """
    API: Web Based Lookup Tests

    """

    # Insert a test email at the head of our table
    NotifyEmailBase.EMAIL_TEMPLATES = (
        (
            # Testing URL
            'Testing Lookup',
            re.compile(r'^(?P<id>[^@]+)@(?P<domain>l2g\.com)$', re.I),
            {
                'port': 123,
                'smtp_host': 'smtp.l2g.com',
                'secure': True,
                'login_type': (NotifyEmailBase.WebBaseLogin.USERID, )
            },
        ),
    ) + NotifyEmailBase.EMAIL_TEMPLATES

    obj = Apprise.instantiate(
        'mailto://*****:*****@l2g.com', suppress_exceptions=True)

    assert isinstance(obj, plugins.NotifyEmail)
    assert len(obj.targets) == 1
    assert (False, '*****@*****.**') in obj.targets
    assert obj.from_addr == '*****@*****.**'
    assert obj.password == 'pass'
    assert obj.user == 'user'
    assert obj.secure is True
    assert obj.port == 123
    assert obj.smtp_host == 'smtp.l2g.com'

    # We get the same results if an email is identified as the username
    # because the USERID variable forces that we can't use an email
    obj = Apprise.instantiate(
        'mailto://*****:*****@[email protected]', suppress_exceptions=True)
    assert obj.user == 'user'
Beispiel #21
0
def test_config_base_parse_yaml_file02(tmpdir):
    """
    API: ConfigBase.parse_yaml_file (#2)

    """
    t = tmpdir.mkdir("matching-tags").join("apprise.yml")
    t.write("""urls:
  - pover://nsisxnvnqixq39t0cw54pxieyvtdd9@2jevtmstfg5a7hfxndiybasttxxfku:
    - tag: test1
  - pover://rg8ta87qngcrkc6t4qbykxktou0uug@tqs3i88xlufexwl8t4asglt4zp5wfn:
    - tag: test2
  - pover://jcqgnlyq2oetea4qg3iunahj8d5ijm@evalvutkhc8ipmz2lcgc70wtsm0qpb:
    - tag: test3""")

    # Create ourselves a config object
    ac = AppriseConfig(paths=str(t))

    # The number of configuration files that exist
    assert len(ac) == 1

    # no notifications are loaded
    assert len(ac.servers()) == 3

    # Test our ability to add Config objects to our apprise object
    a = Apprise()

    # Add our configuration object
    assert a.add(servers=ac) is True

    # Detect our 3 entry as they should have loaded successfully
    assert len(a) == 3

    # No match
    assert sum(1 for _ in a.find('no-match')) == 0
    # Match everything
    assert sum(1 for _ in a.find('all')) == 3
    # Match test1 entry
    assert sum(1 for _ in a.find('test1')) == 1
    # Match test2 entry
    assert sum(1 for _ in a.find('test2')) == 1
    # Match test3 entry
    assert sum(1 for _ in a.find('test3')) == 1
    # Match test1 or test3 entry
    assert sum(1 for _ in a.find('test1, test3')) == 2
Beispiel #22
0
def test_discord_attachments(mock_post):
    """
    API: NotifyDiscord() Attachment Checks

    """
    # Disable Throttling to speed testing
    plugins.NotifyBase.request_rate_per_sec = 0

    # Initialize some generic (but valid) tokens
    webhook_id = 'C' * 24
    webhook_token = 'D' * 64

    # Prepare Mock return object
    mock_post.return_value = requests.Request()
    mock_post.return_value.status_code = requests.codes.ok

    # Test our markdown
    obj = Apprise.instantiate('discord://{}/{}/?format=markdown'.format(
        webhook_id, webhook_token))

    # attach our content
    attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))

    assert obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO,
        attach=attach) is True

    # An invalid attachment will cause a failure
    path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg')
    attach = AppriseAttachment(path)
    assert obj.notify(
        body='body', title='title', notify_type=NotifyType.INFO,
        attach=path) is False

    # Throw an exception on the second call to requests.post()
    mock_post.return_value = None
    response = mock.Mock()
    response.status_code = requests.codes.ok
    mock_post.side_effect = [response, OSError()]

    # update our attachment to be valid
    attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))
    # Test our markdown

    # We'll fail now because of an internal exception
    assert obj.send(body="test", attach=attach) is False
Beispiel #23
0
def test_plugin_ses_attachments(mock_post):
    """
    NotifySES() Attachment Checks

    """
    # Disable Throttling to speed testing
    plugins.NotifySES.request_rate_per_sec = 0

    # Prepare Mock return object
    response = mock.Mock()
    response.content = AWS_SES_GOOD_RESPONSE
    response.status_code = requests.codes.ok
    mock_post.return_value = response

    # prepare our attachment
    attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))

    # Test our markdown
    obj = Apprise.instantiate('ses://%s/%s/%s/%s/' %
                              ('*****@*****.**', TEST_ACCESS_KEY_ID,
                               TEST_ACCESS_KEY_SECRET, TEST_REGION))

    # Send a good attachment
    assert obj.notify(body="test", attach=attach) is True

    # Reset our mock object
    mock_post.reset_mock()

    # Add another attachment so we drop into the area of the PushBullet code
    # that sends remaining attachments (if more detected)
    attach.add(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))

    # Send our attachments
    assert obj.notify(body="test", attach=attach) is True

    # Test our call count
    assert mock_post.call_count == 1

    # Reset our mock object
    mock_post.reset_mock()

    # An invalid attachment will cause a failure
    path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg')
    attach = AppriseAttachment(path)
    assert obj.notify(body="test", attach=attach) is False
Beispiel #24
0
def send_notification(message, subject):
    apprise_client = Apprise()
    if APPRISE_CONFIG_STRING:
        apprise_client.add(APPRISE_CONFIG_STRING)
    if APPRISE_CONFIG_URL:
        config = AppriseConfig()
        config.add(APPRISE_CONFIG_URL)
        apprise_client.add(config)

    res = apprise_client.notify(body=message, title=subject)
    print(res)
    if not res:
        print('Failed to send notification')
    else:
        print('Successfully sent notification')

    return res
def test_plugin_simplepush_general(mock_post):
    """
    NotifySimplePush() General Tests
    """
    # Disable Throttling to speed testing
    plugins.NotifyBase.request_rate_per_sec = 0

    # Prepare a good response
    response = mock.Mock()
    response.content = json.dumps({
        'status': 'OK',
    })
    response.status_code = requests.codes.ok
    mock_post.return_value = response

    obj = Apprise.instantiate('spush://{}'.format('Y' * 14))

    # Verify our content works as expected
    assert obj.notify(title="test", body="test") is True
def test_smtplib_send_okay(mock_smtplib):
    """
    API: Test a successfully sent email

    """

    from apprise.plugins import NotifyEmailBase

    obj = Apprise.instantiate('mailto://*****:*****@gmail.com',
                              suppress_exceptions=False)
    assert (isinstance(obj, plugins.NotifyEmail))

    # Support an email simulation where we can correctly quit
    mock_smtplib.starttls.return_value = True
    mock_smtplib.login.return_value = True
    mock_smtplib.sendmail.return_value = True
    mock_smtplib.quit.return_value = True

    obj.notify(title='test', body='body', notify_type=NotifyType.INFO)
Beispiel #27
0
def test_smtplib_init_fail(mock_smtplib):
    """
    API: Test exception handling when calling smtplib.SMTP()

    """
    # Disable Throttling to speed testing
    plugins.NotifyBase.NotifyBase.request_rate_per_sec = 0

    obj = Apprise.instantiate('mailto://*****:*****@gmail.com',
                              suppress_exceptions=False)
    assert (isinstance(obj, plugins.NotifyEmail))

    # Support Exception handling of smtplib.SMTP
    mock_smtplib.side_effect = RuntimeError('Test')

    assert obj.notify(body='body', title='test',
                      notify_type=NotifyType.INFO) is False

    # A handled and expected exception
    mock_smtplib.side_effect = smtplib.SMTPException('Test')
    assert obj.notify(body='body', title='test',
                      notify_type=NotifyType.INFO) is False
def test_object_parsing():
    """
    API: NotifySNS Plugin() Object Parsing

    """

    # Create our object
    a = Apprise()

    # Now test failing variations of our URL
    assert(a.add('sns://') is False)
    assert(a.add('sns://nosecret') is False)
    assert(a.add('sns://nosecret/noregion/') is False)

    # This is valid, but a rather useless URL; there is nothing to notify
    assert(a.add('sns://norecipient/norecipient/us-west-2') is True)
    assert(len(a) == 1)

    # Parse a good one
    assert(a.add('sns://oh/yeah/us-west-2/abcdtopic/+12223334444') is True)
    assert(len(a) == 2)

    assert(a.add('sns://oh/yeah/us-west-2/12223334444') is True)
    assert(len(a) == 3)
Beispiel #29
0
def test_object_parsing():
    """
    API: NotifySNS Plugin() Object Parsing

    """

    # Create our object
    a = Apprise()

    # Now test failing variations of our URL
    assert a.add('sns://') is False
    assert a.add('sns://nosecret') is False
    assert a.add('sns://nosecret/noregion/') is False

    # This is valid but without valid recipients, the URL is actually useless
    assert a.add('sns://norecipient/norecipient/us-west-2') is False
    assert len(a) == 0

    # Parse a good one
    assert a.add('sns://oh/yeah/us-west-2/abcdtopic/+12223334444') is True
    assert len(a) == 1

    assert a.add('sns://oh/yeah/us-west-2/12223334444') is True
    assert len(a) == 2
Beispiel #30
0
def test_pushbullet_attachments(mock_post):
    """
    API: NotifyPushBullet() Attachment Checks

    """
    # Disable Throttling to speed testing
    plugins.NotifyBase.request_rate_per_sec = 0

    # Initialize some generic (but valid) tokens
    access_token = 't' * 32

    # Prepare Mock return object
    response = mock.Mock()
    response.content = dumps({
        "file_name": "cat.jpg",
        "file_type": "image/jpeg",
        "file_url": "https://dl.pushb.com/abc/cat.jpg",
        "upload_url": "https://upload.pushbullet.com/abcd123",
    })
    response.status_code = requests.codes.ok
    mock_post.return_value = response

    # prepare our attachment
    attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))

    # Test our markdown
    obj = Apprise.instantiate(
        'pbul://{}/?format=markdown'.format(access_token))

    # Send a good attachment
    assert obj.notify(body="test", attach=attach) is True

    # Add another attachment so we drop into the area of the PushBullet code
    # that sends remaining attachments (if more detected)
    attach.add(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))

    # Send our attachments
    assert obj.notify(body="test", attach=attach) is True

    # An invalid attachment will cause a failure
    path = os.path.join(TEST_VAR_DIR, '/invalid/path/to/an/invalid/file.jpg')
    attach = AppriseAttachment(path)
    assert obj.notify(body="test", attach=attach) is False

    # Throw an exception on the first call to requests.post()
    mock_post.return_value = None
    mock_post.side_effect = requests.RequestException()

    # We'll fail now because of an internal exception
    assert obj.send(body="test", attach=attach) is False

    # Throw an exception on the second call to requests.post()
    mock_post.side_effect = [response, OSError()]

    # We'll fail now because of an internal exception
    assert obj.send(body="test", attach=attach) is False

    # Throw an exception on the third call to requests.post()
    mock_post.side_effect = [
        response, response, requests.RequestException()]

    # We'll fail now because of an internal exception
    assert obj.send(body="test", attach=attach) is False

    # Throw an exception on the forth call to requests.post()
    mock_post.side_effect = [
        response, response, response, requests.RequestException()]

    # We'll fail now because of an internal exception
    assert obj.send(body="test", attach=attach) is False

    # Test case where we don't get a valid response back
    response.content = '}'
    mock_post.side_effect = response

    # We'll fail because of an invalid json object
    assert obj.send(body="test", attach=attach) is False

    #
    # Test bad responses
    #

    # Prepare a bad response
    response.content = dumps({
        "file_name": "cat.jpg",
        "file_type": "image/jpeg",
        "file_url": "https://dl.pushb.com/abc/cat.jpg",
        "upload_url": "https://upload.pushbullet.com/abcd123",
    })
    bad_response = mock.Mock()
    bad_response.content = response.content
    bad_response.status_code = 400

    # Throw an exception on the third call to requests.post()
    mock_post.return_value = bad_response

    # prepare our attachment
    attach = AppriseAttachment(os.path.join(TEST_VAR_DIR, 'apprise-test.gif'))

    # We'll fail now because we were unable to send the attachment
    assert obj.send(body="test", attach=attach) is False

    # Throw an exception on the second call
    mock_post.side_effect = [response, bad_response, response]
    assert obj.send(body="test", attach=attach) is False

    # Throw an OSError
    mock_post.side_effect = [response, OSError()]
    assert obj.send(body="test", attach=attach) is False

    # Throw an exception on the third call
    mock_post.side_effect = [response, response, bad_response]
    assert obj.send(body="test", attach=attach) is False

    # Throw an exception on the fourth call
    mock_post.side_effect = [response, response, response, bad_response]
    assert obj.send(body="test", attach=attach) is False

    # A good message
    mock_post.side_effect = [response, response, response, response]
    assert obj.send(body="test", attach=attach) is True
Beispiel #31
0
    def notify(self, servers, body, title, notify_type=NotifyType.INFO,
               body_format=NotifyFormat.MARKDOWN):
        """
        processes list of servers specified
        """

        # Decode our data
        body = decode(body)
        title = decode(title)

        # Apprise Asset Object
        asset = AppriseAsset(theme=self.default_theme)
        asset.app_id = 'NZB-Notify'
        asset.app_desc = 'NZB Notification'
        asset.app_url = 'https://github.com/caronc/nzb-notify'

        # Source Theme from GitHub Page
        asset.image_url_mask = 'https://raw.githubusercontent.com' \
                               '/caronc/nzb-notify/master/Notify' \
                               '/apprise-theme/{THEME}/apprise-{TYPE}-{XY}.png'

        asset.image_path_mask = join(
            dirname(__file__),
            'Notify', 'apprise-theme', '{THEME}',
            'apprise-{TYPE}-{XY}.png')

        # Include Image Flag
        _url = self.parse_url(self.get('IncludeImage'))

        # Define some globals to use in this function
        image_path = None
        image_url = None

        if _url:
            # Toggle our include image flag right away to True
            include_image = True

            # Get some more details
            if not re.match('^(https?|file)$', _url['schema'], re.IGNORECASE):
                self.logger.error(
                    'An invalid image url protocol (%s://) was specified.' %
                    _url['schema'],
                )
                return False

            if _url['schema'] == 'file':
                if not isfile(_url['fullpath']):
                    self.logger.error(
                        'The specified file %s was not found.' %
                        _url['fullpath'],
                    )
                    return False
                image_path = _url['fullpath']

            else:
                # We're dealing with a web request
                image_url = _url['url']

        else:
            # Dealing with the old way of doing things; just toggling a
            # true/false flag
            include_image = self.parse_bool(self.get('IncludeImage'), False)

        if isinstance(servers, basestring):
            # servers can be a list of URLs, or it can be
            # a string which will be parsed into this list
            # we wanted.
            servers = self.parse_list(self.get('Servers', ''))

        # Create our apprise object
        a = Apprise(asset=asset)

        for server in servers:

            # Add our URL
            if not a.add(server):
                # Validation Failure
                self.logger.error(
                    'Could not initialize %s instance.' % server,
                )
                continue

        # Notify our servers
        a.notify(body=body, title=title, notify_type=notify_type,
                 body_format=body_format)

        # Always return true
        return True