|
1 | 1 | /* |
2 | | - * Copyright 2015 The gRPC Authors |
| 2 | + * Copyright 2026 The gRPC Authors |
3 | 3 | * |
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | 5 | * you may not use this file except in compliance with the License. |
|
16 | 16 |
|
17 | 17 | package io.grpc; |
18 | 18 |
|
19 | | -import com.google.common.base.Preconditions; |
20 | | -import java.lang.annotation.Documented; |
21 | | -import java.lang.annotation.Retention; |
22 | | -import java.lang.annotation.RetentionPolicy; |
| 19 | +import static com.google.common.truth.Truth.assertThat; |
| 20 | + |
| 21 | +import java.lang.reflect.Field; |
23 | 22 | import java.net.SocketAddress; |
24 | 23 | import java.util.ArrayList; |
25 | | -import java.util.Collections; |
26 | 24 | import java.util.List; |
| 25 | +import org.junit.Test; |
| 26 | +import org.junit.runner.RunWith; |
| 27 | +import org.junit.runners.JUnit4; |
27 | 28 |
|
28 | 29 | /** |
29 | | - * A group of {@link SocketAddress}es that are considered equivalent when channel makes connections. |
30 | | - * |
31 | | - * <p>Usually the addresses are addresses resolved from the same host name, and connecting to any of |
32 | | - * them is equally sufficient. They do have order. An address appears earlier on the list is likely |
33 | | - * to be tried earlier. |
| 30 | + * Unit tests for {@link EquivalentAddressGroup}. |
34 | 31 | */ |
35 | | -@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770") |
36 | | -public final class EquivalentAddressGroup { |
37 | | - |
38 | | - /** |
39 | | - * The authority to be used when constructing Subchannels for this EquivalentAddressGroup. |
40 | | - * However, if the channel has overridden authority via |
41 | | - * {@link ManagedChannelBuilder#overrideAuthority(String)}, the transport will use the channel's |
42 | | - * authority override. |
43 | | - * |
44 | | - * <p>The authority <strong>must</strong> be from a trusted source, because if the authority is |
45 | | - * tampered with, RPCs may be sent to attackers which may leak sensitive user data. If the |
46 | | - * authority was acquired by doing I/O, the communication must be authenticated (e.g., via TLS). |
47 | | - * Recognize that the server that provided the authority can trivially impersonate the service. |
48 | | - */ |
49 | | - @Attr |
50 | | - @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6138") |
51 | | - public static final Attributes.Key<String> ATTR_AUTHORITY_OVERRIDE = |
52 | | - Attributes.Key.create("io.grpc.EquivalentAddressGroup.ATTR_AUTHORITY_OVERRIDE"); |
53 | | - /** |
54 | | - * The name of the locality that this EquivalentAddressGroup is in. |
55 | | - */ |
56 | | - public static final Attributes.Key<String> ATTR_LOCALITY_NAME = |
57 | | - Attributes.Key.create("io.grpc.EquivalentAddressGroup.LOCALITY"); |
58 | | - private final List<SocketAddress> addrs; |
59 | | - private final Attributes attrs; |
60 | | - |
61 | | - /** |
62 | | - * {@link SocketAddress} docs say that the addresses are immutable, so we cache the hashCode. |
63 | | - */ |
64 | | - private final int hashCode; |
65 | | - |
66 | | - /** |
67 | | - * List constructor without {@link Attributes}. |
68 | | - */ |
69 | | - public EquivalentAddressGroup(List<SocketAddress> addrs) { |
70 | | - this(addrs, Attributes.EMPTY); |
71 | | - } |
| 32 | +@RunWith(JUnit4.class) |
| 33 | +public class EquivalentAddressGroupTest { |
72 | 34 |
|
73 | | - /** |
74 | | - * List constructor with {@link Attributes}. |
75 | | - */ |
76 | | - public EquivalentAddressGroup(List<SocketAddress> addrs, @Attr Attributes attrs) { |
77 | | - Preconditions.checkArgument(!addrs.isEmpty(), "addrs is empty"); |
78 | | - this.addrs = Collections.unmodifiableList(new ArrayList<>(addrs)); |
79 | | - this.attrs = Preconditions.checkNotNull(attrs, "attrs"); |
80 | | - // Attributes may contain mutable objects, which means Attributes' hashCode may change over |
81 | | - // time, thus we don't cache Attributes' hashCode. |
82 | | - hashCode = this.addrs.hashCode(); |
83 | | - } |
| 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); |
84 | 43 |
|
85 | | - /** |
86 | | - * Singleton constructor without Attributes. |
87 | | - */ |
88 | | - public EquivalentAddressGroup(SocketAddress addr) { |
89 | | - this(addr, Attributes.EMPTY); |
| 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()); |
90 | 54 | } |
91 | 55 |
|
92 | | - /** |
93 | | - * Singleton constructor with Attributes. |
94 | | - */ |
95 | | - public EquivalentAddressGroup(SocketAddress addr, @Attr Attributes attrs) { |
96 | | - this(Collections.singletonList(addr), attrs); |
97 | | - } |
| 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); |
98 | 64 |
|
99 | | - /** |
100 | | - * Returns an immutable list of the addresses. |
101 | | - */ |
102 | | - public List<SocketAddress> getAddresses() { |
103 | | - return addrs; |
| 65 | + String expected = "[" + addrs + "/{}]"; |
| 66 | + assertThat(eag.toString()).isEqualTo(expected); |
104 | 67 | } |
105 | 68 |
|
106 | | - /** |
107 | | - * Returns the attributes. |
108 | | - */ |
109 | | - @Attr |
110 | | - public Attributes getAttributes() { |
111 | | - return attrs; |
| 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 | + } |
112 | 77 | } |
113 | 78 |
|
114 | | - @Override |
115 | | - public String toString() { |
116 | | - // TODO(zpencer): Summarize return value if addr is very large |
117 | | - return "[" + addrs + "/" + attrs + "]"; |
118 | | - } |
| 79 | + private static final class FakeSocketAddress extends SocketAddress { |
119 | 80 |
|
120 | | - @Override |
121 | | - public int hashCode() { |
122 | | - // Avoids creating an iterator on the underlying array list. |
123 | | - return hashCode; |
124 | | - } |
| 81 | + private final String name; |
125 | 82 |
|
126 | | - /** |
127 | | - * Returns true if the given object is also an {@link EquivalentAddressGroup} with an equal |
128 | | - * address list and equal attribute values. |
129 | | - * |
130 | | - * <p>Note that if the attributes include mutable values, it is possible for two objects to be |
131 | | - * considered equal at one point in time and not equal at another (due to concurrent mutation of |
132 | | - * attribute values). |
133 | | - */ |
134 | | - @Override |
135 | | - public boolean equals(Object other) { |
136 | | - if (this == other) { |
137 | | - return true; |
138 | | - } |
139 | | - if (!(other instanceof EquivalentAddressGroup)) { |
140 | | - return false; |
| 83 | + FakeSocketAddress(String name) { |
| 84 | + this.name = name; |
141 | 85 | } |
142 | | - EquivalentAddressGroup that = (EquivalentAddressGroup) other; |
143 | | - if (addrs.size() != that.addrs.size()) { |
144 | | - return false; |
145 | | - } |
146 | | - // Avoids creating an iterator on the underlying array list. |
147 | | - for (int i = 0; i < addrs.size(); i++) { |
148 | | - if (!addrs.get(i).equals(that.addrs.get(i))) { |
149 | | - return false; |
150 | | - } |
151 | | - } |
152 | | - if (!attrs.equals(that.attrs)) { |
153 | | - return false; |
| 86 | + |
| 87 | + @Override |
| 88 | + public String toString() { |
| 89 | + return name; |
154 | 90 | } |
155 | | - return true; |
156 | 91 | } |
157 | | - |
158 | | - /** |
159 | | - * Annotation for {@link EquivalentAddressGroup}'s attributes. It follows the annotation semantics |
160 | | - * defined by {@link Attributes}. |
161 | | - */ |
162 | | - @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4972") |
163 | | - @Retention(RetentionPolicy.SOURCE) |
164 | | - @Documented |
165 | | - public @interface Attr {} |
166 | 92 | } |
0 commit comments