def test_user_message_does_not_exist(self): # type: () -> None missed_message = {'message_id': 100} with mock.patch('logging.error') as mock_logger: apn.handle_push_notification(self.user_profile.id, missed_message) mock_logger.assert_called_with("Could not find UserMessage with " "message_id 100")
def consume(self, event: Dict[str, Any]) -> None: try: if event.get("type", "add") == "remove": message_ids = event.get("message_ids") if message_ids is None: # TODO/compatibility: Previously, we sent only one `message_id` in # a payload for notification remove events. This was later changed # to send a list of `message_ids` (with that field name), but we need # compatibility code for events present in the queue during upgrade. # Remove this when one can no longer upgrade from 1.9.2 (or earlier) # to any version after 2.0.0 message_ids = [event["message_id"]] handle_remove_push_notification(event["user_profile_id"], message_ids) else: handle_push_notification(event["user_profile_id"], event) except PushNotificationBouncerRetryLaterError: def failure_processor(event: Dict[str, Any]) -> None: logger.warning( "Maximum retries exceeded for trigger:%s event:push_notification", event["user_profile_id"], ) retry_event(self.queue_name, event, failure_processor)
def test_send_notifications_to_bouncer(self): # type: () -> None user_profile = self.example_user('hamlet') message = self.get_message(Recipient.PERSONAL, type_id=1) UserMessage.objects.create( user_profile=user_profile, message=message ) missed_message = { 'message_id': message.id, 'trigger': 'private_message', } with self.settings(PUSH_NOTIFICATION_BOUNCER_URL=True), \ mock.patch('zerver.lib.push_notifications.get_apns_payload', return_value={'apns': True}), \ mock.patch('zerver.lib.push_notifications.get_gcm_payload', return_value={'gcm': True}), \ mock.patch('zerver.lib.push_notifications' '.send_notifications_to_bouncer') as mock_send: apn.handle_push_notification(user_profile.id, missed_message) mock_send.assert_called_with(user_profile.id, {'apns': True}, {'gcm': True}, )
def consume(self, data: Mapping[str, Any]) -> None: if data.get("type", "add") == "remove": message_ids = data.get('message_ids') if message_ids is None: # legacy task across an upgrade message_ids = [data['message_id']] handle_remove_push_notification(data['user_profile_id'], message_ids) else: handle_push_notification(data['user_profile_id'], data)
def consume(self, data: Mapping[str, Any]) -> None: if data.get("type", "add") == "remove": message_ids = data.get('message_ids') if message_ids is None: # legacy task across an upgrade message_ids = [data['message_id']] handle_remove_push_notification(data['user_profile_id'], message_ids) else: handle_push_notification(data['user_profile_id'], data)
def test_disabled_notifications(self): # type: () -> None user_profile = self.example_user('hamlet') user_profile.enable_online_email_notifications = False user_profile.enable_online_push_notifications = False user_profile.enable_offline_email_notifications = False user_profile.enable_offline_push_notifications = False user_profile.enable_stream_push_notifications = False user_profile.save() apn.handle_push_notification(user_profile.id, {})
def test_end_to_end(self): # type: () -> None remote_gcm_tokens = [u'dddd'] for token in remote_gcm_tokens: RemotePushDeviceToken.objects.create( kind=RemotePushDeviceToken.GCM, token=apn.hex_to_b64(token), user_id=self.user_profile.id, server=RemoteZulipServer.objects.get(uuid=self.server_uuid), ) message = self.get_message(Recipient.PERSONAL, type_id=1) UserMessage.objects.create( user_profile=self.user_profile, message=message ) missed_message = { 'message_id': message.id, 'triggers': { 'private_message': True, 'mentioned': False, 'stream_push_notify': False, }, } with self.settings(PUSH_NOTIFICATION_BOUNCER_URL=''), \ mock.patch('zerver.lib.push_notifications.requests.request', side_effect=self.bounce_request), \ mock.patch('zerver.lib.push_notifications.gcm') as mock_gcm, \ mock.patch('zerver.lib.push_notifications._apns_client') as mock_apns, \ mock.patch('logging.info') as mock_info, \ mock.patch('logging.warning'): apns_devices = [ (apn.b64_to_hex(device.token), device.ios_app_id, device.token) for device in RemotePushDeviceToken.objects.filter( kind=PushDeviceToken.APNS) ] gcm_devices = [ (apn.b64_to_hex(device.token), device.ios_app_id, device.token) for device in RemotePushDeviceToken.objects.filter( kind=PushDeviceToken.GCM) ] mock_gcm.json_request.return_value = { 'success': {gcm_devices[0][2]: message.id}} mock_apns.get_notification_result.return_value = 'Success' apn.handle_push_notification(self.user_profile.id, missed_message) for _, _, token in apns_devices: mock_info.assert_any_call( "APNs: Success sending for user %d to device %s", self.user_profile.id, token) for _, _, token in gcm_devices: mock_info.assert_any_call( "GCM: Sent %s as %s" % (token, message.id))
def test_read_message(self): # type: () -> None user_profile = self.example_user('hamlet') message = self.get_message(Recipient.PERSONAL, type_id=1) UserMessage.objects.create(user_profile=user_profile, flags=UserMessage.flags.read, message=message) missed_message = { 'message_id': message.id, 'trigger': 'private_message', } apn.handle_push_notification(user_profile.id, missed_message)
def test_end_to_end_connection_error(self): # type: () -> None remote_gcm_tokens = [u'dddd'] for token in remote_gcm_tokens: RemotePushDeviceToken.objects.create( kind=RemotePushDeviceToken.GCM, token=apn.hex_to_b64(token), user_id=self.user_profile.id, server=RemoteZulipServer.objects.get(uuid=self.server_uuid), ) message = self.get_message(Recipient.PERSONAL, type_id=1) UserMessage.objects.create( user_profile=self.user_profile, message=message ) def retry(queue_name, event, processor): # type: (Any, Any, Any) -> None apn.handle_push_notification(event['user_profile_id'], event) missed_message = { 'user_profile_id': self.user_profile.id, 'message_id': message.id, 'triggers': { 'private_message': True, 'mentioned': False, 'stream_push_notify': False, }, } with self.settings(PUSH_NOTIFICATION_BOUNCER_URL=''), \ mock.patch('zerver.lib.push_notifications.requests.request', side_effect=self.bounce_request), \ mock.patch('zerver.lib.push_notifications.gcm') as mock_gcm, \ mock.patch('zerver.lib.push_notifications.send_notifications_to_bouncer', side_effect=requests.ConnectionError), \ mock.patch('zerver.lib.queue.queue_json_publish', side_effect=retry) as mock_retry, \ mock.patch('logging.warning') as mock_warn: gcm_devices = [ (apn.b64_to_hex(device.token), device.ios_app_id, device.token) for device in RemotePushDeviceToken.objects.filter( kind=PushDeviceToken.GCM) ] mock_gcm.json_request.return_value = { 'success': {gcm_devices[0][2]: message.id}} apn.handle_push_notification(self.user_profile.id, missed_message) self.assertEqual(mock_retry.call_count, 3) mock_warn.assert_called_with("Maximum retries exceeded for " "trigger:%s event:" "push_notification" % (self.user_profile.id,))
def test_end_to_end(self): # type: () -> None remote_gcm_tokens = [u'dddd'] for token in remote_gcm_tokens: RemotePushDeviceToken.objects.create( kind=RemotePushDeviceToken.GCM, token=apn.hex_to_b64(token), user_id=self.user_profile.id, server=RemoteZulipServer.objects.get(uuid=self.server_uuid), ) message = self.get_message(Recipient.PERSONAL, type_id=1) UserMessage.objects.create( user_profile=self.user_profile, message=message ) missed_message = { 'message_id': message.id, 'trigger': 'private_message', } with self.settings(PUSH_NOTIFICATION_BOUNCER_URL=''), \ mock.patch('zerver.lib.push_notifications.requests.request', side_effect=self.bounce_request), \ mock.patch('zerver.lib.push_notifications.gcm') as mock_gcm, \ mock.patch('zerver.lib.push_notifications._apns_client') as mock_apns, \ mock.patch('logging.info') as mock_info, \ mock.patch('logging.warning'): apns_devices = [ (apn.b64_to_hex(device.token), device.ios_app_id, device.token) for device in RemotePushDeviceToken.objects.filter( kind=PushDeviceToken.APNS) ] gcm_devices = [ (apn.b64_to_hex(device.token), device.ios_app_id, device.token) for device in RemotePushDeviceToken.objects.filter( kind=PushDeviceToken.GCM) ] mock_gcm.json_request.return_value = { 'success': {gcm_devices[0][2]: message.id}} mock_apns.get_notification_result.return_value = 'Success' apn.handle_push_notification(self.user_profile.id, missed_message) for _, _, token in apns_devices: mock_info.assert_any_call( "APNs: Success sending for user %d to device %s", self.user_profile.id, token) for _, _, token in gcm_devices: mock_info.assert_any_call( "GCM: Sent %s as %s" % (token, message.id))
def consume(self, event: Dict[str, Any]) -> None: try: if event.get("type", "add") == "remove": message_ids = event.get('message_ids') if message_ids is None: # legacy task across an upgrade message_ids = [event['message_id']] handle_remove_push_notification(event['user_profile_id'], message_ids) else: handle_push_notification(event['user_profile_id'], event) except PushNotificationBouncerRetryLaterError: def failure_processor(event: Dict[str, Any]) -> None: logger.warning( "Maximum retries exceeded for trigger:%s event:push_notification", event['user_profile_id']) retry_event(self.queue_name, event, failure_processor)
def test_read_message(self): # type: () -> None user_profile = self.example_user('hamlet') message = self.get_message(Recipient.PERSONAL, type_id=1) UserMessage.objects.create( user_profile=user_profile, flags=UserMessage.flags.read, message=message ) missed_message = { 'message_id': message.id, 'trigger': 'private_message', } apn.handle_push_notification(user_profile.id, missed_message)
def test_end_to_end_connection_error(self): # type: () -> None remote_gcm_tokens = [u'dddd'] for token in remote_gcm_tokens: RemotePushDeviceToken.objects.create( kind=RemotePushDeviceToken.GCM, token=apn.hex_to_b64(token), user_id=self.user_profile.id, server=RemoteZulipServer.objects.get(uuid=self.server_uuid), ) message = self.get_message(Recipient.PERSONAL, type_id=1) UserMessage.objects.create( user_profile=self.user_profile, message=message ) def retry(queue_name, event, processor): # type: (Any, Any, Any) -> None apn.handle_push_notification(event['user_profile_id'], event) missed_message = { 'user_profile_id': self.user_profile.id, 'message_id': message.id, 'trigger': 'private_message', } with self.settings(PUSH_NOTIFICATION_BOUNCER_URL=''), \ mock.patch('zerver.lib.push_notifications.requests.request', side_effect=self.bounce_request), \ mock.patch('zerver.lib.push_notifications.gcm') as mock_gcm, \ mock.patch('zerver.lib.push_notifications.send_notifications_to_bouncer', side_effect=requests.ConnectionError), \ mock.patch('zerver.lib.queue.queue_json_publish', side_effect=retry) as mock_retry, \ mock.patch('logging.warning') as mock_warn: gcm_devices = [ (apn.b64_to_hex(device.token), device.ios_app_id, device.token) for device in RemotePushDeviceToken.objects.filter( kind=PushDeviceToken.GCM) ] mock_gcm.json_request.return_value = { 'success': {gcm_devices[0][2]: message.id}} apn.handle_push_notification(self.user_profile.id, missed_message) self.assertEqual(mock_retry.call_count, 3) mock_warn.assert_called_with("Maximum retries exceeded for " "trigger:%s event:" "push_notification" % (self.user_profile.id,))
def test_non_bouncer_push(self): # type: () -> None message = self.get_message(Recipient.PERSONAL, type_id=1) UserMessage.objects.create( user_profile=self.user_profile, message=message ) for token in [u'dddd']: PushDeviceToken.objects.create( kind=PushDeviceToken.GCM, token=apn.hex_to_b64(token), user=self.user_profile) android_devices = list( PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.GCM)) apple_devices = list( PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.APNS)) missed_message = { 'message_id': message.id, 'triggers': { 'private_message': True, 'mentioned': False, 'stream_push_notify': False, }, } with mock.patch('zerver.lib.push_notifications.get_apns_payload', return_value={'apns': True}), \ mock.patch('zerver.lib.push_notifications.get_gcm_payload', return_value={'gcm': True}), \ mock.patch('zerver.lib.push_notifications' '.send_apple_push_notification') as mock_send_apple, \ mock.patch('zerver.lib.push_notifications' '.send_android_push_notification') as mock_send_android: apn.handle_push_notification(self.user_profile.id, missed_message) mock_send_apple.assert_called_with(self.user_profile.id, apple_devices, {'apns': True}) mock_send_android.assert_called_with(android_devices, {'gcm': True})
def test_non_bouncer_push(self): # type: () -> None message = self.get_message(Recipient.PERSONAL, type_id=1) UserMessage.objects.create( user_profile=self.user_profile, message=message ) for token in [u'dddd']: PushDeviceToken.objects.create( kind=PushDeviceToken.GCM, token=apn.hex_to_b64(token), user=self.user_profile) android_devices = list( PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.GCM)) apple_devices = list( PushDeviceToken.objects.filter(user=self.user_profile, kind=PushDeviceToken.APNS)) missed_message = { 'message_id': message.id, 'trigger': 'private_message', } with mock.patch('zerver.lib.push_notifications.get_apns_payload', return_value={'apns': True}), \ mock.patch('zerver.lib.push_notifications.get_gcm_payload', return_value={'gcm': True}), \ mock.patch('zerver.lib.push_notifications' '.send_apple_push_notification') as mock_send_apple, \ mock.patch('zerver.lib.push_notifications' '.send_android_push_notification') as mock_send_android: apn.handle_push_notification(self.user_profile.id, missed_message) mock_send_apple.assert_called_with(self.user_profile.id, apple_devices, {'apns': True}) mock_send_android.assert_called_with(android_devices, {'gcm': True})
def consume(self, data: Mapping[str, Any]) -> None: if data.get("type", "add") == "remove": handle_remove_push_notification(data['user_profile_id'], data['message_id']) else: handle_push_notification(data['user_profile_id'], data)
def consume(self, data): # type: (Mapping[str, Any]) -> None handle_push_notification(data['user_profile_id'], data)
def consume(self, data): # type: (Mapping[str, Any]) -> None handle_push_notification(data['user_profile_id'], data)
def consume(self, data: Mapping[str, Any]) -> None: if data.get("type", "add") == "remove": handle_remove_push_notification(data['user_profile_id'], data['message_id']) else: handle_push_notification(data['user_profile_id'], data)
def retry(queue_name, event, processor): # type: (Any, Any, Any) -> None apn.handle_push_notification(event['user_profile_id'], event)