mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-13 14:16:46 +00:00
Add a 'timeout' lookup plugin that returns round(base * TIMEOUT_FACTOR)
(group_vars default 1, so value-identical to the old literals). One knob
in group_vars stretches every wait in the stack for a slow uplink:
TIMEOUT_FACTOR: 2 doubles them all.
- plugins/lookup/timeout.py + unit tests (identity, factor scaling,
string coercion, error paths).
- group_vars/all/17_resource.yml: TIMEOUT_FACTOR: 1.
- Convert all 34 literal 'timeout:' task keywords / module args across 25
task+handler files to "{{ lookup('timeout', <base>) | int }}".
- tests/lint/repository/yaml/test_timeout_uses_lookup.py enforces the
lookup in every task/handler timeout (opt-out: # nocheck: timeout-lookup).
- swarm.yml pre-deploy build handler: add the missing timeout (same
network-build hang vector as compose.yml's Build compose).
- Drop 13 pre-existing narration comments in the touched files (comment
lint enforces whole-file on any edited file).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
119 lines
3.5 KiB
Python
119 lines
3.5 KiB
Python
"""Unit tests for the timeout lookup plugin.
|
|
|
|
Pins the scaling contract:
|
|
|
|
* factor unset -> identity (value-identical drop-in for the literal).
|
|
* TIMEOUT_FACTOR from play vars scales the base.
|
|
* an explicit ``factor=`` kwarg overrides the global.
|
|
* numeric strings are coerced; non-numeric / negative base or factor raises.
|
|
* exactly one positional term is required.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import unittest
|
|
|
|
from ansible.errors import AnsibleError
|
|
|
|
from . import PROJECT_ROOT
|
|
|
|
|
|
def _load_lookup():
|
|
spec = importlib.util.spec_from_file_location(
|
|
"lookup_timeout", str(PROJECT_ROOT / "plugins/lookup/timeout.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 TestTimeoutLookup(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.LookupModule = _load_lookup()
|
|
|
|
def _make(self, variables):
|
|
lm = self.LookupModule()
|
|
lm._templar = _DummyTemplar(variables)
|
|
lm._loader = None
|
|
return lm
|
|
|
|
def test_factor_unset_is_identity(self):
|
|
lm = self._make({})
|
|
self.assertEqual(lm.run([3600], variables={}), [3600])
|
|
|
|
def test_factor_one_is_identity(self):
|
|
vars_ = {"TIMEOUT_FACTOR": 1}
|
|
lm = self._make(vars_)
|
|
self.assertEqual(lm.run([3600], variables=vars_), [3600])
|
|
|
|
def test_factor_two_doubles(self):
|
|
vars_ = {"TIMEOUT_FACTOR": 2}
|
|
lm = self._make(vars_)
|
|
self.assertEqual(lm.run([600], variables=vars_), [1200])
|
|
|
|
def test_fractional_factor_rounds(self):
|
|
vars_ = {"TIMEOUT_FACTOR": 1.5}
|
|
lm = self._make(vars_)
|
|
self.assertEqual(lm.run([100], variables=vars_), [150])
|
|
|
|
def test_string_base_coerced(self):
|
|
vars_ = {"TIMEOUT_FACTOR": 2}
|
|
lm = self._make(vars_)
|
|
self.assertEqual(lm.run(["300"], variables=vars_), [600])
|
|
|
|
def test_string_factor_coerced(self):
|
|
vars_ = {"TIMEOUT_FACTOR": "2"}
|
|
lm = self._make(vars_)
|
|
self.assertEqual(lm.run([300], variables=vars_), [600])
|
|
|
|
def test_explicit_factor_kwarg_overrides_global(self):
|
|
vars_ = {"TIMEOUT_FACTOR": 5}
|
|
lm = self._make(vars_)
|
|
self.assertEqual(lm.run([100], variables=vars_, factor=3), [300])
|
|
|
|
def test_zero_base_stays_zero(self):
|
|
vars_ = {"TIMEOUT_FACTOR": 4}
|
|
lm = self._make(vars_)
|
|
self.assertEqual(lm.run([0], variables=vars_), [0])
|
|
|
|
def test_no_term_raises(self):
|
|
lm = self._make({})
|
|
with self.assertRaises(AnsibleError):
|
|
lm.run([], variables={})
|
|
|
|
def test_too_many_terms_raises(self):
|
|
lm = self._make({})
|
|
with self.assertRaises(AnsibleError):
|
|
lm.run([1, 2], variables={})
|
|
|
|
def test_non_numeric_base_raises(self):
|
|
lm = self._make({})
|
|
with self.assertRaises(AnsibleError):
|
|
lm.run(["abc"], variables={})
|
|
|
|
def test_negative_factor_raises(self):
|
|
vars_ = {"TIMEOUT_FACTOR": -1}
|
|
lm = self._make(vars_)
|
|
with self.assertRaises(AnsibleError):
|
|
lm.run([100], variables=vars_)
|
|
|
|
def test_none_terms_raises(self):
|
|
lm = self._make({})
|
|
with self.assertRaises(AnsibleError):
|
|
lm.run(None, variables={})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|