From bc4b5b912e1259e61ec6a892461ba775b9fb2a5d Mon Sep 17 00:00:00 2001 From: Eliel Sousa Date: Sat, 12 Sep 2026 16:42:16 -0300 Subject: [PATCH] docs: o /healthz respondia uma coisa e a wiki anunciava outra A pagina do painel e a de diagnostico documentavam OMNIROUTE_SERVICE_UNREACHABLE; o servidor responde GATEWAY_SERVICE_UNREACHABLE. Nada quebra por causa disso: o painel funciona, o healthcheck funciona, os testes passavam. Quem perde e quem monta um alerta sobre a string documentada -- ele nunca dispara, e o silencio parece saude. Corrigida a documentacao para o valor real, e nao o contrario: mudar o codigo quebraria quem ja monitora a resposta que ele de fato devolve. Novo teste: cada resposta que o /healthz produz tem de aparecer na documentacao, e nenhuma pagina pode citar resposta que o codigo nunca devolve. Verificado que ele pega a regressao -- reintroduzir a string antiga numa copia falha o teste, com arquivo e linha. --- docs/wiki/Dashboard.md | 2 +- docs/wiki/Troubleshooting.md | 2 +- tests/test_healthz_documentado.py | 76 +++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 tests/test_healthz_documentado.py diff --git a/docs/wiki/Dashboard.md b/docs/wiki/Dashboard.md index 5716ea5..a9594f5 100644 --- a/docs/wiki/Dashboard.md +++ b/docs/wiki/Dashboard.md @@ -113,7 +113,7 @@ Kept for automation; the dashboard itself does not use them. | Endpoint | Method | Purpose | | :--- | :--- | :--- | -| `/healthz` | GET | Unauthenticated liveness probe. `OK`, `DATABASE_NOT_READY` or `OMNIROUTE_SERVICE_UNREACHABLE`. | +| `/healthz` | GET | Unauthenticated liveness probe. `OK`, `DATABASE_NOT_READY` or `GATEWAY_SERVICE_UNREACHABLE`. | | `/api/status` | GET | Full state as JSON. | | `/api/cron-status` | GET | Scheduler state and history. | | `/api/sync` | POST | Trigger a synchronization pass. | diff --git a/docs/wiki/Troubleshooting.md b/docs/wiki/Troubleshooting.md index f103b0d..e60cbf0 100644 --- a/docs/wiki/Troubleshooting.md +++ b/docs/wiki/Troubleshooting.md @@ -80,7 +80,7 @@ If the numbers still look wrong, the synchronizer may not be writing at all — | :--- | :--- | | `OK` | Database readable and gateway reachable. | | `DATABASE_NOT_READY` | `DB_PATH` points at a file that does not exist. | -| `OMNIROUTE_SERVICE_UNREACHABLE` | `OMNIROUTE_URL` is wrong, or the gateway is down. | +| `GATEWAY_SERVICE_UNREACHABLE` | `OMNIROUTE_URL` is wrong, or the gateway is down. | --- diff --git a/tests/test_healthz_documentado.py b/tests/test_healthz_documentado.py new file mode 100644 index 0000000..b00000b --- /dev/null +++ b/tests/test_healthz_documentado.py @@ -0,0 +1,76 @@ +"""A documentação do /healthz tem de citar as respostas que o código produz. + +A wiki anunciava `OMNIROUTE_SERVICE_UNREACHABLE` e o servidor respondia +`GATEWAY_SERVICE_UNREACHABLE`. Nada quebra: o painel funciona, o healthcheck +funciona, os testes passam. Quem perde é quem monta um alerta sobre a string +documentada — ele nunca dispara, e o silêncio parece saúde. + +Este teste lê as respostas direto do fonte do servidor e exige que cada uma +apareça na documentação. +""" + +import os +import re +import unittest + +RAIZ = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +SERVIDOR = os.path.join(RAIZ, "src", "omini_rtksync", "web.py") + + +def respostas_do_healthz() -> set: + """Os literais que o /healthz devolve, lidos do fonte.""" + with open(SERVIDOR, encoding="utf-8") as f: + fonte = f.read() + inicio = fonte.find("def serve_healthz") + assert inicio > 0, "serve_healthz nao encontrada" + trecho = fonte[inicio:inicio + 1500] + return set(re.findall(r'b"([A-Z][A-Z0-9_]+)"', trecho)) + + +def paginas_de_documentacao(): + for pasta, dirs, arquivos in os.walk(RAIZ): + dirs[:] = [d for d in dirs if d not in (".git", "tmp", "node_modules", "__pycache__")] + for a in arquivos: + if a.endswith(".md"): + yield os.path.join(pasta, a) + + +class TestHealthzDocumentado(unittest.TestCase): + def test_every_answer_the_code_returns_is_documented(self): + respostas = respostas_do_healthz() + self.assertTrue(respostas, "nenhuma resposta encontrada no fonte") + + documentado = "" + for p in paginas_de_documentacao(): + with open(p, encoding="utf-8") as f: + documentado += f.read() + + faltando = sorted(r for r in respostas if r not in documentado) + self.assertEqual( + faltando, + [], + "o /healthz responde isto e a documentacao nao cita: " + ", ".join(faltando), + ) + + def test_no_page_invents_an_answer_the_code_never_returns(self): + respostas = respostas_do_healthz() + inventadas = [] + # O sublinhado precisa ser aceito no meio: OMNIROUTE_SERVICE_UNREACHABLE + # tem um segmento entre o prefixo e o sufixo, e um padrao que pare no + # primeiro sublinhado deixa passar justamente o caso que motivou o teste. + padrao = re.compile(r"`([A-Z][A-Z0-9_]*_(?:NOT_READY|UNREACHABLE|UNAVAILABLE))`") + for p in paginas_de_documentacao(): + with open(p, encoding="utf-8") as f: + for n, linha in enumerate(f, 1): + for citado in padrao.findall(linha): + if citado not in respostas: + inventadas.append(os.path.relpath(p, RAIZ) + ":" + str(n) + " " + citado) + self.assertEqual( + inventadas, + [], + "documentacao cita resposta que o codigo nunca devolve: " + ", ".join(inventadas), + ) + + +if __name__ == "__main__": + unittest.main()