@@ -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