Ensure containers are started before binding datasource properties
Update `TestcontainersLifecycleBeanPostProcessor` so that containers are now initialized either on the first `postProcessAfterInitialization` call with a frozen configuration or just before a test container property is supplied. Prior to this commit, it was assumed that the first post-process call after the configuration was frozen was suitably early to initialize the containers. This turns out to not be no always the case. Specifically, in the `finishBeanFactoryInitialization` method of `AbstractApplicationContext` we see that `LoadTimeWeaverAware` beans are obtained before the configuration is frozen. One such bean is `DefaultPersistenceUnitManager` which is likely to need datasource properties that will require a started container. To fix the problem, the `TestcontainersPropertySource` now publishes a `BeforeTestcontainersPropertySuppliedEvent` to the ApplicationContext just before any value is supplied. By listening for this event, we can ensure that containers are initialized and started before any dynamic property is read. Fixes gh-38913
This commit is contained in:
parent
f59fa2e3f7
commit
89874d351a
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -20,6 +20,7 @@ import java.lang.reflect.Method;
|
|||
import java.lang.reflect.Modifier;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.boot.testcontainers.properties.TestcontainersPropertySource;
|
||||
import org.springframework.core.MethodIntrospector;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
|
@ -43,16 +44,17 @@ class DynamicPropertySourceMethodsImporter {
|
|||
this.environment = environment;
|
||||
}
|
||||
|
||||
void registerDynamicPropertySources(Class<?> definitionClass) {
|
||||
void registerDynamicPropertySources(BeanDefinitionRegistry beanDefinitionRegistry, Class<?> definitionClass) {
|
||||
Set<Method> methods = MethodIntrospector.selectMethods(definitionClass, this::isAnnotated);
|
||||
if (methods.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
DynamicPropertyRegistry registry = TestcontainersPropertySource.attach(this.environment);
|
||||
DynamicPropertyRegistry dynamicPropertyRegistry = TestcontainersPropertySource.attach(this.environment,
|
||||
beanDefinitionRegistry);
|
||||
methods.forEach((method) -> {
|
||||
assertValid(method);
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
ReflectionUtils.invokeMethod(method, null, registry);
|
||||
ReflectionUtils.invokeMethod(method, null, dynamicPropertyRegistry);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -62,7 +62,7 @@ class ImportTestcontainersRegistrar implements ImportBeanDefinitionRegistrar {
|
|||
for (Class<?> definitionClass : definitionClasses) {
|
||||
this.containerFieldsImporter.registerBeanDefinitions(registry, definitionClass);
|
||||
if (this.dynamicPropertySourceMethodsImporter != null) {
|
||||
this.dynamicPropertySourceMethodsImporter.registerDynamicPropertySources(definitionClass);
|
||||
this.dynamicPropertySourceMethodsImporter.registerDynamicPropertySources(registry, definitionClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -48,7 +48,10 @@ public class TestcontainersLifecycleApplicationContextInitializer
|
|||
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
|
||||
applicationContext.addBeanFactoryPostProcessor(new TestcontainersLifecycleBeanFactoryPostProcessor());
|
||||
TestcontainersStartup startup = TestcontainersStartup.get(applicationContext.getEnvironment());
|
||||
beanFactory.addBeanPostProcessor(new TestcontainersLifecycleBeanPostProcessor(beanFactory, startup));
|
||||
TestcontainersLifecycleBeanPostProcessor beanPostProcessor = new TestcontainersLifecycleBeanPostProcessor(
|
||||
beanFactory, startup);
|
||||
beanFactory.addBeanPostProcessor(beanPostProcessor);
|
||||
applicationContext.addApplicationListener(beanPostProcessor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -38,6 +38,8 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
|||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
|
||||
import org.springframework.boot.testcontainers.properties.BeforeTestcontainersPropertySuppliedEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
|
@ -56,7 +58,8 @@ import org.springframework.core.log.LogMessage;
|
|||
* @see TestcontainersLifecycleApplicationContextInitializer
|
||||
*/
|
||||
@Order(Ordered.LOWEST_PRECEDENCE)
|
||||
class TestcontainersLifecycleBeanPostProcessor implements DestructionAwareBeanPostProcessor {
|
||||
class TestcontainersLifecycleBeanPostProcessor
|
||||
implements DestructionAwareBeanPostProcessor, ApplicationListener<BeforeTestcontainersPropertySuppliedEvent> {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(TestcontainersLifecycleBeanPostProcessor.class);
|
||||
|
||||
|
@ -74,9 +77,14 @@ class TestcontainersLifecycleBeanPostProcessor implements DestructionAwareBeanPo
|
|||
this.startup = startup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(BeforeTestcontainersPropertySuppliedEvent event) {
|
||||
initializeContainers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (this.beanFactory.isConfigurationFrozen() && this.containersInitialized.compareAndSet(false, true)) {
|
||||
if (this.beanFactory.isConfigurationFrozen()) {
|
||||
initializeContainers();
|
||||
}
|
||||
if (bean instanceof Startable startableBean) {
|
||||
|
@ -121,15 +129,17 @@ class TestcontainersLifecycleBeanPostProcessor implements DestructionAwareBeanPo
|
|||
}
|
||||
|
||||
private void initializeContainers() {
|
||||
logger.trace("Initializing containers");
|
||||
List<String> beanNames = List.of(this.beanFactory.getBeanNamesForType(ContainerState.class, false, false));
|
||||
List<Object> beans = getBeans(beanNames);
|
||||
if (beans != null) {
|
||||
logger.trace(LogMessage.format("Initialized containers %s", beanNames));
|
||||
}
|
||||
else {
|
||||
logger.trace(LogMessage.format("Failed to initialize containers %s", beanNames));
|
||||
this.containersInitialized.set(false);
|
||||
if (this.containersInitialized.compareAndSet(false, true)) {
|
||||
logger.trace("Initializing containers");
|
||||
List<String> beanNames = List.of(this.beanFactory.getBeanNamesForType(ContainerState.class, false, false));
|
||||
List<Object> beans = getBeans(beanNames);
|
||||
if (beans != null) {
|
||||
logger.trace(LogMessage.format("Initialized containers %s", beanNames));
|
||||
}
|
||||
else {
|
||||
logger.trace(LogMessage.format("Failed to initialize containers %s", beanNames));
|
||||
this.containersInitialized.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testcontainers.properties;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* Event published just before the {@link Supplier value supplier} of a
|
||||
* {@link TestcontainersPropertySource} property is called.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public class BeforeTestcontainersPropertySuppliedEvent extends ApplicationEvent {
|
||||
|
||||
private final String propertyName;
|
||||
|
||||
BeforeTestcontainersPropertySuppliedEvent(TestcontainersPropertySource source, String propertyName) {
|
||||
super(source);
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the property about to be supplied.
|
||||
* @return the propertyName the property name
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return this.propertyName;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -19,10 +19,20 @@ package org.springframework.boot.testcontainers.properties;
|
|||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.testcontainers.containers.Container;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
@ -44,6 +54,8 @@ public class TestcontainersPropertySource extends EnumerablePropertySource<Map<S
|
|||
|
||||
private final DynamicPropertyRegistry registry;
|
||||
|
||||
private final Set<ApplicationEventPublisher> eventPublishers = new CopyOnWriteArraySet<>();
|
||||
|
||||
TestcontainersPropertySource() {
|
||||
this(Collections.synchronizedMap(new LinkedHashMap<>()));
|
||||
}
|
||||
|
@ -57,10 +69,20 @@ public class TestcontainersPropertySource extends EnumerablePropertySource<Map<S
|
|||
};
|
||||
}
|
||||
|
||||
private void addEventPublisher(ApplicationEventPublisher eventPublisher) {
|
||||
this.eventPublishers.add(eventPublisher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
Supplier<Object> valueSupplier = this.source.get(name);
|
||||
return (valueSupplier != null) ? valueSupplier.get() : null;
|
||||
return (valueSupplier != null) ? getProperty(name, valueSupplier) : null;
|
||||
}
|
||||
|
||||
private Object getProperty(String name, Supplier<Object> valueSupplier) {
|
||||
BeforeTestcontainersPropertySuppliedEvent event = new BeforeTestcontainersPropertySuppliedEvent(this, name);
|
||||
this.eventPublishers.forEach((eventPublisher) -> eventPublisher.publishEvent(event));
|
||||
return valueSupplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,20 +96,73 @@ public class TestcontainersPropertySource extends EnumerablePropertySource<Map<S
|
|||
}
|
||||
|
||||
public static DynamicPropertyRegistry attach(Environment environment) {
|
||||
Assert.state(environment instanceof ConfigurableEnvironment,
|
||||
"TestcontainersPropertySource can only be attached to a ConfigurableEnvironment");
|
||||
return attach((ConfigurableEnvironment) environment);
|
||||
return attach(environment, null);
|
||||
}
|
||||
|
||||
private static DynamicPropertyRegistry attach(ConfigurableEnvironment environment) {
|
||||
static DynamicPropertyRegistry attach(ConfigurableApplicationContext applicationContext) {
|
||||
return attach(applicationContext.getEnvironment(), applicationContext, null);
|
||||
}
|
||||
|
||||
public static DynamicPropertyRegistry attach(Environment environment, BeanDefinitionRegistry registry) {
|
||||
return attach(environment, null, registry);
|
||||
}
|
||||
|
||||
private static DynamicPropertyRegistry attach(Environment environment, ApplicationEventPublisher eventPublisher,
|
||||
BeanDefinitionRegistry registry) {
|
||||
Assert.state(environment instanceof ConfigurableEnvironment,
|
||||
"TestcontainersPropertySource can only be attached to a ConfigurableEnvironment");
|
||||
TestcontainersPropertySource propertySource = getOrAdd((ConfigurableEnvironment) environment);
|
||||
if (eventPublisher != null) {
|
||||
propertySource.addEventPublisher(eventPublisher);
|
||||
}
|
||||
else if (registry != null) {
|
||||
registry.registerBeanDefinition(EventPublisherRegistrar.NAME, new RootBeanDefinition(
|
||||
EventPublisherRegistrar.class, () -> new EventPublisherRegistrar(environment)));
|
||||
}
|
||||
return propertySource.registry;
|
||||
}
|
||||
|
||||
static TestcontainersPropertySource getOrAdd(ConfigurableEnvironment environment) {
|
||||
PropertySource<?> propertySource = environment.getPropertySources().get(NAME);
|
||||
if (propertySource == null) {
|
||||
environment.getPropertySources().addFirst(new TestcontainersPropertySource());
|
||||
return attach(environment);
|
||||
return getOrAdd(environment);
|
||||
}
|
||||
Assert.state(propertySource instanceof TestcontainersPropertySource,
|
||||
"Incorrect DynamicValuesPropertySource type registered");
|
||||
return ((TestcontainersPropertySource) propertySource).registry;
|
||||
return ((TestcontainersPropertySource) propertySource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link BeanFactoryPostProcessor} to register the {@link ApplicationEventPublisher}
|
||||
* to the {@link TestcontainersPropertySource}. This class is a
|
||||
* {@link BeanFactoryPostProcessor} so that it is initialized as early as possible.
|
||||
*/
|
||||
private static class EventPublisherRegistrar implements BeanFactoryPostProcessor, ApplicationEventPublisherAware {
|
||||
|
||||
static final String NAME = EventPublisherRegistrar.class.getName();
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
EventPublisherRegistrar(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
|
||||
this.eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
if (this.eventPublisher != null) {
|
||||
TestcontainersPropertySource.getOrAdd((ConfigurableEnvironment) this.environment)
|
||||
.addEventPublisher(this.eventPublisher);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,9 +16,12 @@
|
|||
|
||||
package org.springframework.boot.testcontainers.properties;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
|
||||
/**
|
||||
|
@ -28,6 +31,8 @@ import org.springframework.test.context.DynamicPropertyRegistry;
|
|||
* @author Phillip Webb
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
@ConditionalOnClass(DynamicPropertyRegistry.class)
|
||||
public class TestcontainersPropertySourceAutoConfiguration {
|
||||
|
||||
|
@ -35,8 +40,8 @@ public class TestcontainersPropertySourceAutoConfiguration {
|
|||
}
|
||||
|
||||
@Bean
|
||||
DynamicPropertyRegistry dynamicPropertyRegistry(ConfigurableEnvironment environment) {
|
||||
return TestcontainersPropertySource.attach(environment);
|
||||
static DynamicPropertyRegistry dynamicPropertyRegistry(ConfigurableApplicationContext applicationContext) {
|
||||
return TestcontainersPropertySource.attach(applicationContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.testcontainers.lifecycle;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.testcontainers.context.ImportTestcontainers;
|
||||
import org.springframework.boot.testcontainers.lifecycle.TestcontainersImportWithPropertiesInjectedIntoLoadTimeWeaverAwareBeanIntegrationTests.Containers;
|
||||
import org.springframework.boot.testsupport.testcontainers.DisabledIfDockerUnavailable;
|
||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.weaving.LoadTimeWeaverAware;
|
||||
import org.springframework.instrument.classloading.LoadTimeWeaver;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
/**
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@DirtiesContext
|
||||
@DisabledIfDockerUnavailable
|
||||
@ImportTestcontainers(Containers.class)
|
||||
class TestcontainersImportWithPropertiesInjectedIntoLoadTimeWeaverAwareBeanIntegrationTests {
|
||||
|
||||
// gh-38913
|
||||
|
||||
@Test
|
||||
void starts() {
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
@EnableConfigurationProperties(MockDataSourceProperties.class)
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
MockEntityManager mockEntityManager(MockDataSourceProperties properties) {
|
||||
return new MockEntityManager();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MockEntityManager implements LoadTimeWeaverAware {
|
||||
|
||||
@Override
|
||||
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConfigurationProperties("spring.datasource")
|
||||
public static class MockDataSourceProperties {
|
||||
|
||||
private String url;
|
||||
|
||||
public String getUrl() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Containers {
|
||||
|
||||
@Container
|
||||
static PostgreSQLContainer<?> container = new PostgreSQLContainer<>(DockerImageNames.postgresql());
|
||||
|
||||
@DynamicPropertySource
|
||||
static void setConnectionProperties(DynamicPropertyRegistry registry) {
|
||||
registry.add("spring.datasource.url", container::getJdbcUrl);
|
||||
registry.add("spring.datasource.password", container::getPassword);
|
||||
registry.add("spring.datasource.username", container::getUsername);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,6 +16,9 @@
|
|||
|
||||
package org.springframework.boot.testcontainers.properties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
|
@ -25,6 +28,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|||
import org.springframework.boot.testcontainers.lifecycle.TestcontainersLifecycleApplicationContextInitializer;
|
||||
import org.springframework.boot.testsupport.testcontainers.DisabledIfDockerUnavailable;
|
||||
import org.springframework.boot.testsupport.testcontainers.RedisContainer;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
@ -46,11 +50,16 @@ class TestcontainersPropertySourceAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
void containerBeanMethodContributesProperties() {
|
||||
this.contextRunner.withUserConfiguration(ContainerAndPropertiesConfiguration.class).run((context) -> {
|
||||
TestBean testBean = context.getBean(TestBean.class);
|
||||
RedisContainer redisContainer = context.getBean(RedisContainer.class);
|
||||
assertThat(testBean.getUsingPort()).isEqualTo(redisContainer.getFirstMappedPort());
|
||||
});
|
||||
List<ApplicationEvent> events = new ArrayList<>();
|
||||
this.contextRunner.withUserConfiguration(ContainerAndPropertiesConfiguration.class)
|
||||
.withInitializer((context) -> context.addApplicationListener(events::add))
|
||||
.run((context) -> {
|
||||
TestBean testBean = context.getBean(TestBean.class);
|
||||
RedisContainer redisContainer = context.getBean(RedisContainer.class);
|
||||
assertThat(testBean.getUsingPort()).isEqualTo(redisContainer.getFirstMappedPort());
|
||||
assertThat(events.stream().filter(BeforeTestcontainersPropertySuppliedEvent.class::isInstance))
|
||||
.hasSize(1);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,10 +16,15 @@
|
|||
|
||||
package org.springframework.boot.testcontainers.properties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
@ -101,4 +106,20 @@ class TestcontainersPropertySourceTests {
|
|||
assertThat(p1).isSameAs(p2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPropertyPublishesEvent() {
|
||||
try (GenericApplicationContext applicationContext = new GenericApplicationContext()) {
|
||||
List<ApplicationEvent> events = new ArrayList<>();
|
||||
applicationContext.addApplicationListener(events::add);
|
||||
DynamicPropertyRegistry registry = TestcontainersPropertySource.attach(applicationContext.getEnvironment(),
|
||||
(BeanDefinitionRegistry) applicationContext.getBeanFactory());
|
||||
applicationContext.refresh();
|
||||
registry.add("test", () -> "spring");
|
||||
assertThat(applicationContext.getEnvironment().containsProperty("test")).isTrue();
|
||||
assertThat(events.isEmpty());
|
||||
assertThat(applicationContext.getEnvironment().getProperty("test")).isEqualTo("spring");
|
||||
assertThat(events.stream().filter(BeforeTestcontainersPropertySuppliedEvent.class::isInstance)).hasSize(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue