"""Tests para query_osint_db. Mockean urllib.request.urlopen para no depender del service osint_db vivo: se interceptan el exito (cuerpo {status:ok,...}), el error de dominio del service ({status:error,...}) y el error de red (conexion rechazada). """ import io import json import urllib.error from query_osint_db import query_osint_db class _FakeResponse: """Context manager que imita la respuesta de urllib.request.urlopen.""" def __init__(self, payload: dict): self._raw = json.dumps(payload).encode("utf-8") def __enter__(self): return self def __exit__(self, *exc): return False def read(self): return self._raw def test_query_ok_devuelve_cuerpo_del_service(monkeypatch): payload = { "status": "ok", "columns": ["count_star()"], "rows": [{"count_star()": 42}], "row_count": 1, "truncated": False, } captured = {} def fake_urlopen(req, timeout=None): captured["url"] = req.full_url captured["body"] = json.loads(req.data.decode("utf-8")) captured["method"] = req.get_method() return _FakeResponse(payload) monkeypatch.setattr("urllib.request.urlopen", fake_urlopen) result = query_osint_db("SELECT COUNT(*) FROM personas") assert result == payload assert result["status"] == "ok" assert result["rows"] == [{"count_star()": 42}] assert captured["url"] == "http://127.0.0.1:8771/api/query" assert captured["body"] == {"sql": "SELECT COUNT(*) FROM personas"} assert captured["method"] == "POST" def test_query_error_de_dominio_se_reenvia(monkeypatch): payload = {"status": "error", "error": "Catalog Error: Table no existe"} def fake_urlopen(req, timeout=None): return _FakeResponse(payload) monkeypatch.setattr("urllib.request.urlopen", fake_urlopen) result = query_osint_db("SELECT * FROM tabla_inexistente") assert result["status"] == "error" assert "no existe" in result["error"] def test_service_caido_devuelve_error_claro(monkeypatch): def fake_urlopen(req, timeout=None): raise urllib.error.URLError("Connection refused") monkeypatch.setattr("urllib.request.urlopen", fake_urlopen) result = query_osint_db("SELECT 1") assert result["status"] == "error" assert "osint_db service not reachable" in result["error"] assert "http://127.0.0.1:8771/api/query" in result["error"] def test_base_url_custom_se_respeta(monkeypatch): captured = {} def fake_urlopen(req, timeout=None): captured["url"] = req.full_url return _FakeResponse({"status": "ok", "rows": [], "row_count": 0}) monkeypatch.setattr("urllib.request.urlopen", fake_urlopen) query_osint_db("SELECT 1", base_url="http://10.0.0.5:9000/") assert captured["url"] == "http://10.0.0.5:9000/api/query" def test_http_error_con_cuerpo_json_se_reenvia(monkeypatch): body = json.dumps({"status": "error", "error": "boom"}).encode("utf-8") def fake_urlopen(req, timeout=None): raise urllib.error.HTTPError( url=req.full_url, code=500, msg="Internal Server Error", hdrs=None, fp=io.BytesIO(body), ) monkeypatch.setattr("urllib.request.urlopen", fake_urlopen) result = query_osint_db("SELECT 1") assert result["status"] == "error" assert result["error"] == "boom"