Ejemplo n.º 1
0
    def test_send_local_online_presence_to(self):
        """Tests that send_local_presence_to_users sends local online presence to local users."""
        # Create a user who will send presence updates
        self.presence_receiver_id = self.register_user("presence_receiver",
                                                       "monkey")
        self.presence_receiver_tok = self.login("presence_receiver", "monkey")

        # And another user that will send presence updates out
        self.presence_sender_id = self.register_user("presence_sender",
                                                     "monkey")
        self.presence_sender_tok = self.login("presence_sender", "monkey")

        # Put them in a room together so they will receive each other's presence updates
        room_id = self.helper.create_room_as(
            self.presence_receiver_id,
            tok=self.presence_receiver_tok,
        )
        self.helper.join(room_id,
                         self.presence_sender_id,
                         tok=self.presence_sender_tok)

        # Presence sender comes online
        send_presence_update(
            self,
            self.presence_sender_id,
            self.presence_sender_tok,
            "online",
            "I'm online!",
        )

        # Presence receiver should have received it
        presence_updates, sync_token = sync_presence(self,
                                                     self.presence_receiver_id)
        self.assertEqual(len(presence_updates), 1)

        presence_update = presence_updates[0]  # type: UserPresenceState
        self.assertEqual(presence_update.user_id, self.presence_sender_id)
        self.assertEqual(presence_update.state, "online")

        # Syncing again should result in no presence updates
        presence_updates, sync_token = sync_presence(self,
                                                     self.presence_receiver_id,
                                                     sync_token)
        self.assertEqual(len(presence_updates), 0)

        # Trigger sending local online presence
        self.get_success(
            self.module_api.send_local_online_presence_to([
                self.presence_receiver_id,
            ]))

        # Presence receiver should have received online presence again
        presence_updates, sync_token = sync_presence(self,
                                                     self.presence_receiver_id,
                                                     sync_token)
        self.assertEqual(len(presence_updates), 1)

        presence_update = presence_updates[0]  # type: UserPresenceState
        self.assertEqual(presence_update.user_id, self.presence_sender_id)
        self.assertEqual(presence_update.state, "online")

        # Presence sender goes offline
        send_presence_update(
            self,
            self.presence_sender_id,
            self.presence_sender_tok,
            "offline",
            "I slink back into the darkness.",
        )

        # Trigger sending local online presence
        self.get_success(
            self.module_api.send_local_online_presence_to([
                self.presence_receiver_id,
            ]))

        # Presence receiver should *not* have received offline state
        presence_updates, sync_token = sync_presence(self,
                                                     self.presence_receiver_id,
                                                     sync_token)
        self.assertEqual(len(presence_updates), 0)
Ejemplo n.º 2
0
    def test_send_local_online_presence_to_federation(self):
        """Tests that send_local_presence_to_users sends local online presence to remote users."""
        # Create a user who will send presence updates
        self.presence_sender_id = self.register_user("presence_sender",
                                                     "monkey")
        self.presence_sender_tok = self.login("presence_sender", "monkey")

        # And a room they're a part of
        room_id = self.helper.create_room_as(
            self.presence_sender_id,
            tok=self.presence_sender_tok,
        )

        # Mark them as online
        send_presence_update(
            self,
            self.presence_sender_id,
            self.presence_sender_tok,
            "online",
            "I'm online!",
        )

        # Make up a remote user to send presence to
        remote_user_id = "@far_away_person:island"

        # Create a join membership event for the remote user into the room.
        # This allows presence information to flow from one user to the other.
        self.get_success(
            inject_member_event(
                self.hs,
                room_id,
                sender=remote_user_id,
                target=remote_user_id,
                membership="join",
            ))

        # The remote user would have received the existing room members' presence
        # when they joined the room.
        #
        # Thus we reset the mock, and try sending online local user
        # presence again
        self.hs.get_federation_transport_client().send_transaction.reset_mock()

        # Broadcast local user online presence
        self.get_success(
            self.module_api.send_local_online_presence_to([remote_user_id]))

        # Check that a presence update was sent as part of a federation transaction
        found_update = False
        calls = (self.hs.get_federation_transport_client().send_transaction.
                 call_args_list)
        for call in calls:
            call_args = call[0]
            federation_transaction = call_args[0]  # type: Transaction

            # Get the sent EDUs in this transaction
            edus = federation_transaction.get_dict()["edus"]

            for edu in edus:
                # Make sure we're only checking presence-type EDUs
                if edu["edu_type"] != EduTypes.Presence:
                    continue

                # EDUs can contain multiple presence updates
                for presence_update in edu["content"]["push"]:
                    if presence_update["user_id"] == self.presence_sender_id:
                        found_update = True

        self.assertTrue(found_update)
Ejemplo n.º 3
0
def _test_sending_local_online_presence_to_local_user(
        test_case: HomeserverTestCase, test_with_workers: bool = False):
    """Tests that send_local_presence_to_users sends local online presence to local users.

    This simultaneously tests two different usecases:
        * Testing that this method works when either called from a worker or the main process.
            - We test this by calling this method from both a TestCase that runs in monolith mode, and one that
              runs with a main and generic_worker.
        * Testing that multiple devices syncing simultaneously will all receive a snapshot of local,
            online presence - but only once per device.

    Args:
        test_with_workers: If True, this method will call ModuleApi.send_local_online_presence_to on a
            worker process. The test users will still sync with the main process. The purpose of testing
            with a worker is to check whether a Synapse module running on a worker can inform other workers/
            the main process that they should include additional presence when a user next syncs.
    """
    if test_with_workers:
        # Create a worker process to make module_api calls against
        worker_hs = test_case.make_worker_hs(
            "synapse.app.generic_worker", {"worker_name": "presence_writer"})

    # Create a user who will send presence updates
    test_case.presence_receiver_id = test_case.register_user(
        "presence_receiver1", "monkey")
    test_case.presence_receiver_tok = test_case.login("presence_receiver1",
                                                      "monkey")

    # And another user that will send presence updates out
    test_case.presence_sender_id = test_case.register_user(
        "presence_sender2", "monkey")
    test_case.presence_sender_tok = test_case.login("presence_sender2",
                                                    "monkey")

    # Put them in a room together so they will receive each other's presence updates
    room_id = test_case.helper.create_room_as(
        test_case.presence_receiver_id,
        tok=test_case.presence_receiver_tok,
    )
    test_case.helper.join(room_id,
                          test_case.presence_sender_id,
                          tok=test_case.presence_sender_tok)

    # Presence sender comes online
    send_presence_update(
        test_case,
        test_case.presence_sender_id,
        test_case.presence_sender_tok,
        "online",
        "I'm online!",
    )

    # Presence receiver should have received it
    presence_updates, sync_token = sync_presence(
        test_case, test_case.presence_receiver_id)
    test_case.assertEqual(len(presence_updates), 1)

    presence_update = presence_updates[0]  # type: UserPresenceState
    test_case.assertEqual(presence_update.user_id,
                          test_case.presence_sender_id)
    test_case.assertEqual(presence_update.state, "online")

    if test_with_workers:
        # Replicate the current sync presence token from the main process to the worker process.
        # We need to do this so that the worker process knows the current presence stream ID to
        # insert into the database when we call ModuleApi.send_local_online_presence_to.
        test_case.replicate()

    # Syncing again should result in no presence updates
    presence_updates, sync_token = sync_presence(
        test_case, test_case.presence_receiver_id, sync_token)
    test_case.assertEqual(len(presence_updates), 0)

    # We do an (initial) sync with a second "device" now, getting a new sync token.
    # We'll use this in a moment.
    _, sync_token_second_device = sync_presence(test_case,
                                                test_case.presence_receiver_id)

    # Determine on which process (main or worker) to call ModuleApi.send_local_online_presence_to on
    if test_with_workers:
        module_api_to_use = worker_hs.get_module_api()
    else:
        module_api_to_use = test_case.module_api

    # Trigger sending local online presence. We expect this information
    # to be saved to the database where all processes can access it.
    # Note that we're syncing via the master.
    d = module_api_to_use.send_local_online_presence_to([
        test_case.presence_receiver_id,
    ])
    d = defer.ensureDeferred(d)

    if test_with_workers:
        # In order for the required presence_set_state replication request to occur between the
        # worker and main process, we need to pump the reactor. Otherwise, the coordinator that
        # reads the request on the main process won't do so, and the request will time out.
        while not d.called:
            test_case.reactor.advance(0.1)

    test_case.get_success(d)

    # The presence receiver should have received online presence again.
    presence_updates, sync_token = sync_presence(
        test_case, test_case.presence_receiver_id, sync_token)
    test_case.assertEqual(len(presence_updates), 1)

    presence_update = presence_updates[0]  # type: UserPresenceState
    test_case.assertEqual(presence_update.user_id,
                          test_case.presence_sender_id)
    test_case.assertEqual(presence_update.state, "online")

    # We attempt to sync with the second sync token we received above - just to check that
    # multiple syncing devices will each receive the necessary online presence.
    presence_updates, sync_token_second_device = sync_presence(
        test_case, test_case.presence_receiver_id, sync_token_second_device)
    test_case.assertEqual(len(presence_updates), 1)

    presence_update = presence_updates[0]  # type: UserPresenceState
    test_case.assertEqual(presence_update.user_id,
                          test_case.presence_sender_id)
    test_case.assertEqual(presence_update.state, "online")

    # However, if we now sync with either "device", we won't receive another burst of online presence
    # until the API is called again sometime in the future
    presence_updates, sync_token = sync_presence(
        test_case, test_case.presence_receiver_id, sync_token)

    # Now we check that we don't receive *offline* updates using ModuleApi.send_local_online_presence_to.

    # Presence sender goes offline
    send_presence_update(
        test_case,
        test_case.presence_sender_id,
        test_case.presence_sender_tok,
        "offline",
        "I slink back into the darkness.",
    )

    # Presence receiver should have received the updated, offline state
    presence_updates, sync_token = sync_presence(
        test_case, test_case.presence_receiver_id, sync_token)
    test_case.assertEqual(len(presence_updates), 1)

    # Now trigger sending local online presence.
    d = module_api_to_use.send_local_online_presence_to([
        test_case.presence_receiver_id,
    ])
    d = defer.ensureDeferred(d)

    if test_with_workers:
        # In order for the required presence_set_state replication request to occur between the
        # worker and main process, we need to pump the reactor. Otherwise, the coordinator that
        # reads the request on the main process won't do so, and the request will time out.
        while not d.called:
            test_case.reactor.advance(0.1)

    test_case.get_success(d)

    # Presence receiver should *not* have received offline state
    presence_updates, sync_token = sync_presence(
        test_case, test_case.presence_receiver_id, sync_token)
    test_case.assertEqual(len(presence_updates), 0)