Skip to content

Commit 3c8890d

Browse files
committed
test(showcase): add integration tests for resumable upload
1 parent 5c9ee5c commit 3c8890d

2 files changed

Lines changed: 248 additions & 0 deletions

File tree

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.showcase.v1beta1.it;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
21+
import com.google.api.gax.rpc.ResumableUploadCallSettings;
22+
import com.google.api.gax.rpc.ResumableUploadFuture;
23+
import com.google.showcase.v1beta1.ResumableUploadServiceClient;
24+
import com.google.showcase.v1beta1.UploadMediaRequest;
25+
import com.google.showcase.v1beta1.UploadMediaResponse;
26+
import com.google.showcase.v1beta1.it.util.TestClientInitializer;
27+
import java.io.ByteArrayInputStream;
28+
import java.io.IOException;
29+
import java.io.InputStream;
30+
import java.nio.charset.StandardCharsets;
31+
import java.nio.file.Files;
32+
import java.nio.file.Path;
33+
import java.util.concurrent.TimeUnit;
34+
import org.junit.jupiter.api.AfterAll;
35+
import org.junit.jupiter.api.BeforeAll;
36+
import org.junit.jupiter.api.Test;
37+
import org.junit.jupiter.api.io.TempDir;
38+
39+
/**
40+
* Integration tests for generated {@link ResumableUploadServiceClient} against the Showcase server.
41+
*/
42+
class ITResumableUpload {
43+
44+
private static final int SHOWCASE_CHUNK_SIZE = 256 * 1024; // 256KB
45+
private static ResumableUploadServiceClient client;
46+
47+
@BeforeAll
48+
static void createClients() throws Exception {
49+
client = TestClientInitializer.createHttpJsonResumableUploadClient(SHOWCASE_CHUNK_SIZE);
50+
}
51+
52+
@AfterAll
53+
static void destroyClients() throws InterruptedException {
54+
if (client != null) {
55+
client.close();
56+
client.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
57+
}
58+
}
59+
60+
@Test
61+
void testGeneratedClient_uploadMedia_synchronousConvenienceMethod(@TempDir Path tempDir)
62+
throws Exception {
63+
Path file =
64+
createTempFile(
65+
tempDir,
66+
"it-client-sync.txt",
67+
"Hello from generated ResumableUploadServiceClient synchronous convenience method!"
68+
.getBytes(StandardCharsets.UTF_8));
69+
UploadMediaRequest request =
70+
UploadMediaRequest.newBuilder().setName("it-client-sync.txt").build();
71+
72+
try (InputStream stream = Files.newInputStream(file)) {
73+
UploadMediaResponse response = client.uploadMedia(request, stream, null);
74+
assertThat(response.getName()).isEqualTo("it-client-sync.txt");
75+
assertThat(response.getSize()).isEqualTo(Files.size(file));
76+
}
77+
}
78+
79+
@Test
80+
void testGeneratedClient_uploadMediaCallable_asynchronousFutureCall(@TempDir Path tempDir)
81+
throws Exception {
82+
Path file =
83+
createTempFile(
84+
tempDir,
85+
"it-client-callable.txt",
86+
"Hello from generated ResumableUploadServiceClient callable futureCall!"
87+
.getBytes(StandardCharsets.UTF_8));
88+
UploadMediaRequest request =
89+
UploadMediaRequest.newBuilder().setName("it-client-callable.txt").build();
90+
91+
try (InputStream stream = Files.newInputStream(file)) {
92+
ResumableUploadFuture<UploadMediaResponse> future =
93+
client
94+
.uploadMediaCallable()
95+
.futureCall(request, stream, (ResumableUploadCallSettings) null);
96+
97+
UploadMediaResponse response = future.get(10, TimeUnit.SECONDS);
98+
assertThat(future.isDone()).isTrue();
99+
assertThat(future.isCancelled()).isFalse();
100+
assertThat(future.getUploadSessionUrl()).isNotNull();
101+
assertThat(future.getUploadSessionUrl()).contains("/resumable/upload");
102+
assertThat(response.getName()).isEqualTo("it-client-callable.txt");
103+
assertThat(response.getSize()).isEqualTo(Files.size(file));
104+
}
105+
}
106+
107+
@Test
108+
void testGeneratedClient_multiChunkUpload(@TempDir Path tempDir) throws Exception {
109+
// 600KB payload = 2 full 256KB chunks + 1 partial 88KB chunk
110+
int totalBytes = 600 * 1024;
111+
Path file = createTempFile(tempDir, "it-client-multi-chunk.txt", totalBytes);
112+
UploadMediaRequest request =
113+
UploadMediaRequest.newBuilder().setName("it-client-multi-chunk.txt").build();
114+
115+
try (InputStream stream = Files.newInputStream(file)) {
116+
UploadMediaResponse response = client.uploadMedia(request, stream, null);
117+
assertThat(response.getName()).isEqualTo("it-client-multi-chunk.txt");
118+
assertThat(response.getSize()).isEqualTo(Files.size(file));
119+
}
120+
}
121+
122+
@Test
123+
void testGeneratedClient_zeroByteUpload() throws Exception {
124+
UploadMediaRequest request =
125+
UploadMediaRequest.newBuilder().setName("it-client-zero-byte.txt").build();
126+
127+
try (InputStream stream = new ByteArrayInputStream(new byte[0])) {
128+
UploadMediaResponse response = client.uploadMedia(request, stream, null);
129+
assertThat(response.getName()).isEqualTo("it-client-zero-byte.txt");
130+
assertThat(response.getSize()).isEqualTo(0);
131+
}
132+
}
133+
134+
@Test
135+
void testGeneratedClient_exactChunkBoundaryUpload(@TempDir Path tempDir) throws Exception {
136+
// Exactly 2 full 256KB chunks (512KB total) -> triggers 0-byte finalize request
137+
int totalBytes = 512 * 1024;
138+
Path file = createTempFile(tempDir, "it-client-exact-chunks.txt", totalBytes);
139+
UploadMediaRequest request =
140+
UploadMediaRequest.newBuilder().setName("it-client-exact-chunks.txt").build();
141+
142+
try (InputStream stream = Files.newInputStream(file)) {
143+
UploadMediaResponse response = client.uploadMedia(request, stream, null);
144+
assertThat(response.getName()).isEqualTo("it-client-exact-chunks.txt");
145+
assertThat(response.getSize()).isEqualTo(Files.size(file));
146+
}
147+
}
148+
149+
@Test
150+
void testGeneratedClient_grpcClientDelegation_uploadMedia(@TempDir Path tempDir)
151+
throws Exception {
152+
Path file =
153+
createTempFile(
154+
tempDir,
155+
"it-grpc-delegation.txt",
156+
"Hello from generated ResumableUploadServiceClient gRPC delegation!"
157+
.getBytes(StandardCharsets.UTF_8));
158+
UploadMediaRequest request =
159+
UploadMediaRequest.newBuilder().setName("it-grpc-delegation.txt").build();
160+
161+
try (ResumableUploadServiceClient grpcClient =
162+
TestClientInitializer.createGrpcResumableUploadClient(SHOWCASE_CHUNK_SIZE)) {
163+
try (InputStream stream = Files.newInputStream(file)) {
164+
UploadMediaResponse response = grpcClient.uploadMedia(request, stream, null);
165+
assertThat(response.getName()).isEqualTo("it-grpc-delegation.txt");
166+
assertThat(response.getSize()).isEqualTo(Files.size(file));
167+
}
168+
169+
try (InputStream stream = Files.newInputStream(file)) {
170+
ResumableUploadFuture<UploadMediaResponse> future =
171+
grpcClient
172+
.uploadMediaCallable()
173+
.futureCall(request, stream, (ResumableUploadCallSettings) null);
174+
UploadMediaResponse response = future.get(10, TimeUnit.SECONDS);
175+
assertThat(future.isDone()).isTrue();
176+
assertThat(future.isCancelled()).isFalse();
177+
assertThat(future.getUploadSessionUrl()).isNotNull();
178+
assertThat(future.getUploadSessionUrl()).contains("/resumable/upload");
179+
assertThat(response.getName()).isEqualTo("it-grpc-delegation.txt");
180+
assertThat(response.getSize()).isEqualTo(Files.size(file));
181+
}
182+
}
183+
}
184+
185+
@Test
186+
void testGeneratedClient_uploadMedia_withCustomCallSettings(@TempDir Path tempDir)
187+
throws Exception {
188+
// 600KB payload with custom per-call 512KB chunk size override (default is 256KB)
189+
int totalBytes = 600 * 1024;
190+
Path file = createTempFile(tempDir, "it-client-custom-call-settings.txt", totalBytes);
191+
UploadMediaRequest request =
192+
UploadMediaRequest.newBuilder().setName("it-client-custom-call-settings.txt").build();
193+
ResumableUploadCallSettings callSettings =
194+
ResumableUploadCallSettings.newBuilder().setChunkSize(512 * 1024).build();
195+
196+
try (InputStream stream = Files.newInputStream(file)) {
197+
UploadMediaResponse response = client.uploadMedia(request, stream, callSettings);
198+
assertThat(response.getName()).isEqualTo("it-client-custom-call-settings.txt");
199+
assertThat(response.getSize()).isEqualTo(Files.size(file));
200+
}
201+
}
202+
203+
private static Path createTempFile(Path dir, String fileName, byte[] data) throws IOException {
204+
Path path = dir.resolve(fileName);
205+
Files.write(path, data);
206+
return path;
207+
}
208+
209+
private static Path createTempFile(Path dir, String fileName, int size) throws IOException {
210+
byte[] data = new byte[size];
211+
for (int i = 0; i < size; i++) {
212+
data[i] = (byte) (i % 256);
213+
}
214+
return createTempFile(dir, fileName, data);
215+
}
216+
}

java-showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/util/TestClientInitializer.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import com.google.showcase.v1beta1.EchoSettings;
3434
import com.google.showcase.v1beta1.IdentityClient;
3535
import com.google.showcase.v1beta1.IdentitySettings;
36+
import com.google.showcase.v1beta1.ResumableUploadServiceClient;
37+
import com.google.showcase.v1beta1.ResumableUploadServiceSettings;
3638
import com.google.showcase.v1beta1.SequenceServiceClient;
3739
import com.google.showcase.v1beta1.SequenceServiceSettings;
3840
import com.google.showcase.v1beta1.WaitRequest;
@@ -539,4 +541,34 @@ public static SequenceServiceClient createHttpJsonSequenceClientWithRetrySetting
539541
.build());
540542
return SequenceServiceClient.create(settingsBuilder.build());
541543
}
544+
545+
public static ResumableUploadServiceClient createHttpJsonResumableUploadClient(int chunkSize)
546+
throws Exception {
547+
ResumableUploadServiceSettings.Builder settingsBuilder =
548+
ResumableUploadServiceSettings.newHttpJsonBuilder();
549+
settingsBuilder
550+
.setCredentialsProvider(NoCredentialsProvider.create())
551+
.setTransportChannelProvider(
552+
ResumableUploadServiceSettings.defaultHttpJsonTransportProviderBuilder()
553+
.setHttpTransport(new NetHttpTransport.Builder().doNotValidateCertificate().build())
554+
.setEndpoint(DEFAULT_HTTPJSON_ENDPOINT)
555+
.build());
556+
settingsBuilder.uploadMediaSettings().setChunkSize(chunkSize);
557+
return ResumableUploadServiceClient.create(settingsBuilder.build());
558+
}
559+
560+
public static ResumableUploadServiceClient createGrpcResumableUploadClient(int chunkSize)
561+
throws Exception {
562+
ResumableUploadServiceSettings.Builder settingsBuilder =
563+
ResumableUploadServiceSettings.newBuilder()
564+
.setCredentialsProvider(NoCredentialsProvider.create())
565+
.setTransportChannelProvider(
566+
ResumableUploadServiceSettings.defaultGrpcTransportProviderBuilder()
567+
.setEndpoint(DEFAULT_GRPC_ENDPOINT)
568+
.setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
569+
.build())
570+
.setEndpoint(DEFAULT_HTTPJSON_ENDPOINT);
571+
settingsBuilder.uploadMediaSettings().setChunkSize(chunkSize);
572+
return ResumableUploadServiceClient.create(settingsBuilder.build());
573+
}
542574
}

0 commit comments

Comments
 (0)