|
16 | 16 |
|
17 | 17 | package com.google.cloud.storage.it; |
18 | 18 |
|
| 19 | +import static com.google.cloud.storage.TestUtils.assertAll; |
19 | 20 | import static com.google.cloud.storage.TestUtils.xxd; |
20 | 21 | import static com.google.common.truth.Truth.assertThat; |
21 | 22 | import static java.nio.charset.StandardCharsets.UTF_8; |
22 | 23 | import static org.junit.Assert.assertArrayEquals; |
23 | 24 | import static org.junit.Assert.assertNotNull; |
| 25 | +import static org.junit.Assert.assertThrows; |
24 | 26 | import static org.junit.Assert.fail; |
25 | 27 |
|
26 | 28 | import com.google.cloud.ReadChannel; |
|
52 | 54 | import java.io.IOException; |
53 | 55 | import java.nio.ByteBuffer; |
54 | 56 | import java.nio.channels.Channels; |
| 57 | +import java.nio.channels.ClosedChannelException; |
55 | 58 | import java.nio.channels.FileChannel; |
56 | 59 | import java.nio.channels.WritableByteChannel; |
57 | 60 | import java.nio.file.Files; |
@@ -372,6 +375,40 @@ public void seekAfterReadWorks() throws IOException { |
372 | 375 | } |
373 | 376 | } |
374 | 377 |
|
| 378 | + @Test |
| 379 | + public void seekBackToStartAfterReachingEndOfObjectWorks() throws IOException { |
| 380 | + ObjectAndContent obj512KiB = objectsFixture.getObj512KiB(); |
| 381 | + BlobInfo gen1 = obj512KiB.getInfo(); |
| 382 | + byte[] bytes = obj512KiB.getContent().getBytes(); |
| 383 | + |
| 384 | + int from = bytes.length - 5; |
| 385 | + byte[] expected1 = Arrays.copyOfRange(bytes, from, bytes.length); |
| 386 | + |
| 387 | + String xxdExpected1 = xxd(expected1); |
| 388 | + String xxdExpected2 = xxd(bytes); |
| 389 | + try (ReadChannel reader = storage.reader(gen1.getBlobId())) { |
| 390 | + // seek forward to a new offset |
| 391 | + reader.seek(from); |
| 392 | + |
| 393 | + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| 394 | + WritableByteChannel out = Channels.newChannel(baos)) { |
| 395 | + ByteStreams.copy(reader, out); |
| 396 | + String xxd = xxd(baos.toByteArray()); |
| 397 | + assertThat(xxd).isEqualTo(xxdExpected1); |
| 398 | + } |
| 399 | + |
| 400 | + // seek back to the beginning |
| 401 | + reader.seek(0); |
| 402 | + // read again |
| 403 | + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| 404 | + WritableByteChannel out = Channels.newChannel(baos)) { |
| 405 | + ByteStreams.copy(reader, out); |
| 406 | + String xxd = xxd(baos.toByteArray()); |
| 407 | + assertThat(xxd).isEqualTo(xxdExpected2); |
| 408 | + } |
| 409 | + } |
| 410 | + } |
| 411 | + |
375 | 412 | @Test |
376 | 413 | public void limitAfterReadWorks() throws IOException { |
377 | 414 | ObjectAndContent obj512KiB = objectsFixture.getObj512KiB(); |
@@ -469,6 +506,29 @@ public void responseWith416ReturnsZeroAndLeavesTheChannelOpen() throws IOExcepti |
469 | 506 | } |
470 | 507 | } |
471 | 508 |
|
| 509 | + /** Read channel does not consider itself closed once it returns {@code -1} from read. */ |
| 510 | + @Test |
| 511 | + public void readChannelIsAlwaysOpen_willReturnNegative1UntilExplicitlyClosed() throws Exception { |
| 512 | + int length = 10; |
| 513 | + byte[] bytes = DataGenerator.base64Characters().genBytes(length); |
| 514 | + |
| 515 | + BlobInfo info1 = BlobInfo.newBuilder(bucket, generator.randomObjectName()).build(); |
| 516 | + Blob gen1 = storage.create(info1, bytes, BlobTargetOption.doesNotExist()); |
| 517 | + |
| 518 | + try (ReadChannel reader = storage.reader(gen1.getBlobId())) { |
| 519 | + ByteBuffer buf = ByteBuffer.allocate(length * 2); |
| 520 | + int read = reader.read(buf); |
| 521 | + assertAll( |
| 522 | + () -> assertThat(read).isEqualTo(length), () -> assertThat(reader.isOpen()).isTrue()); |
| 523 | + int read2 = reader.read(buf); |
| 524 | + assertAll(() -> assertThat(read2).isEqualTo(-1), () -> assertThat(reader.isOpen()).isTrue()); |
| 525 | + int read3 = reader.read(buf); |
| 526 | + assertAll(() -> assertThat(read3).isEqualTo(-1), () -> assertThat(reader.isOpen()).isTrue()); |
| 527 | + reader.close(); |
| 528 | + assertThrows(ClosedChannelException.class, () -> reader.read(buf)); |
| 529 | + } |
| 530 | + } |
| 531 | + |
472 | 532 | private void captureAndRestoreTest(@Nullable Integer position, @Nullable Integer endOffset) |
473 | 533 | throws IOException { |
474 | 534 | ObjectAndContent obj512KiB = objectsFixture.getObj512KiB(); |
|
0 commit comments