//! Arc refcount stress test - rapid announce/drop cycles //! Tests for memory leaks in rapid channel creation/destruction with Arc values. use announcement::Announcement; use std::sync::Arc; use std::thread; /// Test: Arc refcount: cycle detection /// /// Verifies: Arc reference cycles are handled correctly /// Category: refcount // Test 1: Rapid Arc refcount cycles (single-threaded) #[test] fn test_arc_refcount_rapid_cycles() { let data = Arc::new(vec![0u8; 1024]); // 1KB test data let initial_count = Arc::strong_count(&data); // Run 10,000 create/announce/drop cycles for i in 0..10_000 { { let (announcer, announcement) = Announcement::new(); // Create a few listeners let l1 = announcement.listener(); let l2 = announcement.listener(); let l3 = announcement.listener(); // Announce the Arc announcer.announce(data.clone()).unwrap(); // Retrieve values let _v1 = l1.try_listen().unwrap(); let _v2 = l2.try_listen().unwrap(); let _v3 = l3.try_listen().unwrap(); // Everything drops here when block ends } // Periodic check after everything has dropped if i % 1000 == 0 { let current_count = Arc::strong_count(&data); assert_eq!( current_count, initial_count, "Refcount leak detected at iteration {}: expected {}, got {}", i, initial_count, current_count ); } } // Final verification assert_eq!( Arc::strong_count(&data), initial_count, "Final refcount mismatch after 10k cycles" ); } /// Test: Refcount test: arc refcount mixed drop patterns /// /// Verifies: Verifies arc refcount mixed drop patterns /// Category: refcount // Test 2: Rapid Arc cycles with mixed drop patterns #[test] fn test_arc_refcount_mixed_drop_patterns() { let data = Arc::new(vec![42u8; 512]); let initial_count = Arc::strong_count(&data); for i in 0..5_000 { { let (announcer, announcement) = Announcement::new(); // Create various numbers of listeners let listener_count = (i % 10) + 1; let mut listeners = Vec::new(); for _ in 0..listener_count { listeners.push(announcement.listener()); } // Announce announcer.announce(data.clone()).unwrap(); // Drop listeners in different patterns match i % 4 { 0 => drop(listeners), // Drop all at once 1 => { // Drop one at a time for l in listeners { drop(l); } } 2 => { // Retrieve then drop let values: Vec<_> = listeners.iter().map(|l| l.try_listen().unwrap()).collect(); drop(values); drop(listeners); } _ => { // Drop half, retrieve from rest let mid = listeners.len() / 2; drop(listeners.drain(0..mid).collect::>()); for l in &listeners { let _ = l.try_listen(); } } } // Block ends - everything drops including announcement } // Verify refcount periodically after everything dropped if i % 500 == 0 { assert_eq!(Arc::strong_count(&data), initial_count); } } assert_eq!(Arc::strong_count(&data), initial_count); } /// Test: Arc refcount: cycle detection /// /// Verifies: Arc reference cycles are handled correctly /// Category: refcount // Test 3: Concurrent Arc refcount stress #[test] fn test_arc_refcount_concurrent_cycles() { let data = Arc::new(vec![0u8; 2048]); let initial_count = Arc::strong_count(&data); let mut handles = Vec::new(); // 8 threads all doing rapid cycles for thread_id in 0..8 { let data_clone = data.clone(); handles.push(thread::spawn(move || { for i in 0..1_000 { let (announcer, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..5 { listeners.push(announcement.listener()); } announcer.announce(data_clone.clone()).unwrap(); // Mix of operations match i % 3 { 0 => { // Just drop everything drop(listeners); } 1 => { // Retrieve and verify for l in &listeners { let v = l.try_listen().unwrap(); assert_eq!(v.len(), 2048); } } _ => { // Mixed let _ = listeners[0].try_listen(); drop(listeners); } } if i % 100 == 0 && thread_id == 0 { println!("Thread {} completed {} iterations", thread_id, i); } } })); } // Wait for all threads for handle in handles { handle.join().unwrap(); } // Final refcount should be back to initial assert_eq!( Arc::strong_count(&data), initial_count, "Refcount leak after concurrent stress test" ); } /// Test: Refcount test: arc refcount with announcer drop /// /// Verifies: Verifies arc refcount with announcer drop /// Category: refcount // Test 4: Arc refcount with announcer drop (no announce) #[test] fn test_arc_refcount_with_announcer_drop() { let data = Arc::new(vec![1u8; 256]); let initial_count = Arc::strong_count(&data); for _ in 0..10_000 { let (announcer, announcement) = Announcement::>>::new(); let _l1 = announcement.listener(); let _l2 = announcement.listener(); // Drop announcer WITHOUT announcing drop(announcer); // Listeners should see closed, no Arc refcount change for data // since it was never announced } // Refcount should be unchanged assert_eq!(Arc::strong_count(&data), initial_count); } /// Test: Refcount test: arc refcount with listener cloning /// /// Verifies: Verifies arc refcount with listener cloning /// Category: refcount // Test 5: Arc refcount with listener cloning stress #[test] fn test_arc_refcount_with_listener_cloning() { let data = Arc::new(vec![7u8; 512]); let initial_count = Arc::strong_count(&data); for _ in 0..5_000 { let (announcer, announcement) = Announcement::new(); let l1 = announcement.listener(); // Clone listener many times let mut clones = vec![l1.clone()]; for _ in 0..10 { clones.push(clones[0].clone()); } announcer.announce(data.clone()).unwrap(); // All clones retrieve for l in &clones { let _v = l.try_listen().unwrap(); } // Everything drops } assert_eq!(Arc::strong_count(&data), initial_count); }