@@ -422,6 +422,18 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
422422 "exclusive_as_user" , "password" , self .exclusive_as_user_device_id
423423 )
424424
425+ self .exclusive_as_user_2_device_id = "exclusive_as_device_2"
426+ self .exclusive_as_user_2 = self .register_user ("exclusive_as_user_2" , "password" )
427+ self .exclusive_as_user_2_token = self .login (
428+ "exclusive_as_user_2" , "password" , self .exclusive_as_user_2_device_id
429+ )
430+
431+ self .exclusive_as_user_3_device_id = "exclusive_as_device_3"
432+ self .exclusive_as_user_3 = self .register_user ("exclusive_as_user_3" , "password" )
433+ self .exclusive_as_user_3_token = self .login (
434+ "exclusive_as_user_3" , "password" , self .exclusive_as_user_3_device_id
435+ )
436+
425437 def _notify_interested_services (self ) -> None :
426438 # This is normally set in `notify_interested_services` but we need to call the
427439 # internal async version so the reactor gets pushed to completion.
@@ -849,6 +861,119 @@ def test_application_services_receive_bursts_of_to_device(self) -> None:
849861 for count in service_id_to_message_count .values ():
850862 self .assertEqual (count , number_of_messages )
851863
864+ @unittest .override_config (
865+ {"experimental_features" : {"msc2409_to_device_messages_enabled" : True }}
866+ )
867+ def test_application_services_receive_local_to_device_for_many_users (self ) -> None :
868+ """
869+ Test that when a user sends a to-device message to many users
870+ in an application service's user namespace, the
871+ application service will receive all of them.
872+ """
873+ interested_appservice = self ._register_application_service (
874+ namespaces = {
875+ ApplicationService .NS_USERS : [
876+ {
877+ "regex" : "@exclusive_as_user:.+" ,
878+ "exclusive" : True ,
879+ },
880+ {
881+ "regex" : "@exclusive_as_user_2:.+" ,
882+ "exclusive" : True ,
883+ },
884+ {
885+ "regex" : "@exclusive_as_user_3:.+" ,
886+ "exclusive" : True ,
887+ },
888+ ],
889+ },
890+ )
891+
892+ # Have local_user send a to-device message to exclusive_as_users
893+ message_content = {"some_key" : "some really interesting value" }
894+ chan = self .make_request (
895+ "PUT" ,
896+ "/_matrix/client/r0/sendToDevice/m.room_key_request/3" ,
897+ content = {
898+ "messages" : {
899+ self .exclusive_as_user : {
900+ self .exclusive_as_user_device_id : message_content
901+ },
902+ self .exclusive_as_user_2 : {
903+ self .exclusive_as_user_2_device_id : message_content
904+ },
905+ self .exclusive_as_user_3 : {
906+ self .exclusive_as_user_3_device_id : message_content
907+ },
908+ }
909+ },
910+ access_token = self .local_user_token ,
911+ )
912+ self .assertEqual (chan .code , 200 , chan .result )
913+
914+ # Have exclusive_as_user send a to-device message to local_user
915+ for user_token in [
916+ self .exclusive_as_user_token ,
917+ self .exclusive_as_user_2_token ,
918+ self .exclusive_as_user_3_token ,
919+ ]:
920+ chan = self .make_request (
921+ "PUT" ,
922+ "/_matrix/client/r0/sendToDevice/m.room_key_request/4" ,
923+ content = {
924+ "messages" : {
925+ self .local_user : {self .local_user_device_id : message_content }
926+ }
927+ },
928+ access_token = user_token ,
929+ )
930+ self .assertEqual (chan .code , 200 , chan .result )
931+
932+ # Check if our application service - that is interested in exclusive_as_user - received
933+ # the to-device message as part of an AS transaction.
934+ # Only the local_user -> exclusive_as_user to-device message should have been forwarded to the AS.
935+ #
936+ # The uninterested application service should not have been notified at all.
937+ self .send_mock .assert_called_once ()
938+ (
939+ service ,
940+ _events ,
941+ _ephemeral ,
942+ to_device_messages ,
943+ _otks ,
944+ _fbks ,
945+ _device_list_summary ,
946+ ) = self .send_mock .call_args [0 ]
947+
948+ # Assert that this was the same to-device message that local_user sent
949+ self .assertEqual (service , interested_appservice )
950+
951+ # Assert expected number of messages
952+ self .assertEqual (len (to_device_messages ), 3 )
953+
954+ for device_msg in to_device_messages :
955+ self .assertEqual (device_msg ["type" ], "m.room_key_request" )
956+ self .assertEqual (device_msg ["sender" ], self .local_user )
957+ self .assertEqual (device_msg ["content" ], message_content )
958+
959+ self .assertEqual (to_device_messages [0 ]["to_user_id" ], self .exclusive_as_user )
960+ self .assertEqual (
961+ to_device_messages [0 ]["to_device_id" ],
962+ self .exclusive_as_user_device_id ,
963+ )
964+
965+ self .assertEqual (to_device_messages [1 ]["to_user_id" ], self .exclusive_as_user_2 )
966+ self .assertEqual (
967+ to_device_messages [1 ]["to_device_id" ],
968+ self .exclusive_as_user_2_device_id ,
969+ )
970+
971+ self .assertEqual (to_device_messages [2 ]["to_user_id" ], self .exclusive_as_user_3 )
972+ self .assertEqual (
973+ to_device_messages [2 ]["to_device_id" ],
974+ self .exclusive_as_user_3_device_id ,
975+ )
976+
852977 def _register_application_service (
853978 self ,
854979 namespaces : Optional [Dict [str , Iterable [Dict ]]] = None ,
0 commit comments