test_core_improvements.py #1

  • //
  • guest/
  • russell_jackson/
  • sdp/
  • test/
  • test_core_improvements.py
  • View
  • Commits
  • Open Download .zip Download (13 KB)
#!/usr/bin/env python3
"""Offline coverage of bounded cleanup and retained/correlated run logs."""
import importlib.util
import fcntl
import json
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
from unittest.mock import patch

import test_core_review as core
import test_runtime_review as runtime
import test_maintenance_review as maintenance


class LogRetention(unittest.TestCase):
    def setUp(self):
        self.tmp = tempfile.TemporaryDirectory(prefix="sdp-run-logs-")
        self.addCleanup(self.tmp.cleanup)
        self.root = Path(self.tmp.name)
        self.log = self.root / "log with spaces.log"

    def rotate(self, language, keep="2", size="0"):
        if language == "python":
            core.logger.prepare_run_log(self.log, keep, size)
        else:
            result = subprocess.run([core.BASH, "-c", 'source "$HELPER"; sdp_prepare_run_log "$FILE"'],
                                    env=dict(os.environ, HELPER=str(core.BIN / "sdp_structured_log.sh"),
                                             FILE=str(self.log), SDP_RUN_LOG_KEEP=keep,
                                             SDP_RUN_LOG_MAX_BYTES=size), capture_output=True, text=True)
            self.assertEqual(result.returncode, 0, result.stderr)

    def test_rotation_retains_latest_two_runs_in_both_languages(self):
        for language in ["python", "bash"]:
            with self.subTest(language=language):
                for path in self.root.iterdir():
                    path.unlink()
                unrelated = self.log.with_name(self.log.name + ".run-unrelated")
                unrelated.write_text("leave this alone")
                for number in range(4):
                    self.log.write_text(str(number))
                    self.rotate(language)
                archives = [p for p in self.root.iterdir() if p != unrelated]
                self.assertEqual(sorted(p.read_text() for p in archives), ["2", "3"])
                self.assertEqual(unrelated.read_text(), "leave this alone")

    def test_size_budget_keeps_latest_failure_even_if_large(self):
        for language in ["python", "bash"]:
            with self.subTest(language=language):
                for path in self.root.iterdir():
                    path.unlink()
                self.log.write_text("old")
                self.rotate(language, "0", "5")
                self.log.write_text("large failed run diagnostics")
                self.rotate(language, "0", "5")
                archives = list(self.root.iterdir())
                self.assertEqual(len(archives), 1)
                self.assertEqual(archives[0].read_text(), "large failed run diagnostics")

    def test_future_dated_legacy_archive_never_displaces_current_failure(self):
        for language in ["python", "bash"]:
            with self.subTest(language=language):
                for path in self.root.iterdir():
                    path.unlink()
                legacy = self.log.with_name(self.log.name + ".run-20990101T000000Z-legacy")
                legacy.write_text("old diagnostics with future timestamp")
                os.utime(legacy, (4070908800, 4070908800))
                self.log.write_text("current failure")
                self.rotate(language, "1", "1")
                archives = list(self.root.iterdir())
                self.assertEqual(len(archives), 1)
                self.assertEqual(archives[0].read_text(), "current failure")

    def test_mixed_languages_keep_rotation_order_with_identical_timestamps(self):
        for number, language in enumerate(["python", "bash", "python", "bash", "python"]):
            # Emulate a coarse clock/filesystem and future-dated metadata.
            for path in self.root.iterdir():
                os.utime(path, (4070908800, 4070908800))
            self.log.write_text(str(number))
            self.rotate(language)
        self.assertEqual(sorted(p.read_text() for p in self.root.iterdir()), ["3", "4"])

    def test_invalid_limits_preserve_previous_log(self):
        self.log.write_text("previous failure")
        with self.assertRaises(ValueError):
            core.logger.prepare_run_log(self.log, "invalid")
        result = subprocess.run([core.BASH, "-c", 'source "$HELPER"; sdp_prepare_run_log "$FILE"'],
                                env=dict(os.environ, HELPER=str(core.BIN / "sdp_structured_log.sh"),
                                         FILE=str(self.log), SDP_RUN_LOG_KEEP="-1"), capture_output=True)
        self.assertEqual(result.returncode, 1)
        self.assertEqual(self.log.read_text(), "previous failure")

    def test_symlink_targets_are_not_modified(self):
        target = self.root / "valuable"
        target.write_text("evidence")
        self.log.symlink_to(target)
        with self.assertRaises(ValueError):
            core.logger.prepare_run_log(self.log)
        self.assertEqual(target.read_text(), "evidence")

    def test_overflow_limits_do_not_rotate_or_delete_logs(self):
        self.log.write_text("previous failure")
        huge = "18446744073709551620"
        with self.assertRaises(ValueError):
            core.logger.prepare_run_log(self.log, huge)
        result = subprocess.run([core.BASH, "-c", 'source "$HELPER"; sdp_prepare_run_log "$FILE"'],
                                env=dict(os.environ, HELPER=str(core.BIN / "sdp_structured_log.sh"),
                                         FILE=str(self.log), SDP_RUN_LOG_KEEP=huge), capture_output=True)
        self.assertEqual(result.returncode, 1)
        self.assertEqual(self.log.read_text(), "previous failure")

    def test_python_run_id_correlates_context_json_and_prom_comment(self):
        env = {"LOGS": str(self.root), "SDP_METRICS_DIR": str(self.root)}
        with patch.dict(os.environ, env):
            with core.logger.run("sample.py", mode="jsonl") as event:
                self.assertEqual(core.logger.current_run_id(), event.run_id)
                event.add(run_id="cannot override")
            self.assertEqual(json.loads((self.root / "sample.jsonl").read_text())["run_id"], event.run_id)
            prom = core.logger.SDPEvent("sample.py", mode="prom")
            prom.emit(0)
            content = (self.root / "p4_sdp_sample.prom").read_text()
            self.assertIn("# run_id " + prom.run_id, content)
            self.assertNotIn('run_id="', content)

    def test_shell_run_id_correlates_text_and_json(self):
        f = core.CoreReview(methodName="runTest")
        f.setUp()
        self.addCleanup(f.doCleanups)
        script = f.root / "correlate.sh"
        script.write_text('source "' + str(core.BIN / "sdp_structured_log.sh") + '"\nsdp_run_log_init correlate.sh\necho diagnostic\n')
        result = f.run_bash(script)
        self.assertEqual(result.returncode, 0, result.stderr)
        event = json.loads((f.logs / "correlate.jsonl").read_text())
        self.assertIn("run_id=" + event["run_id"], (f.logs / "correlate.log").read_text())

    def test_maintenance_preserves_failure_and_correlates_next_run(self):
        env = {"LOGS": str(self.root), "SDP_RUN_LOG_KEEP": "2"}
        log = self.root / "maintenance_sample.log"
        log.write_text("previous failure diagnostics")
        with patch.dict(os.environ, env), patch.dict(sys.modules, {"sdp_structured_log": core.logger}):
            with core.logger.run("maintenance_sample.py") as event:
                with maintenance.sdputils.maintenance_run("maintenance_sample.py", "1"):
                    print("current diagnostics")
        self.assertIn("run_id=" + event.run_id, log.read_text())
        self.assertEqual(next(self.root.glob(log.name + ".run-*")).read_text(), "previous failure diagnostics")
        self.assertEqual(json.loads((self.root / "maintenance_sample.jsonl").read_text())["run_id"], event.run_id)

    def test_verify_preserves_all_previous_diagnostics_before_work(self):
        spec = importlib.util.spec_from_file_location("improved_verify", core.BIN / "p4verify.py")
        module = importlib.util.module_from_spec(spec)
        sys.modules[spec.name] = module
        self.addCleanup(sys.modules.pop, spec.name, None)
        spec.loader.exec_module(module)
        module.sdplog = core.logger
        names = ["verify_output.log", "p4verify.log", "p4verify_errors.log", "p4verify-shelves.log", "p4verify_autotune.csv"]
        for name in names:
            (self.root / name).write_text("previous failure in " + name)
        verify = module.P4Verify.__new__(module.P4Verify)
        verify.instance = "1"
        verify.debug = False
        verify.L = None
        verify._sdp_event = core.logger.SDPEvent("p4verify.py")
        verify.load_sdp_environment = lambda: None
        class StopBeforeExternalWork(Exception):
            pass
        def stop():
            raise StopBeforeExternalWork()
        verify.check_backup_functions_present = stop
        with patch.dict(os.environ, {"LOGS": str(self.root)}):
            with self.assertRaises(StopBeforeExternalWork):
                verify.run()
        for name in names:
            archives = list(self.root.glob(name + ".run-*"))
            self.assertEqual(len(archives), 1, name)
            self.assertEqual(archives[0].read_text(), "previous failure in " + name)

    def test_competing_verifier_does_not_rotate_active_logs_or_start_work(self):
        spec = importlib.util.spec_from_file_location("locked_verify", core.BIN / "p4verify.py")
        module = importlib.util.module_from_spec(spec)
        sys.modules[spec.name] = module
        self.addCleanup(sys.modules.pop, spec.name, None)
        spec.loader.exec_module(module)
        verify = module.P4Verify.__new__(module.P4Verify)
        verify.instance, verify.L = "1", None
        verify._sdp_event = core.logger.SDPEvent("p4verify.py")
        verify.load_sdp_environment = lambda: None
        active = self.root / "verify_output.log"
        active.write_text("running verification diagnostics")
        with (self.root / "p4verify.lock").open("a") as lock, patch.dict(os.environ, {"LOGS": str(self.root)}):
            fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
            verify._run_locked = lambda _: self.fail("Competing invocation started work")
            verify.run()
            self.assertEqual(verify._sdp_event.status, "skipped")
        self.assertEqual(active.read_text(), "running verification diagnostics")
        self.assertEqual(list(self.root.glob("*.run-*")), [])
        with patch.dict(os.environ, {"LOGS": str(self.root)}):
            verify._run_locked = lambda _: None
            verify.run()  # Persistent filename does not prevent a later run.


class BoundedCacheCleanup(unittest.TestCase):
    def fixture(self):
        suite = runtime.CacheCleanupReview(methodName="runTest")
        suite.setUp()
        self.addCleanup(suite.doCleanups)
        f = suite.fixture
        for n in range(4):
            (f.home / ("depots/depot " + str(n))).mkdir()
        f.write_executable(f.mockbin / "find", "#!" + sys.executable + r'''
import fcntl, json, os, sys, time
from pathlib import Path
root = Path(os.environ["SDP_TEST_ROOT"])
if sys.argv[1] == str(root / "metrics"):
    sys.exit(0)
state = root / "workers.json"
with (root / "workers.lock").open("a") as lock:
    fcntl.flock(lock, fcntl.LOCK_EX)
    data = json.loads(state.read_text()) if state.exists() else {"active": 0, "maximum": 0, "done": 0}
    data["active"] += 1
    data["maximum"] = max(data["active"], data["maximum"])
    state.write_text(json.dumps(data))
time.sleep(0.15)
with (root / "workers.lock").open("a") as lock:
    fcntl.flock(lock, fcntl.LOCK_EX)
    data = json.loads(state.read_text())
    data["active"] -= 1
    data["done"] += 1
    state.write_text(json.dumps(data))
sys.stdout.write("..")
''')
        return f

    def test_worker_limit_is_obeyed_and_all_counts_are_collected(self):
        f = self.fixture()
        result = f.run_script("cacheclean.sh", "1", extra={"SDP_CACHE_CLEAN_WORKERS": "2"})
        self.assertEqual(result.returncode, 0, result.stderr + f.log("cacheclean"))
        state = json.loads((f.root / "workers.json").read_text())
        self.assertEqual(state, {"active": 0, "maximum": 2, "done": 5})
        self.assertEqual(f.event("cacheclean")["files_removed"], 10)
        self.assertEqual(f.event("cacheclean")["depot_count"], 5)
        self.assertIn("seconds", f.log("cacheclean"))

    def test_invalid_worker_limit_runs_no_deletions(self):
        f = self.fixture()
        for limit in ["0", "257", "18446744073709551620", "invalid"]:
            with self.subTest(limit=limit):
                result = f.run_script("cacheclean.sh", "1", extra={"SDP_CACHE_CLEAN_WORKERS": limit})
                self.assertEqual(result.returncode, 1)
                self.assertFalse((f.root / "workers.json").exists())


if __name__ == "__main__":
    unittest.main()
# Change User Description Committed
#1 34004 Russell C. Jackson (Rusty) Improve SDP backup/recovery, Maintenance, logging and cloud operation.

Add owned checkpoint locks, recovery-aware retention, preserved database switches,
bounded cleanup and coordinated AWS/Azure snapshots. Fix service-user password
initialization, edge staging, standby promotion state parsing, proxy cache setup,
typed depot verification and historical-server configuration/error handling.
Remove unused OTP programs; keep Windows removed, server.locks cleanup and the
journal-count condition unchanged. Add no global shell strict modes.

Update operational documentation and add reproducible mkdirs.sh/mkdirs.cfg
container assurance. Validate Ubuntu 26.04 and UBI 8.10/9.8/10.2 across both Python
runtimes: 44 stages; 428 offline tests per runtime/OS, zero offline skips;
19 deployed-archive comparisons per combination. Three six-node topology runs
pass all 30 recovery/failure scenarios. P4D 2023.1 through 2026.1 on UBI 8/9
pass all 14 cells and 98 scenarios. Static, documentation and provenance checks
pass. Containers do not certify every fleet kernel, patch build or integration.

Tested source manifest SHA-256:
e1a23e17b8ced8c1148d9a250589977c6f6e98606bf2a81dc3ff5d7c909e3695
Deployed comparison archive SHA-256:
1bd23217356ee3808e040d39aea5be9519bda7c8f2b4924656a70aff8ad7293a