Django Channels Postgres InterfaceError: соединение уже закрыто - PullRequest
0 голосов
/ 15 января 2019

Я не могу обернуться вокруг этой проблемы. Я пишу тесты для моих потребителей каналов, следуя описанию в документации . Обычно я использую юнит-тест по умолчанию в Django, но так как для каналов требуется использование pytest, я использую его, но все равно хотел бы поддерживать структуру классов написания тестов.

У меня были проблемы с написанием метода настройки, аналогичного unittest, который я использовал бы для инициализации атрибутов теста. Я пробовал фиксации метода , фиксации класса с использованием autouse = true , но ни одна из них не работала, так как я не мог получить доступ к атрибутам экземпляра в тестовых методах. Наконец, я просто решил написать экземплярный метод set_up и вручную вызывать его для каждого класса. Это то, что я до сих пор:

@pytest.mark.django_db
@pytest.mark.asyncio
class TestChatConsumer(object):

    @database_sync_to_async
    def set_up(self):

        self.user = UserFactory()
        self.api_client = APIClientFactory()
        self.token = TokenFactory(user=self.user)

        self.credentials = {
            'AUTHORIZATION': self.token.key,
            ...
        }

        self.credentials_params = '&'.join(['{}={}'.format(k, v) for k, v in self.credentials.items()])
        self.authless_endpoint = '/api/v1/ws/'
        self.endpoint = self.authless_endpoint + '?' + self.credentials_params

    async def test_connect_without_credentials(self):
        await self.set_up()
        communicator = WebsocketCommunicator(application, self.authless_endpoint)
        connected, subprotocol = await communicator.connect()
        assert not connected

    async def test_connect_with_credentials(self):
        await self.set_up()
        communicator = WebsocketCommunicator(application, self.endpoint)
        connected, subprotocol = await communicator.connect()
        assert connected

Проблема в том, что я продолжаю получать psycopg2.InterfaceError: connection already closed, когда мой потребитель пытается получить доступ к базе данных в своем коде внутри метода connect. Он использует database_sync_to_async и работает довольно хорошо, когда я тестирую его вручную.

В частности, строка в методе connect, которая вызывает ошибку, выглядит следующим образом:

await database_sync_to_async(user.inbox.increment_connections)().

Не уверен, что именно проблема заключается в том, что database_sync_to_async должен должным образом очистить старые соединения, чтобы новые могли быть правильно созданы.

Любая помощь будет очень признательна.

1 Ответ

0 голосов
/ 15 января 2019

Видимо, я искал не в том месте. Проблема была в этой строке:

await database_sync_to_async(user.inbox.increment_connections)().

inbox является связанным менеджером, поэтому он пытается получить его до фактического database_sync_to_async, и он терпит неудачу, так как требует вызова db.

Я попробовал это await database_sync_to_async(user).inbox.increment_connections(), и оно не сработало, так как оно оборачивает метод, а не атрибут, поэтому в итоге я использовал prefetch_related, чтобы получить inbox во время аутентификации. Таким образом, user.inbox больше не требует вызова базы данных, и он отлично работает

...