Skip to content

Commit 1185678

Browse files
committed
Test process_spider_exception on both asyncio & non-asyncio reactors
1 parent 59e16e3 commit 1185678

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

sh_scrapy/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
from scrapy import version_info as scrapy_version_info
55

66

7+
# Flag to check if Scrapy version requires spider argument in some core components.
8+
# Also indicates whether or not async versions of some methods are supported.
79
_SCRAPY_NO_SPIDER_ARG = scrapy_version_info >= (2, 14, 0)

tests/test_diskquota.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,53 @@ async def run_test():
111111
assert crawler.engine.close_spider.call_args[0] == ('spider', 'diskusage_exceeded')
112112

113113
asyncio.run(run_test())
114+
115+
116+
@pytest.mark.skipif(not _SCRAPY_NO_SPIDER_ARG, reason="Only test on recent Scrapy versions")
117+
def test_spider_mware_process_stopped_asyncio_reactor(crawler):
118+
"""Test that disk quota error closes spider using the asyncio reactor."""
119+
120+
crawler.engine = mock.Mock()
121+
# Mock close_spider_async to return a coroutine
122+
async def mock_close_spider_async(**kwargs):
123+
pass
124+
crawler.engine.close_spider_async = mock.Mock(side_effect=mock_close_spider_async)
125+
126+
mware = DiskQuotaSpiderMiddleware(crawler)
127+
error = IOError()
128+
error.errno = 122
129+
130+
# Mock is_asyncio_available to return True (simulate asyncio reactor)
131+
with mock.patch("scrapy.utils.asyncio.is_asyncio_available", return_value=True):
132+
with mock.patch("asyncio.create_task") as mock_create_task:
133+
mware.process_spider_exception("response", error)
134+
135+
# Verify close_spider_async was called with correct reason
136+
assert mock_create_task.called
137+
assert crawler.engine.close_spider_async.called
138+
assert crawler.engine.close_spider_async.call_args[1] == {'reason': 'diskusage_exceeded'}
139+
140+
141+
@pytest.mark.skipif(not _SCRAPY_NO_SPIDER_ARG, reason="Only test on recent Scrapy versions")
142+
def test_spider_mware_process_stopped_non_asyncio_reactor(crawler):
143+
"""Test that disk quota error closes spider using a non-asyncio reactor (Twisted)."""
144+
145+
crawler.engine = mock.Mock()
146+
# Mock close_spider_async to return a coroutine
147+
async def mock_close_spider_async(**kwargs):
148+
pass
149+
crawler.engine.close_spider_async = mock.Mock(side_effect=mock_close_spider_async)
150+
151+
mware = DiskQuotaSpiderMiddleware(crawler)
152+
error = IOError()
153+
error.errno = 122
154+
155+
# Mock is_asyncio_available to return False (simulate Twisted reactor)
156+
with mock.patch("scrapy.utils.asyncio.is_asyncio_available", return_value=False):
157+
with mock.patch("sh_scrapy.diskquota.deferred_from_coro") as mock_deferred:
158+
mware.process_spider_exception("response", error)
159+
160+
# Verify close_spider_async was called with correct reason
161+
assert mock_deferred.called
162+
assert crawler.engine.close_spider_async.called
163+
assert crawler.engine.close_spider_async.call_args[1] == {'reason': 'diskusage_exceeded'}

0 commit comments

Comments
 (0)