Spaces:
Configuration error
Configuration error
| from agentcache.core import KV, SearchService | |
| from agentcache.search import SearchIndex | |
| def test_kv_scopes_import(): | |
| """Verify KV class is importable and defines standard scope keys.""" | |
| assert KV.folders == "mem:folders" | |
| assert KV.obs_lookup == "mem:obs_lookup" | |
| assert KV.memories == "mem:memories" | |
| assert KV.folder_obs("src/core", "agent1") == "mem:folder:src/core:agent1" | |
| def test_search_service_index_remove_and_search(tmp_db): | |
| """Verify SearchService index, remove, and search operations work end-to-end.""" | |
| kv = tmp_db | |
| bm25 = SearchIndex() | |
| svc = SearchService(bm25_index=bm25, kv=kv) | |
| obs1 = { | |
| "id": "obs_1", | |
| "title": "Auth Middleware", | |
| "text": "Implemented JWT token validation in authentication middleware", | |
| "folderPath": "src/auth", | |
| "agentId": "agent_alpha", | |
| } | |
| obs2 = { | |
| "id": "obs_2", | |
| "title": "Database Connection", | |
| "text": "SQLite database pool initialization and query optimization", | |
| "folderPath": "src/db", | |
| "agentId": "agent_beta", | |
| } | |
| # Populate KV store for hydration | |
| kv.set( | |
| KV.folders, | |
| "src/auth:agent_alpha", | |
| {"folderPath": "src/auth", "agentId": "agent_alpha"}, | |
| ) | |
| kv.set(KV.folder_obs("src/auth", "agent_alpha"), "obs_1", obs1) | |
| kv.set(KV.obs_lookup, "obs_1", {"folderPath": "src/auth", "agentId": "agent_alpha"}) | |
| kv.set( | |
| KV.folders, | |
| "src/db:agent_beta", | |
| {"folderPath": "src/db", "agentId": "agent_beta"}, | |
| ) | |
| kv.set(KV.folder_obs("src/db", "agent_beta"), "obs_2", obs2) | |
| kv.set(KV.obs_lookup, "obs_2", {"folderPath": "src/db", "agentId": "agent_beta"}) | |
| # Index observations into SearchService | |
| svc.index(obs1) | |
| svc.index(obs2) | |
| # Search for JWT token validation | |
| results = svc.search("JWT token", limit=10) | |
| assert len(results) >= 1 | |
| assert results[0]["id"] == "obs_1" | |
| assert "score" in results[0] | |
| # Filtered search by folder_path | |
| filtered = svc.search("token", folder_path="src/db", limit=10) | |
| assert len(filtered) == 0 | |
| filtered_auth = svc.search("token", folder_path="src/auth", limit=10) | |
| assert len(filtered_auth) == 1 | |
| assert filtered_auth[0]["id"] == "obs_1" | |
| # Filtered search by agent_id (returns only matching agent) | |
| filtered_agent = svc.search("validation", agent_id="agent_alpha", limit=10) | |
| assert len(filtered_agent) == 1 | |
| assert filtered_agent[0]["agentId"] == "agent_alpha" | |
| filtered_wrong_agent = svc.search("validation", agent_id="agent_other", limit=10) | |
| assert len(filtered_wrong_agent) == 0 | |
| # Remove obs1 and verify it no longer matches | |
| svc.remove("obs_1") | |
| post_remove = svc.search("JWT token", limit=10) | |
| assert len(post_remove) == 0 | |
| def test_search_service_persistence(tmp_db): | |
| """Verify IndexPersistence saves and loads index data sharded in SQLite.""" | |
| kv = tmp_db | |
| bm25 = SearchIndex() | |
| svc = SearchService(bm25_index=bm25, kv=kv) | |
| obs = { | |
| "id": "obs_persist_1", | |
| "title": "Cache Eviction", | |
| "text": "LRU cache eviction policy implemented for high throughput", | |
| } | |
| kv.set(KV.memories, "obs_persist_1", obs) | |
| svc.index(obs) | |
| svc.flush_persist() | |
| # Create fresh SearchService and load persisted index | |
| new_bm25 = SearchIndex() | |
| new_svc = SearchService(bm25_index=new_bm25, kv=kv) | |
| loaded = new_svc.load_persisted() | |
| assert loaded["bm25"] is True | |
| assert new_svc.bm25_size > 0 | |
| results = new_svc.search("LRU cache", limit=10) | |
| assert len(results) >= 1 | |
| # Search for a term never indexed returns an empty list (no error/exception) | |
| non_existent = new_svc.search("nonexistenttermxyz", limit=10) | |
| assert isinstance(non_existent, list) | |
| assert len(non_existent) == 0 | |
| def test_http_search_routes_end_to_end(app_client): | |
| """Verify Flask HTTP search endpoints work end-to-end with real SQLite DB.""" | |
| client = app_client | |
| import agentcache.app as app_mod | |
| kv = app_mod.kv | |
| search_svc = app_mod.search_service | |
| obs = { | |
| "id": "obs_http_1", | |
| "title": "API Authentication Strategy", | |
| "text": "Secure OAuth2 bearer token authorization for external endpoints", | |
| "folderPath": "src/api", | |
| "agentId": "agent_gamma", | |
| } | |
| kv.set( | |
| KV.folders, | |
| "src/api:agent_gamma", | |
| {"folderPath": "src/api", "agentId": "agent_gamma"}, | |
| ) | |
| kv.set(KV.folder_obs("src/api", "agent_gamma"), "obs_http_1", obs) | |
| kv.set( | |
| KV.obs_lookup, "obs_http_1", {"folderPath": "src/api", "agentId": "agent_gamma"} | |
| ) | |
| search_svc.index(obs) | |
| # POST /agentcache/search | |
| res = client.post("/agentcache/search", json={"query": "OAuth2 bearer token"}) | |
| assert res.status_code == 200 | |
| data = res.get_json() | |
| assert isinstance(data, list) | |
| assert len(data) == 1 | |
| assert data[0]["id"] == "obs_http_1" | |
| assert data[0]["folderPath"] == "src/api" | |
| # POST /agentmemory/search (alias endpoint) | |
| res_alias = client.post( | |
| "/agentmemory/search", json={"query": "OAuth2 bearer token", "limit": 5} | |
| ) | |
| assert res_alias.status_code == 200 | |
| data_alias = res_alias.get_json() | |
| assert len(data_alias) == 1 | |
| assert data_alias[0]["id"] == "obs_http_1" | |
| # Validation paths: missing or empty query -> 400 | |
| res_no_query = client.post("/agentcache/search", json={}) | |
| assert res_no_query.status_code == 400 | |
| res_empty_query = client.post("/agentcache/search", json={"query": ""}) | |
| assert res_empty_query.status_code == 400 | |
| res_alias_no_query = client.post("/agentmemory/search", json={}) | |
| assert res_alias_no_query.status_code == 400 | |