mirror of https://github.com/grpc/grpc-java.git
xds: Implement XdsServingStatusListener as per the new xDS server gRFC (#7876)
This commit is contained in:
parent
7b70161eef
commit
8030c3a11d
|
|
@ -104,7 +104,6 @@ public final class XdsClientWrapperForServerSds {
|
||||||
throw new XdsInitializationException("No management server provided by bootstrap");
|
throw new XdsInitializationException("No management server provided by bootstrap");
|
||||||
}
|
}
|
||||||
} catch (XdsInitializationException e) {
|
} catch (XdsInitializationException e) {
|
||||||
reportError(Status.fromThrowable(e));
|
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
Node node = bootstrapInfo.getNode();
|
Node node = bootstrapInfo.getNode();
|
||||||
|
|
@ -116,9 +115,7 @@ public final class XdsClientWrapperForServerSds {
|
||||||
newServerApi = serverInfo.isUseProtocolV3() && experimentalNewServerApiEnvVar;
|
newServerApi = serverInfo.isUseProtocolV3() && experimentalNewServerApiEnvVar;
|
||||||
String grpcServerResourceId = bootstrapInfo.getGrpcServerResourceId();
|
String grpcServerResourceId = bootstrapInfo.getGrpcServerResourceId();
|
||||||
if (newServerApi && grpcServerResourceId == null) {
|
if (newServerApi && grpcServerResourceId == null) {
|
||||||
reportError(
|
throw new IOException("missing grpc_server_resource_name_id value in xds bootstrap");
|
||||||
Status.INVALID_ARGUMENT.withDescription("missing grpc_server_resource_name_id value"));
|
|
||||||
throw new IOException("missing grpc_server_resource_name_id value");
|
|
||||||
}
|
}
|
||||||
XdsClient xdsClientImpl =
|
XdsClient xdsClientImpl =
|
||||||
new ServerXdsClient(
|
new ServerXdsClient(
|
||||||
|
|
@ -152,14 +149,14 @@ public final class XdsClientWrapperForServerSds {
|
||||||
public void onResourceDoesNotExist(String resourceName) {
|
public void onResourceDoesNotExist(String resourceName) {
|
||||||
logger.log(Level.WARNING, "Resource {0} is unavailable", resourceName);
|
logger.log(Level.WARNING, "Resource {0} is unavailable", resourceName);
|
||||||
curListener = null;
|
curListener = null;
|
||||||
reportError(Status.NOT_FOUND.withDescription(resourceName));
|
reportError(Status.NOT_FOUND.withDescription(resourceName).asException());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError(Status error) {
|
public void onError(Status error) {
|
||||||
logger.log(
|
logger.log(
|
||||||
Level.WARNING, "ListenerWatcher in XdsClientWrapperForServerSds: {0}", error);
|
Level.WARNING, "ListenerWatcher in XdsClientWrapperForServerSds: {0}", error);
|
||||||
reportError(error);
|
reportError(error.asException());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
xdsClient.watchListenerData(port, listenerWatcher);
|
xdsClient.watchListenerData(port, listenerWatcher);
|
||||||
|
|
@ -225,9 +222,9 @@ public final class XdsClientWrapperForServerSds {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reportError(Status status) {
|
private void reportError(Throwable throwable) {
|
||||||
for (ServerWatcher watcher : getServerWatchers()) {
|
for (ServerWatcher watcher : getServerWatchers()) {
|
||||||
watcher.onError(status);
|
watcher.onError(throwable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,7 +246,7 @@ public final class XdsClientWrapperForServerSds {
|
||||||
public interface ServerWatcher {
|
public interface ServerWatcher {
|
||||||
|
|
||||||
/** Called to report errors from the control plane including "not found". */
|
/** Called to report errors from the control plane including "not found". */
|
||||||
void onError(Status error);
|
void onError(Throwable throwable);
|
||||||
|
|
||||||
/** Called to report successful receipt of server config. */
|
/** Called to report successful receipt of server config. */
|
||||||
void onSuccess(DownstreamTlsContext downstreamTlsContext);
|
void onSuccess(DownstreamTlsContext downstreamTlsContext);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package io.grpc.xds;
|
package io.grpc.xds;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
@ -26,7 +27,6 @@ import io.grpc.Internal;
|
||||||
import io.grpc.Server;
|
import io.grpc.Server;
|
||||||
import io.grpc.ServerBuilder;
|
import io.grpc.ServerBuilder;
|
||||||
import io.grpc.ServerCredentials;
|
import io.grpc.ServerCredentials;
|
||||||
import io.grpc.Status;
|
|
||||||
import io.grpc.netty.InternalNettyServerBuilder;
|
import io.grpc.netty.InternalNettyServerBuilder;
|
||||||
import io.grpc.netty.NettyServerBuilder;
|
import io.grpc.netty.NettyServerBuilder;
|
||||||
import io.grpc.xds.internal.sds.SdsProtocolNegotiators;
|
import io.grpc.xds.internal.sds.SdsProtocolNegotiators;
|
||||||
|
|
@ -42,12 +42,13 @@ public final class XdsServerBuilder extends ForwardingServerBuilder<XdsServerBui
|
||||||
|
|
||||||
private final NettyServerBuilder delegate;
|
private final NettyServerBuilder delegate;
|
||||||
private final int port;
|
private final int port;
|
||||||
private ErrorNotifier errorNotifier;
|
private XdsServingStatusListener xdsServingStatusListener;
|
||||||
private AtomicBoolean isServerBuilt = new AtomicBoolean(false);
|
private AtomicBoolean isServerBuilt = new AtomicBoolean(false);
|
||||||
|
|
||||||
private XdsServerBuilder(NettyServerBuilder nettyDelegate, int port) {
|
private XdsServerBuilder(NettyServerBuilder nettyDelegate, int port) {
|
||||||
this.delegate = nettyDelegate;
|
this.delegate = nettyDelegate;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
|
xdsServingStatusListener = new DefaultListener("port:" + port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -56,9 +57,11 @@ public final class XdsServerBuilder extends ForwardingServerBuilder<XdsServerBui
|
||||||
return delegate;
|
return delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the {@link ErrorNotifier}. Pass null to unset a previously set value. */
|
/** Set the {@link XdsServingStatusListener}. */
|
||||||
public XdsServerBuilder errorNotifier(ErrorNotifier errorNotifier) {
|
public XdsServerBuilder xdsServingStatusListener(
|
||||||
this.errorNotifier = errorNotifier;
|
XdsServingStatusListener xdsServingStatusListener) {
|
||||||
|
this.xdsServingStatusListener =
|
||||||
|
checkNotNull(xdsServingStatusListener, "xdsServingStatusListener");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,7 +94,7 @@ public final class XdsServerBuilder extends ForwardingServerBuilder<XdsServerBui
|
||||||
InternalNettyServerBuilder.eagAttributes(delegate, Attributes.newBuilder()
|
InternalNettyServerBuilder.eagAttributes(delegate, Attributes.newBuilder()
|
||||||
.set(SdsProtocolNegotiators.SERVER_XDS_CLIENT, xdsClient)
|
.set(SdsProtocolNegotiators.SERVER_XDS_CLIENT, xdsClient)
|
||||||
.build());
|
.build());
|
||||||
return new ServerWrapperForXds(delegate.build(), xdsClient, errorNotifier);
|
return new ServerWrapperForXds(delegate.build(), xdsClient, xdsServingStatusListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ServerBuilder<?> transportBuilder() {
|
public ServerBuilder<?> transportBuilder() {
|
||||||
|
|
@ -99,8 +102,40 @@ public final class XdsServerBuilder extends ForwardingServerBuilder<XdsServerBui
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Watcher to receive error notifications from xDS control plane during {@code start()}. */
|
/** Watcher to receive error notifications from xDS control plane during {@code start()}. */
|
||||||
public interface ErrorNotifier {
|
public interface XdsServingStatusListener {
|
||||||
|
|
||||||
void onError(Status error);
|
/** Callback invoked when server begins serving. */
|
||||||
|
void onServing();
|
||||||
|
|
||||||
|
/** Callback invoked when server is forced to be "not serving" due to an error.
|
||||||
|
* @param throwable cause of the error
|
||||||
|
*/
|
||||||
|
void onNotServing(Throwable throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Default implementation that logs at WARNING level. */
|
||||||
|
private static class DefaultListener implements XdsServingStatusListener {
|
||||||
|
XdsLogger xdsLogger;
|
||||||
|
boolean notServing;
|
||||||
|
|
||||||
|
DefaultListener(String prefix) {
|
||||||
|
xdsLogger = XdsLogger.withPrefix(prefix);
|
||||||
|
notServing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Log calls to onServing() following a call to onNotServing() at WARNING level. */
|
||||||
|
@Override
|
||||||
|
public void onServing() {
|
||||||
|
if (notServing) {
|
||||||
|
notServing = false;
|
||||||
|
xdsLogger.log(XdsLogger.XdsLogLevel.WARNING, "Entering serving state.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNotServing(Throwable throwable) {
|
||||||
|
xdsLogger.log(XdsLogger.XdsLogLevel.WARNING, throwable.getMessage());
|
||||||
|
notServing = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.util.concurrent.SettableFuture;
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
import io.grpc.Server;
|
import io.grpc.Server;
|
||||||
import io.grpc.ServerServiceDefinition;
|
import io.grpc.ServerServiceDefinition;
|
||||||
import io.grpc.Status;
|
|
||||||
import io.grpc.xds.EnvoyServerProtoData;
|
import io.grpc.xds.EnvoyServerProtoData;
|
||||||
import io.grpc.xds.XdsClientWrapperForServerSds;
|
import io.grpc.xds.XdsClientWrapperForServerSds;
|
||||||
import io.grpc.xds.XdsServerBuilder;
|
import io.grpc.xds.XdsServerBuilder;
|
||||||
|
|
@ -45,7 +44,7 @@ import javax.annotation.Nullable;
|
||||||
public final class ServerWrapperForXds extends Server {
|
public final class ServerWrapperForXds extends Server {
|
||||||
private final Server delegate;
|
private final Server delegate;
|
||||||
private final XdsClientWrapperForServerSds xdsClientWrapperForServerSds;
|
private final XdsClientWrapperForServerSds xdsClientWrapperForServerSds;
|
||||||
@Nullable XdsServerBuilder.ErrorNotifier errorNotifier;
|
private XdsServerBuilder.XdsServingStatusListener xdsServingStatusListener;
|
||||||
@Nullable XdsClientWrapperForServerSds.ServerWatcher serverWatcher;
|
@Nullable XdsClientWrapperForServerSds.ServerWatcher serverWatcher;
|
||||||
private AtomicBoolean started = new AtomicBoolean();
|
private AtomicBoolean started = new AtomicBoolean();
|
||||||
|
|
||||||
|
|
@ -53,11 +52,12 @@ public final class ServerWrapperForXds extends Server {
|
||||||
public ServerWrapperForXds(
|
public ServerWrapperForXds(
|
||||||
Server delegate,
|
Server delegate,
|
||||||
XdsClientWrapperForServerSds xdsClientWrapperForServerSds,
|
XdsClientWrapperForServerSds xdsClientWrapperForServerSds,
|
||||||
@Nullable XdsServerBuilder.ErrorNotifier errorNotifier) {
|
XdsServerBuilder.XdsServingStatusListener xdsServingStatusListener) {
|
||||||
this.delegate = checkNotNull(delegate, "delegate");
|
this.delegate = checkNotNull(delegate, "delegate");
|
||||||
this.xdsClientWrapperForServerSds =
|
this.xdsClientWrapperForServerSds =
|
||||||
checkNotNull(xdsClientWrapperForServerSds, "xdsClientWrapperForServerSds");
|
checkNotNull(xdsClientWrapperForServerSds, "xdsClientWrapperForServerSds");
|
||||||
this.errorNotifier = errorNotifier;
|
this.xdsServingStatusListener =
|
||||||
|
checkNotNull(xdsServingStatusListener, "xdsServingStatusListener");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -77,6 +77,7 @@ public final class ServerWrapperForXds extends Server {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
delegate.start();
|
delegate.start();
|
||||||
|
xdsServingStatusListener.onServing();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,15 +87,12 @@ public final class ServerWrapperForXds extends Server {
|
||||||
serverWatcher =
|
serverWatcher =
|
||||||
new XdsClientWrapperForServerSds.ServerWatcher() {
|
new XdsClientWrapperForServerSds.ServerWatcher() {
|
||||||
@Override
|
@Override
|
||||||
public void onError(Status error) {
|
public void onError(Throwable throwable) {
|
||||||
if (errorNotifier != null) {
|
xdsServingStatusListener.onNotServing(throwable);
|
||||||
errorNotifier.onError(error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSuccess(EnvoyServerProtoData.DownstreamTlsContext downstreamTlsContext) {
|
public void onSuccess(EnvoyServerProtoData.DownstreamTlsContext downstreamTlsContext) {
|
||||||
removeServerWatcher();
|
|
||||||
settableFuture.set(downstreamTlsContext);
|
settableFuture.set(downstreamTlsContext);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
|
import io.grpc.StatusException;
|
||||||
import io.grpc.inprocess.InProcessSocketAddress;
|
import io.grpc.inprocess.InProcessSocketAddress;
|
||||||
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
||||||
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
||||||
|
|
@ -171,12 +172,19 @@ public class XdsClientWrapperForServerSdsTestMisc {
|
||||||
mock(XdsClientWrapperForServerSds.ServerWatcher.class);
|
mock(XdsClientWrapperForServerSds.ServerWatcher.class);
|
||||||
xdsClientWrapperForServerSds.addServerWatcher(mockServerWatcher);
|
xdsClientWrapperForServerSds.addServerWatcher(mockServerWatcher);
|
||||||
registeredWatcher.onError(Status.INTERNAL);
|
registeredWatcher.onError(Status.INTERNAL);
|
||||||
verify(mockServerWatcher).onError(eq(Status.INTERNAL));
|
ArgumentCaptor<Throwable> argCaptor = ArgumentCaptor.forClass(null);
|
||||||
|
verify(mockServerWatcher).onError(argCaptor.capture());
|
||||||
|
Throwable throwable = argCaptor.getValue();
|
||||||
|
assertThat(throwable).isInstanceOf(StatusException.class);
|
||||||
|
Status captured = ((StatusException)throwable).getStatus();
|
||||||
|
assertThat(captured.getCode()).isEqualTo(Status.Code.INTERNAL);
|
||||||
reset(mockServerWatcher);
|
reset(mockServerWatcher);
|
||||||
registeredWatcher.onResourceDoesNotExist("not-found Error");
|
registeredWatcher.onResourceDoesNotExist("not-found Error");
|
||||||
ArgumentCaptor<Status> argCaptor = ArgumentCaptor.forClass(null);
|
ArgumentCaptor<Throwable> argCaptor1 = ArgumentCaptor.forClass(null);
|
||||||
verify(mockServerWatcher).onError(argCaptor.capture());
|
verify(mockServerWatcher).onError(argCaptor1.capture());
|
||||||
Status captured = argCaptor.getValue();
|
throwable = argCaptor1.getValue();
|
||||||
|
assertThat(throwable).isInstanceOf(StatusException.class);
|
||||||
|
captured = ((StatusException)throwable).getStatus();
|
||||||
assertThat(captured.getCode()).isEqualTo(Status.Code.NOT_FOUND);
|
assertThat(captured.getCode()).isEqualTo(Status.Code.NOT_FOUND);
|
||||||
assertThat(captured.getDescription()).isEqualTo("not-found Error");
|
assertThat(captured.getDescription()).isEqualTo("not-found Error");
|
||||||
InetAddress ipLocalAddress = InetAddress.getByName("10.1.2.3");
|
InetAddress ipLocalAddress = InetAddress.getByName("10.1.2.3");
|
||||||
|
|
@ -203,14 +211,7 @@ public class XdsClientWrapperForServerSdsTestMisc {
|
||||||
.hasMessageThat()
|
.hasMessageThat()
|
||||||
.contains("Cannot find bootstrap configuration");
|
.contains("Cannot find bootstrap configuration");
|
||||||
}
|
}
|
||||||
ArgumentCaptor<Status> argCaptor = ArgumentCaptor.forClass(null);
|
verify(mockServerWatcher, never()).onError(any(Throwable.class));
|
||||||
verify(mockServerWatcher).onError(argCaptor.capture());
|
|
||||||
Status captured = argCaptor.getValue();
|
|
||||||
assertThat(captured.getCode()).isEqualTo(Status.Code.UNKNOWN);
|
|
||||||
assertThat(captured.getCause()).isInstanceOf(XdsInitializationException.class);
|
|
||||||
assertThat(captured.getCause())
|
|
||||||
.hasMessageThat()
|
|
||||||
.contains("Cannot find bootstrap configuration");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DownstreamTlsContext sendListenerUpdate(
|
private DownstreamTlsContext sendListenerUpdate(
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import static org.mockito.Mockito.verify;
|
||||||
import com.google.common.util.concurrent.SettableFuture;
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
import io.grpc.InsecureServerCredentials;
|
import io.grpc.InsecureServerCredentials;
|
||||||
import io.grpc.Status;
|
import io.grpc.Status;
|
||||||
|
import io.grpc.StatusException;
|
||||||
import io.grpc.testing.GrpcCleanupRule;
|
import io.grpc.testing.GrpcCleanupRule;
|
||||||
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
||||||
import io.grpc.xds.internal.sds.ServerWrapperForXds;
|
import io.grpc.xds.internal.sds.ServerWrapperForXds;
|
||||||
|
|
@ -62,14 +63,15 @@ public class XdsServerBuilderTest {
|
||||||
private XdsClientWrapperForServerSds xdsClientWrapperForServerSds;
|
private XdsClientWrapperForServerSds xdsClientWrapperForServerSds;
|
||||||
|
|
||||||
private XdsServerBuilder buildServer(
|
private XdsServerBuilder buildServer(
|
||||||
XdsServerBuilder.ErrorNotifier errorNotifier, boolean injectMockXdsClient)
|
XdsServerBuilder.XdsServingStatusListener xdsServingStatusListener,
|
||||||
|
boolean injectMockXdsClient)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
port = XdsServerTestHelper.findFreePort();
|
port = XdsServerTestHelper.findFreePort();
|
||||||
XdsServerBuilder builder =
|
XdsServerBuilder builder =
|
||||||
XdsServerBuilder.forPort(
|
XdsServerBuilder.forPort(
|
||||||
port, XdsServerCredentials.create(InsecureServerCredentials.create()));
|
port, XdsServerCredentials.create(InsecureServerCredentials.create()));
|
||||||
if (errorNotifier != null) {
|
if (xdsServingStatusListener != null) {
|
||||||
builder = builder.errorNotifier(errorNotifier);
|
builder = builder.xdsServingStatusListener(xdsServingStatusListener);
|
||||||
}
|
}
|
||||||
xdsClientWrapperForServerSds = new XdsClientWrapperForServerSds(port);
|
xdsClientWrapperForServerSds = new XdsClientWrapperForServerSds(port);
|
||||||
if (injectMockXdsClient) {
|
if (injectMockXdsClient) {
|
||||||
|
|
@ -82,7 +84,9 @@ public class XdsServerBuilderTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyServer(
|
private void verifyServer(
|
||||||
Future<Throwable> future, XdsServerBuilder.ErrorNotifier mockErrorNotifier)
|
Future<Throwable> future,
|
||||||
|
XdsServerBuilder.XdsServingStatusListener mockXdsServingStatusListener,
|
||||||
|
Status notServingStatus)
|
||||||
throws InterruptedException, ExecutionException, TimeoutException {
|
throws InterruptedException, ExecutionException, TimeoutException {
|
||||||
if (future != null) {
|
if (future != null) {
|
||||||
Throwable exception = future.get(5, TimeUnit.SECONDS);
|
Throwable exception = future.get(5, TimeUnit.SECONDS);
|
||||||
|
|
@ -93,10 +97,18 @@ public class XdsServerBuilderTest {
|
||||||
InetSocketAddress socketAddress = (InetSocketAddress) list.get(0);
|
InetSocketAddress socketAddress = (InetSocketAddress) list.get(0);
|
||||||
assertThat(socketAddress.getAddress().isAnyLocalAddress()).isTrue();
|
assertThat(socketAddress.getAddress().isAnyLocalAddress()).isTrue();
|
||||||
assertThat(socketAddress.getPort()).isEqualTo(port);
|
assertThat(socketAddress.getPort()).isEqualTo(port);
|
||||||
if (mockErrorNotifier != null) {
|
if (mockXdsServingStatusListener != null) {
|
||||||
verify(mockErrorNotifier, never()).onError(any(Status.class));
|
if (notServingStatus != null) {
|
||||||
|
ArgumentCaptor<Throwable> argCaptor = ArgumentCaptor.forClass(null);
|
||||||
|
verify(mockXdsServingStatusListener, times(1)).onNotServing(argCaptor.capture());
|
||||||
|
Throwable throwable = argCaptor.getValue();
|
||||||
|
assertThat(throwable).isInstanceOf(StatusException.class);
|
||||||
|
assertThat(((StatusException) throwable).getStatus()).isEqualTo(notServingStatus);
|
||||||
|
} else {
|
||||||
|
verify(mockXdsServingStatusListener, never()).onNotServing(any(Throwable.class));
|
||||||
|
verify(mockXdsServingStatusListener, times(1)).onServing();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
assertThat(xdsClientWrapperForServerSds.serverWatchers).isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyShutdown() throws InterruptedException {
|
private void verifyShutdown() throws InterruptedException {
|
||||||
|
|
@ -135,7 +147,7 @@ public class XdsServerBuilderTest {
|
||||||
port,
|
port,
|
||||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
||||||
null);
|
null);
|
||||||
verifyServer(future, null);
|
verifyServer(future, null, null);
|
||||||
verifyShutdown();
|
verifyShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,125 +167,128 @@ public class XdsServerBuilderTest {
|
||||||
} catch (IllegalStateException expected) {
|
} catch (IllegalStateException expected) {
|
||||||
assertThat(expected).hasMessageThat().contains("Already started");
|
assertThat(expected).hasMessageThat().contains("Already started");
|
||||||
}
|
}
|
||||||
verifyServer(null,null);
|
verifyServer(null,null, null);
|
||||||
verifyShutdown();
|
verifyShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void xdsServerStartAndShutdownWithErrorNotifier()
|
public void xdsServerStartAndShutdownWithXdsServingStatusListener()
|
||||||
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
||||||
XdsServerBuilder.ErrorNotifier mockErrorNotifier = mock(XdsServerBuilder.ErrorNotifier.class);
|
XdsServerBuilder.XdsServingStatusListener mockXdsServingStatusListener =
|
||||||
buildServer(mockErrorNotifier, true);
|
mock(XdsServerBuilder.XdsServingStatusListener.class);
|
||||||
|
buildServer(mockXdsServingStatusListener, true);
|
||||||
Future<Throwable> future = startServerAsync();
|
Future<Throwable> future = startServerAsync();
|
||||||
XdsServerTestHelper.generateListenerUpdate(
|
XdsServerTestHelper.generateListenerUpdate(
|
||||||
listenerWatcher,
|
listenerWatcher,
|
||||||
port,
|
port,
|
||||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
||||||
null);
|
null);
|
||||||
verifyServer(future, mockErrorNotifier);
|
verifyServer(future, mockXdsServingStatusListener, null);
|
||||||
verifyShutdown();
|
verifyShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void xdsServer_serverWatcher()
|
public void xdsServer_serverWatcher()
|
||||||
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
||||||
XdsServerBuilder.ErrorNotifier mockErrorNotifier = mock(XdsServerBuilder.ErrorNotifier.class);
|
XdsServerBuilder.XdsServingStatusListener mockXdsServingStatusListener =
|
||||||
buildServer(mockErrorNotifier, true);
|
mock(XdsServerBuilder.XdsServingStatusListener.class);
|
||||||
|
buildServer(mockXdsServingStatusListener, true);
|
||||||
Future<Throwable> future = startServerAsync();
|
Future<Throwable> future = startServerAsync();
|
||||||
listenerWatcher.onError(Status.ABORTED);
|
listenerWatcher.onError(Status.ABORTED);
|
||||||
verify(mockErrorNotifier).onError(Status.ABORTED);
|
ArgumentCaptor<Throwable> argCaptor = ArgumentCaptor.forClass(null);
|
||||||
|
verify(mockXdsServingStatusListener).onNotServing(argCaptor.capture());
|
||||||
|
Throwable throwable = argCaptor.getValue();
|
||||||
|
assertThat(throwable).isInstanceOf(StatusException.class);
|
||||||
|
Status captured = ((StatusException) throwable).getStatus();
|
||||||
|
assertThat(captured.getCode()).isEqualTo(Status.Code.ABORTED);
|
||||||
assertThat(xdsClientWrapperForServerSds.serverWatchers).hasSize(1);
|
assertThat(xdsClientWrapperForServerSds.serverWatchers).hasSize(1);
|
||||||
assertThat(future.isDone()).isFalse();
|
assertThat(future.isDone()).isFalse();
|
||||||
reset(mockErrorNotifier);
|
reset(mockXdsServingStatusListener);
|
||||||
listenerWatcher.onResourceDoesNotExist("not found error");
|
listenerWatcher.onResourceDoesNotExist("not found error");
|
||||||
ArgumentCaptor<Status> argCaptor = ArgumentCaptor.forClass(null);
|
argCaptor = ArgumentCaptor.forClass(null);
|
||||||
verify(mockErrorNotifier).onError(argCaptor.capture());
|
verify(mockXdsServingStatusListener).onNotServing(argCaptor.capture());
|
||||||
Status captured = argCaptor.getValue();
|
throwable = argCaptor.getValue();
|
||||||
|
assertThat(throwable).isInstanceOf(StatusException.class);
|
||||||
|
captured = ((StatusException) throwable).getStatus();
|
||||||
assertThat(captured.getCode()).isEqualTo(Status.Code.NOT_FOUND);
|
assertThat(captured.getCode()).isEqualTo(Status.Code.NOT_FOUND);
|
||||||
assertThat(captured.getDescription()).isEqualTo("not found error");
|
assertThat(captured.getDescription()).isEqualTo("not found error");
|
||||||
assertThat(xdsClientWrapperForServerSds.serverWatchers).hasSize(1);
|
assertThat(xdsClientWrapperForServerSds.serverWatchers).hasSize(1);
|
||||||
assertThat(future.isDone()).isFalse();
|
assertThat(future.isDone()).isFalse();
|
||||||
reset(mockErrorNotifier);
|
reset(mockXdsServingStatusListener);
|
||||||
XdsServerTestHelper.generateListenerUpdate(
|
XdsServerTestHelper.generateListenerUpdate(
|
||||||
listenerWatcher,
|
listenerWatcher,
|
||||||
port,
|
port,
|
||||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
||||||
null);
|
null);
|
||||||
verifyServer(future, mockErrorNotifier);
|
verifyServer(future, mockXdsServingStatusListener, null);
|
||||||
verifyShutdown();
|
verifyShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void xdsServer_startError()
|
public void xdsServer_startError()
|
||||||
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
||||||
XdsServerBuilder.ErrorNotifier mockErrorNotifier = mock(XdsServerBuilder.ErrorNotifier.class);
|
XdsServerBuilder.XdsServingStatusListener mockXdsServingStatusListener =
|
||||||
buildServer(mockErrorNotifier, true);
|
mock(XdsServerBuilder.XdsServingStatusListener.class);
|
||||||
|
buildServer(mockXdsServingStatusListener, true);
|
||||||
Future<Throwable> future = startServerAsync();
|
Future<Throwable> future = startServerAsync();
|
||||||
// create port conflict for start to fail
|
// create port conflict for start to fail
|
||||||
ServerSocket serverSocket = new ServerSocket(port);
|
ServerSocket serverSocket = new ServerSocket(port);
|
||||||
XdsServerTestHelper.generateListenerUpdate(
|
XdsServerTestHelper.generateListenerUpdate(
|
||||||
listenerWatcher,
|
listenerWatcher,
|
||||||
port,
|
port,
|
||||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
||||||
null);
|
null);
|
||||||
Throwable exception = future.get(5, TimeUnit.SECONDS);
|
Throwable exception = future.get(5, TimeUnit.SECONDS);
|
||||||
assertThat(exception).isInstanceOf(IOException.class);
|
assertThat(exception).isInstanceOf(IOException.class);
|
||||||
assertThat(exception).hasMessageThat().contains("Failed to bind");
|
assertThat(exception).hasMessageThat().contains("Failed to bind");
|
||||||
verify(mockErrorNotifier, never()).onError(any(Status.class));
|
verify(mockXdsServingStatusListener, never()).onNotServing(any(Throwable.class));
|
||||||
serverSocket.close();
|
serverSocket.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void xdsServerWithoutMockXdsClient_startError()
|
public void xdsServerWithoutMockXdsClient_startError()
|
||||||
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
||||||
XdsServerBuilder.ErrorNotifier mockErrorNotifier = mock(XdsServerBuilder.ErrorNotifier.class);
|
XdsServerBuilder.XdsServingStatusListener mockXdsServingStatusListener =
|
||||||
buildServer(mockErrorNotifier, false);
|
mock(XdsServerBuilder.XdsServingStatusListener.class);
|
||||||
|
buildServer(mockXdsServingStatusListener, false);
|
||||||
try {
|
try {
|
||||||
xdsServer.start();
|
xdsServer.start();
|
||||||
fail("exception expected");
|
fail("exception expected");
|
||||||
} catch (IOException expected) {
|
} catch (IOException expected) {
|
||||||
assertThat(expected)
|
assertThat(expected).hasMessageThat().contains("Cannot find bootstrap configuration");
|
||||||
.hasMessageThat()
|
|
||||||
.contains("Cannot find bootstrap configuration");
|
|
||||||
}
|
}
|
||||||
ArgumentCaptor<Status> argCaptor = ArgumentCaptor.forClass(null);
|
verify(mockXdsServingStatusListener, never()).onNotServing(any(Throwable.class));
|
||||||
verify(mockErrorNotifier).onError(argCaptor.capture());
|
|
||||||
Status captured = argCaptor.getValue();
|
|
||||||
assertThat(captured.getCode()).isEqualTo(Status.Code.UNKNOWN);
|
|
||||||
assertThat(captured.getCause()).isInstanceOf(XdsInitializationException.class);
|
|
||||||
assertThat(captured.getCause())
|
|
||||||
.hasMessageThat()
|
|
||||||
.contains("Cannot find bootstrap configuration");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void xdsServerStartSecondUpdateAndError()
|
public void xdsServerStartSecondUpdateAndError()
|
||||||
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
throws IOException, InterruptedException, TimeoutException, ExecutionException {
|
||||||
XdsServerBuilder.ErrorNotifier mockErrorNotifier = mock(XdsServerBuilder.ErrorNotifier.class);
|
XdsServerBuilder.XdsServingStatusListener mockXdsServingStatusListener =
|
||||||
buildServer(mockErrorNotifier, true);
|
mock(XdsServerBuilder.XdsServingStatusListener.class);
|
||||||
|
buildServer(mockXdsServingStatusListener, true);
|
||||||
Future<Throwable> future = startServerAsync();
|
Future<Throwable> future = startServerAsync();
|
||||||
XdsServerTestHelper.generateListenerUpdate(
|
XdsServerTestHelper.generateListenerUpdate(
|
||||||
listenerWatcher,
|
listenerWatcher,
|
||||||
port,
|
port,
|
||||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
||||||
null);
|
null);
|
||||||
XdsServerTestHelper.generateListenerUpdate(
|
XdsServerTestHelper.generateListenerUpdate(
|
||||||
listenerWatcher,
|
listenerWatcher,
|
||||||
port,
|
port,
|
||||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1"),
|
||||||
null);
|
null);
|
||||||
verify(mockErrorNotifier, never()).onError(any(Status.class));
|
verify(mockXdsServingStatusListener, never()).onNotServing(any(Throwable.class));
|
||||||
verifyServer(future, mockErrorNotifier);
|
verifyServer(future, mockXdsServingStatusListener, null);
|
||||||
listenerWatcher.onError(Status.ABORTED);
|
listenerWatcher.onError(Status.ABORTED);
|
||||||
verify(mockErrorNotifier, never()).onError(any(Status.class));
|
verifyServer(null, mockXdsServingStatusListener, Status.ABORTED);
|
||||||
verifyServer(null, mockErrorNotifier);
|
|
||||||
verifyShutdown();
|
verifyShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void xdsServer_2ndBuild_expectException() throws IOException {
|
public void xdsServer_2ndBuild_expectException() throws IOException {
|
||||||
XdsServerBuilder.ErrorNotifier mockErrorNotifier = mock(XdsServerBuilder.ErrorNotifier.class);
|
XdsServerBuilder.XdsServingStatusListener mockXdsServingStatusListener =
|
||||||
XdsServerBuilder builder = buildServer(mockErrorNotifier, true);
|
mock(XdsServerBuilder.XdsServingStatusListener.class);
|
||||||
|
XdsServerBuilder builder = buildServer(mockXdsServingStatusListener, true);
|
||||||
try {
|
try {
|
||||||
builder.build();
|
builder.build();
|
||||||
fail("exception expected");
|
fail("exception expected");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue