peijun1's picture
Deploy AI Studio Proxy API to Hugging Face Spaces
a5784e9
Raw
History Blame Contribute Delete
13.1 kB
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from browser_utils.page_controller_modules.response import ResponseController
from models import ClientDisconnectedError
@pytest.fixture
def response_controller(mock_page):
logger = MagicMock()
req_id = "test_req_id"
return ResponseController(mock_page, logger, req_id)
@pytest.mark.asyncio
async def test_get_response_success(response_controller, mock_page):
"""Test successful response retrieval."""
check_client_disconnected = MagicMock(return_value=False)
expected_content = "Test response content"
# Mock locators
response_container = AsyncMock()
response_element = AsyncMock()
mock_page.locator.return_value.last = response_container
response_container.locator.return_value = response_element
# Mock helper functions
with (
patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect,
patch(
"browser_utils.page_controller_modules.response._wait_for_response_completion",
new_callable=AsyncMock,
) as mock_wait,
patch(
"browser_utils.page_controller_modules.response._get_final_response_content",
new_callable=AsyncMock,
) as mock_get_content,
):
mock_expect.return_value.to_be_attached = AsyncMock()
mock_wait.return_value = True
mock_get_content.return_value = expected_content
result = await response_controller.get_response(check_client_disconnected)
assert result == expected_content
mock_expect.return_value.to_be_attached.assert_called()
mock_wait.assert_called()
mock_get_content.assert_called()
@pytest.mark.asyncio
async def test_get_response_client_disconnected(response_controller, mock_page):
"""Test response retrieval with client disconnection."""
check_client_disconnected = MagicMock(
side_effect=lambda x: True
if "Retrieve Response - Response element attached" in x
else False
)
# Mock locators
response_container = AsyncMock()
response_element = AsyncMock()
mock_page.locator.return_value.last = response_container
response_container.locator.return_value = response_element
with patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect:
mock_expect.return_value.to_be_attached = AsyncMock()
with pytest.raises(ClientDisconnectedError):
await response_controller.get_response(check_client_disconnected)
@pytest.mark.asyncio
async def test_get_response_empty_content(response_controller, mock_page):
"""Test response retrieval when content is empty."""
check_client_disconnected = MagicMock(return_value=False)
# Mock locators
response_container = AsyncMock()
response_element = AsyncMock()
mock_page.locator.return_value.last = response_container
response_container.locator.return_value = response_element
with (
patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect,
patch(
"browser_utils.page_controller_modules.response._wait_for_response_completion",
new_callable=AsyncMock,
) as mock_wait,
patch(
"browser_utils.page_controller_modules.response._get_final_response_content",
new_callable=AsyncMock,
) as mock_get_content,
patch(
"browser_utils.page_controller_modules.response.save_error_snapshot",
new_callable=AsyncMock,
) as mock_save_snapshot,
):
mock_expect.return_value.to_be_attached = AsyncMock()
mock_wait.return_value = True
mock_get_content.return_value = ""
result = await response_controller.get_response(check_client_disconnected)
assert result == ""
mock_save_snapshot.assert_called()
@pytest.mark.asyncio
async def test_get_response_completion_timeout(response_controller, mock_page):
"""Test response retrieval when completion detection times out."""
check_client_disconnected = MagicMock(return_value=False)
expected_content = "Partial content"
# Mock locators
response_container = AsyncMock()
response_element = AsyncMock()
mock_page.locator.return_value.last = response_container
response_container.locator.return_value = response_element
with (
patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect,
patch(
"browser_utils.page_controller_modules.response._wait_for_response_completion",
new_callable=AsyncMock,
) as mock_wait,
patch(
"browser_utils.page_controller_modules.response._get_final_response_content",
new_callable=AsyncMock,
) as mock_get_content,
):
mock_expect.return_value.to_be_attached = AsyncMock()
mock_wait.return_value = False # Simulate timeout/failure
mock_get_content.return_value = expected_content
result = await response_controller.get_response(check_client_disconnected)
assert result == expected_content
# Should still try to get content even if completion check failed
mock_get_content.assert_called()
@pytest.mark.asyncio
async def test_get_response_cancelled_error(response_controller, mock_page):
"""Test get_response re-raises CancelledError."""
import asyncio
check_client_disconnected = MagicMock(return_value=False)
# Mock locators
response_container = AsyncMock()
response_element = AsyncMock()
mock_page.locator.return_value.last = response_container
response_container.locator.return_value = response_element
with patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect:
# Simulate CancelledError
mock_expect.return_value.to_be_attached = AsyncMock(
side_effect=asyncio.CancelledError()
)
with pytest.raises(asyncio.CancelledError):
await response_controller.get_response(check_client_disconnected)
@pytest.mark.asyncio
async def test_get_response_general_exception(response_controller, mock_page):
"""Test get_response saves snapshot for general exceptions."""
check_client_disconnected = MagicMock(return_value=False)
# Mock locators
response_container = AsyncMock()
response_element = AsyncMock()
mock_page.locator.return_value.last = response_container
response_container.locator.return_value = response_element
with (
patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect,
patch(
"browser_utils.page_controller_modules.response.save_error_snapshot",
new_callable=AsyncMock,
) as mock_save_snapshot,
):
# Simulate general exception (not ClientDisconnectedError)
mock_expect.return_value.to_be_attached = AsyncMock(
side_effect=ValueError("Test error")
)
with pytest.raises(ValueError):
await response_controller.get_response(check_client_disconnected)
# Should save error snapshot (line 79)
mock_save_snapshot.assert_called_once()
assert "get_response_error_" in str(mock_save_snapshot.call_args)
@pytest.mark.asyncio
async def test_ensure_generation_stopped_button_enabled(response_controller, mock_page):
"""Test ensure_generation_stopped when button is enabled."""
check_client_disconnected = MagicMock(return_value=None)
submit_button = AsyncMock()
mock_page.locator.return_value = submit_button
# Button is enabled, should click it
submit_button.is_enabled = AsyncMock(return_value=True)
submit_button.click = AsyncMock()
with patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect:
mock_expect.return_value.to_be_disabled = AsyncMock()
await response_controller.ensure_generation_stopped(check_client_disconnected)
# Should check if enabled
submit_button.is_enabled.assert_called()
# Should click button (lines 100-104)
submit_button.click.assert_called_once()
# Should wait for disabled
mock_expect.return_value.to_be_disabled.assert_called()
@pytest.mark.asyncio
async def test_ensure_generation_stopped_button_disabled(
response_controller, mock_page
):
"""Test ensure_generation_stopped when button is already disabled."""
check_client_disconnected = MagicMock(return_value=None)
submit_button = AsyncMock()
mock_page.locator.return_value = submit_button
# Button is already disabled
submit_button.is_enabled = AsyncMock(return_value=False)
submit_button.click = AsyncMock()
with patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect:
mock_expect.return_value.to_be_disabled = AsyncMock()
await response_controller.ensure_generation_stopped(check_client_disconnected)
# Should check if enabled
submit_button.is_enabled.assert_called()
# Should NOT click button (lines 105-106)
submit_button.click.assert_not_called()
# Should still wait for disabled
mock_expect.return_value.to_be_disabled.assert_called()
@pytest.mark.asyncio
async def test_ensure_generation_stopped_button_check_exception(
response_controller, mock_page
):
"""Test ensure_generation_stopped handles button check exceptions."""
check_client_disconnected = MagicMock(return_value=None)
submit_button = AsyncMock()
mock_page.locator.return_value = submit_button
# Button check raises exception (lines 107-110)
submit_button.is_enabled = AsyncMock(side_effect=ValueError("Button check failed"))
with patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect:
mock_expect.return_value.to_be_disabled = AsyncMock()
# Should not raise, just log warning
await response_controller.ensure_generation_stopped(check_client_disconnected)
# Should still wait for disabled
mock_expect.return_value.to_be_disabled.assert_called()
@pytest.mark.asyncio
async def test_ensure_generation_stopped_final_wait_exception(
response_controller, mock_page
):
"""Test ensure_generation_stopped handles final wait exceptions."""
check_client_disconnected = MagicMock(return_value=None)
submit_button = AsyncMock()
mock_page.locator.return_value = submit_button
submit_button.is_enabled = AsyncMock(return_value=False)
with patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect:
# Final wait raises timeout exception (lines 117-120)
mock_expect.return_value.to_be_disabled = AsyncMock(
side_effect=ValueError("Timeout waiting for disabled")
)
# Should not raise, just log warning
await response_controller.ensure_generation_stopped(check_client_disconnected)
@pytest.mark.asyncio
async def test_ensure_generation_stopped_cancelled_error_button_check(
response_controller, mock_page
):
"""Test ensure_generation_stopped re-raises CancelledError during button check."""
import asyncio
check_client_disconnected = MagicMock(return_value=None)
submit_button = AsyncMock()
mock_page.locator.return_value = submit_button
# Button check raises CancelledError (line 108-109)
submit_button.is_enabled = AsyncMock(side_effect=asyncio.CancelledError())
with pytest.raises(asyncio.CancelledError):
await response_controller.ensure_generation_stopped(check_client_disconnected)
@pytest.mark.asyncio
async def test_ensure_generation_stopped_cancelled_error_final_wait(
response_controller, mock_page
):
"""Test ensure_generation_stopped re-raises CancelledError during final wait."""
import asyncio
check_client_disconnected = MagicMock(return_value=None)
submit_button = AsyncMock()
mock_page.locator.return_value = submit_button
submit_button.is_enabled = AsyncMock(return_value=False)
with patch(
"browser_utils.page_controller_modules.response.expect_async",
new_callable=MagicMock,
) as mock_expect:
# Final wait raises CancelledError (lines 118-119)
mock_expect.return_value.to_be_disabled = AsyncMock(
side_effect=asyncio.CancelledError()
)
with pytest.raises(asyncio.CancelledError):
await response_controller.ensure_generation_stopped(
check_client_disconnected
)