diff --git a/modules/yugabytedb/build.gradle b/modules/yugabytedb/build.gradle index 68a6f03abc7..8d0ba6ca3d0 100644 --- a/modules/yugabytedb/build.gradle +++ b/modules/yugabytedb/build.gradle @@ -4,7 +4,6 @@ dependencies { api project(':jdbc') testImplementation project(':jdbc-test') // YCQL driver - compileOnly 'com.yugabyte:java-driver-core:4.6.0-yb-11' testImplementation 'com.yugabyte:java-driver-core:4.6.0-yb-11' // YSQL driver testImplementation 'com.yugabyte:jdbc-yugabytedb:42.3.4' diff --git a/modules/yugabytedb/src/main/java/org/testcontainers/containers/YCQLSessionDelegate.java b/modules/yugabytedb/src/main/java/org/testcontainers/containers/YCQLSessionDelegate.java deleted file mode 100644 index 844260e80fe..00000000000 --- a/modules/yugabytedb/src/main/java/org/testcontainers/containers/YCQLSessionDelegate.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.testcontainers.containers; - -import com.datastax.oss.driver.api.core.CqlSession; - -/** - * A builder abstraction to construct {@link CqlSession} instance from - * {@link YugabyteDBYCQLContainer} instance. - * - * @author srinivasa-vasu - */ -public interface YCQLSessionDelegate { - - /** - * Constructs a {@link CqlSession} instance from {@link YugabyteDBYCQLContainer} - * instance. - * @param container YCQL container instance - * @return {@link CqlSession} instance - */ - default CqlSession builder(YugabyteDBYCQLContainer container) { - return CqlSession.builder().withLocalDatacenter(container.getLocalDc()).withKeyspace(container.getKeyspace()) - .withAuthCredentials(container.getUsername(), container.getPassword()) - .addContactPoint(container.getContactPoint()).build(); - } - -} diff --git a/modules/yugabytedb/src/main/java/org/testcontainers/containers/YugabyteDBYCQLContainer.java b/modules/yugabytedb/src/main/java/org/testcontainers/containers/YugabyteDBYCQLContainer.java index e1c886ba79c..09ccca9ace4 100644 --- a/modules/yugabytedb/src/main/java/org/testcontainers/containers/YugabyteDBYCQLContainer.java +++ b/modules/yugabytedb/src/main/java/org/testcontainers/containers/YugabyteDBYCQLContainer.java @@ -27,7 +27,7 @@ public class YugabyteDBYCQLContainer extends GenericContainerycqlsh cli within the container to execute the + * statements at one go. It is recommended to use frameworks such as liquibase to manage + * this requirement. This functionality is kept to address the initialization requirements + * from standalone services that can't leverage liquibase or something similar. * * @author srinivasa-vasu * @see YugabyteDBYCQLContainer */ @RequiredArgsConstructor -public final class YugabyteDBYCQLDelegate extends AbstractDatabaseDelegate implements YCQLSessionDelegate { +@Slf4j +public final class YugabyteDBYCQLDelegate extends AbstractYCQLDelegate { - private final YugabyteDBYCQLContainer container; + private static final String BIN_PATH = "/home/yugabyte/tserver/bin/ycqlsh"; - @Override - protected CqlSession createNewConnection() { - return builder(container); - } + private final YugabyteDBYCQLContainer container; @Override - public void execute(String statement, String scriptPath, int lineNumber, boolean continueOnError, + public void execute(Collection statements, String scriptPath, boolean continueOnError, boolean ignoreFailedDrops) { - getConnection().execute(statement); - } - - @Override - protected void closeConnectionQuietly(CqlSession session) { - if (session != null) { - session.close(); + try { + ExecResult result = container.execInContainer(BIN_PATH, "-u", container.getUsername(), "-p", + container.getPassword(), "-k", container.getKeyspace(), "-e", StringUtils.join(statements, ";")); + if (result.getExitCode() != 0) { + throw new RuntimeException(result.getStderr()); + } + } + catch (Exception e) { + log.debug(e.getMessage(), e); + throw new UncategorizedScriptException(e.getMessage(), e); } } diff --git a/modules/yugabytedb/src/main/java/org/testcontainers/containers/strategy/YugabyteDBYCQLWaitStrategy.java b/modules/yugabytedb/src/main/java/org/testcontainers/containers/strategy/YugabyteDBYCQLWaitStrategy.java index 73274dfc562..245ca0ae5fa 100644 --- a/modules/yugabytedb/src/main/java/org/testcontainers/containers/strategy/YugabyteDBYCQLWaitStrategy.java +++ b/modules/yugabytedb/src/main/java/org/testcontainers/containers/strategy/YugabyteDBYCQLWaitStrategy.java @@ -1,10 +1,11 @@ package org.testcontainers.containers.strategy; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; -import com.datastax.oss.driver.api.core.CqlSession; import lombok.RequiredArgsConstructor; -import org.testcontainers.containers.YCQLSessionDelegate; +import lombok.extern.slf4j.Slf4j; +import org.testcontainers.containers.Container.ExecResult; import org.testcontainers.containers.YugabyteDBYCQLContainer; import org.testcontainers.containers.wait.strategy.AbstractWaitStrategy; import org.testcontainers.containers.wait.strategy.WaitStrategyTarget; @@ -25,22 +26,40 @@ * @author srinivasa-vasu */ @RequiredArgsConstructor -public final class YugabyteDBYCQLWaitStrategy extends AbstractWaitStrategy implements YCQLSessionDelegate { +@Slf4j +public final class YugabyteDBYCQLWaitStrategy extends AbstractWaitStrategy { private static final String YCQL_TEST_QUERY = "SELECT release_version FROM system.local"; + private static final String BIN_PATH = "/home/yugabyte/tserver/bin/ycqlsh"; + private final WaitStrategyTarget target; @Override public void waitUntilReady(WaitStrategyTarget target) { YugabyteDBYCQLContainer container = (YugabyteDBYCQLContainer) target; + AtomicBoolean status = new AtomicBoolean(true); retryUntilSuccess((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () -> { - getRateLimiter().doWhenReady(() -> { - try (CqlSession session = builder(container)) { - session.execute(YCQL_TEST_QUERY); + YugabyteDBYCQLWaitStrategy.this.getRateLimiter().doWhenReady(() -> { + try { + ExecResult result = container.execInContainer(BIN_PATH, "-u", container.getUsername(), "-p", + container.getPassword(), "-k", container.getKeyspace(), "-e", YCQL_TEST_QUERY); + if (result.getExitCode() != 0) { + status.set(false); + log.debug(result.getStderr()); + } + } + catch (Exception e) { + status.set(false); + log.debug(e.getMessage(), e); + } + finally { + if (!status.getAndSet(true)) { + throw new RuntimeException("container hasn't come up yet"); + } } }); - return true; + return status; }); } diff --git a/modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYCQLTest.java b/modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYCQLTest.java index 2f097797fe7..9e220f8c8fa 100644 --- a/modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYCQLTest.java +++ b/modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYCQLTest.java @@ -4,11 +4,12 @@ import com.datastax.oss.driver.api.core.CqlSession; import com.datastax.oss.driver.api.core.cql.ResultSet; -import org.junit.Assert; import org.junit.Test; import org.testcontainers.containers.YugabyteDBYCQLContainer; import org.testcontainers.utility.DockerImageName; +import static org.assertj.core.api.Assertions.assertThat; + /** * YugabyteDB YCQL API unit test class * @@ -16,7 +17,7 @@ */ public class YugabyteDBYCQLTest { - private static final String IMAGE_NAME = "yugabytedb/yugabyte:2.14.0.0-b94"; + private static final String IMAGE_NAME = "yugabytedb/yugabyte:2.14.3.1-b1"; private static final DockerImageName YBDB_TEST_IMAGE = DockerImageName.parse(IMAGE_NAME); @@ -34,8 +35,8 @@ public void testSmoke() { // startingYCQLContainer { ycqlContainer.start(); // } - Assert.assertNotNull("Smoke test simple query execution fails!", - performQuery(ycqlContainer, "SELECT release_version FROM system.local").one().getString(0)); + assertThat(performQuery(ycqlContainer, "SELECT release_version FROM system.local").wasApplied()) + .as("A sample test query succeeds").isTrue(); } } @@ -45,10 +46,9 @@ public void testCustomKeyspace() throws InterruptedException { try (final YugabyteDBYCQLContainer ycqlContainer = new YugabyteDBYCQLContainer(YBDB_TEST_IMAGE) .withKeyspaceName(key)) { ycqlContainer.start(); - Assert.assertEquals("Custom keyspace creation fails!", key, - performQuery(ycqlContainer, - "SELECT keyspace_name FROM system_schema.keyspaces where keyspace_name='" + key + "'").one() - .getString(0)); + assertThat(performQuery(ycqlContainer, + "SELECT keyspace_name FROM system_schema.keyspaces where keyspace_name='" + key + "'").one() + .getString(0)).as("Custom keyspace creation succeeds").isEqualTo(key); } } @@ -58,9 +58,8 @@ public void testAuthenticationEnabled() throws InterruptedException { try (final YugabyteDBYCQLContainer ycqlContainer = new YugabyteDBYCQLContainer(YBDB_TEST_IMAGE) .withUsername(role).withPassword(role)) { ycqlContainer.start(); - Assert.assertEquals("Keyspace login fails with authentication enabled!", role, - performQuery(ycqlContainer, "SELECT role FROM system_auth.roles where role='" + role + "'").one() - .getString(0)); + assertThat(performQuery(ycqlContainer, "SELECT role FROM system_auth.roles where role='" + role + "'").one() + .getString(0)).as("Keyspace login with authentication enabled succeeds").isEqualTo(role); } } @@ -69,8 +68,8 @@ public void testAuthenticationDisabled() { try (final YugabyteDBYCQLContainer ycqlContainer = new YugabyteDBYCQLContainer(YBDB_TEST_IMAGE).withPassword("") .withUsername("")) { ycqlContainer.start(); - Assert.assertTrue("Query execution fails!", - performQuery(ycqlContainer, "SELECT release_version FROM system.local").wasApplied()); + assertThat(performQuery(ycqlContainer, "SELECT release_version FROM system.local").wasApplied()) + .as("Keyspace login with authentication disabled succeeds").isTrue(); } } @@ -80,8 +79,9 @@ public void testInitScript() throws InterruptedException { try (final YugabyteDBYCQLContainer ycqlContainer = new YugabyteDBYCQLContainer(YBDB_TEST_IMAGE) .withKeyspaceName(key).withUsername(key).withPassword(key).withInitScript("init/init_yql.sql")) { ycqlContainer.start(); - Assert.assertTrue("Query execution fails to execute statements from a custom script!", - performQuery(ycqlContainer, "SELECT * FROM random.bar").wasApplied()); + ResultSet output = performQuery(ycqlContainer, "SELECT greet FROM random.dsql"); + assertThat(output.wasApplied()).as("Statements from a custom script execution succeeds").isTrue(); + assertThat(output.one().getString(0)).as("A record match succeeds").isEqualTo("Hello DSQL"); } } diff --git a/modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYSQLTest.java b/modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYSQLTest.java index 0480343546c..701af83cb04 100644 --- a/modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYSQLTest.java +++ b/modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYSQLTest.java @@ -2,14 +2,13 @@ import java.sql.SQLException; -import org.hamcrest.CoreMatchers; -import org.hamcrest.MatcherAssert; -import org.junit.Assert; import org.junit.Test; import org.testcontainers.containers.YugabyteDBYSQLContainer; import org.testcontainers.db.AbstractContainerDatabaseTest; import org.testcontainers.utility.DockerImageName; +import static org.assertj.core.api.Assertions.assertThat; + /** * YugabyteDB YSQL API unit test class * @@ -17,7 +16,7 @@ */ public class YugabyteDBYSQLTest extends AbstractContainerDatabaseTest { - private static final String IMAGE_NAME = "yugabytedb/yugabyte:2.14.0.0-b94"; + private static final String IMAGE_NAME = "yugabytedb/yugabyte:2.14.3.1-b1"; private static final DockerImageName YBDB_TEST_IMAGE = DockerImageName.parse(IMAGE_NAME); @@ -31,7 +30,8 @@ public void testSmoke() throws SQLException { // startingYSQLContainer { ysqlContainer.start(); // } - Assert.assertEquals("Query execution fails!", 1, performQuery(ysqlContainer, "SELECT 1").getInt(1)); + assertThat(performQuery(ysqlContainer, "SELECT 1").getInt(1)).as("A sample test query succeeds") + .isEqualTo(1); } } @@ -41,18 +41,18 @@ public void testCustomDatabase() throws SQLException { try (final YugabyteDBYSQLContainer ysqlContainer = new YugabyteDBYSQLContainer(YBDB_TEST_IMAGE) .withDatabaseName(key)) { ysqlContainer.start(); - Assert.assertEquals("Query execution on a custom database fails!", 1, - performQuery(ysqlContainer, "SELECT 1").getInt(1)); + assertThat(performQuery(ysqlContainer, "SELECT 1").getInt(1)) + .as("A test query on a custom database succeeds").isEqualTo(1); } } @Test - public void testExplicitInitScript() throws SQLException { + public void testInitScript() throws SQLException { try (final YugabyteDBYSQLContainer ysqlContainer = new YugabyteDBYSQLContainer(YBDB_TEST_IMAGE) .withInitScript("init/init_yql.sql")) { ysqlContainer.start(); - Assert.assertEquals("Value from the init script does not match the real value", "hello world", - performQuery(ysqlContainer, "SELECT foo FROM bar").getString(1)); + assertThat(performQuery(ysqlContainer, "SELECT greet FROM dsql").getString(1)) + .as("A record match succeeds").isEqualTo("Hello DSQL"); } } @@ -62,10 +62,9 @@ public void testWithAdditionalUrlParamInJdbcUrl() { .withUrlParam("sslmode", "disable").withUrlParam("application_name", "yugabyte")) { ysqlContainer.start(); String jdbcUrl = ysqlContainer.getJdbcUrl(); - MatcherAssert.assertThat(jdbcUrl, CoreMatchers.containsString("?")); - MatcherAssert.assertThat(jdbcUrl, CoreMatchers.containsString("&")); - MatcherAssert.assertThat(jdbcUrl, CoreMatchers.containsString("sslmode=disable")); - MatcherAssert.assertThat(jdbcUrl, CoreMatchers.containsString("application_name=yugabyte")); + assertThat(jdbcUrl).contains("?").contains("&").contains("sslmode=disable") + .contains("application_name=yugabyte") + .as("A JDBC connection string with additional parameter validation succeeds"); } } @@ -74,8 +73,8 @@ public void testWithCustomRole() throws SQLException { try (final YugabyteDBYSQLContainer ysqlContainer = new YugabyteDBYSQLContainer(YBDB_TEST_IMAGE) .withDatabaseName("yugabyte").withPassword("yugabyte").withUsername("yugabyte")) { ysqlContainer.start(); - Assert.assertEquals("Query execution with a custom role fails!", 1, - performQuery(ysqlContainer, "SELECT 1").getInt(1)); + assertThat(performQuery(ysqlContainer, "SELECT 1").getInt(1)) + .as("A sample test query with a custom role succeeds").isEqualTo(1); } } diff --git a/modules/yugabytedb/src/test/resources/init/init_yql.sql b/modules/yugabytedb/src/test/resources/init/init_yql.sql index f09647da277..31cbaa6a758 100644 --- a/modules/yugabytedb/src/test/resources/init/init_yql.sql +++ b/modules/yugabytedb/src/test/resources/init/init_yql.sql @@ -1,5 +1,5 @@ -CREATE TABLE bar( - foo text primary key +CREATE TABLE dsql( + greet text primary key ); -INSERT INTO bar (foo) VALUES ('hello world'); +INSERT INTO dsql (greet) VALUES ('Hello DSQL');