Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,91 @@ public void moreReadsOnTheSameSession() throws Exception {
}
}

@Test
public void severalRanges_areAllServedFromTheOpen() throws Exception {
ReadAsFutureBytes bytes0To10 =
ReadProjectionConfigs.asFutureBytes().withRangeSpec(RangeSpec.of(0, 10));
ReadAsFutureByteString byteString100To110 =
ReadProjectionConfigs.asFutureByteString().withRangeSpec(RangeSpec.of(100, 10));
ReadAsFutureBytes bytes1000To1010 =
ReadProjectionConfigs.asFutureBytes().withRangeSpec(RangeSpec.of(1000, 10));
TestExporter exporter = new TestExporter();

try (Storage traced = tracedStorage(exporter);
BlobReadSession session =
traced
.blobReadSession(
blobId, ImmutableList.of(bytes0To10, byteString100To110, bytes1000To1010))
.get(30, SECONDS)) {
Comment on lines +163 to +168

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The OpenTelemetrySdk instance created in tracedStorage is never closed, which can lead to resource leaks (such as threads or exporters) when running tests. Since OpenTelemetrySdk implements AutoCloseable, we should manage its lifecycle using try-with-resources. We can inline the creation of OpenTelemetrySdk and traced directly in the try-with-resources block, which also allows us to remove the helper method tracedStorage if it's not used elsewhere.

    try (OpenTelemetrySdk otel =
            OpenTelemetrySdk.builder()
                .setTracerProvider(
                    SdkTracerProvider.builder()
                        .addSpanProcessor(SimpleSpanProcessor.create(exporter))
                        .build())
                .build();
        Storage traced =
            storage.getOptions().toBuilder().setOpenTelemetry(otel).build().getService();
        BlobReadSession session =
            traced
                .blobReadSession(
                    blobId, ImmutableList.of(bytes0To10, byteString100To110, bytes1000To1010))
                .get(30, SECONDS)) {
References
  1. Use try-with-resources to manage closeable resources in tests to ensure they are safely closed and prevent resource leaks.

assertThat(xxd(session.readAs(bytes1000To1010).get(30, SECONDS)))
.isEqualTo(xxd(content.getBytes(1000, 10)));
try (DisposableByteString b = session.readAs(byteString100To110).get(30, SECONDS)) {
assertThat(xxd(b.byteString().toByteArray())).isEqualTo(xxd(content.getBytes(100, 10)));
}
assertThat(xxd(session.readAs(bytes0To10).get(30, SECONDS)))
.isEqualTo(xxd(content.getBytes(0, 10)));
}

List<String> cacheStatus =
exporter.getExportedSpans().stream()
.map(s -> s.getAttributes().get(AttributeKey.stringKey("gcs.bidi.cache_status")))
.filter(Objects::nonNull)
.collect(toList());
assertThat(cacheStatus).containsExactly("HIT", "HIT", "HIT");
}

@Test
public void severalRanges_withTwoPastTheEnd_onlyThoseReadAsFail() throws Exception {
ReadAsFutureBytes good1 =
ReadProjectionConfigs.asFutureBytes().withRangeSpec(RangeSpec.of(0, 10));
ReadAsFutureBytes bad1 =
ReadProjectionConfigs.asFutureBytes().withRangeSpec(RangeSpec.beginAt(OBJECT_SIZE + 1));
ReadAsFutureBytes good2 =
ReadProjectionConfigs.asFutureBytes().withRangeSpec(RangeSpec.of(100, 10));
ReadAsFutureBytes bad2 =
ReadProjectionConfigs.asFutureBytes().withRangeSpec(RangeSpec.beginAt(OBJECT_SIZE + 100));

try (BlobReadSession session =
storage
.blobReadSession(blobId, ImmutableList.of(good1, bad1, good2, bad2))
.get(30, SECONDS)) {
assertThat(xxd(session.readAs(good1).get(30, SECONDS)))
.isEqualTo(xxd(content.getBytes(0, 10)));
assertThat(xxd(session.readAs(good2).get(30, SECONDS)))
.isEqualTo(xxd(content.getBytes(100, 10)));
for (ReadAsFutureBytes bad : ImmutableList.of(bad1, bad2)) {
ExecutionException e =
assertThrows(ExecutionException.class, () -> session.readAs(bad).get(30, SECONDS));
assertThat(e).hasCauseThat().hasCauseThat().isInstanceOf(OutOfRangeException.class);
}
}
}

@Test
public void severalRanges_withOneSpanningManyResponses() throws Exception {
ChecksummedTestContent large =
ChecksummedTestContent.of(DataGenerator.base64Characters().genBytes(16 * 1024 * 1024));
BlobId largeBlobId = create(large);
ReadAsFutureBytes whole = ReadProjectionConfigs.asFutureBytes();
ReadAsFutureBytes near16MiB =
ReadProjectionConfigs.asFutureBytes().withRangeSpec(RangeSpec.of(15 * 1024 * 1024, 1024));
ReadAsFutureBytes near8MiB =
ReadProjectionConfigs.asFutureBytes().withRangeSpec(RangeSpec.of(8 * 1024 * 1024, 1024));

try (BlobReadSession session =
storage
.blobReadSession(largeBlobId, ImmutableList.of(whole, near16MiB, near8MiB))
.get(30, SECONDS)) {
byte[] all = session.readAs(whole).get(30, SECONDS);
assertThat(all.length).isEqualTo(large.getBytes().length);
assertThat(Hashing.crc32c().hashBytes(all).asInt()).isEqualTo(large.getCrc32c());
assertThat(xxd(session.readAs(near16MiB).get(30, SECONDS)))
.isEqualTo(xxd(large.getBytes(15 * 1024 * 1024, 1024)));
assertThat(xxd(session.readAs(near8MiB).get(30, SECONDS)))
.isEqualTo(xxd(large.getBytes(8 * 1024 * 1024, 1024)));
}
}

@Test
public void outOfRange_theOpenSucceeds_andReadAsFails() throws Exception {
ReadAsFutureBytes config =
Expand Down Expand Up @@ -229,6 +314,17 @@ public void close_withoutClaimingTheFastOpenRead() throws Exception {
assertThrows(IllegalStateException.class, () -> session.readAs(READ_10_TO_20));
}

private Storage tracedStorage(TestExporter exporter) {
OpenTelemetrySdk otel =
OpenTelemetrySdk.builder()
.setTracerProvider(
SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(exporter))
.build())
.build();
return storage.getOptions().toBuilder().setOpenTelemetry(otel).build().getService();
}

private BlobId create(ChecksummedTestContent content) throws Exception {
BlobInfo info = BlobInfo.newBuilder(bucket, generator.randomObjectName()).build();
BlobAppendableUpload upload =
Expand Down
Loading