Spring-boot: Embedded Tomcat connector exceptions with Spring boot tests

Created on 20 Sep 2017  路  4Comments  路  Source: spring-projects/spring-boot

Description

I'm experiencing a strange exception when I run a test suite:

Caused by: org.springframework.boot.context.embedded.tomcat.ConnectorStartFailedException: 
Connector configured to listen on port 9109 failed to start

The following message is logged:

***************************
APPLICATION FAILED TO START
***************************

Description:

The Tomcat connector configured to listen on port 9109 failed to start. The port may already be in use or the connector may be misconfigured.

Action:

Verify the connector's configuration, identify and stop any process that's listening on port 9109, or configure this application to listen on another port.

The root cause seems to be the following:

java.net.BindException: Address already in use

Spring Version

1.5.6.RELEASE


Steps to reproduce

I was able to reproduce the problem with the following classes:

BaseTest

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ApplicationBootstrap.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource(locations = "classpath:integration-test.properties")
public abstract class BaseTest {
}

Test1

public class Test1 extends BaseTest {

    @Test
    public void test1() {
        System.out.println("foo");
    }

}

Test2

@TestPropertySource(properties = "NEW_PROPERTY=true")
public class Test2 extends BaseTest {

    @Test
    public void test2() {
        System.out.println("bar");
    }

}

When I run all the tests, Test1 is run first without issue and then it looks as if the application context is refreshed before Test2 is run. Test2 fails with

java.lang.IllegalStateException: Failed to load ApplicationContext

Caused by the ConnectorStartFailedException described above

invalid

Most helpful comment

This is working as designed. Spring Framework's test framework will, by default, cache contexts for possible reuse by multiple test classes. You have two tests with different configuration (due to @TestPropertySource) so they will use different application contexts. The context for the first test will be cached and kept open while the second test is running. Both tests are configured to use the same port for Tomcat's connector. As a result, when the second test is run, the context fails to start due to a port clash with the connector from the first test. You have a few options:

  1. Use RANDOM_PORT
  2. Remove @TestPropertySource from Test2 so that the contexts have identical configuration and the context from the first test can be reused for the second test.
  3. Use @DirtiesContext so that the context isn't cached

If you require further guidance, please follow up on Stack Overflow or Gitter.

All 4 comments

This is working as designed. Spring Framework's test framework will, by default, cache contexts for possible reuse by multiple test classes. You have two tests with different configuration (due to @TestPropertySource) so they will use different application contexts. The context for the first test will be cached and kept open while the second test is running. Both tests are configured to use the same port for Tomcat's connector. As a result, when the second test is run, the context fails to start due to a port clash with the connector from the first test. You have a few options:

  1. Use RANDOM_PORT
  2. Remove @TestPropertySource from Test2 so that the contexts have identical configuration and the context from the first test can be reused for the second test.
  3. Use @DirtiesContext so that the context isn't cached

If you require further guidance, please follow up on Stack Overflow or Gitter.

I wouldnt be so quick to write this off as invalid

  1. I can't use RANDOM_PORT in this case as the port needs to be predictable
  2. I need to run a test suite with a certain property enabled and another test suite with the property disabled so I cant just remove @TestPropertySource
  3. While @DirtiesContext does fix the issue, it makes the tests very slow as it forces a refresh of the application context for each test class so I wouldnt accept that as a solution

This is working as designed

I have used this pattern with earlier versions of spring boot and it works


The application context seems to be refreshed when Test2 is run as there is a new property, but it looks like it doesnt clean to the extent of @DirtiesContext. Is there a way to fix this?

I have used this pattern with earlier versions of spring boot and it works

I can't think how that could be. If you have two contexts that are cached and kept open, both configured to use the same port they will fail with a port clash. If you can provide an example of the pattern working with earlier versions of Boot then we can investigate further.

The application context seems to be refreshed when Test2 is run as there is a new property, but it looks like it doesnt clean to the extent of @DirtiesContext. Is there a way to fix this?

No. There's no cleaning going on. There are two application contexts and the second context is refreshed while the first is cached and kept open. @DirtiesContext prevents the context from being cached and kept open.

No. There's no cleaning going on. There are two application contexts and the second context is refreshed while the first is cached and kept open. @DirtiesContext prevents the context from being cached and kept open.

Oh I see. A lack of understanding on my part.

I have used this pattern with earlier versions of spring boot and it works

It turns out that while I was using @TestPropertySource without issue, the server was configured with a random port so there was no conflicts.


It seems that I need to rethink my approach. Thanks for your help 馃槂

Was this page helpful?
0 / 5 - 0 ratings