interop-testing: Add cartesian product HTTP/2 interop test
diff --git a/interop-testing/src/test/java/io/grpc/testing/integration/Http2NettyTest.java b/interop-testing/src/test/java/io/grpc/testing/integration/Http2NettyTest.java
index aead88e..2c741a9 100644
--- a/interop-testing/src/test/java/io/grpc/testing/integration/Http2NettyTest.java
+++ b/interop-testing/src/test/java/io/grpc/testing/integration/Http2NettyTest.java
@@ -16,11 +16,7 @@
package io.grpc.testing.integration;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
import io.grpc.ChannelCredentials;
-import io.grpc.Metadata;
import io.grpc.ServerBuilder;
import io.grpc.ServerCredentials;
import io.grpc.TlsChannelCredentials;
@@ -30,9 +26,7 @@
import io.grpc.netty.InternalNettyServerBuilder;
import io.grpc.netty.NettyChannelBuilder;
import io.grpc.netty.NettyServerBuilder;
-import io.grpc.stub.MetadataUtils;
import java.io.IOException;
-import java.net.InetAddress;
import java.net.InetSocketAddress;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -85,35 +79,7 @@
}
@Test
- public void remoteAddr() {
- InetSocketAddress isa = (InetSocketAddress) obtainRemoteClientAddr();
- assertEquals(InetAddress.getLoopbackAddress(), isa.getAddress());
- // It should not be the same as the server
- assertNotEquals(((InetSocketAddress) getListenAddress()).getPort(), isa.getPort());
- }
-
- @Test
- public void localAddr() throws Exception {
- InetSocketAddress isa = (InetSocketAddress) obtainLocalServerAddr();
- assertEquals(InetAddress.getLoopbackAddress(), isa.getAddress());
- assertEquals(((InetSocketAddress) getListenAddress()).getPort(), isa.getPort());
- }
-
- @Test
public void tlsInfo() {
assertX500SubjectDn("CN=testclient, O=Internet Widgits Pty Ltd, ST=Some-State, C=AU");
}
-
- @Test
- public void contentLengthPermitted() throws Exception {
- // Some third-party gRPC implementations (e.g., ServiceTalk) include Content-Length. The HTTP/2
- // code starting in Netty 4.1.60.Final has special-cased handling of Content-Length, and may
- // call uncommon methods on our custom headers implementation.
- // https://github.com/grpc/grpc-java/issues/7953
- Metadata contentLength = new Metadata();
- contentLength.put(Metadata.Key.of("content-length", Metadata.ASCII_STRING_MARSHALLER), "5");
- blockingStub
- .withInterceptors(MetadataUtils.newAttachHeadersInterceptor(contentLength))
- .emptyCall(EMPTY);
- }
}
diff --git a/interop-testing/src/test/java/io/grpc/testing/integration/Http2Test.java b/interop-testing/src/test/java/io/grpc/testing/integration/Http2Test.java
new file mode 100644
index 0000000..198836b
--- /dev/null
+++ b/interop-testing/src/test/java/io/grpc/testing/integration/Http2Test.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2022 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.testing.integration;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import io.grpc.ChannelCredentials;
+import io.grpc.ManagedChannelBuilder;
+import io.grpc.Metadata;
+import io.grpc.ServerBuilder;
+import io.grpc.ServerCredentials;
+import io.grpc.TlsChannelCredentials;
+import io.grpc.TlsServerCredentials;
+import io.grpc.internal.testing.TestUtils;
+import io.grpc.netty.InternalNettyChannelBuilder;
+import io.grpc.netty.InternalNettyServerBuilder;
+import io.grpc.netty.NettyChannelBuilder;
+import io.grpc.netty.NettyServerBuilder;
+import io.grpc.okhttp.InternalOkHttpChannelBuilder;
+import io.grpc.okhttp.InternalOkHttpServerBuilder;
+import io.grpc.okhttp.OkHttpChannelBuilder;
+import io.grpc.okhttp.OkHttpServerBuilder;
+import io.grpc.stub.MetadataUtils;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.Arrays;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * Integration tests for GRPC over the various HTTP2 transports.
+ */
+@RunWith(Parameterized.class)
+public class Http2Test extends AbstractInteropTest {
+ @BeforeClass
+ public static void loadConscrypt() throws Exception {
+ // Load conscrypt if it is available. Either Conscrypt or Jetty ALPN needs to be available for
+ // OkHttp to negotiate.
+ TestUtils.installConscryptIfAvailable();
+ }
+
+ enum Transport {
+ NETTY, OKHTTP;
+ }
+
+ /** Parameterized test cases. */
+ @Parameters(name = "client={0},server={1}")
+ public static Iterable<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ {Transport.NETTY, Transport.NETTY},
+ {Transport.OKHTTP, Transport.OKHTTP},
+ {Transport.OKHTTP, Transport.NETTY},
+ {Transport.NETTY, Transport.OKHTTP},
+ });
+ }
+
+ private final Transport clientType;
+ private final Transport serverType;
+
+ public Http2Test(Transport clientType, Transport serverType) {
+ this.clientType = clientType;
+ this.serverType = serverType;
+ }
+
+ @Override
+ protected ServerBuilder<?> getServerBuilder() {
+ // Starts the server with HTTPS.
+ ServerCredentials serverCreds;
+ try {
+ serverCreds = TlsServerCredentials.create(
+ TestUtils.loadCert("server1.pem"), TestUtils.loadCert("server1.key"));
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ ServerBuilder<?> builder;
+ if (serverType == Transport.NETTY) {
+ NettyServerBuilder nettyBuilder = NettyServerBuilder.forPort(0, serverCreds)
+ .flowControlWindow(AbstractInteropTest.TEST_FLOW_CONTROL_WINDOW);
+ // Disable the default census stats tracer, use testing tracer instead.
+ InternalNettyServerBuilder.setStatsEnabled(nettyBuilder, false);
+ builder = nettyBuilder;
+ } else {
+ OkHttpServerBuilder okHttpBuilder = OkHttpServerBuilder.forPort(0, serverCreds)
+ .flowControlWindow(AbstractInteropTest.TEST_FLOW_CONTROL_WINDOW);
+ // Disable the default census stats tracer, use testing tracer instead.
+ InternalOkHttpServerBuilder.setStatsEnabled(okHttpBuilder, false);
+ builder = okHttpBuilder;
+ }
+ return builder
+ .maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE)
+ .addStreamTracerFactory(createCustomCensusTracerFactory());
+ }
+
+ @Override
+ protected ManagedChannelBuilder<?> createChannelBuilder() {
+ ChannelCredentials channelCreds;
+ try {
+ channelCreds = TlsChannelCredentials.newBuilder()
+ .trustManager(TestUtils.loadCert("ca.pem"))
+ .build();
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ int port = ((InetSocketAddress) getListenAddress()).getPort();
+ ManagedChannelBuilder<?> builder;
+ if (clientType == Transport.NETTY) {
+ NettyChannelBuilder nettyBuilder = NettyChannelBuilder
+ .forAddress("localhost", port, channelCreds)
+ .flowControlWindow(AbstractInteropTest.TEST_FLOW_CONTROL_WINDOW);
+ // Disable the default census stats interceptor, use testing interceptor instead.
+ InternalNettyChannelBuilder.setStatsEnabled(nettyBuilder, false);
+ builder = nettyBuilder;
+ } else {
+ OkHttpChannelBuilder okHttpBuilder = OkHttpChannelBuilder
+ .forAddress("localhost", port, channelCreds)
+ .flowControlWindow(AbstractInteropTest.TEST_FLOW_CONTROL_WINDOW);
+ // Disable the default census stats interceptor, use testing interceptor instead.
+ InternalOkHttpChannelBuilder.setStatsEnabled(okHttpBuilder, false);
+ builder = okHttpBuilder;
+ }
+ return builder
+ .overrideAuthority(TestUtils.TEST_SERVER_HOST)
+ .maxInboundMessageSize(AbstractInteropTest.MAX_MESSAGE_SIZE)
+ .intercept(createCensusStatsClientInterceptor());
+ }
+
+ @Test
+ public void remoteAddr() {
+ InetSocketAddress isa = (InetSocketAddress) obtainRemoteClientAddr();
+ assertEquals(InetAddress.getLoopbackAddress(), isa.getAddress());
+ // It should not be the same as the server
+ assertNotEquals(((InetSocketAddress) getListenAddress()).getPort(), isa.getPort());
+ }
+
+ @Test
+ public void localAddr() throws Exception {
+ InetSocketAddress isa = (InetSocketAddress) obtainLocalServerAddr();
+ assertEquals(InetAddress.getLoopbackAddress(), isa.getAddress());
+ assertEquals(((InetSocketAddress) getListenAddress()).getPort(), isa.getPort());
+ }
+
+ @Test
+ public void contentLengthPermitted() throws Exception {
+ // Some third-party gRPC implementations (e.g., ServiceTalk) include Content-Length. The HTTP/2
+ // code starting in Netty 4.1.60.Final has special-cased handling of Content-Length, and may
+ // call uncommon methods on our custom headers implementation.
+ // https://github.com/grpc/grpc-java/issues/7953
+ Metadata contentLength = new Metadata();
+ contentLength.put(Metadata.Key.of("content-length", Metadata.ASCII_STRING_MARSHALLER), "5");
+ blockingStub
+ .withInterceptors(MetadataUtils.newAttachHeadersInterceptor(contentLength))
+ .emptyCall(EMPTY);
+ }
+}
diff --git a/okhttp/src/main/java/io/grpc/okhttp/InternalOkHttpServerBuilder.java b/okhttp/src/main/java/io/grpc/okhttp/InternalOkHttpServerBuilder.java
new file mode 100644
index 0000000..78a409a
--- /dev/null
+++ b/okhttp/src/main/java/io/grpc/okhttp/InternalOkHttpServerBuilder.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 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.okhttp;
+
+import io.grpc.Internal;
+import io.grpc.ServerStreamTracer;
+import io.grpc.internal.InternalServer;
+import io.grpc.internal.TransportTracer;
+import java.util.List;
+
+/**
+ * Internal {@link OkHttpServerBuilder} accessor. This is intended for usage internal to
+ * the gRPC team. If you *really* think you need to use this, contact the gRPC team first.
+ */
+@Internal
+public final class InternalOkHttpServerBuilder {
+ public static InternalServer buildTransportServers(OkHttpServerBuilder builder,
+ List<? extends ServerStreamTracer.Factory> streamTracerFactories) {
+ return builder.buildTransportServers(streamTracerFactories);
+ }
+
+ public static void setTransportTracerFactory(OkHttpServerBuilder builder,
+ TransportTracer.Factory transportTracerFactory) {
+ builder.setTransportTracerFactory(transportTracerFactory);
+ }
+
+ public static void setStatsEnabled(OkHttpServerBuilder builder, boolean value) {
+ builder.setStatsEnabled(value);
+ }
+
+ private InternalOkHttpServerBuilder() {}
+}