import json
import os
import tempfile
import pytest
from silk import GraphStore
ONTOLOGY = json.dumps(
{
"node_types": {
"entity": {
"properties": {
"status": {"value_type": "string", "required": False},
},
},
},
"edge_types": {
"LINKS": {
"source_types": ["entity"],
"target_types": ["entity"],
"properties": {},
},
},
}
)
class TestPersistence:
def test_persistent_store_creates_file(self):
with tempfile.TemporaryDirectory() as tmpdir:
path = os.path.join(tmpdir, "test.redb")
assert not os.path.exists(path)
store = GraphStore("inst-1", ONTOLOGY, path)
assert os.path.exists(path)
assert store.len() == 1
def test_persistent_store_survives_reopen(self):
with tempfile.TemporaryDirectory() as tmpdir:
path = os.path.join(tmpdir, "test.redb")
store = GraphStore("inst-1", ONTOLOGY, path)
store.add_node("n1", "entity", "Node 1")
store.add_node("n2", "entity", "Node 2")
assert store.len() == 3 del store
store2 = GraphStore.open(path)
assert store2.len() == 3
assert len(store2.heads()) == 1
def test_persistent_store_preserves_heads(self):
with tempfile.TemporaryDirectory() as tmpdir:
path = os.path.join(tmpdir, "test.redb")
store = GraphStore("inst-1", ONTOLOGY, path)
h1 = store.add_node("n1", "entity", "Node 1")
h2 = store.add_node("n2", "entity", "Node 2")
heads_before = store.heads()
del store
store2 = GraphStore.open(path)
assert len(store2.heads()) == 1
assert store2.heads()[0] == h2
def test_persistent_store_get_entry(self):
with tempfile.TemporaryDirectory() as tmpdir:
path = os.path.join(tmpdir, "test.redb")
store = GraphStore("inst-1", ONTOLOGY, path)
h1 = store.add_node("n1", "entity", "Node 1")
del store
store2 = GraphStore.open(path)
entry = store2.get(h1)
assert entry is not None
assert entry["hash"] == h1
def test_open_nonexistent_raises(self):
with pytest.raises(IOError):
GraphStore.open("/tmp/nonexistent_silk_test.redb")
def test_in_memory_default_still_works(self):
store = GraphStore("inst-1", ONTOLOGY)
store.add_node("n1", "entity", "Node 1")
assert store.len() == 2
assert len(store.heads()) == 1
class TestEntriesSince:
def test_entries_since_none_returns_all(self):
store = GraphStore("inst-1", ONTOLOGY)
store.add_node("n1", "entity", "Node 1")
store.add_node("n2", "entity", "Node 2")
entries = store.entries_since()
assert len(entries) == 3
def test_entries_since_hash_returns_delta(self):
store = GraphStore("inst-1", ONTOLOGY)
h1 = store.add_node("n1", "entity", "Node 1")
h2 = store.add_node("n2", "entity", "Node 2")
h3 = store.add_node("n3", "entity", "Node 3")
delta = store.entries_since(h1)
hashes = [e["hash"] for e in delta]
assert len(hashes) == 2
assert h2 in hashes
assert h3 in hashes
def test_entries_since_preserves_causal_order(self):
store = GraphStore("inst-1", ONTOLOGY)
h1 = store.add_node("n1", "entity", "Node 1")
h2 = store.add_node("n2", "entity", "Node 2")
h3 = store.add_node("n3", "entity", "Node 3")
all_entries = store.entries_since()
hashes = [e["hash"] for e in all_entries]
assert hashes.index(h1) < hashes.index(h2)
assert hashes.index(h2) < hashes.index(h3)
def test_entries_since_latest_returns_empty(self):
store = GraphStore("inst-1", ONTOLOGY)
h1 = store.add_node("n1", "entity", "Node 1")
delta = store.entries_since(h1)
assert len(delta) == 0
def test_entries_since_persistent(self):
with tempfile.TemporaryDirectory() as tmpdir:
path = os.path.join(tmpdir, "test.redb")
store = GraphStore("inst-1", ONTOLOGY, path)
h1 = store.add_node("n1", "entity", "Node 1")
store.add_node("n2", "entity", "Node 2")
del store
store2 = GraphStore.open(path)
delta = store2.entries_since(h1)
assert len(delta) == 1
def test_entry_payload_is_json(self):
store = GraphStore("inst-1", ONTOLOGY)
store.add_node("n1", "entity", "Node 1", {"status": "active"})
entries = store.entries_since()
for e in entries:
assert "payload" in e
parsed = json.loads(e["payload"])
assert "op" in parsed