|
52 | 52 | import java.security.DigestInputStream;
|
53 | 53 | import java.security.MessageDigest;
|
54 | 54 | import java.util.*;
|
| 55 | +import java.util.concurrent.ThreadPoolExecutor; |
55 | 56 | import java.util.concurrent.TimeUnit;
|
56 | 57 | import java.util.concurrent.TimeoutException;
|
57 | 58 | import java.util.concurrent.atomic.AtomicLong;
|
@@ -168,6 +169,88 @@ public void testLargeFileUploaderProgressListener() throws Exception {
|
168 | 169 | client.deleteObject(getTestBucket(), key);
|
169 | 170 | }
|
170 | 171 |
|
| 172 | + @Test |
| 173 | + public void testLFUCopy() { |
| 174 | + String srcKey = "lfu-source.bin"; |
| 175 | + String dstKey = "lfu-single-copy.bin"; |
| 176 | + String dstKey2 = "lfu-multipart-copy.bin"; |
| 177 | + |
| 178 | + byte[] data = new byte[(int) MockMultipartSource.totalSize]; |
| 179 | + new Random().nextBytes(data); |
| 180 | + client.putObject(getTestBucket(), srcKey, data, null); |
| 181 | + S3ObjectMetadata sourceMetadata = client.getObjectMetadata(getTestBucket(), srcKey); |
| 182 | + Assert.assertEquals(MockMultipartSource.totalSize, sourceMetadata.getContentLength().longValue()); |
| 183 | + |
| 184 | + //Single Copy |
| 185 | + S3ObjectMetadata objectMetadata = new S3ObjectMetadata().addUserMetadata("key", "value"); |
| 186 | + LargeFileUploader uploader = new TestLargeFileUploader(client, getTestBucket(), srcKey, getTestBucket(), dstKey) |
| 187 | + .withObjectMetadata(objectMetadata); |
| 188 | + uploader.upload(); |
| 189 | + Assert.assertEquals(0, uploader.getBytesTransferred()); |
| 190 | + Assert.assertEquals(sourceMetadata.getETag(), uploader.getETag()); |
| 191 | + Assert.assertEquals(MockMultipartSource.totalSize, client.getObjectMetadata(getTestBucket(), dstKey).getContentLength().longValue()); |
| 192 | + Assert.assertEquals(objectMetadata.getUserMetadata(), client.getObjectMetadata(getTestBucket(), dstKey).getUserMetadata()); |
| 193 | + |
| 194 | + //Multi Part Copy |
| 195 | + LargeFileUploader uploader2 = new TestLargeFileUploader(client, getTestBucket(), srcKey, getTestBucket(), dstKey2) |
| 196 | + .withObjectMetadata(objectMetadata) |
| 197 | + .withPartSize(MockMultipartSource.partSize) |
| 198 | + .withMpuThreshold(MockMultipartSource.partSize); |
| 199 | + uploader2.upload(); |
| 200 | + Assert.assertEquals(0, uploader2.getBytesTransferred()); |
| 201 | + Assert.assertTrue(uploader2.getETag().contains("-")); // hyphen signifies multipart / updated object |
| 202 | + Assert.assertEquals(MockMultipartSource.totalSize, client.getObjectMetadata(getTestBucket(), dstKey2).getContentLength().longValue()); |
| 203 | + Assert.assertEquals(objectMetadata.getUserMetadata(), client.getObjectMetadata(getTestBucket(), dstKey2).getUserMetadata()); |
| 204 | + } |
| 205 | + |
| 206 | + @Test |
| 207 | + public void testLFUCopyPauseResume() throws Exception { |
| 208 | + String srcKey = "mpu-copy-pause.source"; |
| 209 | + String dstKey = "mpu-copy-pause.target"; |
| 210 | + |
| 211 | + MockMultipartSource mockMultipartSource = new MockMultipartSource(); |
| 212 | + LargeFileUploader lfu = new TestLargeFileUploader(client, getTestBucket(), srcKey, mockMultipartSource) |
| 213 | + .withPartSize(mockMultipartSource.getPartSize()).withMpuThreshold((int) mockMultipartSource.getTotalSize()); |
| 214 | + lfu.doMultipartUpload(); |
| 215 | + |
| 216 | + lfu = new TestLargeFileUploader(client, getTestBucket(), srcKey, getTestBucket(), dstKey) |
| 217 | + .withPartSize(mockMultipartSource.getPartSize()).withMpuThreshold((int) mockMultipartSource.getTotalSize()) |
| 218 | + .withThreads(1); |
| 219 | + LargeFileUpload upload = lfu.uploadAsync(); |
| 220 | + |
| 221 | + // wait for first a few parts to start |
| 222 | + while (lfu.getExecutorService() == null || ((ThreadPoolExecutor) lfu.getExecutorService()).getCompletedTaskCount() == 0) { |
| 223 | + Thread.sleep(100); |
| 224 | + } |
| 225 | + LargeFileUploaderResumeContext resumeContext = upload.pause(); |
| 226 | + |
| 227 | + // object should not exist |
| 228 | + try { |
| 229 | + Assert.assertNull(client.getObjectMetadata(getTestBucket(), dstKey)); |
| 230 | + } catch (S3Exception e) { |
| 231 | + Assert.assertEquals(404, e.getHttpCode()); |
| 232 | + Assert.assertEquals("NoSuchKey", e.getErrorCode()); |
| 233 | + } |
| 234 | + |
| 235 | + // check resume context accuracy |
| 236 | + Assert.assertNotNull(resumeContext.getUploadId()); |
| 237 | + Assert.assertNotNull(resumeContext.getUploadedParts()); |
| 238 | + Assert.assertFalse(resumeContext.getUploadedParts().isEmpty()); |
| 239 | + List<MultipartPart> parts = client.listParts(getTestBucket(), dstKey, resumeContext.getUploadId()).getParts(); |
| 240 | + Assert.assertNotNull(parts); |
| 241 | + |
| 242 | + lfu = new TestLargeFileUploader(client, getTestBucket(), srcKey, getTestBucket(), dstKey) |
| 243 | + .withPartSize(mockMultipartSource.getPartSize()).withMpuThreshold((int) mockMultipartSource.getTotalSize()) |
| 244 | + .withResumeContext(resumeContext); |
| 245 | + lfu.doMultipartUpload(); |
| 246 | + |
| 247 | + // Unfortunately, MPU Etag is not preserved even if copy parts matches the original multipart upload. |
| 248 | + // So the content verification is done by calculating md5sum instead of checking ETag. |
| 249 | + //Assert.assertEquals(mockMultipartSource.getMpuETag(), client.getObjectMetadata(getTestBucket(), dstKey).getETag()); |
| 250 | + Assert.assertEquals(DigestUtils.md5Hex(client.getObject(getTestBucket(), srcKey).getObject()), DigestUtils.md5Hex(client.getObject(getTestBucket(), dstKey).getObject())); |
| 251 | + Assert.assertEquals(mockMultipartSource.getTotalSize(), client.getObjectMetadata(getTestBucket(), dstKey).getContentLength().longValue()); |
| 252 | + } |
| 253 | + |
171 | 254 | @Test
|
172 | 255 | public void testLargeFileUploaderStream() {
|
173 | 256 | String key = "large-file-uploader-stream.bin";
|
|
0 commit comments