From 75dcc7543ab1472d35fb56374901fc67fb9fc31f Mon Sep 17 00:00:00 2001 From: Mickael Jeanroy Date: Sat, 25 Nov 2023 14:56:54 +0100 Subject: [PATCH] feat: add jetty 12 module --- junit-servers-jetty-12/pom.xml | 150 +++++++++ .../junit/servers/jetty11/EmbeddedJetty.java | 297 ++++++++++++++++++ .../servers/jetty11/EmbeddedJettyFactory.java | 186 +++++++++++ .../jetty11/EmbeddedJettyProvider.java | 44 +++ .../junit4/AbstractJettyJunit4Test.java | 43 +++ .../jetty11/junit4/JettyServerJunit4Rule.java | 59 ++++ .../junit4/JettyServerJunit4Runner.java | 64 ++++ .../jetty11/jupiter/JettyServerExtension.java | 85 +++++ .../servers/jetty11/jupiter/JettyTest.java | 43 +++ ...nit.servers.servers.EmbeddedServerProvider | 27 ++ .../jetty11/EmbeddedJettyFactoryTest.java | 109 +++++++ .../jetty11/EmbeddedJettyProviderTest.java | 54 ++++ .../servers/jetty11/EmbeddedJettyTest.java | 194 ++++++++++++ .../servers/jetty11/JettyJunit4Test.java | 49 +++ .../jetty11/JettyServerJunit4RuleTest.java | 135 ++++++++ .../jetty11/JettyServerJunit4RunnerTest.java | 97 ++++++ .../jetty11/junit4/JettyJunit4Test.java | 48 +++ .../junit4/JettyServerJunit4RuleTest.java | 135 ++++++++ .../junit4/JettyServerJunit4RunnerTest.java | 97 ++++++ .../jetty11/jupiter/FakeExtensionContext.java | 206 ++++++++++++ .../servers/jetty11/jupiter/FakeStore.java | 106 +++++++ .../servers/jetty11/jupiter/FixtureClass.java | 44 +++ .../jupiter/JettyServerExtensionTest.java | 87 +++++ ...EmbeddedJettyConfigurationMockBuilder.java | 44 +++ .../tests/EmbeddedJettyMockBuilder.java | 192 +++++++++++ .../servers/junit4/JunitServerRunnerTest.java | 93 ++++++ .../junit/servers/junit4/ServerRuleTest.java | 82 +++++ .../src/test/resources/custom-web.xml | 38 +++ .../src/test/resources/hello-world.html | 7 + .../src/test/resources/index.html | 7 + .../src/test/resources/logback-test.xml | 35 +++ pom.xml | 21 ++ 32 files changed, 2878 insertions(+) create mode 100644 junit-servers-jetty-12/pom.xml create mode 100644 junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJetty.java create mode 100644 junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyFactory.java create mode 100644 junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyProvider.java create mode 100644 junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/AbstractJettyJunit4Test.java create mode 100644 junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4Rule.java create mode 100644 junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4Runner.java create mode 100644 junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyServerExtension.java create mode 100644 junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyTest.java create mode 100644 junit-servers-jetty-12/src/main/resources/META-INF/services/com.github.mjeanroy.junit.servers.servers.EmbeddedServerProvider create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyFactoryTest.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyProviderTest.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyTest.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyJunit4Test.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyServerJunit4RuleTest.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyServerJunit4RunnerTest.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyJunit4Test.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4RuleTest.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4RunnerTest.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FakeExtensionContext.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FakeStore.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FixtureClass.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyServerExtensionTest.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/tests/EmbeddedJettyConfigurationMockBuilder.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/tests/EmbeddedJettyMockBuilder.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/junit4/JunitServerRunnerTest.java create mode 100644 junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/junit4/ServerRuleTest.java create mode 100644 junit-servers-jetty-12/src/test/resources/custom-web.xml create mode 100644 junit-servers-jetty-12/src/test/resources/hello-world.html create mode 100644 junit-servers-jetty-12/src/test/resources/index.html create mode 100644 junit-servers-jetty-12/src/test/resources/logback-test.xml diff --git a/junit-servers-jetty-12/pom.xml b/junit-servers-jetty-12/pom.xml new file mode 100644 index 00000000..9fc729d0 --- /dev/null +++ b/junit-servers-jetty-12/pom.xml @@ -0,0 +1,150 @@ + + + + 4.0.0 + + + junit-servers + com.github.mjeanroy + 3.0.1-SNAPSHOT + + + junit-servers-jetty-12 + junit-servers-jetty-12 + jar + https://github.com/mjeanroy/junit-servers + Add Jetty 12 Embedded Server to your junit tests case. + + + com.github.mjeanroy.junit.servers.jetty9 + + + + + com.github.mjeanroy + junit-servers-core + ${project.version} + + + + junit + junit + provided + + + org.junit.jupiter + junit-jupiter-api + provided + + + + org.eclipse.jetty + jetty-server + ${jetty12.version} + + + org.eclipse.jetty + jetty-jndi + ${jetty12.version} + + + org.eclipse.jetty + jetty-util + ${jetty12.version} + + + org.eclipse.jetty.ee10 + jetty-ee10-servlet + ${jetty12.version} + + + org.eclipse.jetty.ee10 + jetty-ee10-servlets + ${jetty12.version} + + + org.eclipse.jetty.ee10 + jetty-ee10-webapp + ${jetty12.version} + + + org.eclipse.jetty.ee10 + jetty-ee10-apache-jsp + ${jetty12.version} + + + org.eclipse.jetty.ee10 + jetty-ee10-annotations + ${jetty12.version} + + + org.eclipse.jetty.websocket + jetty-websocket-jetty-server + ${jetty12.version} + + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.vintage + junit-vintage-engine + test + + + org.assertj + assertj-core + test + + + org.mockito + mockito-core + test + + + org.apache.commons + commons-lang3 + test + + + nl.jqno.equalsverifier + equalsverifier + test + + + com.squareup.okhttp3 + okhttp + test + + + org.slf4j + slf4j-api + test + + + ch.qos.logback + logback-classic + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.codehaus.mojo + versions-maven-plugin + + + + diff --git a/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJetty.java b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJetty.java new file mode 100644 index 00000000..c201595b --- /dev/null +++ b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJetty.java @@ -0,0 +1,297 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11; + +import com.github.mjeanroy.junit.servers.commons.core.CompositeClassLoader; +import com.github.mjeanroy.junit.servers.commons.core.Java; +import com.github.mjeanroy.junit.servers.exceptions.ServerInitializationException; +import com.github.mjeanroy.junit.servers.exceptions.ServerStartException; +import com.github.mjeanroy.junit.servers.exceptions.ServerStopException; +import com.github.mjeanroy.junit.servers.jetty.AbstractEmbeddedJetty; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import com.github.mjeanroy.junit.servers.loggers.Logger; +import com.github.mjeanroy.junit.servers.loggers.LoggerFactory; +import com.github.mjeanroy.junit.servers.servers.AbstractEmbeddedServer; +import org.eclipse.jetty.ee10.annotations.AnnotationConfiguration; +import org.eclipse.jetty.ee10.webapp.FragmentConfiguration; +import org.eclipse.jetty.ee10.webapp.JettyWebXmlConfiguration; +import org.eclipse.jetty.ee10.webapp.MetaInfConfiguration; +import org.eclipse.jetty.ee10.webapp.WebAppContext; +import org.eclipse.jetty.ee10.webapp.WebInfConfiguration; +import org.eclipse.jetty.ee10.webapp.WebXmlConfiguration; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.util.resource.PathResourceFactory; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.util.resource.ResourceFactory; + +import java.io.File; + +import static com.github.mjeanroy.junit.servers.commons.lang.Strings.isNotBlank; + +/** + * Jetty 11 Embedded Server. + */ +public class EmbeddedJetty extends AbstractEmbeddedServer { + + /** + * Class Logger. + */ + private static final Logger log = LoggerFactory.getLogger(AbstractEmbeddedJetty.class); + + /** + * Instance of Jetty Server. + */ + private final Server server; + + /** + * Jetty Web App Context. + */ + private volatile WebAppContext webAppContext; + + /** + * Server Connector, lazily initialized. + */ + private volatile ServerConnector connector; + + /** + * Build embedded jetty server with default configuration. + */ + public EmbeddedJetty() { + this(EmbeddedJettyConfiguration.defaultConfiguration()); + } + + /** + * Build embedded jetty server. + * + * @param configuration Server configuration. + */ + public EmbeddedJetty(EmbeddedJettyConfiguration configuration) { + super(configuration); + this.server = initServer(); + } + + private Server initServer() { + log.debug("Initialize jetty server"); + Server server = new Server(configuration.getPort()); + server.setStopAtShutdown(configuration.isStopAtShutdown()); + server.setStopTimeout(configuration.getStopTimeout()); + return server; + } + + private WebAppContext initContext() { + try { + log.debug("Initialize jetty webapp context"); + return createdWebAppContext(); + } + catch (Exception ex) { + log.error(ex.getMessage(), ex); + throw new ServerInitializationException(ex); + } + } + + @Override + public Server getDelegate() { + return server; + } + + @Override + protected void doStart() { + try { + log.debug("Initializing embedded jetty context"); + webAppContext = initContext(); + + log.debug("Starting embedded jetty"); + server.start(); + + log.debug("Looking for embedded jetty server connector"); + connector = findConnector(); + } + catch (Exception ex) { + log.error(ex.getMessage(), ex); + throw new ServerStartException(ex); + } + } + + /** + * Build web app context used to launch server. + * May be override by subclasses. + * + * @throws Exception May be thrown by web app context initialization (will be wrapped later). + */ + private WebAppContext createdWebAppContext() throws Exception { + final String path = configuration.getPath(); + final String webapp = configuration.getWebapp(); + final String classpath = configuration.getClasspath(); + final ClassLoader parentClassLoader = configuration.getParentClassLoader(); + final String overrideDescriptor = configuration.getOverrideDescriptor(); + final Resource baseResource = configuration.getBaseResource(); + final String containerJarPattern = configuration.getContainerJarPattern(); + final String webInfJarPattern = configuration.getWebInfJarPattern(); + + final WebAppContext ctx = new WebAppContext(); + + if (containerJarPattern != null) { + log.debug("Setting jetty 'containerJarPattern' attribute: {}", containerJarPattern); + ctx.setAttribute(containerJarPatternPropertyName(), containerJarPattern); + } + else if (Java.isPostJdk9()) { + // Fix to make TLD scanning works with Java >= 9 + log.debug("Setting default jetty 'containerJarPattern' for JRE >= 9: {}"); + ctx.setAttribute(containerJarPatternPropertyName(), ".*\\.jar"); + } + + if (webInfJarPattern != null) { + log.debug("Setting jetty 'WebInfJarPattern' attribute: {}", webInfJarPattern); + ctx.setAttribute(webInfJarPatternPropertyName(), webInfJarPattern); + } + + final ClassLoader systemClassLoader = Thread.currentThread().getContextClassLoader(); + final ClassLoader classLoader; + + if (parentClassLoader != null) { + log.debug("Overriding jetty parent classloader"); + classLoader = new CompositeClassLoader(parentClassLoader, systemClassLoader); + } + else { + log.debug("Using current thread classloader as jetty parent classloader"); + classLoader = systemClassLoader; + } + + log.debug("Set jetty classloader"); + ctx.setClassLoader(classLoader); + + log.debug("Set jetty context path to: {}", path); + ctx.setContextPath(path); + + Resource actualBaseResource = baseResource; + if (actualBaseResource == null) { + log.debug("Initializing default jetty base resource from: {}", webapp); + actualBaseResource = ResourceFactory.of(ctx).newResource(webapp); + } + else { + log.debug("Initializing jetty base resource from: {}", baseResource); + } + + if (actualBaseResource != null) { + ctx.setBaseResource(actualBaseResource); + } + + if (overrideDescriptor != null) { + log.debug("Set jetty descriptor: {}", overrideDescriptor); + ctx.setOverrideDescriptor(overrideDescriptor); + } + + ctx.addConfiguration(new WebInfConfiguration()); + ctx.addConfiguration(new WebXmlConfiguration()); + ctx.addConfiguration(new AnnotationConfiguration()); + ctx.addConfiguration(new JettyWebXmlConfiguration()); + ctx.addConfiguration(new MetaInfConfiguration()); + ctx.addConfiguration(new FragmentConfiguration()); + + log.debug("Initializing jetty configuration classes"); + if (actualBaseResource == null) { + ctx.removeConfiguration(WebInfConfiguration.class); + } + + if (isNotBlank(classpath)) { + log.debug("Adding jetty container resource: {}", classpath); + + // Fix to scan Spring WebApplicationInitializer + // This will add compiled classes to jetty classpath + // See: http://stackoverflow.com/questions/13222071/spring-3-1-webapplicationinitializer-embedded-jetty-8-annotationconfiguration + // And more precisely: http://stackoverflow.com/a/18449506/1215828 + final File classes = new File(classpath); + final Resource containerResources = new PathResourceFactory().newResource(classes.toURI()); + ctx.getMetaData().addContainerResource(containerResources); + } + + ctx.setParentLoaderPriority(true); + ctx.setWar(webapp); + ctx.setServer(server); + + // Add server context + server.setHandler(ctx); + + return ctx; + } + + @Override + protected void doStop() { + try { + log.debug("Stopping embedded jettu"); + server.stop(); + + log.debug("Clearing jetty webapp context"); + webAppContext = null; + + log.debug("Clearing jetty server connector"); + connector = null; + } + catch (Exception ex) { + throw new ServerStopException(ex); + } + } + + @Override + public String getScheme() { + return isStarted() ? server.getURI().getScheme() : super.getScheme(); + } + + @Override + public Object getServletContext() { + return webAppContext.getServletContext(); + } + + @Override + protected int doGetPort() { + return connector.getLocalPort(); + } + + private String containerJarPatternPropertyName() { + return MetaInfConfiguration.CONTAINER_JAR_PATTERN; + } + + private String webInfJarPatternPropertyName() { + return MetaInfConfiguration.WEBINF_JAR_PATTERN; + } + + private WebAppContext getWebAppContext() { + return webAppContext; + } + + private ServerConnector findConnector() { + log.debug("Extracting jetty server connector"); + for (Connector connector : server.getConnectors()) { + if (connector instanceof ServerConnector) { + return (ServerConnector) connector; + } + } + + log.warn("Cannot find jetty server connector"); + return null; + } +} diff --git a/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyFactory.java b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyFactory.java new file mode 100644 index 00000000..fffc51d8 --- /dev/null +++ b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyFactory.java @@ -0,0 +1,186 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11; + +import com.github.mjeanroy.junit.servers.jetty.AbstractEmbeddedJettyFactory; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfigurationProvider; +import com.github.mjeanroy.junit.servers.jetty.IllegalJettyConfigurationException; +import com.github.mjeanroy.junit.servers.jetty.JettyConfiguration; +import com.github.mjeanroy.junit.servers.loggers.Logger; +import com.github.mjeanroy.junit.servers.loggers.LoggerFactory; +import com.github.mjeanroy.junit.servers.servers.AbstractConfiguration; + +import static com.github.mjeanroy.junit.servers.commons.reflect.Annotations.findAnnotation; +import static com.github.mjeanroy.junit.servers.commons.reflect.Classes.instantiate; +import static com.github.mjeanroy.junit.servers.engine.Servers.findConfiguration; + +/** + * Static factories for {@link EmbeddedJetty} that can be used in JUnit 4 Runner implementation + * or JUnit Jupiter Extension. + */ +public final class EmbeddedJettyFactory { + + /** + * Class Logger. + */ + private static final Logger log = LoggerFactory.getLogger(AbstractEmbeddedJettyFactory.class); + + private static final EmbeddedJettyFactory INSTANCE = new EmbeddedJettyFactory(); + + /** + * Instantiate embedded jetty from given test class. + * + * @param testClass The test class. + * @return Created embedded jetty instance. + */ + public static EmbeddedJetty createFrom(Class testClass) { + return INSTANCE.instantiateFrom(testClass); + } + + /** + * Instantiate embedded jetty from given test class, with given provided configuration (may be {@code null}). + * + * @param testClass The test class. + * @param configuration The configuration to use, may be {@code null}. + * @return Created embedded jetty instance. + */ + public static EmbeddedJetty createFrom(Class testClass, AbstractConfiguration configuration) { + if (configuration == null) { + return createFrom(testClass); + } + + if (!(configuration instanceof EmbeddedJettyConfiguration)) { + throw new IllegalJettyConfigurationException(EmbeddedJettyConfiguration.class); + } + + return INSTANCE.instantiateFrom(testClass, (EmbeddedJettyConfiguration) configuration); + } + + // Ensure non instantiation. + private EmbeddedJettyFactory() { + } + + /** + * Instantiate embedded jetty from given test class. + * + * @param testClass The test class. + * @return Created embedded jetty instance. + */ + private EmbeddedJetty instantiateFrom(Class testClass) { + return instantiateFrom(testClass, null); + } + + /** + * Instantiate embedded jetty from given test class, with given provided configuration (may be {@code null}). + * + * @param testClass The test class. + * @param configuration The configuration to use, may be {@code null}. + * @return Created embedded jetty instance. + */ + private EmbeddedJetty instantiateFrom(Class testClass, EmbeddedJettyConfiguration configuration) { + log.debug("Instantiating embedded jetty for test class: {}", testClass); + EmbeddedJettyConfiguration configurationToUse = extractConfiguration(testClass, configuration); + return configurationToUse == null ? instantiateFrom() : instantiateFrom(configurationToUse); + } + + private EmbeddedJetty instantiateFrom() { + return new EmbeddedJetty(); + } + + private EmbeddedJetty instantiateFrom(EmbeddedJettyConfiguration config) { + return new EmbeddedJetty(config); + } + + /** + * Try to extract Jetty configuration from: + *
    + *
  • The given {@code configuration} if it is not {@code null}.
  • + *
  • A class field/method annotated with {@link com.github.mjeanroy.junit.servers.annotations.TestServerConfiguration} on given {@code testClass} otherwise.
  • + *
+ * + * @param testClass The test class to analyze. + * @param configuration The configuration to use if not {@code null}. + * @return The Jetty configuration. + * @throws IllegalJettyConfigurationException If extracted {@code configuration} is not an instance of required configuration type. + */ + private EmbeddedJettyConfiguration extractConfiguration(Class testClass, EmbeddedJettyConfiguration configuration) { + if (configuration != null) { + log.debug("Returning provided configuration instance: {}", configuration); + return checkConfiguration(configuration); + } + + Class providerClass = findEmbeddedJettyConfigurationProvider(testClass); + if (providerClass != null) { + return buildEmbeddedJettyConfiguration(testClass, providerClass); + } + + log.debug("Extracting configuration from given test class: {}", testClass); + return checkConfiguration( + findConfiguration(testClass) + ); + } + + private Class findEmbeddedJettyConfigurationProvider(Class testClass) { + JettyConfiguration configurationAnnotation = findAnnotation(testClass, JettyConfiguration.class); + return configurationAnnotation == null ? null : configurationAnnotation.providedBy(); + } + + /** + * Create configuration using custom annotation, dedicated to Jetty. + * + * @param testClass The tested class. + * @param providerClass The provider class. + * @return The configuration. + */ + private EmbeddedJettyConfiguration buildEmbeddedJettyConfiguration( + Class testClass, + Class providerClass + ) { + log.debug("Returning configuration provided by test class"); + EmbeddedJettyConfigurationProvider provider = instantiate(providerClass); + return provider.build(testClass); + } + + /** + * Ensure that given {@code configuration} parameter is an instance of compatible class and returns it, + * or fail with {@link IllegalJettyConfigurationException} otherwise. + * + * @param configuration The configuration. + * @return The configuration. + */ + private EmbeddedJettyConfiguration checkConfiguration(Object configuration) { + if (configuration == null) { + return null; + } + + if (!(configuration instanceof EmbeddedJettyConfiguration)) { + log.error("Cannot instantiate embedded jetty using configuration {} because it does not extends {} class", configuration, EmbeddedJettyConfiguration.class); + throw new IllegalJettyConfigurationException(EmbeddedJettyConfiguration.class); + } + + return (EmbeddedJettyConfiguration) configuration; + } +} diff --git a/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyProvider.java b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyProvider.java new file mode 100644 index 00000000..5aa9465d --- /dev/null +++ b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyProvider.java @@ -0,0 +1,44 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11; + +import com.github.mjeanroy.junit.servers.servers.EmbeddedServerProvider; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; + +/** + * Jetty Embedded Server provider, used by the service provider interface from the JDK. + */ +public class EmbeddedJettyProvider implements EmbeddedServerProvider { + + @Override + public EmbeddedJetty instantiate() { + return new EmbeddedJetty(); + } + + @Override + public EmbeddedJetty instantiate(EmbeddedJettyConfiguration configuration) { + return new EmbeddedJetty(configuration); + } +} diff --git a/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/AbstractJettyJunit4Test.java b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/AbstractJettyJunit4Test.java new file mode 100644 index 00000000..74711630 --- /dev/null +++ b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/AbstractJettyJunit4Test.java @@ -0,0 +1,43 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.junit4; + +import com.github.mjeanroy.junit.servers.annotations.TestServer; +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import org.junit.runner.RunWith; + +/** + * Simple abstraction that define a server rule using jetty as embedded server. + */ +@RunWith(JettyServerJunit4Runner.class) +public abstract class AbstractJettyJunit4Test { + + /** + * The started embedded server. + */ + @TestServer + public static EmbeddedJetty server; + +} diff --git a/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4Rule.java b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4Rule.java new file mode 100644 index 00000000..17bf5a41 --- /dev/null +++ b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4Rule.java @@ -0,0 +1,59 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.junit4; + +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import com.github.mjeanroy.junit.servers.junit4.ServerRule; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; + +/** + * Rule that can be used to start and stop embedded jetty server. + */ +public class JettyServerJunit4Rule extends ServerRule { + /** + * Create rule. + * + * @param jetty Jetty Embedded Server. + */ + public JettyServerJunit4Rule(EmbeddedJetty jetty) { + super(jetty); + } + + /** + * Create rule using jetty as embedded server. + */ + public JettyServerJunit4Rule() { + this(new EmbeddedJetty()); + } + + /** + * Create rule. + * + * @param configuration Jetty Configuration. + */ + public JettyServerJunit4Rule(EmbeddedJettyConfiguration configuration) { + this(new EmbeddedJetty(configuration)); + } +} diff --git a/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4Runner.java b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4Runner.java new file mode 100644 index 00000000..1fae419e --- /dev/null +++ b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4Runner.java @@ -0,0 +1,64 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.junit4; + +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJettyFactory; +import com.github.mjeanroy.junit.servers.junit4.JunitServerRunner; +import com.github.mjeanroy.junit.servers.loggers.Logger; +import com.github.mjeanroy.junit.servers.loggers.LoggerFactory; +import org.junit.runners.model.InitializationError; + +/** + * Rule that can be used to start and stop embedded jetty server. + */ +public class JettyServerJunit4Runner extends JunitServerRunner { + + /** + * Class Logger. + */ + private static final Logger log = LoggerFactory.getLogger(JettyServerJunit4Runner.class); + + /** + * Create runner. + * + * @param klass Running class. + * @throws InitializationError If an error occurred while starting embedded server. + */ + public JettyServerJunit4Runner(Class klass) throws InitializationError { + super(klass, instantiate(klass)); + } + + /** + * Instantiate embedded jetty to be used in tests. + * + * @param klass The tested class. + * @return The embedded jetty. + */ + private static EmbeddedJetty instantiate(Class klass) { + log.debug("Instantiate embedded jetty for class: {}", klass); + return EmbeddedJettyFactory.createFrom(klass); + } +} diff --git a/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyServerExtension.java b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyServerExtension.java new file mode 100644 index 00000000..36030747 --- /dev/null +++ b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyServerExtension.java @@ -0,0 +1,85 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.jupiter; + +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJettyFactory; +import com.github.mjeanroy.junit.servers.jupiter.JunitServerExtension; +import com.github.mjeanroy.junit.servers.loggers.Logger; +import com.github.mjeanroy.junit.servers.loggers.LoggerFactory; +import com.github.mjeanroy.junit.servers.servers.AbstractConfiguration; +import com.github.mjeanroy.junit.servers.servers.EmbeddedServer; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; + +/** + * A specialized {@link JunitServerExtension} that will instantiate an {@link EmbeddedJetty} + * server automatically instead of using the Service Provider API. + * + * Since this jupiter extends {@link JunitServerExtension}, it has exactly the same features (parameter + * injections, etc.). + * + * @see JunitServerExtension + */ +public class JettyServerExtension extends JunitServerExtension { + + /** + * Class Logger. + */ + private static final Logger log = LoggerFactory.getLogger(JettyServerExtension.class); + + /** + * Create the jupiter with default behavior. + */ + public JettyServerExtension() { + super(); + } + + /** + * Create the jupiter and specify the embedded jetty instance to use. + * + * @param jetty The embedded jetty instance to use. + * @throws NullPointerException If {@code jetty} is {@code null}. + */ + public JettyServerExtension(EmbeddedJetty jetty) { + super(jetty); + } + + /** + * Create the jupiter and specify the embedded jetty configuration to use (when using + * * jupiter with {@link org.junit.jupiter.api.extension.RegisterExtension}). + * + * @param configuration The embedded jetty configuration to use. + * @throws NullPointerException If {@code configuration} is {@code null}. + */ + public JettyServerExtension(EmbeddedJettyConfiguration configuration) { + super(configuration); + } + + @Override + protected EmbeddedServer instantiateServer(Class testClass, AbstractConfiguration configuration) { + log.debug("Instantiating embedded jetty for test class: {}", testClass); + return EmbeddedJettyFactory.createFrom(testClass, configuration); + } +} diff --git a/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyTest.java b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyTest.java new file mode 100644 index 00000000..27d64cc7 --- /dev/null +++ b/junit-servers-jetty-12/src/main/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyTest.java @@ -0,0 +1,43 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.jupiter; + +import org.junit.jupiter.api.extension.ExtendWith; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Exception used to create a test with {@link JettyServerExtension}. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@ExtendWith(JettyServerExtension.class) +@Documented +public @interface JettyTest { +} diff --git a/junit-servers-jetty-12/src/main/resources/META-INF/services/com.github.mjeanroy.junit.servers.servers.EmbeddedServerProvider b/junit-servers-jetty-12/src/main/resources/META-INF/services/com.github.mjeanroy.junit.servers.servers.EmbeddedServerProvider new file mode 100644 index 00000000..0e3f83ef --- /dev/null +++ b/junit-servers-jetty-12/src/main/resources/META-INF/services/com.github.mjeanroy.junit.servers.servers.EmbeddedServerProvider @@ -0,0 +1,27 @@ +## +# The MIT License (MIT) +# +# Copyright (c) 2014-2022 +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +## + +# This is the implementation that will be automatically discovered by the SPI used +# in the junit-servers-core module. +com.github.mjeanroy.junit.servers.jetty11.EmbeddedJettyProvider diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyFactoryTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyFactoryTest.java new file mode 100644 index 00000000..8b378400 --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyFactoryTest.java @@ -0,0 +1,109 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11; + +import com.github.mjeanroy.junit.servers.annotations.TestServerConfiguration; +import com.github.mjeanroy.junit.servers.jetty.JettyConfiguration; +import com.github.mjeanroy.junit.servers.servers.AbstractConfiguration; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfigurationProvider; +import com.github.mjeanroy.junit.servers.jetty.IllegalJettyConfigurationException; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class EmbeddedJettyFactoryTest { + + @Test + void it_should_create_embedded_jetty_from_class_using_default_configuration() { + final EmbeddedJetty jetty = EmbeddedJettyFactory.createFrom(ClassUsingDefaultConfiguration.class); + assertThat(jetty).isNotNull(); + assertThat(jetty.getConfiguration()).isEqualTo(EmbeddedJettyConfiguration.defaultConfiguration()); + } + + @Test + void it_should_create_embedded_jetty_from_class_using_provided_configuration() { + final EmbeddedJettyConfiguration providedConfiguration = EmbeddedJettyConfiguration.builder().withPath("/test").build(); + final EmbeddedJetty jetty = EmbeddedJettyFactory.createFrom(ClassUsingDefaultConfiguration.class, providedConfiguration); + + assertThat(jetty).isNotNull(); + assertThat(jetty.getConfiguration()).isEqualTo(providedConfiguration); + } + + @Test + void it_should_create_embedded_tomcat_from_class_using_configuration_provider() { + final EmbeddedJetty jetty = EmbeddedJettyFactory.createFrom(ClassAnnotatedWithConfigurationProvider.class); + assertThat(jetty).isNotNull(); + assertThat(jetty.getConfiguration()).isSameAs(DefaultEmbeddedJettyConfigurationProvider.CONFIGURATION); + } + + @Test + void it_should_create_embedded_jetty_from_class_using_custom_configuration() { + final EmbeddedJetty jetty = EmbeddedJettyFactory.createFrom(ClassUsingCustomConfiguration.class); + assertThat(jetty).isNotNull(); + assertThat(jetty.getConfiguration()).isSameAs(ClassUsingCustomConfiguration.configuration); + } + + @Test + void it_should_fail_to_create_embedded_jetty_from_class_using_non_valid_configuration() { + assertThatThrownBy(() -> EmbeddedJettyFactory.createFrom(ClassUsingNonJettyConfiguration.class)) + .isInstanceOf(IllegalJettyConfigurationException.class) + .hasMessage( + "Embedded jetty server requires a configuration that is an instance of com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration, please fix it." + ); + } + + private static class ClassUsingDefaultConfiguration { + } + + @JettyConfiguration(providedBy = DefaultEmbeddedJettyConfigurationProvider.class) + private static class ClassAnnotatedWithConfigurationProvider { + } + + private static class ClassUsingCustomConfiguration { + @TestServerConfiguration + private static EmbeddedJettyConfiguration configuration = EmbeddedJettyConfiguration.builder() + .withStopTimeout(100) + .build(); + } + + private static class ClassUsingNonJettyConfiguration { + @TestServerConfiguration + private static CustomConfiguration configuration = new CustomConfiguration(); + } + + private static class CustomConfiguration extends AbstractConfiguration { + } + + private static class DefaultEmbeddedJettyConfigurationProvider implements EmbeddedJettyConfigurationProvider { + private static final EmbeddedJettyConfiguration CONFIGURATION = EmbeddedJettyConfiguration.builder().build(); + + @Override + public EmbeddedJettyConfiguration build(Class testClass) { + return CONFIGURATION; + } + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyProviderTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyProviderTest.java new file mode 100644 index 00000000..18c1b339 --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyProviderTest.java @@ -0,0 +1,54 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11; + +import com.github.mjeanroy.junit.servers.jetty11.tests.EmbeddedJettyConfigurationMockBuilder; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import org.junit.jupiter.api.Test; + +import static com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration.defaultConfiguration; +import static org.assertj.core.api.Assertions.assertThat; + +class EmbeddedJettyProviderTest { + + @Test + void it_should_instantiate_jetty_with_default_configuration() { + final EmbeddedJettyProvider provider = new EmbeddedJettyProvider(); + final EmbeddedJetty jetty = provider.instantiate(); + + assertThat(jetty).isNotNull(); + assertThat(jetty.getConfiguration()).isNotNull().isEqualTo(defaultConfiguration()); + } + + @Test + void it_should_instantiate_jetty_with_custom_configuration() { + final EmbeddedJettyProvider provider = new EmbeddedJettyProvider(); + final EmbeddedJettyConfiguration configuration = new EmbeddedJettyConfigurationMockBuilder().build(); + final EmbeddedJetty jetty = provider.instantiate(configuration); + + assertThat(jetty).isNotNull(); + assertThat(jetty.getConfiguration()).isNotNull().isSameAs(configuration); + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyTest.java new file mode 100644 index 00000000..f594c66f --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/EmbeddedJettyTest.java @@ -0,0 +1,194 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11; + +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.eclipse.jetty.ee10.webapp.WebAppContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +class EmbeddedJettyTest { + + private volatile EmbeddedJetty jetty; + + @AfterEach + void tearDown() { + jetty.stop(); + } + + @Test + void it_should_start_jetty() throws Exception { + jetty = new EmbeddedJetty(); + assertThat(jetty.getScheme()).isEqualTo("http"); + assertThat(jetty.getHost()).isEqualTo("localhost"); + assertThat(jetty.getPath()).isEqualTo("/"); + + jetty.start(); + assertThat(jetty.isStarted()).isTrue(); + assertThat(jetty.getPort()).isNotZero(); + assertThat(jetty.getUrl()).isEqualTo(localUrl(jetty.getPort())); + + // Since there is no webapp deployed, we should get a 404 + HttpResponse rsp = get(jetty.getUrl()); + assertThat(rsp.statusCode).isEqualTo(404); + assertThat(rsp.responseBody).isNotEmpty(); + } + + @Test + void it_should_stop_jetty() { + jetty = new EmbeddedJetty(); + assertThat(jetty.getScheme()).isEqualTo("http"); + assertThat(jetty.getHost()).isEqualTo("localhost"); + assertThat(jetty.getPath()).isEqualTo("/"); + + jetty.start(); + assertThat(jetty.isStarted()).isTrue(); + assertThat(jetty.getPort()).isNotZero(); + assertThat(jetty.getUrl()).isEqualTo(localUrl(jetty.getPort())); + + jetty.stop(); + assertThat(jetty.isStarted()).isFalse(); + assertThat(jetty.getPort()).isZero(); + assertThat(jetty.getUrl()).isEqualTo(localUrl(jetty.getPort())); + } + + @Test + void it_should_get_configuration_port_until_jetty_is_started() { + jetty = new EmbeddedJetty(); + assertThat(jetty.getPort()).isZero(); + + jetty.start(); + assertThat(jetty.getPort()).isNotZero(); + + jetty.stop(); + assertThat(jetty.getPort()).isZero(); + } + + @Test + void it_should_get_servlet_context() { + jetty = new EmbeddedJetty(); + jetty.start(); + assertThat(jetty.getServletContext()).isNotNull(); + } + + @Test + void it_should_get_original_jetty() { + jetty = new EmbeddedJetty(); + assertThat(jetty.getDelegate()).isNotNull(); + } + + @Test + void it_should_add_parent_classloader(@TempDir Path tmp) throws Exception { + final File tmpFile = Files.createTempFile(tmp, null, null).toFile(); + final File dir = tmpFile.getParentFile(); + final URL url = dir.toURI().toURL(); + final String name = tmpFile.getName(); + + try (URLClassLoader urlClassLoader = new URLClassLoader(new URL[] { url })) { + assertThat(urlClassLoader.getResource(name)).isNotNull(); + + jetty = new EmbeddedJetty(EmbeddedJettyConfiguration.builder() + .withWebapp(dir) + .withParentClasspath(url) + .build()); + + jetty.start(); + + HttpResponse rsp = get(jetty.getUrl()); + assertThat(rsp.statusCode).isEqualTo(200); + assertThat(rsp.responseBody).isNotEmpty(); + + WebAppContext ctx = (WebAppContext) jetty.getDelegate().getHandler(); + ClassLoader cl = ctx.getClassLoader(); + assertThat(cl).isNotNull(); + assertThat(cl.getResource("custom-web.xml")).isNotNull(); + assertThat(cl.getResource(name)).isNotNull(); + } + } + + @Test + void it_should_override_web_xml() throws Exception { + File customWebXml = getCustomWebXml(); + + jetty = new EmbeddedJetty(EmbeddedJettyConfiguration.builder() + .withWebapp(customWebXml.getParentFile()) + .withOverrideDescriptor(customWebXml.getAbsolutePath()) + .build()); + + jetty.start(); + + HttpResponse rsp = get(jetty.getUrl() + "hello"); + assertThat(rsp.statusCode).isEqualTo(200); + assertThat(rsp.responseBody).isNotEmpty().contains("Hello World"); + } + + private static File getCustomWebXml() { + String resourceName = "/custom-web.xml"; + URL resource = EmbeddedJettyTest.class.getResource("/custom-web.xml"); + if (resource == null) { + throw new AssertionError("Cannot find resource: " + resourceName); + } + + String webXmlPath = resource.getFile(); + return new File(webXmlPath); + } + + private static HttpResponse get(String url) throws IOException { + OkHttpClient client = new OkHttpClient(); + Request rq = new Request.Builder().url(url).build(); + try (Response rsp = client.newCall(rq).execute()) { + int statusCode = rsp.code(); + String responseBody = rsp.body() == null ? null : rsp.body().string(); + return new HttpResponse(statusCode, responseBody); + } + } + + private static String localUrl(int port) { + return "http://localhost:" + port + "/"; + } + + private static final class HttpResponse { + private final int statusCode; + private final String responseBody; + + private HttpResponse(int statusCode, String responseBody) { + this.statusCode = statusCode; + this.responseBody = responseBody; + } + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyJunit4Test.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyJunit4Test.java new file mode 100644 index 00000000..3f282e3e --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyJunit4Test.java @@ -0,0 +1,49 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11; + +import com.github.mjeanroy.junit.servers.annotations.TestHttpClient; +import com.github.mjeanroy.junit.servers.client.HttpClient; +import com.github.mjeanroy.junit.servers.jetty11.junit4.AbstractJettyJunit4Test; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JettyJunit4Test extends AbstractJettyJunit4Test { + + @TestHttpClient + private HttpClient client; + + @Test + public void it_should_have_a_server() { + assertThat(server).isNotNull(); + assertThat(server.getPort()).isPositive(); + } + + @Test + public void it_should_have_a_client() { + assertThat(client).isNotNull(); + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyServerJunit4RuleTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyServerJunit4RuleTest.java new file mode 100644 index 00000000..a851d1ce --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyServerJunit4RuleTest.java @@ -0,0 +1,135 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11; + +import com.github.mjeanroy.junit.servers.jetty11.junit4.JettyServerJunit4Rule; +import com.github.mjeanroy.junit.servers.jetty11.tests.EmbeddedJettyConfigurationMockBuilder; +import com.github.mjeanroy.junit.servers.jetty11.tests.EmbeddedJettyMockBuilder; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import org.junit.jupiter.api.Test; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.mockito.InOrder; +import org.mockito.Mockito; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +class JettyServerJunit4RuleTest { + + @Test + void it_should_create_rule_with_server() throws Throwable { + final EmbeddedJettyConfiguration config = new EmbeddedJettyConfigurationMockBuilder().build(); + final EmbeddedJetty jetty = new EmbeddedJettyMockBuilder().withConfiguration(config).build(); + final JettyServerJunit4Rule rule = createRule(jetty); + + assertThat(rule.getServer()).isSameAs(jetty); + assertThat(rule.getScheme()).isEqualTo(jetty.getScheme()); + assertThat(rule.getHost()).isEqualTo(jetty.getHost()); + assertThat(rule.getPort()).isEqualTo(jetty.getPort()); + assertThat(rule.getPath()).isEqualTo(jetty.getPath()); + assertThat(rule.getUrl()).isEqualTo(jetty.getUrl()); + + verify(jetty, never()).start(); + verify(jetty, never()).stop(); + + evaluateRule(rule); + + InOrder inOrder = Mockito.inOrder(jetty); + inOrder.verify(jetty).start(); + inOrder.verify(jetty).stop(); + } + + @Test + void it_should_create_server_from_configuration() throws Throwable { + final EmbeddedJettyConfiguration configuration = EmbeddedJettyConfiguration.defaultConfiguration(); + final JettyServerJunit4Rule rule = createRule(configuration); + + assertThat(rule.getPort()).isZero(); + assertRule(rule); + } + + @Test + void it_should_create_server_with_default_configuration() throws Throwable { + final JettyServerJunit4Rule rule = createRule(); + + assertThat(rule.getPort()).isZero(); // not started + assertRule(rule); + } + + private static JettyServerJunit4Rule createRule() { + return new JettyServerJunit4Rule(); + } + + private static JettyServerJunit4Rule createRule(EmbeddedJettyConfiguration configuration) { + return new JettyServerJunit4Rule(configuration); + } + + private static JettyServerJunit4Rule createRule(EmbeddedJetty jetty) { + return new JettyServerJunit4Rule(jetty); + } + + private static void assertRule(final JettyServerJunit4Rule rule) throws Throwable { + final Statement statement = spy(new FakeStatement(rule)); + + evaluateRule(rule, statement); + + verify(statement).evaluate(); + assertThat(rule.getPort()).isZero(); // not started + } + + private static void evaluateRule(JettyServerJunit4Rule rule) throws Throwable { + final Statement statement = mock(Statement.class); + evaluateRule(rule, statement); + } + + private static void evaluateRule(JettyServerJunit4Rule rule, Statement statement) throws Throwable { + final Description description = mock(Description.class); + final Statement testStatement = rule.apply(statement, description); + testStatement.evaluate(); + } + + private static class FakeStatement extends Statement { + private final JettyServerJunit4Rule rule; + + private FakeStatement(JettyServerJunit4Rule rule) { + this.rule = rule; + } + + @Override + public void evaluate() { + assertThat(rule.getScheme()).isEqualTo("http"); + assertThat(rule.getHost()).isEqualTo("localhost"); + assertThat(rule.getPath()).isEqualTo("/"); + assertThat(rule.getPort()).isGreaterThan(0); + assertThat(rule.getUrl()).isEqualTo( + rule.getScheme() + "://" + rule.getHost() + ":" + rule.getPort() + rule.getPath() + ); + } + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyServerJunit4RunnerTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyServerJunit4RunnerTest.java new file mode 100644 index 00000000..03a6f4bd --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/JettyServerJunit4RunnerTest.java @@ -0,0 +1,97 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11; + +import com.github.mjeanroy.junit.servers.annotations.TestServer; +import com.github.mjeanroy.junit.servers.annotations.TestServerConfiguration; +import com.github.mjeanroy.junit.servers.jetty11.junit4.JettyServerJunit4Runner; +import com.github.mjeanroy.junit.servers.servers.AbstractConfiguration; +import com.github.mjeanroy.junit.servers.servers.EmbeddedServer; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import org.junit.Ignore; +import org.junit.jupiter.api.Test; + +import static com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration.defaultConfiguration; +import static org.apache.commons.lang3.reflect.FieldUtils.readField; +import static org.assertj.core.api.Assertions.assertThat; + +class JettyServerJunit4RunnerTest { + + private static final EmbeddedJettyConfiguration configuration = defaultConfiguration(); + + @Test + void it_should_instantiate_jetty_with_default_configuration() throws Exception { + final JettyServerJunit4Runner runner = createRunner(TestClassWithConfiguration.class); + final EmbeddedServer server = (EmbeddedServer) readField(runner, "server", true); + final AbstractConfiguration conf = (AbstractConfiguration) readField(runner, "configuration", true); + + assertThat(server).isInstanceOf(EmbeddedJetty.class); + assertThat(conf).isInstanceOf(EmbeddedJettyConfiguration.class).isNotSameAs(configuration); + } + + @Test + void it_should_instantiate_jetty_with_configuration() throws Exception { + final JettyServerJunit4Runner runner = createRunner(TestClassWithConfigurationInitializer.class); + final EmbeddedServer server = (EmbeddedServer) readField(runner, "server", true); + final AbstractConfiguration conf = (AbstractConfiguration) readField(runner, "configuration", true); + + assertThat(server).isInstanceOf(EmbeddedJetty.class); + assertThat(conf).isInstanceOf(EmbeddedJettyConfiguration.class).isSameAs(configuration); + } + + private static JettyServerJunit4Runner createRunner(Class klass) throws Exception { + return new JettyServerJunit4Runner(klass); + } + + @Ignore + public static class TestClassWithConfiguration { + + @TestServer + private static EmbeddedServer server; + + @TestServerConfiguration + private static EmbeddedJettyConfiguration configuration; + + @org.junit.Test + public void fooTest() { + } + } + + @Ignore + public static class TestClassWithConfigurationInitializer { + + @TestServer + private static EmbeddedServer server; + + @TestServerConfiguration + private static EmbeddedJettyConfiguration initConfiguration() { + return configuration; + } + + @org.junit.Test + public void fooTest() { + } + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyJunit4Test.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyJunit4Test.java new file mode 100644 index 00000000..b18f7fec --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyJunit4Test.java @@ -0,0 +1,48 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.junit4; + +import com.github.mjeanroy.junit.servers.annotations.TestHttpClient; +import com.github.mjeanroy.junit.servers.client.HttpClient; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class JettyJunit4Test extends AbstractJettyJunit4Test { + + @TestHttpClient + private HttpClient client; + + @Test + public void it_should_have_a_server() { + assertThat(server).isNotNull(); + assertThat(server.getPort()).isPositive(); + } + + @Test + public void it_should_have_a_client() { + assertThat(client).isNotNull(); + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4RuleTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4RuleTest.java new file mode 100644 index 00000000..3a8e435c --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4RuleTest.java @@ -0,0 +1,135 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.junit4; + +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import com.github.mjeanroy.junit.servers.jetty11.tests.EmbeddedJettyConfigurationMockBuilder; +import com.github.mjeanroy.junit.servers.jetty11.tests.EmbeddedJettyMockBuilder; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import org.junit.jupiter.api.Test; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.mockito.InOrder; +import org.mockito.Mockito; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +class JettyServerJunit4RuleTest { + + @Test + void it_should_create_rule_with_server() throws Throwable { + final EmbeddedJettyConfiguration config = new EmbeddedJettyConfigurationMockBuilder().build(); + final EmbeddedJetty jetty = new EmbeddedJettyMockBuilder().withConfiguration(config).build(); + final JettyServerJunit4Rule rule = createRule(jetty); + + assertThat(rule.getServer()).isSameAs(jetty); + assertThat(rule.getScheme()).isEqualTo(jetty.getScheme()); + assertThat(rule.getHost()).isEqualTo(jetty.getHost()); + assertThat(rule.getPort()).isEqualTo(jetty.getPort()); + assertThat(rule.getPath()).isEqualTo(jetty.getPath()); + assertThat(rule.getUrl()).isEqualTo(jetty.getUrl()); + + verify(jetty, never()).start(); + verify(jetty, never()).stop(); + + evaluateRule(rule); + + InOrder inOrder = Mockito.inOrder(jetty); + inOrder.verify(jetty).start(); + inOrder.verify(jetty).stop(); + } + + @Test + void it_should_create_server_from_configuration() throws Throwable { + final EmbeddedJettyConfiguration configuration = EmbeddedJettyConfiguration.defaultConfiguration(); + final JettyServerJunit4Rule rule = createRule(configuration); + + assertThat(rule.getPort()).isZero(); + assertRule(rule); + } + + @Test + void it_should_create_server_with_default_configuration() throws Throwable { + final JettyServerJunit4Rule rule = createRule(); + + assertThat(rule.getPort()).isZero(); // not started + assertRule(rule); + } + + private static JettyServerJunit4Rule createRule() { + return new JettyServerJunit4Rule(); + } + + private static JettyServerJunit4Rule createRule(EmbeddedJettyConfiguration configuration) { + return new JettyServerJunit4Rule(configuration); + } + + private static JettyServerJunit4Rule createRule(EmbeddedJetty jetty) { + return new JettyServerJunit4Rule(jetty); + } + + private static void assertRule(final JettyServerJunit4Rule rule) throws Throwable { + final Statement statement = spy(new FakeStatement(rule)); + + evaluateRule(rule, statement); + + verify(statement).evaluate(); + assertThat(rule.getPort()).isZero(); // not started + } + + private static void evaluateRule(JettyServerJunit4Rule rule) throws Throwable { + final Statement statement = mock(Statement.class); + evaluateRule(rule, statement); + } + + private static void evaluateRule(JettyServerJunit4Rule rule, Statement statement) throws Throwable { + final Description description = mock(Description.class); + final Statement testStatement = rule.apply(statement, description); + testStatement.evaluate(); + } + + private static class FakeStatement extends Statement { + private final JettyServerJunit4Rule rule; + + private FakeStatement(JettyServerJunit4Rule rule) { + this.rule = rule; + } + + @Override + public void evaluate() { + assertThat(rule.getScheme()).isEqualTo("http"); + assertThat(rule.getHost()).isEqualTo("localhost"); + assertThat(rule.getPath()).isEqualTo("/"); + assertThat(rule.getPort()).isGreaterThan(0); + assertThat(rule.getUrl()).isEqualTo( + rule.getScheme() + "://" + rule.getHost() + ":" + rule.getPort() + rule.getPath() + ); + } + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4RunnerTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4RunnerTest.java new file mode 100644 index 00000000..697c354f --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/junit4/JettyServerJunit4RunnerTest.java @@ -0,0 +1,97 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.junit4; + +import com.github.mjeanroy.junit.servers.annotations.TestServer; +import com.github.mjeanroy.junit.servers.annotations.TestServerConfiguration; +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import com.github.mjeanroy.junit.servers.servers.AbstractConfiguration; +import com.github.mjeanroy.junit.servers.servers.EmbeddedServer; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import org.junit.Ignore; +import org.junit.jupiter.api.Test; + +import static com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration.defaultConfiguration; +import static org.apache.commons.lang3.reflect.FieldUtils.readField; +import static org.assertj.core.api.Assertions.assertThat; + +class JettyServerJunit4RunnerTest { + + private static final EmbeddedJettyConfiguration configuration = defaultConfiguration(); + + @Test + void it_should_instantiate_jetty_with_default_configuration() throws Exception { + final JettyServerJunit4Runner runner = createRunner(TestClassWithConfiguration.class); + final EmbeddedServer server = (EmbeddedServer) readField(runner, "server", true); + final AbstractConfiguration conf = (AbstractConfiguration) readField(runner, "configuration", true); + + assertThat(server).isInstanceOf(EmbeddedJetty.class); + assertThat(conf).isInstanceOf(EmbeddedJettyConfiguration.class).isNotSameAs(configuration); + } + + @Test + void it_should_instantiate_jetty_with_configuration() throws Exception { + final JettyServerJunit4Runner runner = createRunner(TestClassWithConfigurationInitializer.class); + final EmbeddedServer server = (EmbeddedServer) readField(runner, "server", true); + final AbstractConfiguration conf = (AbstractConfiguration) readField(runner, "configuration", true); + + assertThat(server).isInstanceOf(EmbeddedJetty.class); + assertThat(conf).isInstanceOf(EmbeddedJettyConfiguration.class).isSameAs(configuration); + } + + private static JettyServerJunit4Runner createRunner(Class klass) throws Exception { + return new JettyServerJunit4Runner(klass); + } + + @Ignore + public static class TestClassWithConfiguration { + + @TestServer + private static EmbeddedServer server; + + @TestServerConfiguration + private static EmbeddedJettyConfiguration configuration; + + @org.junit.Test + public void fooTest() { + } + } + + @Ignore + public static class TestClassWithConfigurationInitializer { + + @TestServer + private static EmbeddedServer server; + + @TestServerConfiguration + private static EmbeddedJettyConfiguration initConfiguration() { + return configuration; + } + + @org.junit.Test + public void fooTest() { + } + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FakeExtensionContext.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FakeExtensionContext.java new file mode 100644 index 00000000..c6687011 --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FakeExtensionContext.java @@ -0,0 +1,206 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.jupiter; + +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExecutableInvoker; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.TestInstances; +import org.junit.jupiter.api.parallel.ExecutionMode; + +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.function.Function; + +/** + * A fake {@link ExtensionContext} + */ +class FakeExtensionContext implements ExtensionContext { + + /** + * The test context stores. + */ + private final Map stores; + + /** + * The test unique identifier. + */ + private final String id; + + /** + * The tested instance. + */ + private final Object testInstance; + + FakeExtensionContext(Object testInstance) { + this.stores = new HashMap<>(); + this.id = UUID.randomUUID().toString(); + this.testInstance = testInstance; + } + + @Override + public Optional getParent() { + throw new UnsupportedOperationException(); + } + + @Override + public ExtensionContext getRoot() { + throw new UnsupportedOperationException(); + } + + @Override + public String getUniqueId() { + return id; + } + + @Override + public String getDisplayName() { + throw new UnsupportedOperationException(); + } + + @Override + public Set getTags() { + throw new UnsupportedOperationException(); + } + + @Override + public Optional getElement() { + throw new UnsupportedOperationException(); + } + + @Override + public Optional> getTestClass() { + throw new UnsupportedOperationException(); + } + + @Override + public Class getRequiredTestClass() { + return testInstance.getClass(); + } + + @Override + public Optional getTestInstanceLifecycle() { + throw new UnsupportedOperationException(); + } + + @Override + public Optional getTestInstance() { + throw new UnsupportedOperationException(); + } + + @Override + public Optional getTestInstances() { + throw new UnsupportedOperationException(); + } + + @Override + public TestInstances getRequiredTestInstances() { + throw new UnsupportedOperationException(); + } + + @Override + public Object getRequiredTestInstance() { + return testInstance; + } + + @Override + public Optional getTestMethod() { + throw new UnsupportedOperationException(); + } + + @Override + public Method getRequiredTestMethod() { + throw new UnsupportedOperationException(); + } + + @Override + public Optional getExecutionException() { + throw new UnsupportedOperationException(); + } + + @Override + public Optional getConfigurationParameter(String key) { + throw new UnsupportedOperationException(); + } + + @Override + public Optional getConfigurationParameter(String key, Function transformer) { + throw new UnsupportedOperationException(); + } + + @Override + public void publishReportEntry(Map map) { + throw new UnsupportedOperationException(); + } + + @Override + public void publishReportEntry(String key, String value) { + throw new UnsupportedOperationException(); + } + + @Override + public void publishReportEntry(String value) { + throw new UnsupportedOperationException(); + } + + @Override + public Store getStore(Namespace namespace) { + if (!stores.containsKey(namespace)) { + stores.put(namespace, new FakeStore()); + } + + return stores.get(namespace); + } + + @Override + public ExecutionMode getExecutionMode() { + return ExecutionMode.SAME_THREAD; + } + + @Override + public ExecutableInvoker getExecutableInvoker() { + throw new UnsupportedOperationException(); + } + + /** + * Get the single created store, or fail with {@link AssertionError} otherwise (no store, or more than + * one store created). + * + * @return The single created store. + */ + FakeStore getSingleStore() { + int size = stores.size(); + if (size != 1) { + throw new AssertionError("Cannot get single store, found " + size + " stores instead."); + } + + return stores.values().iterator().next(); + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FakeStore.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FakeStore.java new file mode 100644 index 00000000..1dd5a9ff --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FakeStore.java @@ -0,0 +1,106 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.jupiter; + +import org.junit.jupiter.api.extension.ExtensionContext.Store; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +/** + * A fake {@link Store} implementation using a map as internal implementation. + */ +class FakeStore implements Store { + + /** + * The internal map implementation. + */ + private final Map map; + + FakeStore() { + map = new HashMap<>(); + } + + @Override + public Object get(Object key) { + return map.get(key); + } + + @Override + @SuppressWarnings("unchecked") + public V get(Object key, Class requiredType) { + return (V) get(key); + } + + @Override + public Object getOrComputeIfAbsent(K key, Function defaultCreator) { + if (!map.containsKey(key)) { + map.put(key, defaultCreator.apply(key)); + } + + return map.get(key); + } + + @Override + @SuppressWarnings("unchecked") + public V getOrComputeIfAbsent(K key, Function defaultCreator, Class requiredType) { + return (V) getOrComputeIfAbsent(key, defaultCreator); + } + + @Override + public void put(Object key, Object value) { + map.put(key, value); + } + + @Override + public Object remove(Object key) { + return map.remove(key); + } + + @Override + @SuppressWarnings("unchecked") + public V remove(Object key, Class requiredType) { + return (V) remove(key); + } + + /** + * Get current store size (number of stored entries). + * + * @return Store size. + */ + int size() { + return map.size(); + } + + /** + * Check if store is empty. + * + * @return {@code true} if store is empty, {@code false} otherwise. + */ + boolean isEmpty() { + return size() == 0; + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FixtureClass.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FixtureClass.java new file mode 100644 index 00000000..f552ee67 --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/FixtureClass.java @@ -0,0 +1,44 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.jupiter; + +import com.github.mjeanroy.junit.servers.annotations.TestHttpClient; +import com.github.mjeanroy.junit.servers.annotations.TestServer; +import com.github.mjeanroy.junit.servers.annotations.TestServerConfiguration; +import com.github.mjeanroy.junit.servers.client.HttpClient; +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; + +class FixtureClass { + + @TestServer + EmbeddedJetty jetty; + + @TestServerConfiguration + EmbeddedJettyConfiguration configuration; + + @TestHttpClient + HttpClient client; +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyServerExtensionTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyServerExtensionTest.java new file mode 100644 index 00000000..d7dd6a90 --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/jupiter/JettyServerExtensionTest.java @@ -0,0 +1,87 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.jupiter; + +import com.github.mjeanroy.junit.servers.engine.EmbeddedServerRunner; +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import com.github.mjeanroy.junit.servers.jetty11.tests.EmbeddedJettyMockBuilder; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class JettyServerExtensionTest { + + @Test + void it_should_start_given_jetty_server_before_all_tests() { + final EmbeddedJetty jetty = new EmbeddedJettyMockBuilder().build(); + final JettyServerExtension extension = new JettyServerExtension(jetty); + final FixtureClass testInstance = new FixtureClass(); + final FakeExtensionContext context = new FakeExtensionContext(testInstance); + + extension.beforeAll(context); + + final FakeStore store = context.getSingleStore(); + final EmbeddedServerRunner serverAdapter = store.get("serverAdapter", EmbeddedServerRunner.class); + + assertThat(serverAdapter).isNotNull(); + assertThat(serverAdapter.getServer()).isSameAs(jetty); + assertThat(serverAdapter.getServer().isStarted()).isTrue(); + } + + @Test + void it_should_start_jetty_server_using_given_configuration_before_all_tests() { + final EmbeddedJettyConfiguration configuration = EmbeddedJettyConfiguration.defaultConfiguration(); + final JettyServerExtension extension = new JettyServerExtension(configuration); + final FixtureClass testInstance = new FixtureClass(); + final FakeExtensionContext context = new FakeExtensionContext(testInstance); + + extension.beforeAll(context); + + final FakeStore store = context.getSingleStore(); + final EmbeddedServerRunner serverAdapter = store.get("serverAdapter", EmbeddedServerRunner.class); + + assertThat(serverAdapter).isNotNull(); + assertThat(serverAdapter.getServer()).isNotNull().isExactlyInstanceOf(EmbeddedJetty.class); + assertThat(serverAdapter.getServer().getConfiguration()).isSameAs(configuration); + assertThat(serverAdapter.getServer().isStarted()).isTrue(); + } + + @Test + void it_should_start_server_with_default_configuration_before_all_tests() { + final JettyServerExtension extension = new JettyServerExtension(); + final FixtureClass testInstance = new FixtureClass(); + final FakeExtensionContext context = new FakeExtensionContext(testInstance); + + extension.beforeAll(context); + + final FakeStore store = context.getSingleStore(); + final EmbeddedServerRunner serverAdapter = store.get("serverAdapter", EmbeddedServerRunner.class); + + assertThat(serverAdapter).isNotNull(); + assertThat(serverAdapter.getServer()).isNotNull().isExactlyInstanceOf(EmbeddedJetty.class); + assertThat(serverAdapter.getServer().isStarted()).isTrue(); + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/tests/EmbeddedJettyConfigurationMockBuilder.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/tests/EmbeddedJettyConfigurationMockBuilder.java new file mode 100644 index 00000000..e0553811 --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/tests/EmbeddedJettyConfigurationMockBuilder.java @@ -0,0 +1,44 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.tests; + +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; + +import static org.mockito.Mockito.mock; + +/** + * Builder for mock instances of {@link EmbeddedJettyConfiguration}. + */ +public class EmbeddedJettyConfigurationMockBuilder { + + /** + * Build mock instance of {@link EmbeddedJettyConfiguration}. + * + * @return The mock instance. + */ + public EmbeddedJettyConfiguration build() { + return mock(EmbeddedJettyConfiguration.class); + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/tests/EmbeddedJettyMockBuilder.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/tests/EmbeddedJettyMockBuilder.java new file mode 100644 index 00000000..5becc9fa --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/jetty11/tests/EmbeddedJettyMockBuilder.java @@ -0,0 +1,192 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.jetty11.tests; + +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Builder for mock instances of {@link EmbeddedJetty}. + */ +public class EmbeddedJettyMockBuilder { + + /** + * Server scheme (for example, {@code "http"} or {@code "https"}). + * Default is {@code "http"} + */ + private String scheme; + + /** + * Server host (default is {@code "localhost"}). + */ + private String host; + + /** + * Server port (default is {@code 80}). + */ + private int port; + + /** + * Server path (default is {@code "/"}). + */ + private String path; + + /** + * Server URL (default is an URL built using {@link #scheme}, {@link #host}, {@link #port} and {@link #path}). + */ + private String url; + + /** + * Server Configuration. + */ + private EmbeddedJettyConfiguration configuration; + + /** + * Create builder with default initial values. + */ + public EmbeddedJettyMockBuilder() { + this.scheme = "http"; + this.host = "localhost"; + this.port = 80; + this.path = "/"; + } + + /** + * Set new {@link #scheme}. + * + * @param scheme New {@link #scheme} + * @return The builder. + */ + public EmbeddedJettyMockBuilder withScheme(String scheme) { + this.scheme = scheme; + return this; + } + + /** + * Set new {@link #host}. + * + * @param host New {@link #host} + * @return The builder. + */ + public EmbeddedJettyMockBuilder withHost(String host) { + this.host = host; + return this; + } + + /** + * Set new {@link #port}. + * + * @param port New {@link #port} + * @return The builder. + */ + public EmbeddedJettyMockBuilder withPort(int port) { + this.port = port; + return this; + } + + /** + * Set new {@link #path}. + * + * @param path New {@link #path} + * @return The builder. + */ + public EmbeddedJettyMockBuilder withPath(String path) { + this.path = path; + return this; + } + + /** + * Set new {@link #url}. + * + * @param url New {@link #url} + * @return The builder. + */ + public EmbeddedJettyMockBuilder withUrl(String url) { + this.url = url; + return this; + } + + /** + * Set new {@link #configuration}. + * + * @param configuration New {@link #configuration} + * @return The builder. + */ + public EmbeddedJettyMockBuilder withConfiguration(EmbeddedJettyConfiguration configuration) { + this.configuration = configuration; + return this; + } + + /** + * Build mock instance of {@link EmbeddedJetty}. + * + * @return The mock instance. + */ + public EmbeddedJetty build() { + EmbeddedJetty jetty = mock(EmbeddedJetty.class); + when(jetty.getScheme()).thenReturn(scheme); + when(jetty.getHost()).thenReturn(host); + when(jetty.getPort()).thenReturn(port); + when(jetty.getPath()).thenReturn(path); + when(jetty.isStarted()).thenReturn(false); + + String url = this.url == null ? url(scheme, host, port, path) : this.url; + when(jetty.getUrl()).thenReturn(url); + + EmbeddedJettyConfiguration configuration = this.configuration == null ? new EmbeddedJettyConfigurationMockBuilder().build() : this.configuration; + when(jetty.getConfiguration()).thenReturn(configuration); + + doAnswer(new IsStartedAnswer(jetty, true)).when(jetty).start(); + doAnswer(new IsStartedAnswer(jetty, false)).when(jetty).stop(); + + return jetty; + } + + private static String url(String scheme, String host, int port, String path) { + return scheme + "://" + host + ":" + port + path; + } + + private static class IsStartedAnswer implements Answer { + private final EmbeddedJetty jetty; + private final boolean isStarted; + + private IsStartedAnswer(EmbeddedJetty jetty, boolean isStarted) { + this.jetty = jetty; + this.isStarted = isStarted; + } + + @Override + public Void answer(InvocationOnMock invocationOnMock) { + when(jetty.isStarted()).thenReturn(isStarted); + return null; + } + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/junit4/JunitServerRunnerTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/junit4/JunitServerRunnerTest.java new file mode 100644 index 00000000..512c4ad0 --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/junit4/JunitServerRunnerTest.java @@ -0,0 +1,93 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.junit4; + +import com.github.mjeanroy.junit.servers.annotations.TestServer; +import com.github.mjeanroy.junit.servers.annotations.TestServerConfiguration; +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import com.github.mjeanroy.junit.servers.servers.AbstractConfiguration; +import com.github.mjeanroy.junit.servers.servers.EmbeddedServer; +import org.junit.jupiter.api.Test; + +import static com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration.defaultConfiguration; +import static org.apache.commons.lang3.reflect.FieldUtils.readField; +import static org.assertj.core.api.Assertions.assertThat; + +class JunitServerRunnerTest { + + private static final EmbeddedJettyConfiguration configuration = defaultConfiguration(); + + @Test + void it_should_instantiate_jetty_with_configuration() throws Exception { + final JunitServerRunner runner = new JunitServerRunner(TestClassWithConfigurationMethod.class); + final EmbeddedServer server = (EmbeddedServer) readField(runner, "server", true); + final AbstractConfiguration conf = (AbstractConfiguration) readField(runner, "configuration", true); + + assertThat(server).isInstanceOf(EmbeddedJetty.class); + assertThat(conf).isSameAs(configuration); + } + + @Test + void it_should_instantiate_jetty_with_default_configuration() throws Exception { + final JunitServerRunner runner = new JunitServerRunner(TestClassWithInjectedConfiguration.class); + final EmbeddedServer server = (EmbeddedServer) readField(runner, "server", true); + final AbstractConfiguration conf = (AbstractConfiguration) readField(runner, "configuration", true); + + assertThat(server).isInstanceOf(EmbeddedJetty.class); + assertThat(conf).isNotSameAs(configuration).isEqualTo(configuration); + } + + public static class TestClassWithInjectedConfiguration { + + @TestServer + private static EmbeddedServer server; + + @TestServerConfiguration + private static EmbeddedJettyConfiguration configuration; + + public TestClassWithInjectedConfiguration() { + } + + @org.junit.Test + public void fooTest() { + } + } + + public static class TestClassWithConfigurationMethod { + + @TestServer + private static EmbeddedServer server; + + @TestServerConfiguration + private static EmbeddedJettyConfiguration initConfiguration() { + return configuration; + } + + @org.junit.Test + public void fooTest() { + } + } +} diff --git a/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/junit4/ServerRuleTest.java b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/junit4/ServerRuleTest.java new file mode 100644 index 00000000..b0f5a261 --- /dev/null +++ b/junit-servers-jetty-12/src/test/java/com/github/mjeanroy/junit/servers/junit4/ServerRuleTest.java @@ -0,0 +1,82 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2014-2022 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.github.mjeanroy.junit.servers.junit4; + +import com.github.mjeanroy.junit.servers.jetty.EmbeddedJettyConfiguration; +import com.github.mjeanroy.junit.servers.jetty11.EmbeddedJetty; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class ServerRuleTest { + + private ServerRule rule; + + @AfterEach + void tearDown() { + if (rule != null) { + rule.stop(); + } + } + + @Test + void it_should_start_jetty_because_of_classpath_detection() { + rule = new ServerRule(); + assertThat(rule.getServer()).isExactlyInstanceOf(EmbeddedJetty.class); + assertThat(rule.getServer().getConfiguration()).isEqualTo(EmbeddedJettyConfiguration.defaultConfiguration()); + } + + @Test + void it_should_start_jetty_with_custom_configuration_because_of_classpath_detection() { + final EmbeddedJettyConfiguration configuration = EmbeddedJettyConfiguration.builder() + .withPort(9000) + .build(); + + rule = new ServerRule(configuration); + assertThat(rule.getServer()).isExactlyInstanceOf(EmbeddedJetty.class); + assertThat(rule.getServer().getConfiguration()).isEqualTo(configuration); + } + + @Test + void it_should_start_jetty_and_get_real_port() { + rule = new ServerRule(); + assertThat(rule.getPort()).isZero(); + + rule.start(); + assertThat(rule.getPort()).isNotZero(); + } + + @Test + void it_should_start_jetty_and_get_uri() { + rule = new ServerRule(); + rule.start(); + assertThat(rule.getUrl()).isEqualTo(localUrl(rule.getPort())); + } + + private static String localUrl(int port) { + return "http://localhost:" + port + "/"; + } +} diff --git a/junit-servers-jetty-12/src/test/resources/custom-web.xml b/junit-servers-jetty-12/src/test/resources/custom-web.xml new file mode 100644 index 00000000..28271759 --- /dev/null +++ b/junit-servers-jetty-12/src/test/resources/custom-web.xml @@ -0,0 +1,38 @@ + + + + + + page + /hello-world.html + + + page + /hello + + diff --git a/junit-servers-jetty-12/src/test/resources/hello-world.html b/junit-servers-jetty-12/src/test/resources/hello-world.html new file mode 100644 index 00000000..10a240a0 --- /dev/null +++ b/junit-servers-jetty-12/src/test/resources/hello-world.html @@ -0,0 +1,7 @@ + + + + index.html + +Hello World + \ No newline at end of file diff --git a/junit-servers-jetty-12/src/test/resources/index.html b/junit-servers-jetty-12/src/test/resources/index.html new file mode 100644 index 00000000..9b870b23 --- /dev/null +++ b/junit-servers-jetty-12/src/test/resources/index.html @@ -0,0 +1,7 @@ + + + + index.html + +Index + \ No newline at end of file diff --git a/junit-servers-jetty-12/src/test/resources/logback-test.xml b/junit-servers-jetty-12/src/test/resources/logback-test.xml new file mode 100644 index 00000000..60427fe0 --- /dev/null +++ b/junit-servers-jetty-12/src/test/resources/logback-test.xml @@ -0,0 +1,35 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + diff --git a/pom.xml b/pom.xml index 38a9ec63..a88230d9 100644 --- a/pom.xml +++ b/pom.xml @@ -102,6 +102,7 @@ 9.4.53.v20231009 10.0.18 11.0.18 + 12.0.3 8.5.96 9.0.83 @@ -449,6 +450,26 @@ + + java17 + + [17,) + + + junit-servers-core + junit-servers-jetty + junit-servers-jetty-9 + junit-servers-jetty-10 + junit-servers-jetty-11 + junit-servers-jetty-12 + junit-servers-tomcat + junit-servers-tomcat-8 + junit-servers-tomcat-9 + junit-servers-tomcat-10 + junit-servers-samples + + + release