Skip to content

Commit 1ab2661

Browse files
committed
test(showcase): add integration tests for resumable upload
1 parent ec249fe commit 1ab2661

1 file changed

Lines changed: 215 additions & 0 deletions

File tree

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
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+
import static org.junit.jupiter.api.Assertions.assertThrows;
21+
22+
import com.google.api.client.http.javanet.NetHttpTransport;
23+
import com.google.api.gax.core.NoCredentialsProvider;
24+
import com.google.api.gax.rpc.FailedPreconditionException;
25+
import com.google.api.gax.rpc.ResumableUploadFuture;
26+
import com.google.showcase.v1beta1.ResumableUploadServiceClient;
27+
import com.google.showcase.v1beta1.ResumableUploadServiceSettings;
28+
import com.google.showcase.v1beta1.UploadMediaRequest;
29+
import com.google.showcase.v1beta1.UploadMediaResponse;
30+
import com.google.showcase.v1beta1.it.util.TestClientInitializer;
31+
import io.grpc.ManagedChannelBuilder;
32+
import java.io.FileInputStream;
33+
import java.io.IOException;
34+
import java.io.InputStream;
35+
import java.nio.charset.StandardCharsets;
36+
import java.nio.file.Files;
37+
import java.nio.file.Path;
38+
import java.util.concurrent.TimeUnit;
39+
import org.junit.jupiter.api.AfterAll;
40+
import org.junit.jupiter.api.BeforeAll;
41+
import org.junit.jupiter.api.Test;
42+
import org.junit.jupiter.api.io.TempDir;
43+
44+
/**
45+
* Integration tests for generated {@link ResumableUploadServiceClient} against the Showcase server.
46+
*/
47+
class ITResumableUpload {
48+
49+
private static final int SHOWCASE_CHUNK_SIZE = 256 * 1024; // 256KB
50+
private static ResumableUploadServiceClient client;
51+
52+
@BeforeAll
53+
static void createClients() throws Exception {
54+
ResumableUploadServiceSettings.Builder settingsBuilder =
55+
ResumableUploadServiceSettings.newHttpJsonBuilder();
56+
settingsBuilder
57+
.setCredentialsProvider(NoCredentialsProvider.create())
58+
.setTransportChannelProvider(
59+
ResumableUploadServiceSettings.defaultHttpJsonTransportProviderBuilder()
60+
.setHttpTransport(new NetHttpTransport.Builder().doNotValidateCertificate().build())
61+
.setEndpoint(TestClientInitializer.DEFAULT_HTTPJSON_ENDPOINT)
62+
.build());
63+
settingsBuilder.uploadMediaSettings().setChunkSize(SHOWCASE_CHUNK_SIZE);
64+
client = ResumableUploadServiceClient.create(settingsBuilder.build());
65+
}
66+
67+
@AfterAll
68+
static void destroyClients() throws InterruptedException {
69+
if (client != null) {
70+
client.close();
71+
client.awaitTermination(TestClientInitializer.AWAIT_TERMINATION_SECONDS, TimeUnit.SECONDS);
72+
}
73+
}
74+
75+
@Test
76+
void testGeneratedClient_uploadMedia_synchronousConvenienceMethod(@TempDir Path tempDir)
77+
throws Exception {
78+
Path file =
79+
createTempFile(
80+
tempDir,
81+
"it-client-sync.txt",
82+
"Hello from generated ResumableUploadServiceClient synchronous convenience method!"
83+
.getBytes(StandardCharsets.UTF_8));
84+
UploadMediaRequest request =
85+
UploadMediaRequest.newBuilder().setName("it-client-sync.txt").build();
86+
87+
try (InputStream stream = new FileInputStream(file.toFile())) {
88+
UploadMediaResponse response = client.uploadMedia(request, stream);
89+
assertThat(response.getName()).isEqualTo("it-client-sync.txt");
90+
assertThat(response.getSize()).isEqualTo(Files.size(file));
91+
}
92+
}
93+
94+
@Test
95+
void testGeneratedClient_uploadMediaCallable_asynchronousFutureCall(@TempDir Path tempDir)
96+
throws Exception {
97+
Path file =
98+
createTempFile(
99+
tempDir,
100+
"it-client-callable.txt",
101+
"Hello from generated ResumableUploadServiceClient callable futureCall!"
102+
.getBytes(StandardCharsets.UTF_8));
103+
UploadMediaRequest request =
104+
UploadMediaRequest.newBuilder().setName("it-client-callable.txt").build();
105+
106+
try (InputStream stream = new FileInputStream(file.toFile())) {
107+
ResumableUploadFuture<UploadMediaResponse> future =
108+
client.uploadMediaCallable().futureCall(request, stream);
109+
110+
UploadMediaResponse response = future.get(10, TimeUnit.SECONDS);
111+
assertThat(future.isDone()).isTrue();
112+
assertThat(future.isCancelled()).isFalse();
113+
assertThat(future.getUploadSessionUrl()).isNotNull();
114+
assertThat(response.getName()).isEqualTo("it-client-callable.txt");
115+
assertThat(response.getSize()).isEqualTo(Files.size(file));
116+
}
117+
}
118+
119+
@Test
120+
void testGeneratedClient_multiChunkUpload(@TempDir Path tempDir) throws Exception {
121+
// 600KB payload = 2 full 256KB chunks + 1 partial 88KB chunk
122+
int totalBytes = 600 * 1024;
123+
Path file = createTempFile(tempDir, "it-client-multi-chunk.txt", totalBytes);
124+
UploadMediaRequest request =
125+
UploadMediaRequest.newBuilder().setName("it-client-multi-chunk.txt").build();
126+
127+
try (InputStream stream = new FileInputStream(file.toFile())) {
128+
UploadMediaResponse response = client.uploadMedia(request, stream);
129+
assertThat(response.getName()).isEqualTo("it-client-multi-chunk.txt");
130+
assertThat(response.getSize()).isEqualTo(Files.size(file));
131+
}
132+
}
133+
134+
@Test
135+
void testGeneratedClient_zeroByteUpload(@TempDir Path tempDir) throws Exception {
136+
Path file = tempDir.resolve("it-client-zero-byte.txt");
137+
Files.createFile(file);
138+
UploadMediaRequest request =
139+
UploadMediaRequest.newBuilder().setName("it-client-zero-byte.txt").build();
140+
141+
try (InputStream stream = new FileInputStream(file.toFile())) {
142+
UploadMediaResponse response = client.uploadMedia(request, stream);
143+
assertThat(response.getName()).isEqualTo("it-client-zero-byte.txt");
144+
assertThat(response.getSize()).isEqualTo(0);
145+
}
146+
}
147+
148+
@Test
149+
void testGeneratedClient_exactChunkBoundaryUpload(@TempDir Path tempDir) throws Exception {
150+
// Exactly 2 full 256KB chunks (512KB total) -> triggers 0-byte finalize request
151+
int totalBytes = 512 * 1024;
152+
Path file = createTempFile(tempDir, "it-client-exact-chunks.txt", totalBytes);
153+
UploadMediaRequest request =
154+
UploadMediaRequest.newBuilder().setName("it-client-exact-chunks.txt").build();
155+
156+
try (InputStream stream = new FileInputStream(file.toFile())) {
157+
UploadMediaResponse response = client.uploadMedia(request, stream);
158+
assertThat(response.getName()).isEqualTo("it-client-exact-chunks.txt");
159+
assertThat(response.getSize()).isEqualTo(Files.size(file));
160+
}
161+
}
162+
163+
@Test
164+
void testChannelGuards_grpcChannelOnly_throwsFailedPreconditionException(@TempDir Path tempDir)
165+
throws Exception {
166+
ResumableUploadServiceSettings grpcSettings =
167+
ResumableUploadServiceSettings.newBuilder()
168+
.setCredentialsProvider(NoCredentialsProvider.create())
169+
.setTransportChannelProvider(
170+
ResumableUploadServiceSettings.defaultGrpcTransportProviderBuilder()
171+
.setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
172+
.build())
173+
.setEndpoint(TestClientInitializer.DEFAULT_GRPC_ENDPOINT)
174+
.build();
175+
176+
Path file =
177+
createTempFile(
178+
tempDir, "guard-test.txt", "guard test data".getBytes(StandardCharsets.UTF_8));
179+
180+
try (ResumableUploadServiceClient grpcClient =
181+
ResumableUploadServiceClient.create(grpcSettings)) {
182+
UploadMediaRequest request =
183+
UploadMediaRequest.newBuilder().setName("guard-test.txt").build();
184+
185+
try (InputStream stream1 = new FileInputStream(file.toFile())) {
186+
// 1. Verify synchronous convenience call fails fast
187+
FailedPreconditionException syncException =
188+
assertThrows(
189+
FailedPreconditionException.class, () -> grpcClient.uploadMedia(request, stream1));
190+
assertThat(syncException.getMessage())
191+
.contains("Resumable uploads execute over HTTP/REST and require credentials");
192+
}
193+
194+
// 2. Verify callable getter fails fast
195+
FailedPreconditionException callableException =
196+
assertThrows(FailedPreconditionException.class, () -> grpcClient.uploadMediaCallable());
197+
assertThat(callableException.getMessage())
198+
.contains("Resumable uploads execute over HTTP/REST and require credentials");
199+
}
200+
}
201+
202+
private static Path createTempFile(Path dir, String fileName, byte[] data) throws IOException {
203+
Path path = dir.resolve(fileName);
204+
Files.write(path, data);
205+
return path;
206+
}
207+
208+
private static Path createTempFile(Path dir, String fileName, int size) throws IOException {
209+
byte[] data = new byte[size];
210+
for (int i = 0; i < size; i++) {
211+
data[i] = (byte) (i % 256);
212+
}
213+
return createTempFile(dir, fileName, data);
214+
}
215+
}

0 commit comments

Comments
 (0)