Skip to content

Commit 00a6e72

Browse files
committed
Add unit test for readahead cache
1 parent e69626e commit 00a6e72

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

src/metadata/cache.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ impl<F: MetadataFetch> ReadaheadMetadataCache<F> {
106106
}
107107
}
108108

109+
/// Access the inner MetadataFetch
110+
pub fn inner(&self) -> &F {
111+
&self.inner
112+
}
113+
109114
/// Set the initial fetch size in bytes, otherwise defaults to 32 KiB
110115
pub fn with_initial_size(mut self, initial: u64) -> Self {
111116
self.initial = initial;
@@ -154,3 +159,79 @@ impl<F: MetadataFetch + Send + Sync> MetadataFetch for ReadaheadMetadataCache<F>
154159
})
155160
}
156161
}
162+
163+
#[cfg(test)]
164+
mod test {
165+
use futures::future::FutureExt;
166+
167+
use super::*;
168+
169+
struct TestFetch {
170+
data: Bytes,
171+
/// The number of fetches that actually reach the raw Fetch implementation
172+
num_fetches: Arc<Mutex<u64>>,
173+
}
174+
175+
impl TestFetch {
176+
fn new(data: Bytes) -> Self {
177+
Self {
178+
data,
179+
num_fetches: Arc::new(Mutex::new(0)),
180+
}
181+
}
182+
}
183+
184+
impl MetadataFetch for TestFetch {
185+
fn fetch(
186+
&self,
187+
range: Range<u64>,
188+
) -> futures::future::BoxFuture<'_, crate::error::AsyncTiffResult<Bytes>> {
189+
if range.start as usize >= self.data.len() {
190+
return async { Ok(Bytes::new()) }.boxed();
191+
}
192+
193+
let end = (range.end as usize).min(self.data.len());
194+
let slice = self.data.slice(range.start as _..end);
195+
async move {
196+
let mut g = self.num_fetches.lock().await;
197+
*g += 1;
198+
Ok(slice)
199+
}
200+
.boxed()
201+
}
202+
}
203+
204+
#[tokio::test]
205+
async fn test_readahead_cache() {
206+
let data = Bytes::from_static(b"abcdefghijklmnopqrstuvwxyz");
207+
let fetch = TestFetch::new(data.clone());
208+
let cache = ReadaheadMetadataCache::new(fetch)
209+
.with_initial_size(2)
210+
.with_multiplier(3.0);
211+
212+
// Make initial request
213+
let result = cache.fetch(0..2).await.unwrap();
214+
assert_eq!(result.as_ref(), b"ab");
215+
assert_eq!(*cache.inner.num_fetches.lock().await, 1);
216+
217+
// Making a request within the cached range should not trigger a new fetch
218+
let result = cache.fetch(1..2).await.unwrap();
219+
assert_eq!(result.as_ref(), b"b");
220+
assert_eq!(*cache.inner.num_fetches.lock().await, 1);
221+
222+
// Making a request that exceeds the cached range should trigger a new fetch
223+
let result = cache.fetch(2..5).await.unwrap();
224+
assert_eq!(result.as_ref(), b"cde");
225+
assert_eq!(*cache.inner.num_fetches.lock().await, 2);
226+
227+
// Multiplier should be accurate: initial was 2, next was 6 (2*3), so total cached is now 8
228+
let result = cache.fetch(5..8).await.unwrap();
229+
assert_eq!(result.as_ref(), b"fgh");
230+
assert_eq!(*cache.inner.num_fetches.lock().await, 2);
231+
232+
// Should work even for fetch range larger than underlying buffer
233+
let result = cache.fetch(8..20).await.unwrap();
234+
assert_eq!(result.as_ref(), b"ijklmnopqrst");
235+
assert_eq!(*cache.inner.num_fetches.lock().await, 3);
236+
}
237+
}

0 commit comments

Comments
 (0)