update db2 'between' logic to be exclusive

Signed-off-by: Ryan DCruz <rd@enfuse.io>

use .acceptLicense() instead of the classpath file

checkstyle

add test to verify a result set that's smaller than requested page size

cleanup
This commit is contained in:
Tyler Carpenter-Rivers
2022-04-11 19:30:47 -07:00
committed by Glenn Renfro
parent 62cccc2727
commit fc89e23144
4 changed files with 216 additions and 3 deletions

View File

@@ -24,6 +24,7 @@ import org.springframework.data.domain.Pageable;
* database specific features.
*
* @author Thomas Schuettel
* @author Ryan DCruz
*/
public class Db2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
@@ -31,8 +32,7 @@ public class Db2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
public String getPageQuery(Pageable pageable) {
long offset = pageable.getOffset() + 1;
return generateRowNumSqlQueryWithNesting(getSelectClause(), false,
"TMP_ROW_NUM BETWEEN " + offset + " AND "
+ (offset + pageable.getPageSize()));
"TMP_ROW_NUM >= " + offset + " AND TMP_ROW_NUM < " + (offset + pageable.getPageSize()));
}
private String generateRowNumSqlQueryWithNesting(String selectClause,

View File

@@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Glenn Renfro
* @author Ryan DCruz
*/
public class FindAllPagingQueryProviderTests {
@@ -66,7 +67,16 @@ public class FindAllPagingQueryProviderTests {
+ "OVER (ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC) AS "
+ "TMP_ROW_NUM FROM %PREFIX%EXECUTION) TASK_EXECUTION_PAGE "
+ "WHERE TMP_ROW_NUM >= 1 AND TMP_ROW_NUM < 11 ORDER BY START_TIME DESC, "
+ "TASK_EXECUTION_ID DESC" } });
+ "TASK_EXECUTION_ID DESC" },
{ "DB2/Linux",
"SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, "
+ "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM "
+ "(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, "
+ "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID, ROW_NUMBER() "
+ "OVER() as TMP_ROW_NUM FROM "
+ "(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, "
+ "EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM %PREFIX%EXECUTION ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC)) "
+ "WHERE TMP_ROW_NUM >= 1 AND TMP_ROW_NUM < 11"}});
}
@ParameterizedTest

View File

@@ -17,6 +17,7 @@
<test.containers.version>1.16.3</test.containers.version>
<test.rabbit.containers.version>1.16.3</test.rabbit.containers.version>
<test.ducttape.version>1.0.8</test.ducttape.version>
<db2-jdbc.version>11.5.7.0</db2-jdbc.version>
</properties>
<dependencyManagement>
@@ -28,6 +29,13 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${test.containers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
@@ -103,12 +111,29 @@
<version>${test.containers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>rabbitmq</artifactId>
<version>${test.rabbit.containers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>db2</artifactId>
<version>${test.containers.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.ibm.db2</groupId>
<artifactId>jcc</artifactId>
<version>${db2-jdbc.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.rnorth.duct-tape</groupId>
<artifactId>duct-tape</artifactId>

View File

@@ -0,0 +1,178 @@
/*
* Copyright 2015-2022 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.cloud.task.database.support.db2;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.sql.DataSource;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Db2Container;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.cloud.task.executionid.TaskStartApplication;
import org.springframework.cloud.task.repository.TaskExecution;
import org.springframework.cloud.task.repository.dao.TaskExecutionDao;
import org.springframework.cloud.task.repository.database.support.Db2PagingQueryProvider;
import org.springframework.cloud.task.repository.support.SimpleTaskExplorer;
import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.context.jdbc.SqlConfig.ErrorMode.CONTINUE_ON_ERROR;
/**
* @author Tyler Carpenter-Rivers
* @author Ryan DCruz
* @see Db2PagingQueryProvider
*/
@SpringBootTest(
classes = {TaskStartApplication.class, Db2PagingQueryProviderTest.TestConfig.class},
properties = "spring.cloud.task.events.enabled=false"
)
@Testcontainers(disabledWithoutDocker = true)
@DirtiesContext
@Sql(
scripts = "classpath:/org/springframework/cloud/task/schema-db2.sql",
config = @SqlConfig(errorMode = CONTINUE_ON_ERROR)
)
@Sql(statements = {
" DELETE FROM TASK_EXECUTION_PARAMS ",
" DELETE FROM TASK_TASK_BATCH ",
" DELETE FROM TASK_EXECUTION "
})
class Db2PagingQueryProviderTest {
@Container
public static Db2Container db2Container =
new Db2Container(DockerImageName.parse("ibmcom/db2:11.5.7.0"))
.acceptLicense()
.withDatabaseName("test")
.withStartupTimeoutSeconds(30)
.withExposedPorts(50000);
@DynamicPropertySource
static void properties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", db2Container::getJdbcUrl);
registry.add("spring.datasource.username", db2Container::getUsername);
registry.add("spring.datasource.password", db2Container::getPassword);
}
@Autowired
private SimpleTaskExplorer simpleTaskExplorer;
@Autowired
private TaskExecutionDao taskExecutionDao;
@DisplayName("Scenario: The page request size is less than the total number of elements" +
"Given the total number of elements is 3" +
"And the page request size is 2" +
"When the query is executed" +
"Then the returned page has 2 elements")
@Test
void pageRequest() {
// setup test data
taskExecutionDao.createTaskExecution(
UUID.randomUUID().toString(), new Date(), List.of(), UUID.randomUUID().toString());
taskExecutionDao.createTaskExecution(
UUID.randomUUID().toString(), new Date(), List.of(), UUID.randomUUID().toString());
taskExecutionDao.createTaskExecution(
UUID.randomUUID().toString(), new Date(), List.of(), UUID.randomUUID().toString());
PageRequest pageRequest = PageRequest.of(0, 2);
// run subject under test
Page<TaskExecution> page = simpleTaskExplorer.findAll(pageRequest);
// assert and verify
assertThat(page.getTotalElements())
.as("Expected the total number of records in the table to be 3")
.isEqualTo(3);
assertThat(pageRequest.getPageSize())
.as("Expected the size of the returned page to be 2")
.isEqualTo(2);
}
@DisplayName("Scenario: the page request size is larger than the total number of elements" +
"Given the total number of elements is 1" +
"And the page request size is 2" +
"When the query is executed" +
"Then the returned page has 1 element")
@Test
void pageRequestSinglePageEntries() {
// setup test data
taskExecutionDao.createTaskExecution(
UUID.randomUUID().toString(), new Date(), List.of(), UUID.randomUUID().toString());
PageRequest pageRequest = PageRequest.of(0, 2);
// run subject under test
Page<TaskExecution> page = simpleTaskExplorer.findAll(pageRequest);
// assert and verify
assertThat(page.getTotalElements())
.as("Should only have one record in the table")
.isEqualTo(1);
assertThat(page.getNumberOfElements())
.as("Should have one record in the returned page")
.isEqualTo(1);
assertThat(page.getTotalPages())
.as("Should expect the total number of pages to be 1")
.isEqualTo(1);
}
@TestConfiguration
public static class TestConfig {
@Bean
@ConfigurationProperties("spring.datasource")
public DataSource dataSource() {
return new DriverManagerDataSource();
}
@Bean
public TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean(DataSource dataSource) {
return new TaskExecutionDaoFactoryBean(dataSource);
}
@Bean
public TaskExecutionDao taskExecutionDao(TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean) throws Exception {
return taskExecutionDaoFactoryBean.getObject();
}
}
}