use std::fs;
use rocketmq_store::consume_queue::mapped_file_queue::MappedFileQueue;
use rocketmq_store::log_file::mapped_file::MappedFile;
use tempfile::TempDir;
fn create_test_files(dir: &TempDir, num_files: usize, file_size: u64) {
for i in 0..num_files {
let offset = i as u64 * file_size;
let file_path = dir.path().join(format!("{:020}", offset));
let data = vec![i as u8; file_size as usize];
fs::write(&file_path, data).expect("Failed to write test file");
}
}
#[test]
fn test_load_empty_directory() {
let temp_dir = TempDir::new().unwrap();
let mut queue = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
1024 * 1024,
None,
);
std::env::set_var("ROCKETMQ_SAFE_LOAD", "1");
assert!(queue.load());
let mut queue2 = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
1024 * 1024,
None,
);
std::env::remove_var("ROCKETMQ_SAFE_LOAD");
assert!(queue2.load());
}
#[test]
fn test_load_single_file() {
let temp_dir = TempDir::new().unwrap();
let file_size = 1024 * 1024u64;
create_test_files(&temp_dir, 1, file_size);
let mut queue1 = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
file_size,
None,
);
std::env::set_var("ROCKETMQ_SAFE_LOAD", "1");
assert!(queue1.load());
let files1 = queue1.get_mapped_files();
assert_eq!(files1.read().len(), 1);
let mut queue2 = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
file_size,
None,
);
std::env::remove_var("ROCKETMQ_SAFE_LOAD");
assert!(queue2.load());
let files2 = queue2.get_mapped_files();
assert_eq!(files2.read().len(), 1);
let f1 = &files1.read()[0];
let f2 = &files2.read()[0];
assert_eq!(f1.get_wrote_position(), f2.get_wrote_position());
assert_eq!(f1.get_flushed_position(), f2.get_flushed_position());
assert_eq!(f1.get_committed_position(), f2.get_committed_position());
}
#[test]
fn test_load_multiple_files_ordered() {
let temp_dir = TempDir::new().unwrap();
let file_size = 1024 * 1024u64;
let num_files = 10;
create_test_files(&temp_dir, num_files, file_size);
let mut queue1 = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
file_size,
None,
);
std::env::set_var("ROCKETMQ_SAFE_LOAD", "1");
assert!(queue1.load());
let mut queue2 = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
file_size,
None,
);
std::env::remove_var("ROCKETMQ_SAFE_LOAD");
assert!(queue2.load());
let files1 = queue1.get_mapped_files();
let files2 = queue2.get_mapped_files();
assert_eq!(files1.read().len(), files2.read().len());
assert_eq!(files1.read().len(), num_files);
for i in 0..num_files {
let f1 = &files1.read()[i];
let f2 = &files2.read()[i];
assert_eq!(f1.get_file_name(), f2.get_file_name());
assert_eq!(f1.get_file_from_offset(), f2.get_file_from_offset());
}
}
#[test]
fn test_load_removes_empty_last_file() {
let temp_dir = TempDir::new().unwrap();
let file_size = 1024 * 1024u64;
let num_files = 5;
for i in 0..num_files - 1 {
let offset = i as u64 * file_size;
let file_path = temp_dir.path().join(format!("{:020}", offset));
let data = vec![i as u8; file_size as usize];
fs::write(&file_path, data).unwrap();
}
let last_offset = (num_files - 1) as u64 * file_size;
let last_path = temp_dir.path().join(format!("{:020}", last_offset));
fs::write(&last_path, vec![]).unwrap();
let mut queue1 = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
file_size,
None,
);
std::env::set_var("ROCKETMQ_SAFE_LOAD", "1");
assert!(queue1.load());
assert_eq!(queue1.get_mapped_files().read().len(), num_files - 1);
assert!(!last_path.exists());
fs::write(&last_path, vec![]).unwrap();
let mut queue2 = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
file_size,
None,
);
std::env::remove_var("ROCKETMQ_SAFE_LOAD");
assert!(queue2.load());
assert_eq!(queue2.get_mapped_files().read().len(), num_files - 1);
assert!(!last_path.exists()); }
#[test]
fn test_load_rejects_size_mismatch() {
let temp_dir = TempDir::new().unwrap();
let expected_size = 1024 * 1024u64;
let actual_size = 512 * 1024u64;
let file_path = temp_dir.path().join("00000000000000000000");
fs::write(&file_path, vec![0u8; actual_size as usize]).unwrap();
let mut queue1 = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
expected_size,
None,
);
std::env::set_var("ROCKETMQ_SAFE_LOAD", "1");
assert!(!queue1.load());
let mut queue2 = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
expected_size,
None,
);
std::env::remove_var("ROCKETMQ_SAFE_LOAD");
assert!(!queue2.load());
}
#[test]
fn test_parallel_enabled_threshold() {
let temp_dir = TempDir::new().unwrap();
let file_size = 128 * 1024u64; let num_files = 20;
create_test_files(&temp_dir, num_files, file_size);
let mut queue = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
file_size,
None,
);
std::env::remove_var("ROCKETMQ_SAFE_LOAD");
let start = std::time::Instant::now();
assert!(queue.load());
let elapsed = start.elapsed();
println!("Parallel load of {} files took {:?}", num_files, elapsed);
assert_eq!(queue.get_mapped_files().read().len(), num_files);
}
#[test]
#[ignore] fn test_load_stress_100_files() {
let temp_dir = TempDir::new().unwrap();
let file_size = 64 * 1024u64; let num_files = 100;
create_test_files(&temp_dir, num_files, file_size);
let mut queue = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
file_size,
None,
);
std::env::remove_var("ROCKETMQ_SAFE_LOAD");
let start = std::time::Instant::now();
assert!(queue.load());
let elapsed = start.elapsed();
println!("Loaded {} files in {:?}", num_files, elapsed);
assert_eq!(queue.get_mapped_files().read().len(), num_files);
}
#[test]
fn test_load_data_integrity() {
let temp_dir = TempDir::new().unwrap();
let file_size = 4096u64;
let num_files = 5;
for i in 0..num_files {
let offset = i as u64 * file_size;
let file_path = temp_dir.path().join(format!("{:020}", offset));
let mut data = vec![0u8; file_size as usize];
for (idx, byte) in data.iter_mut().enumerate() {
*byte = ((i * 256 + idx) % 256) as u8;
}
fs::write(&file_path, data).unwrap();
}
let mut queue = MappedFileQueue::new(
temp_dir.path().to_string_lossy().to_string(),
file_size,
None,
);
std::env::remove_var("ROCKETMQ_SAFE_LOAD");
assert!(queue.load());
let files = queue.get_mapped_files();
for (i, file) in files.read().iter().enumerate() {
let bytes = file.get_bytes(0, file_size as usize).unwrap();
let expected_first = (i * 256) % 256;
let expected_last = (i * 256 + file_size as usize - 1) % 256;
assert_eq!(bytes[0], expected_first as u8);
assert_eq!(bytes[bytes.len() - 1], expected_last as u8);
}
}