Hybrid fixture providing real asyncio primitives + mock browser boundaries. Use this for tests that need real lock/queue behavior but don't need a real browser. This is useful for testing concurrency without the overhead of integration tests. Provides: - REAL asyncio.Lock inst
()
| 325 | |
| 326 | @pytest.fixture |
| 327 | def real_locks_mock_browser(): |
| 328 | """ |
| 329 | Hybrid fixture providing real asyncio primitives + mock browser boundaries. |
| 330 | |
| 331 | Use this for tests that need real lock/queue behavior but don't need a real browser. |
| 332 | This is useful for testing concurrency without the overhead of integration tests. |
| 333 | |
| 334 | Provides: |
| 335 | - REAL asyncio.Lock instances (processing_lock, model_switching_lock, params_cache_lock) |
| 336 | - REAL asyncio.Queue (request_queue) |
| 337 | - MOCK browser/page (external I/O boundaries) |
| 338 | |
| 339 | Use when: |
| 340 | - Testing lock contention and mutual exclusion |
| 341 | - Testing queue processing without full integration |
| 342 | - Need real async behavior but not real browser |
| 343 | |
| 344 | Don't use when: |
| 345 | - Testing pure logic (use regular fixtures) |
| 346 | - Testing full request flow (use real_server_state from integration conftest) |
| 347 | |
| 348 | Example: |
| 349 | async def test_lock_behavior(real_locks_mock_browser): |
| 350 | async with real_locks_mock_browser.processing_lock: |
| 351 | # This actually blocks other tasks |
| 352 | await some_operation() |
| 353 | """ |
| 354 | from api_utils.server_state import state |
| 355 | |
| 356 | # Reset state to clean slate |
| 357 | state.reset() |
| 358 | |
| 359 | # Create REAL asyncio primitives |
| 360 | state.processing_lock = asyncio.Lock() |
| 361 | state.model_switching_lock = asyncio.Lock() |
| 362 | state.params_cache_lock = asyncio.Lock() |
| 363 | state.request_queue = asyncio.Queue() |
| 364 | |
| 365 | # Mock only external boundaries (browser/page - these are I/O) |
| 366 | mock_page = AsyncMock() |
| 367 | mock_page.goto = AsyncMock() |
| 368 | mock_page.wait_for_selector = AsyncMock() |
| 369 | mock_page.click = AsyncMock() |
| 370 | mock_page.fill = AsyncMock() |
| 371 | mock_page.evaluate = AsyncMock() |
| 372 | mock_page.locator = MagicMock(return_value=MagicMock()) |
| 373 | mock_page.is_closed = MagicMock(return_value=False) # Page is open |
| 374 | |
| 375 | mock_browser = AsyncMock() |
| 376 | mock_browser.close = AsyncMock() |
| 377 | |
| 378 | state.page_instance = mock_page |
| 379 | state.browser_instance = mock_browser |
| 380 | state.is_page_ready = True |
| 381 | state.is_browser_connected = True |
| 382 | |
| 383 | yield state |
| 384 |