From 78a71b71ccfb2fe05040a78434082051dd917245 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Thu, 2 May 2019 18:51:06 -0500 Subject: [PATCH] Issue #3620 - Exit Server.start() if LifeCycle.start() fails + DeploymentManager will hang onto errors encountered and report them en-masse if on it's own doStart(). + Added jetty-deploy test cases. + Added test-distribution test case. + Updated test-distribution to allow this kind of test case. Signed-off-by: Joakim Erdfelt --- .../jetty/deploy/DeploymentManager.java | 24 +++ .../jetty/deploy/BadAppDeployTest.java | 181 ++++++++++++++++++ .../test/resources/webapps/badapp/badapp.war | Bin 0 -> 3498 bytes .../test/resources/webapps/badapp/badapp.xml | 8 + tests/test-distribution/pom.xml | 1 - .../distribution/DistributionTester.java | 31 ++- .../tests/distribution/BadStartupTest.java | 64 +++++++ .../src/test/resources/badapp/badapp.war | Bin 0 -> 3498 bytes .../src/test/resources/badapp/badapp.xml | 8 + 9 files changed, 310 insertions(+), 7 deletions(-) create mode 100644 jetty-deploy/src/test/java/org/eclipse/jetty/deploy/BadAppDeployTest.java create mode 100644 jetty-deploy/src/test/resources/webapps/badapp/badapp.war create mode 100644 jetty-deploy/src/test/resources/webapps/badapp/badapp.xml create mode 100644 tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/BadStartupTest.java create mode 100644 tests/test-distribution/src/test/resources/badapp/badapp.war create mode 100644 tests/test-distribution/src/test/resources/badapp/badapp.xml diff --git a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java index 5fcfbbc1cae..a61c471cd8b 100644 --- a/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java +++ b/jetty-deploy/src/main/java/org/eclipse/jetty/deploy/DeploymentManager.java @@ -68,6 +68,7 @@ import org.eclipse.jetty.xml.XmlConfiguration; public class DeploymentManager extends ContainerLifeCycle { private static final Logger LOG = Log.getLogger(DeploymentManager.class); + private List onStartupErrors; /** * Represents a single tracked app within the deployment manager. @@ -237,6 +238,14 @@ public class DeploymentManager extends ContainerLifeCycle { startAppProvider(provider); } + + if (onStartupErrors != null) + { + RuntimeException mex = new RuntimeException("Failed to successfully start App Providers (See log for details)"); + onStartupErrors.forEach((cause) -> mex.addSuppressed(cause)); + throw mex; + } + super.doStart(); } @@ -507,6 +516,7 @@ public class DeploymentManager extends ContainerLifeCycle catch (Throwable t) { LOG.warn("Unable to reach node goal: " + nodeName,t); + LOG.info("state() = {}", getState()); // migrate to FAILED node Node failed = _lifecycle.getNodeByName(AppLifeCycle.FAILED); appentry.setLifeCycleNode(failed); @@ -519,9 +529,23 @@ public class DeploymentManager extends ContainerLifeCycle // The runBindings failed for 'failed' node LOG.ignore(ignore); } + + if (isStarting()) + { + addOnStartupError(t); + } } } + private synchronized void addOnStartupError(Throwable cause) + { + if(onStartupErrors == null) + { + onStartupErrors = new ArrayList(); + } + onStartupErrors.add(cause); + } + /** * Move an {@link App} through the {@link AppLifeCycle} to the desired {@link Node}, executing each lifecycle step * in the process to reach the desired state. diff --git a/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/BadAppDeployTest.java b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/BadAppDeployTest.java new file mode 100644 index 00000000000..8ab3663b82f --- /dev/null +++ b/jetty-deploy/src/test/java/org/eclipse/jetty/deploy/BadAppDeployTest.java @@ -0,0 +1,181 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.deploy; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import javax.servlet.ServletException; + +import org.eclipse.jetty.deploy.providers.WebAppProvider; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.ServerConnector; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.server.handler.DefaultHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; +import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.StacklessLogging; +import org.eclipse.jetty.webapp.WebAppContext; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static java.time.Duration.ofSeconds; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(WorkDirExtension.class) +public class BadAppDeployTest +{ + public WorkDir workDir; + private Server server; + + @AfterEach + public void stopServer() throws Exception + { + if (server != null) + { + server.stop(); + } + } + + @Test + public void testBadApp_XmlOrder() throws Exception + { + /* Non-working Bean Order as reported in Issue #3620 + It is important that this Order be maintained for an accurate test case. + ### BEAN: QueuedThreadPool[qtp1327763628]@4f2410ac{STOPPED,8<=0<=200,i=0,r=-1,q=0}[NO_TRY] + ### BEAN: ServerConnector@16f65612{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} + ### BEAN: HandlerCollection@5f150435{STOPPED} + ### BEAN: DeploymentManager@1c53fd30{STOPPED} + */ + + /* Working Bean Order + ### BEAN: QueuedThreadPool[qtp1530388690]@5b37e0d2{STOPPED,8<=0<=200,i=0,r=-1,q=0}[NO_TRY] + ### BEAN: ServerConnector@5e265ba4{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} + ### BEAN: DeploymentManager@3419866c{STOPPED} + ### BEAN: HandlerCollection@63e31ee{STOPPED} + */ + + server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(0); + server.addConnector(connector); + + ContextHandlerCollection contexts = new ContextHandlerCollection(); + HandlerCollection handlers = new HandlerCollection(); + handlers.addHandler(contexts); + handlers.addHandler(new DefaultHandler()); + server.setHandler(handlers); // this should be done before addBean(deploymentManager) + + DeploymentManager deploymentManager = new DeploymentManager(); + deploymentManager.setContexts(contexts); + WebAppProvider webAppProvider = new WebAppProvider(); + deploymentManager.addAppProvider(webAppProvider); + + Path webappsDir = workDir.getEmptyPathDir().resolve("webapps").toAbsolutePath(); + + FS.ensureDirExists(webappsDir); + + copyTestResource("webapps/badapp/badapp.war", webappsDir.resolve("badapp.war")); + copyTestResource("webapps/badapp/badapp.xml", webappsDir.resolve("badapp.xml")); + + webAppProvider.setMonitoredDirName(webappsDir.toString()); + webAppProvider.setScanInterval(1); + + server.addBean(deploymentManager); // this should be done after setHandler(handlers) + + assertTimeoutPreemptively(ofSeconds(10), () -> { + + try (StacklessLogging ignore = new StacklessLogging(Log.getLogger(WebAppContext.class), + Log.getLogger(DeploymentManager.class), + Log.getLogger("org.eclipse.jetty.server.handler.ContextHandler.badapp"))) + { + RuntimeException cause = assertThrows(RuntimeException.class, () -> server.start()); + assertThat(cause.getMessage(), containsString("Failed to successfully start App Providers")); + assertTrue(server.isFailed(), "Server should be in failed state"); + } + }); + } + + @Test + public void testBadApp_EmbeddedOrder() throws Exception + { + /* Working Bean Order + ### BEAN: QueuedThreadPool[qtp1530388690]@5b37e0d2{STOPPED,8<=0<=200,i=0,r=-1,q=0}[NO_TRY] + ### BEAN: ServerConnector@5e265ba4{HTTP/1.1,[http/1.1]}{0.0.0.0:8080} + ### BEAN: DeploymentManager@3419866c{STOPPED} + ### BEAN: HandlerCollection@63e31ee{STOPPED} + */ + + server = new Server(); + ServerConnector connector = new ServerConnector(server); + connector.setPort(0); + server.addConnector(connector); + + ContextHandlerCollection contexts = new ContextHandlerCollection(); + + DeploymentManager deploymentManager = new DeploymentManager(); + deploymentManager.setContexts(contexts); + WebAppProvider webAppProvider = new WebAppProvider(); + deploymentManager.addAppProvider(webAppProvider); + + Path webappsDir = workDir.getEmptyPathDir().resolve("webapps").toAbsolutePath(); + + FS.ensureDirExists(webappsDir); + + copyTestResource("webapps/badapp/badapp.war", webappsDir.resolve("badapp.war")); + copyTestResource("webapps/badapp/badapp.xml", webappsDir.resolve("badapp.xml")); + + webAppProvider.setMonitoredDirName(webappsDir.toString()); + webAppProvider.setScanInterval(1); + + server.addBean(deploymentManager); // this should be done before setHandler(handlers) + + HandlerCollection handlers = new HandlerCollection(); + handlers.addHandler(contexts); + handlers.addHandler(new DefaultHandler()); + server.setHandler(handlers); // this should be done after addBean(deploymentManager) + + assertTimeoutPreemptively(ofSeconds(10), () -> { + + try (StacklessLogging ignore = new StacklessLogging(Log.getLogger(WebAppContext.class), + Log.getLogger(DeploymentManager.class), + Log.getLogger("org.eclipse.jetty.server.handler.ContextHandler.badapp"))) + { + ServletException cause = assertThrows(ServletException.class, () -> server.start()); + assertThat(cause.getMessage(), containsString("intentionally")); + assertTrue(server.isFailed(), "Server should be in failed state"); + } + }); + } + + private void copyTestResource(String testResourceFile, Path webappsFile) throws IOException + { + Path srcFile = MavenTestingUtils.getTestResourcePathFile(testResourceFile); + Files.copy(srcFile, webappsFile); + } +} diff --git a/jetty-deploy/src/test/resources/webapps/badapp/badapp.war b/jetty-deploy/src/test/resources/webapps/badapp/badapp.war new file mode 100644 index 0000000000000000000000000000000000000000..3fc1a60d5fed97cce688c80c755daa1973329997 GIT binary patch literal 3498 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 literal 0 HcmV?d00001 diff --git a/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml b/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml new file mode 100644 index 00000000000..d085d7b9cec --- /dev/null +++ b/jetty-deploy/src/test/resources/webapps/badapp/badapp.xml @@ -0,0 +1,8 @@ + + + + + /badapp + /badapp.war + true + diff --git a/tests/test-distribution/pom.xml b/tests/test-distribution/pom.xml index fb9106462ae..47dad9d2a39 100644 --- a/tests/test-distribution/pom.xml +++ b/tests/test-distribution/pom.xml @@ -78,7 +78,6 @@ org.eclipse.jetty.toolchain jetty-test-helper - test org.eclipse.jetty diff --git a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java index 44a2a9edda9..9faf5b73010 100644 --- a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java +++ b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java @@ -62,6 +62,8 @@ import org.eclipse.aether.spi.connector.transport.TransporterFactory; import org.eclipse.aether.transfer.AbstractTransferListener; import org.eclipse.aether.transport.file.FileTransporterFactory; import org.eclipse.aether.transport.http.HttpTransporterFactory; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -166,6 +168,21 @@ public class DistributionTester } } + /** + * Installs content from {@code src/test/resources/} into {@code ${jetty.base}/} + * + * @param testResourcePath the location of the source file in {@code src/test/resources} + * @param baseResourcePath the location of the destination file in {@code ${jetty.base}} + * @throws IOException if unable to copy file + */ + public void installBaseResource(String testResourcePath, String baseResourcePath) throws IOException + { + Path srcFile = MavenTestingUtils.getTestResourcePath(testResourcePath); + Path destFile = config.jettyBase.resolve(baseResourcePath); + + Files.copy(srcFile, destFile); + } + /** * Installs in {@code ${jetty.base}/webapps} the given war file under the given context path. * @@ -176,7 +193,7 @@ public class DistributionTester public void installWarFile(File warFile, String context) throws IOException { //webapps - Path webapps = Paths.get(config.jettyBase.toString(), "webapps", context); + Path webapps = config.jettyBase.resolve("webapps").resolve(context); if (!Files.exists(webapps)) Files.createDirectories(webapps); unzip(warFile, webapps.toFile()); @@ -213,7 +230,9 @@ public class DistributionTester if (config.jettyBase == null) { - config.jettyBase = Files.createTempDirectory("jetty_base_"); + Path bases = MavenTestingUtils.getTargetTestingPath("bases"); + FS.ensureDirExists(bases); + config.jettyBase = Files.createTempDirectory(bases, "jetty_base_"); } else { @@ -225,12 +244,12 @@ public class DistributionTester private String getJavaExecutable() { String[] javaExecutables = new String[]{"java", "java.exe"}; - File javaHomeDir = new File(System.getProperty("java.home")); + Path javaBinDir = Paths.get(System.getProperty("java.home")).resolve("bin"); for (String javaExecutable : javaExecutables) { - File javaFile = new File(javaHomeDir, "bin" + File.separator + javaExecutable); - if (javaFile.exists() && javaFile.isFile()) - return javaFile.getAbsolutePath(); + Path javaFile = javaBinDir.resolve(javaExecutable); + if (Files.exists(javaFile) && Files.isRegularFile(javaFile)) + return javaFile.toAbsolutePath().toString(); } return "java"; } diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/BadStartupTest.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/BadStartupTest.java new file mode 100644 index 00000000000..8a1283b75c2 --- /dev/null +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/BadStartupTest.java @@ -0,0 +1,64 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.tests.distribution; + +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Tests where we expect the server to not start properly. + * Presumably due to bad configuration, or bad webapps. + */ +public class BadStartupTest +{ + @Test + public void testThrowOnUnavailable_BadApp() throws Exception + { + String jettyVersion = System.getProperty("jettyVersion"); + DistributionTester distribution = DistributionTester.Builder.newInstance() + .jettyVersion(jettyVersion) + .mavenLocalRepository(System.getProperty("mavenRepoPath")) + .build(); + + try (DistributionTester.Run run1 = distribution.start("--add-to-start=http,deploy")) + { + assertTrue(run1.awaitFor(5, TimeUnit.SECONDS)); + assertThat(run1.getExitValue(), is(0)); + + // Setup webapps directory + distribution.installBaseResource("badapp/badapp.war", + "webapps/badapp.war"); + distribution.installBaseResource("badapp/badapp.xml", + "webapps/badapp.xml"); + + int port = distribution.freePort(); + try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) + { + assertTrue(run2.awaitFor(5, TimeUnit.SECONDS), "Should have exited"); + assertThat("Should have gotten a non-zero exit code", run2.getExitValue(), not(is(0))); + } + } + } +} diff --git a/tests/test-distribution/src/test/resources/badapp/badapp.war b/tests/test-distribution/src/test/resources/badapp/badapp.war new file mode 100644 index 0000000000000000000000000000000000000000..3fc1a60d5fed97cce688c80c755daa1973329997 GIT binary patch literal 3498 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 literal 0 HcmV?d00001 diff --git a/tests/test-distribution/src/test/resources/badapp/badapp.xml b/tests/test-distribution/src/test/resources/badapp/badapp.xml new file mode 100644 index 00000000000..d085d7b9cec --- /dev/null +++ b/tests/test-distribution/src/test/resources/badapp/badapp.xml @@ -0,0 +1,8 @@ + + + + + /badapp + /badapp.war + true +