S3MultipartOutputStream extends AbortableOutputStream { @Override public void write(int b) throws IOException { if (part == null) { if (partNumber == 1) { uploadId = upload.start(); } part = new S3PartOutputStream(partSize, partNumber++); } part.write(b); if (part.size() >= partSize) { performUpload(); } }  @Override void write(int b); @Override void close(); @Override void abort(); static S3MultipartOutputStreamBuilder builder(); static final int MINIMUM_PART_SIZE; }
@Test public void singlePart() throws IOException { when(upload.start()).thenReturn(UPLOAD_ID); ArgumentCaptor<S3Part> partCaptor = ArgumentCaptor.forClass(S3Part.class); when(upload.upload(eq(UPLOAD_ID), partCaptor.capture())).thenReturn(partETag1); try (OutputStream output = new S3MultipartOutputStream(upload, 2, retry, asyncHandler)) { output.write(new byte[] { 0, 1 }); } List<S3Part> parts = partCaptor.getAllValues(); assertThat(parts.size(), is(1)); S3Part part1 = parts.get(0); assertThat(part1.getNumber(), is(1)); assertThat(part1.getSize(), is(2)); assertThat(part1.getMd5(), is(MD5_FOR_BYTES_ZERO_ONE)); assertThat(ByteStreams.toByteArray(part1.getInputStream()), is(new byte[] { 0, 1 })); verify(upload).complete(UPLOAD_ID, ImmutableList.of(partETag1)); }
@Test public void twoParts() throws IOException { when(upload.start()).thenReturn(UPLOAD_ID); ArgumentCaptor<S3Part> partCaptor = ArgumentCaptor.forClass(S3Part.class); when(upload.upload(eq(UPLOAD_ID), partCaptor.capture())).thenReturn(partETag1, partETag2); try (OutputStream output = new S3MultipartOutputStream(upload, 1, retry, asyncHandler)) { output.write(new byte[] { 0, 1 }); } List<S3Part> parts = partCaptor.getAllValues(); assertThat(parts.size(), is(2)); Map<Integer, S3Part> map = Maps.uniqueIndex(parts, S3Part::getNumber); S3Part part1 = map.get(1); assertThat(part1.getNumber(), is(1)); assertThat(part1.getSize(), is(1)); assertThat(part1.getMd5(), is(MD5_FOR_BYTE_ZERO)); assertThat(ByteStreams.toByteArray(part1.getInputStream()), is(new byte[] { 0 })); S3Part part2 = map.get(2); assertThat(part2.getNumber(), is(2)); assertThat(part2.getSize(), is(1)); assertThat(part2.getMd5(), is(MD5_FOR_BYTE_ONE)); assertThat(ByteStreams.toByteArray(part2.getInputStream()), is(new byte[] { 1 })); @SuppressWarnings("unchecked") ArgumentCaptor<List<PartETag>> tagCaptor = ArgumentCaptor.forClass(List.class); verify(upload).complete(eq(UPLOAD_ID), tagCaptor.capture()); assertThat(tagCaptor.getValue(), hasSize(2)); assertThat(tagCaptor.getValue(), containsInAnyOrder(partETag1, partETag2)); }