@@ -1080,10 +1080,10 @@ def _spy_factory():
10801080
10811081@pytest .mark .asyncio
10821082async def test_concurrent_prepare_tables_no_race_condition ():
1083- """Verifies that concurrent calls to _prepare_tables wait for table creation.
1083+ """Verifies that concurrent calls to prepare_tables wait for table creation.
10841084 Reproduces the race condition from
10851085 https://github.com/google/adk-python/issues/4445: when concurrent requests
1086- arrive at startup, _prepare_tables must not return before tables exist.
1086+ arrive at startup, prepare_tables must not return before tables exist.
10871087 Previously, the early-return guard checked _db_schema_version (set during
10881088 schema detection) instead of _tables_created, so a second request could
10891089 slip through after schema detection but before table creation finished.
@@ -1096,7 +1096,7 @@ async def test_concurrent_prepare_tables_no_race_condition():
10961096
10971097 # Launch several concurrent create_session calls, each with a unique
10981098 # app_name to avoid IntegrityError on the shared app_states row.
1099- # Each will call _prepare_tables internally. If the race condition
1099+ # Each will call prepare_tables internally. If the race condition
11001100 # exists, some of these will fail because the "sessions" table doesn't
11011101 # exist yet.
11021102 num_concurrent = 5
@@ -1114,7 +1114,7 @@ async def test_concurrent_prepare_tables_no_race_condition():
11141114 for i , result in enumerate (results ):
11151115 assert not isinstance (result , BaseException ), (
11161116 f'Concurrent create_session #{ i } raised { result !r} ; tables were'
1117- ' likely not ready due to the _prepare_tables race condition.'
1117+ ' likely not ready due to the prepare_tables race condition.'
11181118 )
11191119
11201120 # All sessions should be retrievable.
@@ -1133,17 +1133,17 @@ async def test_concurrent_prepare_tables_no_race_condition():
11331133async def test_prepare_tables_serializes_schema_detection_and_creation ():
11341134 """Verifies schema detection and table creation happen atomically under one
11351135 lock, so concurrent callers cannot observe a partially-initialized state.
1136- After _prepare_tables completes, both _db_schema_version and _tables_created
1136+ After prepare_tables completes, both _db_schema_version and _tables_created
11371137 must be set.
11381138 """
11391139 service = DatabaseSessionService ('sqlite+aiosqlite:///:memory:' )
11401140 try :
11411141 assert not service ._tables_created
11421142 assert service ._db_schema_version is None
11431143
1144- await service ._prepare_tables ()
1144+ await service .prepare_tables ()
11451145
1146- # Both must be set after a single _prepare_tables call.
1146+ # Both must be set after a single prepare_tables call.
11471147 assert service ._tables_created
11481148 assert service ._db_schema_version is not None
11491149
@@ -1159,17 +1159,17 @@ async def test_prepare_tables_serializes_schema_detection_and_creation():
11591159
11601160@pytest .mark .asyncio
11611161async def test_prepare_tables_idempotent_after_creation ():
1162- """Calling _prepare_tables multiple times is safe and idempotent.
1162+ """Calling prepare_tables multiple times is safe and idempotent.
11631163 After tables are created, subsequent calls should return immediately via
11641164 the fast path without errors.
11651165 """
11661166 service = DatabaseSessionService ('sqlite+aiosqlite:///:memory:' )
11671167 try :
1168- await service ._prepare_tables ()
1168+ await service .prepare_tables ()
11691169 assert service ._tables_created
11701170
11711171 # Call again — should be a no-op via the fast path.
1172- await service ._prepare_tables ()
1172+ await service .prepare_tables ()
11731173 assert service ._tables_created
11741174
11751175 # Service should still work.
@@ -1181,6 +1181,33 @@ async def test_prepare_tables_idempotent_after_creation():
11811181 await service .close ()
11821182
11831183
1184+ @pytest .mark .asyncio
1185+ async def test_public_prepare_tables_eager_initialization ():
1186+ """Calling the public prepare_tables() eagerly initializes tables so that
1187+ the first real database operation does not pay the setup cost.
1188+ """
1189+ service = DatabaseSessionService ('sqlite+aiosqlite:///:memory:' )
1190+ try :
1191+ # Before calling prepare_tables, tables are not created.
1192+ assert not service ._tables_created
1193+ assert service ._db_schema_version is None
1194+
1195+ # Eagerly prepare tables via the public API.
1196+ await service .prepare_tables ()
1197+
1198+ # Tables should now be ready.
1199+ assert service ._tables_created
1200+ assert service ._db_schema_version is not None
1201+
1202+ # Subsequent operations should work without any additional setup cost.
1203+ session = await service .create_session (
1204+ app_name = 'app' , user_id = 'user' , session_id = 's1'
1205+ )
1206+ assert session .id == 's1'
1207+ finally :
1208+ await service .close ()
1209+
1210+
11841211@pytest .mark .asyncio
11851212@pytest .mark .parametrize (
11861213 'state_delta, expect_app_lock, expect_user_lock' ,
0 commit comments