Skip to content

Commit 3bb271e

Browse files
Add smoke test to verify Redis SSL connection
See gh-34815
1 parent 161b54b commit 3bb271e

File tree

17 files changed

+592
-3
lines changed

17 files changed

+592
-3
lines changed

Diff for: spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/redis/RedisConnectionConfiguration.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,7 @@ protected SslBundles getSslBundles() {
151151
}
152152

153153
protected boolean isSslEnabled() {
154-
return getConnectionDetails() instanceof PropertiesRedisConnectionDetails
155-
&& getProperties().getSsl().isEnabled();
154+
return getProperties().getSsl().isEnabled();
156155
}
157156

158157
protected boolean isPoolEnabled(Pool pool) {

Diff for: spring-boot-project/spring-boot-tools/spring-boot-test-support/src/main/java/org/springframework/boot/testsupport/testcontainers/DockerImageNames.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public final class DockerImageNames {
4747

4848
private static final String RABBIT_VERSION = "3.11-alpine";
4949

50-
private static final String REDIS_VERSION = "4.0.14";
50+
private static final String REDIS_VERSION = "7.0.11";
5151

5252
private static final String REDPANDA_VERSION = "v23.1.2";
5353

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
plugins {
2+
id "java"
3+
id "org.springframework.boot.conventions"
4+
}
5+
6+
description = "Spring Boot Data Redis smoke test"
7+
8+
dependencies {
9+
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-data-redis"))
10+
11+
testImplementation(project(":spring-boot-project:spring-boot-test"))
12+
testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))
13+
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
14+
testImplementation(project(":spring-boot-project:spring-boot-testcontainers"))
15+
testImplementation("io.projectreactor:reactor-core")
16+
testImplementation("io.projectreactor:reactor-test")
17+
testImplementation("org.junit.jupiter:junit-jupiter")
18+
testImplementation("org.junit.platform:junit-platform-engine")
19+
testImplementation("org.junit.platform:junit-platform-launcher")
20+
testImplementation("org.testcontainers:junit-jupiter")
21+
testImplementation("org.testcontainers:testcontainers")
22+
testImplementation("redis.clients:jedis")
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2012-2023 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 smoketest.data.redis;
18+
19+
import org.springframework.data.annotation.Id;
20+
import org.springframework.data.redis.core.RedisHash;
21+
22+
@RedisHash("persons")
23+
public class PersonHash {
24+
25+
@Id
26+
private String id;
27+
28+
private String description;
29+
30+
public String getId() {
31+
return this.id;
32+
}
33+
34+
public void setId(String id) {
35+
this.id = id;
36+
}
37+
38+
public String getDescription() {
39+
return this.description;
40+
}
41+
42+
public void setDescription(String description) {
43+
this.description = description;
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2012-2023 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 smoketest.data.redis;
18+
19+
import org.springframework.boot.autoconfigure.SpringBootApplication;
20+
21+
@SpringBootApplication
22+
public class SampleRedisApplication {
23+
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2012-2023 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 smoketest.data.redis;
18+
19+
import org.springframework.data.repository.CrudRepository;
20+
21+
interface SampleRepository extends CrudRepository<PersonHash, String> {
22+
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2012-2023 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 smoketest.data.redis;
18+
19+
import java.nio.charset.Charset;
20+
import java.nio.charset.StandardCharsets;
21+
22+
import org.springframework.data.redis.connection.RedisConnection;
23+
import org.springframework.data.redis.core.RedisOperations;
24+
import org.springframework.stereotype.Service;
25+
26+
@Service
27+
public class SampleService {
28+
29+
private static final Charset CHARSET = StandardCharsets.UTF_8;
30+
31+
private final RedisOperations<Object, Object> operations;
32+
33+
public SampleService(RedisOperations<Object, Object> operations) {
34+
this.operations = operations;
35+
}
36+
37+
public boolean hasRecord(PersonHash personHash) {
38+
return this.operations.execute((RedisConnection connection) -> connection.keyCommands()
39+
.exists(("persons:" + personHash.getId()).getBytes(CHARSET)));
40+
}
41+
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright 2012-2023 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 smoketest.data.redis;
18+
19+
import java.nio.charset.Charset;
20+
import java.nio.charset.StandardCharsets;
21+
22+
import org.junit.jupiter.api.Test;
23+
import org.testcontainers.junit.jupiter.Container;
24+
import org.testcontainers.junit.jupiter.Testcontainers;
25+
26+
import org.springframework.beans.factory.annotation.Autowired;
27+
import org.springframework.boot.test.context.SpringBootTest;
28+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
29+
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
30+
import org.springframework.boot.testsupport.testcontainers.RedisContainer;
31+
import org.springframework.data.redis.core.RedisOperations;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
35+
/**
36+
* Smoke tests for Redis using Jedis with SSL.
37+
*
38+
* @author Scott Frederick
39+
*/
40+
@Testcontainers(disabledWithoutDocker = true)
41+
@ClassPathExclusions("lettuce-core-*.jar")
42+
@SpringBootTest(properties = { "spring.data.redis.ssl.bundle=client",
43+
"spring.ssl.bundle.pem.client.keystore.certificate=classpath:ssl/test-client.crt",
44+
"spring.ssl.bundle.pem.client.keystore.private-key=classpath:ssl/test-client.key",
45+
"spring.ssl.bundle.pem.client.truststore.certificate=classpath:ssl/test-ca.crt" })
46+
class SampleRedisApplicationJedisSslTests {
47+
48+
private static final Charset CHARSET = StandardCharsets.UTF_8;
49+
50+
@Container
51+
@ServiceConnection
52+
static RedisContainer redis = new SecureRedisContainer();
53+
54+
@Autowired
55+
private RedisOperations<Object, Object> operations;
56+
57+
@Autowired
58+
private SampleRepository exampleRepository;
59+
60+
@Test
61+
void testRepository() {
62+
PersonHash personHash = new PersonHash();
63+
personHash.setDescription("Look, new @DataRedisTest!");
64+
assertThat(personHash.getId()).isNull();
65+
PersonHash savedEntity = this.exampleRepository.save(personHash);
66+
assertThat(savedEntity.getId()).isNotNull();
67+
assertThat(this.operations
68+
.execute((org.springframework.data.redis.connection.RedisConnection connection) -> connection.keyCommands()
69+
.exists(("persons:" + savedEntity.getId()).getBytes(CHARSET))))
70+
.isTrue();
71+
this.exampleRepository.deleteAll();
72+
}
73+
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2012-2023 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 smoketest.data.redis;
18+
19+
import java.util.UUID;
20+
21+
import org.junit.jupiter.api.Test;
22+
import org.testcontainers.junit.jupiter.Container;
23+
import org.testcontainers.junit.jupiter.Testcontainers;
24+
import reactor.test.StepVerifier;
25+
26+
import org.springframework.beans.factory.annotation.Autowired;
27+
import org.springframework.boot.test.context.SpringBootTest;
28+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
29+
import org.springframework.boot.testsupport.testcontainers.RedisContainer;
30+
import org.springframework.data.redis.core.ReactiveRedisOperations;
31+
32+
/**
33+
* Smoke tests for Redis using reactive operations and SSL.
34+
*
35+
* @author Scott Frederick
36+
*/
37+
@Testcontainers(disabledWithoutDocker = true)
38+
@SpringBootTest(properties = { "spring.data.redis.ssl.bundle=client",
39+
"spring.ssl.bundle.pem.client.keystore.certificate=classpath:ssl/test-client.crt",
40+
"spring.ssl.bundle.pem.client.keystore.private-key=classpath:ssl/test-client.key",
41+
"spring.ssl.bundle.pem.client.truststore.certificate=classpath:ssl/test-ca.crt" })
42+
class SampleRedisApplicationReactiveSslTests {
43+
44+
@Container
45+
@ServiceConnection
46+
static RedisContainer redis = new SecureRedisContainer();
47+
48+
@Autowired
49+
private ReactiveRedisOperations<Object, Object> operations;
50+
51+
@Test
52+
void testRepository() {
53+
String id = UUID.randomUUID().toString();
54+
StepVerifier.create(this.operations.opsForValue().set(id, "Hello World"))
55+
.expectNext(Boolean.TRUE)
56+
.verifyComplete();
57+
StepVerifier.create(this.operations.opsForValue().get(id)).expectNext("Hello World").verifyComplete();
58+
StepVerifier.create(this.operations.execute((action) -> action.serverCommands().flushDb()))
59+
.expectNext("OK")
60+
.verifyComplete();
61+
}
62+
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2012-2023 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 smoketest.data.redis;
18+
19+
import java.nio.charset.Charset;
20+
import java.nio.charset.StandardCharsets;
21+
22+
import org.junit.jupiter.api.Test;
23+
import org.testcontainers.junit.jupiter.Container;
24+
import org.testcontainers.junit.jupiter.Testcontainers;
25+
26+
import org.springframework.beans.factory.annotation.Autowired;
27+
import org.springframework.boot.test.context.SpringBootTest;
28+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
29+
import org.springframework.boot.testsupport.testcontainers.RedisContainer;
30+
import org.springframework.data.redis.core.RedisOperations;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
34+
/**
35+
* Smoke tests for Redis with SSL.
36+
*
37+
* @author Scott Frederick
38+
*/
39+
@Testcontainers(disabledWithoutDocker = true)
40+
@SpringBootTest(properties = { "spring.data.redis.ssl.bundle=client",
41+
"spring.ssl.bundle.pem.client.keystore.certificate=classpath:ssl/test-client.crt",
42+
"spring.ssl.bundle.pem.client.keystore.private-key=classpath:ssl/test-client.key",
43+
"spring.ssl.bundle.pem.client.truststore.certificate=classpath:ssl/test-ca.crt" })
44+
class SampleRedisApplicationSslTests {
45+
46+
private static final Charset CHARSET = StandardCharsets.UTF_8;
47+
48+
@Container
49+
@ServiceConnection
50+
static RedisContainer redis = new SecureRedisContainer();
51+
52+
@Autowired
53+
private RedisOperations<Object, Object> operations;
54+
55+
@Autowired
56+
private SampleRepository exampleRepository;
57+
58+
@Test
59+
void testRepository() {
60+
PersonHash personHash = new PersonHash();
61+
personHash.setDescription("Look, new @DataRedisTest!");
62+
assertThat(personHash.getId()).isNull();
63+
PersonHash savedEntity = this.exampleRepository.save(personHash);
64+
assertThat(savedEntity.getId()).isNotNull();
65+
assertThat(this.operations
66+
.execute((org.springframework.data.redis.connection.RedisConnection connection) -> connection.keyCommands()
67+
.exists(("persons:" + savedEntity.getId()).getBytes(CHARSET))))
68+
.isTrue();
69+
this.exampleRepository.deleteAll();
70+
}
71+
72+
}

0 commit comments

Comments
 (0)