/** * <p> * Aborts any multipart uploads that were initiated before the specified date. * </p> * <p> * This method is useful for cleaning up any interrupted multipart uploads. * <code>TransferManager</code> attempts to abort any failed uploads, * but in some cases this may not be possible, such as if network connectivity * is completely lost. * </p> * * @param bucketName * The name of the bucket containing the multipart uploads to * abort. * @param date * The date indicating which multipart uploads should be aborted. */ public void abortMultipartUploads(String bucketName, Date date) throws AmazonServiceException, AmazonClientException { MultipartUploadListing uploadListing = s3.listMultipartUploads(appendSingleObjectUserAgent( new ListMultipartUploadsRequest(bucketName))); do { for (MultipartUpload upload : uploadListing.getMultipartUploads()) { if (upload.getInitiated().compareTo(date) < 0) { s3.abortMultipartUpload(appendSingleObjectUserAgent(new AbortMultipartUploadRequest( bucketName, upload.getKey(), upload.getUploadId()))); } } ListMultipartUploadsRequest request = new ListMultipartUploadsRequest(bucketName) .withUploadIdMarker(uploadListing.getNextUploadIdMarker()) .withKeyMarker(uploadListing.getNextKeyMarker()); uploadListing = s3.listMultipartUploads(appendSingleObjectUserAgent(request)); } while (uploadListing.isTruncated()); }
/** * Tests if not yet completed / aborted multipart uploads are listed. * * @throws Exception not expected */ @Test public void shouldListMultipartUploads() throws Exception { s3Client.createBucket(BUCKET_NAME); assertThat(s3Client.listMultipartUploads(new ListMultipartUploadsRequest(BUCKET_NAME)) .getMultipartUploads(), is(empty())); final InitiateMultipartUploadResult initiateMultipartUploadResult = s3Client .initiateMultipartUpload(new InitiateMultipartUploadRequest(BUCKET_NAME, UPLOAD_FILE_NAME)); final String uploadId = initiateMultipartUploadResult.getUploadId(); final MultipartUploadListing listing = s3Client.listMultipartUploads(new ListMultipartUploadsRequest(BUCKET_NAME)); assertThat(listing.getMultipartUploads(), is(not(empty()))); assertThat(listing.getBucketName(), equalTo(BUCKET_NAME)); assertThat(listing.getMultipartUploads(), hasSize(1)); final MultipartUpload upload = listing.getMultipartUploads().get(0); assertThat(upload.getUploadId(), equalTo(uploadId)); assertThat(upload.getKey(), equalTo(UPLOAD_FILE_NAME)); }
/** * Creates and returns a mock {@link MultipartUpload} with the given initiated timestamp. * * @param initiated the timestamp to set to initiate the object * * @return the mock object */ private MultipartUpload getMultipartUpload(Date initiated) { MultipartUpload multipartUpload = new MultipartUpload(); multipartUpload.setInitiated(initiated); return multipartUpload; }
/** * <p> Returns a mock {@link MultipartUploadListing}. </p> <p> The return object has the following properties. <dl> <dt>multipartUploads</dt> <dd>Length 3 * list</dd> <p/> <dt>multipartUploads[0].initiated</dt> <dd>5 minutes prior to the object creation time.</dd> <p/> <dt>multipartUploads[1].initiated</dt> * <dd>15 minutes prior to the object creation time.</dd> <p/> <dt>multipartUploads[2].initiated</dt> <dd>20 minutes prior to the object creation time.</dd> * </dl> <p/> All other properties as set to default as defined in the by {@link MultipartUploadListing} constructor. </p> * * @return a mock object */ private MultipartUploadListing getMultipartUploadListing() { // Return 3 multipart uploads with 2 of them started more than 10 minutes ago. MultipartUploadListing multipartUploadListing = new MultipartUploadListing(); List<MultipartUpload> multipartUploads = new ArrayList<>(); multipartUploadListing.setMultipartUploads(multipartUploads); Date now = new Date(); multipartUploads.add(getMultipartUpload(HerdDateUtils.addMinutes(now, -5))); multipartUploads.add(getMultipartUpload(HerdDateUtils.addMinutes(now, -15))); multipartUploads.add(getMultipartUpload(HerdDateUtils.addMinutes(now, -20))); return multipartUploadListing; }
@Override public int abortMultipartUploads(S3FileTransferRequestParamsDto params, Date thresholdDate) { // Create an Amazon S3 client. AmazonS3Client s3Client = getAmazonS3(params); int abortedMultipartUploadsCount = 0; try { // List upload markers. Null implies initial list request. String uploadIdMarker = null; String keyMarker = null; boolean truncated; do { // Create the list multipart request, optionally using the last markers. ListMultipartUploadsRequest request = new ListMultipartUploadsRequest(params.getS3BucketName()); request.setUploadIdMarker(uploadIdMarker); request.setKeyMarker(keyMarker); // Request the multipart upload listing. MultipartUploadListing uploadListing = s3Operations.listMultipartUploads(TransferManager.appendSingleObjectUserAgent(request), s3Client); for (MultipartUpload upload : uploadListing.getMultipartUploads()) { if (upload.getInitiated().compareTo(thresholdDate) < 0) { // Abort the upload. s3Operations.abortMultipartUpload(TransferManager .appendSingleObjectUserAgent(new AbortMultipartUploadRequest(params.getS3BucketName(), upload.getKey(), upload.getUploadId())), s3Client); // Log the information about the aborted multipart upload. LOGGER.info("Aborted S3 multipart upload. s3Key=\"{}\" s3BucketName=\"{}\" s3MultipartUploadInitiatedDate=\"{}\"", upload.getKey(), params.getS3BucketName(), upload.getInitiated()); // Increment the counter. abortedMultipartUploadsCount++; } } // Determine whether there are more uploads to list. truncated = uploadListing.isTruncated(); if (truncated) { // Record the list markers. uploadIdMarker = uploadListing.getNextUploadIdMarker(); keyMarker = uploadListing.getNextKeyMarker(); } } while (truncated); } finally { // Shutdown the Amazon S3 client instance to release resources. s3Client.shutdown(); } return abortedMultipartUploadsCount; }
@Test public void testAbortMultipartUploadsAssertTruncatedResult() { S3Operations originalS3Operations = (S3Operations) ReflectionTestUtils.getField(s3Dao, "s3Operations"); S3Operations mockS3Operations = mock(S3Operations.class); ReflectionTestUtils.setField(s3Dao, "s3Operations", mockS3Operations); try { String s3BucketName = "s3BucketName"; String uploadKey = "uploadKey"; String uploadId = "uploadId"; Date uploadInitiated = new Date(0); S3FileTransferRequestParamsDto s3FileTransferRequestParamsDto = new S3FileTransferRequestParamsDto(); s3FileTransferRequestParamsDto.setS3BucketName(s3BucketName); Date thresholdDate = new Date(1); when(mockS3Operations.listMultipartUploads(any(), any())).then(new Answer<MultipartUploadListing>() { @Override public MultipartUploadListing answer(InvocationOnMock invocation) throws Throwable { ListMultipartUploadsRequest listMultipartUploadsRequest = invocation.getArgument(0); String keyMarker = listMultipartUploadsRequest.getKeyMarker(); String uploadIdMarker = listMultipartUploadsRequest.getUploadIdMarker(); MultipartUploadListing multipartUploadListing = new MultipartUploadListing(); if (keyMarker == null || uploadIdMarker == null) { multipartUploadListing.setNextKeyMarker("nextKeyMarker"); multipartUploadListing.setNextUploadIdMarker("nextUploadIdMarker"); multipartUploadListing.setTruncated(true); } else { assertEquals("nextKeyMarker", keyMarker); assertEquals("nextUploadIdMarker", uploadIdMarker); MultipartUpload multipartUpload = new MultipartUpload(); multipartUpload.setUploadId(uploadId); multipartUpload.setKey(uploadKey); multipartUpload.setInitiated(uploadInitiated); multipartUploadListing.getMultipartUploads().add(multipartUpload); } return multipartUploadListing; } }); assertEquals(1, s3Dao.abortMultipartUploads(s3FileTransferRequestParamsDto, thresholdDate)); // Assert listMultipartUploads() is called twice due to truncation verify(mockS3Operations, times(2)).listMultipartUploads(any(), any()); /* * Assert that S3Operations.abortMultipartUpload is called exactly ONCE with arguments matching the given ArgumentMatcher */ verify(mockS3Operations).abortMultipartUpload(argThat( argument -> Objects.equal(s3BucketName, argument.getBucketName()) && Objects.equal(uploadKey, argument.getKey()) && Objects.equal(uploadId, argument.getUploadId())), any()); // Assert that no other interactions occur with the mock verifyNoMoreInteractions(mockS3Operations); } finally { ReflectionTestUtils.setField(s3Dao, "s3Operations", originalS3Operations); } }