def setUp(self, fgcm): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) self.gcm_config = {'s3_bucket': 'None', 'max_data': 32, 'ttl': 60, 'senderid_list': {'test123': {"auth": "12345678abcdefg"}}} self.gcm = fgcm self.router = GCMRouter(settings, self.gcm_config) self.headers = {"content-encoding": "aesgcm", "encryption": "test", "encryption-key": "test"} # Payloads are Base64-encoded. self.notif = Notification(10, "q60d6g", dummy_chid, self.headers, 200) self.router_data = dict( router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg"))) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result fgcm.send.return_value = mock_result
def setUp(self): conf = AutopushConfig( hostname="localhost", statsd_host=None, ) self.gcm_config = { 'max_data': 32, 'ttl': 60, 'senderIDs': { 'test123': { "auth": "12345678abcdefg" } } } self.response = Mock(spec=requests.Response) self.response.status_code = 200 self.response.headers = dict() self.response.content = json.dumps({ "multicast_id": 5174939174563864884, "success": 1, "failure": 0, "canonical_ids": 0, "results": [{ "message_id": "0:1510011451922224%7a0e7efbaab8b7cc" }] }) self.gcm = gcmclient.GCM(api_key="SomeKey") self.gcm._sender = Mock(return_value=self.response) self.router = GCMRouter(conf, self.gcm_config, SinkMetrics()) self.router.gcm['test123'] = self.gcm self.headers = { "content-encoding": "aesgcm", "encryption": "test", "encryption-key": "test" } # Payloads are Base64-encoded. self.notif = WebPushNotification( uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="q60d6g", headers=self.headers, ttl=200, message_id=10, ) self.notif.cleanup_headers() self.router_data = dict(router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg")))
def test_init(self): conf = AutopushConfig( hostname="localhost", statsd_host=None, ) with pytest.raises(IOError): GCMRouter(conf, {"senderIDs": {}}, SinkMetrics())
def test_init(self): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) with assert_raises(IOError): GCMRouter(settings, {"senderIDs": {}})
def setUp(self, fgcm): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) self.gcm_config = {'s3_bucket': 'None', 'max_data': 32, 'senderid_list': {'test123': {"auth": "12345678abcdefg"}}} self.gcm = fgcm self.router = GCMRouter(settings, self.gcm_config) self.headers = {"content-encoding": "aesgcm", "encryption": "test", "encryption-key": "test"} # Data will most likely be binary values. self.notif = Notification(10, "\xab\xad\x1d\xea", dummy_chid, self.headers, 200) self.router_data = dict( router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg"))) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result fgcm.send.return_value = mock_result
def test_gcmclient_fail(self, fgcm): fgcm.side_effect = Exception settings = AutopushSettings( hostname="localhost", statsd_host=None, ) with assert_raises(IOError): GCMRouter(settings, {"senderIDs": {"test123": {"auth": "abcd"}}})
def setUp(self, fgcm): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) self.gcm_config = { 'max_data': 32, 'ttl': 60, 'senderIDs': { 'test123': { "auth": "12345678abcdefg" } } } self.gcm = fgcm self.router = GCMRouter(settings, self.gcm_config) self.headers = { "content-encoding": "aesgcm", "encryption": "test", "encryption-key": "test" } # Payloads are Base64-encoded. self.notif = WebPushNotification( uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="q60d6g", headers=self.headers, ttl=200, message_id=10, ) self.notif.cleanup_headers() self.router_data = dict(router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg"))) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result fgcm.send.return_value = mock_result
def setUp(self, fgcm): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) gcm_config = {'s3_bucket': 'None', 'senderid_list': {'test123': {"auth": "12345678abcdefg"}}} self.gcm = fgcm self.router = GCMRouter(settings, gcm_config) self.notif = Notification(10, "data", dummy_chid, None, 200) self.router_data = dict( router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg"))) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result fgcm.send.return_value = mock_result
def setUp(self): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) # Mock out GCM client self._old_gcm = gcmclient.GCM gcmclient.GCM = Mock(spec=gcmclient.GCM) gcm_config = {'apikey': '12345678abcdefg'} self.router = GCMRouter(settings, gcm_config) self.notif = Notification(10, "data", dummy_chid) self.router_data = dict(router_data=dict(token="connect_data")) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result self.router.gcm.send.return_value = mock_result
class GCMRouterTestCase(unittest.TestCase): def setUp(self): conf = AutopushConfig( hostname="localhost", statsd_host=None, ) self.gcm_config = { 'max_data': 32, 'ttl': 60, 'senderIDs': { 'test123': { "auth": "12345678abcdefg" } } } self.response = Mock(spec=requests.Response) self.response.status_code = 200 self.response.headers = dict() self.response.content = json.dumps({ "multicast_id": 5174939174563864884, "success": 1, "failure": 0, "canonical_ids": 0, "results": [{ "message_id": "0:1510011451922224%7a0e7efbaab8b7cc" }] }) self.gcm = gcmclient.GCM(api_key="SomeKey") self.gcm._sender = Mock(return_value=self.response) self.router = GCMRouter(conf, self.gcm_config, SinkMetrics()) self.router.gcm['test123'] = self.gcm self.headers = { "content-encoding": "aesgcm", "encryption": "test", "encryption-key": "test" } # Payloads are Base64-encoded. self.notif = WebPushNotification( uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="q60d6g", headers=self.headers, ttl=200, message_id=10, ) self.notif.cleanup_headers() self.router_data = dict(router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg"))) def _check_error_call(self, exc, code, response=None, errno=None): assert isinstance(exc, RouterException) assert exc.status_code == code if errno is not None: assert exc.errno == errno assert self.gcm._sender.called if response: assert exc.response_body == response self.flushLoggedErrors() def test_init(self): conf = AutopushConfig( hostname="localhost", statsd_host=None, ) with pytest.raises(IOError): GCMRouter(conf, {"senderIDs": {}}, SinkMetrics()) def test_register(self): router_data = {"token": "test123"} self.router.register("uaid", router_data=router_data, app_id="test123") # Check the information that will be recorded for this user assert router_data == { "token": "test123", "creds": { "senderID": "test123", "auth": "12345678abcdefg" } } def test_register_bad(self): with pytest.raises(RouterException): self.router.register("uaid", router_data={}, app_id="") with pytest.raises(RouterException): self.router.register("uaid", router_data={}, app_id=None) with pytest.raises(RouterException): self.router.register("uaid", router_data={"token": "abcd1234"}, app_id="invalid123") def test_route_notification(self): self.router.gcm['test123'] = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): assert isinstance(result, RouterResponse) assert self.gcm._sender.called # Make sure the data was encoded as base64 payload = json.loads(self.gcm._sender.call_args[1]['data']) data = payload['data'] assert data['body'] == 'q60d6g' assert data['enc'] == 'test' assert data['chid'] == dummy_chid assert data['enckey'] == 'test' assert data['con'] == 'aesgcm' d.addCallback(check_results) return d def test_ttl_none(self): self.router.gcm['test123'] = self.gcm self.notif = WebPushNotification(uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="q60d6g", headers=self.headers, ttl=None) self.notif.cleanup_headers() d = self.router.route_notification(self.notif, self.router_data) def check_results(result): assert isinstance(result, RouterResponse) assert result.status_code == 201 assert result.logged_status == 200 assert "TTL" in result.headers assert self.gcm._sender.called # Make sure the data was encoded as base64 payload = json.loads(self.gcm._sender.call_args[1]['data']) data = payload['data'] assert data['body'] == 'q60d6g' assert data['enc'] == 'test' assert data['chid'] == dummy_chid assert data['enckey'] == 'test' assert data['con'] == 'aesgcm' # use the defined min TTL assert payload['time_to_live'] == 60 d.addCallback(check_results) return d def test_ttl_high(self): self.router.gcm['test123'] = self.gcm self.notif = WebPushNotification(uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="q60d6g", headers=self.headers, ttl=5184000) self.notif.cleanup_headers() d = self.router.route_notification(self.notif, self.router_data) def check_results(result): assert isinstance(result, RouterResponse) assert self.gcm._sender.called # Make sure the data was encoded as base64 payload = json.loads(self.gcm._sender.call_args[1]['data']) data = payload['data'] assert data['body'] == 'q60d6g' assert data['enc'] == 'test' assert data['chid'] == dummy_chid assert data['enckey'] == 'test' assert data['con'] == 'aesgcm' # use the defined min TTL assert payload['time_to_live'] == 2419200 d.addCallback(check_results) return d def test_long_data(self): self.router.gcm['test123'] = self.gcm bad_notif = WebPushNotification( uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="\x01abcdefghijklmnopqrstuvwxyz0123456789", headers=self.headers, ttl=200) d = self.router.route_notification(bad_notif, self.router_data) def check_results(result): assert isinstance(result.value, RouterException) assert result.value.status_code == 413 assert result.value.errno == 104 d.addBoth(check_results) return d def test_route_crypto_notification(self): del (self.notif.headers['encryption_key']) self.notif.headers['crypto_key'] = 'crypto' d = self.router.route_notification(self.notif, self.router_data) def check_results(result): assert isinstance(result, RouterResponse) assert self.gcm._sender.called d.addCallback(check_results) return d def test_router_notification_gcm_auth_error(self): self.response.status_code = 401 d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500, "Server error", 901) d.addBoth(check_results) return d def test_router_notification_gcm_other_error(self): self.gcm._sender.side_effect = Exception d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500, "Server error") d.addBoth(check_results) return d def test_router_notification_connection_error(self): from requests.exceptions import ConnectionError def throw_other(*args, **kwargs): raise ConnectionError("oh my!") self.gcm._sender.side_effect = throw_other self.router.gcm['test123'] = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 502, "Server error", 902) d.addBoth(check_results) return d def test_router_notification_gcm_id_change(self): self.response.content = json.dumps({ "multicast_id": 5174939174563864884, "success": 1, "failure": 0, "canonical_ids": 1, "results": [{ "message_id": "0:1510011451922224%7a0e7efbaab8b7cc", "registration_id": "new", }] }) self.router.metrics = Mock() d = self.router.route_notification(self.notif, self.router_data) def check_results(result): assert isinstance(result, RouterResponse) assert result.router_data == dict(token="new") assert self.router.metrics.increment.call_args[0][0] == ( 'notification.bridge.error') self.router.metrics.increment.call_args[1]['tags'].sort() assert self.router.metrics.increment.call_args[1]['tags'] == [ 'platform:gcm', 'reason:reregister' ] assert self.gcm._sender.called d.addCallback(check_results) return d def test_router_notification_gcm_not_regged(self): self.response.content = json.dumps({ "multicast_id": 5174939174563864884, "success": 1, "failure": 1, "canonical_ids": 0, "results": [{ "error": "NotRegistered" }] }) self.router.metrics = Mock() d = self.router.route_notification(self.notif, self.router_data) def check_results(result): assert isinstance(result, RouterResponse) assert result.router_data == dict() assert self.router.metrics.increment.call_args[0][0] == ( 'notification.bridge.error') self.router.metrics.increment.call_args[1]['tags'].sort() assert self.router.metrics.increment.call_args[1]['tags'] == [ 'platform:gcm', 'reason:unregistered' ] assert self.gcm._sender.called d.addCallback(check_results) return d def test_router_notification_gcm_failed_items(self): self.response.content = json.dumps({ "multicast_id": 5174939174563864884, "success": 1, "failure": 1, "canonical_ids": 0, "results": [{ "error": "InvalidRegistration" }] }) self.router.metrics = Mock() d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): assert self.router.metrics.increment.called assert self.router.metrics.increment.call_args[0][0] == ( 'notification.bridge.error') self.router.metrics.increment.call_args[1]['tags'].sort() assert self.router.metrics.increment.call_args[1]['tags'] == [ 'platform:gcm', 'reason:failure' ] assert fail.value.message == 'GCM unable to deliver' self._check_error_call(fail.value, 410) d.addBoth(check_results) return d def test_router_notification_gcm_needs_retry(self): self.response.headers['Retry-After'] = "123" self.response.status_code = 500 self.response.content = "" self.router.metrics = Mock() d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): assert self.router.metrics.increment.called assert self.router.metrics.increment.call_args[0][0] == ( 'notification.bridge.error') self.router.metrics.increment.call_args[1]['tags'].sort() assert self.router.metrics.increment.call_args[1]['tags'] == [ 'platform:gcm', 'reason:retry' ] assert fail.value.message == 'GCM failure to deliver, retry' self._check_error_call(fail.value, 503) d.addBoth(check_results) return d def test_router_notification_gcm_no_auth(self): d = self.router.route_notification(self.notif, {"router_data": { "token": "abc" }}) def check_results(fail): assert isinstance(fail.value, RouterException) assert fail.value.message == "Server error" assert fail.value.status_code == 500 assert fail.value.errno == 900 d.addBoth(check_results) return d def test_amend(self): router_data = {"token": "test123"} self.router.register("uaid", router_data=router_data, app_id="test123") resp = {"key": "value"} self.router.amend_endpoint_response( resp, self.router_data.get('router_data')) assert {"key": "value", "senderid": "test123"} == resp def test_register_invalid_token(self): with pytest.raises(RouterException): self.router.register(uaid="uaid", router_data={"token": "invalid"}, app_id="invalid")
class GCMRouterTestCase(unittest.TestCase): @patch("gcmclient.gcm.GCM", spec=gcmclient.gcm.GCM) def setUp(self, fgcm): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) gcm_config = {'s3_bucket': 'None', 'senderid_list': {'test123': {"auth": "12345678abcdefg"}}} self.gcm = fgcm self.router = GCMRouter(settings, gcm_config) self.notif = Notification(10, "data", dummy_chid, None, 200) self.router_data = dict( router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg"))) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result fgcm.send.return_value = mock_result def tearDown(self): self.router.senderIDs.stop() def _check_error_call(self, exc, code): ok_(isinstance(exc, RouterException)) eq_(exc.status_code, code) assert(self.router.gcm.send.called) self.flushLoggedErrors() def test_init(self): self.router.senderIDs.get_ID = Mock() def throw_ex(): raise AttributeError fsenderids = Mock() fsenderids.choose_ID.side_effect = throw_ex self.assertRaises(IOError, GCMRouter, {}, {"senderIDs": fsenderids}) def test_register(self): result = self.router.register("uaid", {"token": "connect_data"}) # Check the information that will be recorded for this user eq_(result, {"token": "connect_data", "creds": {"senderID": "test123", "auth": "12345678abcdefg"}}) def test_register_bad(self): self.assertRaises(RouterException, self.router.register, "uaid", {}) def test_route_notification(self): self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) assert(self.router.gcm.send.called) d.addCallback(check_results) return d def test_router_notification_gcm_auth_error(self): def throw_auth(arg): raise gcmclient.GCMAuthenticationError() self.gcm.send.side_effect = throw_auth self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500) d.addBoth(check_results) return d def test_router_notification_gcm_other_error(self): def throw_other(arg): raise Exception("oh my!") self.gcm.send.side_effect = throw_other self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500) d.addBoth(check_results) return d def test_router_notification_gcm_id_change(self): self.mock_result.canonical["old"] = "new" self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict(token="new")) assert(self.router.gcm.send.called) d.addCallback(check_results) return d def test_router_notification_gcm_not_regged(self): self.mock_result.not_registered = {"connect_data": True} self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict()) assert(self.router.gcm.send.called) d.addCallback(check_results) return d def test_router_notification_gcm_failed_items(self): self.mock_result.failed = dict(connect_data=True) self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 503) d.addBoth(check_results) return d def test_router_notification_gcm_needs_retry(self): self.mock_result.needs_retry.return_value = True self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 503) d.addBoth(check_results) return d def test_router_notification_gcm_no_auth(self): d = self.router.route_notification(self.notif, {"router_data": {"token": "abc"}}) def check_results(fail): eq_(fail.value.status_code, 500) d.addBoth(check_results) return d def test_ammend(self): self.router.register("uaid", {"token": "connect_data"}) resp = {"key": "value"} eq_({"key": "value", "senderid": "test123"}, self.router.amend_msg(resp))
def __init__( self, crypto_key=None, datadog_api_key=None, datadog_app_key=None, datadog_flush_interval=None, hostname=None, port=None, router_scheme=None, router_hostname=None, router_port=None, endpoint_scheme=None, endpoint_hostname=None, endpoint_port=None, router_conf={}, router_tablename="router", router_read_throughput=5, router_write_throughput=5, storage_tablename="storage", storage_read_throughput=5, storage_write_throughput=5, message_tablename="message", message_read_throughput=5, message_write_throughput=5, statsd_host="localhost", statsd_port=8125, resolve_hostname=False, max_data=4096, # Reflected up from UDP Router wake_timeout=0, env='development', enable_cors=False, s3_bucket=DEFAULT_BUCKET, senderid_expry=SENDERID_EXPRY, senderid_list={}, hello_timeout=0, ): """Initialize the Settings object Upon creation, the HTTP agent will initialize, all configured routers will be setup and started, logging will be started, and the database will have a preflight check done. """ # Use a persistent connection pool for HTTP requests. pool = HTTPConnectionPool(reactor) self.agent = Agent(reactor, connectTimeout=5, pool=pool) # Metrics setup if datadog_api_key: self.metrics = DatadogMetrics( api_key=datadog_api_key, app_key=datadog_app_key, flush_interval=datadog_flush_interval) elif statsd_host: self.metrics = TwistedMetrics(statsd_host, statsd_port) else: self.metrics = SinkMetrics() if not crypto_key: crypto_key = [Fernet.generate_key()] if not isinstance(crypto_key, list): crypto_key = [crypto_key] self.update(crypto_key=crypto_key) self.crypto_key = crypto_key self.max_data = max_data self.clients = {} # Setup hosts/ports/urls default_hostname = socket.gethostname() self.hostname = hostname or default_hostname if resolve_hostname: self.hostname = resolve_ip(self.hostname) self.port = port self.endpoint_hostname = endpoint_hostname or self.hostname self.router_hostname = router_hostname or self.hostname self.router_conf = router_conf self.router_url = canonical_url(router_scheme or 'http', self.router_hostname, router_port) self.endpoint_url = canonical_url(endpoint_scheme or 'http', self.endpoint_hostname, endpoint_port) # Database objects self.router_table = get_router_table(router_tablename, router_read_throughput, router_write_throughput) self.storage_table = get_storage_table(storage_tablename, storage_read_throughput, storage_write_throughput) self.message_table = get_message_table(message_tablename, message_read_throughput, message_write_throughput) self.storage = Storage(self.storage_table, self.metrics) self.router = Router(self.router_table, self.metrics) self.message = Message(self.message_table, self.metrics) # Run preflight check preflight_check(self.storage, self.router) # CORS self.cors = enable_cors # Force timeout in idle seconds self.wake_timeout = wake_timeout # Setup the routers self.routers = {} self.routers["simplepush"] = SimpleRouter( self, router_conf.get("simplepush")) self.routers["webpush"] = WebPushRouter(self, None) if 'apns' in router_conf: self.routers["apns"] = APNSRouter(self, router_conf["apns"]) if 'gcm' in router_conf: self.routers["gcm"] = GCMRouter(self, router_conf["gcm"]) # Env self.env = env self.hello_timeout = hello_timeout
class GCMRouterTestCase(unittest.TestCase): @patch("gcmclient.gcm.GCM", spec=gcmclient.gcm.GCM) def setUp(self, fgcm): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) self.gcm_config = { 'max_data': 32, 'ttl': 60, 'senderIDs': { 'test123': { "auth": "12345678abcdefg" } } } self.gcm = fgcm self.router = GCMRouter(settings, self.gcm_config) self.headers = { "content-encoding": "aesgcm", "encryption": "test", "encryption-key": "test" } # Payloads are Base64-encoded. self.notif = WebPushNotification( uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="q60d6g", headers=self.headers, ttl=200, message_id=10, ) self.notif.cleanup_headers() self.router_data = dict(router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg"))) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result fgcm.send.return_value = mock_result def _check_error_call(self, exc, code, response=None): ok_(isinstance(exc, RouterException)) eq_(exc.status_code, code) ok_(self.router.gcm['test123'].send.called) if response: eq_(exc.response_body, response) self.flushLoggedErrors() def test_init(self): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) with assert_raises(IOError): GCMRouter(settings, {"senderIDs": {}}) def test_register(self): router_data = {"token": "test123"} self.router.register("uaid", router_data=router_data, app_id="test123") # Check the information that will be recorded for this user eq_( router_data, { "token": "test123", "creds": { "senderID": "test123", "auth": "12345678abcdefg" } }) def test_register_bad(self): with assert_raises(RouterException): self.router.register("uaid", router_data={}, app_id="") with assert_raises(RouterException): self.router.register("uaid", router_data={}, app_id='') with assert_raises(RouterException): self.router.register("uaid", router_data={"token": "abcd1234"}, app_id="invalid123") @patch("gcmclient.GCM") def test_gcmclient_fail(self, fgcm): fgcm.side_effect = Exception settings = AutopushSettings( hostname="localhost", statsd_host=None, ) with assert_raises(IOError): GCMRouter(settings, {"senderIDs": {"test123": {"auth": "abcd"}}}) def test_route_notification(self): self.router.gcm['test123'] = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) ok_(self.router.gcm['test123'].send.called) # Make sure the data was encoded as base64 data = self.router.gcm['test123'].send.call_args[0][0].data eq_(data['body'], 'q60d6g') eq_(data['enc'], 'test') eq_(data['chid'], dummy_chid) eq_(data['enckey'], 'test') eq_(data['con'], 'aesgcm') d.addCallback(check_results) return d def test_ttl_none(self): self.router.gcm['test123'] = self.gcm self.notif = WebPushNotification(uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="q60d6g", headers=self.headers, ttl=None) self.notif.cleanup_headers() d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.status_code, 201) eq_(result.logged_status, 200) ok_("TTL" in result.headers) ok_(self.router.gcm['test123'].send.called) # Make sure the data was encoded as base64 data = self.router.gcm['test123'].send.call_args[0][0].data options = self.router.gcm['test123'].send.call_args[0][0].options eq_(data['body'], 'q60d6g') eq_(data['enc'], 'test') eq_(data['chid'], dummy_chid) eq_(data['enckey'], 'test') eq_(data['con'], 'aesgcm') # use the defined min TTL eq_(options['time_to_live'], 60) d.addCallback(check_results) return d def test_ttl_high(self): self.router.gcm['test123'] = self.gcm self.notif = WebPushNotification(uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="q60d6g", headers=self.headers, ttl=5184000) self.notif.cleanup_headers() d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) ok_(self.router.gcm['test123'].send.called) # Make sure the data was encoded as base64 data = self.router.gcm['test123'].send.call_args[0][0].data options = self.router.gcm['test123'].send.call_args[0][0].options eq_(data['body'], 'q60d6g') eq_(data['enc'], 'test') eq_(data['chid'], dummy_chid) eq_(data['enckey'], 'test') eq_(data['con'], 'aesgcm') # use the defined min TTL eq_(options['time_to_live'], 2419200) d.addCallback(check_results) return d def test_long_data(self): self.router.gcm['test123'] = self.gcm bad_notif = WebPushNotification( uaid=uuid.UUID(dummy_uaid), channel_id=uuid.UUID(dummy_chid), data="\x01abcdefghijklmnopqrstuvwxyz0123456789", headers=self.headers, ttl=200) d = self.router.route_notification(bad_notif, self.router_data) def check_results(result): ok_(isinstance(result.value, RouterException)) eq_(result.value.status_code, 413) eq_(result.value.errno, 104) d.addBoth(check_results) return d def test_route_crypto_notification(self): self.router.gcm['test123'] = self.gcm del (self.notif.headers['encryption_key']) self.notif.headers['crypto_key'] = 'crypto' d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) ok_(self.router.gcm['test123'].send.called) d.addCallback(check_results) return d def test_router_notification_gcm_auth_error(self): def throw_auth(arg): raise gcmclient.GCMAuthenticationError() self.gcm.send.side_effect = throw_auth self.router.gcm['test123'] = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500, "Server error") d.addBoth(check_results) return d def test_router_notification_gcm_other_error(self): def throw_other(arg): raise Exception("oh my!") self.gcm.send.side_effect = throw_other self.router.gcm['test123'] = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500, "Server error") d.addBoth(check_results) return d def test_router_notification_connection_error(self): from requests.exceptions import ConnectionError def throw_other(*args, **kwargs): raise ConnectionError("oh my!") self.gcm.send.side_effect = throw_other self.router.gcm['test123'] = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 502, "Server error") d.addBoth(check_results) return d def test_router_notification_gcm_id_change(self): self.mock_result.canonical["old"] = "new" self.router.gcm['test123'] = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict(token="new")) ok_(self.router.gcm['test123'].send.called) d.addCallback(check_results) return d def test_router_notification_gcm_not_regged(self): self.mock_result.not_registered = {"connect_data": True} self.router.gcm['test123'] = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict()) ok_(self.router.gcm['test123'].send.called) d.addCallback(check_results) return d def test_router_notification_gcm_failed_items(self): self.mock_result.failed = dict(connect_data=True) self.router.gcm['test123'] = self.gcm self.router.metrics = Mock() d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): ok_(self.router.metrics.increment.called) eq_(self.router.metrics.increment.call_args[0][0], 'updates.client.bridge.gcm.failed.failure') eq_(fail.value.message, 'GCM unable to deliver') self._check_error_call(fail.value, 410) d.addBoth(check_results) return d def test_router_notification_gcm_needs_retry(self): self.mock_result.needs_retry.return_value = True self.router.gcm['test123'] = self.gcm self.router.metrics = Mock() d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): ok_(self.router.metrics.increment.called) eq_(self.router.metrics.increment.call_args[0][0], 'updates.client.bridge.gcm.failed.retry') eq_(fail.value.message, 'GCM failure to deliver, retry') self._check_error_call(fail.value, 503) d.addBoth(check_results) return d def test_router_notification_gcm_no_auth(self): d = self.router.route_notification(self.notif, {"router_data": { "token": "abc" }}) def check_results(fail): eq_(fail.value.status_code, 500, "Server error") d.addBoth(check_results) return d def test_amend(self): router_data = {"token": "test123"} self.router.register("uaid", router_data=router_data, app_id="test123") resp = {"key": "value"} self.router.amend_endpoint_response( resp, self.router_data.get('router_data')) eq_({"key": "value", "senderid": "test123"}, resp) def test_register_invalid_token(self): with assert_raises(RouterException): self.router.register(uaid="uaid", router_data={"token": "invalid"}, app_id="invalid")
def __init__( self, crypto_key=None, datadog_api_key=None, datadog_app_key=None, datadog_flush_interval=None, hostname=None, port=None, router_scheme=None, router_hostname=None, router_port=None, endpoint_scheme=None, endpoint_hostname=None, endpoint_port=None, router_conf=None, router_tablename="router", router_read_throughput=5, router_write_throughput=5, storage_tablename="storage", storage_read_throughput=5, storage_write_throughput=5, message_tablename="message", message_read_throughput=5, message_write_throughput=5, statsd_host="localhost", statsd_port=8125, resolve_hostname=False, max_data=4096, # Reflected up from UDP Router wake_timeout=0, env='development', enable_cors=False, hello_timeout=0, bear_hash_key=None, preflight_uaid="deadbeef00000000deadbeef00000000", ami_id=None, client_certs=None, msg_limit=100, debug=False, connect_timeout=0.5, ): """Initialize the Settings object Upon creation, the HTTP agent will initialize, all configured routers will be setup and started, logging will be started, and the database will have a preflight check done. """ # Use a persistent connection pool for HTTP requests. pool = HTTPConnectionPool(reactor) if not debug: pool._factory = QuietClientFactory self.agent = Agent(reactor, connectTimeout=connect_timeout, pool=pool) if not crypto_key: crypto_key = [Fernet.generate_key()] if not isinstance(crypto_key, list): crypto_key = [crypto_key] self.update(crypto_key=crypto_key) self.crypto_key = crypto_key if bear_hash_key is None: bear_hash_key = [] if not isinstance(bear_hash_key, list): bear_hash_key = [bear_hash_key] self.bear_hash_key = bear_hash_key self.max_data = max_data self.clients = {} # Setup hosts/ports/urls default_hostname = socket.gethostname() self.hostname = hostname or default_hostname if resolve_hostname: self.hostname = resolve_ip(self.hostname) # Metrics setup if datadog_api_key: self.metrics = DatadogMetrics( hostname=self.hostname, api_key=datadog_api_key, app_key=datadog_app_key, flush_interval=datadog_flush_interval, ) elif statsd_host: self.metrics = TwistedMetrics(statsd_host, statsd_port) else: self.metrics = SinkMetrics() self.port = port self.endpoint_hostname = endpoint_hostname or self.hostname self.router_hostname = router_hostname or self.hostname if router_conf is None: router_conf = {} self.router_conf = router_conf self.router_url = canonical_url(router_scheme or 'http', self.router_hostname, router_port) self.endpoint_url = canonical_url(endpoint_scheme or 'http', self.endpoint_hostname, endpoint_port) self.enable_tls_auth = client_certs is not None self.client_certs = client_certs # Database objects self.router_table = get_router_table(router_tablename, router_read_throughput, router_write_throughput) self.storage_table = get_storage_table(storage_tablename, storage_read_throughput, storage_write_throughput) self.message_table = get_rotating_message_table( message_tablename, message_read_throughput=message_read_throughput, message_write_throughput=message_write_throughput) self._message_prefix = message_tablename self.message_limit = msg_limit self.storage = Storage(self.storage_table, self.metrics) self.router = Router(self.router_table, self.metrics) # Used to determine whether a connection is out of date with current # db objects. There are three noteworty cases: # 1 "Last Month" the table requires a rollover. # 2 "This Month" the most common case. # 3 "Next Month" where the system will soon be rolling over, but with # timing, some nodes may roll over sooner. Ensuring the next month's # table is present before the switchover is the main reason for this, # just in case some nodes do switch sooner. self.create_initial_message_tables() # Run preflight check preflight_check(self.storage, self.router, preflight_uaid) # CORS self.cors = enable_cors # Force timeout in idle seconds self.wake_timeout = wake_timeout # Setup the routers self.routers = dict() self.routers["simplepush"] = SimpleRouter( self, router_conf.get("simplepush")) self.routers["webpush"] = WebPushRouter(self, None) if 'apns' in router_conf: self.routers["apns"] = APNSRouter(self, router_conf["apns"]) if 'gcm' in router_conf: self.routers["gcm"] = GCMRouter(self, router_conf["gcm"]) # Env self.env = env self.hello_timeout = hello_timeout self.ami_id = ami_id # Generate messages per legacy rules, only used for testing to # generate legacy data. self._notification_legacy = False
class GCMRouterTestCase(unittest.TestCase): @patch("gcmclient.gcm.GCM", spec=gcmclient.gcm.GCM) def setUp(self, fgcm): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) self.gcm_config = {'s3_bucket': 'None', 'max_data': 32, 'senderid_list': {'test123': {"auth": "12345678abcdefg"}}} self.gcm = fgcm self.router = GCMRouter(settings, self.gcm_config) self.headers = {"content-encoding": "aesgcm", "encryption": "test", "encryption-key": "test"} # Data will most likely be binary values. self.notif = Notification(10, "\xab\xad\x1d\xea", dummy_chid, self.headers, 200) self.router_data = dict( router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg"))) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result fgcm.send.return_value = mock_result def tearDown(self): self.router.senderIDs.stop() def _check_error_call(self, exc, code): ok_(isinstance(exc, RouterException)) eq_(exc.status_code, code) assert(self.router.gcm.send.called) self.flushLoggedErrors() def test_init(self): self.router.senderIDs.get_ID = Mock() def throw_ex(): raise AttributeError fsenderids = Mock() fsenderids.choose_ID.side_effect = throw_ex self.assertRaises(IOError, GCMRouter, {}, {"senderIDs": fsenderids}) def test_register(self): result = self.router.register("uaid", {"token": "connect_data"}) # Check the information that will be recorded for this user eq_(result, {"token": "connect_data", "creds": {"senderID": "test123", "auth": "12345678abcdefg"}}) def test_register_bad(self): self.assertRaises(RouterException, self.router.register, "uaid", {}) def test_invalid_token(self): self.router.gcm = self.gcm (t, v) = self.router.check_token("test123") ok_(t) eq_(v, self.gcm_config['senderid_list'].keys()[0]) (t, v) = self.router.check_token("invalid") eq_(t, False) eq_(v, self.gcm_config['senderid_list'].keys()[0]) def test_route_notification(self): self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) assert(self.router.gcm.send.called) # Make sure the data was encoded as base64 data = self.router.gcm.send.call_args[0][0].data eq_(data['body'], 'q60d6g==') eq_(data['enc'], 'test') eq_(data['enckey'], 'test') eq_(data['con'], 'aesgcm') d.addCallback(check_results) return d def test_long_data(self): self.router.gcm = self.gcm badNotif = Notification( 10, "\x01abcdefghijklmnopqrstuvwxyz0123456789", dummy_chid, self.headers, 200) d = self.router.route_notification(badNotif, self.router_data) def check_results(result): ok_(isinstance(result.value, RouterException)) eq_(result.value.status_code, 413) eq_(result.value.errno, 104) d.addBoth(check_results) return d def test_route_crypto_notification(self): self.router.gcm = self.gcm del(self.notif.headers['encryption-key']) self.notif.headers['crypto-key'] = 'crypto' d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) assert(self.router.gcm.send.called) d.addCallback(check_results) return d def test_router_missing_enc_key_header(self): self.router.gcm = self.gcm del(self.notif.headers['encryption-key']) d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result.value, RouterException)) eq_(result.value.status_code, 400) d.addBoth(check_results) return d def test_router_bogus_headers(self): self.router.gcm = self.gcm self.notif.headers['crypto-key'] = "crypto" d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result.value, RouterException)) eq_(result.value.status_code, 400) d.addBoth(check_results) return d def test_router_missing_enc_header(self): self.router.gcm = self.gcm del(self.notif.headers['encryption']) d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result.value, RouterException)) eq_(result.value.status_code, 400) d.addBoth(check_results) return d def test_router_missing_cont_enc_header(self): self.router.gcm = self.gcm del(self.notif.headers['content-encoding']) d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result.value, RouterException)) eq_(result.value.status_code, 400) d.addBoth(check_results) return d def test_router_notification_gcm_auth_error(self): def throw_auth(arg): raise gcmclient.GCMAuthenticationError() self.gcm.send.side_effect = throw_auth self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500) d.addBoth(check_results) return d def test_router_notification_gcm_other_error(self): def throw_other(arg): raise Exception("oh my!") self.gcm.send.side_effect = throw_other self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500) d.addBoth(check_results) return d def test_router_notification_gcm_id_change(self): self.mock_result.canonical["old"] = "new" self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict(token="new")) assert(self.router.gcm.send.called) d.addCallback(check_results) return d def test_router_notification_gcm_not_regged(self): self.mock_result.not_registered = {"connect_data": True} self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict()) assert(self.router.gcm.send.called) d.addCallback(check_results) return d def test_router_notification_gcm_failed_items(self): self.mock_result.failed = dict(connect_data=True) self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 503) d.addBoth(check_results) return d def test_router_notification_gcm_needs_retry(self): self.mock_result.needs_retry.return_value = True self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 503) d.addBoth(check_results) return d def test_router_notification_gcm_no_auth(self): d = self.router.route_notification(self.notif, {"router_data": {"token": "abc"}}) def check_results(fail): eq_(fail.value.status_code, 500) d.addBoth(check_results) return d def test_ammend(self): self.router.register("uaid", {"token": "connect_data"}) resp = {"key": "value"} result = self.router.amend_msg(resp, self.router_data.get('router_data')) eq_({"key": "value", "senderid": "test123"}, result)
class GCMRouterTestCase(unittest.TestCase): @patch("gcmclient.gcm.GCM", spec=gcmclient.gcm.GCM) def setUp(self, fgcm): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) self.gcm_config = {'s3_bucket': 'None', 'max_data': 32, 'ttl': 60, 'senderid_list': {'test123': {"auth": "12345678abcdefg"}}} self.gcm = fgcm self.router = GCMRouter(settings, self.gcm_config) self.headers = {"content-encoding": "aesgcm", "encryption": "test", "encryption-key": "test"} # Payloads are Base64-encoded. self.notif = Notification(10, "q60d6g", dummy_chid, self.headers, 200) self.router_data = dict( router_data=dict( token="connect_data", creds=dict(senderID="test123", auth="12345678abcdefg"))) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result fgcm.send.return_value = mock_result def tearDown(self): self.router.senderIDs.stop() def _check_error_call(self, exc, code): ok_(isinstance(exc, RouterException)) eq_(exc.status_code, code) assert(self.router.gcm.send.called) self.flushLoggedErrors() def test_init(self): self.router.senderIDs.get_ID = Mock() def throw_ex(): raise AttributeError fsenderids = Mock() fsenderids.choose_ID.side_effect = throw_ex self.assertRaises(IOError, GCMRouter, {}, {"senderIDs": fsenderids}) def test_register(self): result = self.router.register("uaid", {"token": "connect_data"}) # Check the information that will be recorded for this user eq_(result, {"token": "connect_data", "creds": {"senderID": "test123", "auth": "12345678abcdefg"}}) def test_register_bad(self): self.assertRaises(RouterException, self.router.register, "uaid", {}) def test_invalid_token(self): self.router.gcm = self.gcm (t, v) = self.router.check_token("test123") ok_(t) eq_(v, self.gcm_config['senderid_list'].keys()[0]) (t, v) = self.router.check_token("invalid") eq_(t, False) eq_(v, self.gcm_config['senderid_list'].keys()[0]) def test_route_notification(self): self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) assert(self.router.gcm.send.called) # Make sure the data was encoded as base64 data = self.router.gcm.send.call_args[0][0].data eq_(data['body'], 'q60d6g') eq_(data['enc'], 'test') eq_(data['enckey'], 'test') eq_(data['con'], 'aesgcm') d.addCallback(check_results) return d def test_ttl_none(self): self.router.gcm = self.gcm self.notif = Notification(version=10, data="q60d6g", channel_id=dummy_chid, headers=self.headers, ttl=None) d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) assert(self.router.gcm.send.called) # Make sure the data was encoded as base64 data = self.router.gcm.send.call_args[0][0].data options = self.router.gcm.send.call_args[0][0].options eq_(data['body'], 'q60d6g') eq_(data['enc'], 'test') eq_(data['enckey'], 'test') eq_(data['con'], 'aesgcm') # use the defined min TTL eq_(options['time_to_live'], 60) d.addCallback(check_results) return d def test_long_data(self): self.router.gcm = self.gcm badNotif = Notification( 10, "\x01abcdefghijklmnopqrstuvwxyz0123456789", dummy_chid, self.headers, 200) d = self.router.route_notification(badNotif, self.router_data) def check_results(result): ok_(isinstance(result.value, RouterException)) eq_(result.value.status_code, 413) eq_(result.value.errno, 104) d.addBoth(check_results) return d def test_route_crypto_notification(self): self.router.gcm = self.gcm del(self.notif.headers['encryption-key']) self.notif.headers['crypto-key'] = 'crypto' d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) assert(self.router.gcm.send.called) d.addCallback(check_results) return d def test_router_notification_gcm_auth_error(self): def throw_auth(arg): raise gcmclient.GCMAuthenticationError() self.gcm.send.side_effect = throw_auth self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500) d.addBoth(check_results) return d def test_router_notification_gcm_other_error(self): def throw_other(arg): raise Exception("oh my!") self.gcm.send.side_effect = throw_other self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500) d.addBoth(check_results) return d def test_router_notification_gcm_id_change(self): self.mock_result.canonical["old"] = "new" self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict(token="new")) assert(self.router.gcm.send.called) d.addCallback(check_results) return d def test_router_notification_gcm_not_regged(self): self.mock_result.not_registered = {"connect_data": True} self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict()) assert(self.router.gcm.send.called) d.addCallback(check_results) return d def test_router_notification_gcm_failed_items(self): self.mock_result.failed = dict(connect_data=True) self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 503) d.addBoth(check_results) return d def test_router_notification_gcm_needs_retry(self): self.mock_result.needs_retry.return_value = True self.router.gcm = self.gcm d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 503) d.addBoth(check_results) return d def test_router_notification_gcm_no_auth(self): d = self.router.route_notification(self.notif, {"router_data": {"token": "abc"}}) def check_results(fail): eq_(fail.value.status_code, 500) d.addBoth(check_results) return d def test_ammend(self): self.router.register("uaid", {"token": "connect_data"}) resp = {"key": "value"} result = self.router.amend_msg(resp, self.router_data.get('router_data')) eq_({"key": "value", "senderid": "test123"}, result)
class GCMRouterTestCase(unittest.TestCase): def setUp(self): settings = AutopushSettings( hostname="localhost", statsd_host=None, ) # Mock out GCM client self._old_gcm = gcmclient.GCM gcmclient.GCM = Mock(spec=gcmclient.GCM) gcm_config = {'apikey': '12345678abcdefg'} self.router = GCMRouter(settings, gcm_config) self.notif = Notification(10, "data", dummy_chid) self.router_data = dict(router_data=dict(token="connect_data")) mock_result = Mock(spec=gcmclient.gcm.Result) mock_result.canonical = dict() mock_result.failed = dict() mock_result.not_registered = dict() mock_result.needs_retry.return_value = False self.mock_result = mock_result self.router.gcm.send.return_value = mock_result def tearDown(self): gcmclient.GCM = self._old_gcm def _check_error_call(self, exc, code): ok_(isinstance(exc, RouterException)) eq_(exc.status_code, code) self.router.gcm.send.assert_called() self.flushLoggedErrors() def test_register(self): result = self.router.register("uaid", {"token": "connect_data"}) eq_(result, {"token": "connect_data"}) def test_register_bad(self): self.assertRaises(RouterException, self.router.register, "uaid", {}) def test_router_notification(self): d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) self.router.gcm.send.assert_called() d.addCallback(check_results) return d def test_router_notification_gcm_auth_error(self): def throw_auth(arg): raise gcmclient.GCMAuthenticationError() self.router.gcm.send.side_effect = throw_auth d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500) d.addBoth(check_results) return d def test_router_notification_gcm_other_error(self): def throw_other(arg): raise Exception("oh my!") self.router.gcm.send.side_effect = throw_other d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 500) d.addBoth(check_results) return d def test_router_notification_gcm_id_change(self): self.mock_result.canonical["old"] = "new" d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict(token="new")) self.router.gcm.send.assert_called() d.addCallback(check_results) return d def test_router_notification_gcm_not_regged(self): self.mock_result.not_registered = {"connect_data": True} d = self.router.route_notification(self.notif, self.router_data) def check_results(result): ok_(isinstance(result, RouterResponse)) eq_(result.router_data, dict()) self.router.gcm.send.assert_called() d.addCallback(check_results) return d def test_router_notification_gcm_failed_items(self): self.mock_result.failed = dict(connect_data=True) d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 503) d.addBoth(check_results) return d def test_router_notification_gcm_needs_retry(self): self.mock_result.needs_retry.return_value = True d = self.router.route_notification(self.notif, self.router_data) def check_results(fail): self._check_error_call(fail.value, 503) d.addBoth(check_results) return d