Skip to content

Commit 102f4b7

Browse files
hpoettkercppwfs
authored andcommitted
Use strict H2 query syntax for paging query provider
Simplify tests a bit Updated to snapshot dependencies Updated test and to set the version of h2 to us boot bom.
1 parent f74d38a commit 102f4b7

File tree

11 files changed

+191
-173
lines changed

11 files changed

+191
-173
lines changed

pom.xml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,30 @@
9494
<artifactId>spring-cloud-stream-test-support</artifactId>
9595
<version>${spring-cloud-stream.version}</version>
9696
</dependency>
97+
<dependency> <groupId>org.springframework</groupId>
98+
<artifactId>spring-jdbc</artifactId>
99+
<version>5.3.15-SNAPSHOT</version>
100+
</dependency>
101+
<dependency>
102+
<groupId>org.springframework.batch</groupId>
103+
<artifactId>spring-batch-core</artifactId>
104+
<version>${spring-batch.version}</version>
105+
</dependency>
106+
<dependency>
107+
<groupId>org.springframework.batch</groupId>
108+
<artifactId>spring-batch-infrastructure</artifactId>
109+
<version>${spring-batch.version}</version>
110+
</dependency>
111+
<dependency>
112+
<groupId>org.springframework.batch</groupId>
113+
<artifactId>spring-batch-integration</artifactId>
114+
<version>${spring-batch.version}</version>
115+
</dependency>
116+
<dependency>
117+
<groupId>org.springframework.batch</groupId>
118+
<artifactId>spring-batch-test</artifactId>
119+
<version>${spring-batch.version}</version>
120+
</dependency>
97121
</dependencies>
98122
</dependencyManagement>
99123

@@ -110,6 +134,7 @@
110134
</modules>
111135

112136
<properties>
137+
<spring-batch.version>4.3.5-SNAPSHOT</spring-batch.version>
113138
<spring-cloud-stream.version>3.2.1</spring-cloud-stream.version>
114139
<spring-cloud-deployer.version>2.7.0</spring-cloud-deployer.version>
115140
<spring-cloud-deployer-local.version>2.7.0

spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/JdbcBatchItemWriterAutoConfigurationTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ private ApplicationContextRunner updatePropertiesForTest(
150150
return applicationContextRunner.withPropertyValues("spring.batch.job.jobName=job",
151151
"spring.batch.job.stepName=step1", "spring.batch.job.chunkSize=5",
152152
"spring.batch.job.jdbcbatchitemwriter.name=fooWriter",
153-
"spring.batch.job.jdbcbatchitemwriter.sql=INSERT INTO item (item_name) VALUES (:item_name)");
153+
"spring.batch.job.jdbcbatchitemwriter.sql=INSERT INTO item (item_name) VALUES (:item_name)",
154+
"spring.batch.jdbc.initialize-schema=always");
154155
}
155156

156157
private void validateResultAndBean(ApplicationContext context) {

spring-cloud-starter-single-step-batch-job/src/test/java/org/springframework/cloud/task/batch/autoconfigure/jdbc/JdbcCursorItemReaderAutoConfigurationTests.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ public void testIntegration() {
100100
.withPropertyValues("spring.batch.job.jobName=integrationJob",
101101
"spring.batch.job.stepName=step1", "spring.batch.job.chunkSize=5",
102102
"spring.batch.job.jdbccursoritemreader.name=fooReader",
103-
"spring.batch.job.jdbccursoritemreader.sql=select item_name from item");
103+
"spring.batch.job.jdbccursoritemreader.sql=select item_name from item",
104+
"spring.batch.jdbc.initialize-schema=always");
104105

105106
applicationContextRunner.run((context) -> {
106107
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
@@ -137,7 +138,8 @@ public void testCustomRowMapper() {
137138
.withPropertyValues("spring.batch.job.jobName=rowMapperJob",
138139
"spring.batch.job.stepName=step1", "spring.batch.job.chunkSize=5",
139140
"spring.batch.job.jdbccursoritemreader.name=fooReader",
140-
"spring.batch.job.jdbccursoritemreader.sql=select * from item");
141+
"spring.batch.job.jdbccursoritemreader.sql=select * from item",
142+
"spring.batch.jdbc.initialize-schema=always");
141143

142144
applicationContextRunner.run((context) -> {
143145
JobLauncher jobLauncher = context.getBean(JobLauncher.class);

spring-cloud-starter-single-step-batch-job/src/test/resources/schema-h2.sql

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -2,82 +2,3 @@ CREATE TABLE IF NOT EXISTS item
22
(
33
item_name varchar(55)
44
);
5-
CREATE TABLE IF NOT EXISTS BATCH_JOB_INSTANCE (
6-
JOB_INSTANCE_ID BIGINT IDENTITY NOT NULL PRIMARY KEY ,
7-
VERSION BIGINT ,
8-
JOB_NAME VARCHAR(100) NOT NULL,
9-
JOB_KEY VARCHAR(32) NOT NULL,
10-
constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)
11-
) ;
12-
13-
CREATE TABLE IF NOT EXISTS BATCH_JOB_EXECUTION (
14-
JOB_EXECUTION_ID BIGINT IDENTITY NOT NULL PRIMARY KEY ,
15-
VERSION BIGINT ,
16-
JOB_INSTANCE_ID BIGINT NOT NULL,
17-
CREATE_TIME TIMESTAMP NOT NULL,
18-
START_TIME TIMESTAMP DEFAULT NULL ,
19-
END_TIME TIMESTAMP DEFAULT NULL ,
20-
STATUS VARCHAR(10) ,
21-
EXIT_CODE VARCHAR(2500) ,
22-
EXIT_MESSAGE VARCHAR(2500) ,
23-
LAST_UPDATED TIMESTAMP,
24-
JOB_CONFIGURATION_LOCATION VARCHAR(2500) NULL,
25-
constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
26-
references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
27-
) ;
28-
29-
CREATE TABLE IF NOT EXISTS BATCH_JOB_EXECUTION_PARAMS (
30-
JOB_EXECUTION_ID BIGINT NOT NULL ,
31-
TYPE_CD VARCHAR(6) NOT NULL ,
32-
KEY_NAME VARCHAR(100) NOT NULL ,
33-
STRING_VAL VARCHAR(250) ,
34-
DATE_VAL TIMESTAMP DEFAULT NULL ,
35-
LONG_VAL BIGINT ,
36-
DOUBLE_VAL DOUBLE PRECISION ,
37-
IDENTIFYING CHAR(1) NOT NULL ,
38-
constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID)
39-
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
40-
) ;
41-
42-
CREATE TABLE IF NOT EXISTS BATCH_STEP_EXECUTION (
43-
STEP_EXECUTION_ID BIGINT IDENTITY NOT NULL PRIMARY KEY ,
44-
VERSION BIGINT NOT NULL,
45-
STEP_NAME VARCHAR(100) NOT NULL,
46-
JOB_EXECUTION_ID BIGINT NOT NULL,
47-
START_TIME TIMESTAMP NOT NULL ,
48-
END_TIME TIMESTAMP DEFAULT NULL ,
49-
STATUS VARCHAR(10) ,
50-
COMMIT_COUNT BIGINT ,
51-
READ_COUNT BIGINT ,
52-
FILTER_COUNT BIGINT ,
53-
WRITE_COUNT BIGINT ,
54-
READ_SKIP_COUNT BIGINT ,
55-
WRITE_SKIP_COUNT BIGINT ,
56-
PROCESS_SKIP_COUNT BIGINT ,
57-
ROLLBACK_COUNT BIGINT ,
58-
EXIT_CODE VARCHAR(2500) ,
59-
EXIT_MESSAGE VARCHAR(2500) ,
60-
LAST_UPDATED TIMESTAMP,
61-
constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)
62-
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
63-
) ;
64-
65-
CREATE TABLE IF NOT EXISTS BATCH_STEP_EXECUTION_CONTEXT (
66-
STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
67-
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
68-
SERIALIZED_CONTEXT LONGVARCHAR ,
69-
constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
70-
references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
71-
) ;
72-
73-
CREATE TABLE IF NOT EXISTS BATCH_JOB_EXECUTION_CONTEXT (
74-
JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
75-
SHORT_CONTEXT VARCHAR(2500) NOT NULL,
76-
SERIALIZED_CONTEXT LONGVARCHAR ,
77-
constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
78-
references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
79-
) ;
80-
81-
CREATE SEQUENCE IF NOT EXISTS BATCH_STEP_EXECUTION_SEQ;
82-
CREATE SEQUENCE IF NOT EXISTS BATCH_JOB_EXECUTION_SEQ;
83-
CREATE SEQUENCE IF NOT EXISTS BATCH_JOB_SEQ;

spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/H2PagingQueryProvider.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2019 the original author or authors.
2+
* Copyright 2016-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,15 +23,17 @@
2323
* H2 implementation of a {@link PagingQueryProvider} using database specific features.
2424
*
2525
* @author Glenn Renfro
26+
* @author Henning Pöttker
2627
*/
2728
public class H2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
2829

2930
@Override
3031
public String getPageQuery(Pageable pageable) {
31-
String topClause = new StringBuilder().append("LIMIT ")
32-
.append(pageable.getOffset()).append(" ").append(pageable.getPageSize())
32+
String limitClause = new StringBuilder().append("OFFSET ")
33+
.append(pageable.getOffset()).append(" ROWS FETCH NEXT ")
34+
.append(pageable.getPageSize()).append(" ROWS ONLY")
3335
.toString();
34-
return SqlPagingQueryUtils.generateTopJumpToQuery(this, topClause);
36+
return SqlPagingQueryUtils.generateLimitJumpToQuery(this, limitClause);
3537
}
3638

3739
}

spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskAutoConfigurationTests.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,6 @@ public void testRepositoryNotInitialized() {
133133
.withPropertyValues("spring.cloud.task.tablePrefix=foobarless");
134134

135135
verifyExceptionThrownDefaultExecutable(ApplicationContextException.class,
136-
"Failed to start " + "bean 'taskLifecycleListener'; nested exception is "
137-
+ "org.springframework.dao.DataAccessResourceFailureException: "
138-
+ "Could not obtain sequence value; nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: "
139-
+ "Syntax error in SQL statement \"SELECT FOOBARLESSSEQ.NEXTVAL FROM[*] DUAL\"; "
140-
+ "expected \"identifier\"; SQL statement:\n"
141-
+ "select foobarlessSEQ.nextval from dual [42001-200]",
142136
applicationContextRunner);
143137
}
144138

@@ -176,6 +170,17 @@ public void testMultipleDataSources() {
176170

177171
}
178172

173+
public void verifyExceptionThrownDefaultExecutable(Class classToCheck, ApplicationContextRunner applicationContextRunner) {
174+
Executable executable = () -> {
175+
applicationContextRunner.run((context) -> {
176+
Throwable expectedException = context.getStartupFailure();
177+
assertThat(expectedException).isNotNull();
178+
throw expectedException;
179+
});
180+
};
181+
assertThatExceptionOfType(classToCheck).isThrownBy(executable::execute);
182+
}
183+
179184
public void verifyExceptionThrownDefaultExecutable(Class classToCheck, String message,
180185
ApplicationContextRunner applicationContextRunner) {
181186
Executable executable = () -> {
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2022-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.task.repository;
18+
19+
import java.util.UUID;
20+
21+
import javax.sql.DataSource;
22+
23+
import org.h2.engine.Mode.ModeEnum;
24+
import org.junit.jupiter.params.ParameterizedTest;
25+
import org.junit.jupiter.params.provider.EnumSource;
26+
27+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
28+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
29+
import org.springframework.cloud.task.configuration.EnableTask;
30+
import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;
31+
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
35+
/**
36+
* @author Henning Pöttker
37+
*/
38+
class H2TaskRepositoryIntegrationTests {
39+
40+
@ParameterizedTest
41+
@EnumSource(ModeEnum.class)
42+
void testTaskRepository(ModeEnum mode) {
43+
String connectionUrl = String.format("jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;MODE=%s", UUID.randomUUID(), mode);
44+
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
45+
.withUserConfiguration(TestConfiguration.class)
46+
.withBean(DataSource.class,
47+
() -> new SimpleDriverDataSource(new org.h2.Driver(), connectionUrl, "sa", ""));
48+
49+
applicationContextRunner.run((context -> {
50+
TaskExplorer taskExplorer = context.getBean(TaskExplorer.class);
51+
assertThat(taskExplorer.getTaskExecutionCount()).isOne();
52+
}));
53+
}
54+
55+
@EnableTask
56+
@ImportAutoConfiguration(SimpleTaskAutoConfiguration.class)
57+
static class TestConfiguration {
58+
}
59+
60+
}

spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/dao/BaseTaskExecutionDaoTestCases.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
*
3636
* @author Gunnar Hillert
3737
*/
38-
public class BaseTaskExecutionDaoTestCases {
38+
public abstract class BaseTaskExecutionDaoTestCases {
3939

4040
protected TaskExecutionDao dao;
4141

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2022-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.task.repository.database.support;
18+
19+
import java.util.HashMap;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.UUID;
23+
24+
import javax.sql.DataSource;
25+
26+
import org.h2.engine.Mode.ModeEnum;
27+
import org.junit.jupiter.params.ParameterizedTest;
28+
import org.junit.jupiter.params.provider.EnumSource;
29+
30+
import org.springframework.batch.item.database.Order;
31+
import org.springframework.data.domain.PageRequest;
32+
import org.springframework.jdbc.core.JdbcTemplate;
33+
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
34+
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
35+
import org.springframework.transaction.PlatformTransactionManager;
36+
import org.springframework.transaction.support.TransactionTemplate;
37+
38+
import static org.assertj.core.api.Assertions.assertThat;
39+
40+
/**
41+
* @author Henning Pöttker
42+
*/
43+
class H2PagingQueryProviderTests {
44+
45+
@ParameterizedTest
46+
@EnumSource(ModeEnum.class)
47+
void testH2PagingQueryProvider(ModeEnum mode) {
48+
String connectionUrl = String.format("jdbc:h2:mem:%s;MODE=%s", UUID.randomUUID(), mode);
49+
DataSource dataSource = new SimpleDriverDataSource(new org.h2.Driver(), connectionUrl, "sa", "");
50+
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
51+
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
52+
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
53+
54+
transactionTemplate.executeWithoutResult(status -> {
55+
jdbcTemplate.execute("CREATE TABLE TEST_TABLE (ID BIGINT NOT NULL, STRING VARCHAR(10) NOT NULL)");
56+
jdbcTemplate.execute("INSERT INTO TEST_TABLE (ID, STRING) VALUES (1, 'Spring')");
57+
jdbcTemplate.execute("INSERT INTO TEST_TABLE (ID, STRING) VALUES (2, 'Cloud')");
58+
jdbcTemplate.execute("INSERT INTO TEST_TABLE (ID, STRING) VALUES (3, 'Task')");
59+
60+
H2PagingQueryProvider queryProvider = new H2PagingQueryProvider();
61+
queryProvider.setSelectClause("STRING");
62+
queryProvider.setFromClause("TEST_TABLE");
63+
Map<String, Order> sortKeys = new HashMap<>();
64+
sortKeys.put("ID", Order.ASCENDING);
65+
queryProvider.setSortKeys(sortKeys);
66+
67+
List<String> firstPage = jdbcTemplate.queryForList(
68+
queryProvider.getPageQuery(PageRequest.of(0, 2)),
69+
String.class
70+
);
71+
assertThat(firstPage).containsExactly("Spring", "Cloud");
72+
73+
List<String> secondPage = jdbcTemplate.queryForList(
74+
queryProvider.getPageQuery(PageRequest.of(1, 2)),
75+
String.class
76+
);
77+
assertThat(secondPage).containsExactly("Task");
78+
});
79+
}
80+
81+
}

spring-cloud-task-samples/single-step-batch-job/src/main/resources/application.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ spring.application.name=Single Step Batch Job
22
spring.batch.job.jobName=job
33
spring.batch.job.stepName=step1
44
spring.batch.job.chunkSize=5
5+
spring.batch.jdbc.initialize-schema=always

0 commit comments

Comments
 (0)