Skip to content

Commit

Permalink
test: add new StorageNativeCanaryTest
Browse files Browse the repository at this point in the history
Update native-image related config to be specific for this class.

Update maven config to explicitly configure this new class as it's only class for test when run under -Pnative
  • Loading branch information
BenWhitehead committed Jan 25, 2023
1 parent 95ecae7 commit e40c0e6
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 22 deletions.
16 changes: 16 additions & 0 deletions google-cloud-storage/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -340,5 +340,21 @@
</dependency>
</dependencies>
</profile>
<profile>
<id>native</id>
<properties>
<!--
Override the default match pattern for native image tests since we have a custom
test specifically for native image validation.
-->
<test>com.google.cloud.storage.it.StorageNativeCanaryTest</test>
<!--
Temporary workaround to prevent -Penable-integration-tests along with -Pnative
from also running all integration tests during the integration-test phase.
-->
<failsafe.includes/>
<failsafe.excludes>*</failsafe.excludes>
</properties>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.cloud.storage.it;

import static com.google.cloud.storage.TestUtils.assertAll;
import static com.google.common.truth.Truth.assertThat;

import com.google.api.gax.paging.Page;
import com.google.cloud.ReadChannel;
import com.google.cloud.WriteChannel;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.BucketInfo;
import com.google.cloud.storage.DataGenerator;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.Storage.BlobListOption;
import com.google.cloud.storage.Storage.BlobSourceOption;
import com.google.cloud.storage.Storage.BlobWriteOption;
import com.google.cloud.storage.TransportCompatibility.Transport;
import com.google.cloud.storage.it.runner.StorageITRunner;
import com.google.cloud.storage.it.runner.annotations.Backend;
import com.google.cloud.storage.it.runner.annotations.CrossRun;
import com.google.cloud.storage.it.runner.annotations.Inject;
import com.google.cloud.storage.it.runner.registry.Generator;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(StorageITRunner.class)
@CrossRun(
backends = {Backend.PROD},
transports = {Transport.HTTP, Transport.GRPC})
public final class StorageNativeCanaryTest {

private static final int _512KiB = 512 * 1024;
private static final int _256KiB = 256 * 1024;
private static final byte[] bytes = DataGenerator.base64Characters().genBytes(_512KiB);

@Inject public Storage storage;
@Inject public Generator generator;

/**
* When testing on Native Image, we're primarily wanting to verify the primary code paths are
* properly detected by the native image compiler.
*
* <p>For Storage, we have a few "primary code paths" we want to ensure are validated:
*
* <ul>
* <li>Can a (Unary) Request Succeed?
* <li>Can a (ServerStream) Object Read Request Succeed?
* <li>Can a (ClientStream) Object Write Request Succeed?
* <li>Can a (Page over Unary) Paginated Request Succeed?
* </ul>
*
* To validate this, our happy path test is as follows:
*
* <ul>
* <li>Create a temporary bucket (Unary)
* <li>Insert two (2) objects (Unary, ServerStream)
* <li>List all objects, using a pageSize of 1 (Page over Unary)
* <li>Read all bytes of each object (ServerStream)
* <li>Delete each object (Unary)
* <li>Delete temporary bucket (Unary)
* </ul>
*/
@Test
public void canary_happyPath() throws Exception {
// create a temporary bucket
try (TemporaryBucket tempB =
TemporaryBucket.newBuilder()
.setStorage(storage)
.setBucketInfo(BucketInfo.of(generator.randomBucketName()))
.build()) {
String bucketName = tempB.getBucket().getName();

// insert 2 objects
BlobInfo info1 = BlobInfo.newBuilder(bucketName, generator.randomObjectName()).build();
BlobInfo info2 = BlobInfo.newBuilder(bucketName, generator.randomObjectName()).build();
uploadUsingWriter(info1);
uploadUsingWriter(info2);

// list objects
Page<Blob> page = storage.list(bucketName, BlobListOption.pageSize(1));
List<Blob> blobs = ImmutableList.copyOf(page.iterateAll());

// read all bytes of each object
List<BlobWithContent> actual =
blobs.stream().map(this::readAll).collect(ImmutableList.toImmutableList());

List<Boolean> deletes =
blobs.stream()
.map(b -> storage.delete(b.getBlobId(), BlobSourceOption.generationMatch()))
.collect(ImmutableList.toImmutableList());

assertAll(
() -> {
List<String> actualNames =
actual.stream()
.map(BlobWithContent::getInfo)
.map(BlobInfo::getBlobId)
.map(BlobId::getName)
.collect(ImmutableList.toImmutableList());

assertThat(actualNames).isEqualTo(ImmutableList.of(info1.getName(), info2.getName()));
},
() -> {
// if the content isn't equal carry it through
List<BlobWithContent> contentNotEquals =
actual.stream()
.filter(bwc -> !Arrays.equals(bwc.getContent(), bytes))
.collect(ImmutableList.toImmutableList());
assertThat(contentNotEquals).isEmpty();
},
() -> assertThat(deletes.stream().anyMatch(isFalse())).isFalse());
}
}

private void uploadUsingWriter(BlobInfo info) throws IOException {
try (WriteChannel w = storage.writer(info, BlobWriteOption.doesNotExist())) {
// set our size to the smallest resumable size so we can send multiple requests
w.setChunkSize(_256KiB);
ByteStreams.copy(Channels.newChannel(new ByteArrayInputStream(bytes)), w);
}
}

private BlobWithContent readAll(BlobInfo info) {
try (ReadChannel r = storage.reader(info.getBlobId(), BlobSourceOption.generationMatch());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
WritableByteChannel w = Channels.newChannel(baos)) {
// only buffer up to half the object
r.setChunkSize(_256KiB);
ByteStreams.copy(r, w);
return new BlobWithContent(info, baos.toByteArray());
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private static Predicate<Boolean> isFalse() {
return b -> !b;
}

private static final class BlobWithContent {
private final BlobInfo info;
private final byte[] content;

private BlobWithContent(BlobInfo info, byte[] content) {
this.info = info;
this.content = content;
}

public BlobInfo getInfo() {
return info;
}

public byte[] getContent() {
return content;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,23 @@
# build time. Initializing these classes explicitly at build time results in a
# successful build.
Args = \
--initialize-at-build-time=com.google.cloud.conformance.storage.v1,\
com.google.protobuf,\
com.google.auth.oauth2,\
com.google.cloud.storage.conformance.retry,\
com.google.common.base.Charsets,\
com.google.gson.stream.JsonReader,\
--initialize-at-build-time=com.google.cloud.storage.it.StorageNativeCanaryTest,\
com.fasterxml.jackson,\
com.google.api.client.http,\
com.google.api.client.json,\
com.google.api.client.util,\
com.google.api.client.http.javanet.NetHttpTransport,\
com.google.api.client.http.HttpTransport,\
com.google.api.client.json.JsonParser$1,\
com.google.api.client.json.gson.GsonParser$1,\
com.google.common.io.BaseEncoding,\
com.google.common.math.IntMath$1,\
com.google.common.collect.Platform,\
com.google.gson.Gson,\
com.google.common.truth,\
com.google.auth.oauth2,\
com.google.cloud.storage.it.runner,\
com.google.common.base,\
com.google.common.collect,\
com.google.gson.internal.reflect,\
com.google.gson.internal.bind,\
com.google.gson.internal,\
com.google.gson.internal.sql.SqlTypesSupport,\
com.google.gson.FieldNamingPolicy$3,\
com.google.gson.LongSerializationPolicy$2,\
com.google.common.io,\
com.google.common.math,\
com.google.common.truth,\
com.google.gson,\
com.google.protobuf,\
com.google.rpc,\
io.grpc,\
io.opencensus,\
net.jqwik


Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"methods":[{"name":"<init>","parameterTypes":[] }]}
,
{
"name":"com.google.cloud.storage.conformance.retry.TestBench$RetryTestResource",
"name":"com.google.cloud.storage.it.runner.registry.TestBench$RetryTestResource",
"allDeclaredFields":true,
"methods":[{"name":"<init>","parameterTypes":[] }]}
]

0 comments on commit e40c0e6

Please sign in to comment.