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

Commit c3f29e0

Browse files
committed
test: modify ChannelUsageTest to comply with grpc-gcp behavior'
grpc-gcp is likely to repeatedly select the same channel if multiple requests are being sent at the same time. This caused the ChannelUsageTest to (randomly) fail, as it executed multiple requests in parallel. The test is now changed to execute the requests sequentially to trigger random channel selection.
1 parent ad35e2a commit c3f29e0

1 file changed

Lines changed: 13 additions & 28 deletions

File tree

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

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323

2424
import com.google.cloud.NoCredentials;
2525
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
26-
import com.google.common.util.concurrent.ListeningExecutorService;
27-
import com.google.common.util.concurrent.MoreExecutors;
2826
import com.google.protobuf.ListValue;
2927
import com.google.spanner.v1.ResultSetMetadata;
3028
import com.google.spanner.v1.SpannerGrpc;
@@ -40,13 +38,12 @@
4038
import io.grpc.ServerInterceptor;
4139
import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder;
4240
import java.net.InetSocketAddress;
43-
import java.time.Duration;
4441
import java.util.Arrays;
4542
import java.util.Collection;
43+
import java.util.Deque;
4644
import java.util.Set;
4745
import java.util.concurrent.ConcurrentHashMap;
48-
import java.util.concurrent.CountDownLatch;
49-
import java.util.concurrent.Executors;
46+
import java.util.concurrent.ConcurrentLinkedDeque;
5047
import java.util.logging.Level;
5148
import java.util.logging.Logger;
5249
import org.junit.After;
@@ -103,6 +100,7 @@ public static Collection<Object[]> data() {
103100
// Track channel hints (from X-Goog-Spanner-Request-Id header) per RPC method
104101
private static final Set<Long> batchCreateSessionChannelHints = ConcurrentHashMap.newKeySet();
105102
private static final Set<Long> executeSqlChannelHints = ConcurrentHashMap.newKeySet();
103+
private static final Deque<Long> allExecuteSqlChannelHints = new ConcurrentLinkedDeque<>();
106104

107105
private static Level originalLogLevel;
108106

@@ -148,6 +146,7 @@ public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
148146
if (call.getMethodDescriptor()
149147
.equals(SpannerGrpc.getExecuteStreamingSqlMethod())) {
150148
executeSqlChannelHints.add(channelHint);
149+
allExecuteSqlChannelHints.add(channelHint);
151150
}
152151
} catch (NumberFormatException e) {
153152
// Ignore parse errors
@@ -185,6 +184,7 @@ public void reset() {
185184
mockSpanner.reset();
186185
batchCreateSessionChannelHints.clear();
187186
executeSqlChannelHints.clear();
187+
allExecuteSqlChannelHints.clear();
188188
}
189189

190190
private SpannerOptions createSpannerOptions() {
@@ -215,35 +215,20 @@ public void testUsesAllChannels() throws InterruptedException {
215215
final int multiplier = 10;
216216
try (Spanner spanner = createSpannerOptions().getService()) {
217217
DatabaseClient client = spanner.getDatabaseClient(DatabaseId.of("p", "i", "d"));
218-
ListeningExecutorService executor =
219-
MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(numChannels * multiplier));
220-
CountDownLatch latch = new CountDownLatch(numChannels * multiplier);
221218
for (int run = 0; run < numChannels * multiplier; run++) {
222-
executor.submit(
223-
() -> {
224-
// Use a multi-use read-only transaction to make sure we keep a session in use for
225-
// a longer period of time.
226-
try (ReadOnlyTransaction transaction = client.readOnlyTransaction()) {
227-
try (ResultSet resultSet = transaction.executeQuery(SELECT1)) {
228-
while (resultSet.next()) {}
229-
}
230-
latch.countDown();
231-
// Wait here until we now that all threads have reached this point and have a
232-
// session in use.
233-
latch.await();
234-
try (ResultSet resultSet = transaction.executeQuery(SELECT1)) {
235-
while (resultSet.next()) {}
236-
}
237-
}
238-
return true;
239-
});
219+
try (ReadOnlyTransaction transaction = client.readOnlyTransaction()) {
220+
for (int i = 0; i < 2; i++) {
221+
try (ResultSet resultSet = transaction.executeQuery(SELECT1)) {
222+
while (resultSet.next()) {}
223+
}
224+
}
225+
}
240226
}
241-
executor.shutdown();
242-
assertTrue(executor.awaitTermination(Duration.ofSeconds(10L)));
243227
}
244228
// Bound the channel hints to numChannels (matching gRPC-GCP behavior) and verify
245229
// that channels are being distributed. The raw channel hints may be unbounded (based on
246230
// session index), but gRPC-GCP bounds them to the actual number of channels.
231+
assertEquals(2 * numChannels * multiplier, allExecuteSqlChannelHints.size());
247232
Set<Long> boundedChannelHints =
248233
executeSqlChannelHints.stream().map(hint -> hint % numChannels).collect(toSet());
249234
// Verify that channel distribution is working:

0 commit comments

Comments
 (0)