"""app.tasks.enrichment.enrich_company: the Celery task end-to-end (mocked HTTP, real DB) - confirms the CompanyEnrichment row persists with the expected status after the task runs, and that a missing company is a clean no-op rather than a crash.""" from __future__ import annotations import uuid import httpx import pytest import respx from app.core.config import Settings from app.models.company import Company from app.repositories.company_enrichment_repository import CompanyEnrichmentRepository from app.tasks.enrichment import _enrich_company_async async def _make_company(db_session) -> Company: company = Company( id=uuid.uuid4(), user_id=uuid.uuid4(), name="Acme Corp", slug=f"acme-{uuid.uuid4().hex[:6]}", official_website="https://acme.example.com", ) db_session.add(company) await db_session.commit() return company def _mock_empty_endpoints() -> None: for path in ( "company/details", "company/funding", "company/updates", "competitor/listing", "product/listing", "customer/listing", ): respx.get(f"https://nubela.co/api/v1/{path}").mock( return_value=httpx.Response(200, json={}) ) @pytest.mark.asyncio async def test_enrich_company_task_persists_a_complete_result(db_session, monkeypatch): monkeypatch.setattr( "app.tasks.enrichment.get_settings", lambda: Settings(ninjapear_api_key="test-key") ) company = await _make_company(db_session) with respx.mock: _mock_empty_endpoints() await _enrich_company_async(str(company.id)) enrichment = await CompanyEnrichmentRepository(db_session).get_for_company(company.id) assert enrichment is not None assert enrichment.status.value == "complete" assert enrichment.fetched_at is not None @pytest.mark.asyncio async def test_enrich_company_task_records_partial_status_on_a_failed_section( db_session, monkeypatch ): monkeypatch.setattr( "app.tasks.enrichment.get_settings", lambda: Settings(ninjapear_api_key="test-key") ) company = await _make_company(db_session) with respx.mock: respx.get("https://nubela.co/api/v1/company/details").mock( return_value=httpx.Response(200, json={}) ) respx.get("https://nubela.co/api/v1/company/funding").mock( return_value=httpx.Response(500, text="boom") ) respx.get("https://nubela.co/api/v1/company/updates").mock( return_value=httpx.Response(200, json={}) ) respx.get("https://nubela.co/api/v1/competitor/listing").mock( return_value=httpx.Response(200, json={}) ) respx.get("https://nubela.co/api/v1/product/listing").mock( return_value=httpx.Response(200, json={}) ) respx.get("https://nubela.co/api/v1/customer/listing").mock( return_value=httpx.Response(200, json={}) ) await _enrich_company_async(str(company.id)) enrichment = await CompanyEnrichmentRepository(db_session).get_for_company(company.id) assert enrichment.status.value == "partial" assert "funding" in enrichment.errors @pytest.mark.asyncio async def test_enrich_company_task_is_a_no_op_for_a_missing_company(db_session, monkeypatch): monkeypatch.setattr( "app.tasks.enrichment.get_settings", lambda: Settings(ninjapear_api_key="test-key") ) # Should return cleanly rather than raising - no company, nothing to do. await _enrich_company_async(str(uuid.uuid4()))