Skip to content

Commit d2b1616

Browse files
committed
fix: remove flakiness on download retries
1 parent 971b382 commit d2b1616

File tree

1 file changed

+48
-25
lines changed
  • mithril-client/src/file_downloader

1 file changed

+48
-25
lines changed

mithril-client/src/file_downloader/retry.rs

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ impl FileDownloader for RetryDownloader {
9797
#[cfg(test)]
9898
mod tests {
9999

100-
use std::time::Instant;
100+
use std::{sync::Mutex, time::Instant};
101101

102102
use mithril_common::entities::FileUri;
103103

@@ -227,22 +227,59 @@ mod tests {
227227

228228
#[tokio::test]
229229
async fn should_delay_between_retries() {
230-
let mock_file_downloader = MockFileDownloaderBuilder::default()
231-
.with_file_uri("http://whatever/00001.tar.gz")
232-
.with_compression(None)
233-
.with_failure()
234-
.with_times(4)
235-
.build();
236-
let delay = Duration::from_millis(50);
230+
struct FileDownloaderAssertDelay {
231+
expected_delay_greater_than_or_equal: Duration,
232+
expected_delay_less_than: Duration,
233+
last_attempt_start_time: Mutex<Option<Instant>>,
234+
}
235+
236+
#[async_trait]
237+
impl FileDownloader for FileDownloaderAssertDelay {
238+
async fn download_unpack(
239+
&self,
240+
_location: &FileDownloaderUri,
241+
_file_size: u64,
242+
_target_dir: &Path,
243+
_compression_algorithm: Option<CompressionAlgorithm>,
244+
_download_event_type: DownloadEvent,
245+
) -> StdResult<()> {
246+
let mut last_attempt_start_time = self.last_attempt_start_time.lock().unwrap();
247+
if let Some(last_start_attempt) = *last_attempt_start_time {
248+
let duration = last_start_attempt.elapsed();
249+
assert!(
250+
duration >= self.expected_delay_greater_than_or_equal,
251+
"duration should be greater than or equal to {}ms but was {}ms",
252+
self.expected_delay_greater_than_or_equal.as_millis(),
253+
duration.as_millis()
254+
);
255+
assert!(
256+
duration < self.expected_delay_less_than,
257+
"duration should be less than {}ms but was {}ms",
258+
self.expected_delay_less_than.as_millis(),
259+
duration.as_millis()
260+
);
261+
}
262+
*last_attempt_start_time = Some(Instant::now());
263+
264+
Err(anyhow::anyhow!("Download failed"))
265+
}
266+
}
267+
268+
let delay_ms = 50;
269+
let mock_file_downloader = Arc::new(FileDownloaderAssertDelay {
270+
expected_delay_greater_than_or_equal: Duration::from_millis(delay_ms),
271+
expected_delay_less_than: Duration::from_millis(2 * delay_ms),
272+
last_attempt_start_time: Mutex::new(None),
273+
});
274+
237275
let retry_downloader = RetryDownloader::new(
238-
Arc::new(mock_file_downloader),
276+
mock_file_downloader.clone(),
239277
FileDownloadRetryPolicy {
240278
attempts: 4,
241-
delay_between_attempts: delay,
279+
delay_between_attempts: Duration::from_millis(delay_ms),
242280
},
243281
);
244282

245-
let start = Instant::now();
246283
retry_downloader
247284
.download_unpack(
248285
&FileDownloaderUri::FileUri(FileUri("http://whatever/00001.tar.gz".to_string())),
@@ -256,19 +293,5 @@ mod tests {
256293
)
257294
.await
258295
.expect_err("An error should be returned when all download attempts fail");
259-
let duration = start.elapsed();
260-
261-
assert!(
262-
duration >= delay * 3,
263-
"Duration should be at least 3 times the delay ({}ms) but was {}ms",
264-
delay.as_millis() * 3,
265-
duration.as_millis()
266-
);
267-
assert!(
268-
duration < delay * 4,
269-
"Duration should be less than 4 times the delay ({}ms) but was {}ms",
270-
delay.as_millis() * 4,
271-
duration.as_millis()
272-
);
273296
}
274297
}

0 commit comments

Comments
 (0)