Initial release: iai-mcp v0.1.0
Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: XNLLLLH <XNLLLLH@users.noreply.github.com>
This commit is contained in:
commit
f6b876fbe7
332 changed files with 97258 additions and 0 deletions
187
tests/test_events.py
Normal file
187
tests/test_events.py
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
"""Tests for the events LanceDB table + events.py module (Plan 02-01, D-STORAGE).
|
||||
|
||||
Covers:
|
||||
- events table created on MemoryStore instantiation
|
||||
- write_event / query_events round-trip
|
||||
- kind/severity/since filters
|
||||
- ordering (newest first)
|
||||
- limit default + explicit
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
# ----------------------------------------------------------- table creation
|
||||
|
||||
|
||||
def test_events_table_created_on_store_init(tmp_path):
|
||||
"""MemoryStore() creates events table with the D-STORAGE schema."""
|
||||
from iai_mcp.store import EVENTS_TABLE, MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
assert EVENTS_TABLE in store._table_names()
|
||||
|
||||
|
||||
def test_budget_ledger_table_created(tmp_path):
|
||||
from iai_mcp.store import BUDGET_TABLE, MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
assert BUDGET_TABLE in store._table_names()
|
||||
|
||||
|
||||
def test_ratelimit_ledger_table_created(tmp_path):
|
||||
from iai_mcp.store import MemoryStore, RATELIMIT_TABLE
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
assert RATELIMIT_TABLE in store._table_names()
|
||||
|
||||
|
||||
# ------------------------------------------------------ write_event / query
|
||||
|
||||
|
||||
def test_events_write_and_query_roundtrip(tmp_path):
|
||||
from iai_mcp.events import query_events, write_event
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
event_id = write_event(store, kind="test", data={"x": 1}, session_id="s1")
|
||||
assert isinstance(event_id, UUID)
|
||||
|
||||
results = query_events(store, kind="test")
|
||||
assert len(results) == 1
|
||||
assert results[0]["kind"] == "test"
|
||||
assert results[0]["data"]["x"] == 1
|
||||
assert results[0]["session_id"] == "s1"
|
||||
|
||||
|
||||
def test_events_write_returns_uuid(tmp_path):
|
||||
from iai_mcp.events import write_event
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
ev = write_event(store, kind="k", data={})
|
||||
assert isinstance(ev, UUID)
|
||||
|
||||
|
||||
def test_events_query_filter_kind(tmp_path):
|
||||
from iai_mcp.events import query_events, write_event
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
write_event(store, kind="a", data={})
|
||||
write_event(store, kind="b", data={})
|
||||
write_event(store, kind="c", data={})
|
||||
|
||||
assert len(query_events(store, kind="a")) == 1
|
||||
assert len(query_events(store, kind="b")) == 1
|
||||
assert len(query_events(store)) == 3
|
||||
|
||||
|
||||
def test_events_query_filter_since(tmp_path, monkeypatch):
|
||||
"""Events at different timestamps; since=30min-ago returns only the newer."""
|
||||
from iai_mcp.events import query_events, write_event
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
# We can't easily freeze time; instead write both events, then query with
|
||||
# since = far-future-past to confirm filter works (both return).
|
||||
write_event(store, kind="t", data={"old": True})
|
||||
write_event(store, kind="t", data={"new": True})
|
||||
|
||||
# since in the future -> no results
|
||||
future = datetime.now(timezone.utc) + timedelta(hours=1)
|
||||
assert query_events(store, kind="t", since=future) == []
|
||||
|
||||
# since well in the past -> 2 results
|
||||
past = datetime.now(timezone.utc) - timedelta(hours=1)
|
||||
assert len(query_events(store, kind="t", since=past)) == 2
|
||||
|
||||
|
||||
def test_events_query_filter_severity(tmp_path):
|
||||
from iai_mcp.events import query_events, write_event
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
write_event(store, kind="k", data={}, severity="info")
|
||||
write_event(store, kind="k", data={}, severity="warning")
|
||||
write_event(store, kind="k", data={}, severity="critical")
|
||||
|
||||
assert len(query_events(store, severity="critical")) == 1
|
||||
assert len(query_events(store, severity="warning")) == 1
|
||||
assert len(query_events(store, severity="info")) == 1
|
||||
|
||||
|
||||
def test_events_query_limit_default_100(tmp_path):
|
||||
from iai_mcp.events import query_events, write_event
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
for i in range(150):
|
||||
write_event(store, kind="bulk", data={"i": i})
|
||||
|
||||
# Default limit
|
||||
results = query_events(store, kind="bulk")
|
||||
assert len(results) == 100
|
||||
|
||||
# Explicit limit
|
||||
results = query_events(store, kind="bulk", limit=50)
|
||||
assert len(results) == 50
|
||||
|
||||
|
||||
def test_events_query_ordering_newest_first(tmp_path):
|
||||
"""Events must come back in descending ts order (newest first)."""
|
||||
import time
|
||||
|
||||
from iai_mcp.events import query_events, write_event
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
write_event(store, kind="ord", data={"i": 0})
|
||||
time.sleep(0.01)
|
||||
write_event(store, kind="ord", data={"i": 1})
|
||||
time.sleep(0.01)
|
||||
write_event(store, kind="ord", data={"i": 2})
|
||||
|
||||
results = query_events(store, kind="ord")
|
||||
# Newest (i=2) first
|
||||
ordered_is = [r["data"]["i"] for r in results]
|
||||
assert ordered_is == [2, 1, 0]
|
||||
|
||||
|
||||
def test_events_source_ids_roundtrip(tmp_path):
|
||||
"""source_ids list[UUID] is preserved as JSON array of strings."""
|
||||
from iai_mcp.events import query_events, write_event
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
ids = [uuid4(), uuid4()]
|
||||
write_event(store, kind="s", data={}, source_ids=ids)
|
||||
results = query_events(store, kind="s")
|
||||
assert len(results) == 1
|
||||
src = results[0]["source_ids"]
|
||||
assert set(src) == {str(i) for i in ids}
|
||||
|
||||
|
||||
def test_events_domain_roundtrip(tmp_path):
|
||||
from iai_mcp.events import query_events, write_event
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
write_event(store, kind="k", data={}, domain="coding")
|
||||
results = query_events(store, kind="k")
|
||||
assert len(results) == 1
|
||||
assert results[0]["domain"] == "coding"
|
||||
|
||||
|
||||
def test_events_empty_store_returns_empty(tmp_path):
|
||||
from iai_mcp.events import query_events
|
||||
from iai_mcp.store import MemoryStore
|
||||
|
||||
store = MemoryStore(path=tmp_path)
|
||||
assert query_events(store) == []
|
||||
assert query_events(store, kind="nothing") == []
|
||||
Loading…
Add table
Add a link
Reference in a new issue