Skip to content

Commit f50394b

Browse files
maqijacderida
authored andcommitted
test: heavy duty parallel_fetch test of streaming_decrypt_from_storage
1 parent 061637f commit f50394b

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

tests/integration_tests.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,115 @@ fn test_streaming_decrypt_with_parallel_retrieval() -> Result<()> {
693693
Ok(())
694694
}
695695

696+
#[test]
697+
fn test_streaming_decrypt_from_storage_with_parallel_random_chunks() -> Result<()> {
698+
use std::collections::HashMap;
699+
use rand::seq::SliceRandom;
700+
use rand::thread_rng;
701+
702+
let temp_dir = TempDir::new()?;
703+
704+
// Generate 100MB content
705+
let content_size = 100 * 1024 * 1024; // 100MB
706+
let original_data = random_bytes(content_size);
707+
println!("Generated {} bytes of test data", content_size);
708+
709+
// Encrypt to get datamap and encrypted_chunks
710+
let (data_map, encrypted_chunks) = encrypt(original_data.clone())?;
711+
println!("Encrypted into {} chunks", encrypted_chunks.len());
712+
713+
// Create a storage map from encrypted_chunks using their hashes as keys
714+
let mut chunk_storage = HashMap::new();
715+
for chunk in encrypted_chunks.iter() {
716+
let hash = XorName::from_content(&chunk.content);
717+
chunk_storage.insert(hash, chunk.content.clone());
718+
}
719+
720+
// Create destination file for streaming_decrypt_from_storage
721+
let output_path = temp_dir.path().join("decrypted_output.dat");
722+
723+
// Create parallel chunk fetcher that returns chunks in random order
724+
// This is the key function that simulates a parallel storage system where
725+
// multiple chunks are requested and returned in random order
726+
let parallel_chunk_fetcher = |chunk_requests: &[(usize, XorName)]| -> Result<Vec<(usize, Bytes)>> {
727+
let mut results = Vec::new();
728+
729+
println!("Parallel fetch request for {} chunks", chunk_requests.len());
730+
731+
// Collect all requested chunks first
732+
for &(index, hash) in chunk_requests {
733+
if let Some(content) = chunk_storage.get(&hash) {
734+
results.push((index, content.clone()));
735+
println!(" Found chunk {} with hash: {}", index, hex::encode(hash));
736+
} else {
737+
return Err(Error::Generic(format!(
738+
"Chunk not found for hash: {}",
739+
hex::encode(hash)
740+
)));
741+
}
742+
}
743+
744+
// Randomize the order before returning to simulate parallel retrieval
745+
// where chunks arrive in non-deterministic order
746+
let mut rng = thread_rng();
747+
results.shuffle(&mut rng);
748+
749+
Ok(results)
750+
};
751+
752+
streaming_decrypt_from_storage(&data_map, &output_path, parallel_chunk_fetcher)?;
753+
println!("Successfully decrypted to file using streaming: {:?}", output_path);
754+
755+
// Read back the decrypted content from disk
756+
let mut decrypted_data = Vec::new();
757+
File::open(&output_path)?.read_to_end(&mut decrypted_data)?;
758+
println!("Read back {} bytes from decrypted file", decrypted_data.len());
759+
760+
// Compare hash first using XorName (which provides content hashing)
761+
let original_hash = XorName::from_content(&original_data);
762+
let decrypted_hash = XorName::from_content(&decrypted_data);
763+
764+
if original_hash != decrypted_hash {
765+
println!("Hash mismatch detected!");
766+
println!("Original hash: {}", hex::encode(original_hash));
767+
println!("Decrypted hash: {}", hex::encode(decrypted_hash));
768+
769+
// Further compare the raw content for debugging
770+
assert_eq!(
771+
original_data.len(),
772+
decrypted_data.len(),
773+
"Data length mismatch: original={}, decrypted={}",
774+
original_data.len(),
775+
decrypted_data.len()
776+
);
777+
778+
// Find first difference
779+
for (i, (orig, decr)) in original_data.iter().zip(decrypted_data.iter()).enumerate() {
780+
if orig != decr {
781+
panic!(
782+
"First difference at byte {}: original=0x{:02x}, decrypted=0x{:02x}",
783+
i, orig, decr
784+
);
785+
}
786+
}
787+
788+
panic!("Hashes don't match but raw content is identical - this shouldn't happen");
789+
} else {
790+
println!("✓ Hash comparison passed!");
791+
792+
// Do a final raw content comparison for completeness
793+
assert_eq!(
794+
original_data.as_ref(),
795+
decrypted_data.as_slice(),
796+
"Raw content mismatch despite matching hashes"
797+
);
798+
println!("✓ Raw content comparison passed!");
799+
}
800+
801+
println!("Test completed successfully - 100MB data encrypted and streaming decrypted correctly with parallel randomized chunk fetching");
802+
Ok(())
803+
}
804+
696805
#[test]
697806
fn test_chunk_verification() -> Result<()> {
698807
let storage = StorageBackend::new()?;

0 commit comments

Comments
 (0)