diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/spi/DefaultStorageRpc.java b/gcloud-java-storage/src/main/java/com/google/gcloud/spi/DefaultStorageRpc.java index 70cad8c7773e..b1e188f1d1fb 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/spi/DefaultStorageRpc.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/spi/DefaultStorageRpc.java @@ -15,6 +15,7 @@ package com.google.gcloud.spi; import static com.google.gcloud.spi.StorageRpc.Option.DELIMITER; +import static com.google.gcloud.spi.StorageRpc.Option.FIELDS; import static com.google.gcloud.spi.StorageRpc.Option.IF_GENERATION_MATCH; import static com.google.gcloud.spi.StorageRpc.Option.IF_GENERATION_NOT_MATCH; import static com.google.gcloud.spi.StorageRpc.Option.IF_METAGENERATION_MATCH; @@ -150,6 +151,7 @@ public Tuple> list(Map options) { .setPrefix(PREFIX.getString(options)) .setMaxResults(MAX_RESULTS.getLong(options)) .setPageToken(PAGE_TOKEN.getString(options)) + .setFields(FIELDS.getString(options)) .execute(); return Tuple.>of(buckets.getNextPageToken(), buckets.getItems()); } catch (IOException ex) { @@ -168,6 +170,7 @@ public Tuple> list(String bucket, Map .setPrefix(PREFIX.getString(options)) .setMaxResults(MAX_RESULTS.getLong(options)) .setPageToken(PAGE_TOKEN.getString(options)) + .setFields(FIELDS.getString(options)) .execute(); return Tuple.>of( objects.getNextPageToken(), objects.getItems()); @@ -184,6 +187,7 @@ public Bucket get(Bucket bucket, Map options) { .setProjection(DEFAULT_PROJECTION) .setIfMetagenerationMatch(IF_METAGENERATION_MATCH.getLong(options)) .setIfMetagenerationNotMatch(IF_METAGENERATION_NOT_MATCH.getLong(options)) + .setFields(FIELDS.getString(options)) .execute(); } catch (IOException ex) { throw translate(ex); @@ -207,7 +211,8 @@ private Storage.Objects.Get getRequest(StorageObject object, Map opti .setIfMetagenerationMatch(IF_METAGENERATION_MATCH.getLong(options)) .setIfMetagenerationNotMatch(IF_METAGENERATION_NOT_MATCH.getLong(options)) .setIfGenerationMatch(IF_GENERATION_MATCH.getLong(options)) - .setIfGenerationNotMatch(IF_GENERATION_NOT_MATCH.getLong(options)); + .setIfGenerationNotMatch(IF_GENERATION_NOT_MATCH.getLong(options)) + .setFields(FIELDS.getString(options)); } @Override diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/spi/StorageRpc.java b/gcloud-java-storage/src/main/java/com/google/gcloud/spi/StorageRpc.java index 40382a857fca..e4b1be785951 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/spi/StorageRpc.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/spi/StorageRpc.java @@ -47,7 +47,8 @@ enum Option { MAX_RESULTS("maxResults"), PAGE_TOKEN("pageToken"), DELIMITER("delimiter"), - VERSIONS("versions"); + VERSIONS("versions"), + FIELDS("fields"); private final String value; diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/BatchRequest.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/BatchRequest.java index 6e815648497a..bf77c731754e 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/BatchRequest.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/BatchRequest.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; +import com.google.gcloud.storage.Storage.BlobGetOption; import com.google.gcloud.storage.Storage.BlobSourceOption; import com.google.gcloud.storage.Storage.BlobTargetOption; @@ -35,13 +36,13 @@ public final class BatchRequest implements Serializable { private final Map> toDelete; private final Map> toUpdate; - private final Map> toGet; + private final Map> toGet; public static class Builder { private Map> toDelete = new LinkedHashMap<>(); private Map> toUpdate = new LinkedHashMap<>(); - private Map> toGet = new LinkedHashMap<>(); + private Map> toGet = new LinkedHashMap<>(); private Builder() {} @@ -72,7 +73,7 @@ public Builder update(BlobInfo blobInfo, BlobTargetOption... options) { /** * Retrieve metadata for the given blob. */ - public Builder get(String bucket, String blob, BlobSourceOption... options) { + public Builder get(String bucket, String blob, BlobGetOption... options) { toGet.put(BlobId.of(bucket, blob), Lists.newArrayList(options)); return this; } @@ -80,7 +81,7 @@ public Builder get(String bucket, String blob, BlobSourceOption... options) { /** * Retrieve metadata for the given blob. */ - public Builder get(BlobId blob, BlobSourceOption... options) { + public Builder get(BlobId blob, BlobGetOption... options) { toGet.put(blob, Lists.newArrayList(options)); return this; } @@ -120,7 +121,7 @@ public Map> toUpdate() { return toUpdate; } - public Map> toGet() { + public Map> toGet() { return toGet; } diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java index 8f988922aad9..d35fcef026c8 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java @@ -18,7 +18,8 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.gcloud.storage.Blob.BlobSourceOption.convert; +import static com.google.gcloud.storage.Blob.BlobSourceOption.toSourceOptions; +import static com.google.gcloud.storage.Blob.BlobSourceOption.toGetOptions; import com.google.common.base.Function; import com.google.common.collect.Lists; @@ -29,6 +30,7 @@ import com.google.gcloud.storage.Storage.SignUrlOption; import java.net.URL; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -56,7 +58,7 @@ private BlobSourceOption(StorageRpc.Option rpcOption) { super(rpcOption, null); } - private Storage.BlobSourceOption convert(BlobInfo blobInfo) { + private Storage.BlobSourceOption toSourceOptions(BlobInfo blobInfo) { switch (rpcOption()) { case IF_GENERATION_MATCH: return Storage.BlobSourceOption.generationMatch(blobInfo.generation()); @@ -71,6 +73,21 @@ private Storage.BlobSourceOption convert(BlobInfo blobInfo) { } } + private Storage.BlobGetOption toGetOption(BlobInfo blobInfo) { + switch (rpcOption()) { + case IF_GENERATION_MATCH: + return Storage.BlobGetOption.generationMatch(blobInfo.generation()); + case IF_GENERATION_NOT_MATCH: + return Storage.BlobGetOption.generationNotMatch(blobInfo.generation()); + case IF_METAGENERATION_MATCH: + return Storage.BlobGetOption.metagenerationMatch(blobInfo.metageneration()); + case IF_METAGENERATION_NOT_MATCH: + return Storage.BlobGetOption.metagenerationNotMatch(blobInfo.metageneration()); + default: + throw new AssertionError("Unexpected enum value"); + } + } + public static BlobSourceOption generationMatch() { return new BlobSourceOption(StorageRpc.Option.IF_GENERATION_MATCH); } @@ -87,11 +104,21 @@ public static BlobSourceOption metagenerationNotMatch() { return new BlobSourceOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH); } - static Storage.BlobSourceOption[] convert(BlobInfo blobInfo, BlobSourceOption... options) { + static Storage.BlobSourceOption[] toSourceOptions(BlobInfo blobInfo, + BlobSourceOption... options) { Storage.BlobSourceOption[] convertedOptions = new Storage.BlobSourceOption[options.length]; int index = 0; for (BlobSourceOption option : options) { - convertedOptions[index++] = option.convert(blobInfo); + convertedOptions[index++] = option.toSourceOptions(blobInfo); + } + return convertedOptions; + } + + static Storage.BlobGetOption[] toGetOptions(BlobInfo blobInfo, BlobSourceOption... options) { + Storage.BlobGetOption[] convertedOptions = new Storage.BlobGetOption[options.length]; + int index = 0; + for (BlobSourceOption option : options) { + convertedOptions[index++] = option.toGetOption(blobInfo); } return convertedOptions; } @@ -100,7 +127,7 @@ static Storage.BlobSourceOption[] convert(BlobInfo blobInfo, BlobSourceOption... /** * Constructs a {@code Blob} object for the provided {@code BlobInfo}. The storage service is used * to issue requests. - * + * * @param storage the storage service used for issuing requests * @param info blob's info */ @@ -112,7 +139,7 @@ public Blob(Storage storage, BlobInfo info) { /** * Creates a {@code Blob} object for the provided bucket and blob names. Performs an RPC call to * get the latest blob information. - * + * * @param storage the storage service used for issuing requests * @param bucket bucket's name * @param blob blob's name @@ -126,7 +153,7 @@ public static Blob load(Storage storage, String bucket, String blob) { /** * Creates a {@code Blob} object for the provided {@code blobId}. Performs an RPC call to get the * latest blob information. - * + * * @param storage the storage service used for issuing requests * @param blobId blob's identifier * @return the {@code Blob} object or {@code null} if not found. @@ -159,7 +186,10 @@ public BlobId id() { * @throws StorageException upon failure */ public boolean exists(BlobSourceOption... options) { - return storage.get(info.blobId(), convert(info, options)) != null; + int length = options.length; + Storage.BlobGetOption[] getOptions = Arrays.copyOf(toGetOptions(info, options), length + 1); + getOptions[length] = Storage.BlobGetOption.fields(); + return storage.get(info.blobId(), getOptions) != null; } /** @@ -180,7 +210,7 @@ public byte[] content(Storage.BlobSourceOption... options) { * @throws StorageException upon failure */ public Blob reload(BlobSourceOption... options) { - return new Blob(storage, storage.get(info.blobId(), convert(info, options))); + return new Blob(storage, storage.get(info.blobId(), toGetOptions(info, options))); } /** @@ -224,7 +254,7 @@ public Blob update(BlobInfo blobInfo, BlobTargetOption... options) { */ public CopyWriter copyTo(BlobId targetBlob, BlobSourceOption... options) { CopyRequest copyRequest = CopyRequest.builder().source(info.bucket(), info.name()) - .sourceOptions(convert(info, options)).target(targetBlob).build(); + .sourceOptions(toSourceOptions(info, options)).target(targetBlob).build(); return storage.copy(copyRequest); } @@ -236,7 +266,7 @@ public CopyWriter copyTo(BlobId targetBlob, BlobSourceOption... options) { * @throws StorageException upon failure */ public boolean delete(BlobSourceOption... options) { - return storage.delete(info.blobId(), convert(info, options)); + return storage.delete(info.blobId(), toSourceOptions(info, options)); } /** @@ -275,7 +305,7 @@ public CopyWriter copyTo(String targetBucket, String targetBlob, BlobSourceOptio * @throws StorageException upon failure */ public BlobReadChannel reader(BlobSourceOption... options) { - return storage.reader(info.blobId(), convert(info, options)); + return storage.reader(info.blobId(), toSourceOptions(info, options)); } /** diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Bucket.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Bucket.java index 1f696d07ac33..7c386373995f 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Bucket.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Bucket.java @@ -18,16 +18,18 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.gcloud.storage.Bucket.BucketSourceOption.toGetOptions; +import static com.google.gcloud.storage.Bucket.BucketSourceOption.toSourceOptions; import com.google.common.base.Function; import com.google.common.base.MoreObjects; import com.google.common.collect.Iterators; import com.google.gcloud.PageImpl; import com.google.gcloud.Page; -import com.google.gcloud.storage.Storage.BlobSourceOption; +import com.google.gcloud.spi.StorageRpc; +import com.google.gcloud.storage.Storage.BlobGetOption; import com.google.gcloud.storage.Storage.BlobTargetOption; import com.google.gcloud.storage.Storage.BlobWriteOption; -import com.google.gcloud.storage.Storage.BucketSourceOption; import com.google.gcloud.storage.Storage.BucketTargetOption; import java.io.IOException; @@ -35,6 +37,7 @@ import java.io.ObjectInputStream; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -119,6 +122,66 @@ public boolean equals(Object obj) { } } + public static class BucketSourceOption extends Option { + + private static final long serialVersionUID = 6928872234155522371L; + + private BucketSourceOption(StorageRpc.Option rpcOption) { + super(rpcOption, null); + } + + private Storage.BucketSourceOption toSourceOptions(BucketInfo bucketInfo) { + switch (rpcOption()) { + case IF_METAGENERATION_MATCH: + return Storage.BucketSourceOption.metagenerationMatch(bucketInfo.metageneration()); + case IF_METAGENERATION_NOT_MATCH: + return Storage.BucketSourceOption.metagenerationNotMatch(bucketInfo.metageneration()); + default: + throw new AssertionError("Unexpected enum value"); + } + } + + private Storage.BucketGetOption toGetOption(BucketInfo bucketInfo) { + switch (rpcOption()) { + case IF_METAGENERATION_MATCH: + return Storage.BucketGetOption.metagenerationMatch(bucketInfo.metageneration()); + case IF_METAGENERATION_NOT_MATCH: + return Storage.BucketGetOption.metagenerationNotMatch(bucketInfo.metageneration()); + default: + throw new AssertionError("Unexpected enum value"); + } + } + + public static BucketSourceOption metagenerationMatch() { + return new BucketSourceOption(StorageRpc.Option.IF_METAGENERATION_MATCH); + } + + public static BucketSourceOption metagenerationNotMatch() { + return new BucketSourceOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH); + } + + static Storage.BucketSourceOption[] toSourceOptions(BucketInfo bucketInfo, + BucketSourceOption... options) { + Storage.BucketSourceOption[] convertedOptions = + new Storage.BucketSourceOption[options.length]; + int index = 0; + for (BucketSourceOption option : options) { + convertedOptions[index++] = option.toSourceOptions(bucketInfo); + } + return convertedOptions; + } + + static Storage.BucketGetOption[] toGetOptions(BucketInfo bucketInfo, + BucketSourceOption... options) { + Storage.BucketGetOption[] convertedOptions = new Storage.BucketGetOption[options.length]; + int index = 0; + for (BucketSourceOption option : options) { + convertedOptions[index++] = option.toGetOption(bucketInfo); + } + return convertedOptions; + } + } + /** * Constructs a {@code Bucket} object for the provided {@code BucketInfo}. The storage service is * used to issue requests. @@ -158,8 +221,11 @@ public BucketInfo info() { * @return true if this bucket exists, false otherwise * @throws StorageException upon failure */ - public boolean exists() { - return storage.get(info.name()) != null; + public boolean exists(BucketSourceOption... options) { + int length = options.length; + Storage.BucketGetOption[] getOptions = Arrays.copyOf(toGetOptions(info, options), length + 1); + getOptions[length] = Storage.BucketGetOption.fields(); + return storage.get(info.name(), getOptions) != null; } /** @@ -170,7 +236,7 @@ public boolean exists() { * @throws StorageException upon failure */ public Bucket reload(BucketSourceOption... options) { - return new Bucket(storage, storage.get(info.name(), options)); + return new Bucket(storage, storage.get(info.name(), toGetOptions(info, options))); } /** @@ -198,7 +264,7 @@ public Bucket update(BucketInfo bucketInfo, BucketTargetOption... options) { * @throws StorageException upon failure */ public boolean delete(BucketSourceOption... options) { - return storage.delete(info.name(), options); + return storage.delete(info.name(), toSourceOptions(info, options)); } /** @@ -221,7 +287,7 @@ public Page list(Storage.BlobListOption... options) { * @param options blob search options * @throws StorageException upon failure */ - public Blob get(String blob, BlobSourceOption... options) { + public Blob get(String blob, BlobGetOption... options) { return new Blob(storage, storage.get(BlobId.of(info.name(), blob), options)); } diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java index 2fd4df0cc6ba..52387310de71 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java @@ -19,9 +19,11 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import com.google.gcloud.AuthCredentials.ServiceAccountAuthCredentials; import com.google.gcloud.Service; import com.google.gcloud.Page; @@ -33,6 +35,7 @@ import java.net.URL; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; @@ -70,6 +73,89 @@ String entry() { } } + enum BucketField { + ID("id"), + SELF_LINK("selfLink"), + NAME("name"), + TIME_CREATED("timeCreated"), + METAGENERATION("metageneration"), + ACL("acl"), + DEFAULT_OBJECT_ACL("defaultObjectAcl"), + OWNER("owner"), + LOCATION("location"), + WEBSITE("website"), + VERSIONING("versioning"), + CORS("cors"), + STORAGE_CLASS("storageClass"), + ETAG("etag"); + + private final String selector; + + BucketField(String selector) { + this.selector = selector; + } + + public String selector() { + return selector; + } + + static String selector(BucketField... fields) { + HashSet fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 1); + fieldStrings.add(NAME.selector()); + for (BucketField field : fields) { + fieldStrings.add(field.selector()); + } + return Joiner.on(',').join(fieldStrings); + } + } + + enum BlobField { + ACL("acl"), + BUCKET("bucket"), + CACHE_CONTROL("cacheControl"), + COMPONENT_COUNT("componentCount"), + CONTENT_DISPOSITION("contentDisposition"), + CONTENT_ENCODING("contentEncoding"), + CONTENT_LANGUAGE("contentLanguage"), + CONTENT_TYPE("contentType"), + CRC32C("crc32c"), + ETAG("etag"), + GENERATION("generation"), + ID("id"), + KIND("kind"), + MD5HASH("md5Hash"), + MEDIA_LINK("mediaLink"), + METADATA("metadata"), + METAGENERATION("metageneration"), + NAME("name"), + OWNER("owner"), + SELF_LINK("selfLink"), + SIZE("size"), + STORAGE_CLASS("storageClass"), + TIME_DELETED("timeDeleted"), + UPDATED("updated"); + + private final String selector; + + BlobField(String selector) { + this.selector = selector; + } + + public String selector() { + return selector; + } + + static String selector(BlobField... fields) { + HashSet fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 2); + fieldStrings.add(BUCKET.selector()); + fieldStrings.add(NAME.selector()); + for (BlobField field : fields) { + fieldStrings.add(field.selector()); + } + return Joiner.on(',').join(fieldStrings); + } + } + class BucketTargetOption extends Option { private static final long serialVersionUID = -5880204616982900975L; @@ -116,6 +202,37 @@ public static BucketSourceOption metagenerationNotMatch(long metageneration) { } } + class BucketGetOption extends Option { + + private static final long serialVersionUID = 1901844869484087395L; + + private BucketGetOption(StorageRpc.Option rpcOption, long metageneration) { + super(rpcOption, metageneration); + } + + private BucketGetOption(StorageRpc.Option rpcOption, String value) { + super(rpcOption, value); + } + + public static BucketGetOption metagenerationMatch(long metageneration) { + return new BucketGetOption(StorageRpc.Option.IF_METAGENERATION_MATCH, metageneration); + } + + public static BucketGetOption metagenerationNotMatch(long metageneration) { + return new BucketGetOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH, metageneration); + } + + /** + * Returns an option to specify the bucket's fields to be returned by the RPC call. If this + * option is not provided all bucket's fields are returned. {@code BucketGetOption.fields}) can + * be used to specify only the fields of interest. Bucket name is always returned, even if not + * specified. + */ + public static BucketGetOption fields(BucketField... fields) { + return new BucketGetOption(StorageRpc.Option.FIELDS, BucketField.selector(fields)); + } + } + class BlobTargetOption extends Option { private static final long serialVersionUID = 214616862061934846L; @@ -277,6 +394,45 @@ public static BlobSourceOption metagenerationNotMatch(long metageneration) { } } + class BlobGetOption extends Option { + + private static final long serialVersionUID = 803817709703661480L; + + private BlobGetOption(StorageRpc.Option rpcOption, long value) { + super(rpcOption, value); + } + + private BlobGetOption(StorageRpc.Option rpcOption, String value) { + super(rpcOption, value); + } + + public static BlobGetOption generationMatch(long generation) { + return new BlobGetOption(StorageRpc.Option.IF_GENERATION_MATCH, generation); + } + + public static BlobGetOption generationNotMatch(long generation) { + return new BlobGetOption(StorageRpc.Option.IF_GENERATION_NOT_MATCH, generation); + } + + public static BlobGetOption metagenerationMatch(long metageneration) { + return new BlobGetOption(StorageRpc.Option.IF_METAGENERATION_MATCH, metageneration); + } + + public static BlobGetOption metagenerationNotMatch(long metageneration) { + return new BlobGetOption(StorageRpc.Option.IF_METAGENERATION_NOT_MATCH, metageneration); + } + + /** + * Returns an option to specify the blob's fields to be returned by the RPC call. If this option + * is not provided all blob's fields are returned. {@code BlobGetOption.fields}) can be used to + * specify only the fields of interest. Blob name and bucket are always returned, even if not + * specified. + */ + public static BlobGetOption fields(BlobField... fields) { + return new BlobGetOption(StorageRpc.Option.FIELDS, BlobField.selector(fields)); + } + } + class BucketListOption extends Option { private static final long serialVersionUID = 8754017079673290353L; @@ -296,6 +452,18 @@ public static BucketListOption startPageToken(String pageToken) { public static BucketListOption prefix(String prefix) { return new BucketListOption(StorageRpc.Option.PREFIX, prefix); } + + /** + * Returns an option to specify the bucket's fields to be returned by the RPC call. If this + * option is not provided all bucket's fields are returned. {@code BucketListOption.fields}) can + * be used to specify only the fields of interest. Bucket name is always returned, even if not + * specified. + */ + public static BucketListOption fields(BucketField... fields) { + StringBuilder builder = new StringBuilder(); + builder.append("items(").append(BucketField.selector(fields)).append(")"); + return new BucketListOption(StorageRpc.Option.FIELDS, builder.toString()); + } } class BlobListOption extends Option { @@ -321,6 +489,18 @@ public static BlobListOption prefix(String prefix) { public static BlobListOption recursive(boolean recursive) { return new BlobListOption(StorageRpc.Option.DELIMITER, recursive); } + + /** + * Returns an option to specify the blob's fields to be returned by the RPC call. If this option + * is not provided all blob's fields are returned. {@code BlobListOption.fields}) can be used to + * specify only the fields of interest. Blob name and bucket are always returned, even if not + * specified. + */ + public static BlobListOption fields(BlobField... fields) { + StringBuilder builder = new StringBuilder(); + builder.append("items(").append(BlobField.selector(fields)).append(")"); + return new BlobListOption(StorageRpc.Option.FIELDS, builder.toString()); + } } class SignUrlOption implements Serializable { @@ -800,21 +980,21 @@ private static void checkContentType(BlobInfo blobInfo) throws IllegalArgumentEx * * @throws StorageException upon failure */ - BucketInfo get(String bucket, BucketSourceOption... options); + BucketInfo get(String bucket, BucketGetOption... options); /** * Return the requested blob or {@code null} if not found. * * @throws StorageException upon failure */ - BlobInfo get(String bucket, String blob, BlobSourceOption... options); + BlobInfo get(String bucket, String blob, BlobGetOption... options); /** * Return the requested blob or {@code null} if not found. * * @throws StorageException upon failure */ - BlobInfo get(BlobId blob, BlobSourceOption... options); + BlobInfo get(BlobId blob, BlobGetOption... options); /** * Return the requested blob or {@code null} if not found. diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java index d1e85368fecb..4c85113e940e 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageImpl.java @@ -167,7 +167,7 @@ public StorageObject call() { } @Override - public BucketInfo get(String bucket, BucketSourceOption... options) { + public BucketInfo get(String bucket, BucketGetOption... options) { final com.google.api.services.storage.model.Bucket bucketPb = BucketInfo.of(bucket).toPb(); final Map optionsMap = optionMap(options); try { @@ -192,12 +192,12 @@ public com.google.api.services.storage.model.Bucket call() { } @Override - public BlobInfo get(String bucket, String blob, BlobSourceOption... options) { + public BlobInfo get(String bucket, String blob, BlobGetOption... options) { return get(BlobId.of(bucket, blob), options); } @Override - public BlobInfo get(BlobId blob, BlobSourceOption... options) { + public BlobInfo get(BlobId blob, BlobGetOption... options) { final StorageObject storedObject = blob.toPb(); final Map optionsMap = optionMap(options); try { @@ -222,7 +222,7 @@ public StorageObject call() { @Override public BlobInfo get(BlobId blob) { - return get(blob, new BlobSourceOption[0]); + return get(blob, new BlobGetOption[0]); } private abstract static class BasePageFetcher @@ -510,7 +510,7 @@ public BatchResponse apply(BatchRequest batchRequest) { } List>> toGet = Lists.newArrayListWithCapacity(batchRequest.toGet().size()); - for (Map.Entry> entry : batchRequest.toGet().entrySet()) { + for (Map.Entry> entry : batchRequest.toGet().entrySet()) { BlobId blob = entry.getKey(); Map optionsMap = optionMap(null, null, entry.getValue()); toGet.add(Tuple.>of(blob.toPb(), optionsMap)); diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BatchRequestTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BatchRequestTest.java index 06b1105d7b9b..600c8af0d554 100644 --- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BatchRequestTest.java +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BatchRequestTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue; import com.google.common.collect.Iterables; +import com.google.gcloud.storage.Storage.BlobGetOption; import com.google.gcloud.storage.Storage.BlobSourceOption; import com.google.gcloud.storage.Storage.BlobTargetOption; @@ -42,7 +43,7 @@ public void testBatchRequest() { .update(BlobInfo.builder("b2", "o1").build(), BlobTargetOption.predefinedAcl(PUBLIC_READ)) .update(BlobInfo.builder("b2", "o2").build()) .get("b3", "o1") - .get("b3", "o2", BlobSourceOption.generationMatch(1)) + .get("b3", "o2", BlobGetOption.generationMatch(1)) .get("b3", "o3") .build(); @@ -68,16 +69,14 @@ public void testBatchRequest() { assertTrue(Iterables.isEmpty(update.getValue())); assertFalse(updates.hasNext()); - Iterator>> gets = request - .toGet().entrySet().iterator(); - Entry> get = gets.next(); + Iterator>> gets = request.toGet().entrySet().iterator(); + Entry> get = gets.next(); assertEquals(BlobId.of("b3", "o1"), get.getKey()); assertTrue(Iterables.isEmpty(get.getValue())); get = gets.next(); assertEquals(BlobId.of("b3", "o2"), get.getKey()); assertEquals(1, Iterables.size(get.getValue())); - assertEquals(BlobSourceOption.generationMatch(1), - Iterables.getFirst(get.getValue(), null)); + assertEquals(BlobGetOption.generationMatch(1), Iterables.getFirst(get.getValue(), null)); get = gets.next(); assertEquals(BlobId.of("b3", "o3"), get.getKey()); assertTrue(Iterables.isEmpty(get.getValue())); diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BlobTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BlobTest.java index defb1d35e3f4..02e325716c8b 100644 --- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BlobTest.java +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BlobTest.java @@ -72,14 +72,16 @@ public void testInfo() throws Exception { @Test public void testExists_True() throws Exception { - expect(storage.get(BLOB_INFO.blobId(), new Storage.BlobSourceOption[0])).andReturn(BLOB_INFO); + Storage.BlobGetOption[] expectedOptions = {Storage.BlobGetOption.fields()}; + expect(storage.get(BLOB_INFO.blobId(), expectedOptions)).andReturn(BLOB_INFO); replay(storage); assertTrue(blob.exists()); } @Test public void testExists_False() throws Exception { - expect(storage.get(BLOB_INFO.blobId(), new Storage.BlobSourceOption[0])).andReturn(null); + Storage.BlobGetOption[] expectedOptions = {Storage.BlobGetOption.fields()}; + expect(storage.get(BLOB_INFO.blobId(), expectedOptions)).andReturn(null); replay(storage); assertFalse(blob.exists()); } @@ -95,7 +97,7 @@ public void testContent() throws Exception { @Test public void testReload() throws Exception { BlobInfo updatedInfo = BLOB_INFO.toBuilder().cacheControl("c").build(); - expect(storage.get(BLOB_INFO.blobId(), new Storage.BlobSourceOption[0])).andReturn(updatedInfo); + expect(storage.get(BLOB_INFO.blobId(), new Storage.BlobGetOption[0])).andReturn(updatedInfo); replay(storage); Blob updatedBlob = blob.reload(); assertSame(storage, blob.storage()); diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BucketTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BucketTest.java index decac7b1e0d2..5d8fc5a9dffc 100644 --- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BucketTest.java +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/BucketTest.java @@ -75,14 +75,16 @@ public void testInfo() throws Exception { @Test public void testExists_True() throws Exception { - expect(storage.get(BUCKET_INFO.name())).andReturn(BUCKET_INFO); + Storage.BucketGetOption[] expectedOptions = {Storage.BucketGetOption.fields()}; + expect(storage.get(BUCKET_INFO.name(), expectedOptions)).andReturn(BUCKET_INFO); replay(storage); assertTrue(bucket.exists()); } @Test public void testExists_False() throws Exception { - expect(storage.get(BUCKET_INFO.name())).andReturn(null); + Storage.BucketGetOption[] expectedOptions = {Storage.BucketGetOption.fields()}; + expect(storage.get(BUCKET_INFO.name(), expectedOptions)).andReturn(null); replay(storage); assertFalse(bucket.exists()); } @@ -137,7 +139,7 @@ public void testList() throws Exception { @Test public void testGet() throws Exception { BlobInfo info = BlobInfo.builder("b", "n").build(); - expect(storage.get(BlobId.of(bucket.info().name(), "n"), new Storage.BlobSourceOption[0])) + expect(storage.get(BlobId.of(bucket.info().name(), "n"), new Storage.BlobGetOption[0])) .andReturn(info); replay(storage); Blob blob = bucket.get("n"); diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java index d15e07dfeff7..423e972a8de6 100644 --- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/ITStorageTest.java @@ -26,7 +26,10 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.gcloud.Page; import com.google.gcloud.RestorableState; +import com.google.gcloud.storage.Storage.BlobField; +import com.google.gcloud.storage.Storage.BucketField; import com.google.gcloud.storage.testing.RemoteGcsHelper; import org.junit.AfterClass; @@ -80,17 +83,46 @@ public static void afterClass() @Test(timeout = 5000) public void testListBuckets() throws InterruptedException { - Iterator bucketIterator = - storage.list(Storage.BucketListOption.prefix(BUCKET)).values().iterator(); + Iterator bucketIterator = storage.list(Storage.BucketListOption.prefix(BUCKET), + Storage.BucketListOption.fields()).values().iterator(); while (!bucketIterator.hasNext()) { Thread.sleep(500); - bucketIterator = storage.list(Storage.BucketListOption.prefix(BUCKET)).values().iterator(); + bucketIterator = storage.list(Storage.BucketListOption.prefix(BUCKET), + Storage.BucketListOption.fields()).values().iterator(); } while (bucketIterator.hasNext()) { - assertTrue(bucketIterator.next().name().startsWith(BUCKET)); + BucketInfo remoteBucket = bucketIterator.next(); + assertTrue(remoteBucket.name().startsWith(BUCKET)); + assertNull(remoteBucket.createTime()); + assertNull(remoteBucket.selfLink()); } } + @Test + public void testGetBucketSelectedFields() { + BucketInfo remoteBucket = storage.get(BUCKET, Storage.BucketGetOption.fields(BucketField.ID)); + assertEquals(BUCKET, remoteBucket.name()); + assertNull(remoteBucket.createTime()); + assertNotNull(remoteBucket.id()); + } + + @Test + public void testGetBucketAllSelectedFields() { + BucketInfo remoteBucket = storage.get(BUCKET, + Storage.BucketGetOption.fields(BucketField.values())); + assertEquals(BUCKET, remoteBucket.name()); + assertNotNull(remoteBucket.createTime()); + assertNotNull(remoteBucket.selfLink()); + } + + @Test + public void testGetBucketEmptyFields() { + BucketInfo remoteBucket = storage.get(BUCKET, Storage.BucketGetOption.fields()); + assertEquals(BUCKET, remoteBucket.name()); + assertNull(remoteBucket.createTime()); + assertNull(remoteBucket.selfLink()); + } + @Test public void testCreateBlob() { String blobName = "test-create-blob"; @@ -160,6 +192,104 @@ public void testCreateBlobMd5Fail() throws UnsupportedEncodingException { } } + @Test + public void testGetBlobEmptySelectedFields() { + String blobName = "test-get-empty-selected-fields-blob"; + BlobInfo blob = BlobInfo.builder(BUCKET, blobName).contentType(CONTENT_TYPE).build(); + assertNotNull(storage.create(blob)); + BlobInfo remoteBlob = storage.get(blob.blobId(), Storage.BlobGetOption.fields()); + assertEquals(blob.blobId(), remoteBlob.blobId()); + assertNull(remoteBlob.contentType()); + assertTrue(storage.delete(BUCKET, blobName)); + } + + @Test + public void testGetBlobSelectedFields() { + String blobName = "test-get-selected-fields-blob"; + BlobInfo blob = BlobInfo.builder(BUCKET, blobName) + .contentType(CONTENT_TYPE) + .metadata(ImmutableMap.of("k", "v")) + .build(); + assertNotNull(storage.create(blob)); + BlobInfo remoteBlob = storage.get(blob.blobId(), Storage.BlobGetOption.fields( + BlobField.METADATA)); + assertEquals(blob.blobId(), remoteBlob.blobId()); + assertEquals(ImmutableMap.of("k", "v"), remoteBlob.metadata()); + assertNull(remoteBlob.contentType()); + assertTrue(storage.delete(BUCKET, blobName)); + } + + @Test + public void testGetBlobAllSelectedFields() { + String blobName = "test-get-all-selected-fields-blob"; + BlobInfo blob = BlobInfo.builder(BUCKET, blobName) + .contentType(CONTENT_TYPE) + .metadata(ImmutableMap.of("k", "v")) + .build(); + assertNotNull(storage.create(blob)); + BlobInfo remoteBlob = storage.get(blob.blobId(), + Storage.BlobGetOption.fields(BlobField.values())); + assertEquals(blob.blobId(), remoteBlob.blobId()); + assertEquals(ImmutableMap.of("k", "v"), remoteBlob.metadata()); + assertNotNull(remoteBlob.id()); + assertNotNull(remoteBlob.selfLink()); + assertTrue(storage.delete(BUCKET, blobName)); + } + + @Test + public void testListBlobsSelectedFields() { + String[] blobNames = {"test-list-blobs-selected-fields-blob1", + "test-list-blobs-selected-fields-blob2"}; + ImmutableMap metadata = ImmutableMap.of("k", "v"); + BlobInfo blob1 = BlobInfo.builder(BUCKET, blobNames[0]) + .contentType(CONTENT_TYPE) + .metadata(metadata) + .build(); + BlobInfo blob2 = BlobInfo.builder(BUCKET, blobNames[1]) + .contentType(CONTENT_TYPE) + .metadata(metadata) + .build(); + assertNotNull(storage.create(blob1)); + assertNotNull(storage.create(blob2)); + Page page = storage.list(BUCKET, + Storage.BlobListOption.prefix("test-list-blobs-selected-fields-blob"), + Storage.BlobListOption.fields(BlobField.METADATA)); + int index = 0; + for (BlobInfo remoteBlob : page.values()) { + assertEquals(BUCKET, remoteBlob.bucket()); + assertEquals(blobNames[index++], remoteBlob.name()); + assertEquals(metadata, remoteBlob.metadata()); + assertNull(remoteBlob.contentType()); + } + assertTrue(storage.delete(BUCKET, blobNames[0])); + assertTrue(storage.delete(BUCKET, blobNames[1])); + } + + @Test + public void testListBlobsEmptySelectedFields() { + String[] blobNames = {"test-list-blobs-empty-selected-fields-blob1", + "test-list-blobs-empty-selected-fields-blob2"}; + BlobInfo blob1 = BlobInfo.builder(BUCKET, blobNames[0]) + .contentType(CONTENT_TYPE) + .build(); + BlobInfo blob2 = BlobInfo.builder(BUCKET, blobNames[1]) + .contentType(CONTENT_TYPE) + .build(); + assertNotNull(storage.create(blob1)); + assertNotNull(storage.create(blob2)); + Page page = storage.list(BUCKET, + Storage.BlobListOption.prefix("test-list-blobs-empty-selected-fields-blob"), + Storage.BlobListOption.fields()); + int index = 0; + for (BlobInfo remoteBlob : page.values()) { + assertEquals(BUCKET, remoteBlob.bucket()); + assertEquals(blobNames[index++], remoteBlob.name()); + assertNull(remoteBlob.contentType()); + } + assertTrue(storage.delete(BUCKET, blobNames[0])); + assertTrue(storage.delete(BUCKET, blobNames[1])); + } + @Test public void testUpdateBlob() { String blobName = "test-update-blob"; @@ -442,7 +572,7 @@ public void testBatchRequestFail() { BatchRequest batchRequest = BatchRequest.builder() .update(updatedBlob, Storage.BlobTargetOption.generationMatch()) .delete(BUCKET, blobName, Storage.BlobSourceOption.generationMatch(-1L)) - .get(BUCKET, blobName, Storage.BlobSourceOption.generationMatch(-1L)) + .get(BUCKET, blobName, Storage.BlobGetOption.generationMatch(-1L)) .build(); BatchResponse updateResponse = storage.apply(batchRequest); assertEquals(1, updateResponse.updates().size()); diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java index 6c77b4fcfc99..d5e2f8de7397 100644 --- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/StorageImplTest.java @@ -138,13 +138,32 @@ public class StorageImplTest { private static final Storage.BlobWriteOption BLOB_WRITE_CRC2C = Storage.BlobWriteOption.crc32cMatch(); - // Bucket source options + // Bucket get/source options private static final Storage.BucketSourceOption BUCKET_SOURCE_METAGENERATION = Storage.BucketSourceOption.metagenerationMatch(BUCKET_INFO1.metageneration()); private static final Map BUCKET_SOURCE_OPTIONS = ImmutableMap.of( StorageRpc.Option.IF_METAGENERATION_MATCH, BUCKET_SOURCE_METAGENERATION.value()); + private static final Storage.BucketGetOption BUCKET_GET_METAGENERATION = + Storage.BucketGetOption.metagenerationMatch(BUCKET_INFO1.metageneration()); + private static final Storage.BucketGetOption BUCKET_GET_FIELDS = + Storage.BucketGetOption.fields(Storage.BucketField.LOCATION, Storage.BucketField.ACL); + private static final Storage.BucketGetOption BUCKET_GET_EMPTY_FIELDS = + Storage.BucketGetOption.fields(); + private static final Map BUCKET_GET_OPTIONS = ImmutableMap.of( + StorageRpc.Option.IF_METAGENERATION_MATCH, BUCKET_SOURCE_METAGENERATION.value()); - // Blob source options + // Blob get/source options + private static final Storage.BlobGetOption BLOB_GET_METAGENERATION = + Storage.BlobGetOption.metagenerationMatch(BLOB_INFO1.metageneration()); + private static final Storage.BlobGetOption BLOB_GET_GENERATION = + Storage.BlobGetOption.generationMatch(BLOB_INFO1.generation()); + private static final Storage.BlobGetOption BLOB_GET_FIELDS = + Storage.BlobGetOption.fields(Storage.BlobField.CONTENT_TYPE, Storage.BlobField.CRC32C); + private static final Storage.BlobGetOption BLOB_GET_EMPTY_FIELDS = + Storage.BlobGetOption.fields(); + private static final Map BLOB_GET_OPTIONS = ImmutableMap.of( + StorageRpc.Option.IF_METAGENERATION_MATCH, BLOB_GET_METAGENERATION.value(), + StorageRpc.Option.IF_GENERATION_MATCH, BLOB_GET_GENERATION.value()); private static final Storage.BlobSourceOption BLOB_SOURCE_METAGENERATION = Storage.BlobSourceOption.metagenerationMatch(BLOB_INFO1.metageneration()); private static final Storage.BlobSourceOption BLOB_SOURCE_GENERATION = @@ -161,6 +180,10 @@ public class StorageImplTest { Storage.BucketListOption.maxResults(42L); private static final Storage.BucketListOption BUCKET_LIST_PREFIX = Storage.BucketListOption.prefix("prefix"); + private static final Storage.BucketListOption BUCKET_LIST_FIELDS = + Storage.BucketListOption.fields(Storage.BucketField.LOCATION, Storage.BucketField.ACL); + private static final Storage.BucketListOption BUCKET_LIST_EMPTY_FIELDS = + Storage.BucketListOption.fields(); private static final Map BUCKET_LIST_OPTIONS = ImmutableMap.of( StorageRpc.Option.MAX_RESULTS, BUCKET_LIST_MAX_RESULT.value(), StorageRpc.Option.PREFIX, BUCKET_LIST_PREFIX.value()); @@ -170,6 +193,10 @@ public class StorageImplTest { Storage.BlobListOption.maxResults(42L); private static final Storage.BlobListOption BLOB_LIST_PREFIX = Storage.BlobListOption.prefix("prefix"); + private static final Storage.BlobListOption BLOB_LIST_FIELDS = + Storage.BlobListOption.fields(Storage.BlobField.CONTENT_TYPE, Storage.BlobField.MD5HASH); + private static final Storage.BlobListOption BLOB_LIST_EMPTY_FIELDS = + Storage.BlobListOption.fields(); private static final Map BLOB_LIST_OPTIONS = ImmutableMap.of( StorageRpc.Option.MAX_RESULTS, BLOB_LIST_MAX_RESULT.value(), StorageRpc.Option.PREFIX, BLOB_LIST_PREFIX.value()); @@ -359,16 +386,51 @@ public void testGetBucket() { @Test public void testGetBucketWithOptions() { - EasyMock.expect(storageRpcMock.get(BucketInfo.of(BUCKET_NAME1).toPb(), BUCKET_SOURCE_OPTIONS)) + EasyMock.expect(storageRpcMock.get(BucketInfo.of(BUCKET_NAME1).toPb(), BUCKET_GET_OPTIONS)) .andReturn(BUCKET_INFO1.toPb()); EasyMock.replay(storageRpcMock); storage = options.service(); - BucketInfo bucket = - storage.get(BUCKET_NAME1, - Storage.BucketSourceOption.metagenerationMatch(BUCKET_INFO1.metageneration())); + BucketInfo bucket = storage.get(BUCKET_NAME1, BUCKET_GET_METAGENERATION); assertEquals(BUCKET_INFO1, bucket); } + @Test + public void testGetBucketWithSelectedFields() { + Capture> capturedOptions = + Capture.>newInstance(); + EasyMock.expect(storageRpcMock.get(EasyMock.eq(BucketInfo.of(BUCKET_NAME1).toPb()), + EasyMock.capture(capturedOptions))).andReturn(BUCKET_INFO1.toPb()); + EasyMock.replay(storageRpcMock); + storage = options.service(); + BucketInfo bucket = storage.get(BUCKET_NAME1, BUCKET_GET_METAGENERATION, BUCKET_GET_FIELDS); + assertEquals(BUCKET_GET_METAGENERATION.value(), + capturedOptions.getValue().get(BUCKET_GET_METAGENERATION.rpcOption())); + String selector = (String) capturedOptions.getValue().get(BLOB_GET_FIELDS.rpcOption()); + assertTrue(selector.contains("name")); + assertTrue(selector.contains("location")); + assertTrue(selector.contains("acl")); + assertEquals(17, selector.length()); + assertEquals(BUCKET_INFO1.name(), bucket.name()); + } + + @Test + public void testGetBucketWithEmptyFields() { + Capture> capturedOptions = + Capture.>newInstance(); + EasyMock.expect(storageRpcMock.get(EasyMock.eq(BucketInfo.of(BUCKET_NAME1).toPb()), + EasyMock.capture(capturedOptions))).andReturn(BUCKET_INFO1.toPb()); + EasyMock.replay(storageRpcMock); + storage = options.service(); + BucketInfo bucket = storage.get(BUCKET_NAME1, BUCKET_GET_METAGENERATION, + BUCKET_GET_EMPTY_FIELDS); + assertEquals(BUCKET_GET_METAGENERATION.value(), + capturedOptions.getValue().get(BUCKET_GET_METAGENERATION.rpcOption())); + String selector = (String) capturedOptions.getValue().get(BLOB_GET_FIELDS.rpcOption()); + assertTrue(selector.contains("name")); + assertEquals(4, selector.length()); + assertEquals(BUCKET_INFO1.name(), bucket.name()); + } + @Test public void testGetBlob() { EasyMock.expect( @@ -383,12 +445,56 @@ public void testGetBlob() { @Test public void testGetBlobWithOptions() { EasyMock.expect( - storageRpcMock.get(BlobId.of(BUCKET_NAME1, BLOB_NAME1).toPb(), BLOB_SOURCE_OPTIONS)) + storageRpcMock.get(BlobId.of(BUCKET_NAME1, BLOB_NAME1).toPb(), BLOB_GET_OPTIONS)) .andReturn(BLOB_INFO1.toPb()); EasyMock.replay(storageRpcMock); storage = options.service(); BlobInfo blob = - storage.get(BUCKET_NAME1, BLOB_NAME1, BLOB_SOURCE_METAGENERATION, BLOB_SOURCE_GENERATION); + storage.get(BUCKET_NAME1, BLOB_NAME1, BLOB_GET_METAGENERATION, BLOB_GET_GENERATION); + assertEquals(BLOB_INFO1, blob); + } + + @Test + public void testGetBlobWithSelectedFields() { + Capture> capturedOptions = + Capture.>newInstance(); + EasyMock.expect(storageRpcMock.get(EasyMock.eq(BlobId.of(BUCKET_NAME1, BLOB_NAME1).toPb()), + EasyMock.capture(capturedOptions))).andReturn(BLOB_INFO1.toPb()); + EasyMock.replay(storageRpcMock); + storage = options.service(); + BlobInfo blob = storage.get(BUCKET_NAME1, BLOB_NAME1, BLOB_GET_METAGENERATION, + BLOB_GET_GENERATION, BLOB_GET_FIELDS); + assertEquals(BLOB_GET_METAGENERATION.value(), + capturedOptions.getValue().get(BLOB_GET_METAGENERATION.rpcOption())); + assertEquals(BLOB_GET_GENERATION.value(), + capturedOptions.getValue().get(BLOB_GET_GENERATION.rpcOption())); + String selector = (String) capturedOptions.getValue().get(BLOB_GET_FIELDS.rpcOption()); + assertTrue(selector.contains("bucket")); + assertTrue(selector.contains("name")); + assertTrue(selector.contains("contentType")); + assertTrue(selector.contains("crc32c")); + assertEquals(30, selector.length()); + assertEquals(BLOB_INFO1, blob); + } + + @Test + public void testGetBlobWithEmptyFields() { + Capture> capturedOptions = + Capture.>newInstance(); + EasyMock.expect(storageRpcMock.get(EasyMock.eq(BlobId.of(BUCKET_NAME1, BLOB_NAME1).toPb()), + EasyMock.capture(capturedOptions))).andReturn(BLOB_INFO1.toPb()); + EasyMock.replay(storageRpcMock); + storage = options.service(); + BlobInfo blob = storage.get(BUCKET_NAME1, BLOB_NAME1, BLOB_GET_METAGENERATION, + BLOB_GET_GENERATION, BLOB_GET_EMPTY_FIELDS); + assertEquals(BLOB_GET_METAGENERATION.value(), + capturedOptions.getValue().get(BLOB_GET_METAGENERATION.rpcOption())); + assertEquals(BLOB_GET_GENERATION.value(), + capturedOptions.getValue().get(BLOB_GET_GENERATION.rpcOption())); + String selector = (String) capturedOptions.getValue().get(BLOB_GET_FIELDS.rpcOption()); + assertTrue(selector.contains("bucket")); + assertTrue(selector.contains("name")); + assertEquals(11, selector.length()); assertEquals(BLOB_INFO1, blob); } @@ -432,6 +538,48 @@ public void testListBucketsWithOptions() { assertArrayEquals(bucketList.toArray(), Iterables.toArray(page.values(), BucketInfo.class)); } + @Test + public void testListBucketsWithSelectedFields() { + String cursor = "cursor"; + Capture> capturedOptions = + Capture.>newInstance(); + ImmutableList bucketList = ImmutableList.of(BUCKET_INFO1, BUCKET_INFO2); + Tuple> result = + Tuple.of(cursor, Iterables.transform(bucketList, BucketInfo.TO_PB_FUNCTION)); + EasyMock.expect(storageRpcMock.list(EasyMock.capture(capturedOptions))).andReturn(result); + EasyMock.replay(storageRpcMock); + storage = options.service(); + Page page = storage.list(BUCKET_LIST_FIELDS); + String selector = (String) capturedOptions.getValue().get(BLOB_LIST_FIELDS.rpcOption()); + assertTrue(selector.contains("items")); + assertTrue(selector.contains("name")); + assertTrue(selector.contains("acl")); + assertTrue(selector.contains("location")); + assertEquals(24, selector.length()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(bucketList.toArray(), Iterables.toArray(page.values(), BucketInfo.class)); + } + + @Test + public void testListBucketsWithEmptyFields() { + String cursor = "cursor"; + Capture> capturedOptions = + Capture.>newInstance(); + ImmutableList bucketList = ImmutableList.of(BUCKET_INFO1, BUCKET_INFO2); + Tuple> result = + Tuple.of(cursor, Iterables.transform(bucketList, BucketInfo.TO_PB_FUNCTION)); + EasyMock.expect(storageRpcMock.list(EasyMock.capture(capturedOptions))).andReturn(result); + EasyMock.replay(storageRpcMock); + storage = options.service(); + Page page = storage.list(BUCKET_LIST_EMPTY_FIELDS); + String selector = (String) capturedOptions.getValue().get(BLOB_LIST_FIELDS.rpcOption()); + assertTrue(selector.contains("items")); + assertTrue(selector.contains("name")); + assertEquals(11, selector.length()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(bucketList.toArray(), Iterables.toArray(page.values(), BucketInfo.class)); + } + @Test public void testListBlobs() { String cursor = "cursor"; @@ -473,6 +621,64 @@ public void testListBlobsWithOptions() { assertArrayEquals(blobList.toArray(), Iterables.toArray(page.values(), BlobInfo.class)); } + @Test + public void testListBlobsWithSelectedFields() { + String cursor = "cursor"; + Capture> capturedOptions = + Capture.>newInstance(); + ImmutableList blobList = ImmutableList.of(BLOB_INFO1, BLOB_INFO2); + Tuple> result = + Tuple.of(cursor, Iterables.transform(blobList, BlobInfo.TO_PB_FUNCTION)); + EasyMock.expect( + storageRpcMock.list(EasyMock.eq(BUCKET_NAME1), EasyMock.capture(capturedOptions))) + .andReturn(result); + EasyMock.replay(storageRpcMock); + storage = options.service(); + Page page = + storage.list(BUCKET_NAME1, BLOB_LIST_MAX_RESULT, BLOB_LIST_PREFIX, BLOB_LIST_FIELDS); + assertEquals(BLOB_LIST_MAX_RESULT.value(), + capturedOptions.getValue().get(BLOB_LIST_MAX_RESULT.rpcOption())); + assertEquals(BLOB_LIST_PREFIX.value(), + capturedOptions.getValue().get(BLOB_LIST_PREFIX.rpcOption())); + String selector = (String) capturedOptions.getValue().get(BLOB_LIST_FIELDS.rpcOption()); + assertTrue(selector.contains("items")); + assertTrue(selector.contains("bucket")); + assertTrue(selector.contains("name")); + assertTrue(selector.contains("contentType")); + assertTrue(selector.contains("md5Hash")); + assertEquals(38, selector.length()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(blobList.toArray(), Iterables.toArray(page.values(), BlobInfo.class)); + } + + @Test + public void testListBlobsWithEmptyFields() { + String cursor = "cursor"; + Capture> capturedOptions = + Capture.>newInstance(); + ImmutableList blobList = ImmutableList.of(BLOB_INFO1, BLOB_INFO2); + Tuple> result = + Tuple.of(cursor, Iterables.transform(blobList, BlobInfo.TO_PB_FUNCTION)); + EasyMock.expect( + storageRpcMock.list(EasyMock.eq(BUCKET_NAME1), EasyMock.capture(capturedOptions))) + .andReturn(result); + EasyMock.replay(storageRpcMock); + storage = options.service(); + Page page = + storage.list(BUCKET_NAME1, BLOB_LIST_MAX_RESULT, BLOB_LIST_PREFIX, BLOB_LIST_EMPTY_FIELDS); + assertEquals(BLOB_LIST_MAX_RESULT.value(), + capturedOptions.getValue().get(BLOB_LIST_MAX_RESULT.rpcOption())); + assertEquals(BLOB_LIST_PREFIX.value(), + capturedOptions.getValue().get(BLOB_LIST_PREFIX.rpcOption())); + String selector = (String) capturedOptions.getValue().get(BLOB_LIST_EMPTY_FIELDS.rpcOption()); + assertTrue(selector.contains("items")); + assertTrue(selector.contains("bucket")); + assertTrue(selector.contains("name")); + assertEquals(18, selector.length()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(blobList.toArray(), Iterables.toArray(page.values(), BlobInfo.class)); + } + @Test public void testUpdateBucket() { BucketInfo updatedBucketInfo = BUCKET_INFO1.toBuilder().indexPage("some-page").build();