Skip to content

Commit

Permalink
chore: add test for tolerating empty responses
Browse files Browse the repository at this point in the history
  • Loading branch information
Rjected committed Nov 3, 2023
1 parent caca6f6 commit 2335dc2
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
26 changes: 26 additions & 0 deletions crates/net/downloaders/src/bodies/bodies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,4 +762,30 @@ mod tests {
header += resp.len();
}
}

// Check that the downloader can tolerate a few completely empty responses
#[tokio::test]
async fn can_tolerate_empty_responses() {
// Generate some random blocks
let db = create_test_rw_db();
let (headers, mut bodies) = generate_bodies(0..=99);

insert_headers(db.db(), &headers);

// respond with empty bodies for every other request.
let client = Arc::new(
TestBodiesClient::default().with_bodies(bodies.clone()).with_empty_responses(2),
);
let mut downloader = BodiesDownloaderBuilder::default()
.with_request_limit(3)
.with_stream_batch_size(100)
.build(client.clone(), Arc::new(TestConsensus::default()), db);

// Download the requested range
downloader.set_download_range(0..=99).expect("failed to set download range");
assert_matches!(
downloader.next().await,
Some(Ok(res)) => assert_eq!(res, zip_blocks(headers.iter().take(100), &mut bodies))
);
}
}
25 changes: 25 additions & 0 deletions crates/net/downloaders/src/test_utils/bodies_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct TestBodiesClient {
should_delay: bool,
max_batch_size: Option<usize>,
times_requested: AtomicU64,
empty_response_mod: Option<u64>,
}

impl TestBodiesClient {
Expand All @@ -35,6 +36,13 @@ impl TestBodiesClient {
self
}

/// Instructs the client to respond with empty responses some portion of the time. Every
/// `empty_mod` responses, the client will respond with an empty response.
pub(crate) fn with_empty_responses(mut self, empty_mod: u64) -> Self {
self.empty_response_mod = Some(empty_mod);
self
}

pub(crate) fn with_max_batch_size(mut self, max_batch_size: usize) -> Self {
self.max_batch_size = Some(max_batch_size);
self
Expand All @@ -43,6 +51,18 @@ impl TestBodiesClient {
pub(crate) fn times_requested(&self) -> u64 {
self.times_requested.load(Ordering::Relaxed)
}

/// Returns whether or not the client should respond with an empty response.
///
/// This will only return true if `empty_response_mod` is `Some`, and `times_requested %
/// empty_response_mod == 0`.
pub(crate) fn should_respond_empty(&self) -> bool {
if let Some(empty_response_mod) = self.empty_response_mod {
self.times_requested.load(Ordering::Relaxed) % empty_response_mod == 0
} else {
false
}
}
}

impl DownloadClient for TestBodiesClient {
Expand All @@ -68,8 +88,13 @@ impl BodiesClient for TestBodiesClient {
let max_batch_size = self.max_batch_size;

self.times_requested.fetch_add(1, Ordering::Relaxed);
let should_respond_empty = self.should_respond_empty();

Box::pin(async move {
if should_respond_empty {
return Ok((PeerId::default(), vec![]).into());
}

if should_delay {
tokio::time::sleep(Duration::from_millis((hashes[0][0] % 100) as u64)).await;
}
Expand Down

0 comments on commit 2335dc2

Please sign in to comment.