/** * @param responseContent the contents of the response * @param httpStatus the HTTP status code from the response * @param httpResponseMessage the HTTP status message from the response * @param totalContentLength the total content length for the batch job, including the length * from this response's corresponding request * @param resumableSessionURI the URI to use for further incremental uploads * @throws NullPointerException if {@code responseContent} is null. */ public BatchJobUploadResponse(InputStream responseContent, int httpStatus, String httpResponseMessage, long totalContentLength, @Nullable URI resumableSessionURI) { this.responseContent = Preconditions.checkNotNull(responseContent, "Null response content"); this.httpStatus = httpStatus; this.httpResponseMessage = httpResponseMessage; this.uploadStatus = new BatchJobUploadStatus(totalContentLength, resumableSessionURI); }
/** * Constructs the content range header value for the specified arguments. * @param requestLength the length of the request that's about to be uploaded * @param isLastRequest if the request is the last request for the job * @param batchJobUploadStatus the status of the job <em>before</em> this upload * @return the content range header value, e.g., {@code bytes 0-99/100}, * {@code 100-199/*}, etc. */ @VisibleForTesting String constructContentRangeHeaderValue( long requestLength, boolean isLastRequest, BatchJobUploadStatus batchJobUploadStatus) { Preconditions.checkArgument(requestLength > 0, "Request length %s is <= 0", requestLength); long previousTotalLength = batchJobUploadStatus.getTotalContentLength(); long contentLowerBound = previousTotalLength; long contentUpperBound = previousTotalLength + requestLength - 1; String totalBytesString; if (isLastRequest) { totalBytesString = String.valueOf(contentUpperBound + 1); } else { totalBytesString = "*"; } return String.format("bytes %d-%d/%s", contentLowerBound, contentUpperBound, totalBytesString); } }
/** * Test that verifies that {@link BatchJobUploadStatus} instances are serializable. */ @Test public void testSerializable() throws IOException, ClassNotFoundException { BatchJobUploadStatus status = new BatchJobUploadStatus(500L, URI.create("http://www.example.com/upload")); ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); ObjectOutputStream outputStream = new ObjectOutputStream(byteOutputStream); outputStream.writeObject(status); outputStream.close(); ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(byteOutputStream.toByteArray())); Object deserializedObject = inputStream.readObject(); assertTrue( "Deserialized status should be a BatchJobUploadStatus", deserializedObject instanceof BatchJobUploadStatus); BatchJobUploadStatus deserializedStatus = (BatchJobUploadStatus) deserializedObject; assertEquals("Deserialized status upload URI does not match original", status.getResumableUploadUri(), deserializedStatus.getResumableUploadUri()); assertEquals("Deserialized status total content length does not match original", status.getTotalContentLength(), deserializedStatus.getTotalContentLength()); }
@Test public void testUploadIncrementalBatchJobOperations_logging() throws Exception { BatchJobUploadStatus status = new BatchJobUploadStatus(10, URI.create(mockHttpServer.getServerUrl())); String uploadRequestBody = "<mutate>testUpload</mutate>"; when(uploadBodyProvider.getHttpContent(request, false, true)) .thenReturn(new ByteArrayContent(null, uploadRequestBody.getBytes(UTF_8))); mockHttpServer.setMockResponse(new MockResponse("testUploadResponse")); String expectedBody = "testUpload</mutate>"; expectedBody = Strings.padEnd(expectedBody, BatchJobUploader.REQUIRED_CONTENT_LENGTH_INCREMENT, ' '); // Invoke the incremental upload method. BatchJobUploadResponse response = uploader.uploadIncrementalBatchJobOperations(request, true, status); verify(batchJobLogger, times(1)).logUpload( expectedBody, status.getResumableUploadUri(), response, null ); }
@Test public void testToString() { Long totalContentLength = 500L; String uploadUrl = "http://www.example.com/upload"; BatchJobUploadStatus status = new BatchJobUploadStatus(totalContentLength, URI.create(uploadUrl)); assertThat( "toString should contain the total content length", status.toString(), Matchers.containsString(totalContentLength.toString())); assertThat( "toString should contain the upload URL", status.toString(), Matchers.containsString(uploadUrl)); }
Preconditions.checkNotNull(batchJobUploadStatus, "Null batch job upload status"); Preconditions.checkNotNull( batchJobUploadStatus.getResumableUploadUri(), "No resumable session URI"); if (batchJobUploadStatus.getTotalContentLength() == 0) { URI uploadUri = initiateResumableUpload(batchJobUploadStatus.getResumableUploadUri()); effectiveStatus = new BatchJobUploadStatus(0, uploadUri); } else { effectiveStatus = batchJobUploadStatus; request, effectiveStatus.getTotalContentLength() == 0, isLastRequest); try { content = postProcessContent( content, effectiveStatus.getTotalContentLength() == 0L, isLastRequest); } catch (IOException e) { throw new BatchJobException("Failed to post-process the request content", e); new GenericUrl(effectiveStatus.getResumableUploadUri()), content); batchJobUploadResponse = new BatchJobUploadResponse( response, effectiveStatus.getTotalContentLength() + httpRequest.getContent().getLength(), effectiveStatus.getResumableUploadUri()); return batchJobUploadResponse; } catch (HttpResponseException e) { e.getStatusMessage(), effectiveStatus.getTotalContentLength() + contentLength, effectiveStatus.getResumableUploadUri());
Preconditions.checkNotNull(batchJobUploadStatus, "Null batch job upload status"); Preconditions.checkNotNull( batchJobUploadStatus.getResumableUploadUri(), "No resumable session URI"); if (batchJobUploadStatus.getTotalContentLength() == 0) { URI uploadUri = initiateResumableUpload(batchJobUploadStatus.getResumableUploadUri()); effectiveStatus = new BatchJobUploadStatus(0, uploadUri); } else { effectiveStatus = batchJobUploadStatus; request, effectiveStatus.getTotalContentLength() == 0, isLastRequest); try { content = postProcessContent( content, effectiveStatus.getTotalContentLength() == 0L, isLastRequest); } catch (IOException e) { throw new BatchJobException("Failed to post-process the request content", e); new GenericUrl(effectiveStatus.getResumableUploadUri()), content); batchJobUploadResponse = new BatchJobUploadResponse( response, effectiveStatus.getTotalContentLength() + httpRequest.getContent().getLength(), effectiveStatus.getResumableUploadUri()); return batchJobUploadResponse; } catch (HttpResponseException e) { e.getStatusMessage(), effectiveStatus.getTotalContentLength() + contentLength, effectiveStatus.getResumableUploadUri());
/** * @param responseContent the contents of the response * @param httpStatus the HTTP status code from the response * @param httpResponseMessage the HTTP status message from the response * @param totalContentLength the total content length for the batch job, including the length * from this response's corresponding request * @param resumableSessionURI the URI to use for further incremental uploads * @throws NullPointerException if {@code responseContent} is null. */ public BatchJobUploadResponse(InputStream responseContent, int httpStatus, String httpResponseMessage, long totalContentLength, @Nullable URI resumableSessionURI) { this.responseContent = Preconditions.checkNotNull(responseContent, "Null response content"); this.httpStatus = httpStatus; this.httpResponseMessage = httpResponseMessage; this.uploadStatus = new BatchJobUploadStatus(totalContentLength, resumableSessionURI); }
/** * Constructs the content range header value for the specified arguments. * @param requestLength the length of the request that's about to be uploaded * @param isLastRequest if the request is the last request for the job * @param batchJobUploadStatus the status of the job <em>before</em> this upload * @return the content range header value, e.g., {@code bytes 0-99/100}, * {@code 100-199/*}, etc. */ @VisibleForTesting String constructContentRangeHeaderValue( long requestLength, boolean isLastRequest, BatchJobUploadStatus batchJobUploadStatus) { Preconditions.checkArgument(requestLength > 0, "Request length %s is <= 0", requestLength); long previousTotalLength = batchJobUploadStatus.getTotalContentLength(); long contentLowerBound = previousTotalLength; long contentUpperBound = previousTotalLength + requestLength - 1; String totalBytesString; if (isLastRequest) { totalBytesString = String.valueOf(contentUpperBound + 1); } else { totalBytesString = "*"; } return String.format("bytes %d-%d/%s", contentLowerBound, contentUpperBound, totalBytesString); } }
@Test public void testUploadIncrementalBatchJobOperations_notFirst() throws Exception { BatchJobUploadStatus status = new BatchJobUploadStatus(10, URI.create(mockHttpServer.getServerUrl())); String uploadRequestBody = "<mutate>testUpload</mutate>"; when(uploadBodyProvider.getHttpContent(request, false, true)) new BatchJobUploadStatus( status.getTotalContentLength() + expectedBody.getBytes(UTF_8).length, URI.create(mockHttpServer.getServerUrl())); BatchJobUploadStatus actualStatus = response.getBatchJobUploadStatus(); assertEquals( "Status total content length is incorrect", expectedStatus.getTotalContentLength(), actualStatus.getTotalContentLength()); assertEquals( "Status resumable upload URI is incorrect", expectedStatus.getResumableUploadUri(), actualStatus.getResumableUploadUri());
@Override public BatchJobUploadResponse uploadBatchJobOperations( Iterable<Operation> operations, String uploadUrl) throws BatchJobException { // All uploads must go through the incremental upload workflow. return uploadIncrementalBatchJobOperations( operations, true, new BatchJobUploadStatus(0, URI.create(uploadUrl))); }
@Test public void testUploadIncrementalBatchJobOperations_notFirst_notLast() throws Exception { BatchJobUploadStatus status = new BatchJobUploadStatus(10, URI.create(mockHttpServer.getServerUrl())); String uploadRequestBody = "<mutate>testUpload</mutate>"; when(uploadBodyProvider.getHttpContent(request, false, false)) new BatchJobUploadStatus( status.getTotalContentLength() + expectedBody.getBytes(UTF_8).length, URI.create(mockHttpServer.getServerUrl())); BatchJobUploadStatus actualStatus = response.getBatchJobUploadStatus(); assertEquals( "Status total content length is incorrect", expectedStatus.getTotalContentLength(), actualStatus.getTotalContentLength()); assertEquals( "Status resumable upload URI is incorrect", expectedStatus.getResumableUploadUri(), actualStatus.getResumableUploadUri());
@Override public BatchJobUploadResponse uploadBatchJobOperations( Iterable<Operation> operations, String uploadUrl) throws BatchJobException { // All uploads must go through the incremental upload workflow. return uploadIncrementalBatchJobOperations( operations, true, new BatchJobUploadStatus(0, URI.create(uploadUrl))); }
@Test public void testUploadIncrementalBatchJobOperations_firstAndLast() throws Exception { BatchJobUploadStatus status = new BatchJobUploadStatus(0, URI.create(mockHttpServer.getServerUrl())); String uploadRequestBody = "testUpload"; when(uploadBodyProvider.getHttpContent(request, true, true)) new BatchJobUploadStatus( uploadRequestBody.getBytes(UTF_8).length, URI.create(mockHttpServer.getServerUrl())); BatchJobUploadStatus actualStatus = response.getBatchJobUploadStatus(); assertEquals( "Status total content length is incorrect", expectedStatus.getTotalContentLength(), actualStatus.getTotalContentLength()); assertEquals( "Status resumable upload URI is incorrect", expectedStatus.getResumableUploadUri(), actualStatus.getResumableUploadUri());
@Override public BatchJobUploadResponse uploadBatchJobOperations( Iterable<Operation> operations, String uploadUrl) throws BatchJobException { // All uploads must go through the incremental upload workflow. return uploadIncrementalBatchJobOperations( operations, true, new BatchJobUploadStatus(0, URI.create(uploadUrl))); }
@Override public BatchJobUploadResponse uploadBatchJobOperations( Iterable<Operation> operations, String uploadUrl) throws BatchJobException { // All uploads must go through the incremental upload workflow. return uploadIncrementalBatchJobOperations( operations, true, new BatchJobUploadStatus(0, URI.create(uploadUrl))); }
@Override public BatchJobUploadResponse uploadBatchJobOperations( Iterable<Operation> operations, String uploadUrl) throws BatchJobException { // All uploads must go through the incremental upload workflow. return uploadIncrementalBatchJobOperations( operations, true, new BatchJobUploadStatus(0, URI.create(uploadUrl))); }
@Override public BatchJobUploadResponse uploadBatchJobOperations( Iterable<Operation> operations, String uploadUrl) throws BatchJobException { // All uploads must go through the incremental upload workflow. return uploadIncrementalBatchJobOperations( operations, true, new BatchJobUploadStatus(0, URI.create(uploadUrl))); }
@Override public BatchJobUploadResponse uploadBatchJobOperations( Iterable<Operation> operations, String uploadUrl) throws BatchJobException { // All uploads must go through the incremental upload workflow. return uploadIncrementalBatchJobOperations( operations, true, new BatchJobUploadStatus(0, URI.create(uploadUrl))); }
@Override public BatchJobUploadResponse uploadBatchJobOperations( Iterable<Operation> operations, String uploadUrl) throws BatchJobException { // All uploads must go through the incremental upload workflow. return uploadIncrementalBatchJobOperations( operations, true, new BatchJobUploadStatus(0, URI.create(uploadUrl))); }