diff --git a/modules/cassandra/build.gradle b/modules/cassandra/build.gradle
index 9704a05b69d..8284fec8b72 100644
--- a/modules/cassandra/build.gradle
+++ b/modules/cassandra/build.gradle
@@ -1,6 +1,6 @@
description = "TestContainers :: Cassandra"
dependencies {
- compile project(":database-commons")
+ compile project(":jdbc")
compile "com.datastax.cassandra:cassandra-driver-core:3.7.1"
}
diff --git a/modules/cassandra/pom.xml b/modules/cassandra/pom.xml
new file mode 100644
index 00000000000..2f939f2810b
--- /dev/null
+++ b/modules/cassandra/pom.xml
@@ -0,0 +1,94 @@
+
+
+ 4.0.0
+ org.testcontainers
+ cassandra-2179
+ pr-2179
+ jar
+
+ cassandra
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.6.0
+
+ true
+ 256m
+ 1024m
+
+ 1.8
+ UTF-8
+
+
+
+
+
+
+ 1.12.3
+ 3.8.0
+
+
+
+
+
+ org.testcontainers
+ testcontainers-bom
+ ${testcontainers.version}
+ import
+ pom
+
+
+
+
+
+
+
+ org.testcontainers
+ database-commons
+
+
+ org.testcontainers
+ jdbc
+
+
+ commons-io
+ commons-io
+ 2.6
+
+
+ org.projectlombok
+ lombok
+ 1.18.8
+
+
+ org.rnorth.duct-tape
+ duct-tape
+ 1.0.7
+
+
+ com.datastax.cassandra
+ cassandra-driver-core
+ ${datastax.version}
+
+
+ com.datastax.cassandra
+ cassandra-driver-mapping
+ ${datastax.version}
+
+
+ com.datastax.cassandra
+ cassandra-driver-extras
+ ${datastax.version}
+
+
+
+ com.github.adejanovski
+ cassandra-jdbc-wrapper
+ 3.1.0
+ test
+
+
+
diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java
index a78d23e4b4b..29fbfaed143 100644
--- a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java
+++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainer.java
@@ -22,32 +22,53 @@
*
* @author Eugeny Karpov
*/
-public class CassandraContainer> extends GenericContainer {
+public class CassandraContainer> extends JdbcDatabaseContainer {
- public static final String IMAGE = "cassandra";
+ public static final String NAME = "cassandra";
public static final Integer CQL_PORT = 9042;
+ public static final Integer THRIFT_PORT = 9160;
+ public static final Integer JMX_PORT = 7199;
private static final String CONTAINER_CONFIG_LOCATION = "/etc/cassandra";
private static final String USERNAME = "cassandra";
private static final String PASSWORD = "cassandra";
+ private static final String DEFAULT_DRIVER_CLASSNAME = "com.github.adejanovski.cassandra.jdbc.CassandraDriver";
+
+ public static final String IMAGE = "cassandra";
+ public static final String DEFAULT_TAG = "3.11.2";
private String configLocation;
private String initScriptPath;
+ private boolean enableNativeAPI;
private boolean enableJmxReporting;
+ private String driverClassname = DEFAULT_DRIVER_CLASSNAME;
public CassandraContainer() {
- this(IMAGE + ":3.11.2");
+ this(IMAGE + ":" + DEFAULT_TAG);
}
public CassandraContainer(String dockerImageName) {
super(dockerImageName);
addExposedPort(CQL_PORT);
setStartupAttempts(3);
+ this.enableNativeAPI = false;
this.enableJmxReporting = false;
}
+ @Override
+ protected Integer getLivenessCheckPort() {
+ return getMappedPort(CQL_PORT);
+ }
+
@Override
protected void configure() {
optionallyMapResourceParameterAsVolume(CONTAINER_CONFIG_LOCATION, configLocation);
+ if (enableNativeAPI) {
+ addExposedPort(THRIFT_PORT);
+ addEnv("CASSANDRA_START_RPC", "true");
+ }
+ if (enableJmxReporting) {
+ addExposedPort(JMX_PORT);
+ }
}
@Override
@@ -58,7 +79,7 @@ protected void containerIsStarted(InspectContainerResponse containerInfo) {
/**
* Load init script content and apply it to the database if initScriptPath is set
*/
- private void runInitScriptIfRequired() {
+ protected void runInitScriptIfRequired() {
if (initScriptPath != null) {
try {
URL resource = Thread.currentThread().getContextClassLoader().getResource(initScriptPath);
@@ -118,6 +139,24 @@ public SELF withInitScript(String initScriptPath) {
return self();
}
+ /**
+ * Initialize Cassandra with Native support (via thrift over RPC) with default driver classname.
+ * This is usually required for JDBC access.
+ */
+ public SELF withNativeAPI(boolean enableNativeAPI) {
+ return withNativeAPI(enableNativeAPI, DEFAULT_DRIVER_CLASSNAME);
+ }
+
+ /**
+ * Initialize Cassandra with Native support (via thrift over RPC) using specified driver classname.
+ * This is usually required for JDBC access.
+ */
+ public SELF withNativeAPI(boolean enableNativeAPI, String driverClassname) {
+ this.enableNativeAPI = enableNativeAPI;
+ this.driverClassname = driverClassname;
+ return self();
+ }
+
/**
* Initialize Cassandra client with JMX reporting enabled or disabled
*/
@@ -150,6 +189,64 @@ public String getPassword() {
return PASSWORD;
}
+ /**
+ * Get recommended driver classname.
+ */
+ @Override
+ public String getDriverClassName() {
+ return driverClassname;
+ }
+
+ /**
+ * Get JDBC URL
+ *
+ * Returns appropriate JDBC URL if JDBC support is enabled. Otherwise throws UnsupportedOperationException.
+ * If a keyspace is used it should be appended to the URL.
+ */
+ @Override
+ public String getJdbcUrl() {
+ if (enableNativeAPI) {
+ return "jdbc:cassandra://" + getContainerIpAddress() + ":" + getMappedPort(THRIFT_PORT);
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Gets SQL query that can be used to verify the server is up. This query returns
+ * the server release version.
+ */
+ @Override
+ protected String getTestQueryString() {
+ return "SELECT release_version FROM system.local";
+ }
+
+ /**
+ * Get mapped JQL port.
+ *
+ * @return
+ */
+ public int getCqlPort() {
+ return getMappedPort(CQL_PORT);
+ }
+
+ /**
+ * Get mapped Native (thrift-over-RPC) port. This is used by most JDBC driver implementations.
+ *
+ * @return thrift port, or -1 if NativeAPI is not enabled
+ */
+ public int getNativePort() {
+ return enableNativeAPI ? getMappedPort(THRIFT_PORT) : -1;
+ }
+
+ /**
+ * Get mapped JMX port.
+ *
+ * @return jmx port, or -1 if JMX is not enabled
+ */
+ public int getJmxPort() {
+ return enableJmxReporting ? getMappedPort(JMX_PORT) : -1;
+ }
+
/**
* Get configured Cluster
*
@@ -173,7 +270,15 @@ public static Cluster getCluster(ContainerState containerState) {
return getCluster(containerState, false);
}
- private DatabaseDelegate getDatabaseDelegate() {
+ /**
+ * Close down server. This has no effect.
+ */
+ @Override
+ public void close() {
+ // no-op
+ }
+
+ protected DatabaseDelegate getDatabaseDelegate() {
return new CassandraDatabaseDelegate(this);
}
}
diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainerProvider.java b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainerProvider.java
new file mode 100644
index 00000000000..3d3653f7002
--- /dev/null
+++ b/modules/cassandra/src/main/java/org/testcontainers/containers/CassandraContainerProvider.java
@@ -0,0 +1,24 @@
+package org.testcontainers.containers;
+
+import org.testcontainers.containers.JdbcDatabaseContainer;
+import org.testcontainers.containers.JdbcDatabaseContainerProvider;
+
+/**
+ * Implementation of JdbcDatabaseContainerProvider for Cassandra.
+ */
+public class CassandraContainerProvider extends JdbcDatabaseContainerProvider {
+ @Override
+ public boolean supports(String databaseType) {
+ return databaseType.equals(CassandraContainer.NAME);
+ }
+
+ @Override
+ public JdbcDatabaseContainer newInstance() {
+ return newInstance(CassandraContainer.DEFAULT_TAG);
+ }
+
+ @Override
+ public JdbcDatabaseContainer newInstance(String tag) {
+ return new CassandraContainer(CassandraContainer.IMAGE + ":" + tag);
+ }
+}
diff --git a/modules/cassandra/src/main/java/org/testcontainers/containers/delegate/CassandraDatabaseDelegate.java b/modules/cassandra/src/main/java/org/testcontainers/containers/delegate/CassandraDatabaseDelegate.java
index e55dd31b0ff..324812eb8d2 100644
--- a/modules/cassandra/src/main/java/org/testcontainers/containers/delegate/CassandraDatabaseDelegate.java
+++ b/modules/cassandra/src/main/java/org/testcontainers/containers/delegate/CassandraDatabaseDelegate.java
@@ -5,6 +5,7 @@
import com.datastax.driver.core.exceptions.DriverException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+
import org.testcontainers.containers.CassandraContainer;
import org.testcontainers.containers.ContainerState;
import org.testcontainers.delegate.AbstractDatabaseDelegate;
diff --git a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java
index 6105aa275c9..080ab1f79d5 100644
--- a/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java
+++ b/modules/cassandra/src/test/java/org/testcontainers/containers/CassandraContainerTest.java
@@ -6,10 +6,19 @@
import com.datastax.driver.core.Session;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
+import org.testcontainers.containers.output.OutputFrame;
import org.testcontainers.containers.wait.CassandraQueryWaitStrategy;
+import org.testcontainers.containers.wait.strategy.HostPortWaitStrategy;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.time.Duration;
import static org.junit.Assert.*;
+import static java.time.temporal.ChronoUnit.SECONDS;
+
/**
* @author Eugeny Karpov
*/
@@ -106,6 +115,23 @@ public void testCassandraGetCluster() {
}
}
+ @Test
+ public void testCassandraJdbcQuery() throws SQLException {
+ try (CassandraContainer cassandraContainer = new CassandraContainer<>().withNativeAPI(true)) {
+ cassandraContainer.withLogConsumer(obj -> System.out.println(((OutputFrame) obj).getUtf8String().trim()));
+ // this doesn't seem to have any effect
+ //cassandraContainer.setWaitStrategy(new HostPortWaitStrategy().withStartupTimeout(Duration.of(90, SECONDS)));
+ cassandraContainer.setWaitStrategy(new CassandraQueryWaitStrategy());
+ cassandraContainer.start();
+ try (Connection conn = cassandraContainer.createConnection("");
+ Statement stmt = conn.createStatement();
+ java.sql.ResultSet rs = stmt.executeQuery("SELECT release_version FROM system.local")) {
+ assertTrue("no records found", rs.next());
+ assertEquals("Result set has no release_version", cassandraContainer.DEFAULT_TAG, rs.getString("release_version"));
+ }
+ }
+ }
+
private void testInitScript(CassandraContainer cassandraContainer) {
ResultSet resultSet = performQuery(cassandraContainer, "SELECT * FROM keySpaceTest.catalog_category");
assertTrue("Query was not applied", resultSet.wasApplied());