use std::time::Instant;
use allframe_core::otel::{
configure_from_file, disable_tracing, enable_tracing, get_config, traced,
};
#[tokio::test]
async fn test_otel_with_router() {
#[traced]
async fn handle_request() -> Result<String, String> {
Ok("Hello".to_string())
}
let result = handle_request().await.unwrap();
assert_eq!(result, "Hello");
}
#[tokio::test]
async fn test_otel_with_clean_arch() {
use std::sync::Arc;
use allframe_core::arch::{domain, handler, repository, use_case};
#[domain]
#[derive(Debug)]
struct User {
id: String,
}
#[repository]
#[async_trait::async_trait]
trait UserRepository: Send + Sync + std::fmt::Debug {
async fn find(&self, id: &str) -> Result<Option<User>, String>;
}
#[derive(Debug)]
struct InMemoryUserRepository;
#[async_trait::async_trait]
impl UserRepository for InMemoryUserRepository {
#[traced]
async fn find(&self, id: &str) -> Result<Option<User>, String> {
Ok(Some(User { id: id.to_string() }))
}
}
#[use_case]
#[derive(Debug)]
struct GetUserUseCase {
repo: Arc<dyn UserRepository>,
}
impl GetUserUseCase {
#[traced(skip(self))]
async fn execute(&self, id: &str) -> Result<Option<User>, String> {
self.repo.find(id).await
}
}
#[handler]
#[traced(skip(use_case))]
async fn get_user_handler(use_case: Arc<GetUserUseCase>) -> Result<Option<User>, String> {
use_case.execute("123").await
}
let repo = Arc::new(InMemoryUserRepository);
let use_case = Arc::new(GetUserUseCase { repo });
let result = get_user_handler(use_case).await.unwrap();
assert!(result.is_some());
assert_eq!(result.unwrap().id, "123");
}
#[tokio::test]
async fn test_otel_with_cqrs() {
use allframe_core::cqrs::{Event, EventStore, EventTypeName};
use allframe_macros::{command, command_handler};
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
enum UserEvent {
Created { user_id: String },
}
impl EventTypeName for UserEvent {}
impl Event for UserEvent {}
#[command]
#[derive(Debug)]
struct CreateUserCommand {
user_id: String,
}
#[command_handler]
#[traced(skip(store))]
async fn handle_create_user(
cmd: CreateUserCommand,
store: &EventStore<UserEvent>,
) -> Result<(), String> {
let event = UserEvent::Created {
user_id: cmd.user_id.clone(),
};
store.append(&cmd.user_id, vec![event]).await?;
Ok(())
}
let store = EventStore::new();
handle_create_user(
CreateUserCommand {
user_id: "123".to_string(),
},
&store,
)
.await
.unwrap();
let events = store.get_events("123").await.unwrap();
assert_eq!(events.len(), 1);
let UserEvent::Created { user_id } = &events[0];
assert_eq!(user_id, "123");
}
#[tokio::test]
async fn test_otel_performance_overhead() {
#[traced]
async fn fast_operation() -> Result<u64, String> {
let mut sum = 0u64;
for i in 0..1000 {
sum += i;
}
Ok(sum)
}
disable_tracing();
let start = Instant::now();
for _ in 0..1000 {
fast_operation().await.unwrap();
}
let without_tracing = start.elapsed();
enable_tracing();
let start = Instant::now();
for _ in 0..1000 {
fast_operation().await.unwrap();
}
let with_tracing = start.elapsed();
let overhead_pct = ((with_tracing.as_micros() as f64 - without_tracing.as_micros() as f64)
/ without_tracing.as_micros() as f64)
* 100.0;
assert!(overhead_pct < 10.0, "Overhead: {}%", overhead_pct);
}
#[tokio::test]
#[allow(deprecated)]
async fn test_otel_configuration() {
configure_from_file("tests/fixtures/otel_config.toml")
.await
.ok();
let config = get_config();
assert!(!config.service_name.is_empty());
assert!(!config.exporter_type.is_empty());
assert!(config.sampling_rate > 0.0);
assert!(config.batch_size > 0);
}