Testcontainers implementation for Apache Cassandra, providing lightweight, throwaway database instances for Java integration testing
Advanced wait strategies and database operation delegation for ensuring container readiness and executing database operations.
Custom wait strategy that ensures Cassandra is ready to accept CQL queries before considering the container ready for use.
/**
* Waits until Cassandra returns its version by executing a query.
* This strategy ensures the database is not only running but ready to process CQL queries.
*/
public class CassandraQueryWaitStrategy extends AbstractWaitStrategy {
/**
* Wait until Cassandra is ready by executing version query.
* Executes "SELECT release_version FROM system.local" until success or timeout.
*/
protected void waitUntilReady();
}Usage Examples:
import org.testcontainers.cassandra.CassandraContainer;
import org.testcontainers.cassandra.wait.CassandraQueryWaitStrategy;
// The CassandraContainer uses CassandraQueryWaitStrategy by default
CassandraContainer cassandra = new CassandraContainer("cassandra:3.11.2");
// No need to explicitly set wait strategy - it's automatic
// Manual wait strategy configuration (if needed for customization)
CassandraContainer cassandra = new CassandraContainer("cassandra:3.11.2")
.waitingFor(new CassandraQueryWaitStrategy());Wait Strategy Process:
Timeout Configuration:
// Custom timeout (inherits from AbstractWaitStrategy)
CassandraContainer cassandra = new CassandraContainer("cassandra:3.11.2")
.waitingFor(new CassandraQueryWaitStrategy()
.withStartupTimeout(Duration.ofMinutes(5)));Database delegate that handles CQL script and statement execution via the cqlsh command inside the container.
/**
* Cassandra database delegate for executing CQL statements and scripts.
* Uses cqlsh command directly inside the container for maximum compatibility.
*/
public class CassandraDatabaseDelegate extends AbstractDatabaseDelegate<Void> {
/**
* Create database delegate for the given container
* @param container Container state for accessing the running container
*/
public CassandraDatabaseDelegate(ContainerState container);
/**
* Execute CQL statement or script file
* @param statement CQL statement to execute (if not null/empty)
* @param scriptPath Path to script file inside container (if statement is null/empty)
* @param lineNumber Line number for error reporting
* @param continueOnError Whether to continue execution on error
* @param ignoreFailedDrops Whether to ignore failed DROP statements
*/
public void execute(
String statement,
String scriptPath,
int lineNumber,
boolean continueOnError,
boolean ignoreFailedDrops
);
}Internal Usage:
The database delegate is primarily used internally by the container for:
withInitScript()Execution Methods:
// Statement execution (used internally)
delegate.execute("CREATE KEYSPACE test WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1}",
null, 1, false, false);
// Script file execution (used internally)
delegate.execute(null, "/tmp/init.cql", -1, false, false);Command Generation:
The delegate constructs cqlsh commands based on container configuration:
# Basic command
cqlsh -e "SELECT release_version FROM system.local"
# With authentication (when container has auth enabled)
cqlsh -u cassandra -p cassandra -e "SELECT release_version FROM system.local"
# Script file execution
cqlsh -f /tmp/init.cql
# With authentication for script
cqlsh -u cassandra -p cassandra -f /tmp/init.cqlBoth wait strategies and database delegates handle various error conditions:
Wait Strategy Errors:
import org.testcontainers.containers.ContainerLaunchException;
try {
cassandra.start();
} catch (ContainerLaunchException e) {
// Wait strategy timeout or query execution failure
if (e.getMessage().contains("Timed out waiting for Cassandra")) {
logger.error("Cassandra failed to become ready within timeout", e);
}
}Database Delegate Errors:
import org.testcontainers.ext.ScriptUtils.ScriptStatementFailedException;
// These exceptions are thrown internally and propagated through container methods
try {
cassandra.withInitScript("invalid-script.cql").start();
} catch (ScriptStatementFailedException e) {
logger.error("CQL script execution failed at line " + e.getLineNumber(), e);
}For advanced use cases, you can extend the wait strategy:
import org.testcontainers.cassandra.wait.CassandraQueryWaitStrategy;
public class CustomCassandraWaitStrategy extends CassandraQueryWaitStrategy {
@Override
protected void waitUntilReady() {
// Custom readiness logic
super.waitUntilReady(); // Execute standard version query
// Additional custom checks
DatabaseDelegate delegate = new CassandraDatabaseDelegate(waitStrategyTarget);
delegate.execute("SELECT COUNT(*) FROM system.peers", "", 1, false, false);
}
}
// Usage
CassandraContainer cassandra = new CassandraContainer("cassandra:3.11.2")
.waitingFor(new CustomCassandraWaitStrategy());Legacy implementations in the org.testcontainers.containers package are deprecated:
/**
* @deprecated use org.testcontainers.cassandra.wait.CassandraQueryWaitStrategy instead
*/
@Deprecated
public class CassandraQueryWaitStrategy extends AbstractWaitStrategy {
protected void waitUntilReady();
}
/**
* @deprecated use org.testcontainers.cassandra.delegate.CassandraDatabaseDelegate instead
*/
@Deprecated
public class CassandraDatabaseDelegate extends AbstractDatabaseDelegate<Session> {
public CassandraDatabaseDelegate(ContainerState container);
public void execute(String statement, String scriptPath, int lineNumber,
boolean continueOnError, boolean ignoreFailedDrops);
}Key Differences:
Void connection typeThe current implementation is more robust and doesn't require specific driver versions, making it more suitable for diverse testing environments.
Install with Tessl CLI
npx tessl i tessl/maven-org-testcontainers--cassandra