import time
from silk import GraphStore, CompactionPolicy, IntervalPolicy, ThresholdPolicy
ONTOLOGY = {
"node_types": {"entity": {"properties": {}}},
"edge_types": {}
}
def _store():
return GraphStore("test", ONTOLOGY)
def test_threshold_no_compact_below():
store = _store()
store.add_node("n1", "entity", "A")
policy = ThresholdPolicy(max_entries=100)
result = policy.check(store)
assert result is None
assert store.len() > 1
def test_threshold_compacts_above():
store = _store()
for i in range(20):
store.add_node(f"n{i}", "entity", f"Node {i}")
assert store.len() > 20
policy = ThresholdPolicy(max_entries=10)
result = policy.check(store)
assert result is not None assert len(result) == 64 assert store.len() == 1
def test_threshold_preserves_data():
store = _store()
for i in range(15):
store.add_node(f"n{i}", "entity", f"Node {i}")
policy = ThresholdPolicy(max_entries=5)
policy.check(store)
for i in range(15):
assert store.get_node(f"n{i}") is not None
def test_threshold_should_compact():
store = _store()
for i in range(10):
store.add_node(f"n{i}", "entity", f"Node {i}")
policy = ThresholdPolicy(max_entries=100)
assert policy.should_compact(store) is False
policy2 = ThresholdPolicy(max_entries=5)
assert policy2.should_compact(store) is True
def test_interval_first_check_compacts():
store = _store()
store.add_node("n1", "entity", "A")
policy = IntervalPolicy(seconds=0.01)
time.sleep(0.02)
result = policy.check(store)
assert result is not None
assert store.len() == 1
def test_interval_second_check_skips():
store = _store()
store.add_node("n1", "entity", "A")
policy = IntervalPolicy(seconds=10.0) policy.check(store)
store.add_node("n2", "entity", "B")
result = policy.check(store) assert result is None
assert store.len() == 2
def test_interval_compacts_after_wait():
store = _store()
store.add_node("n1", "entity", "A")
policy = IntervalPolicy(seconds=0.01)
policy.check(store)
store.add_node("n2", "entity", "B")
time.sleep(0.02)
result = policy.check(store)
assert result is not None
assert store.len() == 1
def test_custom_policy():
class AlwaysCompact:
def should_compact(self, store):
return True
def check(self, store):
if self.should_compact(store):
return store.compact()
return None
store = _store()
store.add_node("n1", "entity", "A")
policy = AlwaysCompact()
result = policy.check(store)
assert result is not None
assert store.len() == 1
def test_custom_policy_never():
class NeverCompact:
def should_compact(self, store):
return False
def check(self, store):
return None
store = _store()
store.add_node("n1", "entity", "A")
policy = NeverCompact()
result = policy.check(store)
assert result is None
assert store.len() > 1
def test_protocol_check():
class Good:
def should_compact(self, store): return False
def check(self, store): return None
class Bad:
pass
assert isinstance(Good(), CompactionPolicy)
assert not isinstance(Bad(), CompactionPolicy)
def test_builtin_policies_implement_protocol():
assert isinstance(IntervalPolicy(seconds=60), CompactionPolicy)
assert isinstance(ThresholdPolicy(max_entries=100), CompactionPolicy)
def test_policies_pass_reclaim_disk(tmp_path):
import os
path = str(tmp_path / "policy.redb")
ontology = {
"node_types": {"entity": {"properties": {"status": {"value_type": "string"}}}},
"edge_types": {}
}
store = GraphStore("test", ontology, path=path)
filler = "x" * 200
for i in range(300):
store.add_node(f"n{i}", "entity", f"Node {i}", {"status": filler})
for i in range(300):
store.remove_node(f"n{i}")
size_before = os.path.getsize(path)
policy = ThresholdPolicy(max_entries=10, reclaim_disk=True)
result = policy.check(store)
assert result is not None
assert store.len() == 1
assert os.path.getsize(path) < size_before / 2
def test_interval_policy_accepts_reclaim_disk():
store = _store()
store.add_node("n1", "entity", "A")
policy = IntervalPolicy(seconds=0, reclaim_disk=True)
result = policy.check(store)
assert result is not None
assert store.len() == 1