Files
app-catalog-felhom.eu/scripts/test_healthcheck_explained.py
T

79 lines
3.1 KiB
Python

#!/usr/bin/env python3
"""R-760: every catalog service that has NO compose `healthcheck:` says why, in a comment inside its own block.
A missing healthcheck is sometimes right (the image has no shell; the image brings its own — adventurelog-frontend,
R-655), but a silent one cannot be told apart from a forgotten one: vikunja carried none for months with nothing
saying whether that was a choice. This test reads the committed composes as TEXT (catalog CI has no PyYAML) and
fails for a service block with neither a `healthcheck:` key nor a `# No healthcheck` comment.
COMPANION RED-PROOF: with the R-760 comment removed from templates/vikunja/docker-compose.yml this test fails and
names `vikunja/vikunja`."""
import glob
import io
import os
import re
import unittest
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
EXPLAINED = re.compile(r"^\s*#\s*No healthcheck", re.I)
def service_blocks(text):
"""Yield (service name, [lines]) for each service under the top-level `services:` key."""
in_services = False
name, lines = None, []
for line in text.splitlines():
if re.match(r"^\S", line): # a top-level key (or a top-level comment) ends the services block
if name:
yield name, lines
name, lines = None, []
in_services = line.startswith("services:")
continue
if not in_services:
continue
m = re.match(r"^ ([A-Za-z0-9_.-]+):\s*$", line)
if m:
if name:
yield name, lines
name, lines = m.group(1), []
elif name:
lines.append(line)
if name:
yield name, lines
def unexplained(text):
out = []
for svc, lines in service_blocks(text):
if any(re.match(r"^ healthcheck:", l) for l in lines):
continue
if any(EXPLAINED.match(l) for l in lines):
continue
out.append(svc)
return out
class HealthcheckExplained(unittest.TestCase):
def test_parser_sees_a_missing_and_an_explained_service(self):
# decoys for the parser itself: a silent service convicts, an explained one and a checked one pass
text = ("services:\n a:\n image: x:1\n b:\n image: y:1\n # No healthcheck: no shell\n"
" c:\n image: z:1\n healthcheck:\n test: [\"CMD\", \"true\"]\nvolumes:\n d:\n")
self.assertEqual(unexplained(text), ["a"])
def test_every_catalog_service_has_a_healthcheck_or_says_why(self):
paths = sorted(glob.glob(os.path.join(ROOT, "templates", "*", "docker-compose.yml")))
self.assertGreater(len(paths), 40, "the template glob found too few composes — the test would pass empty")
bad = []
for p in paths:
app = os.path.basename(os.path.dirname(p))
with io.open(p, encoding="utf-8") as f:
text = f.read()
for svc in unexplained(text):
bad.append("%s/%s" % (app, svc))
self.assertEqual(bad, [], "service(s) with no compose healthcheck and no '# No healthcheck' comment "
"saying why: %s" % bad)
if __name__ == "__main__":
unittest.main()