#!/usr/bin/env python3 import os import sys import tempfile import time import unittest from pathlib import Path sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from registry import Registry # noqa: E402 class RegistryTests(unittest.TestCase): def setUp(self): self.reg = Registry(n=4) def test_unique_slots(self): a = self.reg.assign("AA:BB:CC:DD:EE:01") b = self.reg.assign("AA:BB:CC:DD:EE:02") self.assertIsNotNone(a) self.assertIsNotNone(b) self.assertNotEqual(a.slot, b.slot) def test_collector_assigns_slot(self): s = self.reg.assign("11:22:33:44:55:66") self.assertEqual(s.slot, 0) # sensor cannot pick slot — second assign same addr returns same s2 = self.reg.assign("11:22:33:44:55:66") self.assertIs(s, s2) def test_pool_full(self): for i in range(4): self.assertIsNotNone(self.reg.assign(f"AA:BB:CC:DD:EE:0{i}")) self.assertTrue(self.reg.pool_full()) self.assertIsNone(self.reg.assign("FF:FF:FF:FF:FF:FF")) def test_stale_keeps_slot(self): s = self.reg.assign("AA:BB:CC:DD:EE:10") s.last_seen = time.time() - 1000 self.reg.reevaluate(now=time.time(), period_s=30) # k=3 → stale at 90s; lost at 180s — 1000s → lost # use milder silence for stale only s2 = self.reg.assign("AA:BB:CC:DD:EE:11") s2.last_seen = time.time() - 100 self.reg.reevaluate(now=time.time(), period_s=30) self.assertEqual(s2.state, "stale") self.assertIs(self.reg.slots[s2.slot], s2) def test_lost_frees_slot(self): s = self.reg.assign("AA:BB:CC:DD:EE:20") slot = s.slot s.last_seen = time.time() - 10000 self.reg.reevaluate(now=time.time(), period_s=30) self.assertIsNone(self.reg.slots[slot]) self.assertNotIn("AA:BB:CC:DD:EE:20", self.reg.by_addr) def test_pool_full_iff_no_none(self): self.assertFalse(self.reg.pool_full()) for i in range(4): self.reg.assign(f"AA:00:00:00:00:0{i}") self.assertTrue(self.reg.pool_full()) self.assertTrue(None not in self.reg.slots) def test_persist(self): with tempfile.TemporaryDirectory() as td: path = Path(td) / "reg.json" r1 = Registry(n=4, path=path) r1.assign("AA:BB:CC:DD:EE:30") r1.save() r2 = Registry(n=4, path=path) r2.load() self.assertIn("AA:BB:CC:DD:EE:30", r2.by_addr) self.assertEqual(r2.by_addr["AA:BB:CC:DD:EE:30"].slot, 0) def test_status_name_and_age(self): s = self.reg.assign("AA:BB:CC:DD:EE:40") s.last_seen = time.time() - 125 st = self.reg.status_dict( names={"AA:BB:CC:DD:EE:40": "Коридор"}, report_interval_min=15, ) self.assertEqual(st["report_interval_min"], 15) self.assertEqual(st["period_s"], 900) row = st["slots"][s.slot] self.assertEqual(row["name"], "Коридор") self.assertGreaterEqual(row["age_s"], 124) self.assertLessEqual(row["age_s"], 126) s.battery = 30 st = self.reg.status_dict(names={"AA:BB:CC:DD:EE:40": "Коридор"}) row = st["slots"][s.slot] self.assertAlmostEqual(row["voltage_v"], 3.0) self.assertEqual(row["charge_percent"], 90) if __name__ == "__main__": unittest.main()