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

lzljs3620320 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 8190730f9 [test] Introduce CatalogTestBase (#872)
8190730f9 is described below

commit 8190730f9edd0ad6423c4fc54f953b570e7d83d2
Author: Kerwin <[email protected]>
AuthorDate: Wed Apr 12 10:06:46 2023 +0800

    [test] Introduce CatalogTestBase (#872)
---
 .../java/org/apache/paimon/catalog/Catalog.java    |  14 +
 .../org/apache/paimon/catalog/CatalogTestBase.java | 609 +++++++++++++++++++++
 .../paimon/catalog/FileSystemCatalogTest.java      |  47 ++
 paimon-hive/paimon-hive-catalog/pom.xml            |  94 ++++
 .../org/apache/paimon/hive/HiveCatalogTest.java    |  86 +++
 .../src/test/resources/hive-site.xml               |  53 ++
 6 files changed, 903 insertions(+)

diff --git a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java 
b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
index 16545250a..45a828b79 100644
--- a/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
+++ b/paimon-core/src/main/java/org/apache/paimon/catalog/Catalog.java
@@ -108,6 +108,20 @@ public interface Catalog extends AutoCloseable {
      */
     List<String> listTables(String databaseName) throws 
DatabaseNotExistException;
 
+    /**
+     * Check if a table exists in this catalog.
+     *
+     * @param identifier Path of the table
+     * @return true if the given table exists in the catalog false otherwise
+     */
+    default boolean tableExists(Identifier identifier) {
+        try {
+            return getTable(identifier) != null;
+        } catch (TableNotExistException e) {
+            return false;
+        }
+    }
+
     /**
      * Drop a table.
      *
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java 
b/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java
new file mode 100644
index 000000000..321cbbc28
--- /dev/null
+++ b/paimon-core/src/test/java/org/apache/paimon/catalog/CatalogTestBase.java
@@ -0,0 +1,609 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.catalog;
+
+import org.apache.paimon.fs.FileIO;
+import org.apache.paimon.fs.Path;
+import org.apache.paimon.options.CatalogOptions;
+import org.apache.paimon.options.Options;
+import org.apache.paimon.schema.Schema;
+import org.apache.paimon.schema.SchemaChange;
+import org.apache.paimon.shade.guava30.com.google.common.collect.Lists;
+import org.apache.paimon.shade.guava30.com.google.common.collect.Maps;
+import org.apache.paimon.table.Table;
+import org.apache.paimon.types.DataField;
+import org.apache.paimon.types.DataTypes;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+/** Base test class of paimon catalog in {@link Catalog}. */
+public abstract class CatalogTestBase {
+
+    @TempDir java.nio.file.Path tempFile;
+    protected String warehouse;
+    protected FileIO fileIO;
+    protected Catalog catalog;
+    protected static final Schema DEFAULT_TABLE_SCHEMA =
+            new Schema(
+                    Lists.newArrayList(
+                            new DataField(0, "pk", DataTypes.INT()),
+                            new DataField(1, "col1", DataTypes.STRING()),
+                            new DataField(2, "col2", DataTypes.STRING())),
+                    Collections.emptyList(),
+                    Collections.emptyList(),
+                    Maps.newHashMap(),
+                    "");
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        warehouse = tempFile.toUri().toString();
+        Options catalogOptions = new Options();
+        catalogOptions.set(CatalogOptions.WAREHOUSE, warehouse);
+        CatalogContext catalogContext = CatalogContext.create(catalogOptions);
+        fileIO = FileIO.get(new Path(warehouse), catalogContext);
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        if (catalog != null) {
+            catalog.close();
+        }
+    }
+
+    @Test
+    public abstract void testListDatabasesWhenNoDatabases();
+
+    @Test
+    public void testListDatabases() throws Exception {
+        catalog.createDatabase("db1", false);
+        catalog.createDatabase("db2", false);
+        catalog.createDatabase("db3", false);
+
+        List<String> databases = catalog.listDatabases();
+        assertThat(databases).contains("db1", "db2", "db3");
+    }
+
+    @Test
+    public void testDatabaseExistsWhenExists() throws Exception {
+        // Database exists returns true when the database exists
+        catalog.createDatabase("test_db", false);
+        boolean exists = catalog.databaseExists("test_db");
+        assertThat(exists).isTrue();
+
+        // Database exists returns false when the database does not exist
+        exists = catalog.databaseExists("non_existing_db");
+        assertThat(exists).isFalse();
+    }
+
+    @Test
+    public void testCreateDatabase() throws Exception {
+        // Create database creates a new database when it does not exist
+        catalog.createDatabase("new_db", false);
+        boolean exists = catalog.databaseExists("new_db");
+        assertThat(exists).isTrue();
+
+        catalog.createDatabase("existing_db", false);
+
+        // Create database throws DatabaseAlreadyExistException when database 
already exists and
+        // ignoreIfExists is false
+        assertThatExceptionOfType(Catalog.DatabaseAlreadyExistException.class)
+                .isThrownBy(() -> catalog.createDatabase("existing_db", false))
+                .withMessage("Database existing_db already exists.");
+
+        // Create database does not throw exception when database already 
exists and ignoreIfExists
+        // is true
+        assertThatCode(() -> catalog.createDatabase("existing_db", true))
+                .doesNotThrowAnyException();
+    }
+
+    @Test
+    public void testDropDatabase() throws Exception {
+        // Drop database deletes the database when it exists and there are no 
tables
+        catalog.createDatabase("db_to_drop", false);
+        catalog.dropDatabase("db_to_drop", false, false);
+        boolean exists = catalog.databaseExists("db_to_drop");
+        assertThat(exists).isFalse();
+
+        // Drop database does not throw exception when database does not exist 
and ignoreIfNotExists
+        // is true
+        assertThatCode(() -> catalog.dropDatabase("non_existing_db", true, 
false))
+                .doesNotThrowAnyException();
+
+        // Drop database deletes all tables in the database when cascade is 
true
+        catalog.createDatabase("db_to_drop", false);
+        catalog.createTable(Identifier.create("db_to_drop", "table1"), 
DEFAULT_TABLE_SCHEMA, false);
+        catalog.createTable(Identifier.create("db_to_drop", "table2"), 
DEFAULT_TABLE_SCHEMA, false);
+
+        catalog.dropDatabase("db_to_drop", false, true);
+        exists = catalog.databaseExists("db_to_drop");
+        assertThat(exists).isFalse();
+
+        // Drop database throws DatabaseNotEmptyException when cascade is 
false and there are tables
+        // in the database
+        catalog.createDatabase("db_with_tables", false);
+        catalog.createTable(
+                Identifier.create("db_with_tables", "table1"), 
DEFAULT_TABLE_SCHEMA, false);
+
+        assertThatExceptionOfType(Catalog.DatabaseNotEmptyException.class)
+                .isThrownBy(() -> catalog.dropDatabase("db_with_tables", 
false, false))
+                .withMessage("Database db_with_tables is not empty.");
+    }
+
+    @Test
+    public void testListTables() throws Exception {
+        // List tables returns an empty list when there are no tables in the 
database
+        catalog.createDatabase("test_db", false);
+        List<String> tables = catalog.listTables("test_db");
+        assertThat(tables).isEmpty();
+
+        // List tables returns a list with the names of all tables in the 
database
+        catalog.createTable(Identifier.create("test_db", "table1"), 
DEFAULT_TABLE_SCHEMA, false);
+        catalog.createTable(Identifier.create("test_db", "table2"), 
DEFAULT_TABLE_SCHEMA, false);
+        catalog.createTable(Identifier.create("test_db", "table3"), 
DEFAULT_TABLE_SCHEMA, false);
+
+        tables = catalog.listTables("test_db");
+        assertThat(tables).containsExactlyInAnyOrder("table1", "table2", 
"table3");
+    }
+
+    @Test
+    public void testTableExists() throws Exception {
+        // Table exists returns true when the table exists in the database
+        catalog.createDatabase("test_db", false);
+        Identifier identifier = Identifier.create("test_db", "test_table");
+        catalog.createTable(identifier, DEFAULT_TABLE_SCHEMA, false);
+
+        boolean exists = catalog.tableExists(identifier);
+        assertThat(exists).isTrue();
+
+        // Table exists returns false when the table does not exist in the 
database
+        exists = catalog.tableExists(Identifier.create("non_existing_db", 
"non_existing_table"));
+        assertThat(exists).isFalse();
+    }
+
+    @Test
+    public void testCreateTable() throws Exception {
+        catalog.createDatabase("test_db", false);
+        // Create table creates a new table when it does not exist
+        Identifier identifier = Identifier.create("test_db", "new_table");
+        catalog.createTable(identifier, DEFAULT_TABLE_SCHEMA, false);
+        boolean exists = catalog.tableExists(identifier);
+        assertThat(exists).isTrue();
+
+        // Create table throws Exception when table is system table
+        assertThatExceptionOfType(IllegalArgumentException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.createTable(
+                                        Identifier.create("test_db", 
"$system_table"),
+                                        DEFAULT_TABLE_SCHEMA,
+                                        false))
+                .withMessage(
+                        "Cannot 'createTable' for system table 
'Identifier{database='test_db', table='$system_table'}', please use data 
table.");
+
+        // Create table throws DatabaseNotExistException when database does 
not exist
+        assertThatExceptionOfType(Catalog.DatabaseNotExistException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.createTable(
+                                        Identifier.create("non_existing_db", 
"test_table"),
+                                        DEFAULT_TABLE_SCHEMA,
+                                        false))
+                .withMessage("Database non_existing_db does not exist.");
+
+        // Create table throws TableAlreadyExistException when table already 
exists and
+        // ignoreIfExists is false
+        Identifier existingTable = Identifier.create("test_db", 
"existing_table");
+        catalog.createTable(
+                existingTable,
+                new Schema(
+                        Lists.newArrayList(new DataField(0, "col1", 
DataTypes.STRING())),
+                        Collections.emptyList(),
+                        Collections.emptyList(),
+                        Maps.newHashMap(),
+                        ""),
+                false);
+        assertThatExceptionOfType(Catalog.TableAlreadyExistException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.createTable(
+                                        existingTable,
+                                        new Schema(
+                                                Lists.newArrayList(
+                                                        new DataField(
+                                                                0, "col2", 
DataTypes.STRING())),
+                                                Collections.emptyList(),
+                                                Collections.emptyList(),
+                                                Maps.newHashMap(),
+                                                ""),
+                                        false))
+                .withMessage("Table test_db.existing_table already exists.");
+
+        // Create table does not throw exception when table already exists and 
ignoreIfExists is
+        // true
+        assertThatCode(
+                        () ->
+                                catalog.createTable(
+                                        existingTable,
+                                        new Schema(
+                                                Lists.newArrayList(
+                                                        new DataField(
+                                                                0, "col2", 
DataTypes.STRING())),
+                                                Collections.emptyList(),
+                                                Collections.emptyList(),
+                                                Maps.newHashMap(),
+                                                ""),
+                                        true))
+                .doesNotThrowAnyException();
+    }
+
+    @Test
+    public void testGetTable() throws Exception {
+        catalog.createDatabase("test_db", false);
+
+        // Get system and data table when the table exists
+        Identifier identifier = Identifier.create("test_db", "test_table");
+        catalog.createTable(identifier, DEFAULT_TABLE_SCHEMA, false);
+        Table systemTable = catalog.getTable(Identifier.create("test_db", 
"test_table$snapshots"));
+        assertThat(systemTable).isNotNull();
+        Table dataTable = catalog.getTable(identifier);
+        assertThat(dataTable).isNotNull();
+
+        // Get system table throws Exception when table contains multiple '$' 
separator
+        assertThatExceptionOfType(IllegalArgumentException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.getTable(
+                                        Identifier.create(
+                                                "test_db", 
"test_table$snapshots$snapshots")))
+                .withMessage(
+                        "System table can only contain one '$' separator, but 
this is: test_table$snapshots$snapshots");
+
+        // Get system table throws TableNotExistException when data table does 
not exist
+        assertThatExceptionOfType(Catalog.TableNotExistException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.getTable(
+                                        Identifier.create(
+                                                "test_db", 
"non_existing_table$snapshots")))
+                .withMessage("Table test_db.non_existing_table does not 
exist.");
+
+        // Get system table throws TableNotExistException when system table 
type does not exist
+        assertThatExceptionOfType(Catalog.TableNotExistException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.getTable(
+                                        Identifier.create("test_db", 
"non_existing_table$schema1")))
+                .withMessage("Table test_db.non_existing_table does not 
exist.");
+
+        // Get data table throws TableNotExistException when table does not 
exist
+        assertThatExceptionOfType(Catalog.TableNotExistException.class)
+                .isThrownBy(
+                        () -> catalog.getTable(Identifier.create("test_db", 
"non_existing_table")))
+                .withMessage("Table test_db.non_existing_table does not 
exist.");
+
+        // Get data table throws TableNotExistException when database does not 
exist
+        assertThatExceptionOfType(Catalog.TableNotExistException.class)
+                .isThrownBy(
+                        () -> 
catalog.getTable(Identifier.create("non_existing_db", "test_table")))
+                .withMessage("Table non_existing_db.test_table does not 
exist.");
+    }
+
+    @Test
+    public void testDropTable() throws Exception {
+        catalog.createDatabase("test_db", false);
+
+        // Drop table deletes the table when it exists
+        Identifier identifier = Identifier.create("test_db", "table_to_drop");
+        catalog.createTable(identifier, DEFAULT_TABLE_SCHEMA, false);
+        catalog.dropTable(identifier, false);
+        boolean exists = catalog.tableExists(identifier);
+        assertThat(exists).isFalse();
+
+        // Drop table throws Exception when table is system table
+        assertThatExceptionOfType(IllegalArgumentException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.dropTable(
+                                        Identifier.create("test_db", 
"$system_table"), false))
+                .withMessage(
+                        "Cannot 'dropTable' for system table 
'Identifier{database='test_db', table='$system_table'}', please use data 
table.");
+
+        // Drop table throws TableNotExistException when table does not exist 
and ignoreIfNotExists
+        // is false
+        Identifier nonExistingTable = Identifier.create("test_db", 
"non_existing_table");
+        assertThatExceptionOfType(Catalog.TableNotExistException.class)
+                .isThrownBy(() -> catalog.dropTable(nonExistingTable, false))
+                .withMessage("Table test_db.non_existing_table does not 
exist.");
+
+        // Drop table does not throw exception when table does not exist and 
ignoreIfNotExists is
+        // true
+        assertThatCode(() -> catalog.dropTable(nonExistingTable, 
true)).doesNotThrowAnyException();
+    }
+
+    @Test
+    public void testRenameTable() throws Exception {
+        catalog.createDatabase("test_db", false);
+
+        // Rename table renames an existing table
+        Identifier fromTable = Identifier.create("test_db", "test_table");
+        catalog.createTable(fromTable, DEFAULT_TABLE_SCHEMA, false);
+        Identifier toTable = Identifier.create("test_db", "new_table");
+        catalog.renameTable(fromTable, toTable, false);
+        assertThat(catalog.tableExists(fromTable)).isFalse();
+        assertThat(catalog.tableExists(toTable)).isTrue();
+
+        // Rename table throws Exception when original or target table is 
system table
+        assertThatExceptionOfType(IllegalArgumentException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.renameTable(
+                                        Identifier.create("test_db", 
"$system_table"),
+                                        toTable,
+                                        false))
+                .withMessage(
+                        "Cannot 'renameTable' for system table 
'Identifier{database='test_db', table='$system_table'}', please use data 
table.");
+
+        assertThatExceptionOfType(IllegalArgumentException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.renameTable(
+                                        fromTable,
+                                        Identifier.create("test_db", 
"$system_table"),
+                                        false))
+                .withMessage(
+                        "Cannot 'renameTable' for system table 
'Identifier{database='test_db', table='$system_table'}', please use data 
table.");
+
+        // Rename table throws TableNotExistException when table does not exist
+        assertThatExceptionOfType(Catalog.TableNotExistException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.renameTable(
+                                        Identifier.create("test_db", 
"non_existing_table"),
+                                        Identifier.create("test_db", 
"new_table"),
+                                        false))
+                .withMessage("Table test_db.non_existing_table does not 
exist.");
+    }
+
+    @Test
+    public void testAlterTable() throws Exception {
+        catalog.createDatabase("test_db", false);
+
+        // Alter table adds a new column to an existing table
+        Identifier identifier = Identifier.create("test_db", "test_table");
+        catalog.createTable(
+                identifier,
+                new Schema(
+                        Lists.newArrayList(new DataField(0, "col1", 
DataTypes.STRING())),
+                        Collections.emptyList(),
+                        Collections.emptyList(),
+                        Maps.newHashMap(),
+                        ""),
+                false);
+        catalog.alterTable(
+                identifier,
+                Lists.newArrayList(SchemaChange.addColumn("col2", 
DataTypes.DATE())),
+                false);
+        Table table = catalog.getTable(identifier);
+        assertThat(table.rowType().getFields()).hasSize(2);
+        int index = table.rowType().getFieldIndex("col2");
+        assertThat(index).isEqualTo(1);
+        
assertThat(table.rowType().getTypeAt(index)).isEqualTo(DataTypes.DATE());
+
+        // Alter table throws Exception when table is system table
+        assertThatExceptionOfType(IllegalArgumentException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        Identifier.create("test_db", 
"$system_table"),
+                                        Lists.newArrayList(
+                                                SchemaChange.addColumn("col2", 
DataTypes.DATE())),
+                                        false))
+                .withMessage(
+                        "Cannot 'alterTable' for system table 
'Identifier{database='test_db', table='$system_table'}', please use data 
table.");
+
+        // Alter table throws TableNotExistException when table does not exist
+        assertThatExceptionOfType(Catalog.TableNotExistException.class)
+                .isThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        Identifier.create("test_db", 
"non_existing_table"),
+                                        Lists.newArrayList(
+                                                SchemaChange.addColumn("col3", 
DataTypes.INT())),
+                                        false))
+                .withMessage("Table test_db.non_existing_table does not 
exist.");
+
+        // Alter table adds a column throws Exception when column already 
exists
+        assertThatThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        identifier,
+                                        Lists.newArrayList(
+                                                SchemaChange.addColumn("col1", 
DataTypes.INT())),
+                                        false))
+                .hasRootCauseInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("The column [col1] exists in the table");
+    }
+
+    @Test
+    public void testAlterTableRenameColumn() throws Exception {
+        catalog.createDatabase("test_db", false);
+
+        // Alter table renames a column in an existing table
+        Identifier identifier = Identifier.create("test_db", "test_table");
+        catalog.createTable(
+                identifier,
+                new Schema(
+                        Lists.newArrayList(new DataField(0, "col1", 
DataTypes.STRING())),
+                        Collections.emptyList(),
+                        Collections.emptyList(),
+                        Maps.newHashMap(),
+                        ""),
+                false);
+        catalog.alterTable(
+                identifier,
+                Lists.newArrayList(SchemaChange.renameColumn("col1", 
"new_col1")),
+                false);
+        Table table = catalog.getTable(identifier);
+
+        assertThat(table.rowType().getFields()).hasSize(1);
+        assertThat(table.rowType().getFieldIndex("col1")).isLessThan(0);
+        assertThat(table.rowType().getFieldIndex("new_col1")).isEqualTo(0);
+
+        // Alter table renames a new column throws Exception when column 
already exists
+        assertThatThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        identifier,
+                                        Lists.newArrayList(
+                                                
SchemaChange.renameColumn("col1", "new_col1")),
+                                        false))
+                .hasRootCauseInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("The column [new_col1] exists in the 
table");
+
+        // Alter table renames a column throws Exception when column does not 
exist
+        assertThatThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        identifier,
+                                        Lists.newArrayList(
+                                                SchemaChange.renameColumn(
+                                                        "non_existing_col", 
"new_col2")),
+                                        false))
+                .hasMessageContaining("Can not find column: 
[non_existing_col]");
+    }
+
+    @Test
+    public void testAlterTableDropColumn() throws Exception {
+        catalog.createDatabase("test_db", false);
+
+        // Alter table drop a column in an existing table
+        Identifier identifier = Identifier.create("test_db", "test_table");
+        catalog.createTable(
+                identifier,
+                new Schema(
+                        Lists.newArrayList(
+                                new DataField(0, "col1", DataTypes.STRING()),
+                                new DataField(1, "col2", DataTypes.STRING())),
+                        Collections.emptyList(),
+                        Collections.emptyList(),
+                        Maps.newHashMap(),
+                        ""),
+                false);
+        catalog.alterTable(identifier, 
Lists.newArrayList(SchemaChange.dropColumn("col1")), false);
+        Table table = catalog.getTable(identifier);
+
+        assertThat(table.rowType().getFields()).hasSize(1);
+        assertThat(table.rowType().getFieldIndex("col1")).isLessThan(0);
+
+        // Alter table drop all fields throws Exception
+        assertThatThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        identifier,
+                                        
Lists.newArrayList(SchemaChange.dropColumn("col2")),
+                                        false))
+                .hasRootCauseInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining(" Cannot drop all fields in table");
+
+        // Alter table drop a column throws Exception when column does not 
exist
+        assertThatThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        identifier,
+                                        Lists.newArrayList(
+                                                
SchemaChange.dropColumn("non_existing_col")),
+                                        false))
+                .hasMessageContaining("The column [non_existing_col] doesn't 
exist in the table");
+    }
+
+    @Test
+    public void testAlterTableUpdateColumnType() throws Exception {
+        catalog.createDatabase("test_db", false);
+
+        // Alter table update a column type in an existing table
+        Identifier identifier = Identifier.create("test_db", "test_table");
+        catalog.createTable(
+                identifier,
+                new Schema(
+                        Lists.newArrayList(
+                                new DataField(0, "dt", DataTypes.STRING()),
+                                new DataField(1, "col1", DataTypes.BIGINT())),
+                        Lists.newArrayList("dt"),
+                        Collections.emptyList(),
+                        Maps.newHashMap(),
+                        ""),
+                false);
+        catalog.alterTable(
+                identifier,
+                Lists.newArrayList(SchemaChange.updateColumnType("col1", 
DataTypes.DOUBLE())),
+                false);
+        Table table = catalog.getTable(identifier);
+
+        assertThat(table.rowType().getFieldIndex("col1")).isEqualTo(1);
+        assertThat(table.rowType().getTypeAt(1)).isEqualTo(DataTypes.DOUBLE());
+
+        // Alter table update a column type throws Exception when column data 
type does not support
+        // implicit cast
+        assertThatThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        identifier,
+                                        Lists.newArrayList(
+                                                SchemaChange.updateColumnType(
+                                                        "col1", 
DataTypes.STRING())),
+                                        false))
+                .hasRootCauseInstanceOf(IllegalStateException.class)
+                .hasMessageContaining(
+                        "Column type col1[DOUBLE] cannot be converted to 
STRING without loosing information.");
+
+        // Alter table update a column type throws Exception when column does 
not exist
+        assertThatThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        identifier,
+                                        Lists.newArrayList(
+                                                SchemaChange.updateColumnType(
+                                                        "non_existing_col", 
DataTypes.INT())),
+                                        false))
+                .hasMessageContaining("Can not find column: 
[non_existing_col]");
+
+        // Alter table update a column type throws Exception when column is 
partition columns
+        assertThatThrownBy(
+                        () ->
+                                catalog.alterTable(
+                                        identifier,
+                                        Lists.newArrayList(
+                                                SchemaChange.updateColumnType(
+                                                        "dt", 
DataTypes.DATE())),
+                                        false))
+                .hasRootCauseInstanceOf(IllegalArgumentException.class)
+                .hasMessageContaining("Cannot update partition column [dt] 
type in the table");
+    }
+}
diff --git 
a/paimon-core/src/test/java/org/apache/paimon/catalog/FileSystemCatalogTest.java
 
b/paimon-core/src/test/java/org/apache/paimon/catalog/FileSystemCatalogTest.java
new file mode 100644
index 000000000..426d088d4
--- /dev/null
+++ 
b/paimon-core/src/test/java/org/apache/paimon/catalog/FileSystemCatalogTest.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.catalog;
+
+import org.apache.paimon.fs.Path;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/** Tests for {@link FileSystemCatalog}. */
+public class FileSystemCatalogTest extends CatalogTestBase {
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+        catalog = new FileSystemCatalog(fileIO, new Path(warehouse));
+    }
+
+    @Test
+    @Override
+    public void testListDatabasesWhenNoDatabases() {
+        // List databases returns an empty list when there are no databases
+        List<String> databases = catalog.listDatabases();
+        assertThat(databases).isEmpty();
+    }
+}
diff --git a/paimon-hive/paimon-hive-catalog/pom.xml 
b/paimon-hive/paimon-hive-catalog/pom.xml
index 105d27a6a..61f714721 100644
--- a/paimon-hive/paimon-hive-catalog/pom.xml
+++ b/paimon-hive/paimon-hive-catalog/pom.xml
@@ -128,6 +128,100 @@ under the License.
                 </exclusion>
             </exclusions>
         </dependency>
+
+        <!-- Test -->
+
+        <dependency>
+            <groupId>org.apache.paimon</groupId>
+            <artifactId>paimon-core</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.paimon</groupId>
+            <artifactId>paimon-format</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.hive</groupId>
+            <artifactId>hive-exec</artifactId>
+            <version>${hive.version}</version>
+            <scope>provided</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-annotations</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-databind</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.orc</groupId>
+                    <artifactId>orc-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.pentaho</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.calcite</groupId>
+                    <artifactId>calcite-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.calcite</groupId>
+                    <artifactId>calcite-druid</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.calcite.avatica</groupId>
+                    <artifactId>avatica</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.calcite</groupId>
+                    <artifactId>calcite-avatica</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-inline</artifactId>
+            <version>${mockito.version}</version>
+            <type>jar</type>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>${mockito.version}</version>
+            <type>jar</type>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-junit-jupiter</artifactId>
+            <version>${mockito.version}</version>
+            <type>jar</type>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/HiveCatalogTest.java
 
b/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/HiveCatalogTest.java
new file mode 100644
index 000000000..9b9ef1be8
--- /dev/null
+++ 
b/paimon-hive/paimon-hive-catalog/src/test/java/org/apache/paimon/hive/HiveCatalogTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.paimon.hive;
+
+import org.apache.paimon.catalog.CatalogTestBase;
+import org.apache.paimon.catalog.Identifier;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+import java.util.List;
+import java.util.UUID;
+
+import static 
org.apache.hadoop.hive.conf.HiveConf.ConfVars.METASTORECONNECTURLKEY;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
+
+/** Tests for {@link HiveCatalog}. */
+public class HiveCatalogTest extends CatalogTestBase {
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        super.setUp();
+        HiveConf hiveConf = new HiveConf();
+        String jdoConnectionURL = "jdbc:derby:memory:" + UUID.randomUUID();
+        hiveConf.setVar(METASTORECONNECTURLKEY, jdoConnectionURL + 
";create=true");
+        hiveConf.setVar(HiveConf.ConfVars.METASTOREWAREHOUSE, warehouse);
+        HiveMetaStoreClient metaStoreClient = new 
HiveMetaStoreClient(hiveConf);
+        String metastoreClientClass = 
"org.apache.hadoop.hive.metastore.HiveMetaStoreClient";
+        try (MockedStatic<HiveCatalog> mocked = 
Mockito.mockStatic(HiveCatalog.class)) {
+            mocked.when(() -> HiveCatalog.createClient(hiveConf, 
metastoreClientClass))
+                    .thenReturn(metaStoreClient);
+        }
+        catalog = new HiveCatalog(fileIO, hiveConf, metastoreClientClass);
+    }
+
+    @Test
+    @Override
+    public void testListDatabasesWhenNoDatabases() {
+        // List databases returns an empty list when there are no databases
+        List<String> databases = catalog.listDatabases();
+        assertThat(databases).containsExactly("default");
+    }
+
+    @Test
+    public void testCheckIdentifierUpperCase() throws Exception {
+        catalog.createDatabase("test_db", false);
+        assertThatThrownBy(
+                        () ->
+                                catalog.createTable(
+                                        Identifier.create("TEST_DB", 
"new_table"),
+                                        DEFAULT_TABLE_SCHEMA,
+                                        false))
+                .hasRootCauseInstanceOf(IllegalStateException.class)
+                .hasRootCauseMessage("Database name[TEST_DB] cannot contain 
upper case");
+
+        assertThatThrownBy(
+                        () ->
+                                catalog.createTable(
+                                        Identifier.create("test_db", 
"NEW_TABLE"),
+                                        DEFAULT_TABLE_SCHEMA,
+                                        false))
+                .hasRootCauseInstanceOf(IllegalStateException.class)
+                .hasRootCauseMessage("Table name[NEW_TABLE] cannot contain 
upper case");
+    }
+}
diff --git a/paimon-hive/paimon-hive-catalog/src/test/resources/hive-site.xml 
b/paimon-hive/paimon-hive-catalog/src/test/resources/hive-site.xml
new file mode 100644
index 000000000..6dbe4c962
--- /dev/null
+++ b/paimon-hive/paimon-hive-catalog/src/test/resources/hive-site.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<configuration>
+
+    <!-- allow integral partition filter pushdown to avoid unstable test -->
+       <property>
+               <name>hive.metastore.integral.jdo.pushdown</name>
+               <value>true</value>
+       </property>
+
+       <property>
+               <name>hive.metastore.schema.verification</name>
+               <value>false</value>
+       </property>
+
+       <property>
+               <name>hive.metastore.client.capability.check</name>
+               <value>false</value>
+       </property>
+
+       <property>
+               <name>datanucleus.schema.autoCreateTables</name>
+               <value>true</value>
+       </property>
+
+       <property>
+               <name>datanucleus.schema.autoCreateAll</name>
+               <value>true</value>
+       </property>
+
+       <property>
+               <name>common-key</name>
+               <value>common-val</value>
+       </property>
+
+</configuration>


Reply via email to