2727import java .nio .file .Path ;
2828import java .time .Duration ;
2929import java .util .Optional ;
30+ import java .util .concurrent .atomic .AtomicLong ;
3031import org .apache .commons .lang3 .RandomStringUtils ;
3132import org .apache .logging .log4j .Level ;
3233import org .assertj .core .api .Assertions ;
@@ -151,8 +152,11 @@ void pauseAndResume_ObjectNotChanged_shouldResumeDownload(S3TransferManager tm)
151152 assertEqualsBySdkFields (resumableFileDownload .downloadFileRequest (), request );
152153 assertThat (testDownloadListener .getObjectResponse ).isNotNull ();
153154
155+ // wait to give CRT client time to write last bytes to file if any
156+ long actualInProgressFileSize = waitUntilFileSizeStable (path );
157+
154158 // Skip the test if everything has been downloaded.
155- Assumptions .assumeTrue (resumableFileDownload . bytesTransferred () < sourceFile .length ());
159+ Assumptions .assumeTrue (actualInProgressFileSize < sourceFile .length ());
156160
157161 assertThat (resumableFileDownload .s3ObjectLastModified ()).hasValue (testDownloadListener .getObjectResponse .lastModified ());
158162 // Request may not be cancelled right away when pause is invoked, so there may be more bytes written to the file
@@ -162,7 +166,7 @@ void pauseAndResume_ObjectNotChanged_shouldResumeDownload(S3TransferManager tm)
162166 assertThat (download .completionFuture ()).isCancelled ();
163167
164168 log .debug (() -> "Resuming download " );
165- verifyFileDownload (path , resumableFileDownload , OBJ_SIZE - bytesTransferred , tm );
169+ verifyFileDownload (path , resumableFileDownload , OBJ_SIZE - actualInProgressFileSize , tm );
166170 }
167171
168172 private void assertEqualsBySdkFields (DownloadFileRequest actual , DownloadFileRequest expected ) {
@@ -252,6 +256,25 @@ private static void waitUntilFirstByteBufferDelivered(FileDownload download) {
252256 waiter .run (() -> download .progress ().snapshot ());
253257 }
254258
259+ /**
260+ * CRT File downloads can continue to flush bytes to the file after pause. Wait until the file size is stable.
261+ *
262+ * @param file
263+ * @return the final file size
264+ */
265+ private static long waitUntilFileSizeStable (Path file ) {
266+ final AtomicLong fileSize = new AtomicLong (0L );
267+ Waiter <Path > waiter = Waiter .builder (Path .class )
268+ .addAcceptor (WaiterAcceptor .successOnResponseAcceptor (p -> file .toFile ().length () == fileSize .getAndSet (file .toFile ().length ())))
269+ .addAcceptor (WaiterAcceptor .retryOnResponseAcceptor (r -> true ))
270+ .overrideConfiguration (o -> o .waitTimeout (Duration .ofMinutes (1 ))
271+ .maxAttempts (Integer .MAX_VALUE )
272+ .backoffStrategy (FixedDelayBackoffStrategy .create (Duration .ofMillis (500 ))))
273+ .build ();
274+ waiter .run (() -> file );
275+ return file .toFile ().length ();
276+ }
277+
255278 private static final class TestDownloadListener implements TransferListener {
256279 private int transferInitiatedCount = 0 ;
257280 private GetObjectResponse getObjectResponse ;
0 commit comments