def test_push_notifications_worker(self) -> None: """ The push notifications system has its own comprehensive test suite, so we can limit ourselves to simple unit testing the queue processor, without going deeper into the system - by mocking the handle_push_notification functions to immediately produce the effect we want, to test its handling by the queue processor. """ fake_client = self.FakeClient() def fake_publish(queue_name: str, event: Dict[str, Any], processor: Callable[[Any], None]) -> None: fake_client.queue.append((queue_name, event)) def generate_new_message_notification() -> Dict[str, Any]: return build_offline_notification(1, 1) def generate_remove_notification() -> Dict[str, Any]: return { "type": "remove", "user_profile_id": 1, "message_ids": [1], } with simulated_queue_client(lambda: fake_client): worker = queue_processors.PushNotificationsWorker() worker.setup() with patch('zerver.worker.queue_processors.handle_push_notification') as mock_handle_new, \ patch('zerver.worker.queue_processors.handle_remove_push_notification') as mock_handle_remove, \ patch('zerver.worker.queue_processors.initialize_push_notifications'): event_new = generate_new_message_notification() event_remove = generate_remove_notification() fake_client.queue.append(('missedmessage_mobile_notifications', event_new)) fake_client.queue.append(('missedmessage_mobile_notifications', event_remove)) worker.start() mock_handle_new.assert_called_once_with(event_new['user_profile_id'], event_new) mock_handle_remove.assert_called_once_with(event_remove['user_profile_id'], event_remove['message_ids']) with patch('zerver.worker.queue_processors.handle_push_notification', side_effect=PushNotificationBouncerRetryLaterError("test")) as mock_handle_new, \ patch('zerver.worker.queue_processors.handle_remove_push_notification', side_effect=PushNotificationBouncerRetryLaterError("test")) as mock_handle_remove, \ patch('zerver.worker.queue_processors.initialize_push_notifications'): event_new = generate_new_message_notification() event_remove = generate_remove_notification() fake_client.queue.append(('missedmessage_mobile_notifications', event_new)) fake_client.queue.append(('missedmessage_mobile_notifications', event_remove)) with patch('zerver.lib.queue.queue_json_publish', side_effect=fake_publish), \ self.assertLogs('zerver.worker.queue_processors', 'WARNING') as warn_logs: worker.start() self.assertEqual(mock_handle_new.call_count, 1 + MAX_REQUEST_RETRIES) self.assertEqual(mock_handle_remove.call_count, 1 + MAX_REQUEST_RETRIES) self.assertEqual(warn_logs.output, [ 'WARNING:zerver.worker.queue_processors:Maximum retries exceeded for trigger:1 event:push_notification', ] * 2)
def test_push_notifications_worker(self) -> None: """ The push notifications system has its own comprehensive test suite, so we can limit ourselves to simple unit testing the queue processor, without going deeper into the system - by mocking the handle_push_notification functions to immediately produce the effect we want, to test its handling by the queue processor. """ fake_client = FakeClient() def fake_publish( queue_name: str, event: Dict[str, Any], processor: Callable[[Any], None] ) -> None: fake_client.enqueue(queue_name, event) def generate_new_message_notification() -> Dict[str, Any]: return build_offline_notification(1, 1) def generate_remove_notification() -> Dict[str, Any]: return { "type": "remove", "user_profile_id": 1, "message_ids": [1], } with simulated_queue_client(fake_client): worker = queue_processors.PushNotificationsWorker() worker.setup() with patch( "zerver.worker.queue_processors.handle_push_notification" ) as mock_handle_new, patch( "zerver.worker.queue_processors.handle_remove_push_notification" ) as mock_handle_remove, patch( "zerver.worker.queue_processors.initialize_push_notifications" ): event_new = generate_new_message_notification() event_remove = generate_remove_notification() fake_client.enqueue("missedmessage_mobile_notifications", event_new) fake_client.enqueue("missedmessage_mobile_notifications", event_remove) worker.start() mock_handle_new.assert_called_once_with(event_new["user_profile_id"], event_new) mock_handle_remove.assert_called_once_with( event_remove["user_profile_id"], event_remove["message_ids"] ) with patch( "zerver.worker.queue_processors.handle_push_notification", side_effect=PushNotificationBouncerRetryLaterError("test"), ) as mock_handle_new, patch( "zerver.worker.queue_processors.handle_remove_push_notification", side_effect=PushNotificationBouncerRetryLaterError("test"), ) as mock_handle_remove, patch( "zerver.worker.queue_processors.initialize_push_notifications" ): event_new = generate_new_message_notification() event_remove = generate_remove_notification() fake_client.enqueue("missedmessage_mobile_notifications", event_new) fake_client.enqueue("missedmessage_mobile_notifications", event_remove) with mock_queue_publish( "zerver.lib.queue.queue_json_publish", side_effect=fake_publish ), self.assertLogs("zerver.worker.queue_processors", "WARNING") as warn_logs: worker.start() self.assertEqual(mock_handle_new.call_count, 1 + MAX_REQUEST_RETRIES) self.assertEqual(mock_handle_remove.call_count, 1 + MAX_REQUEST_RETRIES) self.assertEqual( warn_logs.output, [ "WARNING:zerver.worker.queue_processors:Maximum retries exceeded for trigger:1 event:push_notification", ] * 2, ) # This verifies the compatibility code for the `message_id` -> `message_ids` # conversion for "remove" events. with patch( "zerver.worker.queue_processors.handle_remove_push_notification" ) as mock_handle_remove, patch( "zerver.worker.queue_processors.initialize_push_notifications" ): event_new = dict( user_profile_id=10, message_id=33, type="remove", ) fake_client.enqueue("missedmessage_mobile_notifications", event_new) worker.start() # The `message_id` field should have been converted to a list with a single element. mock_handle_remove.assert_called_once_with(10, [33])