Skip to content

Commit e1e1fb6

Browse files
authored
test: add showcase test for api-version (#2737)
This pr updates gapic-showcase version to 0.35.0 and adds showcase tests to verify behavior of api version headers being emitted (changes in #2630 and #2671).
1 parent 4ecc89b commit e1e1fb6

File tree

3 files changed

+326
-2
lines changed

3 files changed

+326
-2
lines changed

gax-java/gax/src/main/java/com/google/api/gax/rpc/ApiClientHeaderProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class ApiClientHeaderProvider implements HeaderProvider, Serializable {
4242
private static final long serialVersionUID = -8876627296793342119L;
4343
static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-goog-user-project";
4444

45-
static final String API_VERSION_HEADER_KEY = "x-goog-api-version";
45+
public static final String API_VERSION_HEADER_KEY = "x-goog-api-version";
4646

4747
private final Map<String, String> headers;
4848

showcase/gapic-showcase/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
</parent>
2020

2121
<properties>
22-
<gapic-showcase.version>0.33.0</gapic-showcase.version>
22+
<gapic-showcase.version>0.35.0</gapic-showcase.version>
2323
</properties>
2424

2525
<build>
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
/*
2+
* Copyright 2024 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+
package com.google.showcase.v1beta1.it;
17+
18+
import static com.google.common.truth.Truth.assertThat;
19+
import static org.junit.Assert.assertThrows;
20+
21+
import com.google.api.gax.httpjson.*;
22+
import com.google.api.gax.rpc.ApiClientHeaderProvider;
23+
import com.google.api.gax.rpc.FixedHeaderProvider;
24+
import com.google.api.gax.rpc.StubSettings;
25+
import com.google.common.collect.ImmutableList;
26+
import com.google.showcase.v1beta1.*;
27+
import com.google.showcase.v1beta1.it.util.TestClientInitializer;
28+
import com.google.showcase.v1beta1.stub.ComplianceStubSettings;
29+
import com.google.showcase.v1beta1.stub.EchoStubSettings;
30+
import io.grpc.*;
31+
import java.io.IOException;
32+
import java.util.ArrayList;
33+
import java.util.concurrent.TimeUnit;
34+
import org.junit.After;
35+
import org.junit.Before;
36+
import org.junit.Test;
37+
38+
// TODO: add testing on error responses once feat is implemented in showcase.
39+
// https://github.com/googleapis/gapic-showcase/pull/1456
40+
// TODO: watch for showcase gRPC trailer changes suggested in
41+
// https://github.com/googleapis/gapic-showcase/pull/1509#issuecomment-2089147103
42+
public class ITApiVersionHeaders {
43+
private static final String HTTP_RESPONSE_HEADER_STRING =
44+
"x-showcase-request-" + ApiClientHeaderProvider.API_VERSION_HEADER_KEY;
45+
private static final Metadata.Key<String> API_VERSION_HEADER_KEY =
46+
Metadata.Key.of(
47+
ApiClientHeaderProvider.API_VERSION_HEADER_KEY, Metadata.ASCII_STRING_MARSHALLER);
48+
49+
private static final String EXPECTED_ECHO_API_VERSION = "v1_20240408";
50+
private static final String CUSTOM_API_VERSION = "user-supplied-version";
51+
private static final String EXPECTED_EXCEPTION_MESSAGE =
52+
"Header provider can't override the header: "
53+
+ ApiClientHeaderProvider.API_VERSION_HEADER_KEY;
54+
private static final int DEFAULT_AWAIT_TERMINATION_SEC = 10;
55+
56+
// Implement a client interceptor to retrieve the trailing metadata from response.
57+
private static class GrpcCapturingClientInterceptor implements ClientInterceptor {
58+
private Metadata metadata;
59+
60+
@Override
61+
public <RequestT, ResponseT> ClientCall<RequestT, ResponseT> interceptCall(
62+
MethodDescriptor<RequestT, ResponseT> method, final CallOptions callOptions, Channel next) {
63+
ClientCall<RequestT, ResponseT> call = next.newCall(method, callOptions);
64+
return new ForwardingClientCall.SimpleForwardingClientCall<RequestT, ResponseT>(call) {
65+
@Override
66+
public void start(Listener<ResponseT> responseListener, Metadata headers) {
67+
Listener<ResponseT> wrappedListener =
68+
new SimpleForwardingClientCallListener<ResponseT>(responseListener) {
69+
@Override
70+
public void onClose(Status status, Metadata trailers) {
71+
if (status.isOk()) {
72+
metadata = trailers;
73+
}
74+
super.onClose(status, trailers);
75+
}
76+
};
77+
78+
super.start(wrappedListener, headers);
79+
}
80+
};
81+
}
82+
}
83+
84+
private static class SimpleForwardingClientCallListener<RespT>
85+
extends ClientCall.Listener<RespT> {
86+
private final ClientCall.Listener<RespT> delegate;
87+
88+
SimpleForwardingClientCallListener(ClientCall.Listener<RespT> delegate) {
89+
this.delegate = delegate;
90+
}
91+
92+
@Override
93+
public void onHeaders(Metadata headers) {
94+
delegate.onHeaders(headers);
95+
}
96+
97+
@Override
98+
public void onMessage(RespT message) {
99+
delegate.onMessage(message);
100+
}
101+
102+
@Override
103+
public void onClose(Status status, Metadata trailers) {
104+
delegate.onClose(status, trailers);
105+
}
106+
107+
@Override
108+
public void onReady() {
109+
delegate.onReady();
110+
}
111+
}
112+
// Implement a client interceptor to retrieve the response headers
113+
private static class HttpJsonCapturingClientInterceptor implements HttpJsonClientInterceptor {
114+
private HttpJsonMetadata metadata;
115+
116+
@Override
117+
public <RequestT, ResponseT> HttpJsonClientCall<RequestT, ResponseT> interceptCall(
118+
ApiMethodDescriptor<RequestT, ResponseT> method,
119+
HttpJsonCallOptions callOptions,
120+
HttpJsonChannel next) {
121+
HttpJsonClientCall<RequestT, ResponseT> call = next.newCall(method, callOptions);
122+
return new ForwardingHttpJsonClientCall.SimpleForwardingHttpJsonClientCall<
123+
RequestT, ResponseT>(call) {
124+
@Override
125+
public void start(Listener<ResponseT> responseListener, HttpJsonMetadata requestHeaders) {
126+
Listener<ResponseT> forwardingResponseListener =
127+
new ForwardingHttpJsonClientCallListener.SimpleForwardingHttpJsonClientCallListener<
128+
ResponseT>(responseListener) {
129+
@Override
130+
public void onHeaders(HttpJsonMetadata responseHeaders) {
131+
metadata = responseHeaders;
132+
super.onHeaders(responseHeaders);
133+
}
134+
135+
@Override
136+
public void onMessage(ResponseT message) {
137+
super.onMessage(message);
138+
}
139+
140+
@Override
141+
public void onClose(int statusCode, HttpJsonMetadata trailers) {
142+
super.onClose(statusCode, trailers);
143+
}
144+
};
145+
146+
super.start(forwardingResponseListener, requestHeaders);
147+
}
148+
};
149+
}
150+
}
151+
152+
private HttpJsonCapturingClientInterceptor httpJsonInterceptor;
153+
private GrpcCapturingClientInterceptor grpcInterceptor;
154+
private HttpJsonCapturingClientInterceptor httpJsonComplianceInterceptor;
155+
private GrpcCapturingClientInterceptor grpcComplianceInterceptor;
156+
private EchoClient grpcClient;
157+
private EchoClient httpJsonClient;
158+
private ComplianceClient grpcComplianceClient;
159+
private ComplianceClient httpJsonComplianceClient;
160+
161+
@Before
162+
public void createClients() throws Exception {
163+
// Create gRPC Interceptor and Client
164+
grpcInterceptor = new GrpcCapturingClientInterceptor();
165+
grpcClient = TestClientInitializer.createGrpcEchoClient(ImmutableList.of(grpcInterceptor));
166+
167+
// Create HttpJson Interceptor and Client
168+
httpJsonInterceptor = new HttpJsonCapturingClientInterceptor();
169+
httpJsonClient =
170+
TestClientInitializer.createHttpJsonEchoClient(ImmutableList.of(httpJsonInterceptor));
171+
172+
// Create gRPC ComplianceClient and Interceptor
173+
// Creating a compliance client to test case where api version is not set
174+
grpcComplianceInterceptor = new GrpcCapturingClientInterceptor();
175+
grpcComplianceClient =
176+
TestClientInitializer.createGrpcComplianceClient(
177+
ImmutableList.of(grpcComplianceInterceptor));
178+
179+
// Create HttpJson ComplianceClient and Interceptor
180+
httpJsonComplianceInterceptor = new HttpJsonCapturingClientInterceptor();
181+
httpJsonComplianceClient =
182+
TestClientInitializer.createHttpJsonComplianceClient(
183+
ImmutableList.of(httpJsonComplianceInterceptor));
184+
}
185+
186+
@After
187+
public void destroyClient() throws InterruptedException {
188+
grpcClient.close();
189+
httpJsonClient.close();
190+
grpcComplianceClient.close();
191+
httpJsonComplianceClient.close();
192+
193+
grpcClient.awaitTermination(DEFAULT_AWAIT_TERMINATION_SEC, TimeUnit.SECONDS);
194+
httpJsonClient.awaitTermination(DEFAULT_AWAIT_TERMINATION_SEC, TimeUnit.SECONDS);
195+
grpcComplianceClient.awaitTermination(DEFAULT_AWAIT_TERMINATION_SEC, TimeUnit.SECONDS);
196+
httpJsonComplianceClient.awaitTermination(DEFAULT_AWAIT_TERMINATION_SEC, TimeUnit.SECONDS);
197+
}
198+
199+
@Test
200+
public void testGrpc_matchesApiVersion() {
201+
grpcClient.echo(EchoRequest.newBuilder().build());
202+
String headerValue = grpcInterceptor.metadata.get(API_VERSION_HEADER_KEY);
203+
assertThat(headerValue).isEqualTo(EXPECTED_ECHO_API_VERSION);
204+
}
205+
206+
@Test
207+
public void testHttpJson_matchesHeaderName() {
208+
httpJsonClient.echo(EchoRequest.newBuilder().build());
209+
ArrayList headerValues =
210+
(ArrayList) httpJsonInterceptor.metadata.getHeaders().get(HTTP_RESPONSE_HEADER_STRING);
211+
String headerValue = (String) headerValues.get(0);
212+
assertThat(headerValue).isEqualTo(EXPECTED_ECHO_API_VERSION);
213+
}
214+
215+
@Test
216+
public void testGrpc_noApiVersion() {
217+
RepeatRequest request =
218+
RepeatRequest.newBuilder().setInfo(ComplianceData.newBuilder().setFString("test")).build();
219+
grpcComplianceClient.repeatDataSimplePath(request);
220+
assertThat(API_VERSION_HEADER_KEY).isNotIn(grpcComplianceInterceptor.metadata.keys());
221+
}
222+
223+
@Test
224+
public void testHttpJson_noApiVersion() {
225+
RepeatRequest request =
226+
RepeatRequest.newBuilder().setInfo(ComplianceData.newBuilder().setFString("test")).build();
227+
httpJsonComplianceClient.repeatDataSimplePath(request);
228+
assertThat(API_VERSION_HEADER_KEY)
229+
.isNotIn(httpJsonComplianceInterceptor.metadata.getHeaders().keySet());
230+
}
231+
232+
@Test
233+
public void testGrpcEcho_userApiVersionThrowsException() throws IOException {
234+
StubSettings stubSettings =
235+
grpcClient
236+
.getSettings()
237+
.getStubSettings()
238+
.toBuilder()
239+
.setHeaderProvider(
240+
FixedHeaderProvider.create(
241+
ApiClientHeaderProvider.API_VERSION_HEADER_KEY, CUSTOM_API_VERSION))
242+
.build();
243+
244+
IllegalArgumentException exception =
245+
assertThrows(
246+
IllegalArgumentException.class,
247+
() -> EchoClient.create(EchoSettings.create((EchoStubSettings) stubSettings)));
248+
assertThat(exception.getMessage()).isEqualTo(EXPECTED_EXCEPTION_MESSAGE);
249+
}
250+
251+
@Test
252+
public void testHttpJsonEcho_userApiVersionThrowsException() throws IOException {
253+
StubSettings stubSettings =
254+
httpJsonClient
255+
.getSettings()
256+
.getStubSettings()
257+
.toBuilder()
258+
.setHeaderProvider(
259+
FixedHeaderProvider.create(
260+
ApiClientHeaderProvider.API_VERSION_HEADER_KEY, CUSTOM_API_VERSION))
261+
.build();
262+
263+
IllegalArgumentException exception =
264+
assertThrows(
265+
IllegalArgumentException.class,
266+
() -> EchoClient.create(EchoSettings.create((EchoStubSettings) stubSettings)));
267+
assertThat(exception.getMessage()).isEqualTo(EXPECTED_EXCEPTION_MESSAGE);
268+
}
269+
270+
@Test
271+
public void testGrpcCompliance_userApiVersionSetSuccess() throws IOException {
272+
StubSettings stubSettingsWithApiVersionHeader =
273+
grpcComplianceClient
274+
.getSettings()
275+
.getStubSettings()
276+
.toBuilder()
277+
.setHeaderProvider(
278+
FixedHeaderProvider.create(
279+
ApiClientHeaderProvider.API_VERSION_HEADER_KEY, CUSTOM_API_VERSION))
280+
.build();
281+
try (ComplianceClient customComplianceClient =
282+
ComplianceClient.create(
283+
ComplianceSettings.create((ComplianceStubSettings) stubSettingsWithApiVersionHeader))) {
284+
285+
RepeatRequest request =
286+
RepeatRequest.newBuilder()
287+
.setInfo(ComplianceData.newBuilder().setFString("test"))
288+
.build();
289+
customComplianceClient.repeatDataSimplePath(request);
290+
String headerValue = grpcComplianceInterceptor.metadata.get(API_VERSION_HEADER_KEY);
291+
assertThat(headerValue).isEqualTo(CUSTOM_API_VERSION);
292+
}
293+
}
294+
295+
@Test
296+
public void testHttpJsonCompliance_userApiVersionSetSuccess() throws IOException {
297+
StubSettings httpJsonStubSettingsWithApiVersionHeader =
298+
httpJsonComplianceClient
299+
.getSettings()
300+
.getStubSettings()
301+
.toBuilder()
302+
.setHeaderProvider(
303+
FixedHeaderProvider.create(
304+
ApiClientHeaderProvider.API_VERSION_HEADER_KEY, CUSTOM_API_VERSION))
305+
.build();
306+
try (ComplianceClient customComplianceClient =
307+
ComplianceClient.create(
308+
ComplianceSettings.create(
309+
(ComplianceStubSettings) httpJsonStubSettingsWithApiVersionHeader))) {
310+
311+
RepeatRequest request =
312+
RepeatRequest.newBuilder()
313+
.setInfo(ComplianceData.newBuilder().setFString("test"))
314+
.build();
315+
customComplianceClient.repeatDataSimplePath(request);
316+
317+
ArrayList headerValues =
318+
(ArrayList)
319+
httpJsonComplianceInterceptor.metadata.getHeaders().get(HTTP_RESPONSE_HEADER_STRING);
320+
String headerValue = (String) headerValues.get(0);
321+
assertThat(headerValue).isEqualTo(CUSTOM_API_VERSION);
322+
}
323+
}
324+
}

0 commit comments

Comments
 (0)