JCLOUDS-1005: Backblaze B2 large file operations
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/3d84d3cb Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/3d84d3cb Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/3d84d3cb Branch: refs/heads/master Commit: 3d84d3cb2d9c69fe38d25e99e87c3cfe0244648e Parents: 882a65b Author: Andrew Gaul <[email protected]> Authored: Sun May 29 20:27:50 2016 -0700 Committer: Andrew Gaul <[email protected]> Committed: Thu Jun 16 16:12:32 2016 -0700 ---------------------------------------------------------------------- .../b2/src/main/java/org/jclouds/b2/B2Api.java | 4 + .../jclouds/b2/binders/UploadPartBinder.java | 41 ++++ .../b2/domain/GetUploadPartResponse.java | 35 +++ .../jclouds/b2/domain/ListPartsResponse.java | 51 ++++ .../ListUnfinishedLargeFilesResponse.java | 55 +++++ .../b2/domain/MultipartUploadResponse.java | 41 ++++ .../jclouds/b2/domain/UploadPartResponse.java | 34 +++ .../org/jclouds/b2/features/MultipartApi.java | 104 ++++++++ .../b2/features/MultipartApiLiveTest.java | 194 +++++++++++++++ .../b2/features/MultipartApiMockTest.java | 246 +++++++++++++++++++ .../resources/cancel_large_file_request.json | 3 + .../resources/cancel_large_file_response.json | 6 + .../resources/finish_large_file_request.json | 7 + .../resources/finish_large_file_response.json | 14 ++ .../resources/get_upload_part_url_request.json | 3 + .../resources/get_upload_part_url_response.json | 5 + .../src/test/resources/list_parts_request.json | 5 + .../src/test/resources/list_parts_response.json | 26 ++ .../list_unfinished_large_files_request.json | 5 + .../list_unfinished_large_files_response.json | 16 ++ .../resources/start_large_file_request.json | 8 + .../resources/start_large_file_response.json | 11 + .../test/resources/upload_part_response.json | 6 + 23 files changed, 920 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/main/java/org/jclouds/b2/B2Api.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/main/java/org/jclouds/b2/B2Api.java b/providers/b2/src/main/java/org/jclouds/b2/B2Api.java index bbb6404..bd4ca28 100644 --- a/providers/b2/src/main/java/org/jclouds/b2/B2Api.java +++ b/providers/b2/src/main/java/org/jclouds/b2/B2Api.java @@ -20,6 +20,7 @@ import java.io.Closeable; import org.jclouds.b2.features.AuthorizationApi; import org.jclouds.b2.features.BucketApi; +import org.jclouds.b2.features.MultipartApi; import org.jclouds.b2.features.ObjectApi; import org.jclouds.rest.annotations.Delegate; @@ -33,4 +34,7 @@ public interface B2Api extends Closeable { @Delegate ObjectApi getObjectApi(); + + @Delegate + MultipartApi getMultipartApi(); } http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/main/java/org/jclouds/b2/binders/UploadPartBinder.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/main/java/org/jclouds/b2/binders/UploadPartBinder.java b/providers/b2/src/main/java/org/jclouds/b2/binders/UploadPartBinder.java new file mode 100644 index 0000000..0275412 --- /dev/null +++ b/providers/b2/src/main/java/org/jclouds/b2/binders/UploadPartBinder.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.b2.binders; + +import java.util.Map; + +import org.jclouds.http.HttpRequest; +import org.jclouds.b2.domain.GetUploadPartResponse; +import org.jclouds.rest.MapBinder; + +import com.google.common.net.HttpHeaders; + +public final class UploadPartBinder implements MapBinder { + @Override + public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) { + GetUploadPartResponse uploadUrl = (GetUploadPartResponse) postParams.get("response"); + return (R) request.toBuilder() + .endpoint(uploadUrl.uploadUrl()) + .replaceHeader(HttpHeaders.AUTHORIZATION, uploadUrl.authorizationToken()) + .build(); + } + + @Override + public <R extends HttpRequest> R bindToRequest(R request, Object input) { + throw new UnsupportedOperationException(); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/main/java/org/jclouds/b2/domain/GetUploadPartResponse.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/main/java/org/jclouds/b2/domain/GetUploadPartResponse.java b/providers/b2/src/main/java/org/jclouds/b2/domain/GetUploadPartResponse.java new file mode 100644 index 0000000..d6222cc --- /dev/null +++ b/providers/b2/src/main/java/org/jclouds/b2/domain/GetUploadPartResponse.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.b2.domain; + +import java.net.URI; + +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class GetUploadPartResponse { + public abstract String fileId(); + public abstract URI uploadUrl(); + public abstract String authorizationToken(); + + @SerializedNames({"fileId", "uploadUrl", "authorizationToken"}) + public static GetUploadPartResponse create(String fileId, URI uploadUrl, String authorizationToken) { + return new AutoValue_GetUploadPartResponse(fileId, uploadUrl, authorizationToken); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/main/java/org/jclouds/b2/domain/ListPartsResponse.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/main/java/org/jclouds/b2/domain/ListPartsResponse.java b/providers/b2/src/main/java/org/jclouds/b2/domain/ListPartsResponse.java new file mode 100644 index 0000000..1ed9b41 --- /dev/null +++ b/providers/b2/src/main/java/org/jclouds/b2/domain/ListPartsResponse.java @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.b2.domain; + +import java.util.Date; +import java.util.List; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; + +@AutoValue +public abstract class ListPartsResponse { + @Nullable public abstract Integer nextPartNumber(); + public abstract List<Entry> parts(); + + @SerializedNames({"nextPartNumber", "parts"}) + public static ListPartsResponse create(@Nullable Integer nextPartNumber, List<Entry> parts) { + return new AutoValue_ListPartsResponse(nextPartNumber, ImmutableList.copyOf(parts)); + } + + @AutoValue + public abstract static class Entry { + public abstract long contentLength(); + public abstract String contentSha1(); + public abstract String fileId(); + public abstract int partNumber(); + public abstract Date uploadTimestamp(); + + @SerializedNames({"contentLength", "contentSha1", "fileId", "partNumber", "uploadTimestamp"}) + public static Entry create(long contentLength, String contentSha1, String fileId, int partNumber, long uploadTimestamp) { + return new AutoValue_ListPartsResponse_Entry(contentLength, contentSha1, fileId, partNumber, new Date(uploadTimestamp)); + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/main/java/org/jclouds/b2/domain/ListUnfinishedLargeFilesResponse.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/main/java/org/jclouds/b2/domain/ListUnfinishedLargeFilesResponse.java b/providers/b2/src/main/java/org/jclouds/b2/domain/ListUnfinishedLargeFilesResponse.java new file mode 100644 index 0000000..986fd63 --- /dev/null +++ b/providers/b2/src/main/java/org/jclouds/b2/domain/ListUnfinishedLargeFilesResponse.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.b2.domain; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +@AutoValue +public abstract class ListUnfinishedLargeFilesResponse { + @Nullable public abstract String nextFileId(); + public abstract List<Entry> files(); + + @SerializedNames({"nextFileId", "files"}) + public static ListUnfinishedLargeFilesResponse create(@Nullable String nextFileId, List<Entry> files) { + return new AutoValue_ListUnfinishedLargeFilesResponse(nextFileId, ImmutableList.copyOf(files)); + } + + @AutoValue + public abstract static class Entry { + public abstract String accountId(); + public abstract String bucketId(); + public abstract String contentType(); + public abstract String fileId(); + public abstract Map<String, String> fileInfo(); + public abstract String fileName(); + public abstract Date uploadTimestamp(); + + @SerializedNames({"accountId", "bucketId", "contentType", "fileId", "fileInfo", "fileName", "uploadTimestamp"}) + public static Entry create(String accountId, String bucketId, String contentType, String fileId, Map<String, String> fileInfo, String fileName, long uploadTimestamp) { + return new AutoValue_ListUnfinishedLargeFilesResponse_Entry(accountId, bucketId, contentType, fileId, ImmutableMap.copyOf(fileInfo), fileName, new Date(uploadTimestamp)); + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/main/java/org/jclouds/b2/domain/MultipartUploadResponse.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/main/java/org/jclouds/b2/domain/MultipartUploadResponse.java b/providers/b2/src/main/java/org/jclouds/b2/domain/MultipartUploadResponse.java new file mode 100644 index 0000000..bfd1dfe --- /dev/null +++ b/providers/b2/src/main/java/org/jclouds/b2/domain/MultipartUploadResponse.java @@ -0,0 +1,41 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.b2.domain; + +import java.util.Date; +import java.util.Map; + +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; +import com.google.common.collect.ImmutableMap; + +@AutoValue +public abstract class MultipartUploadResponse { + public abstract String accountId(); + public abstract String bucketId(); + public abstract String contentType(); + public abstract String fileId(); + public abstract Map<String, String> fileInfo(); + public abstract String fileName(); + public abstract Date uploadTimestamp(); + + @SerializedNames({"accountId", "bucketId", "contentType", "fileId", "fileInfo", "fileName", "uploadTimestamp"}) + public static MultipartUploadResponse create(String accountId, String bucketId, String contentType, String fileId, Map<String, String> fileInfo, String fileName, long uploadTimestamp) { + return new AutoValue_MultipartUploadResponse(accountId, bucketId, contentType, fileId, ImmutableMap.copyOf(fileInfo), fileName, new Date(uploadTimestamp)); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/main/java/org/jclouds/b2/domain/UploadPartResponse.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/main/java/org/jclouds/b2/domain/UploadPartResponse.java b/providers/b2/src/main/java/org/jclouds/b2/domain/UploadPartResponse.java new file mode 100644 index 0000000..1a8b3ad --- /dev/null +++ b/providers/b2/src/main/java/org/jclouds/b2/domain/UploadPartResponse.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.b2.domain; + +import org.jclouds.json.SerializedNames; + +import com.google.auto.value.AutoValue; + +@AutoValue +public abstract class UploadPartResponse { + public abstract long contentLength(); + public abstract String contentSha1(); + public abstract String fileId(); + public abstract int partNumber(); + + @SerializedNames({"contentLength", "contentSha1", "fileId", "partNumber"}) + public static UploadPartResponse create(long contentLength, String contentSha1, String fileId, int partNumber) { + return new AutoValue_UploadPartResponse(contentLength, contentSha1, fileId, partNumber); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/main/java/org/jclouds/b2/features/MultipartApi.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/main/java/org/jclouds/b2/features/MultipartApi.java b/providers/b2/src/main/java/org/jclouds/b2/features/MultipartApi.java new file mode 100644 index 0000000..5affc4e --- /dev/null +++ b/providers/b2/src/main/java/org/jclouds/b2/features/MultipartApi.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.b2.features; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +import static org.jclouds.blobstore.attr.BlobScopes.CONTAINER; + +import java.util.Collection; +import java.util.Map; + +import javax.inject.Named; +import javax.ws.rs.Consumes; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; + +import org.jclouds.blobstore.attr.BlobScope; +import org.jclouds.io.Payload; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.b2.binders.UploadPartBinder; +import org.jclouds.b2.domain.B2Object; +import org.jclouds.b2.domain.GetUploadPartResponse; +import org.jclouds.b2.domain.ListPartsResponse; +import org.jclouds.b2.domain.ListUnfinishedLargeFilesResponse; +import org.jclouds.b2.domain.MultipartUploadResponse; +import org.jclouds.b2.domain.UploadPartResponse; +import org.jclouds.b2.filters.RequestAuthorization; +import org.jclouds.rest.annotations.MapBinder; +import org.jclouds.rest.annotations.PayloadParam; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.binders.BindToJsonPayload; + +@BlobScope(CONTAINER) +@Consumes(APPLICATION_JSON) +public interface MultipartApi { + @Named("b2_start_large_file") + @POST + @Path("/b2api/v1/b2_start_large_file") + @RequestFilters(RequestAuthorization.class) + @MapBinder(BindToJsonPayload.class) + @Produces(APPLICATION_JSON) + MultipartUploadResponse startLargeFile(@PayloadParam("bucketId") String bucketId, @PayloadParam("fileName") String fileName, @PayloadParam("contentType") String contentType, @PayloadParam("fileInfo") Map<String, String> fileInfo); + + @Named("b2_cancel_large_file") + @POST + @Path("/b2api/v1/b2_cancel_large_file") + @RequestFilters(RequestAuthorization.class) + @MapBinder(BindToJsonPayload.class) + @Produces(APPLICATION_JSON) + B2Object cancelLargeFile(@PayloadParam("fileId") String fileId); + + @Named("b2_finish_large_file") + @POST + @Path("/b2api/v1/b2_finish_large_file") + @RequestFilters(RequestAuthorization.class) + @MapBinder(BindToJsonPayload.class) + @Produces(APPLICATION_JSON) + B2Object finishLargeFile(@PayloadParam("fileId") String fileId, @PayloadParam("partSha1Array") Collection<String> contentSha1List); + + @Named("b2_get_upload_part_url") + @POST + @Path("/b2api/v1/b2_get_upload_part_url") + @RequestFilters(RequestAuthorization.class) + @MapBinder(BindToJsonPayload.class) + @Produces(APPLICATION_JSON) + GetUploadPartResponse getUploadPartUrl(@PayloadParam("fileId") String fileId); + + @Named("b2_upload_part") + @POST + @MapBinder(UploadPartBinder.class) + UploadPartResponse uploadPart(@PayloadParam("response") GetUploadPartResponse response, @HeaderParam("X-Bz-Part-Number") int partNumber, @HeaderParam("X-Bz-Content-Sha1") String sha1, @PayloadParam("payload") Payload payload); + + @Named("b2_list_parts") + @POST + @Path("/b2api/v1/b2_list_parts") + @RequestFilters(RequestAuthorization.class) + @MapBinder(BindToJsonPayload.class) + @Produces(APPLICATION_JSON) + ListPartsResponse listParts(@PayloadParam("fileId") String fileId, @PayloadParam("startPartNumber") @Nullable Integer startPartNumber, @PayloadParam("maxPartCount") @Nullable Integer maxPartCount); + + @Named("b2_list_unfinished_large_files") + @POST + @Path("/b2api/v1/b2_list_unfinished_large_files") + @RequestFilters(RequestAuthorization.class) + @MapBinder(BindToJsonPayload.class) + @Produces(APPLICATION_JSON) + ListUnfinishedLargeFilesResponse listUnfinishedLargeFiles(@PayloadParam("bucketId") String bucketId, @PayloadParam("startFileId") @Nullable String startFileId, @PayloadParam("maxFileCount") @Nullable Integer maxFileCount); +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/java/org/jclouds/b2/features/MultipartApiLiveTest.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/java/org/jclouds/b2/features/MultipartApiLiveTest.java b/providers/b2/src/test/java/org/jclouds/b2/features/MultipartApiLiveTest.java new file mode 100644 index 0000000..332eee3 --- /dev/null +++ b/providers/b2/src/test/java/org/jclouds/b2/features/MultipartApiLiveTest.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.b2.features; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; +import java.util.Random; + +import org.jclouds.io.Payload; +import org.jclouds.io.Payloads; +import org.jclouds.b2.domain.Action; +import org.jclouds.b2.domain.B2Object; +import org.jclouds.b2.domain.Bucket; +import org.jclouds.b2.domain.BucketType; +import org.jclouds.b2.domain.GetUploadPartResponse; +import org.jclouds.b2.domain.ListPartsResponse; +import org.jclouds.b2.domain.ListUnfinishedLargeFilesResponse; +import org.jclouds.b2.domain.MultipartUploadResponse; +import org.jclouds.b2.internal.BaseB2ApiLiveTest; +import org.jclouds.utils.TestUtils; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.hash.Hashing; +import com.google.common.io.ByteSource; + +public final class MultipartApiLiveTest extends BaseB2ApiLiveTest { + private static final Random random = new Random(); + + @Test(groups = "live") + public void testCancelMultipart() throws Exception { + BucketApi bucketApi = api.getBucketApi(); + MultipartApi multipartApi = api.getMultipartApi(); + + String fileName = "file-name"; + String contentType = "text/plain"; + Map<String, String> fileInfo = ImmutableMap.of("author", "unknown"); + + Bucket bucket = bucketApi.createBucket(getBucketName(), BucketType.ALL_PRIVATE); + try { + MultipartUploadResponse response = multipartApi.startLargeFile(bucket.bucketId(), fileName, contentType, fileInfo); + multipartApi.cancelLargeFile(response.fileId()); + } finally { + bucketApi.deleteBucket(bucket.bucketId()); + } + } + + @Test(groups = "live") + public void testFinishMultipart() throws Exception { + BucketApi bucketApi = api.getBucketApi(); + ObjectApi objectApi = api.getObjectApi(); + MultipartApi multipartApi = api.getMultipartApi(); + + String fileName = "file-name"; + String contentType = "text/plain"; + Map<String, String> fileInfo = ImmutableMap.of("author", "unknown"); + + Bucket bucket = bucketApi.createBucket(getBucketName(), BucketType.ALL_PRIVATE); + MultipartUploadResponse response = null; + B2Object b2Object = null; + try { + response = multipartApi.startLargeFile(bucket.bucketId(), fileName, contentType, fileInfo); + + ByteSource part1 = TestUtils.randomByteSource().slice(0, 100 * 1024 * 1024); + String hash1 = part1.hash(Hashing.sha1()).toString(); + Payload payload1 = Payloads.newByteSourcePayload(part1); + payload1.getContentMetadata().setContentLength(part1.size()); + GetUploadPartResponse uploadUrl = multipartApi.getUploadPartUrl(response.fileId()); + multipartApi.uploadPart(uploadUrl, 1, hash1, payload1); + + ByteSource part2 = TestUtils.randomByteSource().slice(0, 1); + String hash2 = part2.hash(Hashing.sha1()).toString(); + Payload payload2 = Payloads.newByteSourcePayload(part2); + payload2.getContentMetadata().setContentLength(part2.size()); + uploadUrl = multipartApi.getUploadPartUrl(response.fileId()); + multipartApi.uploadPart(uploadUrl, 2, hash2, payload2); + + b2Object = multipartApi.finishLargeFile(response.fileId(), ImmutableList.of(hash1, hash2)); + response = null; + + assertThat(b2Object.fileName()).isEqualTo(fileName); + assertThat(b2Object.fileInfo()).isEqualTo(fileInfo); + assertThat(b2Object.uploadTimestamp()).isAfterYear(2015); + assertThat(b2Object.action()).isEqualTo(Action.UPLOAD); + assertThat(b2Object.bucketId()).isEqualTo(bucket.bucketId()); + assertThat(b2Object.contentLength()).isEqualTo(100 * 1024 * 1024 + 1); + assertThat(b2Object.contentType()).isEqualTo(contentType); + } finally { + if (b2Object != null) { + objectApi.deleteFileVersion(fileName, b2Object.fileId()); + } + if (response != null) { + multipartApi.cancelLargeFile(response.fileId()); + } + bucketApi.deleteBucket(bucket.bucketId()); + } + } + + @Test(groups = "live") + public void testListParts() throws Exception { + BucketApi bucketApi = api.getBucketApi(); + ObjectApi objectApi = api.getObjectApi(); + MultipartApi multipartApi = api.getMultipartApi(); + + String fileName = "file-name"; + String contentType = "text/plain"; + Map<String, String> fileInfo = ImmutableMap.of("author", "unknown"); + + Bucket bucket = bucketApi.createBucket(getBucketName(), BucketType.ALL_PRIVATE); + MultipartUploadResponse response = null; + B2Object b2Object = null; + try { + response = multipartApi.startLargeFile(bucket.bucketId(), fileName, contentType, fileInfo); + + ListPartsResponse listParts = multipartApi.listParts(response.fileId(), 1, 1000); + assertThat(listParts.parts()).hasSize(0); + + long contentLength = 1024 * 1024; + ByteSource part = TestUtils.randomByteSource().slice(0, contentLength); + String hash = part.hash(Hashing.sha1()).toString(); + Payload payload = Payloads.newByteSourcePayload(part); + payload.getContentMetadata().setContentLength(contentLength); + GetUploadPartResponse uploadUrl = multipartApi.getUploadPartUrl(response.fileId()); + multipartApi.uploadPart(uploadUrl, 1, hash, payload); + + listParts = multipartApi.listParts(response.fileId(), 1, 1000); + assertThat(listParts.parts()).hasSize(1); + + ListPartsResponse.Entry entry = listParts.parts().get(0); + assertThat(entry.contentLength()).isEqualTo(contentLength); + assertThat(entry.contentSha1()).isEqualTo(hash); + assertThat(entry.partNumber()).isEqualTo(1); + } finally { + if (response != null) { + multipartApi.cancelLargeFile(response.fileId()); + } + bucketApi.deleteBucket(bucket.bucketId()); + } + } + + @Test(groups = "live") + public void testListUnfinishedLargeFiles() throws Exception { + BucketApi bucketApi = api.getBucketApi(); + ObjectApi objectApi = api.getObjectApi(); + MultipartApi multipartApi = api.getMultipartApi(); + + String fileName = "file-name"; + String contentType = "text/plain"; + Map<String, String> fileInfo = ImmutableMap.of("author", "unknown"); + + Bucket bucket = bucketApi.createBucket(getBucketName(), BucketType.ALL_PRIVATE); + MultipartUploadResponse response = null; + B2Object b2Object = null; + try { + ListUnfinishedLargeFilesResponse unfinishedLargeFiles = multipartApi.listUnfinishedLargeFiles(bucket.bucketId(), null, null); + assertThat(unfinishedLargeFiles.files()).hasSize(0); + + response = multipartApi.startLargeFile(bucket.bucketId(), fileName, contentType, fileInfo); + + unfinishedLargeFiles = multipartApi.listUnfinishedLargeFiles(bucket.bucketId(), null, null); + assertThat(unfinishedLargeFiles.files()).hasSize(1); + + ListUnfinishedLargeFilesResponse.Entry entry = unfinishedLargeFiles.files().get(0); + assertThat(entry.contentType()).isEqualTo(contentType); + assertThat(entry.fileInfo()).isEqualTo(fileInfo); + assertThat(entry.fileName()).isEqualTo(fileName); + } finally { + if (response != null) { + multipartApi.cancelLargeFile(response.fileId()); + } + bucketApi.deleteBucket(bucket.bucketId()); + } + } + + private static String getBucketName() { + return "jcloudstestbucket-" + random.nextInt(Integer.MAX_VALUE); + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/java/org/jclouds/b2/features/MultipartApiMockTest.java ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/java/org/jclouds/b2/features/MultipartApiMockTest.java b/providers/b2/src/test/java/org/jclouds/b2/features/MultipartApiMockTest.java new file mode 100644 index 0000000..7220b88 --- /dev/null +++ b/providers/b2/src/test/java/org/jclouds/b2/features/MultipartApiMockTest.java @@ -0,0 +1,246 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jclouds.b2.features; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.jclouds.b2.features.B2TestUtils.api; +import static org.jclouds.b2.features.B2TestUtils.assertAuthentication; +import static org.jclouds.b2.features.B2TestUtils.assertRequest; +import static org.jclouds.b2.features.B2TestUtils.createMockWebServer; +import static org.jclouds.b2.features.B2TestUtils.stringFromResource; + +import java.net.URI; +import java.util.Collection; +import java.util.Date; +import java.util.Map; + +import org.jclouds.io.Payload; +import org.jclouds.io.Payloads; +import org.jclouds.b2.domain.Action; +import org.jclouds.b2.domain.B2Object; +import org.jclouds.b2.domain.GetUploadPartResponse; +import org.jclouds.b2.domain.ListPartsResponse; +import org.jclouds.b2.domain.ListUnfinishedLargeFilesResponse; +import org.jclouds.b2.domain.MultipartUploadResponse; +import org.jclouds.b2.domain.UploadPartResponse; +import org.jclouds.utils.TestUtils; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; + +@Test(groups = "unit", testName = "MultipartApiMockTest") +public final class MultipartApiMockTest { + private static final String ACCOUNT_ID = "YOUR_ACCOUNT_ID"; + private static final String AUTHORIZATION_TOKEN = "3_20160409004829_42b8f80ba60fb4323dcaad98_ec81302316fccc2260201cbf17813247f312cf3b_000_uplg"; + private static final String BUCKET_NAME = "BUCKET_NAME"; + private static final String BUCKET_ID = "e73ede9c9c8412db49f60715"; + private static final String CONTENT_TYPE = "b2/x-auto"; + private static final String FILE_ID = "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028"; + private static final Map<String, String> FILE_INFO = ImmutableMap.of("author", "unknown"); + private static final String FILE_NAME = "bigfile.dat"; + private static final String SHA1 = "062685a84ab248d2488f02f6b01b948de2514ad8"; + private static final Date UPLOAD_TIMESTAMP = new Date(1460162909000L); + + public void testStartLargeFile() throws Exception { + MockWebServer server = createMockWebServer(); + server.enqueue(new MockResponse().setBody(stringFromResource("/authorize_account_response.json"))); + server.enqueue(new MockResponse().setBody(stringFromResource("/start_large_file_response.json"))); + + try { + MultipartApi api = api(server.getUrl("/").toString(), "b2").getMultipartApi(); + MultipartUploadResponse response = api.startLargeFile(BUCKET_ID, FILE_NAME, CONTENT_TYPE, FILE_INFO); + assertThat(response.accountId()).isEqualTo(ACCOUNT_ID); + assertThat(response.bucketId()).isEqualTo(BUCKET_ID); + assertThat(response.contentType()).isEqualTo(CONTENT_TYPE); + assertThat(response.fileId()).isEqualTo(FILE_ID); + assertThat(response.fileInfo()).isEqualTo(FILE_INFO); + assertThat(response.fileName()).isEqualTo(FILE_NAME); + assertThat(response.uploadTimestamp()).isEqualTo(UPLOAD_TIMESTAMP); + + assertThat(server.getRequestCount()).isEqualTo(2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "POST", "/b2api/v1/b2_start_large_file", "/start_large_file_request.json"); + } finally { + server.shutdown(); + } + } + + public void testCancelLargeFile() throws Exception { + MockWebServer server = createMockWebServer(); + server.enqueue(new MockResponse().setBody(stringFromResource("/authorize_account_response.json"))); + server.enqueue(new MockResponse().setBody(stringFromResource("/cancel_large_file_response.json"))); + + try { + MultipartApi api = api(server.getUrl("/").toString(), "b2").getMultipartApi(); + B2Object response = api.cancelLargeFile(FILE_ID); + assertThat(response.accountId()).isEqualTo(ACCOUNT_ID); + assertThat(response.bucketId()).isEqualTo(BUCKET_ID); + assertThat(response.fileId()).isEqualTo(FILE_ID); + assertThat(response.fileName()).isEqualTo(FILE_NAME); + + assertThat(server.getRequestCount()).isEqualTo(2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "POST", "/b2api/v1/b2_cancel_large_file", "/cancel_large_file_request.json"); + } finally { + server.shutdown(); + } + } + + public void testFinishLargeFile() throws Exception { + MockWebServer server = createMockWebServer(); + server.enqueue(new MockResponse().setBody(stringFromResource("/authorize_account_response.json"))); + server.enqueue(new MockResponse().setBody(stringFromResource("/finish_large_file_response.json"))); + Collection<String> sha1 = ImmutableList.of( + "0000000000000000000000000000000000000000", + "ffffffffffffffffffffffffffffffffffffffff"); + + try { + MultipartApi api = api(server.getUrl("/").toString(), "b2").getMultipartApi(); + B2Object response = api.finishLargeFile(FILE_ID, sha1); + assertThat(response.accountId()).isEqualTo(ACCOUNT_ID); + assertThat(response.action()).isEqualTo(Action.UPLOAD); + assertThat(response.bucketId()).isEqualTo(BUCKET_ID); + assertThat(response.contentLength()).isEqualTo(208158542); + assertThat(response.contentSha1()).isNull(); + assertThat(response.contentType()).isEqualTo(CONTENT_TYPE); + assertThat(response.fileId()).isEqualTo(FILE_ID); + assertThat(response.fileInfo()).isEqualTo(FILE_INFO); + assertThat(response.fileName()).isEqualTo(FILE_NAME); + assertThat(response.uploadTimestamp()).isEqualTo(UPLOAD_TIMESTAMP); + + assertThat(server.getRequestCount()).isEqualTo(2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "POST", "/b2api/v1/b2_finish_large_file", "/finish_large_file_request.json"); + } finally { + server.shutdown(); + } + } + + public void testGetUploadPartUrl() throws Exception { + MockWebServer server = createMockWebServer(); + server.enqueue(new MockResponse().setBody(stringFromResource("/authorize_account_response.json"))); + server.enqueue(new MockResponse().setBody(stringFromResource("/get_upload_part_url_response.json"))); + + try { + MultipartApi api = api(server.getUrl("/").toString(), "b2").getMultipartApi(); + GetUploadPartResponse response = api.getUploadPartUrl(FILE_ID); + assertThat(response.authorizationToken()).isEqualTo(AUTHORIZATION_TOKEN); + assertThat(response.fileId()).isEqualTo(FILE_ID); + assertThat(response.uploadUrl()).isEqualTo(URI.create("https://pod-000-1016-09.backblaze.com/b2api/v1/b2_upload_part/4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001/0037")); + + assertThat(server.getRequestCount()).isEqualTo(2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "POST", "/b2api/v1/b2_get_upload_part_url", "/get_upload_part_url_request.json"); + } finally { + server.shutdown(); + } + } + + public void testUploadPart() throws Exception { + MockWebServer server = createMockWebServer(); + server.enqueue(new MockResponse().setBody(stringFromResource("/upload_part_response.json"))); + + try { + MultipartApi api = api(server.getUrl("/").toString(), "b2").getMultipartApi(); + GetUploadPartResponse uploadPart = GetUploadPartResponse.create(FILE_ID, server.getUrl("/b2api/v1/b2_upload_part/4a48fe8875c6214145260818/c001_v0001007_t0042").toURI(), AUTHORIZATION_TOKEN); + long contentLength = 100 * 1000 * 1000; + Payload payload = Payloads.newByteSourcePayload(TestUtils.randomByteSource().slice(0, contentLength)); + payload.getContentMetadata().setContentLength(contentLength); + UploadPartResponse response = api.uploadPart(uploadPart, 1, SHA1, payload); + assertThat(response.contentLength()).isEqualTo(contentLength); + assertThat(response.contentSha1()).isEqualTo(SHA1); + assertThat(response.fileId()).isEqualTo(FILE_ID); + assertThat(response.partNumber()).isEqualTo(1); + + assertThat(server.getRequestCount()).isEqualTo(1); + assertRequest(server.takeRequest(), "POST", "/b2api/v1/b2_upload_part/4a48fe8875c6214145260818/c001_v0001007_t0042"); + } finally { + server.shutdown(); + } + } + + public void testListParts() throws Exception { + MockWebServer server = createMockWebServer(); + server.enqueue(new MockResponse().setBody(stringFromResource("/authorize_account_response.json"))); + server.enqueue(new MockResponse().setBody(stringFromResource("/list_parts_response.json"))); + + try { + MultipartApi api = api(server.getUrl("/").toString(), "b2").getMultipartApi(); + ListPartsResponse response = api.listParts(FILE_ID, 1, 1000); + assertThat(response.nextPartNumber()).isNull(); + assertThat(response.parts()).hasSize(3); + + ListPartsResponse.Entry entry = response.parts().get(0); + assertThat(entry.contentLength()).isEqualTo(100000000); + assertThat(entry.contentSha1()).isEqualTo("062685a84ab248d2488f02f6b01b948de2514ad8"); + assertThat(entry.fileId()).isEqualTo("4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001"); + assertThat(entry.partNumber()).isEqualTo(1); + assertThat(entry.uploadTimestamp()).isEqualTo(new Date(1462212185000L)); + + entry = response.parts().get(1); + assertThat(entry.contentLength()).isEqualTo(100000000); + assertThat(entry.contentSha1()).isEqualTo("cf634751c3d9f6a15344f23cbf13f3fc9542addf"); + assertThat(entry.fileId()).isEqualTo("4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001"); + assertThat(entry.partNumber()).isEqualTo(2); + assertThat(entry.uploadTimestamp()).isEqualTo(new Date(1462212296000L)); + + entry = response.parts().get(2); + assertThat(entry.contentLength()).isEqualTo(8158554); + assertThat(entry.contentSha1()).isEqualTo("00ad164147cbbd60aedb2b04ff66b0f74f962753"); + assertThat(entry.fileId()).isEqualTo("4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001"); + assertThat(entry.partNumber()).isEqualTo(3); + assertThat(entry.uploadTimestamp()).isEqualTo(new Date(1462212327000L)); + + assertThat(server.getRequestCount()).isEqualTo(2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "POST", "/b2api/v1/b2_list_parts", "/list_parts_request.json"); + } finally { + server.shutdown(); + } + } + + public void testListUnfinishedLargeFiles() throws Exception { + MockWebServer server = createMockWebServer(); + server.enqueue(new MockResponse().setBody(stringFromResource("/authorize_account_response.json"))); + server.enqueue(new MockResponse().setBody(stringFromResource("/list_unfinished_large_files_response.json"))); + + try { + MultipartApi api = api(server.getUrl("/").toString(), "b2").getMultipartApi(); + ListUnfinishedLargeFilesResponse response = api.listUnfinishedLargeFiles(BUCKET_ID, FILE_ID, 1000); + assertThat(response.nextFileId()).isNull(); + assertThat(response.files()).hasSize(1); + + ListUnfinishedLargeFilesResponse.Entry entry = response.files().get(0); + assertThat(entry.accountId()).isEqualTo(ACCOUNT_ID); + assertThat(entry.bucketId()).isEqualTo(BUCKET_ID); + assertThat(entry.contentType()).isEqualTo("application/octet-stream"); + assertThat(entry.fileId()).isEqualTo("4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001"); + assertThat(entry.fileInfo()).isEqualTo(FILE_INFO); + assertThat(entry.fileName()).isEqualTo(FILE_NAME); + assertThat(entry.uploadTimestamp()).isEqualTo(new Date(1462212184000L)); + + assertThat(server.getRequestCount()).isEqualTo(2); + assertAuthentication(server); + assertRequest(server.takeRequest(), "POST", "/b2api/v1/b2_list_unfinished_large_files", "/list_unfinished_large_files_request.json"); + } finally { + server.shutdown(); + } + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/cancel_large_file_request.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/cancel_large_file_request.json b/providers/b2/src/test/resources/cancel_large_file_request.json new file mode 100644 index 0000000..7dd68bd --- /dev/null +++ b/providers/b2/src/test/resources/cancel_large_file_request.json @@ -0,0 +1,3 @@ +{ + "fileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028" +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/cancel_large_file_response.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/cancel_large_file_response.json b/providers/b2/src/test/resources/cancel_large_file_response.json new file mode 100644 index 0000000..84c6c0e --- /dev/null +++ b/providers/b2/src/test/resources/cancel_large_file_response.json @@ -0,0 +1,6 @@ +{ + "accountId": "YOUR_ACCOUNT_ID", + "bucketId": "e73ede9c9c8412db49f60715", + "fileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028", + "fileName": "bigfile.dat" +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/finish_large_file_request.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/finish_large_file_request.json b/providers/b2/src/test/resources/finish_large_file_request.json new file mode 100644 index 0000000..8cef10a --- /dev/null +++ b/providers/b2/src/test/resources/finish_large_file_request.json @@ -0,0 +1,7 @@ +{ + "partSha1Array": [ + "0000000000000000000000000000000000000000", + "ffffffffffffffffffffffffffffffffffffffff" + ], + "fileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028" +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/finish_large_file_response.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/finish_large_file_response.json b/providers/b2/src/test/resources/finish_large_file_response.json new file mode 100644 index 0000000..b663239 --- /dev/null +++ b/providers/b2/src/test/resources/finish_large_file_response.json @@ -0,0 +1,14 @@ +{ + "accountId": "YOUR_ACCOUNT_ID", + "action": "upload", + "bucketId": "e73ede9c9c8412db49f60715", + "contentLength": 208158542, + "contentSha1": "none", + "contentType": "b2/x-auto", + "fileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028", + "fileInfo": { + "author": "unknown" + }, + "fileName": "bigfile.dat", + "uploadTimestamp": 1460162909000 +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/get_upload_part_url_request.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/get_upload_part_url_request.json b/providers/b2/src/test/resources/get_upload_part_url_request.json new file mode 100644 index 0000000..7dd68bd --- /dev/null +++ b/providers/b2/src/test/resources/get_upload_part_url_request.json @@ -0,0 +1,3 @@ +{ + "fileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028" +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/get_upload_part_url_response.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/get_upload_part_url_response.json b/providers/b2/src/test/resources/get_upload_part_url_response.json new file mode 100644 index 0000000..7ebf04e --- /dev/null +++ b/providers/b2/src/test/resources/get_upload_part_url_response.json @@ -0,0 +1,5 @@ +{ + "authorizationToken": "3_20160409004829_42b8f80ba60fb4323dcaad98_ec81302316fccc2260201cbf17813247f312cf3b_000_uplg", + "fileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028", + "uploadUrl": "https://pod-000-1016-09.backblaze.com/b2api/v1/b2_upload_part/4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001/0037" +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/list_parts_request.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/list_parts_request.json b/providers/b2/src/test/resources/list_parts_request.json new file mode 100644 index 0000000..f998faa --- /dev/null +++ b/providers/b2/src/test/resources/list_parts_request.json @@ -0,0 +1,5 @@ +{ + "fileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028", + "startPartNumber": 1, + "maxPartCount": 1000 +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/list_parts_response.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/list_parts_response.json b/providers/b2/src/test/resources/list_parts_response.json new file mode 100644 index 0000000..6b4ccab --- /dev/null +++ b/providers/b2/src/test/resources/list_parts_response.json @@ -0,0 +1,26 @@ +{ + "nextPartNumber": null, + "parts": [ + { + "contentLength": 100000000, + "contentSha1": "062685a84ab248d2488f02f6b01b948de2514ad8", + "fileId": "4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001", + "partNumber": 1, + "uploadTimestamp": 1462212185000 + }, + { + "contentLength": 100000000, + "contentSha1": "cf634751c3d9f6a15344f23cbf13f3fc9542addf", + "fileId": "4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001", + "partNumber": 2, + "uploadTimestamp": 1462212296000 + }, + { + "contentLength": 8158554, + "contentSha1": "00ad164147cbbd60aedb2b04ff66b0f74f962753", + "fileId": "4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001", + "partNumber": 3, + "uploadTimestamp": 1462212327000 + } + ] +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/list_unfinished_large_files_request.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/list_unfinished_large_files_request.json b/providers/b2/src/test/resources/list_unfinished_large_files_request.json new file mode 100644 index 0000000..e86d2a9 --- /dev/null +++ b/providers/b2/src/test/resources/list_unfinished_large_files_request.json @@ -0,0 +1,5 @@ +{ + "bucketId": "e73ede9c9c8412db49f60715", + "startFileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028", + "maxFileCount": 1000 +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/list_unfinished_large_files_response.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/list_unfinished_large_files_response.json b/providers/b2/src/test/resources/list_unfinished_large_files_response.json new file mode 100644 index 0000000..753c589 --- /dev/null +++ b/providers/b2/src/test/resources/list_unfinished_large_files_response.json @@ -0,0 +1,16 @@ +{ + "files": [ + { + "accountId": "YOUR_ACCOUNT_ID", + "bucketId": "e73ede9c9c8412db49f60715", + "contentType": "application/octet-stream", + "fileId": "4_ze73ede9c9c8412db49f60715_f100b4e93fbae6252_d20150824_m224353_c900_v8881000_t0001", + "fileInfo": { + "author": "unknown" + }, + "fileName": "bigfile.dat", + "uploadTimestamp": 1462212184000 + } + ], + "nextFileId": null +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/start_large_file_request.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/start_large_file_request.json b/providers/b2/src/test/resources/start_large_file_request.json new file mode 100644 index 0000000..3b4e90f --- /dev/null +++ b/providers/b2/src/test/resources/start_large_file_request.json @@ -0,0 +1,8 @@ +{ + "fileName": "bigfile.dat", + "bucketId": "e73ede9c9c8412db49f60715", + "contentType": "b2/x-auto", + "fileInfo": { + "author": "unknown" + } +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/start_large_file_response.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/start_large_file_response.json b/providers/b2/src/test/resources/start_large_file_response.json new file mode 100644 index 0000000..01838b4 --- /dev/null +++ b/providers/b2/src/test/resources/start_large_file_response.json @@ -0,0 +1,11 @@ +{ + "accountId": "YOUR_ACCOUNT_ID", + "bucketId": "e73ede9c9c8412db49f60715", + "contentType": "b2/x-auto", + "fileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028", + "fileInfo": { + "author": "unknown" + }, + "fileName": "bigfile.dat", + "uploadTimestamp": 1460162909000 +} http://git-wip-us.apache.org/repos/asf/jclouds/blob/3d84d3cb/providers/b2/src/test/resources/upload_part_response.json ---------------------------------------------------------------------- diff --git a/providers/b2/src/test/resources/upload_part_response.json b/providers/b2/src/test/resources/upload_part_response.json new file mode 100644 index 0000000..fb99aa4 --- /dev/null +++ b/providers/b2/src/test/resources/upload_part_response.json @@ -0,0 +1,6 @@ +{ + "contentLength": 100000000, + "contentSha1": "062685a84ab248d2488f02f6b01b948de2514ad8", + "fileId": "4_za71f544e781e6891531b001a_f200ec353a2184825_d20160409_m004829_c000_v0001016_t0028", + "partNumber": 1 +}
