mirror of https://github.com/grpc/grpc-java.git
Handle empty address list from NameResolver.
Passing an empty list to NameResolver.Listener.onUpdate() will trigger onError(). It is documented in the javadoc and enforced by ManagedChannelImpl. Forbid empty address list in EquivalentAddressGroup. Resolves #1657
This commit is contained in:
parent
51fd870cfd
commit
7659f6ed68
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
package io.grpc;
|
package io.grpc;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -49,6 +51,7 @@ public final class EquivalentAddressGroup {
|
||||||
private final List<SocketAddress> addrs;
|
private final List<SocketAddress> addrs;
|
||||||
|
|
||||||
public EquivalentAddressGroup(List<SocketAddress> addrs) {
|
public EquivalentAddressGroup(List<SocketAddress> addrs) {
|
||||||
|
Preconditions.checkArgument(!addrs.isEmpty(), "addrs is empty");
|
||||||
this.addrs = Collections.unmodifiableList(new ArrayList<SocketAddress>(addrs));
|
this.addrs = Collections.unmodifiableList(new ArrayList<SocketAddress>(addrs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,9 @@ public abstract class LoadBalancer<T> {
|
||||||
* Handles newly resolved addresses and service config from name resolution system.
|
* Handles newly resolved addresses and service config from name resolution system.
|
||||||
*
|
*
|
||||||
* <p>Implementations should not modify the given {@code servers}.
|
* <p>Implementations should not modify the given {@code servers}.
|
||||||
|
*
|
||||||
|
* @param servers the resolved server addresses. Never empty.
|
||||||
|
* @param config extra configuration data from naming system.
|
||||||
*/
|
*/
|
||||||
public void handleResolvedAddresses(List<ResolvedServerInfo> servers, Attributes config) { }
|
public void handleResolvedAddresses(List<ResolvedServerInfo> servers, Attributes config) { }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,9 @@ public abstract class NameResolver {
|
||||||
* Handles updates on resolved addresses and config.
|
* Handles updates on resolved addresses and config.
|
||||||
*
|
*
|
||||||
* <p>Implementations will not modify the given {@code servers}.
|
* <p>Implementations will not modify the given {@code servers}.
|
||||||
|
*
|
||||||
|
* @param servers the resolved server addresses. An empty list will trigger {@link #onError}
|
||||||
|
* @param config extra configuration data from naming system
|
||||||
*/
|
*/
|
||||||
void onUpdate(List<ResolvedServerInfo> servers, Attributes config);
|
void onUpdate(List<ResolvedServerInfo> servers, Attributes config);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,11 @@ public final class ManagedChannelImpl extends ManagedChannel implements WithLogI
|
||||||
this.nameResolver.start(new NameResolver.Listener() {
|
this.nameResolver.start(new NameResolver.Listener() {
|
||||||
@Override
|
@Override
|
||||||
public void onUpdate(List<ResolvedServerInfo> servers, Attributes config) {
|
public void onUpdate(List<ResolvedServerInfo> servers, Attributes config) {
|
||||||
loadBalancer.handleResolvedAddresses(servers, config);
|
if (servers.isEmpty()) {
|
||||||
|
onError(Status.UNAVAILABLE.withDescription("NameResolver returned an empty list"));
|
||||||
|
} else {
|
||||||
|
loadBalancer.handleResolvedAddresses(servers, config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -362,6 +362,27 @@ public class ManagedChannelImplTest {
|
||||||
Status status = statusCaptor.getValue();
|
Status status = statusCaptor.getValue();
|
||||||
assertSame(error.getCode(), status.getCode());
|
assertSame(error.getCode(), status.getCode());
|
||||||
assertSame(error.getCause(), status.getCause());
|
assertSame(error.getCause(), status.getCause());
|
||||||
|
assertEquals(1, loadBalancerFactory.balancers.size());
|
||||||
|
verify(loadBalancerFactory.balancers.get(0)).handleNameResolutionError(same(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nameResolverReturnsEmptyList() {
|
||||||
|
String errorDescription = "NameResolver returned an empty list";
|
||||||
|
ManagedChannel channel = createChannel(
|
||||||
|
new FakeNameResolverFactory(new ArrayList<ResolvedServerInfo>()), NO_INTERCEPTOR);
|
||||||
|
ClientCall<String, Integer> call = channel.newCall(method, CallOptions.DEFAULT);
|
||||||
|
call.start(mockCallListener, new Metadata());
|
||||||
|
ArgumentCaptor<Status> statusCaptor = ArgumentCaptor.forClass(Status.class);
|
||||||
|
verify(mockCallListener, timeout(1000)).onClose(statusCaptor.capture(), any(Metadata.class));
|
||||||
|
Status status = statusCaptor.getValue();
|
||||||
|
assertSame(Status.Code.UNAVAILABLE, status.getCode());
|
||||||
|
assertTrue(status.getDescription(), status.getDescription().contains(errorDescription));
|
||||||
|
assertEquals(1, loadBalancerFactory.balancers.size());
|
||||||
|
verify(loadBalancerFactory.balancers.get(0)).handleNameResolutionError(statusCaptor.capture());
|
||||||
|
status = statusCaptor.getValue();
|
||||||
|
assertSame(Status.Code.UNAVAILABLE, status.getCode());
|
||||||
|
assertEquals(errorDescription, status.getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue