fault-log-analyzer/tests/test_storage.py

132 lines
4.7 KiB
Python

import _bootstrap # noqa: F401
import unittest
from datetime import datetime, timezone
from fault_log_analyzer.models import (
Event,
FaultFilterRule,
FaultLog,
FaultType,
RootCause,
)
from fault_log_analyzer.storage import (
InMemoryDedupCache,
InMemoryEventRepository,
InMemoryFaultLogRepository,
InMemoryFaultTypeRepository,
InMemoryFilterRuleRepository,
InMemoryLogSink,
InMemoryRootCauseRepository,
)
def make_log(fid, host="h-1", fault_type="disk_full", level="ERROR", message="disk full", minute=0):
return FaultLog(
fault_log_id=fid,
host_id=host,
fingerprint=f"fp-{fid}",
level=level,
message=message,
occurred_at=datetime(2025, 1, 1, 0, minute, 0, tzinfo=timezone.utc),
fault_type=fault_type,
)
class TestInMemoryFaultLogRepository(unittest.TestCase):
def setUp(self):
self.repo = InMemoryFaultLogRepository()
self.repo.save(make_log("fl1", host="h-1", fault_type="disk_full", level="ERROR", message="disk full", minute=1))
self.repo.save(make_log("fl2", host="h-2", fault_type="oom", level="FATAL", message="oom killed", minute=2))
def test_get(self):
self.assertIsNotNone(self.repo.get("fl1"))
self.assertIsNone(self.repo.get("nope"))
def test_list_filter_by_host(self):
total, items = self.repo.list(host_id="h-1")
self.assertEqual(total, 1)
self.assertEqual(items[0].fault_log_id, "fl1")
def test_list_filter_by_fault_type(self):
total, items = self.repo.list(fault_type="oom")
self.assertEqual(total, 1)
self.assertEqual(items[0].fault_log_id, "fl2")
def test_list_filter_by_level_and_keyword(self):
total, _ = self.repo.list(level="fatal")
self.assertEqual(total, 1)
total, items = self.repo.list(keyword="disk")
self.assertEqual(total, 1)
self.assertEqual(items[0].fault_log_id, "fl1")
def test_pagination(self):
total, items = self.repo.list(page=1, page_size=1)
self.assertEqual(total, 2)
self.assertEqual(len(items), 1)
class TestInMemoryRootCauseRepository(unittest.TestCase):
def test_save_and_get(self):
repo = InMemoryRootCauseRepository()
repo.save(RootCause(fault_log_id="fl1", cause_type="disk_full", confidence=0.9))
self.assertEqual(repo.get("fl1").cause_type, "disk_full")
self.assertIsNone(repo.get("nope"))
class TestInMemoryFaultTypeRepository(unittest.TestCase):
def test_add_list_get(self):
repo = InMemoryFaultTypeRepository()
repo.add(FaultType(fault_type="disk_full", name="磁盘满"))
self.assertEqual(repo.get("disk_full").name, "磁盘满")
self.assertEqual(len(repo.list()), 1)
def test_add_empty_raises(self):
repo = InMemoryFaultTypeRepository()
with self.assertRaises(ValueError):
repo.add(FaultType(fault_type="", name="x"))
class TestInMemoryFilterRuleRepository(unittest.TestCase):
def test_add_assigns_id(self):
repo = InMemoryFilterRuleRepository()
rule = repo.add(FaultFilterRule(name="disk", pattern="disk"))
self.assertIsNotNone(rule.id)
self.assertEqual(len(repo.list()), 1)
class TestInMemoryEventRepository(unittest.TestCase):
def test_list_by_host_window(self):
e1 = Event(event_id="e1", host_id="h-1", metric="cpu", value=1.0,
fired_at=datetime(2025, 1, 1, 0, 0, 0, tzinfo=timezone.utc))
e2 = Event(event_id="e2", host_id="h-2", metric="cpu", value=1.0,
fired_at=datetime(2025, 1, 1, 0, 0, 0, tzinfo=timezone.utc))
repo = InMemoryEventRepository([e1, e2])
start = datetime(2024, 12, 31, tzinfo=timezone.utc)
end = datetime(2025, 1, 2, tzinfo=timezone.utc)
self.assertEqual(len(repo.list_by_host("h-1", start, end)), 1)
self.assertEqual(repo.list_by_host("h-1", start, end)[0].event_id, "e1")
class TestInMemoryLogSink(unittest.TestCase):
def test_write_and_search(self):
sink = InMemoryLogSink()
sink.write(make_log("fl1", host="h-1", level="ERROR", message="disk full"))
sink.write(make_log("fl2", host="h-2", level="FATAL", message="oom"))
self.assertEqual(len(sink.search()), 2)
self.assertEqual(len(sink.search(host_id="h-1")), 1)
self.assertEqual(len(sink.search(level="fatal")), 1)
self.assertEqual(len(sink.search(keyword="disk")), 1)
class TestInMemoryDedupCache(unittest.TestCase):
def test_seen_before(self):
cache = InMemoryDedupCache()
self.assertFalse(cache.seen_before("fp1"))
self.assertTrue(cache.seen_before("fp1"))
self.assertFalse(cache.seen_before("fp2"))
if __name__ == "__main__":
unittest.main()