Exemple #1
0
    def test_config_error(self):
        """
        If channel layer doesn't specify TEST_CONFIG, `make_test_backend`
        should result into error.
        """

        with self.assertRaises(InvalidChannelLayerError):
            channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)
Exemple #2
0
    def test_config_error(self):
        """
        If channel layer doesn't specify TEST_CONFIG, `make_test_backend`
        should result into error.
        """

        with self.assertRaises(InvalidChannelLayerError):
            channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)
async def test_model_observer_delete_wrapper(settings):
    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumerObserverDelete(AsyncAPIConsumer):
        async def accept(self, **kwargs):
            await self.user_change_observer_delete.subscribe()
            await super().accept()

        @model_observer(get_user_model())
        async def user_change_observer_delete(self,
                                              message,
                                              observer=None,
                                              **kwargs):
            await self.send_json(message)

    communicator = WebsocketCommunicator(TestConsumerObserverDelete,
                                         "/testws/")

    connected, _ = await communicator.connect()

    assert connected
    await communicator.receive_nothing()

    user = await database_sync_to_async(get_user_model()
                                        )(username="******",
                                          email="*****@*****.**")
    await database_sync_to_async(user.save)()

    response = await communicator.receive_json_from()
    await communicator.receive_nothing()

    assert {
        "action": "create",
        "pk": user.pk,
        "type": "user.change.observer.delete",
    } == response
    pk = user.pk

    await database_sync_to_async(user.delete)()

    response = await communicator.receive_json_from()

    await communicator.receive_nothing()

    assert {
        "action": "delete",
        "pk": pk,
        "type": "user.change.observer.delete",
    } == response

    await communicator.disconnect()
async def test_model_observer_custom_groups_wrapper(settings):
    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumer(AsyncAPIConsumer):
        async def accept(self, **kwargs):
            await self.user_change_custom_groups_wrapper.subscribe(
                username="******")
            await super().accept()

        @model_observer(get_user_model())
        async def user_change_custom_groups_wrapper(self, message, **kwargs):
            await self.send_json(message)

        @user_change_custom_groups_wrapper.groups
        def user_change_custom_groups_wrapper(self,
                                              instance=None,
                                              username=None,
                                              **kwargs):
            if username:
                yield "-instance-username-{}".format(slugify(username))
            else:
                yield "-instance-username-{}".format(instance.username)

    communicator = WebsocketCommunicator(TestConsumer, "/testws/")

    connected, _ = await communicator.connect()

    assert connected

    user = await database_sync_to_async(get_user_model().objects.create
                                        )(username="******",
                                          email="*****@*****.**")

    response = await communicator.receive_json_from()

    assert {
        "action": "create",
        "pk": user.pk,
        "type": "user.change.custom.groups.wrapper",
    } == response

    await communicator.disconnect()

    user = await database_sync_to_async(get_user_model().objects.create
                                        )(username="******",
                                          email="*****@*****.**")

    # no event since this is only subscribed to 'test'
    with pytest.raises(asyncio.TimeoutError):
        await communicator.receive_json_from()
async def test_model_observer_wrapper_in_transaction(settings):
    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumer(AsyncAPIConsumer):
        async def accept(self, **kwargs):
            await TestConsumer.user_change_wrapper_in_transaction.subscribe(
                self)
            await super().accept()

        @model_observer(get_user_model())
        async def user_change_wrapper_in_transaction(self,
                                                     message,
                                                     action,
                                                     message_type,
                                                     observer=None,
                                                     **kwargs):
            await self.send_json(
                dict(body=message, action=action, type=message_type))

    communicator = WebsocketCommunicator(TestConsumer(), "/testws/")

    connected, _ = await communicator.connect()

    assert connected

    @database_sync_to_async
    def create_user_and_wait():

        with transaction.atomic():
            user = get_user_model().objects.create(username="******",
                                                   email="*****@*****.**")
            assert async_to_sync(communicator.receive_nothing(timeout=0.1))
            user.username = "******"
            user.save()
            assert async_to_sync(communicator.receive_nothing(timeout=0.1))
            return user

    user = await create_user_and_wait()

    response = await communicator.receive_json_from()

    assert {
        "action": "create",
        "body": {
            "pk": user.pk
        },
        "type": "user.change.wrapper.in.transaction",
    } == response

    await communicator.disconnect()
Exemple #6
0
    def test_config_instance(self):
        """
        If channel layer provides TEST_CONFIG, `make_test_backend` should
        return channel layer instance appropriate for testing.
        """

        layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)
        self.assertEqual(layer.expiry, 100500)
Exemple #7
0
    def test_config_instance(self):
        """
        If channel layer provides TEST_CONFIG, `make_test_backend` should
        return channel layer instance appropriate for testing.
        """

        layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)
        self.assertEqual(layer.expiry, 100500)
async def test_model_observer_many_connections_wrapper(settings):
    settings.CHANNEL_LAYERS={
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumer(AsyncAPIConsumer):

        async def accept(self):
            await TestConsumer.user_change.subscribe(self)
            await super().accept()

        @model_observer(get_user_model())
        async def user_change(self, message, **kwargs):
            await self.send_json(message)

    communicator1 = WebsocketCommunicator(TestConsumer, "/testws/")

    connected, _ = await communicator1.connect()

    assert connected

    communicator2 = WebsocketCommunicator(TestConsumer, "/testws/")

    connected, _ = await communicator2.connect()

    assert connected

    user = await database_sync_to_async(get_user_model().objects.create)(
        username='******',
        email='*****@*****.**'
    )

    response = await communicator1.receive_json_from()

    assert {
               'action': 'create',
               'pk': user.pk,
               'type': 'user.change'
           } == response

    await communicator1.disconnect()

    response = await communicator2.receive_json_from()

    assert {
               'action': 'create',
               'pk': user.pk,
               'type': 'user.change'
           } == response

    await communicator2.disconnect()
async def test_observer_wrapper(settings):
    settings.CHANNEL_LAYERS={
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumer(AsyncAPIConsumer):

        async def accept(self):
            await TestConsumer.handle_user_logged_in.subscribe(self)
            await super().accept()

        @observer(user_logged_in)
        async def handle_user_logged_in(self, *args, observer=None, **kwargs):
            await self.send_json({
                    'message': kwargs,
                    'observer': observer is not None
                }
            )

    communicator = WebsocketCommunicator(TestConsumer, "/testws/")

    connected, _ = await communicator.connect()

    assert connected

    user = await database_sync_to_async(get_user_model().objects.create)(
        username='******',
        email='*****@*****.**'
    )

    await database_sync_to_async(user_logged_in.send)(
        sender=user.__class__,
        request=None,
        user=user
    )

    response = await communicator.receive_json_from()

    assert {'message': {}, 'observer': True} == response

    await communicator.disconnect()
Exemple #10
0
async def test_unsubscribe_observer_model_instance_mixin(settings):
    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumer(ObserverModelInstanceMixin, GenericAsyncAPIConsumer):

        queryset = get_user_model().objects.all()
        serializer_class = UserSerializer

        async def accept(self, subprotocol=None):
            await super().accept()

        @action()
        async def update_username(self, pk=None, username=None, **kwargs):
            user = await database_sync_to_async(self.get_object)(pk=pk)
            user.username = username
            await database_sync_to_async(user.save)()
            return {'pk': pk}, 200

    assert not await database_sync_to_async(
        get_user_model().objects.all().exists)()

    # Test a normal connection
    communicator = WebsocketCommunicator(TestConsumer, "/testws/")
    connected, _ = await communicator.connect()
    assert connected

    u1 = await database_sync_to_async(get_user_model().objects.create
                                      )(username='******',
                                        email='*****@*****.**')

    # lookup up u1
    await communicator.send_json_to({
        "action": "subscribe_instance",
        "pk": u1.id,
        "request_id": 4
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "subscribe_instance",
        "errors": [],
        "response_status": 201,
        "request_id": 4,
        "data": None
    }

    await communicator.send_json_to({
        "action": "update_username",
        "pk": u1.id,
        "username": "******",
        "request_id": 5
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "update_username",
        "errors": [],
        "response_status": 200,
        "request_id": 5,
        "data": {
            'pk': u1.id
        }
    }

    response = await communicator.receive_json_from()

    assert response == {
        "action": "update",
        "errors": [],
        "response_status": 200,
        "request_id": 4,
        "data": {
            'email': '*****@*****.**',
            'id': u1.pk,
            'username': '******'
        },
    }

    # unsubscribe
    # lookup up u1

    await communicator.send_json_to({
        "action": "unsubscribe_instance",
        "pk": u1.id,
        "request_id": 4
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "unsubscribe_instance",
        "errors": [],
        "response_status": 204,
        "request_id": 4,
        "data": None
    }

    await communicator.send_json_to({
        "action": "update_username",
        "pk": u1.id,
        "username": "******",
        "request_id": 5
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "update_username",
        "errors": [],
        "response_status": 200,
        "request_id": 5,
        "data": {
            'pk': u1.id
        }
    }

    await communicator.disconnect()
Exemple #11
0
async def test_two_observer_model_instance_mixins(settings):
    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestUserConsumer(ObserverModelInstanceMixin,
                           GenericAsyncAPIConsumer):

        queryset = get_user_model().objects.all()
        serializer_class = UserSerializer

        async def accept(self, subprotocol=None):
            await super().accept()

        @action()
        async def update_username(self, pk=None, username=None, **kwargs):
            user = await database_sync_to_async(self.get_object)(pk=pk)
            user.username = username
            await database_sync_to_async(user.save)()
            return {'pk': pk}, 200

    class TestOtherConsumer(ObserverModelInstanceMixin,
                            GenericAsyncAPIConsumer):

        queryset = TestModel.objects.all()
        serializer_class = UserSerializer

        async def accept(self, subprotocol=None):
            await super().accept()

        @action()
        async def update_username(self, pk=None, name=None, **kwargs):
            tm = await database_sync_to_async(self.get_object)(pk=pk)
            tm.name = name
            await database_sync_to_async(tm.save)()
            return {'pk': pk}, 200

    assert not await database_sync_to_async(
        get_user_model().objects.all().exists)()

    # Test a normal connection
    communicator1 = WebsocketCommunicator(TestOtherConsumer, "/testws/")
    connected, _ = await communicator1.connect()
    assert connected

    # Test a normal connection
    communicator2 = WebsocketCommunicator(TestUserConsumer, "/testws/")
    connected, _ = await communicator2.connect()
    assert connected

    u1 = await database_sync_to_async(get_user_model().objects.create
                                      )(username='******',
                                        email='*****@*****.**')
    t1 = await database_sync_to_async(TestModel.objects.create)(name='test2')

    await communicator1.send_json_to({
        "action": "subscribe_instance",
        "pk": t1.id,
        "request_id": 4
    })

    response = await communicator1.receive_json_from()

    assert response == {
        "action": "subscribe_instance",
        "errors": [],
        "response_status": 201,
        "request_id": 4,
        "data": None
    }

    await communicator2.send_json_to({
        "action": "subscribe_instance",
        "pk": u1.id,
        "request_id": 4
    })

    response = await communicator2.receive_json_from()

    assert response == {
        "action": "subscribe_instance",
        "errors": [],
        "response_status": 201,
        "request_id": 4,
        "data": None
    }

    # update the user

    u1.username = '******'

    await database_sync_to_async(u1.save)()

    # user is updated
    await communicator2.receive_json_from()

    # test model is not
    assert await communicator1.receive_nothing()
Exemple #12
0
async def test_observer_model_instance_mixin_with_many_subs(settings):
    """
    This tests when there are 2 instances subscribed to on the same consumer.
    """

    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumerMultipleSubs(ObserverModelInstanceMixin,
                                   GenericAsyncAPIConsumer):

        queryset = get_user_model().objects.all()
        serializer_class = UserSerializer

        async def accept(self, subprotocol=None):
            await super().accept()

        @action()
        async def update_username(self, pk=None, username=None, **kwargs):
            user = await database_sync_to_async(self.get_object)(pk=pk)
            user.username = username
            await database_sync_to_async(user.save)()
            return {"pk": pk}, 200

    assert not await database_sync_to_async(
        get_user_model().objects.all().exists)()

    # Test a normal connection
    communicator = WebsocketCommunicator(TestConsumerMultipleSubs(),
                                         "/testws/")
    connected, _ = await communicator.connect()
    assert connected

    u1 = await database_sync_to_async(get_user_model().objects.create
                                      )(username="******",
                                        email="*****@*****.**")

    u2 = await database_sync_to_async(get_user_model().objects.create
                                      )(username="******",
                                        email="*****@*****.**")

    # Subscribe to instance user 1
    await communicator.send_json_to({
        "action": "subscribe_instance",
        "pk": u1.id,
        "request_id": 4
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "subscribe_instance",
        "errors": [],
        "response_status": 201,
        "request_id": 4,
        "data": None,
    }

    # Subscribe to instance user 2
    await communicator.send_json_to({
        "action": "subscribe_instance",
        "pk": u2.id,
        "request_id": 5
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "subscribe_instance",
        "errors": [],
        "response_status": 201,
        "request_id": 5,
        "data": None,
    }

    # lookup up u1
    await communicator.send_json_to({
        "action": "update_username",
        "pk": u1.id,
        "username": "******",
        "request_id": 10,
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "update_username",
        "errors": [],
        "response_status": 200,
        "request_id": 10,
        "data": {
            "pk": u1.id
        },
    }

    response = await communicator.receive_json_from()

    assert response == {
        "action": "update",
        "errors": [],
        "response_status": 200,
        "request_id": 4,
        "data": {
            "email": "*****@*****.**",
            "id": u1.id,
            "username": "******"
        },
    }

    assert await communicator.receive_nothing()

    # Update U2
    await communicator.send_json_to({
        "action": "update_username",
        "pk": u2.id,
        "username": "******",
        "request_id": 11,
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "update_username",
        "errors": [],
        "response_status": 200,
        "request_id": 11,
        "data": {
            "pk": u2.id
        },
    }

    response = await communicator.receive_json_from()

    assert response == {
        "action": "update",
        "errors": [],
        "response_status": 200,
        "request_id": 5,
        "data": {
            "email": "*****@*****.**",
            "id": u2.id,
            "username": "******"
        },
    }

    await communicator.disconnect()
Exemple #13
0
async def test_observer_model_instance_mixin(settings):
    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumer(ObserverModelInstanceMixin, GenericAsyncAPIConsumer):

        queryset = get_user_model().objects.all()
        serializer_class = UserSerializer

        async def accept(self, subprotocol=None):
            await super().accept()

        @action()
        async def update_username(self, pk=None, username=None, **kwargs):
            user = await database_sync_to_async(self.get_object)(pk=pk)
            user.username = username
            await database_sync_to_async(user.save)()
            return {"pk": pk}, 200

    assert not await database_sync_to_async(
        get_user_model().objects.all().exists)()

    # Test a normal connection
    communicator = WebsocketCommunicator(TestConsumer(), "/testws/")
    connected, _ = await communicator.connect()
    assert connected

    await communicator.send_json_to({
        "action": "retrieve",
        "pk": 100,
        "request_id": 1
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "retrieve",
        "errors": ["Not found"],
        "response_status": 404,
        "request_id": 1,
        "data": None,
    }

    u1 = await database_sync_to_async(get_user_model().objects.create
                                      )(username="******",
                                        email="*****@*****.**")
    u2 = await database_sync_to_async(get_user_model().objects.create
                                      )(username="******",
                                        email="*****@*****.**")

    # lookup a pk that is not there
    await communicator.send_json_to({
        "action": "retrieve",
        "pk": u1.id - 1,
        "request_id": 1
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "retrieve",
        "errors": ["Not found"],
        "response_status": 404,
        "request_id": 1,
        "data": None,
    }

    # lookup up u1
    await communicator.send_json_to({
        "action": "retrieve",
        "pk": u1.id,
        "request_id": 1
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "retrieve",
        "errors": [],
        "response_status": 200,
        "request_id": 1,
        "data": {
            "email": "*****@*****.**",
            "id": u1.id,
            "username": "******"
        },
    }

    # lookup up u1
    await communicator.send_json_to({
        "action": "subscribe_instance",
        "pk": u1.id,
        "request_id": 4
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "subscribe_instance",
        "errors": [],
        "response_status": 201,
        "request_id": 4,
        "data": None,
    }

    u3 = await database_sync_to_async(get_user_model().objects.create
                                      )(username="******",
                                        email="*****@*****.**")

    # lookup up u1
    await communicator.send_json_to({
        "action": "update_username",
        "pk": u1.id,
        "username": "******",
        "request_id": 5,
    })

    response = await communicator.receive_json_from()

    assert response == {
        "action": "update_username",
        "errors": [],
        "response_status": 200,
        "request_id": 5,
        "data": {
            "pk": u1.id
        },
    }

    response = await communicator.receive_json_from()

    assert response == {
        "action": "update",
        "errors": [],
        "response_status": 200,
        "request_id": 4,
        "data": {
            "email": "*****@*****.**",
            "id": u1.id,
            "username": "******"
        },
    }

    u1_pk = u1.pk

    await database_sync_to_async(u1.delete)()

    response = await communicator.receive_json_from()

    assert response == {
        "action": "delete",
        "errors": [],
        "response_status": 204,
        "request_id": 4,
        "data": {
            "pk": u1_pk
        },
    }

    await communicator.disconnect()
async def test_model_observer_many_consumers_wrapper(settings):
    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumer(AsyncAPIConsumer):
        async def accept(self, **kwargs):
            await self.user_change_many_consumers_wrapper_1.subscribe()
            await super().accept()

        @model_observer(get_user_model())
        async def user_change_many_consumers_wrapper_1(self,
                                                       message,
                                                       action,
                                                       message_type,
                                                       observer=None,
                                                       **kwargs):
            await self.send_json(
                dict(body=message, action=action, type=message_type))

    class TestConsumer2(AsyncAPIConsumer):
        async def accept(self, **kwargs):
            await self.user_change_many_consumers_wrapper_2.subscribe()
            await super().accept()

        @model_observer(get_user_model())
        async def user_change_many_consumers_wrapper_2(self,
                                                       message,
                                                       action,
                                                       message_type,
                                                       observer=None,
                                                       **kwargs):
            await self.send_json(
                dict(body=message, action=action, type=message_type))

    communicator1 = WebsocketCommunicator(TestConsumer(), "/testws/")

    connected, _ = await communicator1.connect()

    assert connected

    communicator2 = WebsocketCommunicator(TestConsumer2(), "/testws/")

    connected, _ = await communicator2.connect()

    assert connected

    user = await database_sync_to_async(get_user_model().objects.create
                                        )(username="******",
                                          email="*****@*****.**")

    response = await communicator1.receive_json_from()

    assert {
        "action": "create",
        "body": {
            "pk": user.pk
        },
        "type": "user.change.many.consumers.wrapper.1",
    } == response

    await communicator1.disconnect()

    response = await communicator2.receive_json_from()

    assert {
        "action": "create",
        "body": {
            "pk": user.pk
        },
        "type": "user.change.many.consumers.wrapper.2",
    } == response

    await communicator2.disconnect()
async def test_model_observer_with_class_serializer(settings):
    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = get_user_model()
            fields = ['id', 'username']

    class TestConsumerObserverUsers(AsyncAPIConsumer):
        async def accept(self, **kwargs):
            await self.users_changes.subscribe()
            await super().accept()

        @model_observer(get_user_model(), serializer_class=UserSerializer)
        async def users_changes(self, message, action, **kwargs):
            await self.reply(data=message, action=action)

    communicator = WebsocketCommunicator(TestConsumerObserverUsers(),
                                         "/testws/")

    connected, _ = await communicator.connect()

    assert connected

    user = await database_sync_to_async(get_user_model().objects.create
                                        )(username="******",
                                          email="*****@*****.**")

    response = await communicator.receive_json_from()

    assert {
        "action": "create",
        "response_status": 200,
        "request_id": None,
        "errors": [],
        "data": {
            "id": user.pk,
            "username": user.username,
        },
    } == response

    user.username = "******"
    await database_sync_to_async(user.save)()

    response = await communicator.receive_json_from()

    assert {
        "action": "update",
        "response_status": 200,
        "request_id": None,
        "errors": [],
        "data": {
            "id": user.pk,
            "username": user.username,
        },
    } == response

    pk = user.pk
    await database_sync_to_async(user.delete)()

    response = await communicator.receive_json_from()

    assert {
        "action": "delete",
        "response_status": 200,
        "request_id": None,
        "errors": [],
        "data": {
            "id": pk,
            "username": user.username,
        },
    } == response

    await communicator.disconnect()
async def test_model_observer_with_request_id(settings):
    settings.CHANNEL_LAYERS = {
        "default": {
            "BACKEND": "channels.layers.InMemoryChannelLayer",
            "TEST_CONFIG": {
                "expiry": 100500,
            },
        },
    }

    layer = channel_layers.make_test_backend(DEFAULT_CHANNEL_LAYER)

    class TestConsumerObserverCustomGroups(AsyncAPIConsumer):
        @action()
        async def subscribe(self, username, request_id, **kwargs):
            await self.user_change_custom_groups.subscribe(
                username=username, request_id=request_id)

        @model_observer(get_user_model())
        async def user_change_custom_groups(self,
                                            message,
                                            action,
                                            message_type,
                                            observer=None,
                                            subscribing_request_ids=None,
                                            **kwargs):
            await self.send_json(
                dict(
                    body=message,
                    action=action,
                    type=message_type,
                    subscribing_request_ids=subscribing_request_ids,
                ))

        @user_change_custom_groups.groups_for_signal
        def user_change_custom_groups(self, instance=None, **kwargs):
            yield "-instance-username-{}".format(instance.username)

        @user_change_custom_groups.groups_for_consumer
        def user_change_custom_groups(self, username=None, **kwargs):
            yield "-instance-username-{}".format(slugify(username))

    communicator = WebsocketCommunicator(TestConsumerObserverCustomGroups(),
                                         "/testws/")

    connected, _ = await communicator.connect()

    assert connected

    await communicator.send_json_to({
        "action": "subscribe",
        "username": "******",
        "request_id": 5,
    })

    user = await database_sync_to_async(get_user_model().objects.create
                                        )(username="******",
                                          email="*****@*****.**")

    response = await communicator.receive_json_from()

    assert {
        "action": "create",
        "body": {
            "pk": user.pk
        },
        "type": "user.change.custom.groups",
        "subscribing_request_ids": [5],
    } == response

    await communicator.disconnect()