@Test public void testTimerThreadLeak() throws Exception { Tomcat tomcat = getTomcatInstance(); // No file system docBase required Context ctx = tomcat.addContext("", null); if (ctx instanceof StandardContext) { ((StandardContext) ctx).setClearReferencesStopTimerThreads(true); } Tomcat.addServlet(ctx, "taskServlet", new TaskServlet()); ctx.addServletMapping("/", "taskServlet"); tomcat.start(); // This will trigger the timer & thread creation getUrl("http://localhost:" + getPort() + "/"); // Stop the context ctx.stop(); Thread[] threads = getThreads(); for (Thread thread : threads) { if (thread != null && thread.isAlive() && TaskServlet.TIMER_THREAD_NAME.equals(thread.getName())) { thread.join(5000); if (thread.isAlive()) { fail("Timer thread still running"); } } } }
static StandardContext configure(Tomcat tomcat, Props props) { try { StandardContext context = (StandardContext) tomcat.addWebapp(getContextPath(props), webappPath(props)); context.setClearReferencesHttpClientKeepAliveThread(false); context.setClearReferencesStatic(false); context.setClearReferencesStopThreads(false); context.setClearReferencesStopTimerThreads(false); context.setClearReferencesStopTimerThreads(false); context.setAntiResourceLocking(false); context.setReloadable(false); context.setUseHttpOnly(true); context.setTldValidation(false); context.setXmlValidation(false); context.setXmlNamespaceAware(false); context.setUseNaming(false); context.setDelegate(true); context.setJarScanner(new NullJarScanner()); configureRails(props, context); for (Map.Entry<Object, Object> entry : props.rawProperties().entrySet()) { String key = entry.getKey().toString(); context.addParameter(key, entry.getValue().toString()); } return context; } catch (Exception e) { throw new IllegalStateException("Fail to configure webapp", e); } }