Possibility to execute DB migration tests for Quarkus distribution (#12688)
Closes #12685
This commit is contained in:
parent
7fccdb10d8
commit
17f1d04960
10 changed files with 5912 additions and 16 deletions
|
@ -286,11 +286,35 @@ Run the test (Update according to your DB connection, versions etc):
|
||||||
-Dprevious.product.unpacked.folder.name=keycloak-$OLD_KEYCLOAK_VERSION \
|
-Dprevious.product.unpacked.folder.name=keycloak-$OLD_KEYCLOAK_VERSION \
|
||||||
-Dmigration.import.file.name=migration-realm-$OLD_KEYCLOAK_VERSION.json \
|
-Dmigration.import.file.name=migration-realm-$OLD_KEYCLOAK_VERSION.json \
|
||||||
-Dauth.server.ssl.required=false \
|
-Dauth.server.ssl.required=false \
|
||||||
-Djdbc.mvn.version=2.2.4
|
-Djdbc.mvn.version=2.2.4 \
|
||||||
|
-Dsurefire.failIfNoSpecifiedTests=false
|
||||||
|
|
||||||
|
|
||||||
For the available versions of old keycloak server, you can take a look to [this directory](tests/base/src/test/resources/migration-test) .
|
For the available versions of old keycloak server, you can take a look to [this directory](tests/base/src/test/resources/migration-test) .
|
||||||
|
|
||||||
|
### DB migration test with Quarkus
|
||||||
|
It is possible to execute DB migration tests for Keycloak with Quarkus distribution by specifying auth server as `-Pauth-server-quarkus`
|
||||||
|
and instead of the `auth-server-migration-legacy`, use only `auth-server-migration`.
|
||||||
|
|
||||||
|
The first version of Keycloak on Quarkus is version `17.0.0`.
|
||||||
|
Therefore, it is not possible to define the older version.
|
||||||
|
You can execute those tests as follows:
|
||||||
|
```
|
||||||
|
export OLD_KEYCLOAK_VERSION=17.0.0
|
||||||
|
|
||||||
|
mvn -B -f testsuite/integration-arquillian/pom.xml \
|
||||||
|
clean install \
|
||||||
|
-Pjpa,auth-server-quarkus,db-mariadb,auth-server-migration \
|
||||||
|
-Dtest=MigrationTest \
|
||||||
|
-Dmigration.mode=auto \
|
||||||
|
-Dmigrated.auth.server.version=$OLD_KEYCLOAK_VERSION \
|
||||||
|
-Dprevious.product.unpacked.folder.name=keycloak-$OLD_KEYCLOAK_VERSION \
|
||||||
|
-Dmigration.import.file.name=migration-realm-$OLD_KEYCLOAK_VERSION.json \
|
||||||
|
-Dauth.server.ssl.required=false \
|
||||||
|
-Djdbc.mvn.version=2.2.4 \
|
||||||
|
-Dsurefire.failIfNoSpecifiedTests=false
|
||||||
|
```
|
||||||
|
|
||||||
### DB migration test with manual mode
|
### DB migration test with manual mode
|
||||||
|
|
||||||
Same test as above, but it uses manual migration mode. During startup of the new Keycloak server, Liquibase won't automatically perform DB update, but it
|
Same test as above, but it uses manual migration mode. During startup of the new Keycloak server, Liquibase won't automatically perform DB update, but it
|
||||||
|
|
|
@ -457,6 +457,7 @@ public class AuthServerTestEnricher {
|
||||||
if (suiteContext.isAuthServerMigrationEnabled()) {
|
if (suiteContext.isAuthServerMigrationEnabled()) {
|
||||||
log.info("## STOP old container: " + suiteContext.getMigratedAuthServerInfo().getQualifier());
|
log.info("## STOP old container: " + suiteContext.getMigratedAuthServerInfo().getQualifier());
|
||||||
stopContainerEvent.fire(new StopContainer(suiteContext.getMigratedAuthServerInfo().getArquillianContainer()));
|
stopContainerEvent.fire(new StopContainer(suiteContext.getMigratedAuthServerInfo().getArquillianContainer()));
|
||||||
|
suiteContext.setMigratedAuthServerInfo(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration {
|
||||||
private String profile;
|
private String profile;
|
||||||
private String javaOpts;
|
private String javaOpts;
|
||||||
private boolean reaugmentBeforeStart;
|
private boolean reaugmentBeforeStart;
|
||||||
|
private String importFile = System.getProperty("migration.import.file.name");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate() throws ConfigurationException {
|
public void validate() throws ConfigurationException {
|
||||||
|
@ -155,4 +156,13 @@ public class KeycloakQuarkusConfiguration implements ContainerConfiguration {
|
||||||
this.debugPort = debugPort;
|
this.debugPort = debugPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getImportFile() {
|
||||||
|
return importFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImportFile(String importFile) {
|
||||||
|
this.importFile = importFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,15 @@ import javax.net.ssl.SSLSocketFactory;
|
||||||
import javax.net.ssl.TrustManager;
|
import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.security.KeyManagementException;
|
import java.security.KeyManagementException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
@ -22,7 +24,6 @@ import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
@ -70,6 +71,7 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
||||||
@Override
|
@Override
|
||||||
public void start() throws LifecycleException {
|
public void start() throws LifecycleException {
|
||||||
try {
|
try {
|
||||||
|
importRealm();
|
||||||
container = startContainer();
|
container = startContainer();
|
||||||
waitForReadiness();
|
waitForReadiness();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -127,6 +129,28 @@ public class KeycloakQuarkusServerDeployableContainer implements DeployableConta
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void importRealm() throws IOException, URISyntaxException {
|
||||||
|
if (suiteContext.get().isAuthServerMigrationEnabled() && configuration.getImportFile() != null) {
|
||||||
|
final String importFileName = configuration.getImportFile();
|
||||||
|
|
||||||
|
log.infof("Importing realm from file '%s'", importFileName);
|
||||||
|
|
||||||
|
final URL url = getClass().getResource("/migration-test/" + importFileName);
|
||||||
|
if (url == null) throw new IllegalArgumentException("Cannot find migration import file");
|
||||||
|
|
||||||
|
final Path path = Paths.get(url.toURI());
|
||||||
|
final File wrkDir = configuration.getProvidersPath().resolve("bin").toFile();
|
||||||
|
final List<String> commands = new ArrayList<>();
|
||||||
|
|
||||||
|
commands.add(getCommand());
|
||||||
|
commands.add("import");
|
||||||
|
commands.add("--file=" + wrkDir.toPath().relativize(path));
|
||||||
|
|
||||||
|
final ProcessBuilder pb = new ProcessBuilder(commands);
|
||||||
|
pb.directory(wrkDir).inheritIO().start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Process startContainer() throws IOException {
|
private Process startContainer() throws IOException {
|
||||||
ProcessBuilder pb = new ProcessBuilder(getProcessCommands());
|
ProcessBuilder pb = new ProcessBuilder(getProcessCommands());
|
||||||
File wrkDir = configuration.getProvidersPath().resolve("bin").toFile();
|
File wrkDir = configuration.getProvidersPath().resolve("bin").toFile();
|
||||||
|
|
|
@ -42,15 +42,16 @@ public class MigrationTestExecutionDecider implements TestExecutionDecider {
|
||||||
if (migrationTest && migrationAnnotation != null) {
|
if (migrationTest && migrationAnnotation != null) {
|
||||||
log.info("migration from version: " + migratedAuthServerVersion);
|
log.info("migration from version: " + migratedAuthServerVersion);
|
||||||
|
|
||||||
String versionFrom = migrationAnnotation.versionFrom();
|
final String versionPrefix = migrationAnnotation.versionPrefix();
|
||||||
|
|
||||||
if (migratedAuthServerVersion.startsWith(versionFrom)) {
|
if (migratedAuthServerVersion.startsWith(versionPrefix)) {
|
||||||
return ExecutionDecision.execute();
|
return ExecutionDecision.execute();
|
||||||
} else {
|
} else {
|
||||||
return ExecutionDecision.dontExecute(method.getName() + "doesn't fit with migration version.");
|
return ExecutionDecision.dontExecute(method.getName() + "doesn't fit with migration version.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((migrationTest && migrationAnnotation == null) || (!migrationTest && migrationAnnotation != null)) {
|
|
||||||
|
if (migrationTest || migrationAnnotation != null) {
|
||||||
return ExecutionDecision.dontExecute("Migration test and no migration annotation or no migration test and migration annotation");
|
return ExecutionDecision.dontExecute("Migration test and no migration annotation or no migration test and migration annotation");
|
||||||
}
|
}
|
||||||
return ExecutionDecision.execute();
|
return ExecutionDecision.execute();
|
||||||
|
|
|
@ -31,5 +31,5 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
@Target({ElementType.METHOD})
|
@Target({ElementType.METHOD})
|
||||||
public @interface Migration {
|
public @interface Migration {
|
||||||
String versionFrom();
|
String versionPrefix();
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,19 @@ public class MigrationTest extends AbstractMigrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Migration(versionFrom = "9.")
|
@Migration(versionPrefix = "17.")
|
||||||
|
public void migration17_xTest() throws Exception{
|
||||||
|
testMigratedData(false);
|
||||||
|
testMigrationTo18_x();
|
||||||
|
|
||||||
|
// Always test offline-token login during migration test
|
||||||
|
testOfflineTokenLogin();
|
||||||
|
testExtremelyLongClientAttribute(migrationRealm);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Migration(versionPrefix = "9.")
|
||||||
|
@AuthServerContainerExclude(AuthServer.QUARKUS)
|
||||||
public void migration9_xTest() throws Exception {
|
public void migration9_xTest() throws Exception {
|
||||||
testMigratedData(false);
|
testMigratedData(false);
|
||||||
testMigrationTo12_x(true);
|
testMigrationTo12_x(true);
|
||||||
|
@ -72,7 +84,8 @@ public class MigrationTest extends AbstractMigrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Migration(versionFrom = "4.")
|
@Migration(versionPrefix = "4.")
|
||||||
|
@AuthServerContainerExclude(AuthServer.QUARKUS)
|
||||||
public void migration4_xTest() throws Exception {
|
public void migration4_xTest() throws Exception {
|
||||||
testMigratedData();
|
testMigratedData();
|
||||||
testMigrationTo5_x();
|
testMigrationTo5_x();
|
||||||
|
@ -89,7 +102,8 @@ public class MigrationTest extends AbstractMigrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Migration(versionFrom = "3.")
|
@Migration(versionPrefix = "3.")
|
||||||
|
@AuthServerContainerExclude(AuthServer.QUARKUS)
|
||||||
public void migration3_xTest() throws Exception {
|
public void migration3_xTest() throws Exception {
|
||||||
testMigratedData();
|
testMigratedData();
|
||||||
testMigrationTo4_x();
|
testMigrationTo4_x();
|
||||||
|
@ -106,7 +120,8 @@ public class MigrationTest extends AbstractMigrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Migration(versionFrom = "2.")
|
@Migration(versionPrefix = "2.")
|
||||||
|
@AuthServerContainerExclude(AuthServer.QUARKUS)
|
||||||
public void migration2_xTest() throws Exception {
|
public void migration2_xTest() throws Exception {
|
||||||
//the realm with special characters in its id was successfully migrated (no error during migration)
|
//the realm with special characters in its id was successfully migrated (no error during migration)
|
||||||
//removing it now as testMigratedData() expects specific clients and roles
|
//removing it now as testMigratedData() expects specific clients and roles
|
||||||
|
@ -132,7 +147,8 @@ public class MigrationTest extends AbstractMigrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Migration(versionFrom = "1.")
|
@Migration(versionPrefix = "1.")
|
||||||
|
@AuthServerContainerExclude(AuthServer.QUARKUS)
|
||||||
public void migration1_xTest() throws Exception {
|
public void migration1_xTest() throws Exception {
|
||||||
testMigratedData(false);
|
testMigratedData(false);
|
||||||
testMigrationTo2_x();
|
testMigrationTo2_x();
|
||||||
|
|
|
@ -751,13 +751,16 @@
|
||||||
<property name="enabled">${auth.server.migration}</property>
|
<property name="enabled">${auth.server.migration}</property>
|
||||||
<property name="adapterImplClass">org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer</property>
|
<property name="adapterImplClass">org.keycloak.testsuite.arquillian.containers.KeycloakQuarkusServerDeployableContainer</property>
|
||||||
<property name="bindHttpPortOffset">${auth.server.port.offset}</property>
|
<property name="bindHttpPortOffset">${auth.server.port.offset}</property>
|
||||||
<property name="javaOpts">-Xms512m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=512m -Djava.net.preferIPv4Stack=true</property>
|
<property name="importFile">${migration.import.file.name}</property>
|
||||||
<property name="javaVmArguments">
|
<property name="javaOpts">
|
||||||
${migration.import.props.previous}
|
-Xms512m
|
||||||
|
-Xmx512m
|
||||||
|
-XX:MetaspaceSize=96M
|
||||||
|
-XX:MaxMetaspaceSize=512m
|
||||||
|
-Djava.net.preferIPv4Stack=true
|
||||||
${auth.server.memory.settings}
|
${auth.server.memory.settings}
|
||||||
-Dauth.server.db.host=${auth.server.db.host}
|
-Dauth.server.db.host=${auth.server.db.host}
|
||||||
</property>
|
</property>
|
||||||
<property name="managementPort">${auth.server.management.port}</property>
|
|
||||||
</configuration>
|
</configuration>
|
||||||
</container>
|
</container>
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1932,6 +1932,7 @@
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
|
<migration.import.file.name>${migration.import.file.name}</migration.import.file.name>
|
||||||
<migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
|
<migrated.auth.server.version>${migrated.auth.server.version}</migrated.auth.server.version>
|
||||||
<auth.server.migration>true</auth.server.migration>
|
<auth.server.migration>true</auth.server.migration>
|
||||||
<keycloak.migration.home>${containers.home}/auth-server-migration</keycloak.migration.home>
|
<keycloak.migration.home>${containers.home}/auth-server-migration</keycloak.migration.home>
|
||||||
|
|
Loading…
Reference in a new issue