#Testing Login function (JWT base Auth) return "sys:1: SAWarning: The garbage collector [...]"

1 messages ยท Page 1 of 1 (latest)

uneven scaffold
#

Hi guys ! Putting this to reference this issue, not solution yet.

Running this test return a warning and not push data into DB :

pytestmark = pytest.mark.anyio

#remove trio from tests
@pytest.fixture(scope="session")
def anyio_backend() -> str:
    return "asyncio"


@pytest.fixture(scope="function")
async def test_client() -> AsyncIterator[AsyncTestClient[Litestar]]:
    async with AsyncTestClient(app=test_app) as client:
        yield client


class TestAccess:

    jwt_token:str = None

    async def test_create_access(self, test_client: AsyncTestClient[Litestar]) -> None:
        data = {
            "email": "[email protected]",
            "password": "Pouet123!"
        }
        response = await test_client.post(urls.ACCESS_REGISTER, json=data)
        assert response.status_code == status_codes.HTTP_201_CREATED


    async def test_login_access(self, test_client: AsyncTestClient[Litestar]) -> None:
        data = {
            "email": "[email protected]",
            "password": "Pouet123!"
        }
        response = await test_client.post(urls.ACCESS_LOGIN, data=data) #need to login with formdata and not json
        self.jwt_token = response.headers['authorization']

        assert response.status_code == status_codes.HTTP_201_CREATED

The error : sys:1: SAWarning: The garbage collector is trying to clean up non-checked-in connection <AdaptedConnection <Connection(Thread-3, stopped daemon 1216)>>, which will be dropped, as it cannot be safely terminated. Please ensure that SQLAlchemy pooled connections are returned to the pool explicitly, either by calling close() or by using appropriate context managers to manage their lifecycle.

slender sluiceBOT
#
Notes for Testing Login function (JWT base Auth) return "sys:1: SAWarning: The garbage collector [...]"
At your assistance

@uneven scaffold

No Response?

If no response in a reasonable time, ping @Member.

Closing

To close, type !solve or byte solve.

MCVE

Please include an MCVE so that we can reproduce your issue locally.

eager finch
#

It's hard to say what's going on without seeing how you create the app, but it seems to be related to how you're setting up your app / SQLAlchemy

#

A general word of advice: Don't use async in your tests unless you absolutely have to. Neither anyio nor pytest-asyncio are a great experience to work with an can cause a lot of unnecessary headaches. If you're just using the test client, the synchronous one will work just as well

uneven scaffold
#

thinking that it was necessary to test the app on async mode if it's defined as async

eager finch
eager finch
uneven scaffold
# eager finch No, it's not. The sync test client creates its own async environment in which th...

๐Ÿ˜ฎ Btw same warning on sync declaring my app like this :

db_config = SQLAlchemyAsyncConfig(
    connection_string=os.getenv("TEST_DATABASE_URL"),
    metadata=UUIDAuditBase.metadata,
    before_send_handler=autocommit_before_send_handler, #autocommit set to TRUE, commit before send response
)

test_app = Litestar(route_handlers=routers,
    on_app_init=[jwt_auth.on_app_init],
    cors_config = settings.cors_config,
    openapi_config = settings.openapi_config,
    plugins = [
        SQLAlchemyPlugin(db_config)
    ],
    dependencies = dependencies,
    debug = os.getenv("DEBUG"))
uneven scaffold
#

generate an .sqlite-journal file btw

uneven scaffold
eager finch
#

Are the tests failing?

uneven scaffold
#

nope, the two are passed

eager finch
#

Can you try to create a minimal, reproducible example?

uneven scaffold
#

i will

uneven scaffold
#
from typing import TYPE_CHECKING

from litestar import Litestar

from litestar.contrib.sqlalchemy.plugins import SQLAlchemyAsyncConfig, SQLAlchemyPlugin
from advanced_alchemy.extensions.litestar.plugins.init.config.asyncio import autocommit_before_send_handler
from litestar.contrib.sqlalchemy.base import UUIDAuditBase

from app import cors_config, openapi_config
from dotenv import load_dotenv
import os
from litestar.di import Provide
from app import jwt_auth, dependencies, routers

load_dotenv() #load all .env variables into file


db_config = SQLAlchemyAsyncConfig(
    connection_string='sqlite+aiosqlite:///TEST_db.sqlite',
    metadata=UUIDAuditBase.metadata,
    before_send_handler=autocommit_before_send_handler, #autocommit set to TRUE, commit before send response
)

test_app = Litestar(route_handlers=routers,
    on_app_init=[jwt_auth.on_app_init],
    cors_config = cors_config,
    openapi_config = openapi_config,
    plugins = [
        SQLAlchemyPlugin(db_config)
    ],
    dependencies = dependencies,
    debug = 'True')

test app settings

#
import pytest

from litestar import status_codes
from litestar.testing import TestClient

from litestar.status_codes import HTTP_200_OK

from litestar import Litestar, MediaType, get
from collections.abc import AsyncIterator

from tests.setup import test_app
from app import ACCESS_LOGIN, ACCESS_REGISTER, ACCESS_LOGOUT

from collections.abc import Iterator


@pytest.fixture(scope="function")
def test_client() -> Iterator[TestClient[Litestar]]:
    with TestClient(app=test_app) as client:
        yield client


## USER CRUD
class TestClass:

    jwt_token:str = None

    def test_create_access(self, test_client: TestClient[Litestar]) -> None:
        data = {
            "email": "[email protected]",
            "password": "Pouet123!"
        }
        response = test_client.post(ACCESS_REGISTER, json=data)
        print(response, response.content, response.headers) 
        assert response.status_code == status_codes.HTTP_201_CREATED


    def test_login_access(self, test_client: TestClient[Litestar]) -> None:
        data = {
            "email": "[email protected]",
            "password": "Pouet123!"
        }
        response = test_client.post(ACCESS_LOGIN, data=data) #need to login with formdata and not json
        print(response, response.content, response.headers) 
        self.jwt_token = response.headers['authorization']

        assert response.status_code == status_codes.HTTP_201_CREATED

TEST file runned by pytest

uneven scaffold
eager finch
# uneven scaffold hope it's enought "minimal", not perfect tho but removed stuff

I'll check it out later, but just some quick tips for creating MCVEs:
You should generally only include stuff that's necessary to replicate the behaviour. You have included a lot of things like models, that aren't necessary. e.g. you could have slimmed down your DB model to just one field. Ideally, everything fits into one self contained file, which someone can just execute as is. That also means not using things like .env files, as others don't have access to them

#

The purpose isn't just that it's less work for people trying to solve your issue, but quite often, slimming an issue down to such a degree can also give you a hint as to what's going on, and sometimes even fix the thing outright. It's a great thing to do when debugging in general ๐Ÿ™‚

#

After skimming through it, I'm not seeing anything egregiously wrong. Can you try changing the scope of your test client fixture to session?

uneven scaffold
eager finch
#

No worries ๐Ÿ™‚

uneven scaffold
#

got this warning too, maybe it helo :

venv\lib\site-packages\litestar\app.py:567
  C:\...\litestar_test\venv\lib\site-packages\litestar\app.py:567: PytestCollectionWarning: cannot collect 'test_app' because it is not a function.
    async def __call__(

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
eager finch
#

Ha

#

Maybe, but I don't think so. What's happening though is that pytest thinks this is something it should test, since it starts with the test_ prefix

uneven scaffold
eager finch
#

It doesn't affect your original issue tho, right?

uneven scaffold
#

nope, doesn't affect it

uneven scaffold
uneven scaffold
# eager finch It doesn't affect your original issue tho, right?

Find a solution :

  • Disable before_send_handler=async_autocommit_before_send_handler on db_config (SQLAlchemyAsyncConfig)
  • Specify on Service SQLAlchemyAsyncRepositoryService auto_commit: bool | None = True, instead of auto_commit: bool | None = None,

Don't know if I've found a bug or misunderstand how it work but there we go

blissful hedge
#

can you change this to

#
before_send_handler='autocommit'
uneven scaffold
blissful hedge
#

The way the autocommit handler was modified in recent versions to enable multi-database support. You can now supply a list of SQLAlchemyConfigs into the plugin each with a distinct session key

#

I'd have to look at exactly why that happened like that, but IIRC, the default handler may need to be updated depending on your config.

#

anyway, but because the session is in a different key than it expects

#

the test teardown doesn't actually tear down correctly

#

which is why you are seeing the warning re the garbage collection