Skip to content

Commit 997e681

Browse files
committed
use netty mock server for metrics test
1 parent cfb0404 commit 997e681

File tree

4 files changed

+156
-12
lines changed

4 files changed

+156
-12
lines changed

google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInMetricsConstant.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public class BuiltInMetricsConstant {
4949
OPERATION_LATENCIES_NAME,
5050
ATTEMPT_LATENCIES_NAME,
5151
OPERATION_COUNT_NAME,
52-
ATTEMPT_COUNT_NAME)
52+
ATTEMPT_COUNT_NAME,
53+
GFE_LATENCIES_NAME)
5354
.stream()
5455
.map(m -> METER_NAME + '/' + m)
5556
.collect(Collectors.toSet());

google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ void initialize(
9494
}
9595
}
9696

97+
@VisibleForTesting
98+
void initialize(
99+
OpenTelemetry openTelemetry,
100+
String projectId,
101+
String client_name,
102+
@Nullable Credentials credentials,
103+
@Nullable String monitoringHost) {
104+
initialize(projectId, client_name, credentials, monitoringHost);
105+
this.builtInOpenTelemetryMetricsRecorder =
106+
new BuiltInOpenTelemetryMetricsRecorder(openTelemetry, clientAttributes);
107+
}
108+
97109
OpenTelemetry getOpenTelemetry() {
98110
return this.openTelemetry;
99111
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2023 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+
* http://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.cloud.spanner;
18+
19+
import com.google.api.gax.grpc.testing.LocalChannelProvider;
20+
import com.google.cloud.NoCredentials;
21+
import io.grpc.ForwardingServerCall;
22+
import io.grpc.ManagedChannelBuilder;
23+
import io.grpc.Metadata;
24+
import io.grpc.Server;
25+
import io.grpc.ServerCall;
26+
import io.grpc.ServerCallHandler;
27+
import io.grpc.ServerInterceptor;
28+
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
29+
import java.io.IOException;
30+
import java.net.InetSocketAddress;
31+
import java.util.Random;
32+
import java.util.concurrent.ExecutorService;
33+
import java.util.concurrent.Executors;
34+
import java.util.concurrent.atomic.AtomicInteger;
35+
import org.junit.After;
36+
import org.junit.AfterClass;
37+
import org.junit.Before;
38+
import org.junit.BeforeClass;
39+
40+
abstract class AbstractNettyMockServerTest {
41+
protected static MockSpannerServiceImpl mockSpanner;
42+
43+
protected static Server server;
44+
protected static InetSocketAddress address;
45+
static ExecutorService executor;
46+
protected static LocalChannelProvider channelProvider;
47+
protected static AtomicInteger fakeServerTiming =
48+
new AtomicInteger(new Random().nextInt(1000) + 1);
49+
50+
protected Spanner spanner;
51+
52+
@BeforeClass
53+
public static void startMockServer() throws IOException {
54+
mockSpanner = new MockSpannerServiceImpl();
55+
mockSpanner.setAbortProbability(0.0D); // We don't want any unpredictable aborted transactions.
56+
57+
address = new InetSocketAddress("localhost", 0);
58+
server =
59+
NettyServerBuilder.forAddress(address)
60+
.addService(mockSpanner)
61+
.intercept(
62+
new ServerInterceptor() {
63+
@Override
64+
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
65+
ServerCall<ReqT, RespT> serverCall,
66+
Metadata headers,
67+
ServerCallHandler<ReqT, RespT> serverCallHandler) {
68+
return serverCallHandler.startCall(
69+
new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(
70+
serverCall) {
71+
@Override
72+
public void sendHeaders(Metadata headers) {
73+
headers.put(
74+
Metadata.Key.of("server-timing", Metadata.ASCII_STRING_MARSHALLER),
75+
String.format("gfet4t7; dur=%d", fakeServerTiming.get()));
76+
super.sendHeaders(headers);
77+
}
78+
},
79+
headers);
80+
}
81+
})
82+
.build()
83+
.start();
84+
executor = Executors.newSingleThreadExecutor();
85+
}
86+
87+
@AfterClass
88+
public static void stopMockServer() throws InterruptedException {
89+
server.shutdown();
90+
server.awaitTermination();
91+
executor.shutdown();
92+
}
93+
94+
@Before
95+
public void createSpannerInstance() {
96+
String endpoint = address.getHostString() + ":" + server.getPort();
97+
spanner =
98+
SpannerOptions.newBuilder()
99+
.setProjectId("test-project")
100+
.setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
101+
.setHost("http://" + endpoint)
102+
.setCredentials(NoCredentials.getInstance())
103+
.setSessionPoolOption(SessionPoolOptions.newBuilder().setFailOnSessionLeak().build())
104+
.build()
105+
.getService();
106+
}
107+
108+
@After
109+
public void cleanup() {
110+
spanner.close();
111+
mockSpanner.reset();
112+
mockSpanner.removeAllExecutionTimes();
113+
}
114+
}

google-cloud-spanner/src/test/java/com/google/cloud/spanner/OpenTelemetryBuiltInMetricsTracerTest.java

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
import org.junit.runners.JUnit4;
6161

6262
@RunWith(JUnit4.class)
63-
public class OpenTelemetryBuiltInMetricsTracerTest extends AbstractMockServerTest {
63+
public class OpenTelemetryBuiltInMetricsTracerTest extends AbstractNettyMockServerTest {
6464

6565
private static final Statement SELECT_RANDOM = Statement.of("SELECT * FROM random");
6666

@@ -71,7 +71,8 @@ public class OpenTelemetryBuiltInMetricsTracerTest extends AbstractMockServerTes
7171

7272
private static Map<String, String> attributes;
7373

74-
private static Attributes expectedBaseAttributes;
74+
private static Attributes expectedCommonBaseAttributes;
75+
private static Attributes expectedCommonRequestAttributes;
7576

7677
private static final long MIN_LATENCY = 0;
7778

@@ -91,10 +92,11 @@ public static void setup() {
9192
String client_name = "spanner-java/";
9293
openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(meterProvider.build()).build();
9394
provider.reset();
94-
provider.initialize("test-project", client_name, null, null);
95+
// provider.getOpenTelemetry().getMeterProvider().
96+
provider.initialize(openTelemetry, "test-project", client_name, null, null);
9597
attributes = provider.getClientAttributes();
9698

97-
expectedBaseAttributes =
99+
expectedCommonBaseAttributes =
98100
Attributes.builder()
99101
.put(BuiltInMetricsConstant.PROJECT_ID_KEY, "test-project")
100102
.put(BuiltInMetricsConstant.INSTANCE_CONFIG_ID_KEY, "unknown")
@@ -105,6 +107,14 @@ public static void setup() {
105107
.put(BuiltInMetricsConstant.CLIENT_UID_KEY, attributes.get("client_uid"))
106108
.put(BuiltInMetricsConstant.CLIENT_HASH_KEY, attributes.get("client_hash"))
107109
.build();
110+
111+
expectedCommonRequestAttributes =
112+
Attributes.builder()
113+
.put(BuiltInMetricsConstant.INSTANCE_ID_KEY, "i")
114+
.put(BuiltInMetricsConstant.DATABASE_KEY, "d")
115+
.put(BuiltInMetricsConstant.DIRECT_PATH_ENABLED_KEY, "false")
116+
.put(BuiltInMetricsConstant.DIRECT_PATH_USED_KEY, "false")
117+
.build();
108118
}
109119

110120
@BeforeClass
@@ -139,19 +149,19 @@ public void createSpannerInstance() {
139149
.setRetryDelayMultiplier(1.0)
140150
.setTotalTimeoutDuration(Duration.ofMinutes(10L))
141151
.build()));
152+
String endpoint = address.getHostString() + ":" + server.getPort();
142153
spanner =
143-
builder
154+
SpannerOptions.newBuilder()
144155
.setProjectId("test-project")
145-
.setChannelProvider(channelProvider)
156+
.setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
157+
.setHost("http://" + endpoint)
146158
.setCredentials(NoCredentials.getInstance())
147159
.setSessionPoolOption(
148160
SessionPoolOptions.newBuilder()
149161
.setWaitForMinSessionsDuration(Duration.ofSeconds(5L))
150162
.setFailOnSessionLeak()
151163
.setSkipVerifyingBeginTransactionForMuxRW(true)
152164
.build())
153-
// Setting this to false so that Spanner Options does not register Metrics Tracer
154-
// factory again.
155165
.setBuiltInMetricsEnabled(false)
156166
.setApiTracerFactory(metricsTracerFactory)
157167
.build()
@@ -169,8 +179,9 @@ public void testMetricsSingleUseQuery() {
169179

170180
long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
171181
Attributes expectedAttributes =
172-
expectedBaseAttributes
182+
expectedCommonBaseAttributes
173183
.toBuilder()
184+
.putAll(expectedCommonRequestAttributes)
174185
.put(BuiltInMetricsConstant.STATUS_KEY, "OK")
175186
.put(BuiltInMetricsConstant.METHOD_KEY, "Spanner.ExecuteStreamingSql")
176187
.build();
@@ -196,6 +207,11 @@ public void testMetricsSingleUseQuery() {
196207
getMetricData(metricReader, BuiltInMetricsConstant.ATTEMPT_COUNT_NAME);
197208
assertNotNull(attemptCountMetricData);
198209
assertThat(getAggregatedValue(attemptCountMetricData, expectedAttributes)).isEqualTo(1);
210+
211+
MetricData gfeLatencyMetricData =
212+
getMetricData(metricReader, BuiltInMetricsConstant.GFE_LATENCIES_NAME);
213+
long gfeLatencyValue = getAggregatedValue(attemptLatencyMetricData, expectedAttributes);
214+
assertThat(gfeLatencyValue).isEqualTo(gfeLatencyValue);
199215
}
200216

201217
@Test
@@ -212,14 +228,15 @@ public void testMetricsWithGaxRetryUnaryRpc() {
212228
stopwatch.elapsed(TimeUnit.MILLISECONDS);
213229

214230
Attributes expectedAttributesBeginTransactionOK =
215-
expectedBaseAttributes
231+
expectedCommonBaseAttributes
216232
.toBuilder()
233+
.putAll(expectedCommonRequestAttributes)
217234
.put(BuiltInMetricsConstant.STATUS_KEY, "OK")
218235
.put(BuiltInMetricsConstant.METHOD_KEY, "Spanner.BeginTransaction")
219236
.build();
220237

221238
Attributes expectedAttributesBeginTransactionFailed =
222-
expectedBaseAttributes
239+
expectedCommonBaseAttributes
223240
.toBuilder()
224241
.put(BuiltInMetricsConstant.STATUS_KEY, "UNAVAILABLE")
225242
.put(BuiltInMetricsConstant.METHOD_KEY, "Spanner.BeginTransaction")

0 commit comments

Comments
 (0)