Как запустить testcontainer с динамическим портом для весенних данных elasticsearch

В моем тестовом примере используются аннотации @SpringBootTest для отображения контекста, а также есть Autowired в некотором репозитории. Testcontainer запускается в методе @BeforeAll(). Проблема в том, что RestClientConfig инициализируется/вводится до @BeforeAll() в тестовом примере. Когда testcontainer запускается, он экспортирует какой-то динамический порт.

Мне нужно установить фиксированный порт в тестовом контейнере 34343 и использовать тот же порт в файле свойств для RestClientConfig.

container = new ElasticsearchContainer(ELASTICSEARCH_IMAGE)
        .withEnv("discovery.type", "single-node")
        .withExposedPorts(9200)     
        .withCreateContainerCmdModifier(cmd -> cmd.withHostConfig(
                    new HostConfig().withPortBindings(new PortBinding(Ports.Binding.bindPort(34343), new ExposedPort(9200)))));

Есть ли способ запустить контейнер и получить его динамический порт, а затем использовать его для инициализации RestClientConfig?

Однако я не использовал аннотацию @Testcontainers. Это необходимо?

3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
1
0
49
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий
  1. Вы можете использовать инициализатор конфигурации контекста для установки свойств во время выполнения, которые вы можете позже использовать в своем RestClientConfig.

Покажу на примере настройки контейнера Postgresql:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class)
@ContextConfiguration(initializers = AbstractTestcontainersTest.DockerPostgreDataSourceInitializer.class)
public abstract class AbstractTestcontainersTest {

    protected static final String DB_CONTAINER_NAME = "postgres-auth-test";
    protected static PostgreSQLContainer<?> postgreDBContainer =
            new PostgreSQLContainer<>(DockerImageName.parse("public.ecr.aws/docker/library/postgres:12.10-alpine")
                    .asCompatibleSubstituteFor("postgres"))
            .withUsername("postgres")
            .withPassword("change_me")
            .withInitScript("db.sql")
            .withCreateContainerCmdModifier(cmd -> cmd.withName(DB_CONTAINER_NAME))
            .withDatabaseName("zpot_main");

    @BeforeAll
    public static void beforeAll() throws ShellExecutionException {
        postgreDBContainer.start();
    }

    @AfterAll
    public static void afterAll() {
        postgreDBContainer.stop();
    }

    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()
            );
        }
    }
}

Вся настройка производится в DockerPostgreDataSourceInitializer, где я задаю все нужные мне свойства. Вам также необходимо аннотировать свой тестовый класс аннотацией @ContextConfiguration. Вы можете сделать что-то подобное с вашим ElasticSearchContainer. Как я только что проверил, у ElasticSearchContainer есть метод getHttpHostAddress(), который возвращает комбинацию host+dynamic_port для вашего контейнера. Вы можете получить эту пару хост-порт и установить в свойствах, которые будут использоваться позже в конфигурации вашего клиента. Если вам нужен только порт, вы можете вызвать container.getMappedPort(9200) и снова указать этот порт в свойствах.

  1. Что касается аннотации @Testcontainers, она вам понадобится, если вы хотите, чтобы testcontainers управляли жизненным циклом вашего контейнера. В этом случае вам также необходимо аннотировать контейнер аннотацией @Container. Ваш контейнер будет запущен либо один раз перед всеми методами тестирования в классе, если ваш контейнер является статическим полем, либо перед каждым методом тестирования, если это обычное поле. Подробнее об этом можно прочитать здесь: https://www.testcontainers.org/test_framework_integration/junit_5/#extension. Или вы можете запустить свой контейнер вручную с помощью аннотированных методов установки @BeforeAll или @BeforeEach. Другими словами, нет, вам не нужно использовать аннотацию @Testcontainers.

Более новые версии Spring предоставляют @DynamicPropertySource именно для этого варианта использования: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/DynamicPropertySource.html

Ваш код должен выглядеть примерно так:

 @SpringJUnitConfig(...)
 @Testcontainers
 class ExampleIntegrationTests {

     @Container
     static ElasticsearchContainer elastic= new ElasticsearchContainer(ELASTICSEARCH_IMAGE)
        .withEnv("discovery.type", "single-node");

     // ...

     @DynamicPropertySource
     static void elasticProperties(DynamicPropertyRegistry registry) {
         registry.add("spring.elasticsearch.rest.uris", elastic::getHttpHostAddress);
     }

 }

Другие вопросы по теме