Skip to content

Commit 00b2aaa

Browse files
author
sg530.kim
committed
api: Summarize EquivalentAddressGroup toString
1 parent 228fc8e commit 00b2aaa

File tree

3 files changed

+148
-19
lines changed

3 files changed

+148
-19
lines changed

api/src/main/java/io/grpc/EquivalentAddressGroup.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
*/
3535
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770")
3636
public final class EquivalentAddressGroup {
37+
private static final int MAX_ADDRESSES_TO_STRING = 100;
3738

3839
/**
3940
* The authority to be used when constructing Subchannels for this EquivalentAddressGroup.
@@ -113,8 +114,24 @@ public Attributes getAttributes() {
113114

114115
@Override
115116
public String toString() {
116-
// TODO(zpencer): Summarize return value if addr is very large
117-
return "[" + addrs + "/" + attrs + "]";
117+
StringBuilder sb = new StringBuilder();
118+
sb.append('[');
119+
if (addrs.size() <= MAX_ADDRESSES_TO_STRING) {
120+
sb.append(addrs);
121+
} else {
122+
sb.append('[');
123+
for (int i = 0; i < MAX_ADDRESSES_TO_STRING; i++) {
124+
if (i > 0) {
125+
sb.append(", ");
126+
}
127+
sb.append(addrs.get(i));
128+
}
129+
sb.append(", ... ");
130+
sb.append(addrs.size() - MAX_ADDRESSES_TO_STRING);
131+
sb.append(" more]");
132+
}
133+
sb.append('/').append(attrs).append(']');
134+
return sb.toString();
118135
}
119136

120137
@Override

api/src/test/java/io/grpc/CallOptionsTest.java

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@
2929
import static org.junit.Assert.fail;
3030
import static org.mockito.Mockito.mock;
3131

32-
import com.google.common.base.Objects;
32+
import com.google.common.truth.Fact;
33+
import com.google.common.truth.FailureMetadata;
34+
import com.google.common.truth.Subject;
3335
import io.grpc.ClientStreamTracer.StreamInfo;
3436
import io.grpc.internal.SerializingExecutor;
3537
import java.time.Duration;
@@ -106,17 +108,15 @@ public void allWiths() {
106108

107109
@Test
108110
public void noStrayModifications() {
109-
assertThat(equal(allSet, allSet.withAuthority("blah").withAuthority(sampleAuthority)))
110-
.isTrue();
111-
assertThat(
112-
equal(allSet,
113-
allSet.withDeadline(Deadline.after(314, NANOSECONDS)).withDeadline(sampleDeadline)))
114-
.isTrue();
115-
assertThat(
116-
equal(allSet,
111+
assertAbout(callOptions()).that(allSet.withAuthority("blah").withAuthority(sampleAuthority))
112+
.isEquivalentTo(allSet);
113+
assertAbout(callOptions()).that(
114+
allSet.withDeadline(Deadline.after(314, NANOSECONDS)).withDeadline(sampleDeadline))
115+
.isEquivalentTo(allSet);
116+
assertAbout(callOptions()).that(
117117
allSet.withCallCredentials(mock(CallCredentials.class))
118-
.withCallCredentials(sampleCreds)))
119-
.isTrue();
118+
.withCallCredentials(sampleCreds))
119+
.isEquivalentTo(allSet);
120120
}
121121

122122
@Test
@@ -265,12 +265,32 @@ public void getWaitForReady() {
265265
assertSame(CallOptions.DEFAULT.withoutWaitForReady().getWaitForReady(), Boolean.FALSE);
266266
}
267267

268-
// Only used in noStrayModifications()
269-
// TODO(carl-mastrangelo): consider making a CallOptionsSubject for Truth.
270-
private static boolean equal(CallOptions o1, CallOptions o2) {
271-
return Objects.equal(o1.getDeadline(), o2.getDeadline())
272-
&& Objects.equal(o1.getAuthority(), o2.getAuthority())
273-
&& Objects.equal(o1.getCredentials(), o2.getCredentials());
268+
private static Subject.Factory<CallOptionsSubject, CallOptions> callOptions() {
269+
return CallOptionsSubject::new;
270+
}
271+
272+
private static final class CallOptionsSubject extends Subject {
273+
274+
private final CallOptions actual;
275+
276+
private CallOptionsSubject(FailureMetadata metadata, CallOptions actual) {
277+
super(metadata, actual);
278+
this.actual = actual;
279+
}
280+
281+
public void isEquivalentTo(CallOptions expected) {
282+
if (actual == null) {
283+
failWithActual("expected", expected);
284+
return;
285+
}
286+
if (expected == null) {
287+
failWithoutActual(Fact.simpleFact("expected non-null CallOptions"));
288+
return;
289+
}
290+
check("deadline").that(actual.getDeadline()).isEqualTo(expected.getDeadline());
291+
check("authority").that(actual.getAuthority()).isEqualTo(expected.getAuthority());
292+
check("credentials").that(actual.getCredentials()).isEqualTo(expected.getCredentials());
293+
}
274294
}
275295

276296
private static class FakeTicker extends Deadline.Ticker {
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2026 The gRPC Authors
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 io.grpc;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
21+
import java.lang.reflect.Field;
22+
import java.net.SocketAddress;
23+
import java.util.ArrayList;
24+
import java.util.List;
25+
import org.junit.Test;
26+
import org.junit.runner.RunWith;
27+
import org.junit.runners.JUnit4;
28+
29+
/**
30+
* Unit tests for {@link EquivalentAddressGroup}.
31+
*/
32+
@RunWith(JUnit4.class)
33+
public class EquivalentAddressGroupTest {
34+
35+
@Test
36+
public void toString_summarizesLargeAddressList() {
37+
int maxAddressesToString = maxAddressesToString();
38+
List<SocketAddress> addrs = new ArrayList<>();
39+
for (int i = 0; i <= maxAddressesToString; i++) {
40+
addrs.add(new FakeSocketAddress("addr" + i));
41+
}
42+
EquivalentAddressGroup eag = new EquivalentAddressGroup(addrs);
43+
44+
StringBuilder expected = new StringBuilder();
45+
expected.append('[').append('[');
46+
for (int i = 0; i < maxAddressesToString; i++) {
47+
if (i > 0) {
48+
expected.append(", ");
49+
}
50+
expected.append(addrs.get(i));
51+
}
52+
expected.append(", ... 1 more]/{}]");
53+
assertThat(eag.toString()).isEqualTo(expected.toString());
54+
}
55+
56+
@Test
57+
public void toString_doesNotSummarizeAtMaxAddressCount() {
58+
int maxAddressesToString = maxAddressesToString();
59+
List<SocketAddress> addrs = new ArrayList<>();
60+
for (int i = 0; i < maxAddressesToString; i++) {
61+
addrs.add(new FakeSocketAddress("addr" + i));
62+
}
63+
EquivalentAddressGroup eag = new EquivalentAddressGroup(addrs);
64+
65+
String expected = "[" + addrs + "/{}]";
66+
assertThat(eag.toString()).isEqualTo(expected);
67+
}
68+
69+
private static int maxAddressesToString() {
70+
try {
71+
Field field = EquivalentAddressGroup.class.getDeclaredField("MAX_ADDRESSES_TO_STRING");
72+
field.setAccessible(true);
73+
return (int) field.get(null);
74+
} catch (NoSuchFieldException | IllegalAccessException e) {
75+
throw new LinkageError("Unable to read MAX_ADDRESSES_TO_STRING", e);
76+
}
77+
}
78+
79+
private static final class FakeSocketAddress extends SocketAddress {
80+
81+
private final String name;
82+
83+
FakeSocketAddress(String name) {
84+
this.name = name;
85+
}
86+
87+
@Override
88+
public String toString() {
89+
return name;
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)