This is an automated email from the ASF dual-hosted git repository. orpiske pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit dea274f3a9c30bfb66dafc3f6b92f1f7f8972376 Author: Otavio Rodolfo Piske <angusyo...@gmail.com> AuthorDate: Wed Sep 7 17:38:25 2022 +0200 CAMEL-18456: created a test infra module for embedded Jetty --- test-infra/camel-test-infra-jetty/pom.xml | 70 ++++++++++++ .../src/main/resources/META-INF/MANIFEST.MF | 0 .../test/infra/jetty/common/JettyProperties.java | 29 +++++ .../infra/jetty/services/JettyConfiguration.java | 117 +++++++++++++++++++ .../jetty/services/JettyConfigurationBuilder.java | 75 +++++++++++++ .../infra/jetty/services/JettyEmbeddedService.java | 124 +++++++++++++++++++++ .../test/infra/jetty/services/JettyService.java | 44 ++++++++ test-infra/pom.xml | 1 + 8 files changed, 460 insertions(+) diff --git a/test-infra/camel-test-infra-jetty/pom.xml b/test-infra/camel-test-infra-jetty/pom.xml new file mode 100644 index 00000000000..6ec3bbb5e3b --- /dev/null +++ b/test-infra/camel-test-infra-jetty/pom.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>camel-test-infra-parent</artifactId> + <groupId>org.apache.camel</groupId> + <relativePath>../camel-test-infra-parent/pom.xml</relativePath> + <version>3.19.0-SNAPSHOT</version> + </parent> + + <modelVersion>4.0.0</modelVersion> + + <artifactId>camel-test-infra-jetty</artifactId> + <name>Camel :: Test Infra :: Jetty</name> + + <dependencies> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-infra-common</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + </dependency> + + <dependency> + <groupId>org.awaitility</groupId> + <artifactId>awaitility</artifactId> + </dependency> + + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-servlet</artifactId> + <version>${jetty-version}</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <version>${jetty-version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + </plugin> + </plugins> + </build> + + +</project> diff --git a/test-infra/camel-test-infra-jetty/src/main/resources/META-INF/MANIFEST.MF b/test-infra/camel-test-infra-jetty/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/common/JettyProperties.java b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/common/JettyProperties.java new file mode 100644 index 00000000000..d01b0604022 --- /dev/null +++ b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/common/JettyProperties.java @@ -0,0 +1,29 @@ +/* + * 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.camel.test.infra.jetty.common; + +public final class JettyProperties { + /** + * The Jetty server address in the format host:port + */ + public static final String JETTY_ADDRESS = "jetty.address"; + + private JettyProperties() { + + } +} diff --git a/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyConfiguration.java b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyConfiguration.java new file mode 100644 index 00000000000..22d11728d45 --- /dev/null +++ b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyConfiguration.java @@ -0,0 +1,117 @@ +/* + * 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.camel.test.infra.jetty.services; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.net.ssl.SSLContext; +import javax.servlet.Servlet; + +import org.eclipse.jetty.servlet.ServletHolder; + +/** + * A configuration holder for embedded Jetty instances + */ +public class JettyConfiguration { + public static final String ROOT_CONTEXT_PATH = "/"; + + /** + * A configuration holder for Jetty servlet holders + * + * @param <T> + */ + public static class ServletConfiguration<T> { + public static final String ROOT_PATH_SPEC = "/*"; + + private final T servlet; + private final String pathSpec; + + public ServletConfiguration(T servlet, String pathSpec) { + this.servlet = servlet; + this.pathSpec = pathSpec; + } + + public T getServlet() { + return servlet; + } + + public String getPathSpec() { + return pathSpec; + } + + public ServletHolder buildServletHolder() { + if (servlet instanceof ServletHolder) { + return (ServletHolder) servlet; + } + + ServletHolder servletHolder = new ServletHolder(); + + if (servlet instanceof String) { + servletHolder.setClassName((String) servlet); + } else { + if (servlet instanceof Servlet) { + servletHolder.setServlet((Servlet) servlet); + } else { + throw new IllegalArgumentException( + "Unknown servlet type: " + (servlet == null ? "null" : servlet.getClass())); + } + } + + return servletHolder; + } + } + + private int port; + private SSLContext sslContext; + private List<ServletConfiguration<?>> servletConfigurations = new ArrayList<>(); + private String contextPath; + + public int getPort() { + return port; + } + + void setPort(int port) { + this.port = port; + } + + public SSLContext getSslContext() { + return sslContext; + } + + void setSslContext(SSLContext sslContext) { + this.sslContext = sslContext; + } + + public String getContextPath() { + return contextPath; + } + + public void setContextPath(String contextPath) { + this.contextPath = contextPath; + } + + void addServletConfiguration(ServletConfiguration<?> servletConfiguration) { + servletConfigurations.add(servletConfiguration); + } + + public List<ServletConfiguration<?>> getServletConfigurations() { + return Collections.unmodifiableList(servletConfigurations); + } +} diff --git a/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyConfigurationBuilder.java b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyConfigurationBuilder.java new file mode 100644 index 00000000000..dc70caab7e0 --- /dev/null +++ b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyConfigurationBuilder.java @@ -0,0 +1,75 @@ +/* + * 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.camel.test.infra.jetty.services; + +import java.util.function.Supplier; + +import javax.net.ssl.SSLContext; + +/** + * This builder can be used to build and configure a configuration holder for embedded Jetty instances + */ +public final class JettyConfigurationBuilder { + private JettyConfiguration jettyConfiguration = new JettyConfiguration(); + + private JettyConfigurationBuilder() { + } + + public JettyConfigurationBuilder withPort(int port) { + jettyConfiguration.setPort(port); + + return this; + } + + public JettyConfigurationBuilder withSslContext(SSLContext sslContext) { + jettyConfiguration.setSslContext(sslContext); + + return this; + } + + public JettyConfigurationBuilder withSslContext(Supplier<SSLContext> contextSupplier) { + return withSslContext(contextSupplier::get); + } + + public JettyConfigurationBuilder addServletConfiguration(JettyConfiguration.ServletConfiguration servletConfiguration) { + jettyConfiguration.addServletConfiguration(servletConfiguration); + + return this; + } + + public JettyConfigurationBuilder withContextPath(String contextPath) { + jettyConfiguration.setContextPath(contextPath); + + return this; + } + + public JettyConfiguration build() { + return jettyConfiguration; + } + + public static JettyConfigurationBuilder emptyTemplate() { + return new JettyConfigurationBuilder(); + } + + public static JettyConfiguration bare() { + // Setups a very basic Jetty server with a randomly allocated port + return emptyTemplate() + .withPort(0) + .build(); + } +} diff --git a/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyEmbeddedService.java b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyEmbeddedService.java new file mode 100644 index 00000000000..b3b484cd3c9 --- /dev/null +++ b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyEmbeddedService.java @@ -0,0 +1,124 @@ +/* + * 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.camel.test.infra.jetty.services; + +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.SSLContext; + +import org.apache.camel.test.infra.jetty.common.JettyProperties; +import org.awaitility.Awaitility; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.SslConnectionFactory; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.util.ssl.SslContextFactory; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * An embedded Jetty service that can be used to run servlets for testing purposes + */ +public class JettyEmbeddedService implements JettyService, BeforeEachCallback, AfterEachCallback { + + private final JettyConfiguration jettyConfiguration; + private ServerConnector connector; + private Server server; + + /** + * Builds an instance of the service using the provided configuration + * + * @param jettyConfiguration the configuration to use when building the service + */ + public JettyEmbeddedService(JettyConfiguration jettyConfiguration) { + this.jettyConfiguration = jettyConfiguration; + } + + private ServerConnector createConnector(JettyConfiguration jettyConfiguration) { + ServerConnector connector; + SSLContext sslContext = jettyConfiguration.getSslContext(); + if (sslContext != null) { + SslContextFactory sslContextFactory = new SslContextFactory.Server(); + sslContextFactory.setSslContext(sslContext); + + connector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, null)); + } else { + connector = new ServerConnector(server); + } + + return connector; + } + + @Override + public void registerProperties() { + System.setProperty(JettyProperties.JETTY_ADDRESS, "localhost:" + getPort()); + } + + @Override + public void initialize() { + try { + server = new Server(jettyConfiguration.getPort()); + + connector = createConnector(jettyConfiguration); + + server.addConnector(connector); + + ServletContextHandler contextHandler = new ServletContextHandler(); + contextHandler.setContextPath(jettyConfiguration.getContextPath()); + for (JettyConfiguration.ServletConfiguration servletConfiguration : jettyConfiguration.getServletConfigurations()) { + contextHandler.addServlet(servletConfiguration.buildServletHolder(), servletConfiguration.getPathSpec()); + } + server.setHandler(contextHandler); + + server.start(); + Awaitility.await().atMost(10, TimeUnit.SECONDS).until(server::isStarted); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void shutdown() { + try { + server.stop(); + + Awaitility.await().atMost(10, TimeUnit.SECONDS).until(server::isStopped); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + server.destroy(); + server = null; + } + } + + @Override + public void afterEach(ExtensionContext extensionContext) throws Exception { + shutdown(); + } + + @Override + public void beforeEach(ExtensionContext extensionContext) throws Exception { + initialize(); + } + + @Override + public int getPort() { + return jettyConfiguration.getPort(); + } +} diff --git a/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyService.java b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyService.java new file mode 100644 index 00000000000..7b7f5776859 --- /dev/null +++ b/test-infra/camel-test-infra-jetty/src/test/java/org/apache/camel/test/infra/jetty/services/JettyService.java @@ -0,0 +1,44 @@ +/* + * 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.camel.test.infra.jetty.services; + +import org.apache.camel.test.infra.common.services.TestService; +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.BeforeAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +/** + * Test infra service for Jetty + */ +public interface JettyService extends BeforeAllCallback, AfterAllCallback, TestService { + @Override + default void beforeAll(ExtensionContext extensionContext) throws Exception { + initialize(); + } + + @Override + default void afterAll(ExtensionContext extensionContext) throws Exception { + shutdown(); + } + + /** + * Gets the port used to run the service + * + * @return the port number + */ + int getPort(); +} diff --git a/test-infra/pom.xml b/test-infra/pom.xml index 6c895552797..e5d6d7eb68e 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -74,5 +74,6 @@ <module>camel-test-infra-openldap</module> <module>camel-test-infra-ignite</module> <module>camel-test-infra-hashicorp-vault</module> + <module>camel-test-infra-jetty</module> </modules> </project>