Repository: dialoguemd/fastapi-sqla (language: python)

Issue:
fix: table reflection with async db url - DIA-51295
## Description 

* Table reflection does not work when using async sqlalchemy configuration with `sqlalchemy>=2.0.0`;
* It was not discovered by tests: I noticed it when trying to upgrade a project to `fastapi-sqla=2.8.0` and   `sqlalchemy>=2.0.0`;
* It worked in tests because the fixture `async_session` depended on `sqla_reflection` which would run reflection in synchronous mode; Any subsequent call to `Base.prepare` to do reflection would do nothing as reflection already occurred in test setup;
* Added a `async_sqla_reflection` fixture to make async tests fail;
* Added an integration folder in tests and added a set of test in async mode; Will continue in other PRs to reorganize tests;
* Updated tearing down configured sqla mappers & metadata in tests;
* Renamed tables created in test to ease troubleshooting;

### TODO:

* [x] Reproduce bug in test
* [x] Fix it

## Related

* #76 
* [DIA-51295]


[DIA-51295]: https://dialoguemd.atlassian.net/browse/DIA-51295?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ


Discussion / hints:
# [Codecov](https://codecov.io/gh/dialoguemd/fastapi-sqla/pull/81?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd) Report
> Merging [#81](https://codecov.io/gh/dialoguemd/fastapi-sqla/pull/81?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd) (7350058) into [master](https://codecov.io/gh/dialoguemd/fastapi-sqla/commit/6758175b8513058db322a8d2b0591b3fb4f5df14?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd) (6758175) will **not change** coverage.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff            @@
##            master       #81   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            6         6           
  Lines          398       404    +6     
  Branches        48        52    +4     
=========================================
+ Hits           398       404    +6     
```

| Flag | Coverage Δ | |
|---|---|---|
| python_version3.10-sqlalchemy1.3-asyncpg-aws_rds_iam | `65.34% <30.76%> (-0.99%)` | :arrow_down: |
| python_version3.10-sqlalchemy1.3-asyncpg-noaws_rds_iam | `63.36% <30.76%> (-0.96%)` | :arrow_down: |
| python_version3.10-sqlalchemy1.3-noasyncpg-aws_rds_iam | `65.09% <30.76%> (-0.99%)` | :arrow_down: |
| python_version3.10-sqlalchemy1.3-noasyncpg-noaws_rds_iam | `63.11% <30.76%> (-0.96%)` | :arrow_down: |
| python_version3.10-sqlalchemy1.4-asyncpg-aws_rds_iam | `96.78% <100.00%> (+0.55%)` | :arrow_up: |
| python_version3.10-sqlalchemy1.4-asyncpg-noaws_rds_iam | `94.80% <100.00%> (+0.58%)` | :arrow_up: |
| python_version3.10-sqlalchemy1.4-noasyncpg-aws_rds_iam | `77.72% <46.15%> (-0.42%)` | :arrow_down: |
| python_version3.10-sqlalchemy1.4-noasyncpg-noaws_rds_iam | `75.74% <46.15%> (-0.39%)` | :arrow_down: |
| python_version3.10-sqlalchemy2.0-asyncpg-aws_rds_iam | `96.03% <92.30%> (-0.20%)` | :arrow_down: |
| python_version3.10-sqlalchemy2.0-asyncpg-noaws_rds_iam | `94.05% <92.30%> (-0.17%)` | :arrow_down: |
| python_version3.10-sqlalchemy2.0-noasyncpg-aws_rds_iam | `76.98% <38.46%> (-1.17%)` | :arrow_down: |
| python_version3.10-sqlalchemy2.0-noasyncpg-noaws_rds_iam | `75.00% <38.46%> (-1.14%)` | :arrow_down: |
| python_version3.11-sqlalchemy1.3-asyncpg-aws_rds_iam | `65.34% <30.76%> (-0.99%)` | :arrow_down: |
| python_version3.11-sqlalchemy1.3-asyncpg-noaws_rds_iam | `63.36% <30.76%> (-0.96%)` | :arrow_down: |
| python_version3.11-sqlalchemy1.3-noasyncpg-aws_rds_iam | `65.09% <30.76%> (-0.99%)` | :arrow_down: |
| python_version3.11-sqlalchemy1.3-noasyncpg-noaws_rds_iam | `63.11% <30.76%> (-0.96%)` | :arrow_down: |
| python_version3.11-sqlalchemy1.4-asyncpg-aws_rds_iam | `96.78% <100.00%> (+0.55%)` | :arrow_up: |
| python_version3.11-sqlalchemy1.4-asyncpg-noaws_rds_iam | `94.80% <100.00%> (+0.58%)` | :arrow_up: |
| python_version3.11-sqlalchemy1.4-noasyncpg-aws_rds_iam | `77.72% <46.15%> (-0.42%)` | :arrow_down: |
| python_version3.11-sqlalchemy1.4-noasyncpg-noaws_rds_iam | `75.74% <46.15%> (-0.39%)` | :arrow_down: |
| python_version3.11-sqlalchemy2.0-asyncpg-aws_rds_iam | `96.03% <92.30%> (-0.20%)` | :arrow_down: |
| python_version3.11-sqlalchemy2.0-asyncpg-noaws_rds_iam | `94.05% <92.30%> (-0.17%)` | :arrow_down: |
| python_version3.11-sqlalchemy2.0-noasyncpg-aws_rds_iam | `76.98% <38.46%> (-1.17%)` | :arrow_down: |
| python_version3.11-sqlalchemy2.0-noasyncpg-noaws_rds_iam | `75.00% <38.46%> (-1.14%)` | :arrow_down: |
| python_version3.9-sqlalchemy1.3-asyncpg-aws_rds_iam | `65.34% <30.76%> (-0.99%)` | :arrow_down: |
| python_version3.9-sqlalchemy1.3-asyncpg-noaws_rds_iam | `63.36% <30.76%> (-0.96%)` | :arrow_down: |
| python_version3.9-sqlalchemy1.3-noasyncpg-aws_rds_iam | `65.09% <30.76%> (-0.99%)` | :arrow_down: |
| python_version3.9-sqlalchemy1.3-noasyncpg-noaws_rds_iam | `63.11% <30.76%> (-0.96%)` | :arrow_down: |
| python_version3.9-sqlalchemy1.4-asyncpg-aws_rds_iam | `96.78% <100.00%> (+0.55%)` | :arrow_up: |
| python_version3.9-sqlalchemy1.4-asyncpg-noaws_rds_iam | `94.80% <100.00%> (+0.58%)` | :arrow_up: |
| python_version3.9-sqlalchemy1.4-noasyncpg-aws_rds_iam | `77.72% <46.15%> (-0.42%)` | :arrow_down: |
| python_version3.9-sqlalchemy1.4-noasyncpg-noaws_rds_iam | `75.74% <46.15%> (-0.39%)` | :arrow_down: |
| python_version3.9-sqlalchemy2.0-asyncpg-aws_rds_iam | `96.03% <92.30%> (-0.20%)` | :arrow_down: |
| python_version3.9-sqlalchemy2.0-asyncpg-noaws_rds_iam | `94.05% <92.30%> (-0.17%)` | :arrow_down: |
| python_version3.9-sqlalchemy2.0-noasyncpg-aws_rds_iam | `76.98% <38.46%> (-1.17%)` | :arrow_down: |
| python_version3.9-sqlalchemy2.0-noasyncpg-noaws_rds_iam | `75.00% <38.46%> (-1.14%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/dialoguemd/fastapi-sqla/pull/81?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd) | Coverage Δ | |
|---|---|---|
| [fastapi\_sqla/\_pytest\_plugin.py](https://codecov.io/gh/dialoguemd/fastapi-sqla/pull/81?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd#diff-ZmFzdGFwaV9zcWxhL19weXRlc3RfcGx1Z2luLnB5) | `100.00% <100.00%> (ø)` | |
| [fastapi\_sqla/asyncio\_support.py](https://codecov.io/gh/dialoguemd/fastapi-sqla/pull/81?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd#diff-ZmFzdGFwaV9zcWxhL2FzeW5jaW9fc3VwcG9ydC5weQ==) | `100.00% <100.00%> (ø)` | |
| [fastapi\_sqla/sqla.py](https://codecov.io/gh/dialoguemd/fastapi-sqla/pull/81?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd#diff-ZmFzdGFwaV9zcWxhL3NxbGEucHk=) | `100.00% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dialoguemd)

Closing to simplify in another PR

Fix patch:
diff --git a/fastapi_sqla/asyncio_support.py b/fastapi_sqla/asyncio_support.py
index 642d11ed..d94f326c 100644
--- a/fastapi_sqla/asyncio_support.py
+++ b/fastapi_sqla/asyncio_support.py
@@ -45,7 +45,9 @@ async def startup():
         )
         raise
 
-    Base.prepare(engine.engine)
+    async with engine.connect() as connection:
+        await connection.run_sync(lambda conn: Base.prepare(conn.engine))
+
     _AsyncSession.configure(bind=engine, expire_on_commit=False)
     logger.info("startup", async_engine=engine)
 


Test patch:
diff --git a/fastapi_sqla/_pytest_plugin.py b/fastapi_sqla/_pytest_plugin.py
index 3ccec5b5..9eeb687b 100644
--- a/fastapi_sqla/_pytest_plugin.py
+++ b/fastapi_sqla/_pytest_plugin.py
@@ -178,7 +178,15 @@ async def patch_new_engine(async_sqlalchemy_url, async_sqla_connection, request)
                 yield new_engine
 
     @fixture
-    async def async_session(async_sqla_connection, sqla_reflection, patch_new_engine):
+    async def async_sqla_reflection(sqla_modules, async_sqla_connection):
+        from fastapi_sqla import Base
+
+        await async_sqla_connection.run_sync(lambda conn: Base.prepare(conn.engine))
+
+    @fixture
+    async def async_session(
+        async_sqla_connection, async_sqla_reflection, patch_new_engine
+    ):
         from fastapi_sqla.asyncio_support import _AsyncSession
 
         session = _AsyncSession(bind=async_sqla_connection)
diff --git a/tests/test_middleware.py b/tests/test_middleware.py
index c55c8c23..86819d3d 100644
--- a/tests/test_middleware.py
+++ b/tests/test_middleware.py
@@ -89,7 +89,7 @@ async def a_middleware(request, call_next):
 
 
 @fixture
-async def client(app):
+async def client(app, mock_middleware):
 
     async with LifespanManager(app):
         transport = httpx.ASGITransport(app=app, raise_app_exceptions=False)
diff --git a/tests/test_startup.py b/tests/test_startup.py
index d014df73..b7aeb595 100644
--- a/tests/test_startup.py
+++ b/tests/test_startup.py
@@ -126,6 +126,6 @@ async def test_async_startup_with_aws_rds_iam_enabled(
 
     await startup()
 
-    boto_client_mock.generate_db_auth_token.assert_called_once_with(
+    boto_client_mock.generate_db_auth_token.assert_called_with(
         DBHostname=db_host, Port=5432, DBUsername=db_user
     )