mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-11-25 22:42:06 +00:00
Refactor JVM memory filters, add Redis sizing and Docker cleanup service
- Replace jvm_filters with unified memory_filters (JVM + Redis helpers) - Add redis_maxmemory_mb filter and unit tests - Introduce sys-ctl-cln-docker role (systemd-based Docker prune + anon volumes) - Refactor disk space health check to Python script and wire SIZE_PERCENT_CLEANUP_DISC_SPACE - Adjust schedules and services for Docker cleanup and disk space health See discussion: https://chatgpt.com/share/6925c1c5-ee38-800f-84b6-da29ccfa7537
This commit is contained in:
123
tests/unit/roles/sys-ctl-hlth-disc-space/files/script.py
Normal file
123
tests/unit/roles/sys-ctl-hlth-disc-space/files/script.py
Normal file
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
import pathlib
|
||||
import contextlib
|
||||
import importlib.util
|
||||
from types import SimpleNamespace
|
||||
from unittest import mock
|
||||
|
||||
|
||||
def load_target_module():
|
||||
"""
|
||||
Load the target script (roles/sys-ctl-hlth-disc-space/files/script.py)
|
||||
via its file path so that dashes in the directory name are not an issue.
|
||||
"""
|
||||
# tests/unit/roles/sys-ctl-hlth-disc-space/files/script.py
|
||||
test_file_path = pathlib.Path(__file__).resolve()
|
||||
repo_root = test_file_path.parents[4] # go up: files -> ... -> unit -> tests -> <root>
|
||||
|
||||
script_path = repo_root / "roles" / "sys-ctl-hlth-disc-space" / "files" / "script.py"
|
||||
if not script_path.is_file():
|
||||
raise FileNotFoundError(f"Target script not found at: {script_path}")
|
||||
|
||||
spec = importlib.util.spec_from_file_location("disk_space_script", script_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
assert spec.loader is not None
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
# Load the module once for all tests
|
||||
SCRIPT_MODULE = load_target_module()
|
||||
|
||||
|
||||
class TestDiskSpaceScript(unittest.TestCase):
|
||||
def test_get_disk_usage_percentages_parses_output(self):
|
||||
"""
|
||||
Ensure get_disk_usage_percentages parses 'df --output=pcent' correctly
|
||||
and returns integer percentages without the '%' sign.
|
||||
"""
|
||||
# Fake df output, including header line and various spacings
|
||||
fake_df_output = "Use%\n 10%\n 50%\n100%\n"
|
||||
|
||||
with mock.patch.object(
|
||||
SCRIPT_MODULE.subprocess,
|
||||
"run",
|
||||
return_value=SimpleNamespace(stdout=fake_df_output, returncode=0),
|
||||
):
|
||||
result = SCRIPT_MODULE.get_disk_usage_percentages()
|
||||
|
||||
self.assertEqual(result, [10, 50, 100])
|
||||
|
||||
def test_main_exits_zero_when_below_threshold(self):
|
||||
"""
|
||||
If all filesystems are below or equal the threshold,
|
||||
main() should exit with status code 0.
|
||||
"""
|
||||
# First call: 'df' (printing only) -> we don't care about stdout here
|
||||
df_print_cp = SimpleNamespace(stdout="Filesystem ...\n", returncode=0)
|
||||
# Second call: 'df --output=pcent'
|
||||
df_pcent_cp = SimpleNamespace(stdout="Use%\n 10%\n 50%\n 80%\n", returncode=0)
|
||||
|
||||
def fake_run(args, capture_output=False, text=False, check=False):
|
||||
# Decide which fake result to return based on the arguments
|
||||
if args == ["df", "--output=pcent"]:
|
||||
return df_pcent_cp
|
||||
elif args == ["df"]:
|
||||
return df_print_cp
|
||||
else:
|
||||
raise AssertionError(f"Unexpected subprocess.run args: {args}")
|
||||
|
||||
with mock.patch.object(SCRIPT_MODULE.subprocess, "run", side_effect=fake_run):
|
||||
with mock.patch.object(sys, "argv", ["script.py", "80"]):
|
||||
with mock.patch.object(SCRIPT_MODULE.sys, "exit", side_effect=SystemExit) as mock_exit:
|
||||
# Capture stdout to avoid clutter in test output
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
with self.assertRaises(SystemExit):
|
||||
SCRIPT_MODULE.main()
|
||||
|
||||
# Expect no filesystem above 80% -> exit code 0
|
||||
mock_exit.assert_called_once_with(0)
|
||||
|
||||
def test_main_exits_with_error_count_and_prints_warnings(self):
|
||||
"""
|
||||
If some filesystems exceed the threshold, main() should:
|
||||
- Print a warning for each filesystem that exceeds it
|
||||
- Exit with a status code equal to the number of such filesystems
|
||||
"""
|
||||
df_print_cp = SimpleNamespace(stdout="Filesystem ...\n", returncode=0)
|
||||
# Two filesystems above threshold (90%, 95%), one below (60%)
|
||||
df_pcent_cp = SimpleNamespace(stdout="Use%\n 60%\n 90%\n 95%\n", returncode=0)
|
||||
|
||||
def fake_run(args, capture_output=False, text=False, check=False):
|
||||
if args == ["df", "--output=pcent"]:
|
||||
return df_pcent_cp
|
||||
elif args == ["df"]:
|
||||
return df_print_cp
|
||||
else:
|
||||
raise AssertionError(f"Unexpected subprocess.run args: {args}")
|
||||
|
||||
with mock.patch.object(SCRIPT_MODULE.subprocess, "run", side_effect=fake_run):
|
||||
with mock.patch.object(sys, "argv", ["script.py", "80"]):
|
||||
with mock.patch.object(SCRIPT_MODULE.sys, "exit", side_effect=SystemExit) as mock_exit:
|
||||
buffer = io.StringIO()
|
||||
with contextlib.redirect_stdout(buffer):
|
||||
with self.assertRaises(SystemExit):
|
||||
SCRIPT_MODULE.main()
|
||||
|
||||
# Expect exit code 2 (two filesystems over 80%)
|
||||
mock_exit.assert_called_once_with(2)
|
||||
|
||||
output = buffer.getvalue()
|
||||
self.assertIn("Checking disk space usage...", output)
|
||||
self.assertIn("WARNING: 90% exceeds the limit of 80%.", output)
|
||||
self.assertIn("WARNING: 95% exceeds the limit of 80%.", output)
|
||||
# Ensure the "below threshold" value does not produce a warning
|
||||
self.assertNotIn("60% exceeds the limit of 80%.", output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user