I have a Postgres test container with a maximum of 100 connections. The test container is reused for different tests.
@Bean
@ServiceConnection
@RestartScope
public PostgreSQLContainer<?> postgreSQLContainer() {
return createpostgreSQLContainer( dockerImageName );
}
The Hikari Pool has a maximum of 25 connections.
If I now run more than 4 Spring Boot test classes in a row, I see that a Hikari pool with 25 connections is created for each test class. However, these pools will no longer be closed also when the test is over. After more than 4 tests, all connections are used up and the tests fail because they can no longer acquire a connection.
How to solve the problem?
EDIT: I once built an MRE that shows the problem. If you run them all TOGETHER in IDE(e.g. Intellij) or maven, you will see the error messages in the logs. The problem is that 2-3 Hikarki pools are opened with 55 connections. But the TestContainer can only open 100.
What I've found out so far is the following:
The problem is your tests.
@ExtendWith( SpringExtension.class )
@SpringBootTest(
classes = {
TestConfig.class,
SQLContainerConfiguration.class,
TestWebConfig.class },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT )
@ActiveProfiles( "test" )
@EnableAutoConfiguration
class ConnectionPoolIssueTest1 {
@ExtendWith( SpringExtension.class )
@SpringBootTest(
classes = {
TestConfig.class,
SQLContainerConfiguration.class },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT )
@ActiveProfiles( "test" )
@EnableAutoConfiguration
class ConnectionPoolIssueTest2 {
@ExtendWith( SpringExtension.class )
@SpringBootTest(
classes = {
TestConfig.class,
SQLContainerConfiguration.class,
TestWebConfig.class },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT )
@ActiveProfiles( "test" )
@EnableAutoConfiguration
class ConnectionPoolIssueTest3 {
@ExtendWith( SpringExtension.class )
@SpringBootTest(
classes = {
TestConfig.class,
SQLContainerConfiguration.class },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT )
@ActiveProfiles( "test" )
@EnableAutoConfiguration
class ConnectionPoolIssueTest4 {
@ExtendWith( SpringExtension.class )
@SpringBootTest(
classes = {
TestConfig.class,
SQLContainerConfiguration.class,
TestWebConfig.class },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT )
@ActiveProfiles( "test" )
@EnableAutoConfiguration
class ConnectionPoolIssueTest5 {
@ExtendWith( SpringExtension.class )
@SpringBootTest(
classes = {
TestConfig.class,
SQLContainerConfiguration.class,
TestWebConfig.class },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT )
@ActiveProfiles( "test" )
@EnableAutoConfiguration
class ConnectionPoolIssueTest6 {
As explained in the Spring Framework Reference Guide the testing support in Spring will use context caching. To determine a key there is quite a long list of things that influence it.
An
ApplicationContext
can be uniquely identified by the combination of configuration parameters that is used to load it. Consequently, the unique combination of configuration parameters is used to generate a key under which the context is cached. The TestContext framework uses the following configuration parameters to build the context cache key:
locations
(from@ContextConfiguration
)
classes
(from@ContextConfiguration
)
contextInitializerClasses
(from@ContextConfiguration
)
contextCustomizers
(fromContextCustomizerFactory
) – this includes@DynamicPropertySource
methods as well as various features from Spring Boot’s testing support such as@MockBean
and@SpyBean
.
contextLoader
(from@ContextConfiguration
)
parent
(from@ContextHierarchy
)
activeProfiles
(from@ActiveProfiles
)
propertySourceDescriptors
(from@TestPropertySource
)
propertySourceProperties
(from@TestPropertySource
)
resourceBasePath
(from@WebAppConfiguration
)
In your test setup there are at least 2 different permutations of configuration. Due to differences in the classes
one with 2 (TestConfig
and SQLContainerConfiguration
and one with 3 classes (TestConfig,
SQLContainerConfigurationand
TestWebConfig`). This will result in at least 2 different instances.
TIP: You don't need @ExtendWith
nor @EnableAutoConfiguration
that is only overhead.