in cas_client/src/remote_client.rs [1198:1294]
fn test_reconstruct_file_two_terms() -> Result<()> {
// Arrange server
let server = MockServer::start();
let xorb_hash_1: MerkleHash = MerkleHash::from_hex(&format!("{:0>64}", "1"))?; // "0....1"
let xorb_hash_2: MerkleHash = MerkleHash::from_hex(&format!("{:0>64}", "2"))?; // "0....2"
let (cas_object, chunks_serialized, raw_data, _raw_data_chunk_hash_and_boundaries) =
build_cas_object(NUM_CHUNKS, ChunkSize::Fixed(CHUNK_SIZE), CompressionScheme::ByteGrouping4LZ4);
// Test case: two terms and skip first and last 100 bytes
const FILE_SIZE: u64 = (NUM_CHUNKS - 1) as u64 * CHUNK_SIZE as u64;
const SKIP_BYTES: u64 = 100;
const FIRST_SEGMENT_FILE_RANGE: FileRange = FileRange {
start: SKIP_BYTES,
end: FILE_SIZE - SKIP_BYTES,
_marker: std::marker::PhantomData,
};
let test_case = TestCase {
file_hash: MerkleHash::from_hex(&format!("{:0>64}", "1"))?, // "0....3"
reconstruction_response: QueryReconstructionResponse {
offset_into_first_range: SKIP_BYTES,
terms: vec![
CASReconstructionTerm {
hash: xorb_hash_1.into(),
range: ChunkRange::new(0, 5),
unpacked_length: CHUNK_SIZE * 5,
},
CASReconstructionTerm {
hash: xorb_hash_2.into(),
range: ChunkRange::new(6, NUM_CHUNKS),
unpacked_length: CHUNK_SIZE * (NUM_CHUNKS - 6),
},
],
fetch_info: HashMap::from([
(
// this constructs the first term
xorb_hash_1.into(),
vec![CASReconstructionFetchInfo {
range: ChunkRange::new(0, 7),
url: server.url(format!("/get_xorb/{xorb_hash_1}/")),
url_range: {
let (start, end) = cas_object.get_byte_offset(0, 7)?;
HttpRange::from(FileRange::new(start as u64, end as u64))
},
}],
),
(
// this constructs the second term
xorb_hash_2.into(),
vec![CASReconstructionFetchInfo {
range: ChunkRange::new(4, NUM_CHUNKS),
url: server.url(format!("/get_xorb/{xorb_hash_2}/")),
url_range: {
let (start, end) = cas_object.get_byte_offset(4, NUM_CHUNKS)?;
HttpRange::from(FileRange::new(start as u64, end as u64))
},
}],
),
]),
},
file_range: FileRange::new(SKIP_BYTES, FILE_SIZE - SKIP_BYTES),
expected_data: [
&raw_data[SKIP_BYTES as usize..(5 * CHUNK_SIZE) as usize],
&raw_data[(6 * CHUNK_SIZE) as usize..(NUM_CHUNKS * CHUNK_SIZE) as usize - SKIP_BYTES as usize],
]
.concat(),
expect_error: false,
};
// Arrange server mocks
let _mock_fi_416 = server.mock(|when, then| {
when.method(GET)
.path(format!("/reconstruction/{}", test_case.file_hash))
.matches(mock_no_match_range_header!(HttpRange::from(FIRST_SEGMENT_FILE_RANGE)));
then.status(416);
});
let _mock_fi_200 = server.mock(|when, then| {
let w = when.method(GET).path(format!("/reconstruction/{}", test_case.file_hash));
w.header(RANGE.as_str(), HttpRange::from(FIRST_SEGMENT_FILE_RANGE).range_header());
then.status(200).json_body_obj(&test_case.reconstruction_response);
});
for (k, v) in &test_case.reconstruction_response.fetch_info {
for term in v {
let data = FileRange::from(term.url_range);
let data = chunks_serialized[data.start as usize..data.end as usize].to_vec();
let _mock_data = server.mock(|when, then| {
when.method(GET)
.path(format!("/get_xorb/{k}/"))
.header(RANGE.as_str(), term.url_range.range_header());
then.status(200).body(&data);
});
}
}
test_reconstruct_file(test_case, &server.base_url())
}