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
256 lines
9.2 KiB
Python
256 lines
9.2 KiB
Python
"""Integration tests for usage logger with real Redis components."""
|
|
|
|
import os
|
|
import pytest
|
|
import asyncio
|
|
from datetime import datetime, timezone
|
|
from types import SimpleNamespace
|
|
from uuid import UUID
|
|
from unittest.mock import patch
|
|
|
|
from cognee.shared.usage_logger import log_usage
|
|
from cognee.infrastructure.databases.cache.config import get_cache_config
|
|
from cognee.infrastructure.databases.cache.get_cache_engine import (
|
|
get_cache_engine,
|
|
create_cache_engine,
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def usage_logging_config():
|
|
"""Fixture to enable usage logging via environment variables."""
|
|
original_env = os.environ.copy()
|
|
os.environ["USAGE_LOGGING"] = "true"
|
|
os.environ["CACHE_BACKEND"] = "redis"
|
|
os.environ["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
|
|
def usage_logging_disabled():
|
|
"""Fixture to disable usage logging via environment variables."""
|
|
original_env = os.environ.copy()
|
|
os.environ["USAGE_LOGGING"] = "false"
|
|
os.environ["CACHE_BACKEND"] = "redis"
|
|
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
|
|
def redis_adapter():
|
|
"""Real RedisAdapter instance for testing."""
|
|
from cognee.infrastructure.databases.cache.redis.RedisAdapter import RedisAdapter
|
|
|
|
host = os.getenv("CACHE_HOST")
|
|
try:
|
|
yield RedisAdapter(host=host, port=6379, log_key="test_usage_logs")
|
|
except Exception as e:
|
|
pytest.skip(f"Redis not available: {e}")
|
|
|
|
|
|
@pytest.fixture
|
|
def test_user():
|
|
"""Test user object."""
|
|
return SimpleNamespace(id="test-user-123")
|
|
|
|
|
|
class TestDecoratorBehavior:
|
|
"""Test decorator behavior with real components."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_decorator_configuration(
|
|
self, usage_logging_disabled, usage_logging_config, redis_adapter
|
|
):
|
|
"""Test decorator skips when disabled and logs when enabled."""
|
|
# Test disabled
|
|
call_count = 0
|
|
|
|
@log_usage(function_name="test_func", log_type="test")
|
|
async def test_func():
|
|
nonlocal call_count
|
|
call_count += 1
|
|
return "result"
|
|
|
|
assert await test_func() == "result"
|
|
assert call_count == 1
|
|
|
|
# Test enabled with cache engine None
|
|
with patch("cognee.shared.usage_logger.get_cache_engine") as mock_get:
|
|
mock_get.return_value = None
|
|
assert await test_func() == "result"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_decorator_logging(self, usage_logging_config, redis_adapter, test_user):
|
|
"""Test decorator logs to Redis with correct structure."""
|
|
|
|
@log_usage(function_name="test_func", log_type="test")
|
|
async def test_func(param1: str, param2: int = 42, user=None):
|
|
await asyncio.sleep(0.01)
|
|
return {"result": f"{param1}_{param2}"}
|
|
|
|
with patch("cognee.shared.usage_logger.get_cache_engine") as mock_get:
|
|
mock_get.return_value = redis_adapter
|
|
|
|
result = await test_func("value1", user=test_user)
|
|
assert result == {"result": "value1_42"}
|
|
|
|
logs = await redis_adapter.get_usage_logs("test-user-123", limit=10)
|
|
log = logs[0]
|
|
assert log["function_name"] == "test_func"
|
|
assert log["type"] == "test"
|
|
assert log["user_id"] == "test-user-123"
|
|
assert log["parameters"]["param1"] == "value1"
|
|
assert log["parameters"]["param2"] == 42
|
|
assert log["success"] is True
|
|
assert all(
|
|
field in log
|
|
for field in [
|
|
"timestamp",
|
|
"result",
|
|
"error",
|
|
"duration_ms",
|
|
"start_time",
|
|
"end_time",
|
|
"metadata",
|
|
]
|
|
)
|
|
assert "cognee_version" in log["metadata"]
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_multiple_calls(self, usage_logging_config, redis_adapter, test_user):
|
|
"""Test multiple consecutive calls are all logged."""
|
|
|
|
@log_usage(function_name="multi_test", log_type="test")
|
|
async def multi_func(call_num: int, user=None):
|
|
return {"call": call_num}
|
|
|
|
with patch("cognee.shared.usage_logger.get_cache_engine") as mock_get:
|
|
mock_get.return_value = redis_adapter
|
|
|
|
for i in range(3):
|
|
await multi_func(i, user=test_user)
|
|
|
|
logs = await redis_adapter.get_usage_logs("test-user-123", limit=10)
|
|
assert len(logs) >= 3
|
|
call_nums = {log["parameters"]["call_num"] for log in logs[:3]}
|
|
assert call_nums == {0, 1, 2}
|
|
|
|
|
|
class TestRealRedisIntegration:
|
|
"""Test real Redis integration."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_redis_storage_retrieval_and_ttl(
|
|
self, usage_logging_config, redis_adapter, test_user
|
|
):
|
|
"""Test logs are stored, retrieved with correct order/limits, and TTL is set."""
|
|
|
|
@log_usage(function_name="redis_test", log_type="test")
|
|
async def redis_func(data: str, user=None):
|
|
return {"processed": data}
|
|
|
|
@log_usage(function_name="order_test", log_type="test")
|
|
async def order_func(num: int, user=None):
|
|
return {"num": num}
|
|
|
|
with patch("cognee.shared.usage_logger.get_cache_engine") as mock_get:
|
|
mock_get.return_value = redis_adapter
|
|
|
|
# Storage
|
|
await redis_func("test_data", user=test_user)
|
|
logs = await redis_adapter.get_usage_logs("test-user-123", limit=10)
|
|
assert logs[0]["function_name"] == "redis_test"
|
|
assert logs[0]["parameters"]["data"] == "test_data"
|
|
|
|
# Order (most recent first)
|
|
for i in range(3):
|
|
await order_func(i, user=test_user)
|
|
await asyncio.sleep(0.01)
|
|
|
|
logs = await redis_adapter.get_usage_logs("test-user-123", limit=10)
|
|
assert [log["parameters"]["num"] for log in logs[:3]] == [2, 1, 0]
|
|
|
|
# Limit
|
|
assert len(await redis_adapter.get_usage_logs("test-user-123", limit=2)) == 2
|
|
|
|
# TTL
|
|
ttl = await redis_adapter.async_redis.ttl("test_usage_logs:test-user-123")
|
|
assert 0 < ttl <= 604800
|
|
|
|
|
|
class TestEdgeCases:
|
|
"""Test edge cases in integration tests."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_edge_cases(self, usage_logging_config, redis_adapter, test_user):
|
|
"""Test no params, defaults, complex structures, exceptions, None, circular refs."""
|
|
|
|
@log_usage(function_name="no_params", log_type="test")
|
|
async def no_params_func(user=None):
|
|
return "result"
|
|
|
|
@log_usage(function_name="defaults_only", log_type="test")
|
|
async def defaults_only_func(param1: str = "default1", param2: int = 42, user=None):
|
|
return {"param1": param1, "param2": param2}
|
|
|
|
@log_usage(function_name="complex_test", log_type="test")
|
|
async def complex_func(user=None):
|
|
return {
|
|
"nested": {
|
|
"list": [1, 2, 3],
|
|
"uuid": UUID("123e4567-e89b-12d3-a456-426614174000"),
|
|
"datetime": datetime(2024, 1, 15, tzinfo=timezone.utc),
|
|
}
|
|
}
|
|
|
|
@log_usage(function_name="exception_test", log_type="test")
|
|
async def exception_func(user=None):
|
|
raise RuntimeError("Test exception")
|
|
|
|
@log_usage(function_name="none_test", log_type="test")
|
|
async def none_func(user=None):
|
|
return None
|
|
|
|
with patch("cognee.shared.usage_logger.get_cache_engine") as mock_get:
|
|
mock_get.return_value = redis_adapter
|
|
|
|
# No parameters
|
|
await no_params_func(user=test_user)
|
|
logs = await redis_adapter.get_usage_logs("test-user-123", limit=10)
|
|
assert logs[0]["parameters"] == {}
|
|
|
|
# Default parameters
|
|
await defaults_only_func(user=test_user)
|
|
logs = await redis_adapter.get_usage_logs("test-user-123", limit=10)
|
|
assert logs[0]["parameters"]["param1"] == "default1"
|
|
assert logs[0]["parameters"]["param2"] == 42
|
|
|
|
# Complex nested structures
|
|
await complex_func(user=test_user)
|
|
logs = await redis_adapter.get_usage_logs("test-user-123", limit=10)
|
|
assert isinstance(logs[0]["result"]["nested"]["uuid"], str)
|
|
assert isinstance(logs[0]["result"]["nested"]["datetime"], str)
|
|
|
|
# Exception handling
|
|
with pytest.raises(RuntimeError):
|
|
await exception_func(user=test_user)
|
|
logs = await redis_adapter.get_usage_logs("test-user-123", limit=10)
|
|
assert logs[0]["success"] is False
|
|
assert "Test exception" in logs[0]["error"]
|
|
|
|
# None return value
|
|
assert await none_func(user=test_user) is None
|
|
logs = await redis_adapter.get_usage_logs("test-user-123", limit=10)
|
|
assert logs[0]["result"] is None
|