From 02dc3b5e5377d8848c889647e72102cd9acc646d Mon Sep 17 00:00:00 2001
From: Dmitry <58846611+dmitry-fa@users.noreply.github.com>
Date: Tue, 14 Jul 2020 23:47:40 +0300
Subject: [PATCH 01/35] fix:
PostPolicyV4.PostFieldsV4.Builder.addCustomMetadataField() allows to add
prefixed an not prefixed custom fields (#398)
* changes to PostPolicyV4
* PostPolicyV4.addCustomMetadataField() allows to add prefixed an not prefixed custom fields
* deprecate incorrectly named method
* fix format
* addCustomMetadataField -> setCustomMetadataField
---
.../google/cloud/storage/PostPolicyV4.java | 38 +++++++++++++------
1 file changed, 27 insertions(+), 11 deletions(-)
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/PostPolicyV4.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/PostPolicyV4.java
index df2936dc9..cc9b413a2 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/PostPolicyV4.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/PostPolicyV4.java
@@ -31,8 +31,8 @@
* @see POST Object
*/
public final class PostPolicyV4 {
- private String url;
- private Map fields;
+ private final String url;
+ private final Map fields;
private PostPolicyV4(String url, Map fields) {
this.url = url;
@@ -58,7 +58,7 @@ public Map getFields() {
* Object Form fields
*/
public static final class PostFieldsV4 {
- private Map fieldsMap;
+ private final Map fieldsMap;
private PostFieldsV4(Builder builder) {
this.fieldsMap = builder.fieldsMap;
@@ -81,10 +81,11 @@ public Map getFieldsMap() {
}
public static class Builder {
- private Map fieldsMap;
+ private static final String CUSTOM_FIELD_PREFIX = "x-goog-meta-";
+ private final Map fieldsMap;
private Builder() {
- fieldsMap = new HashMap<>();
+ this.fieldsMap = new HashMap<>();
}
public PostFieldsV4 build() {
@@ -121,7 +122,13 @@ public Builder setContentType(String contentType) {
return this;
}
+ /** @deprecated use {@link #setExpires(String)} */
+ @Deprecated
public Builder Expires(String expires) {
+ return setExpires(expires);
+ }
+
+ public Builder setExpires(String expires) {
fieldsMap.put("expires", expires);
return this;
}
@@ -136,8 +143,17 @@ public Builder setSuccessActionStatus(int successActionStatus) {
return this;
}
+ /** @deprecated use {@link #setCustomMetadataField(String, String)} */
+ @Deprecated
public Builder AddCustomMetadataField(String field, String value) {
- fieldsMap.put("x-goog-meta-" + field, value);
+ return setCustomMetadataField(field, value);
+ }
+
+ public Builder setCustomMetadataField(String field, String value) {
+ if (!field.startsWith(CUSTOM_FIELD_PREFIX)) {
+ field = CUSTOM_FIELD_PREFIX + value;
+ }
+ fieldsMap.put(field, value);
return this;
}
}
@@ -270,8 +286,8 @@ Builder addCustomCondition(ConditionV4Type type, String field, String value) {
* Policy document
*/
public static final class PostPolicyV4Document {
- private String expiration;
- private PostConditionsV4 conditions;
+ private final String expiration;
+ private final PostConditionsV4 conditions;
private PostPolicyV4Document(String expiration, PostConditionsV4 conditions) {
this.expiration = expiration;
@@ -363,9 +379,9 @@ public enum ConditionV4Type {
* Policy document
*/
static final class ConditionV4 {
- ConditionV4Type type;
- String operand1;
- String operand2;
+ final ConditionV4Type type;
+ final String operand1;
+ final String operand2;
private ConditionV4(ConditionV4Type type, String operand1, String operand2) {
this.type = type;
From 05cbbdaf10fc06a2dee3a05f5b0437c79029e1dd Mon Sep 17 00:00:00 2001
From: WhiteSource Renovate
Date: Tue, 14 Jul 2020 22:51:15 +0200
Subject: [PATCH 02/35] chore(deps): update dependency
com.google.cloud:google-cloud-storage to v1.111.2 (#427)
---
samples/install-without-bom/pom.xml | 2 +-
samples/snapshot/pom.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index cbe71fe42..4dad481d1 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -29,7 +29,7 @@
com.google.cloudgoogle-cloud-storage
- 1.111.1
+ 1.111.2
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index cad01e090..f662ee168 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -28,7 +28,7 @@
com.google.cloudgoogle-cloud-storage
- 1.111.1
+ 1.111.2
From 275f452a5993f95a84fb603a5f4b436238b39439 Mon Sep 17 00:00:00 2001
From: Ajit Thakor <49403056+athakor@users.noreply.github.com>
Date: Wed, 15 Jul 2020 21:23:47 +0530
Subject: [PATCH 03/35] fix(docs): example of Storage#testIamPermissions (#434)
---
.../src/main/java/com/google/cloud/storage/Storage.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
index eb15dd37a..70863b17f 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
@@ -3517,7 +3517,7 @@ HmacKeyMetadata updateHmacKeyState(
* String bucketName = "my-unique-bucket";
* List response =
* storage.testIamPermissions(
- * bucket,
+ * bucketName,
* ImmutableList.of("storage.buckets.get", "storage.buckets.getIamPolicy"));
* for (boolean hasPermission : response) {
* // Do something with permission test response
From fbfa9ecf277794e07d9a3c46d5b5022f54c37afd Mon Sep 17 00:00:00 2001
From: WhiteSource Renovate
Date: Thu, 16 Jul 2020 00:25:44 +0200
Subject: [PATCH 04/35] deps: update dependency
com.google.api-client:google-api-client to v1.30.10 (#423)
---
google-cloud-storage/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/google-cloud-storage/pom.xml b/google-cloud-storage/pom.xml
index 196a66538..8b0097909 100644
--- a/google-cloud-storage/pom.xml
+++ b/google-cloud-storage/pom.xml
@@ -33,7 +33,7 @@
com.google.api-clientgoogle-api-client
- 1.30.9
+ 1.30.10com.google.apis
From 6ef57ebc9eeddc90f13ef87274e8ab0b7eb53290 Mon Sep 17 00:00:00 2001
From: WhiteSource Renovate
Date: Thu, 16 Jul 2020 00:51:44 +0200
Subject: [PATCH 05/35] deps: update dependency
com.google.apis:google-api-services-storage to v1-rev20200611-1.30.10 (#428)
---
pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 40d8e2968..353a1b62c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,7 +78,7 @@
com.google.apisgoogle-api-services-storage
- v1-rev20200611-1.30.9
+ v1-rev20200611-1.30.10org.easymock
From 43202f6124623901abc1d14f4cdb20d08e0db6f1 Mon Sep 17 00:00:00 2001
From: "release-please[bot]"
<55107282+release-please[bot]@users.noreply.github.com>
Date: Wed, 15 Jul 2020 15:52:31 -0700
Subject: [PATCH 06/35] chore: release 1.111.3-SNAPSHOT (#432)
* updated versions.txt [ci skip]
* updated samples/pom.xml [ci skip]
* updated samples/snippets/pom.xml [ci skip]
* updated samples/install-without-bom/pom.xml [ci skip]
* updated samples/snapshot/pom.xml [ci skip]
* updated google-cloud-storage/pom.xml [ci skip]
* updated pom.xml
Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
---
google-cloud-storage/pom.xml | 4 ++--
pom.xml | 2 +-
versions.txt | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/google-cloud-storage/pom.xml b/google-cloud-storage/pom.xml
index 8b0097909..ffacd7054 100644
--- a/google-cloud-storage/pom.xml
+++ b/google-cloud-storage/pom.xml
@@ -2,7 +2,7 @@
4.0.0google-cloud-storage
- 1.111.2
+ 1.111.3-SNAPSHOTjarGoogle Cloud Storagehttps://github.com/googleapis/java-storage
@@ -12,7 +12,7 @@
com.google.cloudgoogle-cloud-storage-parent
- 1.111.2
+ 1.111.3-SNAPSHOTgoogle-cloud-storage
diff --git a/pom.xml b/pom.xml
index 353a1b62c..853bd01e9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.google.cloudgoogle-cloud-storage-parentpom
- 1.111.2
+ 1.111.3-SNAPSHOTStorage Parenthttps://github.com/googleapis/java-storage
diff --git a/versions.txt b/versions.txt
index 2eee41669..ef36ef925 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,4 +1,4 @@
# Format:
# module:released-version:current-version
-google-cloud-storage:1.111.2:1.111.2
\ No newline at end of file
+google-cloud-storage:1.111.2:1.111.3-SNAPSHOT
\ No newline at end of file
From 66d1eb793383b9e83992824b392cedd28d54609f Mon Sep 17 00:00:00 2001
From: Dmitry <58846611+dmitry-fa@users.noreply.github.com>
Date: Thu, 16 Jul 2020 01:54:32 +0300
Subject: [PATCH 07/35] feat: auto content-type on blob creation (#338)
* feat: auto content-type on blob creation
* feat: auto content-type on blob creation
* feat: auto content-type on blob creation
* feat: auto content-type on blob creation
* feat: auto content-type on blob creation
* feat: auto content-type on blob creation
* detection content type is made optional
---
.../com/google/cloud/storage/Storage.java | 32 +++++++++--
.../cloud/storage/spi/v1/HttpStorageRpc.java | 23 ++++++--
.../cloud/storage/spi/v1/StorageRpc.java | 3 +-
.../cloud/storage/it/ITStorageTest.java | 57 +++++++++++++++++++
4 files changed, 104 insertions(+), 11 deletions(-)
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
index 70863b17f..202615cdd 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
@@ -521,6 +521,15 @@ public static BlobTargetOption disableGzipContent() {
return new BlobTargetOption(StorageRpc.Option.IF_DISABLE_GZIP_CONTENT, true);
}
+ /**
+ * Returns an option for detecting content type. If this option is used, the content type is
+ * detected from the blob name if not explicitly set. This option is on the client side only, it
+ * does not appear in a RPC call.
+ */
+ public static BlobTargetOption detectContentType() {
+ return new BlobTargetOption(StorageRpc.Option.DETECT_CONTENT_TYPE, true);
+ }
+
/**
* Returns an option to set a customer-supplied AES256 key for server-side encryption of the
* blob.
@@ -593,6 +602,7 @@ enum Option {
CUSTOMER_SUPPLIED_KEY,
KMS_KEY_NAME,
USER_PROJECT,
+ DETECT_CONTENT_TYPE,
IF_DISABLE_GZIP_CONTENT;
StorageRpc.Option toRpcOption() {
@@ -733,6 +743,15 @@ public static BlobWriteOption userProject(String userProject) {
public static BlobWriteOption disableGzipContent() {
return new BlobWriteOption(Option.IF_DISABLE_GZIP_CONTENT, true);
}
+
+ /**
+ * Returns an option for detecting content type. If this option is used, the content type is
+ * detected from the blob name if not explicitly set. This option is on the client side only, it
+ * does not appear in a RPC call.
+ */
+ public static BlobWriteOption detectContentType() {
+ return new BlobWriteOption(Option.DETECT_CONTENT_TYPE, true);
+ }
}
/** Class for specifying blob source options. */
@@ -1832,9 +1851,10 @@ public static Builder newBuilder() {
* Creates a new blob. Direct upload is used to upload {@code content}. For large content, {@link
* #writer} is recommended as it uses resumable upload. MD5 and CRC32C hashes of {@code content}
* are computed and used for validating transferred data. Accepts an optional userProject {@link
- * BlobGetOption} option which defines the project id to assign operational costs.
+ * BlobGetOption} option which defines the project id to assign operational costs. The content
+ * type is detected from the blob name if not explicitly set.
*
- *
Example of creating a blob from a byte array.
+ *
Example of creating a blob from a byte array:
*
*
{@code
* String bucketName = "my-unique-bucket";
@@ -1857,7 +1877,7 @@ public static Builder newBuilder() {
* Accepts a userProject {@link BlobGetOption} option, which defines the project id to assign
* operational costs.
*
- *
Example of creating a blob from a byte array.
+ *
Example of creating a blob from a byte array:
*
*
{@code
* String bucketName = "my-unique-bucket";
@@ -1876,7 +1896,7 @@ Blob create(
/**
* Creates a new blob. Direct upload is used to upload {@code content}. For large content, {@link
- * #writer} is recommended as it uses resumable upload. By default any md5 and crc32c values in
+ * #writer} is recommended as it uses resumable upload. By default any MD5 and CRC32C values in
* the given {@code blobInfo} are ignored unless requested via the {@code
* BlobWriteOption.md5Match} and {@code BlobWriteOption.crc32cMatch} options. The given input
* stream is closed upon success.
@@ -2603,11 +2623,11 @@ Blob createFrom(
ReadChannel reader(BlobId blob, BlobSourceOption... options);
/**
- * Creates a blob and return a channel for writing its content. By default any md5 and crc32c
+ * Creates a blob and returns a channel for writing its content. By default any MD5 and CRC32C
* values in the given {@code blobInfo} are ignored unless requested via the {@code
* BlobWriteOption.md5Match} and {@code BlobWriteOption.crc32cMatch} options.
*
- *
Example of writing a blob's content through a writer.
+ *
Example of writing a blob's content through a writer:
*
*
{@code
* String bucketName = "my-unique-bucket";
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
index 519a9e9fa..ec849281e 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
@@ -77,9 +77,12 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
+import java.net.FileNameMap;
+import java.net.URLConnection;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
public class HttpStorageRpc implements StorageRpc {
@@ -98,6 +101,7 @@ public class HttpStorageRpc implements StorageRpc {
private final HttpRequestInitializer batchRequestInitializer;
private static final long MEGABYTE = 1024L * 1024L;
+ private static final FileNameMap FILE_NAME_MAP = URLConnection.getFileNameMap();
public HttpStorageRpc(StorageOptions options) {
HttpTransportOptions transportOptions = (HttpTransportOptions) options.getTransportOptions();
@@ -286,7 +290,7 @@ public StorageObject create(
.insert(
storageObject.getBucket(),
storageObject,
- new InputStreamContent(storageObject.getContentType(), content));
+ new InputStreamContent(detectContentType(storageObject, options), content));
insert.getMediaHttpUploader().setDirectUploadEnabled(true);
Boolean disableGzipContent = Option.IF_DISABLE_GZIP_CONTENT.getBoolean(options);
if (disableGzipContent != null) {
@@ -372,6 +376,19 @@ public Tuple> list(final String bucket, Map options) {
+ String contentType = object.getContentType();
+ if (contentType != null) {
+ return contentType;
+ }
+
+ if (Boolean.TRUE == Option.DETECT_CONTENT_TYPE.get(options)) {
+ contentType = FILE_NAME_MAP.getContentTypeFor(object.getName().toLowerCase(Locale.ENGLISH));
+ }
+
+ return firstNonNull(contentType, "application/octet-stream");
+ }
+
private static Function objectFromPrefix(final String bucket) {
return new Function() {
@Override
@@ -834,9 +851,7 @@ public String open(StorageObject object, Map
*
* @param blobInfo the blob uploaded in the form
+ * @param duration time before expiration
+ * @param unit duration time unit
* @param fields the fields specified in the form
* @param conditions which conditions every upload must satisfy
* @param duration how long until the form expires, in milliseconds
@@ -2861,9 +2863,8 @@ PostPolicyV4 generateSignedPostPolicyV4(
/**
* Generates a presigned post policy without any conditions. Automatically creates required
- * conditions. See full documentation for generateSignedPostPolicyV4( BlobInfo blobInfo, long
- * duration, TimeUnit unit, PostFieldsV4 fields, PostConditionsV4 conditions,
- * PostPolicyV4Option... options) above.
+ * conditions. See full documentation for {@link #generateSignedPostPolicyV4(BlobInfo, long,
+ * TimeUnit, PostPolicyV4.PostFieldsV4, PostPolicyV4.PostConditionsV4, PostPolicyV4Option...)}.
*/
PostPolicyV4 generateSignedPostPolicyV4(
BlobInfo blobInfo,
@@ -2874,9 +2875,8 @@ PostPolicyV4 generateSignedPostPolicyV4(
/**
* Generates a presigned post policy without any fields. Automatically creates required fields.
- * See full documentation for generateSignedPostPolicyV4( BlobInfo blobInfo, long duration,
- * TimeUnit unit, PostFieldsV4 fields, PostConditionsV4 conditions, PostPolicyV4Option... options)
- * above.
+ * See full documentation for {@link #generateSignedPostPolicyV4(BlobInfo, long, TimeUnit,
+ * PostPolicyV4.PostFieldsV4, PostPolicyV4.PostConditionsV4, PostPolicyV4Option...)}.
*/
PostPolicyV4 generateSignedPostPolicyV4(
BlobInfo blobInfo,
@@ -2887,9 +2887,9 @@ PostPolicyV4 generateSignedPostPolicyV4(
/**
* Generates a presigned post policy without any fields or conditions. Automatically creates
- * required fields and conditions. See full documentation for generateSignedPostPolicyV4( BlobInfo
- * blobInfo, long duration, TimeUnit unit, PostFieldsV4 fields, PostConditionsV4 conditions,
- * PostPolicyV4Option... options) above.
+ * required fields and conditions. See full documentation for {@link
+ * #generateSignedPostPolicyV4(BlobInfo, long, TimeUnit, PostPolicyV4.PostFieldsV4,
+ * PostPolicyV4.PostConditionsV4, PostPolicyV4Option...)}.
*/
PostPolicyV4 generateSignedPostPolicyV4(
BlobInfo blobInfo, long duration, TimeUnit unit, PostPolicyV4Option... options);
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/PostPolicyV4Test.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/PostPolicyV4Test.java
new file mode 100644
index 000000000..8213f6093
--- /dev/null
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/PostPolicyV4Test.java
@@ -0,0 +1,592 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Licensed 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 com.google.cloud.storage;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import org.junit.Test;
+
+public class PostPolicyV4Test {
+ private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+
+ private void assertNotSameButEqual(Map expected, Map returned) {
+ assertNotSame(expected, returned);
+ assertEquals("map sizes", expected.size(), returned.size());
+ for (String key : expected.keySet()) {
+ assertEquals("value of $" + key, expected.get(key), returned.get(key));
+ }
+ }
+
+ private static final String[] VALID_FIELDS = {
+ "acl",
+ "bucket",
+ "cache-control",
+ "content-disposition",
+ "content-encoding",
+ "content-type",
+ "expires",
+ "file",
+ "key",
+ "policy",
+ "success_action_redirect",
+ "success_action_status",
+ "x-goog-algorithm",
+ "x-goog-credential",
+ "x-goog-date",
+ "x-goog-signature",
+ };
+
+ private static final String CUSTOM_PREFIX = "x-goog-meta-";
+
+ private static Map initAllFields() {
+ Map fields = new HashMap<>();
+ for (String key : VALID_FIELDS) {
+ fields.put(key, "value of " + key);
+ }
+ fields.put(CUSTOM_PREFIX + "custom", "value of custom field");
+ return Collections.unmodifiableMap(fields);
+ }
+
+ private static final Map ALL_FIELDS = initAllFields();
+
+ @Test
+ public void testPostPolicyV4_of() {
+ String url = "http://example.com";
+ PostPolicyV4 policy = PostPolicyV4.of(url, ALL_FIELDS);
+ assertEquals(url, policy.getUrl());
+ assertNotSameButEqual(ALL_FIELDS, policy.getFields());
+ }
+
+ @Test
+ public void testPostPolicyV4_ofMalformedURL() {
+ try {
+ PostPolicyV4.of("example.com", new HashMap());
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("example.com is not an absolute URL", e.getMessage());
+ }
+
+ try {
+ PostPolicyV4.of("Scio nescio", new HashMap());
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals(
+ "java.net.URISyntaxException: Illegal character in path at index 4: Scio nescio",
+ e.getMessage());
+ }
+ }
+
+ @Test
+ public void testPostPolicyV4_ofInvalidField() {
+ Map fields = new HashMap<>(ALL_FIELDS);
+ fields.put("$file", "file.txt");
+ try {
+ PostPolicyV4.of("http://google.com", fields);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid key: $file", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testPostFieldsV4_of() {
+ PostPolicyV4.PostFieldsV4 fields = PostPolicyV4.PostFieldsV4.of(ALL_FIELDS);
+ assertNotSameButEqual(ALL_FIELDS, fields.getFieldsMap());
+ }
+
+ @Test
+ public void testPostFieldsV4_ofInvalidField() {
+ Map map = new HashMap<>();
+ map.put("$file", "file.txt");
+ try {
+ PostPolicyV4.PostFieldsV4.of(map);
+ fail();
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid key: $file", e.getMessage());
+ }
+ }
+
+ @Test
+ public void testPostPolicyV4_builder() {
+ PostPolicyV4.PostFieldsV4.Builder builder = PostPolicyV4.PostFieldsV4.newBuilder();
+ builder.setAcl("acl");
+ builder.setCacheControl("cache-control");
+ builder.setContentDisposition("content-disposition");
+ builder.setContentType("content-type");
+ builder.setExpires("expires");
+ builder.setSuccessActionRedirect("success_action_redirect");
+ Map map = builder.build().getFieldsMap();
+ assertEquals("map size", 6, map.size());
+ for (String key : map.keySet()) {
+ assertEquals("value of $" + key, key, map.get(key));
+ }
+
+ Map expectedUpdated = new HashMap<>(map);
+ builder.setCustomMetadataField("xxx", "XXX");
+ builder.setCustomMetadataField(CUSTOM_PREFIX + "yyy", "YYY");
+ builder.setAcl(null);
+ builder.setContentType("new-content-type");
+ builder.setSuccessActionStatus(42);
+ expectedUpdated.put(CUSTOM_PREFIX + "xxx", "XXX");
+ expectedUpdated.put(CUSTOM_PREFIX + "yyy", "YYY");
+ expectedUpdated.put("acl", null);
+ expectedUpdated.put("content-type", "new-content-type");
+ expectedUpdated.put("success_action_status", "42");
+ Map updated = builder.build().getFieldsMap();
+ assertNotSameButEqual(expectedUpdated, updated);
+ }
+
+ @Test
+ public void testPostPolicyV4_setContentLength() {
+ PostPolicyV4.PostFieldsV4.Builder builder = PostPolicyV4.PostFieldsV4.newBuilder();
+ builder.setContentLength(12345);
+ assertTrue(builder.build().getFieldsMap().isEmpty());
+ }
+
+ @Test
+ public void testPostConditionsV4_builder() {
+ PostPolicyV4.PostConditionsV4.Builder builder = PostPolicyV4.PostConditionsV4.newBuilder();
+ assertTrue(builder.build().getConditions().isEmpty());
+
+ builder.addAclCondition(PostPolicyV4.ConditionV4Type.STARTS_WITH, "public");
+ builder.addBucketCondition(PostPolicyV4.ConditionV4Type.MATCHES, "travel-maps");
+ builder.addContentLengthRangeCondition(0, 100000);
+
+ PostPolicyV4.PostConditionsV4 postConditionsV4 = builder.build();
+ Set conditions = postConditionsV4.getConditions();
+ assertEquals(3, conditions.size());
+
+ try {
+ conditions.clear();
+ fail();
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+
+ PostPolicyV4.PostConditionsV4 postConditionsV4Extended =
+ postConditionsV4
+ .toBuilder()
+ .addCustomCondition(PostPolicyV4.ConditionV4Type.STARTS_WITH, "key", "")
+ .build();
+ assertEquals(4, postConditionsV4Extended.getConditions().size());
+ }
+
+ interface ConditionTest {
+ /**
+ * Calls one of addCondition method on the given builder and returns expected ConditionV4
+ * object.
+ */
+ PostPolicyV4.ConditionV4 addCondition(PostPolicyV4.PostConditionsV4.Builder builder);
+ }
+
+ @Test
+ public void testPostConditionsV4_addCondition() {
+ // shortcuts
+ final PostPolicyV4.ConditionV4Type eq = PostPolicyV4.ConditionV4Type.MATCHES;
+ final PostPolicyV4.ConditionV4Type startsWith = PostPolicyV4.ConditionV4Type.STARTS_WITH;
+ final PostPolicyV4.ConditionV4Type range = PostPolicyV4.ConditionV4Type.CONTENT_LENGTH_RANGE;
+
+ ConditionTest[] cases = {
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addContentLengthRangeCondition(123, 456);
+ return new PostPolicyV4.ConditionV4(range, "123", "456");
+ }
+
+ @Override
+ public String toString() {
+ return "addContentLengthRangeCondition()";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ long date = 2000000000000L;
+ builder.addExpiresCondition(date);
+ return new PostPolicyV4.ConditionV4(eq, "expires", dateFormat.format(date));
+ }
+
+ @Override
+ public String toString() {
+ return "addExpiresCondition(long)";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addExpiresCondition("2030-Dec-31");
+ return new PostPolicyV4.ConditionV4(eq, "expires", "2030-Dec-31");
+ }
+
+ @Override
+ public String toString() {
+ return "addExpiresCondition(String)";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addExpiresCondition(range, 0);
+ return new PostPolicyV4.ConditionV4(eq, "expires", dateFormat.format(0));
+ }
+
+ @Override
+ public String toString() {
+ return "@deprecated addExpiresCondition(type,long)";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addExpiresCondition(startsWith, "2030-Dec-31");
+ return new PostPolicyV4.ConditionV4(eq, "expires", "2030-Dec-31");
+ }
+
+ @Override
+ public String toString() {
+ return "@deprecated addExpiresCondition(type,String)";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addSuccessActionStatusCondition(202);
+ return new PostPolicyV4.ConditionV4(eq, "success_action_status", "202");
+ }
+
+ @Override
+ public String toString() {
+ return "addSuccessActionStatusCondition(int)";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addSuccessActionStatusCondition(startsWith, 202);
+ return new PostPolicyV4.ConditionV4(eq, "success_action_status", "202");
+ }
+
+ @Override
+ public String toString() {
+ return "@deprecated addSuccessActionStatusCondition(type,int)";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addAclCondition(startsWith, "read");
+ return new PostPolicyV4.ConditionV4(startsWith, "acl", "read");
+ }
+
+ @Override
+ public String toString() {
+ return "addAclCondition()";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addBucketCondition(eq, "my-bucket");
+ return new PostPolicyV4.ConditionV4(eq, "bucket", "my-bucket");
+ }
+
+ @Override
+ public String toString() {
+ return "addBucketCondition()";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addCacheControlCondition(eq, "false");
+ return new PostPolicyV4.ConditionV4(eq, "cache-control", "false");
+ }
+
+ @Override
+ public String toString() {
+ return "addCacheControlCondition()";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addContentDispositionCondition(startsWith, "gzip");
+ return new PostPolicyV4.ConditionV4(startsWith, "content-disposition", "gzip");
+ }
+
+ @Override
+ public String toString() {
+ return "addContentDispositionCondition()";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addContentEncodingCondition(eq, "koi8");
+ return new PostPolicyV4.ConditionV4(eq, "content-encoding", "koi8");
+ }
+
+ @Override
+ public String toString() {
+ return "addContentEncodingCondition()";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addContentTypeCondition(startsWith, "application/");
+ return new PostPolicyV4.ConditionV4(startsWith, "content-type", "application/");
+ }
+
+ @Override
+ public String toString() {
+ return "addContentTypeCondition()";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addKeyCondition(startsWith, "");
+ return new PostPolicyV4.ConditionV4(startsWith, "key", "");
+ }
+
+ @Override
+ public String toString() {
+ return "addKeyCondition()";
+ }
+ },
+ new ConditionTest() {
+ @Override
+ public PostPolicyV4.ConditionV4 addCondition(
+ PostPolicyV4.PostConditionsV4.Builder builder) {
+ builder.addSuccessActionRedirectUrlCondition(eq, "fail");
+ return new PostPolicyV4.ConditionV4(eq, "success_action_redirect", "fail");
+ }
+
+ @Override
+ public String toString() {
+ return "addSuccessActionRedirectUrlCondition()";
+ }
+ },
+ };
+
+ for (ConditionTest testCase : cases) {
+ PostPolicyV4.PostConditionsV4.Builder builder = PostPolicyV4.PostConditionsV4.newBuilder();
+ PostPolicyV4.ConditionV4 expected = testCase.addCondition(builder);
+ Set conditions = builder.build().getConditions();
+ assertEquals("size", 1, conditions.size());
+ PostPolicyV4.ConditionV4 actual = conditions.toArray(new PostPolicyV4.ConditionV4[1])[0];
+ assertEquals(testCase.toString(), expected, actual);
+ }
+ }
+
+ @Test
+ public void testPostConditionsV4_addConditionFail() {
+ final PostPolicyV4.PostConditionsV4.Builder builder =
+ PostPolicyV4.PostConditionsV4.newBuilder();
+ final PostPolicyV4.ConditionV4Type range = PostPolicyV4.ConditionV4Type.CONTENT_LENGTH_RANGE;
+
+ Callable[] cases = {
+ new Callable() {
+ @Override
+ public Void call() {
+ builder.addAclCondition(range, "");
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "acl";
+ }
+ },
+ new Callable() {
+ @Override
+ public Void call() {
+ builder.addBucketCondition(range, "");
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "bucket";
+ }
+ },
+ new Callable() {
+ @Override
+ public Void call() {
+ builder.addCacheControlCondition(range, "");
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "cache-control";
+ }
+ },
+ new Callable() {
+ @Override
+ public Void call() {
+ builder.addContentDispositionCondition(range, "");
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "content-disposition";
+ }
+ },
+ new Callable() {
+ @Override
+ public Void call() {
+ builder.addContentEncodingCondition(range, "");
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "content-encoding";
+ }
+ },
+ new Callable() {
+ @Override
+ public Void call() {
+ builder.addContentTypeCondition(range, "");
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "content-type";
+ }
+ },
+ new Callable() {
+ @Override
+ public Void call() {
+ builder.addKeyCondition(range, "");
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "key";
+ }
+ },
+ new Callable() {
+ @Override
+ public Void call() {
+ builder.addSuccessActionRedirectUrlCondition(range, "");
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "success_action_redirect";
+ }
+ },
+ };
+
+ for (Callable testCase : cases) {
+ try {
+ testCase.call();
+ fail();
+ } catch (Exception e) {
+ String expected =
+ "java.lang.IllegalArgumentException: Field "
+ + testCase
+ + " can't use content-length-range";
+ assertEquals(expected, e.toString());
+ }
+ }
+ assertTrue(builder.build().getConditions().isEmpty());
+ }
+
+ @Test
+ public void testPostConditionsV4_toString() {
+ PostPolicyV4.PostConditionsV4.Builder builder = PostPolicyV4.PostConditionsV4.newBuilder();
+ builder.addKeyCondition(PostPolicyV4.ConditionV4Type.MATCHES, "test-object");
+ builder.addAclCondition(PostPolicyV4.ConditionV4Type.STARTS_WITH, "public");
+ builder.addContentLengthRangeCondition(246, 266);
+
+ Set toStringSet = new HashSet<>();
+ for (PostPolicyV4.ConditionV4 conditionV4 : builder.build().getConditions()) {
+ toStringSet.add(conditionV4.toString());
+ }
+ assertEquals(3, toStringSet.size());
+
+ String[] expectedStrings = {
+ "[\"eq\", \"$key\", \"test-object\"]",
+ "[\"starts-with\", \"$acl\", \"public\"]",
+ "[\"content-length-range\", 246, 266]"
+ };
+
+ for (String expected : expectedStrings) {
+ assertTrue(expected + "/" + toStringSet, toStringSet.contains(expected));
+ }
+ }
+
+ @Test
+ public void testPostPolicyV4Document_of_toJson() {
+ PostPolicyV4.PostConditionsV4 emptyConditions =
+ PostPolicyV4.PostConditionsV4.newBuilder().build();
+ PostPolicyV4.PostPolicyV4Document emptyDocument =
+ PostPolicyV4.PostPolicyV4Document.of("", emptyConditions);
+ String emptyJson = emptyDocument.toJson();
+ assertEquals(emptyJson, "{\"conditions\":[],\"expiration\":\"\"}");
+
+ PostPolicyV4.PostConditionsV4 postConditionsV4 =
+ PostPolicyV4.PostConditionsV4.newBuilder()
+ .addBucketCondition(PostPolicyV4.ConditionV4Type.MATCHES, "my-bucket")
+ .addKeyCondition(PostPolicyV4.ConditionV4Type.STARTS_WITH, "")
+ .addContentLengthRangeCondition(1, 1000)
+ .build();
+
+ String expiration = dateFormat.format(System.currentTimeMillis());
+ PostPolicyV4.PostPolicyV4Document document =
+ PostPolicyV4.PostPolicyV4Document.of(expiration, postConditionsV4);
+ String json = document.toJson();
+ assertEquals(
+ json,
+ "{\"conditions\":[{\"bucket\":\"my-bucket\"},[\"starts-with\",\"$key\",\"\"],[\"content-length-range\",1,1000]],\"expiration\":\""
+ + expiration
+ + "\"}");
+ }
+}
From 37cb632320c1b3448ff86cca93e64a828e9b900d Mon Sep 17 00:00:00 2001
From: Yoshi Automation Bot
Date: Wed, 26 Aug 2020 09:31:44 -0700
Subject: [PATCH 30/35] build: temporarily disable reporting to unblock
releases
Source-Author: Stephanie Wang
Source-Date: Tue Aug 25 13:05:26 2020 -0400
Source-Repo: googleapis/synthtool
Source-Sha: 968465a1cad496e1292ef4584a054a35f756ff94
Source-Link: https://github.com/googleapis/synthtool/commit/968465a1cad496e1292ef4584a054a35f756ff94
---
.kokoro/release/stage.sh | 5 +++--
synth.metadata | 4 ++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/.kokoro/release/stage.sh b/.kokoro/release/stage.sh
index 3c482cbc5..d19191fc8 100755
--- a/.kokoro/release/stage.sh
+++ b/.kokoro/release/stage.sh
@@ -16,8 +16,9 @@
set -eo pipefail
# Start the releasetool reporter
-python3 -m pip install gcp-releasetool
-python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script
+# Disable reporting due to issue observed with Kokoro blocking releases
+# python3 -m pip install gcp-releasetool
+# python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script
source $(dirname "$0")/common.sh
MAVEN_SETTINGS_FILE=$(realpath $(dirname "$0")/../../)/settings.xml
diff --git a/synth.metadata b/synth.metadata
index 31f1a9816..c283453cd 100644
--- a/synth.metadata
+++ b/synth.metadata
@@ -4,14 +4,14 @@
"git": {
"name": ".",
"remote": "https://github.com/googleapis/java-storage.git",
- "sha": "6c372fa81e49ac74bdda6f9b10914fac42767247"
+ "sha": "8602b81eae95868e184fd4ab290396707bd21a8e"
}
},
{
"git": {
"name": "synthtool",
"remote": "https://github.com/googleapis/synthtool.git",
- "sha": "9602086c6c5b05db77950c7f7495a2a3868f3537"
+ "sha": "968465a1cad496e1292ef4584a054a35f756ff94"
}
}
],
From 1e3e88a391651421469e5c7a8216a788eaa4ba5a Mon Sep 17 00:00:00 2001
From: Ajit Thakor <49403056+athakor@users.noreply.github.com>
Date: Wed, 26 Aug 2020 23:34:29 +0530
Subject: [PATCH 31/35] feat: add support of daysSinceNoncurrentTime and
noncurrentTimeBefore OLM options (#335)
* feat: add support of daysSinceNoncurrentTime and noncurrentTimeBefore OLM options
* feat: add javadoc
* feat: change noncurrentTimeBefore type to date only
* feat: update java doc
---
.../com/google/cloud/storage/BucketInfo.java | 63 +++++++++++++++++--
.../google/cloud/storage/BucketInfoTest.java | 17 +++++
.../google/cloud/storage/StorageImplTest.java | 37 +++++++++++
.../cloud/storage/it/ITStorageTest.java | 4 ++
4 files changed, 117 insertions(+), 4 deletions(-)
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
index b3e96113b..038df91d9 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
@@ -351,7 +351,9 @@ public LifecycleRule(LifecycleAction action, LifecycleCondition condition) {
&& condition.getAge() == null
&& condition.getCreatedBefore() == null
&& condition.getMatchesStorageClass() == null
- && condition.getNumberOfNewerVersions() == null) {
+ && condition.getNumberOfNewerVersions() == null
+ && condition.getDaysSinceNoncurrentTime() == null
+ && condition.getNoncurrentTimeBefore() == null) {
throw new IllegalArgumentException(
"You must specify at least one condition to use object lifecycle "
+ "management. Please see https://cloud.google.com/storage/docs/lifecycle for details.");
@@ -419,7 +421,13 @@ Rule toPb() {
? null
: transform(
lifecycleCondition.getMatchesStorageClass(),
- Functions.toStringFunction()));
+ Functions.toStringFunction()))
+ .setDaysSinceNoncurrentTime(lifecycleCondition.getDaysSinceNoncurrentTime())
+ .setNoncurrentTimeBefore(
+ lifecycleCondition.getNoncurrentTimeBefore() == null
+ ? null
+ : new DateTime(
+ true, lifecycleCondition.getNoncurrentTimeBefore().getValue(), 0));
rule.setCondition(condition);
@@ -462,7 +470,9 @@ static LifecycleRule fromPb(Rule rule) {
public StorageClass apply(String storageClass) {
return StorageClass.valueOf(storageClass);
}
- }));
+ }))
+ .setDaysSinceNoncurrentTime(condition.getDaysSinceNoncurrentTime())
+ .setNoncurrentTimeBefore(condition.getNoncurrentTimeBefore());
return new LifecycleRule(lifecycleAction, conditionBuilder.build());
}
@@ -480,6 +490,8 @@ public static class LifecycleCondition implements Serializable {
private final Integer numberOfNewerVersions;
private final Boolean isLive;
private final List matchesStorageClass;
+ private final Integer daysSinceNoncurrentTime;
+ private final DateTime noncurrentTimeBefore;
private LifecycleCondition(Builder builder) {
this.age = builder.age;
@@ -487,6 +499,8 @@ private LifecycleCondition(Builder builder) {
this.numberOfNewerVersions = builder.numberOfNewerVersions;
this.isLive = builder.isLive;
this.matchesStorageClass = builder.matchesStorageClass;
+ this.daysSinceNoncurrentTime = builder.daysSinceNoncurrentTime;
+ this.noncurrentTimeBefore = builder.noncurrentTimeBefore;
}
public Builder toBuilder() {
@@ -495,7 +509,9 @@ public Builder toBuilder() {
.setCreatedBefore(this.createdBefore)
.setNumberOfNewerVersions(this.numberOfNewerVersions)
.setIsLive(this.isLive)
- .setMatchesStorageClass(this.matchesStorageClass);
+ .setMatchesStorageClass(this.matchesStorageClass)
+ .setDaysSinceNoncurrentTime(this.daysSinceNoncurrentTime)
+ .setNoncurrentTimeBefore(this.noncurrentTimeBefore);
}
public static Builder newBuilder() {
@@ -510,6 +526,8 @@ public String toString() {
.add("numberofNewerVersions", numberOfNewerVersions)
.add("isLive", isLive)
.add("matchesStorageClass", matchesStorageClass)
+ .add("daysSinceNoncurrentTime", daysSinceNoncurrentTime)
+ .add("noncurrentTimeBefore", noncurrentTimeBefore)
.toString();
}
@@ -533,6 +551,18 @@ public List getMatchesStorageClass() {
return matchesStorageClass;
}
+ /** Returns the number of days elapsed since the noncurrent timestamp of an object. */
+ public Integer getDaysSinceNoncurrentTime() {
+ return daysSinceNoncurrentTime;
+ }
+
+ /**
+ * Returns the date in RFC 3339 format with only the date part (for instance, "2013-01-15").
+ */
+ public DateTime getNoncurrentTimeBefore() {
+ return noncurrentTimeBefore;
+ }
+
/** Builder for {@code LifecycleCondition}. */
public static class Builder {
private Integer age;
@@ -540,6 +570,8 @@ public static class Builder {
private Integer numberOfNewerVersions;
private Boolean isLive;
private List matchesStorageClass;
+ private Integer daysSinceNoncurrentTime;
+ private DateTime noncurrentTimeBefore;
private Builder() {}
@@ -594,6 +626,29 @@ public Builder setMatchesStorageClass(List matchesStorageClass) {
return this;
}
+ /**
+ * Sets the number of days elapsed since the noncurrent timestamp of an object. The
+ * condition is satisfied if the days elapsed is at least this number. This condition is
+ * relevant only for versioned objects. The value of the field must be a nonnegative
+ * integer. If it's zero, the object version will become eligible for Lifecycle action as
+ * soon as it becomes noncurrent.
+ */
+ public Builder setDaysSinceNoncurrentTime(Integer daysSinceNoncurrentTime) {
+ this.daysSinceNoncurrentTime = daysSinceNoncurrentTime;
+ return this;
+ }
+
+ /**
+ * Sets the date in RFC 3339 format with only the date part (for instance, "2013-01-15").
+ * Note that only date part will be considered, if the time is specified it will be
+ * truncated. This condition is satisfied when the noncurrent time on an object is before
+ * this date. This condition is relevant only for versioned objects.
+ */
+ public Builder setNoncurrentTimeBefore(DateTime noncurrentTimeBefore) {
+ this.noncurrentTimeBefore = noncurrentTimeBefore;
+ return this;
+ }
+
/** Builds a {@code LifecycleCondition} object. * */
public LifecycleCondition build() {
return new LifecycleCondition(this);
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java
index 425cfb702..c7b3aa198 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import com.google.api.client.util.DateTime;
import com.google.api.services.storage.model.Bucket;
import com.google.api.services.storage.model.Bucket.Lifecycle.Rule;
import com.google.cloud.storage.Acl.Project;
@@ -328,6 +329,22 @@ public void testLifecycleRules() {
setStorageClassLifecycleRule.getAction().getStorageClass());
assertTrue(setStorageClassLifecycleRule.getCondition().getIsLive());
assertEquals(10, setStorageClassLifecycleRule.getCondition().getNumNewerVersions().intValue());
+
+ Rule lifecycleRule =
+ new LifecycleRule(
+ LifecycleAction.newSetStorageClassAction(StorageClass.COLDLINE),
+ LifecycleCondition.newBuilder()
+ .setIsLive(true)
+ .setNumberOfNewerVersions(10)
+ .setDaysSinceNoncurrentTime(30)
+ .setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis()))
+ .build())
+ .toPb();
+ assertEquals(StorageClass.COLDLINE.toString(), lifecycleRule.getAction().getStorageClass());
+ assertTrue(lifecycleRule.getCondition().getIsLive());
+ assertEquals(10, lifecycleRule.getCondition().getNumNewerVersions().intValue());
+ assertEquals(30, lifecycleRule.getCondition().getDaysSinceNoncurrentTime().intValue());
+ assertNotNull(lifecycleRule.getCondition().getNoncurrentTimeBefore());
}
@Test
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java
index 24f5ed9e7..35c4e253c 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java
@@ -29,6 +29,7 @@
import static org.junit.Assert.assertTrue;
import com.google.api.client.googleapis.json.GoogleJsonError;
+import com.google.api.client.util.DateTime;
import com.google.api.core.ApiClock;
import com.google.api.services.storage.model.Policy.Bindings;
import com.google.api.services.storage.model.StorageObject;
@@ -2232,4 +2233,40 @@ public void testV4PostPolicy() {
assertEquals(outputFields.get("key"), "my-object");
assertEquals("https://storage.googleapis.com/my-bucket/", policy.getUrl());
}
+
+ @Test
+ public void testBucketLifecycleRules() {
+ BucketInfo bucketInfo =
+ BucketInfo.newBuilder("b")
+ .setLocation("us")
+ .setLifecycleRules(
+ ImmutableList.of(
+ new BucketInfo.LifecycleRule(
+ BucketInfo.LifecycleRule.LifecycleAction.newSetStorageClassAction(
+ StorageClass.COLDLINE),
+ BucketInfo.LifecycleRule.LifecycleCondition.newBuilder()
+ .setAge(1)
+ .setNumberOfNewerVersions(3)
+ .setIsLive(false)
+ .setCreatedBefore(new DateTime(System.currentTimeMillis()))
+ .setMatchesStorageClass(ImmutableList.of(StorageClass.COLDLINE))
+ .setDaysSinceNoncurrentTime(30)
+ .setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis()))
+ .build())))
+ .build();
+ EasyMock.expect(
+ storageRpcMock.create(bucketInfo.toPb(), new HashMap()))
+ .andReturn(bucketInfo.toPb());
+ EasyMock.replay(storageRpcMock);
+ initializeService();
+ Bucket bucket = storage.create(bucketInfo);
+ BucketInfo.LifecycleRule lifecycleRule = bucket.getLifecycleRules().get(0);
+ assertEquals(3, lifecycleRule.getCondition().getNumberOfNewerVersions().intValue());
+ assertNotNull(lifecycleRule.getCondition().getCreatedBefore());
+ assertFalse(lifecycleRule.getCondition().getIsLive());
+ assertEquals(1, lifecycleRule.getCondition().getAge().intValue());
+ assertEquals(1, lifecycleRule.getCondition().getMatchesStorageClass().size());
+ assertEquals(30, lifecycleRule.getCondition().getDaysSinceNoncurrentTime().intValue());
+ assertNotNull(lifecycleRule.getCondition().getNoncurrentTimeBefore());
+ }
}
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
index a741f3eb7..d92ca5921 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
@@ -456,6 +456,8 @@ public void testGetBucketLifecycleRules() {
.setIsLive(false)
.setCreatedBefore(new DateTime(System.currentTimeMillis()))
.setMatchesStorageClass(ImmutableList.of(StorageClass.COLDLINE))
+ .setDaysSinceNoncurrentTime(30)
+ .setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis()))
.build())))
.build());
Bucket remoteBucket =
@@ -472,6 +474,8 @@ public void testGetBucketLifecycleRules() {
assertFalse(lifecycleRule.getCondition().getIsLive());
assertEquals(1, lifecycleRule.getCondition().getAge().intValue());
assertEquals(1, lifecycleRule.getCondition().getMatchesStorageClass().size());
+ assertEquals(30, lifecycleRule.getCondition().getDaysSinceNoncurrentTime().intValue());
+ assertNotNull(lifecycleRule.getCondition().getNoncurrentTimeBefore());
} finally {
storage.delete(lifecycleTestBucketName);
}
From cf94230a5f02dcc16e364aa528d97046d80f59a0 Mon Sep 17 00:00:00 2001
From: WhiteSource Renovate
Date: Wed, 26 Aug 2020 20:05:10 +0200
Subject: [PATCH 32/35] deps: update dependency
com.google.api.grpc:grpc-google-cloud-kms-v1 to v0.86.1 (#463)
---
google-cloud-storage/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/google-cloud-storage/pom.xml b/google-cloud-storage/pom.xml
index 587822656..6db71ffd4 100644
--- a/google-cloud-storage/pom.xml
+++ b/google-cloud-storage/pom.xml
@@ -117,7 +117,7 @@
com.google.api.grpcgrpc-google-cloud-kms-v1
- 0.86.0
+ 0.86.1test
From 1af8288016f2526ddbe221ef22dc705e28b18b77 Mon Sep 17 00:00:00 2001
From: Ajit Thakor <49403056+athakor@users.noreply.github.com>
Date: Thu, 27 Aug 2020 20:16:07 +0530
Subject: [PATCH 33/35] feat: add support of customTimeBefore and
daysSinceCustomTime (#396)
* feat: add support of customTimeBefore and daysSinceCustomTime
* feat: add javadoc
* feat: change customTimeBefore type to date only
* feat: update javadoc
* feat: updated java doc
---
.../com/google/cloud/storage/BucketInfo.java | 58 +++++++++++++++++--
.../google/cloud/storage/BucketInfoTest.java | 5 ++
.../google/cloud/storage/StorageImplTest.java | 4 ++
.../cloud/storage/it/ITStorageTest.java | 4 ++
4 files changed, 67 insertions(+), 4 deletions(-)
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
index 038df91d9..602be08ac 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BucketInfo.java
@@ -353,7 +353,9 @@ public LifecycleRule(LifecycleAction action, LifecycleCondition condition) {
&& condition.getMatchesStorageClass() == null
&& condition.getNumberOfNewerVersions() == null
&& condition.getDaysSinceNoncurrentTime() == null
- && condition.getNoncurrentTimeBefore() == null) {
+ && condition.getNoncurrentTimeBefore() == null
+ && condition.getCustomTimeBefore() == null
+ && condition.getDaysSinceCustomTime() == null) {
throw new IllegalArgumentException(
"You must specify at least one condition to use object lifecycle "
+ "management. Please see https://cloud.google.com/storage/docs/lifecycle for details.");
@@ -427,7 +429,12 @@ Rule toPb() {
lifecycleCondition.getNoncurrentTimeBefore() == null
? null
: new DateTime(
- true, lifecycleCondition.getNoncurrentTimeBefore().getValue(), 0));
+ true, lifecycleCondition.getNoncurrentTimeBefore().getValue(), 0))
+ .setCustomTimeBefore(
+ lifecycleCondition.getCustomTimeBefore() == null
+ ? null
+ : new DateTime(true, lifecycleCondition.getCustomTimeBefore().getValue(), 0))
+ .setDaysSinceCustomTime(lifecycleCondition.getDaysSinceCustomTime());
rule.setCondition(condition);
@@ -472,7 +479,9 @@ public StorageClass apply(String storageClass) {
}
}))
.setDaysSinceNoncurrentTime(condition.getDaysSinceNoncurrentTime())
- .setNoncurrentTimeBefore(condition.getNoncurrentTimeBefore());
+ .setNoncurrentTimeBefore(condition.getNoncurrentTimeBefore())
+ .setCustomTimeBefore(condition.getCustomTimeBefore())
+ .setDaysSinceCustomTime(condition.getDaysSinceCustomTime());
return new LifecycleRule(lifecycleAction, conditionBuilder.build());
}
@@ -492,6 +501,8 @@ public static class LifecycleCondition implements Serializable {
private final List matchesStorageClass;
private final Integer daysSinceNoncurrentTime;
private final DateTime noncurrentTimeBefore;
+ private final DateTime customTimeBefore;
+ private final Integer daysSinceCustomTime;
private LifecycleCondition(Builder builder) {
this.age = builder.age;
@@ -501,6 +512,8 @@ private LifecycleCondition(Builder builder) {
this.matchesStorageClass = builder.matchesStorageClass;
this.daysSinceNoncurrentTime = builder.daysSinceNoncurrentTime;
this.noncurrentTimeBefore = builder.noncurrentTimeBefore;
+ this.customTimeBefore = builder.customTimeBefore;
+ this.daysSinceCustomTime = builder.daysSinceCustomTime;
}
public Builder toBuilder() {
@@ -511,7 +524,9 @@ public Builder toBuilder() {
.setIsLive(this.isLive)
.setMatchesStorageClass(this.matchesStorageClass)
.setDaysSinceNoncurrentTime(this.daysSinceNoncurrentTime)
- .setNoncurrentTimeBefore(this.noncurrentTimeBefore);
+ .setNoncurrentTimeBefore(this.noncurrentTimeBefore)
+ .setCustomTimeBefore(this.customTimeBefore)
+ .setDaysSinceCustomTime(this.daysSinceCustomTime);
}
public static Builder newBuilder() {
@@ -528,6 +543,8 @@ public String toString() {
.add("matchesStorageClass", matchesStorageClass)
.add("daysSinceNoncurrentTime", daysSinceNoncurrentTime)
.add("noncurrentTimeBefore", noncurrentTimeBefore)
+ .add("customTimeBefore", customTimeBefore)
+ .add("daysSinceCustomTime", daysSinceCustomTime)
.toString();
}
@@ -563,6 +580,16 @@ public DateTime getNoncurrentTimeBefore() {
return noncurrentTimeBefore;
}
+ /* Returns the date in RFC 3339 format with only the date part (for instance, "2013-01-15").*/
+ public DateTime getCustomTimeBefore() {
+ return customTimeBefore;
+ }
+
+ /** Returns the number of days elapsed since the user-specified timestamp set on an object. */
+ public Integer getDaysSinceCustomTime() {
+ return daysSinceCustomTime;
+ }
+
/** Builder for {@code LifecycleCondition}. */
public static class Builder {
private Integer age;
@@ -572,6 +599,8 @@ public static class Builder {
private List matchesStorageClass;
private Integer daysSinceNoncurrentTime;
private DateTime noncurrentTimeBefore;
+ private DateTime customTimeBefore;
+ private Integer daysSinceCustomTime;
private Builder() {}
@@ -649,6 +678,27 @@ public Builder setNoncurrentTimeBefore(DateTime noncurrentTimeBefore) {
return this;
}
+ /**
+ * Sets the date in RFC 3339 format with only the date part (for instance, "2013-01-15").
+ * Note that only date part will be considered, if the time is specified it will be
+ * truncated. This condition is satisfied when the custom time on an object is before this
+ * date in UTC.
+ */
+ public Builder setCustomTimeBefore(DateTime customTimeBefore) {
+ this.customTimeBefore = customTimeBefore;
+ return this;
+ }
+
+ /**
+ * Sets the number of days elapsed since the user-specified timestamp set on an object. The
+ * condition is satisfied if the days elapsed is at least this number. If no custom
+ * timestamp is specified on an object, the condition does not apply.
+ */
+ public Builder setDaysSinceCustomTime(Integer daysSinceCustomTime) {
+ this.daysSinceCustomTime = daysSinceCustomTime;
+ return this;
+ }
+
/** Builds a {@code LifecycleCondition} object. * */
public LifecycleCondition build() {
return new LifecycleCondition(this);
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java
index c7b3aa198..8def7c306 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BucketInfoTest.java
@@ -338,6 +338,8 @@ public void testLifecycleRules() {
.setNumberOfNewerVersions(10)
.setDaysSinceNoncurrentTime(30)
.setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis()))
+ .setCustomTimeBefore(new DateTime(System.currentTimeMillis()))
+ .setDaysSinceCustomTime(30)
.build())
.toPb();
assertEquals(StorageClass.COLDLINE.toString(), lifecycleRule.getAction().getStorageClass());
@@ -345,6 +347,9 @@ public void testLifecycleRules() {
assertEquals(10, lifecycleRule.getCondition().getNumNewerVersions().intValue());
assertEquals(30, lifecycleRule.getCondition().getDaysSinceNoncurrentTime().intValue());
assertNotNull(lifecycleRule.getCondition().getNoncurrentTimeBefore());
+ assertEquals(StorageClass.COLDLINE.toString(), lifecycleRule.getAction().getStorageClass());
+ assertEquals(30, lifecycleRule.getCondition().getDaysSinceCustomTime().intValue());
+ assertNotNull(lifecycleRule.getCondition().getCustomTimeBefore());
}
@Test
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java
index 35c4e253c..590fe37af 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageImplTest.java
@@ -2252,6 +2252,8 @@ public void testBucketLifecycleRules() {
.setMatchesStorageClass(ImmutableList.of(StorageClass.COLDLINE))
.setDaysSinceNoncurrentTime(30)
.setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis()))
+ .setCustomTimeBefore(new DateTime(System.currentTimeMillis()))
+ .setDaysSinceCustomTime(30)
.build())))
.build();
EasyMock.expect(
@@ -2268,5 +2270,7 @@ public void testBucketLifecycleRules() {
assertEquals(1, lifecycleRule.getCondition().getMatchesStorageClass().size());
assertEquals(30, lifecycleRule.getCondition().getDaysSinceNoncurrentTime().intValue());
assertNotNull(lifecycleRule.getCondition().getNoncurrentTimeBefore());
+ assertEquals(30, lifecycleRule.getCondition().getDaysSinceCustomTime().intValue());
+ assertNotNull(lifecycleRule.getCondition().getCustomTimeBefore());
}
}
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
index d92ca5921..52947795b 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java
@@ -458,6 +458,8 @@ public void testGetBucketLifecycleRules() {
.setMatchesStorageClass(ImmutableList.of(StorageClass.COLDLINE))
.setDaysSinceNoncurrentTime(30)
.setNoncurrentTimeBefore(new DateTime(System.currentTimeMillis()))
+ .setCustomTimeBefore(new DateTime(System.currentTimeMillis()))
+ .setDaysSinceCustomTime(30)
.build())))
.build());
Bucket remoteBucket =
@@ -476,6 +478,8 @@ public void testGetBucketLifecycleRules() {
assertEquals(1, lifecycleRule.getCondition().getMatchesStorageClass().size());
assertEquals(30, lifecycleRule.getCondition().getDaysSinceNoncurrentTime().intValue());
assertNotNull(lifecycleRule.getCondition().getNoncurrentTimeBefore());
+ assertEquals(30, lifecycleRule.getCondition().getDaysSinceCustomTime().intValue());
+ assertNotNull(lifecycleRule.getCondition().getCustomTimeBefore());
} finally {
storage.delete(lifecycleTestBucketName);
}
From 6f4585eb6706390865cf5fb565fa8062d0071045 Mon Sep 17 00:00:00 2001
From: Ajit Thakor <49403056+athakor@users.noreply.github.com>
Date: Fri, 28 Aug 2020 04:28:34 +0530
Subject: [PATCH 34/35] feat: add support of customTime metadata (#413)
* feat: support customTime metadata
* feat: add javaDoc
* feat: address few nits
* feat: fix the api breaking change
* Add exception to avoid breaking change
* Add exception to avoid breaking change
Co-authored-by: Jesse Lovelace
---
.../java/com/google/cloud/storage/Blob.java | 6 +++
.../com/google/cloud/storage/BlobInfo.java | 41 +++++++++++++++++++
.../google/cloud/storage/BlobInfoTest.java | 6 +++
.../com/google/cloud/storage/BlobTest.java | 5 +++
.../cloud/storage/it/ITStorageTest.java | 4 +-
5 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java
index 679b410a6..398eb3166 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java
@@ -434,6 +434,12 @@ Builder setCreateTime(Long createTime) {
return this;
}
+ @Override
+ public Builder setCustomTime(Long customTime) {
+ infoBuilder.setCustomTime(customTime);
+ return this;
+ }
+
@Override
Builder setIsDirectory(boolean isDirectory) {
infoBuilder.setIsDirectory(isDirectory);
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java
index ef38ba033..67256d1c7 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java
@@ -84,6 +84,7 @@ public StorageObject apply(BlobInfo blobInfo) {
private final String etag;
private final String md5;
private final String crc32c;
+ private final Long customTime;
private final String mediaLink;
private final Map metadata;
private final Long metageneration;
@@ -260,6 +261,26 @@ public abstract static class Builder {
*/
public abstract Builder setCrc32c(String crc32c);
+ /**
+ * Sets the custom time for an object. Once set it can't be unset and only changed to a custom
+ * datetime in the future. To unset the custom time, you must either perform a rewrite operation
+ * or upload the data again.
+ *
+ *