|
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