Skip to content

fix: add a AsyncTestClientTransport for the AsyncTestClient #4142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: main
Choose a base branch
from

Conversation

euri10
Copy link
Contributor

@euri10 euri10 commented Apr 24, 2025

Description

Closes

fixes #1920

Copy link

codecov bot commented Apr 24, 2025

Codecov Report

Attention: Patch coverage is 85.71429% with 4 lines in your changes missing coverage. Please review.

Project coverage is 98.35%. Comparing base (6225a82) to head (4dffcb5).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
litestar/testing/transport.py 85.18% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4142      +/-   ##
==========================================
- Coverage   98.37%   98.35%   -0.02%     
==========================================
  Files         348      348              
  Lines       15845    15861      +16     
  Branches     1749     1750       +1     
==========================================
+ Hits        15587    15600      +13     
- Misses        123      127       +4     
+ Partials      135      134       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@euri10 euri10 marked this pull request as draft April 24, 2025 07:38
Copy link

Documentation preview will be available shortly at https://litestar-org.github.io/litestar-docs-preview/4142

@euri10
Copy link
Contributor Author

euri10 commented Apr 24, 2025

any idea how to cover this ? I dont understand why it pops now though

@euri10 euri10 marked this pull request as ready for review April 24, 2025 14:31

app = Litestar(route_handlers=[return_loop_id])

async with AsyncTestClient(app) as client_1, AsyncTestClient(app) as client_2:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should even be the same loop with different client instances, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think so, this added test is just the mcve from the issue and it fails before the changes, is there something I should add ?

Copy link
Contributor Author

@euri10 euri10 Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize the diff is overly complicate, the PR is simple: before AsyncTestClient used TestClientTransport hence the issue.
so I created a BaseClientTransport that essentially takes care of request/response and added a ASGITestClientTransport that inherits httpx ASGIBaseTransport and overrides handle_async_request while TestClientTransport overrides handle_request, the BaseClientTransport is what's common between the 2 transports.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think so, this added test is just the mcve from the issue and it fails before the changes, is there something I should add ?

Yeah, maybe a test for the transport in particular that shows the client always uses the currently running loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually if this test was using TestClient instead of AsyncTestClient it wouldn't pass as start_blocking_portal creates a new event loop.

This should even be the same loop with different client instances, right?

by different client instances you meant a AsyncTestClient and a TestClient ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I mean different instances AsyncClient. But actually, I think the test should probably just show that the client uses the running loop from the context it's created in.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this refactoring done, I think you actually don't even need 2 transports. The sync version could just do

with self.client.portal() as portal:
    return portal.call(self.handle_async_request, request)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the benefit of having 2 transports is that they respectively inherit their httpx counterparts so I think it's a little bit more mypy friendly but I may be wrong

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, that makes sense. Maybe could still move the request handling fn into the common base class?

@provinzkraut
Copy link
Member

I don't think the behaviour is fully fixed yet, as the LifespanHandler still uses a portal.

async def test_lifespan_loop() -> None:
    mock = MagicMock()

    @contextlib.asynccontextmanager
    async def lifespan(app: Litestar) -> AsyncGenerator[None, None]:
        mock(asyncio.get_running_loop())
        yield

    app = Litestar(lifespan=[lifespan])

    async with AsyncTestClient(app):
        pass

    mock.assert_called_once_with(asyncio.get_running_loop())

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Bug: the app for test client is running in a different event loop
2 participants