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

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


The following commit(s) were added to refs/heads/main by this push:
     new 0221fef05e [#8312] feat(iceberg-rest):Support endpoint to retrieve 
valid credentials for a given table  (#8592)
0221fef05e is described below

commit 0221fef05e00f0ea1ad3bd431661e9aa8381779b
Author: Xiaojian Sun <[email protected]>
AuthorDate: Mon Sep 22 17:00:09 2025 +0800

    [#8312] feat(iceberg-rest):Support endpoint to retrieve valid credentials 
for a given table  (#8592)
    
    ### What changes were proposed in this pull request?
    
    Support endpoint to retrieve valid credentials for a given table.
    
    ### Why are the changes needed?
    
    Fix: #8312
    
    ### Does this PR introduce _any_ user-facing change?
    
    N/A
    
    ### How was this patch tested?
    
    
    
org.apache.gravitino.iceberg.service.rest.TestIcebergTableOperations#testGetTableCredentials
---
 .../listener/api/event/OperationType.java          |  1 +
 docs/iceberg-rest-service.md                       |  1 -
 .../iceberg/service/CatalogWrapperForREST.java     | 66 +++++++++++++++++-----
 .../dispatcher/IcebergTableEventDispatcher.java    | 33 +++++++++++
 .../IcebergTableOperationDispatcher.java           | 11 ++++
 .../dispatcher/IcebergTableOperationExecutor.java  |  9 +++
 .../service/rest/IcebergTableOperations.java       | 36 ++++++++++++
 .../api/event/IcebergLoadTableCredentialEvent.java | 37 ++++++++++++
 .../IcebergLoadTableCredentialFailureEvent.java    | 37 ++++++++++++
 .../event/IcebergLoadTableCredentialPreEvent.java  | 37 ++++++++++++
 .../service/rest/TestIcebergTableOperations.java   | 25 ++++++++
 11 files changed, 279 insertions(+), 14 deletions(-)

diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java 
b/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
index 3c7b1439b1..c9b760d901 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/OperationType.java
@@ -25,6 +25,7 @@ public enum OperationType {
   DROP_TABLE,
   PURGE_TABLE,
   LOAD_TABLE,
+  LOAD_TABLE_CREDENTIAL,
   LIST_TABLE,
   ALTER_TABLE,
   RENAME_TABLE,
diff --git a/docs/iceberg-rest-service.md b/docs/iceberg-rest-service.md
index 5241681500..93240bd1c0 100644
--- a/docs/iceberg-rest-service.md
+++ b/docs/iceberg-rest-service.md
@@ -23,7 +23,6 @@ There are some key difference between Gravitino Iceberg REST 
server and Gravitin
   - multi table transaction
   - pagination
   - scan planning
-  - load table credentials
 - Works as a catalog proxy, supporting `Hive` and `JDBC` as catalog backend.
 - Supports credential vending for `S3`、`GCS`、`OSS` and `ADLS`.
 - Supports different storages like `S3`, `HDFS`, `OSS`, `GCS`, `ADLS` and 
provides the capability to support other storages.
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/CatalogWrapperForREST.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/CatalogWrapperForREST.java
index ffe38661cd..df9192ebd7 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/CatalogWrapperForREST.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/CatalogWrapperForREST.java
@@ -45,6 +45,8 @@ import org.apache.iceberg.catalog.Namespace;
 import org.apache.iceberg.catalog.TableIdentifier;
 import org.apache.iceberg.exceptions.ServiceUnavailableException;
 import org.apache.iceberg.rest.requests.CreateTableRequest;
+import org.apache.iceberg.rest.responses.ImmutableLoadCredentialsResponse;
+import org.apache.iceberg.rest.responses.LoadCredentialsResponse;
 import org.apache.iceberg.rest.responses.LoadTableResponse;
 
 /** Process Iceberg REST specific operations, like credential vending. */
@@ -100,6 +102,39 @@ public class CatalogWrapperForREST extends 
IcebergCatalogWrapper {
     return loadTableResponse;
   }
 
+  /**
+   * Get table credentials.
+   *
+   * @param identifier The table identifier for which to load credentials
+   * @return A {@link 
org.apache.iceberg.rest.responses.LoadCredentialsResponse} object containing
+   *     the credentials.
+   */
+  public LoadCredentialsResponse getTableCredentials(TableIdentifier 
identifier) {
+    try {
+      LoadTableResponse loadTableResponse = super.loadTable(identifier);
+      Credential credential = getCredential(loadTableResponse);
+      org.apache.iceberg.rest.credentials.Credential icebergCredential =
+          new org.apache.iceberg.rest.credentials.Credential() {
+            @Override
+            public String prefix() {
+              return "";
+            }
+
+            @Override
+            public Map<String, String> config() {
+              return CredentialPropertyUtils.toIcebergProperties(credential);
+            }
+
+            @Override
+            public void validate() {}
+          };
+      return 
ImmutableLoadCredentialsResponse.builder().addCredentials(icebergCredential).build();
+    } catch (ServiceUnavailableException e) {
+      LOG.warn("Service unavailable when loading table credentials for table: 
{}", identifier, e);
+      return ImmutableLoadCredentialsResponse.builder().build();
+    }
+  }
+
   @Override
   public void close() {
     if (catalogCredentialManager != null) {
@@ -113,6 +148,23 @@ public class CatalogWrapperForREST extends 
IcebergCatalogWrapper {
 
   private LoadTableResponse injectCredentialConfig(
       TableIdentifier tableIdentifier, LoadTableResponse loadTableResponse) {
+    final Credential credential = getCredential(loadTableResponse);
+
+    LOG.info(
+        "Generate credential: {} for Iceberg table: {}",
+        credential.credentialType(),
+        tableIdentifier);
+
+    Map<String, String> credentialConfig = 
CredentialPropertyUtils.toIcebergProperties(credential);
+    return LoadTableResponse.builder()
+        .withTableMetadata(loadTableResponse.tableMetadata())
+        .addAllConfig(loadTableResponse.config())
+        .addAllConfig(getCatalogConfigToClient())
+        .addAllConfig(credentialConfig)
+        .build();
+  }
+
+  private Credential getCredential(LoadTableResponse loadTableResponse) {
     TableMetadata tableMetadata = loadTableResponse.tableMetadata();
     String[] path =
         Stream.of(
@@ -129,19 +181,7 @@ public class CatalogWrapperForREST extends 
IcebergCatalogWrapper {
     if (credential == null) {
       throw new ServiceUnavailableException("Couldn't generate credential, 
%s", context);
     }
-
-    LOG.info(
-        "Generate credential: {} for Iceberg table: {}",
-        credential.credentialType(),
-        tableIdentifier);
-
-    Map<String, String> credentialConfig = 
CredentialPropertyUtils.toIcebergProperties(credential);
-    return LoadTableResponse.builder()
-        .withTableMetadata(loadTableResponse.tableMetadata())
-        .addAllConfig(loadTableResponse.config())
-        .addAllConfig(getCatalogConfigToClient())
-        .addAllConfig(credentialConfig)
-        .build();
+    return credential;
   }
 
   @VisibleForTesting
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableEventDispatcher.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableEventDispatcher.java
index 1dddce8904..0bcf8a3c5f 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableEventDispatcher.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableEventDispatcher.java
@@ -33,6 +33,9 @@ import 
org.apache.gravitino.listener.api.event.IcebergDropTablePreEvent;
 import org.apache.gravitino.listener.api.event.IcebergListTableEvent;
 import org.apache.gravitino.listener.api.event.IcebergListTableFailureEvent;
 import org.apache.gravitino.listener.api.event.IcebergListTablePreEvent;
+import org.apache.gravitino.listener.api.event.IcebergLoadTableCredentialEvent;
+import 
org.apache.gravitino.listener.api.event.IcebergLoadTableCredentialFailureEvent;
+import 
org.apache.gravitino.listener.api.event.IcebergLoadTableCredentialPreEvent;
 import org.apache.gravitino.listener.api.event.IcebergLoadTableEvent;
 import org.apache.gravitino.listener.api.event.IcebergLoadTableFailureEvent;
 import org.apache.gravitino.listener.api.event.IcebergLoadTablePreEvent;
@@ -52,6 +55,7 @@ import org.apache.iceberg.rest.requests.CreateTableRequest;
 import org.apache.iceberg.rest.requests.RenameTableRequest;
 import org.apache.iceberg.rest.requests.UpdateTableRequest;
 import org.apache.iceberg.rest.responses.ListTablesResponse;
+import org.apache.iceberg.rest.responses.LoadCredentialsResponse;
 import org.apache.iceberg.rest.responses.LoadTableResponse;
 
 /**
@@ -230,4 +234,33 @@ public class IcebergTableEventDispatcher implements 
IcebergTableOperationDispatc
     eventBus.dispatchEvent(
         new IcebergRenameTableEvent(context, gravitinoNameIdentifier, 
renameTableRequest));
   }
+
+  /**
+   * Get credentials for an Iceberg table.
+   *
+   * @param context Iceberg REST request context information.
+   * @param tableIdentifier The Iceberg table identifier.
+   * @return A {@link 
org.apache.iceberg.rest.responses.LoadCredentialsResponse} object containing
+   *     the credentials.
+   */
+  @Override
+  public LoadCredentialsResponse getTableCredentials(
+      IcebergRequestContext context, TableIdentifier tableIdentifier) {
+    NameIdentifier gravitinoNameIdentifier =
+        IcebergRestUtils.getGravitinoNameIdentifier(
+            metalakeName, context.catalogName(), tableIdentifier);
+    eventBus.dispatchEvent(
+        new IcebergLoadTableCredentialPreEvent(context, 
gravitinoNameIdentifier));
+    LoadCredentialsResponse loadCredentialsResponse;
+    try {
+      loadCredentialsResponse =
+          icebergTableOperationDispatcher.getTableCredentials(context, 
tableIdentifier);
+    } catch (Exception e) {
+      eventBus.dispatchEvent(
+          new IcebergLoadTableCredentialFailureEvent(context, 
gravitinoNameIdentifier, e));
+      throw e;
+    }
+    eventBus.dispatchEvent(new IcebergLoadTableCredentialEvent(context, 
gravitinoNameIdentifier));
+    return loadCredentialsResponse;
+  }
 }
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationDispatcher.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationDispatcher.java
index 34c0a71741..75762b42e8 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationDispatcher.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationDispatcher.java
@@ -26,6 +26,7 @@ import org.apache.iceberg.rest.requests.CreateTableRequest;
 import org.apache.iceberg.rest.requests.RenameTableRequest;
 import org.apache.iceberg.rest.requests.UpdateTableRequest;
 import org.apache.iceberg.rest.responses.ListTablesResponse;
+import org.apache.iceberg.rest.responses.LoadCredentialsResponse;
 import org.apache.iceberg.rest.responses.LoadTableResponse;
 
 /**
@@ -102,4 +103,14 @@ public interface IcebergTableOperationDispatcher {
    * @param renameTableRequest Rename table request information.
    */
   void renameTable(IcebergRequestContext context, RenameTableRequest 
renameTableRequest);
+
+  /**
+   * Get credentials for an Iceberg table.
+   *
+   * @param context Iceberg REST request context information.
+   * @param tableIdentifier The Iceberg table identifier.
+   * @return A {@link LoadCredentialsResponse} object containing the 
credentials.
+   */
+  LoadCredentialsResponse getTableCredentials(
+      IcebergRequestContext context, TableIdentifier tableIdentifier);
 }
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java
index 31e94ab9f6..cec833136a 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/dispatcher/IcebergTableOperationExecutor.java
@@ -27,6 +27,7 @@ import org.apache.iceberg.rest.requests.CreateTableRequest;
 import org.apache.iceberg.rest.requests.RenameTableRequest;
 import org.apache.iceberg.rest.requests.UpdateTableRequest;
 import org.apache.iceberg.rest.responses.ListTablesResponse;
+import org.apache.iceberg.rest.responses.LoadCredentialsResponse;
 import org.apache.iceberg.rest.responses.LoadTableResponse;
 
 public class IcebergTableOperationExecutor implements 
IcebergTableOperationDispatcher {
@@ -97,4 +98,12 @@ public class IcebergTableOperationExecutor implements 
IcebergTableOperationDispa
         .getCatalogWrapper(context.catalogName())
         .renameTable(renameTableRequest);
   }
+
+  @Override
+  public LoadCredentialsResponse getTableCredentials(
+      IcebergRequestContext context, TableIdentifier tableIdentifier) {
+    return icebergCatalogWrapperManager
+        .getCatalogWrapper(context.catalogName())
+        .getTableCredentials(tableIdentifier);
+  }
 }
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
index f6a9070100..68d8c20af2 100644
--- 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/iceberg/service/rest/IcebergTableOperations.java
@@ -56,6 +56,7 @@ import org.apache.iceberg.rest.requests.CreateTableRequest;
 import org.apache.iceberg.rest.requests.ReportMetricsRequest;
 import org.apache.iceberg.rest.requests.UpdateTableRequest;
 import org.apache.iceberg.rest.responses.ListTablesResponse;
+import org.apache.iceberg.rest.responses.LoadCredentialsResponse;
 import org.apache.iceberg.rest.responses.LoadTableResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -332,6 +333,41 @@ public class IcebergTableOperations {
     }
   }
 
+  @GET
+  @Path("{table}/credentials")
+  @Produces(MediaType.APPLICATION_JSON)
+  @Timed(name = "get-table-credentials." + MetricNames.HTTP_PROCESS_DURATION, 
absolute = true)
+  @ResponseMetered(name = "get-table-credentials", absolute = true)
+  public Response getTableCredentials(
+      @PathParam("prefix") String prefix,
+      @Encoded() @PathParam("namespace") String namespace,
+      @PathParam("table") String table) {
+    String catalogName = IcebergRestUtils.getCatalogName(prefix);
+    Namespace icebergNS = RESTUtil.decodeNamespace(namespace);
+    LOG.info(
+        "Get Iceberg table credentials, catalog: {}, namespace: {}, table: {}",
+        catalogName,
+        icebergNS,
+        table);
+    try {
+      return Utils.doAs(
+          httpRequest,
+          () -> {
+            // Convert Iceberg table identifier to Gravitino NameIdentifier
+            TableIdentifier tableIdentifier = TableIdentifier.of(icebergNS, 
table);
+            // First check if the table exists
+            IcebergRequestContext context =
+                new IcebergRequestContext(httpServletRequest(), catalogName);
+            // Get credentials using the table operation dispatcher
+            LoadCredentialsResponse credentialsResponse =
+                tableOperationDispatcher.getTableCredentials(context, 
tableIdentifier);
+            return IcebergRestUtils.ok(credentialsResponse);
+          });
+    } catch (Exception e) {
+      return IcebergExceptionMapper.toRESTResponse(e);
+    }
+  }
+
   private boolean isCredentialVending(String accessDelegation) {
     if (StringUtils.isBlank(accessDelegation)) {
       return false;
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableCredentialEvent.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableCredentialEvent.java
new file mode 100644
index 0000000000..cafadb0c11
--- /dev/null
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableCredentialEvent.java
@@ -0,0 +1,37 @@
+/*
+ *  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.gravitino.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+
+/** Represent an event after loading Iceberg table credential successfully. */
+@DeveloperApi
+public class IcebergLoadTableCredentialEvent extends IcebergTableEvent {
+  public IcebergLoadTableCredentialEvent(
+      IcebergRequestContext icebergRequestContext, NameIdentifier 
resourceIdentifier) {
+    super(icebergRequestContext, resourceIdentifier);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.LOAD_TABLE_CREDENTIAL;
+  }
+}
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableCredentialFailureEvent.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableCredentialFailureEvent.java
new file mode 100644
index 0000000000..a21800e942
--- /dev/null
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableCredentialFailureEvent.java
@@ -0,0 +1,37 @@
+/*
+ *  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.gravitino.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+
+/** Represent a failure event when loading Iceberg table credential failed. */
+@DeveloperApi
+public class IcebergLoadTableCredentialFailureEvent extends 
IcebergTableFailureEvent {
+  public IcebergLoadTableCredentialFailureEvent(
+      IcebergRequestContext icebergRequestContext, NameIdentifier 
nameIdentifier, Exception e) {
+    super(icebergRequestContext, nameIdentifier, e);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.LOAD_TABLE_CREDENTIAL;
+  }
+}
diff --git 
a/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableCredentialPreEvent.java
 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableCredentialPreEvent.java
new file mode 100644
index 0000000000..f536424c23
--- /dev/null
+++ 
b/iceberg/iceberg-rest-server/src/main/java/org/apache/gravitino/listener/api/event/IcebergLoadTableCredentialPreEvent.java
@@ -0,0 +1,37 @@
+/*
+ *  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.gravitino.listener.api.event;
+
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.annotation.DeveloperApi;
+
+/** Represent a pre event before loading Iceberg table credential. */
+@DeveloperApi
+public class IcebergLoadTableCredentialPreEvent extends IcebergTablePreEvent {
+  public IcebergLoadTableCredentialPreEvent(
+      IcebergRequestContext icebergRequestContext, NameIdentifier 
tableIdentifier) {
+    super(icebergRequestContext, tableIdentifier);
+  }
+
+  @Override
+  public OperationType operationType() {
+    return OperationType.LOAD_TABLE_CREDENTIAL;
+  }
+}
diff --git 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
index b076df1bdd..28d45d4019 100644
--- 
a/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
+++ 
b/iceberg/iceberg-rest-server/src/test/java/org/apache/gravitino/iceberg/service/rest/TestIcebergTableOperations.java
@@ -471,4 +471,29 @@ public class TestIcebergTableOperations extends 
IcebergNamespaceTestBase {
     Response response = doCreateTable(ns, name);
     Assertions.assertEquals(status, response.getStatus());
   }
+
+  @ParameterizedTest
+  
@MethodSource("org.apache.gravitino.iceberg.service.rest.IcebergRestTestUtil#testNamespaces")
+  public void testGetTableCredentials(Namespace ns) {
+    String tableName = "test_table_credentials";
+
+    // First create the namespace
+    verifyCreateNamespaceSucc(ns);
+
+    // Then create a table
+    verifyCreateTableSucc(ns, tableName);
+
+    // Then test getting credentials
+    Response response = doGetTableCredentials(ns, tableName);
+    Assertions.assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+    // Verify the response contains credentials (even if empty)
+    String responseBody = response.readEntity(String.class);
+    Assertions.assertNotNull(responseBody);
+    Assertions.assertTrue(responseBody.contains("credentials"));
+  }
+
+  private Response doGetTableCredentials(Namespace ns, String tableName) {
+    return getTableClientBuilder(ns, Optional.of(tableName + 
"/credentials")).get();
+  }
 }

Reply via email to