Polishing.

Refactor Testcontainers config infrastructure.

See #2381
This commit is contained in:
Mark Paluch
2024-10-21 14:58:43 +02:00
parent b4b41eb1bf
commit a7bbd125f3
4 changed files with 118 additions and 182 deletions

View File

@@ -19,20 +19,17 @@ package org.springframework.data.jpa.repository.procedures;
import static org.assertj.core.api.Assertions.*;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.NamedStoredProcedureQuery;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.dialect.MySQLDialect;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan.Filter;
@@ -41,20 +38,12 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import org.testcontainers.containers.MySQLContainer;
import com.mysql.cj.jdbc.MysqlDataSource;
import org.testcontainers.containers.MySQLContainer;
/**
* Testcase to verify {@link org.springframework.jdbc.object.StoredProcedure}s work with MySQL.
@@ -234,7 +223,11 @@ class MySqlStoredProcedureIntegrationTests {
basePackageClasses = Config.class, //
includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = EmployeeRepositoryWithNoCursor.class))
@EnableTransactionManagement
static class Config {
static class Config extends StoredProcedureConfigSupport {
public Config() {
super(MySQLDialect.class, new ClassPathResource("scripts/mysql-stored-procedures.sql"));
}
@SuppressWarnings("resource")
@Bean(initMethod = "start", destroyMethod = "stop")
@@ -245,51 +238,5 @@ class MySqlStoredProcedureIntegrationTests {
.withPassword("test") //
.withConfigurationOverride("");
}
@Bean
public DataSource dataSource(MySQLContainer<?> container) {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setUrl(container.getJdbcUrl());
dataSource.setUser(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@Bean
public AbstractEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setPersistenceUnitRootLocation("simple-persistence");
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factoryBean.setPackagesToScan(this.getClass().getPackage().getName());
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty("hibernate.dialect", MySQLDialect.class.getCanonicalName());
factoryBean.setJpaProperties(properties);
return factoryBean;
}
@Bean
PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
@Bean
DataSourceInitializer initializer(DataSource dataSource) {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
ClassPathResource script = new ClassPathResource("scripts/mysql-stored-procedures.sql");
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(script);
populator.setSeparator(";;");
initializer.setDatabasePopulator(populator);
return initializer;
}
}
}

View File

@@ -19,7 +19,6 @@ package org.springframework.data.jpa.repository.procedures;
import static org.assertj.core.api.Assertions.*;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.NamedStoredProcedureQuery;
@@ -30,14 +29,10 @@ import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import javax.sql.DataSource;
import org.hibernate.dialect.PostgreSQLDialect;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.postgresql.ds.PGSimpleDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@@ -48,15 +43,8 @@ import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.jpa.util.DisabledOnHibernate62;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
@@ -265,7 +253,11 @@ class PostgresStoredProcedureIntegrationTests {
@EnableJpaRepositories(considerNestedRepositories = true,
includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = EmployeeRepositoryWithRefCursor.class))
@EnableTransactionManagement
static class Config {
static class Config extends StoredProcedureConfigSupport {
public Config() {
super(PostgreSQLDialect.class, new ClassPathResource("scripts/postgres-stored-procedures.sql"));
}
@SuppressWarnings("resource")
@Bean(initMethod = "start", destroyMethod = "stop")
@@ -274,51 +266,5 @@ class PostgresStoredProcedureIntegrationTests {
return new PostgreSQLContainer<>("postgres:15.3") //
.withUsername("postgres");
}
@Bean
public DataSource dataSource(PostgreSQLContainer<?> container) {
PGSimpleDataSource dataSource = new PGSimpleDataSource();
dataSource.setUrl(container.getJdbcUrl());
dataSource.setUser(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@Bean
public AbstractEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setPersistenceUnitRootLocation("simple-persistence");
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factoryBean.setPackagesToScan(this.getClass().getPackage().getName());
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty("hibernate.dialect", PostgreSQLDialect.class.getCanonicalName());
factoryBean.setJpaProperties(properties);
return factoryBean;
}
@Bean
PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
@Bean
DataSourceInitializer initializer(DataSource dataSource) {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
ClassPathResource script = new ClassPathResource("scripts/postgres-stored-procedures.sql");
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(script);
populator.setSeparator(";;");
initializer.setDatabasePopulator(populator);
return initializer;
}
}
}

View File

@@ -16,21 +16,17 @@
package org.springframework.data.jpa.repository.procedures;
import jakarta.persistence.Entity;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import java.util.Date;
import java.util.Properties;
import java.util.UUID;
import javax.sql.DataSource;
import org.hibernate.dialect.PostgreSQLDialect;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.postgresql.ds.PGSimpleDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
@@ -41,17 +37,11 @@ import org.springframework.data.jpa.repository.Temporal;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.jpa.repository.query.Procedure;
import org.springframework.data.jpa.util.DisabledOnHibernate61;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import org.testcontainers.containers.PostgreSQLContainer;
/**
@@ -138,63 +128,18 @@ class PostgresStoredProcedureNullHandlingIntegrationTests {
@EnableJpaRepositories(considerNestedRepositories = true,
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = TestModelRepository.class))
@EnableTransactionManagement
static class Config {
static class Config extends StoredProcedureConfigSupport {
public Config() {
super(PostgreSQLDialect.class, new ClassPathResource("scripts/postgres-nullable-stored-procedures.sql"));
}
@SuppressWarnings("resource")
@Bean(initMethod = "start", destroyMethod = "stop")
public PostgreSQLContainer<?> container() {
return new PostgreSQLContainer<>("postgres:15.3") //
.withUsername("postgres");
}
@Bean
public DataSource dataSource(PostgreSQLContainer<?> container) {
PGSimpleDataSource dataSource = new PGSimpleDataSource();
dataSource.setUrl(container.getJdbcUrl());
dataSource.setUser(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@Bean
public AbstractEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setPersistenceUnitRootLocation("simple-persistence");
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factoryBean.setPackagesToScan(this.getClass().getPackage().getName());
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty("hibernate.dialect", PostgreSQLDialect.class.getCanonicalName());
properties.setProperty("hibernate.proc.param_null_passing", "true");
properties.setProperty("hibernate.globally_quoted_identifiers", "true");
properties.setProperty("hibernate.globally_quoted_identifiers_skip_column_definitions", "true");
factoryBean.setJpaProperties(properties);
return factoryBean;
}
@Bean
PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
@Bean
DataSourceInitializer initializer(DataSource dataSource) {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
ClassPathResource script = new ClassPathResource("scripts/postgres-nullable-stored-procedures.sql");
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(script);
populator.setSeparator(";;");
initializer.setDatabasePopulator(populator);
return initializer;
}
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 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.data.jpa.repository.procedures;
import jakarta.persistence.EntityManagerFactory;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.testcontainers.containers.JdbcDatabaseContainer;
/**
* Support class for integration testing with Testcontainers
*
* @author Mark Paluch
*/
class StoredProcedureConfigSupport {
private final Class<?> dialect;
private final Resource initScript;
StoredProcedureConfigSupport(Class<?> dialect, Resource initScript) {
this.dialect = dialect;
this.initScript = initScript;
}
@Bean
DataSource dataSource(JdbcDatabaseContainer<?> container) {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl(container.getJdbcUrl());
dataSource.setUsername(container.getUsername());
dataSource.setPassword(container.getPassword());
return dataSource;
}
@Bean
AbstractEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setPersistenceUnitRootLocation("simple-persistence");
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factoryBean.setPackagesToScan(this.getClass().getPackage().getName());
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty("hibernate.dialect", dialect.getCanonicalName());
factoryBean.setJpaProperties(properties);
return factoryBean;
}
@Bean
PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
@Bean
DataSourceInitializer initializer(DataSource dataSource) {
DataSourceInitializer initializer = new DataSourceInitializer();
initializer.setDataSource(dataSource);
ResourceDatabasePopulator populator = new ResourceDatabasePopulator(initScript);
populator.setSeparator(";;");
initializer.setDatabasePopulator(populator);
return initializer;
}
}