Skip to content

Commit e015209

Browse files
snicollmhalbritter
andcommitted
Polish "Upgrade to Testcontainers 1.20.2"
This commit review the original upgrade to retain compatiblity with the deprecated Cassandra and ConfluentKafka containers. This commit also fixes the SSL Cassandra tests. The new container uses a custom wait strategy that uses plain text and does not work with an SSL container. Closes gh-42670 Co-authored-by: Moritz Halbritter <[email protected]>
1 parent a7fb369 commit e015209

File tree

7 files changed

+336
-0
lines changed

7 files changed

+336
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2012-2024 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.boot.testcontainers.service.connection.cassandra;
18+
19+
import com.datastax.oss.driver.api.core.CqlSession;
20+
import org.junit.jupiter.api.Test;
21+
import org.testcontainers.containers.CassandraContainer;
22+
import org.testcontainers.junit.jupiter.Container;
23+
import org.testcontainers.junit.jupiter.Testcontainers;
24+
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
27+
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
28+
import org.springframework.boot.autoconfigure.cassandra.CassandraConnectionDetails;
29+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
30+
import org.springframework.boot.testsupport.container.TestImage;
31+
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
33+
34+
import static org.assertj.core.api.Assertions.assertThat;
35+
36+
/**
37+
* Tests for {@link DeprecatedCassandraContainerConnectionDetailsFactory}.
38+
*
39+
* @author Andy Wilkinson
40+
* @deprecated since 3.4.0 for removal in 3.6.0
41+
*/
42+
@SpringJUnitConfig
43+
@Testcontainers(disabledWithoutDocker = true)
44+
@Deprecated(since = "3.4.0", forRemoval = true)
45+
class DeprecatedCassandraContainerConnectionDetailsFactoryTests {
46+
47+
@Container
48+
@ServiceConnection
49+
static final CassandraContainer<?> cassandra = TestImage.container(CassandraContainer.class);
50+
51+
@Autowired(required = false)
52+
private CassandraConnectionDetails connectionDetails;
53+
54+
@Autowired
55+
private CqlSession cqlSession;
56+
57+
@Test
58+
void connectionCanBeMadeToCassandraContainer() {
59+
assertThat(this.connectionDetails).isNotNull();
60+
assertThat(this.cqlSession.getMetadata().getNodes()).hasSize(1);
61+
}
62+
63+
@Configuration(proxyBeanMethods = false)
64+
@ImportAutoConfiguration(CassandraAutoConfiguration.class)
65+
static class TestConfiguration {
66+
67+
}
68+
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2012-2024 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.boot.testcontainers.service.connection.kafka;
18+
19+
import java.time.Duration;
20+
import java.util.ArrayList;
21+
import java.util.List;
22+
23+
import org.awaitility.Awaitility;
24+
import org.junit.jupiter.api.Test;
25+
import org.testcontainers.containers.KafkaContainer;
26+
import org.testcontainers.junit.jupiter.Container;
27+
import org.testcontainers.junit.jupiter.Testcontainers;
28+
29+
import org.springframework.beans.factory.annotation.Autowired;
30+
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration;
32+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
33+
import org.springframework.boot.testsupport.container.TestImage;
34+
import org.springframework.context.annotation.Bean;
35+
import org.springframework.context.annotation.Configuration;
36+
import org.springframework.kafka.annotation.KafkaListener;
37+
import org.springframework.kafka.core.KafkaTemplate;
38+
import org.springframework.test.context.TestPropertySource;
39+
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
40+
41+
import static org.assertj.core.api.Assertions.assertThat;
42+
43+
/**
44+
* Tests for {@link DeprecatedConfluentKafkaContainerConnectionDetailsFactory}.
45+
*
46+
* @author Moritz Halbritter
47+
* @author Andy Wilkinson
48+
* @author Phillip Webb
49+
* @deprecated since 3.4.0 for removal in 3.6.0
50+
*/
51+
@SpringJUnitConfig
52+
@Testcontainers(disabledWithoutDocker = true)
53+
@TestPropertySource(properties = { "spring.kafka.consumer.group-id=test-group",
54+
"spring.kafka.consumer.auto-offset-reset=earliest" })
55+
@Deprecated(since = "3.4.0", forRemoval = true)
56+
class DeprecatedConfluentKafkaContainerConnectionDetailsFactoryIntegrationTests {
57+
58+
@Container
59+
@ServiceConnection
60+
static final KafkaContainer kafka = TestImage.container(KafkaContainer.class);
61+
62+
@Autowired
63+
private KafkaTemplate<String, String> kafkaTemplate;
64+
65+
@Autowired
66+
private TestListener listener;
67+
68+
@Test
69+
void connectionCanBeMadeToKafkaContainer() {
70+
this.kafkaTemplate.send("test-topic", "test-data");
71+
Awaitility.waitAtMost(Duration.ofMinutes(4))
72+
.untilAsserted(() -> assertThat(this.listener.messages).containsExactly("test-data"));
73+
}
74+
75+
@Configuration(proxyBeanMethods = false)
76+
@ImportAutoConfiguration(KafkaAutoConfiguration.class)
77+
static class TestConfiguration {
78+
79+
@Bean
80+
TestListener testListener() {
81+
return new TestListener();
82+
}
83+
84+
}
85+
86+
static class TestListener {
87+
88+
private final List<String> messages = new ArrayList<>();
89+
90+
@KafkaListener(topics = "test-topic")
91+
void processMessage(String message) {
92+
this.messages.add(message);
93+
}
94+
95+
}
96+
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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 org.springframework.boot.testcontainers.service.connection.cassandra;
18+
19+
import java.net.InetSocketAddress;
20+
import java.util.List;
21+
22+
import org.testcontainers.containers.CassandraContainer;
23+
24+
import org.springframework.boot.autoconfigure.cassandra.CassandraConnectionDetails;
25+
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
26+
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
27+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
28+
29+
/**
30+
* {@link ContainerConnectionDetailsFactory} to create {@link CassandraConnectionDetails}
31+
* from a {@link ServiceConnection @ServiceConnection}-annotated
32+
* {@link CassandraContainer}.
33+
*
34+
* @author Moritz Halbritter
35+
* @author Andy Wilkinson
36+
* @author Phillip Webb
37+
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of
38+
* {@link CassandraContainerConnectionDetailsFactory}.
39+
*/
40+
@Deprecated(since = "3.4.0", forRemoval = true)
41+
class DeprecatedCassandraContainerConnectionDetailsFactory
42+
extends ContainerConnectionDetailsFactory<CassandraContainer<?>, CassandraConnectionDetails> {
43+
44+
@Override
45+
protected CassandraConnectionDetails getContainerConnectionDetails(
46+
ContainerConnectionSource<CassandraContainer<?>> source) {
47+
return new CassandraContainerConnectionDetails(source);
48+
}
49+
50+
/**
51+
* {@link CassandraConnectionDetails} backed by a {@link ContainerConnectionSource}.
52+
*/
53+
private static final class CassandraContainerConnectionDetails
54+
extends ContainerConnectionDetails<CassandraContainer<?>> implements CassandraConnectionDetails {
55+
56+
private CassandraContainerConnectionDetails(ContainerConnectionSource<CassandraContainer<?>> source) {
57+
super(source);
58+
}
59+
60+
@Override
61+
public List<Node> getContactPoints() {
62+
InetSocketAddress contactPoint = getContainer().getContactPoint();
63+
return List.of(new Node(contactPoint.getHostString(), contactPoint.getPort()));
64+
}
65+
66+
@Override
67+
public String getUsername() {
68+
return getContainer().getUsername();
69+
}
70+
71+
@Override
72+
public String getPassword() {
73+
return getContainer().getPassword();
74+
}
75+
76+
@Override
77+
public String getLocalDatacenter() {
78+
return getContainer().getLocalDatacenter();
79+
}
80+
81+
}
82+
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright 2012-2024 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.boot.testcontainers.service.connection.kafka;
18+
19+
import java.util.List;
20+
21+
import org.testcontainers.containers.KafkaContainer;
22+
23+
import org.springframework.boot.autoconfigure.kafka.KafkaConnectionDetails;
24+
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory;
25+
import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource;
26+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
27+
28+
/**
29+
* {@link ContainerConnectionDetailsFactory} to create {@link KafkaConnectionDetails} from
30+
* a {@link ServiceConnection @ServiceConnection}-annotated {@link KafkaContainer}.
31+
*
32+
* @author Moritz Halbritter
33+
* @author Andy Wilkinson
34+
* @author Phillip Webb
35+
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of
36+
* {@link ConfluentKafkaContainerConnectionDetailsFactory}.
37+
*/
38+
@Deprecated(since = "3.4.0", forRemoval = true)
39+
class DeprecatedConfluentKafkaContainerConnectionDetailsFactory
40+
extends ContainerConnectionDetailsFactory<KafkaContainer, KafkaConnectionDetails> {
41+
42+
@Override
43+
protected KafkaConnectionDetails getContainerConnectionDetails(ContainerConnectionSource<KafkaContainer> source) {
44+
return new ConfluentKafkaContainerConnectionDetails(source);
45+
}
46+
47+
/**
48+
* {@link KafkaConnectionDetails} backed by a {@link ContainerConnectionSource}.
49+
*/
50+
private static final class ConfluentKafkaContainerConnectionDetails
51+
extends ContainerConnectionDetails<KafkaContainer> implements KafkaConnectionDetails {
52+
53+
private ConfluentKafkaContainerConnectionDetails(ContainerConnectionSource<KafkaContainer> source) {
54+
super(source);
55+
}
56+
57+
@Override
58+
public List<String> getBootstrapServers() {
59+
return List.of(getContainer().getBootstrapServers());
60+
}
61+
62+
}
63+
64+
}

spring-boot-project/spring-boot-testcontainers/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ org.springframework.boot.testcontainers.service.connection.activemq.ActiveMQCont
1313
org.springframework.boot.testcontainers.service.connection.activemq.ArtemisContainerConnectionDetailsFactory,\
1414
org.springframework.boot.testcontainers.service.connection.amqp.RabbitContainerConnectionDetailsFactory,\
1515
org.springframework.boot.testcontainers.service.connection.cassandra.CassandraContainerConnectionDetailsFactory,\
16+
org.springframework.boot.testcontainers.service.connection.cassandra.DeprecatedCassandraContainerConnectionDetailsFactory,\
1617
org.springframework.boot.testcontainers.service.connection.couchbase.CouchbaseContainerConnectionDetailsFactory,\
1718
org.springframework.boot.testcontainers.service.connection.elasticsearch.ElasticsearchContainerConnectionDetailsFactory,\
1819
org.springframework.boot.testcontainers.service.connection.flyway.FlywayContainerConnectionDetailsFactory,\
1920
org.springframework.boot.testcontainers.service.connection.hazelcast.HazelcastContainerConnectionDetailsFactory,\
2021
org.springframework.boot.testcontainers.service.connection.jdbc.JdbcContainerConnectionDetailsFactory,\
2122
org.springframework.boot.testcontainers.service.connection.kafka.ApacheKafkaContainerConnectionDetailsFactory,\
2223
org.springframework.boot.testcontainers.service.connection.kafka.ConfluentKafkaContainerConnectionDetailsFactory,\
24+
org.springframework.boot.testcontainers.service.connection.kafka.DeprecatedConfluentKafkaContainerConnectionDetailsFactory,\
2325
org.springframework.boot.testcontainers.service.connection.ldap.OpenLdapContainerConnectionDetailsFactory,\
2426
org.springframework.boot.testcontainers.service.connection.liquibase.LiquibaseContainerConnectionDetailsFactory,\
2527
org.springframework.boot.testcontainers.service.connection.mongo.MongoContainerConnectionDetailsFactory,\

spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,16 @@ public enum TestImage {
8383
CASSANDRA("cassandra", "3.11.10", () -> CassandraContainer.class,
8484
(container) -> ((CassandraContainer) container).withStartupTimeout(Duration.ofMinutes(10))),
8585

86+
/**
87+
* A container image suitable for testing Cassandra using the deprecated
88+
* {@link org.testcontainers.containers.CassandraContainer}.
89+
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of {@link #CASSANDRA}
90+
*/
91+
@Deprecated(since = "3.4.0", forRemoval = true)
92+
CASSANDRA_DEPRECATED("cassandra", "3.11.10", () -> org.testcontainers.containers.CassandraContainer.class,
93+
(container) -> ((org.testcontainers.containers.CassandraContainer<?>) container)
94+
.withStartupTimeout(Duration.ofMinutes(10))),
95+
8696
/**
8797
* A container image suitable for testing Couchbase.
8898
*/
@@ -119,6 +129,15 @@ public enum TestImage {
119129
*/
120130
CONFLUENT_KAFKA("confluentinc/cp-kafka", "7.4.0", () -> ConfluentKafkaContainer.class),
121131

132+
/**
133+
* A container image suitable for testing Confluent's distribution of Kafka using the
134+
* deprecated {@link org.testcontainers.containers.KafkaContainer}.
135+
* @deprecated since 3.4.0 for removal in 3.6.0 in favor of {@link #CONFLUENT_KAFKA}
136+
*/
137+
@Deprecated(since = "3.4.0", forRemoval = true)
138+
CONFLUENT_KAFKA_DEPRECATED("confluentinc/cp-kafka", "7.4.0",
139+
() -> org.testcontainers.containers.KafkaContainer.class),
140+
122141
/**
123142
* A container image suitable for testing OpenLDAP.
124143
*/

spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-cassandra/src/dockerTest/java/smoketest/data/cassandra/SecureCassandraContainer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package smoketest.data.cassandra;
1818

1919
import org.testcontainers.cassandra.CassandraContainer;
20+
import org.testcontainers.containers.wait.strategy.Wait;
2021
import org.testcontainers.utility.DockerImageName;
2122
import org.testcontainers.utility.MountableFile;
2223

@@ -29,6 +30,7 @@ class SecureCassandraContainer extends CassandraContainer {
2930

3031
SecureCassandraContainer(DockerImageName dockerImageName) {
3132
super(dockerImageName);
33+
setWaitStrategy(Wait.defaultWaitStrategy()); // default strategy uses plain text
3234
withCopyFileToContainer(MountableFile.forClasspathResource("/ssl/cassandra.yaml"),
3335
"/etc/cassandra/cassandra.yaml");
3436
withCopyFileToContainer(MountableFile.forClasspathResource("/ssl/test-server.p12"),

0 commit comments

Comments
 (0)