Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.

Commit 97bd6cf

Browse files
committed
add tests
1 parent de62468 commit 97bd6cf

3 files changed

Lines changed: 136 additions & 6 deletions

File tree

google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/ChannelFinderServerFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
* Factory for creating and caching server connections for location-aware routing.
2323
*
2424
* <p>Implementations are expected to cache {@link ChannelFinderServer} instances such that repeated
25-
* calls with the same address return the same instance. This allows the {@link
26-
* com.google.cloud.spanner.spi.v1.KeyRangeCache} to efficiently manage server references.
25+
* calls with the same address return the same instance. This allows routing components to
26+
* efficiently manage server references.
2727
*
2828
* <p>Implementations must be thread-safe. Multiple threads may concurrently call {@link
2929
* #create(String)} with different addresses.

google-cloud-spanner/src/main/java/com/google/cloud/spanner/spi/v1/GrpcChannelFinderServerFactory.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,12 @@ static class GrpcChannelFinderServer implements ChannelFinderServer {
147147
*/
148148
GrpcChannelFinderServer(String address, TransportChannelProvider provider) throws IOException {
149149
this.address = address;
150-
GrpcTransportChannel transportChannel = (GrpcTransportChannel) provider.getTransportChannel();
150+
TransportChannelProvider readyProvider = provider;
151+
if (provider.needsHeaders()) {
152+
readyProvider = provider.withHeaders(java.util.Collections.emptyMap());
153+
}
154+
GrpcTransportChannel transportChannel =
155+
(GrpcTransportChannel) readyProvider.getTransportChannel();
151156
this.channel = (ManagedChannel) transportChannel.getChannel();
152157
}
153158

@@ -173,9 +178,15 @@ public boolean isHealthy() {
173178
if (channel.isShutdown() || channel.isTerminated()) {
174179
return false;
175180
}
176-
// Check connectivity state without triggering a connection attempt
177-
ConnectivityState state = channel.getState(false);
178-
return state != ConnectivityState.SHUTDOWN && state != ConnectivityState.TRANSIENT_FAILURE;
181+
// Check connectivity state without triggering a connection attempt.
182+
// Some channel implementations don't support getState(), in which case
183+
// we assume the channel is healthy if it's not shutdown/terminated.
184+
try {
185+
ConnectivityState state = channel.getState(false);
186+
return state != ConnectivityState.SHUTDOWN && state != ConnectivityState.TRANSIENT_FAILURE;
187+
} catch (UnsupportedOperationException e) {
188+
return true;
189+
}
179190
}
180191

181192
@Override
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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+
* 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.spi.v1;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
import static org.junit.Assert.assertThrows;
21+
22+
import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider;
23+
import com.google.cloud.spanner.SpannerException;
24+
import io.grpc.ManagedChannelBuilder;
25+
import org.junit.Test;
26+
27+
public class GrpcChannelFinderServerFactoryTest {
28+
29+
private static InstantiatingGrpcChannelProvider createProvider(String endpoint) {
30+
return InstantiatingGrpcChannelProvider.newBuilder()
31+
.setEndpoint(endpoint)
32+
.setChannelConfigurator(ManagedChannelBuilder::usePlaintext)
33+
.build();
34+
}
35+
36+
@Test
37+
public void defaultServerIsCached() throws Exception {
38+
GrpcChannelFinderServerFactory factory =
39+
new GrpcChannelFinderServerFactory(createProvider("localhost:1234"));
40+
try {
41+
ChannelFinderServer defaultServer = factory.defaultServer();
42+
ChannelFinderServer server = factory.create(defaultServer.getAddress());
43+
assertThat(server).isSameInstanceAs(defaultServer);
44+
} finally {
45+
factory.shutdown();
46+
}
47+
}
48+
49+
@Test
50+
public void createCachesPerAddress() throws Exception {
51+
GrpcChannelFinderServerFactory factory =
52+
new GrpcChannelFinderServerFactory(createProvider("localhost:1234"));
53+
try {
54+
ChannelFinderServer first = factory.create("localhost:1111");
55+
ChannelFinderServer second = factory.create("localhost:1111");
56+
ChannelFinderServer third = factory.create("localhost:2222");
57+
58+
assertThat(second).isSameInstanceAs(first);
59+
assertThat(third).isNotSameInstanceAs(first);
60+
} finally {
61+
factory.shutdown();
62+
}
63+
}
64+
65+
@Test
66+
public void evictRemovesNonDefaultServer() throws Exception {
67+
GrpcChannelFinderServerFactory factory =
68+
new GrpcChannelFinderServerFactory(createProvider("localhost:1234"));
69+
try {
70+
ChannelFinderServer first = factory.create("localhost:1111");
71+
factory.evict("localhost:1111");
72+
ChannelFinderServer second = factory.create("localhost:1111");
73+
74+
assertThat(second).isNotSameInstanceAs(first);
75+
} finally {
76+
factory.shutdown();
77+
}
78+
}
79+
80+
@Test
81+
public void evictIgnoresDefaultServer() throws Exception {
82+
GrpcChannelFinderServerFactory factory =
83+
new GrpcChannelFinderServerFactory(createProvider("localhost:1234"));
84+
try {
85+
ChannelFinderServer defaultServer = factory.defaultServer();
86+
factory.evict(defaultServer.getAddress());
87+
ChannelFinderServer server = factory.create(defaultServer.getAddress());
88+
89+
assertThat(server).isSameInstanceAs(defaultServer);
90+
} finally {
91+
factory.shutdown();
92+
}
93+
}
94+
95+
@Test
96+
public void shutdownPreventsNewServers() throws Exception {
97+
GrpcChannelFinderServerFactory factory =
98+
new GrpcChannelFinderServerFactory(createProvider("localhost:1234"));
99+
factory.shutdown();
100+
101+
assertThrows(SpannerException.class, () -> factory.create("localhost:1111"));
102+
assertThat(factory.defaultServer().getChannel().isShutdown()).isTrue();
103+
}
104+
105+
@Test
106+
public void healthReflectsChannelShutdown() throws Exception {
107+
GrpcChannelFinderServerFactory factory =
108+
new GrpcChannelFinderServerFactory(createProvider("localhost:1234"));
109+
try {
110+
ChannelFinderServer server = factory.create("localhost:1111");
111+
assertThat(server.isHealthy()).isTrue();
112+
113+
server.getChannel().shutdownNow();
114+
assertThat(server.isHealthy()).isFalse();
115+
} finally {
116+
factory.shutdown();
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)