# tests/test_background_tasks.py from unittest.mock import AsyncMock, patch import pytest from app.tasks.background_tasks import process_marketplace_import from models.database.marketplace_import_job import MarketplaceImportJob @pytest.mark.integration @pytest.mark.database @pytest.mark.marketplace class TestBackgroundTasks: @pytest.mark.asyncio async def test_marketplace_import_success(self, db, test_user, test_vendor): """Test successful marketplace import background task""" # Create import job job = MarketplaceImportJob( status="pending", source_url="http://example.com/test.csv", marketplace="TestMarket", vendor_id=test_vendor.id, user_id=test_user.id, language="en", ) db.add(job) db.commit() db.refresh(job) # Store the job ID before it becomes detached job_id = job.id # Mock CSV processor and prevent session from closing with ( patch("app.tasks.background_tasks.CSVProcessor") as mock_processor, patch("app.tasks.background_tasks.SessionLocal", return_value=db), ): mock_instance = mock_processor.return_value mock_instance.process_marketplace_csv_from_url = AsyncMock( return_value={ "imported": 10, "updated": 5, "total_processed": 15, "errors": 0, } ) # Run background task await process_marketplace_import( job_id, "http://example.com/test.csv", "TestMarket", "TESTVENDOR", 1000 ) # Re-query the job using the stored ID updated_job = ( db.query(MarketplaceImportJob) .filter(MarketplaceImportJob.id == job_id) .first() ) assert updated_job is not None assert updated_job.status == "completed" assert updated_job.imported_count == 10 assert updated_job.updated_count == 5 assert updated_job.total_processed == 15 assert updated_job.error_count == 0 assert updated_job.started_at is not None assert updated_job.completed_at is not None @pytest.mark.asyncio async def test_marketplace_import_failure(self, db, test_user, test_vendor): """Test marketplace import failure handling""" # Create import job job = MarketplaceImportJob( status="pending", source_url="http://example.com/test.csv", marketplace="TestMarket", vendor_id=test_vendor.id, user_id=test_user.id, language="en", ) db.add(job) db.commit() db.refresh(job) # Store the job ID before it becomes detached job_id = job.id # Mock CSV processor to raise exception with ( patch("app.tasks.background_tasks.CSVProcessor") as mock_processor, patch("app.tasks.background_tasks.SessionLocal", return_value=db), ): mock_instance = mock_processor.return_value mock_instance.process_marketplace_csv_from_url = AsyncMock( side_effect=Exception("Import failed") ) # Run background task - this should not raise the exception # because it's handled in the background task try: await process_marketplace_import( job_id, "http://example.com/test.csv", "TestMarket", "TESTVENDOR", 1000, ) except Exception: # The background task should handle exceptions internally # If an exception propagates here, that's a bug in the background task pass # Re-query the job using the stored ID updated_job = ( db.query(MarketplaceImportJob) .filter(MarketplaceImportJob.id == job_id) .first() ) assert updated_job is not None assert updated_job.status == "failed" assert "Import failed" in updated_job.error_message @pytest.mark.asyncio async def test_marketplace_import_job_not_found(self, db): """Test handling when import job doesn't exist""" with ( patch("app.tasks.background_tasks.CSVProcessor") as mock_processor, patch("app.tasks.background_tasks.SessionLocal", return_value=db), ): mock_instance = mock_processor.return_value mock_instance.process_marketplace_csv_from_url = AsyncMock( return_value={ "imported": 10, "updated": 5, "total_processed": 15, "errors": 0, } ) # Run background task with non-existent job ID await process_marketplace_import( 999, # Non-existent job ID "http://example.com/test.csv", "TestMarket", "TESTVENDOR", 1000, ) # Should not raise an exception, just log and return # The CSV processor should not be called mock_instance.process_marketplace_csv_from_url.assert_not_called() @pytest.mark.asyncio async def test_marketplace_import_with_errors(self, db, test_user, test_vendor): """Test marketplace import with some errors""" # Create import job job = MarketplaceImportJob( status="pending", source_url="http://example.com/test.csv", marketplace="TestMarket", vendor_id=test_vendor.id, user_id=test_user.id, language="en", ) db.add(job) db.commit() db.refresh(job) # Store the job ID before it becomes detached job_id = job.id # Mock CSV processor with some errors with ( patch("app.tasks.background_tasks.CSVProcessor") as mock_processor, patch("app.tasks.background_tasks.SessionLocal", return_value=db), ): mock_instance = mock_processor.return_value mock_instance.process_marketplace_csv_from_url = AsyncMock( return_value={ "imported": 8, "updated": 5, "total_processed": 15, "errors": 2, } ) # Run background task await process_marketplace_import( job_id, "http://example.com/test.csv", "TestMarket", "TESTVENDOR", 1000 ) # Re-query the job using the stored ID updated_job = ( db.query(MarketplaceImportJob) .filter(MarketplaceImportJob.id == job_id) .first() ) assert updated_job is not None assert updated_job.status == "completed_with_errors" assert updated_job.imported_count == 8 assert updated_job.updated_count == 5 assert updated_job.error_count == 2 assert updated_job.total_processed == 15 assert "2 rows had errors" in updated_job.error_message