Why is this Django test opening so many database connections?

73 views Asked by At

I'm testing my Django REST API using Schemathesis and Django's built-in unittest. The code for my test suite is:

from contextlib import contextmanager

import schemathesis
from hypothesis import given, settings
from hypothesis.extra.django import LiveServerTestCase as HypothesisLiveServerTestCase

from my_app.api import api_v1
from my_app.tests import AuthTokenFactory

# 3 requests per second - `3/s`
# 100 requests per minute - `100/m`
# 1000 requests per hour - `1000/h`
# 10000 requests per day - `10000/d`
RATE_LIMIT = "10/s"

openapi_schema = api_v1.get_openapi_schema()


@contextmanager
def authenticated_strategy(strategy, token: str):
    @given(case=strategy)
    @settings(deadline=None)
    def f(case):
        case.call_and_validate(headers={"Authorization": f"Bearer {token}"})

    yield f


class TestApiSchemathesis(HypothesisLiveServerTestCase):
    """
    Tests the REST API using Schemathesis.

    It does this by spinning up a live server, and then uses Schemathesis to
    automatically generate schema-conforming requests to the API.
    """

    def setUp(self):
        super().setUp()
        self.schema = schemathesis.from_dict(
            openapi_schema, base_url=self.live_server_url, rate_limit=RATE_LIMIT
        )

    def test_api(self):
        """
        Loop over all API endpoints and methods, and runs property tests for each.
        """
        auth_token = AuthTokenFactory().token
        for endpoint in self.schema:
            for method in self.schema[endpoint]:
                with self.subTest(endpoint=f"{method.upper()} {endpoint}"):
                    strategy = self.schema[endpoint][method].as_strategy()
                    with authenticated_strategy(strategy, auth_token) as run_strategy:
                        run_strategy()

This has been running in CI just fine for a while, but now that I've added some new REST endpoints, I've started getting errors like:

psycopg2.OperationalError: connection to server at "localhost" (::1), port 5432 failed: FATAL:  sorry, too many clients already

and

django.db.utils.OperationalError: database "test_myapp" is being accessed by other users
DETAIL:  There are 99 other sessions using the database.

It seems like this test is opening too many connections to my app's database. I'm not sure whether that's because Django's LiveServerTestCase isn't closing DB connections properly, or because Schemathesis runs many tests in parallel and each request opens a new DB connection (that would surprise me).

How can I ensure that my test doesn't exhaust the database's connections? Or how can I debug this further?

0

There are 0 answers