c889a57b6b
Test Suites / Build CI Environment (push) Has been cancelled
Test Suites / Basic Tests (push) Has been cancelled
Test Suites / End-to-End Tests (push) Has been cancelled
Test Suites / CLI Tests (push) Has been cancelled
Test Suites / Slow End-to-End Tests (push) Has been cancelled
Test Suites / Graph Database Tests (push) Has been cancelled
Test Suites / Vector DB Tests (push) Has been cancelled
Test Suites / Temporal Graph Test (push) Has been cancelled
Test Suites / Search Test on Different DBs (push) Has been cancelled
Test Suites / Example Tests (push) Has been cancelled
Test Suites / Notebook Tests (push) Has been cancelled
Test Suites / OS and Python Tests Ubuntu (push) Has been cancelled
Test Suites / OS and Python Tests Extended (push) Has been cancelled
Test Suites / LLM Test Suite (push) Has been cancelled
Test Suites / S3 File Storage Test (push) Has been cancelled
Test Suites / Run Integration Tests (push) Has been cancelled
Test Suites / MCP Tests (push) Has been cancelled
Test Suites / Docker Compose Test (push) Has been cancelled
Test Suites / Docker CI test (push) Has been cancelled
Test Suites / Relational DB Migration Tests (push) Has been cancelled
Test Suites / Distributed Cognee Test (push) Has been cancelled
Test Suites / DB Examples Tests (push) Has been cancelled
Test Suites / Test Completion Status (push) Has been cancelled
Test Suites / Claude Code Review (push) Has been cancelled
Test Suites / basic checks (push) Has been cancelled
build | Build and Push Cognee MCP Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
build | Build and Push Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.11) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.12) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (kuzu, kuzu) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (neo4j, neo4j) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Examples (push) Has been cancelled
Weighted Edges Tests / Code Quality for Weighted Edges (push) Has been cancelled
281 lines
9.5 KiB
Python
281 lines
9.5 KiB
Python
import os
|
|
import pytest
|
|
import pytest_asyncio
|
|
import asyncio
|
|
from fastapi.testclient import TestClient
|
|
|
|
import cognee
|
|
from cognee.api.client import app
|
|
from cognee.infrastructure.databases.cache.config import get_cache_config
|
|
from cognee.infrastructure.databases.cache.get_cache_engine import create_cache_engine
|
|
from cognee.modules.users.methods import get_default_user, get_authenticated_user
|
|
|
|
|
|
async def _reset_engines_and_prune():
|
|
"""Reset db engine caches and prune data/system."""
|
|
try:
|
|
from cognee.infrastructure.databases.vector import get_vector_engine_async
|
|
|
|
vector_engine = await get_vector_engine_async()
|
|
if hasattr(vector_engine, "engine") and hasattr(vector_engine.engine, "dispose"):
|
|
await vector_engine.engine.dispose(close=True)
|
|
except Exception:
|
|
pass
|
|
|
|
await cognee.prune.prune_data()
|
|
await cognee.prune.prune_system(metadata=True)
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def event_loop():
|
|
"""Use a single asyncio event loop for this test module."""
|
|
loop = asyncio.new_event_loop()
|
|
try:
|
|
yield loop
|
|
finally:
|
|
loop.close()
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def e2e_config():
|
|
"""Configure environment for E2E tests."""
|
|
original_env = os.environ.copy()
|
|
os.environ["USAGE_LOGGING"] = "true"
|
|
os.environ["CACHE_BACKEND"] = "redis"
|
|
os.environ.setdefault("CACHE_HOST", "localhost")
|
|
os.environ.setdefault("CACHE_PORT", "6379")
|
|
get_cache_config.cache_clear()
|
|
create_cache_engine.cache_clear()
|
|
yield
|
|
os.environ.clear()
|
|
os.environ.update(original_env)
|
|
get_cache_config.cache_clear()
|
|
create_cache_engine.cache_clear()
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def authenticated_client(test_client):
|
|
"""Override authentication to use default user."""
|
|
|
|
async def override_get_authenticated_user():
|
|
return await get_default_user()
|
|
|
|
app.dependency_overrides[get_authenticated_user] = override_get_authenticated_user
|
|
yield test_client
|
|
app.dependency_overrides.pop(get_authenticated_user, None)
|
|
|
|
|
|
@pytest_asyncio.fixture(scope="session")
|
|
async def test_data_setup():
|
|
"""Set up test data: prune first, then add file and cognify."""
|
|
await _reset_engines_and_prune()
|
|
|
|
dataset_name = "test_e2e_dataset"
|
|
test_text = "Germany is located in Europe right next to the Netherlands."
|
|
|
|
await cognee.add(test_text, dataset_name)
|
|
await cognee.cognify([dataset_name])
|
|
|
|
yield dataset_name
|
|
|
|
await _reset_engines_and_prune()
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def mcp_data_setup():
|
|
"""Set up test data for MCP tests: prune first, then add file and cognify."""
|
|
await _reset_engines_and_prune()
|
|
|
|
dataset_name = "test_mcp_dataset"
|
|
test_text = "Germany is located in Europe right next to the Netherlands."
|
|
|
|
await cognee.add(test_text, dataset_name)
|
|
await cognee.cognify([dataset_name])
|
|
|
|
yield dataset_name
|
|
|
|
await _reset_engines_and_prune()
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def test_client():
|
|
"""TestClient instance for API calls."""
|
|
with TestClient(app) as client:
|
|
yield client
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def cache_engine(e2e_config):
|
|
"""Get cache engine for log verification in test's event loop."""
|
|
from cognee.infrastructure.databases.cache.redis.RedisAdapter import RedisAdapter
|
|
|
|
config = get_cache_config()
|
|
if not config.usage_logging or config.cache_backend != "redis":
|
|
pytest.skip("Redis usage logging not configured")
|
|
|
|
engine = RedisAdapter(
|
|
host=config.cache_host,
|
|
port=config.cache_port,
|
|
username=config.cache_username,
|
|
password=config.cache_password,
|
|
log_key="usage_logs",
|
|
)
|
|
return engine
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_api_endpoint_logging(e2e_config, authenticated_client, cache_engine):
|
|
"""Test that API endpoints succeed and log to Redis."""
|
|
user = await get_default_user()
|
|
dataset_name = "test_e2e_api_dataset"
|
|
|
|
add_response = authenticated_client.post(
|
|
"/api/v1/add",
|
|
data={"datasetName": dataset_name},
|
|
files=[
|
|
(
|
|
"data",
|
|
(
|
|
"test.txt",
|
|
b"Germany is located in Europe right next to the Netherlands.",
|
|
"text/plain",
|
|
),
|
|
)
|
|
],
|
|
)
|
|
assert add_response.status_code in [200, 201], f"Add endpoint failed: {add_response.text}"
|
|
|
|
cognify_response = authenticated_client.post(
|
|
"/api/v1/cognify",
|
|
json={"datasets": [dataset_name], "run_in_background": False},
|
|
)
|
|
assert cognify_response.status_code in [200, 201], (
|
|
f"Cognify endpoint failed: {cognify_response.text}"
|
|
)
|
|
|
|
search_response = authenticated_client.post(
|
|
"/api/v1/search",
|
|
json={"query": "Germany", "search_type": "GRAPH_COMPLETION", "datasets": [dataset_name]},
|
|
)
|
|
assert search_response.status_code == 200, f"Search endpoint failed: {search_response.text}"
|
|
|
|
logs = await cache_engine.get_usage_logs(str(user.id), limit=20)
|
|
|
|
add_logs = [log for log in logs if log.get("function_name") == "POST /v1/add"]
|
|
assert len(add_logs) > 0
|
|
assert add_logs[0]["type"] == "api_endpoint"
|
|
assert add_logs[0]["user_id"] == str(user.id)
|
|
assert add_logs[0]["success"] is True
|
|
|
|
cognify_logs = [log for log in logs if log.get("function_name") == "POST /v1/cognify"]
|
|
assert len(cognify_logs) > 0
|
|
assert cognify_logs[0]["type"] == "api_endpoint"
|
|
assert cognify_logs[0]["user_id"] == str(user.id)
|
|
assert cognify_logs[0]["success"] is True
|
|
|
|
search_logs = [log for log in logs if log.get("function_name") == "POST /v1/search"]
|
|
assert len(search_logs) > 0
|
|
assert search_logs[0]["type"] == "api_endpoint"
|
|
assert search_logs[0]["user_id"] == str(user.id)
|
|
assert search_logs[0]["success"] is True
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_mcp_tool_logging(e2e_config, cache_engine):
|
|
"""Test that MCP tools succeed and log to Redis."""
|
|
import sys
|
|
import importlib.util
|
|
from pathlib import Path
|
|
|
|
await _reset_engines_and_prune()
|
|
|
|
repo_root = Path(__file__).parent.parent.parent
|
|
mcp_src_path = repo_root / "cognee-mcp" / "src"
|
|
mcp_server_path = mcp_src_path / "server.py"
|
|
|
|
if not mcp_server_path.exists():
|
|
pytest.skip(f"MCP server not found at {mcp_server_path}")
|
|
|
|
if str(mcp_src_path) not in sys.path:
|
|
sys.path.insert(0, str(mcp_src_path))
|
|
|
|
spec = importlib.util.spec_from_file_location("mcp_server_module", mcp_server_path)
|
|
mcp_server_module = importlib.util.module_from_spec(spec)
|
|
|
|
import os
|
|
|
|
original_cwd = os.getcwd()
|
|
try:
|
|
os.chdir(str(mcp_src_path))
|
|
spec.loader.exec_module(mcp_server_module)
|
|
finally:
|
|
os.chdir(original_cwd)
|
|
|
|
if mcp_server_module.cognee_client is None:
|
|
cognee_client_path = mcp_src_path / "cognee_client.py"
|
|
if cognee_client_path.exists():
|
|
spec_client = importlib.util.spec_from_file_location(
|
|
"cognee_client", cognee_client_path
|
|
)
|
|
cognee_client_module = importlib.util.module_from_spec(spec_client)
|
|
spec_client.loader.exec_module(cognee_client_module)
|
|
CogneeClient = cognee_client_module.CogneeClient
|
|
mcp_server_module.cognee_client = CogneeClient()
|
|
else:
|
|
pytest.skip(f"CogneeClient not found at {cognee_client_path}")
|
|
|
|
test_text = "Germany is located in Europe right next to the Netherlands."
|
|
await mcp_server_module.cognify(data=test_text)
|
|
await asyncio.sleep(30.0)
|
|
|
|
list_result = await mcp_server_module.list_data()
|
|
assert list_result is not None, "List data should return results"
|
|
|
|
search_result = await mcp_server_module.search(
|
|
search_query="Germany", search_type="GRAPH_COMPLETION", top_k=5
|
|
)
|
|
assert search_result is not None, "Search should return results"
|
|
|
|
interaction_data = "User: What is Germany?\nAgent: Germany is a country in Europe."
|
|
await mcp_server_module.save_interaction(data=interaction_data)
|
|
await asyncio.sleep(30.0)
|
|
|
|
status_result = await mcp_server_module.cognify_status()
|
|
assert status_result is not None, "Cognify status should return results"
|
|
|
|
logs = await cache_engine.get_usage_logs("unknown", limit=50)
|
|
mcp_logs = [log for log in logs if log.get("type") == "mcp_tool"]
|
|
assert len(mcp_logs) == 5, (
|
|
f"Expected 5 MCP logs before prune. Found: {[log.get('function_name') for log in mcp_logs]}"
|
|
)
|
|
expected_tools_before_prune = [
|
|
"MCP cognify",
|
|
"MCP list_data",
|
|
"MCP search",
|
|
"MCP save_interaction",
|
|
"MCP cognify_status",
|
|
]
|
|
function_names = [log.get("function_name") for log in mcp_logs]
|
|
for expected_tool in expected_tools_before_prune:
|
|
assert expected_tool in function_names, (
|
|
f"Should have {expected_tool} log. Found: {function_names}"
|
|
)
|
|
for log in mcp_logs:
|
|
assert log["type"] == "mcp_tool"
|
|
assert log["user_id"] == "unknown"
|
|
assert log["success"] is True
|
|
|
|
await mcp_server_module.prune()
|
|
await asyncio.sleep(0.5)
|
|
|
|
logs_after_prune = await cache_engine.get_usage_logs("unknown", limit=50)
|
|
mcp_logs_after_prune = [log for log in logs_after_prune if log.get("type") == "mcp_tool"]
|
|
assert len(mcp_logs_after_prune) == 1, (
|
|
f"After prune, Redis is flushed so only the prune log should remain. "
|
|
f"Found: {[log.get('function_name') for log in mcp_logs_after_prune]}"
|
|
)
|
|
assert mcp_logs_after_prune[0]["function_name"] == "MCP prune"
|
|
assert mcp_logs_after_prune[0]["type"] == "mcp_tool"
|
|
assert mcp_logs_after_prune[0]["user_id"] == "unknown"
|
|
assert mcp_logs_after_prune[0]["success"] is True
|