Skip to content

Commit 296c007

Browse files
authored
Fix: Append child channel configurators instead of overwriting (#12921)
appends child channels instead of overwriting them while propagating to subsequent child channels
1 parent d49a589 commit 296c007

7 files changed

Lines changed: 104 additions & 42 deletions

File tree

core/src/main/java/io/grpc/internal/ManagedChannelImplBuilder.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -762,8 +762,12 @@ protected ManagedChannelImplBuilder addMetricSink(MetricSink metricSink) {
762762
@Override
763763
public ManagedChannelImplBuilder childChannelConfigurator(
764764
ChannelConfigurator channelConfigurator) {
765-
this.channelConfigurator = checkNotNull(channelConfigurator,
766-
"childChannelConfigurator");
765+
checkNotNull(channelConfigurator, "childChannelConfigurator");
766+
ChannelConfigurator oldConfigurator = this.channelConfigurator;
767+
this.channelConfigurator = builder -> {
768+
oldConfigurator.configureChannelBuilder(builder);
769+
channelConfigurator.configureChannelBuilder(builder);
770+
};
767771
return this;
768772
}
769773

core/src/test/java/io/grpc/internal/ManagedChannelImplBuilderTest.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -808,13 +808,6 @@ public void setNameResolverExtArgs() {
808808
assertThat(builder.nameResolverCustomArgs.get(testKey)).isEqualTo(42);
809809
}
810810

811-
@Test
812-
public void childChannelConfigurator_setsField() {
813-
ChannelConfigurator configurator = builder -> { };
814-
assertSame(builder, builder.childChannelConfigurator(configurator));
815-
assertSame(configurator, builder.channelConfigurator);
816-
}
817-
818811
@Test
819812
public void childChannelConfigurator_propagatesMetricsAndInterceptors_xdsTarget() {
820813
// Setup Mocks
@@ -902,16 +895,13 @@ public String getDefaultScheme() {
902895
assertNotNull("Child channel configurator should be present in NameResolver.Args",
903896
channelConfiguratorInArgs);
904897

905-
// Verify the configurator is the one we passed
906-
assertThat(channelConfiguratorInArgs).isSameInstanceAs(configurator);
907-
908898
// Verify the configurator logically applies (by running it on a real builder)
909899
ManagedChannelImplBuilder childBuilder = new ManagedChannelImplBuilder(
910900
"xds:///child-service-target",
911901
mockClientTransportFactoryBuilder,
912902
new FixedPortProvider(DUMMY_PORT));
913903

914-
configurator.configureChannelBuilder(childBuilder);
904+
channelConfiguratorInArgs.configureChannelBuilder(childBuilder);
915905
assertThat(childBuilder.metricSinks).contains(mockMetricSink);
916906
}
917907

core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,10 @@ public void immediateDeadlineExceeded() {
499499

500500
@Test
501501
public void childChannelConfigurator_passedToNameResolverArgs() {
502-
ChannelConfigurator configurator = builder -> { };
502+
final boolean[] configuratorInvoked = new boolean[1];
503+
ChannelConfigurator configurator = builder -> {
504+
configuratorInvoked[0] = true;
505+
};
503506
channelBuilder.childChannelConfigurator(configurator);
504507
AtomicReference<NameResolver.Args> actualArgs = new AtomicReference<>();
505508
channelBuilder.nameResolverRegistry.register(new NameResolverProvider() {
@@ -528,12 +531,18 @@ protected int priority() {
528531
});
529532
createChannel();
530533
assertNotNull(actualArgs.get());
531-
assertSame(configurator, actualArgs.get().getChildChannelConfigurator());
534+
ChannelConfigurator childConfigurator = actualArgs.get().getChildChannelConfigurator();
535+
assertNotNull(childConfigurator);
536+
childConfigurator.configureChannelBuilder(channelBuilder);
537+
assertTrue(configuratorInvoked[0]);
532538
}
533539

534540
@Test
535541
public void childChannelConfigurator_passedToResolvingOobChannelNameResolverArgs() {
536-
ChannelConfigurator configurator = builder -> { };
542+
final boolean[] configuratorInvoked = new boolean[1];
543+
ChannelConfigurator configurator = builder -> {
544+
configuratorInvoked[0] = true;
545+
};
537546
channelBuilder.childChannelConfigurator(configurator);
538547
AtomicReference<NameResolver.Args> oobArgs = new AtomicReference<>();
539548
channelBuilder.nameResolverRegistry.register(new NameResolverProvider() {
@@ -567,7 +576,10 @@ protected int priority() {
567576
ManagedChannel oob = helper.createResolvingOobChannelBuilder("oobauthority").build();
568577
oob.getState(true);
569578
assertNotNull(oobArgs.get());
570-
assertSame(configurator, oobArgs.get().getChildChannelConfigurator());
579+
ChannelConfigurator childConfigurator = oobArgs.get().getChildChannelConfigurator();
580+
assertNotNull(childConfigurator);
581+
childConfigurator.configureChannelBuilder(channelBuilder);
582+
assertTrue(configuratorInvoked[0]);
571583
oob.shutdownNow();
572584
}
573585

xds/src/main/java/io/grpc/xds/XdsServerBuilder.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.util.logging.Logger;
4747
import javax.annotation.Nullable;
4848

49+
4950
/**
5051
* A version of {@link ServerBuilder} to create xDS managed servers.
5152
*/
@@ -118,7 +119,12 @@ public XdsServerBuilder drainGraceTime(long drainGraceTime, TimeUnit drainGraceT
118119
* @return this
119120
*/
120121
public XdsServerBuilder childChannelConfigurator(ChannelConfigurator channelConfigurator) {
121-
this.channelConfigurator = checkNotNull(channelConfigurator, "channelConfigurator");
122+
checkNotNull(channelConfigurator, "channelConfigurator");
123+
ChannelConfigurator oldConfigurator = this.channelConfigurator;
124+
this.channelConfigurator = builder -> {
125+
oldConfigurator.configureChannelBuilder(builder);
126+
channelConfigurator.configureChannelBuilder(builder);
127+
};
122128
return this;
123129
}
124130

xds/src/test/java/io/grpc/xds/FakeControlPlaneXdsIntegrationTest.java

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
import io.grpc.LoadBalancerRegistry;
6363
import io.grpc.LongCounterMetricInstrument;
6464
import io.grpc.ManagedChannel;
65-
import io.grpc.ManagedChannelBuilder;
6665
import io.grpc.Metadata;
6766
import io.grpc.MethodDescriptor;
6867
import io.grpc.NoopMetricSink;
@@ -375,17 +374,18 @@ public void pingPong_logicalDns_authorityOverride() {
375374

376375
@Test
377376
public void childChannelConfigurator_passesMetricSinkToChannel_E2E() throws Exception {
378-
CountingMetricSink sink = new CountingMetricSink();
379-
ChannelConfigurator configurator = new ChannelConfigurator() {
380-
@Override
381-
public void configureChannelBuilder(ManagedChannelBuilder<?> builder) {
382-
InternalManagedChannelBuilder.addMetricSink(builder, sink);
383-
}
384-
};
377+
CountingMetricSink sink1 = new CountingMetricSink();
378+
ChannelConfigurator configurator1 =
379+
builder -> InternalManagedChannelBuilder.addMetricSink(builder, sink1);
380+
381+
CountingMetricSink sink2 = new CountingMetricSink();
382+
ChannelConfigurator configurator2 =
383+
builder -> InternalManagedChannelBuilder.addMetricSink(builder, sink2);
385384

386385
ManagedChannel channel = Grpc.newChannelBuilder("test-xds:///test-server",
387386
InsecureChannelCredentials.create())
388-
.childChannelConfigurator(configurator)
387+
.childChannelConfigurator(configurator1)
388+
.childChannelConfigurator(configurator2)
389389
.build();
390390

391391
try {
@@ -394,34 +394,39 @@ public void configureChannelBuilder(ManagedChannelBuilder<?> builder) {
394394
blockingStub.unaryRpc(SimpleRequest.getDefaultInstance());
395395

396396
// The xDS client inside the channel configurator will have created an ADS stream.
397-
// The metric sink should have received attempt or connection metrics.
398-
sink.awaitCall();
397+
// Both metric sinks should have received attempt or connection metrics.
398+
sink1.awaitCall();
399+
sink2.awaitCall();
399400
} finally {
400401
channel.shutdownNow();
401402
}
402403
}
403404

404405
@Test
405406
public void childChannelConfigurator_passesMetricSinkToServer_E2E() throws Exception {
406-
CountingMetricSink sink = new CountingMetricSink();
407-
ChannelConfigurator configurator = builder -> {
408-
// Child channels (xDS client connections) created by this server get the sink.
409-
InternalManagedChannelBuilder.addMetricSink(builder, sink);
410-
};
407+
CountingMetricSink sink1 = new CountingMetricSink();
408+
ChannelConfigurator configurator1 =
409+
builder -> InternalManagedChannelBuilder.addMetricSink(builder, sink1);
410+
411+
CountingMetricSink sink2 = new CountingMetricSink();
412+
ChannelConfigurator configurator2 =
413+
builder -> InternalManagedChannelBuilder.addMetricSink(builder, sink2);
411414

412415
// We start an XdsServer manually.
413416
// XdsServer needs RDS, LDS, etc. from control plane.
414417
XdsServerBuilder serverBuilder = XdsServerBuilder.forPort(
415418
0, InsecureServerCredentials.create())
416419
.addService(new SimpleServiceGrpc.SimpleServiceImplBase() {})
417420
.overrideBootstrapForTest(controlPlane.defaultBootstrapOverride())
418-
.childChannelConfigurator(configurator);
421+
.childChannelConfigurator(configurator1)
422+
.childChannelConfigurator(configurator2);
419423

420424
Server childServer = serverBuilder.build().start();
421425

422426
try {
423427
// The server xDS client will connect to control plane to get LDS.
424-
sink.awaitCall();
428+
sink1.awaitCall();
429+
sink2.awaitCall();
425430
} finally {
426431
childServer.shutdownNow();
427432
}

xds/src/test/java/io/grpc/xds/GrpcXdsTransportFactoryTest.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import static com.google.common.truth.Truth.assertThat;
2020
import static org.junit.Assert.assertNotNull;
21-
import static org.junit.Assert.assertSame;
2221
import static org.mockito.Mockito.mock;
2322
import static org.mockito.Mockito.verify;
2423
import static org.mockito.Mockito.when;
@@ -260,13 +259,20 @@ protected int priority() {
260259
};
261260
NameResolverRegistry.getDefaultRegistry().register(testProvider);
262261
try {
263-
ChannelConfigurator configurer = builder -> { };
262+
final boolean[] configuratorInvoked = new boolean[1];
263+
ChannelConfigurator configurer = builder -> {
264+
configuratorInvoked[0] = true;
265+
};
264266
GrpcXdsTransportFactory factory = new GrpcXdsTransportFactory(null, configurer);
265267
XdsTransportFactory.XdsTransport transport = factory.create(
266268
Bootstrapper.ServerInfo.create(
267269
"test-xds-transport://localhost:8080", InsecureChannelCredentials.create()));
268270
assertNotNull(capturedArgs.get());
269-
assertSame(configurer, capturedArgs.get().getChildChannelConfigurator());
271+
ChannelConfigurator childConfigurator = capturedArgs.get().getChildChannelConfigurator();
272+
assertNotNull(childConfigurator);
273+
ManagedChannelBuilder<?> testBuilder = mock(ManagedChannelBuilder.class);
274+
childConfigurator.configureChannelBuilder(testBuilder);
275+
assertThat(configuratorInvoked[0]).isTrue();
270276
transport.shutdown();
271277
} finally {
272278
NameResolverRegistry.getDefaultRegistry().deregister(testProvider);

xds/src/test/java/io/grpc/xds/XdsServerBuilderTest.java

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818

1919
import static com.google.common.truth.Truth.assertThat;
2020
import static io.grpc.xds.XdsServerTestHelper.buildTestListener;
21+
import static org.junit.Assert.assertNotSame;
2122
import static org.junit.Assert.fail;
2223
import static org.mockito.Mockito.any;
23-
import static org.mockito.Mockito.eq;
2424
import static org.mockito.Mockito.mock;
2525
import static org.mockito.Mockito.never;
2626
import static org.mockito.Mockito.reset;
@@ -33,6 +33,7 @@
3333
import io.grpc.BindableService;
3434
import io.grpc.ChannelConfigurator;
3535
import io.grpc.InsecureServerCredentials;
36+
import io.grpc.ManagedChannelBuilder;
3637
import io.grpc.ServerServiceDefinition;
3738
import io.grpc.Status;
3839
import io.grpc.StatusException;
@@ -406,7 +407,10 @@ public void testOverrideBootstrap() throws Exception {
406407

407408
@Test
408409
public void start_passesChannelConfiguratorToClientPoolFactory() throws Exception {
409-
ChannelConfigurator configurer = builder -> { };
410+
final boolean[] configuratorInvoked = new boolean[1];
411+
ChannelConfigurator configurer = builder -> {
412+
configuratorInvoked[0] = true;
413+
};
410414
XdsClientPoolFactory mockPoolFactory = mock(XdsClientPoolFactory.class);
411415
@SuppressWarnings("unchecked")
412416
ObjectPool<XdsClient> mockPool = mock(ObjectPool.class);
@@ -420,8 +424,43 @@ public void start_passesChannelConfiguratorToClientPoolFactory() throws Exceptio
420424

421425
Future<?> unused = startServerAsync();
422426

427+
ArgumentCaptor<ChannelConfigurator> configuratorCaptor =
428+
ArgumentCaptor.forClass(ChannelConfigurator.class);
423429
verify(mockPoolFactory).getOrCreate(
424-
any(), any(), any(), eq(configurer));
430+
any(), any(), any(), configuratorCaptor.capture());
431+
432+
ManagedChannelBuilder<?> testBuilder = mock(ManagedChannelBuilder.class);
433+
configuratorCaptor.getValue().configureChannelBuilder(testBuilder);
434+
assertThat(configuratorInvoked[0]).isTrue();
435+
}
436+
437+
@Test
438+
public void childChannelConfigurator_appendsConfigurators() throws Exception {
439+
ChannelConfigurator configurer1 = builder -> { };
440+
ChannelConfigurator configurer2 = builder -> { };
441+
442+
XdsClientPoolFactory mockPoolFactory = mock(XdsClientPoolFactory.class);
443+
@SuppressWarnings("unchecked")
444+
ObjectPool<XdsClient> mockPool = mock(ObjectPool.class);
445+
when(mockPool.getObject()).thenReturn(xdsClient);
446+
when(mockPoolFactory.getOrCreate(any(), any(), any(), any())).thenReturn(mockPool);
447+
448+
buildBuilder(null);
449+
builder.childChannelConfigurator(configurer1);
450+
builder.childChannelConfigurator(configurer2);
451+
builder.xdsClientPoolFactory(mockPoolFactory);
452+
xdsServer = cleanupRule.register((XdsServerWrapper) builder.build());
453+
454+
Future<?> unused = startServerAsync();
455+
456+
// The captured configurator should be a composite of configurer1 and configurer2
457+
ArgumentCaptor<ChannelConfigurator> captor = ArgumentCaptor.forClass(ChannelConfigurator.class);
458+
verify(mockPoolFactory).getOrCreate(
459+
any(), any(), any(), captor.capture());
460+
ChannelConfigurator captured = captor.getValue();
461+
462+
assertNotSame(configurer1, captured);
463+
assertNotSame(configurer2, captured);
425464
}
426465

427466
@Test

0 commit comments

Comments
 (0)