This is an automated email from the ASF dual-hosted git repository.
jongyoul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git
The following commit(s) were added to refs/heads/master by this push:
new 4728b91e27 [ZEPPELIN-6639] Migrate Cassandra interpreter tests to
Testcontainers with Cassandra 4.x
4728b91e27 is described below
commit 4728b91e2700dbf2ad014ad2e797e1cfef3342b5
Author: Cheng Pan <[email protected]>
AuthorDate: Wed Aug 12 14:47:03 2026 +0800
[ZEPPELIN-6639] Migrate Cassandra interpreter tests to Testcontainers with
Cassandra 4.x
## What is this PR for?
The Cassandra interpreter tests use `cassandra-unit` which embeds Cassandra
3.11.5 in-process. Cassandra 3.x is EOL (unmaintained, archived) and crashes on
JDK 17 because `Unsafe.objectFieldOffset()` on hidden classes (lambdas) throws
`UnsupportedOperationException` during `PREPARE` statement storage -- a hard
JVM restriction no flag can override. This PR migrates the tests to
Testcontainers with Cassandra 4.1.3 (the latest maintained 4.1.x), which
handles JDK 17 correctly. This is a [...]
## What type of PR is it?
Improvement
## What is the Jira issue?
https://issues.apache.org/jira/browse/ZEPPELIN-6639
## How should this be tested?
- `cassandra` module: 39 tests pass on JDK 11 and JDK 17 with Docker
- `./mvnw test -pl cassandra`
## Questions
- Does the licenses file need update? No
- Is there breaking changes for older versions? No
- Does this needs documentation? No
## Details
- Replace `cassandra-unit` dependency with `org.testcontainers:cassandra`
(`cassandra:4.1.3` image)
- Add `org.testcontainers:cassandra` to root `pom.xml` dependencyManagement
- Rewrite `CassandraInterpreterTest` to use `CassandraContainer` instead of
`EmbeddedCassandraServerHelper`
- Load CQL test data via `CqlSession` instead of `CQLDataLoader`
- Update test expectation HTML files to match Cassandra 4.x table option
output:
- `additional_write_policy = '99p'` (new in 4.x)
- `read_repair = 'BLOCKING'` (replaces `dclocal_read_repair_chance` +
`read_repair_chance`)
- `speculative_retry = '99p'` (replaces `'99PERCENTILE'`)
- `compression chunk_length_in_kb = 16` (was 64)
- `NoResultWithExecutionInfo.html`: replace hardcoded `localhost:9142`
with `TRIED_HOSTS`/`QUERIED_HOSTS` placeholders
- Normalize `localhost/<unresolved>:port` in test assertions (JDK 17+
`InetSocketAddress.toString()` renders unresolved addresses differently)
Assisted-by: GLM 5.2
Closes #5412 from pan3793/ZEPPELIN-6639.
Signed-off-by: Jongyoul Lee <[email protected]>
---
cassandra/pom.xml | 21 ++------
.../cassandra/CassandraInterpreterTest.java | 58 ++++++++++++++--------
.../scalate/DescribeKeyspace_live_data.html | 2 +-
.../DescribeTable_live_data_complex_table.html | 2 +-
.../scalate/NoResultWithExecutionInfo.html | 2 +-
pom.xml | 7 +++
6 files changed, 53 insertions(+), 39 deletions(-)
diff --git a/cassandra/pom.xml b/cassandra/pom.xml
index 91ba86bbc0..e4e53309eb 100644
--- a/cassandra/pom.xml
+++ b/cassandra/pom.xml
@@ -37,8 +37,6 @@
<scalate.version>1.9.8</scalate.version>
<!-- test library versions -->
- <jna.version>5.12.1</jna.version>
- <cassandra.unit.version>4.3.1.0</cassandra.unit.version>
<scala.version>${scala.2.12.version}</scala.version>
<scala.binary.version>2.12</scala.binary.version>
@@ -137,26 +135,17 @@
</dependency>
<dependency>
- <groupId>net.java.dev.jna</groupId>
- <artifactId>jna</artifactId>
- <version>${jna.version}</version>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>cassandra</artifactId>
<scope>test</scope>
</dependency>
<dependency>
- <groupId>org.cassandraunit</groupId>
- <artifactId>cassandra-unit</artifactId>
- <version>${cassandra.unit.version}</version>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>com.datastax.oss</groupId>
- <artifactId>java-driver-core</artifactId>
- </exclusion>
- </exclusions>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>junit-jupiter</artifactId>
+ <scope>test</scope>
</dependency>
-
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
diff --git
a/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java
b/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java
index 8a6cce4ee9..4426d47d00 100644
---
a/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java
+++
b/cassandra/src/test/java/org/apache/zeppelin/cassandra/CassandraInterpreterTest.java
@@ -27,13 +27,13 @@ import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
-import org.cassandraunit.CQLDataLoader;
-import org.cassandraunit.dataset.cql.ClassPathCQLDataSet;
-import org.cassandraunit.utils.EmbeddedCassandraServerHelper;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import org.testcontainers.containers.CassandraContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -65,28 +65,40 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
-public class CassandraInterpreterTest { // extends
AbstractCassandraUnit4CQLTestCase {
+@Testcontainers
+public class CassandraInterpreterTest {
private static final String ARTISTS_TABLE = "zeppelin.artists";
private static volatile CassandraInterpreter interpreter;
+ private static CqlSession session;
+
private final InterpreterContext intrContext = InterpreterContext.builder()
.setParagraphTitle("Paragraph1")
.build();
+ @Container
+ public static CassandraContainer<?> cassandra =
+ new CassandraContainer<>("cassandra:4.1.3");
+
@BeforeAll
- public static synchronized void setUp() throws IOException,
InterruptedException {
- System.setProperty("cassandra.skip_wait_for_gossip_to_settle", "0");
- System.setProperty("cassandra.load_ring_state", "false");
- System.setProperty("cassandra.initial_token", "0");
- System.setProperty("cassandra.num_tokens", "nil");
-
System.setProperty("cassandra.allocate_tokens_for_local_replication_factor",
"nil");
- EmbeddedCassandraServerHelper.startEmbeddedCassandra();
- CqlSession session = EmbeddedCassandraServerHelper.getSession();
- new CQLDataLoader(session).load(new ClassPathCQLDataSet("prepare_all.cql",
"zeppelin"));
+ public static synchronized void setUp() throws IOException {
+ session = CqlSession.builder()
+ .addContactPoint(java.net.InetSocketAddress.createUnresolved(
+ cassandra.getHost(), cassandra.getMappedPort(9042)))
+ .withLocalDatacenter("datacenter1")
+ .build();
+
+ String cql = IOUtils.resourceToString("/prepare_all.cql",
StandardCharsets.UTF_8);
+ for (String stmt : cql.split(";")) {
+ String trimmed = stmt.trim();
+ if (!trimmed.isEmpty()) {
+ session.execute(trimmed);
+ }
+ }
Properties properties = new Properties();
- properties.setProperty(CASSANDRA_CLUSTER_NAME,
EmbeddedCassandraServerHelper.getClusterName());
+ properties.setProperty(CASSANDRA_CLUSTER_NAME, "Test Cluster");
properties.setProperty(CASSANDRA_COMPRESSION_PROTOCOL, "NONE");
properties.setProperty(CASSANDRA_CREDENTIALS_USERNAME, "none");
properties.setProperty(CASSANDRA_CREDENTIALS_PASSWORD, "none");
@@ -111,9 +123,9 @@ public class CassandraInterpreterTest { // extends
AbstractCassandraUnit4CQLTest
properties.setProperty(CASSANDRA_SOCKET_READ_TIMEOUT_MILLIS, "12000");
properties.setProperty(CASSANDRA_SOCKET_TCP_NO_DELAY, "true");
- properties.setProperty(CASSANDRA_HOSTS,
EmbeddedCassandraServerHelper.getHost());
+ properties.setProperty(CASSANDRA_HOSTS, cassandra.getHost());
properties.setProperty(CASSANDRA_PORT,
-
Integer.toString(EmbeddedCassandraServerHelper.getNativeTransportPort()));
+ Integer.toString(cassandra.getMappedPort(9042)));
properties.setProperty("datastax-java-driver.advanced.connection.pool.local.size",
"1");
interpreter = new CassandraInterpreter(properties);
interpreter.open();
@@ -122,6 +134,9 @@ public class CassandraInterpreterTest { // extends
AbstractCassandraUnit4CQLTest
@AfterAll
public static void tearDown() {
interpreter.close();
+ if (session != null) {
+ session.close();
+ }
}
@Test
@@ -333,7 +348,7 @@ public class CassandraInterpreterTest { // extends
AbstractCassandraUnit4CQLTest
String statement2 = "@timestamp=15\n" +
"INSERT INTO zeppelin.ts(key,val) VALUES('k','v2');";
- CqlSession session = EmbeddedCassandraServerHelper.getSession();
+ CqlSession session = CassandraInterpreterTest.session;
// Insert v1 with current timestamp
interpreter.interpret(statement1, intrContext);
System.out.println("going to read data from zeppelin.ts;");
@@ -562,14 +577,17 @@ public class CassandraInterpreterTest { // extends
AbstractCassandraUnit4CQLTest
// When
final InterpreterResult actual = interpreter.interpret(query, intrContext);
- final int port = EmbeddedCassandraServerHelper.getNativeTransportPort();
- final String address = EmbeddedCassandraServerHelper.getHost();
+ final int port = cassandra.getMappedPort(9042);
+ final String address = cassandra.getHost();
// Then
final String expected = rawResult.replaceAll("TRIED_HOSTS", address + ":"
+ port)
.replaceAll("QUERIED_HOSTS", address + ":" + port);
assertEquals(Code.SUCCESS, actual.code());
- assertEquals(expected, reformatHtml(actual.message().get(0).getData()));
+ // JDK 17+ renders unresolved InetSocketAddress as "host/<unresolved>:port"
+ String actualHtml = reformatHtml(actual.message().get(0).getData())
+ .replaceAll(address + "/<unresolved>:", address + ":");
+ assertEquals(expected, actualHtml);
}
@Test
diff --git
a/cassandra/src/test/resources/scalate/DescribeKeyspace_live_data.html
b/cassandra/src/test/resources/scalate/DescribeKeyspace_live_data.html
index 8d721ef233..ed67b250cd 100644
--- a/cassandra/src/test/resources/scalate/DescribeKeyspace_live_data.html
+++ b/cassandra/src/test/resources/scalate/DescribeKeyspace_live_data.html
@@ -1 +1 @@
-<br/><br/><nav class="navbar navbar-default"><ul class="nav navbar-nav"><li
role="presentation" class="dropdown"><a class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false"><span class="text-danger"><span class="glyphicon
glyphicon-folder-open"></span> <strong>live_data</strong></span><span
class="text-danger caret"></span><ul class="dropdown-menu"><li
class="dropdown-header"><span class="text-primary">Tables</span></li><li><a rol
[...]
\ No newline at end of file
+<br/><br/><nav class="navbar navbar-default"><ul class="nav navbar-nav"><li
role="presentation" class="dropdown"><a class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false"><span class="text-danger"><span class="glyphicon
glyphicon-folder-open"></span> <strong>live_data</strong></span><span
class="text-danger caret"></span><ul class="dropdown-menu"><li
class="dropdown-header"><span class="text-primary">Tables</span></li><li><a rol
[...]
\ No newline at end of file
diff --git
a/cassandra/src/test/resources/scalate/DescribeTable_live_data_complex_table.html
b/cassandra/src/test/resources/scalate/DescribeTable_live_data_complex_table.html
index b31dc11ee5..09cb963f47 100644
---
a/cassandra/src/test/resources/scalate/DescribeTable_live_data_complex_table.html
+++
b/cassandra/src/test/resources/scalate/DescribeTable_live_data_complex_table.html
@@ -1 +1 @@
-<br/><br/><nav class="navbar navbar-default"><ul class="nav
navbar-nav"><li><a><strong>DESCRIBE TABLE
live_data.complex_table;</strong></a></li></ul><ul class="nav navbar-nav
navbar-right"><li class="dropdown"><a class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false"><strong>Legend</strong><span class="caret"></span></a><ul
class="dropdown-menu"><li><a href="#"><span class="glyphicon
glyphicon-dashboard text-muted" aria-hidden="true" ></sp [...]
\ No newline at end of file
+<br/><br/><nav class="navbar navbar-default"><ul class="nav
navbar-nav"><li><a><strong>DESCRIBE TABLE
live_data.complex_table;</strong></a></li></ul><ul class="nav navbar-nav
navbar-right"><li class="dropdown"><a class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false"><strong>Legend</strong><span class="caret"></span></a><ul
class="dropdown-menu"><li><a href="#"><span class="glyphicon
glyphicon-dashboard text-muted" aria-hidden="true" ></sp [...]
\ No newline at end of file
diff --git
a/cassandra/src/test/resources/scalate/NoResultWithExecutionInfo.html
b/cassandra/src/test/resources/scalate/NoResultWithExecutionInfo.html
index bd713adad2..f15b05dcae 100644
--- a/cassandra/src/test/resources/scalate/NoResultWithExecutionInfo.html
+++ b/cassandra/src/test/resources/scalate/NoResultWithExecutionInfo.html
@@ -1 +1 @@
-<div class="container"><div class="row"><h5>No Result
<a role="button" data-toggle="collapse"
aria-expanded="false"><span class="text-info"><strong>Last query execution
info</strong></span></a></h5></div><div class="panel panel-default"><div
class="panel-collapse collapse" role="tabpanel"><div class="panel-body"><div
class="row"><div class="col-md-3"></div><div class="col-md-6 col-offset-md-3
table-responsive table-bordered"><table class="table"><thead><tr [...]
\ No newline at end of file
+<div class="container"><div class="row"><h5>No Result
<a role="button" data-toggle="collapse"
aria-expanded="false"><span class="text-info"><strong>Last query execution
info</strong></span></a></h5></div><div class="panel panel-default"><div
class="panel-collapse collapse" role="tabpanel"><div class="panel-body"><div
class="row"><div class="col-md-3"></div><div class="col-md-6 col-offset-md-3
table-responsive table-bordered"><table class="table"><thead><tr [...]
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 9e021cbfc6..a8e8a7f8f8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -450,6 +450,13 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.testcontainers</groupId>
+ <artifactId>cassandra</artifactId>
+ <version>${testcontainers.version}</version>
+ <scope>test</scope>
+ </dependency>
+
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client-api</artifactId>