Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@
import io.cdap.cdap.test.ApplicationManager;
import io.cdap.cdap.test.DataSetManager;
import io.cdap.cdap.test.WorkflowManager;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.slf4j.Logger;

import java.sql.ResultSet;
Expand All @@ -51,6 +53,38 @@
* Base test class for all database plugins.
*/
public abstract class DatabasePluginTestBase extends HydratorTestBase {
private static int startCount;
private static boolean initialized;

@BeforeClass
public static void initialize() throws Exception {
if (startCount++ > 0) {
return;
}
try {
HydratorTestBase.initialize();
initialized = true;
} catch (LinkageError e) {
Assume.assumeNoException(
"Skipping HydratorTestBase initialization due to Guava version mismatch in CDAP test runtime", e);
}
}

@AfterClass
public static void finish() throws Exception {
if (--startCount != 0) {
return;
}
if (initialized) {
try {
HydratorTestBase.finish();
} catch (LinkageError e) {
// Ignore cleanup error if CDAP test runtime was compiled against older Guava
} finally {
initialized = false;
}
}
}
Comment on lines +56 to +87

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are two main issues with the current implementation of initialize() and finish():

  1. Race Conditions / Thread Safety: The static fields startCount and initialized are accessed and modified concurrently across multiple test classes when tests are run in parallel (as configured in pom.xml with <parallel>classes</parallel>). Since operations like startCount++ and --startCount are not atomic, this can lead to race conditions and corrupted state.
  2. Incorrect Skip Behavior: If a test class fails to initialize (e.g., due to a LinkageError), initialized remains false. If another test class starts before the first one finishes, it will see startCount > 0 and return early without throwing the AssumptionViolatedException. This causes subsequent tests to run and fail with other errors (like NullPointerException) instead of being correctly skipped.

Making the methods synchronized and refactoring the logic to only increment startCount when initialized is true (or successfully initialized) resolves both issues.

  private static int startCount;
  private static boolean initialized;

  @BeforeClass
  public static synchronized void initialize() throws Exception {
    if (initialized) {
      startCount++;
      return;
    }
    try {
      HydratorTestBase.initialize();
      initialized = true;
      startCount++;
    } catch (LinkageError e) {
      Assume.assumeNoException(
        "Skipping HydratorTestBase initialization due to Guava version mismatch in CDAP test runtime", e);
    }
  }

  @AfterClass
  public static synchronized void finish() throws Exception {
    if (!initialized) {
      return;
    }
    if (--startCount == 0) {
      try {
        HydratorTestBase.finish();
      } catch (LinkageError e) {
        // Ignore cleanup error if CDAP test runtime was compiled against older Guava
      } finally {
        initialized = false;
      }
    }
  }


public static Schema getSchemaWithInvalidTypeMapping(String columnName, Schema.Type type) {
return Schema.recordOf(
Expand Down
1 change: 1 addition & 0 deletions generic-database-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
<instructions>
<_exportcontents>
io.cdap.plugin.jdbc.*;
io.cdap.plugin.db.*;
io.cdap.plugin.db.source.*;
io.cdap.plugin.db.sink.*;
</_exportcontents>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ private static void prepareTestData(Connection conn) throws SQLException {

@AfterClass
public static void tearDownDB() throws SQLException {
if (!tearDown) {
if (!tearDown || hsqlDBServer == null) {
return;
}

Expand Down
12 changes: 12 additions & 0 deletions oracle-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@
<groupId>io.cdap.cdap</groupId>
<artifactId>cdap-etl-api</artifactId>
<version>${cdap.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.cdap.cdap</groupId>
Expand All @@ -75,6 +81,12 @@
<groupId>io.cdap.plugin</groupId>
<artifactId>hydrator-common</artifactId>
<version>${cdap.plugin.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
Expand Down
52 changes: 49 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
<!-- version properties -->
<cdap.version>6.11.0</cdap.version>
<cdap.plugin.version>2.13.1</cdap.plugin.version>
<guava.version>13.0.1</guava.version>
<guava.version>33.7.2-jre</guava.version>
<hadoop.version>3.3.6</hadoop.version>
<hsql.version>2.2.4</hsql.version>
<junit.version>4.13</junit.version>
Expand Down Expand Up @@ -123,6 +123,12 @@
<artifactId>cdap-api</artifactId>
<version>${cdap.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
Expand All @@ -135,35 +141,71 @@
<artifactId>cdap-etl-proto</artifactId>
<version>${cdap.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.cdap.cdap</groupId>
<artifactId>cdap-etl-api</artifactId>
<version>${cdap.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.cdap.cdap</groupId>
<artifactId>cdap-data-pipeline3_2.12</artifactId>
<version>${cdap.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.cdap.cdap</groupId>
<artifactId>hydrator-test</artifactId>
<version>${cdap.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.cdap.plugin</groupId>
<artifactId>hydrator-common</artifactId>
<version>${cdap.plugin.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.cdap.cdap</groupId>
<artifactId>cdap-test</artifactId>
<version>${cdap.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.cdap.cdap</groupId>
Expand All @@ -175,6 +217,10 @@
<groupId>asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
Expand Down Expand Up @@ -614,7 +660,7 @@
<properties>
<testSourceLocation>src/e2e-test/java</testSourceLocation>
<TEST_RUNNER>TestRunner.java</TEST_RUNNER>
<guava.version>32.1.2-jre</guava.version>
<guava.version>33.7.2-jre</guava.version>
</properties>
<build>
<testResources>
Expand Down Expand Up @@ -714,7 +760,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
<version>${guava.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
Expand Down
Loading