Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat: expose timeStorageClassUpdated property of blob's (#456)
* feat: expose timeStorageClassUpdated field of blob

* fix: package imports

* feat: update javadoc

* feat: add exception to avoid breaking change
  • Loading branch information
athakor committed Sep 3, 2020
1 parent db358c8 commit 57853ec
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 1 deletion.
Expand Up @@ -410,6 +410,12 @@ public Builder setStorageClass(StorageClass storageClass) {
return this;
}

@Override
public Builder setTimeStorageClassUpdated(Long timeStorageClassUpdated) {
infoBuilder.setTimeStorageClassUpdated(timeStorageClassUpdated);
return this;
}

@Override
Builder setMetageneration(Long metageneration) {
infoBuilder.setMetageneration(metageneration);
Expand Down
Expand Up @@ -96,6 +96,7 @@ public StorageObject apply(BlobInfo blobInfo) {
private final String contentDisposition;
private final String contentLanguage;
private final StorageClass storageClass;
private final Long timeStorageClassUpdated;
private final Integer componentCount;
private final boolean isDirectory;
private final CustomerEncryption customerEncryption;
Expand Down Expand Up @@ -297,6 +298,16 @@ public Builder setCustomTime(Long customTime) {
/** Sets the blob's storage class. */
public abstract Builder setStorageClass(StorageClass storageClass);

/**
* Sets the modification time of an object's storage class. Once set it can't be unset directly,
* the only way is to rewrite the object with the desired storage class.
*/
public Builder setTimeStorageClassUpdated(Long timeStorageClassUpdated) {
throw new UnsupportedOperationException(
"Override setTimeStorageClassUpdated with your own implementation,"
+ " or use com.google.cloud.storage.Blob.");
}

/** Sets the blob's user provided metadata. */
public abstract Builder setMetadata(Map<String, String> metadata);

Expand Down Expand Up @@ -356,6 +367,7 @@ static final class BuilderImpl extends Builder {
private Boolean isDirectory;
private CustomerEncryption customerEncryption;
private StorageClass storageClass;
private Long timeStorageClassUpdated;
private String kmsKeyName;
private Boolean eventBasedHold;
private Boolean temporaryHold;
Expand Down Expand Up @@ -391,6 +403,7 @@ static final class BuilderImpl extends Builder {
createTime = blobInfo.createTime;
isDirectory = blobInfo.isDirectory;
storageClass = blobInfo.storageClass;
timeStorageClassUpdated = blobInfo.timeStorageClassUpdated;
kmsKeyName = blobInfo.kmsKeyName;
eventBasedHold = blobInfo.eventBasedHold;
temporaryHold = blobInfo.temporaryHold;
Expand Down Expand Up @@ -564,6 +577,12 @@ public Builder setStorageClass(StorageClass storageClass) {
return this;
}

@Override
public Builder setTimeStorageClassUpdated(Long timeStorageClassUpdated) {
this.timeStorageClassUpdated = timeStorageClassUpdated;
return this;
}

@Override
Builder setMetageneration(Long metageneration) {
this.metageneration = metageneration;
Expand Down Expand Up @@ -657,6 +676,7 @@ public BlobInfo build() {
createTime = builder.createTime;
isDirectory = firstNonNull(builder.isDirectory, Boolean.FALSE);
storageClass = builder.storageClass;
timeStorageClassUpdated = builder.timeStorageClassUpdated;
kmsKeyName = builder.kmsKeyName;
eventBasedHold = builder.eventBasedHold;
temporaryHold = builder.temporaryHold;
Expand Down Expand Up @@ -917,6 +937,14 @@ public StorageClass getStorageClass() {
return storageClass;
}

/**
* Returns the time that the object's storage class was last changed or the time of the object
* creation.
*/
public Long getTimeStorageClassUpdated() {
return timeStorageClassUpdated;
}

/** Returns the Cloud KMS key used to encrypt the blob, if any. */
public String getKmsKeyName() {
return kmsKeyName;
Expand Down Expand Up @@ -1049,6 +1077,9 @@ public ObjectAccessControl apply(Acl acl) {
if (storageClass != null) {
storageObject.setStorageClass(storageClass.toString());
}
if (timeStorageClassUpdated != null) {
storageObject.setTimeStorageClassUpdated(new DateTime(timeStorageClassUpdated));
}

Map<String, String> pbMetadata = metadata;
if (metadata != null && !Data.isNull(metadata)) {
Expand Down Expand Up @@ -1193,6 +1224,9 @@ public Acl apply(ObjectAccessControl objectAccessControl) {
if (storageObject.getStorageClass() != null) {
builder.setStorageClass(StorageClass.valueOf(storageObject.getStorageClass()));
}
if (storageObject.getTimeStorageClassUpdated() != null) {
builder.setTimeStorageClassUpdated(storageObject.getTimeStorageClassUpdated().getValue());
}
if (storageObject.getKmsKeyName() != null) {
builder.setKmsKeyName(storageObject.getKmsKeyName());
}
Expand Down
Expand Up @@ -154,7 +154,8 @@ enum BlobField implements FieldSelector {
TEMPORARY_HOLD("temporaryHold"),
RETENTION_EXPIRATION_TIME("retentionExpirationTime"),
UPDATED("updated"),
CUSTOM_TIME("customTime");
CUSTOM_TIME("customTime"),
TIME_STORAGE_CLASS_UPDATED("timeStorageClassUpdated");

static final List<? extends FieldSelector> REQUIRED_FIELDS = ImmutableList.of(BUCKET, NAME);

Expand Down
Expand Up @@ -75,6 +75,7 @@ public class BlobInfoTest {
private static final String KMS_KEY_NAME =
"projects/p/locations/kr-loc/keyRings/kr/cryptoKeys/key";
private static final StorageClass STORAGE_CLASS = StorageClass.COLDLINE;
private static final Long TIME_STORAGE_CLASS_UPDATED = CREATE_TIME;
private static final Boolean EVENT_BASED_HOLD = true;
private static final Boolean TEMPORARY_HOLD = true;
private static final Long RETENTION_EXPIRATION_TIME = 10L;
Expand Down Expand Up @@ -104,6 +105,7 @@ public class BlobInfoTest {
.setCreateTime(CREATE_TIME)
.setCustomTime(CUSTOM_TIME)
.setStorageClass(STORAGE_CLASS)
.setTimeStorageClassUpdated(TIME_STORAGE_CLASS_UPDATED)
.setKmsKeyName(KMS_KEY_NAME)
.setEventBasedHold(EVENT_BASED_HOLD)
.setTemporaryHold(TEMPORARY_HOLD)
Expand Down Expand Up @@ -199,6 +201,7 @@ public void testBuilder() {
assertEquals(CREATE_TIME, BLOB_INFO.getCreateTime());
assertEquals(CUSTOM_TIME, BLOB_INFO.getCustomTime());
assertEquals(STORAGE_CLASS, BLOB_INFO.getStorageClass());
assertEquals(TIME_STORAGE_CLASS_UPDATED, BLOB_INFO.getTimeStorageClassUpdated());
assertEquals(KMS_KEY_NAME, BLOB_INFO.getKmsKeyName());
assertEquals(EVENT_BASED_HOLD, BLOB_INFO.getEventBasedHold());
assertEquals(TEMPORARY_HOLD, BLOB_INFO.getTemporaryHold());
Expand Down Expand Up @@ -264,6 +267,7 @@ private void compareBlobs(BlobInfo expected, BlobInfo value) {
assertEquals(expected.getCustomTime(), value.getCustomTime());
assertEquals(expected.getUpdateTime(), value.getUpdateTime());
assertEquals(expected.getStorageClass(), value.getStorageClass());
assertEquals(expected.getTimeStorageClassUpdated(), value.getTimeStorageClassUpdated());
assertEquals(expected.getKmsKeyName(), value.getKmsKeyName());
assertEquals(expected.getEventBasedHold(), value.getEventBasedHold());
assertEquals(expected.getTemporaryHold(), value.getTemporaryHold());
Expand Down Expand Up @@ -319,6 +323,7 @@ public void testToPbAndFromPb() {
assertEquals(0L, (long) blobInfo.getSize());
assertNull(blobInfo.getUpdateTime());
assertNull(blobInfo.getStorageClass());
assertNull(blobInfo.getTimeStorageClassUpdated());
assertNull(blobInfo.getKmsKeyName());
assertNull(blobInfo.getEventBasedHold());
assertNull(blobInfo.getTemporaryHold());
Expand Down
Expand Up @@ -92,6 +92,8 @@ public class BlobTest {
private static final Long UPDATE_TIME = DELETE_TIME - 1L;
private static final Long CREATE_TIME = UPDATE_TIME - 1L;
private static final Long CUSTOM_TIME = CREATE_TIME - 1L;
private static final StorageClass STORAGE_CLASS = StorageClass.COLDLINE;
private static final Long TIME_STORAGE_CLASS_UPDATED = CREATE_TIME;
private static final String ENCRYPTION_ALGORITHM = "AES256";
private static final String KEY_SHA256 = "keySha";
private static final BlobInfo.CustomerEncryption CUSTOMER_ENCRYPTION =
Expand Down Expand Up @@ -124,6 +126,8 @@ public class BlobTest {
.setUpdateTime(UPDATE_TIME)
.setCreateTime(CREATE_TIME)
.setCustomTime(CUSTOM_TIME)
.setStorageClass(STORAGE_CLASS)
.setTimeStorageClassUpdated(TIME_STORAGE_CLASS_UPDATED)
.setCustomerEncryption(CUSTOMER_ENCRYPTION)
.setKmsKeyName(KMS_KEY_NAME)
.setEventBasedHold(EVENT_BASED_HOLD)
Expand Down Expand Up @@ -513,6 +517,8 @@ public void testBuilder() {
.setCrc32c(CRC32)
.setCreateTime(CREATE_TIME)
.setCustomTime(CUSTOM_TIME)
.setStorageClass(STORAGE_CLASS)
.setTimeStorageClassUpdated(TIME_STORAGE_CLASS_UPDATED)
.setCustomerEncryption(CUSTOMER_ENCRYPTION)
.setKmsKeyName(KMS_KEY_NAME)
.setEventBasedHold(EVENT_BASED_HOLD)
Expand Down Expand Up @@ -543,6 +549,8 @@ public void testBuilder() {
assertEquals(CRC32_HEX_STRING, blob.getCrc32cToHexString());
assertEquals(CREATE_TIME, blob.getCreateTime());
assertEquals(CUSTOM_TIME, blob.getCustomTime());
assertEquals(STORAGE_CLASS, blob.getStorageClass());
assertEquals(TIME_STORAGE_CLASS_UPDATED, blob.getTimeStorageClassUpdated());
assertEquals(CUSTOMER_ENCRYPTION, blob.getCustomerEncryption());
assertEquals(KMS_KEY_NAME, blob.getKmsKeyName());
assertEquals(EVENT_BASED_HOLD, blob.getEventBasedHold());
Expand Down Expand Up @@ -576,6 +584,8 @@ public void testBuilder() {
assertNull(blob.getCrc32c());
assertNull(blob.getCrc32cToHexString());
assertNull(blob.getCreateTime());
assertNull(blob.getStorageClass());
assertNull(blob.getTimeStorageClassUpdated());
assertNull(blob.getCustomerEncryption());
assertNull(blob.getKmsKeyName());
assertNull(blob.getEventBasedHold());
Expand Down
Expand Up @@ -3567,4 +3567,42 @@ public void testBucketUpdateTime() throws ExecutionException, InterruptedExcepti
RemoteStorageHelper.forceDelete(storage, bucketName, 5, TimeUnit.SECONDS);
}
}

@Test
public void testBlobTimeStorageClassUpdated() {
String blobName = "test-blob-with-storage-class";
StorageClass storageClass = StorageClass.COLDLINE;
BlobInfo blob = BlobInfo.newBuilder(BUCKET, blobName).setStorageClass(storageClass).build();
Blob remoteBlob = storage.create(blob);
assertThat(remoteBlob).isNotNull();
assertThat(remoteBlob.getBucket()).isEqualTo(blob.getBucket());
assertThat(remoteBlob.getName()).isEqualTo(blob.getName());
assertThat(remoteBlob.getCreateTime()).isNotNull();
assertThat(remoteBlob.getUpdateTime()).isEqualTo(remoteBlob.getCreateTime());
assertThat(remoteBlob.getTimeStorageClassUpdated()).isEqualTo(remoteBlob.getCreateTime());

// We can't change an object's storage class directly, the only way is to rewrite the object
// with the desired storage class.
BlobId blobId = BlobId.of(BUCKET, blobName);
Storage.CopyRequest request =
Storage.CopyRequest.newBuilder()
.setSource(blobId)
.setTarget(BlobInfo.newBuilder(blobId).setStorageClass(StorageClass.STANDARD).build())
.build();
Blob updatedBlob1 = storage.copy(request).getResult();
assertThat(updatedBlob1.getTimeStorageClassUpdated()).isNotNull();
assertThat(updatedBlob1.getCreateTime()).isGreaterThan(remoteBlob.getCreateTime());
assertThat(updatedBlob1.getUpdateTime()).isGreaterThan(remoteBlob.getCreateTime());
assertThat(updatedBlob1.getTimeStorageClassUpdated())
.isGreaterThan(remoteBlob.getTimeStorageClassUpdated());

// Updates the other properties of the blob's to check the difference between blob updateTime
// and timeStorageClassUpdated.
Blob updatedBlob2 = updatedBlob1.toBuilder().setContentType(CONTENT_TYPE).build().update();
assertThat(updatedBlob2.getUpdateTime())
.isGreaterThan(updatedBlob2.getTimeStorageClassUpdated());
assertThat(updatedBlob2.getTimeStorageClassUpdated())
.isEqualTo(updatedBlob1.getTimeStorageClassUpdated());
assertThat(updatedBlob2.delete()).isTrue();
}
}

0 comments on commit 57853ec

Please sign in to comment.