65 lines
2.0 KiB
Python
65 lines
2.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Pure state-machine tests for the proposed storage monitor hysteresis."""
|
|
|
|
from dataclasses import dataclass
|
|
|
|
MIB = 1024 * 1024
|
|
|
|
|
|
@dataclass
|
|
class Monitor:
|
|
state: str = "OK"
|
|
low_streak: int = 0
|
|
good_streak: int = 0
|
|
notifications: int = 0
|
|
|
|
def sample(self, free: int | None, low: int, full: int) -> str:
|
|
if free is None:
|
|
return self.state
|
|
clear = max(low + 256 * MIB, low * 5 // 4)
|
|
old = self.state
|
|
if free <= full:
|
|
self.state, self.low_streak, self.good_streak = "CRITICAL", 0, 0
|
|
elif free <= low:
|
|
self.low_streak += 1
|
|
self.good_streak = 0
|
|
if self.low_streak >= 2:
|
|
self.state = "LOW"
|
|
elif free >= clear:
|
|
self.good_streak += 1
|
|
self.low_streak = 0
|
|
if self.good_streak >= 3:
|
|
self.state = "OK"
|
|
else:
|
|
self.low_streak = self.good_streak = 0
|
|
if self.state != old:
|
|
self.notifications += 1
|
|
return self.state
|
|
|
|
|
|
def main():
|
|
low, full = 800 * MIB, 100 * MIB
|
|
m = Monitor()
|
|
assert m.sample(700 * MIB, low, full) == "OK"
|
|
assert m.sample(700 * MIB, low, full) == "LOW"
|
|
assert m.notifications == 1
|
|
for _ in range(10):
|
|
assert m.sample(750 * MIB, low, full) == "LOW"
|
|
assert m.notifications == 1
|
|
assert m.sample(90 * MIB, low, full) == "CRITICAL"
|
|
assert m.notifications == 2
|
|
clear = max(low + 256 * MIB, low * 5 // 4)
|
|
assert m.sample(clear, low, full) == "CRITICAL"
|
|
assert m.sample(clear, low, full) == "CRITICAL"
|
|
assert m.sample(clear, low, full) == "OK"
|
|
assert m.notifications == 3
|
|
assert m.sample(None, low, full) == "OK"
|
|
# eMMC health is intentionally absent from the capacity input/state.
|
|
health_warning = True
|
|
assert health_warning and m.state == "OK"
|
|
print("PASS: entry debounce, critical, hysteresis, dedupe, unknown, health separation")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|