Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 13:02:24 +08:00

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