Skip to content

Commit

Permalink
test cases around most basic functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
jmichalicek committed Nov 18, 2016
1 parent 79c64d0 commit b051ae5
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 22 deletions.
44 changes: 25 additions & 19 deletions jwt_apns_client/jwt_apns_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ class Alert(object):
"""

def __init__(self, *args, **kwargs):
self.title = kwargs.get('title', None)
self.body = kwargs.get('body', None)
self.title_loc_key = kwargs.get('title_loc_key', None)
self.title_loc_args = kwargs.get('title_loc_args', None)
self.action_loc_key = kwargs.get('action_loc_key', None)
self.loc_key = kwargs.get('loc_key', None)
self.loc_args = kwargs.get('loc_args', None)
self.launch_image = kwargs.get('launch_image', None)
self.title = kwargs.pop('title', None)
self.body = kwargs.pop('body', None)
self.title_loc_key = kwargs.pop('title_loc_key', None)
self.title_loc_args = kwargs.pop('title_loc_args', None)
self.action_loc_key = kwargs.pop('action_loc_key', None)
self.loc_key = kwargs.pop('loc_key', None)
self.loc_args = kwargs.pop('loc_args', None)
self.launch_image = kwargs.pop('launch_image', None)
super(Alert, self).__init__(*args, **kwargs)

def get_payload_dict(self):
Expand All @@ -58,21 +58,21 @@ def __init__(self, *args, **kwargs):
:param apns_key_path: (str) Path to file with the apns auth key
:param api_version: (int) The API version. Default is 3
:param topic: (str) The APNs topic
:param environment: (str) development or production. Default is production.
:param environment: (str) development or production. Default is development.
:param api_host: (str) The host for the API. If not specified then defaults to the standard host for
the specified environment.
:param api_port: (int) The port to make the http2 connection on. Default is 443.
"""
self.algorithm = kwargs.get('algorithm', ALGORITHM)
self.team_id = kwargs.get('team_id')
self.apns_key_id = kwargs.get('apns_key_id')
self.apns_key_path = kwargs.get('apns_key_path')
self.api_version = kwargs.get(api_version, 3)
self.algorithm = kwargs.pop('algorithm', ALGORITHM)
self.team_id = kwargs.pop('team_id', None)
self.apns_key_id = kwargs.pop('apns_key_id', None)
self.apns_key_path = kwargs.pop('apns_key_path', None)
self.api_version = kwargs.pop('api_version', 3)
self.secret = self.get_secret()
self.environment = kwargs.get('environment', 'production')
self.api_host = kwargs.get('api_host',
self.environment = kwargs.pop('environment', APNSEnvironments.DEV)
self.api_host = kwargs.pop('api_host',
PROD_API_HOST if self.environment == APNSEnvironments.PROD else DEV_API_HOST)
self.api_port = kwargs.get('api_port', 443)
self.api_port = kwargs.pop('api_port', 443)
self._conn = None
super(APNSConnection, self).__init__(*args, **kwargs)

Expand Down Expand Up @@ -120,8 +120,8 @@ def get_payload_data(self, alert=None, badge=None, sound=None, content=None, cat

def get_request_headers(self, token=None, topic=None, priority=10, expiration=0):
"""
See https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1
for details on topic, expiration, and priority values.
See details on topic, expiration, priority values, etc. at
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1
:param token: the jwt token
:param topic: the message topic
Expand All @@ -142,6 +142,8 @@ def get_request_headers(self, token=None, topic=None, priority=10, expiration=0)
'authorization': 'bearer %s' % token.decode('ascii')
}

return request_headers

def get_request_payload(self, alert=None, badge=None, sound=None, content=None, category=None, thread=None):
"""
Returns the request payload as utf-8 encoded json
Expand Down Expand Up @@ -222,6 +224,9 @@ def send_notification(self, device_registration_id, **kwargs):
headers = self.get_request_headers()
payload = self.get_request_payload(**kwargs)
path = u'/%d/device/%s' % (self.api_version, device_registration_id)

# TODO: what if the connection has timed out? Should this automatically create a new one? Probably.
# Can that be detected in self.connection ?
conn = self.connection
conn.request(
'POST',
Expand All @@ -238,6 +243,7 @@ def send_notification(self, device_registration_id, **kwargs):
reason = data_dict.get('reason', '')
notification_response = NotificationResponse(status=status, reason=reason, host=conn.host, port=conn.port,
path=path, payload=payload, headers=headers)
return notification_response


class NotificationResponse(object):
Expand Down
2 changes: 2 additions & 0 deletions requirements_py2_dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# python 2 specific dev requirements
mock==2.0.0
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ universal = 1

[flake8]
exclude = docs
max-line-length = 120
3 changes: 3 additions & 0 deletions tests/test_files/apns_key.p8
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
INVALID_FAKE_KEY
-----END PRIVATE KEY-----
165 changes: 163 additions & 2 deletions tests/test_jwt_apns_client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals, absolute_import, print_function, division

"""
test_jwt_apns_client
Expand All @@ -9,16 +10,21 @@
"""


import os
import sys
import unittest
from contextlib import contextmanager
from click.testing import CliRunner

try:
from unittest import mock
except ImportError:
import mock

from jwt_apns_client import jwt_apns_client
from jwt_apns_client import cli



class TestJwt_apns_client(unittest.TestCase):

def setUp(self):
Expand All @@ -37,4 +43,159 @@ def test_command_line_interface(self):
assert 'jwt_apns_client.cli.main' in result.output
help_result = runner.invoke(cli.main, ['--help'])
assert help_result.exit_code == 0
assert '--help Show this message and exit.' in help_result.output
assert '--help Show this message and exit.' in help_result.output

def test_module_constants(self):
assert 'ES256' == jwt_apns_client.ALGORITHM
assert 'api.push.apple.com' == jwt_apns_client.PROD_API_HOST
assert 'api.development.push.apple.com' == jwt_apns_client.DEV_API_HOST
assert '443' == jwt_apns_client.API_PORT


class AlertTest(unittest.TestCase):

def test_init_params(self):
"""
Test that the passed in params set the expected object attributes.
"""
alert = jwt_apns_client.Alert(title='title', body='body', title_loc_key='title_loc_key',
title_loc_args=[1, 2], action_loc_key='action_loc_key', loc_key='loc_key',
loc_args=[3, 4], launch_image='launch_image.png')
self.assertEqual('title', alert.title)
self.assertEqual('body', alert.body)
self.assertEqual('title_loc_key', alert.title_loc_key)
self.assertEqual([1, 2], alert.title_loc_args)
self.assertEqual('action_loc_key', alert.action_loc_key)
self.assertEqual('loc_key', alert.loc_key)
self.assertEqual([3, 4], alert.loc_args)
self.assertEqual('launch_image.png', alert.launch_image)

def test_get_payload_dict(self):
"""
A dict of the data in the object should be returned. Paramters with underscores should be converted
to hyphens in the dict keys.
"""
alert = jwt_apns_client.Alert(title='title', body='body', title_loc_key='title_loc_key',
title_loc_args=[1, 2], action_loc_key='action_loc_key', loc_key='loc_key',
loc_args=[3, 4], launch_image='launch_image.png')
expected = {
'title': 'title', 'body': 'body', 'title-loc-key': 'title_loc_key', 'title-loc-args': [1, 2],
'action-loc-key': 'action_loc_key', 'loc-key': 'loc_key', 'loc-args': [3, 4],
'launch-image': 'launch_image.png'
}
self.assertEqual(expected, alert.get_payload_dict())


class NotificationResponseTest(unittest.TestCase):
def test_init_params(self):
"""
Test that the passed in params set the expected object attributes.
"""
notification = jwt_apns_client.NotificationResponse(status=400, reason='reason', host='api.example.org', port=80,
path='/api/3/device/12345asdf', payload='payload',
headers={'h': '1'})
self.assertEqual(400, notification.status)
self.assertEqual('reason', notification.reason)
self.assertEqual('api.example.org', notification.host)
self.assertEqual(80, notification.port)
self.assertEqual('/api/3/device/12345asdf', notification.path)
self.assertEqual('payload', notification.payload)
self.assertEqual({'h': '1'}, notification.headers)

def test_init_params_default(self):
"""
Test the default init params
"""
notification = jwt_apns_client.NotificationResponse()
self.assertEqual(200, notification.status)
self.assertEqual('', notification.reason)
self.assertEqual('', notification.host)
self.assertEqual(443, notification.port)
self.assertEqual('', notification.path)
self.assertEqual(None, notification.payload)
self.assertEqual(None, notification.headers)


class APNSConnectionTest(unittest.TestCase):
TESTS_DIR = os.path.dirname(os.path.abspath(__file__))
FILES_DIR = os.path.join(TESTS_DIR, 'test_files')
KEY_FILE_PATH = os.path.join(FILES_DIR, 'apns_key.p8')

def test_init_params(self):
"""
Test that the passed in params set the expected object attributes.
"""

expected_secret = (
'-----BEGIN PRIVATE KEY-----\n'
'INVALID_FAKE_KEY\n'
'-----END PRIVATE KEY-----\n'
)
connection = jwt_apns_client.APNSConnection(algorithm='HS256',
team_id='TEAMID',
apns_key_id='asdf1234',
apns_key_path=self.KEY_FILE_PATH,
api_version=2, # not a value we would really want to pass
environment=jwt_apns_client.APNSEnvironments.PROD,
api_host='api.example.org',
api_port=442)
self.assertEqual('HS256', connection.algorithm)
self.assertEqual('TEAMID', connection.team_id)
self.assertEqual('asdf1234', connection.apns_key_id)
self.assertEqual(self.KEY_FILE_PATH, connection.apns_key_path)
self.assertEqual(2, connection.api_version)
self.assertEqual('prod', connection.environment)
self.assertEqual('api.example.org', connection.api_host)
self.assertEqual(442, connection.api_port)
self.assertEqual(expected_secret, connection.secret)
self.assertEqual(None, connection._conn)

def test_init_params_default(self):
"""
Test the default init params
"""
connection = jwt_apns_client.APNSConnection()
self.assertEqual('ES256', connection.algorithm)
self.assertEqual(None, connection.team_id)
self.assertEqual(None, connection.apns_key_id)
self.assertEqual(None, connection.apns_key_path)
self.assertEqual(3, connection.api_version)
self.assertEqual('dev', connection.environment)
self.assertEqual('api.development.push.apple.com', connection.api_host)
self.assertEqual(443, connection.api_port)
self.assertEqual('', connection.secret)
self.assertEqual(None, connection._conn)

def test_send_notification(self):
pass

def test_get_token_headers(self):
pass

def test_get_secret(self):
pass

def test_get_request_token(self):
pass

def test_get_request_payload(self):
pass

def test_get_request_headers(self):
pass

def test_get_payload_data(self):
pass

def test_connection_not_cached(self):
"""
Test that if we do not already have a connection, self.connection creates and returns an HTTPConnection
"""
pass

def test_connection_cached(self):
"""
Test that if we already have a connection, self.connection returns the existing HTTPConnection without
creating a new one
"""
pass
6 changes: 5 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
[tox]
envlist = py26, py27, py33, py34, py35, flake8
envlist = py27, py34, py35, flake8

[testenv:flake8]
basepython=python
deps=flake8
commands=flake8 jwt_apns_client

[testenv:py27]
deps =
-r{toxinidir}/requirements_py2_dev.txt

[testenv]
setenv =
PYTHONPATH = {toxinidir}:{toxinidir}/jwt_apns_client
Expand Down

0 comments on commit b051ae5

Please sign in to comment.