Skip to content

Commit

Permalink
Support Testcontainer JDBC URLs with Replace.NON_TEST
Browse files Browse the repository at this point in the history
Update `TestDatabaseAutoConfiguration` so that Testcontainer JDBC URLs
are also detected when using `Replace.NON_TEST`.

Closes gh-35253
  • Loading branch information
philwebb committed Sep 12, 2024
1 parent af34690 commit 3723a9e
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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.test.autoconfigure.jdbc;

import javax.sql.DataSource;

import com.zaxxer.hikari.HikariDataSource;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Testcontainers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabaseTestcontainersJdbcUrlIntegrationTests.InitializeDatasourceUrl;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.support.TestPropertySourceUtils;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Integration test for {@link AutoConfigureTestDatabase} with Testcontainers and a
* {@link ServiceConnection @ServiceConnection}.
*
* @author Phillip Webb
*/
@SpringBootTest
@ContextConfiguration(initializers = InitializeDatasourceUrl.class)
@AutoConfigureTestDatabase(replace = Replace.NON_TEST)
@Testcontainers(disabledWithoutDocker = true)
@OverrideAutoConfiguration(enabled = false)
class AutoConfigureTestDatabaseTestcontainersJdbcUrlIntegrationTests {

@Autowired
private DataSource dataSource;

@Test
void dataSourceIsNotReplaced() {
assertThat(this.dataSource).isInstanceOf(HikariDataSource.class).isNotInstanceOf(EmbeddedDatabase.class);
}

@Configuration
@ImportAutoConfiguration(DataSourceAutoConfiguration.class)
static class Config {

}

static class InitializeDatasourceUrl implements ApplicationContextInitializer<ConfigurableApplicationContext> {

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(applicationContext,
"spring.datasource.url=jdbc:tc:postgis:" + TestImage.POSTGRESQL.getTag() + ":///");
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ enum Replace {
* created using Docker Compose)</li>
* <li>Any connection configured using a {@code spring.datasource.url} backed by a
* {@link DynamicPropertySource @DynamicPropertySource}</li>
* <li>Any connection configured using a {@code spring.datasource.url} with the
* Testcontainers JDBC syntax</li>
* </ul>
* @since 3.4.0
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ static class EmbeddedDataSourceBeanFactoryPostProcessor implements BeanDefinitio
private static final ConfigurationPropertyName DATASOURCE_URL_PROPERTY = ConfigurationPropertyName
.of("spring.datasource.url");

private static final Bindable<String> BINDABLE_STRING = Bindable.of(String.class);

private static final String DYNAMIC_VALUES_PROPERTY_SOURCE_CLASS = "org.springframework.test.context.support.DynamicValuesPropertySource";

private static final Log logger = LogFactory.getLog(EmbeddedDataSourceBeanFactoryPostProcessor.class);
Expand Down Expand Up @@ -190,7 +192,7 @@ private boolean isAutoConfigured(BeanDefinitionHolder holder) {
}

private boolean isConnectingToTestDatabase(ConfigurableListableBeanFactory beanFactory) {
return isUsingTestServiceConnection(beanFactory) || isUsingDynamicPropertySournce();
return isUsingTestServiceConnection(beanFactory) || isUsingTestDatasourceUrl();
}

private boolean isUsingTestServiceConnection(ConfigurableListableBeanFactory beanFactory) {
Expand All @@ -208,11 +210,16 @@ private boolean isUsingTestServiceConnection(ConfigurableListableBeanFactory bea
return false;
}

private boolean isUsingDynamicPropertySournce() {
private boolean isUsingTestDatasourceUrl() {
List<ConfigurationProperty> bound = new ArrayList<>();
Binder.get(this.environment, new BoundPropertiesTrackingBindHandler(bound::add))
.bind(DATASOURCE_URL_PROPERTY, Bindable.of(String.class));
return (!bound.isEmpty()) ? isBoundToDynamicValuesPropertySource(bound.get(0)) : false;
.bind(DATASOURCE_URL_PROPERTY, BINDABLE_STRING);
return (!bound.isEmpty()) ? isUsingTestDatasourceUrl(bound.get(0)) : false;
}

private boolean isUsingTestDatasourceUrl(ConfigurationProperty configurationProperty) {
return isBoundToDynamicValuesPropertySource(configurationProperty)
|| isTestcontainersUrl(configurationProperty);
}

private boolean isBoundToDynamicValuesPropertySource(ConfigurationProperty configurationProperty) {
Expand All @@ -227,6 +234,11 @@ private boolean isDynamicValuesPropertySource(PropertySource<?> propertySource)
&& DYNAMIC_VALUES_PROPERTY_SOURCE_CLASS.equals(propertySource.getClass().getName());
}

private boolean isTestcontainersUrl(ConfigurationProperty configurationProperty) {
Object value = configurationProperty.getValue();
return (value != null) && value.toString().startsWith("jdbc:tc:");
}

}

static class EmbeddedDataSourceFactoryBean implements FactoryBean<DataSource>, EnvironmentAware, InitializingBean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,10 @@ private <C extends Container<?>> C createContainer(Class<C> containerClass) {
}
}

public String getTag() {
return this.tag;
}

@Override
public String toString() {
return (this.tag != null) ? this.name + ":" + this.tag : this.name;
Expand Down

0 comments on commit 3723a9e

Please sign in to comment.