"""Extended tests for InMemoryVectorIndex delete operations."""
import pytest
from core.models import IndexRecord, RequestContext
from providers.vector_index.in_memory_index import InMemoryVectorIndex
class TestInMemoryDeleteOperations:
"""Tests for delete_account_data and delete_by_owner_space methods."""
def test_delete_account_data_removes_all_account_records(self):
"""Test deleting all records for an account."""
index = InMemoryVectorIndex()
records = [
IndexRecord(
id="1", uri="ctx://acme/users/u1/memories/profile",
level=0, text="abstract", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={"category": "profile"}
),
IndexRecord(
id="2", uri="ctx://acme/users/u1/memories/preferences/p1",
level=0, text="pref1", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={"category": "preference"}
),
IndexRecord(
id="3", uri="ctx://other/users/u2/memories/profile",
level=0, text="other", filters={"account_id": "other", "owner_space": "user:u2"},
metadata={"category": "profile"}
),
]
index.upsert(records)
deleted = index.delete_account_data("acme")
assert deleted == 2
assert index.count() == 1
assert index.get_record("1") is None
assert index.get_record("2") is None
assert index.get_record("3") is not None
def test_delete_account_data_returns_count(self):
"""Test delete_account_data returns correct count."""
index = InMemoryVectorIndex()
records = [
IndexRecord(
id=f"{i}", uri=f"ctx://acme/users/u1/memories/p{i}",
level=0, text=f"text{i}", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={}
)
for i in range(5)
]
index.upsert(records)
assert index.delete_account_data("acme") == 5
assert index.delete_account_data("nonexistent") == 0
def test_delete_by_owner_space_removes_matching_records(self):
"""Test deleting by account_id + owner_space."""
index = InMemoryVectorIndex()
records = [
IndexRecord(
id="1", uri="ctx://acme/users/u1/memories/profile",
level=0, text="u1 profile", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={"category": "profile"}
),
IndexRecord(
id="2", uri="ctx://acme/users/u2/memories/profile",
level=0, text="u2 profile", filters={"account_id": "acme", "owner_space": "user:u2"},
metadata={"category": "profile"}
),
IndexRecord(
id="3", uri="ctx://acme/agents/a1/skills/s1",
level=0, text="agent skill", filters={"account_id": "acme", "owner_space": "agent:a1"},
metadata={"category": "skill"}
),
]
index.upsert(records)
deleted = index.delete_by_owner_space("acme", "user:u1")
assert deleted == 1
assert index.count() == 2
assert index.get_record("1") is None
assert index.get_record("2") is not None
assert index.get_record("3") is not None
def test_delete_by_owner_space_scoped_to_account(self):
"""Test delete_by_owner_space requires both account_id and owner_space match."""
index = InMemoryVectorIndex()
records = [
IndexRecord(
id="1", uri="ctx://acme/users/u1/memories/profile",
level=0, text="acme u1", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={}
),
IndexRecord(
id="2", uri="ctx://other/users/u1/memories/profile",
level=0, text="other u1", filters={"account_id": "other", "owner_space": "user:u1"},
metadata={}
),
]
index.upsert(records)
deleted = index.delete_by_owner_space("acme", "user:u1")
assert deleted == 1
assert index.get_record("1") is None
assert index.get_record("2") is not None
class TestInMemorySearchByVector:
"""Tests for search_by_vector method."""
def test_search_by_vector_filters_by_account(self):
"""Test search_by_vector enforces account_id filter."""
index = InMemoryVectorIndex()
records = [
IndexRecord(
id="1", uri="ctx://acme/users/u1/memories/profile",
level=0, text="profile", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={"category": "profile"}
),
IndexRecord(
id="2", uri="ctx://other/users/u2/memories/profile",
level=0, text="profile", filters={"account_id": "other", "owner_space": "user:u2"},
metadata={"category": "profile"}
),
]
index.upsert(records)
query_vector = index._mock_vector("profile")
results = index.search_by_vector(
query_vector=query_vector,
filters={"account_id": "acme"},
top_k=10
)
assert len(results) == 1
assert results[0].uri == "ctx://acme/users/u1/memories/profile"
def test_search_by_vector_returns_top_k(self):
"""Test search_by_vector respects top_k limit."""
index = InMemoryVectorIndex()
records = [
IndexRecord(
id=str(i), uri=f"ctx://acme/users/u1/memories/p{i}",
level=0, text=f"text{i}", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={}
)
for i in range(10)
]
index.upsert(records)
query_vector = index._mock_vector("text")
results = index.search_by_vector(
query_vector=query_vector,
filters={"account_id": "acme"},
top_k=5
)
assert len(results) == 5
def test_search_children_filters_by_parent_uri(self):
"""Test search_children only returns direct children of parent_uri."""
index = InMemoryVectorIndex()
records = [
IndexRecord(
id="1", uri="ctx://acme/users/u1/memories/preferences/p1",
level=0, text="pref1", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={"parent_uri": "ctx://acme/users/u1/memories/preferences/", "category": "preference"}
),
IndexRecord(
id="2", uri="ctx://acme/users/u1/memories/preferences/p2",
level=0, text="pref2", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={"parent_uri": "ctx://acme/users/u1/memories/preferences/", "category": "preference"}
),
IndexRecord(
id="3", uri="ctx://acme/users/u1/memories/entities/e1",
level=0, text="entity", filters={"account_id": "acme", "owner_space": "user:u1"},
metadata={"parent_uri": "ctx://acme/users/u1/memories/entities/", "category": "entity"}
),
]
index.upsert(records)
query_vector = index._mock_vector("pref")
results = index.search_children(
parent_uri="ctx://acme/users/u1/memories/preferences/",
query_vector=query_vector,
filters={"account_id": "acme"},
top_k=10
)
assert len(results) == 2
uris = {r.uri for r in results}
assert uris == {
"ctx://acme/users/u1/memories/preferences/p1",
"ctx://acme/users/u1/memories/preferences/p2",
}