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 e4a049e17a [#6740] feat(core): Support group pre-event to Gravitino 
server (#6743)
e4a049e17a is described below

commit e4a049e17acdbf78bc17c6fddf71937528c133aa
Author: Lord of Abyss <[email protected]>
AuthorDate: Tue Mar 25 15:02:34 2025 +0800

    [#6740] feat(core): Support group pre-event to Gravitino server (#6743)
    
    ### What changes were proposed in this pull request?
    
    Support group pre-event to Gravitino server
    
    
    
![image](https://github.com/user-attachments/assets/f09750e2-b5a9-4da0-859b-fd4adf8ae90a)
    
    
    ### Why are the changes needed?
    
    Fix: #6740
    
    ### Does this PR introduce _any_ user-facing change?
    
    NO
    
    ### How was this patch tested?
    
    local test
---
 .../api/event/AccessControlEventDispatcher.java    |  18 +-
 ...{AddUserPreEvent.java => AddGroupPreEvent.java} |  29 ++--
 .../listener/api/event/AddUserPreEvent.java        |   2 +-
 ...{GetUserPreEvent.java => GetGroupPreEvent.java} |  31 ++--
 .../listener/api/event/GetUserPreEvent.java        |   2 +-
 .../{UserPreEvent.java => GroupPreEvent.java}      |  11 +-
 ...erPreEvent.java => ListGroupNamesPreEvent.java} |  22 ++-
 .../{UserPreEvent.java => ListGroupsPreEvent.java} |  23 ++-
 .../listener/api/event/OperationType.java          |   7 +-
 ...tUserPreEvent.java => RemoveGroupPreEvent.java} |  30 ++--
 .../gravitino/listener/api/event/UserPreEvent.java |   4 +-
 .../listener/api/event/TestGroupEvent.java         | 193 +++++++++++++++++++++
 .../listener/api/event/TestUserEvent.java          |  14 +-
 docs/gravitino-server-config.md                    |  23 +--
 14 files changed, 323 insertions(+), 86 deletions(-)

diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
index 7c658ef942..e5614d1845 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AccessControlEventDispatcher.java
@@ -144,7 +144,9 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   public Group addGroup(String metalake, String group)
       throws GroupAlreadyExistsException, NoSuchMetalakeException {
     try {
-      // TODO: add Event
+      String initiator = PrincipalUtils.getCurrentUserName();
+
+      eventBus.dispatchEvent(new AddGroupPreEvent(initiator, 
NameIdentifier.of(metalake), group));
       return dispatcher.addGroup(metalake, group);
     } catch (Exception e) {
       // TODO: add failure event
@@ -156,7 +158,10 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   @Override
   public boolean removeGroup(String metalake, String group) throws 
NoSuchMetalakeException {
     try {
-      // TODO: add Event
+      String initiator = PrincipalUtils.getCurrentUserName();
+
+      eventBus.dispatchEvent(
+          new RemoveGroupPreEvent(initiator, NameIdentifier.of(metalake), 
group));
       return dispatcher.removeGroup(metalake, group);
     } catch (Exception e) {
       // TODO: add failure event
@@ -168,6 +173,9 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   @Override
   public Group getGroup(String metalake, String group)
       throws NoSuchGroupException, NoSuchMetalakeException {
+    String initiator = PrincipalUtils.getCurrentUserName();
+
+    eventBus.dispatchEvent(new GetGroupPreEvent(initiator, 
NameIdentifier.of(metalake), group));
     try {
       return dispatcher.getGroup(metalake, group);
     } catch (Exception e) {
@@ -179,6 +187,9 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   /** {@inheritDoc} */
   @Override
   public Group[] listGroups(String metalake) {
+    String initiator = PrincipalUtils.getCurrentUserName();
+
+    eventBus.dispatchEvent(new ListGroupsPreEvent(initiator, 
NameIdentifier.of(metalake)));
     try {
       // TODO: add Event
       return dispatcher.listGroups(metalake);
@@ -191,6 +202,9 @@ public class AccessControlEventDispatcher implements 
AccessControlDispatcher {
   /** {@inheritDoc} */
   @Override
   public String[] listGroupNames(String metalake) {
+    String initiator = PrincipalUtils.getCurrentUserName();
+
+    eventBus.dispatchEvent(new ListGroupNamesPreEvent(initiator, 
NameIdentifier.of(metalake)));
     try {
       // TODO: add Event
       return dispatcher.listGroupNames(metalake);
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AddGroupPreEvent.java
similarity index 60%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/AddGroupPreEvent.java
index 91e1bd61a6..85594ef31a 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AddGroupPreEvent.java
@@ -22,31 +22,32 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represents an event triggered before add a user to a metalake. */
+/** Represents an event triggered before add a group to a metalake. */
 @DeveloperApi
-public class AddUserPreEvent extends UserPreEvent {
-  private final String userName;
+public class AddGroupPreEvent extends GroupPreEvent {
+  private final String groupName;
 
   /**
-   * Construct a new {@link AddUserPreEvent} instance.
+   * Construct a new {@link AddGroupPreEvent} instance with the given 
initiator, identifier and
+   * group name.
    *
-   * @param initiator the user who initiated the add-user request.
-   * @param identifier the identifier of the metalake which the user is being 
added to.
-   * @param userName the username which is requested to be added to the 
metalake.
+   * @param initiator the user who initiated the add-group request.
+   * @param identifier the identifier of the metalake which the group is being 
added to.
+   * @param groupName the group name which is requested to be added to the 
metalake.
    */
-  public AddUserPreEvent(String initiator, NameIdentifier identifier, String 
userName) {
+  protected AddGroupPreEvent(String initiator, NameIdentifier identifier, 
String groupName) {
     super(initiator, identifier);
 
-    this.userName = userName;
+    this.groupName = groupName;
   }
 
   /**
-   * Returns the user information which is being added to the metalake.
+   * Returns the group information which is being added to the metalake.
    *
-   * @return the username which is requested to be added to the metalake.
+   * @return the group name which is requested to be added to the metalake.
    */
-  public String userName() {
-    return userName;
+  public String groupName() {
+    return groupName;
   }
 
   /**
@@ -56,6 +57,6 @@ public class AddUserPreEvent extends UserPreEvent {
    */
   @Override
   public OperationType operationType() {
-    return OperationType.ADD_USER;
+    return OperationType.ADD_GROUP;
   }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
index 91e1bd61a6..611ec97b6d 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/AddUserPreEvent.java
@@ -28,7 +28,7 @@ public class AddUserPreEvent extends UserPreEvent {
   private final String userName;
 
   /**
-   * Construct a new {@link AddUserPreEvent} instance.
+   * Construct a new {@link AddUserPreEvent} instance with initiator, 
identifier and username.
    *
    * @param initiator the user who initiated the add-user request.
    * @param identifier the identifier of the metalake which the user is being 
added to.
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetGroupPreEvent.java
similarity index 61%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/GetGroupPreEvent.java
index 1c848fedc2..ea09c34d85 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetGroupPreEvent.java
@@ -22,31 +22,32 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represents an event triggered before get a user from specific metalake */
+/** Represents an event triggered before get a group from specific metalake */
 @DeveloperApi
-public class GetUserPreEvent extends UserPreEvent {
-  private final String userName;
+public class GetGroupPreEvent extends GroupPreEvent {
+  private final String groupName;
 
   /**
-   * Construct a new {@link GetUserPreEvent} instance with the specified user, 
identifier and user
-   * info.
+   * Construct a new {@link GetGroupPreEvent} instance with the given 
initiator and identifier and
+   * group name.
    *
-   * @param initiator the user who initiated the add-user request.
-   * @param identifier the identifier of the metalake which the user is being 
added to.
-   * @param userName the username which is requested to be retrieved.
+   * @param initiator the user who initiated the get-group request.
+   * @param identifier the identifier of the metalake which the group is 
getting retrieved from.
+   * @param groupName the group name which is requested to be retrieved.
    */
-  public GetUserPreEvent(String initiator, NameIdentifier identifier, String 
userName) {
+  protected GetGroupPreEvent(String initiator, NameIdentifier identifier, 
String groupName) {
     super(initiator, identifier);
-    this.userName = userName;
+
+    this.groupName = groupName;
   }
 
   /**
-   * Returns the user info for the user which is getting retrieved.
+   * Returns the group info for the group which is getting retrieved.
    *
-   * @return the username which is requested to be retrieved.
+   * @return the group name which is requested to be retrieved.
    */
-  public String userName() {
-    return userName;
+  public String groupName() {
+    return groupName;
   }
 
   /**
@@ -56,6 +57,6 @@ public class GetUserPreEvent extends UserPreEvent {
    */
   @Override
   public OperationType operationType() {
-    return OperationType.GET_USER;
+    return OperationType.GET_GROUP;
   }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
index 1c848fedc2..42562ff514 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
@@ -32,7 +32,7 @@ public class GetUserPreEvent extends UserPreEvent {
    * info.
    *
    * @param initiator the user who initiated the add-user request.
-   * @param identifier the identifier of the metalake which the user is being 
added to.
+   * @param identifier the identifier of the metalake which the user is 
getting retrieved from.
    * @param userName the username which is requested to be retrieved.
    */
   public GetUserPreEvent(String initiator, NameIdentifier identifier, String 
userName) {
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GroupPreEvent.java
similarity index 75%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/GroupPreEvent.java
index 0316226ab0..1dfca4a740 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/GroupPreEvent.java
@@ -22,17 +22,16 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represent a pre-event for an user operation request. */
+/** Represent a pre-event for a group operation request. */
 @DeveloperApi
-public abstract class UserPreEvent extends PreEvent {
-
+public abstract class GroupPreEvent extends PreEvent {
   /**
-   * Create a new {@link UserPreEvent} instance for an access request.
+   * Construct a new {@link GroupPreEvent} instance for a group operation 
request.
    *
    * @param initiator the user who triggered the event.
-   * @param identifier the identifier of the model being operated on.
+   * @param identifier the identifier of the metalake which is being operated 
on.
    */
-  protected UserPreEvent(String initiator, NameIdentifier identifier) {
+  protected GroupPreEvent(String initiator, NameIdentifier identifier) {
     super(initiator, identifier);
   }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListGroupNamesPreEvent.java
similarity index 63%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/ListGroupNamesPreEvent.java
index 0316226ab0..cf0e702e21 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListGroupNamesPreEvent.java
@@ -22,17 +22,25 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represent a pre-event for an user operation request. */
+/** Represents an event triggered before list group name from specific 
metalake */
 @DeveloperApi
-public abstract class UserPreEvent extends PreEvent {
+public class ListGroupNamesPreEvent extends GroupPreEvent {
 
   /**
-   * Create a new {@link UserPreEvent} instance for an access request.
-   *
-   * @param initiator the user who triggered the event.
-   * @param identifier the identifier of the model being operated on.
+   * @param initiator the user who initiated the list-group-names request.
+   * @param identifier the identifier of the metalake which is being listed.
    */
-  protected UserPreEvent(String initiator, NameIdentifier identifier) {
+  protected ListGroupNamesPreEvent(String initiator, NameIdentifier 
identifier) {
     super(initiator, identifier);
   }
+
+  /**
+   * Returns the operation type for this event.
+   *
+   * @return the operation type for this event.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_GROUP_NAMES;
+  }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListGroupsPreEvent.java
similarity index 60%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/ListGroupsPreEvent.java
index 0316226ab0..4461a04a03 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/ListGroupsPreEvent.java
@@ -22,17 +22,26 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represent a pre-event for an user operation request. */
+/** Represents an event triggered before list groups from specific metalake */
 @DeveloperApi
-public abstract class UserPreEvent extends PreEvent {
-
+public class ListGroupsPreEvent extends GroupPreEvent {
   /**
-   * Create a new {@link UserPreEvent} instance for an access request.
+   * Construct a new {@code ListGroupPreEvent} instance with the given 
initiator and identifier.
    *
-   * @param initiator the user who triggered the event.
-   * @param identifier the identifier of the model being operated on.
+   * @param initiator the user who initiated the list group operation.
+   * @param identifier the identifier of the metalake which is being listed.
    */
-  protected UserPreEvent(String initiator, NameIdentifier identifier) {
+  protected ListGroupsPreEvent(String initiator, NameIdentifier identifier) {
     super(initiator, identifier);
   }
+
+  /**
+   * Returns the operation type for this event.
+   *
+   * @return the operation type for this event.
+   */
+  @Override
+  public OperationType operationType() {
+    return OperationType.LIST_GROUPS;
+  }
 }
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 8477cd3e8f..a7ff5da95b 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
@@ -119,7 +119,12 @@ public enum OperationType {
   LIST_USERS,
   LIST_USER_NAMES,
 
-  // TODO GROUP
+  // Group
+  ADD_GROUP,
+  REMOVE_GROUP,
+  GET_GROUP,
+  LIST_GROUPS,
+  LIST_GROUP_NAMES,
 
   // TODO ROLE
 
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveGroupPreEvent.java
similarity index 57%
copy from 
core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
copy to 
core/src/main/java/org/apache/gravitino/listener/api/event/RemoveGroupPreEvent.java
index 1c848fedc2..b42b90d739 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/GetUserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/RemoveGroupPreEvent.java
@@ -22,31 +22,31 @@ package org.apache.gravitino.listener.api.event;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.annotation.DeveloperApi;
 
-/** Represents an event triggered before get a user from specific metalake */
+/** Represents an event triggered before remove a group from specific 
metalake. */
 @DeveloperApi
-public class GetUserPreEvent extends UserPreEvent {
-  private final String userName;
+public class RemoveGroupPreEvent extends GroupPreEvent {
+  private final String groupName;
 
   /**
-   * Construct a new {@link GetUserPreEvent} instance with the specified user, 
identifier and user
-   * info.
+   * Construct a new {@link RemoveGroupPreEvent} instance with initiator, 
identifier and group name.
    *
-   * @param initiator the user who initiated the add-user request.
-   * @param identifier the identifier of the metalake which the user is being 
added to.
-   * @param userName the username which is requested to be retrieved.
+   * @param initiator the user who initiated the remove group operation.
+   * @param identifier the identifier of the metalake where the group is 
removed.
+   * @param groupName the group name which is requested to be removed from the 
metalake.
    */
-  public GetUserPreEvent(String initiator, NameIdentifier identifier, String 
userName) {
+  protected RemoveGroupPreEvent(String initiator, NameIdentifier identifier, 
String groupName) {
     super(initiator, identifier);
-    this.userName = userName;
+
+    this.groupName = groupName;
   }
 
   /**
-   * Returns the user info for the user which is getting retrieved.
+   * Returns the group information which is being removed from the metalake.
    *
-   * @return the username which is requested to be retrieved.
+   * @return the group name which is requested to be removed from the metalake.
    */
-  public String userName() {
-    return userName;
+  public String groupName() {
+    return groupName;
   }
 
   /**
@@ -56,6 +56,6 @@ public class GetUserPreEvent extends UserPreEvent {
    */
   @Override
   public OperationType operationType() {
-    return OperationType.GET_USER;
+    return OperationType.REMOVE_GROUP;
   }
 }
diff --git 
a/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java 
b/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java
index 0316226ab0..c51495c2cc 100644
--- 
a/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java
+++ 
b/core/src/main/java/org/apache/gravitino/listener/api/event/UserPreEvent.java
@@ -27,10 +27,10 @@ import org.apache.gravitino.annotation.DeveloperApi;
 public abstract class UserPreEvent extends PreEvent {
 
   /**
-   * Create a new {@link UserPreEvent} instance for an access request.
+   * Create a new {@link UserPreEvent} instance for a user operation request.
    *
    * @param initiator the user who triggered the event.
-   * @param identifier the identifier of the model being operated on.
+   * @param identifier the identifier of the metalake which is being operated 
on.
    */
   protected UserPreEvent(String initiator, NameIdentifier identifier) {
     super(initiator, identifier);
diff --git 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestGroupEvent.java
 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestGroupEvent.java
new file mode 100644
index 0000000000..22c6301362
--- /dev/null
+++ 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestGroupEvent.java
@@ -0,0 +1,193 @@
+/*
+ * 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 static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.gravitino.NameIdentifier;
+import org.apache.gravitino.authorization.Group;
+import org.apache.gravitino.exceptions.GravitinoRuntimeException;
+import org.apache.gravitino.exceptions.NoSuchGroupException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
+import org.apache.gravitino.listener.DummyEventListener;
+import org.apache.gravitino.listener.EventBus;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+public class TestGroupEvent {
+
+  private static final String METALAKE = "demo_metalake";
+  private static final String INEXIST_METALAKE = "inexist_metalake";
+  private AccessControlEventDispatcher dispatcher;
+  private AccessControlEventDispatcher failureDispatcher;
+  private DummyEventListener dummyEventListener;
+  private String groupName;
+  private String otherGroupName;
+  private String inExistGroupName;
+  private Group group;
+  private Group otherGroup;
+  private NameIdentifier identifier;
+
+  @BeforeAll
+  void init() {
+    this.groupName = "group_test";
+    this.otherGroupName = "group_admin";
+    this.inExistGroupName = "group_not_exist";
+    this.group = getMockGroup(groupName, ImmutableList.of("test", "engineer"));
+    this.otherGroup = getMockGroup(otherGroupName, null);
+    this.identifier = NameIdentifier.of(METALAKE);
+
+    this.dummyEventListener = new DummyEventListener();
+    EventBus eventBus = new 
EventBus(Collections.singletonList(dummyEventListener));
+    this.dispatcher = new AccessControlEventDispatcher(eventBus, 
mockGroupDispatcher());
+    this.failureDispatcher =
+        new AccessControlEventDispatcher(eventBus, 
mockExceptionGroupDispatcher());
+
+    System.out.println(failureDispatcher);
+  }
+
+  @Test
+  void testAddGroupPreEvent() {
+    dispatcher.addGroup(METALAKE, groupName);
+
+    // validate event
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(AddGroupPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+    Assertions.assertEquals(OperationType.ADD_GROUP, preEvent.operationType());
+
+    AddGroupPreEvent addGroupPreEvent = (AddGroupPreEvent) preEvent;
+    Assertions.assertEquals(identifier, addGroupPreEvent.identifier());
+    Assertions.assertEquals(groupName, addGroupPreEvent.groupName());
+  }
+
+  @Test
+  void testGetGroupPreEventWithExistingGroup() {
+    dispatcher.getGroup(METALAKE, groupName);
+
+    // validate event
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(GetGroupPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+    Assertions.assertEquals(OperationType.GET_GROUP, preEvent.operationType());
+
+    GetGroupPreEvent getGroupPreEvent = (GetGroupPreEvent) preEvent;
+    Assertions.assertEquals(identifier, getGroupPreEvent.identifier());
+    Assertions.assertEquals(groupName, getGroupPreEvent.groupName());
+  }
+
+  @Test
+  void testGroupNotFoundGetGroupPreEvent() {
+    Assertions.assertThrows(
+        NoSuchGroupException.class, () -> dispatcher.getGroup(METALAKE, 
inExistGroupName));
+  }
+
+  @Test
+  void testGetGroupPreEventWithInexistMetalake() {
+    Assertions.assertThrows(
+        NoSuchMetalakeException.class, () -> 
dispatcher.getGroup(INEXIST_METALAKE, groupName));
+  }
+
+  @Test
+  void testListGroupsPreEvent() {
+    dispatcher.listGroups(METALAKE);
+
+    // validate event
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(ListGroupsPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+    Assertions.assertEquals(OperationType.LIST_GROUPS, 
preEvent.operationType());
+
+    ListGroupsPreEvent listGroupsPreEvent = (ListGroupsPreEvent) preEvent;
+    Assertions.assertEquals(identifier, listGroupsPreEvent.identifier());
+  }
+
+  @Test
+  void testListGroupNamesPreEvent() {
+    dispatcher.listGroupNames(METALAKE);
+
+    // validate event
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(ListGroupNamesPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+    Assertions.assertEquals(OperationType.LIST_GROUP_NAMES, 
preEvent.operationType());
+
+    ListGroupNamesPreEvent listGroupNamesPreEvent = (ListGroupNamesPreEvent) 
preEvent;
+    Assertions.assertEquals(identifier, listGroupNamesPreEvent.identifier());
+  }
+
+  @Test
+  void testRemoveGroupPreEvent() {
+    dispatcher.removeGroup(METALAKE, groupName);
+
+    // validate event
+    PreEvent preEvent = dummyEventListener.popPreEvent();
+    Assertions.assertEquals(RemoveGroupPreEvent.class, preEvent.getClass());
+    Assertions.assertEquals(OperationStatus.UNPROCESSED, 
preEvent.operationStatus());
+    Assertions.assertEquals(OperationType.REMOVE_GROUP, 
preEvent.operationType());
+
+    RemoveGroupPreEvent removeGroupPreEvent = (RemoveGroupPreEvent) preEvent;
+    Assertions.assertEquals(identifier, removeGroupPreEvent.identifier());
+    Assertions.assertEquals(groupName, removeGroupPreEvent.groupName());
+  }
+
+  private Group getMockGroup(String name, List<String> roles) {
+    Group mockGroup = mock(Group.class);
+    when(mockGroup.name()).thenReturn(name);
+    when(mockGroup.roles()).thenReturn(roles);
+
+    return mockGroup;
+  }
+
+  private AccessControlEventDispatcher mockGroupDispatcher() {
+    AccessControlEventDispatcher dispatcher = 
mock(AccessControlEventDispatcher.class);
+    when(dispatcher.addGroup(METALAKE, groupName)).thenReturn(group);
+    when(dispatcher.addGroup(METALAKE, otherGroupName)).thenReturn(otherGroup);
+
+    when(dispatcher.removeGroup(METALAKE, groupName)).thenReturn(true);
+    when(dispatcher.removeGroup(METALAKE, inExistGroupName)).thenReturn(false);
+
+    when(dispatcher.listGroups(METALAKE)).thenReturn(new Group[] {group, 
otherGroup});
+    when(dispatcher.listGroupNames(METALAKE)).thenReturn(new String[] 
{groupName, otherGroupName});
+
+    when(dispatcher.getGroup(METALAKE, groupName)).thenReturn(group);
+    when(dispatcher.getGroup(METALAKE, inExistGroupName))
+        .thenThrow(new NoSuchGroupException("group not found"));
+    when(dispatcher.getGroup(INEXIST_METALAKE, groupName))
+        .thenThrow(new NoSuchMetalakeException("metalake not found"));
+
+    return dispatcher;
+  }
+
+  private AccessControlEventDispatcher mockExceptionGroupDispatcher() {
+    return mock(
+        AccessControlEventDispatcher.class,
+        invocation -> {
+          throw new GravitinoRuntimeException("Exception for all methods");
+        });
+  }
+}
diff --git 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestUserEvent.java 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestUserEvent.java
index 5acf13e1f9..9fcff6f86a 100644
--- 
a/core/src/test/java/org/apache/gravitino/listener/api/event/TestUserEvent.java
+++ 
b/core/src/test/java/org/apache/gravitino/listener/api/event/TestUserEvent.java
@@ -28,6 +28,7 @@ import java.util.List;
 import org.apache.gravitino.NameIdentifier;
 import org.apache.gravitino.authorization.User;
 import org.apache.gravitino.exceptions.GravitinoRuntimeException;
+import org.apache.gravitino.exceptions.NoSuchMetalakeException;
 import org.apache.gravitino.exceptions.NoSuchUserException;
 import org.apache.gravitino.listener.DummyEventListener;
 import org.apache.gravitino.listener.EventBus;
@@ -39,6 +40,7 @@ import org.junit.jupiter.api.TestInstance;
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public class TestUserEvent {
   private static final String METALAKE = "demo_metalake";
+  private static final String INEXIST_METALAKE = "inexist_metalake";
   private AccessControlEventDispatcher dispatcher;
   private AccessControlEventDispatcher failureDispatcher;
   private DummyEventListener dummyEventListener;
@@ -48,7 +50,6 @@ public class TestUserEvent {
   private User user;
   private User otherUser;
   private NameIdentifier identifier;
-  private NameIdentifier otherIdentifier;
 
   @BeforeAll
   void init() {
@@ -58,7 +59,6 @@ public class TestUserEvent {
     this.user = getMockUser(userName, ImmutableList.of("test", "engineer"));
     this.otherUser = getMockUser(otherUserName, null);
     this.identifier = NameIdentifier.of(METALAKE);
-    this.otherIdentifier = NameIdentifier.of(otherUserName);
 
     this.dummyEventListener = new DummyEventListener();
     EventBus eventBus = new 
EventBus(Collections.singletonList(dummyEventListener));
@@ -66,9 +66,7 @@ public class TestUserEvent {
     this.failureDispatcher =
         new AccessControlEventDispatcher(eventBus, 
mockExceptionUserDispatcher());
 
-    System.out.println(dispatcher);
     System.out.println(failureDispatcher);
-    System.out.println(otherIdentifier);
   }
 
   @Test
@@ -109,6 +107,12 @@ public class TestUserEvent {
         NoSuchUserException.class, () -> dispatcher.getUser(METALAKE, 
inExistUserName));
   }
 
+  @Test
+  void testGetUserPreEventWithNonExistingMetalake() {
+    Assertions.assertThrows(
+        NoSuchMetalakeException.class, () -> 
dispatcher.getUser(INEXIST_METALAKE, userName));
+  }
+
   @Test
   void testListUserPreEvent() {
     dispatcher.listUsers(METALAKE);
@@ -165,6 +169,8 @@ public class TestUserEvent {
     when(dispatcher.getUser(METALAKE, userName)).thenReturn(user);
     when(dispatcher.getUser(METALAKE, inExistUserName))
         .thenThrow(new NoSuchUserException("user not found"));
+    when(dispatcher.getUser(INEXIST_METALAKE, userName))
+        .thenThrow(new NoSuchMetalakeException("user not found"));
 
     return dispatcher;
   }
diff --git a/docs/gravitino-server-config.md b/docs/gravitino-server-config.md
index afcce0c42c..092735ee71 100644
--- a/docs/gravitino-server-config.md
+++ b/docs/gravitino-server-config.md
@@ -132,18 +132,19 @@ Gravitino triggers a pre-event before the operation, a 
post-event after the comp
 
 ##### Pre-event
 
-| Operation type                       | Pre-event                             
                                                                                
                                                                                
                                                                                
                                  | Since Version    |
-|--------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|
-| Iceberg REST server table operation  | `IcebergCreateTablePreEvent`, 
`IcebergUpdateTablePreEvent`, `IcebergDropTablePreEvent`, 
`IcebergLoadTablePreEvent`, `IcebergListTablePreEvent`, 
`IcebergTableExistsPreEvent`, `IcebergRenameTablePreEvent`                      
                                                                                
        | 0.7.0-incubating |
-| Gravitino server table operation     | `CreateTablePreEvent`, 
`AlterTablePreEvent`, `DropTablePreEvent`, `PurgeTablePreEvent`, 
`LoadTablePreEvent`, `ListTablePreEvent`                                        
                                                                                
                                                                | 
0.8.0-incubating |
-| Gravitino server schema operation    | `CreateSchemaPreEvent`, 
`AlterSchemaPreEvent`, `DropSchemaPreEvent`, `LoadSchemaPreEvent`, 
`ListSchemaPreEvent`                                                            
                                                                                
                                                             | 0.8.0-incubating 
|
-| Gravitino server catalog operation   | `CreateCatalogPreEvent`, 
`AlterCatalogPreEvent`, `DropCatalogPreEvent`, `LoadCatalogPreEvent`, 
`ListCatalogPreEvent`                                                           
                                                                                
                                                         | 0.8.0-incubating |
-| Gravitino server metalake operation  | `CreateMetalakePreEvent`, 
`AlterMetalakePreEvent`,`DropMetalakePreEvent`,`LoadMetalakePreEvent`,`ListMetalakePreEvent`
                                                                                
                                                                                
                                  | 0.8.0-incubating |
-| Gravitino server partition operation | `AddPartitionPreEvent`, 
`DropPartitionPreEvent`, `GetPartitionPreEvent`, 
`PurgePartitionPreEvent`,`ListPartitionPreEvent`,`ListPartitionNamesPreEvent`   
                                                                                
                                                                               
| 0.8.0-incubating |
-| Gravitino server fileset operation   | `CreateFilesetPreEvent`, 
`AlterFilesetPreEvent`, `DropFilesetPreEvent`, 
`LoadFilesetPreEvent`,`ListFilesetPreEvent`,`GetFileLocationPreEvent`           
                                                                                
                                                                                
| 0.8.0-incubating |
-| Gravitino server model operation     | `DeleteModelPreEvent`, 
`DeleteModelVersionPreEvent`, 
`RegisterAndLinkModelPreEvent`,`GetModelPreEvent`, 
`GetModelVersionPreEvent`,`LinkModelVersionPreEvent`,`ListModelPreEvent`,`RegisterModelPreEvent`
                                                                                
                                                             | 0.9.0-incubating 
|
+| Operation type                       | Pre-event                             
                                                                                
                                                                                
                                                                                
                                     | Since Version    |
+|--------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|
+| Iceberg REST server table operation  | `IcebergCreateTablePreEvent`, 
`IcebergUpdateTablePreEvent`, `IcebergDropTablePreEvent`, 
`IcebergLoadTablePreEvent`, `IcebergListTablePreEvent`, 
`IcebergTableExistsPreEvent`, `IcebergRenameTablePreEvent`                      
                                                                                
           | 0.7.0-incubating |
+| Gravitino server table operation     | `CreateTablePreEvent`, 
`AlterTablePreEvent`, `DropTablePreEvent`, `PurgeTablePreEvent`, 
`LoadTablePreEvent`, `ListTablePreEvent`                                        
                                                                                
                                                                   | 
0.8.0-incubating |
+| Gravitino server schema operation    | `CreateSchemaPreEvent`, 
`AlterSchemaPreEvent`, `DropSchemaPreEvent`, `LoadSchemaPreEvent`, 
`ListSchemaPreEvent`                                                            
                                                                                
                                                                | 
0.8.0-incubating |
+| Gravitino server catalog operation   | `CreateCatalogPreEvent`, 
`AlterCatalogPreEvent`, `DropCatalogPreEvent`, `LoadCatalogPreEvent`, 
`ListCatalogPreEvent`                                                           
                                                                                
                                                            | 0.8.0-incubating |
+| Gravitino server metalake operation  | `CreateMetalakePreEvent`, 
`AlterMetalakePreEvent`,`DropMetalakePreEvent`,`LoadMetalakePreEvent`,`ListMetalakePreEvent`
                                                                                
                                                                                
                                     | 0.8.0-incubating |
+| Gravitino server partition operation | `AddPartitionPreEvent`, 
`DropPartitionPreEvent`, `GetPartitionPreEvent`, 
`PurgePartitionPreEvent`,`ListPartitionPreEvent`,`ListPartitionNamesPreEvent`   
                                                                                
                                                                                
  | 0.8.0-incubating |
+| Gravitino server fileset operation   | `CreateFilesetPreEvent`, 
`AlterFilesetPreEvent`, `DropFilesetPreEvent`, 
`LoadFilesetPreEvent`,`ListFilesetPreEvent`,`GetFileLocationPreEvent`           
                                                                                
                                                                                
   | 0.8.0-incubating |
+| Gravitino server model operation     | `DeleteModelPreEvent`, 
`DeleteModelVersionPreEvent`, 
`RegisterAndLinkModelPreEvent`,`GetModelPreEvent`, 
`GetModelVersionPreEvent`,`LinkModelVersionPreEvent`,`ListModelPreEvent`,`RegisterModelPreEvent`
                                                                                
                                   | 0.9.0-incubating |
 | Gravitino server tag operation       | `ListTagsPreEvent`, 
`ListTagsInfoPreEvent`, `CreateTagPreEvent`, `GetTagPreEvent`, 
`AlterTagPreEvent`, `DeleteTagPreEvent`, `ListMetadataObjectsForTagPreEvent`, 
`ListTagsForMetadataObjectPreEvent`, `ListTagsInfoForMetadataObjectPreEvent`, 
`AssociateTagsForMetadataObjectPreEvent`, `GetTagForMetadataObjectPreEvent` | 
0.9.0-incubating |
-| Gravitino server user operation      | `AddUserPreEvent`, `GetUserPreEvent`, 
`ListUserNamesPreEvent`, `ListUserPreEvent`, `RemoveUserPreEvent` | 
0.9.0-incubating |
+| Gravitino server user operation      | `AddUserPreEvent`, `GetUserPreEvent`, 
`ListUserNamesPreEvent`, `ListUsersPreEvent`, `RemoveUserPreEvent`              
                                                                                
                                                                                
                                     | 0.9.0-incubating |
+| Gravitino server group operation     | `AddGroupPreEvent`, 
`GetGroupPreEvent`, `ListGroupNamesPreEvent`, `ListGroupsPreEvent`, 
`RemoveGroupPreEvent`                                                           
                                                                                
                                                                   | 
0.9.0-incubating |
 
 #### Event listener plugin
 


Reply via email to