mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 19:01:54 +00:00
157 lines
5.4 KiB
Python
157 lines
5.4 KiB
Python
"""Unit tests for the smtp_host lookup plugin.
|
|
|
|
Pins the SMTP endpoint matrix msmtp relays through: the configured relay in
|
|
production, loopback on a host that carries the stack, and the swarm manager's
|
|
routing mesh on a bare infra node inside the containerised test rig.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import unittest
|
|
|
|
from ansible.errors import AnsibleError
|
|
|
|
from . import PROJECT_ROOT
|
|
|
|
RELAY = "mail.infinito.test"
|
|
MANAGER = "swarm-manager-01"
|
|
|
|
|
|
def _load_lookup():
|
|
spec = importlib.util.spec_from_file_location(
|
|
"lookup_smtp_host",
|
|
str(PROJECT_ROOT / "plugins/lookup/smtp_host.py"),
|
|
)
|
|
mod = importlib.util.module_from_spec(spec)
|
|
assert spec and spec.loader
|
|
spec.loader.exec_module(mod)
|
|
return mod.LookupModule
|
|
|
|
|
|
class _DummyTemplar:
|
|
def __init__(self, available_variables=None):
|
|
self.available_variables = available_variables or {}
|
|
|
|
def template(self, value):
|
|
return value
|
|
|
|
|
|
class _RenderingTemplar:
|
|
"""A templar that actually resolves expressions, like the real one.
|
|
|
|
``_DummyTemplar`` returns its input unchanged, so it cannot expose a value
|
|
that only misbehaves while still an unrendered template.
|
|
"""
|
|
|
|
def __init__(self, available_variables=None, rendered=None):
|
|
self.available_variables = available_variables or {}
|
|
self._rendered = rendered or {}
|
|
|
|
def template(self, value):
|
|
return self._rendered.get(value, value)
|
|
|
|
|
|
def _email(external=True, host=RELAY):
|
|
return {"external": external, "host": host}
|
|
|
|
|
|
class TestSmtpHostLookup(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.LookupModule = _load_lookup()
|
|
|
|
def _resolve(self, variables, email=None):
|
|
lm = self.LookupModule()
|
|
lm._templar = _DummyTemplar(variables)
|
|
lm._loader = None
|
|
return lm.run([email if email is not None else _email()], variables=variables)[
|
|
0
|
|
]
|
|
|
|
def test_production_keeps_the_configured_relay(self):
|
|
vars_ = {"DOCKER_IN_CONTAINER": False, "DEPLOYMENT_MODE": "swarm"}
|
|
self.assertEqual(self._resolve(vars_), RELAY)
|
|
|
|
def test_non_external_mail_keeps_the_configured_relay(self):
|
|
vars_ = {"DOCKER_IN_CONTAINER": True, "DEPLOYMENT_MODE": "swarm"}
|
|
email = _email(external=False, host="localhost")
|
|
self.assertEqual(self._resolve(vars_, email), "localhost")
|
|
|
|
def test_compose_rig_uses_loopback(self):
|
|
vars_ = {"DOCKER_IN_CONTAINER": True, "DEPLOYMENT_MODE": "compose"}
|
|
self.assertEqual(self._resolve(vars_), "127.0.0.1")
|
|
|
|
def test_an_unrendered_group_var_still_reaches_the_rig_loopback(self):
|
|
"""DOCKER_IN_CONTAINER is a group_vars expression, and a lookup receives it
|
|
raw. Read unrendered it is neither true nor false, so the rig kept the
|
|
configured relay instead of loopback — and on an onion node that relay is a
|
|
.onion, which msmtp cannot route (EX_UNAVAILABLE, 'proxy failure')."""
|
|
raw = "{{ (ansible_facts['env']['container'] | default('')) != '' }}"
|
|
vars_ = {"DOCKER_IN_CONTAINER": raw, "DEPLOYMENT_MODE": "compose"}
|
|
lm = self.LookupModule()
|
|
lm._templar = _RenderingTemplar(vars_, {raw: True})
|
|
lm._loader = None
|
|
self.assertEqual(lm.run([_email()], variables=vars_)[0], "127.0.0.1")
|
|
|
|
def test_swarm_node_uses_loopback(self):
|
|
vars_ = {
|
|
"DOCKER_IN_CONTAINER": True,
|
|
"DEPLOYMENT_MODE": "swarm",
|
|
"group_names": ["svc-swarm-node"],
|
|
}
|
|
self.assertEqual(self._resolve(vars_), "127.0.0.1")
|
|
|
|
def test_infra_node_enters_through_the_manager(self):
|
|
vars_ = {
|
|
"DOCKER_IN_CONTAINER": True,
|
|
"DEPLOYMENT_MODE": "swarm",
|
|
"group_names": ["svc-nfs-server"],
|
|
"groups": {"svc-swarm-manager": [MANAGER, "swarm-manager-02"]},
|
|
}
|
|
self.assertEqual(self._resolve(vars_), MANAGER)
|
|
|
|
def test_infra_node_without_manager_falls_back_to_the_relay(self):
|
|
vars_ = {
|
|
"DOCKER_IN_CONTAINER": True,
|
|
"DEPLOYMENT_MODE": "swarm",
|
|
"group_names": ["svc-nfs-server"],
|
|
"groups": {"svc-swarm-manager": []},
|
|
}
|
|
self.assertEqual(self._resolve(vars_), RELAY)
|
|
|
|
def test_string_booleans_are_coerced(self):
|
|
vars_ = {"DOCKER_IN_CONTAINER": "True", "DEPLOYMENT_MODE": "compose"}
|
|
self.assertEqual(self._resolve(vars_, _email(external="yes")), "127.0.0.1")
|
|
|
|
def test_swarm_node_wins_over_a_populated_manager_group(self):
|
|
vars_ = {
|
|
"DOCKER_IN_CONTAINER": True,
|
|
"DEPLOYMENT_MODE": "swarm",
|
|
"group_names": ["svc-swarm-node"],
|
|
"groups": {"svc-swarm-manager": [MANAGER]},
|
|
}
|
|
self.assertEqual(self._resolve(vars_), "127.0.0.1")
|
|
|
|
def test_missing_terms_raise(self):
|
|
lm = self.LookupModule()
|
|
lm._templar = _DummyTemplar({})
|
|
with self.assertRaises(AnsibleError):
|
|
lm.run([], variables={})
|
|
|
|
def test_too_many_terms_raise(self):
|
|
lm = self.LookupModule()
|
|
lm._templar = _DummyTemplar({})
|
|
with self.assertRaises(AnsibleError):
|
|
lm.run([_email(), _email()], variables={})
|
|
|
|
def test_non_mapping_term_raises(self):
|
|
lm = self.LookupModule()
|
|
lm._templar = _DummyTemplar({})
|
|
with self.assertRaises(AnsibleError):
|
|
lm.run([RELAY], variables={})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|