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/&lt;unresolved&gt;: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 + "/&lt;unresolved&gt;:", 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>&nbsp;&nbsp;<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>&nbsp;&nbsp;<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 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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>

Reply via email to