125 lines
4.2 KiB
Python
125 lines
4.2 KiB
Python
"""Shared paths, script modules, synthetic logs and the CLI test case of the kvb-check-ansible tests."""
|
|||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import json
|
||
|
|
import subprocess
|
||
|
|
import sys
|
||
|
|
import tempfile
|
||
|
|
import unittest
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
SKILL = Path(__file__).resolve().parents[1] / "skills" / "kvb-check-ansible"
|
||
|
|
sys.path.insert(0, str(SKILL / "scripts"))
|
||
|
|
|
||
|
|
import ansible_bench
|
||
|
|
import ansible_log
|
||
|
|
import ansible_tables
|
||
|
|
|
||
|
|
__all__ = [
|
||
|
|
"BENCH",
|
||
|
|
"MIDNIGHT_LOG",
|
||
|
|
"PROFILE_DIR",
|
||
|
|
"PROFILE_LOG",
|
||
|
|
"SCRIPT",
|
||
|
|
"WALL_KINDS",
|
||
|
|
"WALL_LOG",
|
||
|
|
"LogCase",
|
||
|
|
"ansible_bench",
|
||
|
|
"ansible_log",
|
||
|
|
"ansible_tables",
|
||
|
|
]
|
||
|
|
|
||
|
|
SCRIPT = SKILL / "scripts" / "ansible_tasks.py"
|
||
|
|
PROFILE_DIR = SKILL / "scripts" / "profile"
|
||
|
|
BENCH = SKILL / "bench"
|
||
|
|
STARS = " " + "*" * 40
|
||
|
|
|
||
|
|
WALL_LOG = "\n".join(
|
||
|
|
[
|
||
|
|
"2026-11-07T06:45:40.0000000Z PLAY [deploy]" + STARS,
|
||
|
|
"2026-11-07T06:45:40.5000000Z TASK [setup : install]" + STARS,
|
||
|
|
"2026-11-07T06:45:43.0000000Z \x1b[0;33mchanged: [host]\x1b[0m",
|
||
|
|
"2026-11-07T06:45:44.0000000Z TASK [setup : check]" + STARS,
|
||
|
|
"2026-11-07T06:45:44.1000000Z skipping: [host]",
|
||
|
|
"2026-11-07T06:45:44.2Z TASK [setup : install]" + STARS,
|
||
|
|
"2026-11-07T06:45:44.5000000Z skipping: [host] => (item=a)",
|
||
|
|
"2026-11-07T06:45:45.0000000Z ok: [host] => (item=b)",
|
||
|
|
"2026-11-07T06:45:45.700000000Z TASK [setup : include]" + STARS,
|
||
|
|
"2026-11-07T06:45:45.8000000Z included: /x/y.yml for host",
|
||
|
|
"2026-11-07T06:45:46.0 TASK [setup : flush]" + STARS,
|
||
|
|
"2026-11-07T06:45:46.5000000Z [WARNING]: nothing to flush",
|
||
|
|
"2026-11-07T06:45:46.8000000Z RUNNING HANDLER [setup : restart]" + STARS,
|
||
|
|
"2026-11-07T06:45:48.0000000Z fatal: [host]: FAILED! => {}",
|
||
|
|
"2026-11-07T06:45:48.0000000Z PLAY RECAP" + STARS,
|
||
|
|
"2026-11-07T06:45:48.0000000Z host : ok=2 changed=1 skipped=1 failed=1",
|
||
|
|
]
|
||
|
|
) + "\n"
|
||
|
|
|
||
|
|
PROFILE_LINE = "Saturday 07 November 2026 06:45:40 +0000 ({}) 0:00:00.020 " + "*" * 20
|
||
|
|
PROFILE_LOG = "\n".join(
|
||
|
|
[
|
||
|
|
"PLAY [deploy]" + STARS,
|
||
|
|
"",
|
||
|
|
"TASK [Gathering Facts]" + STARS,
|
||
|
|
PROFILE_LINE.format("0:00:00.020"),
|
||
|
|
"ok: [host]",
|
||
|
|
"TASK [setup : install]" + STARS,
|
||
|
|
PROFILE_LINE.format("0:00:02.000"),
|
||
|
|
"changed: [host]",
|
||
|
|
"TASK [setup : check]" + STARS,
|
||
|
|
PROFILE_LINE.format("0:00:03.500"),
|
||
|
|
"skipping: [host]",
|
||
|
|
"TASK [setup : install]" + STARS,
|
||
|
|
PROFILE_LINE.format("0:00:00.100"),
|
||
|
|
"included: /x/y.yml for host",
|
||
|
|
"RUNNING HANDLER [setup : restart]" + STARS,
|
||
|
|
PROFILE_LINE.format("0:01:01.500"),
|
||
|
|
"ok: [host]",
|
||
|
|
"PLAY RECAP" + STARS,
|
||
|
|
"host : ok=3 changed=1 skipped=1",
|
||
|
|
"TASKS RECAP" + STARS,
|
||
|
|
PROFILE_LINE.format("0:00:00.400"),
|
||
|
|
"=" * 40,
|
||
|
|
"setup : install ----------------------- 63.50s",
|
||
|
|
]
|
||
|
|
) + "\n"
|
||
|
|
|
||
|
|
MIDNIGHT_LOG = chr(0xFEFF) + "2026-11-07T23:59:59.5Z TASK [late]" + STARS + "\n2026-11-08T00:00:00.25Z PLAY RECAP" + STARS + "\n"
|
||
|
|
|
||
|
|
WALL_KINDS = [
|
||
|
|
"kind\tcount\tsum\tmean\t<0.25\t<0.5\t<1\t<2\t>=2",
|
||
|
|
"ran\t3\t6.2\t2.0667\t0\t0\t0\t2\t1",
|
||
|
|
"other\t1\t0.8\t0.8000\t0\t0\t1\t0\t0",
|
||
|
|
"included\t1\t0.3\t0.3000\t0\t1\t0\t0\t0",
|
||
|
|
"skipped\t1\t0.2\t0.2000\t1\t0\t0\t0\t0",
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
class LogCase(unittest.TestCase):
|
||
|
|
def setUp(self):
|
||
|
|
tmp = tempfile.TemporaryDirectory()
|
||
|
|
self.addCleanup(tmp.cleanup)
|
||
|
|
self.base = Path(tmp.name)
|
||
|
|
self.wall = self.write("wall.log", WALL_LOG)
|
||
|
|
self.profile = self.write("profile.log", PROFILE_LOG)
|
||
|
|
|
||
|
|
def write(self, name: str, text: str) -> Path:
|
||
|
|
path = self.base / name
|
||
|
|
path.write_text(text, encoding="utf-8")
|
||
|
|
return path
|
||
|
|
|
||
|
|
def run_script(self, *args: str, env: dict | None = None) -> subprocess.CompletedProcess:
|
||
|
|
return subprocess.run(
|
||
|
|
[sys.executable, str(SCRIPT), *args], capture_output=True, text=True, check=False, env=env
|
||
|
|
)
|
||
|
|
|
||
|
|
def lines(self, *args: str) -> list[str]:
|
||
|
|
result = self.run_script(*args)
|
||
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
||
|
|
return result.stdout.splitlines()
|
||
|
|
|
||
|
|
def report(self, *args: str) -> dict:
|
||
|
|
result = self.run_script(*args, "--json")
|
||
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
||
|
|
return json.loads(result.stdout)
|