use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use tokio::time::sleep;
use crate::application::callbacks::{ConnectionState, EventHandler, TelegramFilter};
use crate::protocol::{
address::{Address, GroupAddress, IndividualAddress},
telegram::{Direction, Priority, Telegram, TelegramType},
};
#[tokio::test]
async fn test_concurrent_callback_registration() {
let handler = Arc::new(EventHandler::new());
let registration_count = Arc::new(AtomicUsize::new(0));
let mut task_handles = Vec::new();
for _i in 0..10 {
let handler_clone = handler.clone();
let count_clone = registration_count.clone();
let handle = tokio::spawn(async move {
let _telegram_handle = handler_clone
.register_telegram_callback_sync(move |_| {
})
.await;
let _connection_handle = handler_clone
.register_connection_callback_sync(move |_| {
})
.await;
count_clone.fetch_add(2, Ordering::SeqCst); });
task_handles.push(handle);
}
for handle in task_handles {
handle.await.unwrap();
}
assert_eq!(registration_count.load(Ordering::SeqCst), 20); assert_eq!(handler.total_callback_count().await, 20);
assert_eq!(handler.telegram_callback_count().await, 10);
assert_eq!(handler.connection_callback_count().await, 10);
}
#[tokio::test]
async fn test_concurrent_callback_execution() {
let handler = Arc::new(EventHandler::new());
let execution_count = Arc::new(AtomicUsize::new(0));
for _ in 0..5 {
let count_clone = execution_count.clone();
let _handle = handler
.register_connection_callback_sync(move |_state| {
count_clone.fetch_add(1, Ordering::SeqCst);
})
.await;
}
let mut task_handles = Vec::new();
for _ in 0..10 {
let handler_clone = handler.clone();
let handle = tokio::spawn(async move {
handler_clone
.notify_connection_state_changed(ConnectionState::Connected)
.await;
});
task_handles.push(handle);
}
for handle in task_handles {
handle.await.unwrap();
}
assert_eq!(execution_count.load(Ordering::SeqCst), 50);
}
#[tokio::test]
async fn test_concurrent_registration_and_unregistration() {
let handler = Arc::new(EventHandler::new());
let mut callback_handles = Vec::new();
for _ in 0..5 {
let handle = handler.register_telegram_callback_sync(|_| {}).await;
callback_handles.push(handle);
}
assert_eq!(handler.telegram_callback_count().await, 5);
let mut task_handles = Vec::new();
for _ in 0..3 {
let handler_clone = handler.clone();
let handle = tokio::spawn(async move {
let _callback_handle = handler_clone.register_telegram_callback_sync(|_| {}).await;
sleep(Duration::from_millis(10)).await;
});
task_handles.push(handle);
}
for callback_handle in callback_handles.into_iter().take(3) {
let handler_clone = handler.clone();
let handle = tokio::spawn(async move {
sleep(Duration::from_millis(5)).await; handler_clone
.unregister_telegram_callback(callback_handle)
.await;
});
task_handles.push(handle);
}
for handle in task_handles {
handle.await.unwrap();
}
let final_count = handler.telegram_callback_count().await;
assert!(
(2..=5).contains(&final_count),
"Final count should be between 2 and 5, got {final_count}"
);
}
#[tokio::test]
async fn test_concurrent_mixed_operations() {
let handler = Arc::new(EventHandler::new());
let telegram_execution_count = Arc::new(AtomicUsize::new(0));
let connection_execution_count = Arc::new(AtomicUsize::new(0));
let telegram = Telegram {
source: IndividualAddress::from_raw(0x1234),
destination: Address::Group(GroupAddress::new(0, 1, 1)),
payload: vec![0x01],
priority: Priority::Normal,
direction: Direction::Incoming,
telegram_type: TelegramType::GroupValueWrite,
gateway_id: None,
timestamp: std::time::SystemTime::now(),
};
let mut task_handles = Vec::new();
for i in 0..5 {
let handler_clone = handler.clone();
let telegram_count = telegram_execution_count.clone();
let connection_count = connection_execution_count.clone();
let handle = tokio::spawn(async move {
let _telegram_handle = handler_clone
.register_telegram_callback_sync(move |_| {
telegram_count.fetch_add(1, Ordering::SeqCst);
})
.await;
let _connection_handle = handler_clone
.register_connection_callback_sync(move |_| {
connection_count.fetch_add(1, Ordering::SeqCst);
})
.await;
sleep(Duration::from_millis(i * 2)).await;
});
task_handles.push(handle);
}
for i in 0..3 {
let handler_clone = handler.clone();
let telegram_clone = telegram.clone();
let handle = tokio::spawn(async move {
sleep(Duration::from_millis(i * 5 + 10)).await;
handler_clone
.notify_telegram_received(&telegram_clone)
.await;
handler_clone
.notify_connection_state_changed(ConnectionState::Connected)
.await;
});
task_handles.push(handle);
}
for handle in task_handles {
handle.await.unwrap();
}
sleep(Duration::from_millis(100)).await;
let telegram_executions = telegram_execution_count.load(Ordering::SeqCst);
let connection_executions = connection_execution_count.load(Ordering::SeqCst);
assert!(
telegram_executions > 0,
"Telegram callbacks should have been executed"
);
assert!(
connection_executions > 0,
"Connection callbacks should have been executed"
);
println!(
"Execution counts - Telegram: {telegram_executions}, Connection: {connection_executions}"
);
}
#[tokio::test]
async fn test_concurrent_filter_operations() {
let handler = Arc::new(EventHandler::new());
let matching_count = Arc::new(AtomicUsize::new(0));
let non_matching_count = Arc::new(AtomicUsize::new(0));
let mut task_handles = Vec::new();
for i in 0..5 {
let handler_clone = handler.clone();
let matching_clone = matching_count.clone();
let non_matching_clone = non_matching_count.clone();
let handle = tokio::spawn(async move {
if i % 2 == 0 {
let _handle = handler_clone
.register_telegram_callback_sync_filtered(
move |_| {
matching_clone.fetch_add(1, Ordering::SeqCst);
},
TelegramFilter::GroupAddresses(vec![GroupAddress::new(0, 1, 1)]),
false,
)
.await;
} else {
let _handle = handler_clone
.register_telegram_callback_sync_filtered(
move |_| {
non_matching_clone.fetch_add(1, Ordering::SeqCst);
},
TelegramFilter::GroupAddresses(vec![GroupAddress::new(0, 2, 2)]),
false,
)
.await;
}
});
task_handles.push(handle);
}
for handle in task_handles {
handle.await.unwrap();
}
let telegram = Telegram {
source: IndividualAddress::from_raw(0x1234),
destination: Address::Group(GroupAddress::new(0, 1, 1)),
payload: vec![0x01],
priority: Priority::Normal,
direction: Direction::Incoming,
telegram_type: TelegramType::GroupValueWrite,
gateway_id: None,
timestamp: std::time::SystemTime::now(),
};
let mut notification_handles = Vec::new();
for _ in 0..3 {
let handler_clone = handler.clone();
let telegram_clone = telegram.clone();
let handle = tokio::spawn(async move {
handler_clone
.notify_telegram_received(&telegram_clone)
.await;
});
notification_handles.push(handle);
}
for handle in notification_handles {
handle.await.unwrap();
}
let matching_executions = matching_count.load(Ordering::SeqCst);
let non_matching_executions = non_matching_count.load(Ordering::SeqCst);
assert_eq!(
matching_executions, 9,
"Matching callbacks should be executed 9 times"
);
assert_eq!(
non_matching_executions, 0,
"Non-matching callbacks should not be executed"
);
}