This is an automated email from the ASF dual-hosted git repository.
jerryshao pushed a commit to branch branch-1.3
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-1.3 by this push:
new b3eaaaa54b [Cherry-pick to branch-1.3] [#11172] fix(audit): skip audit
events for internal Iceberg REST metadata operations (#11188) (#11440)
b3eaaaa54b is described below
commit b3eaaaa54b7965fa6b6211e37be8c3d6c269b2c1
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Jun 5 11:33:49 2026 +0800
[Cherry-pick to branch-1.3] [#11172] fix(audit): skip audit events for
internal Iceberg REST metadata operations (#11188) (#11440)
**Cherry-pick Information:**
- Original commit: a2839877d3e833dc0b5ed852043c92504fe602bb
- Target branch: `branch-1.3`
- Status: ✅ Clean cherry-pick (no conflicts)
Co-authored-by: Shane <[email protected]>
---
.../java/org/apache/gravitino/GravitinoEnv.java | 98 +++++++++++++++++++++
.../catalog/TableOperationDispatcher.java | 36 +++++++-
.../gravitino/catalog/ViewOperationDispatcher.java | 35 +++++++-
.../catalog/TestTableOperationDispatcher.java | 38 +++++++++
.../catalog/TestViewOperationDispatcher.java | 36 ++++++++
.../dispatcher/IcebergNamespaceHookDispatcher.java | 8 +-
.../dispatcher/IcebergTableHookDispatcher.java | 4 +-
.../dispatcher/IcebergViewHookDispatcher.java | 4 +-
.../provider/DynamicIcebergConfigProvider.java | 4 +-
.../TestIcebergNamespaceHookDispatcher.java | 99 +++++++++++++++++++---
.../dispatcher/TestIcebergTableHookDispatcher.java | 69 ++++++++++++---
.../dispatcher/TestIcebergViewHookDispatcher.java | 41 +++++++--
.../provider/TestDynamicIcebergConfigProvider.java | 64 ++++++++++----
.../authorization/PassThroughAuthorizer.java | 3 +-
.../authorization/TestPassThroughAuthorizer.java | 35 ++++++++
.../jcasbin/TestJcasbinAuthorizer.java | 6 ++
16 files changed, 513 insertions(+), 67 deletions(-)
diff --git a/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
b/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
index df80fad2ca..c845c43c49 100644
--- a/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
+++ b/core/src/main/java/org/apache/gravitino/GravitinoEnv.java
@@ -120,14 +120,17 @@ public class GravitinoEnv {
private EntityStore entityStore;
private CatalogDispatcher catalogDispatcher;
+ private CatalogDispatcher internalCatalogDispatcher;
private CatalogManager catalogManager;
private MetalakeManager metalakeManager;
private SchemaDispatcher schemaDispatcher;
+ private SchemaDispatcher internalSchemaDispatcher;
private TableDispatcher tableDispatcher;
+ private TableDispatcher internalTableDispatcher;
private PartitionDispatcher partitionDispatcher;
@@ -140,6 +143,7 @@ public class GravitinoEnv {
private FunctionDispatcher functionDispatcher;
private ViewDispatcher viewDispatcher;
+ private ViewDispatcher internalViewDispatcher;
private MetalakeDispatcher metalakeDispatcher;
@@ -150,6 +154,7 @@ public class GravitinoEnv {
private PolicyDispatcher policyDispatcher;
private AccessControlDispatcher accessControlDispatcher;
+ private AccessControlDispatcher internalAccessControlDispatcher;
private IdGenerator idGenerator;
@@ -167,6 +172,7 @@ public class GravitinoEnv {
private EventBus eventBus;
private OwnerDispatcher ownerDispatcher;
+ private OwnerDispatcher internalOwnerDispatcher;
private FutureGrantManager futureGrantManager;
private GravitinoAuthorizer gravitinoAuthorizer;
private StatisticDispatcher statisticDispatcher;
@@ -241,6 +247,19 @@ public class GravitinoEnv {
return catalogDispatcher;
}
+ /**
+ * Get the internal CatalogDispatcher associated with the Gravitino
environment.
+ *
+ * <p>The internal dispatcher preserves normalization but skips hooks and
event emission. It is
+ * intended for infrastructure catalog lookups that should not be recorded
as user API audit
+ * events.
+ *
+ * @return The internal CatalogDispatcher instance.
+ */
+ public CatalogDispatcher internalCatalogDispatcher() {
+ return internalCatalogDispatcher;
+ }
+
/**
* Get the SchemaDispatcher associated with the Gravitino environment.
*
@@ -250,6 +269,19 @@ public class GravitinoEnv {
return schemaDispatcher;
}
+ /**
+ * Get the internal SchemaDispatcher associated with the Gravitino
environment.
+ *
+ * <p>The internal dispatcher preserves normalization but skips hooks and
event emission. It is
+ * intended for infrastructure code that synchronizes metadata as part of
another user-visible
+ * operation.
+ *
+ * @return The internal SchemaDispatcher instance.
+ */
+ public SchemaDispatcher internalSchemaDispatcher() {
+ return internalSchemaDispatcher;
+ }
+
/**
* Get the TableDispatcher associated with the Gravitino environment.
*
@@ -259,6 +291,19 @@ public class GravitinoEnv {
return tableDispatcher;
}
+ /**
+ * Get the internal TableDispatcher associated with the Gravitino
environment.
+ *
+ * <p>The internal dispatcher preserves normalization but skips hooks and
event emission. It is
+ * intended for infrastructure code that synchronizes metadata as part of
another user-visible
+ * operation.
+ *
+ * @return The internal TableDispatcher instance.
+ */
+ public TableDispatcher internalTableDispatcher() {
+ return internalTableDispatcher;
+ }
+
/**
* Get the ModelDispatcher associated with the Gravitino environment.
*
@@ -286,6 +331,19 @@ public class GravitinoEnv {
return viewDispatcher;
}
+ /**
+ * Get the internal ViewDispatcher associated with the Gravitino environment.
+ *
+ * <p>The internal dispatcher preserves normalization but skips hook/event
side effects from
+ * dependent schema lookups. It is intended for infrastructure code that
synchronizes metadata as
+ * part of another user-visible operation.
+ *
+ * @return The internal ViewDispatcher instance.
+ */
+ public ViewDispatcher internalViewDispatcher() {
+ return internalViewDispatcher;
+ }
+
/**
* * Get the PartitionDispatcher associated with the Gravitino environment.
*
@@ -382,6 +440,18 @@ public class GravitinoEnv {
return accessControlDispatcher;
}
+ /**
+ * Get the internal AccessControlDispatcher associated with the Gravitino
environment.
+ *
+ * <p>The internal dispatcher skips hooks and event emission. It is intended
for authorization
+ * infrastructure lookups that should not be recorded as user API audit
events.
+ *
+ * @return The internal AccessControlDispatcher instance.
+ */
+ public AccessControlDispatcher internalAccessControlDispatcher() {
+ return internalAccessControlDispatcher;
+ }
+
/**
* Get the tagDispatcher associated with the Gravitino environment.
*
@@ -409,6 +479,18 @@ public class GravitinoEnv {
return ownerDispatcher;
}
+ /**
+ * Get the internal OwnerDispatcher associated with the Gravitino
environment.
+ *
+ * <p>The internal dispatcher skips event emission. It is intended for
infrastructure ownership
+ * synchronization that happens as part of another user-visible operation.
+ *
+ * @return The internal OwnerDispatcher instance.
+ */
+ public OwnerDispatcher internalOwnerDispatcher() {
+ return internalOwnerDispatcher;
+ }
+
/**
* Get the FutureGrantManager associated with the Gravitino environment.
*
@@ -569,6 +651,7 @@ public class GravitinoEnv {
this.catalogManager = new CatalogManager(config, entityStore, idGenerator);
CatalogNormalizeDispatcher catalogNormalizeDispatcher =
new CatalogNormalizeDispatcher(catalogManager);
+ this.internalCatalogDispatcher = catalogNormalizeDispatcher;
CatalogEventDispatcher catalogEventDispatcher =
new CatalogEventDispatcher(eventBus, catalogNormalizeDispatcher);
this.catalogDispatcher = new CatalogHookDispatcher(catalogEventDispatcher);
@@ -580,6 +663,7 @@ public class GravitinoEnv {
new SchemaOperationDispatcher(catalogManager, entityStore,
idGenerator);
SchemaNormalizeDispatcher schemaNormalizeDispatcher =
new SchemaNormalizeDispatcher(schemaOperationDispatcher,
catalogManager);
+ this.internalSchemaDispatcher = schemaNormalizeDispatcher;
SchemaEventDispatcher schemaEventDispatcher =
new SchemaEventDispatcher(eventBus, schemaNormalizeDispatcher);
this.schemaDispatcher = new SchemaHookDispatcher(schemaEventDispatcher);
@@ -588,6 +672,11 @@ public class GravitinoEnv {
new TableOperationDispatcher(catalogManager, entityStore, idGenerator);
TableNormalizeDispatcher tableNormalizeDispatcher =
new TableNormalizeDispatcher(tableOperationDispatcher, catalogManager);
+ TableOperationDispatcher internalTableOperationDispatcher =
+ new TableOperationDispatcher(
+ catalogManager, entityStore, idGenerator, () ->
internalSchemaDispatcher);
+ this.internalTableDispatcher =
+ new TableNormalizeDispatcher(internalTableOperationDispatcher,
catalogManager);
TableEventDispatcher tableEventDispatcher =
new TableEventDispatcher(eventBus, tableNormalizeDispatcher);
this.tableDispatcher = new TableHookDispatcher(tableEventDispatcher);
@@ -644,6 +733,11 @@ public class GravitinoEnv {
new ViewOperationDispatcher(catalogManager, entityStore, idGenerator);
ViewNormalizeDispatcher viewNormalizeDispatcher =
new ViewNormalizeDispatcher(viewOperationDispatcher, catalogManager);
+ ViewOperationDispatcher internalViewOperationDispatcher =
+ new ViewOperationDispatcher(
+ catalogManager, entityStore, idGenerator, () ->
internalSchemaDispatcher);
+ this.internalViewDispatcher =
+ new ViewNormalizeDispatcher(internalViewOperationDispatcher,
catalogManager);
ViewEventDispatcher viewEventDispatcher =
new ViewEventDispatcher(eventBus, viewNormalizeDispatcher);
this.viewDispatcher = viewEventDispatcher;
@@ -657,15 +751,19 @@ public class GravitinoEnv {
if (enableAuthorization) {
AccessControlManager accessControlManager =
new AccessControlManager(entityStore, idGenerator, config);
+ this.internalAccessControlDispatcher = accessControlManager;
AccessControlEventDispatcher accessControlEventDispatcher =
new AccessControlEventDispatcher(eventBus, accessControlManager);
this.accessControlDispatcher = new
AccessControlHookDispatcher(accessControlEventDispatcher);
OwnerDispatcher ownerManager = new OwnerManager(entityStore);
+ this.internalOwnerDispatcher = ownerManager;
this.ownerDispatcher = new OwnerEventManager(eventBus, ownerManager);
this.futureGrantManager = new FutureGrantManager(entityStore,
ownerManager);
} else {
this.accessControlDispatcher = null;
+ this.internalAccessControlDispatcher = null;
this.ownerDispatcher = null;
+ this.internalOwnerDispatcher = null;
this.futureGrantManager = null;
}
diff --git
a/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
b/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
index 244edec88d..34677f3e31 100644
---
a/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
+++
b/core/src/main/java/org/apache/gravitino/catalog/TableOperationDispatcher.java
@@ -26,6 +26,7 @@ import static
org.apache.gravitino.utils.NameIdentifierUtil.getCatalogIdentifier
import static
org.apache.gravitino.utils.NameIdentifierUtil.getSchemaIdentifier;
import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import java.time.Instant;
import java.util.Arrays;
@@ -33,6 +34,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.commons.lang3.tuple.Pair;
@@ -72,6 +74,8 @@ public class TableOperationDispatcher extends
OperationDispatcher implements Tab
private static final Logger LOG =
LoggerFactory.getLogger(TableOperationDispatcher.class);
+ private final Supplier<SchemaDispatcher> schemaDispatcherSupplier;
+
/**
* Creates a new TableOperationDispatcher instance.
*
@@ -81,7 +85,26 @@ public class TableOperationDispatcher extends
OperationDispatcher implements Tab
*/
public TableOperationDispatcher(
CatalogManager catalogManager, EntityStore store, IdGenerator
idGenerator) {
+ this(catalogManager, store, idGenerator, () ->
GravitinoEnv.getInstance().schemaDispatcher());
+ }
+
+ /**
+ * Creates a new TableOperationDispatcher instance.
+ *
+ * @param catalogManager The CatalogManager instance to be used for table
operations.
+ * @param store The EntityStore instance to be used for table operations.
+ * @param idGenerator The IdGenerator instance to be used for table
operations.
+ * @param schemaDispatcherSupplier The SchemaDispatcher supplier to ensure
schemas are imported.
+ */
+ public TableOperationDispatcher(
+ CatalogManager catalogManager,
+ EntityStore store,
+ IdGenerator idGenerator,
+ Supplier<SchemaDispatcher> schemaDispatcherSupplier) {
super(catalogManager, store, idGenerator);
+ this.schemaDispatcherSupplier =
+ Preconditions.checkNotNull(
+ schemaDispatcherSupplier, "schemaDispatcherSupplier must not be
null");
}
/**
@@ -118,7 +141,7 @@ public class TableOperationDispatcher extends
OperationDispatcher implements Tab
if (!entityCombinedTable.imported()) {
// Load the schema to make sure the schema is imported.
- SchemaDispatcher schemaDispatcher =
GravitinoEnv.getInstance().schemaDispatcher();
+ SchemaDispatcher schemaDispatcher = getSchemaDispatcher();
NameIdentifier schemaIdent =
NameIdentifier.of(ident.namespace().levels());
schemaDispatcher.loadSchema(schemaIdent);
@@ -180,7 +203,7 @@ public class TableOperationDispatcher extends
OperationDispatcher implements Tab
throws NoSuchSchemaException, TableAlreadyExistsException {
// Load the schema to make sure the schema exists.
- SchemaDispatcher schemaDispatcher =
GravitinoEnv.getInstance().schemaDispatcher();
+ SchemaDispatcher schemaDispatcher = getSchemaDispatcher();
NameIdentifier schemaIdent = NameIdentifier.of(ident.namespace().levels());
schemaDispatcher.loadSchema(schemaIdent);
@@ -505,6 +528,15 @@ public class TableOperationDispatcher extends
OperationDispatcher implements Tab
table.tableFromCatalog().properties()));
}
+ private SchemaDispatcher getSchemaDispatcher() {
+ SchemaDispatcher schemaDispatcher = schemaDispatcherSupplier.get();
+ Preconditions.checkArgument(
+ schemaDispatcher != null,
+ "schemaDispatcherSupplier returned null. "
+ + "SchemaDispatcher must be available for table operations.");
+ return schemaDispatcher;
+ }
+
private EntityCombinedTable internalLoadTable(NameIdentifier ident) {
NameIdentifier catalogIdentifier = getCatalogIdentifier(ident);
Table table =
diff --git
a/core/src/main/java/org/apache/gravitino/catalog/ViewOperationDispatcher.java
b/core/src/main/java/org/apache/gravitino/catalog/ViewOperationDispatcher.java
index a7b9ab1416..5b3937ee48 100644
---
a/core/src/main/java/org/apache/gravitino/catalog/ViewOperationDispatcher.java
+++
b/core/src/main/java/org/apache/gravitino/catalog/ViewOperationDispatcher.java
@@ -29,6 +29,7 @@ import java.time.Instant;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Supplier;
import javax.annotation.Nullable;
import org.apache.gravitino.EntityAlreadyExistsException;
import org.apache.gravitino.EntityStore;
@@ -60,6 +61,8 @@ public class ViewOperationDispatcher extends
OperationDispatcher implements View
private static final Logger LOG =
LoggerFactory.getLogger(ViewOperationDispatcher.class);
+ private final Supplier<SchemaDispatcher> schemaDispatcherSupplier;
+
/**
* Creates a new ViewOperationDispatcher instance.
*
@@ -69,7 +72,26 @@ public class ViewOperationDispatcher extends
OperationDispatcher implements View
*/
public ViewOperationDispatcher(
CatalogManager catalogManager, EntityStore store, IdGenerator
idGenerator) {
+ this(catalogManager, store, idGenerator, () ->
GravitinoEnv.getInstance().schemaDispatcher());
+ }
+
+ /**
+ * Creates a new ViewOperationDispatcher instance.
+ *
+ * @param catalogManager The CatalogManager instance to be used for view
operations.
+ * @param store The EntityStore instance to be used for view operations.
+ * @param idGenerator The IdGenerator instance to be used for view
operations.
+ * @param schemaDispatcherSupplier The SchemaDispatcher supplier to ensure
schemas are imported.
+ */
+ public ViewOperationDispatcher(
+ CatalogManager catalogManager,
+ EntityStore store,
+ IdGenerator idGenerator,
+ Supplier<SchemaDispatcher> schemaDispatcherSupplier) {
super(catalogManager, store, idGenerator);
+ this.schemaDispatcherSupplier =
+ Preconditions.checkNotNull(
+ schemaDispatcherSupplier, "schemaDispatcherSupplier must not be
null");
}
/**
@@ -107,7 +129,7 @@ public class ViewOperationDispatcher extends
OperationDispatcher implements View
TreeLockUtils.doWithTreeLock(ident, LockType.READ, () ->
internalLoadView(ident));
if (!entityCombinedView.imported()) {
- SchemaDispatcher schemaDispatcher =
GravitinoEnv.getInstance().schemaDispatcher();
+ SchemaDispatcher schemaDispatcher = getSchemaDispatcher();
NameIdentifier schemaIdent =
NameIdentifier.of(ident.namespace().levels());
schemaDispatcher.loadSchema(schemaIdent);
@@ -148,7 +170,7 @@ public class ViewOperationDispatcher extends
OperationDispatcher implements View
"representations must not be null or empty");
// Load the schema to make sure the schema exists.
- SchemaDispatcher schemaDispatcher =
GravitinoEnv.getInstance().schemaDispatcher();
+ SchemaDispatcher schemaDispatcher = getSchemaDispatcher();
NameIdentifier schemaIdent = NameIdentifier.of(ident.namespace().levels());
schemaDispatcher.loadSchema(schemaIdent);
@@ -527,6 +549,15 @@ public class ViewOperationDispatcher extends
OperationDispatcher implements View
.withImported(true);
}
+ private SchemaDispatcher getSchemaDispatcher() {
+ SchemaDispatcher schemaDispatcher = schemaDispatcherSupplier.get();
+ Preconditions.checkArgument(
+ schemaDispatcher != null,
+ "schemaDispatcherSupplier returned null. "
+ + "SchemaDispatcher must be available for view operations.");
+ return schemaDispatcher;
+ }
+
private ViewEntity applyChangesToEntity(
ViewEntity current, View alteredView, ViewChange[] changes) {
String name = alteredView.name();
diff --git
a/core/src/test/java/org/apache/gravitino/catalog/TestTableOperationDispatcher.java
b/core/src/test/java/org/apache/gravitino/catalog/TestTableOperationDispatcher.java
index 9c44e46c7e..10b21dc41d 100644
---
a/core/src/test/java/org/apache/gravitino/catalog/TestTableOperationDispatcher.java
+++
b/core/src/test/java/org/apache/gravitino/catalog/TestTableOperationDispatcher.java
@@ -43,6 +43,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
+import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.commons.lang3.reflect.FieldUtils;
@@ -258,6 +259,43 @@ public class TestTableOperationDispatcher extends
TestOperationDispatcher {
Assertions.assertEquals("test", loadedTable4.auditInfo().creator());
}
+ @Test
+ public void
testTableOperationDispatcherRejectsNullSchemaDispatcherSupplier() {
+ Assertions.assertThrows(
+ NullPointerException.class,
+ () -> new TableOperationDispatcher(catalogManager, entityStore,
idGenerator, null));
+ }
+
+ @Test
+ public void
testCreateTableFailsFastWhenSchemaDispatcherSupplierReturnsNull() throws
IOException {
+ Namespace tableNs = Namespace.of(metalake, catalog,
"schema-null-dispatcher");
+ Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
+
schemaOperationDispatcher.createSchema(NameIdentifier.of(tableNs.levels()),
"comment", props);
+
+ Supplier<SchemaDispatcher> nullSchemaDispatcherSupplier = () -> null;
+ TableOperationDispatcher dispatcher =
+ new TableOperationDispatcher(
+ catalogManager, entityStore, idGenerator,
nullSchemaDispatcherSupplier);
+ NameIdentifier tableIdent = NameIdentifier.of(tableNs,
"table_null_dispatcher");
+ Column[] columns =
+ new Column[] {
+ TestColumn.builder()
+ .withName("col1")
+ .withPosition(0)
+ .withType(Types.StringType.get())
+ .build()
+ };
+
+ IllegalArgumentException exception =
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () -> dispatcher.createTable(tableIdent, columns, "comment",
props, new Transform[0]));
+ Assertions.assertEquals(
+ "schemaDispatcherSupplier returned null. "
+ + "SchemaDispatcher must be available for table operations.",
+ exception.getMessage());
+ }
+
@Test
public void testConcurrentImportTableReusesExistingEntity() throws
IOException {
Namespace tableNs = Namespace.of(metalake, catalog, "schema52");
diff --git
a/core/src/test/java/org/apache/gravitino/catalog/TestViewOperationDispatcher.java
b/core/src/test/java/org/apache/gravitino/catalog/TestViewOperationDispatcher.java
index a3c4146e8a..5f28bcd20e 100644
---
a/core/src/test/java/org/apache/gravitino/catalog/TestViewOperationDispatcher.java
+++
b/core/src/test/java/org/apache/gravitino/catalog/TestViewOperationDispatcher.java
@@ -40,6 +40,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import java.util.function.Supplier;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.gravitino.Config;
import org.apache.gravitino.Entity;
@@ -198,6 +199,41 @@ public class TestViewOperationDispatcher extends
TestOperationDispatcher {
}
}
+ @Test
+ public void testViewOperationDispatcherRejectsNullSchemaDispatcherSupplier()
{
+ Assertions.assertThrows(
+ NullPointerException.class,
+ () -> new ViewOperationDispatcher(catalogManager, entityStore,
idGenerator, null));
+ }
+
+ @Test
+ public void testCreateViewFailsFastWhenSchemaDispatcherSupplierReturnsNull()
throws IOException {
+ Namespace viewNs = Namespace.of(metalake, catalog,
"schema-null-view-dispatcher");
+ Map<String, String> props = ImmutableMap.of("k1", "v1", "k2", "v2");
+ schemaOperationDispatcher.createSchema(NameIdentifier.of(viewNs.levels()),
"comment", props);
+
+ Supplier<SchemaDispatcher> nullSchemaDispatcherSupplier = () -> null;
+ ViewOperationDispatcher dispatcher =
+ new ViewOperationDispatcher(
+ catalogManager, entityStore, idGenerator,
nullSchemaDispatcherSupplier);
+ NameIdentifier viewIdent = NameIdentifier.of(viewNs,
"view_null_dispatcher");
+ Representation[] representations =
+ new Representation[] {
+ SQLRepresentation.builder().withDialect("spark-sql").withSql("SELECT
1").build()
+ };
+
+ IllegalArgumentException exception =
+ Assertions.assertThrows(
+ IllegalArgumentException.class,
+ () ->
+ dispatcher.createView(
+ viewIdent, "comment", new Column[0], representations,
null, null, props));
+ Assertions.assertEquals(
+ "schemaDispatcherSupplier returned null. "
+ + "SchemaDispatcher must be available for view operations.",
+ exception.getMessage());
+ }
+
@Test
public void testLoadViewAutoImportsIntoEntityStore() throws IOException {
Namespace viewNs = Namespace.of(metalake, catalog, "schema63");
diff --git
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergNamespaceHookDispatcher.java
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergNamespaceHookDispatcher.java
index 505b5dc87e..e316352339 100644
---
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergNamespaceHookDispatcher.java
+++
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergNamespaceHookDispatcher.java
@@ -96,7 +96,7 @@ public class IcebergNamespaceHookDispatcher implements
IcebergNamespaceOperation
catalogName,
newlyOwned,
context.userName(),
- GravitinoEnv.getInstance().ownerDispatcher());
+ GravitinoEnv.getInstance().internalOwnerDispatcher());
return createNamespaceResponse;
}
@@ -228,13 +228,13 @@ public class IcebergNamespaceHookDispatcher implements
IcebergNamespaceOperation
namespace,
registerTableRequest.name(),
context.userName(),
- GravitinoEnv.getInstance().ownerDispatcher());
+ GravitinoEnv.getInstance().internalOwnerDispatcher());
return response;
}
private void importTable(String catalogName, Namespace namespace, String
tableName) {
- TableDispatcher tableDispatcher =
GravitinoEnv.getInstance().tableDispatcher();
+ TableDispatcher tableDispatcher =
GravitinoEnv.getInstance().internalTableDispatcher();
if (tableDispatcher != null) {
tableDispatcher.loadTable(
IcebergIdentifierUtils.toGravitinoTableIdentifier(
@@ -246,7 +246,7 @@ public class IcebergNamespaceHookDispatcher implements
IcebergNamespaceOperation
}
private void importSchema(String catalogName, Namespace namespace) {
- SchemaDispatcher schemaDispatcher =
GravitinoEnv.getInstance().schemaDispatcher();
+ SchemaDispatcher schemaDispatcher =
GravitinoEnv.getInstance().internalSchemaDispatcher();
if (schemaDispatcher != null) {
schemaDispatcher.loadSchema(
IcebergIdentifierUtils.toGravitinoSchemaIdentifier(
diff --git
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableHookDispatcher.java
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableHookDispatcher.java
index 9f081571f5..d39d93f1ae 100644
---
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableHookDispatcher.java
+++
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableHookDispatcher.java
@@ -209,11 +209,11 @@ public class IcebergTableHookDispatcher implements
IcebergTableOperationDispatch
namespace,
tableName,
context.userName(),
- GravitinoEnv.getInstance().ownerDispatcher());
+ GravitinoEnv.getInstance().internalOwnerDispatcher());
}
private void importTableEntity(String catalogName, Namespace namespace,
String tableName) {
- TableDispatcher tableDispatcher =
GravitinoEnv.getInstance().tableDispatcher();
+ TableDispatcher tableDispatcher =
GravitinoEnv.getInstance().internalTableDispatcher();
if (tableDispatcher != null) {
tableDispatcher.loadTable(
IcebergIdentifierUtils.toGravitinoTableIdentifier(
diff --git
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergViewHookDispatcher.java
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergViewHookDispatcher.java
index a6e35fef50..dcde32b92c 100644
---
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergViewHookDispatcher.java
+++
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergViewHookDispatcher.java
@@ -76,7 +76,7 @@ public class IcebergViewHookDispatcher implements
IcebergViewOperationDispatcher
namespace,
createViewRequest.name(),
context.userName(),
- GravitinoEnv.getInstance().ownerDispatcher());
+ GravitinoEnv.getInstance().internalOwnerDispatcher());
return response;
}
@@ -181,7 +181,7 @@ public class IcebergViewHookDispatcher implements
IcebergViewOperationDispatcher
* @param viewName The name of the view.
*/
private void importView(String catalogName, Namespace namespace, String
viewName) {
- ViewDispatcher viewDispatcher =
GravitinoEnv.getInstance().viewDispatcher();
+ ViewDispatcher viewDispatcher =
GravitinoEnv.getInstance().internalViewDispatcher();
if (viewDispatcher != null) {
try {
viewDispatcher.loadView(
diff --git
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/provider/DynamicIcebergConfigProvider.java
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/provider/DynamicIcebergConfigProvider.java
index 9194b4dc07..2bbefbade0 100644
---
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/provider/DynamicIcebergConfigProvider.java
+++
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/provider/DynamicIcebergConfigProvider.java
@@ -251,10 +251,10 @@ public class DynamicIcebergConfigProvider implements
IcebergConfigProvider {
InternalCatalogFetcher(String metalake) {
this.metalake = metalake;
- CatalogDispatcher dispatcher =
GravitinoEnv.getInstance().catalogDispatcher();
+ CatalogDispatcher dispatcher =
GravitinoEnv.getInstance().internalCatalogDispatcher();
Preconditions.checkState(
dispatcher != null,
- "CatalogDispatcher is not available. "
+ "Internal CatalogDispatcher is not available. "
+ "Internal catalog fetcher requires running within Gravitino
server.");
this.catalogDispatcher = dispatcher;
}
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergNamespaceHookDispatcher.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergNamespaceHookDispatcher.java
index eb212f8e4f..7d5e76922b 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergNamespaceHookDispatcher.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergNamespaceHookDispatcher.java
@@ -67,21 +67,65 @@ public class TestIcebergNamespaceHookDispatcher {
private IcebergNamespaceHookDispatcher hookDispatcher;
private IcebergNamespaceOperationDispatcher mockDispatcher;
private OwnerDispatcher mockOwnerDispatcher;
+ private OwnerDispatcher mockInternalOwnerDispatcher;
+ private SchemaDispatcher mockSchemaDispatcher;
+ private SchemaDispatcher mockInternalSchemaDispatcher;
+ private TableDispatcher mockTableDispatcher;
+ private TableDispatcher mockInternalTableDispatcher;
private EntityStore mockEntityStore;
private LockManager mockLockManager;
private IcebergRequestContext mockContext;
+ private OwnerDispatcher previousOwnerDispatcher;
+ private OwnerDispatcher previousInternalOwnerDispatcher;
+ private SchemaDispatcher previousSchemaDispatcher;
+ private SchemaDispatcher previousInternalSchemaDispatcher;
+ private TableDispatcher previousTableDispatcher;
+ private TableDispatcher previousInternalTableDispatcher;
+ private EntityStore previousEntityStore;
+ private LockManager previousLockManager;
+
@BeforeEach
public void setUp() throws IllegalAccessException {
mockDispatcher = mock(IcebergNamespaceOperationDispatcher.class);
mockOwnerDispatcher = mock(OwnerDispatcher.class);
- SchemaDispatcher mockSchemaDispatcher = mock(SchemaDispatcher.class);
- TableDispatcher mockTableDispatcher = mock(TableDispatcher.class);
+ mockInternalOwnerDispatcher = mock(OwnerDispatcher.class);
+ mockSchemaDispatcher = mock(SchemaDispatcher.class);
+ mockInternalSchemaDispatcher = mock(SchemaDispatcher.class);
+ mockTableDispatcher = mock(TableDispatcher.class);
+ mockInternalTableDispatcher = mock(TableDispatcher.class);
+
+ previousOwnerDispatcher =
+ (OwnerDispatcher) FieldUtils.readField(GravitinoEnv.getInstance(),
"ownerDispatcher", true);
+ previousInternalOwnerDispatcher =
+ (OwnerDispatcher)
+ FieldUtils.readField(GravitinoEnv.getInstance(),
"internalOwnerDispatcher", true);
+ previousSchemaDispatcher =
+ (SchemaDispatcher)
+ FieldUtils.readField(GravitinoEnv.getInstance(),
"schemaDispatcher", true);
+ previousInternalSchemaDispatcher =
+ (SchemaDispatcher)
+ FieldUtils.readField(GravitinoEnv.getInstance(),
"internalSchemaDispatcher", true);
+ previousTableDispatcher =
+ (TableDispatcher) FieldUtils.readField(GravitinoEnv.getInstance(),
"tableDispatcher", true);
+ previousInternalTableDispatcher =
+ (TableDispatcher)
+ FieldUtils.readField(GravitinoEnv.getInstance(),
"internalTableDispatcher", true);
+ previousEntityStore =
+ (EntityStore) FieldUtils.readField(GravitinoEnv.getInstance(),
"entityStore", true);
+ previousLockManager =
+ (LockManager) FieldUtils.readField(GravitinoEnv.getInstance(),
"lockManager", true);
FieldUtils.writeField(GravitinoEnv.getInstance(), "ownerDispatcher",
mockOwnerDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "internalOwnerDispatcher",
mockInternalOwnerDispatcher, true);
FieldUtils.writeField(
GravitinoEnv.getInstance(), "schemaDispatcher", mockSchemaDispatcher,
true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "internalSchemaDispatcher",
mockInternalSchemaDispatcher, true);
FieldUtils.writeField(GravitinoEnv.getInstance(), "tableDispatcher",
mockTableDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "internalTableDispatcher",
mockInternalTableDispatcher, true);
mockEntityStore = mock(EntityStore.class);
FieldUtils.writeField(GravitinoEnv.getInstance(), "entityStore",
mockEntityStore, true);
@@ -105,11 +149,29 @@ public class TestIcebergNamespaceHookDispatcher {
@AfterEach
public void tearDown() throws IllegalAccessException {
- FieldUtils.writeField(GravitinoEnv.getInstance(), "ownerDispatcher", null,
true);
- FieldUtils.writeField(GravitinoEnv.getInstance(), "schemaDispatcher",
null, true);
- FieldUtils.writeField(GravitinoEnv.getInstance(), "tableDispatcher", null,
true);
- FieldUtils.writeField(GravitinoEnv.getInstance(), "entityStore", null,
true);
- FieldUtils.writeField(GravitinoEnv.getInstance(), "lockManager", null,
true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "ownerDispatcher",
previousOwnerDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(),
+ "internalOwnerDispatcher",
+ previousInternalOwnerDispatcher,
+ true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "schemaDispatcher",
previousSchemaDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(),
+ "internalSchemaDispatcher",
+ previousInternalSchemaDispatcher,
+ true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "tableDispatcher",
previousTableDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(),
+ "internalTableDispatcher",
+ previousInternalTableDispatcher,
+ true);
+ FieldUtils.writeField(GravitinoEnv.getInstance(), "entityStore",
previousEntityStore, true);
+ FieldUtils.writeField(GravitinoEnv.getInstance(), "lockManager",
previousLockManager, true);
Class<?> holderClass =
Arrays.stream(IcebergRESTServerContext.class.getDeclaredClasses())
@@ -129,7 +191,7 @@ public class TestIcebergNamespaceHookDispatcher {
when(mockDispatcher.createNamespace(mockContext,
mockRequest)).thenReturn(mockResponse);
doThrow(new RuntimeException("Set owner failed"))
- .when(mockOwnerDispatcher)
+ .when(mockInternalOwnerDispatcher)
.setOwners(any(), any(), any(), any());
RuntimeException thrown =
@@ -137,6 +199,7 @@ public class TestIcebergNamespaceHookDispatcher {
RuntimeException.class, () ->
hookDispatcher.createNamespace(mockContext, mockRequest));
Assertions.assertEquals("Set owner failed", thrown.getMessage());
verify(mockDispatcher).createNamespace(mockContext, mockRequest);
+ verify(mockOwnerDispatcher, never()).setOwners(any(), any(), any(), any());
}
@Test
@@ -150,7 +213,7 @@ public class TestIcebergNamespaceHookDispatcher {
.thenReturn(mockResponse);
doThrow(new RuntimeException("Set owner failed"))
- .when(mockOwnerDispatcher)
+ .when(mockInternalOwnerDispatcher)
.setOwner(any(), any(), any(), any());
RuntimeException thrown =
@@ -159,6 +222,7 @@ public class TestIcebergNamespaceHookDispatcher {
() -> hookDispatcher.registerTable(mockContext, namespace,
mockRequest));
Assertions.assertEquals("Set owner failed", thrown.getMessage());
verify(mockDispatcher).registerTable(mockContext, namespace, mockRequest);
+ verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
}
@Test
@@ -172,15 +236,18 @@ public class TestIcebergNamespaceHookDispatcher {
// Schema import (loadSchema) throwing must propagate so the caller learns
the namespace
// exists in Iceberg but is not registered in Gravitino. setOwner is
therefore unreachable.
- SchemaDispatcher schemaDispatcher =
GravitinoEnv.getInstance().schemaDispatcher();
- doThrow(new RuntimeException("Import
failed")).when(schemaDispatcher).loadSchema(any());
+ doThrow(new RuntimeException("Import failed"))
+ .when(mockInternalSchemaDispatcher)
+ .loadSchema(any());
RuntimeException thrown =
Assertions.assertThrows(
RuntimeException.class, () ->
hookDispatcher.createNamespace(mockContext, mockRequest));
Assertions.assertEquals("Import failed", thrown.getMessage());
+ verify(mockInternalOwnerDispatcher, never()).setOwners(any(), any(),
any(), any());
verify(mockOwnerDispatcher, never()).setOwners(any(), any(), any(), any());
+ verify(mockSchemaDispatcher, never()).loadSchema(any());
}
@Test
@@ -195,8 +262,9 @@ public class TestIcebergNamespaceHookDispatcher {
// Table import (loadTable) throwing must propagate so the caller learns
the table exists in
// Iceberg but is not registered in Gravitino. setOwner is therefore
unreachable.
- TableDispatcher tableDispatcher =
GravitinoEnv.getInstance().tableDispatcher();
- doThrow(new RuntimeException("Import
failed")).when(tableDispatcher).loadTable(any());
+ doThrow(new RuntimeException("Import failed"))
+ .when(mockInternalTableDispatcher)
+ .loadTable(any());
RuntimeException thrown =
Assertions.assertThrows(
@@ -204,7 +272,9 @@ public class TestIcebergNamespaceHookDispatcher {
() -> hookDispatcher.registerTable(mockContext, namespace,
mockRequest));
Assertions.assertEquals("Import failed", thrown.getMessage());
+ verify(mockInternalOwnerDispatcher, never()).setOwner(any(), any(), any(),
any());
verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
+ verify(mockTableDispatcher, never()).loadTable(any());
}
@Test
@@ -248,8 +318,9 @@ public class TestIcebergNamespaceHookDispatcher {
@SuppressWarnings("unchecked")
ArgumentCaptor<List<MetadataObject>> captor =
ArgumentCaptor.forClass(List.class);
- verify(mockOwnerDispatcher)
+ verify(mockInternalOwnerDispatcher)
.setOwners(eq(TEST_METALAKE), captor.capture(), eq(TEST_USER),
eq(Owner.Type.USER));
+ verify(mockOwnerDispatcher, never()).setOwners(any(), any(), any(), any());
List<String> names =
captor.getValue().stream().map(MetadataObject::fullName).collect(Collectors.toList());
Assertions.assertEquals(
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergTableHookDispatcher.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergTableHookDispatcher.java
index 2d4f2e125c..40a11ec015 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergTableHookDispatcher.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergTableHookDispatcher.java
@@ -76,13 +76,17 @@ public class TestIcebergTableHookDispatcher {
private IcebergTableOperationDispatcher mockDispatcher;
private EntityStore mockEntityStore;
private TableDispatcher mockTableDispatcher;
+ private TableDispatcher mockInternalTableDispatcher;
private OwnerDispatcher mockOwnerDispatcher;
+ private OwnerDispatcher mockInternalOwnerDispatcher;
private IcebergRequestContext mockContext;
private Config previousConfig;
private EntityStore previousEntityStore;
private TableDispatcher previousTableDispatcher;
+ private TableDispatcher previousInternalTableDispatcher;
private OwnerDispatcher previousOwnerDispatcher;
+ private OwnerDispatcher previousInternalOwnerDispatcher;
@BeforeEach
public void setUp() throws IllegalAccessException {
@@ -92,7 +96,9 @@ public class TestIcebergTableHookDispatcher {
// Mock GravitinoEnv components
mockEntityStore = mock(EntityStore.class);
mockTableDispatcher = mock(TableDispatcher.class);
+ mockInternalTableDispatcher = mock(TableDispatcher.class);
mockOwnerDispatcher = mock(OwnerDispatcher.class);
+ mockInternalOwnerDispatcher = mock(OwnerDispatcher.class);
Config mockConfig = mock(Config.class);
when(mockConfig.get(Configs.SCHEMA_SEPARATOR)).thenReturn(":");
@@ -101,12 +107,22 @@ public class TestIcebergTableHookDispatcher {
(EntityStore) FieldUtils.readField(GravitinoEnv.getInstance(),
"entityStore", true);
previousTableDispatcher =
(TableDispatcher) FieldUtils.readField(GravitinoEnv.getInstance(),
"tableDispatcher", true);
+ previousInternalTableDispatcher =
+ (TableDispatcher)
+ FieldUtils.readField(GravitinoEnv.getInstance(),
"internalTableDispatcher", true);
previousOwnerDispatcher =
(OwnerDispatcher) FieldUtils.readField(GravitinoEnv.getInstance(),
"ownerDispatcher", true);
+ previousInternalOwnerDispatcher =
+ (OwnerDispatcher)
+ FieldUtils.readField(GravitinoEnv.getInstance(),
"internalOwnerDispatcher", true);
FieldUtils.writeField(GravitinoEnv.getInstance(), "config", mockConfig,
true);
FieldUtils.writeField(GravitinoEnv.getInstance(), "entityStore",
mockEntityStore, true);
FieldUtils.writeField(GravitinoEnv.getInstance(), "tableDispatcher",
mockTableDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "internalTableDispatcher",
mockInternalTableDispatcher, true);
FieldUtils.writeField(GravitinoEnv.getInstance(), "ownerDispatcher",
mockOwnerDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "internalOwnerDispatcher",
mockInternalOwnerDispatcher, true);
// Create mock IcebergRESTServerContext
IcebergConfigProvider mockConfigProvider =
mock(IcebergConfigProvider.class);
@@ -131,8 +147,18 @@ public class TestIcebergTableHookDispatcher {
FieldUtils.writeField(GravitinoEnv.getInstance(), "entityStore",
previousEntityStore, true);
FieldUtils.writeField(
GravitinoEnv.getInstance(), "tableDispatcher",
previousTableDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(),
+ "internalTableDispatcher",
+ previousInternalTableDispatcher,
+ true);
FieldUtils.writeField(
GravitinoEnv.getInstance(), "ownerDispatcher",
previousOwnerDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(),
+ "internalOwnerDispatcher",
+ previousInternalOwnerDispatcher,
+ true);
// Reset IcebergRESTServerContext singleton
Class<?> holderClass =
@@ -161,12 +187,14 @@ public class TestIcebergTableHookDispatcher {
NameIdentifier expectedIdentifier =
IcebergIdentifierUtils.toGravitinoTableIdentifier(
TEST_METALAKE, TEST_CATALOG, TableIdentifier.of(namespace,
"test_table"), ":");
- verify(mockTableDispatcher).loadTable(expectedIdentifier);
+ verify(mockInternalTableDispatcher).loadTable(expectedIdentifier);
+ verify(mockTableDispatcher, never()).loadTable(any());
// Verify ownership was set
ArgumentCaptor<String> userCaptor = ArgumentCaptor.forClass(String.class);
- verify(mockOwnerDispatcher)
+ verify(mockInternalOwnerDispatcher)
.setOwner(eq(TEST_METALAKE), any(), userCaptor.capture(),
eq(Owner.Type.USER));
+ verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
Assertions.assertEquals(TEST_USER, userCaptor.getValue());
}
@@ -196,7 +224,8 @@ public class TestIcebergTableHookDispatcher {
IcebergIdentifierUtils.toGravitinoTableIdentifier(
TEST_METALAKE, TEST_CATALOG, tableId, ":");
verify(mockEntityStore, never()).delete(expectedIdentifier,
Entity.EntityType.TABLE);
- verify(mockTableDispatcher).loadTable(expectedIdentifier);
+ verify(mockInternalTableDispatcher).loadTable(expectedIdentifier);
+ verify(mockTableDispatcher, never()).loadTable(any());
}
@Test
@@ -211,7 +240,8 @@ public class TestIcebergTableHookDispatcher {
IcebergIdentifierUtils.toGravitinoTableIdentifier(
TEST_METALAKE, TEST_CATALOG, tableId, ":");
verify(mockEntityStore).delete(expectedIdentifier,
Entity.EntityType.TABLE);
- verify(mockTableDispatcher).loadTable(expectedIdentifier);
+ verify(mockInternalTableDispatcher).loadTable(expectedIdentifier);
+ verify(mockTableDispatcher, never()).loadTable(any());
}
@Test
@@ -293,7 +323,8 @@ public class TestIcebergTableHookDispatcher {
NameIdentifier destIdentifier =
IcebergIdentifierUtils.toGravitinoTableIdentifier(TEST_METALAKE,
TEST_CATALOG, dest, ":");
verify(mockEntityStore).delete(sourceIdentifier, Entity.EntityType.TABLE);
- verify(mockTableDispatcher).loadTable(destIdentifier);
+ verify(mockInternalTableDispatcher).loadTable(destIdentifier);
+ verify(mockTableDispatcher, never()).loadTable(any());
}
@Test
@@ -312,12 +343,15 @@ public class TestIcebergTableHookDispatcher {
when(mockEntityStore.update(any(), eq(TableEntity.class),
eq(Entity.EntityType.TABLE), any()))
.thenReturn(mockTableEntity);
when(mockDispatcher.tableExists(mockContext, dest)).thenReturn(true);
- doThrow(new RuntimeException("import
failed")).when(mockTableDispatcher).loadTable(any());
+ doThrow(new RuntimeException("import failed"))
+ .when(mockInternalTableDispatcher)
+ .loadTable(any());
Assertions.assertDoesNotThrow(() ->
hookDispatcher.renameTable(mockContext, request));
verify(mockDispatcher).renameTable(mockContext, request);
- verify(mockTableDispatcher).loadTable(any());
+ verify(mockInternalTableDispatcher).loadTable(any());
+ verify(mockTableDispatcher, never()).loadTable(any());
}
@Test
@@ -364,7 +398,7 @@ public class TestIcebergTableHookDispatcher {
when(mockDispatcher.createTable(mockContext, namespace,
request)).thenReturn(mockResponse);
doThrow(new RuntimeException("Set owner failed"))
- .when(mockOwnerDispatcher)
+ .when(mockInternalOwnerDispatcher)
.setOwner(any(), any(), any(), any());
RuntimeException thrown =
@@ -373,6 +407,7 @@ public class TestIcebergTableHookDispatcher {
() -> hookDispatcher.createTable(mockContext, namespace, request));
Assertions.assertEquals("Set owner failed", thrown.getMessage());
verify(mockDispatcher).createTable(mockContext, namespace, request);
+ verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
}
@Test
@@ -394,9 +429,11 @@ public class TestIcebergTableHookDispatcher {
verify(mockDispatcher).createTable(mockContext, namespace, request);
// Verify table import was NOT called for staged create
+ verify(mockInternalTableDispatcher, never()).loadTable(any());
verify(mockTableDispatcher, never()).loadTable(any());
// Verify ownership was NOT set for staged create
+ verify(mockInternalOwnerDispatcher, never()).setOwner(any(), any(), any(),
any());
verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
}
@@ -419,11 +456,13 @@ public class TestIcebergTableHookDispatcher {
NameIdentifier gravitinoTableId =
IcebergIdentifierUtils.toGravitinoTableIdentifier(
TEST_METALAKE, TEST_CATALOG, tableId, ":");
- verify(mockTableDispatcher).loadTable(gravitinoTableId);
+ verify(mockInternalTableDispatcher).loadTable(gravitinoTableId);
+ verify(mockTableDispatcher, never()).loadTable(any());
ArgumentCaptor<String> userCaptor = ArgumentCaptor.forClass(String.class);
- verify(mockOwnerDispatcher)
+ verify(mockInternalOwnerDispatcher)
.setOwner(eq(TEST_METALAKE), any(), userCaptor.capture(),
eq(Owner.Type.USER));
+ verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
Assertions.assertEquals(TEST_USER, userCaptor.getValue());
}
@@ -444,9 +483,11 @@ public class TestIcebergTableHookDispatcher {
verify(mockDispatcher).updateTable(mockContext, tableId, request);
// Verify table import was NOT called for a regular update
+ verify(mockInternalTableDispatcher, never()).loadTable(any());
verify(mockTableDispatcher, never()).loadTable(any());
// Verify ownership was NOT set
+ verify(mockInternalOwnerDispatcher, never()).setOwner(any(), any(), any(),
any());
verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
}
@@ -474,7 +515,9 @@ public class TestIcebergTableHookDispatcher {
// Import failure (the loadTable call) must propagate so the caller learns
the table exists in
// Iceberg but is not registered in Gravitino. setOwner is therefore
unreachable.
- doThrow(new RuntimeException("Import
failed")).when(mockTableDispatcher).loadTable(any());
+ doThrow(new RuntimeException("Import failed"))
+ .when(mockInternalTableDispatcher)
+ .loadTable(any());
RuntimeException thrown =
Assertions.assertThrows(
@@ -483,7 +526,9 @@ public class TestIcebergTableHookDispatcher {
Assertions.assertEquals("Import failed", thrown.getMessage());
verify(mockDispatcher).createTable(mockContext, namespace, request);
- verify(mockTableDispatcher).loadTable(any());
+ verify(mockInternalTableDispatcher).loadTable(any());
+ verify(mockTableDispatcher, never()).loadTable(any());
+ verify(mockInternalOwnerDispatcher, never()).setOwner(any(), any(), any(),
any());
verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
}
}
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergViewHookDispatcher.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergViewHookDispatcher.java
index 4fdf1426b9..929aeac842 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergViewHookDispatcher.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/dispatcher/TestIcebergViewHookDispatcher.java
@@ -74,21 +74,27 @@ public class TestIcebergViewHookDispatcher {
private IcebergViewOperationDispatcher mockExecutor;
private EntityStore mockEntityStore;
private ViewDispatcher mockViewDispatcher;
+ private ViewDispatcher mockInternalViewDispatcher;
private OwnerDispatcher mockOwnerDispatcher;
+ private OwnerDispatcher mockInternalOwnerDispatcher;
private IcebergRequestContext mockContext;
private GravitinoEnv gravitinoEnv;
private Config previousConfig;
private EntityStore previousEntityStore;
private ViewDispatcher previousViewDispatcher;
+ private ViewDispatcher previousInternalViewDispatcher;
private OwnerDispatcher previousOwnerDispatcher;
+ private OwnerDispatcher previousInternalOwnerDispatcher;
@BeforeEach
public void setUp() {
mockExecutor = mock(IcebergViewOperationDispatcher.class);
mockEntityStore = mock(EntityStore.class);
mockViewDispatcher = mock(ViewDispatcher.class);
+ mockInternalViewDispatcher = mock(ViewDispatcher.class);
mockOwnerDispatcher = mock(OwnerDispatcher.class);
+ mockInternalOwnerDispatcher = mock(OwnerDispatcher.class);
mockContext = mock(IcebergRequestContext.class);
when(mockContext.catalogName()).thenReturn(CATALOG);
@@ -103,12 +109,20 @@ public class TestIcebergViewHookDispatcher {
previousEntityStore = (EntityStore) FieldUtils.readField(gravitinoEnv,
"entityStore", true);
previousViewDispatcher =
(ViewDispatcher) FieldUtils.readField(gravitinoEnv,
"viewDispatcher", true);
+ previousInternalViewDispatcher =
+ (ViewDispatcher) FieldUtils.readField(gravitinoEnv,
"internalViewDispatcher", true);
previousOwnerDispatcher =
(OwnerDispatcher) FieldUtils.readField(gravitinoEnv,
"ownerDispatcher", true);
+ previousInternalOwnerDispatcher =
+ (OwnerDispatcher) FieldUtils.readField(gravitinoEnv,
"internalOwnerDispatcher", true);
FieldUtils.writeField(gravitinoEnv, "config", mockConfig, true);
FieldUtils.writeField(gravitinoEnv, "entityStore", mockEntityStore,
true);
FieldUtils.writeField(gravitinoEnv, "viewDispatcher",
mockViewDispatcher, true);
+ FieldUtils.writeField(
+ gravitinoEnv, "internalViewDispatcher", mockInternalViewDispatcher,
true);
FieldUtils.writeField(gravitinoEnv, "ownerDispatcher",
mockOwnerDispatcher, true);
+ FieldUtils.writeField(
+ gravitinoEnv, "internalOwnerDispatcher",
mockInternalOwnerDispatcher, true);
} catch (Exception e) {
throw new RuntimeException("Failed to setup test", e);
}
@@ -124,7 +138,11 @@ public class TestIcebergViewHookDispatcher {
FieldUtils.writeField(gravitinoEnv, "config", previousConfig, true);
FieldUtils.writeField(gravitinoEnv, "entityStore", previousEntityStore,
true);
FieldUtils.writeField(gravitinoEnv, "viewDispatcher",
previousViewDispatcher, true);
+ FieldUtils.writeField(
+ gravitinoEnv, "internalViewDispatcher",
previousInternalViewDispatcher, true);
FieldUtils.writeField(gravitinoEnv, "ownerDispatcher",
previousOwnerDispatcher, true);
+ FieldUtils.writeField(
+ gravitinoEnv, "internalOwnerDispatcher",
previousInternalOwnerDispatcher, true);
} catch (Exception e) {
// Ignore cleanup errors
}
@@ -161,10 +179,12 @@ public class TestIcebergViewHookDispatcher {
// Verify view was imported into Gravitino
NameIdentifier expectedIdent = NameIdentifier.of(METALAKE, CATALOG,
SCHEMA_NAME, VIEW_NAME);
- verify(mockViewDispatcher, times(1)).loadView(eq(expectedIdent));
+ verify(mockInternalViewDispatcher, times(1)).loadView(eq(expectedIdent));
+ verify(mockViewDispatcher, never()).loadView(any());
// Verify ownership was set
- verify(mockOwnerDispatcher, times(1)).setOwner(any(), any(), eq(USER),
any());
+ verify(mockInternalOwnerDispatcher, times(1)).setOwner(any(), any(),
eq(USER), any());
+ verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
assertEquals(mockResponse, response);
}
@@ -195,7 +215,7 @@ public class TestIcebergViewHookDispatcher {
// Simulate import failure
doThrow(new RuntimeException("Import failed"))
- .when(mockViewDispatcher)
+ .when(mockInternalViewDispatcher)
.loadView(any(NameIdentifier.class));
// Should not throw - import is best-effort
@@ -230,7 +250,7 @@ public class TestIcebergViewHookDispatcher {
when(mockExecutor.createView(mockContext, namespace,
createRequest)).thenReturn(mockResponse);
doThrow(new RuntimeException("Set owner failed"))
- .when(mockOwnerDispatcher)
+ .when(mockInternalOwnerDispatcher)
.setOwner(any(), any(), any(), any());
RuntimeException thrown =
@@ -239,7 +259,9 @@ public class TestIcebergViewHookDispatcher {
() -> hookDispatcher.createView(mockContext, namespace,
createRequest));
assertEquals("Set owner failed", thrown.getMessage());
verify(mockExecutor, times(1)).createView(mockContext, namespace,
createRequest);
- verify(mockViewDispatcher, times(1)).loadView(any(NameIdentifier.class));
+ verify(mockInternalViewDispatcher,
times(1)).loadView(any(NameIdentifier.class));
+ verify(mockViewDispatcher, never()).loadView(any());
+ verify(mockOwnerDispatcher, never()).setOwner(any(), any(), any(), any());
}
@Test
@@ -268,7 +290,8 @@ public class TestIcebergViewHookDispatcher {
NameIdentifier expectedIdent =
IcebergIdentifierUtils.toGravitinoTableIdentifier(METALAKE, CATALOG,
viewIdent, ":");
verify(mockEntityStore, never()).delete(eq(expectedIdent),
eq(Entity.EntityType.VIEW));
- verify(mockViewDispatcher, times(1)).loadView(eq(expectedIdent));
+ verify(mockInternalViewDispatcher, times(1)).loadView(eq(expectedIdent));
+ verify(mockViewDispatcher, never()).loadView(any());
}
@Test
@@ -282,7 +305,8 @@ public class TestIcebergViewHookDispatcher {
NameIdentifier expectedIdent =
IcebergIdentifierUtils.toGravitinoTableIdentifier(METALAKE, CATALOG,
viewIdent, ":");
verify(mockEntityStore, times(1)).delete(eq(expectedIdent),
eq(Entity.EntityType.VIEW));
- verify(mockViewDispatcher, times(1)).loadView(eq(expectedIdent));
+ verify(mockInternalViewDispatcher, times(1)).loadView(eq(expectedIdent));
+ verify(mockViewDispatcher, never()).loadView(any());
}
@Test
@@ -354,7 +378,8 @@ public class TestIcebergViewHookDispatcher {
NameIdentifier destGravitinoIdent =
IcebergIdentifierUtils.toGravitinoTableIdentifier(METALAKE, CATALOG,
destIdent, ":");
verify(mockEntityStore, times(1)).delete(eq(sourceGravitinoIdent),
eq(Entity.EntityType.VIEW));
- verify(mockViewDispatcher, times(1)).loadView(eq(destGravitinoIdent));
+ verify(mockInternalViewDispatcher,
times(1)).loadView(eq(destGravitinoIdent));
+ verify(mockViewDispatcher, never()).loadView(any());
}
@Test
diff --git
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/provider/TestDynamicIcebergConfigProvider.java
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/provider/TestDynamicIcebergConfigProvider.java
index 669e41a24d..2177778734 100644
---
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/provider/TestDynamicIcebergConfigProvider.java
+++
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/provider/TestDynamicIcebergConfigProvider.java
@@ -63,6 +63,7 @@ public class TestDynamicIcebergConfigProvider {
public void tearDown() throws IllegalAccessException {
// Clean up GravitinoEnv and IcebergRESTServerContext state after each test
FieldUtils.writeField(GravitinoEnv.getInstance(), "catalogDispatcher",
null, true);
+ FieldUtils.writeField(GravitinoEnv.getInstance(),
"internalCatalogDispatcher", null, true);
resetServerContext();
}
@@ -265,12 +266,13 @@ public class TestDynamicIcebergConfigProvider {
// Enable authorization to use internal fetcher
createMockServerContext(true);
- // Mock CatalogDispatcher
+ // Mock CatalogDispatchers
CatalogDispatcher mockCatalogDispatcher =
Mockito.mock(CatalogDispatcher.class);
+ CatalogDispatcher mockInternalCatalogDispatcher =
Mockito.mock(CatalogDispatcher.class);
Catalog mockCatalog = Mockito.mock(Catalog.class);
NameIdentifier catalogIdent = NameIdentifierUtil.ofCatalog(metalakeName,
catalogName);
-
Mockito.when(mockCatalogDispatcher.loadCatalog(catalogIdent)).thenReturn(mockCatalog);
+
Mockito.when(mockInternalCatalogDispatcher.loadCatalog(catalogIdent)).thenReturn(mockCatalog);
Mockito.when(mockCatalog.provider()).thenReturn("lakehouse-iceberg");
Mockito.when(mockCatalog.properties())
.thenReturn(
@@ -281,9 +283,14 @@ public class TestDynamicIcebergConfigProvider {
}
});
- // Set the mock CatalogDispatcher to GravitinoEnv
+ // Set the mock CatalogDispatchers to GravitinoEnv
FieldUtils.writeField(
GravitinoEnv.getInstance(), "catalogDispatcher",
mockCatalogDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(),
+ "internalCatalogDispatcher",
+ mockInternalCatalogDispatcher,
+ true);
// Initialize provider with required properties
Map<String, String> properties = new HashMap<>();
@@ -292,11 +299,12 @@ public class TestDynamicIcebergConfigProvider {
DynamicIcebergConfigProvider provider = new DynamicIcebergConfigProvider();
provider.initialize(properties);
- // Test that internal interface is used (CatalogDispatcher should be
called)
+ // Test that internal interface is used (internal CatalogDispatcher should
be called)
Optional<IcebergConfig> icebergConfig =
provider.getIcebergCatalogConfig(catalogName);
Assertions.assertTrue(icebergConfig.isPresent());
- Mockito.verify(mockCatalogDispatcher).loadCatalog(catalogIdent);
+ Mockito.verify(mockInternalCatalogDispatcher).loadCatalog(catalogIdent);
+ Mockito.verify(mockCatalogDispatcher,
Mockito.never()).loadCatalog(catalogIdent);
}
@Test
@@ -345,8 +353,9 @@ public class TestDynamicIcebergConfigProvider {
// Enable authorization to use internal fetcher
createMockServerContext(true);
- // Ensure CatalogDispatcher is null (simulating GravitinoEnv not
initialized)
+ // Ensure internal CatalogDispatcher is null (simulating GravitinoEnv not
initialized)
FieldUtils.writeField(GravitinoEnv.getInstance(), "catalogDispatcher",
null, true);
+ FieldUtils.writeField(GravitinoEnv.getInstance(),
"internalCatalogDispatcher", null, true);
// Initialize provider with required properties
Map<String, String> properties = new HashMap<>();
@@ -355,9 +364,13 @@ public class TestDynamicIcebergConfigProvider {
DynamicIcebergConfigProvider provider = new DynamicIcebergConfigProvider();
provider.initialize(properties);
- // Test that IllegalStateException is thrown when CatalogDispatcher is null
- Assertions.assertThrows(
- IllegalStateException.class, () ->
provider.getIcebergCatalogConfig(catalogName));
+ IllegalStateException exception =
+ Assertions.assertThrows(
+ IllegalStateException.class, () ->
provider.getIcebergCatalogConfig(catalogName));
+ Assertions.assertEquals(
+ "Internal CatalogDispatcher is not available. "
+ + "Internal catalog fetcher requires running within Gravitino
server.",
+ exception.getMessage());
}
@Test
@@ -368,16 +381,22 @@ public class TestDynamicIcebergConfigProvider {
// Enable authorization to use internal fetcher
createMockServerContext(true);
- // Mock CatalogDispatcher to throw NoSuchCatalogException
+ // Mock internal CatalogDispatcher to throw NoSuchCatalogException
CatalogDispatcher mockCatalogDispatcher =
Mockito.mock(CatalogDispatcher.class);
+ CatalogDispatcher mockInternalCatalogDispatcher =
Mockito.mock(CatalogDispatcher.class);
NameIdentifier catalogIdent =
NameIdentifierUtil.ofCatalog(metalakeName, nonExistentCatalogName);
- Mockito.when(mockCatalogDispatcher.loadCatalog(catalogIdent))
+ Mockito.when(mockInternalCatalogDispatcher.loadCatalog(catalogIdent))
.thenThrow(new NoSuchCatalogException("Catalog not found: %s",
nonExistentCatalogName));
- // Set the mock CatalogDispatcher to GravitinoEnv
+ // Set the mock CatalogDispatchers to GravitinoEnv
FieldUtils.writeField(
GravitinoEnv.getInstance(), "catalogDispatcher",
mockCatalogDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(),
+ "internalCatalogDispatcher",
+ mockInternalCatalogDispatcher,
+ true);
// Initialize provider with required properties
Map<String, String> properties = new HashMap<>();
@@ -390,7 +409,8 @@ public class TestDynamicIcebergConfigProvider {
Optional<IcebergConfig> result =
provider.getIcebergCatalogConfig(nonExistentCatalogName);
Assertions.assertFalse(result.isPresent());
- Mockito.verify(mockCatalogDispatcher).loadCatalog(catalogIdent);
+ Mockito.verify(mockInternalCatalogDispatcher).loadCatalog(catalogIdent);
+ Mockito.verify(mockCatalogDispatcher,
Mockito.never()).loadCatalog(catalogIdent);
}
@Test
@@ -474,12 +494,13 @@ public class TestDynamicIcebergConfigProvider {
// Enable authorization to use internal fetcher
createMockServerContext(true);
- // Mock CatalogDispatcher
+ // Mock CatalogDispatchers
CatalogDispatcher mockCatalogDispatcher =
Mockito.mock(CatalogDispatcher.class);
+ CatalogDispatcher mockInternalCatalogDispatcher =
Mockito.mock(CatalogDispatcher.class);
Catalog mockCatalog = Mockito.mock(Catalog.class);
NameIdentifier catalogIdent = NameIdentifierUtil.ofCatalog(metalakeName,
catalogName);
-
Mockito.when(mockCatalogDispatcher.loadCatalog(catalogIdent)).thenReturn(mockCatalog);
+
Mockito.when(mockInternalCatalogDispatcher.loadCatalog(catalogIdent)).thenReturn(mockCatalog);
Mockito.when(mockCatalog.provider()).thenReturn("lakehouse-iceberg");
Mockito.when(mockCatalog.properties())
.thenReturn(
@@ -490,9 +511,14 @@ public class TestDynamicIcebergConfigProvider {
}
});
- // Set the mock CatalogDispatcher to GravitinoEnv
+ // Set the mock CatalogDispatchers to GravitinoEnv
FieldUtils.writeField(
GravitinoEnv.getInstance(), "catalogDispatcher",
mockCatalogDispatcher, true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(),
+ "internalCatalogDispatcher",
+ mockInternalCatalogDispatcher,
+ true);
// Initialize provider with required properties
Map<String, String> properties = new HashMap<>();
@@ -535,8 +561,10 @@ public class TestDynamicIcebergConfigProvider {
Assertions.assertTrue(result.isPresent(), "Each thread should get a
valid config");
}
- // Verify CatalogDispatcher was called (at least once, possibly more due
to concurrency)
- Mockito.verify(mockCatalogDispatcher,
Mockito.atLeastOnce()).loadCatalog(catalogIdent);
+ // Verify internal CatalogDispatcher was called (at least once, possibly
more due to
+ // concurrency)
+ Mockito.verify(mockInternalCatalogDispatcher,
Mockito.atLeastOnce()).loadCatalog(catalogIdent);
+ Mockito.verify(mockCatalogDispatcher,
Mockito.never()).loadCatalog(catalogIdent);
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
diff --git
a/server-common/src/main/java/org/apache/gravitino/server/authorization/PassThroughAuthorizer.java
b/server-common/src/main/java/org/apache/gravitino/server/authorization/PassThroughAuthorizer.java
index c58ffea12e..deab84b743 100644
---
a/server-common/src/main/java/org/apache/gravitino/server/authorization/PassThroughAuthorizer.java
+++
b/server-common/src/main/java/org/apache/gravitino/server/authorization/PassThroughAuthorizer.java
@@ -83,7 +83,8 @@ public class PassThroughAuthorizer implements
GravitinoAuthorizer {
@Override
public boolean isMetalakeUser(String metalake, AuthorizationRequestContext
requestContext) {
- AccessControlDispatcher dispatcher =
GravitinoEnv.getInstance().accessControlDispatcher();
+ AccessControlDispatcher dispatcher =
+ GravitinoEnv.getInstance().internalAccessControlDispatcher();
if (dispatcher != null) {
try {
dispatcher.getUser(metalake, PrincipalUtils.getCurrentUserName());
diff --git
a/server-common/src/test/java/org/apache/gravitino/server/authorization/TestPassThroughAuthorizer.java
b/server-common/src/test/java/org/apache/gravitino/server/authorization/TestPassThroughAuthorizer.java
index e6099a6c47..4f7efb875e 100644
---
a/server-common/src/test/java/org/apache/gravitino/server/authorization/TestPassThroughAuthorizer.java
+++
b/server-common/src/test/java/org/apache/gravitino/server/authorization/TestPassThroughAuthorizer.java
@@ -18,15 +18,22 @@
package org.apache.gravitino.server.authorization;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.security.Principal;
+import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.gravitino.Entity;
+import org.apache.gravitino.GravitinoEnv;
import org.apache.gravitino.MetadataObject;
import org.apache.gravitino.MetadataObjects;
+import org.apache.gravitino.UserPrincipal;
+import org.apache.gravitino.authorization.AccessControlDispatcher;
import org.apache.gravitino.authorization.AuthorizationRequestContext;
import org.apache.gravitino.authorization.Privilege;
+import org.apache.gravitino.authorization.User;
+import org.apache.gravitino.utils.PrincipalUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -73,4 +80,32 @@ public class TestPassThroughAuthorizer {
"metalake", "type", "fullName", new
AuthorizationRequestContext()));
}
}
+
+ @Test
+ public void testIsMetalakeUserUsesInternalAccessControlDispatcher() throws
Exception {
+ AccessControlDispatcher dispatcher = mock(AccessControlDispatcher.class);
+ User user = mock(User.class);
+ when(dispatcher.getUser("metalake", "testUser")).thenReturn(user);
+
+ AccessControlDispatcher previousDispatcher =
+ (AccessControlDispatcher)
+ FieldUtils.readField(
+ GravitinoEnv.getInstance(), "internalAccessControlDispatcher",
true);
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "internalAccessControlDispatcher",
dispatcher, true);
+ try (PassThroughAuthorizer passThroughAuthorizer = new
PassThroughAuthorizer()) {
+ PrincipalUtils.doAs(
+ new UserPrincipal("testUser"),
+ () -> {
+ Assertions.assertTrue(
+ passThroughAuthorizer.isMetalakeUser(
+ "metalake", new AuthorizationRequestContext()));
+ return null;
+ });
+ verify(dispatcher).getUser("metalake", "testUser");
+ } finally {
+ FieldUtils.writeField(
+ GravitinoEnv.getInstance(), "internalAccessControlDispatcher",
previousDispatcher, true);
+ }
+ }
}
diff --git
a/server-common/src/test/java/org/apache/gravitino/server/authorization/jcasbin/TestJcasbinAuthorizer.java
b/server-common/src/test/java/org/apache/gravitino/server/authorization/jcasbin/TestJcasbinAuthorizer.java
index 67f84a6f99..5f28bfc7dd 100644
---
a/server-common/src/test/java/org/apache/gravitino/server/authorization/jcasbin/TestJcasbinAuthorizer.java
+++
b/server-common/src/test/java/org/apache/gravitino/server/authorization/jcasbin/TestJcasbinAuthorizer.java
@@ -372,6 +372,12 @@ public class TestJcasbinAuthorizer {
}
}
+ @Test
+ public void testIsMetalakeUserUsesUserInfoCache() {
+ assertTrue(jcasbinAuthorizer.isMetalakeUser(METALAKE, new
AuthorizationRequestContext()));
+ verify(userMetaMapper).getUserUpdatedAt(METALAKE, USERNAME);
+ }
+
@Test
public void testAuthorize() throws Exception {
makeCompletableFutureUseCurrentThread(jcasbinAuthorizer);