Skip to content

Commit 9595507

Browse files
committed
add test case
1 parent 8cd7281 commit 9595507

File tree

3 files changed

+117
-11
lines changed

3 files changed

+117
-11
lines changed

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,15 @@ public void transportShutdown(final Status s) {
633633
addressIndex.getCurrentEagAttributes(), LoadBalancer.ATTR_LOCALITY_NAME),
634634
null, null
635635
));
636+
subchannelMetrics.recordDisconnection(buildLabelSet(
637+
getAttributeOrDefault(
638+
addressIndex.getCurrentEagAttributes(), NameResolver.ATTR_BACKEND_SERVICE),
639+
getAttributeOrDefault(
640+
addressIndex.getCurrentEagAttributes(), LoadBalancer.ATTR_LOCALITY_NAME),
641+
"Peer Pressure",
642+
extractSecurityLevel(
643+
addressIndex.getCurrentEagAttributes().get(GrpcAttributes.ATTR_SECURITY_LEVEL))
644+
));
636645
syncContext.execute(new Runnable() {
637646
@Override
638647
public void run() {
@@ -673,15 +682,6 @@ public void transportTerminated() {
673682
for (ClientTransportFilter filter : transportFilters) {
674683
filter.transportTerminated(transport.getAttributes());
675684
}
676-
subchannelMetrics.recordDisconnection(buildLabelSet(
677-
getAttributeOrDefault(
678-
addressIndex.getCurrentEagAttributes(), NameResolver.ATTR_BACKEND_SERVICE),
679-
getAttributeOrDefault(
680-
addressIndex.getCurrentEagAttributes(), LoadBalancer.ATTR_LOCALITY_NAME),
681-
"Peer Pressure",
682-
extractSecurityLevel(
683-
addressIndex.getCurrentEagAttributes().get(GrpcAttributes.ATTR_SECURITY_LEVEL))
684-
));
685685
syncContext.execute(new Runnable() {
686686
@Override
687687
public void run() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public SubchannelMetrics(MetricRecorder metricRecorder) {
3939
MetricInstrumentRegistry metricInstrumentRegistry
4040
= MetricInstrumentRegistry.getDefaultRegistry();
4141
disconnections = metricInstrumentRegistry.registerLongCounter(
42-
"grpc.subchannel.disconnections1",
42+
"grpc.subchannel.disconnections",
4343
"EXPERIMENTAL. Number of times the selected subchannel becomes disconnected",
4444
"{disconnection}",
4545
Lists.newArrayList("grpc.target"),

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

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,13 @@
2929
import static org.junit.Assert.assertSame;
3030
import static org.junit.Assert.assertThrows;
3131
import static org.junit.Assert.assertTrue;
32+
import static org.mockito.AdditionalAnswers.delegatesTo;
3233
import static org.mockito.ArgumentMatchers.any;
34+
import static org.mockito.ArgumentMatchers.argThat;
3335
import static org.mockito.ArgumentMatchers.eq;
3436
import static org.mockito.ArgumentMatchers.isA;
3537
import static org.mockito.ArgumentMatchers.same;
38+
import static org.mockito.Mockito.inOrder;
3639
import static org.mockito.Mockito.mock;
3740
import static org.mockito.Mockito.never;
3841
import static org.mockito.Mockito.times;
@@ -48,7 +51,10 @@
4851
import io.grpc.InternalLogId;
4952
import io.grpc.InternalWithLogId;
5053
import io.grpc.LoadBalancer;
54+
import io.grpc.MetricInstrument;
5155
import io.grpc.MetricRecorder;
56+
import io.grpc.NameResolver;
57+
import io.grpc.SecurityLevel;
5258
import io.grpc.Status;
5359
import io.grpc.SynchronizationContext;
5460
import io.grpc.internal.InternalSubchannel.CallTracingTransport;
@@ -69,6 +75,7 @@
6975
import org.junit.Test;
7076
import org.junit.runner.RunWith;
7177
import org.junit.runners.JUnit4;
78+
import org.mockito.InOrder;
7279
import org.mockito.Mock;
7380
import org.mockito.junit.MockitoJUnit;
7481
import org.mockito.junit.MockitoRule;
@@ -82,6 +89,9 @@ public class InternalSubchannelTest {
8289
public final MockitoRule mocks = MockitoJUnit.rule();
8390

8491
private static final String AUTHORITY = "fakeauthority";
92+
private static final String BACKEND_SERVICE = "ice-cream-factory-service";
93+
private static final String LOCALITY = "mars-olympus-mons-datacenter";
94+
private static final SecurityLevel SECURITY_LEVEL = SecurityLevel.PRIVACY_AND_INTEGRITY;
8595
private static final String USER_AGENT = "mosaic";
8696
private static final ConnectivityStateInfo UNAVAILABLE_STATE =
8797
ConnectivityStateInfo.forTransientFailure(Status.UNAVAILABLE);
@@ -109,6 +119,12 @@ public void uncaughtException(Thread t, Throwable e) {
109119
@Mock private BackoffPolicy.Provider mockBackoffPolicyProvider;
110120
@Mock private ClientTransportFactory mockTransportFactory;
111121

122+
@Mock private BackoffPolicy mockBackoffPolicy;
123+
private MetricRecorder mockMetricRecorder = mock(MetricRecorder.class,
124+
delegatesTo(new MetricRecorderImpl()));
125+
126+
private static final long RECONNECT_BACKOFF_DELAY_NANOS = TimeUnit.SECONDS.toNanos(1);
127+
112128
private final LinkedList<String> callbackInvokes = new LinkedList<>();
113129
private final InternalSubchannel.Callback mockInternalSubchannelCallback =
114130
new InternalSubchannel.Callback() {
@@ -1449,8 +1465,90 @@ private void createInternalSubchannel(boolean reconnectDisabled,
14491465
new ChannelLoggerImpl(subchannelTracer, fakeClock.getTimeProvider()),
14501466
Collections.emptyList(),
14511467
"",
1452-
new MetricRecorder() {}
1468+
new MetricRecorder() {
1469+
}
1470+
);
1471+
}
1472+
1473+
@Test
1474+
public void subchannelStateChanges_triggersMetrics_disconnectionOnly() {
1475+
// 1. Mock the backoff policy
1476+
when(mockBackoffPolicyProvider.get()).thenReturn(mockBackoffPolicy);
1477+
when(mockBackoffPolicy.nextBackoffNanos()).thenReturn(RECONNECT_BACKOFF_DELAY_NANOS);
1478+
1479+
// 2. Setup Subchannel with attributes
1480+
SocketAddress addr = mock(SocketAddress.class);
1481+
Attributes eagAttributes = Attributes.newBuilder()
1482+
.set(NameResolver.ATTR_BACKEND_SERVICE, BACKEND_SERVICE)
1483+
.set(LoadBalancer.ATTR_LOCALITY_NAME, LOCALITY)
1484+
.set(GrpcAttributes.ATTR_SECURITY_LEVEL, SECURITY_LEVEL)
1485+
.build();
1486+
List<EquivalentAddressGroup> addressGroups =
1487+
Arrays.asList(new EquivalentAddressGroup(Arrays.asList(addr), eagAttributes));
1488+
createInternalSubchannel(new EquivalentAddressGroup(addr));
1489+
InternalLogId logId = InternalLogId.allocate("Subchannel", /*details=*/ AUTHORITY);
1490+
ChannelTracer subchannelTracer = new ChannelTracer(logId, 10,
1491+
fakeClock.getTimeProvider().currentTimeNanos(), "Subchannel");
1492+
LoadBalancer.CreateSubchannelArgs createSubchannelArgs =
1493+
LoadBalancer.CreateSubchannelArgs.newBuilder().setAddresses(addressGroups).build();
1494+
internalSubchannel = new InternalSubchannel(
1495+
createSubchannelArgs, AUTHORITY, USER_AGENT, mockBackoffPolicyProvider,
1496+
mockTransportFactory, fakeClock.getScheduledExecutorService(),
1497+
fakeClock.getStopwatchSupplier(), syncContext, mockInternalSubchannelCallback, channelz,
1498+
CallTracer.getDefaultFactory().create(), subchannelTracer, logId,
1499+
new ChannelLoggerImpl(subchannelTracer, fakeClock.getTimeProvider()),
1500+
Collections.emptyList(), AUTHORITY, mockMetricRecorder
1501+
);
1502+
1503+
// --- Action ---
1504+
internalSubchannel.obtainActiveTransport();
1505+
MockClientTransportInfo transportInfo = transports.poll();
1506+
assertNotNull(transportInfo);
1507+
transportInfo.listener.transportReady();
1508+
fakeClock.runDueTasks();
1509+
1510+
transportInfo.listener.transportShutdown(Status.UNAVAILABLE);
1511+
fakeClock.runDueTasks();
1512+
1513+
// --- Verification ---
1514+
InOrder inOrder = inOrder(mockMetricRecorder);
1515+
1516+
// Verify successful connection metrics
1517+
inOrder.verify(mockMetricRecorder).addLongCounter(
1518+
eqMetricInstrumentName("grpc.subchannel.connection_attempts_succeeded"),
1519+
eq(1L),
1520+
eq(Arrays.asList(AUTHORITY)),
1521+
eq(Arrays.asList(BACKEND_SERVICE, LOCALITY))
1522+
);
1523+
inOrder.verify(mockMetricRecorder).addLongUpDownCounter(
1524+
eqMetricInstrumentName("grpc.subchannel.open_connections"),
1525+
eq(1L),
1526+
eq(Arrays.asList(AUTHORITY)),
1527+
eq(Arrays.asList("privacy_and_integrity", BACKEND_SERVICE, LOCALITY))
1528+
);
1529+
1530+
inOrder.verify(mockMetricRecorder).addLongCounter(
1531+
eqMetricInstrumentName("grpc.subchannel.connection_attempts_failed"),
1532+
eq(1L),
1533+
eq(Arrays.asList(AUTHORITY)),
1534+
eq(Arrays.asList(BACKEND_SERVICE, LOCALITY))
14531535
);
1536+
1537+
// Verify disconnection and automatic failure metrics
1538+
inOrder.verify(mockMetricRecorder).addLongCounter(
1539+
eqMetricInstrumentName("grpc.subchannel.disconnections"),
1540+
eq(1L),
1541+
eq(Arrays.asList(AUTHORITY)),
1542+
eq(Arrays.asList(BACKEND_SERVICE, LOCALITY, "Peer Pressure"))
1543+
);
1544+
inOrder.verify(mockMetricRecorder).addLongUpDownCounter(
1545+
eqMetricInstrumentName("grpc.subchannel.open_connections"),
1546+
eq(-1L),
1547+
eq(Arrays.asList(AUTHORITY)),
1548+
eq(Arrays.asList("privacy_and_integrity", BACKEND_SERVICE, LOCALITY))
1549+
);
1550+
1551+
inOrder.verifyNoMoreInteractions();
14541552
}
14551553

14561554
private void assertNoCallbackInvoke() {
@@ -1463,5 +1561,13 @@ private void assertExactCallbackInvokes(String ... expectedInvokes) {
14631561
callbackInvokes.clear();
14641562
}
14651563

1564+
static class MetricRecorderImpl implements MetricRecorder {
1565+
}
1566+
1567+
@SuppressWarnings("TypeParameterUnusedInFormals")
1568+
private <T extends MetricInstrument> T eqMetricInstrumentName(String name) {
1569+
return argThat(instrument -> instrument.getName().equals(name));
1570+
}
1571+
14661572
private static class FakeSocketAddress extends SocketAddress {}
14671573
}

0 commit comments

Comments
 (0)