From a02dc4007c31f922d02d5e1fdc75ce28369f57ad Mon Sep 17 00:00:00 2001 From: Santiago Pericas-Geertsen Date: Thu, 20 Jun 2024 14:25:00 -0400 Subject: [PATCH] Adds new tests and resources. Signed-off-by: Santiago Pericas-Geertsen --- microprofile/grpc/client/pom.xml | 60 ++++ .../client/ClientMethodDescriptorTest.java | 139 +++++++++ .../client/ClientServiceDescriptorTest.java | 292 ++++++++++++++++++ .../grpc/client/GrpcChannelsProviderTest.java | 252 +++++++++++++++ .../grpc/client/JavaMarshaller.java | 67 ++++ .../test/java/services/TreeMapService.java | 271 ++++++++++++++++ .../grpc/client/src/test/proto/echo.proto | 30 ++ .../grpc/client/src/test/proto/strings.proto | 31 ++ .../src/test/resources/logging.properties | 34 ++ .../grpc/client/src/test/resources/ssl/ca.pem | 17 + .../src/test/resources/ssl/clientCert.pem | 16 + .../src/test/resources/ssl/clientKey.pem | 28 ++ .../client/src/test/resources/ssl/keys.sh | 49 +++ .../src/test/resources/ssl/serverCert.pem | 17 + .../src/test/resources/ssl/serverKey.pem | 28 ++ .../test/resources/test-client-config.yaml | 50 +++ 16 files changed, 1381 insertions(+) create mode 100644 microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/ClientMethodDescriptorTest.java create mode 100644 microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/ClientServiceDescriptorTest.java create mode 100644 microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/GrpcChannelsProviderTest.java create mode 100644 microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/JavaMarshaller.java create mode 100644 microprofile/grpc/client/src/test/java/services/TreeMapService.java create mode 100644 microprofile/grpc/client/src/test/proto/echo.proto create mode 100644 microprofile/grpc/client/src/test/proto/strings.proto create mode 100644 microprofile/grpc/client/src/test/resources/logging.properties create mode 100644 microprofile/grpc/client/src/test/resources/ssl/ca.pem create mode 100644 microprofile/grpc/client/src/test/resources/ssl/clientCert.pem create mode 100644 microprofile/grpc/client/src/test/resources/ssl/clientKey.pem create mode 100644 microprofile/grpc/client/src/test/resources/ssl/keys.sh create mode 100644 microprofile/grpc/client/src/test/resources/ssl/serverCert.pem create mode 100644 microprofile/grpc/client/src/test/resources/ssl/serverKey.pem create mode 100644 microprofile/grpc/client/src/test/resources/test-client-config.yaml diff --git a/microprofile/grpc/client/pom.xml b/microprofile/grpc/client/pom.xml index 4d5b525c464..0c69a59464a 100644 --- a/microprofile/grpc/client/pom.xml +++ b/microprofile/grpc/client/pom.xml @@ -54,5 +54,65 @@ io.helidon.common helidon-common-tls + + io.helidon.webserver + helidon-webserver-grpc + test + + + io.helidon.config + helidon-config-yaml + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.hamcrest + hamcrest-all + test + + + + javax.annotation + javax.annotation-api + provided + true + + + org.mockito + mockito-core + test + + + + + + kr.motd.maven + os-maven-plugin + ${version.plugin.os} + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + + + + test-compile + test-compile-custom + + + + + + \ No newline at end of file diff --git a/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/ClientMethodDescriptorTest.java b/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/ClientMethodDescriptorTest.java new file mode 100644 index 00000000000..fc4b49190d8 --- /dev/null +++ b/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/ClientMethodDescriptorTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. + * + * 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.helidon.microprofile.grpc.client; + +import io.helidon.microprofile.grpc.client.test.Echo; +import io.helidon.microprofile.grpc.client.test.EchoServiceGrpc; + +import io.grpc.MethodDescriptor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsEmptyIterable.emptyIterable; + +public class ClientMethodDescriptorTest { + + private MethodDescriptor.Builder grpcDescriptor; + + @BeforeEach + public void setup() { + grpcDescriptor = EchoServiceGrpc.getServiceDescriptor() + .getMethods() + .stream() + .filter(md -> md.getFullMethodName().equals("EchoService/Echo")) + .findFirst() + .orElseThrow(() -> new AssertionError("Could not find echo method")) + .toBuilder(); + } + + @Test + public void shouldCreateMethodDescriptorFromGrpcDescriptor() { + ClientMethodDescriptor descriptor = ClientMethodDescriptor.create("FooService", + "foo", + grpcDescriptor); + + assertThat(descriptor, is(notNullValue())); + assertThat(descriptor.name(), is("foo")); + assertThat(descriptor.interceptors(), is(emptyIterable())); + + MethodDescriptor expected = grpcDescriptor.build(); + MethodDescriptor methodDescriptor = descriptor.descriptor(); + assertThat(methodDescriptor.getFullMethodName(), is("FooService/foo")); + assertThat(methodDescriptor.getType(), is(expected.getType())); + assertThat(methodDescriptor.getRequestMarshaller(), is(expected.getRequestMarshaller())); + assertThat(methodDescriptor.getResponseMarshaller(), is(expected.getResponseMarshaller())); + } + + @Test + public void shouldCreateBidirectionalMethod() { + ClientMethodDescriptor descriptor = ClientMethodDescriptor.bidirectional("FooService", "foo") + .defaultMarshallerSupplier(new JavaMarshaller.Supplier()) + .build(); + assertThat(descriptor, is(notNullValue())); + assertThat(descriptor.name(), is("foo")); + MethodDescriptor methodDescriptor = descriptor.descriptor(); + assertThat(methodDescriptor.getFullMethodName(), is("FooService/foo")); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.BIDI_STREAMING)); + } + + @Test + public void shouldCreateClientStreamingMethod() { + ClientMethodDescriptor descriptor = ClientMethodDescriptor.clientStreaming("FooService", "foo") + .defaultMarshallerSupplier(new JavaMarshaller.Supplier()) + .build(); + assertThat(descriptor, is(notNullValue())); + assertThat(descriptor.name(), is("foo")); + MethodDescriptor methodDescriptor = descriptor.descriptor(); + assertThat(methodDescriptor.getFullMethodName(), is("FooService/foo")); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.CLIENT_STREAMING)); + } + + @Test + public void shouldCreateServerStreamingMethod() { + ClientMethodDescriptor descriptor = ClientMethodDescriptor.serverStreaming("FooService", "foo") + .defaultMarshallerSupplier(new JavaMarshaller.Supplier()) + .build(); + assertThat(descriptor, is(notNullValue())); + assertThat(descriptor.name(), is("foo")); + MethodDescriptor methodDescriptor = descriptor.descriptor(); + assertThat(methodDescriptor.getFullMethodName(), is("FooService/foo")); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.SERVER_STREAMING)); + } + + @Test + public void shouldCreateUnaryMethod() { + ClientMethodDescriptor descriptor = ClientMethodDescriptor.unary("FooService", "foo") + .defaultMarshallerSupplier(new JavaMarshaller.Supplier()) + .build(); + assertThat(descriptor, is(notNullValue())); + assertThat(descriptor.name(), is("foo")); + MethodDescriptor methodDescriptor = descriptor.descriptor(); + assertThat(methodDescriptor.getFullMethodName(), is("FooService/foo")); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.UNARY)); + } + + @Test + public void shouldSetName() { + ClientMethodDescriptor.Builder builder = ClientMethodDescriptor + .unary("FooService", "foo") + .defaultMarshallerSupplier(new JavaMarshaller.Supplier()); + + builder.fullName("Foo/Bar"); + + ClientMethodDescriptor descriptor = builder.build(); + + assertThat(descriptor.name(), is("Bar")); + assertThat(descriptor.descriptor().getFullMethodName(), is("Foo/Bar")); + } + + @Test + public void testMarshallerTypesForProtoBuilder() { + ClientMethodDescriptor descriptor = ClientMethodDescriptor + .unary("EchoService", "Echo") + .requestType(Echo.EchoRequest.class) + .responseType(Echo.EchoResponse.class) + .build(); + + MethodDescriptor methodDescriptor = descriptor.descriptor(); + assertThat(methodDescriptor.getRequestMarshaller(), instanceOf(MethodDescriptor.PrototypeMarshaller.class)); + assertThat(methodDescriptor.getResponseMarshaller(), instanceOf(MethodDescriptor.PrototypeMarshaller.class)); + } +} diff --git a/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/ClientServiceDescriptorTest.java b/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/ClientServiceDescriptorTest.java new file mode 100644 index 00000000000..7d945d45fd3 --- /dev/null +++ b/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/ClientServiceDescriptorTest.java @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. + * + * 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.helidon.microprofile.grpc.client; + +import java.util.Collection; + +import io.helidon.microprofile.grpc.client.test.StringServiceGrpc; + +import io.grpc.ClientInterceptor; +import io.grpc.MethodDescriptor; +import io.grpc.ServerMethodDefinition; +import io.grpc.ServiceDescriptor; +import org.junit.jupiter.api.Test; +import services.TreeMapService; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.collection.IsEmptyIterable.emptyIterable; +import static org.hamcrest.collection.IsIterableContainingInOrder.contains; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; + +public class ClientServiceDescriptorTest { + + @Test + public void shouldCreateDescriptorFromGrpcServiceDescriptor() { + ServiceDescriptor grpcDescriptor = StringServiceGrpc.getServiceDescriptor(); + ClientServiceDescriptor descriptor = ClientServiceDescriptor.create(grpcDescriptor); + String serviceName = "StringService"; + assertThat(descriptor.name(), is(serviceName)); + assertThat(descriptor.interceptors(), is(emptyIterable())); + + Collection> expectedMethods = grpcDescriptor.getMethods(); + Collection actualMethods = descriptor.methods(); + assertThat(actualMethods.size(), is(expectedMethods.size())); + + for (MethodDescriptor methodDescriptor : expectedMethods) { + String name = methodDescriptor.getFullMethodName().substring(serviceName.length() + 1); + ClientMethodDescriptor method = descriptor.method(name); + assertThat(method.name(), is(name)); + assertThat(method.interceptors(), is(emptyIterable())); + MethodDescriptor actualDescriptor = method.descriptor(); + assertThat(actualDescriptor.getType(), is(methodDescriptor.getType())); + } + } + + @Test + public void shouldCreateDescriptorFromBindableService() { + StringServiceBindableService bindableService = new StringServiceBindableService(); + ClientServiceDescriptor descriptor = ClientServiceDescriptor.create(bindableService); + String serviceName = "StringService"; + assertThat(descriptor.name(), is(serviceName)); + assertThat(descriptor.interceptors(), is(emptyIterable())); + + Collection> expectedMethods = bindableService.bindService().getMethods(); + Collection actualMethods = descriptor.methods(); + assertThat(actualMethods.size(), is(expectedMethods.size())); + + for (ServerMethodDefinition expectedMethod : expectedMethods) { + MethodDescriptor methodDescriptor = expectedMethod.getMethodDescriptor(); + String name = methodDescriptor.getFullMethodName().substring(serviceName.length() + 1); + ClientMethodDescriptor method = descriptor.method(name); + assertThat(method.name(), is(name)); + assertThat(method.interceptors(), is(emptyIterable())); + MethodDescriptor actualDescriptor = method.descriptor(); + assertThat(actualDescriptor.getType(), is(methodDescriptor.getType())); + } + } + + @Test + public void testServiceName() { + ClientServiceDescriptor.Builder builder = ClientServiceDescriptor.builder("TreeMapService", + TreeMapService.class); + assertThat(builder.name(), is("TreeMapService")); + + ClientServiceDescriptor descriptor = builder.build(); + assertThat(descriptor.name(), is("TreeMapService")); + } + + @Test + public void testDefaultMethodCount() { + ClientServiceDescriptor svcDesc = newClientServiceDescriptorBuilder(TreeMapService.class).build(); + assertThat(svcDesc.methods().size(), equalTo(0)); + } + + @Test + public void shouldNotAllowNullName() { + ClientServiceDescriptor.Builder builder = newClientServiceDescriptorBuilder(TreeMapService.class); + + assertThrows(NullPointerException.class, () -> builder.name(null)); + } + + @Test + public void shouldNotAllowEmptyStringName() { + ClientServiceDescriptor.Builder builder = newClientServiceDescriptorBuilder(TreeMapService.class); + + assertThrows(IllegalArgumentException.class, () -> builder.name("")); + } + + @Test + public void shouldNotAllowBlankName() { + ClientServiceDescriptor.Builder builder = newClientServiceDescriptorBuilder(TreeMapService.class); + + assertThrows(IllegalArgumentException.class, () -> builder.name(" \t ")); + } + + @Test + public void shouldAddBidirectionalMethod() { + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .bidirectional("foo") + .build(); + + ClientMethodDescriptor method = descriptor.method("foo"); + assertThat(method, is(notNullValue())); + MethodDescriptor methodDescriptor = method.descriptor(); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.BIDI_STREAMING)); + assertThat(methodDescriptor.getFullMethodName(), is("TreeMapService/foo")); + } + + @Test + public void shouldAddBidirectionalMethodWithConfigurer() { + ClientInterceptor interceptor = mock(ClientInterceptor.class); + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .bidirectional("foo", cfg -> cfg.intercept(interceptor)) + .build(); + + ClientMethodDescriptor method = descriptor.method("foo"); + assertThat(method, is(notNullValue())); + assertThat(method.interceptors(), contains(interceptor)); + MethodDescriptor methodDescriptor = method.descriptor(); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.BIDI_STREAMING)); + assertThat(methodDescriptor.getFullMethodName(), is("TreeMapService/foo")); + } + + @Test + public void shouldAddClientStreamingMethod() { + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .clientStreaming("foo") + .build(); + + ClientMethodDescriptor method = descriptor.method("foo"); + assertThat(method, is(notNullValue())); + MethodDescriptor methodDescriptor = method.descriptor(); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.CLIENT_STREAMING)); + assertThat(methodDescriptor.getFullMethodName(), is("TreeMapService/foo")); + } + + @Test + public void shouldAddClientStreamingMethodWithConfigurer() { + ClientInterceptor interceptor = mock(ClientInterceptor.class); + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .clientStreaming("foo", cfg -> cfg.intercept(interceptor)) + .build(); + + ClientMethodDescriptor method = descriptor.method("foo"); + assertThat(method, is(notNullValue())); + assertThat(method.interceptors(), contains(interceptor)); + MethodDescriptor methodDescriptor = method.descriptor(); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.CLIENT_STREAMING)); + assertThat(methodDescriptor.getFullMethodName(), is("TreeMapService/foo")); + } + + @Test + public void shouldAddServerStreamingMethod() { + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .serverStreaming("foo") + .build(); + + ClientMethodDescriptor method = descriptor.method("foo"); + assertThat(method, is(notNullValue())); + MethodDescriptor methodDescriptor = method.descriptor(); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.SERVER_STREAMING)); + assertThat(methodDescriptor.getFullMethodName(), is("TreeMapService/foo")); + } + + @Test + public void shouldAddServerStreamingMethodWithConfigurer() { + ClientInterceptor interceptor = mock(ClientInterceptor.class); + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .serverStreaming("foo", cfg -> cfg.intercept(interceptor)) + .build(); + + ClientMethodDescriptor method = descriptor.method("foo"); + assertThat(method, is(notNullValue())); + assertThat(method.interceptors(), contains(interceptor)); + MethodDescriptor methodDescriptor = method.descriptor(); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.SERVER_STREAMING)); + assertThat(methodDescriptor.getFullMethodName(), is("TreeMapService/foo")); + } + + @Test + public void shouldAddUnaryMethod() { + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .unary("foo") + .build(); + + ClientMethodDescriptor method = descriptor.method("foo"); + assertThat(method, is(notNullValue())); + MethodDescriptor methodDescriptor = method.descriptor(); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.UNARY)); + assertThat(methodDescriptor.getFullMethodName(), is("TreeMapService/foo")); + } + + @Test + public void shouldAddUnaryMethodWithConfigurer() { + ClientInterceptor interceptor = mock(ClientInterceptor.class); + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .unary("foo", cfg -> cfg.intercept(interceptor)) + .build(); + + ClientMethodDescriptor method = descriptor.method("foo"); + assertThat(method, is(notNullValue())); + assertThat(method.interceptors(), contains(interceptor)); + MethodDescriptor methodDescriptor = method.descriptor(); + assertThat(methodDescriptor.getType(), is(MethodDescriptor.MethodType.UNARY)); + assertThat(methodDescriptor.getFullMethodName(), is("TreeMapService/foo")); + } + + @Test + public void shouldAddInterceptor() { + ClientInterceptor interceptor = mock(ClientInterceptor.class); + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .intercept(interceptor) + .build(); + + assertThat(descriptor.interceptors(), contains(interceptor)); + } + + @Test + public void shouldAddInterceptors() { + ClientInterceptor interceptorOne = mock(ClientInterceptor.class); + ClientInterceptor interceptorTwo = mock(ClientInterceptor.class); + ClientInterceptor interceptorThree = mock(ClientInterceptor.class); + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .intercept(interceptorOne) + .intercept(interceptorTwo, interceptorThree) + .build(); + + assertThat(descriptor.interceptors(), containsInAnyOrder(interceptorOne, interceptorTwo, interceptorThree)); + } + + @Test + public void shouldAddInterceptorToMethod() { + ClientInterceptor interceptor = mock(ClientInterceptor.class); + ClientServiceDescriptor descriptor = newClientServiceDescriptorBuilder(TreeMapService.class) + .unary("foo") + .intercept("foo", interceptor) + .build(); + + ClientMethodDescriptor method = descriptor.method("foo"); + assertThat(method, is(notNullValue())); + assertThat(method.interceptors(), contains(interceptor)); + } + + @Test + public void shouldSetNameOnMethods() { + ClientServiceDescriptor.Builder builder = newClientServiceDescriptorBuilder(TreeMapService.class); + + ClientServiceDescriptor descriptor = builder.unary("bar") + .name("Foo") + .build(); + + ClientMethodDescriptor method = descriptor.method("bar"); + assertThat(method.descriptor().getFullMethodName(), is("Foo/bar")); + } + + public static class StringServiceBindableService + extends StringServiceGrpc.StringServiceImplBase { + } + + private ClientServiceDescriptor.Builder newClientServiceDescriptorBuilder(Class service) { + return ClientServiceDescriptor.builder(service) + .marshallerSupplier(new JavaMarshaller.Supplier()); + } +} diff --git a/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/GrpcChannelsProviderTest.java b/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/GrpcChannelsProviderTest.java new file mode 100644 index 00000000000..62d5d97b41b --- /dev/null +++ b/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/GrpcChannelsProviderTest.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. + * + * 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.helidon.microprofile.grpc.client; + +import java.util.Optional; + +import io.helidon.common.configurable.Resource; +import io.helidon.config.Config; +import io.helidon.config.ConfigSources; +import io.helidon.grpc.core.GrpcTlsDescriptor; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.endsWith; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.mock; + +@SuppressWarnings("deprecation") +public class GrpcChannelsProviderTest { + + private static final String CLIENT_CERT = "ssl/clientCert.pem"; + private static final String CLIENT_KEY = "ssl/clientKey.pem"; + private static final String CA_CERT = "ssl/ca.pem"; + + private static final String DEFAULT_HOST_PORT_CFG = "default_host_port"; + private static final String DEFAULT_HOST_CFG = "default_host"; + private static final String DEFAULT_PORT_CFG = "default_port"; + private static final String DEFAULT_HOST_PORT_SSL_DISABLED_CFG = "default_host_port_ssl_disabled"; + private static final String DEFAULT_HOST_SSL_ONE_WAY_CFG = "default_host_ssl_one_way"; + private static final String DEFAULT_PORT_SSL_CFG = "default_port_ssl"; + private static final String DEFAULT_HOST = "localhost"; + private static final int DEFAULT_PORT = 1408; + private static GrpcChannelsProvider grpcConfig; + + @BeforeAll + public static void initGrpcConfig() { + Config cfg = Config.create(ConfigSources.classpath("test-client-config.yaml")); + grpcConfig = GrpcChannelsProvider.create(cfg.get("grpc")); + } + + @Test + public void testDefaultChannelConfiguration() { + GrpcChannelDescriptor cfg = GrpcChannelDescriptor.builder().build(); + assertThat(cfg.host(), equalTo(DEFAULT_HOST)); + assertThat(cfg.port(), equalTo(DEFAULT_PORT)); + assertThat(cfg.tlsDescriptor().isPresent(), is(false)); + assertThat(cfg.target().isPresent(), is(false)); + assertThat(cfg.loadBalancerPolicy().isPresent(), is(false)); + assertThat(cfg.nameResolverFactory().isPresent(), is(false)); + } + + @Test + public void testChannelConfigurationWithHost() { + GrpcChannelDescriptor cfg = GrpcChannelDescriptor.builder().host("abc.com").build(); + assertThat(cfg.host(), equalTo("abc.com")); + assertThat(cfg.port(), equalTo(DEFAULT_PORT)); + assertThat(cfg.tlsDescriptor().isPresent(), is(false)); + assertThat(cfg.target().isPresent(), is(false)); + assertThat(cfg.loadBalancerPolicy().isPresent(), is(false)); + assertThat(cfg.nameResolverFactory().isPresent(), is(false)); + } + + @Test + public void testChannelConfigurationWithPort() { + GrpcChannelDescriptor cfg = GrpcChannelDescriptor.builder().port(4096).build(); + assertThat(cfg.host(), equalTo("localhost")); + assertThat(cfg.port(), equalTo(4096)); + assertThat(cfg.tlsDescriptor().isPresent(), is(false)); + assertThat(cfg.target().isPresent(), is(false)); + assertThat(cfg.loadBalancerPolicy().isPresent(), is(false)); + assertThat(cfg.nameResolverFactory().isPresent(), is(false)); + } + + @Test + public void testChannelConfigurationWithDefaultSsl() { + GrpcChannelDescriptor cfg = GrpcChannelDescriptor.builder() + .sslDescriptor(GrpcTlsDescriptor.builder().build()) + .build(); + assertThat(cfg.host(), equalTo("localhost")); + assertThat(cfg.port(), equalTo(1408)); + Optional descriptor = cfg.tlsDescriptor(); + assertThat(descriptor.isPresent(), is(true)); + assertThat(descriptor.get().isEnabled(), is(true)); + assertThat(cfg.target().isPresent(), is(false)); + assertThat(cfg.loadBalancerPolicy().isPresent(), is(false)); + assertThat(cfg.nameResolverFactory().isPresent(), is(false)); + } + + @Test + public void testChannelConfigurationWithSslConfig() { + Resource certResource = mock(Resource.class); + Resource keyResource = mock(Resource.class); + Resource trustResource = mock(Resource.class); + + GrpcChannelDescriptor cfg = GrpcChannelDescriptor.builder() + .sslDescriptor( + GrpcTlsDescriptor.builder() + .tlsCaCert(trustResource) + .tlsCert(certResource) + .tlsKey(keyResource) + .build()) + .build(); + assertThat(cfg.host(), equalTo("localhost")); + assertThat(cfg.port(), equalTo(1408)); + Optional descriptor = cfg.tlsDescriptor(); + assertThat(descriptor.isPresent(), is(true)); + GrpcTlsDescriptor tlsDescriptor = descriptor.get(); + assertThat(tlsDescriptor.isEnabled(), is(true)); + assertThat(tlsDescriptor.tlsCaCert(), is(sameInstance(trustResource))); + assertThat(tlsDescriptor.tlsCert(), is(sameInstance(certResource))); + assertThat(tlsDescriptor.tlsKey(), is(sameInstance(keyResource))); + } + + @Test + public void testChannelWithTarget() { + String target = "dns://127.0.0.1:22"; + GrpcChannelDescriptor cfg = GrpcChannelDescriptor.builder() + .target(target) + .build(); + assertThat(cfg.target().isPresent(), is(true)); + assertThat(cfg.target().get(), is(target)); + } + + @Test + public void testChannelWithLoadBalancer() { + String policy = "round-robin"; + GrpcChannelDescriptor cfg = GrpcChannelDescriptor.builder() + .loadBalancerPolicy(policy) + .build(); + assertThat(cfg.loadBalancerPolicy().isPresent(), is(true)); + assertThat(cfg.loadBalancerPolicy().get(), is(policy)); + } + + @Test + public void testConfigLoading() { + String[] expectedChannelConfigNames = new String[] { + DEFAULT_HOST_PORT_CFG, DEFAULT_HOST_CFG, DEFAULT_PORT_CFG, + DEFAULT_HOST_SSL_ONE_WAY_CFG, DEFAULT_PORT_SSL_CFG, + DEFAULT_HOST_PORT_SSL_DISABLED_CFG + }; + + assertThat(grpcConfig.channels().size(), equalTo(expectedChannelConfigNames.length + 2)); + assertThat(grpcConfig.channels().keySet(), hasItems(expectedChannelConfigNames)); + assertThat(grpcConfig.channels().keySet(), hasItems(GrpcChannelsProvider.DEFAULT_CHANNEL_NAME)); + } + + @Test + public void testDefaultHostPortConfig() { + GrpcChannelDescriptor chCfg = grpcConfig.channels().get(DEFAULT_HOST_PORT_CFG); + assertThat(chCfg.host(), equalTo("localhost")); + assertThat(chCfg.port(), equalTo(1408)); + assertThat(chCfg.tlsDescriptor().isPresent(), is(false)); + assertThat(chCfg.target().isPresent(), is(false)); + assertThat(chCfg.loadBalancerPolicy().isPresent(), is(false)); + assertThat(chCfg.nameResolverFactory().isPresent(), is(false)); + } + + @Test + public void testDefaultHostConfig() { + GrpcChannelDescriptor chCfg = grpcConfig.channels().get(DEFAULT_HOST_CFG); + assertThat(chCfg.host(), equalTo("localhost")); + assertThat(chCfg.port(), equalTo(4096)); + assertThat(chCfg.tlsDescriptor().isPresent(), is(false)); + assertThat(chCfg.target().isPresent(), is(false)); + assertThat(chCfg.loadBalancerPolicy().isPresent(), is(false)); + assertThat(chCfg.nameResolverFactory().isPresent(), is(false)); + } + + @Test + public void testDefaultPortConfig() { + GrpcChannelDescriptor chCfg = grpcConfig.channels().get(DEFAULT_PORT_CFG); + assertThat(chCfg.host(), equalTo("non_default_host.com")); + assertThat(chCfg.port(), equalTo(1408)); + assertThat(chCfg.tlsDescriptor().isPresent(), is(false)); + assertThat(chCfg.target().isPresent(), is(false)); + assertThat(chCfg.loadBalancerPolicy().isPresent(), is(false)); + assertThat(chCfg.nameResolverFactory().isPresent(), is(false)); + } + + @Test + public void testDefaultHostPortSslDisabledConfig() { + GrpcChannelDescriptor chCfg = grpcConfig.channels().get(DEFAULT_HOST_PORT_SSL_DISABLED_CFG); + assertThat(chCfg.host(), equalTo("localhost")); + assertThat(chCfg.port(), equalTo(1408)); + + Optional descriptor = chCfg.tlsDescriptor(); + assertThat(descriptor.isPresent(), is(false)); + } + + @Test + public void testDefaultHostSslOneWay() { + GrpcChannelDescriptor chCfg = grpcConfig.channels().get(DEFAULT_HOST_SSL_ONE_WAY_CFG); + assertThat(chCfg.host(), equalTo("localhost")); + assertThat(chCfg.port(), equalTo(4096)); + + Resource trustResource = Resource.create(CA_CERT); + + Optional descriptor = chCfg.tlsDescriptor(); + assertThat(descriptor.isPresent(), is(true)); + GrpcTlsDescriptor ssl = descriptor.get(); + assertThat(ssl, notNullValue()); + assertThat(ssl.isEnabled(), equalTo(true)); + assertThat(ssl.tlsKey(), nullValue()); + assertThat(ssl.tlsCert(), nullValue()); + assertThat(ssl.tlsCaCert(), is(notNullValue())); + assertThat(ssl.tlsCaCert().location(), endsWith(trustResource.location())); + } + + @Test + public void testDefaultPortSsl() { + GrpcChannelDescriptor chCfg = grpcConfig.channels().get(DEFAULT_PORT_SSL_CFG); + assertThat(chCfg.host(), equalTo("non_default_host.com")); + assertThat(chCfg.port(), equalTo(1408)); + + Resource keyResource = Resource.create(CLIENT_KEY); + Resource certResource = Resource.create(CLIENT_CERT); + Resource trustResource = Resource.create(CA_CERT); + + Optional descriptor = chCfg.tlsDescriptor(); + assertThat(descriptor.isPresent(), is(true)); + GrpcTlsDescriptor ssl = descriptor.get(); + assertThat(ssl, notNullValue()); + assertThat(ssl.isEnabled(), equalTo(true)); + assertThat(ssl.tlsKey(), is(notNullValue())); + assertThat(ssl.tlsKey().location(), is(keyResource.location())); + assertThat(ssl.tlsCert(), is(notNullValue())); + assertThat(ssl.tlsCert().location(), endsWith(certResource.location())); + assertThat(ssl.tlsCaCert(), is(notNullValue())); + assertThat(ssl.tlsCaCert().location(), endsWith(trustResource.location())); + } +} diff --git a/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/JavaMarshaller.java b/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/JavaMarshaller.java new file mode 100644 index 00000000000..05ac855b590 --- /dev/null +++ b/microprofile/grpc/client/src/test/java/io/helidon/microprofile/grpc/client/JavaMarshaller.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022, 2024 Oracle and/or its affiliates. + * + * 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.helidon.microprofile.grpc.client; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import io.helidon.grpc.core.MarshallerSupplier; + +import io.grpc.MethodDescriptor; + +/** + * An implementation of a gRPC {@link io.grpc.MethodDescriptor.Marshaller} that + * uses Java serialization for testing. + */ +public class JavaMarshaller implements MethodDescriptor.Marshaller { + + @Override + public InputStream stream(T obj) { + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(out)) { + oos.writeObject(obj); + return new ByteArrayInputStream(out.toByteArray()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + @SuppressWarnings("unchecked") + public T parse(InputStream in) { + try (ObjectInputStream ois = new ObjectInputStream(in)) { + return (T) ois.readObject(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * A {@link io.helidon.grpc.core.MarshallerSupplier} implementation that supplies + * instances of {@link io.helidon.microprofile.grpc.client.JavaMarshaller}. + */ + public static class Supplier + implements MarshallerSupplier { + @Override + public MethodDescriptor.Marshaller get(Class clazz) { + return new JavaMarshaller<>(); + } + } +} diff --git a/microprofile/grpc/client/src/test/java/services/TreeMapService.java b/microprofile/grpc/client/src/test/java/services/TreeMapService.java new file mode 100644 index 00000000000..973b87f8953 --- /dev/null +++ b/microprofile/grpc/client/src/test/java/services/TreeMapService.java @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. + * + * 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 services; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Objects; +import java.util.TreeMap; + +import io.helidon.webserver.grpc.GrpcService; + +import com.google.protobuf.Descriptors; +import io.grpc.stub.StreamObserver; + +import static io.helidon.grpc.core.ResponseHelper.complete; + +/** + * A simple class that implements gRPC service. Used for testing. + */ +public class TreeMapService implements GrpcService { + + /** + * A reference to a {@link services.TreeMapService.Person} named "Bilbo". + */ + public static Person BILBO = new Person(1, "Bilbo", 111, "Male", + new String[] {"Burglaring", "Pipe smoking"}); + + /** + * A reference to a {@link services.TreeMapService.Person} named "Frodo". + */ + public static Person FRODO = new Person(2, "Frodo", 33, "Male", + new String[] {"Long hikes"}); + + /** + * A reference to a {@link services.TreeMapService.Person} named "Aragon". + */ + public static Person ARAGON = new Person(3, "Aragon", 87, "Male", + new String[] {"Pipe smoking", "Hitting on elvish women"}); + + /** + * A reference to a {@link services.TreeMapService.Person} named "Galadriel". + */ + public static Person GALARDRIEL = new Person(4, "Galadriel", 8372, "Female", + new String[] {"Dwarves"}); + + /** + * A reference to a {@link services.TreeMapService.Person} named "Gandalf". + */ + public static Person GANDALF = new Person(5, "Gandalf", 32767, "Male", + new String[] {"Wizardry"}); + + private final TreeMap lorMap = new TreeMap<>(); + + public TreeMapService() { + lorMap.put(1, BILBO); + lorMap.put(2, FRODO); + lorMap.put(3, ARAGON); + lorMap.put(4, GALARDRIEL); + lorMap.put(5, GANDALF); + } + + @Override + public Descriptors.FileDescriptor proto() { + return null; + } + + @Override + public void update(Routing routing) { + // TODO routing.marshallerSupplier(new JavaMarshaller.Supplier()); + routing.unary("get", this::get); + routing.serverStream("greaterOrEqualTo", this::greaterOrEqualTo); + routing.clientStream("sumOfAges", this::sumOfAges); + routing.bidi("persons", this::persons); + } + + /** + * Retrieve the person from the TreeMap. This is a UNARY call. + * + * @param id The id of the person. + * @param observer the call response + */ + public void get(Integer id, StreamObserver observer) { + complete(observer, lorMap.get(id)); + } + + /** + * Return the Persons whose Ids are greater than or equal to the specified key. This is a ServerStreaming call. + * + * @param id The id to use. + * @param observer A {@link io.grpc.stub.StreamObserver} into which {@link services.TreeMapService.Person}s whose ids + * are greater than or equal to the specified id will be emitted. + */ + public void greaterOrEqualTo(Integer id, StreamObserver observer) { + for (Person p : lorMap.tailMap(id).values()) { + observer.onNext(p); + } + observer.onCompleted(); + } + + /** + * Return the sum of ages of all Persons whose Ids are streamed from the client. This is a Client streaming call. + * + * @param observer A {@link io.grpc.stub.StreamObserver} into which the sum of ages of + * all {@link services.TreeMapService.Person}s will be emitted. + * @return A {@link io.grpc.stub.StreamObserver} into which the ids of {@link services.TreeMapService.Person}s + * should be emitted into. + */ + public StreamObserver sumOfAges(StreamObserver observer) { + return new StreamObserver() { + private int sum = 0; + + public void onNext(Integer id) { + System.out.println("Received id: ==> " + id); + Person p = lorMap.get(id); + sum += p != null ? p.age : 0; + } + + public void onError(Throwable t) { + t.printStackTrace(); + } + + public void onCompleted() { + observer.onNext(sum); + observer.onCompleted(); + } + }; + } + + /** + * Streams the {@link services.TreeMapService.Person} into the specified observer for each of the id that is + * streamed (from the client). This is a bi-directional streaming call. + * + * @param observer A {@link io.grpc.stub.StreamObserver} into which the sum of ages of + * all {@link services.TreeMapService.Person}s will be emitted. + * @return A {@link io.grpc.stub.StreamObserver} into which the ids of {@link services.TreeMapService.Person}s + * should be emitted into. + */ + public StreamObserver persons(StreamObserver observer) { + return new StreamObserver() { + public void onNext(Integer id) { + Person p = lorMap.get(id); + if (p != null) { + observer.onNext(p); + } + } + + public void onError(Throwable t) { + t.printStackTrace(); + } + + public void onCompleted() { + observer.onCompleted(); + } + }; + } + + /** + * A person class used in the test code. + */ + public static class Person implements Serializable { + + private final int id; + private final String name; + private final int age; + private final String gender; + private final String[] hobbies; + + /** + * Creates a new Person. + * @param id The id of the person. + * @param name The name of the person. + * @param age The age of the person. + * @param gender The gender of the person. + * @param hobbies The hobbies of the person. + */ + public Person(int id, String name, int age, String gender, String[] hobbies) { + this.id = id; + this.name = name; + this.age = age; + this.gender = gender; + this.hobbies = hobbies; + } + + /** + * Returns the Id of the person. + * @return The id of the person. + */ + public int getId() { + return id; + } + + /** + * Returns the name of the person. + * @return The name of the person. + */ + public String getName() { + return name; + } + + /** + * Returns the gender of the person. + * @return The gender of the person. + */ + public String getGender() { + return gender; + } + + /** + * Returns the hobbies of the person. + * @return The hobbies of the person. + */ + public String[] getHobbies() { + return hobbies; + } + + /** + * Returns the age of the person. + * @return The age of the person. + */ + public int getAge() { + return age; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + ", age=" + age + + ", gender='" + gender + '\'' + + ", hobbies=" + Arrays.toString(hobbies) + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Person person)) { + return false; + } + return getId() == person.getId() && + getAge() == person.getAge() && + Objects.equals(getName(), person.getName()) && + Objects.equals(getGender(), person.getGender()) && + Arrays.equals(getHobbies(), person.getHobbies()); + } + + @Override + public int hashCode() { + int result = Objects.hash(getId(), getName(), getAge(), getGender()); + result = 31 * result + Arrays.hashCode(getHobbies()); + return result; + } + } +} diff --git a/microprofile/grpc/client/src/test/proto/echo.proto b/microprofile/grpc/client/src/test/proto/echo.proto new file mode 100644 index 00000000000..68911ff5c12 --- /dev/null +++ b/microprofile/grpc/client/src/test/proto/echo.proto @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. + * + * 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. + */ + +syntax = "proto3"; +option java_package = "io.helidon.microprofile.grpc.client.test"; + +service EchoService { + rpc Echo (EchoRequest) returns (EchoResponse) {} +} + +message EchoRequest { + string message = 1; +} + +message EchoResponse { + string message = 1; +} diff --git a/microprofile/grpc/client/src/test/proto/strings.proto b/microprofile/grpc/client/src/test/proto/strings.proto new file mode 100644 index 00000000000..8e01019e310 --- /dev/null +++ b/microprofile/grpc/client/src/test/proto/strings.proto @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019, 2024 Oracle and/or its affiliates. + * + * 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. + */ + + +syntax = "proto3"; +option java_package = "io.helidon.microprofile.grpc.client.test"; + +service StringService { + rpc Upper (StringMessage) returns (StringMessage) {} + rpc Lower (StringMessage) returns (StringMessage) {} + rpc Split (StringMessage) returns (stream StringMessage) {} + rpc Join (stream StringMessage) returns (StringMessage) {} + rpc Echo (stream StringMessage) returns (stream StringMessage) {} +} + +message StringMessage { + string text = 1; +} diff --git a/microprofile/grpc/client/src/test/resources/logging.properties b/microprofile/grpc/client/src/test/resources/logging.properties new file mode 100644 index 00000000000..ab333c926fe --- /dev/null +++ b/microprofile/grpc/client/src/test/resources/logging.properties @@ -0,0 +1,34 @@ +# +# Copyright (c) 2019, 2024 Oracle and/or its affiliates. +# +# 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. +# + +# Example Logging Configuration File +# For more information see $JAVA_HOME/jre/lib/logging.properties + +# Send messages to the console +handlers=io.helidon.common.HelidonConsoleHandler + +# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread +java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n + +# Global logging level. Can be overridden by specific loggers +.level=INFO + +# Component specific log levels +#io.helidon.webserver.level=INFO +#io.helidon.config.level=INFO +#io.helidon.security.level=INFO +#io.helidon.common.level=INFO +#io.netty.level=INFO diff --git a/microprofile/grpc/client/src/test/resources/ssl/ca.pem b/microprofile/grpc/client/src/test/resources/ssl/ca.pem new file mode 100644 index 00000000000..9edce3cf46e --- /dev/null +++ b/microprofile/grpc/client/src/test/resources/ssl/ca.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICpjCCAY4CCQDsAfroMCH4tDANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwIBcNMjAwMzMwMDk1NjU3WhgPMjI5NDAxMTIwOTU2NTdaMBQxEjAQ +BgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKbUgPWd5YM775bazo8MmuMHmYsSacUx+01NKVjbXPz8QHJULfdrYzJEs3yJ2bpP +mOBrXDTmW2+v1TUdSRjytf9b6/+NWixovGwhGF/iXJ9dhMhwp1AwL8PViuuJPTcf +acoAbFn1yJtNjZgalevyyN+eto+UFW+qJ+jn7ncTdReke3DeHiEA+lmk1DlAsGLR +sB2gQBC2Xb8wcCltivb/WJRJG+sHja2BTIUbywmYO9UtuLsLE/Wptl+t8ybObj2G +eE/t7/aM6KTOtXb6Q/Z7YPYSrVtIa/MwkFssmcVG0ldaAszUpq5bLanH5H3AHPN5 +1atNHVIYlwom2SrRazg5IisCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAWnMcVDGq +NxigGhtSFdmbnauLPd47ZEFh6iL+bG7QkT15XtpR5Q4GkxaIb1fTsqaxfj6WUG6Z +n6f9OHSuFGiQbV+h2zNVR4q+i7DcDFkbFrK0XtyUYkdHOot+I7XzURsocnZhWoKO +g+Yi0z4uBSol4olK4KNQLS39ePPrm76CqLf4i8wSUF5YEi0ExWhFgM4+19JvVyQ7 +tqRM1rAWajWp696fKP47ZV2Qn39+BRh8TYKIEdStaWWUxtycC8qhnkXspIG7etcN +3kju90KNuLky6WhNOm84GVZ4w339QTSk65yzUgxTxqJMK6elqgCESTuyGS1EJV00 +t2Dcg5m1p2llRQ== +-----END CERTIFICATE----- diff --git a/microprofile/grpc/client/src/test/resources/ssl/clientCert.pem b/microprofile/grpc/client/src/test/resources/ssl/clientCert.pem new file mode 100644 index 00000000000..49aaa60c6b5 --- /dev/null +++ b/microprofile/grpc/client/src/test/resources/ssl/clientCert.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICmTCCAYECAQEwDQYJKoZIhvcNAQEFBQAwFDESMBAGA1UEAwwJbG9jYWxob3N0 +MCAXDTIwMDMzMDA5NTY1N1oYDzIyOTQwMTEyMDk1NjU3WjAPMQ0wCwYDVQQDDAR0 +ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcZyW23ksgNBBo2P +f4VZxHLj+j6jWVVC5B4Wh3dl9VdSLII3T4uWQbNCoe9vIKZRhsuXn/fbHkd89MFi +GkC02kI+d0RpWULqgnRijbEu5fCsxBYa7dpI0DHkHWjTT2qk2vAw1h+z79orRiVt +wLy4vD4Ig6sbna/1AyK89FRHeq/YSMT3b0jhcxRxWSXmKb81UJ1HjNXIW8bElRcj +Z0vMNQsFWkOWOfyN31NRkM+sqy42fKsMPysitpUz5UQzVxpkm0rom89vDO1VubQl +zGK1gBV3Ll9kkZt5+UjkW/XE9leyRg1iSsY8l5NTp0RJNqpzZkrrPYHFIFhszLNe +NvtB4QIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBv5M6wwOroq1iCz1wyWu/RxSGS +nGn4MdFEeIKTx9urMqTiHp9bW7gVGLHQ96ApxFF30PZ58X1JrJn+eerBaaI7yOo0 +FmVDlacqh5jSDvBoIzC8gFIfcDT/Q1xXmeB0KcgMdoZOhdkrX59qVenxrnihtd2I +uIWhutQB9T6VrTGiCB09gWkULsjHvKMJ1ucSG0a2K18Aqccypd3twXmllwPa/vrt +Kv7s9ZVvYibW7xXJBCV1kiZtx5TV+VO100/Ze94vvnAs7kCLZ16oGOFSj0JpCEFz +CAVAif0/huKd4bpMzwCosCPiKSGLETc6S+WTzoy0FAFmygZHEL9diXriQrMa +-----END CERTIFICATE----- diff --git a/microprofile/grpc/client/src/test/resources/ssl/clientKey.pem b/microprofile/grpc/client/src/test/resources/ssl/clientKey.pem new file mode 100644 index 00000000000..b911b963790 --- /dev/null +++ b/microprofile/grpc/client/src/test/resources/ssl/clientKey.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDFxnJbbeSyA0EG +jY9/hVnEcuP6PqNZVULkHhaHd2X1V1IsgjdPi5ZBs0Kh728gplGGy5ef99seR3z0 +wWIaQLTaQj53RGlZQuqCdGKNsS7l8KzEFhrt2kjQMeQdaNNPaqTa8DDWH7Pv2itG +JW3AvLi8PgiDqxudr/UDIrz0VEd6r9hIxPdvSOFzFHFZJeYpvzVQnUeM1chbxsSV +FyNnS8w1CwVaQ5Y5/I3fU1GQz6yrLjZ8qww/KyK2lTPlRDNXGmSbSuibz28M7VW5 +tCXMYrWAFXcuX2SRm3n5SORb9cT2V7JGDWJKxjyXk1OnREk2qnNmSus9gcUgWGzM +s142+0HhAgMBAAECggEAeZXwg+jhada6SS8KAxmWAEGpihSsE6VpBBjDPPDYS6Yt +LJO5MTvdWfK8ihVKukXFZRsQ0hVsLgdA+K9SglU5WdzTzjrOkUOkLCMk23sMG+yE +KeB1GbjSfrvNQ49IKVCknLyBKYI/+rqjU/J6sLzUzVVNorS0u5KLDCx1Abg2YWNW +6PmVdXQzusZB4NMD1eJOqxK4V0rFtFPkA+MgM74DKcMLz1uPnqZ2335Do6arwppv +Cffk63lLPbfaHu6dC7wmVZFSluQ8Ic+l+k+nwGvPFdbXTgnp+lUcTFBExZzh4vDC +yHW1IhCRb30bSd5VlQzv/5UtBXKjBEFXveHyrBZ6AQKBgQD9tu4G9D6SyNLKB5HI +95EvGkLck/mahGHkiXtLUiDeCBw3KIoHJL7MxpyO3n0yj9WIJV4lcc7kewKcz1SM +uHcVwbCauseD8XzOvulOQy3Sr7E9cuAoGF6Ep9+hUh6xSdClblej1/1yVLbXhW2O +9KTyGiHDzGiJ5baT7P2pQ0ci0QKBgQDHjoUMEBSOFXXKMeRl7h2Tp6KQbBACFMnP +xJpHysMDK5wheqJFmtAm5kgoIZ2fUfAsfU2/Uqbb8ZFYiFck1P6dFNlY0bMzhC3g +Nu2l/MzWTIw/fwZ15hy6JCEjSEAskdzA+AkfcvBQkf1eL64XX1KSVd/z8g9nvTDJ +CDY0jStSEQKBgQCyMWG6Fp9AHrYVWP2mRWJ9z5b4LyHWyXWruneS7irRZqbSgrF2 +1PMBBdl9anxKH8VcaspVyDoENPUfx2pdr01MRY5RDjAE1n3PAzz/T6WGXQlB3EXd +Q0hXKUSim/eckvhsyDPbil6ihycn9bl99wtGUt42E4G0oFb8TC3YTL1QkQKBgQCe +3sDfZKHop/8ZlPTfjV1wouHSFqX78i7kwQGOrEbq7DolkStFPMYAYg8KHBEPuLz7 +vlo6OgPrUHtFP24ZPZTi26lZg8El/1JCkZhLMGKnLVPubSNok2VFb+QN4cRtd0aH +PjCNIAVgL4nGBTGVG+dx5vofjRNkpIMFWQtGdSkK8QKBgQCm087/S1bbm4lZv/sP +HB26w9+gSpyFImU7ZWbsfYHtqbTCYdSru/5nGBHwDjz0uMDDuUo+sL6Vt7bFAArX +jR/edzXbfQf7boXsbPTx07rXvYkCe/usQsXpXQnf5QYlR5njj0r6fRLPfxygRbNS +KSdweVzS2u7UrN/NxBqWRPJcSg== +-----END PRIVATE KEY----- diff --git a/microprofile/grpc/client/src/test/resources/ssl/keys.sh b/microprofile/grpc/client/src/test/resources/ssl/keys.sh new file mode 100644 index 00000000000..91f811a5e60 --- /dev/null +++ b/microprofile/grpc/client/src/test/resources/ssl/keys.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# +# Copyright (c) 2020, 2024 Oracle and/or its affiliates. +# +# 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. +# + +# ------------------------------------------------------------------------ +# This file was used to generate the keys and certs used for SSL testing. +# ------------------------------------------------------------------------ + +# Generate CA key: +openssl genrsa -des3 -passout pass:1111 -out ca.key 2048 + +# Generate CA certificate: +openssl req -passin pass:1111 -new -x509 -days 99999 -key ca.key -out ca.pem -subj "/CN=localhost" + +# Generate server key: +openssl genpkey -out serverKey.pem -algorithm RSA -pkeyopt rsa_keygen_bits:2048 + +# Generate server signing request +openssl req -passin pass:1111 -new -key serverKey.pem -out server.csr -subj "/CN=localhost" + +# Self-signed server certificate: +openssl x509 -req -passin pass:1111 -days 99999 -in server.csr -CA ca.pem -CAkey ca.key -set_serial 01 -out serverCert.pem + +# Generate client key +openssl genpkey -out clientKey.pem -algorithm RSA -pkeyopt rsa_keygen_bits:2048 + +# Generate client signing request: +openssl req -passin pass:1111 -new -key clientKey.pem -out client.csr -subj "/CN=test" + +# Self-signed client certificate: +openssl x509 -passin pass:1111 -req -days 99999 -in client.csr -CA ca.pem -CAkey ca.key -set_serial 01 -out clientCert.pem + +rm ca.key +rm server.csr +rm rm client.csr + diff --git a/microprofile/grpc/client/src/test/resources/ssl/serverCert.pem b/microprofile/grpc/client/src/test/resources/ssl/serverCert.pem new file mode 100644 index 00000000000..058c630aa48 --- /dev/null +++ b/microprofile/grpc/client/src/test/resources/ssl/serverCert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICnjCCAYYCAQEwDQYJKoZIhvcNAQEFBQAwFDESMBAGA1UEAwwJbG9jYWxob3N0 +MCAXDTIwMDMzMDA5NTY1N1oYDzIyOTQwMTEyMDk1NjU3WjAUMRIwEAYDVQQDDAls +b2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDU09otBo1b +sNSakO9hzDe3D37mY6i0q0iG3bIhrWb9crvizpIjyOCYuQzmdHCn488c5mEwZUpB +A14J7OX1HwyQyiA+YtNKrhH6D6lSJyxigt/clmINbLTyTS0HRf2M18SnJLlMb20a +kUSuE9AevQsD/68PEbGJYwNkD8Z/mYsTm8kOXBliMG0EX4vzJy3m/ZywJ4CzISC+ +VGm30hlUosssmfgtqmYSkE+PlrMT9lpcDec7zshOyd2QnEJdJERCC3EzfUpPAffh +iepJrfPwbHBJuOyRH+d/WEQwPP9z+AofsVhIxmgrj943tVMWbLoYSLBWFNPcWFBw +NOAoSE4PRnilAgMBAAEwDQYJKoZIhvcNAQEFBQADggEBABpmJFcAZ25R7AG9aV1i +kcGGivTGRq9snt3cuZyRY1XvQCMhZFaWZ5/WiLf7MCIDWKaZmTIbM2cwVI5b9V36 +nvnYd6JjW3ndtYXM0nFDCM3G5+Mw5FAVYobsup6MFgTVpTsNc8doK+b44A9KzXzB +CWXFN4UWptHsJXvS0gaXATXiAqfUbbY4P83CIQuUy6rV1QF9+OFDjWHvIoWK8VNY +U1IvLwzkeA+WGfNl75sOChQe3kdObkG4vu9xq05rHy7P9urWZ3NJWsby1s9cG7Cl +RaLu5XpaPy2tjEZHSWe0F9A8I5H/p5CCyh8/nzBH7CILvMGDzsIbTJSZEUArT+gy +nXI= +-----END CERTIFICATE----- diff --git a/microprofile/grpc/client/src/test/resources/ssl/serverKey.pem b/microprofile/grpc/client/src/test/resources/ssl/serverKey.pem new file mode 100644 index 00000000000..db5a5ab90f0 --- /dev/null +++ b/microprofile/grpc/client/src/test/resources/ssl/serverKey.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDU09otBo1bsNSa +kO9hzDe3D37mY6i0q0iG3bIhrWb9crvizpIjyOCYuQzmdHCn488c5mEwZUpBA14J +7OX1HwyQyiA+YtNKrhH6D6lSJyxigt/clmINbLTyTS0HRf2M18SnJLlMb20akUSu +E9AevQsD/68PEbGJYwNkD8Z/mYsTm8kOXBliMG0EX4vzJy3m/ZywJ4CzISC+VGm3 +0hlUosssmfgtqmYSkE+PlrMT9lpcDec7zshOyd2QnEJdJERCC3EzfUpPAffhiepJ +rfPwbHBJuOyRH+d/WEQwPP9z+AofsVhIxmgrj943tVMWbLoYSLBWFNPcWFBwNOAo +SE4PRnilAgMBAAECggEBAKgY6EMV4MKiCVpHzXsOJJdnGtD3uAFzI+a55f8piaX3 +YCUFCXJQL+0Qg/rlzzEcArMN14e1CRAOi9EFFqAjtPYLX6pGviJHGJXMluz3Wdw5 +CH2fHbUCvmx+vmj3RAthRMbLf7u6ao9IW9mudnxAzhmLcoZRcEtWNBBtUVfpO2rw ++DA/0+P3vxrJ3Ky/QHcf/us+zpkJqhRn1yYe+J8VsGZVXHhOInlx8m9XHVCj+IDL +StA1n5jdIP6LA/Uu5o7fkWapnG7miyR1cUBrGvh0MrT5TnKNynMK0ooFUx5HcEZJ +hfHxwXMnnTz44kMCDe1BJscN2ElHSaSsfCy6zw0p8qUCgYEA+ZIM1RZe/KtkL4XC +WWTrfjLk39Fh2RgQoferG/HkKe8bNpJkL1RMr7YLA2E6r8O+mxeU46eok1P9Ela4 +TQawXHv5SwnJTmzjEpnO4v1VMYf6+RGAuRvsgMYZZ1HfOV/7x1jRPQOSq4QVepkL +zl2ecIJIKQ43CzJhb/nl0QMO6V8CgYEA2k96P5qRqOm0pXTMPe6UjfonPs5ZY8KQ +YVT9dTAmQgbua13TsbfT7FytDRjtis+GDWOXmUd7r8qvRK1P8zoeZtuDw6S8dR2+ +k/Zf0szYcyjjQkIXmh6ceYwx+vpvbiO5uCYZTePE1fpzMgpkNHzQk+RVpPBnuye1 +X+Jir/fKqHsCgYEA2LjSeeyuWb5ABuCh790qfvGVPSNnVA2IzA31whOhbiTcPdyM +MWmEGoX8NFgnjWBvUeD9g2AhjKa/ukAiVYk8d2OVDWuXK4p0+b8lIIqbg6Kw978S +SC0OiJj+kHFRZlKKowbm1JQYtubBfDARR4iWwN7x6O0WMZvzbzjUMFf2iAMCgYBO +c2cr+iDEAZAAMVPAIb9SsgVuZXrsBZwazg7zEOV+rrz46lPLtpK6iqdJYJ7kViUH +JLXyyCRjjMOlO17Suhz4u4PDR6zNrW2yAER5HVHfOF9KjTOsF7oFV+MSHPL0MnRn +/5DyU5qFhqXk4qUV05CkxNYeGqI8OE3Oci0irTovhwKBgQDyh+03r96OXBoS5H3o +w18ujDZIU/xYdbZXUgBCfAzrjf6uIva046aDVXHqzMsSBm6kY7Xw9vRxJA7E7ckQ +LO7pbmhlriOBiU6fu7oTmvR+k/E9e9KcbbjoftRG48uGabcGcZffO6neZEz2FH2l +7ekffuQqdc/26IWzMZyIVpFG+w== +-----END PRIVATE KEY----- diff --git a/microprofile/grpc/client/src/test/resources/test-client-config.yaml b/microprofile/grpc/client/src/test/resources/test-client-config.yaml new file mode 100644 index 00000000000..3ef2cbbd956 --- /dev/null +++ b/microprofile/grpc/client/src/test/resources/test-client-config.yaml @@ -0,0 +1,50 @@ +# +# Copyright (c) 2019, 2024 Oracle and/or its affiliates. +# +# 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. +# + +grpc: + channels: + default_host_port: + default_host: + port: 4096 + default_port: + host: "non_default_host.com" + default_host_port_ssl_disabled: + tls: + enabled: false + tls-key.resource: + resource-path: "ssl/clientKey.pem" + tls-cert.resource: + resource-path: "ssl/clientCert.pem" + tls-ca-cert.resource: + resource-path: "ssl/ca.pem" + default_host_ssl_one_way: + port: 4096 + tls: + enabled: true + tls-ca-cert.resource: + resource-path: "ssl/ca.pem" + default_port_ssl: + host: "non_default_host.com" + tls: + tls-key.resource: + resource-path: "ssl/clientKey.pem" + tls-cert.resource: + resource-path: "ssl/clientCert.pem" + tls-ca-cert.resource: + resource-path: "ssl/ca.pem" + with_target: + target: "dns://localhost:1408" + load-balancer-policy: "round-robin" \ No newline at end of file