This is an automated email from the ASF dual-hosted git repository.

mchades pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 228a1f59d [#4882] improvement(core): Add some ut for MySQL and 
PostgreSQL storage backend. (#4898)
228a1f59d is described below

commit 228a1f59d27c508dfe3a603258c1dce805d76b77
Author: Qi Yu <[email protected]>
AuthorDate: Wed Sep 11 10:08:59 2024 +0800

    [#4882] improvement(core): Add some ut for MySQL and PostgreSQL storage 
backend. (#4898)
    
    ### What changes were proposed in this pull request?
    
    Add some UTs to test MySQL and PostgreSQL storage backend.
    
    
    ### Why are the changes needed?
    
    To improve code robustness.
    
    Fix: #4882
    
    ### Does this PR introduce _any_ user-facing change?
    
    N/A.
    
    ### How was this patch tested?
    
    N/A
    
    ---------
    
    Co-authored-by: Jerry Shao <[email protected]>
---
 core/build.gradle.kts                              |   3 +
 .../gravitino/storage/TestEntityStorage.java       | 128 +++++++++++++--------
 .../integration/test/container/ContainerSuite.java |  11 ++
 .../integration/test/util/AbstractIT.java          |  67 ++++++-----
 4 files changed, 130 insertions(+), 79 deletions(-)

diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index d44023001..cb07b49d9 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -51,11 +51,14 @@ dependencies {
   testCompileOnly(libs.lombok)
 
   testImplementation(project(":integration-test-common", "testArtifacts"))
+  testImplementation(project(":server-common"))
+  testImplementation(project(":clients:client-java"))
   testImplementation(libs.awaitility)
   testImplementation(libs.junit.jupiter.api)
   testImplementation(libs.junit.jupiter.params)
   testImplementation(libs.mockito.core)
   testImplementation(libs.mysql.driver)
+  testImplementation(libs.postgresql.driver)
   testImplementation(libs.testcontainers)
 
   testRuntimeOnly(libs.junit.jupiter.engine)
diff --git 
a/core/src/test/java/org/apache/gravitino/storage/TestEntityStorage.java 
b/core/src/test/java/org/apache/gravitino/storage/TestEntityStorage.java
index d233ac5ba..ecb13c06b 100644
--- a/core/src/test/java/org/apache/gravitino/storage/TestEntityStorage.java
+++ b/core/src/test/java/org/apache/gravitino/storage/TestEntityStorage.java
@@ -19,10 +19,7 @@
 
 package org.apache.gravitino.storage;
 
-import static org.apache.gravitino.Configs.DEFAULT_ENTITY_KV_STORE;
 import static org.apache.gravitino.Configs.DEFAULT_ENTITY_RELATIONAL_STORE;
-import static org.apache.gravitino.Configs.ENTITY_KV_ROCKSDB_BACKEND_PATH;
-import static org.apache.gravitino.Configs.ENTITY_KV_STORE;
 import static 
org.apache.gravitino.Configs.ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER;
 import static 
org.apache.gravitino.Configs.ENTITY_RELATIONAL_JDBC_BACKEND_PASSWORD;
 import static org.apache.gravitino.Configs.ENTITY_RELATIONAL_JDBC_BACKEND_PATH;
@@ -32,7 +29,6 @@ import static 
org.apache.gravitino.Configs.ENTITY_RELATIONAL_STORE;
 import static org.apache.gravitino.Configs.ENTITY_STORE;
 import static org.apache.gravitino.Configs.RELATIONAL_ENTITY_STORE;
 import static org.apache.gravitino.Configs.STORE_DELETE_AFTER_TIME;
-import static org.apache.gravitino.Configs.STORE_TRANSACTION_MAX_SKEW_TIME;
 import static org.apache.gravitino.Configs.VERSION_RETENTION_COUNT;
 
 import com.google.common.base.Preconditions;
@@ -51,6 +47,7 @@ import java.util.List;
 import java.util.UUID;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
 import org.apache.gravitino.Catalog;
 import org.apache.gravitino.Config;
 import org.apache.gravitino.Configs;
@@ -68,6 +65,8 @@ import org.apache.gravitino.authorization.SecurableObjects;
 import org.apache.gravitino.exceptions.NoSuchEntityException;
 import org.apache.gravitino.exceptions.NonEmptyEntityException;
 import org.apache.gravitino.file.Fileset;
+import org.apache.gravitino.integration.test.container.ContainerSuite;
+import org.apache.gravitino.integration.test.util.AbstractIT;
 import org.apache.gravitino.meta.AuditInfo;
 import org.apache.gravitino.meta.BaseMetalake;
 import org.apache.gravitino.meta.CatalogEntity;
@@ -79,14 +78,25 @@ import org.apache.gravitino.meta.SchemaVersion;
 import org.apache.gravitino.meta.TableEntity;
 import org.apache.gravitino.meta.TopicEntity;
 import org.apache.gravitino.meta.UserEntity;
+import org.apache.gravitino.storage.relational.converters.H2ExceptionConverter;
+import 
org.apache.gravitino.storage.relational.converters.MySQLExceptionConverter;
+import 
org.apache.gravitino.storage.relational.converters.PostgreSQLExceptionConverter;
+import 
org.apache.gravitino.storage.relational.converters.SQLExceptionConverterFactory;
 import org.apache.gravitino.storage.relational.session.SqlSessionFactoryHelper;
 import org.apache.ibatis.session.SqlSession;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 import org.mockito.Mockito;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+@Tag("gravitino-docker-test")
 public class TestEntityStorage {
+  private static final Logger LOG = 
LoggerFactory.getLogger(TestEntityStorage.class);
+
   public static final String KV_STORE_PATH =
       "/tmp/gravitino_kv_entityStore_" + 
UUID.randomUUID().toString().replace("-", "");
 
@@ -96,50 +106,72 @@ public class TestEntityStorage {
   private static final String H2_FILE = DB_DIR + ".mv.db";
 
   static Object[] storageProvider() {
-    return new Object[] {Configs.RELATIONAL_ENTITY_STORE};
+    return new Object[] {"h2", "mysql", "postgresql"};
+  }
+
+  @AfterEach
+  void closeSuit() throws IOException {
+    ContainerSuite.getInstance().close();
   }
 
   private void init(String type, Config config) {
     Preconditions.checkArgument(StringUtils.isNotBlank(type));
-    if (type.equals(Configs.KV_STORE_KEY)) {
-      try {
-        FileUtils.deleteDirectory(FileUtils.getFile(KV_STORE_PATH));
-      } catch (Exception e) {
-        // Ignore
-      }
-      Mockito.when(config.get(ENTITY_STORE)).thenReturn("kv");
-      
Mockito.when(config.get(ENTITY_KV_STORE)).thenReturn(DEFAULT_ENTITY_KV_STORE);
-      Mockito.when(config.get(Configs.ENTITY_SERDE)).thenReturn("proto");
-      
Mockito.when(config.get(ENTITY_KV_ROCKSDB_BACKEND_PATH)).thenReturn(KV_STORE_PATH);
-
-      Assertions.assertEquals(KV_STORE_PATH, 
config.get(ENTITY_KV_ROCKSDB_BACKEND_PATH));
-      
Mockito.when(config.get(STORE_TRANSACTION_MAX_SKEW_TIME)).thenReturn(1000L);
-      Mockito.when(config.get(STORE_DELETE_AFTER_TIME)).thenReturn(20 * 60 * 
1000L);
-      Mockito.when(config.get(VERSION_RETENTION_COUNT)).thenReturn(1L);
-    } else if (type.equals(Configs.RELATIONAL_ENTITY_STORE)) {
-      File dir = new File(DB_DIR);
-      if (dir.exists() || !dir.isDirectory()) {
-        dir.delete();
+    File dir = new File(DB_DIR);
+    if (dir.exists() || !dir.isDirectory()) {
+      dir.delete();
+    }
+    dir.mkdirs();
+    Mockito.when(config.get(ENTITY_STORE)).thenReturn(RELATIONAL_ENTITY_STORE);
+    
Mockito.when(config.get(ENTITY_RELATIONAL_STORE)).thenReturn(DEFAULT_ENTITY_RELATIONAL_STORE);
+    
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_PATH)).thenReturn(DB_DIR);
+    Mockito.when(config.get(STORE_DELETE_AFTER_TIME)).thenReturn(20 * 60 * 
1000L);
+    Mockito.when(config.get(VERSION_RETENTION_COUNT)).thenReturn(1L);
+
+    try {
+      if (type.equalsIgnoreCase("h2")) {
+        // The following properties are used to create the JDBC connection; 
they are just for test,
+        // in the real world, they will be set automatically by the 
configuration file if you set
+        // ENTITY_RELATIONAL_STOR as EMBEDDED_ENTITY_RELATIONAL_STORE.
+        Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_URL))
+            
.thenReturn(String.format("jdbc:h2:%s;DB_CLOSE_DELAY=-1;MODE=MYSQL", DB_DIR));
+        
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_USER)).thenReturn("gravitino");
+        
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_PASSWORD)).thenReturn("gravitino");
+        
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER)).thenReturn("org.h2.Driver");
+
+        FieldUtils.writeStaticField(
+            SQLExceptionConverterFactory.class, "converter", new 
H2ExceptionConverter(), true);
+
+      } else if (type.equalsIgnoreCase("mysql")) {
+        String mysqlJdbcUrl = AbstractIT.startAndInitMySQLBackend();
+        
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_URL)).thenReturn(mysqlJdbcUrl);
+        
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_USER)).thenReturn("root");
+        
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_PASSWORD)).thenReturn("root");
+        Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER))
+            .thenReturn("com.mysql.cj.jdbc.Driver");
+
+        FieldUtils.writeStaticField(
+            SQLExceptionConverterFactory.class, "converter", new 
MySQLExceptionConverter(), true);
+
+      } else if (type.equalsIgnoreCase("postgresql")) {
+        String postgreSQLJdbcUrl = AbstractIT.startAndInitPGBackend();
+        
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_URL)).thenReturn(postgreSQLJdbcUrl);
+        
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_USER)).thenReturn("root");
+        
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_PASSWORD)).thenReturn("root");
+        Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER))
+            .thenReturn("org.postgresql.Driver");
+
+        FieldUtils.writeStaticField(
+            SQLExceptionConverterFactory.class,
+            "converter",
+            new PostgreSQLExceptionConverter(),
+            true);
+
+      } else {
+        throw new UnsupportedOperationException("Unsupported entity store 
type: " + type);
       }
-      dir.mkdirs();
-      
Mockito.when(config.get(ENTITY_STORE)).thenReturn(RELATIONAL_ENTITY_STORE);
-      
Mockito.when(config.get(ENTITY_RELATIONAL_STORE)).thenReturn(DEFAULT_ENTITY_RELATIONAL_STORE);
-      
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_PATH)).thenReturn(DB_DIR);
-
-      // The following properties are used to create the JDBC connection; they 
are just for test, in
-      // the real world,
-      // they will be set automatically by the configuration file if you set 
ENTITY_RELATIONAL_STORE
-      // as EMBEDDED_ENTITY_RELATIONAL_STORE.
-      Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_URL))
-          .thenReturn(String.format("jdbc:h2:%s;DB_CLOSE_DELAY=-1;MODE=MYSQL", 
DB_DIR));
-      
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_USER)).thenReturn("gravitino");
-      
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_PASSWORD)).thenReturn("gravitino");
-      
Mockito.when(config.get(ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER)).thenReturn("org.h2.Driver");
-
-      Mockito.when(config.get(STORE_DELETE_AFTER_TIME)).thenReturn(20 * 60 * 
1000L);
-      Mockito.when(config.get(VERSION_RETENTION_COUNT)).thenReturn(1L);
-    } else {
-      throw new UnsupportedOperationException("Unsupported entity store type: 
" + type);
+    } catch (Exception e) {
+      LOG.error("Failed to init entity store", e);
+      throw new RuntimeException(e);
     }
   }
 
@@ -151,7 +183,7 @@ public class TestEntityStorage {
       } catch (Exception e) {
         // Ignore
       }
-    } else if (type.equals(Configs.RELATIONAL_ENTITY_STORE)) {
+    } else if (type.equalsIgnoreCase("h2") || type.equalsIgnoreCase("mysql")) {
       dropAllTables();
       File dir = new File(DB_DIR);
       if (dir.exists()) {
@@ -159,6 +191,8 @@ public class TestEntityStorage {
       }
 
       FileUtils.deleteQuietly(new File(H2_FILE));
+    } else if (type.equalsIgnoreCase("postgresql")) {
+      // Do nothing
     } else {
       throw new UnsupportedOperationException("Unsupported entity store type: 
" + type);
     }
@@ -876,6 +910,8 @@ public class TestEntityStorage {
       store.get(identifier, Entity.EntityType.TABLE, TableEntity.class);
       store.get(identifier, Entity.EntityType.FILESET, FilesetEntity.class);
       store.get(changedNameIdentifier, Entity.EntityType.TOPIC, 
TopicEntity.class);
+
+      destroy(type);
     }
   }
 
@@ -2104,7 +2140,7 @@ public class TestEntityStorage {
   @ParameterizedTest
   @MethodSource("storageProvider")
   void testOptimizedDeleteForKv(String type) throws IOException {
-    if ("relational".equalsIgnoreCase(type)) {
+    if (!"kv".equalsIgnoreCase(type)) {
       return;
     }
 
@@ -2182,6 +2218,8 @@ public class TestEntityStorage {
       Assertions.assertDoesNotThrow(
           () ->
               store.get(filesetEntity1.nameIdentifier(), EntityType.FILESET, 
FilesetEntity.class));
+
+      destroy(type);
     }
   }
 }
diff --git 
a/integration-test-common/src/test/java/org/apache/gravitino/integration/test/container/ContainerSuite.java
 
b/integration-test-common/src/test/java/org/apache/gravitino/integration/test/container/ContainerSuite.java
index 4f477e136..bc311c4bc 100644
--- 
a/integration-test-common/src/test/java/org/apache/gravitino/integration/test/container/ContainerSuite.java
+++ 
b/integration-test-common/src/test/java/org/apache/gravitino/integration/test/container/ContainerSuite.java
@@ -563,6 +563,17 @@ public class ContainerSuite implements Closeable {
   public void close() throws IOException {
     try {
       closer.close();
+      mySQLContainer = null;
+      mySQLVersion5Container = null;
+      hiveContainer = null;
+      hiveRangerContainer = null;
+      trinoContainer = null;
+      trinoITContainers = null;
+      rangerContainer = null;
+      kafkaContainer = null;
+      dorisContainer = null;
+      kerberosHiveContainer = null;
+      pgContainerMap.clear();
     } catch (Exception e) {
       LOG.error("Failed to close ContainerEnvironment", e);
     }
diff --git 
a/integration-test-common/src/test/java/org/apache/gravitino/integration/test/util/AbstractIT.java
 
b/integration-test-common/src/test/java/org/apache/gravitino/integration/test/util/AbstractIT.java
index 3e264652b..6644e1f64 100644
--- 
a/integration-test-common/src/test/java/org/apache/gravitino/integration/test/util/AbstractIT.java
+++ 
b/integration-test-common/src/test/java/org/apache/gravitino/integration/test/util/AbstractIT.java
@@ -32,7 +32,6 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.sql.Connection;
 import java.sql.DriverManager;
-import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -161,21 +160,12 @@ public class AbstractIT {
     }
   }
 
-  protected static void setPGBackend() throws SQLException {
-    String pgUrlWithoutSchema = POSTGRESQL_CONTAINER.getJdbcUrl(META_DATA);
-    customConfigs.put(Configs.ENTITY_STORE_KEY, "relational");
-    customConfigs.put(Configs.ENTITY_RELATIONAL_STORE_KEY, "JDBCBackend");
-    customConfigs.put(Configs.ENTITY_RELATIONAL_JDBC_BACKEND_URL_KEY, 
pgUrlWithoutSchema);
-    customConfigs.put(
-        Configs.ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER_KEY,
-        POSTGRESQL_CONTAINER.getDriverClassName(META_DATA));
-    customConfigs.put(
-        Configs.ENTITY_RELATIONAL_JDBC_BACKEND_USER_KEY, 
POSTGRESQL_CONTAINER.getUsername());
-    customConfigs.put(
-        Configs.ENTITY_RELATIONAL_JDBC_BACKEND_PASSWORD_KEY, 
POSTGRESQL_CONTAINER.getPassword());
-
-    LOG.info("PG URL: {}", pgUrlWithoutSchema);
+  public static String startAndInitPGBackend() {
+    META_DATA = PG_JDBC_BACKEND;
+    containerSuite.startPostgreSQLContainer(META_DATA);
+    POSTGRESQL_CONTAINER = containerSuite.getPostgreSQLContainer();
 
+    String pgUrlWithoutSchema = POSTGRESQL_CONTAINER.getJdbcUrl(META_DATA);
     String randomSchemaName = RandomStringUtils.random(10, true, false);
     // Connect to the PostgreSQL docker and create a schema
     String currentExecuteSql = "";
@@ -216,18 +206,17 @@ public class AbstractIT {
 
     pgUrlWithoutSchema = pgUrlWithoutSchema + "?currentSchema=" + 
randomSchemaName;
     customConfigs.put(Configs.ENTITY_RELATIONAL_JDBC_BACKEND_URL_KEY, 
pgUrlWithoutSchema);
+
+    LOG.info("PG URL: {}", pgUrlWithoutSchema);
+    return pgUrlWithoutSchema;
   }
 
-  private static void setMySQLBackend() {
-    String mysqlUrl = MYSQL_CONTAINER.getJdbcUrl(META_DATA);
-    customConfigs.put(Configs.ENTITY_STORE_KEY, "relational");
-    customConfigs.put(Configs.ENTITY_RELATIONAL_STORE_KEY, "JDBCBackend");
-    customConfigs.put(Configs.ENTITY_RELATIONAL_JDBC_BACKEND_URL_KEY, 
mysqlUrl);
-    customConfigs.put(
-        Configs.ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER_KEY, 
"com.mysql.cj.jdbc.Driver");
-    customConfigs.put(Configs.ENTITY_RELATIONAL_JDBC_BACKEND_USER_KEY, "root");
-    customConfigs.put(Configs.ENTITY_RELATIONAL_JDBC_BACKEND_PASSWORD_KEY, 
"root");
+  public static String startAndInitMySQLBackend() {
+    META_DATA = TestDatabaseName.MYSQL_JDBC_BACKEND;
+    containerSuite.startMySQLContainer(META_DATA);
+    MYSQL_CONTAINER = containerSuite.getMySQLContainer();
 
+    String mysqlUrl = MYSQL_CONTAINER.getJdbcUrl(META_DATA);
     LOG.info("MySQL URL: {}", mysqlUrl);
     // Connect to the mysql docker and create a databases
     try (Connection connection =
@@ -255,6 +244,7 @@ public class AbstractIT {
       for (String sql : initMySQLBackendSqls) {
         statement.execute(sql);
       }
+      return mysqlUrl;
     } catch (Exception e) {
       LOG.error("Failed to create database in mysql", e);
       throw new RuntimeException(e);
@@ -279,18 +269,27 @@ public class AbstractIT {
 
     if ("MySQL".equalsIgnoreCase(System.getenv("jdbcBackend"))) {
       // Start MySQL docker instance.
-      META_DATA = TestDatabaseName.MYSQL_JDBC_BACKEND;
-      containerSuite.startMySQLContainer(META_DATA);
-      MYSQL_CONTAINER = containerSuite.getMySQLContainer();
-
-      setMySQLBackend();
+      String jdbcURL = startAndInitMySQLBackend();
+      customConfigs.put(Configs.ENTITY_STORE_KEY, "relational");
+      customConfigs.put(Configs.ENTITY_RELATIONAL_STORE_KEY, "JDBCBackend");
+      customConfigs.put(Configs.ENTITY_RELATIONAL_JDBC_BACKEND_URL_KEY, 
jdbcURL);
+      customConfigs.put(
+          Configs.ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER_KEY, 
"com.mysql.cj.jdbc.Driver");
+      customConfigs.put(Configs.ENTITY_RELATIONAL_JDBC_BACKEND_USER_KEY, 
"root");
+      customConfigs.put(Configs.ENTITY_RELATIONAL_JDBC_BACKEND_PASSWORD_KEY, 
"root");
     } else if ("PostgreSQL".equalsIgnoreCase(System.getenv("jdbcBackend"))) {
       // Start PostgreSQL docker instance.
-      META_DATA = PG_JDBC_BACKEND;
-      containerSuite.startPostgreSQLContainer(META_DATA);
-      POSTGRESQL_CONTAINER = containerSuite.getPostgreSQLContainer();
-
-      setPGBackend();
+      String pgJdbcUrl = startAndInitPGBackend();
+      customConfigs.put(Configs.ENTITY_STORE_KEY, "relational");
+      customConfigs.put(Configs.ENTITY_RELATIONAL_STORE_KEY, "JDBCBackend");
+      customConfigs.put(Configs.ENTITY_RELATIONAL_JDBC_BACKEND_URL_KEY, 
pgJdbcUrl);
+      customConfigs.put(
+          Configs.ENTITY_RELATIONAL_JDBC_BACKEND_DRIVER_KEY,
+          POSTGRESQL_CONTAINER.getDriverClassName(META_DATA));
+      customConfigs.put(
+          Configs.ENTITY_RELATIONAL_JDBC_BACKEND_USER_KEY, 
POSTGRESQL_CONTAINER.getUsername());
+      customConfigs.put(
+          Configs.ENTITY_RELATIONAL_JDBC_BACKEND_PASSWORD_KEY, 
POSTGRESQL_CONTAINER.getPassword());
     }
 
     File baseDir = new File(System.getProperty("java.io.tmpdir"));

Reply via email to