diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEcho1Test.java b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEcho1Test.java index 535cc97971..24af228cf4 100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEcho1Test.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEcho1Test.java @@ -17,25 +17,6 @@ */ package org.apache.knox.gateway.websockets; -import com.mycila.xmltool.XMLDoc; -import com.mycila.xmltool.XMLTag; -import org.apache.commons.io.FileUtils; -import org.apache.knox.gateway.config.GatewayConfig; -import org.apache.knox.gateway.config.impl.GatewayConfigImpl; -import org.apache.knox.gateway.deploy.DeploymentFactory; -import org.apache.knox.gateway.services.DefaultGatewayServices; -import org.apache.knox.gateway.services.ServiceType; -import org.apache.knox.gateway.services.GatewayServices; -import org.apache.knox.gateway.services.ServiceLifecycleException; -import org.apache.knox.gateway.services.topology.TopologyService; -import org.apache.knox.gateway.topology.TopologyEvent; -import org.apache.knox.gateway.topology.TopologyListener; -import org.apache.knox.test.TestUtils; -import org.easymock.EasyMock; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.server.handler.HandlerCollection; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -43,28 +24,9 @@ import javax.websocket.ContainerProvider; import javax.websocket.Session; import javax.websocket.WebSocketContainer; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; import java.net.URI; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; import java.util.concurrent.TimeUnit; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_TYPE; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_TYPE; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -89,40 +51,7 @@ * * @since 0.10 */ -public class WebsocketEcho1Test { - private static final String TEST_KEY_ALIAS = "test-identity"; - - /** - * Simulate backend websocket - */ - private static Server backendServer; - /** - * URI for backend websocket server - */ - private static URI backendServerUri; - - /** - * Mock Gateway server - */ - private static Server gatewayServer; - - /** - * Mock gateway config - */ - private static GatewayConfig gatewayConfig; - - private static GatewayServices services; - - /** - * URI for gateway server - */ - private static URI serverUri; - - private static File topoDir; - private static Path dataDir; - private static Path securityDir; - private static Path keystoresDir; - private static Path keystoreFile; +public class WebsocketEcho1Test extends WebsocketEchoTestBase { public WebsocketEcho1Test() { super(); @@ -130,27 +59,12 @@ public WebsocketEcho1Test() { @BeforeClass public static void setUpBeforeClass() throws Exception { - topoDir = createDir(); - dataDir = Paths.get(topoDir.getAbsolutePath(), "data").toAbsolutePath(); - securityDir = dataDir.resolve("security"); - keystoresDir = securityDir.resolve("keystores"); - keystoreFile = keystoresDir.resolve("tls.jks"); - - startWebsocketServer(); - startGatewayServer(); + WebsocketEchoTestBase.setUpBeforeClass("http"); } @AfterClass public static void tearDownAfterClass() { - try { - gatewayServer.stop(); - backendServer.stop(); - } catch (final Exception e) { - e.printStackTrace(System.err); - } - - /* Cleanup the created files */ - FileUtils.deleteQuietly(topoDir); + WebsocketEchoTestBase.tearDownAfterClass(); } /* @@ -169,242 +83,4 @@ public void testGatewayRewriteHttpEcho() throws Exception { assertThat(client.messageQueue.get(0), is("Echo")); } - - /** - * Start Mock Websocket server that acts as backend. - * @throws Exception exception on websocket server start - */ - private static void startWebsocketServer() throws Exception { - - backendServer = new Server(); - ServerConnector connector = new ServerConnector(backendServer); - backendServer.addConnector(connector); - - final WebsocketEchoHandler handler = new WebsocketEchoHandler(); - - ContextHandler context = new ContextHandler(); - context.setContextPath("/"); - context.setHandler(handler); - backendServer.setHandler(context); - - // Start Server - backendServer.start(); - - String host = connector.getHost(); - if (host == null) { - host = "localhost"; - } - int port = connector.getLocalPort(); - backendServerUri = new URI(String.format(Locale.ROOT, "http://%s:%d/ws", host, port)); - } - - /** - * Start Gateway Server. - * @throws Exception exception on server start - */ - private static void startGatewayServer() throws Exception { - gatewayServer = new Server(); - final ServerConnector connector = new ServerConnector(gatewayServer); - gatewayServer.addConnector(connector); - - /* workaround so we can add our handler later at runtime */ - HandlerCollection handlers = new HandlerCollection(true); - - /* add some initial handlers */ - ContextHandler context = new ContextHandler(); - context.setContextPath("/"); - handlers.addHandler(context); - - gatewayServer.setHandler(handlers); - - // Start Server - gatewayServer.start(); - - String host = connector.getHost(); - if (host == null) { - host = "localhost"; - } - int port = connector.getLocalPort(); - serverUri = new URI(String.format(Locale.ROOT, "ws://%s:%d/", host, port)); - - /* Setup websocket handler */ - setupGatewayConfig(backendServerUri.toString()); - - final GatewayWebsocketHandler gatewayWebsocketHandler = new GatewayWebsocketHandler( - gatewayConfig, services); - handlers.addHandler(gatewayWebsocketHandler); - gatewayWebsocketHandler.start(); - } - - /** - * Initialize the configs and components required for this test. - * @param backend topology to use - * @throws IOException exception on setting up the gateway - */ - private static void setupGatewayConfig(final String backend) throws IOException { - services = new DefaultGatewayServices(); - - URL serviceUrl = ClassLoader.getSystemResource("websocket-services"); - - final File descriptor = new File(topoDir, "websocket.xml"); - try(OutputStream stream = Files.newOutputStream(descriptor.toPath())) { - createKnoxTopology(backend).toStream(stream); - } - - final TestTopologyListener topoListener = new TestTopologyListener(); - - final Map options = new HashMap<>(); - options.put("persist-master", "false"); - options.put("master", "password"); - - gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class); - EasyMock.expect(gatewayConfig.getGatewayTopologyDir()) - .andReturn(topoDir.toString()).anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayProvidersConfigDir()) - .andReturn(topoDir.getAbsolutePath() + "/shared-providers").anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayDescriptorsDir()) - .andReturn(topoDir.getAbsolutePath() + "/descriptors").anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayServicesDir()) - .andReturn(serviceUrl.getFile()).anyTimes(); - - EasyMock.expect(gatewayConfig.getEphemeralDHKeySize()).andReturn("2048") - .anyTimes(); - - /* Websocket configs */ - EasyMock.expect(gatewayConfig.isWebsocketEnabled()).andReturn(true) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageSize()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageSize()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageBufferSize()) - .andReturn( - GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_BUFFER_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageBufferSize()) - .andReturn( - GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_BUFFER_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketInputBufferSize()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_INPUT_BUFFER_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketAsyncWriteTimeout()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_ASYNC_WRITE_TIMEOUT) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketIdleTimeout()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_IDLE_TIMEOUT).anyTimes(); - - EasyMock.expect(gatewayConfig.getRemoteRegistryConfigurationNames()) - .andReturn(Collections.emptyList()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayDataDir()) - .andReturn(dataDir.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewaySecurityDir()) - .andReturn(securityDir.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayKeystoreDir()) - .andReturn(keystoresDir.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeystorePath()) - .andReturn(keystoreFile.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeystoreType()) - .andReturn(DEFAULT_IDENTITY_KEYSTORE_TYPE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeystorePasswordAlias()) - .andReturn(DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeyAlias()) - .andReturn(TEST_KEY_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeyPassphraseAlias()) - .andReturn(DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeystorePasswordAlias()) - .andReturn(DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeyPassphraseAlias()) - .andReturn(DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeystorePath()) - .andReturn(keystoreFile.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeystoreType()) - .andReturn(DEFAULT_SIGNING_KEYSTORE_TYPE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeyAlias()) - .andReturn(TEST_KEY_ALIAS) - .anyTimes(); - - - EasyMock.replay(gatewayConfig); - - try { - services.init(gatewayConfig, options); - } catch (ServiceLifecycleException e) { - e.printStackTrace(); - } - - DeploymentFactory.setGatewayServices(services); - final TopologyService monitor = services - .getService(ServiceType.TOPOLOGY_SERVICE); - monitor.addTopologyChangeListener(topoListener); - monitor.reloadTopologies(); - } - - private static File createDir() throws IOException { - return TestUtils - .createTempDir(WebsocketEchoTest.class.getSimpleName() + "-"); - } - - private static XMLTag createKnoxTopology(final String backend) { - return XMLDoc.newDocument(true).addRoot("topology").addTag("service") - .addTag("role").addText("WEBSOCKET").addTag("url").addText(backend) - .gotoParent().gotoRoot(); - } - - private static class TestTopologyListener implements TopologyListener { - public List> events = new ArrayList<>(); - - @Override - public void handleTopologyEvent(List events) { - this.events.add(events); - - synchronized (this) { - for (TopologyEvent event : events) { - if (!event.getType().equals(TopologyEvent.Type.DELETED)) { - /* for this test we only care about this part */ - DeploymentFactory.createDeployment(gatewayConfig, - event.getTopology()); - } - } - } - } - } } diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java index 58c09c9c71..f30395d542 100644 --- a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java +++ b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTest.java @@ -17,25 +17,6 @@ */ package org.apache.knox.gateway.websockets; -import com.mycila.xmltool.XMLDoc; -import com.mycila.xmltool.XMLTag; -import org.apache.commons.io.FileUtils; -import org.apache.knox.gateway.config.GatewayConfig; -import org.apache.knox.gateway.config.impl.GatewayConfigImpl; -import org.apache.knox.gateway.deploy.DeploymentFactory; -import org.apache.knox.gateway.services.DefaultGatewayServices; -import org.apache.knox.gateway.services.ServiceType; -import org.apache.knox.gateway.services.GatewayServices; -import org.apache.knox.gateway.services.ServiceLifecycleException; -import org.apache.knox.gateway.services.topology.TopologyService; -import org.apache.knox.gateway.topology.TopologyEvent; -import org.apache.knox.gateway.topology.TopologyListener; -import org.apache.knox.test.TestUtils; -import org.easymock.EasyMock; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.server.handler.HandlerCollection; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -43,28 +24,9 @@ import javax.websocket.ContainerProvider; import javax.websocket.Session; import javax.websocket.WebSocketContainer; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; import java.net.URI; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; import java.util.concurrent.TimeUnit; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_TYPE; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_TYPE; -import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -88,40 +50,7 @@ * * @since 0.10 */ -public class WebsocketEchoTest { - private static final String TEST_KEY_ALIAS = "test-identity"; - - /** - * Simulate backend websocket - */ - private static Server backendServer; - /** - * URI for backend websocket server - */ - private static URI backendServerUri; - - /** - * Mock Gateway server - */ - private static Server gatewayServer; - - /** - * Mock gateway config - */ - private static GatewayConfig gatewayConfig; - - private static GatewayServices services; - - /** - * URI for gateway server - */ - private static URI serverUri; - - private static File topoDir; - private static Path dataDir; - private static Path securityDir; - private static Path keystoresDir; - private static Path keystoreFile; +public class WebsocketEchoTest extends WebsocketEchoTestBase { public WebsocketEchoTest() { super(); @@ -129,27 +58,12 @@ public WebsocketEchoTest() { @BeforeClass public static void setUpBeforeClass() throws Exception { - topoDir = createDir(); - dataDir = Paths.get(topoDir.getAbsolutePath(), "data").toAbsolutePath(); - securityDir = dataDir.resolve("security"); - keystoresDir = securityDir.resolve("keystores"); - keystoreFile = keystoresDir.resolve("tls.jks"); - - startWebsocketServer(); - startGatewayServer(); + WebsocketEchoTestBase.setUpBeforeClass("ws"); } @AfterClass public static void tearDownAfterClass() { - try { - gatewayServer.stop(); - backendServer.stop(); - } catch (final Exception e) { - e.printStackTrace(System.err); - } - - /* Cleanup the created files */ - FileUtils.deleteQuietly(topoDir); + WebsocketEchoTestBase.tearDownAfterClass(); } /* @@ -200,242 +114,4 @@ public void testGatewayRewriteEcho() throws Exception { assertThat(client.messageQueue.get(0), is("Echo")); } - - /** - * Start Mock Websocket server that acts as backend. - * @throws Exception exception on websocket server start - */ - private static void startWebsocketServer() throws Exception { - - backendServer = new Server(); - ServerConnector connector = new ServerConnector(backendServer); - backendServer.addConnector(connector); - - final WebsocketEchoHandler handler = new WebsocketEchoHandler(); - - ContextHandler context = new ContextHandler(); - context.setContextPath("/"); - context.setHandler(handler); - backendServer.setHandler(context); - - // Start Server - backendServer.start(); - - String host = connector.getHost(); - if (host == null) { - host = "localhost"; - } - int port = connector.getLocalPort(); - backendServerUri = new URI(String.format(Locale.ROOT, "ws://%s:%d/ws", host, port)); - } - - /** - * Start Gateway Server. - * @throws Exception exception on server start - */ - private static void startGatewayServer() throws Exception { - gatewayServer = new Server(); - final ServerConnector connector = new ServerConnector(gatewayServer); - gatewayServer.addConnector(connector); - - /* workaround so we can add our handler later at runtime */ - HandlerCollection handlers = new HandlerCollection(true); - - /* add some initial handlers */ - ContextHandler context = new ContextHandler(); - context.setContextPath("/"); - handlers.addHandler(context); - - gatewayServer.setHandler(handlers); - - // Start Server - gatewayServer.start(); - - String host = connector.getHost(); - if (host == null) { - host = "localhost"; - } - int port = connector.getLocalPort(); - serverUri = new URI(String.format(Locale.ROOT, "ws://%s:%d/", host, port)); - - /* Setup websocket handler */ - setupGatewayConfig(backendServerUri.toString()); - - final GatewayWebsocketHandler gatewayWebsocketHandler = new GatewayWebsocketHandler( - gatewayConfig, services); - handlers.addHandler(gatewayWebsocketHandler); - gatewayWebsocketHandler.start(); - } - - /** - * Initialize the configs and components required for this test. - * @param backend topology to use - * @throws IOException exception on setting up the gateway - */ - private static void setupGatewayConfig(final String backend) throws IOException { - services = new DefaultGatewayServices(); - - URL serviceUrl = ClassLoader.getSystemResource("websocket-services"); - - final File descriptor = new File(topoDir, "websocket.xml"); - try(OutputStream stream = Files.newOutputStream(descriptor.toPath())) { - createKnoxTopology(backend).toStream(stream); - } - - final TestTopologyListener topoListener = new TestTopologyListener(); - - final Map options = new HashMap<>(); - options.put("persist-master", "false"); - options.put("master", "password"); - - gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class); - EasyMock.expect(gatewayConfig.getGatewayTopologyDir()) - .andReturn(topoDir.toString()).anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayProvidersConfigDir()) - .andReturn(topoDir.getAbsolutePath() + "/shared-providers").anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayDescriptorsDir()) - .andReturn(topoDir.getAbsolutePath() + "/descriptors").anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayServicesDir()) - .andReturn(serviceUrl.getFile()).anyTimes(); - - EasyMock.expect(gatewayConfig.getEphemeralDHKeySize()).andReturn("2048") - .anyTimes(); - - /* Websocket configs */ - EasyMock.expect(gatewayConfig.isWebsocketEnabled()).andReturn(true) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageSize()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageSize()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageBufferSize()) - .andReturn( - GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_BUFFER_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageBufferSize()) - .andReturn( - GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_BUFFER_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketInputBufferSize()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_INPUT_BUFFER_SIZE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketAsyncWriteTimeout()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_ASYNC_WRITE_TIMEOUT) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getWebsocketIdleTimeout()) - .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_IDLE_TIMEOUT).anyTimes(); - - EasyMock.expect(gatewayConfig.getRemoteRegistryConfigurationNames()) - .andReturn(Collections.emptyList()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayDataDir()) - .andReturn(dataDir.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewaySecurityDir()) - .andReturn(securityDir.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getGatewayKeystoreDir()) - .andReturn(keystoresDir.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeystorePath()) - .andReturn(keystoreFile.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeystoreType()) - .andReturn(DEFAULT_IDENTITY_KEYSTORE_TYPE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeystorePasswordAlias()) - .andReturn(DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeyAlias()) - .andReturn(TEST_KEY_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getIdentityKeyPassphraseAlias()) - .andReturn(DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeystorePasswordAlias()) - .andReturn(DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeyPassphraseAlias()) - .andReturn(DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeystorePath()) - .andReturn(keystoreFile.toString()) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeystoreType()) - .andReturn(DEFAULT_SIGNING_KEYSTORE_TYPE) - .anyTimes(); - - EasyMock.expect(gatewayConfig.getSigningKeyAlias()) - .andReturn(TEST_KEY_ALIAS) - .anyTimes(); - - - EasyMock.replay(gatewayConfig); - - try { - services.init(gatewayConfig, options); - } catch (ServiceLifecycleException e) { - e.printStackTrace(); - } - - DeploymentFactory.setGatewayServices(services); - final TopologyService monitor = services - .getService(ServiceType.TOPOLOGY_SERVICE); - monitor.addTopologyChangeListener(topoListener); - monitor.reloadTopologies(); - } - - private static File createDir() throws IOException { - return TestUtils - .createTempDir(WebsocketEchoTest.class.getSimpleName() + "-"); - } - - private static XMLTag createKnoxTopology(final String backend) { - return XMLDoc.newDocument(true).addRoot("topology").addTag("service") - .addTag("role").addText("WEBSOCKET").addTag("url").addText(backend) - .gotoParent().gotoRoot(); - } - - private static class TestTopologyListener implements TopologyListener { - public List> events = new ArrayList<>(); - - @Override - public void handleTopologyEvent(List events) { - this.events.add(events); - - synchronized (this) { - for (TopologyEvent event : events) { - if (!event.getType().equals(TopologyEvent.Type.DELETED)) { - /* for this test we only care about this part */ - DeploymentFactory.createDeployment(gatewayConfig, - event.getTopology()); - } - } - } - } - } } diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTestBase.java b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTestBase.java new file mode 100644 index 0000000000..889418bd18 --- /dev/null +++ b/gateway-server/src/test/java/org/apache/knox/gateway/websockets/WebsocketEchoTestBase.java @@ -0,0 +1,370 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.knox.gateway.websockets; + +import com.mycila.xmltool.XMLDoc; +import com.mycila.xmltool.XMLTag; +import org.apache.commons.io.FileUtils; +import org.apache.knox.gateway.config.GatewayConfig; +import org.apache.knox.gateway.config.impl.GatewayConfigImpl; +import org.apache.knox.gateway.deploy.DeploymentFactory; +import org.apache.knox.gateway.services.DefaultGatewayServices; +import org.apache.knox.gateway.services.ServiceType; +import org.apache.knox.gateway.services.GatewayServices; +import org.apache.knox.gateway.services.ServiceLifecycleException; +import org.apache.knox.gateway.services.topology.TopologyService; +import org.apache.knox.gateway.topology.TopologyEvent; +import org.apache.knox.gateway.topology.TopologyListener; +import org.apache.knox.test.TestUtils; +import org.easymock.EasyMock; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ContextHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS; +import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEYSTORE_TYPE; +import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS; +import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS; +import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEYSTORE_TYPE; +import static org.apache.knox.gateway.config.GatewayConfig.DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS; + +/** + * Base class for tests that attempt to proxy websocket connections through Knox + * gateway. It setups a websocket socket connection that simply echoes data back. + * + */ +public class WebsocketEchoTestBase { + private static final String TEST_KEY_ALIAS = "test-identity"; + + /** + * Simulate backend websocket + */ + private static Server backendServer; + /** + * URI for backend websocket server + */ + public static URI backendServerUri; + + /** + * Mock Gateway server + */ + private static Server gatewayServer; + + /** + * Mock gateway config + */ + private static GatewayConfig gatewayConfig; + + private static GatewayServices services; + + /** + * URI for gateway server + */ + public static URI serverUri; + + private static File topoDir; + private static Path dataDir; + private static Path securityDir; + private static Path keystoresDir; + private static Path keystoreFile; + + public WebsocketEchoTestBase() { + super(); + } + + public static void setUpBeforeClass(String type) throws Exception { + topoDir = createDir(); + dataDir = Paths.get(topoDir.getAbsolutePath(), "data").toAbsolutePath(); + securityDir = dataDir.resolve("security"); + keystoresDir = securityDir.resolve("keystores"); + keystoreFile = keystoresDir.resolve("tls.jks"); + + startWebsocketServer(type); + startGatewayServer(); + } + + public static void tearDownAfterClass() { + try { + gatewayServer.stop(); + backendServer.stop(); + } catch (final Exception e) { + e.printStackTrace(System.err); + } + + /* Cleanup the created files */ + FileUtils.deleteQuietly(topoDir); + } + + /** + * Start Mock Websocket server that acts as backend. + * @throws Exception exception on websocket server start + */ + private static void startWebsocketServer(String type) throws Exception { + + backendServer = new Server(); + ServerConnector connector = new ServerConnector(backendServer); + backendServer.addConnector(connector); + + final WebsocketEchoHandler handler = new WebsocketEchoHandler(); + + ContextHandler context = new ContextHandler(); + context.setContextPath("/"); + context.setHandler(handler); + backendServer.setHandler(context); + + // Start Server + backendServer.start(); + + String host = connector.getHost(); + if (host == null) { + host = "localhost"; + } + int port = connector.getLocalPort(); + if ("http".equals(type)) { + backendServerUri = new URI(String.format(Locale.ROOT, "http://%s:%d/ws", host, port)); + } else { + backendServerUri = new URI(String.format(Locale.ROOT, "ws://%s:%d/ws", host, port)); + } + } + + /** + * Start Gateway Server. + * @throws Exception exception on server start + */ + private static void startGatewayServer() throws Exception { + gatewayServer = new Server(); + final ServerConnector connector = new ServerConnector(gatewayServer); + gatewayServer.addConnector(connector); + + /* workaround so we can add our handler later at runtime */ + HandlerCollection handlers = new HandlerCollection(true); + + /* add some initial handlers */ + ContextHandler context = new ContextHandler(); + context.setContextPath("/"); + handlers.addHandler(context); + + gatewayServer.setHandler(handlers); + + // Start Server + gatewayServer.start(); + + String host = connector.getHost(); + if (host == null) { + host = "localhost"; + } + int port = connector.getLocalPort(); + serverUri = new URI(String.format(Locale.ROOT, "ws://%s:%d/", host, port)); + + /* Setup websocket handler */ + setupGatewayConfig(backendServerUri.toString()); + + final GatewayWebsocketHandler gatewayWebsocketHandler = new GatewayWebsocketHandler( + gatewayConfig, services); + handlers.addHandler(gatewayWebsocketHandler); + gatewayWebsocketHandler.start(); + } + + /** + * Initialize the configs and components required for this test. + * @param backend topology to use + * @throws IOException exception on setting up the gateway + */ + private static void setupGatewayConfig(final String backend) throws IOException { + services = new DefaultGatewayServices(); + + URL serviceUrl = ClassLoader.getSystemResource("websocket-services"); + + final File descriptor = new File(topoDir, "websocket.xml"); + try(OutputStream stream = Files.newOutputStream(descriptor.toPath())) { + createKnoxTopology(backend).toStream(stream); + } + + final TestTopologyListener topoListener = new TestTopologyListener(); + + final Map options = new HashMap<>(); + options.put("persist-master", "false"); + options.put("master", "password"); + + gatewayConfig = EasyMock.createNiceMock(GatewayConfig.class); + EasyMock.expect(gatewayConfig.getGatewayTopologyDir()) + .andReturn(topoDir.toString()).anyTimes(); + + EasyMock.expect(gatewayConfig.getGatewayProvidersConfigDir()) + .andReturn(topoDir.getAbsolutePath() + "/shared-providers").anyTimes(); + + EasyMock.expect(gatewayConfig.getGatewayDescriptorsDir()) + .andReturn(topoDir.getAbsolutePath() + "/descriptors").anyTimes(); + + EasyMock.expect(gatewayConfig.getGatewayServicesDir()) + .andReturn(serviceUrl.getFile()).anyTimes(); + + EasyMock.expect(gatewayConfig.getEphemeralDHKeySize()).andReturn("2048") + .anyTimes(); + + /* Websocket configs */ + EasyMock.expect(gatewayConfig.isWebsocketEnabled()).andReturn(true) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageSize()) + .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageSize()) + .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_SIZE) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getWebsocketMaxTextMessageBufferSize()) + .andReturn( + GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_TEXT_MESSAGE_BUFFER_SIZE) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getWebsocketMaxBinaryMessageBufferSize()) + .andReturn( + GatewayConfigImpl.DEFAULT_WEBSOCKET_MAX_BINARY_MESSAGE_BUFFER_SIZE) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getWebsocketInputBufferSize()) + .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_INPUT_BUFFER_SIZE) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getWebsocketAsyncWriteTimeout()) + .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_ASYNC_WRITE_TIMEOUT) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getWebsocketIdleTimeout()) + .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_IDLE_TIMEOUT).anyTimes(); + + EasyMock.expect(gatewayConfig.getRemoteRegistryConfigurationNames()) + .andReturn(Collections.emptyList()) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getGatewayDataDir()) + .andReturn(dataDir.toString()) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getGatewaySecurityDir()) + .andReturn(securityDir.toString()) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getGatewayKeystoreDir()) + .andReturn(keystoresDir.toString()) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getIdentityKeystorePath()) + .andReturn(keystoreFile.toString()) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getIdentityKeystoreType()) + .andReturn(DEFAULT_IDENTITY_KEYSTORE_TYPE) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getIdentityKeystorePasswordAlias()) + .andReturn(DEFAULT_IDENTITY_KEYSTORE_PASSWORD_ALIAS) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getIdentityKeyAlias()) + .andReturn(TEST_KEY_ALIAS) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getIdentityKeyPassphraseAlias()) + .andReturn(DEFAULT_IDENTITY_KEY_PASSPHRASE_ALIAS) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getSigningKeystorePasswordAlias()) + .andReturn(DEFAULT_SIGNING_KEYSTORE_PASSWORD_ALIAS) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getSigningKeyPassphraseAlias()) + .andReturn(DEFAULT_SIGNING_KEY_PASSPHRASE_ALIAS) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getSigningKeystorePath()) + .andReturn(keystoreFile.toString()) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getSigningKeystoreType()) + .andReturn(DEFAULT_SIGNING_KEYSTORE_TYPE) + .anyTimes(); + + EasyMock.expect(gatewayConfig.getSigningKeyAlias()) + .andReturn(TEST_KEY_ALIAS) + .anyTimes(); + + + EasyMock.replay(gatewayConfig); + + try { + services.init(gatewayConfig, options); + } catch (ServiceLifecycleException e) { + e.printStackTrace(); + } + + DeploymentFactory.setGatewayServices(services); + final TopologyService monitor = services + .getService(ServiceType.TOPOLOGY_SERVICE); + monitor.addTopologyChangeListener(topoListener); + monitor.reloadTopologies(); + } + + private static File createDir() throws IOException { + return TestUtils + .createTempDir(WebsocketEchoTest.class.getSimpleName() + "-"); + } + + private static XMLTag createKnoxTopology(final String backend) { + return XMLDoc.newDocument(true).addRoot("topology").addTag("service") + .addTag("role").addText("WEBSOCKET").addTag("url").addText(backend) + .gotoParent().gotoRoot(); + } + + private static class TestTopologyListener implements TopologyListener { + public List> events = new ArrayList<>(); + + @Override + public void handleTopologyEvent(List events) { + this.events.add(events); + + synchronized (this) { + for (TopologyEvent event : events) { + if (!event.getType().equals(TopologyEvent.Type.DELETED)) { + /* for this test we only care about this part */ + DeploymentFactory.createDeployment(gatewayConfig, + event.getTopology()); + } + } + } + } + } +}