Skip to content

Commit a2bab58

Browse files
authored
fix: blob.reload() does not work as intuitively expected (#308)
* fix: blob.reload() does not work as intuitively expected * fix: blob.reload() does not work as intuitively expected * fix: blob.reload() does not work as intuitively expected * fix: blob.reload() does not work as intuitively expected * fix: blob.reload() does not work as intuitively expected * fix: blob.reload() does not work as intuitively expected
1 parent 9201de5 commit a2bab58

File tree

3 files changed

+73
-19
lines changed

3 files changed

+73
-19
lines changed

google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java

+27-9
Original file line numberDiff line numberDiff line change
@@ -525,24 +525,41 @@ public byte[] getContent(BlobSourceOption... options) {
525525
}
526526

527527
/**
528-
* Fetches current blob's latest information. Returns {@code null} if the blob does not exist.
528+
* Fetches the latest blob properties. Returns {@code null} if the blob no longer exists.
529529
*
530-
* <p>Example of getting the blob's latest information, if its generation does not match the
531-
* {@link Blob#getGeneration()} value, otherwise a {@link StorageException} is thrown.
530+
* <p>{@code options} parameter can contain the preconditions. For example, the user might want to
531+
* get the blob properties only if the content has not been updated externally. {@code
532+
* StorageException} with the code {@code 412} is thrown if preconditions fail.
533+
*
534+
* <p>Example of retrieving the blob's latest information only if the content is not updated
535+
* externally:
532536
*
533537
* <pre>{@code
534-
* Blob latestBlob = blob.reload(BlobSourceOption.generationNotMatch());
535-
* if (latestBlob == null) {
536-
* // the blob was not found
538+
* Blob blob = storage.get(BlobId.of(bucketName, blobName));
539+
*
540+
* doSomething();
541+
*
542+
* try {
543+
* blob = blob.reload(Blob.BlobSourceOption.generationMatch());
544+
* } catch (StorageException e) {
545+
* if (e.getCode() == 412) {
546+
* // the content was updated externally
547+
* } else {
548+
* throw e;
549+
* }
537550
* }
538551
* }</pre>
539552
*
540-
* @param options blob read options
541-
* @return a {@code Blob} object with latest information or {@code null} if not found
553+
* @param options preconditions to use on reload, see <a
554+
* href="https://cloud.google.com/storage/docs/json_api/v1/objects/get">https://cloud.google.com/storage/docs/json_api/v1/objects/get</a>
555+
* for more information.
556+
* @return a {@code Blob} object with latest information or {@code null} if no longer exists.
542557
* @throws StorageException upon failure
543558
*/
544559
public Blob reload(BlobSourceOption... options) {
545-
return storage.get(getBlobId(), toGetOptions(this, options));
560+
// BlobId with generation unset is needed to retrieve the latest version of the Blob
561+
BlobId idWithoutGeneration = BlobId.of(getBucket(), getName());
562+
return storage.get(idWithoutGeneration, toGetOptions(this, options));
546563
}
547564

548565
/**
@@ -730,6 +747,7 @@ public ReadChannel reader(BlobSourceOption... options) {
730747
* } catch (IOException ex) {
731748
* // handle exception
732749
* }
750+
* blob = blob.reload();
733751
* }</pre>
734752
*
735753
* @param options target blob options

google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java

+16-10
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,11 @@ public class BlobTest {
129129
.setRetentionExpirationTime(RETENTION_EXPIRATION_TIME)
130130
.build();
131131
private static final BlobInfo BLOB_INFO =
132-
BlobInfo.newBuilder("b", "n").setMetageneration(42L).build();
132+
BlobInfo.newBuilder("b", "n", 12345678L).setMetageneration(42L).build();
133+
private static final BlobInfo BLOB_INFO_NO_GENERATION =
134+
BlobInfo.newBuilder(BLOB_INFO.getBucket(), BLOB_INFO.getName())
135+
.setMetageneration(42L)
136+
.build();
133137
private static final BlobInfo DIRECTORY_INFO =
134138
BlobInfo.newBuilder("b", "n/").setSize(0L).setIsDirectory(true).build();
135139
private static final String BASE64_KEY = "JVzfVl8NLD9FjedFuStegjRfES5ll5zc59CIXw572OA=";
@@ -233,7 +237,7 @@ public void testReload() throws Exception {
233237
initializeExpectedBlob(2);
234238
Blob expectedReloadedBlob = expectedBlob.toBuilder().setCacheControl("c").build();
235239
expect(storage.getOptions()).andReturn(mockOptions);
236-
expect(storage.get(BLOB_INFO.getBlobId(), new Storage.BlobGetOption[0]))
240+
expect(storage.get(BLOB_INFO_NO_GENERATION.getBlobId(), new Storage.BlobGetOption[0]))
237241
.andReturn(expectedReloadedBlob);
238242
replay(storage);
239243
initializeBlob();
@@ -245,7 +249,8 @@ public void testReload() throws Exception {
245249
public void testReloadNull() throws Exception {
246250
initializeExpectedBlob(1);
247251
expect(storage.getOptions()).andReturn(mockOptions);
248-
expect(storage.get(BLOB_INFO.getBlobId(), new Storage.BlobGetOption[0])).andReturn(null);
252+
expect(storage.get(BLOB_INFO_NO_GENERATION.getBlobId(), new Storage.BlobGetOption[0]))
253+
.andReturn(null);
249254
replay(storage);
250255
initializeBlob();
251256
Blob reloadedBlob = blob.reload();
@@ -258,7 +263,8 @@ public void testReloadWithOptions() throws Exception {
258263
Blob expectedReloadedBlob = expectedBlob.toBuilder().setCacheControl("c").build();
259264
Storage.BlobGetOption[] options = {Storage.BlobGetOption.metagenerationMatch(42L)};
260265
expect(storage.getOptions()).andReturn(mockOptions);
261-
expect(storage.get(BLOB_INFO.getBlobId(), options)).andReturn(expectedReloadedBlob);
266+
expect(storage.get(BLOB_INFO_NO_GENERATION.getBlobId(), options))
267+
.andReturn(expectedReloadedBlob);
262268
replay(storage);
263269
initializeBlob();
264270
Blob updatedBlob = blob.reload(BlobSourceOption.metagenerationMatch());
@@ -301,8 +307,8 @@ public void testCopyToBucket() throws Exception {
301307
initializeBlob();
302308
CopyWriter returnedCopyWriter = blob.copyTo("bt");
303309
assertEquals(copyWriter, returnedCopyWriter);
304-
assertEquals(capturedCopyRequest.getValue().getSource(), blob.getBlobId());
305-
assertEquals(capturedCopyRequest.getValue().getTarget(), target);
310+
assertEquals(BLOB_INFO_NO_GENERATION.getBlobId(), capturedCopyRequest.getValue().getSource());
311+
assertEquals(target, capturedCopyRequest.getValue().getTarget());
306312
assertFalse(capturedCopyRequest.getValue().overrideInfo());
307313
assertTrue(capturedCopyRequest.getValue().getSourceOptions().isEmpty());
308314
assertTrue(capturedCopyRequest.getValue().getTargetOptions().isEmpty());
@@ -320,8 +326,8 @@ public void testCopyTo() throws Exception {
320326
initializeBlob();
321327
CopyWriter returnedCopyWriter = blob.copyTo("bt", "nt");
322328
assertEquals(copyWriter, returnedCopyWriter);
323-
assertEquals(capturedCopyRequest.getValue().getSource(), blob.getBlobId());
324-
assertEquals(capturedCopyRequest.getValue().getTarget(), target);
329+
assertEquals(BLOB_INFO_NO_GENERATION.getBlobId(), capturedCopyRequest.getValue().getSource());
330+
assertEquals(target, capturedCopyRequest.getValue().getTarget());
325331
assertFalse(capturedCopyRequest.getValue().overrideInfo());
326332
assertTrue(capturedCopyRequest.getValue().getSourceOptions().isEmpty());
327333
assertTrue(capturedCopyRequest.getValue().getTargetOptions().isEmpty());
@@ -340,8 +346,8 @@ public void testCopyToBlobId() throws Exception {
340346
initializeBlob();
341347
CopyWriter returnedCopyWriter = blob.copyTo(targetId);
342348
assertEquals(copyWriter, returnedCopyWriter);
343-
assertEquals(capturedCopyRequest.getValue().getSource(), blob.getBlobId());
344-
assertEquals(capturedCopyRequest.getValue().getTarget(), target);
349+
assertEquals(BLOB_INFO_NO_GENERATION.getBlobId(), capturedCopyRequest.getValue().getSource());
350+
assertEquals(target, capturedCopyRequest.getValue().getTarget());
345351
assertFalse(capturedCopyRequest.getValue().overrideInfo());
346352
assertTrue(capturedCopyRequest.getValue().getSourceOptions().isEmpty());
347353
assertTrue(capturedCopyRequest.getValue().getTargetOptions().isEmpty());

google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java

+30
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static org.junit.Assert.assertArrayEquals;
2222
import static org.junit.Assert.assertEquals;
2323
import static org.junit.Assert.assertFalse;
24+
import static org.junit.Assert.assertNotEquals;
2425
import static org.junit.Assert.assertNotNull;
2526
import static org.junit.Assert.assertNull;
2627
import static org.junit.Assert.assertTrue;
@@ -3243,4 +3244,33 @@ public void testSignedPostPolicyV4() throws Exception {
32433244

32443245
assertEquals("hello world", new String(storage.get(BUCKET, "my-object").getContent()));
32453246
}
3247+
3248+
@Test
3249+
public void testBlobReload() throws Exception {
3250+
String blobName = "test-blob-reload";
3251+
BlobId blobId = BlobId.of(BUCKET, blobName);
3252+
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
3253+
Blob blob = storage.create(blobInfo, new byte[] {0, 1, 2});
3254+
3255+
Blob blobUnchanged = blob.reload();
3256+
assertEquals(blob, blobUnchanged);
3257+
3258+
blob.writer().close();
3259+
try {
3260+
blob.reload(Blob.BlobSourceOption.generationMatch());
3261+
fail("StorageException was expected");
3262+
} catch (StorageException e) {
3263+
assertEquals(412, e.getCode());
3264+
assertEquals("Precondition Failed", e.getMessage());
3265+
}
3266+
3267+
Blob updated = blob.reload();
3268+
assertEquals(blob.getBucket(), updated.getBucket());
3269+
assertEquals(blob.getName(), updated.getName());
3270+
assertNotEquals(blob.getGeneration(), updated.getGeneration());
3271+
assertEquals(new Long(0), updated.getSize());
3272+
3273+
updated.delete();
3274+
assertNull(updated.reload());
3275+
}
32463276
}

0 commit comments

Comments
 (0)