Reputation: 1903
I develop integration tests for my spring boot application, which works with Cassandra. I use CassandraTemplate
for communication with Cassandra.
I have the following config for the database src/test/resources/application.properties:
spring.data.cassandra.contact-points=cassandra-host
spring.data.cassandra.port=9042
To create Testcontainers
with Cassandra I try 2 ways:
1) https://niels.nu/blog/2017/spring-cassandra-integration-tests.html
@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = {ExampleApplication.class})
@ContextConfiguration(initializers = CounterIntegrationTestContainers.Initializer.class)
@EnableConfigurationProperties
public class CounterIntegrationTestContainers extends CounterIntegrationTest {
@ClassRule
public static GenericContainer cassandra =
new GenericContainer("cassandra:3")
.withExposedPorts(9042);
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
EnvironmentTestUtils.addEnvironment(
"testcontainers",
configurableApplicationContext.getEnvironment(),
"cassandra.host=" + cassandra.getContainerIpAddress(),
"cassandra.port=" + cassandra.getMappedPort(9042)
);
}
}
}
2) https://www.baeldung.com/spring-boot-testcontainers-integration-test - in this example we can see postgresql container, but I change it to Cassandra:
public class BaeldungPostgresqlContainer extends PostgreSQLContainer<BaeldungPostgresqlContainer> {
private static final String IMAGE_VERSION = "postgres:11.1";
private static BaeldungPostgresqlContainer container;
private BaeldungPostgresqlContainer() {
super(IMAGE_VERSION);
}
public static BaeldungPostgresqlContainer getInstance() {
if (container == null) {
container = new BaeldungPostgresqlContainer();
}
return container;
}
@Override
public void start() {
super.start();
System.setProperty("DB_URL", container.getJdbcUrl());
System.setProperty("DB_USERNAME", container.getUsername());
System.setProperty("DB_PASSWORD", container.getPassword());
}
@Override
public void stop() {
//do nothing, JVM handles shut down
}
}
So, I have a problem. When I start tests, I got cannot create CassandraTemplate
bean, because Cassandra server is not available. it seems, that Spring Data tries to health check Cassandra before creating of test bean of the database server.
Is there any way to use Testcontainers Cassandra with Spring Data for Apache Cassandra?
Upvotes: 6
Views: 5884
Reputation: 1903
It seems, that I can run tests with such class:
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(
initializers = CassandraTestPrjApplicationTests.Initializer.class
)
public class CassandraTestPrjApplicationTests {
@Test
public void contextLoads() {
}
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
GenericContainer<?> cassandra =
new GenericContainer<>("cassandra:3").withExposedPorts(9042);
cassandra.start();
TestPropertyValues.of(
"spring.data.cassandra.contact-points=" + cassandra.getContainerIpAddress(),
"spring.data.cassandra.port=" + cassandra.getMappedPort(9042)
).applyTo(applicationContext);
}
}
}
and here is my gradle.build:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-cassandra'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testCompile "org.testcontainers:testcontainers:1.12.0"
testCompile "org.testcontainers:cassandra:1.12.0"
}
Upvotes: 3
Reputation: 1850
Considering the first approach, I'd start with checking the container that is running during the test execution: docker ps
and see if it starts (i.e. docker daemon is up) and exposes the correct port.
Then try to telnet
to the corresponding host/port to make sure that service starts during the default 60 seconds timeout period.
It seems enough for the container to start, but if telnet
does not connect during this period, try to increase it like
new GenericContainer("cassandra:3")
.withExposedPorts(9042)
.withStartupTimeout(Duration.ofMinutes(2));
If the container exposes the correct port, but the test does not connect to it,
make sure you use the correct configuration parameters in your test. I see the usage of spring.data.cassandra.contact-points
, the example you've sent uses a bit different configuration, check if you the correct configuration parameter in your cluster initialization code (e.g. "${contact-points}"
instead of "${container.host}"
or vice versa).
One more option to check your integration test logic works as expected (and there's something wrong with testcontainers configuration) is to start Cassandra container and hardcode it's host and port before running the test.
Hope this helps.
Upvotes: 1
Reputation: 95
Can you share logs for the first try (with @ClassRule)? It looks pretty valid for me.
Maybe your test cassandra haven't managed to start? The default testcontainers timeout is 60 seconds for the container's first mapped network port to start listening. check the docs
Upvotes: 1