import pytest from unittest.mock import AsyncMock, MagicMock, patch from httpx import Response from src.infrastructure.elasticsearch.client import ElasticsearchClient from src.infrastructure.repositories.consultor_repository_impl import ConsultorRepositoryImpl from src.domain.services.calculador_pontuacao import CalculadorPontuacao def create_mock_response(json_data, status_code=200): response = MagicMock(spec=Response) response.json.return_value = json_data response.status_code = status_code response.raise_for_status = MagicMock() return response def criar_doc_consultor(id_pessoa, nome, atuacoes): return { "id": id_pessoa, "dadosPessoais": {"nome": nome}, "atuacoes": atuacoes } @pytest.fixture def es_client(): return ElasticsearchClient( url="http://localhost:9200", index="atuacapes_test" ) @pytest.fixture def repository(es_client): return ConsultorRepositoryImpl(es_client) class TestScrollFlowCompleto: @pytest.mark.asyncio async def test_processamento_scroll_com_ranking(self, es_client, repository): docs_batch_1 = [ criar_doc_consultor(1, "COORD AREA", [{ "tipo": "Coordenação de Área de Avaliação", "inicio": "01/01/2018", "dadosCoordenacaoArea": {"tipo": "Coordenador de Área"} }]), criar_doc_consultor(2, "COORD ADJUNTO", [{ "tipo": "Coordenação de Área de Avaliação", "inicio": "01/01/2020", "dadosCoordenacaoArea": {"tipo": "Coordenador Adjunto"} }]), ] docs_batch_2 = [ criar_doc_consultor(3, "CONSULTOR ATIVO", [{ "tipo": "Consultor", "inicio": "01/01/2015", "dadosConsultoria": {"situacaoConsultoria": "Atividade Contínua"} }]), criar_doc_consultor(4, "PESSOA SEM ATUACAO", []), ] scroll_1 = { "_scroll_id": "scroll_1", "hits": { "total": {"value": 4}, "hits": [{"_source": d} for d in docs_batch_1] } } scroll_2 = { "_scroll_id": "scroll_2", "hits": {"hits": [{"_source": d} for d in docs_batch_2]} } scroll_empty = {"_scroll_id": "scroll_3", "hits": {"hits": []}} ranking_results = [] async def processar_batch(docs, progress): for doc in docs: consultor = await repository._construir_consultor(doc) pontuacao = CalculadorPontuacao.calcular_pontuacao_completa(consultor) ranking_results.append({ "id": consultor.id_pessoa, "nome": consultor.nome, "total": pontuacao.total }) with patch.object(es_client, '_client') as mock_client: mock_client.is_closed = False mock_client.post = AsyncMock(side_effect=[ create_mock_response(scroll_1), create_mock_response(scroll_2), create_mock_response(scroll_empty) ]) mock_client.delete = AsyncMock(return_value=create_mock_response({})) result = await es_client.buscar_todos_consultores(processar_batch, batch_size=2) assert result["total"] == 4 assert result["processados"] == 4 assert len(ranking_results) == 4 class TestProgressoScroll: @pytest.mark.asyncio async def test_progress_callback(self, es_client): progress_history = [] async def callback(docs, progress): progress_history.append(progress.copy()) scroll_1 = { "_scroll_id": "s1", "hits": {"total": {"value": 100}, "hits": [{"_source": {"id": i}} for i in range(50)]} } scroll_2 = { "_scroll_id": "s2", "hits": {"hits": [{"_source": {"id": i}} for i in range(50, 100)]} } scroll_empty = {"_scroll_id": "s3", "hits": {"hits": []}} with patch.object(es_client, '_client') as mock_client: mock_client.is_closed = False mock_client.post = AsyncMock(side_effect=[ create_mock_response(scroll_1), create_mock_response(scroll_2), create_mock_response(scroll_empty) ]) mock_client.delete = AsyncMock(return_value=create_mock_response({})) await es_client.buscar_todos_consultores(callback, batch_size=50) assert len(progress_history) == 2 assert progress_history[0]["percentual"] == 50 assert progress_history[0]["processados"] == 50 assert progress_history[1]["percentual"] == 100 assert progress_history[1]["processados"] == 100