-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
636 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ body: | |
- QuestDB | ||
- RabbitMQ | ||
- Redpanda | ||
- ScyllaDB | ||
- Selenium | ||
- Solace | ||
- Solr | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ body: | |
- QuestDB | ||
- RabbitMQ | ||
- Redpanda | ||
- ScyllaDB | ||
- Selenium | ||
- Solace | ||
- Solr | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,6 +47,7 @@ body: | |
- Pulsar | ||
- RabbitMQ | ||
- Redpanda | ||
- ScyllaDB | ||
- Selenium | ||
- Solace | ||
- Solr | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# ScyllaDB Module | ||
|
||
## Usage example | ||
|
||
This example connects to the ScyllaDB Cluster, creates a keyspaces and asserts that is has been created. | ||
|
||
<!--codeinclude--> | ||
[Building CqlSession](../../../modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBDriver4Test.java) inside_block:scylladb | ||
<!--/codeinclude--> | ||
|
||
## Adding this module to your project dependencies | ||
|
||
Add the following dependency to your `pom.xml`/`build.gradle` file: | ||
|
||
=== "Gradle" | ||
```groovy | ||
testImplementation "org.testcontainers:scylladb:{{latest_version}}" | ||
``` | ||
|
||
=== "Maven" | ||
```xml | ||
<dependency> | ||
<groupId>org.testcontainers</groupId> | ||
<artifactId>scylladb</artifactId> | ||
<version>{{latest_version}}</version> | ||
<scope>test</scope> | ||
</dependency> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
description = "Testcontainers :: ScyllaDB" | ||
|
||
configurations.all { | ||
resolutionStrategy { | ||
force 'io.dropwizard.metrics:metrics-core:3.2.6' | ||
} | ||
} | ||
|
||
dependencies { | ||
api project(":database-commons") | ||
api "com.scylladb:java-driver-core:4.15.0.0" | ||
api "com.datastax.cassandra:cassandra-driver-core:3.10.0" | ||
|
||
// testImplementation 'com.datastax.oss:java-driver-core:4.17.0' | ||
testImplementation 'org.assertj:assertj-core:3.24.2' | ||
} |
194 changes: 194 additions & 0 deletions
194
modules/scylladb/src/main/java/org/testcontainers/containers/ScyllaDBContainer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
package org.testcontainers.containers; | ||
|
||
import com.github.dockerjava.api.command.InspectContainerResponse; | ||
import org.apache.commons.io.IOUtils; | ||
import org.testcontainers.containers.delegate.ScyllaDBDatabaseDelegate; | ||
import org.testcontainers.delegate.DatabaseDelegate; | ||
import org.testcontainers.ext.ScriptUtils; | ||
import org.testcontainers.ext.ScriptUtils.ScriptLoadException; | ||
import org.testcontainers.utility.DockerImageName; | ||
import org.testcontainers.utility.MountableFile; | ||
|
||
import java.io.IOException; | ||
import java.net.InetSocketAddress; | ||
import java.net.URL; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.Optional; | ||
|
||
import javax.script.ScriptException; | ||
|
||
/** | ||
* Testcontainers implementation for ScyllaDB. | ||
* <p> | ||
* Supported image: {@code scylladb} | ||
* <p> | ||
* Exposed ports: 9042 | ||
*/ | ||
public class ScyllaDBContainer<SELF extends ScyllaDBContainer<SELF>> extends GenericContainer<SELF> { | ||
|
||
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("scylladb/scylla:5.2.9"); | ||
|
||
public static final Integer CQL_PORT = 9042; | ||
|
||
private static final String DEFAULT_LOCAL_DATACENTER = "datacenter1"; | ||
|
||
private static final String CONTAINER_CONFIG_LOCATION = "/etc/scylla"; | ||
|
||
private static final String USERNAME = "scylladb"; | ||
|
||
private static final String PASSWORD = "scylladb"; | ||
|
||
private String configLocation; | ||
|
||
private String initScriptPath; | ||
|
||
private boolean enableJmxReporting; | ||
|
||
public ScyllaDBContainer(String dockerImageName) { | ||
this(DockerImageName.parse(dockerImageName)); | ||
} | ||
|
||
public ScyllaDBContainer(DockerImageName dockerImageName) { | ||
super(dockerImageName); | ||
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME); | ||
|
||
addExposedPort(CQL_PORT); | ||
this.enableJmxReporting = false; | ||
|
||
withEnv("CASSANDRA_SNITCH", "GossipingPropertyFileSnitch"); | ||
withEnv("JVM_OPTS", "-Dcassandra.skip_wait_for_gossip_to_settle=0 -Dcassandra.initial_token=0"); | ||
withEnv("HEAP_NEWSIZE", "128M"); | ||
withEnv("MAX_HEAP_SIZE", "1024M"); | ||
withEnv("CASSANDRA_ENDPOINT_SNITCH", "GossipingPropertyFileSnitch"); | ||
withEnv("CASSANDRA_DC", DEFAULT_LOCAL_DATACENTER); | ||
} | ||
|
||
@Override | ||
protected void configure() { | ||
optionallyMapResourceParameterAsVolume(CONTAINER_CONFIG_LOCATION, configLocation); | ||
} | ||
|
||
@Override | ||
protected void containerIsStarted(InspectContainerResponse containerInfo) { | ||
runInitScriptIfRequired(); | ||
} | ||
|
||
/** | ||
* Load init script content and apply it to the database if initScriptPath is set | ||
*/ | ||
private void runInitScriptIfRequired() { | ||
if (initScriptPath != null) { | ||
try { | ||
URL resource = Thread.currentThread().getContextClassLoader().getResource(initScriptPath); | ||
if (resource == null) { | ||
logger().warn("Could not load classpath init script: {}", initScriptPath); | ||
throw new ScriptLoadException( | ||
"Could not load classpath init script: " + initScriptPath + ". Resource not found." | ||
); | ||
} | ||
String cql = IOUtils.toString(resource, StandardCharsets.UTF_8); | ||
DatabaseDelegate databaseDelegate = new ScyllaDBDatabaseDelegate(this); | ||
ScriptUtils.executeDatabaseScript(databaseDelegate, initScriptPath, cql); | ||
} catch (IOException e) { | ||
logger().warn("Could not load classpath init script: {}", initScriptPath); | ||
throw new ScriptLoadException("Could not load classpath init script: " + initScriptPath, e); | ||
} catch (ScriptException e) { | ||
logger().error("Error while executing init script: {}", initScriptPath, e); | ||
throw new ScriptUtils.UncategorizedScriptException( | ||
"Error while executing init script: " + initScriptPath, | ||
e | ||
); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Map (effectively replace) directory in Docker with the content of resourceLocation if resource location is not null | ||
* | ||
* Protected to allow for changing implementation by extending the class | ||
* | ||
* @param pathNameInContainer path in docker | ||
* @param resourceLocation relative classpath to resource | ||
*/ | ||
protected void optionallyMapResourceParameterAsVolume(String pathNameInContainer, String resourceLocation) { | ||
Optional | ||
.ofNullable(resourceLocation) | ||
.map(MountableFile::forClasspathResource) | ||
.ifPresent(mountableFile -> withCopyFileToContainer(mountableFile, pathNameInContainer)); | ||
} | ||
|
||
/** | ||
* Initialize ScyllaDB with the custom overridden ScyllaDB configuration | ||
* <p> | ||
* Be aware, that Docker effectively replaces all /etc/sylladb content with the content of config location, so if | ||
* scylladb.yaml in configLocation is absent or corrupted, then ScyllaDB just won't launch | ||
* | ||
* @param configLocation relative classpath with the directory that contains cassandra.yaml and other configuration files | ||
*/ | ||
public SELF withConfigurationOverride(String configLocation) { | ||
this.configLocation = configLocation; | ||
return self(); | ||
} | ||
|
||
/** | ||
* Initialize ScyllaDB with init CQL script | ||
* <p> | ||
* CQL script will be applied after container is started (see using WaitStrategy) | ||
* | ||
* @param initScriptPath relative classpath resource | ||
*/ | ||
public SELF withInitScript(String initScriptPath) { | ||
this.initScriptPath = initScriptPath; | ||
return self(); | ||
} | ||
|
||
/** | ||
* Initialize ScyllaDB client with JMX reporting enabled or disabled | ||
*/ | ||
public SELF withJmxReporting(boolean enableJmxReporting) { | ||
this.enableJmxReporting = enableJmxReporting; | ||
return self(); | ||
} | ||
|
||
/** | ||
* Get username | ||
* | ||
* By default ScyllaDB has authenticator: AllowAllAuthenticator in scylladb.yaml | ||
* If username and password need to be used, then authenticator should be set as PasswordAuthenticator | ||
* (through custom ScyllaDB configuration) and through CQL with default scylladb-scylladb credentials | ||
* user management should be modified | ||
*/ | ||
public String getUsername() { | ||
return USERNAME; | ||
} | ||
|
||
/** | ||
* Get password | ||
* | ||
* By default ScyllaDB has authenticator: AllowAllAuthenticator in scylladb.yaml | ||
* If username and password need to be used, then authenticator should be set as PasswordAuthenticator | ||
* (through custom Cassandra configuration) and through CQL with default scylladb-scylladb credentials | ||
* user management should be modified | ||
*/ | ||
public String getPassword() { | ||
return PASSWORD; | ||
} | ||
|
||
/** | ||
* Retrieve an {@link InetSocketAddress} for connecting to the ScyllaDB container via the driver. | ||
* | ||
* @return A InetSocketAddrss representation of this ScyllaDB container's host and port. | ||
*/ | ||
public InetSocketAddress getContactPoint() { | ||
return new InetSocketAddress(getHost(), getMappedPort(CQL_PORT)); | ||
} | ||
|
||
/** | ||
* Retrieve the Local Datacenter for connecting to the ScyllaDB container via the driver. | ||
* | ||
* @return The configured local Datacenter name. | ||
*/ | ||
public String getLocalDatacenter() { | ||
return getEnvMap().getOrDefault("SCYLLADB_DC", DEFAULT_LOCAL_DATACENTER); | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
...ylladb/src/main/java/org/testcontainers/containers/delegate/ScyllaDBDatabaseDelegate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package org.testcontainers.containers.delegate; | ||
|
||
import com.datastax.oss.driver.api.core.CqlSession; | ||
import com.datastax.oss.driver.api.core.DriverException; | ||
import com.datastax.oss.driver.api.core.cql.ResultSet; | ||
import org.slf4j.Logger; | ||
import org.testcontainers.containers.ContainerState; | ||
import org.testcontainers.containers.ScyllaDBContainer; | ||
import org.testcontainers.delegate.AbstractDatabaseDelegate; | ||
import org.testcontainers.exception.ConnectionCreationException; | ||
import org.testcontainers.ext.ScriptUtils.ScriptStatementFailedException; | ||
import org.testcontainers.utility.DockerLoggerFactory; | ||
|
||
import java.net.InetSocketAddress; | ||
|
||
public class ScyllaDBDatabaseDelegate extends AbstractDatabaseDelegate<CqlSession> { | ||
|
||
public ScyllaDBDatabaseDelegate(ContainerState container) { | ||
this.container = container; | ||
} | ||
|
||
protected Logger logger() { | ||
return DockerLoggerFactory.getLogger(container.getCurrentContainerInfo().getName()); | ||
} | ||
|
||
private final ContainerState container; | ||
|
||
@Override | ||
protected CqlSession createNewConnection() { | ||
try { | ||
return CqlSession | ||
.builder() | ||
.addContactPoint( | ||
new InetSocketAddress(container.getHost(), container.getMappedPort(ScyllaDBContainer.CQL_PORT)) | ||
) | ||
.withLocalDatacenter("datacenter1") | ||
.build(); | ||
} catch (DriverException e) { | ||
throw new ConnectionCreationException("Could not obtain cassandra connection", e); | ||
} | ||
} | ||
|
||
@Override | ||
public void execute( | ||
String statement, | ||
String scriptPath, | ||
int lineNumber, | ||
boolean continueOnError, | ||
boolean ignoreFailedDrops | ||
) { | ||
try { | ||
ResultSet result = getConnection().execute(statement); | ||
if (!result.wasApplied()) { | ||
throw new ScriptStatementFailedException(statement, lineNumber, scriptPath); | ||
} | ||
} catch (DriverException e) { | ||
throw new ScriptStatementFailedException(statement, lineNumber, scriptPath, e); | ||
} | ||
} | ||
|
||
@Override | ||
protected void closeConnectionQuietly(CqlSession session) { | ||
try { | ||
session.close(); | ||
} catch (Exception e) { | ||
logger().error("Could not close cassandra connection", e); | ||
} | ||
} | ||
} |
Oops, something went wrong.