From 86ed2cbf0ee39405ce2e428f52371fea67a4475b Mon Sep 17 00:00:00 2001 From: Maxim Korolyov Date: Tue, 2 Jan 2024 08:23:25 +0100 Subject: [PATCH] add scylladb module --- .github/ISSUE_TEMPLATE/bug_report.yaml | 1 + .github/ISSUE_TEMPLATE/enhancement.yaml | 1 + .github/ISSUE_TEMPLATE/feature.yaml | 1 + .github/dependabot.yml | 5 + .github/labeler.yml | 4 + docs/modules/databases/scylladb.md | 28 +++ modules/scylladb/build.gradle | 15 ++ .../containers/ScyllaDBContainer.java | 194 ++++++++++++++++++ .../delegate/ScyllaDBDatabaseDelegate.java | 69 +++++++ .../wait/ScyllaDBQueryWaitStrategy.java | 43 ++++ .../containers/ScyllaDBContainerTest.java | 117 +++++++++++ .../containers/ScyllaDBDriver4Test.java | 37 ++++ .../containers/ScyllaDBServer5Test.java | 35 ++++ .../scylladb/src/test/resources/initial.cql | 7 + .../src/test/resources/logback-test.xml | 16 ++ .../scylla.yaml | 62 ++++++ 16 files changed, 635 insertions(+) create mode 100644 docs/modules/databases/scylladb.md create mode 100644 modules/scylladb/build.gradle create mode 100644 modules/scylladb/src/main/java/org/testcontainers/containers/ScyllaDBContainer.java create mode 100644 modules/scylladb/src/main/java/org/testcontainers/containers/delegate/ScyllaDBDatabaseDelegate.java create mode 100644 modules/scylladb/src/main/java/org/testcontainers/containers/wait/ScyllaDBQueryWaitStrategy.java create mode 100644 modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBContainerTest.java create mode 100644 modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBDriver4Test.java create mode 100644 modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBServer5Test.java create mode 100644 modules/scylladb/src/test/resources/initial.cql create mode 100644 modules/scylladb/src/test/resources/logback-test.xml create mode 100644 modules/scylladb/src/test/resources/scylla-test-configuration-example/scylla.yaml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 135c8323866..5992ccdc46c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -47,6 +47,7 @@ body: - QuestDB - RabbitMQ - Redpanda + - ScyllaDB - Selenium - Solace - Solr diff --git a/.github/ISSUE_TEMPLATE/enhancement.yaml b/.github/ISSUE_TEMPLATE/enhancement.yaml index d77b4ce07a2..48e5813cc89 100644 --- a/.github/ISSUE_TEMPLATE/enhancement.yaml +++ b/.github/ISSUE_TEMPLATE/enhancement.yaml @@ -47,6 +47,7 @@ body: - QuestDB - RabbitMQ - Redpanda + - ScyllaDB - Selenium - Solace - Solr diff --git a/.github/ISSUE_TEMPLATE/feature.yaml b/.github/ISSUE_TEMPLATE/feature.yaml index 65a27e5f99a..5a2097bb62f 100644 --- a/.github/ISSUE_TEMPLATE/feature.yaml +++ b/.github/ISSUE_TEMPLATE/feature.yaml @@ -47,6 +47,7 @@ body: - Pulsar - RabbitMQ - Redpanda + - ScyllaDB - Selenium - Solace - Solr diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3cb3e0fd222..3569b8b5cc2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -246,6 +246,11 @@ updates: schedule: interval: "weekly" open-pull-requests-limit: 10 + - package-ecosystem: "gradle" + directory: "/modules/scylladb" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 - package-ecosystem: "gradle" directory: "/modules/selenium" schedule: diff --git a/.github/labeler.yml b/.github/labeler.yml index eec54b67829..73df03d65f5 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -156,6 +156,10 @@ - changed-files: - any-glob-to-any-file: - modules/redpanda/**/* +"modules/scylladb": + - changed-files: + - any-glob-to-any-file: + - modules/scylladb/**/* "modules/selenium": - changed-files: - any-glob-to-any-file: diff --git a/docs/modules/databases/scylladb.md b/docs/modules/databases/scylladb.md new file mode 100644 index 00000000000..f2f6d2b6a52 --- /dev/null +++ b/docs/modules/databases/scylladb.md @@ -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. + + +[Building CqlSession](../../../modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBDriver4Test.java) inside_block:scylladb + + +## 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 + + org.testcontainers + scylladb + {{latest_version}} + test + + ``` diff --git a/modules/scylladb/build.gradle b/modules/scylladb/build.gradle new file mode 100644 index 00000000000..acb45635166 --- /dev/null +++ b/modules/scylladb/build.gradle @@ -0,0 +1,15 @@ +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 'org.assertj:assertj-core:3.24.2' +} diff --git a/modules/scylladb/src/main/java/org/testcontainers/containers/ScyllaDBContainer.java b/modules/scylladb/src/main/java/org/testcontainers/containers/ScyllaDBContainer.java new file mode 100644 index 00000000000..e85eaacbdad --- /dev/null +++ b/modules/scylladb/src/main/java/org/testcontainers/containers/ScyllaDBContainer.java @@ -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. + *

+ * Supported image: {@code scylladb} + *

+ * Exposed ports: 9042 + */ +public class ScyllaDBContainer> extends GenericContainer { + + 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("SCYLLADB_ENDPOINT_SNITCH", "GossipingPropertyFileSnitch"); + withEnv("SCYLLADB_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 + *

+ * 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 + *

+ * 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); + } +} diff --git a/modules/scylladb/src/main/java/org/testcontainers/containers/delegate/ScyllaDBDatabaseDelegate.java b/modules/scylladb/src/main/java/org/testcontainers/containers/delegate/ScyllaDBDatabaseDelegate.java new file mode 100644 index 00000000000..255ec5d90c8 --- /dev/null +++ b/modules/scylladb/src/main/java/org/testcontainers/containers/delegate/ScyllaDBDatabaseDelegate.java @@ -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 { + + 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); + } + } +} diff --git a/modules/scylladb/src/main/java/org/testcontainers/containers/wait/ScyllaDBQueryWaitStrategy.java b/modules/scylladb/src/main/java/org/testcontainers/containers/wait/ScyllaDBQueryWaitStrategy.java new file mode 100644 index 00000000000..c72822932ff --- /dev/null +++ b/modules/scylladb/src/main/java/org/testcontainers/containers/wait/ScyllaDBQueryWaitStrategy.java @@ -0,0 +1,43 @@ +package org.testcontainers.containers.wait; + +import org.rnorth.ducttape.TimeoutException; +import org.testcontainers.containers.ContainerLaunchException; +import org.testcontainers.containers.delegate.ScyllaDBDatabaseDelegate; +import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; +import org.testcontainers.delegate.DatabaseDelegate; + +import java.util.concurrent.TimeUnit; + +import static org.rnorth.ducttape.unreliables.Unreliables.retryUntilSuccess; + +/** + * Waits until ScyllaDB returns its version + */ +public class ScyllaDBQueryWaitStrategy extends AbstractWaitStrategy { + + private static final String SELECT_VERSION_QUERY = "SELECT release_version FROM system.local"; + + private static final String TIMEOUT_ERROR = "Timed out waiting for ScyllaDB to be accessible for query execution"; + + @Override + protected void waitUntilReady() { + // execute select version query until success or timeout + try { + retryUntilSuccess( + (int) startupTimeout.getSeconds(), + TimeUnit.SECONDS, + () -> { + getRateLimiter() + .doWhenReady(() -> { + try (DatabaseDelegate databaseDelegate = new ScyllaDBDatabaseDelegate(waitStrategyTarget)) { + databaseDelegate.execute(SELECT_VERSION_QUERY, "", 1, false, false); + } + }); + return true; + } + ); + } catch (TimeoutException e) { + throw new ContainerLaunchException(TIMEOUT_ERROR); + } + } +} diff --git a/modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBContainerTest.java b/modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBContainerTest.java new file mode 100644 index 00000000000..61aceaa3ea6 --- /dev/null +++ b/modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBContainerTest.java @@ -0,0 +1,117 @@ +package org.testcontainers.containers; + +import com.datastax.driver.core.Cluster; +import com.datastax.driver.core.ResultSet; +import com.datastax.driver.core.Row; +import com.datastax.driver.core.Session; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.testcontainers.containers.wait.ScyllaDBQueryWaitStrategy; +import org.testcontainers.utility.DockerImageName; + +import static org.assertj.core.api.Assertions.assertThat; + +@Slf4j +public class ScyllaDBContainerTest { + + private static final DockerImageName SCYLLADB_IMAGE = DockerImageName.parse("scylladb/scylla:5.2.9"); + + private static final String TEST_CLUSTER_NAME_IN_CONF = "Test Cluster Integration Test"; + + private static final String BASIC_QUERY = "SELECT release_version FROM system.local"; + + @Test + public void testSimple() { + try (ScyllaDBContainer scylladbContainer = new ScyllaDBContainer<>(SCYLLADB_IMAGE)) { + scylladbContainer.start(); + ResultSet resultSet = performQuery(scylladbContainer, BASIC_QUERY); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); + assertThat(resultSet.one().getString(0)).as("Result set has release_version").isNotNull(); + } + } + + @Test + public void testSpecificVersion() { + String scyllaDBReportedVersion = "3.0.8"; + try ( + ScyllaDBContainer ScyllaDBContainer = new ScyllaDBContainer<>(SCYLLADB_IMAGE) + ) { + ScyllaDBContainer.start(); + ResultSet resultSet = performQuery(ScyllaDBContainer, BASIC_QUERY); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); + assertThat(resultSet.one().getString(0)).as("ScyllaDB has right version").isEqualTo(scyllaDBReportedVersion); + } + } + + @Test + public void testConfigurationOverride() { + try ( + ScyllaDBContainer ScyllaDBContainer = new ScyllaDBContainer<>(SCYLLADB_IMAGE) + .withConfigurationOverride("scylla-test-configuration-example") + ) { + ScyllaDBContainer.start(); + ResultSet resultSet = performQuery(ScyllaDBContainer, "SELECT cluster_name FROM system.local"); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); + assertThat(resultSet.one().getString(0)) + .as("ScyllaDB configuration is overridden") + .isEqualTo(TEST_CLUSTER_NAME_IN_CONF); + } + } + + @Test(expected = ContainerLaunchException.class) + public void testEmptyConfigurationOverride() { + try ( + ScyllaDBContainer ScyllaDBContainer = new ScyllaDBContainer<>(SCYLLADB_IMAGE) + .withConfigurationOverride("scylladb-empty-configuration") + ) { + ScyllaDBContainer.start(); + } + } + + @Test + public void testInitScript() { + try ( + ScyllaDBContainer ScyllaDBContainer = new ScyllaDBContainer<>(SCYLLADB_IMAGE) + .withInitScript("initial.cql") + ) { + ScyllaDBContainer.start(); + testInitScript(ScyllaDBContainer); + } + } + + @Test + public void testScyllaDBQueryWaitStrategy() { + try ( + ScyllaDBContainer scyllaDBContainer = new ScyllaDBContainer<>(SCYLLADB_IMAGE) + .waitingFor(new ScyllaDBQueryWaitStrategy()) + ) { + scyllaDBContainer.start(); + ResultSet resultSet = performQuery(scyllaDBContainer, BASIC_QUERY); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); + } + } + + private void testInitScript(ScyllaDBContainer ScyllaDBContainer) { + ResultSet resultSet = performQuery(ScyllaDBContainer, "SELECT * FROM keySpaceTest.catalog_category"); + assertThat(resultSet.wasApplied()).as("Query was applied").isTrue(); + Row row = resultSet.one(); + assertThat(row.getLong(0)).as("Inserted row is in expected state").isEqualTo(1); + assertThat(row.getString(1)).as("Inserted row is in expected state").isEqualTo("test_category"); + } + + private ResultSet performQuery(ScyllaDBContainer ScyllaDBContainer, String cql) { + Cluster explicitCluster = Cluster + .builder() + .addContactPoint(ScyllaDBContainer.getHost()) + .withPort(ScyllaDBContainer.getMappedPort(ScyllaDBContainer.CQL_PORT)) + .build(); + return performQuery(explicitCluster, cql); + } + + private ResultSet performQuery(Cluster cluster, String cql) { + try (Cluster closeableCluster = cluster) { + Session session = closeableCluster.newSession(); + return session.execute(cql); + } + } +} diff --git a/modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBDriver4Test.java b/modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBDriver4Test.java new file mode 100644 index 00000000000..3953a1e1118 --- /dev/null +++ b/modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBDriver4Test.java @@ -0,0 +1,37 @@ +package org.testcontainers.containers; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import org.junit.Rule; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ScyllaDBDriver4Test { + + @Rule + public ScyllaDBContainer scyllaDB = new ScyllaDBContainer<>("scylladb/scylla:5.2.9"); + + @Test + public void testCassandraGetContactPoint() { + try ( + // cassandra { + CqlSession session = CqlSession + .builder() + .addContactPoint(this.scyllaDB.getContactPoint()) + .withLocalDatacenter(this.scyllaDB.getLocalDatacenter()) + .build() + // } + ) { + session.execute( + "CREATE KEYSPACE IF NOT EXISTS test WITH replication = \n" + + "{'class':'SimpleStrategy','replication_factor':'1'};" + ); + + KeyspaceMetadata keyspace = session.getMetadata().getKeyspaces().get(CqlIdentifier.fromCql("test")); + + assertThat(keyspace).as("keyspace created").isNotNull(); + } + } +} diff --git a/modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBServer5Test.java b/modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBServer5Test.java new file mode 100644 index 00000000000..f6959744db7 --- /dev/null +++ b/modules/scylladb/src/test/java/org/testcontainers/containers/ScyllaDBServer5Test.java @@ -0,0 +1,35 @@ +package org.testcontainers.containers; + +import com.datastax.oss.driver.api.core.CqlIdentifier; +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.metadata.schema.KeyspaceMetadata; +import org.junit.Rule; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class ScyllaDBServer5Test { + + @Rule + public ScyllaDBContainer scylladb = new ScyllaDBContainer<>("scylladb/scylla:5.2.9"); + + @Test + public void testScyllaDBGetContactPoint() { + try ( + CqlSession session = CqlSession + .builder() + .addContactPoint(this.scylladb.getContactPoint()) + .withLocalDatacenter(this.scylladb.getLocalDatacenter()) + .build() + ) { + session.execute( + "CREATE KEYSPACE IF NOT EXISTS test WITH replication = \n" + + "{'class':'SimpleStrategy','replication_factor':'1'};" + ); + + KeyspaceMetadata keyspace = session.getMetadata().getKeyspaces().get(CqlIdentifier.fromCql("test")); + + assertThat(keyspace).as("test keyspace created").isNotNull(); + } + } +} diff --git a/modules/scylladb/src/test/resources/initial.cql b/modules/scylladb/src/test/resources/initial.cql new file mode 100644 index 00000000000..2caad3746f8 --- /dev/null +++ b/modules/scylladb/src/test/resources/initial.cql @@ -0,0 +1,7 @@ +CREATE KEYSPACE keySpaceTest WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1}; + +USE keySpaceTest; + +CREATE TABLE catalog_category (id bigint primary key, name text); + +INSERT INTO catalog_category (id, name) VALUES (1, 'test_category'); \ No newline at end of file diff --git a/modules/scylladb/src/test/resources/logback-test.xml b/modules/scylladb/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..83ef7a1a3ef --- /dev/null +++ b/modules/scylladb/src/test/resources/logback-test.xml @@ -0,0 +1,16 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger - %msg%n + + + + + + + + + diff --git a/modules/scylladb/src/test/resources/scylla-test-configuration-example/scylla.yaml b/modules/scylladb/src/test/resources/scylla-test-configuration-example/scylla.yaml new file mode 100644 index 00000000000..086ae07239f --- /dev/null +++ b/modules/scylladb/src/test/resources/scylla-test-configuration-example/scylla.yaml @@ -0,0 +1,62 @@ +# ScyllaDB storage config YAML + +# NOTE: +# See https://opensource.docs.scylladb.com/stable/operating-scylla/admin.html for +# full explanations of configuration directives +# /NOTE + +# The name of the cluster. This is mainly used to prevent machines in +# one logical cluster from joining another. +cluster_name: 'Test Cluster Integration Test' + +# This defines the number of tokens randomly assigned to this node on the ring +# The more tokens, relative to other nodes, the larger the proportion of data +# that this node will store. You probably want all nodes to have the same number +# of tokens assuming they have equal hardware capability. +num_tokens: 256 + +# Directory where Scylla should store data on disk. +data_file_directories: + - /var/lib/scylla/data + +# commit log. when running on magnetic HDD, this should be a +# separate spindle than the data directories. +commitlog_directory: /var/lib/scylla/commitlog + +# schema commit log. A special commitlog instance +# used for schema and system tables. +# When running on magnetic HDD, this should be a +# separate spindle than the data directories. +# schema_commitlog_directory: /var/lib/scylla/commitlog/schema + +# seed_provider class_name is saved for future use. +# A seed address is mandatory. +seed_provider: + # The addresses of hosts that will serve as contact points for the joining node. + # It allows the node to discover the cluster ring topology on startup (when + # joining the cluster). + # Once the node has joined the cluster, the seed list has no function. + - class_name: org.apache.cassandra.locator.SimpleSeedProvider + parameters: + # In a new cluster, provide the address of the first node. + # In an existing cluster, specify the address of at least one existing node. + # If you specify addresses of more than one node, use a comma to separate them. + # For example: ",," + - seeds: "127.0.0.1" + +# Address or interface to bind to and tell other Scylla nodes to connect to. +# You _must_ change this if you want multiple nodes to be able to communicate! +# +# Setting listen_address to 0.0.0.0 is always wrong. +listen_address: localhost + +# Address to broadcast to other Scylla nodes +# Leaving this blank will set it to the same value as listen_address +# broadcast_address: 1.2.3.4 + +# port for the CQL native transport to listen for clients on +# For security reasons, you should not expose this port to the internet. Firewall it if needed. +native_transport_port: 9042 + +# Uncomment to enable experimental features +# experimental: true