From d74a10d87a5efe42feed636972597a88d25b9647 Mon Sep 17 00:00:00 2001 From: Dennis Kniep Date: Thu, 14 Aug 2025 09:27:21 +0200 Subject: [PATCH] Add TiDB as supported db Closes #41455 Signed-off-by: Dennis Kniep Signed-off-by: Alexander Schwartz Co-authored-by: Alexander Schwartz --- .github/workflows/ci.yml | 2 +- docs/tests-db.md | 17 +++++ .../META-INF/jpa-changelog-20.0.0.xml | 26 +++++++ pom.xml | 2 + quarkus/tests/integration/pom.xml | 1 + quarkus/tests/junit5/pom.xml | 4 ++ .../junit5/extension/DatabaseContainer.java | 6 +- test-framework/README.md | 1 + test-framework/bom/pom.xml | 6 ++ .../database/database.properties | 3 +- test-framework/db-tidb/pom.xml | 45 ++++++++++++ .../database/TiDBDatabaseSupplier.java | 15 ++++ .../database/TiDBTestDatabase.java | 69 +++++++++++++++++++ .../database/TiDBTestFrameworkExtension.java | 14 ++++ ...cloak.testframework.TestFrameworkExtension | 1 + test-framework/examples/tests/pom.xml | 4 ++ test-framework/pom.xml | 1 + tests/base/pom.xml | 4 ++ .../tests/db/CaseSensitiveSchemaTest.java | 3 +- .../db/PreserveSchemaCaseLiquibaseTest.java | 3 +- testsuite/integration-arquillian/pom.xml | 23 +++++++ .../servers/migration/pom.xml | 2 - 22 files changed, 245 insertions(+), 7 deletions(-) create mode 100755 test-framework/db-tidb/pom.xml create mode 100644 test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBDatabaseSupplier.java create mode 100644 test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBTestDatabase.java create mode 100644 test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBTestFrameworkExtension.java create mode 100644 test-framework/db-tidb/src/main/resources/META-INF/services/org.keycloak.testframework.TestFrameworkExtension diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 08b64439cdf..8dfc79b709a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -693,7 +693,7 @@ jobs: timeout-minutes: 75 strategy: matrix: - db: [postgres, mysql, oracle, mssql, mariadb] + db: [postgres, mysql, oracle, mssql, mariadb, tidb] fail-fast: false steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 diff --git a/docs/tests-db.md b/docs/tests-db.md index 5da4534ff6d..ef32e968afb 100644 --- a/docs/tests-db.md +++ b/docs/tests-db.md @@ -53,6 +53,23 @@ Stop MySQl: docker rm -f mariadb +TiDB +----- + +The simplest way to test with TiDB is to use the official [TiDB docker image](https://hub.docker.com/r/pingcap/tidb). + +Start TiDB: + + docker run --name tidb -p 4000:4000 -d pingcap/tidb:v8.5.2 + +Run tests: + + mvn install -Dkeycloak.connectionsJpa.url=jdbc:mysql://`docker inspect --format '{{ .NetworkSettings.IPAddress }}' tidb`:4000/test -Dkeycloak.connectionsJpa.driver=com.mysql.jdbc.Driver -Dkeycloak.connectionsJpa.user=root -Dkeycloak.connectionsJpa.password= + +Stop TiDB: + + docker rm -f tidb + Using built-in profiles to run database tests using docker containers ------- diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-20.0.0.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-20.0.0.xml index 1c7977a005d..f07beba7c28 100644 --- a/model/jpa/src/main/resources/META-INF/jpa-changelog-20.0.0.xml +++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-20.0.0.xml @@ -55,6 +55,17 @@ + + + + + + + + + + + @@ -68,4 +79,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 083c29efbe4..382493189d1 100644 --- a/pom.xml +++ b/pom.xml @@ -151,6 +151,8 @@ 4.1.2 + v8.5.2 + mirror.gcr.io/pingcap/tidb:${tidb.version} 8.4 mirror.gcr.io/mysql:${mysql.version} 8.3.0 diff --git a/quarkus/tests/integration/pom.xml b/quarkus/tests/integration/pom.xml index 5e5bcf9aa88..96396249310 100644 --- a/quarkus/tests/integration/pom.xml +++ b/quarkus/tests/integration/pom.xml @@ -190,6 +190,7 @@ ${mysql.container} quay.io/infinispan/server:${infinispan.version} ${mssql.container} + ${tidb.container} diff --git a/quarkus/tests/junit5/pom.xml b/quarkus/tests/junit5/pom.xml index 156b9ec1cd3..4f702145ac3 100644 --- a/quarkus/tests/junit5/pom.xml +++ b/quarkus/tests/junit5/pom.xml @@ -102,6 +102,10 @@ org.testcontainers mssqlserver + + org.testcontainers + tidb + diff --git a/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/DatabaseContainer.java b/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/DatabaseContainer.java index c9ad59e4658..35b448c92f5 100644 --- a/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/DatabaseContainer.java +++ b/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/DatabaseContainer.java @@ -26,7 +26,7 @@ import org.testcontainers.containers.MSSQLServerContainer; import org.testcontainers.containers.MariaDBContainer; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.containers.PostgreSQLContainer; -import org.testcontainers.images.PullPolicy; +import org.testcontainers.tidb.TiDBContainer; import org.testcontainers.utility.DockerImageName; public class DatabaseContainer { @@ -95,6 +95,7 @@ public class DatabaseContainer { String MARIADB_IMAGE = System.getProperty("kc.db.mariadb.container.image"); String MYSQL_IMAGE = System.getProperty("kc.db.mysql.container.image"); String MSSQL_IMAGE = System.getProperty("kc.db.mssql.container.image"); + String TIDB_IMAGE = System.getProperty("kc.db.tidb.container.image"); switch (alias) { case "postgres": @@ -109,6 +110,9 @@ public class DatabaseContainer { case "mssql": DockerImageName MSSQL = DockerImageName.parse(MSSQL_IMAGE).asCompatibleSubstituteFor("sqlserver"); return configureJdbcContainer(new MSSQLServerContainer<>(MSSQL)); + case "tidb": + DockerImageName TIDB = DockerImageName.parse(TIDB_IMAGE).asCompatibleSubstituteFor("pingcap/tidb"); + return configureJdbcContainer(new TiDBContainer(TIDB)); default: throw new RuntimeException("Unsupported database: " + alias); } diff --git a/test-framework/README.md b/test-framework/README.md index 7ba2c23cfe2..a3ce07226f9 100644 --- a/test-framework/README.md +++ b/test-framework/README.md @@ -385,6 +385,7 @@ Valid values: | mysql | MySQL test container | | oracle | Oracle test container | | postgres | PostgreSQL test container | +| tidb | TiDb test container | Configuration: diff --git a/test-framework/bom/pom.xml b/test-framework/bom/pom.xml index e26adb3b838..73b71140ef2 100755 --- a/test-framework/bom/pom.xml +++ b/test-framework/bom/pom.xml @@ -75,6 +75,12 @@ ${project.version} test + + org.keycloak.testframework + keycloak-test-framework-db-tidb + ${project.version} + test + org.keycloak.testframework keycloak-test-framework-db-oracle diff --git a/test-framework/core/src/main/resources/org/keycloak/testframework/database/database.properties b/test-framework/core/src/main/resources/org/keycloak/testframework/database/database.properties index d2438e69e9c..5f4c7864e8e 100644 --- a/test-framework/core/src/main/resources/org/keycloak/testframework/database/database.properties +++ b/test-framework/core/src/main/resources/org/keycloak/testframework/database/database.properties @@ -2,4 +2,5 @@ mysql.container=${mysql.container} postgres.container=${postgresql.container} mariadb.container=${mariadb.container} mssql.container=${mssql.container} -oracle.container=${oracledb.container} \ No newline at end of file +oracle.container=${oracledb.container} +tidb.container=${tidb.container} \ No newline at end of file diff --git a/test-framework/db-tidb/pom.xml b/test-framework/db-tidb/pom.xml new file mode 100755 index 00000000000..ee69655908a --- /dev/null +++ b/test-framework/db-tidb/pom.xml @@ -0,0 +1,45 @@ + + + + + + keycloak-test-framework-parent + org.keycloak.testframework + 999.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + keycloak-test-framework-db-tidb + Keycloak Test Framework - TiDB support + jar + TiDB support for Keycloak Test Framework + + + + org.keycloak.testframework + keycloak-test-framework-core + ${project.version} + + + org.testcontainers + tidb + + + diff --git a/test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBDatabaseSupplier.java b/test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBDatabaseSupplier.java new file mode 100644 index 00000000000..07d2d546c52 --- /dev/null +++ b/test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBDatabaseSupplier.java @@ -0,0 +1,15 @@ +package org.keycloak.testframework.database; + +public class TiDBDatabaseSupplier extends AbstractDatabaseSupplier { + + @Override + public String getAlias() { + return "tidb"; + } + + @Override + TestDatabase getTestDatabase() { + return new TiDBTestDatabase(); + } + +} diff --git a/test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBTestDatabase.java b/test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBTestDatabase.java new file mode 100644 index 00000000000..b7e9b9a34b2 --- /dev/null +++ b/test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBTestDatabase.java @@ -0,0 +1,69 @@ +package org.keycloak.testframework.database; + +import org.apache.commons.lang3.StringUtils; +import org.jboss.logging.Logger; +import org.testcontainers.containers.JdbcDatabaseContainer; +import org.testcontainers.tidb.TiDBContainer; +import org.testcontainers.utility.DockerImageName; + +class TiDBTestDatabase extends AbstractContainerTestDatabase { + + private static final Logger LOGGER = Logger.getLogger(TiDBTestDatabase.class); + + public static final String NAME = "tidb"; + + @Override + public JdbcDatabaseContainer createContainer() { + return new TiDBContainer(DockerImageName.parse(DatabaseProperties.getContainerImageName(NAME)).asCompatibleSubstituteFor("pingcap/tidb")){ + @Override + public TiDBContainer withDatabaseName(String databaseName) { + if(StringUtils.equals(this.getDatabaseName(), databaseName)) { + return this; + } + throw new UnsupportedOperationException("The TiDB docker image does not currently support this"); + } + + @Override + public TiDBContainer withUsername(String username) { + if(StringUtils.equals(this.getUsername(), username)) { + return this; + } + throw new UnsupportedOperationException("The TiDB docker image does not currently support this"); + } + + @Override + public TiDBContainer withPassword(String password) { + if(StringUtils.equals(this.getPassword(), password)) { + return this; + } + throw new UnsupportedOperationException("The TiDB docker image does not currently support this"); + } + }.withExposedPorts(4000); + } + + @Override + public String getDatabaseVendor() { + return "mysql"; + } + + @Override + public Logger getLogger() { + return LOGGER; + } + + + @Override + public String getDatabase() { + return "test"; + } + + @Override + public String getUsername() { + return "root"; + } + + @Override + public String getPassword() { + return ""; + } +} diff --git a/test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBTestFrameworkExtension.java b/test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBTestFrameworkExtension.java new file mode 100644 index 00000000000..84c8a128d2b --- /dev/null +++ b/test-framework/db-tidb/src/main/java/org/keycloak/testframework/database/TiDBTestFrameworkExtension.java @@ -0,0 +1,14 @@ +package org.keycloak.testframework.database; + +import org.keycloak.testframework.TestFrameworkExtension; +import org.keycloak.testframework.injection.Supplier; + +import java.util.List; + +public class TiDBTestFrameworkExtension implements TestFrameworkExtension { + + @Override + public List> suppliers() { + return List.of(new TiDBDatabaseSupplier()); + } +} diff --git a/test-framework/db-tidb/src/main/resources/META-INF/services/org.keycloak.testframework.TestFrameworkExtension b/test-framework/db-tidb/src/main/resources/META-INF/services/org.keycloak.testframework.TestFrameworkExtension new file mode 100644 index 00000000000..cc441db8dbd --- /dev/null +++ b/test-framework/db-tidb/src/main/resources/META-INF/services/org.keycloak.testframework.TestFrameworkExtension @@ -0,0 +1 @@ +org.keycloak.testframework.database.TiDBTestFrameworkExtension \ No newline at end of file diff --git a/test-framework/examples/tests/pom.xml b/test-framework/examples/tests/pom.xml index a136ef7f3c8..6cc7f3fc17f 100644 --- a/test-framework/examples/tests/pom.xml +++ b/test-framework/examples/tests/pom.xml @@ -64,6 +64,10 @@ org.keycloak.testframework keycloak-test-framework-db-mysql + + org.keycloak.testframework + keycloak-test-framework-db-tidb + org.keycloak.testframework keycloak-test-framework-db-oracle diff --git a/test-framework/pom.xml b/test-framework/pom.xml index ddd6f79d913..833f5983538 100755 --- a/test-framework/pom.xml +++ b/test-framework/pom.xml @@ -41,6 +41,7 @@ db-mysql db-oracle db-postgres + db-tidb email-server examples oauth diff --git a/tests/base/pom.xml b/tests/base/pom.xml index 0f02e5eee0e..61c37f3c75a 100755 --- a/tests/base/pom.xml +++ b/tests/base/pom.xml @@ -76,6 +76,10 @@ org.keycloak.testframework keycloak-test-framework-db-postgres + + org.keycloak.testframework + keycloak-test-framework-db-tidb + org.keycloak.testframework keycloak-test-framework-email-server diff --git a/tests/base/src/test/java/org/keycloak/tests/db/CaseSensitiveSchemaTest.java b/tests/base/src/test/java/org/keycloak/tests/db/CaseSensitiveSchemaTest.java index fec5a739399..53aca3b50a7 100644 --- a/tests/base/src/test/java/org/keycloak/tests/db/CaseSensitiveSchemaTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/db/CaseSensitiveSchemaTest.java @@ -19,7 +19,8 @@ import org.keycloak.testframework.realm.RoleConfigBuilder; @KeycloakIntegrationTest(config = CaseSensitiveSchemaTest.KeycloakConfig.class) // MSSQL does not support setting the default schema per session -@DisabledForDatabases("mssql") +// TiDb does not support setting the default schema per session. +@DisabledForDatabases({"mssql", "tidb"}) public class CaseSensitiveSchemaTest { @InjectTestDatabase(lifecycle = LifeCycle.CLASS, config = DatabaseConfigurator.class) TestDatabase db; diff --git a/tests/base/src/test/java/org/keycloak/tests/db/PreserveSchemaCaseLiquibaseTest.java b/tests/base/src/test/java/org/keycloak/tests/db/PreserveSchemaCaseLiquibaseTest.java index c5e1e3fff04..d7374c50c33 100644 --- a/tests/base/src/test/java/org/keycloak/tests/db/PreserveSchemaCaseLiquibaseTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/db/PreserveSchemaCaseLiquibaseTest.java @@ -12,8 +12,9 @@ import org.keycloak.testframework.server.KeycloakServerConfigBuilder; @KeycloakIntegrationTest(config = PreserveSchemaCaseLiquibaseTest.KeycloakConfig.class) // MSSQL does not support setting the default schema per session. +// TiDb does not support setting the default schema per session. // Oracle image does not support configuring user/databases with '-' -@DisabledForDatabases({ "mssql", "oracle" }) +@DisabledForDatabases({ "mssql", "oracle", "tidb" }) public class PreserveSchemaCaseLiquibaseTest extends CaseSensitiveSchemaTest { @InjectTestDatabase(lifecycle = LifeCycle.CLASS, config = DatabaseConfigurator.class) diff --git a/testsuite/integration-arquillian/pom.xml b/testsuite/integration-arquillian/pom.xml index f0a08d5e9dd..3a8fafad7c9 100644 --- a/testsuite/integration-arquillian/pom.xml +++ b/testsuite/integration-arquillian/pom.xml @@ -416,6 +416,29 @@ (?si)Ready for start up.*ready [^\n]{0,30}connections + + db-tidb + + mysql + com.mysql.jdbc.Driver + test + root + + jdbc:mysql://${auth.server.db.host}:${docker.database.port}/${keycloak.connectionsJpa.database} + + + + + com.mysql + mysql-connector-j + ${mysql-jdbc.version} + ${tidb.container} + 4000 + false + start + server is running MySQL protocol + + db-postgres diff --git a/testsuite/integration-arquillian/servers/migration/pom.xml b/testsuite/integration-arquillian/servers/migration/pom.xml index 94cf6e625c6..239ae8a78cc 100644 --- a/testsuite/integration-arquillian/servers/migration/pom.xml +++ b/testsuite/integration-arquillian/servers/migration/pom.xml @@ -59,8 +59,6 @@ keycloak.connectionsJpa.password - ^(?!\s*$).+ - "keycloak.connectionsJpa.password" property cannot be empty string! keycloak.connectionsJpa.url