On result2 resolution result have addresses or error (#11330)

Combined success / error status passed via ResolutionResult to the NameResolver.Listener2 interface's onResult2 method - Addresses in the success case or address resolution error in the failure case now get set in ResolutionResult::addressesOrError by the internal name resolvers.
This commit is contained in:
Kannan J 2024-10-07 17:55:56 +05:30 committed by GitHub
parent 94a0a0d1c7
commit 1ded8aff81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 541 additions and 108 deletions

View File

@ -20,13 +20,13 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.base.Objects;
import com.google.errorprone.annotations.InlineMe;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -95,7 +95,8 @@ public abstract class NameResolver {
@Override
public void onResult(ResolutionResult resolutionResult) {
listener.onAddresses(resolutionResult.getAddresses(), resolutionResult.getAttributes());
listener.onAddresses(resolutionResult.getAddressesOrError().getValue(),
resolutionResult.getAttributes());
}
});
}
@ -218,19 +219,21 @@ public abstract class NameResolver {
@Override
@Deprecated
@InlineMe(
replacement = "this.onResult(ResolutionResult.newBuilder().setAddresses(servers)"
+ ".setAttributes(attributes).build())",
imports = "io.grpc.NameResolver.ResolutionResult")
replacement = "this.onResult2(ResolutionResult.newBuilder().setAddressesOrError("
+ "StatusOr.fromValue(servers)).setAttributes(attributes).build())",
imports = {"io.grpc.NameResolver.ResolutionResult", "io.grpc.StatusOr"})
public final void onAddresses(
List<EquivalentAddressGroup> servers, @ResolutionResultAttr Attributes attributes) {
// TODO(jihuncho) need to promote Listener2 if we want to use ConfigOrError
onResult(
ResolutionResult.newBuilder().setAddresses(servers).setAttributes(attributes).build());
onResult2(
ResolutionResult.newBuilder().setAddressesOrError(
StatusOr.fromValue(servers)).setAttributes(attributes).build());
}
/**
* Handles updates on resolved addresses and attributes. If
* {@link ResolutionResult#getAddresses()} is empty, {@link #onError(Status)} will be called.
* {@link ResolutionResult#getAddressesOrError()} is empty, {@link #onError(Status)} will be
* called.
*
* @param resolutionResult the resolved server addresses, attributes, and Service Config.
* @since 1.21.0
@ -584,17 +587,17 @@ public abstract class NameResolver {
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770")
public static final class ResolutionResult {
private final List<EquivalentAddressGroup> addresses;
private final StatusOr<List<EquivalentAddressGroup>> addressesOrError;
@ResolutionResultAttr
private final Attributes attributes;
@Nullable
private final ConfigOrError serviceConfig;
ResolutionResult(
List<EquivalentAddressGroup> addresses,
StatusOr<List<EquivalentAddressGroup>> addressesOrError,
@ResolutionResultAttr Attributes attributes,
ConfigOrError serviceConfig) {
this.addresses = Collections.unmodifiableList(new ArrayList<>(addresses));
this.addressesOrError = addressesOrError;
this.attributes = checkNotNull(attributes, "attributes");
this.serviceConfig = serviceConfig;
}
@ -615,7 +618,7 @@ public abstract class NameResolver {
*/
public Builder toBuilder() {
return newBuilder()
.setAddresses(addresses)
.setAddressesOrError(addressesOrError)
.setAttributes(attributes)
.setServiceConfig(serviceConfig);
}
@ -624,9 +627,20 @@ public abstract class NameResolver {
* Gets the addresses resolved by name resolution.
*
* @since 1.21.0
* @deprecated Will be superseded by getAddressesOrError
*/
@Deprecated
public List<EquivalentAddressGroup> getAddresses() {
return addresses;
return addressesOrError.getValue();
}
/**
* Gets the addresses resolved by name resolution or the error in doing so.
*
* @since 1.65.0
*/
public StatusOr<List<EquivalentAddressGroup>> getAddressesOrError() {
return addressesOrError;
}
/**
@ -652,11 +666,11 @@ public abstract class NameResolver {
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("addresses", addresses)
.add("attributes", attributes)
.add("serviceConfig", serviceConfig)
.toString();
ToStringHelper stringHelper = MoreObjects.toStringHelper(this);
stringHelper.add("addressesOrError", addressesOrError.toString());
stringHelper.add("attributes", attributes);
stringHelper.add("serviceConfigOrError", serviceConfig);
return stringHelper.toString();
}
/**
@ -668,7 +682,7 @@ public abstract class NameResolver {
return false;
}
ResolutionResult that = (ResolutionResult) obj;
return Objects.equal(this.addresses, that.addresses)
return Objects.equal(this.addressesOrError, that.addressesOrError)
&& Objects.equal(this.attributes, that.attributes)
&& Objects.equal(this.serviceConfig, that.serviceConfig);
}
@ -678,7 +692,7 @@ public abstract class NameResolver {
*/
@Override
public int hashCode() {
return Objects.hashCode(addresses, attributes, serviceConfig);
return Objects.hashCode(addressesOrError, attributes, serviceConfig);
}
/**
@ -688,7 +702,8 @@ public abstract class NameResolver {
*/
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770")
public static final class Builder {
private List<EquivalentAddressGroup> addresses = Collections.emptyList();
private StatusOr<List<EquivalentAddressGroup>> addresses =
StatusOr.fromValue(Collections.emptyList());
private Attributes attributes = Attributes.EMPTY;
@Nullable
private ConfigOrError serviceConfig;
@ -700,9 +715,21 @@ public abstract class NameResolver {
* Sets the addresses resolved by name resolution. This field is required.
*
* @since 1.21.0
* @deprecated Will be superseded by setAddressesOrError
*/
@Deprecated
public Builder setAddresses(List<EquivalentAddressGroup> addresses) {
this.addresses = addresses;
setAddressesOrError(StatusOr.fromValue(addresses));
return this;
}
/**
* Sets the addresses resolved by name resolution or the error in doing so. This field is
* required.
* @param addresses Resolved addresses or an error in resolving addresses
*/
public Builder setAddressesOrError(StatusOr<List<EquivalentAddressGroup>> addresses) {
this.addresses = checkNotNull(addresses, "StatusOr addresses cannot be null.");
return this;
}

View File

@ -0,0 +1,102 @@
/*
* Copyright 2024 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.base.Objects;
import javax.annotation.Nullable;
/** Either a Status or a value. */
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/11563")
public class StatusOr<T> {
private StatusOr(Status status, T value) {
this.status = status;
this.value = value;
}
/** Construct from a value. */
public static <T> StatusOr<T> fromValue(@Nullable T value) {
StatusOr<T> result = new StatusOr<T>(null, value);
return result;
}
/** Construct from a non-Ok status. */
public static <T> StatusOr<T> fromStatus(Status status) {
StatusOr<T> result = new StatusOr<T>(checkNotNull(status, "status"), null);
checkArgument(!status.isOk(), "cannot use OK status: %s", status);
return result;
}
/** Returns whether there is a value. */
public boolean hasValue() {
return status == null;
}
/**
* Returns the value if set or throws exception if there is no value set. This method is meant
* to be called after checking the return value of hasValue() first.
*/
public @Nullable T getValue() {
if (status != null) {
throw new IllegalStateException("No value present.");
}
return value;
}
/** Returns the status. If there is a value (which can be null), returns OK. */
public Status getStatus() {
return status == null ? Status.OK : status;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof StatusOr)) {
return false;
}
StatusOr<?> otherStatus = (StatusOr<?>) other;
if (hasValue() != otherStatus.hasValue()) {
return false;
}
if (hasValue()) {
return Objects.equal(value, otherStatus.value);
}
return Objects.equal(status, otherStatus.status);
}
@Override
public int hashCode() {
return Objects.hashCode(status, value);
}
@Override
public String toString() {
ToStringHelper stringHelper = MoreObjects.toStringHelper(this);
if (status == null) {
stringHelper.add("value", value);
} else {
stringHelper.add("error", status);
}
return stringHelper.toString();
}
private final Status status;
private final T value;
}

View File

@ -17,20 +17,43 @@
package io.grpc;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import com.google.common.base.Objects;
import io.grpc.NameResolver.ConfigOrError;
import io.grpc.NameResolver.Listener2;
import io.grpc.NameResolver.ResolutionResult;
import io.grpc.NameResolver.ServiceConfigParser;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.SocketAddress;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
/** Unit tests for the inner classes in {@link NameResolver}. */
@RunWith(JUnit4.class)
public class NameResolverTest {
private static final List<EquivalentAddressGroup> ADDRESSES =
Collections.singletonList(
new EquivalentAddressGroup(new FakeSocketAddress("fake-address-1"), Attributes.EMPTY));
private static final Attributes.Key<String> YOLO_KEY = Attributes.Key.create("yolo");
private static Attributes ATTRIBUTES = Attributes.newBuilder()
.set(YOLO_KEY, "To be, or not to be?").build();
private static ConfigOrError CONFIG = ConfigOrError.fromConfig("foo");
@Rule
public final MockitoRule mocks = MockitoJUnit.rule();
private final int defaultPort = 293;
private final ProxyDetector proxyDetector = mock(ProxyDetector.class);
private final SynchronizationContext syncContext =
@ -41,6 +64,7 @@ public class NameResolverTest {
private final ChannelLogger channelLogger = mock(ChannelLogger.class);
private final Executor executor = Executors.newSingleThreadExecutor();
private final String overrideAuthority = "grpc.io";
@Mock NameResolver.Listener mockListener;
@Test
public void args() {
@ -80,4 +104,90 @@ public class NameResolverTest {
.setOverrideAuthority(overrideAuthority)
.build();
}
@Test
@SuppressWarnings("deprecation")
public void startOnOldListener_wrapperListener2UsedToStart() {
final Listener2[] listener2 = new Listener2[1];
NameResolver nameResolver = new NameResolver() {
@Override
public String getServiceAuthority() {
return null;
}
@Override
public void shutdown() {}
@Override
public void start(Listener2 listener2Arg) {
listener2[0] = listener2Arg;
}
};
nameResolver.start(mockListener);
listener2[0].onResult(ResolutionResult.newBuilder().setAddresses(ADDRESSES)
.setAttributes(ATTRIBUTES).build());
verify(mockListener).onAddresses(eq(ADDRESSES), eq(ATTRIBUTES));
listener2[0].onError(Status.CANCELLED);
verify(mockListener).onError(Status.CANCELLED);
}
@Test
@SuppressWarnings({"deprecation", "InlineMeInliner"})
public void listener2AddressesToListener2ResolutionResultConversion() {
final ResolutionResult[] resolutionResult = new ResolutionResult[1];
NameResolver.Listener2 listener2 = new Listener2() {
@Override
public void onResult(ResolutionResult resolutionResultArg) {
resolutionResult[0] = resolutionResultArg;
}
@Override
public void onError(Status error) {}
};
listener2.onAddresses(ADDRESSES, ATTRIBUTES);
assertThat(resolutionResult[0].getAddressesOrError().getValue()).isEqualTo(ADDRESSES);
assertThat(resolutionResult[0].getAttributes()).isEqualTo(ATTRIBUTES);
}
@Test
public void resolutionResult_toString_addressesAttributesAndConfig() {
ResolutionResult resolutionResult = ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromValue(ADDRESSES))
.setAttributes(ATTRIBUTES)
.setServiceConfig(CONFIG)
.build();
assertThat(resolutionResult.toString()).isEqualTo(
"ResolutionResult{addressesOrError=StatusOr{value="
+ "[[[FakeSocketAddress-fake-address-1]/{}]]}, attributes={yolo=To be, or not to be?}, "
+ "serviceConfigOrError=ConfigOrError{config=foo}}");
}
@Test
public void resolutionResult_hashCode() {
ResolutionResult resolutionResult = ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromValue(ADDRESSES))
.setAttributes(ATTRIBUTES)
.setServiceConfig(CONFIG)
.build();
assertThat(resolutionResult.hashCode()).isEqualTo(
Objects.hashCode(StatusOr.fromValue(ADDRESSES), ATTRIBUTES, CONFIG));
}
private static class FakeSocketAddress extends SocketAddress {
final String name;
FakeSocketAddress(String name) {
this.name = name;
}
@Override
public String toString() {
return "FakeSocketAddress-" + name;
}
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2015 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.TestCase.fail;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link StatusOr}. **/
@RunWith(JUnit4.class)
public class StatusOrTest {
@Test
public void getValue_throwsIfNoValuePresent() {
try {
StatusOr.fromStatus(Status.ABORTED).getValue();
fail("Expected exception.");
} catch (IllegalStateException expected) { }
}
@Test
@SuppressWarnings("TruthIncompatibleType")
public void equals_differentValueTypes() {
assertThat(StatusOr.fromValue(1)).isNotEqualTo(StatusOr.fromValue("1"));
}
@Test
public void equals_differentValues() {
assertThat(StatusOr.fromValue(1)).isNotEqualTo(StatusOr.fromValue(2));
}
@Test
public void equals_sameValues() {
assertThat(StatusOr.fromValue(1)).isEqualTo(StatusOr.fromValue(1));
}
@Test
public void equals_differentStatuses() {
assertThat(StatusOr.fromStatus(Status.ABORTED)).isNotEqualTo(
StatusOr.fromStatus(Status.CANCELLED));
}
@Test
public void equals_sameStatuses() {
assertThat(StatusOr.fromStatus(Status.ABORTED)).isEqualTo(StatusOr.fromStatus(Status.ABORTED));
}
@Test
public void toString_value() {
assertThat(StatusOr.fromValue(1).toString()).isEqualTo("StatusOr{value=1}");
}
@Test
public void toString_nullValue() {
assertThat(StatusOr.fromValue(null).toString()).isEqualTo("StatusOr{value=null}");
}
@Test
public void toString_errorStatus() {
assertThat(StatusOr.fromStatus(Status.ABORTED).toString()).isEqualTo(
"StatusOr{error=Status{code=ABORTED, description=null, cause=null}}");
}
}

View File

@ -500,3 +500,4 @@ configurations {
}
tasks.register('checkForUpdates', CheckForUpdatesTask, project.configurations.checkForUpdates, "libs")

View File

@ -32,6 +32,7 @@ import io.grpc.NameResolver;
import io.grpc.ProxiedSocketAddress;
import io.grpc.ProxyDetector;
import io.grpc.Status;
import io.grpc.StatusOr;
import io.grpc.SynchronizationContext;
import io.grpc.internal.SharedResourceHolder.Resource;
import java.io.IOException;
@ -59,7 +60,7 @@ import javax.annotation.Nullable;
* A DNS-based {@link NameResolver}.
*
* <p>Each {@code A} or {@code AAAA} record emits an {@link EquivalentAddressGroup} in the list
* passed to {@link NameResolver.Listener2#onResult(ResolutionResult)}.
* passed to {@link NameResolver.Listener2#onResult2(ResolutionResult)}.
*
* @see DnsNameResolverProvider
*/
@ -313,15 +314,20 @@ public class DnsNameResolver extends NameResolver {
if (logger.isLoggable(Level.FINER)) {
logger.finer("Using proxy address " + proxiedAddr);
}
resolutionResultBuilder.setAddresses(Collections.singletonList(proxiedAddr));
resolutionResultBuilder.setAddressesOrError(
StatusOr.fromValue(Collections.singletonList(proxiedAddr)));
} else {
result = doResolve(false);
if (result.error != null) {
savedListener.onError(result.error);
InternalResolutionResult finalResult = result;
syncContext.execute(() ->
savedListener.onResult2(ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromStatus(finalResult.error))
.build()));
return;
}
if (result.addresses != null) {
resolutionResultBuilder.setAddresses(result.addresses);
resolutionResultBuilder.setAddressesOrError(StatusOr.fromValue(result.addresses));
}
if (result.config != null) {
resolutionResultBuilder.setServiceConfig(result.config);
@ -334,8 +340,12 @@ public class DnsNameResolver extends NameResolver {
savedListener.onResult2(resolutionResultBuilder.build());
});
} catch (IOException e) {
savedListener.onError(
Status.UNAVAILABLE.withDescription("Unable to resolve host " + host).withCause(e));
syncContext.execute(() ->
savedListener.onResult2(ResolutionResult.newBuilder()
.setAddressesOrError(
StatusOr.fromStatus(
Status.UNAVAILABLE.withDescription(
"Unable to resolve host " + host).withCause(e))).build()));
} finally {
final boolean succeed = result != null && result.error == null;
syncContext.execute(new Runnable() {

View File

@ -81,6 +81,7 @@ import io.grpc.NameResolverProvider;
import io.grpc.NameResolverRegistry;
import io.grpc.ProxyDetector;
import io.grpc.Status;
import io.grpc.StatusOr;
import io.grpc.SynchronizationContext;
import io.grpc.SynchronizationContext.ScheduledHandle;
import io.grpc.internal.AutoConfiguredLoadBalancerFactory.AutoConfiguredLoadBalancer;
@ -1701,7 +1702,13 @@ final class ManagedChannelImpl extends ManagedChannel implements
return Status.OK;
}
List<EquivalentAddressGroup> servers = resolutionResult.getAddresses();
StatusOr<List<EquivalentAddressGroup>> serversOrError =
resolutionResult.getAddressesOrError();
if (!serversOrError.hasValue()) {
handleErrorInSyncContext(serversOrError.getStatus());
return serversOrError.getStatus();
}
List<EquivalentAddressGroup> servers = serversOrError.getValue();
channelLogger.log(
ChannelLogLevel.DEBUG,
"Resolved address: {0}, config={1}",
@ -1709,10 +1716,10 @@ final class ManagedChannelImpl extends ManagedChannel implements
resolutionResult.getAttributes());
if (lastResolutionState != ResolutionState.SUCCESS) {
channelLogger.log(ChannelLogLevel.INFO, "Address resolved: {0}", servers);
channelLogger.log(ChannelLogLevel.INFO, "Address resolved: {0}",
servers);
lastResolutionState = ResolutionState.SUCCESS;
}
ConfigOrError configOrError = resolutionResult.getServiceConfig();
InternalConfigSelector resolvedConfigSelector =
resolutionResult.getAttributes().get(InternalConfigSelector.KEY);
@ -1788,7 +1795,7 @@ final class ManagedChannelImpl extends ManagedChannel implements
}
try {
// TODO(creamsoup): when `servers` is empty and lastResolutionStateCopy == SUCCESS
// TODO(creamsoup): when `serversOrError` is empty and lastResolutionStateCopy == SUCCESS
// and lbNeedAddress, it shouldn't call the handleServiceConfigUpdate. But,
// lbNeedAddress is not deterministic
serviceConfigUpdated = true;
@ -1814,12 +1821,13 @@ final class ManagedChannelImpl extends ManagedChannel implements
}
Attributes attributes = attrBuilder.build();
return helper.lb.tryAcceptResolvedAddresses(
ResolvedAddresses.newBuilder()
.setAddresses(servers)
.setAttributes(attributes)
.setLoadBalancingPolicyConfig(effectiveServiceConfig.getLoadBalancingConfig())
.build());
ResolvedAddresses.Builder resolvedAddresses = ResolvedAddresses.newBuilder()
.setAddresses(serversOrError.getValue())
.setAttributes(attributes)
.setLoadBalancingPolicyConfig(effectiveServiceConfig.getLoadBalancingConfig());
Status addressAcceptanceStatus = helper.lb.tryAcceptResolvedAddresses(
resolvedAddresses.build());
return addressAcceptanceStatus;
}
return Status.OK;
}

View File

@ -45,6 +45,7 @@ import io.grpc.NameResolver;
import io.grpc.NameResolverProvider;
import io.grpc.NameResolverRegistry;
import io.grpc.ProxyDetector;
import io.grpc.StatusOr;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.SocketAddress;
@ -877,9 +878,11 @@ public final class ManagedChannelImplBuilder
@Override
public void start(Listener2 listener) {
listener.onResult(
listener.onResult2(
ResolutionResult.newBuilder()
.setAddresses(Collections.singletonList(new EquivalentAddressGroup(address)))
.setAddressesOrError(
StatusOr.fromValue(
Collections.singletonList(new EquivalentAddressGroup(address))))
.setAttributes(Attributes.EMPTY)
.build());
}

View File

@ -24,6 +24,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.mock;
@ -152,12 +153,11 @@ public class DnsNameResolverTest {
private NameResolver.Listener2 mockListener;
@Captor
private ArgumentCaptor<ResolutionResult> resultCaptor;
@Captor
private ArgumentCaptor<Status> errorCaptor;
@Nullable
private String networkaddressCacheTtlPropertyValue;
@Mock
private RecordFetcher recordFetcher;
@Mock private ProxyDetector mockProxyDetector;
private RetryingNameResolver newResolver(String name, int defaultPort) {
return newResolver(
@ -570,7 +570,7 @@ public class DnsNameResolverTest {
ArgumentCaptor<ResolutionResult> ac = ArgumentCaptor.forClass(ResolutionResult.class);
verify(mockListener).onResult2(ac.capture());
verifyNoMoreInteractions(mockListener);
assertThat(ac.getValue().getAddresses()).isEmpty();
assertThat(ac.getValue().getAddressesOrError().getValue()).isEmpty();
assertThat(ac.getValue().getServiceConfig()).isNull();
verify(mockResourceResolver, never()).resolveSrv(anyString());
@ -578,6 +578,39 @@ public class DnsNameResolverTest {
assertEquals(0, fakeExecutor.numPendingTasks());
}
@Test
public void resolve_addressResolutionError() throws Exception {
DnsNameResolver.enableTxt = true;
when(mockProxyDetector.proxyFor(any(SocketAddress.class))).thenThrow(new IOException());
RetryingNameResolver resolver = newResolver(
"addr.fake:1234", 443, mockProxyDetector, Stopwatch.createUnstarted());
DnsNameResolver dnsResolver = (DnsNameResolver) resolver.getRetriedNameResolver();
dnsResolver.setAddressResolver(new AddressResolver() {
@Override
public List<InetAddress> resolveAddress(String host) throws Exception {
return Collections.emptyList();
}
});
ResourceResolver mockResourceResolver = mock(ResourceResolver.class);
when(mockResourceResolver.resolveTxt(anyString()))
.thenReturn(Collections.<String>emptyList());
dnsResolver.setResourceResolver(mockResourceResolver);
resolver.start(mockListener);
assertThat(fakeExecutor.runDueTasks()).isEqualTo(1);
ArgumentCaptor<ResolutionResult> ac = ArgumentCaptor.forClass(ResolutionResult.class);
verify(mockListener).onResult2(ac.capture());
verifyNoMoreInteractions(mockListener);
assertThat(ac.getValue().getAddressesOrError().getStatus().getCode()).isEqualTo(
Status.UNAVAILABLE.getCode());
assertThat(ac.getValue().getAddressesOrError().getStatus().getDescription()).isEqualTo(
"Unable to resolve host addr.fake");
assertThat(ac.getValue().getAddressesOrError().getStatus().getCause())
.isInstanceOf(IOException.class);
}
// Load balancer rejects the empty addresses.
@Test
public void resolve_emptyResult_notAccepted() throws Exception {
@ -604,7 +637,7 @@ public class DnsNameResolverTest {
ArgumentCaptor<ResolutionResult> ac = ArgumentCaptor.forClass(ResolutionResult.class);
verify(mockListener).onResult2(ac.capture());
verifyNoMoreInteractions(mockListener);
assertThat(ac.getValue().getAddresses()).isEmpty();
assertThat(ac.getValue().getAddressesOrError().getValue()).isEmpty();
assertThat(ac.getValue().getServiceConfig()).isNull();
verify(mockResourceResolver, never()).resolveSrv(anyString());
@ -632,7 +665,7 @@ public class DnsNameResolverTest {
ResolutionResult result = resultCaptor.getValue();
InetSocketAddress resolvedBackendAddr =
(InetSocketAddress) Iterables.getOnlyElement(
Iterables.getOnlyElement(result.getAddresses()).getAddresses());
Iterables.getOnlyElement(result.getAddressesOrError().getValue()).getAddresses());
assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr);
verify(mockAddressResolver).resolveAddress(name);
assertThat(result.getServiceConfig()).isNull();
@ -647,6 +680,7 @@ public class DnsNameResolverTest {
AddressResolver mockAddressResolver = mock(AddressResolver.class);
when(mockAddressResolver.resolveAddress(anyString()))
.thenThrow(new IOException("no addr"));
when(mockListener.onResult2(isA(ResolutionResult.class))).thenReturn(Status.UNAVAILABLE);
String name = "foo.googleapis.com";
RetryingNameResolver resolver = newResolver(name, 81);
@ -655,8 +689,8 @@ public class DnsNameResolverTest {
dnsResolver.setResourceResolver(null);
resolver.start(mockListener);
assertEquals(1, fakeExecutor.runDueTasks());
verify(mockListener).onError(errorCaptor.capture());
Status errorStatus = errorCaptor.getValue();
verify(mockListener).onResult2(resultCaptor.capture());
Status errorStatus = resultCaptor.getValue().getAddressesOrError().getStatus();
assertThat(errorStatus.getCode()).isEqualTo(Code.UNAVAILABLE);
assertThat(errorStatus.getCause()).hasMessageThat().contains("no addr");
@ -704,7 +738,7 @@ public class DnsNameResolverTest {
ResolutionResult result = resultCaptor.getValue();
InetSocketAddress resolvedBackendAddr =
(InetSocketAddress) Iterables.getOnlyElement(
Iterables.getOnlyElement(result.getAddresses()).getAddresses());
Iterables.getOnlyElement(result.getAddressesOrError().getValue()).getAddresses());
assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr);
assertThat(result.getServiceConfig().getConfig()).isNotNull();
verify(mockAddressResolver).resolveAddress(name);
@ -720,6 +754,7 @@ public class DnsNameResolverTest {
AddressResolver mockAddressResolver = mock(AddressResolver.class);
when(mockAddressResolver.resolveAddress(anyString()))
.thenThrow(new IOException("no addr"));
when(mockListener.onResult2(isA(ResolutionResult.class))).thenReturn(Status.UNAVAILABLE);
String name = "foo.googleapis.com";
ResourceResolver mockResourceResolver = mock(ResourceResolver.class);
@ -729,8 +764,8 @@ public class DnsNameResolverTest {
dnsResolver.setResourceResolver(mockResourceResolver);
resolver.start(mockListener);
assertEquals(1, fakeExecutor.runDueTasks());
verify(mockListener).onError(errorCaptor.capture());
Status errorStatus = errorCaptor.getValue();
verify(mockListener).onResult2(resultCaptor.capture());
Status errorStatus = resultCaptor.getValue().getAddressesOrError().getStatus();
assertThat(errorStatus.getCode()).isEqualTo(Code.UNAVAILABLE);
assertThat(errorStatus.getCause()).hasMessageThat().contains("no addr");
verify(mockResourceResolver, never()).resolveTxt(anyString());
@ -762,7 +797,7 @@ public class DnsNameResolverTest {
ResolutionResult result = resultCaptor.getValue();
InetSocketAddress resolvedBackendAddr =
(InetSocketAddress) Iterables.getOnlyElement(
Iterables.getOnlyElement(result.getAddresses()).getAddresses());
Iterables.getOnlyElement(result.getAddressesOrError().getValue()).getAddresses());
assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr);
verify(mockAddressResolver).resolveAddress(name);
assertThat(result.getServiceConfig()).isNull();
@ -794,7 +829,7 @@ public class DnsNameResolverTest {
ResolutionResult result = resultCaptor.getValue();
InetSocketAddress resolvedBackendAddr =
(InetSocketAddress) Iterables.getOnlyElement(
Iterables.getOnlyElement(result.getAddresses()).getAddresses());
Iterables.getOnlyElement(result.getAddressesOrError().getValue()).getAddresses());
assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr);
verify(mockAddressResolver).resolveAddress(name);
assertThat(result.getServiceConfig()).isNotNull();
@ -859,7 +894,7 @@ public class DnsNameResolverTest {
assertEquals(1, fakeExecutor.runDueTasks());
verify(mockListener).onResult2(resultCaptor.capture());
List<EquivalentAddressGroup> result = resultCaptor.getValue().getAddresses();
List<EquivalentAddressGroup> result = resultCaptor.getValue().getAddressesOrError().getValue();
assertThat(result).hasSize(1);
EquivalentAddressGroup eag = result.get(0);
assertThat(eag.getAddresses()).hasSize(1);
@ -1299,9 +1334,9 @@ public class DnsNameResolverTest {
private static void assertAnswerMatches(
List<InetAddress> addrs, int port, ResolutionResult resolutionResult) {
assertThat(resolutionResult.getAddresses()).hasSize(addrs.size());
assertThat(resolutionResult.getAddressesOrError().getValue()).hasSize(addrs.size());
for (int i = 0; i < addrs.size(); i++) {
EquivalentAddressGroup addrGroup = resolutionResult.getAddresses().get(i);
EquivalentAddressGroup addrGroup = resolutionResult.getAddressesOrError().getValue().get(i);
InetSocketAddress socketAddr =
(InetSocketAddress) Iterables.getOnlyElement(addrGroup.getAddresses());
assertEquals("Addr " + i, port, socketAddr.getPort());

View File

@ -63,6 +63,7 @@ import io.grpc.NameResolver;
import io.grpc.NameResolver.ResolutionResult;
import io.grpc.NameResolverProvider;
import io.grpc.Status;
import io.grpc.StatusOr;
import io.grpc.StringMarshaller;
import io.grpc.internal.FakeClock.ScheduledTask;
import io.grpc.internal.ManagedChannelImplBuilder.UnsupportedClientTransportFactoryBuilder;
@ -615,7 +616,7 @@ public class ManagedChannelImplIdlenessTest {
// the NameResolver.
ResolutionResult resolutionResult =
ResolutionResult.newBuilder()
.setAddresses(servers)
.setAddressesOrError(StatusOr.fromValue(servers))
.setAttributes(Attributes.EMPTY)
.build();
nameResolverListenerCaptor.getValue().onResult(resolutionResult);

View File

@ -116,6 +116,7 @@ import io.grpc.SecurityLevel;
import io.grpc.ServerMethodDefinition;
import io.grpc.Status;
import io.grpc.Status.Code;
import io.grpc.StatusOr;
import io.grpc.StringMarshaller;
import io.grpc.SynchronizationContext;
import io.grpc.internal.ClientTransportFactory.ClientTransportOptions;
@ -1095,7 +1096,10 @@ public class ManagedChannelImplTest {
verify(stateListener2).onSubchannelState(stateInfoCaptor.capture());
assertSame(CONNECTING, stateInfoCaptor.getValue().getState());
resolver.listener.onError(resolutionError);
channel.syncContext.execute(() ->
resolver.listener.onResult2(
ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromStatus(resolutionError)).build()));
verify(mockLoadBalancer).handleNameResolutionError(resolutionError);
verifyNoMoreInteractions(mockLoadBalancer);
@ -1117,13 +1121,10 @@ public class ManagedChannelImplTest {
verifyNoMoreInteractions(stateListener1, stateListener2);
// No more callback should be delivered to LoadBalancer after it's shut down
resolver.listener.onResult(
ResolutionResult.newBuilder()
.setAddresses(new ArrayList<>())
.setServiceConfig(
ConfigOrError.fromError(Status.UNAVAILABLE.withDescription("Resolution failed")))
.build());
Thread.sleep(1100);
channel.syncContext.execute(() ->
resolver.listener.onResult2(
ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromStatus(resolutionError)).build()));
assertThat(timer.getPendingTasks()).isEmpty();
resolver.resolved();
verifyNoMoreInteractions(mockLoadBalancer);
@ -3286,11 +3287,19 @@ public class ManagedChannelImplTest {
assertThat(getStats(channel).channelTrace.events).hasSize(prevSize);
prevSize = getStats(channel).channelTrace.events.size();
nameResolverFactory.resolvers.get(0).listener.onError(Status.INTERNAL);
channel.syncContext.execute(() ->
nameResolverFactory.resolvers.get(0).listener.onResult2(
ResolutionResult.newBuilder()
.setAddressesOrError(
StatusOr.fromStatus(Status.INTERNAL)).build()));
assertThat(getStats(channel).channelTrace.events).hasSize(prevSize + 1);
prevSize = getStats(channel).channelTrace.events.size();
nameResolverFactory.resolvers.get(0).listener.onError(Status.INTERNAL);
channel.syncContext.execute(() ->
nameResolverFactory.resolvers.get(0).listener.onResult2(
ResolutionResult.newBuilder()
.setAddressesOrError(
StatusOr.fromStatus(Status.INTERNAL)).build()));
assertThat(getStats(channel).channelTrace.events).hasSize(prevSize);
prevSize = getStats(channel).channelTrace.events.size();
@ -4919,7 +4928,10 @@ public class ManagedChannelImplTest {
void resolved() {
if (error != null) {
listener.onError(error);
syncContext.execute(() ->
listener.onResult2(
ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromStatus(error)).build()));
return;
}
ResolutionResult.Builder builder =

View File

@ -96,7 +96,6 @@ public class GrpclbNameResolverTest {
}
@Captor private ArgumentCaptor<ResolutionResult> resultCaptor;
@Captor private ArgumentCaptor<Status> errorCaptor;
@Mock private ServiceConfigParser serviceConfigParser;
@Mock private NameResolver.Listener2 mockListener;
@ -154,7 +153,7 @@ public class GrpclbNameResolverTest {
verify(mockListener).onResult2(resultCaptor.capture());
ResolutionResult result = resultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty();
assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertThat(result.getAttributes()).isEqualTo(Attributes.EMPTY);
assertThat(result.getServiceConfig()).isNull();
}
@ -196,7 +195,7 @@ public class GrpclbNameResolverTest {
ResolutionResult result = resultCaptor.getValue();
InetSocketAddress resolvedBackendAddr =
(InetSocketAddress) Iterables.getOnlyElement(
Iterables.getOnlyElement(result.getAddresses()).getAddresses());
Iterables.getOnlyElement(result.getAddressesOrError().getValue()).getAddresses());
assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr);
EquivalentAddressGroup resolvedBalancerAddr =
Iterables.getOnlyElement(result.getAttributes().get(GrpclbConstants.ATTR_LB_ADDRS));
@ -227,7 +226,7 @@ public class GrpclbNameResolverTest {
assertThat(fakeClock.runDueTasks()).isEqualTo(1);
verify(mockListener).onResult2(resultCaptor.capture());
ResolutionResult result = resultCaptor.getValue();
assertThat(result.getAddresses())
assertThat(result.getAddressesOrError().getValue())
.containsExactly(
new EquivalentAddressGroup(new InetSocketAddress(backendAddr, DEFAULT_PORT)));
assertThat(result.getAttributes()).isEqualTo(Attributes.EMPTY);
@ -245,8 +244,8 @@ public class GrpclbNameResolverTest {
resolver.start(mockListener);
assertThat(fakeClock.runDueTasks()).isEqualTo(1);
verify(mockListener).onError(errorCaptor.capture());
Status errorStatus = errorCaptor.getValue();
verify(mockListener).onResult2(resultCaptor.capture());
Status errorStatus = resultCaptor.getValue().getAddressesOrError().getStatus();
assertThat(errorStatus.getCode()).isEqualTo(Code.UNAVAILABLE);
assertThat(errorStatus.getCause()).hasMessageThat().contains("no addr");
}
@ -274,7 +273,7 @@ public class GrpclbNameResolverTest {
assertThat(fakeClock.runDueTasks()).isEqualTo(1);
verify(mockListener).onResult2(resultCaptor.capture());
ResolutionResult result = resultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty();
assertThat(result.getAddressesOrError().getValue()).isEmpty();
EquivalentAddressGroup resolvedBalancerAddr =
Iterables.getOnlyElement(result.getAttributes().get(GrpclbConstants.ATTR_LB_ADDRS));
assertThat(resolvedBalancerAddr.getAttributes().get(GrpclbConstants.ATTR_LB_ADDR_AUTHORITY))
@ -311,7 +310,7 @@ public class GrpclbNameResolverTest {
InetSocketAddress resolvedBackendAddr =
(InetSocketAddress) Iterables.getOnlyElement(
Iterables.getOnlyElement(result.getAddresses()).getAddresses());
Iterables.getOnlyElement(result.getAddressesOrError().getValue()).getAddresses());
assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr);
assertThat(result.getAttributes().get(GrpclbConstants.ATTR_LB_ADDRS)).isNull();
verify(mockAddressResolver).resolveAddress(hostName);
@ -335,8 +334,8 @@ public class GrpclbNameResolverTest {
resolver.start(mockListener);
assertThat(fakeClock.runDueTasks()).isEqualTo(1);
verify(mockListener).onError(errorCaptor.capture());
Status errorStatus = errorCaptor.getValue();
verify(mockListener).onResult2(resultCaptor.capture());
Status errorStatus = resultCaptor.getValue().getAddressesOrError().getStatus();
assertThat(errorStatus.getCode()).isEqualTo(Code.UNAVAILABLE);
verify(mockAddressResolver).resolveAddress(hostName);
verify(mockResourceResolver, never()).resolveTxt("_grpc_config." + hostName);

View File

@ -22,16 +22,16 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Preconditions;
import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver;
import io.grpc.StatusOr;
import io.netty.channel.unix.DomainSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
final class UdsNameResolver extends NameResolver {
private NameResolver.Listener2 listener;
private final String authority;
UdsNameResolver(String authority, String targetPath) {
UdsNameResolver(String authority, String targetPath, Args args) {
checkArgument(authority == null, "non-null authority not supported");
this.authority = targetPath;
}
@ -57,8 +57,8 @@ final class UdsNameResolver extends NameResolver {
ResolutionResult.Builder resolutionResultBuilder = ResolutionResult.newBuilder();
List<EquivalentAddressGroup> servers = new ArrayList<>(1);
servers.add(new EquivalentAddressGroup(new DomainSocketAddress(authority)));
resolutionResultBuilder.setAddresses(Collections.unmodifiableList(servers));
listener.onResult(resolutionResultBuilder.build());
resolutionResultBuilder.setAddressesOrError(StatusOr.fromValue(servers));
listener.onResult2(resolutionResultBuilder.build());
}
@Override

View File

@ -34,7 +34,7 @@ public final class UdsNameResolverProvider extends NameResolverProvider {
@Override
public UdsNameResolver newNameResolver(URI targetUri, NameResolver.Args args) {
if (SCHEME.equals(targetUri.getScheme())) {
return new UdsNameResolver(targetUri.getAuthority(), getTargetPathFromUri(targetUri));
return new UdsNameResolver(targetUri.getAuthority(), getTargetPathFromUri(targetUri), args);
} else {
return null;
}

View File

@ -18,10 +18,16 @@ package io.grpc.netty;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import io.grpc.ChannelLogger;
import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver;
import io.grpc.NameResolver.ServiceConfigParser;
import io.grpc.SynchronizationContext;
import io.grpc.internal.FakeClock;
import io.grpc.internal.GrpcUtil;
import io.netty.channel.unix.DomainSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
@ -39,7 +45,7 @@ import org.mockito.junit.MockitoRule;
/** Unit tests for {@link UdsNameResolverProvider}. */
@RunWith(JUnit4.class)
public class UdsNameResolverProviderTest {
private static final int DEFAULT_PORT = 887;
@Rule
public final MockitoRule mocks = MockitoJUnit.rule();
@ -51,16 +57,29 @@ public class UdsNameResolverProviderTest {
UdsNameResolverProvider udsNameResolverProvider = new UdsNameResolverProvider();
private final SynchronizationContext syncContext = new SynchronizationContext(
(t, e) -> {
throw new AssertionError(e);
});
private final FakeClock fakeExecutor = new FakeClock();
private final NameResolver.Args args = NameResolver.Args.newBuilder()
.setDefaultPort(DEFAULT_PORT)
.setProxyDetector(GrpcUtil.DEFAULT_PROXY_DETECTOR)
.setSynchronizationContext(syncContext)
.setServiceConfigParser(mock(ServiceConfigParser.class))
.setChannelLogger(mock(ChannelLogger.class))
.setScheduledExecutorService(fakeExecutor.getScheduledExecutorService())
.build();
@Test
public void testUnixRelativePath() {
UdsNameResolver udsNameResolver =
udsNameResolverProvider.newNameResolver(URI.create("unix:sock.sock"), null);
udsNameResolverProvider.newNameResolver(URI.create("unix:sock.sock"), args);
assertThat(udsNameResolver).isNotNull();
udsNameResolver.start(mockListener);
verify(mockListener).onResult(resultCaptor.capture());
verify(mockListener).onResult2(resultCaptor.capture());
NameResolver.ResolutionResult result = resultCaptor.getValue();
List<EquivalentAddressGroup> list = result.getAddresses();
List<EquivalentAddressGroup> list = result.getAddressesOrError().getValue();
assertThat(list).isNotNull();
assertThat(list).hasSize(1);
EquivalentAddressGroup eag = list.get(0);
@ -75,12 +94,12 @@ public class UdsNameResolverProviderTest {
@Test
public void testUnixAbsolutePath() {
UdsNameResolver udsNameResolver =
udsNameResolverProvider.newNameResolver(URI.create("unix:/sock.sock"), null);
udsNameResolverProvider.newNameResolver(URI.create("unix:/sock.sock"), args);
assertThat(udsNameResolver).isNotNull();
udsNameResolver.start(mockListener);
verify(mockListener).onResult(resultCaptor.capture());
verify(mockListener).onResult2(resultCaptor.capture());
NameResolver.ResolutionResult result = resultCaptor.getValue();
List<EquivalentAddressGroup> list = result.getAddresses();
List<EquivalentAddressGroup> list = result.getAddressesOrError().getValue();
assertThat(list).isNotNull();
assertThat(list).hasSize(1);
EquivalentAddressGroup eag = list.get(0);
@ -95,12 +114,12 @@ public class UdsNameResolverProviderTest {
@Test
public void testUnixAbsoluteAlternatePath() {
UdsNameResolver udsNameResolver =
udsNameResolverProvider.newNameResolver(URI.create("unix:///sock.sock"), null);
udsNameResolverProvider.newNameResolver(URI.create("unix:///sock.sock"), args);
assertThat(udsNameResolver).isNotNull();
udsNameResolver.start(mockListener);
verify(mockListener).onResult(resultCaptor.capture());
verify(mockListener).onResult2(resultCaptor.capture());
NameResolver.ResolutionResult result = resultCaptor.getValue();
List<EquivalentAddressGroup> list = result.getAddresses();
List<EquivalentAddressGroup> list = result.getAddressesOrError().getValue();
assertThat(list).isNotNull();
assertThat(list).hasSize(1);
EquivalentAddressGroup eag = list.get(0);
@ -115,7 +134,7 @@ public class UdsNameResolverProviderTest {
@Test
public void testUnixPathWithAuthority() {
try {
udsNameResolverProvider.newNameResolver(URI.create("unix://localhost/sock.sock"), null);
udsNameResolverProvider.newNameResolver(URI.create("unix://localhost/sock.sock"), args);
fail("exception expected");
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().isEqualTo("non-null authority not supported");

View File

@ -18,10 +18,16 @@ package io.grpc.netty;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import io.grpc.ChannelLogger;
import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver;
import io.grpc.NameResolver.ServiceConfigParser;
import io.grpc.SynchronizationContext;
import io.grpc.internal.FakeClock;
import io.grpc.internal.GrpcUtil;
import io.netty.channel.unix.DomainSocketAddress;
import java.net.SocketAddress;
import java.util.List;
@ -41,7 +47,20 @@ public class UdsNameResolverTest {
@Rule
public final MockitoRule mocks = MockitoJUnit.rule();
private static final int DEFAULT_PORT = 887;
private final FakeClock fakeExecutor = new FakeClock();
private final SynchronizationContext syncContext = new SynchronizationContext(
(t, e) -> {
throw new AssertionError(e);
});
private final NameResolver.Args args = NameResolver.Args.newBuilder()
.setDefaultPort(DEFAULT_PORT)
.setProxyDetector(GrpcUtil.DEFAULT_PROXY_DETECTOR)
.setSynchronizationContext(syncContext)
.setServiceConfigParser(mock(ServiceConfigParser.class))
.setChannelLogger(mock(ChannelLogger.class))
.setScheduledExecutorService(fakeExecutor.getScheduledExecutorService())
.build();
@Mock
private NameResolver.Listener2 mockListener;
@ -52,11 +71,11 @@ public class UdsNameResolverTest {
@Test
public void testValidTargetPath() {
udsNameResolver = new UdsNameResolver(null, "sock.sock");
udsNameResolver = new UdsNameResolver(null, "sock.sock", args);
udsNameResolver.start(mockListener);
verify(mockListener).onResult(resultCaptor.capture());
verify(mockListener).onResult2(resultCaptor.capture());
NameResolver.ResolutionResult result = resultCaptor.getValue();
List<EquivalentAddressGroup> list = result.getAddresses();
List<EquivalentAddressGroup> list = result.getAddressesOrError().getValue();
assertThat(list).isNotNull();
assertThat(list).hasSize(1);
EquivalentAddressGroup eag = list.get(0);
@ -72,7 +91,7 @@ public class UdsNameResolverTest {
@Test
public void testNonNullAuthority() {
try {
udsNameResolver = new UdsNameResolver("authority", "sock.sock");
udsNameResolver = new UdsNameResolver("authority", "sock.sock", args);
fail("exception expected");
} catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().isEqualTo("non-null authority not supported");

View File

@ -21,6 +21,7 @@ import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver;
import io.grpc.NameResolverProvider;
import io.grpc.Status;
import io.grpc.StatusOr;
import java.net.SocketAddress;
import java.net.URI;
import java.util.Collection;
@ -81,9 +82,10 @@ public final class FakeNameResolverProvider extends NameResolverProvider {
if (shutdown) {
listener.onError(Status.FAILED_PRECONDITION.withDescription("Resolver is shutdown"));
} else {
listener.onResult(
listener.onResult2(
ResolutionResult.newBuilder()
.setAddresses(ImmutableList.of(new EquivalentAddressGroup(address)))
.setAddressesOrError(
StatusOr.fromValue(ImmutableList.of(new EquivalentAddressGroup(address))))
.build());
}
}

View File

@ -52,6 +52,7 @@ import io.grpc.NameResolverProvider;
import io.grpc.NameResolverRegistry;
import io.grpc.Status;
import io.grpc.Status.Code;
import io.grpc.StatusOr;
import io.grpc.SynchronizationContext;
import io.grpc.internal.BackoffPolicy;
import io.grpc.internal.FakeClock;
@ -1306,7 +1307,8 @@ public class ClusterResolverLoadBalancerTest {
}
private void deliverEndpointAddresses(List<EquivalentAddressGroup> addresses) {
listener.onResult(ResolutionResult.newBuilder().setAddresses(addresses).build());
listener.onResult(ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromValue(addresses)).build());
}
private void deliverError(Status error) {

View File

@ -737,7 +737,7 @@ public class XdsNameResolverTest {
ImmutableMap.of())));
verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty();
assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertServiceConfigForLoadBalancingConfig(
Collections.singletonList(cluster2),
(Map<String, ?>) result.getServiceConfig().getConfig());
@ -1071,7 +1071,7 @@ public class XdsNameResolverTest {
ImmutableMap.of())));
verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty();
assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertServiceConfigForLoadBalancingConfig(
Arrays.asList(cluster1, cluster2), (Map<String, ?>) result.getServiceConfig().getConfig());
assertThat(result.getAttributes().get(InternalXdsAttributes.XDS_CLIENT_POOL)).isNotNull();
@ -1100,7 +1100,7 @@ public class XdsNameResolverTest {
ImmutableMap.of())));
verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty();
assertThat(result.getAddressesOrError().getValue()).isEmpty();
@SuppressWarnings("unchecked")
Map<String, ?> resultServiceConfig = (Map<String, ?>) result.getServiceConfig().getConfig();
List<Map<String, ?>> rawLbConfigs =
@ -1181,7 +1181,7 @@ public class XdsNameResolverTest {
private void assertEmptyResolutionResult(String resource) {
verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty();
assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertThat((Map<String, ?>) result.getServiceConfig().getConfig()).isEmpty();
InternalConfigSelector configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
Result configResult = configSelector.selectConfig(
@ -1260,7 +1260,7 @@ public class XdsNameResolverTest {
ImmutableMap.of())));
verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty();
assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertServiceConfigForLoadBalancingConfig(
Arrays.asList(cluster1, cluster2), (Map<String, ?>) result.getServiceConfig().getConfig());
assertThat(result.getAttributes().get(InternalXdsAttributes.XDS_CLIENT_POOL)).isNotNull();

View File

@ -43,6 +43,7 @@ import io.grpc.NameResolverRegistry;
import io.grpc.Server;
import io.grpc.ServerCredentials;
import io.grpc.Status;
import io.grpc.StatusOr;
import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver;
import io.grpc.testing.GrpcCleanupRule;
@ -520,7 +521,8 @@ public class XdsSecurityClientServerTest {
}
void resolved() {
ResolutionResult.Builder builder = ResolutionResult.newBuilder().setAddresses(servers);
ResolutionResult.Builder builder = ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromValue(servers));
listener.onResult(builder.build());
}