feat: add institutional governance and recovery contracts
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
import subprocess
|
||||
|
||||
from govoplan_core.commands import fenced_run
|
||||
from govoplan_core.core.runtime_coordination import LeaseClaim
|
||||
|
||||
|
||||
class _IgnoringProcess:
|
||||
def __init__(self) -> None:
|
||||
self.terminated = False
|
||||
self.killed = False
|
||||
self.wait_count = 0
|
||||
|
||||
def poll(self):
|
||||
return None if not self.killed else -9
|
||||
|
||||
def terminate(self) -> None:
|
||||
self.terminated = True
|
||||
|
||||
def kill(self) -> None:
|
||||
self.killed = True
|
||||
|
||||
def wait(self, *, timeout: float):
|
||||
self.wait_count += 1
|
||||
if not self.killed:
|
||||
raise subprocess.TimeoutExpired("command", timeout)
|
||||
return -9
|
||||
|
||||
|
||||
def test_fenced_process_is_killed_when_it_ignores_termination() -> None:
|
||||
process = _IgnoringProcess()
|
||||
|
||||
fenced_run._terminate_process(process, timeout_seconds=0.01)
|
||||
|
||||
assert process.terminated is True
|
||||
assert process.killed is True
|
||||
assert process.wait_count == 2
|
||||
|
||||
|
||||
def test_lease_release_is_best_effort_after_database_loss(monkeypatch) -> None:
|
||||
claim = LeaseClaim(
|
||||
installation_id="installation-1",
|
||||
resource_key="scheduler",
|
||||
holder_node_id="scheduler-1",
|
||||
holder_incarnation="incarnation-1",
|
||||
fencing_token=1,
|
||||
expires_at=datetime(2026, 8, 1, 12, 0, tzinfo=timezone.utc),
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
fenced_run,
|
||||
"get_database",
|
||||
lambda: (_ for _ in ()).throw(RuntimeError("database unavailable")),
|
||||
)
|
||||
|
||||
fenced_run._release(claim)
|
||||
Reference in New Issue
Block a user