Add support for MySQL and Postgres testing.
* Introduce Testcontainers as the mechanism to test against real data stores. * Alter CI to handle running Testcontainers in reduced privilege mode. * Run the data store specific test cases ONLY for the baseline Java 8 test execution. See #2256.
This commit is contained in:
7
Jenkinsfile
vendored
7
Jenkinsfile
vendored
@@ -24,13 +24,16 @@ pipeline {
|
||||
}
|
||||
options { timeout(time: 30, unit: 'MINUTES') }
|
||||
environment {
|
||||
DOCKER_HUB = credentials('hub.docker.com-springbuildmaster')
|
||||
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
|
||||
}
|
||||
steps {
|
||||
script {
|
||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
||||
docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
|
||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Dsort -Dbundlor.enabled=false -U -B'
|
||||
docker.image('adoptopenjdk/openjdk8:latest').inside('-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home') {
|
||||
sh "docker login --username ${DOCKER_HUB_USR} --password ${DOCKER_HUB_PSW}"
|
||||
sh 'PROFILE=all-dbs ci/test.sh'
|
||||
sh "ci/clean.sh"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
ci/clean.sh
Executable file
6
ci/clean.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
|
||||
./mvnw -s settings.xml clean -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-jpa
|
||||
10
ci/test.sh
Executable file
10
ci/test.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
mkdir -p /tmp/jenkins-home/.m2/spring-data-jpa
|
||||
chown -R 1001:1001 .
|
||||
|
||||
MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" \
|
||||
./mvnw -s settings.xml \
|
||||
-P${PROFILE} clean dependency:list test -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-jpa
|
||||
99
pom.xml
99
pom.xml
@@ -23,9 +23,12 @@
|
||||
|
||||
<eclipselink>2.7.9</eclipselink>
|
||||
<hibernate>5.5.3.Final</hibernate>
|
||||
<vavr>0.10.3</vavr>
|
||||
<hibernate.groupId>org.hibernate</hibernate.groupId>
|
||||
<mysql-connector-java>8.0.23</mysql-connector-java>
|
||||
<postgresql>42.2.19</postgresql>
|
||||
<springdata.commons>2.6.0-SNAPSHOT</springdata.commons>
|
||||
<vavr>0.10.3</vavr>
|
||||
|
||||
<hibernate.groupId>org.hibernate</hibernate.groupId>
|
||||
|
||||
<java-module-name>spring.data.jpa</java-module-name>
|
||||
|
||||
@@ -34,6 +37,43 @@
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>all-dbs</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>mysql-test</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/MySql*IntegrationTests.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>postgres-test</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/Postgres*IntegrationTests.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>hibernate-next</id>
|
||||
<properties>
|
||||
@@ -116,6 +156,18 @@
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers-bom</artifactId>
|
||||
<version>${testcontainers}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
@@ -187,6 +239,40 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL testing support -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${mysql-connector-java}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mysql</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Postgres testing support -->
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>${postgresql}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.threeten</groupId>
|
||||
<artifactId>threetenbp</artifactId>
|
||||
@@ -325,6 +411,7 @@
|
||||
</dependencies>
|
||||
<executions>
|
||||
<execution>
|
||||
<!-- override the default-test execution and exclude everything -->
|
||||
<id>default-test</id>
|
||||
<configuration>
|
||||
<excludes>
|
||||
@@ -333,7 +420,7 @@
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>unit-tests</id>
|
||||
<id>unit-test</id>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
@@ -345,7 +432,7 @@
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>integration-tests</id>
|
||||
<id>integration-test</id>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
@@ -359,6 +446,8 @@
|
||||
<exclude>**/*UnitTests.java</exclude>
|
||||
<exclude>**/OpenJpa*</exclude>
|
||||
<exclude>**/EclipseLink*</exclude>
|
||||
<exclude>**/MySql*</exclude>
|
||||
<exclude>**/Postgres*</exclude>
|
||||
</excludes>
|
||||
<argLine>
|
||||
-javaagent:${settings.localRepository}/org/springframework/spring-instrument/${spring}/spring-instrument-${spring}.jar
|
||||
@@ -367,7 +456,7 @@
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>eclipselink-tests</id>
|
||||
<id>eclipselink-test</id>
|
||||
<goals>
|
||||
<goal>test</goal>
|
||||
</goals>
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright 2015-2021 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 static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.sql.DataSource;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.hibernate.dialect.MySQL8Dialect;
|
||||
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;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
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.testcontainers.containers.MySQLContainer;
|
||||
|
||||
import com.mysql.cj.jdbc.MysqlDataSource;
|
||||
|
||||
/**
|
||||
* Testcase to verify {@link org.springframework.jdbc.object.StoredProcedure}s work with MySQL.
|
||||
*
|
||||
* @author Gabriel Basilio
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@Transactional
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = MySqlStoredProcedureIntegrationTests.Config.class)
|
||||
public class MySqlStoredProcedureIntegrationTests {
|
||||
|
||||
@Autowired EmployeeRepositoryWithNoCursor repository;
|
||||
|
||||
@Test // #2256
|
||||
void testGenericSingleObjectFromResultSet() {
|
||||
|
||||
Object[] employee = repository.genericSingleObjectFromResultSet();
|
||||
|
||||
assertThat(employee).containsExactly( //
|
||||
new Object[] { 3, "Fanny" }, //
|
||||
new Object[] { 4, "Gabriel" });
|
||||
}
|
||||
|
||||
@Test // #2256
|
||||
void testGenericObjectsFromResultSet() {
|
||||
|
||||
List<Object[]> employees = repository.genericObjectsFromResultSet();
|
||||
|
||||
assertThat(employees).containsExactly( //
|
||||
new Object[] { 3, "Fanny" }, //
|
||||
new Object[] { 4, "Gabriel" });
|
||||
}
|
||||
|
||||
@Test // #2256
|
||||
void testEntityListFromResultSet() {
|
||||
|
||||
List<Employee> employees = repository.entityListFromResultSet();
|
||||
|
||||
assertThat(employees).containsExactly( //
|
||||
new Employee(3, "Fanny"), //
|
||||
new Employee(4, "Gabriel"));
|
||||
}
|
||||
|
||||
@Test // #2256
|
||||
void testNamedOutputParameter() {
|
||||
|
||||
List<Employee> employees = repository.namedOutputParameter();
|
||||
|
||||
assertThat(employees).containsExactly( //
|
||||
new Employee(3, "Fanny"), //
|
||||
new Employee(4, "Gabriel"));
|
||||
}
|
||||
|
||||
@Test // #2256
|
||||
void testSingleEntityFromResultSet() {
|
||||
|
||||
Employee employee = repository.singleEntityFromResultSet();
|
||||
|
||||
assertThat(employee).isEqualTo(new Employee(3, "Fanny"));
|
||||
}
|
||||
|
||||
@Test // #2256
|
||||
void testEntityListFromSingleRowResultSet() {
|
||||
|
||||
List<Employee> employees = repository.entityListFromSingleRowResultSet();
|
||||
|
||||
assertThat(employees).containsExactly(new Employee(3, "Fanny"));
|
||||
}
|
||||
|
||||
@Test // #2256
|
||||
void testNoResultSet() {
|
||||
|
||||
int count = repository.noResultSet();
|
||||
|
||||
assertThat(count).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test // #2256
|
||||
void testEntityListFromNamedProcedure() {
|
||||
|
||||
List<Employee> employees = repository.entityListFromNamedProcedure();
|
||||
|
||||
assertThat(employees).containsExactly( //
|
||||
new Employee(3, "Fanny"), //
|
||||
new Employee(4, "Gabriel"));
|
||||
}
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@NamedStoredProcedureQuery(name = "get_employees_mysql", procedureName = "get_employees",
|
||||
resultClasses = Employee.class)
|
||||
public static class Employee {
|
||||
|
||||
@Id @GeneratedValue private Integer id;
|
||||
private String name;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public interface EmployeeRepositoryWithNoCursor extends JpaRepository<Employee, Integer> {
|
||||
|
||||
@Procedure(value = "get_employees")
|
||||
Object[] genericSingleObjectFromResultSet();
|
||||
|
||||
@Procedure(value = "get_employees")
|
||||
List<Object[]> genericObjectsFromResultSet();
|
||||
|
||||
@Procedure(value = "get_employees")
|
||||
List<Employee> entityListFromResultSet();
|
||||
|
||||
@Procedure(value = "get_employees", outputParameterName = "p_employees")
|
||||
List<Employee> namedOutputParameter();
|
||||
|
||||
@Procedure(value = "get_single_employee")
|
||||
Employee singleEntityFromResultSet();
|
||||
|
||||
@Procedure(value = "get_single_employee")
|
||||
List<Employee> entityListFromSingleRowResultSet();
|
||||
|
||||
@Procedure(value = "get_employees_count")
|
||||
Integer noResultSet();
|
||||
|
||||
@Procedure(name = "get_employees_mysql")
|
||||
List<Employee> entityListFromNamedProcedure();
|
||||
}
|
||||
|
||||
@EnableJpaRepositories(considerNestedRepositories = true, basePackageClasses = Config.class,
|
||||
includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = EmployeeRepositoryWithNoCursor.class))
|
||||
@EnableTransactionManagement
|
||||
static class Config {
|
||||
|
||||
private MySQLContainer<?> MYSQL_CONTAINER;
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
|
||||
if (MYSQL_CONTAINER == null) {
|
||||
|
||||
MYSQL_CONTAINER = new MySQLContainer<>("mysql:8.0.24") //
|
||||
.withUsername("test") //
|
||||
.withPassword("test") //
|
||||
.withConfigurationOverride("");
|
||||
MYSQL_CONTAINER.start();
|
||||
}
|
||||
|
||||
MysqlDataSource dataSource = new MysqlDataSource();
|
||||
dataSource.setUrl(MYSQL_CONTAINER.getJdbcUrl());
|
||||
dataSource.setUser("root");
|
||||
dataSource.setPassword(MYSQL_CONTAINER.getPassword());
|
||||
dataSource.setDatabaseName(MYSQL_CONTAINER.getDatabaseName());
|
||||
|
||||
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", MySQL8Dialect.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright 2015-2021 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 static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
import javax.sql.DataSource;
|
||||
import javax.transaction.Transactional;
|
||||
|
||||
import org.hibernate.dialect.PostgreSQL91Dialect;
|
||||
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.Filter;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
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.testcontainers.containers.PostgreSQLContainer;
|
||||
|
||||
/**
|
||||
* Testcase to verify {@link org.springframework.jdbc.object.StoredProcedure}s work with Postgres.
|
||||
*
|
||||
* @author Gabriel Basilio
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
@Transactional
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = PostgresStoredProcedureIntegrationTests.Config.class)
|
||||
public class PostgresStoredProcedureIntegrationTests {
|
||||
|
||||
@Autowired EmployeeRepositoryWithRefCursor repository;
|
||||
|
||||
@Test // 2256
|
||||
void testGenericSingleObjectFromResultSet() {
|
||||
|
||||
Object[] employee = repository.genericSingleObjectFromResultSet();
|
||||
|
||||
assertThat(employee).containsExactly( //
|
||||
new Object[] { new BigDecimal("3"), "Fanny" }, //
|
||||
new Object[] { new BigDecimal("4"), "Gabriel" });
|
||||
}
|
||||
|
||||
@Test // 2256
|
||||
void testGenericObjectsFromResultSet() {
|
||||
|
||||
List<Object[]> employees = repository.genericObjectsFromResultSet();
|
||||
|
||||
assertThat(employees).containsExactly( //
|
||||
new Object[] { new BigDecimal("3"), "Fanny" }, //
|
||||
new Object[] { new BigDecimal("4"), "Gabriel" });
|
||||
}
|
||||
|
||||
@Test // 2256
|
||||
void testEntityListFromResultSet() {
|
||||
|
||||
List<Employee> employees = repository.entityListFromResultSet();
|
||||
|
||||
assertThat(employees).containsExactly( //
|
||||
new Employee(3, "Fanny"), //
|
||||
new Employee(4, "Gabriel"));
|
||||
}
|
||||
|
||||
@Test // 2256
|
||||
void testNamedOutputParameter() {
|
||||
|
||||
List<Employee> employees = repository.namedOutputParameter();
|
||||
|
||||
assertThat(employees).containsExactly( //
|
||||
new Employee(3, "Fanny"), //
|
||||
new Employee(4, "Gabriel"));
|
||||
}
|
||||
|
||||
@Test // 2256
|
||||
void testSingleEntityFromResultSet() {
|
||||
|
||||
Employee employee = repository.singleEntityFromResultSet();
|
||||
|
||||
assertThat(employee).isEqualTo(new Employee(3, "Fanny"));
|
||||
}
|
||||
|
||||
@Test // 2256
|
||||
void testEntityListFromSingleRowResultSet() {
|
||||
|
||||
List<Employee> employees = repository.entityListFromSingleRowResultSet();
|
||||
|
||||
assertThat(employees).containsExactly(new Employee(3, "Fanny"));
|
||||
}
|
||||
|
||||
@Test // 2256
|
||||
void testNoResultSet() {
|
||||
|
||||
int count = repository.noResultSet();
|
||||
|
||||
assertThat(count).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test // 2256
|
||||
void testEntityListFromNamedProcedure() {
|
||||
|
||||
List<Employee> employees = repository.entityListFromNamedProcedure();
|
||||
|
||||
assertThat(employees).containsExactly( //
|
||||
new Employee(3, "Fanny"), //
|
||||
new Employee(4, "Gabriel"));
|
||||
}
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@NamedStoredProcedureQuery(name = "get_employees_postgres", procedureName = "get_employees",
|
||||
parameters = { @StoredProcedureParameter(mode = ParameterMode.REF_CURSOR, type = void.class) },
|
||||
resultClasses = Employee.class)
|
||||
public static class Employee {
|
||||
|
||||
@Id @GeneratedValue private Integer id;
|
||||
private String name;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public interface EmployeeRepositoryWithRefCursor extends JpaRepository<Employee, Integer> {
|
||||
|
||||
@Procedure(value = "get_employees", refCursor = true)
|
||||
Object[] genericSingleObjectFromResultSet();
|
||||
|
||||
@Procedure(value = "get_employees", refCursor = true)
|
||||
List<Object[]> genericObjectsFromResultSet();
|
||||
|
||||
@Procedure(value = "get_employees", refCursor = true)
|
||||
List<Employee> entityListFromResultSet();
|
||||
|
||||
@Procedure(value = "get_employees", outputParameterName = "p_employees", refCursor = true)
|
||||
List<Employee> namedOutputParameter();
|
||||
|
||||
@Procedure(value = "get_single_employee", refCursor = true)
|
||||
Employee singleEntityFromResultSet();
|
||||
|
||||
@Procedure(value = "get_single_employee", refCursor = true)
|
||||
List<Employee> entityListFromSingleRowResultSet();
|
||||
|
||||
@Procedure(value = "get_employees_count")
|
||||
Integer noResultSet();
|
||||
|
||||
@Procedure(name = "get_employees_postgres", refCursor = true)
|
||||
List<Employee> entityListFromNamedProcedure();
|
||||
}
|
||||
|
||||
@EnableJpaRepositories(considerNestedRepositories = true,
|
||||
includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = EmployeeRepositoryWithRefCursor.class))
|
||||
@EnableTransactionManagement
|
||||
static class Config {
|
||||
|
||||
private PostgreSQLContainer<?> POSTGRESQL_CONTAINER;
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
|
||||
if (POSTGRESQL_CONTAINER == null) {
|
||||
|
||||
POSTGRESQL_CONTAINER = new PostgreSQLContainer<>("postgres:9.6.12") //
|
||||
.withUsername("postgres");
|
||||
POSTGRESQL_CONTAINER.start();
|
||||
}
|
||||
|
||||
PGSimpleDataSource dataSource = new PGSimpleDataSource();
|
||||
dataSource.setUrl(POSTGRESQL_CONTAINER.getJdbcUrl());
|
||||
dataSource.setUser(POSTGRESQL_CONTAINER.getUsername());
|
||||
dataSource.setPassword(POSTGRESQL_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", PostgreSQL91Dialect.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,15 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework.data" level="error" />
|
||||
<logger name="org.springframework.data" level="error"/>
|
||||
|
||||
<!-- Uncomment these sections to debug -->
|
||||
<!-- <logger name="org.springframework.data.jpa" level="trace" />-->
|
||||
<!-- <logger name="org.springframework.jdbc" level="debug" />-->
|
||||
<!-- <logger name="org.testcontainers" level="debug" />-->
|
||||
|
||||
<root level="error">
|
||||
<appender-ref ref="console" />
|
||||
<appender-ref ref="console"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
27
src/test/resources/scripts/mysql-stored-procedures.sql
Normal file
27
src/test/resources/scripts/mysql-stored-procedures.sql
Normal file
@@ -0,0 +1,27 @@
|
||||
CREATE TABLE employee
|
||||
(
|
||||
ID int NOT NULL,
|
||||
name varchar(50) NOT NULL,
|
||||
primary key (ID)
|
||||
);;
|
||||
|
||||
INSERT INTO employee (ID, NAME) VALUES (3, 'Fanny');;
|
||||
INSERT INTO employee (ID, NAME) VALUES (4, 'Gabriel');;
|
||||
|
||||
DROP PROCEDURE IF EXISTS get_employees;;
|
||||
CREATE PROCEDURE get_employees()
|
||||
BEGIN
|
||||
SELECT * FROM employee;
|
||||
END;;
|
||||
|
||||
DROP PROCEDURE IF EXISTS get_employees_count;;
|
||||
CREATE PROCEDURE get_employees_count(OUT employees INT)
|
||||
BEGIN
|
||||
SELECT COUNT(*) into employees FROM employee;
|
||||
END;;
|
||||
|
||||
DROP PROCEDURE IF EXISTS get_single_employee;;
|
||||
CREATE PROCEDURE get_single_employee()
|
||||
BEGIN
|
||||
SELECT * FROM employee WHERE employee.ID = 3;
|
||||
END;;
|
||||
45
src/test/resources/scripts/postgres-stored-procedures.sql
Normal file
45
src/test/resources/scripts/postgres-stored-procedures.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
CREATE TABLE employee
|
||||
(
|
||||
ID numeric NOT NULL,
|
||||
name text COLLATE pg_catalog."default" NOT NULL,
|
||||
CONSTRAINT employee_pkey PRIMARY KEY (ID)
|
||||
);;
|
||||
|
||||
INSERT INTO employee (ID, NAME) VALUES (3, 'Fanny');;
|
||||
INSERT INTO employee (ID, NAME) VALUES (4, 'Gabriel');;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_employees()
|
||||
RETURNS refcursor
|
||||
LANGUAGE 'plpgsql'
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
ref refcursor;
|
||||
BEGIN
|
||||
OPEN ref FOR SELECT * FROM employee;
|
||||
RETURN ref;
|
||||
END;
|
||||
$BODY$;;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_employees_count()
|
||||
RETURNS integer
|
||||
LANGUAGE 'plpgsql'
|
||||
AS
|
||||
$BODY$
|
||||
BEGIN
|
||||
RETURN (SELECT COUNT(*) FROM employee);
|
||||
END;
|
||||
$BODY$;;
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_single_employee()
|
||||
RETURNS refcursor
|
||||
LANGUAGE 'plpgsql'
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
ref refcursor;
|
||||
BEGIN
|
||||
OPEN ref FOR SELECT * FROM employee WHERE employee.ID = 3;
|
||||
RETURN ref;
|
||||
END;
|
||||
$BODY$;;
|
||||
Reference in New Issue
Block a user