diff --git a/xds/src/main/java/io/grpc/xds/AbstractXdsClient.java b/xds/src/main/java/io/grpc/xds/AbstractXdsClient.java index f949525925..b6bbaf797a 100644 --- a/xds/src/main/java/io/grpc/xds/AbstractXdsClient.java +++ b/xds/src/main/java/io/grpc/xds/AbstractXdsClient.java @@ -24,16 +24,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Stopwatch; import com.google.common.base.Supplier; import com.google.protobuf.Any; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.MessageOrBuilder; -import com.google.protobuf.TypeRegistry; -import com.google.protobuf.util.JsonFormat; import com.google.rpc.Code; -import io.envoyproxy.envoy.config.cluster.v3.Cluster; -import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; -import io.envoyproxy.envoy.config.listener.v3.Listener; -import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; -import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager; import io.envoyproxy.envoy.service.discovery.v3.AggregatedDiscoveryServiceGrpc; import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; @@ -717,44 +708,4 @@ abstract class AbstractXdsClient extends XdsClient { requestWriter.onError(error); } } - - /** - * Convert protobuf message to human readable String format. Useful for protobuf messages - * containing {@link com.google.protobuf.Any} fields. - */ - @VisibleForTesting - static final class MessagePrinter { - private final JsonFormat.Printer printer; - - @VisibleForTesting - MessagePrinter() { - TypeRegistry registry = - TypeRegistry.newBuilder() - .add(Listener.getDescriptor()) - .add(io.envoyproxy.envoy.api.v2.Listener.getDescriptor()) - .add(HttpConnectionManager.getDescriptor()) - .add( - io.envoyproxy.envoy.config.filter.network.http_connection_manager.v2 - .HttpConnectionManager.getDescriptor()) - .add(RouteConfiguration.getDescriptor()) - .add(io.envoyproxy.envoy.api.v2.RouteConfiguration.getDescriptor()) - .add(Cluster.getDescriptor()) - .add(io.envoyproxy.envoy.api.v2.Cluster.getDescriptor()) - .add(ClusterLoadAssignment.getDescriptor()) - .add(io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.getDescriptor()) - .build(); - printer = JsonFormat.printer().usingTypeRegistry(registry); - } - - @VisibleForTesting - String print(MessageOrBuilder message) { - String res; - try { - res = printer.print(message); - } catch (InvalidProtocolBufferException e) { - res = message + " (failed to pretty-print: " + e + ")"; - } - return res; - } - } } diff --git a/xds/src/main/java/io/grpc/xds/MessagePrinter.java b/xds/src/main/java/io/grpc/xds/MessagePrinter.java new file mode 100644 index 0000000000..bc738eed52 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/MessagePrinter.java @@ -0,0 +1,69 @@ +/* + * Copyright 2020 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.xds; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.MessageOrBuilder; +import com.google.protobuf.TypeRegistry; +import com.google.protobuf.util.JsonFormat; +import io.envoyproxy.envoy.config.cluster.v3.Cluster; +import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; +import io.envoyproxy.envoy.config.listener.v3.Listener; +import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; +import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager; +import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext; +import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext; + +/** + * Converts protobuf message to human readable String format. Useful for protobuf messages + * containing {@link com.google.protobuf.Any} fields. + */ +final class MessagePrinter { + private final JsonFormat.Printer printer; + + MessagePrinter() { + TypeRegistry registry = + TypeRegistry.newBuilder() + .add(Listener.getDescriptor()) + .add(io.envoyproxy.envoy.api.v2.Listener.getDescriptor()) + .add(HttpConnectionManager.getDescriptor()) + .add(io.envoyproxy.envoy.config.filter.network.http_connection_manager.v2 + .HttpConnectionManager.getDescriptor()) + // UpstreamTlsContext and DownstreamTlsContext in v3 are not transitively imported + // by top-level resource types. + .add(UpstreamTlsContext.getDescriptor()) + .add(DownstreamTlsContext.getDescriptor()) + .add(RouteConfiguration.getDescriptor()) + .add(io.envoyproxy.envoy.api.v2.RouteConfiguration.getDescriptor()) + .add(Cluster.getDescriptor()) + .add(io.envoyproxy.envoy.api.v2.Cluster.getDescriptor()) + .add(ClusterLoadAssignment.getDescriptor()) + .add(io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.getDescriptor()) + .build(); + printer = JsonFormat.printer().usingTypeRegistry(registry); + } + + String print(MessageOrBuilder message) { + String res; + try { + res = printer.print(message); + } catch (InvalidProtocolBufferException e) { + res = message + " (failed to pretty-print: " + e + ")"; + } + return res; + } +} diff --git a/xds/src/test/java/io/grpc/xds/AbstractXdsClientTest.java b/xds/src/test/java/io/grpc/xds/AbstractXdsClientTest.java deleted file mode 100644 index 054a932c76..0000000000 --- a/xds/src/test/java/io/grpc/xds/AbstractXdsClientTest.java +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright 2020 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.xds; - -import static com.google.common.truth.Truth.assertThat; -import static io.grpc.xds.XdsClientTestHelper.buildCluster; -import static io.grpc.xds.XdsClientTestHelper.buildClusterLoadAssignment; -import static io.grpc.xds.XdsClientTestHelper.buildDiscoveryResponse; -import static io.grpc.xds.XdsClientTestHelper.buildDropOverload; -import static io.grpc.xds.XdsClientTestHelper.buildLbEndpoint; -import static io.grpc.xds.XdsClientTestHelper.buildListener; -import static io.grpc.xds.XdsClientTestHelper.buildLocalityLbEndpoints; -import static io.grpc.xds.XdsClientTestHelper.buildRouteConfiguration; -import static io.grpc.xds.XdsClientTestHelper.buildVirtualHost; - -import com.google.common.collect.ImmutableList; -import com.google.protobuf.Any; -import io.envoyproxy.envoy.config.core.v3.HealthStatus; -import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager; -import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; -import io.grpc.xds.AbstractXdsClient.MessagePrinter; -import io.grpc.xds.AbstractXdsClient.ResourceType; -import java.util.List; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Tests for {@link AbstractXdsClient}. - */ -@RunWith(JUnit4.class) -public class AbstractXdsClientTest { - - @Test - public void messagePrinter_printLdsResponse() { - MessagePrinter printer = new MessagePrinter(); - List listeners = ImmutableList.of( - Any.pack(buildListener("foo.googleapis.com:8080", - Any.pack( - HttpConnectionManager.newBuilder() - .setRouteConfig( - buildRouteConfiguration("route-foo.googleapis.com", - ImmutableList.of( - buildVirtualHost( - ImmutableList.of("foo.googleapis.com", "bar.googleapis.com"), - "cluster.googleapis.com")))) - .build())))); - DiscoveryResponse response = - buildDiscoveryResponse("0", listeners, ResourceType.LDS.typeUrl(), "0000"); - - String expectedString = "{\n" - + " \"versionInfo\": \"0\",\n" - + " \"resources\": [{\n" - + " \"@type\": \"type.googleapis.com/envoy.config.listener.v3.Listener\",\n" - + " \"name\": \"foo.googleapis.com:8080\",\n" - + " \"address\": {\n" - + " },\n" - + " \"filterChains\": [{\n" - + " }],\n" - + " \"apiListener\": {\n" - + " \"apiListener\": {\n" - + " \"@type\": \"type.googleapis.com/envoy.extensions.filters.network" - + ".http_connection_manager.v3.HttpConnectionManager\",\n" - + " \"routeConfig\": {\n" - + " \"name\": \"route-foo.googleapis.com\",\n" - + " \"virtualHosts\": [{\n" - + " \"name\": \"virtualhost00.googleapis.com\",\n" - + " \"domains\": [\"foo.googleapis.com\", \"bar.googleapis.com\"],\n" - + " \"routes\": [{\n" - + " \"match\": {\n" - + " \"prefix\": \"\"\n" - + " },\n" - + " \"route\": {\n" - + " \"cluster\": \"cluster.googleapis.com\"\n" - + " }\n" - + " }]\n" - + " }]\n" - + " }\n" - + " }\n" - + " }\n" - + " }],\n" - + " \"typeUrl\": \"type.googleapis.com/envoy.config.listener.v3.Listener\",\n" - + " \"nonce\": \"0000\"\n" - + "}"; - String res = printer.print(response); - assertThat(res).isEqualTo(expectedString); - } - - @Test - public void messagePrinter_printRdsResponse() { - MessagePrinter printer = new MessagePrinter(); - List routeConfigs = - ImmutableList.of( - Any.pack( - buildRouteConfiguration( - "route-foo.googleapis.com", - ImmutableList.of( - buildVirtualHost( - ImmutableList.of("foo.googleapis.com", "bar.googleapis.com"), - "cluster.googleapis.com"))))); - DiscoveryResponse response = - buildDiscoveryResponse("213", routeConfigs, ResourceType.RDS.typeUrl(), "0052"); - - String expectedString = "{\n" - + " \"versionInfo\": \"213\",\n" - + " \"resources\": [{\n" - + " \"@type\": \"type.googleapis.com/envoy.config.route.v3.RouteConfiguration\",\n" - + " \"name\": \"route-foo.googleapis.com\",\n" - + " \"virtualHosts\": [{\n" - + " \"name\": \"virtualhost00.googleapis.com\",\n" - + " \"domains\": [\"foo.googleapis.com\", \"bar.googleapis.com\"],\n" - + " \"routes\": [{\n" - + " \"match\": {\n" - + " \"prefix\": \"\"\n" - + " },\n" - + " \"route\": {\n" - + " \"cluster\": \"cluster.googleapis.com\"\n" - + " }\n" - + " }]\n" - + " }]\n" - + " }],\n" - + " \"typeUrl\": \"type.googleapis.com/envoy.config.route.v3.RouteConfiguration\",\n" - + " \"nonce\": \"0052\"\n" - + "}"; - String res = printer.print(response); - assertThat(res).isEqualTo(expectedString); - } - - @Test - public void messagePrinter_printCdsResponse() { - MessagePrinter printer = new MessagePrinter(); - List clusters = ImmutableList.of( - Any.pack(buildCluster("cluster-bar.googleapis.com", "service-blaze:cluster-bar", true)), - Any.pack(buildCluster("cluster-foo.googleapis.com", null, false))); - DiscoveryResponse response = - buildDiscoveryResponse("14", clusters, ResourceType.CDS.typeUrl(), "8"); - - String expectedString = "{\n" - + " \"versionInfo\": \"14\",\n" - + " \"resources\": [{\n" - + " \"@type\": \"type.googleapis.com/envoy.config.cluster.v3.Cluster\",\n" - + " \"name\": \"cluster-bar.googleapis.com\",\n" - + " \"type\": \"EDS\",\n" - + " \"edsClusterConfig\": {\n" - + " \"edsConfig\": {\n" - + " \"ads\": {\n" - + " }\n" - + " },\n" - + " \"serviceName\": \"service-blaze:cluster-bar\"\n" - + " },\n" - + " \"lrsServer\": {\n" - + " \"self\": {\n" - + " }\n" - + " }\n" - + " }, {\n" - + " \"@type\": \"type.googleapis.com/envoy.config.cluster.v3.Cluster\",\n" - + " \"name\": \"cluster-foo.googleapis.com\",\n" - + " \"type\": \"EDS\",\n" - + " \"edsClusterConfig\": {\n" - + " \"edsConfig\": {\n" - + " \"ads\": {\n" - + " }\n" - + " }\n" - + " }\n" - + " }],\n" - + " \"typeUrl\": \"type.googleapis.com/envoy.config.cluster.v3.Cluster\",\n" - + " \"nonce\": \"8\"\n" - + "}"; - String res = printer.print(response); - assertThat(res).isEqualTo(expectedString); - } - - @Test - public void messagePrinter_printEdsResponse() { - MessagePrinter printer = new MessagePrinter(); - List clusterLoadAssignments = ImmutableList.of( - Any.pack(buildClusterLoadAssignment("cluster-foo.googleapis.com", - ImmutableList.of( - buildLocalityLbEndpoints("region1", "zone1", "subzone1", - ImmutableList.of( - buildLbEndpoint("192.168.0.1", 8080, HealthStatus.HEALTHY, 2)), - 1, 0), - buildLocalityLbEndpoints("region3", "zone3", "subzone3", - ImmutableList.of( - buildLbEndpoint("192.168.142.5", 80, HealthStatus.UNHEALTHY, 5)), - 2, 1)), - ImmutableList.of( - buildDropOverload("lb", 200), - buildDropOverload("throttle", 1000))))); - - DiscoveryResponse response = - buildDiscoveryResponse("5", clusterLoadAssignments, - ResourceType.EDS.typeUrl(), "004"); - - String expectedString = "{\n" - + " \"versionInfo\": \"5\",\n" - + " \"resources\": [{\n" - + " \"@type\": \"type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment\",\n" - + " \"clusterName\": \"cluster-foo.googleapis.com\",\n" - + " \"endpoints\": [{\n" - + " \"locality\": {\n" - + " \"region\": \"region1\",\n" - + " \"zone\": \"zone1\",\n" - + " \"subZone\": \"subzone1\"\n" - + " },\n" - + " \"lbEndpoints\": [{\n" - + " \"endpoint\": {\n" - + " \"address\": {\n" - + " \"socketAddress\": {\n" - + " \"address\": \"192.168.0.1\",\n" - + " \"portValue\": 8080\n" - + " }\n" - + " }\n" - + " },\n" - + " \"healthStatus\": \"HEALTHY\",\n" - + " \"loadBalancingWeight\": 2\n" - + " }],\n" - + " \"loadBalancingWeight\": 1\n" - + " }, {\n" - + " \"locality\": {\n" - + " \"region\": \"region3\",\n" - + " \"zone\": \"zone3\",\n" - + " \"subZone\": \"subzone3\"\n" - + " },\n" - + " \"lbEndpoints\": [{\n" - + " \"endpoint\": {\n" - + " \"address\": {\n" - + " \"socketAddress\": {\n" - + " \"address\": \"192.168.142.5\",\n" - + " \"portValue\": 80\n" - + " }\n" - + " }\n" - + " },\n" - + " \"healthStatus\": \"UNHEALTHY\",\n" - + " \"loadBalancingWeight\": 5\n" - + " }],\n" - + " \"loadBalancingWeight\": 2,\n" - + " \"priority\": 1\n" - + " }],\n" - + " \"policy\": {\n" - + " \"dropOverloads\": [{\n" - + " \"category\": \"lb\",\n" - + " \"dropPercentage\": {\n" - + " \"numerator\": 200,\n" - + " \"denominator\": \"MILLION\"\n" - + " }\n" - + " }, {\n" - + " \"category\": \"throttle\",\n" - + " \"dropPercentage\": {\n" - + " \"numerator\": 1000,\n" - + " \"denominator\": \"MILLION\"\n" - + " }\n" - + " }]\n" - + " }\n" - + " }],\n" - + " \"typeUrl\": \"type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment\",\n" - + " \"nonce\": \"004\"\n" - + "}"; - String res = printer.print(response); - assertThat(res).isEqualTo(expectedString); - } -} diff --git a/xds/src/test/java/io/grpc/xds/MessagePrinterTest.java b/xds/src/test/java/io/grpc/xds/MessagePrinterTest.java new file mode 100644 index 0000000000..bb6c5517ab --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/MessagePrinterTest.java @@ -0,0 +1,362 @@ +/* + * Copyright 2020 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.xds; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.protobuf.Any; +import com.google.protobuf.UInt32Value; +import io.envoyproxy.envoy.config.cluster.v3.Cluster; +import io.envoyproxy.envoy.config.cluster.v3.Cluster.EdsClusterConfig; +import io.envoyproxy.envoy.config.cluster.v3.Cluster.LbPolicy; +import io.envoyproxy.envoy.config.core.v3.Address; +import io.envoyproxy.envoy.config.core.v3.AggregatedConfigSource; +import io.envoyproxy.envoy.config.core.v3.ConfigSource; +import io.envoyproxy.envoy.config.core.v3.HealthStatus; +import io.envoyproxy.envoy.config.core.v3.Locality; +import io.envoyproxy.envoy.config.core.v3.SelfConfigSource; +import io.envoyproxy.envoy.config.core.v3.SocketAddress; +import io.envoyproxy.envoy.config.core.v3.TransportSocket; +import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; +import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment.Policy; +import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment.Policy.DropOverload; +import io.envoyproxy.envoy.config.endpoint.v3.Endpoint; +import io.envoyproxy.envoy.config.endpoint.v3.LbEndpoint; +import io.envoyproxy.envoy.config.endpoint.v3.LocalityLbEndpoints; +import io.envoyproxy.envoy.config.listener.v3.ApiListener; +import io.envoyproxy.envoy.config.listener.v3.Filter; +import io.envoyproxy.envoy.config.listener.v3.FilterChain; +import io.envoyproxy.envoy.config.listener.v3.Listener; +import io.envoyproxy.envoy.config.route.v3.Route; +import io.envoyproxy.envoy.config.route.v3.RouteAction; +import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; +import io.envoyproxy.envoy.config.route.v3.RouteMatch; +import io.envoyproxy.envoy.config.route.v3.VirtualHost; +import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager; +import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.Rds; +import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext; +import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext; +import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.SdsSecretConfig; +import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext; +import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; +import io.envoyproxy.envoy.type.v3.FractionalPercent; +import io.envoyproxy.envoy.type.v3.FractionalPercent.DenominatorType; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for {@link MessagePrinter}. + */ +@RunWith(JUnit4.class) +public class MessagePrinterTest { + private final MessagePrinter printer = new MessagePrinter(); + + @Test + public void printLdsResponse_v3() { + Listener listener = + Listener.newBuilder().setName("foo.googleapis.com:8080") + .setAddress( + Address.newBuilder() + .setSocketAddress( + SocketAddress.newBuilder().setAddress("10.0.0.1").setPortValue(8080))) + .addFilterChains( + FilterChain.newBuilder() + .addFilters(Filter.getDefaultInstance()) + .setTransportSocket( + TransportSocket.newBuilder() + .setName("envoy.transport_sockets.tls") + .setTypedConfig( + Any.pack( + DownstreamTlsContext.newBuilder() + .setCommonTlsContext( + CommonTlsContext.newBuilder() + .addTlsCertificateSdsSecretConfigs( + SdsSecretConfig.getDefaultInstance())) + .build())))) + .setApiListener( + ApiListener.newBuilder() + .setApiListener( + Any.pack(HttpConnectionManager.newBuilder() + .setRds( + Rds.newBuilder() + .setRouteConfigName("route-foo.googleapis.com") + .setConfigSource( + ConfigSource.newBuilder().setAds( + AggregatedConfigSource.getDefaultInstance()))) + .build()))) + .build(); + DiscoveryResponse response = + DiscoveryResponse.newBuilder() + .setTypeUrl("type.googleapis.com/envoy.config.listener.v3.Listener") + .setVersionInfo("0") + .addResources(Any.pack(listener)) + .setNonce("0000") + .build(); + + String expectedString = "{\n" + + " \"versionInfo\": \"0\",\n" + + " \"resources\": [{\n" + + " \"@type\": \"type.googleapis.com/envoy.config.listener.v3.Listener\",\n" + + " \"name\": \"foo.googleapis.com:8080\",\n" + + " \"address\": {\n" + + " \"socketAddress\": {\n" + + " \"address\": \"10.0.0.1\",\n" + + " \"portValue\": 8080\n" + + " }\n" + + " },\n" + + " \"filterChains\": [{\n" + + " \"filters\": [{\n" + + " }],\n" + + " \"transportSocket\": {\n" + + " \"name\": \"envoy.transport_sockets.tls\",\n" + + " \"typedConfig\": {\n" + + " \"@type\": \"type.googleapis.com/envoy.extensions.transport_sockets" + + ".tls.v3.DownstreamTlsContext\",\n" + + " \"commonTlsContext\": {\n" + + " \"tlsCertificateSdsSecretConfigs\": [{\n" + + " }]\n" + + " }\n" + + " }\n" + + " }\n" + + " }],\n" + + " \"apiListener\": {\n" + + " \"apiListener\": {\n" + + " \"@type\": \"type.googleapis.com/envoy.extensions.filters.network" + + ".http_connection_manager.v3.HttpConnectionManager\",\n" + + " \"rds\": {\n" + + " \"configSource\": {\n" + + " \"ads\": {\n" + + " }\n" + + " },\n" + + " \"routeConfigName\": \"route-foo.googleapis.com\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }],\n" + + " \"typeUrl\": \"type.googleapis.com/envoy.config.listener.v3.Listener\",\n" + + " \"nonce\": \"0000\"\n" + + "}"; + String res = printer.print(response); + assertThat(res).isEqualTo(expectedString); + } + + @Test + public void printRdsResponse_v3() { + RouteConfiguration routeConfiguration = + RouteConfiguration.newBuilder() + .setName("route-foo.googleapis.com") + .addVirtualHosts( + VirtualHost.newBuilder() + .setName("virtualhost.googleapis.com") + .addDomains("foo.googleapis.com") + .addDomains("bar.googleapis.com") + .addRoutes( + Route.newBuilder() + .setMatch( + RouteMatch.newBuilder().setPath("foo.googleapis.com")) + .setRoute( + RouteAction.newBuilder() + .setCluster("cluster.googleapis.com")))) + .build(); + DiscoveryResponse response = + DiscoveryResponse.newBuilder() + .setTypeUrl("type.googleapis.com/envoy.config.route.v3.RouteConfiguration") + .setVersionInfo("0") + .addResources(Any.pack(routeConfiguration)) + .setNonce("0000") + .build(); + + String expectedString = "{\n" + + " \"versionInfo\": \"0\",\n" + + " \"resources\": [{\n" + + " \"@type\": \"type.googleapis.com/envoy.config.route.v3.RouteConfiguration\",\n" + + " \"name\": \"route-foo.googleapis.com\",\n" + + " \"virtualHosts\": [{\n" + + " \"name\": \"virtualhost.googleapis.com\",\n" + + " \"domains\": [\"foo.googleapis.com\", \"bar.googleapis.com\"],\n" + + " \"routes\": [{\n" + + " \"match\": {\n" + + " \"path\": \"foo.googleapis.com\"\n" + + " },\n" + + " \"route\": {\n" + + " \"cluster\": \"cluster.googleapis.com\"\n" + + " }\n" + + " }]\n" + + " }]\n" + + " }],\n" + + " \"typeUrl\": \"type.googleapis.com/envoy.config.route.v3.RouteConfiguration\",\n" + + " \"nonce\": \"0000\"\n" + + "}"; + String res = printer.print(response); + assertThat(res).isEqualTo(expectedString); + } + + @Test + public void printCdsResponse_v3() { + Cluster cluster = + Cluster.newBuilder() + .setName("cluster-foo.googleapis.com") + .setEdsClusterConfig( + EdsClusterConfig.newBuilder() + .setServiceName("backend-service-foo.googleapis.com") + .setEdsConfig( + ConfigSource.newBuilder() + .setAds(AggregatedConfigSource.getDefaultInstance()))) + .setLrsServer(ConfigSource.newBuilder().setSelf(SelfConfigSource.getDefaultInstance())) + .setLbPolicy(LbPolicy.ROUND_ROBIN) + .setTransportSocket( + TransportSocket.newBuilder() + .setTypedConfig( + Any.pack( + UpstreamTlsContext.newBuilder() + .setCommonTlsContext( + CommonTlsContext.newBuilder() + .addTlsCertificateSdsSecretConfigs( + SdsSecretConfig.getDefaultInstance())).build()))) + .build(); + DiscoveryResponse response = + DiscoveryResponse.newBuilder() + .setTypeUrl("type.googleapis.com/envoy.config.cluster.v3.Cluster") + .setVersionInfo("0") + .addResources(Any.pack(cluster)) + .setNonce("0000") + .build(); + + String expectedString = "{\n" + + " \"versionInfo\": \"0\",\n" + + " \"resources\": [{\n" + + " \"@type\": \"type.googleapis.com/envoy.config.cluster.v3.Cluster\",\n" + + " \"name\": \"cluster-foo.googleapis.com\",\n" + + " \"edsClusterConfig\": {\n" + + " \"edsConfig\": {\n" + + " \"ads\": {\n" + + " }\n" + + " },\n" + + " \"serviceName\": \"backend-service-foo.googleapis.com\"\n" + + " },\n" + + " \"transportSocket\": {\n" + + " \"typedConfig\": {\n" + + " \"@type\": \"type.googleapis.com/envoy.extensions.transport_sockets.tls.v3" + + ".UpstreamTlsContext\",\n" + + " \"commonTlsContext\": {\n" + + " \"tlsCertificateSdsSecretConfigs\": [{\n" + + " }]\n" + + " }\n" + + " }\n" + + " },\n" + + " \"lrsServer\": {\n" + + " \"self\": {\n" + + " }\n" + + " }\n" + + " }],\n" + + " \"typeUrl\": \"type.googleapis.com/envoy.config.cluster.v3.Cluster\",\n" + + " \"nonce\": \"0000\"\n" + + "}"; + String res = printer.print(response); + assertThat(res).isEqualTo(expectedString); + } + + @Test + public void printEdsResponse_v3() { + ClusterLoadAssignment clusterLoadAssignment = + ClusterLoadAssignment.newBuilder() + .setClusterName("cluster-foo.googleapis.com") + .setPolicy( + Policy.newBuilder() + .addDropOverloads( + DropOverload.newBuilder() + .setCategory("throttle") + .setDropPercentage( + FractionalPercent.newBuilder() + .setNumerator(80) + .setDenominator(DenominatorType.HUNDRED)))) + .addEndpoints( + LocalityLbEndpoints.newBuilder() + .setLocality( + Locality.newBuilder() + .setRegion("region") + .setZone("zone") + .setSubZone("subzone")).setPriority(1) + .setLoadBalancingWeight(UInt32Value.newBuilder().setValue(20)) + .addLbEndpoints( + LbEndpoint.newBuilder() + .setLoadBalancingWeight(UInt32Value.newBuilder().setValue(100)) + .setHealthStatus(HealthStatus.UNHEALTHY) + .setEndpoint( + Endpoint.newBuilder() + .setAddress( + Address.newBuilder() + .setSocketAddress( + SocketAddress.newBuilder() + .setAddress("10.0.0.1") + .setPortValue(8001)))))) + .build(); + + + DiscoveryResponse response = + DiscoveryResponse.newBuilder() + .setTypeUrl("type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment") + .setVersionInfo("0") + .addResources(Any.pack(clusterLoadAssignment)) + .setNonce("0000") + .build(); + + String expectedString = "{\n" + + " \"versionInfo\": \"0\",\n" + + " \"resources\": [{\n" + + " \"@type\": \"type.googleapis.com/envoy.config.endpoint.v3" + + ".ClusterLoadAssignment\",\n" + + " \"clusterName\": \"cluster-foo.googleapis.com\",\n" + + " \"endpoints\": [{\n" + + " \"locality\": {\n" + + " \"region\": \"region\",\n" + + " \"zone\": \"zone\",\n" + + " \"subZone\": \"subzone\"\n" + + " },\n" + + " \"lbEndpoints\": [{\n" + + " \"endpoint\": {\n" + + " \"address\": {\n" + + " \"socketAddress\": {\n" + + " \"address\": \"10.0.0.1\",\n" + + " \"portValue\": 8001\n" + + " }\n" + + " }\n" + + " },\n" + + " \"healthStatus\": \"UNHEALTHY\",\n" + + " \"loadBalancingWeight\": 100\n" + + " }],\n" + + " \"loadBalancingWeight\": 20,\n" + + " \"priority\": 1\n" + + " }],\n" + + " \"policy\": {\n" + + " \"dropOverloads\": [{\n" + + " \"category\": \"throttle\",\n" + + " \"dropPercentage\": {\n" + + " \"numerator\": 80\n" + + " }\n" + + " }]\n" + + " }\n" + + " }],\n" + + " \"typeUrl\": \"type.googleapis.com/envoy.config.endpoint.v3" + + ".ClusterLoadAssignment\",\n" + + " \"nonce\": \"0000\"\n" + + "}"; + String res = printer.print(response); + assertThat(res).isEqualTo(expectedString); + } +} diff --git a/xds/src/test/java/io/grpc/xds/XdsClientTestHelper.java b/xds/src/test/java/io/grpc/xds/XdsClientTestHelper.java index da9d549a12..9ea9b1f8dc 100644 --- a/xds/src/test/java/io/grpc/xds/XdsClientTestHelper.java +++ b/xds/src/test/java/io/grpc/xds/XdsClientTestHelper.java @@ -16,27 +16,8 @@ package io.grpc.xds; -import com.google.common.collect.ImmutableList; import com.google.protobuf.Any; -import com.google.protobuf.UInt32Value; -import io.envoyproxy.envoy.config.cluster.v3.Cluster; -import io.envoyproxy.envoy.config.cluster.v3.Cluster.DiscoveryType; -import io.envoyproxy.envoy.config.cluster.v3.Cluster.EdsClusterConfig; -import io.envoyproxy.envoy.config.cluster.v3.Cluster.LbPolicy; import io.envoyproxy.envoy.config.core.v3.Address; -import io.envoyproxy.envoy.config.core.v3.AggregatedConfigSource; -import io.envoyproxy.envoy.config.core.v3.ConfigSource; -import io.envoyproxy.envoy.config.core.v3.HealthStatus; -import io.envoyproxy.envoy.config.core.v3.Locality; -import io.envoyproxy.envoy.config.core.v3.SelfConfigSource; -import io.envoyproxy.envoy.config.core.v3.SocketAddress; -import io.envoyproxy.envoy.config.core.v3.TransportSocket; -import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; -import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment.Policy; -import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment.Policy.DropOverload; -import io.envoyproxy.envoy.config.endpoint.v3.Endpoint; -import io.envoyproxy.envoy.config.endpoint.v3.LbEndpoint; -import io.envoyproxy.envoy.config.endpoint.v3.LocalityLbEndpoints; import io.envoyproxy.envoy.config.listener.v3.ApiListener; import io.envoyproxy.envoy.config.listener.v3.FilterChain; import io.envoyproxy.envoy.config.listener.v3.Listener; @@ -45,14 +26,10 @@ import io.envoyproxy.envoy.config.route.v3.RouteAction; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; import io.envoyproxy.envoy.config.route.v3.RouteMatch; import io.envoyproxy.envoy.config.route.v3.VirtualHost; -import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext; import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; -import io.envoyproxy.envoy.type.v3.FractionalPercent; -import io.envoyproxy.envoy.type.v3.FractionalPercent.DenominatorType; import io.grpc.xds.EnvoyProtoData.Node; import java.util.List; -import javax.annotation.Nullable; /** * Helper methods for building protobuf messages with custom data for xDS protocols. @@ -93,24 +70,6 @@ class XdsClientTestHelper { .build(); } - static io.envoyproxy.envoy.api.v2.DiscoveryRequest buildDiscoveryRequestV2( - Node node, String versionInfo, String resourceName, String typeUrl, String nonce) { - return buildDiscoveryRequestV2( - node, versionInfo, ImmutableList.of(resourceName), typeUrl, nonce); - } - - static io.envoyproxy.envoy.api.v2.DiscoveryRequest buildDiscoveryRequestV2( - Node node, String versionInfo, List resourceNames, String typeUrl, String nonce) { - return - io.envoyproxy.envoy.api.v2.DiscoveryRequest.newBuilder() - .setVersionInfo(versionInfo) - .setNode(node.toEnvoyProtoNodeV2()) - .setTypeUrl(typeUrl) - .addAllResourceNames(resourceNames) - .setResponseNonce(nonce) - .build(); - } - static Listener buildListener(String name, com.google.protobuf.Any apiListener) { return Listener.newBuilder() @@ -175,170 +134,4 @@ class XdsClientTestHelper { .setMatch(io.envoyproxy.envoy.api.v2.route.RouteMatch.newBuilder().setPrefix(""))) .build(); } - - static Cluster buildCluster(String clusterName, @Nullable String edsServiceName, - boolean enableLrs) { - return buildSecureCluster(clusterName, edsServiceName, enableLrs, null); - } - - static io.envoyproxy.envoy.api.v2.Cluster buildClusterV2( - String clusterName, @Nullable String edsServiceName, boolean enableLrs) { - return buildSecureClusterV2(clusterName, edsServiceName, enableLrs, null); - } - - static Cluster buildSecureCluster( - String clusterName, @Nullable String edsServiceName, boolean enableLrs, - @Nullable UpstreamTlsContext upstreamTlsContext) { - Cluster.Builder clusterBuilder = Cluster.newBuilder(); - clusterBuilder.setName(clusterName); - clusterBuilder.setType(DiscoveryType.EDS); - EdsClusterConfig.Builder edsClusterConfigBuilder = EdsClusterConfig.newBuilder(); - edsClusterConfigBuilder.setEdsConfig( - ConfigSource.newBuilder() - .setAds(AggregatedConfigSource.getDefaultInstance())); - if (edsServiceName != null) { - edsClusterConfigBuilder.setServiceName(edsServiceName); - } - clusterBuilder.setEdsClusterConfig(edsClusterConfigBuilder); - clusterBuilder.setLbPolicy(LbPolicy.ROUND_ROBIN); - if (enableLrs) { - clusterBuilder.setLrsServer( - ConfigSource.newBuilder() - .setSelf(SelfConfigSource.getDefaultInstance())); - } - if (upstreamTlsContext != null) { - clusterBuilder.setTransportSocket( - TransportSocket.newBuilder() - .setName("envoy.transport_sockets.tls") - .setTypedConfig(Any.pack(upstreamTlsContext))); - } - return clusterBuilder.build(); - } - - static io.envoyproxy.envoy.api.v2.Cluster buildSecureClusterV2( - String clusterName, @Nullable String edsServiceName, boolean enableLrs, - @Nullable io.envoyproxy.envoy.api.v2.auth.UpstreamTlsContext upstreamTlsContext) { - io.envoyproxy.envoy.api.v2.Cluster.Builder clusterBuilder = - io.envoyproxy.envoy.api.v2.Cluster.newBuilder() - .setName(clusterName) - .setType(io.envoyproxy.envoy.api.v2.Cluster.DiscoveryType.EDS); - io.envoyproxy.envoy.api.v2.Cluster.EdsClusterConfig.Builder edsClusterConfigBuilder = - io.envoyproxy.envoy.api.v2.Cluster.EdsClusterConfig.newBuilder() - .setEdsConfig( - io.envoyproxy.envoy.api.v2.core.ConfigSource.newBuilder().setAds( - io.envoyproxy.envoy.api.v2.core.AggregatedConfigSource.getDefaultInstance())); - if (edsServiceName != null) { - edsClusterConfigBuilder.setServiceName(edsServiceName); - } - clusterBuilder - .setEdsClusterConfig(edsClusterConfigBuilder) - .setLbPolicy(io.envoyproxy.envoy.api.v2.Cluster.LbPolicy.ROUND_ROBIN); - if (enableLrs) { - clusterBuilder.setLrsServer( - io.envoyproxy.envoy.api.v2.core.ConfigSource.newBuilder() - .setSelf(io.envoyproxy.envoy.api.v2.core.SelfConfigSource.getDefaultInstance())); - } - if (upstreamTlsContext != null) { - clusterBuilder.setTransportSocket( - io.envoyproxy.envoy.api.v2.core.TransportSocket.newBuilder() - .setName("envoy.transport_sockets.tls").setTypedConfig(Any.pack(upstreamTlsContext))); - } - return clusterBuilder.build(); - } - - static ClusterLoadAssignment buildClusterLoadAssignment(String clusterName, - List localityLbEndpoints, List dropOverloads) { - return - ClusterLoadAssignment.newBuilder() - .setClusterName(clusterName) - .addAllEndpoints(localityLbEndpoints) - .setPolicy(Policy.newBuilder().addAllDropOverloads(dropOverloads)) - .build(); - } - - static DropOverload buildDropOverload(String category, int dropPerMillion) { - return - DropOverload.newBuilder() - .setCategory(category) - .setDropPercentage( - FractionalPercent.newBuilder() - .setNumerator(dropPerMillion) - .setDenominator(DenominatorType.MILLION)) - .build(); - } - - static io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload buildDropOverloadV2( - String category, int dropPerMillion) { - return - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload.newBuilder() - .setCategory(category) - .setDropPercentage( - io.envoyproxy.envoy.type.FractionalPercent.newBuilder() - .setNumerator(dropPerMillion) - .setDenominator( - io.envoyproxy.envoy.type.FractionalPercent.DenominatorType.MILLION)) - .build(); - } - - static LocalityLbEndpoints buildLocalityLbEndpoints( - String region, String zone, String subZone, List lbEndpoints, - int loadBalancingWeight, int priority) { - return - LocalityLbEndpoints.newBuilder() - .setLocality( - Locality.newBuilder() - .setRegion(region) - .setZone(zone) - .setSubZone(subZone)) - .addAllLbEndpoints(lbEndpoints) - .setLoadBalancingWeight(UInt32Value.of(loadBalancingWeight)) - .setPriority(priority) - .build(); - } - - static io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints buildLocalityLbEndpointsV2( - String region, String zone, String subZone, - List lbEndpoints, - int loadBalancingWeight, int priority) { - return - io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints.newBuilder() - .setLocality( - io.envoyproxy.envoy.api.v2.core.Locality.newBuilder() - .setRegion(region) - .setZone(zone) - .setSubZone(subZone)) - .addAllLbEndpoints(lbEndpoints) - .setLoadBalancingWeight(UInt32Value.of(loadBalancingWeight)) - .setPriority(priority) - .build(); - } - - static LbEndpoint buildLbEndpoint( - String address, int port, HealthStatus healthStatus, int loadbalancingWeight) { - return - LbEndpoint.newBuilder() - .setEndpoint( - Endpoint.newBuilder().setAddress( - Address.newBuilder().setSocketAddress( - SocketAddress.newBuilder().setAddress(address).setPortValue(port)))) - .setHealthStatus(healthStatus) - .setLoadBalancingWeight(UInt32Value.of(loadbalancingWeight)) - .build(); - } - - static io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint buildLbEndpointV2( - String address, int port, io.envoyproxy.envoy.api.v2.core.HealthStatus healthStatus, - int loadbalancingWeight) { - return - io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint.newBuilder() - .setEndpoint( - io.envoyproxy.envoy.api.v2.endpoint.Endpoint.newBuilder().setAddress( - io.envoyproxy.envoy.api.v2.core.Address.newBuilder().setSocketAddress( - io.envoyproxy.envoy.api.v2.core.SocketAddress.newBuilder() - .setAddress(address) - .setPortValue(port)))) - .setHealthStatus(healthStatus) - .setLoadBalancingWeight(UInt32Value.of(loadbalancingWeight)) - .build(); - } }