mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-06 06:49:53 -06:00
Support for EDB 17 (#42341)
Closes #42742 Closes #42293 Signed-off-by: Václav Muzikář <vmuzikar@redhat.com>
This commit is contained in:
85
.github/actions/run-store-tests/action.yml
vendored
Normal file
85
.github/actions/run-store-tests/action.yml
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
name: Store IT
|
||||
description: Run Store integration tests
|
||||
|
||||
inputs:
|
||||
db:
|
||||
description: The database to use for tests
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- id: integration-test-setup
|
||||
name: Integration test setup
|
||||
uses: ./.github/actions/integration-test-setup
|
||||
|
||||
- name: Run new base tests
|
||||
shell: bash
|
||||
run: |
|
||||
KC_TEST_DATABASE=${{ inputs.db }} KC_TEST_DATABASE_REUSE=true TESTCONTAINERS_REUSE_ENABLE=true ./mvnw package -f tests/pom.xml -Dtest=DatabaseTestSuite -Dkeycloak.distribution.start.timeout=360
|
||||
|
||||
- name: Database container port
|
||||
shell: bash
|
||||
run: |
|
||||
# The Ryuk container process exists temporarily after the JVM terminates, wait for only the database container to remain
|
||||
while [ "$(docker ps -q | wc -l)" -ne 1 ]; do
|
||||
docker ps
|
||||
sleep 10
|
||||
done
|
||||
DATABASE_PORT=$(docker ps -l --format '{{ .ID }}' | xargs docker port | cut -d ':' -f 2)
|
||||
echo "DATABASE_PORT=$DATABASE_PORT" >> $GITHUB_ENV
|
||||
|
||||
- name: Run base tests
|
||||
shell: bash
|
||||
run: |
|
||||
TESTS=`testsuite/integration-arquillian/tests/base/testsuites/suite.sh database`
|
||||
echo "Tests: $TESTS"
|
||||
./mvnw test ${{ env.SUREFIRE_RETRY }} \
|
||||
-Pauth-server-quarkus -Pdb-${{ inputs.db }} \
|
||||
"-Dwebdriver.chrome.driver=$CHROMEWEBDRIVER/chromedriver" \
|
||||
-Dtest=$TESTS \
|
||||
-Ddocker.database.skip=true \
|
||||
-Ddocker.database.port=$DATABASE_PORT \
|
||||
-Ddocker.container.testdb.ip=localhost \
|
||||
-Dkeycloak.distribution.start.timeout=360 \
|
||||
-pl testsuite/integration-arquillian/tests/base 2>&1 | misc/log/trimmer.sh
|
||||
|
||||
- name: Run cluster JDBC_PING2 UDP smoke test
|
||||
shell: bash
|
||||
run: |
|
||||
./mvnw test ${{ env.SUREFIRE_RETRY }} \
|
||||
-Pauth-server-cluster-quarkus \
|
||||
-Pdb-${{ inputs.db }} \
|
||||
-Dtest=RealmInvalidationClusterTest \
|
||||
-Dsession.cache.owners=2 \
|
||||
-Dauth.server.quarkus.cluster.stack=jdbc-ping-udp \
|
||||
-Ddocker.database.skip=true \
|
||||
-Ddocker.database.port=$DATABASE_PORT \
|
||||
-Ddocker.container.testdb.ip=localhost \
|
||||
-pl testsuite/integration-arquillian/tests/base \
|
||||
2>&1 | misc/log/trimmer.sh
|
||||
|
||||
- name: Run cluster JDBC_PING2 TCP smoke test
|
||||
shell: bash
|
||||
run: |
|
||||
./mvnw test ${{ env.SUREFIRE_RETRY }} \
|
||||
-Pauth-server-cluster-quarkus \
|
||||
-Pdb-${{ inputs.db }} \
|
||||
-Dtest=RealmInvalidationClusterTest \
|
||||
-Dsession.cache.owners=2 \
|
||||
-Dauth.server.quarkus.cluster.stack=jdbc-ping \
|
||||
-Ddocker.database.skip=true \
|
||||
-Ddocker.database.port=$DATABASE_PORT \
|
||||
-Ddocker.container.testdb.ip=localhost \
|
||||
-pl testsuite/integration-arquillian/tests/base \
|
||||
2>&1 | misc/log/trimmer.sh
|
||||
|
||||
- uses: ./.github/actions/upload-flaky-tests
|
||||
name: Upload flaky tests
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
with:
|
||||
job-name: Store IT
|
||||
105
.github/workflows/ci.yml
vendored
105
.github/workflows/ci.yml
vendored
@@ -38,6 +38,7 @@ jobs:
|
||||
ci-webauthn: ${{ steps.conditional.outputs.ci-webauthn }}
|
||||
ci-aurora: ${{ steps.auroradb-tests.outputs.run-aurora-tests }}
|
||||
ci-compatibility-matrix: ${{ steps.version-compatibility.outputs.matrix }}
|
||||
ci-additional-dbs: ${{ steps.additional-dbs-tests.outputs.run-additional-dbs-tests }}
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
@@ -58,6 +59,15 @@ jobs:
|
||||
fi
|
||||
echo "run-aurora-tests=$RUN_AURORADB_TESTS" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Additional DBs conditional check
|
||||
id: additional-dbs-tests
|
||||
run: |
|
||||
RUN_ADDITIONAL_DBS_TESTS=false
|
||||
if [[ $GITHUB_EVENT_NAME != "pull_request" && -n "${{ secrets.PRIVATE_DBS_QUAY_USERNAME }}" && -n "${{ secrets.PRIVATE_DBS_QUAY_TOKEN }}" ]]; then
|
||||
RUN_ADDITIONAL_DBS_TESTS=true
|
||||
fi
|
||||
echo "run-additional-dbs-tests=$RUN_ADDITIONAL_DBS_TESTS" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Version Compatibility Matrix
|
||||
id: version-compatibility
|
||||
env:
|
||||
@@ -571,72 +581,37 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- id: integration-test-setup
|
||||
name: Integration test setup
|
||||
uses: ./.github/actions/integration-test-setup
|
||||
|
||||
- name: Run new base tests
|
||||
run: |
|
||||
KC_TEST_DATABASE=${{ matrix.db }} KC_TEST_DATABASE_REUSE=true TESTCONTAINERS_REUSE_ENABLE=true ./mvnw package -f tests/pom.xml -Dtest=DatabaseTestSuite -Dkeycloak.distribution.start.timeout=360
|
||||
|
||||
- name: Database container port
|
||||
run: |
|
||||
# The Ryuk container process exists temporarily after the JVM terminates, wait for only the database container to remain
|
||||
while [ "$(docker ps -q | wc -l)" -ne 1 ]; do
|
||||
docker ps
|
||||
sleep 10
|
||||
done
|
||||
DATABASE_PORT=$(docker ps -l --format '{{ .ID }}' | xargs docker port | cut -d ':' -f 2)
|
||||
echo "DATABASE_PORT=$DATABASE_PORT" >> $GITHUB_ENV
|
||||
|
||||
- name: Run base tests
|
||||
run: |
|
||||
TESTS=`testsuite/integration-arquillian/tests/base/testsuites/suite.sh database`
|
||||
echo "Tests: $TESTS"
|
||||
./mvnw test ${{ env.SUREFIRE_RETRY }} \
|
||||
-Pauth-server-quarkus -Pdb-${{ matrix.db }} \
|
||||
"-Dwebdriver.chrome.driver=$CHROMEWEBDRIVER/chromedriver" \
|
||||
-Dtest=$TESTS \
|
||||
-Ddocker.database.skip=true \
|
||||
-Ddocker.database.port=$DATABASE_PORT \
|
||||
-Ddocker.container.testdb.ip=localhost \
|
||||
-Dkeycloak.distribution.start.timeout=360 \
|
||||
-pl testsuite/integration-arquillian/tests/base 2>&1 | misc/log/trimmer.sh
|
||||
|
||||
- name: Run cluster JDBC_PING2 UDP smoke test
|
||||
run: |
|
||||
./mvnw test ${{ env.SUREFIRE_RETRY }} \
|
||||
-Pauth-server-cluster-quarkus \
|
||||
-Pdb-${{ matrix.db }} \
|
||||
-Dtest=RealmInvalidationClusterTest \
|
||||
-Dsession.cache.owners=2 \
|
||||
-Dauth.server.quarkus.cluster.stack=jdbc-ping-udp \
|
||||
-Ddocker.database.skip=true \
|
||||
-Ddocker.database.port=$DATABASE_PORT \
|
||||
-Ddocker.container.testdb.ip=localhost \
|
||||
-pl testsuite/integration-arquillian/tests/base \
|
||||
2>&1 | misc/log/trimmer.sh
|
||||
|
||||
- name: Run cluster JDBC_PING2 TCP smoke test
|
||||
run: |
|
||||
./mvnw test ${{ env.SUREFIRE_RETRY }} \
|
||||
-Pauth-server-cluster-quarkus \
|
||||
-Pdb-${{ matrix.db }} \
|
||||
-Dtest=RealmInvalidationClusterTest \
|
||||
-Dsession.cache.owners=2 \
|
||||
-Dauth.server.quarkus.cluster.stack=jdbc-ping \
|
||||
-Ddocker.database.skip=true \
|
||||
-Ddocker.database.port=$DATABASE_PORT \
|
||||
-Ddocker.container.testdb.ip=localhost \
|
||||
-pl testsuite/integration-arquillian/tests/base \
|
||||
2>&1 | misc/log/trimmer.sh
|
||||
|
||||
- uses: ./.github/actions/upload-flaky-tests
|
||||
name: Upload flaky tests
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
- id: run-store-tests
|
||||
name: Run Store Integration Tests - ${{ matrix.db }}
|
||||
uses: ./.github/actions/run-store-tests
|
||||
with:
|
||||
job-name: Store IT
|
||||
db: ${{ matrix.db }}
|
||||
|
||||
store-integration-tests-additional:
|
||||
name: Store IT (additional)
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 75
|
||||
if: needs.conditional.outputs.ci-additional-dbs == 'true'
|
||||
strategy:
|
||||
matrix:
|
||||
db: [edb]
|
||||
fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Login to Quay.io
|
||||
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
|
||||
with:
|
||||
username: ${{ secrets.PRIVATE_DBS_QUAY_USERNAME }}
|
||||
password: ${{ secrets.PRIVATE_DBS_QUAY_TOKEN }}
|
||||
registry: quay.io
|
||||
|
||||
- id: run-store-tests
|
||||
name: Run Store Integration Tests - ${{ matrix.db }}
|
||||
uses: ./.github/actions/run-store-tests
|
||||
with:
|
||||
db: ${{ matrix.db }}
|
||||
|
||||
store-model-tests:
|
||||
name: Store Model Tests
|
||||
|
||||
@@ -168,4 +168,10 @@ Simply set the backup site name (e.g., availability zone) using the following op
|
||||
--cache-remote-backup-sites=<name>
|
||||
----
|
||||
|
||||
When this option is set, Infinispan will automatically replicate the cache data to the specified location.
|
||||
When this option is set, Infinispan will automatically replicate the cache data to the specified location.¨
|
||||
|
||||
= Support for additional databases
|
||||
|
||||
With this release, we added support for the following new database vendors:
|
||||
|
||||
* EnterpriseDB (EDB) Advanced 17.6
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
:developerguide_actiontoken_link: {developerguide_link}#_action_token_handler_spi
|
||||
:developerguide_jsproviders_name: JavaScript Providers
|
||||
:developerguide_jsproviders_link: {developerguide_link}#_script_providers
|
||||
:importexportguide_link: https://www.keycloak.org/nightly/server/importExport
|
||||
:gettingstarted_name: Getting Started Guide
|
||||
:gettingstarted_name_short: Getting Started
|
||||
:gettingstarted_link: https://www.keycloak.org/guides#getting-started
|
||||
|
||||
@@ -12,6 +12,19 @@ This change enhances security by preventing unintended disclosure of authenticat
|
||||
If you are relying on the `acr_values` parameter to be propagated to an identity provider, you must now explicitly set `acr_values` request parameter
|
||||
to the `Forwarded query parameters` setting in the identity provider configuration.
|
||||
|
||||
=== Re-created indexes on the `CLIENT_ATTRIBUTES` and `GROUP_ATTRIBUTE` tables
|
||||
|
||||
In some previous versions of {project_name}, the EnterpriseDB (EDB) was considered unsupported. This has now changed and
|
||||
EDB Advanced is supported starting with this release. If the EDB JDBC driver was used for connecting to EDB in previous versions,
|
||||
some invalid schema changes were applied to the database. To mitigate this, some indexes are automatically re-created during
|
||||
the schema migration to this version. **This affects you if you are using a Postgres database (including EDB), regardless if you
|
||||
used EDB with previous releases.**
|
||||
|
||||
This affects indexes on the `CLIENT_ATTRIBUTES` and `GROUP_ATTRIBUTE` tables. If those tables contain more than 300000 entries,
|
||||
{project_name} will skip the index creation by default during the automatic schema migration and instead log the SQL statement
|
||||
on the console during migration to be applied manually after {project_name}'s startup.
|
||||
See the link:{upgradingguide_link}[{upgradingguide_name}] for details on how to configure a different limit.
|
||||
|
||||
// ------------------------ Notable changes ------------------------ //
|
||||
== Notable changes
|
||||
|
||||
|
||||
@@ -21,9 +21,10 @@ The server has built-in support for different databases. You can query the avail
|
||||
|
||||
|MariaDB Server | `mariadb` | ${properties["mariadb.version"]} | 11.8 (LTS), 11.4 (LTS), 10.11 (LTS), 10.6 (LTS)
|
||||
|Microsoft SQL Server | `mssql` | ${properties["mssql.version"]} | 2022, 2019
|
||||
|MySQL | `mysql` | ${properties["mysql.version"]} | 8.4 (LTS), 8.0 (LTS)
|
||||
|MySQL | `mysql` | ${properties["mysql.version"]} | 8.4 (LTS), 8.0 (LTS)
|
||||
|Oracle Database | `oracle` | ${properties["oracledb.version"]} | 23.x (i.e 23.5+), 19c (19.3+) (*Note: Oracle RAC is also supported if using the same database engine version, e.g 23.5+, 19.3+)
|
||||
|PostgreSQL | `postgres` | ${properties["postgresql.version"]} | 17.x, 16.x, 15.x, 14.x, 13.x
|
||||
|EnterpriseDB Advanced | `postgres` | ${properties["edb.version"]} | 17
|
||||
|Amazon Aurora PostgreSQL | `postgres` | ${properties["aurora-postgresql.version"]} | 17.x, 16.x, 15.x
|
||||
|===
|
||||
|
||||
@@ -49,6 +50,9 @@ this database
|
||||
</@profile.ifCommunity>
|
||||
or skip this section if you want to connect to a different database for which the database driver is already included.
|
||||
|
||||
NOTE: Overriding the built-in database drivers or supplying your own drivers is considered unsupported.
|
||||
The only supported exceptions are explicitly documented in this guide, such as the Oracle Database driver.
|
||||
|
||||
=== Installing the Oracle Database driver
|
||||
|
||||
To install the Oracle Database driver for {project_name}:
|
||||
@@ -184,19 +188,6 @@ The following is a sample command for a PostgreSQL database.
|
||||
|
||||
Be aware that you need to escape characters when invoking commands containing special shell characters such as `;` using the CLI, so you might want to set it in the configuration file instead.
|
||||
|
||||
== Overriding the default JDBC driver
|
||||
|
||||
The server uses a default JDBC driver accordingly to the database you chose.
|
||||
|
||||
To set a different driver you can set the `db-driver` with the fully qualified class name of the JDBC driver:
|
||||
|
||||
<@kc.start parameters="--db postgres --db-driver=my.Driver"/>
|
||||
|
||||
Regardless of the driver you set, the default driver is always available at runtime.
|
||||
|
||||
Only set this property if you really need to. For instance, when leveraging the capabilities from a JDBC Driver Wrapper for
|
||||
a specific cloud database service.
|
||||
|
||||
== Configuring Unicode support for the database
|
||||
|
||||
Unicode support for all fields depends on whether the database allows VARCHAR and CHAR fields to use the Unicode character set.
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed 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.keycloak.connections.jpa.updater.liquibase;
|
||||
|
||||
import liquibase.Scope;
|
||||
import liquibase.database.DatabaseConnection;
|
||||
import liquibase.database.core.PostgresDatabase;
|
||||
import liquibase.exception.DatabaseException;
|
||||
import liquibase.executor.ExecutorService;
|
||||
import liquibase.statement.core.RawSqlStatement;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class PostgresPlusDatabase extends PostgresDatabase {
|
||||
|
||||
public static final String POSTGRESPLUS_PRODUCT_NAME = "EnterpriseDB";
|
||||
|
||||
@Override
|
||||
public String getShortName() {
|
||||
return "postgresplus";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultDatabaseProductName() {
|
||||
return POSTGRESPLUS_PRODUCT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
|
||||
return POSTGRESPLUS_PRODUCT_NAME.equalsIgnoreCase(conn.getDatabaseProductName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultDriver(String url) {
|
||||
String defaultDriver = super.getDefaultDriver(url);
|
||||
|
||||
if (defaultDriver == null) {
|
||||
if (url.startsWith("jdbc:edb:")) {
|
||||
defaultDriver = "com.edb.Driver";
|
||||
}
|
||||
}
|
||||
|
||||
return defaultDriver;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getConnectionSchemaName() {
|
||||
try {
|
||||
return Scope.getCurrentScope().getSingleton(ExecutorService.class).getExecutor(LiquibaseConstants.JDBC_EXECUTOR, this)
|
||||
.queryForObject(new RawSqlStatement("select current_schema"), String.class);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to get current schema", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,11 +18,10 @@
|
||||
package org.keycloak.connections.jpa.updater.liquibase.conn;
|
||||
|
||||
import liquibase.Scope;
|
||||
import liquibase.ScopeManager;
|
||||
import liquibase.ThreadLocalScopeManager;
|
||||
import liquibase.database.AbstractJdbcDatabase;
|
||||
import liquibase.database.Database;
|
||||
import liquibase.database.DatabaseFactory;
|
||||
import liquibase.database.DatabaseConnection;
|
||||
import liquibase.database.jvm.JdbcConnection;
|
||||
import liquibase.exception.LiquibaseException;
|
||||
import liquibase.resource.ClassLoaderResourceAccessor;
|
||||
@@ -30,6 +29,7 @@ import liquibase.resource.ResourceAccessor;
|
||||
import liquibase.ui.LoggerUIService;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.config.DatabaseOptions;
|
||||
import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
@@ -49,6 +49,7 @@ public class DefaultLiquibaseConnectionProvider implements LiquibaseConnectionPr
|
||||
public static final String INDEX_CREATION_THRESHOLD_PARAM = "keycloak.indexCreationThreshold";
|
||||
|
||||
private int indexCreationThreshold;
|
||||
private Class<? extends Database> liquibaseDatabaseClazz;
|
||||
|
||||
private static final AtomicBoolean INITIALIZATION = new AtomicBoolean(false);
|
||||
|
||||
@@ -92,10 +93,26 @@ public class DefaultLiquibaseConnectionProvider implements LiquibaseConnectionPr
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
indexCreationThreshold = config.getInt("indexCreationThreshold", 300000);
|
||||
logger.debugf("indexCreationThreshold is %d", indexCreationThreshold);
|
||||
|
||||
// We need to explicitly handle the default here as Config might not be MicroProfile and hence no actually server config exists
|
||||
String dbAlias = config.root().get(DatabaseOptions.DB.getKey(), "dev-file");
|
||||
logger.debugf("dbAlias is %s", dbAlias);
|
||||
|
||||
// We're not using the Liquibase logic to get the DB. That is because we already know which DB class we want to use
|
||||
// for which DB vendor. We don't want to rely on auto-detection in Liquibase as it might make wrong assumptions (e.g. EDB).
|
||||
String liquibaseType = org.keycloak.config.database.Database.getVendor(dbAlias).orElseThrow().getLiquibaseType();
|
||||
logger.debugf("liquibaseType is %s", liquibaseType);
|
||||
|
||||
try {
|
||||
liquibaseDatabaseClazz = (Class<? extends Database>) Class.forName(liquibaseType);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Failed to load Liquibase Database class: " + liquibaseType, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -114,7 +131,7 @@ public class DefaultLiquibaseConnectionProvider implements LiquibaseConnectionPr
|
||||
|
||||
@Override
|
||||
public KeycloakLiquibase getLiquibase(Connection connection, String defaultSchema) throws LiquibaseException {
|
||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
||||
Database database = getLiquibaseDatabase(connection);
|
||||
if (defaultSchema != null) {
|
||||
database.setDefaultSchemaName(defaultSchema);
|
||||
}
|
||||
@@ -130,7 +147,7 @@ public class DefaultLiquibaseConnectionProvider implements LiquibaseConnectionPr
|
||||
|
||||
@Override
|
||||
public KeycloakLiquibase getLiquibaseForCustomUpdate(Connection connection, String defaultSchema, String changelogLocation, ClassLoader classloader, String changelogTableName) throws LiquibaseException {
|
||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
||||
Database database = getLiquibaseDatabase(connection);
|
||||
if (defaultSchema != null) {
|
||||
database.setDefaultSchemaName(defaultSchema);
|
||||
}
|
||||
@@ -143,4 +160,25 @@ public class DefaultLiquibaseConnectionProvider implements LiquibaseConnectionPr
|
||||
return new KeycloakLiquibase(changelogLocation, resourceAccessor, database);
|
||||
}
|
||||
|
||||
// Similarly to Hibernate, we want to enforce Liquibase to use the same DB as configured in Keycloak
|
||||
private Database getLiquibaseDatabase(Connection connection) {
|
||||
Database liquibaseDatabase;
|
||||
|
||||
// Mimic what DatabaseFactory#findCorrectDatabaseImplementation does: create DB instance using reflections
|
||||
try {
|
||||
liquibaseDatabase = liquibaseDatabaseClazz.getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to create instance of " + liquibaseDatabaseClazz.getName());
|
||||
}
|
||||
DatabaseConnection liquibaseConnection = new JdbcConnection(connection);
|
||||
try {
|
||||
logger.debugf("DB Product Name: %s", liquibaseConnection.getDatabaseProductName());
|
||||
} catch (LiquibaseException e) {
|
||||
logger.debug("Failed to detect DB Product Name", e);
|
||||
}
|
||||
liquibaseDatabase.setConnection(liquibaseConnection);
|
||||
|
||||
return liquibaseDatabase;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@
|
||||
<validCheckSum>7:fad08e83c77d0171ec166bc9bc5d390a</validCheckSum>
|
||||
<validCheckSum>7:72553fac2d2281052acbbbb14aa22ccf</validCheckSum>
|
||||
<validCheckSum>7:b558ad47ea0e4d3c3514225a49cc0d65</validCheckSum>
|
||||
|
||||
<!-- EDB previously did not run this change set, now it does -->
|
||||
<validCheckSum>8:f43dfba07ba249d5d932dc489fd2b886</validCheckSum>
|
||||
<validCheckSum>9:bd2bd0fc7768cf0845ac96a8786fa735</validCheckSum>
|
||||
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
|
||||
<or>
|
||||
<dbms type="mysql"/>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||
|
||||
<changeSet author="keycloak" id="20.0.0-12964-supported-dbs">
|
||||
<validCheckSum>9:e5f243877199fd96bcc842f27a1656ac</validCheckSum>
|
||||
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
|
||||
<or>
|
||||
<dbms type="mysql"/>
|
||||
@@ -38,6 +39,19 @@
|
||||
</modifySql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="keycloak" id="20.0.0-12964-supported-dbs-edb-migration">
|
||||
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
|
||||
<dbms type="postgresql"/>
|
||||
<changeSetExecuted id="20.0.0-12964-supported-dbs" author="keycloak" changeLogFile="META-INF/jpa-changelog-20.0.0.xml"/>
|
||||
<indexExists tableName="GROUP_ATTRIBUTE" indexName="IDX_GROUP_ATT_BY_NAME_VALUE" />
|
||||
</preConditions>
|
||||
<dropIndex tableName="GROUP_ATTRIBUTE" indexName="IDX_GROUP_ATT_BY_NAME_VALUE" />
|
||||
<createIndex tableName="GROUP_ATTRIBUTE" indexName="IDX_GROUP_ATT_BY_NAME_VALUE">
|
||||
<column name="NAME" type="VARCHAR(255)"/>
|
||||
<column name="(value::varchar(250))" valueComputed="(value::varchar(250))" />
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="keycloak" id="20.0.0-12964-unsupported-dbs">
|
||||
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
|
||||
<not>
|
||||
|
||||
@@ -83,4 +83,18 @@
|
||||
</modifySql>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="keycloak" id="24.0.0-26618-edb-migration">
|
||||
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
|
||||
<dbms type="postgresql"/>
|
||||
<indexExists tableName="CLIENT_ATTRIBUTES" indexName="IDX_CLIENT_ATT_BY_NAME_VALUE" />
|
||||
<changeSetExecuted id="24.0.0-26618-drop-index-if-present" author="keycloak" changeLogFile="META-INF/jpa-changelog-24.0.0.xml" />
|
||||
<changeSetExecuted id="24.0.0-26618-reindex" author="keycloak" changeLogFile="META-INF/jpa-changelog-24.0.0.xml" />
|
||||
</preConditions>
|
||||
<dropIndex tableName="CLIENT_ATTRIBUTES" indexName="IDX_CLIENT_ATT_BY_NAME_VALUE"/>
|
||||
<createIndex tableName="CLIENT_ATTRIBUTES" indexName="IDX_CLIENT_ATT_BY_NAME_VALUE">
|
||||
<column name="NAME" type="VARCHAR(255)"/>
|
||||
<column name="substr(VALUE,1,255)" valueComputed="substr(VALUE,1,255)" />
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
~ * See the License for the specific language governing permissions and
|
||||
~ * limitations under the License.
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
|
||||
|
||||
<changeSet author="keycloak" id="25.0.0-28265-tables">
|
||||
<addColumn tableName="OFFLINE_USER_SESSION">
|
||||
@@ -144,6 +144,18 @@
|
||||
<addUniqueConstraint columnNames="CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID" constraintName="UK_EXTERNAL_CONSENT" tableName="USER_CONSENT"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="keycloak" id="unique-consentuser-edb-migration">
|
||||
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
|
||||
<dbms type="postgresql"/>
|
||||
<changeSetExecuted id="unique-consentuser" author="keycloak" changeLogFile="META-INF/jpa-changelog-25.0.0.xml" />
|
||||
<uniqueConstraintExists tableName="USER_CONSENT" constraintName="UK_JKUWUVD56ONTGSUHOGM8UEWRT"/>
|
||||
</preConditions>
|
||||
<customChange class="org.keycloak.connections.jpa.updater.liquibase.custom.JpaUpdate25_0_0_ConsentConstraints"/>
|
||||
<dropUniqueConstraint tableName="USER_CONSENT" constraintName="UK_JKUWUVD56ONTGSUHOGM8UEWRT"/>
|
||||
<addUniqueConstraint columnNames="CLIENT_ID, USER_ID" constraintName="UK_LOCAL_CONSENT" tableName="USER_CONSENT"/>
|
||||
<addUniqueConstraint columnNames="CLIENT_STORAGE_PROVIDER, EXTERNAL_CLIENT_ID, USER_ID" constraintName="UK_EXTERNAL_CONSENT" tableName="USER_CONSENT"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="keycloak" id="unique-consentuser-mysql">
|
||||
<preConditions onSqlOutput="TEST" onFail="MARK_RAN">
|
||||
<or>
|
||||
|
||||
@@ -15,6 +15,5 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase
|
||||
org.keycloak.connections.jpa.updater.liquibase.UpdatedMariaDBDatabase
|
||||
org.keycloak.connections.jpa.updater.liquibase.UpdatedMySqlDatabase
|
||||
3
pom.xml
3
pom.xml
@@ -173,6 +173,9 @@
|
||||
<oracledb.container>mirror.gcr.io/gvenzl/oracle-free:${oracledb.version}-slim-faststart</oracledb.container>
|
||||
<!-- this is the oracle driver version also used in the Quarkus BOM -->
|
||||
<oracle-jdbc.version>23.6.0.24.10</oracle-jdbc.version>
|
||||
<!-- Custom image, lives in test-framework/db-edb/container -->
|
||||
<edb.container>quay.io/keycloakqe/enterprisedb:${edb.version}</edb.container>
|
||||
<edb.version>17</edb.version>
|
||||
|
||||
<!-- Infinispan Server Container -->
|
||||
<infinispan.container>quay.io/infinispan/server:${infinispan.version}</infinispan.container>
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class Database {
|
||||
|
||||
public static boolean isLiquibaseDatabaseSupported(String databaseType, String dbKind) {
|
||||
for (Vendor vendor : DATABASES.values()) {
|
||||
if (vendor.liquibaseTypes.contains(databaseType) && vendor.isOfKind(dbKind)) {
|
||||
if (vendor.liquibaseType.equals(databaseType) && vendor.isOfKind(dbKind)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -177,7 +177,7 @@ public final class Database {
|
||||
return addH2CloseOnExit(addH2NonKeywords(jdbcUrl));
|
||||
}
|
||||
},
|
||||
asList("liquibase.database.core.H2Database"),
|
||||
"liquibase.database.core.H2Database",
|
||||
"dev-mem", "dev-file"
|
||||
),
|
||||
MYSQL("mysql",
|
||||
@@ -190,7 +190,7 @@ public final class Database {
|
||||
getProperty(DatabaseOptions.DB_URL_PORT, namedProperty, "3306"),
|
||||
getProperty(DatabaseOptions.DB_URL_DATABASE, namedProperty, "keycloak"),
|
||||
getProperty(DatabaseOptions.DB_URL_PROPERTIES, namedProperty)),
|
||||
List.of("org.keycloak.connections.jpa.updater.liquibase.UpdatedMySqlDatabase")
|
||||
"org.keycloak.connections.jpa.updater.liquibase.UpdatedMySqlDatabase"
|
||||
),
|
||||
TIDB("tidb",
|
||||
"com.mysql.cj.jdbc.MysqlXADataSource",
|
||||
@@ -202,7 +202,7 @@ public final class Database {
|
||||
getProperty(DatabaseOptions.DB_URL_PORT, namedProperty, "3306"),
|
||||
getProperty(DatabaseOptions.DB_URL_DATABASE, namedProperty, "keycloak"),
|
||||
getProperty(DatabaseOptions.DB_URL_PROPERTIES, namedProperty)),
|
||||
List.of("org.keycloak.connections.jpa.updater.liquibase.UpdatedMySqlDatabase")
|
||||
"org.keycloak.connections.jpa.updater.liquibase.UpdatedMySqlDatabase"
|
||||
),
|
||||
MARIADB("mariadb",
|
||||
"org.mariadb.jdbc.MariaDbDataSource",
|
||||
@@ -214,7 +214,7 @@ public final class Database {
|
||||
getProperty(DatabaseOptions.DB_URL_PORT, namedProperty, "3306"),
|
||||
getProperty(DatabaseOptions.DB_URL_DATABASE, namedProperty, "keycloak"),
|
||||
getProperty(DatabaseOptions.DB_URL_PROPERTIES, namedProperty)),
|
||||
List.of("org.keycloak.connections.jpa.updater.liquibase.UpdatedMariaDBDatabase")
|
||||
"org.keycloak.connections.jpa.updater.liquibase.UpdatedMariaDBDatabase"
|
||||
),
|
||||
POSTGRES("postgresql",
|
||||
"org.postgresql.xa.PGXADataSource",
|
||||
@@ -226,7 +226,7 @@ public final class Database {
|
||||
getProperty(DatabaseOptions.DB_URL_PORT, namedProperty, "5432"),
|
||||
getProperty(DatabaseOptions.DB_URL_DATABASE, namedProperty, "keycloak"),
|
||||
getProperty(DatabaseOptions.DB_URL_PROPERTIES, namedProperty)),
|
||||
asList("liquibase.database.core.PostgresDatabase", "org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase"),
|
||||
"liquibase.database.core.PostgresDatabase",
|
||||
"postgres"
|
||||
),
|
||||
MSSQL("mssql",
|
||||
@@ -239,7 +239,7 @@ public final class Database {
|
||||
getProperty(DatabaseOptions.DB_URL_PORT, namedProperty, "1433"),
|
||||
getProperty(DatabaseOptions.DB_URL_DATABASE, namedProperty, "keycloak"),
|
||||
getProperty(DatabaseOptions.DB_URL_PROPERTIES, namedProperty)),
|
||||
List.of("org.keycloak.quarkus.runtime.storage.database.liquibase.database.CustomMSSQLDatabase"),
|
||||
"org.keycloak.quarkus.runtime.storage.database.liquibase.database.CustomMSSQLDatabase",
|
||||
"mssql"
|
||||
),
|
||||
ORACLE("oracle",
|
||||
@@ -251,7 +251,7 @@ public final class Database {
|
||||
getProperty(DatabaseOptions.DB_URL_HOST, namedProperty, "localhost"),
|
||||
getProperty(DatabaseOptions.DB_URL_PORT, namedProperty, "1521"),
|
||||
getProperty(DatabaseOptions.DB_URL_DATABASE, namedProperty, "keycloak")),
|
||||
List.of("liquibase.database.core.OracleDatabase")
|
||||
"liquibase.database.core.OracleDatabase"
|
||||
);
|
||||
|
||||
final String databaseKind;
|
||||
@@ -259,28 +259,23 @@ public final class Database {
|
||||
final String nonXaDriver;
|
||||
final Function<String, String> dialect;
|
||||
final BiFunction<String, String, String> defaultUrl;
|
||||
final List<String> liquibaseTypes;
|
||||
final String liquibaseType;
|
||||
final String[] aliases;
|
||||
|
||||
Vendor(String databaseKind, String xaDriver, String nonXaDriver, String dialect, String defaultUrl, List<String> liquibaseTypes,
|
||||
String... aliases) {
|
||||
this(databaseKind, xaDriver, nonXaDriver, alias -> dialect, (namedProperty, alias) -> defaultUrl, liquibaseTypes, aliases);
|
||||
}
|
||||
|
||||
Vendor(String databaseKind, String xaDriver, String nonXaDriver, String dialect, BiFunction<String, String, String> defaultUrl,
|
||||
List<String> liquibaseTypes, String... aliases) {
|
||||
this(databaseKind, xaDriver, nonXaDriver, alias -> dialect, defaultUrl, liquibaseTypes, aliases);
|
||||
String liquibaseType, String... aliases) {
|
||||
this(databaseKind, xaDriver, nonXaDriver, alias -> dialect, defaultUrl, liquibaseType, aliases);
|
||||
}
|
||||
|
||||
Vendor(String databaseKind, String xaDriver, String nonXaDriver, Function<String, String> dialect, BiFunction<String, String, String> defaultUrl,
|
||||
List<String> liquibaseTypes,
|
||||
String liquibaseType,
|
||||
String... aliases) {
|
||||
this.databaseKind = databaseKind;
|
||||
this.xaDriver = xaDriver;
|
||||
this.nonXaDriver = nonXaDriver;
|
||||
this.dialect = dialect;
|
||||
this.defaultUrl = defaultUrl;
|
||||
this.liquibaseTypes = liquibaseTypes;
|
||||
this.liquibaseType = liquibaseType;
|
||||
this.aliases = aliases.length == 0 ? new String[]{databaseKind} : aliases;
|
||||
}
|
||||
|
||||
@@ -298,6 +293,10 @@ public final class Database {
|
||||
defaultValue);
|
||||
}
|
||||
|
||||
public String getLiquibaseType() {
|
||||
return liquibaseType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return databaseKind.toLowerCase(Locale.ROOT);
|
||||
|
||||
@@ -38,6 +38,9 @@ quarkus.log.category."io.quarkus.deployment.steps.ReflectiveHierarchyStep".level
|
||||
# https://hibernate.zulipchat.com/#narrow/channel/132096-hibernate-user/topic/Feature.20Request.3A.20Disable.20logging.20of.20SqlExceptionHelper.20for
|
||||
quarkus.log.category."org.hibernate.engine.jdbc.spi.SqlExceptionHelper".level=off
|
||||
|
||||
# Disable irrelevant EDB warning: EnterpriseDB does not store DATE columns. Instead, it auto-converts them to TIMESTAMPs. (edb_redwood_date=true)
|
||||
quarkus.log.category."liquibase.database.core.PostgresDatabase".level=error
|
||||
|
||||
quarkus.log.console.filter=keycloak-filter
|
||||
quarkus.log.file.filter=keycloak-filter
|
||||
quarkus.log.syslog.filter=keycloak-filter
|
||||
|
||||
@@ -57,6 +57,12 @@
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-db-edb</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-db-mariadb</artifactId>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
## Database containers ##
|
||||
edb.container=${edb.container}
|
||||
mysql.container=${mysql.container}
|
||||
postgres.container=${postgresql.container}
|
||||
mariadb.container=${mariadb.container}
|
||||
|
||||
21
test-framework/db-edb/container/Dockerfile
Normal file
21
test-framework/db-edb/container/Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
||||
FROM registry.access.redhat.com/ubi9
|
||||
|
||||
# Get the token at https://www.enterprisedb.com/repos-downloads
|
||||
ARG EDB_REPO_TOKEN=token-must-be-set
|
||||
ENV VERSION=17
|
||||
ENV PGUSER=enterprisedb
|
||||
ENV PGPASSWORD=password
|
||||
ENV PGDATABASE=keycloak
|
||||
ENV PGPORT=5432
|
||||
|
||||
ENV PGDATA=/var/lib/edb/as${VERSION}/data
|
||||
|
||||
RUN (curl -1sSLf "https://downloads.enterprisedb.com/${EDB_REPO_TOKEN}/enterprise/setup.rpm.sh" | bash) && \
|
||||
dnf -y install edb-as${VERSION}-server
|
||||
|
||||
USER enterprisedb
|
||||
WORKDIR /usr/edb/as${VERSION}/bin/
|
||||
|
||||
COPY init-and-start-db.sh .
|
||||
CMD ./init-and-start-db.sh
|
||||
EXPOSE ${PGPORT}
|
||||
9
test-framework/db-edb/container/init-and-start-db.sh
Executable file
9
test-framework/db-edb/container/init-and-start-db.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#! /bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
PGSETUP_INITDB_OPTIONS="-E UTF-8" ./initdb -A md5 -U $PGUSER --pwfile=<(echo "$PGPASSWORD")
|
||||
echo "host all all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf";
|
||||
|
||||
(while ! (sleep 1 && ./createdb $PGDATABASE > /dev/null 2>&1); do echo "Retrying database creation..."; done; echo "Database $PGDATABASE created.") &
|
||||
|
||||
exec ./edb-postgres -c port=$PGPORT -c logging_collector=off -c listen_addresses=*
|
||||
41
test-framework/db-edb/pom.xml
Executable file
41
test-framework/db-edb/pom.xml
Executable file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
|
||||
~ and other contributors as indicated by the @author tags.
|
||||
~
|
||||
~ Licensed 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.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>keycloak-test-framework-parent</artifactId>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<version>999.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>keycloak-test-framework-db-edb</artifactId>
|
||||
<name>Keycloak Test Framework - EDB support</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>EDB support for Keycloak Test Framework</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.keycloak.testframework.database;
|
||||
|
||||
public class EnterpriseDbDatabaseSupplier extends AbstractDatabaseSupplier {
|
||||
|
||||
@Override
|
||||
public String getAlias() {
|
||||
return EnterpriseDbTestDatabase.NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
TestDatabase getTestDatabase() {
|
||||
return new EnterpriseDbTestDatabase();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.keycloak.testframework.database;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.testframework.util.ContainerImages;
|
||||
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
public class EnterpriseDbTestDatabase extends AbstractContainerTestDatabase {
|
||||
private static final Logger LOGGER = Logger.getLogger(EnterpriseDbTestDatabase.class);
|
||||
|
||||
public static final String NAME = "edb";
|
||||
|
||||
@Override
|
||||
public JdbcDatabaseContainer<?> createContainer() {
|
||||
return new KeycloakEnterpriseDbContainer(DockerImageName.parse(ContainerImages.getContainerImageName(NAME)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDatabaseVendor() {
|
||||
return "postgres";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return LOGGER;
|
||||
}
|
||||
}
|
||||
@@ -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 EnterpriseDbTestFrameworkExtension implements TestFrameworkExtension {
|
||||
|
||||
@Override
|
||||
public List<Supplier<?, ?>> suppliers() {
|
||||
return List.of(new EnterpriseDbDatabaseSupplier());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package org.keycloak.testframework.database;
|
||||
|
||||
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
/**
|
||||
* @author Vaclav Muzikar <vmuzikar@redhat.com>
|
||||
*/
|
||||
public class KeycloakEnterpriseDbContainer extends JdbcDatabaseContainer<KeycloakEnterpriseDbContainer> {
|
||||
private String databaseName = "keycloak";
|
||||
private String username = "enterprisedb";
|
||||
private String password = "password";
|
||||
private static final int PORT = 5432;
|
||||
|
||||
public KeycloakEnterpriseDbContainer(DockerImageName dockerImageName) {
|
||||
super(dockerImageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDriverClassName() {
|
||||
return "org.postgresql.Driver";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJdbcUrl() {
|
||||
return String.format("jdbc:postgresql://%s:%d/%s", getHost(), getMappedPort(PORT), getDatabaseName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
addEnv("PGDATABASE", getDatabaseName());
|
||||
addEnv("PGUSER", getUsername());
|
||||
addEnv("PGPASSWORD", getPassword());
|
||||
addExposedPort(PORT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTestQueryString() {
|
||||
return "SELECT 1";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDatabaseName() {
|
||||
return databaseName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakEnterpriseDbContainer withUsername(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakEnterpriseDbContainer withPassword(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakEnterpriseDbContainer withDatabaseName(String dbName) {
|
||||
this.databaseName = dbName;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakEnterpriseDbContainer withUrlParam(String paramName, String paramValue) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.keycloak.testframework.database.EnterpriseDbTestFrameworkExtension
|
||||
@@ -36,6 +36,7 @@
|
||||
<module>bom</module>
|
||||
<module>core</module>
|
||||
<module>junit5-config</module>
|
||||
<module>db-edb</module>
|
||||
<module>db-mariadb</module>
|
||||
<module>db-mssql</module>
|
||||
<module>db-mysql</module>
|
||||
|
||||
@@ -56,6 +56,10 @@
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-ui</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-db-edb</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testframework</groupId>
|
||||
<artifactId>keycloak-test-framework-db-mariadb</artifactId>
|
||||
|
||||
@@ -5,6 +5,8 @@ import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.conditions.DisabledForDatabases;
|
||||
import org.keycloak.testframework.database.DatabaseConfig;
|
||||
import org.keycloak.testframework.database.DatabaseConfigBuilder;
|
||||
import org.keycloak.testframework.database.EnterpriseDbDatabaseSupplier;
|
||||
import org.keycloak.testframework.database.EnterpriseDbTestDatabase;
|
||||
import org.keycloak.testframework.database.PostgresTestDatabase;
|
||||
import org.keycloak.testframework.database.TestDatabase;
|
||||
import org.keycloak.testframework.server.KeycloakServerConfig;
|
||||
@@ -25,7 +27,8 @@ public class CaseSensitiveSchemaTest extends AbstractDBSchemaTest {
|
||||
|
||||
return switch (dbType()) {
|
||||
// DBs that convert unquoted to lower-case by default
|
||||
case PostgresTestDatabase.NAME -> config.option("db-schema", "KEYCLOAK");
|
||||
case PostgresTestDatabase.NAME, EnterpriseDbTestDatabase.NAME
|
||||
-> config.option("db-schema", "KEYCLOAK");
|
||||
// DBs that convert unquoted to upper-case by default
|
||||
case "dev-file", "dev-mem" ->
|
||||
config.option("db-url-properties", ";INIT=CREATE SCHEMA IF NOT EXISTS keycloak").option("db-schema", "keycloak");
|
||||
@@ -37,7 +40,7 @@ public class CaseSensitiveSchemaTest extends AbstractDBSchemaTest {
|
||||
public static class CaseSensitiveDatabaseConfig implements DatabaseConfig {
|
||||
@Override
|
||||
public DatabaseConfigBuilder configure(DatabaseConfigBuilder database) {
|
||||
if (PostgresTestDatabase.NAME.equals(dbType())) {
|
||||
if (PostgresTestDatabase.NAME.equals(dbType()) || EnterpriseDbTestDatabase.NAME.equals(dbType())) {
|
||||
database.initScript("org/keycloak/tests/db/case-sensitive-schema-postgres.sql");
|
||||
}
|
||||
return database;
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
|
||||
import org.keycloak.testframework.database.DatabaseConfig;
|
||||
import org.keycloak.testframework.conditions.DisabledForDatabases;
|
||||
import org.keycloak.testframework.database.DatabaseConfigBuilder;
|
||||
import org.keycloak.testframework.database.EnterpriseDbTestDatabase;
|
||||
import org.keycloak.testframework.database.PostgresTestDatabase;
|
||||
import org.keycloak.testframework.database.TestDatabase;
|
||||
import org.keycloak.testframework.injection.LifeCycle;
|
||||
@@ -36,7 +37,7 @@ public class PreserveSchemaCaseLiquibaseTest extends AbstractDBSchemaTest {
|
||||
private static class PreserveSchemaCaseDatabaseConfig implements DatabaseConfig {
|
||||
@Override
|
||||
public DatabaseConfigBuilder configure(DatabaseConfigBuilder database) {
|
||||
if (dbType().equals(PostgresTestDatabase.NAME)) {
|
||||
if (dbType().equals(PostgresTestDatabase.NAME) || dbType().equals(EnterpriseDbTestDatabase.NAME)) {
|
||||
return database.initScript("org/keycloak/tests/db/preserve-schema-case-liquibase-postgres.sql");
|
||||
}
|
||||
return database.database("keycloak-t");
|
||||
|
||||
@@ -480,6 +480,28 @@
|
||||
<jdbc.mvn.version>${aws-jdbc-wrapper.version}</jdbc.mvn.version>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>db-edb</id>
|
||||
<properties>
|
||||
<keycloak.storage.connections.vendor>postgres</keycloak.storage.connections.vendor>
|
||||
<keycloak.connectionsJpa.driver>org.postgresql.Driver</keycloak.connectionsJpa.driver>
|
||||
<keycloak.connectionsJpa.database>keycloak</keycloak.connectionsJpa.database>
|
||||
<keycloak.connectionsJpa.user>keycloak</keycloak.connectionsJpa.user>
|
||||
<keycloak.connectionsJpa.password>keycloak</keycloak.connectionsJpa.password>
|
||||
<keycloak.connectionsJpa.url>jdbc:postgresql://${auth.server.db.host}:${docker.database.port}/${keycloak.connectionsJpa.database}</keycloak.connectionsJpa.url>
|
||||
<!-- JDBC properties point to "default" JDBC driver for the particular DB -->
|
||||
<!-- For EAP testing, it is recommended to override those with system properties pointing to GAV of more appropriate JDBC driver -->
|
||||
<!-- for the particular EAP version -->
|
||||
<jdbc.mvn.groupId>org.postgresql</jdbc.mvn.groupId>
|
||||
<jdbc.mvn.artifactId>postgresql</jdbc.mvn.artifactId>
|
||||
<jdbc.mvn.version>${postgresql-jdbc.version}</jdbc.mvn.version>
|
||||
<docker.database.image>${edb.container}</docker.database.image>
|
||||
<docker.database.port>5432</docker.database.port>
|
||||
<docker.database.skip>false</docker.database.skip>
|
||||
<docker.database.cmd>./init-and-start-db.sh</docker.database.cmd>
|
||||
<docker.database.wait-for-log-regex>Database keycloak created.</docker.database.wait-for-log-regex>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>db-mariadb</id>
|
||||
<properties>
|
||||
|
||||
@@ -395,6 +395,12 @@
|
||||
<ORACLE_PASSWORD>${keycloak.connectionsJpa.password}</ORACLE_PASSWORD>
|
||||
<APP_USER>${keycloak.connectionsJpa.user}</APP_USER>
|
||||
<APP_USER_PASSWORD>${keycloak.connectionsJpa.password}</APP_USER_PASSWORD>
|
||||
|
||||
<!-- EnterpriseDB -->
|
||||
<PGPORT>${docker.database.port}</PGPORT>
|
||||
<PGDATABASE>${keycloak.connectionsJpa.database}</PGDATABASE>
|
||||
<PGUSER>${keycloak.connectionsJpa.user}</PGUSER>
|
||||
<PGPASSWORD>${keycloak.connectionsJpa.password}</PGPASSWORD>
|
||||
</env>
|
||||
<cmd>${docker.database.cmd}</cmd>
|
||||
<wait>
|
||||
|
||||
Reference in New Issue
Block a user