|
3 | 3 | import asyncio |
4 | 4 | import json |
5 | 5 | from typing import TYPE_CHECKING |
| 6 | +from unittest.mock import AsyncMock, patch |
6 | 7 |
|
7 | 8 | import pytest |
8 | 9 | from sqlalchemy import inspect, select |
| 10 | +from sqlalchemy.exc import SQLAlchemyError |
9 | 11 | from sqlalchemy.ext.asyncio import create_async_engine |
10 | 12 |
|
11 | 13 | from crawlee import Request |
@@ -233,3 +235,45 @@ async def test_data_persistence_across_reopens(configuration: Configuration) -> |
233 | 235 | assert {request1.url, request2.url} == {'https://example.com/1', 'https://example.com/2'} |
234 | 236 |
|
235 | 237 | await reopened_client.drop() |
| 238 | + |
| 239 | + |
| 240 | +async def test_error_handling_on_get_metadata_failure(rq_client: SqlRequestQueueClient) -> None: |
| 241 | + """Test that get_metadata properly handles SQL errors and retries.""" |
| 242 | + with patch( |
| 243 | + 'crawlee.storage_clients._sql._request_queue_client.SqlRequestQueueClient.get_session', |
| 244 | + ) as mock_get_session: |
| 245 | + mock_session = AsyncMock() |
| 246 | + mock_session.__aenter__ = AsyncMock(return_value=mock_session) |
| 247 | + mock_session.__aexit__ = AsyncMock(return_value=None) |
| 248 | + mock_session.execute = AsyncMock(side_effect=SQLAlchemyError('db error')) |
| 249 | + mock_get_session.return_value = mock_session |
| 250 | + |
| 251 | + with ( |
| 252 | + patch('crawlee._utils.retry._retry_sleep', new_callable=AsyncMock) as mock_sleep, |
| 253 | + pytest.raises(SQLAlchemyError), |
| 254 | + ): |
| 255 | + await rq_client.get_metadata() |
| 256 | + |
| 257 | + # Verify that retry logic was attempted |
| 258 | + assert mock_sleep.call_count == 2 # Assuming default max_attempts=3 |
| 259 | + |
| 260 | + |
| 261 | +async def test_get_metadata_does_not_retry_on_unexpected_exception(rq_client: SqlRequestQueueClient) -> None: |
| 262 | + """Test that get_metadata does not retry on unexpected exceptions.""" |
| 263 | + with patch( |
| 264 | + 'crawlee.storage_clients._sql._request_queue_client.SqlRequestQueueClient.get_session', |
| 265 | + ) as mock_get_session: |
| 266 | + mock_session = AsyncMock() |
| 267 | + mock_session.__aenter__ = AsyncMock(return_value=mock_session) |
| 268 | + mock_session.__aexit__ = AsyncMock(return_value=None) |
| 269 | + mock_session.execute = AsyncMock(side_effect=ValueError('unexpected error')) |
| 270 | + mock_get_session.return_value = mock_session |
| 271 | + |
| 272 | + with ( |
| 273 | + patch('crawlee._utils.retry._retry_sleep', new_callable=AsyncMock) as mock_sleep, |
| 274 | + pytest.raises(ValueError, match='unexpected error'), |
| 275 | + ): |
| 276 | + await rq_client.get_metadata() |
| 277 | + |
| 278 | + # Verify that retry logic was not attempted |
| 279 | + assert mock_sleep.call_count == 0 |
0 commit comments