use rand::seq::SliceRandom;
use rand::Rng;
use uri_register::{PostgresUriRegister, UriService};
mod common;
use common::{get_database_url, get_table_name};
async fn setup() -> PostgresUriRegister {
let db_url = get_database_url();
let table_name = get_table_name();
PostgresUriRegister::new(&db_url, &table_name, 20, 10_000)
.await
.expect("Failed to connect to database")
}
#[tokio::test]
async fn test_batch_all_state_combinations() {
let register = setup().await;
let uuid = uuid::Uuid::new_v4();
let mut pre_existing_uris = vec![];
for i in 0..30 {
let uri = format!("http://example.org/stress/preexist/{}/{}", uuid, i);
register
.register_uri(&uri)
.await
.expect("Failed to pre-populate");
pre_existing_uris.push(uri);
}
let fresh_register = setup().await;
let cached_uris = &pre_existing_uris[0..10]; for uri in cached_uris {
fresh_register
.register_uri(uri)
.await
.expect("Failed to cache");
}
let mut test_uris = vec![];
test_uris.extend_from_slice(&pre_existing_uris[0..10]);
test_uris.extend_from_slice(&pre_existing_uris[10..30]);
for i in 0..20 {
test_uris.push(format!("http://example.org/stress/new/{}/{}", uuid, i));
}
test_uris.push(pre_existing_uris[5].clone()); test_uris.push(pre_existing_uris[15].clone()); test_uris.push(format!("http://example.org/stress/new/{}/5", uuid));
let batch_ids = fresh_register
.register_uri_batch(&test_uris)
.await
.expect("Batch registration failed");
assert_eq!(
batch_ids.len(),
test_uris.len(),
"Result length must match input length"
);
for (idx, uri) in test_uris.iter().enumerate() {
let individual_id = fresh_register
.register_uri(uri)
.await
.expect("Individual registration failed");
assert_eq!(
batch_ids[idx], individual_id,
"CORRECTNESS FAILURE at index {}: URI '{}' got ID {} in batch but {} individually",
idx, uri, batch_ids[idx], individual_id
);
}
let fresh_register2 = setup().await;
for uri in cached_uris {
fresh_register2
.register_uri(uri)
.await
.expect("Failed to cache");
}
let batch_map = fresh_register2
.register_uri_batch_hashmap(&test_uris)
.await
.expect("Hashmap batch registration failed");
let unique_uris: std::collections::HashSet<_> = test_uris.iter().collect();
assert_eq!(
batch_map.len(),
unique_uris.len(),
"HashMap should contain exactly {} unique URIs",
unique_uris.len()
);
for uri in unique_uris {
let individual_id = fresh_register2
.register_uri(uri)
.await
.expect("Individual registration failed");
assert_eq!(
batch_map.get(uri),
Some(&individual_id),
"CORRECTNESS FAILURE: URI '{}' mapped to {:?} in hashmap but {} individually",
uri,
batch_map.get(uri),
individual_id
);
}
println!(
"✓ Tested {} URIs across all state combinations",
test_uris.len()
);
}
#[tokio::test]
async fn test_batch_large_random_distribution() {
let register = setup().await;
let uuid = uuid::Uuid::new_v4();
let mut rng = rand::rng();
let mut all_uris = vec![];
for i in 0..100 {
let uri = format!("http://example.org/stress/rand/{}/{}", uuid, i);
register
.register_uri(&uri)
.await
.expect("Failed to pre-populate");
all_uris.push(uri);
}
let fresh_register = setup().await;
let mut cached_indices: Vec<usize> = (0..100).collect();
cached_indices.shuffle(&mut rng);
for &idx in &cached_indices[0..30] {
fresh_register
.register_uri(&all_uris[idx])
.await
.expect("Failed to cache");
}
let mut test_uris = vec![];
let mut selected: Vec<usize> = (0..100).collect();
selected.shuffle(&mut rng);
for &idx in &selected[0..30] {
test_uris.push(all_uris[idx].clone());
}
for i in 100..120 {
test_uris.push(format!("http://example.org/stress/rand/{}/{}", uuid, i));
}
for _ in 0..10 {
let dup_idx = rng.random_range(0..test_uris.len());
test_uris.push(test_uris[dup_idx].clone());
}
test_uris.shuffle(&mut rng);
println!(
"Testing batch of {} URIs with random distribution",
test_uris.len()
);
let batch_ids = fresh_register
.register_uri_batch(&test_uris)
.await
.expect("Batch failed");
assert_eq!(batch_ids.len(), test_uris.len());
for (idx, uri) in test_uris.iter().enumerate() {
let individual_id = fresh_register
.register_uri(uri)
.await
.expect("Individual failed");
assert_eq!(
batch_ids[idx], individual_id,
"Order violation at index {} for URI '{}'",
idx, uri
);
}
let fresh_register2 = setup().await;
for &idx in &cached_indices[0..30] {
fresh_register2
.register_uri(&all_uris[idx])
.await
.expect("Failed to cache");
}
let batch_map = fresh_register2
.register_uri_batch_hashmap(&test_uris)
.await
.expect("Hashmap batch failed");
let unique_uris: std::collections::HashSet<_> = test_uris.iter().collect();
for uri in unique_uris {
let individual_id = fresh_register2
.register_uri(uri)
.await
.expect("Individual failed");
assert_eq!(
batch_map.get(uri),
Some(&individual_id),
"Mapping violation for URI '{}'",
uri
);
}
println!("✓ All {} positions verified correct", test_uris.len());
}
#[tokio::test]
async fn test_batch_heavy_duplicates() {
let register = setup().await;
let uuid = uuid::Uuid::new_v4();
let unique_uris: Vec<String> = (0..10)
.map(|i| format!("http://example.org/stress/dup/{}/{}", uuid, i))
.collect();
let mut test_uris = vec![];
let mut rng = rand::rng();
for _ in 0..100 {
let idx = rng.random_range(0..unique_uris.len());
test_uris.push(unique_uris[idx].clone());
}
println!(
"Testing batch of {} URIs with only {} unique",
test_uris.len(),
unique_uris.len()
);
let batch_ids = register
.register_uri_batch(&test_uris)
.await
.expect("Batch failed");
assert_eq!(batch_ids.len(), 100);
for (idx, uri) in test_uris.iter().enumerate() {
let individual_id = register.register_uri(uri).await.expect("Individual failed");
assert_eq!(
batch_ids[idx], individual_id,
"Duplicate handling error at index {}",
idx
);
}
let uri_to_positions: std::collections::HashMap<&String, Vec<usize>> = test_uris
.iter()
.enumerate()
.fold(std::collections::HashMap::new(), |mut acc, (idx, uri)| {
acc.entry(uri).or_default().push(idx);
acc
});
for (uri, positions) in uri_to_positions {
let first_id = batch_ids[positions[0]];
for &pos in &positions[1..] {
assert_eq!(
batch_ids[pos], first_id,
"Duplicate URI '{}' got different IDs at positions {} and {}",
uri, positions[0], pos
);
}
}
let fresh_register = setup().await;
let batch_map = fresh_register
.register_uri_batch_hashmap(&test_uris)
.await
.expect("Hashmap batch failed");
assert_eq!(
batch_map.len(),
unique_uris.len(),
"Should have exactly 10 unique mappings"
);
for uri in &unique_uris {
let individual_id = fresh_register
.register_uri(uri)
.await
.expect("Individual failed");
assert_eq!(
batch_map.get(uri),
Some(&individual_id),
"Mapping error for duplicate URI '{}'",
uri
);
}
println!("✓ Heavy duplicate scenario passed");
}
#[tokio::test]
async fn test_batch_with_cache_pressure() {
let register = setup().await;
let uuid = uuid::Uuid::new_v4();
let mut old_uris = vec![];
for i in 0..100 {
let uri = format!("http://example.org/stress/cache/{}/{}", uuid, i);
register.register_uri(&uri).await.expect("Failed");
old_uris.push(uri);
}
let mut test_uris = vec![];
test_uris.extend_from_slice(&old_uris[0..30]);
for i in 100..150 {
test_uris.push(format!("http://example.org/stress/cache/{}/{}", uuid, i));
}
test_uris.extend_from_slice(&old_uris[10..20]);
let batch_ids = register
.register_uri_batch(&test_uris)
.await
.expect("Batch failed");
for (idx, uri) in test_uris.iter().enumerate() {
let individual_id = register.register_uri(uri).await.expect("Individual failed");
assert_eq!(
batch_ids[idx], individual_id,
"Cache pressure test failed at index {}",
idx
);
}
let fresh_register = setup().await;
for uri in &old_uris {
fresh_register.register_uri(uri).await.expect("Failed");
}
let batch_map = fresh_register
.register_uri_batch_hashmap(&test_uris)
.await
.expect("Hashmap batch failed");
let unique_uris: std::collections::HashSet<_> = test_uris.iter().collect();
for uri in unique_uris {
let individual_id = fresh_register
.register_uri(uri)
.await
.expect("Individual failed");
assert_eq!(
batch_map.get(uri),
Some(&individual_id),
"Cache pressure hashmap test failed"
);
}
println!("✓ Cache pressure scenario passed");
}
#[tokio::test]
async fn test_batch_concurrent_mixed_states() {
let uuid = uuid::Uuid::new_v4();
let setup_register = setup().await;
let mut shared_uris = vec![];
for i in 0..50 {
let uri = format!("http://example.org/stress/concurrent/{}/{}", uuid, i);
setup_register
.register_uri(&uri)
.await
.expect("Setup failed");
shared_uris.push(uri);
}
let mut handles = vec![];
for task_id in 0..5 {
let shared_uris_clone = shared_uris.clone();
let uuid_clone = uuid;
let handle = tokio::spawn(async move {
let register = setup().await;
let cache_start = task_id * 10;
let cache_end = cache_start + 10;
for uri in &shared_uris_clone[cache_start..cache_end] {
register.register_uri(uri).await.expect("Cache failed");
}
let mut test_uris = vec![];
test_uris.extend_from_slice(&shared_uris_clone);
for i in 0..20 {
test_uris.push(format!(
"http://example.org/stress/concurrent/{}/task{}/{}",
uuid_clone, task_id, i
));
}
let batch_ids = register
.register_uri_batch(&test_uris)
.await
.expect("Concurrent batch failed");
let batch_map = register
.register_uri_batch_hashmap(&test_uris)
.await
.expect("Concurrent hashmap failed");
for (idx, uri) in test_uris.iter().enumerate() {
let individual_id = register.register_uri(uri).await.expect("Individual failed");
assert_eq!(batch_ids[idx], individual_id, "Concurrent order error");
assert_eq!(
batch_map.get(uri),
Some(&individual_id),
"Concurrent mapping error"
);
}
test_uris.len()
});
handles.push(handle);
}
let mut total_tested = 0;
for handle in handles {
total_tested += handle.await.expect("Task panicked");
}
println!(
"✓ Concurrent test verified {} total URIs across 5 tasks",
total_tested
);
}