Skip to content

Commit 2ce5429

Browse files
committed
use netty mock server for metrics test
1 parent 02c0303 commit 2ce5429

File tree

4 files changed

+157
-12
lines changed

4 files changed

+157
-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: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.google.common.base.Stopwatch;
3434
import com.google.common.collect.ImmutableList;
3535
import com.google.common.collect.Range;
36+
import io.grpc.ManagedChannelBuilder;
3637
import io.grpc.Status;
3738
import io.opentelemetry.api.OpenTelemetry;
3839
import io.opentelemetry.api.common.Attributes;
@@ -58,7 +59,7 @@
5859
import org.junit.runners.JUnit4;
5960

6061
@RunWith(JUnit4.class)
61-
public class OpenTelemetryBuiltInMetricsTracerTest extends AbstractMockServerTest {
62+
public class OpenTelemetryBuiltInMetricsTracerTest extends AbstractNettyMockServerTest {
6263

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

@@ -69,7 +70,8 @@ public class OpenTelemetryBuiltInMetricsTracerTest extends AbstractMockServerTes
6970

7071
private static Map<String, String> attributes;
7172

72-
private static Attributes expectedBaseAttributes;
73+
private static Attributes expectedCommonBaseAttributes;
74+
private static Attributes expectedCommonRequestAttributes;
7375

7476
private static final long MIN_LATENCY = 0;
7577

@@ -89,10 +91,11 @@ public static void setup() {
8991
String client_name = "spanner-java/";
9092
openTelemetry = OpenTelemetrySdk.builder().setMeterProvider(meterProvider.build()).build();
9193
provider.reset();
92-
provider.initialize("test-project", client_name, null, null);
94+
// provider.getOpenTelemetry().getMeterProvider().
95+
provider.initialize(openTelemetry, "test-project", client_name, null, null);
9396
attributes = provider.getClientAttributes();
9497

95-
expectedBaseAttributes =
98+
expectedCommonBaseAttributes =
9699
Attributes.builder()
97100
.put(BuiltInMetricsConstant.PROJECT_ID_KEY, "test-project")
98101
.put(BuiltInMetricsConstant.INSTANCE_CONFIG_ID_KEY, "unknown")
@@ -103,6 +106,14 @@ public static void setup() {
103106
.put(BuiltInMetricsConstant.CLIENT_UID_KEY, attributes.get("client_uid"))
104107
.put(BuiltInMetricsConstant.CLIENT_HASH_KEY, attributes.get("client_hash"))
105108
.build();
109+
110+
expectedCommonRequestAttributes =
111+
Attributes.builder()
112+
.put(BuiltInMetricsConstant.INSTANCE_ID_KEY, "i")
113+
.put(BuiltInMetricsConstant.DATABASE_KEY, "d")
114+
.put(BuiltInMetricsConstant.DIRECT_PATH_ENABLED_KEY, "false")
115+
.put(BuiltInMetricsConstant.DIRECT_PATH_USED_KEY, "false")
116+
.build();
106117
}
107118

108119
@BeforeClass
@@ -137,19 +148,19 @@ public void createSpannerInstance() {
137148
.setRetryDelayMultiplier(1.0)
138149
.setTotalTimeoutDuration(Duration.ofMinutes(10L))
139150
.build()));
151+
String endpoint = address.getHostString() + ":" + server.getPort();
140152
spanner =
141-
builder
153+
SpannerOptions.newBuilder()
142154
.setProjectId("test-project")
143-
.setChannelProvider(channelProvider)
155+
.setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
156+
.setHost("http://" + endpoint)
144157
.setCredentials(NoCredentials.getInstance())
145158
.setSessionPoolOption(
146159
SessionPoolOptions.newBuilder()
147160
.setWaitForMinSessionsDuration(Duration.ofSeconds(5L))
148161
.setFailOnSessionLeak()
149162
.setSkipVerifyingBeginTransactionForMuxRW(true)
150163
.build())
151-
// Setting this to false so that Spanner Options does not register Metrics Tracer
152-
// factory again.
153164
.setBuiltInMetricsEnabled(false)
154165
.setApiTracerFactory(metricsTracerFactory)
155166
.build()
@@ -167,8 +178,9 @@ public void testMetricsSingleUseQuery() {
167178

168179
long elapsed = stopwatch.elapsed(TimeUnit.MILLISECONDS);
169180
Attributes expectedAttributes =
170-
expectedBaseAttributes
181+
expectedCommonBaseAttributes
171182
.toBuilder()
183+
.putAll(expectedCommonRequestAttributes)
172184
.put(BuiltInMetricsConstant.STATUS_KEY, "OK")
173185
.put(BuiltInMetricsConstant.METHOD_KEY, "Spanner.ExecuteStreamingSql")
174186
.build();
@@ -190,6 +202,11 @@ public void testMetricsSingleUseQuery() {
190202
MetricData attemptCountMetricData =
191203
getMetricData(metricReader, BuiltInMetricsConstant.ATTEMPT_COUNT_NAME);
192204
assertThat(getAggregatedValue(attemptCountMetricData, expectedAttributes)).isEqualTo(1);
205+
206+
MetricData gfeLatencyMetricData =
207+
getMetricData(metricReader, BuiltInMetricsConstant.GFE_LATENCIES_NAME);
208+
long gfeLatencyValue = getAggregatedValue(attemptLatencyMetricData, expectedAttributes);
209+
assertThat(gfeLatencyValue).isEqualTo(gfeLatencyValue);
193210
}
194211

195212
@Test
@@ -206,14 +223,15 @@ public void testMetricsWithGaxRetryUnaryRpc() {
206223
stopwatch.elapsed(TimeUnit.MILLISECONDS);
207224

208225
Attributes expectedAttributesBeginTransactionOK =
209-
expectedBaseAttributes
226+
expectedCommonBaseAttributes
210227
.toBuilder()
228+
.putAll(expectedCommonRequestAttributes)
211229
.put(BuiltInMetricsConstant.STATUS_KEY, "OK")
212230
.put(BuiltInMetricsConstant.METHOD_KEY, "Spanner.BeginTransaction")
213231
.build();
214232

215233
Attributes expectedAttributesBeginTransactionFailed =
216-
expectedBaseAttributes
234+
expectedCommonBaseAttributes
217235
.toBuilder()
218236
.put(BuiltInMetricsConstant.STATUS_KEY, "UNAVAILABLE")
219237
.put(BuiltInMetricsConstant.METHOD_KEY, "Spanner.BeginTransaction")

0 commit comments

Comments
 (0)