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 static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.MoreObjects; import com.google.common.base.MoreObjects;
import com.google.common.base.MoreObjects.ToStringHelper;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.errorprone.annotations.InlineMe; import com.google.errorprone.annotations.InlineMe;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.net.URI; import java.net.URI;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -95,7 +95,8 @@ public abstract class NameResolver {
@Override @Override
public void onResult(ResolutionResult resolutionResult) { 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 @Override
@Deprecated @Deprecated
@InlineMe( @InlineMe(
replacement = "this.onResult(ResolutionResult.newBuilder().setAddresses(servers)" replacement = "this.onResult2(ResolutionResult.newBuilder().setAddressesOrError("
+ ".setAttributes(attributes).build())", + "StatusOr.fromValue(servers)).setAttributes(attributes).build())",
imports = "io.grpc.NameResolver.ResolutionResult") imports = {"io.grpc.NameResolver.ResolutionResult", "io.grpc.StatusOr"})
public final void onAddresses( public final void onAddresses(
List<EquivalentAddressGroup> servers, @ResolutionResultAttr Attributes attributes) { List<EquivalentAddressGroup> servers, @ResolutionResultAttr Attributes attributes) {
// TODO(jihuncho) need to promote Listener2 if we want to use ConfigOrError // TODO(jihuncho) need to promote Listener2 if we want to use ConfigOrError
onResult( onResult2(
ResolutionResult.newBuilder().setAddresses(servers).setAttributes(attributes).build()); ResolutionResult.newBuilder().setAddressesOrError(
StatusOr.fromValue(servers)).setAttributes(attributes).build());
} }
/** /**
* Handles updates on resolved addresses and attributes. If * 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. * @param resolutionResult the resolved server addresses, attributes, and Service Config.
* @since 1.21.0 * @since 1.21.0
@ -584,17 +587,17 @@ public abstract class NameResolver {
*/ */
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770") @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770")
public static final class ResolutionResult { public static final class ResolutionResult {
private final List<EquivalentAddressGroup> addresses; private final StatusOr<List<EquivalentAddressGroup>> addressesOrError;
@ResolutionResultAttr @ResolutionResultAttr
private final Attributes attributes; private final Attributes attributes;
@Nullable @Nullable
private final ConfigOrError serviceConfig; private final ConfigOrError serviceConfig;
ResolutionResult( ResolutionResult(
List<EquivalentAddressGroup> addresses, StatusOr<List<EquivalentAddressGroup>> addressesOrError,
@ResolutionResultAttr Attributes attributes, @ResolutionResultAttr Attributes attributes,
ConfigOrError serviceConfig) { ConfigOrError serviceConfig) {
this.addresses = Collections.unmodifiableList(new ArrayList<>(addresses)); this.addressesOrError = addressesOrError;
this.attributes = checkNotNull(attributes, "attributes"); this.attributes = checkNotNull(attributes, "attributes");
this.serviceConfig = serviceConfig; this.serviceConfig = serviceConfig;
} }
@ -615,7 +618,7 @@ public abstract class NameResolver {
*/ */
public Builder toBuilder() { public Builder toBuilder() {
return newBuilder() return newBuilder()
.setAddresses(addresses) .setAddressesOrError(addressesOrError)
.setAttributes(attributes) .setAttributes(attributes)
.setServiceConfig(serviceConfig); .setServiceConfig(serviceConfig);
} }
@ -624,9 +627,20 @@ public abstract class NameResolver {
* Gets the addresses resolved by name resolution. * Gets the addresses resolved by name resolution.
* *
* @since 1.21.0 * @since 1.21.0
* @deprecated Will be superseded by getAddressesOrError
*/ */
@Deprecated
public List<EquivalentAddressGroup> getAddresses() { 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 @Override
public String toString() { public String toString() {
return MoreObjects.toStringHelper(this) ToStringHelper stringHelper = MoreObjects.toStringHelper(this);
.add("addresses", addresses) stringHelper.add("addressesOrError", addressesOrError.toString());
.add("attributes", attributes) stringHelper.add("attributes", attributes);
.add("serviceConfig", serviceConfig) stringHelper.add("serviceConfigOrError", serviceConfig);
.toString(); return stringHelper.toString();
} }
/** /**
@ -668,7 +682,7 @@ public abstract class NameResolver {
return false; return false;
} }
ResolutionResult that = (ResolutionResult) obj; 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.attributes, that.attributes)
&& Objects.equal(this.serviceConfig, that.serviceConfig); && Objects.equal(this.serviceConfig, that.serviceConfig);
} }
@ -678,7 +692,7 @@ public abstract class NameResolver {
*/ */
@Override @Override
public int hashCode() { 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") @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770")
public static final class Builder { 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; private Attributes attributes = Attributes.EMPTY;
@Nullable @Nullable
private ConfigOrError serviceConfig; private ConfigOrError serviceConfig;
@ -700,9 +715,21 @@ public abstract class NameResolver {
* Sets the addresses resolved by name resolution. This field is required. * Sets the addresses resolved by name resolution. This field is required.
* *
* @since 1.21.0 * @since 1.21.0
* @deprecated Will be superseded by setAddressesOrError
*/ */
@Deprecated
public Builder setAddresses(List<EquivalentAddressGroup> addresses) { 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; 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; package io.grpc;
import static com.google.common.truth.Truth.assertThat; 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.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 io.grpc.NameResolver.ServiceConfigParser;
import java.lang.Thread.UncaughtExceptionHandler; 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.Executor;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; 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}. */ /** Unit tests for the inner classes in {@link NameResolver}. */
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class NameResolverTest { 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 int defaultPort = 293;
private final ProxyDetector proxyDetector = mock(ProxyDetector.class); private final ProxyDetector proxyDetector = mock(ProxyDetector.class);
private final SynchronizationContext syncContext = private final SynchronizationContext syncContext =
@ -41,6 +64,7 @@ public class NameResolverTest {
private final ChannelLogger channelLogger = mock(ChannelLogger.class); private final ChannelLogger channelLogger = mock(ChannelLogger.class);
private final Executor executor = Executors.newSingleThreadExecutor(); private final Executor executor = Executors.newSingleThreadExecutor();
private final String overrideAuthority = "grpc.io"; private final String overrideAuthority = "grpc.io";
@Mock NameResolver.Listener mockListener;
@Test @Test
public void args() { public void args() {
@ -80,4 +104,90 @@ public class NameResolverTest {
.setOverrideAuthority(overrideAuthority) .setOverrideAuthority(overrideAuthority)
.build(); .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") 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.ProxiedSocketAddress;
import io.grpc.ProxyDetector; import io.grpc.ProxyDetector;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.StatusOr;
import io.grpc.SynchronizationContext; import io.grpc.SynchronizationContext;
import io.grpc.internal.SharedResourceHolder.Resource; import io.grpc.internal.SharedResourceHolder.Resource;
import java.io.IOException; import java.io.IOException;
@ -59,7 +60,7 @@ import javax.annotation.Nullable;
* A DNS-based {@link NameResolver}. * A DNS-based {@link NameResolver}.
* *
* <p>Each {@code A} or {@code AAAA} record emits an {@link EquivalentAddressGroup} in the list * <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 * @see DnsNameResolverProvider
*/ */
@ -313,15 +314,20 @@ public class DnsNameResolver extends NameResolver {
if (logger.isLoggable(Level.FINER)) { if (logger.isLoggable(Level.FINER)) {
logger.finer("Using proxy address " + proxiedAddr); logger.finer("Using proxy address " + proxiedAddr);
} }
resolutionResultBuilder.setAddresses(Collections.singletonList(proxiedAddr)); resolutionResultBuilder.setAddressesOrError(
StatusOr.fromValue(Collections.singletonList(proxiedAddr)));
} else { } else {
result = doResolve(false); result = doResolve(false);
if (result.error != null) { if (result.error != null) {
savedListener.onError(result.error); InternalResolutionResult finalResult = result;
syncContext.execute(() ->
savedListener.onResult2(ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromStatus(finalResult.error))
.build()));
return; return;
} }
if (result.addresses != null) { if (result.addresses != null) {
resolutionResultBuilder.setAddresses(result.addresses); resolutionResultBuilder.setAddressesOrError(StatusOr.fromValue(result.addresses));
} }
if (result.config != null) { if (result.config != null) {
resolutionResultBuilder.setServiceConfig(result.config); resolutionResultBuilder.setServiceConfig(result.config);
@ -334,8 +340,12 @@ public class DnsNameResolver extends NameResolver {
savedListener.onResult2(resolutionResultBuilder.build()); savedListener.onResult2(resolutionResultBuilder.build());
}); });
} catch (IOException e) { } catch (IOException e) {
savedListener.onError( syncContext.execute(() ->
Status.UNAVAILABLE.withDescription("Unable to resolve host " + host).withCause(e)); savedListener.onResult2(ResolutionResult.newBuilder()
.setAddressesOrError(
StatusOr.fromStatus(
Status.UNAVAILABLE.withDescription(
"Unable to resolve host " + host).withCause(e))).build()));
} finally { } finally {
final boolean succeed = result != null && result.error == null; final boolean succeed = result != null && result.error == null;
syncContext.execute(new Runnable() { syncContext.execute(new Runnable() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -96,7 +96,6 @@ public class GrpclbNameResolverTest {
} }
@Captor private ArgumentCaptor<ResolutionResult> resultCaptor; @Captor private ArgumentCaptor<ResolutionResult> resultCaptor;
@Captor private ArgumentCaptor<Status> errorCaptor;
@Mock private ServiceConfigParser serviceConfigParser; @Mock private ServiceConfigParser serviceConfigParser;
@Mock private NameResolver.Listener2 mockListener; @Mock private NameResolver.Listener2 mockListener;
@ -154,7 +153,7 @@ public class GrpclbNameResolverTest {
verify(mockListener).onResult2(resultCaptor.capture()); verify(mockListener).onResult2(resultCaptor.capture());
ResolutionResult result = resultCaptor.getValue(); ResolutionResult result = resultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty(); assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertThat(result.getAttributes()).isEqualTo(Attributes.EMPTY); assertThat(result.getAttributes()).isEqualTo(Attributes.EMPTY);
assertThat(result.getServiceConfig()).isNull(); assertThat(result.getServiceConfig()).isNull();
} }
@ -196,7 +195,7 @@ public class GrpclbNameResolverTest {
ResolutionResult result = resultCaptor.getValue(); ResolutionResult result = resultCaptor.getValue();
InetSocketAddress resolvedBackendAddr = InetSocketAddress resolvedBackendAddr =
(InetSocketAddress) Iterables.getOnlyElement( (InetSocketAddress) Iterables.getOnlyElement(
Iterables.getOnlyElement(result.getAddresses()).getAddresses()); Iterables.getOnlyElement(result.getAddressesOrError().getValue()).getAddresses());
assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr); assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr);
EquivalentAddressGroup resolvedBalancerAddr = EquivalentAddressGroup resolvedBalancerAddr =
Iterables.getOnlyElement(result.getAttributes().get(GrpclbConstants.ATTR_LB_ADDRS)); Iterables.getOnlyElement(result.getAttributes().get(GrpclbConstants.ATTR_LB_ADDRS));
@ -227,7 +226,7 @@ public class GrpclbNameResolverTest {
assertThat(fakeClock.runDueTasks()).isEqualTo(1); assertThat(fakeClock.runDueTasks()).isEqualTo(1);
verify(mockListener).onResult2(resultCaptor.capture()); verify(mockListener).onResult2(resultCaptor.capture());
ResolutionResult result = resultCaptor.getValue(); ResolutionResult result = resultCaptor.getValue();
assertThat(result.getAddresses()) assertThat(result.getAddressesOrError().getValue())
.containsExactly( .containsExactly(
new EquivalentAddressGroup(new InetSocketAddress(backendAddr, DEFAULT_PORT))); new EquivalentAddressGroup(new InetSocketAddress(backendAddr, DEFAULT_PORT)));
assertThat(result.getAttributes()).isEqualTo(Attributes.EMPTY); assertThat(result.getAttributes()).isEqualTo(Attributes.EMPTY);
@ -245,8 +244,8 @@ public class GrpclbNameResolverTest {
resolver.start(mockListener); resolver.start(mockListener);
assertThat(fakeClock.runDueTasks()).isEqualTo(1); assertThat(fakeClock.runDueTasks()).isEqualTo(1);
verify(mockListener).onError(errorCaptor.capture()); verify(mockListener).onResult2(resultCaptor.capture());
Status errorStatus = errorCaptor.getValue(); Status errorStatus = resultCaptor.getValue().getAddressesOrError().getStatus();
assertThat(errorStatus.getCode()).isEqualTo(Code.UNAVAILABLE); assertThat(errorStatus.getCode()).isEqualTo(Code.UNAVAILABLE);
assertThat(errorStatus.getCause()).hasMessageThat().contains("no addr"); assertThat(errorStatus.getCause()).hasMessageThat().contains("no addr");
} }
@ -274,7 +273,7 @@ public class GrpclbNameResolverTest {
assertThat(fakeClock.runDueTasks()).isEqualTo(1); assertThat(fakeClock.runDueTasks()).isEqualTo(1);
verify(mockListener).onResult2(resultCaptor.capture()); verify(mockListener).onResult2(resultCaptor.capture());
ResolutionResult result = resultCaptor.getValue(); ResolutionResult result = resultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty(); assertThat(result.getAddressesOrError().getValue()).isEmpty();
EquivalentAddressGroup resolvedBalancerAddr = EquivalentAddressGroup resolvedBalancerAddr =
Iterables.getOnlyElement(result.getAttributes().get(GrpclbConstants.ATTR_LB_ADDRS)); Iterables.getOnlyElement(result.getAttributes().get(GrpclbConstants.ATTR_LB_ADDRS));
assertThat(resolvedBalancerAddr.getAttributes().get(GrpclbConstants.ATTR_LB_ADDR_AUTHORITY)) assertThat(resolvedBalancerAddr.getAttributes().get(GrpclbConstants.ATTR_LB_ADDR_AUTHORITY))
@ -311,7 +310,7 @@ public class GrpclbNameResolverTest {
InetSocketAddress resolvedBackendAddr = InetSocketAddress resolvedBackendAddr =
(InetSocketAddress) Iterables.getOnlyElement( (InetSocketAddress) Iterables.getOnlyElement(
Iterables.getOnlyElement(result.getAddresses()).getAddresses()); Iterables.getOnlyElement(result.getAddressesOrError().getValue()).getAddresses());
assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr); assertThat(resolvedBackendAddr.getAddress()).isEqualTo(backendAddr);
assertThat(result.getAttributes().get(GrpclbConstants.ATTR_LB_ADDRS)).isNull(); assertThat(result.getAttributes().get(GrpclbConstants.ATTR_LB_ADDRS)).isNull();
verify(mockAddressResolver).resolveAddress(hostName); verify(mockAddressResolver).resolveAddress(hostName);
@ -335,8 +334,8 @@ public class GrpclbNameResolverTest {
resolver.start(mockListener); resolver.start(mockListener);
assertThat(fakeClock.runDueTasks()).isEqualTo(1); assertThat(fakeClock.runDueTasks()).isEqualTo(1);
verify(mockListener).onError(errorCaptor.capture()); verify(mockListener).onResult2(resultCaptor.capture());
Status errorStatus = errorCaptor.getValue(); Status errorStatus = resultCaptor.getValue().getAddressesOrError().getStatus();
assertThat(errorStatus.getCode()).isEqualTo(Code.UNAVAILABLE); assertThat(errorStatus.getCode()).isEqualTo(Code.UNAVAILABLE);
verify(mockAddressResolver).resolveAddress(hostName); verify(mockAddressResolver).resolveAddress(hostName);
verify(mockResourceResolver, never()).resolveTxt("_grpc_config." + 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 com.google.common.base.Preconditions;
import io.grpc.EquivalentAddressGroup; import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver; import io.grpc.NameResolver;
import io.grpc.StatusOr;
import io.netty.channel.unix.DomainSocketAddress; import io.netty.channel.unix.DomainSocketAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
final class UdsNameResolver extends NameResolver { final class UdsNameResolver extends NameResolver {
private NameResolver.Listener2 listener; private NameResolver.Listener2 listener;
private final String authority; private final String authority;
UdsNameResolver(String authority, String targetPath) { UdsNameResolver(String authority, String targetPath, Args args) {
checkArgument(authority == null, "non-null authority not supported"); checkArgument(authority == null, "non-null authority not supported");
this.authority = targetPath; this.authority = targetPath;
} }
@ -57,8 +57,8 @@ final class UdsNameResolver extends NameResolver {
ResolutionResult.Builder resolutionResultBuilder = ResolutionResult.newBuilder(); ResolutionResult.Builder resolutionResultBuilder = ResolutionResult.newBuilder();
List<EquivalentAddressGroup> servers = new ArrayList<>(1); List<EquivalentAddressGroup> servers = new ArrayList<>(1);
servers.add(new EquivalentAddressGroup(new DomainSocketAddress(authority))); servers.add(new EquivalentAddressGroup(new DomainSocketAddress(authority)));
resolutionResultBuilder.setAddresses(Collections.unmodifiableList(servers)); resolutionResultBuilder.setAddressesOrError(StatusOr.fromValue(servers));
listener.onResult(resolutionResultBuilder.build()); listener.onResult2(resolutionResultBuilder.build());
} }
@Override @Override

View File

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

View File

@ -18,10 +18,16 @@ package io.grpc.netty;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import io.grpc.ChannelLogger;
import io.grpc.EquivalentAddressGroup; import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver; 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 io.netty.channel.unix.DomainSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.net.URI; import java.net.URI;
@ -39,7 +45,7 @@ import org.mockito.junit.MockitoRule;
/** Unit tests for {@link UdsNameResolverProvider}. */ /** Unit tests for {@link UdsNameResolverProvider}. */
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class UdsNameResolverProviderTest { public class UdsNameResolverProviderTest {
private static final int DEFAULT_PORT = 887;
@Rule @Rule
public final MockitoRule mocks = MockitoJUnit.rule(); public final MockitoRule mocks = MockitoJUnit.rule();
@ -51,16 +57,29 @@ public class UdsNameResolverProviderTest {
UdsNameResolverProvider udsNameResolverProvider = new UdsNameResolverProvider(); 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 @Test
public void testUnixRelativePath() { public void testUnixRelativePath() {
UdsNameResolver udsNameResolver = UdsNameResolver udsNameResolver =
udsNameResolverProvider.newNameResolver(URI.create("unix:sock.sock"), null); udsNameResolverProvider.newNameResolver(URI.create("unix:sock.sock"), args);
assertThat(udsNameResolver).isNotNull(); assertThat(udsNameResolver).isNotNull();
udsNameResolver.start(mockListener); udsNameResolver.start(mockListener);
verify(mockListener).onResult(resultCaptor.capture()); verify(mockListener).onResult2(resultCaptor.capture());
NameResolver.ResolutionResult result = resultCaptor.getValue(); NameResolver.ResolutionResult result = resultCaptor.getValue();
List<EquivalentAddressGroup> list = result.getAddresses(); List<EquivalentAddressGroup> list = result.getAddressesOrError().getValue();
assertThat(list).isNotNull(); assertThat(list).isNotNull();
assertThat(list).hasSize(1); assertThat(list).hasSize(1);
EquivalentAddressGroup eag = list.get(0); EquivalentAddressGroup eag = list.get(0);
@ -75,12 +94,12 @@ public class UdsNameResolverProviderTest {
@Test @Test
public void testUnixAbsolutePath() { public void testUnixAbsolutePath() {
UdsNameResolver udsNameResolver = UdsNameResolver udsNameResolver =
udsNameResolverProvider.newNameResolver(URI.create("unix:/sock.sock"), null); udsNameResolverProvider.newNameResolver(URI.create("unix:/sock.sock"), args);
assertThat(udsNameResolver).isNotNull(); assertThat(udsNameResolver).isNotNull();
udsNameResolver.start(mockListener); udsNameResolver.start(mockListener);
verify(mockListener).onResult(resultCaptor.capture()); verify(mockListener).onResult2(resultCaptor.capture());
NameResolver.ResolutionResult result = resultCaptor.getValue(); NameResolver.ResolutionResult result = resultCaptor.getValue();
List<EquivalentAddressGroup> list = result.getAddresses(); List<EquivalentAddressGroup> list = result.getAddressesOrError().getValue();
assertThat(list).isNotNull(); assertThat(list).isNotNull();
assertThat(list).hasSize(1); assertThat(list).hasSize(1);
EquivalentAddressGroup eag = list.get(0); EquivalentAddressGroup eag = list.get(0);
@ -95,12 +114,12 @@ public class UdsNameResolverProviderTest {
@Test @Test
public void testUnixAbsoluteAlternatePath() { public void testUnixAbsoluteAlternatePath() {
UdsNameResolver udsNameResolver = UdsNameResolver udsNameResolver =
udsNameResolverProvider.newNameResolver(URI.create("unix:///sock.sock"), null); udsNameResolverProvider.newNameResolver(URI.create("unix:///sock.sock"), args);
assertThat(udsNameResolver).isNotNull(); assertThat(udsNameResolver).isNotNull();
udsNameResolver.start(mockListener); udsNameResolver.start(mockListener);
verify(mockListener).onResult(resultCaptor.capture()); verify(mockListener).onResult2(resultCaptor.capture());
NameResolver.ResolutionResult result = resultCaptor.getValue(); NameResolver.ResolutionResult result = resultCaptor.getValue();
List<EquivalentAddressGroup> list = result.getAddresses(); List<EquivalentAddressGroup> list = result.getAddressesOrError().getValue();
assertThat(list).isNotNull(); assertThat(list).isNotNull();
assertThat(list).hasSize(1); assertThat(list).hasSize(1);
EquivalentAddressGroup eag = list.get(0); EquivalentAddressGroup eag = list.get(0);
@ -115,7 +134,7 @@ public class UdsNameResolverProviderTest {
@Test @Test
public void testUnixPathWithAuthority() { public void testUnixPathWithAuthority() {
try { try {
udsNameResolverProvider.newNameResolver(URI.create("unix://localhost/sock.sock"), null); udsNameResolverProvider.newNameResolver(URI.create("unix://localhost/sock.sock"), args);
fail("exception expected"); fail("exception expected");
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().isEqualTo("non-null authority not supported"); 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 com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import io.grpc.ChannelLogger;
import io.grpc.EquivalentAddressGroup; import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver; 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 io.netty.channel.unix.DomainSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.List; import java.util.List;
@ -41,7 +47,20 @@ public class UdsNameResolverTest {
@Rule @Rule
public final MockitoRule mocks = MockitoJUnit.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 @Mock
private NameResolver.Listener2 mockListener; private NameResolver.Listener2 mockListener;
@ -52,11 +71,11 @@ public class UdsNameResolverTest {
@Test @Test
public void testValidTargetPath() { public void testValidTargetPath() {
udsNameResolver = new UdsNameResolver(null, "sock.sock"); udsNameResolver = new UdsNameResolver(null, "sock.sock", args);
udsNameResolver.start(mockListener); udsNameResolver.start(mockListener);
verify(mockListener).onResult(resultCaptor.capture()); verify(mockListener).onResult2(resultCaptor.capture());
NameResolver.ResolutionResult result = resultCaptor.getValue(); NameResolver.ResolutionResult result = resultCaptor.getValue();
List<EquivalentAddressGroup> list = result.getAddresses(); List<EquivalentAddressGroup> list = result.getAddressesOrError().getValue();
assertThat(list).isNotNull(); assertThat(list).isNotNull();
assertThat(list).hasSize(1); assertThat(list).hasSize(1);
EquivalentAddressGroup eag = list.get(0); EquivalentAddressGroup eag = list.get(0);
@ -72,7 +91,7 @@ public class UdsNameResolverTest {
@Test @Test
public void testNonNullAuthority() { public void testNonNullAuthority() {
try { try {
udsNameResolver = new UdsNameResolver("authority", "sock.sock"); udsNameResolver = new UdsNameResolver("authority", "sock.sock", args);
fail("exception expected"); fail("exception expected");
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
assertThat(e).hasMessageThat().isEqualTo("non-null authority not supported"); 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.NameResolver;
import io.grpc.NameResolverProvider; import io.grpc.NameResolverProvider;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.StatusOr;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.net.URI; import java.net.URI;
import java.util.Collection; import java.util.Collection;
@ -81,9 +82,10 @@ public final class FakeNameResolverProvider extends NameResolverProvider {
if (shutdown) { if (shutdown) {
listener.onError(Status.FAILED_PRECONDITION.withDescription("Resolver is shutdown")); listener.onError(Status.FAILED_PRECONDITION.withDescription("Resolver is shutdown"));
} else { } else {
listener.onResult( listener.onResult2(
ResolutionResult.newBuilder() ResolutionResult.newBuilder()
.setAddresses(ImmutableList.of(new EquivalentAddressGroup(address))) .setAddressesOrError(
StatusOr.fromValue(ImmutableList.of(new EquivalentAddressGroup(address))))
.build()); .build());
} }
} }

View File

@ -52,6 +52,7 @@ import io.grpc.NameResolverProvider;
import io.grpc.NameResolverRegistry; import io.grpc.NameResolverRegistry;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.Status.Code; import io.grpc.Status.Code;
import io.grpc.StatusOr;
import io.grpc.SynchronizationContext; import io.grpc.SynchronizationContext;
import io.grpc.internal.BackoffPolicy; import io.grpc.internal.BackoffPolicy;
import io.grpc.internal.FakeClock; import io.grpc.internal.FakeClock;
@ -1306,7 +1307,8 @@ public class ClusterResolverLoadBalancerTest {
} }
private void deliverEndpointAddresses(List<EquivalentAddressGroup> addresses) { 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) { private void deliverError(Status error) {

View File

@ -737,7 +737,7 @@ public class XdsNameResolverTest {
ImmutableMap.of()))); ImmutableMap.of())));
verify(mockListener).onResult(resolutionResultCaptor.capture()); verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue(); ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty(); assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertServiceConfigForLoadBalancingConfig( assertServiceConfigForLoadBalancingConfig(
Collections.singletonList(cluster2), Collections.singletonList(cluster2),
(Map<String, ?>) result.getServiceConfig().getConfig()); (Map<String, ?>) result.getServiceConfig().getConfig());
@ -1071,7 +1071,7 @@ public class XdsNameResolverTest {
ImmutableMap.of()))); ImmutableMap.of())));
verify(mockListener).onResult(resolutionResultCaptor.capture()); verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue(); ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty(); assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertServiceConfigForLoadBalancingConfig( assertServiceConfigForLoadBalancingConfig(
Arrays.asList(cluster1, cluster2), (Map<String, ?>) result.getServiceConfig().getConfig()); Arrays.asList(cluster1, cluster2), (Map<String, ?>) result.getServiceConfig().getConfig());
assertThat(result.getAttributes().get(InternalXdsAttributes.XDS_CLIENT_POOL)).isNotNull(); assertThat(result.getAttributes().get(InternalXdsAttributes.XDS_CLIENT_POOL)).isNotNull();
@ -1100,7 +1100,7 @@ public class XdsNameResolverTest {
ImmutableMap.of()))); ImmutableMap.of())));
verify(mockListener).onResult(resolutionResultCaptor.capture()); verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue(); ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty(); assertThat(result.getAddressesOrError().getValue()).isEmpty();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, ?> resultServiceConfig = (Map<String, ?>) result.getServiceConfig().getConfig(); Map<String, ?> resultServiceConfig = (Map<String, ?>) result.getServiceConfig().getConfig();
List<Map<String, ?>> rawLbConfigs = List<Map<String, ?>> rawLbConfigs =
@ -1181,7 +1181,7 @@ public class XdsNameResolverTest {
private void assertEmptyResolutionResult(String resource) { private void assertEmptyResolutionResult(String resource) {
verify(mockListener).onResult(resolutionResultCaptor.capture()); verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue(); ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty(); assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertThat((Map<String, ?>) result.getServiceConfig().getConfig()).isEmpty(); assertThat((Map<String, ?>) result.getServiceConfig().getConfig()).isEmpty();
InternalConfigSelector configSelector = result.getAttributes().get(InternalConfigSelector.KEY); InternalConfigSelector configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
Result configResult = configSelector.selectConfig( Result configResult = configSelector.selectConfig(
@ -1260,7 +1260,7 @@ public class XdsNameResolverTest {
ImmutableMap.of()))); ImmutableMap.of())));
verify(mockListener).onResult(resolutionResultCaptor.capture()); verify(mockListener).onResult(resolutionResultCaptor.capture());
ResolutionResult result = resolutionResultCaptor.getValue(); ResolutionResult result = resolutionResultCaptor.getValue();
assertThat(result.getAddresses()).isEmpty(); assertThat(result.getAddressesOrError().getValue()).isEmpty();
assertServiceConfigForLoadBalancingConfig( assertServiceConfigForLoadBalancingConfig(
Arrays.asList(cluster1, cluster2), (Map<String, ?>) result.getServiceConfig().getConfig()); Arrays.asList(cluster1, cluster2), (Map<String, ?>) result.getServiceConfig().getConfig());
assertThat(result.getAttributes().get(InternalXdsAttributes.XDS_CLIENT_POOL)).isNotNull(); 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.Server;
import io.grpc.ServerCredentials; import io.grpc.ServerCredentials;
import io.grpc.Status; import io.grpc.Status;
import io.grpc.StatusOr;
import io.grpc.StatusRuntimeException; import io.grpc.StatusRuntimeException;
import io.grpc.stub.StreamObserver; import io.grpc.stub.StreamObserver;
import io.grpc.testing.GrpcCleanupRule; import io.grpc.testing.GrpcCleanupRule;
@ -520,7 +521,8 @@ public class XdsSecurityClientServerTest {
} }
void resolved() { void resolved() {
ResolutionResult.Builder builder = ResolutionResult.newBuilder().setAddresses(servers); ResolutionResult.Builder builder = ResolutionResult.newBuilder()
.setAddressesOrError(StatusOr.fromValue(servers));
listener.onResult(builder.build()); listener.onResult(builder.build());
} }