Skip to content

Setting management port causes multiple Tomcat instances to start in tests #2798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sawano opened this issue Apr 9, 2015 · 7 comments
Closed
Assignees
Labels
type: bug A general bug
Milestone

Comments

@sawano
Copy link

sawano commented Apr 9, 2015

If I set the management port via configuration then a Tomcat will be started listening on that port when running @WebAppConfiguration tests.
I.e. an application.yml with:

management:
  port: 8081

would cause a Tomcat to start on port 8081 when running a test looking like this:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringApplicationConfiguration(classes = {Application.class})
public class ATest {
...
}

This is not the intended behavior if I am correct or am I missing something?

The implication I am running into (this might be a separate issue) is that if I have two tests with different application contexts then that will cause the second test to fail. Apparently because the loading of the second application context also tries to start a Tomcat on the same port. Which obviously fails.

That is, if the second test looks like:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringApplicationConfiguration(classes = {Application.class, BTest.Conf.class})
public class BTest {
...
}

then running both ATest and BTest will fail one of them.

So I guess the two questions are

  1. Is a Tomcat for the management port supposed to start in the test?
  2. If so, why is the second application context triggering a start of a new Tomcat?

I put some example code that illustrates this here https://github.com/sawano/spring-boot-management-port-test-issue

@snicoll
Copy link
Member

snicoll commented Apr 10, 2015

Well, web integration test does start the server so that makes sense to me. What if you want to test something related to a management endpoint anyway? What if you don't see the value at all? Do you expect the management stuff not to be started either?

It all sounds to me that you have to have @WebAppConfiguration("management.port=0") in your tests (or where you ask boot to randomly choose a port for the main tomcat). After all, you decide to create a separate tomcat instance for the management endpoints...

@sawano
Copy link
Author

sawano commented Apr 10, 2015

Thanks for the response.

My expectation was that a server should never be started when using @WebAppConfiguration. Neither for the "normal" application or the actuator endpoints. Regardless of configured ports
If I wanted to write an integration test that needed an entire server (e.g. Tomcat) I would use @WebIntegrationTest, and use "server.port=0", "management.port=0" to randomize ports to avoid conflicts between tests.

What doesn't make sense to me is that "normally" a Tomcat is never started when writing tests with just @WebAppConfiguration/@SpringApplicationConfiguration combinations. And you will use @WebIntegrationTest in the case you actually do want Tomcat(s) to be started. But at the same time if you happen to specify a management port in your production configuration then suddenly a Tomcat is started regardless of the presence of @WebIntegrationTest. If that really is the intended behavior then I think it should be clearly documented to avoid confusion.

@sawano
Copy link
Author

sawano commented Apr 14, 2015

Just to clarify, I am still wondering if a Tomcat is supposed to start when you do not specify @WebIntegrationTest or if it is a bug that should be addressed.

@snicoll
Copy link
Member

snicoll commented Apr 14, 2015

It's a bug I'd say.

@snicoll snicoll added type: bug A general bug and removed question labels Apr 14, 2015
@snicoll snicoll added this to the 1.2.4 milestone Apr 14, 2015
@wilkinsona
Copy link
Member

A related problem is that if you build a war file with management.port configured, it'll run happily using java -jar but it'll fail when you deploy it to Tomcat:

15-Apr-2015 12:13:35.568 SEVERE [localhost-startStop-1] org.apache.catalina.loader.WebappLoader.startInternal LifecycleException
 java.lang.ClassNotFoundException: org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedWebappClassLoader
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:260)
    at org.apache.catalina.loader.WebappLoader.createClassLoader(WebappLoader.java:508)
    at org.apache.catalina.loader.WebappLoader.startInternal(WebappLoader.java:393)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5030)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

I believe the solution in both cases is to only start up the child context when the current web application context is an EmbeddedWebApplicationContext.

@wilkinsona
Copy link
Member

That doesn't work as, even when deployed to a servlet container as a war, the current web application context is still an EmbeddedWebApplicationContext.

@wilkinsona wilkinsona self-assigned this Apr 15, 2015
@sawano
Copy link
Author

sawano commented Apr 15, 2015

Great! Thanks for the quick response.

bsodzik pushed a commit to bsodzik/spring-boot that referenced this issue May 23, 2015
Prior to this commit, EndpointWebMvcAutoConfiguration would start a
child context if the management port was different to the server port
and the application context was a web application context. This caused
two problems:

If a user built an executable war and configured the management port so
that it was different to the server port, their application would run
successfully when launched with java -jar, but it would fail when
deployed to Tomcat as an attempt would be made to start embedded Tomcat.

Secondly, if a user ran a test annotated with @WebAppConfiguration the
main embedded Tomcat instance would not be started, but the child
context would trigger the creation of a Tomcat instance listening on the
configured management port. This is unexpected as @WebIntegrationTest
or @IntegrationTEST and @WebAppConfiguration should be required to have
the test trigger full startup of the application and listen on the
configured ports.

This commit updates EndpointWebMvcAutoConfiguration so that it will only
start a child context when the management port is different to the
server port and the EmbeddedWebApplicationContext has an embedded
servlet container. This resolves the two problems described above as
there will be no embedded servlet container when deployed to a
standalone container or when a test is run without @IntegrationTEST.

Fixes spring-projectsgh-2798
philwebb added a commit that referenced this issue Jun 2, 2015
Extract @ConditionalOnEnabledEndpoint to a top level class.

See gh-2798
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants