简体   繁体   English

使用 TestContainers 和 HikariPool-1 的 Spring 启动 - 连接不可用,请求在 30000 毫秒后超时

[英]Spring boot with TestContainers and HikariPool-1 - Connection is not available, request timed out after 30000ms

ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(initializers = AbstractIT.DockerPostgreDataSourceInitializer.class)
@Testcontainers
public abstract class AbstractIT {
    

    @SuppressWarnings("resource")
    @Container
    static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:14")
            .withUsername("postgres")
            .withPassword("postgres")
            .withInitScript("sql/init.sql")
            .withDatabaseName("test")
            .withReuse(true);
    
    static {
        postgreDBContainer.start();
    }
    
    public static class DockerPostgreDataSourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        
        @Override
        public void initialize(ConfigurableApplicationContext applicationContext) {
            
            TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
                    applicationContext,
                    "spring.datasource.url=" + postgreDBContainer.getJdbcUrl(),
                    "spring.datasource.username=" + postgreDBContainer.getUsername(),
                    "spring.datasource.password=" + postgreDBContainer.getPassword()
            );
        }
    }
}

SqlExceptionHelper : HikariPool-1 - Connection is not available, request timed out after 30000ms. SqlExceptionHelper : HikariPool-1 - 连接不可用,请求在 30000 毫秒后超时。 ohengine.jdbc.spi.SqlExceptionHelper : Connection to localhost:49168 refused. ohengine.jdbc.spi.SqlExceptionHelper:连接到 localhost:49168 被拒绝。 Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.检查主机名和端口是否正确以及 postmaster 是否接受 TCP/IP 连接。

I created one instance of Textcontainers, I have a lot of integration tests, but only one test class is working, the rest cannot.我创建了一个 Textcontainers 实例,我有很多集成测试,但只有一个测试类在工作,其余的则不能。 because the connection is being closed.因为连接正在关闭。

Installing @DirtiesContext and changing the open connection interval does not solve the problem.安装@DirtiesContext 并更改打开连接间隔并不能解决问题。

Decision.决定。

delete an annotation @Container.删除注解@Container。


 static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<> ......

However, this solution will not allow you to work with the database.但是,此解决方案不允许您使用数据库。 Because when one test class will work.因为当一个测试类将起作用时。 Then there will be an error that the table.... exists.那么就会报错说table....存在。 That is, the test container will try to initiate the table creation script again.也就是说,测试容器将尝试再次启动表创建脚本。 How can I make it so that I can reuse the test container (not create a new one) and at the same time, I can use one database initialization script for all test nodes?我怎样才能做到这一点,以便我可以重用测试容器(而不是创建一个新容器),同时我可以为所有测试节点使用一个数据库初始化脚本?

application-test.yaml应用程序-test.yaml

spring:
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: none
    open-in-view: false
    properties:
      hibernate:
        default-schema: public
        jdbc:
          lob.non_contextual_creation: true # Fix Postgres JPA Error (Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented).
          time_zone: UTC
          # to avoid name conflict of custom table objects
          # with object names in PostgresSQL
      auto_quote_keyword: true

  test:
    database:
      replace: none
  • baseClass基类
@ActiveProfiles("test")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@ContextConfiguration(initializers =
        SpringDataTestcontainerTests
                .DockerPostgresDataInitializer.class)
public abstract class SpringDataTestcontainerTests {

    static PostgreSQLContainer<?> postgreSQLContainer;

    static {
        postgreSQLContainer = new PostgreSQLContainer<>("postgres:14")
              .withUsername("postgres")
               .withPassword("postgres")
                .withInitScript("sql/init.sql")
               .withDatabaseName("test")
                .withReuse(true);


        postgreSQLContainer.start();
    }

    public static class DockerPostgresDataInitializer
            implements ApplicationContextInitializer<ConfigurableApplicationContext> {

        String jdbcUrl = "spring.datasource.url=" + postgreSQLContainer.getJdbcUrl();
        String username = "spring.datasource.username=" + postgreSQLContainer.getUsername();
        String password = "spring.datasource.password=" + postgreSQLContainer.getPassword();

        @Override
        public void initialize(@NotNull ConfigurableApplicationContext applicationContext) {

            TestPropertySourceUtils
                    .addInlinedPropertiesToEnvironment(applicationContext, jdbcUrl, username, password);
        }
    }

    @Autowired
    protected OrderCreateService orderCreateService;

    @Autowired
    protected OrderReadService orderReadService;

    @Autowired
    protected OrderRepository orderRepository;


    @Test
    void contextLoads() throws SQLException {

        ResultSet resultSet = performQuery(postgreSQLContainer);
        resultSet.next();
        int result = resultSet.getInt(1);
        assertEquals(1, result);

        Assertions.assertThat(postgreSQLContainer.isRunning()).isTrue();
    }

    private ResultSet performQuery(@SuppressWarnings("rawtypes") PostgreSQLContainer postgreSQLContainer)
            throws SQLException {

        String query = "SELECT 1";

        String jdbcUrl = postgreSQLContainer.getJdbcUrl();
        String username = postgreSQLContainer.getUsername();
        String password = postgreSQLContainer.getPassword();

        Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
        return conn.createStatement().executeQuery(query);
    }

}

Each test node starts with :每个测试节点都以:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ServiceTest extends SpringDataTestcontainerTests {
}

When using the @Testcontainers and @Container annotation, JUnit-Jupiter will handle the container lifecycle, no need to call start() then.当使用@Testcontainers@Container注解时,JUnit-Jupiter 将处理容器的生命周期,此时无需调用start() The datasource configuration should be injected into the Spring context using the DynamicPropertySource mechanism.数据源配置应该使用 DynamicPropertySource 机制注入到 Spring 上下文中。

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
public abstract class AbstractIT {
    

    @SuppressWarnings("resource")
    @Container
    static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:14")
            .withUsername("postgres")
            .withPassword("postgres")
            .withInitScript("sql/init.sql")
            .withDatabaseName("test")
            .withReuse(true);
    
     @DynamicPropertySource
     static void setupProperties(DynamicPropertyRegistry registry) {
         registry.add("spring.datasource.url", postgreSQLContainer ::getJdbcUrl);
         registry.add("spring.datasource.username", postgreSQLContainer ::getUsername);
         registry.add("spring.datasource.password", postgreSQLContainer ::getPassword);
     }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM