import pytest from unittest.mock import AsyncMock, MagicMock, patch from fastapi.testclient import TestClient from fastapi import FastAPI from src.interface.api.routes import router from src.interface.api.dependencies import ( get_repository, get_ranking_store, get_processar_job, get_es_client, get_ranking_oracle_repo, ) @pytest.fixture def mock_repository(): repo = AsyncMock() repo.contar_total.return_value = 100 return repo @pytest.fixture def mock_ranking_store(): store = MagicMock() store.is_ready.return_value = False return store @pytest.fixture def mock_oracle_repo(): repo = MagicMock() repo.contar_total.return_value = 1000 return repo @pytest.fixture def mock_es_client(): return AsyncMock() @pytest.fixture def mock_job(): return AsyncMock() @pytest.fixture def app(mock_repository, mock_ranking_store, mock_oracle_repo, mock_es_client, mock_job): app = FastAPI() app.include_router(router) app.dependency_overrides[get_repository] = lambda: mock_repository app.dependency_overrides[get_ranking_store] = lambda: mock_ranking_store app.dependency_overrides[get_ranking_oracle_repo] = lambda: mock_oracle_repo app.dependency_overrides[get_es_client] = lambda: mock_es_client app.dependency_overrides[get_processar_job] = lambda: mock_job return app @pytest.fixture def client(app): return TestClient(app) class TestHealthCheck: def test_health_check_ok(self, client): response = client.get("/api/v1/health") assert response.status_code == 200 data = response.json() assert data["status"] == "ok" class TestRankingStatus: def test_status_inicial(self, client): with patch("src.interface.api.routes.job_status") as mock_status: mock_status.to_dict.return_value = { "running": False, "progress": 0, "processados": 0, "total": 0, "mensagem": "", "batch_atual": 0, "total_batches": 0, "tempo_decorrido": None, "tempo_estimado": None, "inicio": None, "fim": None, "erro": None, } response = client.get("/api/v1/ranking/status") assert response.status_code == 200 data = response.json() assert data["running"] is False class TestRankingPaginado: def test_ranking_paginado_sem_oracle(self, client, mock_oracle_repo): mock_oracle_repo.contar_total.return_value = 0 response = client.get("/api/v1/ranking/paginado") assert response.status_code == 503 def test_ranking_paginado_com_dados(self, client, mock_oracle_repo): mock_oracle_repo.contar_total.return_value = 100 mock_oracle_repo.buscar_paginado.return_value = [ MagicMock( id_pessoa=1, nome="Consultor 1", posicao=1, pontuacao_total=500, componente_a=200, componente_b=100, componente_c=100, componente_d=50, componente_e=50, ativo=True, anos_atuacao=5.0, json_detalhes="{}" ) ] response = client.get("/api/v1/ranking/paginado?page=1&size=10") assert response.status_code == 200 data = response.json() assert data["total"] == 100 assert len(data["consultores"]) == 1 def test_ranking_paginado_filtro_ativo(self, client, mock_oracle_repo): mock_oracle_repo.contar_total.return_value = 50 mock_oracle_repo.buscar_paginado.return_value = [] response = client.get("/api/v1/ranking/paginado?ativo=true") assert response.status_code == 200 def test_ranking_paginado_filtro_selos(self, client, mock_oracle_repo): mock_oracle_repo.contar_total.return_value = 0 response = client.get("/api/v1/ranking/paginado?selos=COORD_PPG,BPQ") assert response.status_code == 200 data = response.json() assert data["total"] == 0 class TestBuscaPorNome: def test_busca_por_nome_encontrado(self, client, mock_oracle_repo): mock_oracle_repo.buscar_por_nome.return_value = [ {"ID_PESSOA": 1, "NOME": "João Silva", "POSICAO": 10, "PONTUACAO_TOTAL": 500} ] response = client.get("/api/v1/ranking/busca?nome=João") assert response.status_code == 200 data = response.json() assert len(data) == 1 assert data[0]["nome"] == "João Silva" def test_busca_por_nome_nao_encontrado(self, client, mock_oracle_repo): mock_oracle_repo.buscar_por_nome.return_value = [] response = client.get("/api/v1/ranking/busca?nome=XYZ") assert response.status_code == 200 data = response.json() assert len(data) == 0 def test_busca_por_nome_minimo_3_chars(self, client): response = client.get("/api/v1/ranking/busca?nome=AB") assert response.status_code == 422 class TestRankingEstatisticas: def test_estatisticas_sem_dados(self, client, mock_oracle_repo): mock_oracle_repo.contar_total.return_value = 0 response = client.get("/api/v1/ranking/estatisticas") assert response.status_code == 503 def test_estatisticas_com_dados(self, client, mock_oracle_repo): mock_oracle_repo.contar_total.return_value = 1000 mock_oracle_repo.obter_estatisticas.return_value = { "total_consultores": 1000, "total_ativos": 800, "total_inativos": 200, "ultima_atualizacao": "2024-01-01", "pontuacao_media": 150.5, "pontuacao_maxima": 850, "pontuacao_minima": 10, "media_componentes": {"a": 50, "b": 30, "c": 40, "d": 20, "e": 10} } mock_oracle_repo.obter_distribuicao.return_value = [ {"faixa": "0-100", "quantidade": 500}, {"faixa": "100-200", "quantidade": 300}, ] response = client.get("/api/v1/ranking/estatisticas") assert response.status_code == 200 data = response.json() assert data["total_consultores"] == 1000 assert data["total_ativos"] == 800 class TestPosicaoRanking: def test_posicao_encontrada(self, client, mock_oracle_repo): mock_oracle_repo.contar_total.return_value = 1000 mock_oracle_repo.buscar_por_id.return_value = MagicMock( id_pessoa=123, nome="João Silva", posicao=42, pontuacao_total=500, componente_a=200, componente_b=100, componente_c=100, componente_d=50, componente_e=50, ativo=True, ) response = client.get("/api/v1/ranking/posicao/123") assert response.status_code == 200 data = response.json() assert data["id_pessoa"] == 123 assert data["posicao"] == 42 assert data["encontrado"] is True def test_posicao_nao_encontrada(self, client, mock_oracle_repo): mock_oracle_repo.contar_total.return_value = 1000 mock_oracle_repo.buscar_por_id.return_value = None response = client.get("/api/v1/ranking/posicao/99999") assert response.status_code == 200 data = response.json() assert data["encontrado"] is False class TestProcessarRanking: def test_processar_ranking_inicia(self, client, mock_job): with patch("src.interface.api.routes.job_status") as mock_status: mock_status.is_running = False response = client.post("/api/v1/ranking/processar") assert response.status_code == 200 data = response.json() assert data["sucesso"] is True def test_processar_ranking_ja_executando(self, client): with patch("src.interface.api.routes.job_status") as mock_status: mock_status.is_running = True response = client.post("/api/v1/ranking/processar") assert response.status_code == 409 class TestListarSelos: def test_listar_selos(self, client): response = client.get("/api/v1/ranking/selos") assert response.status_code == 200 data = response.json() assert "selos" in data assert isinstance(data["selos"], list) class TestExportarInfo: def test_info_exportacao(self, client, mock_oracle_repo): mock_oracle_repo.contar_para_exportacao.return_value = 500 response = client.get("/api/v1/ranking/exportar/info") assert response.status_code == 200 data = response.json() assert data["total_consultores"] == 500 assert "estimativa_tamanho_mb" in data class TestCorrigirEncoding: def test_corrigir_encoding_sem_problemas(self): from src.interface.api.routes import corrigir_encoding result = corrigir_encoding("Texto normal") assert result == "Texto normal" def test_corrigir_encoding_none(self): from src.interface.api.routes import corrigir_encoding result = corrigir_encoding(None) assert result is None def test_corrigir_encoding_vazio(self): from src.interface.api.routes import corrigir_encoding result = corrigir_encoding("") assert result == "" class TestNormalizarTexto: def test_normalizar_texto_acentos(self): from src.interface.api.routes import normalizar_texto result = normalizar_texto("Ciências Ambientais") assert result == "ciencias ambientais" def test_normalizar_texto_html_entities(self): from src.interface.api.routes import normalizar_texto result = normalizar_texto("Ciências") assert "ciencias" in result.lower() def test_normalizar_texto_vazio(self): from src.interface.api.routes import normalizar_texto result = normalizar_texto("") assert result == ""