Skip to content

Commit 03838dc

Browse files
committed
merge: resolve conflicts in ITOtelTracing.java and complete merge
2 parents 80fbec8 + 76cbf2b commit 03838dc

File tree

14 files changed

+412
-11
lines changed

14 files changed

+412
-11
lines changed

.github/workflows/sdk-platform-java-nightly.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,4 @@ jobs:
8484
run: |
8585
gh issue create \
8686
--title "Nightly-java8 build on ${{ matrix.os }} failed." \
87-
--body "The build has failed : https://github.com/googleapis/gapic-generator-java/actions/runs/${GITHUB_RUN_ID}"
87+
--body "The build has failed : https://github.com/googleapis/google-cloud-java/actions/runs/${GITHUB_RUN_ID}"

sdk-platform-java/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonCallContext.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,10 +607,11 @@ public ApiTracer getTracer() {
607607
@Override
608608
public HttpJsonCallContext withTracer(@Nonnull ApiTracer newTracer) {
609609
Preconditions.checkNotNull(newTracer);
610+
HttpJsonCallOptions newCallOptions = callOptions.toBuilder().setTracer(newTracer).build();
610611

611612
return new HttpJsonCallContext(
612613
this.channel,
613-
this.callOptions,
614+
newCallOptions,
614615
this.timeout,
615616
this.streamWaitTimeout,
616617
this.streamIdleTimeout,

sdk-platform-java/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonCallOptions.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import static com.google.api.gax.util.TimeConversionUtils.toThreetenInstant;
3636

3737
import com.google.api.core.ObsoleteApi;
38+
import com.google.api.gax.tracing.ApiTracer;
3839
import com.google.auth.Credentials;
3940
import com.google.auto.value.AutoValue;
4041
import com.google.protobuf.TypeRegistry;
@@ -71,6 +72,9 @@ public final org.threeten.bp.Instant getDeadline() {
7172
@Nullable
7273
public abstract TypeRegistry getTypeRegistry();
7374

75+
@Nullable
76+
public abstract ApiTracer getTracer();
77+
7478
public abstract Builder toBuilder();
7579

7680
public static Builder newBuilder() {
@@ -106,6 +110,11 @@ public HttpJsonCallOptions merge(HttpJsonCallOptions inputOptions) {
106110
builder.setTypeRegistry(newTypeRegistry);
107111
}
108112

113+
ApiTracer newTracer = inputOptions.getTracer();
114+
if (newTracer != null) {
115+
builder.setTracer(newTracer);
116+
}
117+
109118
return builder.build();
110119
}
111120

@@ -131,6 +140,8 @@ public final Builder setDeadline(org.threeten.bp.Instant value) {
131140

132141
public abstract Builder setTypeRegistry(TypeRegistry value);
133142

143+
public abstract Builder setTracer(ApiTracer value);
144+
134145
public abstract HttpJsonCallOptions build();
135146
}
136147
}

sdk-platform-java/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonClientCallImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ public void setResult(RunnableResult runnableResult) {
156156
if (runnableResult.getResponseHeaders() != null) {
157157
pendingNotifications.offer(
158158
new OnHeadersNotificationTask<>(listener, runnableResult.getResponseHeaders()));
159+
if (callOptions.getTracer() != null) {
160+
callOptions
161+
.getTracer()
162+
.responseHeadersReceived(runnableResult.getResponseHeaders().getHeaders());
163+
}
159164
}
160165
}
161166

@@ -428,6 +433,7 @@ private boolean consumeMessageFromStream() throws IOException {
428433

429434
ResponseT message =
430435
methodDescriptor.getResponseParser().parse(responseReader, callOptions.getTypeRegistry());
436+
431437
pendingNotifications.offer(new OnMessageNotificationTask<>(listener, message));
432438

433439
return allMessagesConsumed;

sdk-platform-java/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonCallContextTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,16 @@ void testMergeWithTracer() {
252252
.isSameInstanceAs(defaultTracer);
253253
}
254254

255+
@Test
256+
void testWithTracer() {
257+
ApiTracer tracer = Mockito.mock(ApiTracer.class);
258+
HttpJsonCallContext emptyContext = HttpJsonCallContext.createDefault();
259+
// Default context has a default tracer.
260+
assertNotNull(emptyContext.getTracer());
261+
HttpJsonCallContext context = emptyContext.withTracer(tracer);
262+
Truth.assertThat(context.getTracer()).isSameInstanceAs(tracer);
263+
}
264+
255265
@Test
256266
void testWithRetrySettings() {
257267
RetrySettings retrySettings = Mockito.mock(RetrySettings.class);

sdk-platform-java/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonCallOptionsTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,22 @@
3131

3232
import static com.google.api.gax.util.TimeConversionTestUtils.testDurationMethod;
3333
import static com.google.api.gax.util.TimeConversionTestUtils.testInstantMethod;
34+
import static com.google.common.truth.Truth.assertThat;
3435

36+
import com.google.api.gax.tracing.ApiTracer;
3537
import org.junit.jupiter.api.Test;
38+
import org.mockito.Mockito;
3639

3740
public class HttpJsonCallOptionsTest {
3841
private final HttpJsonCallOptions.Builder OPTIONS_BUILDER = HttpJsonCallOptions.newBuilder();
3942

43+
@Test
44+
void testTracer() {
45+
ApiTracer tracer = Mockito.mock(ApiTracer.class);
46+
HttpJsonCallOptions options = OPTIONS_BUILDER.setTracer(tracer).build();
47+
assertThat(options.getTracer()).isSameInstanceAs(tracer);
48+
}
49+
4050
@Test
4151
public void testDeadline() {
4252
final long millis = 3;

sdk-platform-java/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/HttpJsonClientCallImplTest.java

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,35 @@
2929
*/
3030
package com.google.api.gax.httpjson;
3131

32+
import static com.google.common.truth.Truth.assertThat;
33+
3234
import com.google.api.client.http.HttpTransport;
35+
import com.google.api.gax.httpjson.testing.MockHttpService;
36+
import com.google.api.gax.httpjson.testing.TestApiTracer;
37+
import com.google.api.gax.rpc.EndpointContext;
38+
import com.google.api.gax.rpc.ResponseObserver;
39+
import com.google.api.gax.rpc.StreamController;
40+
import com.google.auth.Credentials;
3341
import com.google.common.truth.Truth;
42+
import com.google.protobuf.Field;
3443
import com.google.protobuf.TypeRegistry;
3544
import java.io.ByteArrayInputStream;
3645
import java.io.InputStream;
3746
import java.io.Reader;
47+
import java.util.Collections;
48+
import java.util.HashMap;
49+
import java.util.List;
50+
import java.util.Map;
51+
import java.util.concurrent.CountDownLatch;
3852
import java.util.concurrent.Executor;
53+
import java.util.concurrent.ExecutorService;
54+
import java.util.concurrent.Executors;
3955
import java.util.concurrent.ScheduledThreadPoolExecutor;
4056
import java.util.concurrent.TimeUnit;
57+
import org.junit.jupiter.api.AfterAll;
58+
import org.junit.jupiter.api.AfterEach;
59+
import org.junit.jupiter.api.BeforeAll;
60+
import org.junit.jupiter.api.BeforeEach;
4161
import org.junit.jupiter.api.Test;
4262
import org.junit.jupiter.api.extension.ExtendWith;
4363
import org.mockito.Mock;
@@ -135,4 +155,170 @@ void responseReceived_cancellationTaskExists_isCancelledProperly() throws Interr
135155
// Scheduler is not waiting for any task and should terminate quickly
136156
Truth.assertThat(deadlineSchedulerExecutor.isTerminated()).isTrue();
137157
}
158+
159+
private static final ApiMethodDescriptor<Field, Field> FAKE_METHOD_DESCRIPTOR =
160+
ApiMethodDescriptor.<Field, Field>newBuilder()
161+
.setFullMethodName("google.cloud.v1.Fake/FakeMethod")
162+
.setHttpMethod("POST")
163+
.setRequestFormatter(
164+
ProtoMessageRequestFormatter.<Field>newBuilder()
165+
.setPath(
166+
"/fake/v1/name/{name}",
167+
request -> {
168+
Map<String, String> fields = new HashMap<>();
169+
ProtoRestSerializer<Field> serializer = ProtoRestSerializer.create();
170+
serializer.putPathParam(fields, "name", request.getName());
171+
return fields;
172+
})
173+
.setQueryParamsExtractor(request -> new HashMap<>())
174+
.setRequestBodyExtractor(
175+
request ->
176+
ProtoRestSerializer.create()
177+
.toBody("*", request.toBuilder().clearName().build(), false))
178+
.build())
179+
.setResponseParser(
180+
ProtoMessageResponseParser.<Field>newBuilder()
181+
.setDefaultInstance(Field.getDefaultInstance())
182+
.build())
183+
.build();
184+
185+
private static final MockHttpService MOCK_SERVICE =
186+
new MockHttpService(Collections.singletonList(FAKE_METHOD_DESCRIPTOR), "google.com:443");
187+
188+
private static ExecutorService executorService;
189+
private ManagedHttpJsonChannel channel;
190+
private TestApiTracer tracer;
191+
192+
@BeforeAll
193+
static void initialize() {
194+
executorService = Executors.newFixedThreadPool(2);
195+
}
196+
197+
@AfterAll
198+
static void destroy() {
199+
executorService.shutdownNow();
200+
}
201+
202+
@BeforeEach
203+
void setUp() {
204+
channel =
205+
ManagedHttpJsonChannel.newBuilder()
206+
.setEndpoint("google.com:443")
207+
.setExecutor(executorService)
208+
.setHttpTransport(MOCK_SERVICE)
209+
.build();
210+
tracer = new TestApiTracer();
211+
}
212+
213+
@AfterEach
214+
void tearDown() {
215+
MOCK_SERVICE.reset();
216+
}
217+
218+
@Test
219+
void testBodySizeRecording() throws Exception {
220+
HttpJsonDirectCallable<Field, Field> callable =
221+
new HttpJsonDirectCallable<>(FAKE_METHOD_DESCRIPTOR);
222+
223+
EndpointContext endpointContext = Mockito.mock(EndpointContext.class);
224+
Mockito.lenient()
225+
.doNothing()
226+
.when(endpointContext)
227+
.validateUniverseDomain(
228+
Mockito.any(Credentials.class), Mockito.any(HttpJsonStatusCode.class));
229+
230+
HttpJsonCallContext callContext =
231+
HttpJsonCallContext.createDefault()
232+
.withChannel(channel)
233+
.withEndpointContext(endpointContext)
234+
.withTracer(tracer);
235+
236+
Field request = Field.newBuilder().setName("bob").setNumber(42).build();
237+
Field response = Field.newBuilder().setName("alice").setNumber(43).build();
238+
239+
MOCK_SERVICE.addResponse(response);
240+
241+
callable.futureCall(request, callContext).get();
242+
243+
// Verify response size
244+
// MockHttpService uses ProtoRestSerializer which pretty-prints.
245+
String expectedResponseBody = ProtoRestSerializer.create().toBody("*", response, false);
246+
long expectedResponseSize = expectedResponseBody.getBytes("UTF-8").length;
247+
assertThat(tracer.getResponseReceivedSize()).isEqualTo(expectedResponseSize);
248+
}
249+
250+
@Test
251+
void testBodySizeRecordingServerStreaming() throws Exception {
252+
ApiMethodDescriptor<Field, Field> methodServerStreaming =
253+
FAKE_METHOD_DESCRIPTOR.toBuilder()
254+
.setType(ApiMethodDescriptor.MethodType.SERVER_STREAMING)
255+
.build();
256+
257+
MockHttpService streamingMockService =
258+
new MockHttpService(Collections.singletonList(methodServerStreaming), "google.com:443");
259+
ManagedHttpJsonChannel streamingChannel =
260+
ManagedHttpJsonChannel.newBuilder()
261+
.setEndpoint("google.com:443")
262+
.setExecutor(executorService)
263+
.setHttpTransport(streamingMockService)
264+
.build();
265+
266+
HttpJsonDirectServerStreamingCallable<Field, Field> callable =
267+
new HttpJsonDirectServerStreamingCallable<>(methodServerStreaming);
268+
269+
EndpointContext endpointContext = Mockito.mock(EndpointContext.class);
270+
Mockito.lenient()
271+
.doNothing()
272+
.when(endpointContext)
273+
.validateUniverseDomain(
274+
Mockito.any(Credentials.class), Mockito.any(HttpJsonStatusCode.class));
275+
276+
HttpJsonCallContext callContext =
277+
HttpJsonCallContext.createDefault()
278+
.withChannel(streamingChannel)
279+
.withEndpointContext(endpointContext)
280+
.withTracer(tracer);
281+
282+
Field request = Field.newBuilder().setName("bob").setNumber(42).build();
283+
Field response1 = Field.newBuilder().setName("alice1").setNumber(43).build();
284+
Field response2 = Field.newBuilder().setName("alice2").setNumber(44).build();
285+
286+
streamingMockService.addResponse(new Field[] {response1, response2});
287+
288+
final List<Field> receivedResponses = new java.util.ArrayList<>();
289+
final CountDownLatch latch = new CountDownLatch(1);
290+
291+
callable.call(
292+
request,
293+
new ResponseObserver<Field>() {
294+
@Override
295+
public void onStart(StreamController controller) {
296+
// no behavior needed
297+
}
298+
299+
@Override
300+
public void onResponse(Field response) {
301+
receivedResponses.add(response);
302+
}
303+
304+
@Override
305+
public void onError(Throwable t) {
306+
latch.countDown();
307+
}
308+
309+
@Override
310+
public void onComplete() {
311+
latch.countDown();
312+
}
313+
},
314+
callContext);
315+
316+
latch.await(10, TimeUnit.SECONDS);
317+
318+
assertThat(receivedResponses).hasSize(2);
319+
320+
// Verify response size (0 because streaming chunked responses don't include Content-Length)
321+
assertThat(tracer.getResponseReceivedSize()).isEqualTo(0);
322+
streamingChannel.shutdownNow();
323+
}
138324
}

sdk-platform-java/gax-java/gax-httpjson/src/test/java/com/google/api/gax/httpjson/testing/MockHttpService.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.google.common.collect.ImmutableListMultimap;
4444
import com.google.common.collect.LinkedListMultimap;
4545
import com.google.common.collect.Multimap;
46+
import java.nio.charset.StandardCharsets;
4647
import java.util.LinkedList;
4748
import java.util.List;
4849
import java.util.Queue;
@@ -261,7 +262,11 @@ public MockLowLevelHttpResponse getHttpResponse(String httpMethod, String fullTa
261262
httpContent = methodDescriptor.getResponseParser().serialize(response);
262263
}
263264

264-
httpResponse.setContent(httpContent.getBytes());
265+
byte[] contentBytes = httpContent.getBytes(StandardCharsets.UTF_8);
266+
httpResponse.setContent(contentBytes);
267+
if (methodDescriptor.getType() != MethodType.SERVER_STREAMING) {
268+
httpResponse.addHeader("Content-Length", String.valueOf(contentBytes.length));
269+
}
265270
httpResponse.setStatusCode(200);
266271
return httpResponse;
267272
}

0 commit comments

Comments
 (0)