diff --git a/tests/push/test_http.py b/tests/push/test_http.py
index bcca472617..b42fd284b6 100644
--- a/tests/push/test_http.py
+++ b/tests/push/test_http.py
@@ -17,9 +17,11 @@
# [This file includes modifications made by New Vector Limited]
#
#
-from typing import Any, List, Tuple
+from typing import Any, Dict, List, Tuple
from unittest.mock import Mock
+from parameterized import parameterized
+
from twisted.internet.defer import Deferred
from twisted.test.proto_helpers import MemoryReactor
@@ -1085,3 +1087,161 @@ class HTTPPusherTests(HomeserverTestCase):
self.pump()
self.assertEqual(len(self.push_attempts), 11)
+
+ @parameterized.expand(
+ [
+ # Badge count disabled
+ (True, True),
+ (True, False),
+ # Badge count enabled
+ (False, True),
+ (False, False),
+ ]
+ )
+ @override_config({"experimental_features": {"msc4076_enabled": True}})
+ def test_msc4076_badge_count(
+ self, disable_badge_count: bool, event_id_only: bool
+ ) -> None:
+ # Register the user who gets notified
+ user_id = self.register_user("user", "pass")
+ access_token = self.login("user", "pass")
+
+ # Register the user who sends the message
+ other_user_id = self.register_user("otheruser", "pass")
+ other_access_token = self.login("otheruser", "pass")
+
+ # Register the pusher with disable_badge_count set to True
+ user_tuple = self.get_success(
+ self.hs.get_datastores().main.get_user_by_access_token(access_token)
+ )
+ assert user_tuple is not None
+ device_id = user_tuple.device_id
+
+ # Set the push data dict based on test input parameters
+ push_data: Dict[str, Any] = {
+ "url": "http://example.com/_matrix/push/v1/notify",
+ }
+ if disable_badge_count:
+ push_data["org.matrix.msc4076.disable_badge_count"] = True
+ if event_id_only:
+ push_data["format"] = "event_id_only"
+
+ self.get_success(
+ self.hs.get_pusherpool().add_or_update_pusher(
+ user_id=user_id,
+ device_id=device_id,
+ kind="http",
+ app_id="m.http",
+ app_display_name="HTTP Push Notifications",
+ device_display_name="pushy push",
+ pushkey="a@example.com",
+ lang=None,
+ data=push_data,
+ )
+ )
+
+ # Create a room
+ room = self.helper.create_room_as(user_id, tok=access_token)
+
+ # The other user joins
+ self.helper.join(room=room, user=other_user_id, tok=other_access_token)
+
+ # The other user sends a message
+ self.helper.send(room, body="Hi!", tok=other_access_token)
+
+ # Advance time a bit, so the pusher will register something has happened
+ self.pump()
+
+ # One push was attempted to be sent
+ self.assertEqual(len(self.push_attempts), 1)
+ self.assertEqual(
+ self.push_attempts[0][1], "http://example.com/_matrix/push/v1/notify"
+ )
+
+ if disable_badge_count:
+ # Verify that the notification DOESN'T contain a counts field
+ self.assertNotIn("counts", self.push_attempts[0][2]["notification"])
+ else:
+ # Ensure that the notification DOES contain a counts field
+ self.assertIn("counts", self.push_attempts[0][2]["notification"])
+ self.assertEqual(
+ self.push_attempts[0][2]["notification"]["counts"]["unread"], 1
+ )
+
+ def test_push_backoff(self) -> None:
+ """
+ The HTTP pusher will backoff correctly if it fails to contact the pusher.
+ """
+
+ # Register the user who gets notified
+ user_id = self.register_user("user", "pass")
+ access_token = self.login("user", "pass")
+
+ # Register the user who sends the message
+ other_user_id = self.register_user("otheruser", "pass")
+ other_access_token = self.login("otheruser", "pass")
+
+ # Register the pusher
+ user_tuple = self.get_success(
+ self.hs.get_datastores().main.get_user_by_access_token(access_token)
+ )
+ assert user_tuple is not None
+ device_id = user_tuple.device_id
+
+ self.get_success(
+ self.hs.get_pusherpool().add_or_update_pusher(
+ user_id=user_id,
+ device_id=device_id,
+ kind="http",
+ app_id="m.http",
+ app_display_name="HTTP Push Notifications",
+ device_display_name="pushy push",
+ pushkey="a@example.com",
+ lang=None,
+ data={"url": "http://example.com/_matrix/push/v1/notify"},
+ )
+ )
+
+ # Create a room with the other user
+ room = self.helper.create_room_as(user_id, tok=access_token)
+ self.helper.join(room=room, user=other_user_id, tok=other_access_token)
+
+ # The other user sends some messages
+ self.helper.send(room, body="Message 1", tok=other_access_token)
+
+ # One push was attempted to be sent
+ self.assertEqual(len(self.push_attempts), 1)
+ self.assertEqual(
+ self.push_attempts[0][1], "http://example.com/_matrix/push/v1/notify"
+ )
+ self.assertEqual(
+ self.push_attempts[0][2]["notification"]["content"]["body"], "Message 1"
+ )
+ self.push_attempts[0][0].callback({})
+ self.pump()
+
+ # Send another message, this time it fails
+ self.helper.send(room, body="Message 2", tok=other_access_token)
+ self.assertEqual(len(self.push_attempts), 2)
+ self.push_attempts[1][0].errback(Exception("couldn't connect"))
+ self.pump()
+
+ # Sending yet another message doesn't trigger a push immediately
+ self.helper.send(room, body="Message 3", tok=other_access_token)
+ self.pump()
+ self.assertEqual(len(self.push_attempts), 2)
+
+ # .. but waiting for a bit will cause more pushes
+ self.reactor.advance(10)
+ self.assertEqual(len(self.push_attempts), 3)
+ self.assertEqual(
+ self.push_attempts[2][2]["notification"]["content"]["body"], "Message 2"
+ )
+ self.push_attempts[2][0].callback({})
+ self.pump()
+
+ self.assertEqual(len(self.push_attempts), 4)
+ self.assertEqual(
+ self.push_attempts[3][2]["notification"]["content"]["body"], "Message 3"
+ )
+ self.push_attempts[3][0].callback({})
|