use std::sync::Arc;
use std::thread;
use std::time::Duration;
use crate::container::{IocContainer, ServiceBinder};
#[test]
fn test_no_deadlock_on_concurrent_dispose_and_resolve() {
let container = Arc::new({
let mut container = IocContainer::new();
container.bind_singleton::<String, String>();
container.build().unwrap();
container
});
let scope1 = container.create_scope().unwrap();
let scope2 = container.create_scope().unwrap();
let scope3 = container.create_scope().unwrap();
let mut handles = vec![];
let container_clone = container.clone();
let scope_to_dispose = scope1.clone();
handles.push(thread::spawn(move || {
for _ in 0..10 {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let _ = container_clone.dispose_scope(&scope_to_dispose).await;
let _ = container_clone.create_scope();
});
thread::sleep(Duration::from_micros(10));
}
}));
let container_clone = container.clone();
let scope2_clone = scope2.clone();
let scope3_clone = scope3.clone();
handles.push(thread::spawn(move || {
for i in 0..10 {
let _ = container_clone.resolve_scoped::<String>(&scope2_clone);
let _ = container_clone.resolve_scoped::<String>(&scope3_clone);
let _ = container_clone.resolve::<String>();
thread::sleep(Duration::from_micros(5 + i));
}
}));
let container_clone = container.clone();
let scope2_clone = scope2.clone();
handles.push(thread::spawn(move || {
for _ in 0..5 {
if let Ok(child) = container_clone.create_child_scope(&scope2_clone) {
let _ = container_clone.resolve_scoped::<String>(&child);
}
thread::sleep(Duration::from_micros(15));
}
}));
for handle in handles {
handle
.join()
.expect("Thread should complete without deadlock");
}
}
#[test]
fn test_lock_ordering_consistency() {
let container = Arc::new({
let mut container = IocContainer::new();
container.build().unwrap();
container
});
let scope1 = container.create_scope().unwrap();
let scope2 = container.create_scope().unwrap();
let mut handles = vec![];
let container_clone = container.clone();
let scope = scope1.clone();
handles.push(thread::spawn(move || {
for _ in 0..20 {
if let Ok(new_scope) = container_clone.create_scope() {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let _ = container_clone.dispose_scope(&new_scope).await;
});
}
let _ = container_clone.create_child_scope(&scope);
thread::yield_now();
}
}));
let container_clone = container.clone();
handles.push(thread::spawn(move || {
for _ in 0..20 {
let _ = container_clone.resolve_scoped::<String>(&scope2);
thread::yield_now();
}
}));
for handle in handles {
handle.join().expect("No deadlock should occur");
}
}