Some checks failed
Cross-Node Transaction Testing / transaction-test (push) Has been cancelled
Deploy to Testnet / deploy-testnet (push) Has been cancelled
Documentation Validation / validate-docs (push) Has been cancelled
Documentation Validation / validate-policies-strict (push) Has been cancelled
Integration Tests / test-service-integration (push) Has been cancelled
Multi-Node Stress Testing / stress-test (push) Has been cancelled
Python Tests / test-python (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled
- Added Request parameter to all endpoint functions in agent_security_router.py, analytics.py, bounty.py, and certification.py - Added @rate_limit decorator to all endpoints with appropriate limits: - Write operations (POST/PUT/DELETE): 20 requests per 60 seconds - Read operations (GET): 200 requests per 60 seconds - High-frequency reads (categories/tags): 500 requests per 60 seconds - Validation/monitoring operations: 50 requests per 60 seconds
242 lines
7.6 KiB
Python
242 lines
7.6 KiB
Python
"""
|
|
Tests for distributed tracing module
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import Mock, patch, MagicMock
|
|
from datetime import datetime
|
|
|
|
# Test with OpenTelemetry available
|
|
try:
|
|
from aitbc.tracing import (
|
|
setup_tracing,
|
|
get_tracer,
|
|
instrument_fastapi,
|
|
instrument_httpx,
|
|
instrument_sqlalchemy,
|
|
trace_function,
|
|
trace_async_function,
|
|
trace_span,
|
|
set_span_attribute,
|
|
set_span_error,
|
|
add_span_event,
|
|
OPENTELEMETRY_AVAILABLE
|
|
)
|
|
except ImportError:
|
|
OPENTELEMETRY_AVAILABLE = False
|
|
|
|
|
|
@pytest.mark.skipif(not OPENTELEMETRY_AVAILABLE, reason="OpenTelemetry not available")
|
|
class TestTracingSetup:
|
|
"""Test tracing setup and initialization"""
|
|
|
|
def test_setup_tracing_console_exporter(self):
|
|
"""Test setup_tracing with console exporter"""
|
|
setup_tracing(
|
|
service_name="test-service",
|
|
service_version="1.0.0",
|
|
exporter="console",
|
|
sample_rate=1.0
|
|
)
|
|
tracer = get_tracer()
|
|
assert tracer is not None
|
|
|
|
def test_setup_tracing_otlp_exporter(self):
|
|
"""Test setup_tracing with OTLP exporter"""
|
|
setup_tracing(
|
|
service_name="test-service",
|
|
service_version="1.0.0",
|
|
exporter="otlp",
|
|
sample_rate=1.0
|
|
)
|
|
tracer = get_tracer()
|
|
assert tracer is not None
|
|
|
|
def test_setup_tracing_none_exporter(self):
|
|
"""Test setup_tracing with none exporter"""
|
|
setup_tracing(
|
|
service_name="test-service",
|
|
service_version="1.0.0",
|
|
exporter="none",
|
|
sample_rate=1.0
|
|
)
|
|
tracer = get_tracer()
|
|
# With none exporter, tracer should still be created but may not export
|
|
assert tracer is not None
|
|
|
|
def test_get_tracer_without_setup(self):
|
|
"""Test get_tracer without prior setup"""
|
|
# Reset global tracer
|
|
from aitbc.tracing import _tracer
|
|
from aitbc import tracing
|
|
tracing._tracer = None
|
|
tracer = get_tracer()
|
|
# Should return None if not set up
|
|
assert tracer is None
|
|
|
|
|
|
@pytest.mark.skipif(not OPENTELEMETRY_AVAILABLE, reason="OpenTelemetry not available")
|
|
class TestTracingDecorators:
|
|
"""Test tracing decorators"""
|
|
|
|
def test_trace_function_decorator(self):
|
|
"""Test trace_function decorator"""
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
@trace_function("test_function")
|
|
def test_func(x: int, y: int) -> int:
|
|
return x + y
|
|
|
|
result = test_func(1, 2)
|
|
assert result == 3
|
|
|
|
def test_trace_function_with_exception(self):
|
|
"""Test trace_function decorator with exception"""
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
@trace_function("test_function_exception")
|
|
def test_func() -> None:
|
|
raise ValueError("Test error")
|
|
|
|
with pytest.raises(ValueError):
|
|
test_func()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_trace_async_function_decorator(self):
|
|
"""Test trace_async_function decorator"""
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
@trace_async_function("test_async_function")
|
|
async def test_func(x: int, y: int) -> int:
|
|
return x + y
|
|
|
|
result = await test_func(1, 2)
|
|
assert result == 3
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_trace_async_function_with_exception(self):
|
|
"""Test trace_async_function decorator with exception"""
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
@trace_async_function("test_async_function_exception")
|
|
async def test_func() -> None:
|
|
raise ValueError("Test error")
|
|
|
|
with pytest.raises(ValueError):
|
|
await test_func()
|
|
|
|
|
|
@pytest.mark.skipif(not OPENTELEMETRY_AVAILABLE, reason="OpenTelemetry not available")
|
|
class TestTracingContextManager:
|
|
"""Test tracing context manager"""
|
|
|
|
def test_trace_span_context_manager(self):
|
|
"""Test trace_span context manager"""
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
with trace_span("test_span", {"key": "value"}) as span:
|
|
# Span should be created
|
|
pass
|
|
|
|
# If tracing is available, span should not be None
|
|
# If not available, span should be None
|
|
assert True # Context manager should not raise exception
|
|
|
|
def test_trace_span_without_tracing(self):
|
|
"""Test trace_span without tracing setup"""
|
|
from aitbc.tracing import _tracer
|
|
from aitbc import tracing
|
|
tracing._tracer = None
|
|
|
|
with trace_span("test_span", {"key": "value"}) as span:
|
|
# Span should be None when tracing not available
|
|
assert span is None
|
|
|
|
|
|
@pytest.mark.skipif(not OPENTELEMETRY_AVAILABLE, reason="OpenTelemetry not available")
|
|
class TestTracingHelpers:
|
|
"""Test tracing helper functions"""
|
|
|
|
def test_set_span_attribute(self):
|
|
"""Test set_span_attribute helper"""
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
# Should not raise exception even without active span
|
|
set_span_attribute("test_key", "test_value")
|
|
|
|
def test_set_span_error(self):
|
|
"""Test set_span_error helper"""
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
# Should not raise exception even without active span
|
|
set_span_error(ValueError("Test error"))
|
|
|
|
def test_add_span_event(self):
|
|
"""Test add_span_event helper"""
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
# Should not raise exception even without active span
|
|
add_span_event("test_event", {"key": "value"})
|
|
|
|
|
|
@pytest.mark.skipif(not OPENTELEMETRY_AVAILABLE, reason="OpenTelemetry not available")
|
|
class TestTracingInstrumentation:
|
|
"""Test tracing instrumentation"""
|
|
|
|
def test_instrument_fastapi(self):
|
|
"""Test FastAPI instrumentation"""
|
|
from fastapi import FastAPI
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
app = FastAPI()
|
|
instrument_fastapi(app)
|
|
|
|
# Should not raise exception
|
|
assert True
|
|
|
|
def test_instrument_httpx(self):
|
|
"""Test HTTPX instrumentation"""
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
instrument_httpx()
|
|
|
|
# Should not raise exception
|
|
assert True
|
|
|
|
def test_instrument_sqlalchemy(self):
|
|
"""Test SQLAlchemy instrumentation"""
|
|
from sqlalchemy import create_engine
|
|
setup_tracing("test-service", "1.0.0", "none")
|
|
|
|
engine = create_engine("sqlite:///:memory:")
|
|
instrument_sqlalchemy(engine)
|
|
|
|
# Should not raise exception
|
|
assert True
|
|
|
|
|
|
def test_opentelemetry_not_available():
|
|
"""Test behavior when OpenTelemetry is not available"""
|
|
# This test always runs, even when OpenTelemetry is available
|
|
# to verify graceful degradation
|
|
from aitbc.tracing import OPENTELEMETRY_AVAILABLE
|
|
|
|
if not OPENTELEMETRY_AVAILABLE:
|
|
# When OpenTelemetry is not available, these should not raise exceptions
|
|
setup_tracing("test-service", "1.0.0", "console")
|
|
get_tracer()
|
|
|
|
@trace_function("test")
|
|
def test_func():
|
|
return 1
|
|
|
|
result = test_func()
|
|
assert result == 1
|
|
|
|
with trace_span("test_span"):
|
|
pass
|
|
|
|
set_span_attribute("key", "value")
|
|
set_span_error(ValueError("test"))
|
|
add_span_event("event", {"key": "value"})
|