Skip to content

Commit e121dd7

Browse files
committed
Add Redis integration tests
Signed-off-by: Hyunwoo Jung <[email protected]>
1 parent 639d64f commit e121dd7

File tree

5 files changed

+298
-0
lines changed

5 files changed

+298
-0
lines changed

pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@
134134
<nashorn.version>15.6</nashorn.version>
135135
<beanshell.version>2.0b6</beanshell.version>
136136
<jruby.version>9.4.12.0</jruby.version>
137+
<lettuce.version>6.6.0.RELEASE</lettuce.version>
138+
<testcontainers-redis.version>2.2.4</testcontainers-redis.version>
137139

138140
<!-- samples dependencies -->
139141
<spring-rabbit.version>${spring-amqp.version}</spring-rabbit.version>

spring-batch-infrastructure/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,18 @@
559559
<version>${jruby.version}</version>
560560
<scope>test</scope>
561561
</dependency>
562+
<dependency>
563+
<groupId>io.lettuce</groupId>
564+
<artifactId>lettuce-core</artifactId>
565+
<version>${lettuce.version}</version>
566+
<scope>test</scope>
567+
</dependency>
568+
<dependency>
569+
<groupId>com.redis</groupId>
570+
<artifactId>testcontainers-redis</artifactId>
571+
<version>${testcontainers-redis.version}</version>
572+
<scope>test</scope>
573+
</dependency>
562574

563575
<!-- provided dependencies -->
564576
<dependency>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2025 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.batch.item.redis;
18+
19+
import com.redis.testcontainers.RedisContainer;
20+
import org.junit.jupiter.api.BeforeEach;
21+
import org.junit.jupiter.api.Test;
22+
import org.junit.jupiter.api.extension.ExtendWith;
23+
import org.springframework.batch.item.ExecutionContext;
24+
import org.springframework.batch.item.redis.example.Person;
25+
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
26+
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
27+
import org.springframework.data.redis.core.RedisTemplate;
28+
import org.springframework.data.redis.core.ScanOptions;
29+
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
30+
import org.springframework.data.redis.serializer.StringRedisSerializer;
31+
import org.springframework.test.context.junit.jupiter.SpringExtension;
32+
import org.testcontainers.junit.jupiter.Container;
33+
import org.testcontainers.junit.jupiter.Testcontainers;
34+
import org.testcontainers.utility.DockerImageName;
35+
36+
import java.util.ArrayList;
37+
import java.util.List;
38+
39+
import static org.hamcrest.MatcherAssert.assertThat;
40+
import static org.hamcrest.Matchers.containsInAnyOrder;
41+
42+
/**
43+
* @author Hyunwoo Jung
44+
*/
45+
@Testcontainers(disabledWithoutDocker = true)
46+
@ExtendWith(SpringExtension.class)
47+
class RedisItemReaderIntegrationTests {
48+
49+
private static final DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:8.0.2");
50+
51+
@Container
52+
public static RedisContainer redis = new RedisContainer(REDIS_IMAGE);
53+
54+
private RedisItemReader<String, Person> reader;
55+
56+
private RedisTemplate<String, Person> template;
57+
58+
@BeforeEach
59+
void setUp() {
60+
this.template = setUpRedisTemplate();
61+
this.template.getConnectionFactory().getConnection().serverCommands().flushAll();
62+
}
63+
64+
@Test
65+
void testRead() throws Exception {
66+
this.template.opsForValue().set("person:1", new Person(1, "foo"));
67+
this.template.opsForValue().set("person:2", new Person(2, "bar"));
68+
this.template.opsForValue().set("person:3", new Person(3, "baz"));
69+
this.template.opsForValue().set("person:4", new Person(4, "qux"));
70+
this.template.opsForValue().set("person:5", new Person(5, "quux"));
71+
72+
RedisTemplate<String, Person> redisTemplate = setUpRedisTemplate();
73+
ScanOptions scanOptions = ScanOptions.scanOptions().match("person:*").count(10).build();
74+
this.reader = new RedisItemReader<>(redisTemplate, scanOptions);
75+
76+
this.reader.open(new ExecutionContext());
77+
78+
List<Person> items = new ArrayList<>();
79+
for (int i = 0; i < 5; i++) {
80+
items.add(this.reader.read());
81+
}
82+
83+
assertThat(items, containsInAnyOrder(new Person(1, "foo"), new Person(2, "bar"), new Person(3, "baz"),
84+
new Person(4, "qux"), new Person(5, "quux")));
85+
}
86+
87+
private RedisTemplate<String, Person> setUpRedisTemplate() {
88+
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(
89+
new RedisStandaloneConfiguration(redis.getRedisHost(), redis.getRedisPort()));
90+
connectionFactory.afterPropertiesSet();
91+
92+
RedisTemplate<String, Person> redisTemplate = new RedisTemplate<>();
93+
redisTemplate.setConnectionFactory(connectionFactory);
94+
redisTemplate.setKeySerializer(new StringRedisSerializer());
95+
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
96+
redisTemplate.afterPropertiesSet();
97+
98+
return redisTemplate;
99+
}
100+
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright 2025 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.batch.item.redis;
18+
19+
import com.redis.testcontainers.RedisContainer;
20+
import org.junit.jupiter.api.BeforeEach;
21+
import org.junit.jupiter.api.Test;
22+
import org.junit.jupiter.api.extension.ExtendWith;
23+
import org.springframework.batch.item.Chunk;
24+
import org.springframework.batch.item.redis.example.Person;
25+
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
26+
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
27+
import org.springframework.data.redis.core.RedisTemplate;
28+
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
29+
import org.springframework.data.redis.serializer.StringRedisSerializer;
30+
import org.springframework.test.context.junit.jupiter.SpringExtension;
31+
import org.testcontainers.junit.jupiter.Container;
32+
import org.testcontainers.junit.jupiter.Testcontainers;
33+
import org.testcontainers.utility.DockerImageName;
34+
35+
import static org.junit.jupiter.api.Assertions.*;
36+
37+
/**
38+
* @author Hyunwoo Jung
39+
*/
40+
@Testcontainers(disabledWithoutDocker = true)
41+
@ExtendWith(SpringExtension.class)
42+
class RedisItemWriterIntegrationTests {
43+
44+
private static final DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:8.0.2");
45+
46+
@Container
47+
public static RedisContainer redis = new RedisContainer(REDIS_IMAGE);
48+
49+
private RedisItemWriter<String, Person> writer;
50+
51+
private RedisTemplate<String, Person> template;
52+
53+
@BeforeEach
54+
void setUp() {
55+
this.template = setUpRedisTemplate();
56+
this.template.getConnectionFactory().getConnection().serverCommands().flushAll();
57+
}
58+
59+
@Test
60+
void testWrite() throws Exception {
61+
RedisTemplate<String, Person> redisTemplate = setUpRedisTemplate();
62+
this.writer = new RedisItemWriter<>();
63+
this.writer.setRedisTemplate(redisTemplate);
64+
this.writer.setItemKeyMapper(p -> "person:" + p.getId());
65+
this.writer.setDelete(false);
66+
67+
Chunk<Person> items = new Chunk<>(new Person(1, "foo"), new Person(2, "bar"), new Person(3, "baz"),
68+
new Person(4, "qux"), new Person(5, "quux"));
69+
this.writer.write(items);
70+
71+
assertEquals(new Person(1, "foo"), this.template.opsForValue().get("person:1"));
72+
assertEquals(new Person(2, "bar"), this.template.opsForValue().get("person:2"));
73+
assertEquals(new Person(3, "baz"), this.template.opsForValue().get("person:3"));
74+
assertEquals(new Person(4, "qux"), this.template.opsForValue().get("person:4"));
75+
assertEquals(new Person(5, "quux"), this.template.opsForValue().get("person:5"));
76+
}
77+
78+
@Test
79+
void testDelete() throws Exception {
80+
this.template.opsForValue().set("person:1", new Person(1, "foo"));
81+
this.template.opsForValue().set("person:2", new Person(2, "bar"));
82+
this.template.opsForValue().set("person:3", new Person(3, "baz"));
83+
this.template.opsForValue().set("person:4", new Person(4, "qux"));
84+
this.template.opsForValue().set("person:5", new Person(5, "quux"));
85+
86+
RedisTemplate<String, Person> redisTemplate = setUpRedisTemplate();
87+
this.writer = new RedisItemWriter<>();
88+
this.writer.setRedisTemplate(redisTemplate);
89+
this.writer.setItemKeyMapper(p -> "person:" + p.getId());
90+
this.writer.setDelete(true);
91+
92+
Chunk<Person> items = new Chunk<>(new Person(1, "foo"), new Person(2, "bar"), new Person(3, "baz"),
93+
new Person(4, "qux"), new Person(5, "quux"));
94+
this.writer.write(items);
95+
96+
assertFalse(this.template.hasKey("person:1"));
97+
assertFalse(this.template.hasKey("person:2"));
98+
assertFalse(this.template.hasKey("person:3"));
99+
assertFalse(this.template.hasKey("person:4"));
100+
assertFalse(this.template.hasKey("person:5"));
101+
}
102+
103+
private RedisTemplate<String, Person> setUpRedisTemplate() {
104+
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(
105+
new RedisStandaloneConfiguration(redis.getRedisHost(), redis.getRedisPort()));
106+
connectionFactory.afterPropertiesSet();
107+
108+
RedisTemplate<String, Person> redisTemplate = new RedisTemplate<>();
109+
redisTemplate.setConnectionFactory(connectionFactory);
110+
redisTemplate.setKeySerializer(new StringRedisSerializer());
111+
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
112+
redisTemplate.afterPropertiesSet();
113+
114+
return redisTemplate;
115+
}
116+
117+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright 2025 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.batch.item.redis.example;
18+
19+
import java.io.Serial;
20+
import java.io.Serializable;
21+
import java.util.Objects;
22+
23+
/**
24+
* @author Hyunwoo Jung
25+
*/
26+
public class Person implements Serializable {
27+
28+
@Serial
29+
private static final long serialVersionUID = 2396556853218591048L;
30+
31+
private long id;
32+
33+
private String name;
34+
35+
public Person(long id, String name) {
36+
this.id = id;
37+
this.name = name;
38+
}
39+
40+
public long getId() {
41+
return id;
42+
}
43+
44+
public String getName() {
45+
return name;
46+
}
47+
48+
@Override
49+
public boolean equals(Object o) {
50+
if (o == null || getClass() != o.getClass())
51+
return false;
52+
Person person = (Person) o;
53+
return id == person.id && Objects.equals(name, person.name);
54+
}
55+
56+
@Override
57+
public int hashCode() {
58+
return Objects.hash(id, name);
59+
}
60+
61+
@Override
62+
public String toString() {
63+
return "Person{id=" + id + ", name=" + name + "}";
64+
}
65+
66+
}

0 commit comments

Comments
 (0)