This is an automated email from the ASF dual-hosted git repository.
roryqi 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 89523946e6 [#11068] feat(authn): Add built-in IdP group meta storage
model (#11127)
89523946e6 is described below
commit 89523946e6b20d391700d303f3f8cf9515072404
Author: MaSai <[email protected]>
AuthorDate: Tue May 19 01:17:31 2026 +0800
[#11068] feat(authn): Add built-in IdP group meta storage model (#11127)
### What changes were proposed in this pull request?
This PR adds the built-in IdP group metadata relational storage model
under `plugins:idp-basic`.
It introduces:
- the `IdpGroupPO` persistent object for built-in IdP groups
- the `IdpGroupMetaMapper` MyBatis mapper for querying, inserting, soft
deleting, and cleaning legacy group metadata
- the `IdpGroupMetaSQLProviderFactory` together with base, H2, and
PostgreSQL SQL providers for group metadata
- mapper package registration updates so the built-in IdP group mapper
is loaded by the `idp-basic` plugin
- tests covering the group PO, SQL providers, and storage behavior
This PR keeps the new group metadata storage implementation aligned with
the existing built-in IdP user metadata code by:
- following the same PO, mapper, and SQL provider structure
- keeping MySQL in the base provider and using dedicated H2 and
PostgreSQL providers for dialect differences
- using the shared storage test base and mapper-driven test setup
already used by the user metadata tests
### Why are the changes needed?
The built-in IdP needs a relational group metadata model so group
records can be persisted and queried consistently across the supported
JDBC backends.
Part of apache/gravitino#11068
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
```bash
./gradlew --no-daemon :plugins:idp-basic:test -PskipITs
-PskipDockerTests=false \
--tests org.apache.gravitino.idp.storage.po.TestIdpGroupPO \
--tests
org.apache.gravitino.idp.storage.mapper.TestIdpBasicMapperPackageProvider \
--tests
org.apache.gravitino.idp.storage.mapper.TestIdpGroupMetaSQLProviderFactory \
--tests
org.apache.gravitino.idp.storage.mapper.provider.base.TestIdpGroupMetaBaseSQLProvider
\
--tests
org.apache.gravitino.idp.storage.mapper.provider.h2.TestIdpGroupMetaH2Provider \
--tests
org.apache.gravitino.idp.storage.mapper.provider.postgresql.TestIdpGroupMetaPostgreSQLProvider
\
--tests org.apache.gravitino.idp.storage.mapper.TestIdpGroupMetaStorage
```
`TestIdpGroupMetaStorage` covers H2, MySQL, and PostgreSQL when
`-PskipDockerTests=false` is set.
---
...UserMetaMapper.java => IdpGroupMetaMapper.java} | 40 ++--
.../mapper/IdpGroupMetaSQLProviderFactory.java | 79 ++++++++
.../idp/storage/mapper/IdpUserMetaMapper.java | 4 +
.../mapper/IdpUserMetaSQLProviderFactory.java | 88 +++------
.../storage/mapper/SQLProviderFactoryHelper.java | 68 +++++++
.../provider/IdpBasicMapperPackageProvider.java | 3 +-
.../provider/base/IdpGroupMetaBaseSQLProvider.java | 84 ++++++++
.../IdpGroupMetaH2Provider.java} | 16 +-
.../postgresql/IdpGroupMetaPostgreSQLProvider.java | 42 ++++
.../IdpGroupPO.java} | 32 +--
.../storage/mapper/AbstractIdpMetaStorageTest.java | 66 +------
.../mapper/TestIdpBasicMapperPackageProvider.java | 54 +++++
.../storage/mapper/TestIdpGroupMetaStorage.java | 220 +++++++++++++++++++++
.../idp/storage/mapper/TestIdpUserMetaStorage.java | 158 +++++++++++++--
.../mapper/TestSQLProviderFactoryHelper.java | 68 +++++++
.../base/TestIdpGroupMetaBaseSQLProvider.java | 163 +++++++++++++++
.../provider/h2/TestIdpGroupMetaH2Provider.java} | 22 ++-
.../TestIdpGroupMetaPostgreSQLProvider.java | 45 +++++
.../gravitino/idp/storage/po/TestIdpGroupPO.java | 84 ++++++++
19 files changed, 1141 insertions(+), 195 deletions(-)
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaMapper.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpGroupMetaMapper.java
similarity index 55%
copy from
plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaMapper.java
copy to
plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpGroupMetaMapper.java
index 9aa677ebe2..88419f8349 100644
---
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaMapper.java
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpGroupMetaMapper.java
@@ -20,7 +20,7 @@
package org.apache.gravitino.idp.storage.mapper;
import java.util.List;
-import org.apache.gravitino.idp.storage.po.IdpUserPO;
+import org.apache.gravitino.idp.storage.po.IdpGroupPO;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Param;
@@ -28,35 +28,35 @@ import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
/**
- * A MyBatis mapper for built-in IdP user metadata operations.
+ * A MyBatis mapper for built-in IdP group metadata operations.
*
- * <p>This interface defines the SQL statements MyBatis executes for the
built-in IdP user metadata
+ * <p>This interface defines the SQL statements MyBatis executes for the
built-in IdP group metadata
* store. The SQLs are provided through {@code *Provider} annotations on this
mapper interface. See
* the <a href="https://mybatis.org/mybatis-3/getting-started.html">MyBatis
getting started
* guide</a>.
*/
-public interface IdpUserMetaMapper {
- String IDP_USER_TABLE_NAME = "idp_user_meta";
+public interface IdpGroupMetaMapper {
+ String IDP_GROUP_TABLE_NAME = "idp_group_meta";
- @SelectProvider(type = IdpUserMetaSQLProviderFactory.class, method =
"selectIdpUser")
- IdpUserPO selectIdpUser(@Param("username") String username);
+ @SelectProvider(type = IdpGroupMetaSQLProviderFactory.class, method =
"selectIdpGroup")
+ IdpGroupPO selectIdpGroup(@Param("groupName") String groupName);
- @SelectProvider(type = IdpUserMetaSQLProviderFactory.class, method =
"selectIdpUsers")
- List<IdpUserPO> selectIdpUsers(@Param("usernames") List<String> usernames);
+ /**
+ * Selects active groups by name. An empty list returns all active groups;
pass null for an
+ * explicit error.
+ */
+ @SelectProvider(type = IdpGroupMetaSQLProviderFactory.class, method =
"selectIdpGroups")
+ List<IdpGroupPO> selectIdpGroups(@Param("groupNames") List<String>
groupNames);
- @InsertProvider(type = IdpUserMetaSQLProviderFactory.class, method =
"insertIdpUser")
- void insertIdpUser(@Param("userMeta") IdpUserPO userPO);
+ @InsertProvider(type = IdpGroupMetaSQLProviderFactory.class, method =
"insertIdpGroup")
+ void insertIdpGroup(@Param("groupMeta") IdpGroupPO groupPO);
- @UpdateProvider(type = IdpUserMetaSQLProviderFactory.class, method =
"updateIdpUserPassword")
- Integer updateIdpUserPassword(
- @Param("userId") Long userId, @Param("passwordHash") String
passwordHash);
-
- @UpdateProvider(type = IdpUserMetaSQLProviderFactory.class, method =
"softDeleteIdpUser")
- Integer softDeleteIdpUser(@Param("userId") Long userId);
+ @UpdateProvider(type = IdpGroupMetaSQLProviderFactory.class, method =
"softDeleteIdpGroup")
+ Integer softDeleteIdpGroup(@Param("groupId") Long groupId);
@DeleteProvider(
- type = IdpUserMetaSQLProviderFactory.class,
- method = "deleteIdpUserMetasByLegacyTimeline")
- Integer deleteIdpUserMetasByLegacyTimeline(
+ type = IdpGroupMetaSQLProviderFactory.class,
+ method = "deleteIdpGroupMetasByLegacyTimeline")
+ Integer deleteIdpGroupMetasByLegacyTimeline(
@Param("legacyTimeline") Long legacyTimeline, @Param("limit") int limit);
}
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpGroupMetaSQLProviderFactory.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpGroupMetaSQLProviderFactory.java
new file mode 100644
index 0000000000..4241ffc598
--- /dev/null
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpGroupMetaSQLProviderFactory.java
@@ -0,0 +1,79 @@
+/*
+ * 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.idp.storage.mapper;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.List;
+import java.util.Map;
+import
org.apache.gravitino.idp.storage.mapper.provider.base.IdpGroupMetaBaseSQLProvider;
+import
org.apache.gravitino.idp.storage.mapper.provider.h2.IdpGroupMetaH2Provider;
+import
org.apache.gravitino.idp.storage.mapper.provider.postgresql.IdpGroupMetaPostgreSQLProvider;
+import org.apache.gravitino.idp.storage.po.IdpGroupPO;
+import org.apache.gravitino.storage.relational.JDBCBackend.JDBCBackendType;
+import org.apache.ibatis.annotations.Param;
+
+public class IdpGroupMetaSQLProviderFactory {
+ private static final IdpGroupMetaBaseSQLProvider MYSQL_PROVIDER =
+ new IdpGroupMetaBaseSQLProvider();
+ private static final IdpGroupMetaBaseSQLProvider H2_PROVIDER = new
IdpGroupMetaH2Provider();
+ private static final IdpGroupMetaBaseSQLProvider POSTGRESQL_PROVIDER =
+ new IdpGroupMetaPostgreSQLProvider();
+ private static final Map<JDBCBackendType, IdpGroupMetaBaseSQLProvider>
PROVIDER_MAP =
+ ImmutableMap.of(
+ JDBCBackendType.MYSQL,
+ MYSQL_PROVIDER,
+ JDBCBackendType.H2,
+ H2_PROVIDER,
+ JDBCBackendType.POSTGRESQL,
+ POSTGRESQL_PROVIDER);
+
+ private IdpGroupMetaSQLProviderFactory() {}
+
+ private static IdpGroupMetaBaseSQLProvider currentProvider() {
+ return SQLProviderFactoryHelper.currentProvider(
+ PROVIDER_MAP, IdpGroupMetaSQLProviderFactory.class);
+ }
+
+ static IdpGroupMetaBaseSQLProvider getProvider(String databaseId) {
+ return SQLProviderFactoryHelper.getProvider(
+ databaseId, PROVIDER_MAP, IdpGroupMetaSQLProviderFactory.class);
+ }
+
+ public static String selectIdpGroup(@Param("groupName") String groupName) {
+ return currentProvider().selectIdpGroup(groupName);
+ }
+
+ public static String selectIdpGroups(@Param("groupNames") List<String>
groupNames) {
+ return currentProvider().selectIdpGroups(groupNames);
+ }
+
+ public static String insertIdpGroup(@Param("groupMeta") IdpGroupPO groupPO) {
+ return currentProvider().insertIdpGroup(groupPO);
+ }
+
+ public static String softDeleteIdpGroup(@Param("groupId") Long groupId) {
+ return currentProvider().softDeleteIdpGroup(groupId);
+ }
+
+ public static String deleteIdpGroupMetasByLegacyTimeline(
+ @Param("legacyTimeline") Long legacyTimeline, @Param("limit") int limit)
{
+ return
currentProvider().deleteIdpGroupMetasByLegacyTimeline(legacyTimeline, limit);
+ }
+}
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaMapper.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaMapper.java
index 9aa677ebe2..41c3476030 100644
---
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaMapper.java
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaMapper.java
@@ -41,6 +41,10 @@ public interface IdpUserMetaMapper {
@SelectProvider(type = IdpUserMetaSQLProviderFactory.class, method =
"selectIdpUser")
IdpUserPO selectIdpUser(@Param("username") String username);
+ /**
+ * Selects active users by name. An empty list returns all active users;
pass null for an explicit
+ * error.
+ */
@SelectProvider(type = IdpUserMetaSQLProviderFactory.class, method =
"selectIdpUsers")
List<IdpUserPO> selectIdpUsers(@Param("usernames") List<String> usernames);
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaSQLProviderFactory.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaSQLProviderFactory.java
index 27e77781ed..46057906d9 100644
---
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaSQLProviderFactory.java
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/IdpUserMetaSQLProviderFactory.java
@@ -27,93 +27,57 @@ import
org.apache.gravitino.idp.storage.mapper.provider.h2.IdpUserMetaH2Provider
import
org.apache.gravitino.idp.storage.mapper.provider.postgresql.IdpUserMetaPostgreSQLProvider;
import org.apache.gravitino.idp.storage.po.IdpUserPO;
import org.apache.gravitino.storage.relational.JDBCBackend.JDBCBackendType;
-import org.apache.gravitino.storage.relational.session.SqlSessionFactoryHelper;
import org.apache.ibatis.annotations.Param;
public class IdpUserMetaSQLProviderFactory {
- private static final IdpUserMetaBaseSQLProvider IDP_USER_META_BASE_PROVIDER =
- new IdpUserMetaBaseSQLProvider();
- private static final IdpUserMetaBaseSQLProvider IDP_USER_META_H2_PROVIDER =
- new IdpUserMetaH2Provider();
- private static final IdpUserMetaBaseSQLProvider
IDP_USER_META_POSTGRESQL_PROVIDER =
+ private static final IdpUserMetaBaseSQLProvider MYSQL_PROVIDER = new
IdpUserMetaBaseSQLProvider();
+ private static final IdpUserMetaBaseSQLProvider H2_PROVIDER = new
IdpUserMetaH2Provider();
+ private static final IdpUserMetaBaseSQLProvider POSTGRESQL_PROVIDER =
new IdpUserMetaPostgreSQLProvider();
-
- private static final Map<JDBCBackendType, IdpUserMetaBaseSQLProvider>
- IDP_USER_META_SQL_PROVIDER_MAP =
- ImmutableMap.of(
- JDBCBackendType.MYSQL, IDP_USER_META_BASE_PROVIDER,
- JDBCBackendType.H2, IDP_USER_META_H2_PROVIDER,
- JDBCBackendType.POSTGRESQL, IDP_USER_META_POSTGRESQL_PROVIDER);
-
- static IdpUserMetaBaseSQLProvider getProvider(String databaseId) {
- if (databaseId == null) {
- throw new IllegalStateException(
- "MyBatis databaseId is not configured for IdP user SQL providers.");
- }
-
- try {
- JDBCBackendType jdbcBackendType = JDBCBackendType.fromString(databaseId);
- IdpUserMetaBaseSQLProvider provider =
IDP_USER_META_SQL_PROVIDER_MAP.get(jdbcBackendType);
- if (provider != null) {
- return provider;
- }
-
- throw new IllegalStateException(
- String.format(
- "No IdP user SQL provider registered for backend %s (databaseId:
%s)",
- jdbcBackendType, databaseId));
- } catch (IllegalArgumentException e) {
- throw new IllegalStateException(
- String.format(
- "Unsupported IdP user SQL provider databaseId: %s, supported
backends: %s",
- databaseId, IDP_USER_META_SQL_PROVIDER_MAP.keySet()),
- e);
- }
- }
-
- public static IdpUserMetaBaseSQLProvider h2Provider() {
- return IDP_USER_META_H2_PROVIDER;
- }
-
- public static IdpUserMetaBaseSQLProvider mysqlProvider() {
- return IDP_USER_META_BASE_PROVIDER;
+ private static final Map<JDBCBackendType, IdpUserMetaBaseSQLProvider>
PROVIDER_MAP =
+ ImmutableMap.of(
+ JDBCBackendType.MYSQL,
+ MYSQL_PROVIDER,
+ JDBCBackendType.H2,
+ H2_PROVIDER,
+ JDBCBackendType.POSTGRESQL,
+ POSTGRESQL_PROVIDER);
+
+ private IdpUserMetaSQLProviderFactory() {}
+
+ private static IdpUserMetaBaseSQLProvider currentProvider() {
+ return SQLProviderFactoryHelper.currentProvider(
+ PROVIDER_MAP, IdpUserMetaSQLProviderFactory.class);
}
- public static IdpUserMetaBaseSQLProvider postgresqlProvider() {
- return IDP_USER_META_POSTGRESQL_PROVIDER;
+ static IdpUserMetaBaseSQLProvider getProvider(String databaseId) {
+ return SQLProviderFactoryHelper.getProvider(
+ databaseId, PROVIDER_MAP, IdpUserMetaSQLProviderFactory.class);
}
public static String selectIdpUser(@Param("username") String username) {
- return getProvider(currentDatabaseId()).selectIdpUser(username);
+ return currentProvider().selectIdpUser(username);
}
public static String selectIdpUsers(@Param("usernames") List<String>
usernames) {
- return getProvider(currentDatabaseId()).selectIdpUsers(usernames);
+ return currentProvider().selectIdpUsers(usernames);
}
public static String insertIdpUser(@Param("userMeta") IdpUserPO userPO) {
- return getProvider(currentDatabaseId()).insertIdpUser(userPO);
+ return currentProvider().insertIdpUser(userPO);
}
public static String updateIdpUserPassword(
@Param("userId") Long userId, @Param("passwordHash") String
passwordHash) {
- return getProvider(currentDatabaseId()).updateIdpUserPassword(userId,
passwordHash);
+ return currentProvider().updateIdpUserPassword(userId, passwordHash);
}
public static String softDeleteIdpUser(@Param("userId") Long userId) {
- return getProvider(currentDatabaseId()).softDeleteIdpUser(userId);
+ return currentProvider().softDeleteIdpUser(userId);
}
public static String deleteIdpUserMetasByLegacyTimeline(
@Param("legacyTimeline") Long legacyTimeline, @Param("limit") int limit)
{
- return getProvider(currentDatabaseId())
- .deleteIdpUserMetasByLegacyTimeline(legacyTimeline, limit);
- }
-
- private static String currentDatabaseId() {
- return SqlSessionFactoryHelper.getInstance()
- .getSqlSessionFactory()
- .getConfiguration()
- .getDatabaseId();
+ return
currentProvider().deleteIdpUserMetasByLegacyTimeline(legacyTimeline, limit);
}
}
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/SQLProviderFactoryHelper.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/SQLProviderFactoryHelper.java
new file mode 100644
index 0000000000..cbb6726c45
--- /dev/null
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/SQLProviderFactoryHelper.java
@@ -0,0 +1,68 @@
+/*
+ * 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.idp.storage.mapper;
+
+import java.util.Map;
+import org.apache.gravitino.storage.relational.JDBCBackend.JDBCBackendType;
+import org.apache.gravitino.storage.relational.session.SqlSessionFactoryHelper;
+
+final class SQLProviderFactoryHelper {
+ private SQLProviderFactoryHelper() {}
+
+ static <T> T getProvider(
+ String databaseId, Map<JDBCBackendType, T> providerMap, Class<?>
providerFactoryClass) {
+ if (databaseId == null) {
+ throw new IllegalStateException(
+ String.format(
+ "MyBatis databaseId is not configured for %s.",
+ providerFactoryClass.getSimpleName()));
+ }
+
+ try {
+ JDBCBackendType jdbcBackendType = JDBCBackendType.fromString(databaseId);
+ T provider = providerMap.get(jdbcBackendType);
+ if (provider != null) {
+ return provider;
+ }
+
+ throw new IllegalStateException(
+ String.format(
+ "No %s registered for backend %s (databaseId: %s)",
+ providerFactoryClass.getSimpleName(), jdbcBackendType,
databaseId));
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException(
+ String.format(
+ "Unsupported %s databaseId: %s, supported backends: %s",
+ providerFactoryClass.getSimpleName(), databaseId,
providerMap.keySet()),
+ e);
+ }
+ }
+
+ static <T> T currentProvider(Map<JDBCBackendType, T> providerMap, Class<?>
providerFactoryClass) {
+ return getProvider(currentDatabaseId(), providerMap, providerFactoryClass);
+ }
+
+ static String currentDatabaseId() {
+ return SqlSessionFactoryHelper.getInstance()
+ .getSqlSessionFactory()
+ .getConfiguration()
+ .getDatabaseId();
+ }
+}
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
index 3cf51de9fa..075c994067 100644
---
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
@@ -20,6 +20,7 @@ package org.apache.gravitino.idp.storage.mapper.provider;
import com.google.common.collect.ImmutableList;
import java.util.List;
+import org.apache.gravitino.idp.storage.mapper.IdpGroupMetaMapper;
import org.apache.gravitino.idp.storage.mapper.IdpUserMetaMapper;
import
org.apache.gravitino.storage.relational.mapper.provider.MapperPackageProvider;
@@ -28,6 +29,6 @@ public class IdpBasicMapperPackageProvider implements
MapperPackageProvider {
@Override
public List<Class<?>> getMapperClasses() {
- return ImmutableList.of(IdpUserMetaMapper.class);
+ return ImmutableList.of(IdpUserMetaMapper.class, IdpGroupMetaMapper.class);
}
}
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/base/IdpGroupMetaBaseSQLProvider.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/base/IdpGroupMetaBaseSQLProvider.java
new file mode 100644
index 0000000000..a99edacec2
--- /dev/null
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/base/IdpGroupMetaBaseSQLProvider.java
@@ -0,0 +1,84 @@
+/*
+ * 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.idp.storage.mapper.provider.base;
+
+import java.util.List;
+import org.apache.gravitino.idp.storage.mapper.IdpGroupMetaMapper;
+import org.apache.gravitino.idp.storage.po.IdpGroupPO;
+import org.apache.ibatis.annotations.Param;
+
+public class IdpGroupMetaBaseSQLProvider {
+
+ public String selectIdpGroup(@Param("groupName") String groupName) {
+ return "SELECT group_id as groupId, group_name as groupName,"
+ + " current_version as currentVersion,"
+ + " last_version as lastVersion, deleted_at as deletedAt"
+ + " FROM "
+ + IdpGroupMetaMapper.IDP_GROUP_TABLE_NAME
+ + " WHERE group_name = #{groupName} AND deleted_at = 0";
+ }
+
+ public String selectIdpGroups(@Param("groupNames") List<String> groupNames) {
+ return "<script>"
+ + "SELECT group_id as groupId, group_name as groupName,"
+ + " current_version as currentVersion,"
+ + " last_version as lastVersion, deleted_at as deletedAt"
+ + " FROM "
+ + IdpGroupMetaMapper.IDP_GROUP_TABLE_NAME
+ + " WHERE deleted_at = 0 "
+ + "<foreach collection='groupNames' item='groupName'"
+ + " open='AND group_name IN (' separator=',' close=')'>"
+ + "#{groupName}"
+ + "</foreach>"
+ + "</script>";
+ }
+
+ public String insertIdpGroup(@Param("groupMeta") IdpGroupPO groupPO) {
+ return "INSERT INTO "
+ + IdpGroupMetaMapper.IDP_GROUP_TABLE_NAME
+ + " (group_id, group_name, current_version, last_version, deleted_at)"
+ + " VALUES ("
+ + " #{groupMeta.groupId},"
+ + " #{groupMeta.groupName},"
+ + " #{groupMeta.currentVersion},"
+ + " #{groupMeta.lastVersion},"
+ + " #{groupMeta.deletedAt}"
+ + " )";
+ }
+
+ public String softDeleteIdpGroup(@Param("groupId") Long groupId) {
+ return "UPDATE "
+ + IdpGroupMetaMapper.IDP_GROUP_TABLE_NAME
+ + " SET deleted_at = "
+ + currentTimeMillisExpression()
+ + " WHERE group_id = #{groupId} AND deleted_at = 0";
+ }
+
+ public String deleteIdpGroupMetasByLegacyTimeline(
+ @Param("legacyTimeline") Long legacyTimeline, @Param("limit") int limit)
{
+ return "DELETE FROM "
+ + IdpGroupMetaMapper.IDP_GROUP_TABLE_NAME
+ + " WHERE deleted_at > 0 AND deleted_at < #{legacyTimeline} LIMIT
#{limit}";
+ }
+
+ protected String currentTimeMillisExpression() {
+ return "(UNIX_TIMESTAMP() * 1000.0)";
+ }
+}
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/h2/IdpGroupMetaH2Provider.java
similarity index 61%
copy from
plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
copy to
plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/h2/IdpGroupMetaH2Provider.java
index 3cf51de9fa..b87e0bee38 100644
---
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/h2/IdpGroupMetaH2Provider.java
@@ -16,18 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino.idp.storage.mapper.provider;
-import com.google.common.collect.ImmutableList;
-import java.util.List;
-import org.apache.gravitino.idp.storage.mapper.IdpUserMetaMapper;
-import
org.apache.gravitino.storage.relational.mapper.provider.MapperPackageProvider;
+package org.apache.gravitino.idp.storage.mapper.provider.h2;
-/** Supplies built-in IdP mapper classes from the idp-basic plugin. */
-public class IdpBasicMapperPackageProvider implements MapperPackageProvider {
+import
org.apache.gravitino.idp.storage.mapper.provider.base.IdpGroupMetaBaseSQLProvider;
+
+/** SQL provider for IdP group metadata statements on H2 backends. */
+public class IdpGroupMetaH2Provider extends IdpGroupMetaBaseSQLProvider {
@Override
- public List<Class<?>> getMapperClasses() {
- return ImmutableList.of(IdpUserMetaMapper.class);
+ protected String currentTimeMillisExpression() {
+ return "DATEDIFF('MILLISECOND', TIMESTAMP '1970-01-01 00:00:00',
CURRENT_TIMESTAMP())";
}
}
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/postgresql/IdpGroupMetaPostgreSQLProvider.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/postgresql/IdpGroupMetaPostgreSQLProvider.java
new file mode 100644
index 0000000000..a808bc2472
--- /dev/null
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/postgresql/IdpGroupMetaPostgreSQLProvider.java
@@ -0,0 +1,42 @@
+/*
+ * 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.idp.storage.mapper.provider.postgresql;
+
+import org.apache.gravitino.idp.storage.mapper.IdpGroupMetaMapper;
+import
org.apache.gravitino.idp.storage.mapper.provider.base.IdpGroupMetaBaseSQLProvider;
+import org.apache.ibatis.annotations.Param;
+
+public class IdpGroupMetaPostgreSQLProvider extends
IdpGroupMetaBaseSQLProvider {
+
+ @Override
+ protected String currentTimeMillisExpression() {
+ return "CAST(EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000 AS BIGINT)";
+ }
+
+ @Override
+ public String deleteIdpGroupMetasByLegacyTimeline(
+ @Param("legacyTimeline") Long legacyTimeline, @Param("limit") int limit)
{
+ return "DELETE FROM "
+ + IdpGroupMetaMapper.IDP_GROUP_TABLE_NAME
+ + " WHERE group_id IN (SELECT group_id FROM "
+ + IdpGroupMetaMapper.IDP_GROUP_TABLE_NAME
+ + " WHERE deleted_at > 0 AND deleted_at < #{legacyTimeline} LIMIT
#{limit})";
+ }
+}
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/po/IdpGroupPO.java
similarity index 58%
copy from
plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
copy to
plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/po/IdpGroupPO.java
index 3cf51de9fa..0aa518a1eb 100644
---
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
+++
b/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/po/IdpGroupPO.java
@@ -16,18 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino.idp.storage.mapper.provider;
+package org.apache.gravitino.idp.storage.po;
-import com.google.common.collect.ImmutableList;
-import java.util.List;
-import org.apache.gravitino.idp.storage.mapper.IdpUserMetaMapper;
-import
org.apache.gravitino.storage.relational.mapper.provider.MapperPackageProvider;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
-/** Supplies built-in IdP mapper classes from the idp-basic plugin. */
-public class IdpBasicMapperPackageProvider implements MapperPackageProvider {
-
- @Override
- public List<Class<?>> getMapperClasses() {
- return ImmutableList.of(IdpUserMetaMapper.class);
- }
+@Getter
+@EqualsAndHashCode
+@ToString
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+@Builder(setterPrefix = "with")
+public class IdpGroupPO {
+ private Long groupId;
+ private String groupName;
+ private Long currentVersion;
+ private Long lastVersion;
+ private Long deletedAt;
}
diff --git
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/AbstractIdpMetaStorageTest.java
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/AbstractIdpMetaStorageTest.java
index 06f97b8288..f41f323835 100644
---
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/AbstractIdpMetaStorageTest.java
+++
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/AbstractIdpMetaStorageTest.java
@@ -19,15 +19,11 @@
package org.apache.gravitino.idp.storage.mapper;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.Connection;
import java.sql.DriverManager;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
@@ -38,7 +34,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.gravitino.Config;
import org.apache.gravitino.Configs;
import org.apache.gravitino.config.ConfigConstants;
-import org.apache.gravitino.idp.storage.po.IdpUserPO;
import org.apache.gravitino.integration.test.container.ContainerSuite;
import org.apache.gravitino.integration.test.container.MySQLContainer;
import org.apache.gravitino.integration.test.container.PostgreSQLContainer;
@@ -57,7 +52,6 @@ abstract class AbstractIdpMetaStorageTest {
protected JDBCBackend backend;
protected SqlSession sharedSession;
- protected IdpUserMetaMapper idpUserMetaMapper;
private Config config;
private Path h2Path;
@@ -88,7 +82,7 @@ abstract class AbstractIdpMetaStorageTest {
backend = new JDBCBackend();
backend.initialize(config);
sharedSession =
SqlSessionFactoryHelper.getInstance().getSqlSessionFactory().openSession(true);
- idpUserMetaMapper = sharedSession.getMapper(IdpUserMetaMapper.class);
+ initializeMappers();
}
protected void restartBackend() throws IOException {
@@ -97,61 +91,7 @@ abstract class AbstractIdpMetaStorageTest {
backend = new JDBCBackend();
backend.initialize(config);
sharedSession =
SqlSessionFactoryHelper.getInstance().getSqlSessionFactory().openSession(true);
- idpUserMetaMapper = sharedSession.getMapper(IdpUserMetaMapper.class);
- }
-
- protected IdpUserPO insertUser(
- long userId,
- String userName,
- String passwordHash,
- long currentVersion,
- long lastVersion,
- long deletedAt) {
- IdpUserPO userPO =
- IdpUserPO.builder()
- .withUserId(userId)
- .withUserName(userName)
- .withPasswordHash(passwordHash)
- .withCurrentVersion(currentVersion)
- .withLastVersion(lastVersion)
- .withDeletedAt(deletedAt)
- .build();
- idpUserMetaMapper.insertIdpUser(userPO);
- return userPO;
- }
-
- protected long queryLongValue(String table, String column, String idColumn,
long idValue) {
- try (SqlSession sqlSession =
-
SqlSessionFactoryHelper.getInstance().getSqlSessionFactory().openSession(true);
- Connection connection = sqlSession.getConnection();
- PreparedStatement statement =
- connection.prepareStatement(
- "SELECT " + column + " FROM " + table + " WHERE " + idColumn +
" = ?")) {
- statement.setLong(1, idValue);
- try (ResultSet resultSet = statement.executeQuery()) {
- assertTrue(resultSet.next());
- return resultSet.getLong(1);
- }
- } catch (SQLException e) {
- throw new RuntimeException("Query " + column + " from " + table + "
failed", e);
- }
- }
-
- protected int countRows(String table, String idColumn, long idValue) {
- try (SqlSession sqlSession =
-
SqlSessionFactoryHelper.getInstance().getSqlSessionFactory().openSession(true);
- Connection connection = sqlSession.getConnection();
- PreparedStatement statement =
- connection.prepareStatement(
- "SELECT COUNT(1) FROM " + table + " WHERE " + idColumn + " =
?")) {
- statement.setLong(1, idValue);
- try (ResultSet resultSet = statement.executeQuery()) {
- assertTrue(resultSet.next());
- return resultSet.getInt(1);
- }
- } catch (SQLException e) {
- throw new RuntimeException("Count rows from " + table + " failed", e);
- }
+ initializeMappers();
}
protected void closeSession() {
@@ -161,6 +101,8 @@ abstract class AbstractIdpMetaStorageTest {
}
}
+ protected abstract void initializeMappers();
+
private Config createBackendConfig(String type) throws IOException {
Config backendConfig = new Config(false) {};
backendConfig.set(Configs.ENTITY_STORE, Configs.RELATIONAL_ENTITY_STORE);
diff --git
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpBasicMapperPackageProvider.java
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpBasicMapperPackageProvider.java
new file mode 100644
index 0000000000..3fcf1b6a7b
--- /dev/null
+++
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpBasicMapperPackageProvider.java
@@ -0,0 +1,54 @@
+/*
+ * 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.idp.storage.mapper;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import java.util.ServiceLoader;
+import
org.apache.gravitino.idp.storage.mapper.provider.IdpBasicMapperPackageProvider;
+import
org.apache.gravitino.storage.relational.mapper.provider.MapperPackageProvider;
+import org.junit.jupiter.api.Test;
+
+public class TestIdpBasicMapperPackageProvider {
+
+ @Test
+ public void testGetMapperClasses() {
+ MapperPackageProvider provider = new IdpBasicMapperPackageProvider();
+ List<Class<?>> mapperClasses = provider.getMapperClasses();
+
+ assertEquals(2, mapperClasses.size());
+ assertTrue(
+ mapperClasses.containsAll(List.of(IdpUserMetaMapper.class,
IdpGroupMetaMapper.class)));
+ }
+
+ @Test
+ public void testServiceLoaderDiscoversProvider() {
+ List<MapperPackageProvider> providers =
+ ServiceLoader.load(MapperPackageProvider.class).stream()
+ .map(ServiceLoader.Provider::get)
+ .filter(provider -> provider instanceof
IdpBasicMapperPackageProvider)
+ .toList();
+
+ assertEquals(1, providers.size());
+ assertTrue(providers.get(0) instanceof IdpBasicMapperPackageProvider);
+ }
+}
diff --git
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpGroupMetaStorage.java
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpGroupMetaStorage.java
new file mode 100644
index 0000000000..48ad87d48a
--- /dev/null
+++
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpGroupMetaStorage.java
@@ -0,0 +1,220 @@
+/*
+ * 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.idp.storage.mapper;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertIterableEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.util.Comparator;
+import java.util.List;
+import org.apache.gravitino.idp.storage.po.IdpGroupPO;
+import org.apache.gravitino.storage.relational.session.SqlSessionFactoryHelper;
+import org.apache.ibatis.exceptions.PersistenceException;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+@Tag("gravitino-docker-test")
+class TestIdpGroupMetaStorage extends AbstractIdpMetaStorageTest {
+ private IdpGroupMetaMapper idpGroupMetaMapper;
+
+ @Override
+ protected void initializeMappers() {
+ idpGroupMetaMapper = sharedSession.getMapper(IdpGroupMetaMapper.class);
+ }
+
+ @ParameterizedTest
+ @MethodSource("storageProvider")
+ void testInsertIdpGroupAndSelectIdpGroup(String type) throws IOException {
+ init(type);
+ IdpGroupPO firstGroup =
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("dev")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build();
+ idpGroupMetaMapper.insertIdpGroup(firstGroup);
+
+ assertEquals(firstGroup, idpGroupMetaMapper.selectIdpGroup("dev"));
+ assertNull(idpGroupMetaMapper.selectIdpGroup("unknown"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("storageProvider")
+ void testSelectIdpGroups(String type) throws IOException {
+ init(type);
+ IdpGroupPO firstGroup =
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("dev")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build();
+ IdpGroupPO secondGroup =
+ IdpGroupPO.builder()
+ .withGroupId(2L)
+ .withGroupName("ops")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build();
+ idpGroupMetaMapper.insertIdpGroup(firstGroup);
+ idpGroupMetaMapper.insertIdpGroup(secondGroup);
+
+ List<IdpGroupPO> groups =
idpGroupMetaMapper.selectIdpGroups(List.of("ops", "dev"));
+ groups.sort(Comparator.comparing(IdpGroupPO::getGroupId));
+ assertIterableEquals(List.of(firstGroup, secondGroup), groups);
+ List<IdpGroupPO> groupsWithEmptyFilter =
idpGroupMetaMapper.selectIdpGroups(List.of());
+ groupsWithEmptyFilter.sort(Comparator.comparing(IdpGroupPO::getGroupId));
+ assertIterableEquals(List.of(firstGroup, secondGroup),
groupsWithEmptyFilter);
+ assertThrows(PersistenceException.class, () ->
idpGroupMetaMapper.selectIdpGroups(null));
+ }
+
+ @ParameterizedTest
+ @MethodSource("storageProvider")
+ void testSelectIdpGroupIgnoresDeletedGroups(String type) throws IOException {
+ init(type);
+ IdpGroupPO activeGroup =
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("dev")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build();
+ idpGroupMetaMapper.insertIdpGroup(activeGroup);
+ idpGroupMetaMapper.insertIdpGroup(
+ IdpGroupPO.builder()
+ .withGroupId(2L)
+ .withGroupName("ops")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(10L)
+ .build());
+
+ assertIterableEquals(
+ List.of(activeGroup),
idpGroupMetaMapper.selectIdpGroups(List.of("dev", "ops")));
+ assertNull(idpGroupMetaMapper.selectIdpGroup("ops"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("storageProvider")
+ void testSoftDeleteIdpGroup(String type) throws IOException {
+ init(type);
+ idpGroupMetaMapper.insertIdpGroup(
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("dev")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build());
+
+ assertEquals(1, idpGroupMetaMapper.softDeleteIdpGroup(1L));
+ assertNull(idpGroupMetaMapper.selectIdpGroup("dev"));
+ assertEquals(0, idpGroupMetaMapper.softDeleteIdpGroup(1L));
+ assertEquals(1,
idpGroupMetaMapper.deleteIdpGroupMetasByLegacyTimeline(Long.MAX_VALUE, 10));
+ }
+
+ @ParameterizedTest
+ @MethodSource("storageProvider")
+ void testDeleteIdpGroupMetasByLegacyTimeline(String type) throws IOException
{
+ init(type);
+ idpGroupMetaMapper.insertIdpGroup(
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("legacy-group")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(10L)
+ .build());
+ idpGroupMetaMapper.insertIdpGroup(
+ IdpGroupPO.builder()
+ .withGroupId(2L)
+ .withGroupName("new-group")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(30L)
+ .build());
+ idpGroupMetaMapper.insertIdpGroup(
+ IdpGroupPO.builder()
+ .withGroupId(3L)
+ .withGroupName("active-group")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build());
+
+ assertEquals(1,
idpGroupMetaMapper.deleteIdpGroupMetasByLegacyTimeline(20L, 10));
+ assertEquals(0,
idpGroupMetaMapper.deleteIdpGroupMetasByLegacyTimeline(20L, 10));
+ assertEquals(1,
idpGroupMetaMapper.deleteIdpGroupMetasByLegacyTimeline(40L, 10));
+ assertEquals(0,
idpGroupMetaMapper.deleteIdpGroupMetasByLegacyTimeline(Long.MAX_VALUE, 10));
+ assertEquals("active-group",
idpGroupMetaMapper.selectIdpGroup("active-group").getGroupName());
+ assertNull(idpGroupMetaMapper.selectIdpGroup("legacy-group"));
+ assertNull(idpGroupMetaMapper.selectIdpGroup("new-group"));
+ }
+
+ @ParameterizedTest
+ @MethodSource("storageProvider")
+ void testRestart(String type) throws IOException {
+ init(type);
+ IdpGroupPO expectedActiveGroup =
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("dev")
+ .withCurrentVersion(3L)
+ .withLastVersion(2L)
+ .withDeletedAt(0L)
+ .build();
+ idpGroupMetaMapper.insertIdpGroup(expectedActiveGroup);
+ idpGroupMetaMapper.insertIdpGroup(
+ IdpGroupPO.builder()
+ .withGroupId(2L)
+ .withGroupName("ops")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(10L)
+ .build());
+
+ assertPersistedGroups(expectedActiveGroup);
+
+ restartBackend();
+
+ assertPersistedGroups(expectedActiveGroup);
+ }
+
+ private void assertPersistedGroups(IdpGroupPO expectedActiveGroup) {
+ assertTrue(
+ SqlSessionFactoryHelper.getInstance()
+ .getSqlSessionFactory()
+ .getConfiguration()
+ .hasMapper(IdpGroupMetaMapper.class));
+
+ assertEquals(expectedActiveGroup,
idpGroupMetaMapper.selectIdpGroup("dev"));
+ assertNull(idpGroupMetaMapper.selectIdpGroup("ops"));
+ }
+}
diff --git
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpUserMetaStorage.java
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpUserMetaStorage.java
index 025b3c5fb0..f2d87f4341 100644
---
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpUserMetaStorage.java
+++
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestIdpUserMetaStorage.java
@@ -37,12 +37,27 @@ import org.junit.jupiter.params.provider.MethodSource;
@Tag("gravitino-docker-test")
class TestIdpUserMetaStorage extends AbstractIdpMetaStorageTest {
+ private IdpUserMetaMapper idpUserMetaMapper;
+
+ @Override
+ protected void initializeMappers() {
+ idpUserMetaMapper = sharedSession.getMapper(IdpUserMetaMapper.class);
+ }
@ParameterizedTest
@MethodSource("storageProvider")
void testInsertIdpUserAndSelectIdpUser(String type) throws IOException {
init(type);
- IdpUserPO firstUser = insertUser(1L, "alice", "hash-a", 1L, 0L, 0L);
+ IdpUserPO firstUser =
+ IdpUserPO.builder()
+ .withUserId(1L)
+ .withUserName("alice")
+ .withPasswordHash("hash-a")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build();
+ idpUserMetaMapper.insertIdpUser(firstUser);
assertEquals(firstUser, idpUserMetaMapper.selectIdpUser("alice"));
assertNull(idpUserMetaMapper.selectIdpUser("unknown"));
@@ -52,8 +67,26 @@ class TestIdpUserMetaStorage extends
AbstractIdpMetaStorageTest {
@MethodSource("storageProvider")
void testSelectIdpUsers(String type) throws IOException {
init(type);
- IdpUserPO firstUser = insertUser(1L, "alice", "hash-a", 1L, 0L, 0L);
- IdpUserPO secondUser = insertUser(2L, "bob", "hash-b", 1L, 0L, 0L);
+ IdpUserPO firstUser =
+ IdpUserPO.builder()
+ .withUserId(1L)
+ .withUserName("alice")
+ .withPasswordHash("hash-a")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build();
+ IdpUserPO secondUser =
+ IdpUserPO.builder()
+ .withUserId(2L)
+ .withUserName("bob")
+ .withPasswordHash("hash-b")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build();
+ idpUserMetaMapper.insertIdpUser(firstUser);
+ idpUserMetaMapper.insertIdpUser(secondUser);
List<IdpUserPO> users = idpUserMetaMapper.selectIdpUsers(List.of("bob",
"alice"));
users.sort(Comparator.comparing(IdpUserPO::getUserId));
@@ -68,8 +101,25 @@ class TestIdpUserMetaStorage extends
AbstractIdpMetaStorageTest {
@MethodSource("storageProvider")
void testSelectIdpUsersIgnoresDeletedUsers(String type) throws IOException {
init(type);
- IdpUserPO activeUser = insertUser(1L, "alice", "hash-a", 1L, 0L, 0L);
- insertUser(2L, "bob", "hash-b", 1L, 0L, 10L);
+ IdpUserPO activeUser =
+ IdpUserPO.builder()
+ .withUserId(1L)
+ .withUserName("alice")
+ .withPasswordHash("hash-a")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build();
+ idpUserMetaMapper.insertIdpUser(activeUser);
+ idpUserMetaMapper.insertIdpUser(
+ IdpUserPO.builder()
+ .withUserId(2L)
+ .withUserName("bob")
+ .withPasswordHash("hash-b")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(10L)
+ .build());
assertIterableEquals(
List.of(activeUser), idpUserMetaMapper.selectIdpUsers(List.of("alice",
"bob")));
@@ -80,7 +130,15 @@ class TestIdpUserMetaStorage extends
AbstractIdpMetaStorageTest {
@MethodSource("storageProvider")
void testUpdateIdpUserPassword(String type) throws IOException {
init(type);
- insertUser(1L, "alice", "hash-a", 1L, 0L, 0L);
+ idpUserMetaMapper.insertIdpUser(
+ IdpUserPO.builder()
+ .withUserId(1L)
+ .withUserName("alice")
+ .withPasswordHash("hash-a")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build());
assertEquals(1, idpUserMetaMapper.updateIdpUserPassword(1L, "hash-a-2"));
assertEquals("hash-a-2",
idpUserMetaMapper.selectIdpUser("alice").getPasswordHash());
@@ -92,7 +150,15 @@ class TestIdpUserMetaStorage extends
AbstractIdpMetaStorageTest {
@MethodSource("storageProvider")
void testUpdateIdpUserPasswordKeepsVersionsUnchanged(String type) throws
IOException {
init(type);
- insertUser(1L, "alice", "hash-a", 3L, 2L, 0L);
+ idpUserMetaMapper.insertIdpUser(
+ IdpUserPO.builder()
+ .withUserId(1L)
+ .withUserName("alice")
+ .withPasswordHash("hash-a")
+ .withCurrentVersion(3L)
+ .withLastVersion(2L)
+ .withDeletedAt(0L)
+ .build());
assertEquals(1, idpUserMetaMapper.updateIdpUserPassword(1L, "hash-a-2"));
assertEquals("hash-a-2",
idpUserMetaMapper.selectIdpUser("alice").getPasswordHash());
@@ -104,35 +170,89 @@ class TestIdpUserMetaStorage extends
AbstractIdpMetaStorageTest {
@MethodSource("storageProvider")
void testSoftDeleteIdpUser(String type) throws IOException {
init(type);
- insertUser(1L, "alice", "hash-a", 1L, 0L, 0L);
+ idpUserMetaMapper.insertIdpUser(
+ IdpUserPO.builder()
+ .withUserId(1L)
+ .withUserName("alice")
+ .withPasswordHash("hash-a")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build());
assertEquals(1, idpUserMetaMapper.softDeleteIdpUser(1L));
assertNull(idpUserMetaMapper.selectIdpUser("alice"));
- assertTrue(queryLongValue("idp_user_meta", "deleted_at", "user_id", 1L) >
0L);
- assertEquals(1L, queryLongValue("idp_user_meta", "current_version",
"user_id", 1L));
- assertEquals(0L, queryLongValue("idp_user_meta", "last_version",
"user_id", 1L));
+ assertIterableEquals(List.of(),
idpUserMetaMapper.selectIdpUsers(List.of("alice")));
+ assertEquals(0, idpUserMetaMapper.softDeleteIdpUser(1L));
+ assertEquals(0, idpUserMetaMapper.updateIdpUserPassword(1L, "hash-a-2"));
+ assertEquals(1,
idpUserMetaMapper.deleteIdpUserMetasByLegacyTimeline(Long.MAX_VALUE, 10));
+ assertEquals(0,
idpUserMetaMapper.deleteIdpUserMetasByLegacyTimeline(Long.MAX_VALUE, 10));
}
@ParameterizedTest
@MethodSource("storageProvider")
void testDeleteIdpUserMetasByLegacyTimeline(String type) throws IOException {
init(type);
- insertUser(1L, "legacy-user", "hash", 1L, 0L, 10L);
- insertUser(2L, "new-user", "hash", 1L, 0L, 30L);
- insertUser(3L, "active-user", "hash", 1L, 0L, 0L);
+ idpUserMetaMapper.insertIdpUser(
+ IdpUserPO.builder()
+ .withUserId(1L)
+ .withUserName("legacy-user")
+ .withPasswordHash("hash")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(10L)
+ .build());
+ idpUserMetaMapper.insertIdpUser(
+ IdpUserPO.builder()
+ .withUserId(2L)
+ .withUserName("new-user")
+ .withPasswordHash("hash")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(30L)
+ .build());
+ idpUserMetaMapper.insertIdpUser(
+ IdpUserPO.builder()
+ .withUserId(3L)
+ .withUserName("active-user")
+ .withPasswordHash("hash")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(0L)
+ .build());
assertEquals(1, idpUserMetaMapper.deleteIdpUserMetasByLegacyTimeline(20L,
10));
- assertEquals(0, countRows("idp_user_meta", "user_id", 1L));
- assertEquals(1, countRows("idp_user_meta", "user_id", 2L));
- assertEquals(1, countRows("idp_user_meta", "user_id", 3L));
+ assertEquals(0, idpUserMetaMapper.deleteIdpUserMetasByLegacyTimeline(20L,
10));
+ assertEquals(1, idpUserMetaMapper.deleteIdpUserMetasByLegacyTimeline(40L,
10));
+ assertEquals(0,
idpUserMetaMapper.deleteIdpUserMetasByLegacyTimeline(Long.MAX_VALUE, 10));
+ assertEquals("active-user",
idpUserMetaMapper.selectIdpUser("active-user").getUserName());
+ assertNull(idpUserMetaMapper.selectIdpUser("legacy-user"));
+ assertNull(idpUserMetaMapper.selectIdpUser("new-user"));
}
@ParameterizedTest
@MethodSource("storageProvider")
void testRestart(String type) throws IOException {
init(type);
- IdpUserPO expectedActiveUser = insertUser(1L, "alice", "hash-a", 3L, 2L,
0L);
- insertUser(2L, "bob", "hash-b", 1L, 0L, 10L);
+ IdpUserPO expectedActiveUser =
+ IdpUserPO.builder()
+ .withUserId(1L)
+ .withUserName("alice")
+ .withPasswordHash("hash-a")
+ .withCurrentVersion(3L)
+ .withLastVersion(2L)
+ .withDeletedAt(0L)
+ .build();
+ idpUserMetaMapper.insertIdpUser(expectedActiveUser);
+ idpUserMetaMapper.insertIdpUser(
+ IdpUserPO.builder()
+ .withUserId(2L)
+ .withUserName("bob")
+ .withPasswordHash("hash-b")
+ .withCurrentVersion(1L)
+ .withLastVersion(0L)
+ .withDeletedAt(10L)
+ .build());
assertEquals(1, idpUserMetaMapper.updateIdpUserPassword(1L, "hash-a-2"));
expectedActiveUser =
diff --git
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestSQLProviderFactoryHelper.java
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestSQLProviderFactoryHelper.java
new file mode 100644
index 0000000000..585beeb51f
--- /dev/null
+++
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/TestSQLProviderFactoryHelper.java
@@ -0,0 +1,68 @@
+/*
+ * 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.idp.storage.mapper;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.apache.gravitino.storage.relational.JDBCBackend.JDBCBackendType;
+import org.junit.jupiter.api.Test;
+
+public class TestSQLProviderFactoryHelper {
+ private static final Map<JDBCBackendType, String> PROVIDER_MAP =
+ ImmutableMap.of(
+ JDBCBackendType.MYSQL, "mysql",
+ JDBCBackendType.H2, "h2",
+ JDBCBackendType.POSTGRESQL, "postgresql");
+
+ @Test
+ void testGetProvider() {
+ assertEquals("mysql", provider("mysql"));
+ assertEquals("h2", provider("h2"));
+ assertEquals("postgresql", provider("postgresql"));
+ }
+
+ @Test
+ void testGetProviderWithNullDatabaseId() {
+ IllegalStateException exception =
+ assertThrows(IllegalStateException.class, () -> provider(null));
+ assertEquals(
+ "MyBatis databaseId is not configured for
TestSQLProviderFactoryHelper.",
+ exception.getMessage());
+ }
+
+ @Test
+ void testGetProviderWithUnsupportedDatabaseId() {
+ IllegalStateException exception =
+ assertThrows(IllegalStateException.class, () -> provider("sqlite"));
+ assertEquals(
+ "Unsupported TestSQLProviderFactoryHelper databaseId: sqlite,
supported backends: [MYSQL,"
+ + " H2,"
+ + " POSTGRESQL]",
+ exception.getMessage());
+ }
+
+ private String provider(String databaseId) {
+ return SQLProviderFactoryHelper.getProvider(
+ databaseId, PROVIDER_MAP, TestSQLProviderFactoryHelper.class);
+ }
+}
diff --git
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/provider/base/TestIdpGroupMetaBaseSQLProvider.java
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/provider/base/TestIdpGroupMetaBaseSQLProvider.java
new file mode 100644
index 0000000000..2b98776e18
--- /dev/null
+++
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/provider/base/TestIdpGroupMetaBaseSQLProvider.java
@@ -0,0 +1,163 @@
+/*
+ * 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.idp.storage.mapper.provider.base;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.gravitino.idp.storage.po.IdpGroupPO;
+import org.apache.ibatis.builder.BuilderException;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.SqlSource;
+import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
+import org.apache.ibatis.session.Configuration;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestIdpGroupMetaBaseSQLProvider {
+
+ protected IdpGroupMetaBaseSQLProvider createProvider() {
+ return new IdpGroupMetaBaseSQLProvider() {
+ @Override
+ protected String currentTimeMillisExpression() {
+ return "CURRENT_TIME_MILLIS()";
+ }
+ };
+ }
+
+ protected String expectedDeleteAtClause() {
+ return "deleted_at = CURRENT_TIME_MILLIS()";
+ }
+
+ protected String expectedDeleteIdpGroupMetasByLegacyTimelineSql() {
+ return "DELETE FROM idp_group_meta WHERE deleted_at > 0 AND deleted_at <
#{legacyTimeline}"
+ + " LIMIT #{limit}";
+ }
+
+ @Test
+ void testSelectIdpGroup() {
+ String normalizedSql =
createProvider().selectIdpGroup("group").replaceAll("\\s+", " ").trim();
+
+ Assertions.assertTrue(normalizedSql.contains("SELECT group_id as
groupId"));
+ Assertions.assertTrue(normalizedSql.contains("FROM idp_group_meta"));
+ Assertions.assertTrue(
+ normalizedSql.contains("WHERE group_name = #{groupName} AND deleted_at
= 0"));
+ }
+
+ @Test
+ void testSelectIdpGroups() {
+ String script = createProvider().selectIdpGroups(Arrays.asList("dev",
"ops"));
+ Map<String, Object> params = new HashMap<>();
+ params.put("groupNames", Arrays.asList("dev", "ops"));
+
+ String normalizedSql = renderScript(script, params);
+
+ Assertions.assertTrue(normalizedSql.contains("SELECT group_id as
groupId"));
+ Assertions.assertTrue(normalizedSql.contains("FROM idp_group_meta"));
+ Assertions.assertTrue(
+ normalizedSql.matches(".*group_name
IN\\s*\\(\\s*\\?\\s*,\\s*\\?\\s*\\).*"));
+ Assertions.assertFalse(normalizedSql.matches(".*\\b1\\s*=\\s*0\\b.*"));
+ }
+
+ @Test
+ void testSelectIdpGroupsWithEmptyGroupNames() {
+ String script = createProvider().selectIdpGroups(Collections.emptyList());
+ Map<String, Object> params = new HashMap<>();
+ params.put("groupNames", Collections.emptyList());
+
+ String normalizedSql = renderScript(script, params);
+
+ Assertions.assertFalse(
+ normalizedSql.matches(".*\\bIN\\s*\\(\\s*\\).*"),
+ "Empty groupNames should not generate invalid SQL IN (...) with no
values");
+ Assertions.assertFalse(normalizedSql.matches(".*\\b1\\s*=\\s*0\\b.*"));
+ Assertions.assertEquals(
+ "SELECT group_id as groupId, group_name as groupName, current_version
as"
+ + " currentVersion, last_version as lastVersion, deleted_at as
deletedAt FROM"
+ + " idp_group_meta WHERE deleted_at = 0",
+ normalizedSql);
+ }
+
+ @Test
+ void testSelectIdpGroupsWithNullGroupNames() {
+ String script = createProvider().selectIdpGroups(null);
+ Map<String, Object> params = new HashMap<>();
+ params.put("groupNames", null);
+
+ Assertions.assertThrows(BuilderException.class, () -> renderScript(script,
params));
+ }
+
+ @Test
+ void testInsertIdpGroup() {
+ String normalizedSql =
+ createProvider().insertIdpGroup(newGroupPO()).replaceAll("\\s+", "
").trim();
+
+ Assertions.assertTrue(normalizedSql.contains("INSERT INTO
idp_group_meta"));
+ Assertions.assertTrue(
+ normalizedSql.contains(
+ "(group_id, group_name, current_version, last_version,
deleted_at)"));
+ Assertions.assertTrue(
+ normalizedSql.contains(
+ "VALUES ( #{groupMeta.groupId}, #{groupMeta.groupName},
#{groupMeta.currentVersion},"
+ + " #{groupMeta.lastVersion}, #{groupMeta.deletedAt} )"));
+ }
+
+ @Test
+ void testSoftDeleteIdpGroup() {
+ String normalizedSql =
createProvider().softDeleteIdpGroup(1L).replaceAll("\\s+", " ").trim();
+
+ Assertions.assertTrue(normalizedSql.contains("UPDATE idp_group_meta"));
+ Assertions.assertTrue(normalizedSql.contains(expectedDeleteAtClause()));
+ Assertions.assertTrue(normalizedSql.contains("WHERE group_id = #{groupId}
AND deleted_at = 0"));
+ }
+
+ @Test
+ void testDeleteIdpGroupMetasByLegacyTimeline() {
+ String normalizedSql =
+ createProvider().deleteIdpGroupMetasByLegacyTimeline(1L,
2).replaceAll("\\s+", " ").trim();
+
+ Assertions.assertEquals(expectedDeleteIdpGroupMetasByLegacyTimelineSql(),
normalizedSql);
+ }
+
+ @Test
+ void testCurrentTimeMillisExpression() {
+ Assertions.assertEquals(
+ "(UNIX_TIMESTAMP() * 1000.0)",
+ new IdpGroupMetaBaseSQLProvider().currentTimeMillisExpression());
+ }
+
+ private IdpGroupPO newGroupPO() {
+ return IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("group")
+ .withCurrentVersion(1L)
+ .withLastVersion(1L)
+ .withDeletedAt(0L)
+ .build();
+ }
+
+ private String renderScript(String script, Map<String, Object> params) {
+ SqlSource sqlSource =
+ new XMLLanguageDriver().createSqlSource(new Configuration(), script,
Map.class);
+ BoundSql boundSql = sqlSource.getBoundSql(params);
+ return boundSql.getSql().replaceAll("\\s+", " ").trim();
+ }
+}
diff --git
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/provider/h2/TestIdpGroupMetaH2Provider.java
similarity index 60%
copy from
plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
copy to
plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/provider/h2/TestIdpGroupMetaH2Provider.java
index 3cf51de9fa..fb6584795a 100644
---
a/plugins/idp-basic/src/main/java/org/apache/gravitino/idp/storage/mapper/provider/IdpBasicMapperPackageProvider.java
+++
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/provider/h2/TestIdpGroupMetaH2Provider.java
@@ -16,18 +16,20 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.gravitino.idp.storage.mapper.provider;
-import com.google.common.collect.ImmutableList;
-import java.util.List;
-import org.apache.gravitino.idp.storage.mapper.IdpUserMetaMapper;
-import
org.apache.gravitino.storage.relational.mapper.provider.MapperPackageProvider;
+package org.apache.gravitino.idp.storage.mapper.provider.h2;
-/** Supplies built-in IdP mapper classes from the idp-basic plugin. */
-public class IdpBasicMapperPackageProvider implements MapperPackageProvider {
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
- @Override
- public List<Class<?>> getMapperClasses() {
- return ImmutableList.of(IdpUserMetaMapper.class);
+class TestIdpGroupMetaH2Provider {
+
+ @Test
+ void testCurrentTimeMillisExpression() {
+ IdpGroupMetaH2Provider provider = new IdpGroupMetaH2Provider();
+
+ Assertions.assertEquals(
+ "DATEDIFF('MILLISECOND', TIMESTAMP '1970-01-01 00:00:00',
CURRENT_TIMESTAMP())",
+ provider.currentTimeMillisExpression());
}
}
diff --git
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/provider/postgresql/TestIdpGroupMetaPostgreSQLProvider.java
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/provider/postgresql/TestIdpGroupMetaPostgreSQLProvider.java
new file mode 100644
index 0000000000..bdc1b16987
--- /dev/null
+++
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/mapper/provider/postgresql/TestIdpGroupMetaPostgreSQLProvider.java
@@ -0,0 +1,45 @@
+/*
+ * 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.idp.storage.mapper.provider.postgresql;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestIdpGroupMetaPostgreSQLProvider {
+
+ @Test
+ void testCurrentTimeMillisExpression() {
+ IdpGroupMetaPostgreSQLProvider provider = new
IdpGroupMetaPostgreSQLProvider();
+
+ Assertions.assertEquals(
+ "CAST(EXTRACT(EPOCH FROM CURRENT_TIMESTAMP) * 1000 AS BIGINT)",
+ provider.currentTimeMillisExpression());
+ }
+
+ @Test
+ void testDeleteIdpGroupMetasByLegacyTimeline() {
+ IdpGroupMetaPostgreSQLProvider provider = new
IdpGroupMetaPostgreSQLProvider();
+
+ Assertions.assertEquals(
+ "DELETE FROM idp_group_meta WHERE group_id IN (SELECT group_id FROM
idp_group_meta"
+ + " WHERE deleted_at > 0 AND deleted_at < #{legacyTimeline} LIMIT
#{limit})",
+ provider.deleteIdpGroupMetasByLegacyTimeline(1L, 2));
+ }
+}
diff --git
a/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/po/TestIdpGroupPO.java
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/po/TestIdpGroupPO.java
new file mode 100644
index 0000000000..baaefb8e96
--- /dev/null
+++
b/plugins/idp-basic/src/test/java/org/apache/gravitino/idp/storage/po/TestIdpGroupPO.java
@@ -0,0 +1,84 @@
+/*
+ * 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.idp.storage.po;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestIdpGroupPO {
+
+ @Test
+ public void testIdpGroupPOBuilder() {
+ IdpGroupPO groupPO =
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("engineering")
+ .withCurrentVersion(1L)
+ .withLastVersion(1L)
+ .withDeletedAt(0L)
+ .build();
+
+ Assertions.assertEquals(1L, groupPO.getGroupId());
+ Assertions.assertEquals("engineering", groupPO.getGroupName());
+ Assertions.assertEquals(1L, groupPO.getCurrentVersion());
+ Assertions.assertEquals(1L, groupPO.getLastVersion());
+ Assertions.assertEquals(0L, groupPO.getDeletedAt());
+ }
+
+ @Test
+ public void testEqualsAndHashCode() {
+ IdpGroupPO groupPO1 =
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("engineering")
+ .withCurrentVersion(1L)
+ .withLastVersion(1L)
+ .withDeletedAt(0L)
+ .build();
+
+ IdpGroupPO groupPO2 =
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("engineering")
+ .withCurrentVersion(1L)
+ .withLastVersion(1L)
+ .withDeletedAt(0L)
+ .build();
+
+ Assertions.assertEquals(groupPO1, groupPO2);
+ Assertions.assertEquals(groupPO1.hashCode(), groupPO2.hashCode());
+ }
+
+ @Test
+ public void testBuilderReuseDoesNotMutateBuiltObject() {
+ var builder =
+ IdpGroupPO.builder()
+ .withGroupId(1L)
+ .withGroupName("engineering")
+ .withCurrentVersion(1L)
+ .withLastVersion(1L)
+ .withDeletedAt(0L);
+
+ IdpGroupPO firstGroup = builder.build();
+ IdpGroupPO secondGroup = builder.withGroupName("platform").build();
+
+ Assertions.assertEquals("engineering", firstGroup.getGroupName());
+ Assertions.assertEquals("platform", secondGroup.getGroupName());
+ }
+}