[#29412] DB Allocator removal - dependency cleanup. (#30406)

Signed-off-by: Lukas Hanusovsky <lhanusov@redhat.com>
This commit is contained in:
Lukas Hanusovsky 2024-06-13 15:31:52 +02:00 committed by GitHub
parent 8031703228
commit ca0833b2e4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 3 additions and 1230 deletions

View file

@ -56,7 +56,7 @@ Stop MySQl:
Using built-in profiles to run database tests using docker containers Using built-in profiles to run database tests using docker containers
------- -------
The project provides specific profiles to run database tests using containers. Below is a just a sample of implemented profiles. In order to get a full list, please invoke (`mvn help:all-profiles -pl testsuite/integration-arquillian | grep -- db- | grep -v allocator`): The project provides specific profiles to run database tests using containers. Below is a just a sample of implemented profiles. In order to get a full list, please invoke (`mvn help:all-profiles -pl testsuite/integration-arquillian | grep -- db-`):
* `db-mysql` * `db-mysql`
* `db-postgres` * `db-postgres`
@ -84,35 +84,3 @@ name or tag for the image.
Note that Docker containers may occupy some space even after termination, and Note that Docker containers may occupy some space even after termination, and
especially with databases that might be easily a gigabyte. It is thus especially with databases that might be easily a gigabyte. It is thus
advisable to run `docker system prune` occasionally to reclaim that space. advisable to run `docker system prune` occasionally to reclaim that space.
Using DB Allocator Service
-------
The testsuite can use the DB Allocator Service to allocate and release desired database automatically.
Since some of the database properties (such as JDBC URL, Username or Password) need to be used when building the Auth Server,
the allocation and deallocation need to happen when building the `integration-arquillian` project (instead of `tests/base` as
it happens in other cases).
In order to use the DB Allocator Service, you must use the `jpa` profile with one of the `db-allocator-*`. Here's a full example to
run JPA with Auth Server Quarkus and MSSQL 2016:
```
mvn -f testsuite/integration-arquillian/pom.xml clean verify \
-Pjpa,auth-server-quarkus,db-allocator-db-mssql2016 \
-Ddballocator.uri=<<db-allocator-servlet-url>> \
-Ddballocator.user=<<db-allocator-user>> \
-Dmaven.test.failure.ignore=true
```
Using `-Dmaven.test.failure.ignore=true` is not strictly required but highly recommended. After running the tests,
the DB Allocator Plugin should release the allocated database.
**NOTE**: If you killed the maven surefire test preliminary (for example with CTRL-C or `kill -9` command), it will be
good to manually release the allocated database. Please check `dballocator.uri` and add `?operation=report` to the end of the URL.
Find your DB in the GUI and release it manually.
Below is a just a sample of implemented profiles. In order to get a full list, please invoke (`mvn help:all-profiles -pl testsuite/integration-arquillian | grep -- db-allocator-db-`):
* `db-allocator-db-postgres` - for testing with Postgres 9.6.x
* `db-allocator-db-mysql` - for testing with MySQL 5.7

View file

@ -1,81 +0,0 @@
<?xml version="1.0"?>
<!--
~ Copyright 2019 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 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<parent>
<artifactId>keycloak-testsuite-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>999.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>db-allocator-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>DB Allocator Plugin</name>
<properties>
<maven.version>3.3.9</maven.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>${maven.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>${maven.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.6.0</version>
</plugin>
</plugins>
</build>
</project>

View file

@ -1,184 +0,0 @@
package org.keycloak.testsuite.dballocator;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.keycloak.testsuite.dballocator.client.data.AllocationResult;
import org.keycloak.testsuite.dballocator.client.DBAllocatorServiceClient;
import org.keycloak.testsuite.dballocator.client.data.EraseResult;
import org.keycloak.testsuite.dballocator.client.exceptions.DBAllocatorException;
import org.keycloak.testsuite.dballocator.client.retry.IncrementalBackoffRetryPolicy;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Allocated a DB from DB Allocator Service.
*/
@Mojo(name = "allocate", defaultPhase = LifecyclePhase.PROCESS_TEST_RESOURCES)
public class AllocateDBMojo extends AbstractMojo {
private final Log logger = getLog();
@Parameter(defaultValue = "${project}", required = true, readonly = true)
protected MavenProject project;
@Parameter(defaultValue = "${reactorProjects}", readonly = true)
List<MavenProject> reactorProjects;
/**
* Enables printing out a summary after execution.
*/
@Parameter(property = Constants.PROPERTY_PRINT_SUMMARY, defaultValue = "true")
private boolean printSummary;
/**
* Skips the execution of this Mojo.
*/
@Parameter(property = Constants.PROPERTY_SKIP, defaultValue = "false")
private boolean skip;
/**
* The number of retries for reaching the DB Allocator Service
*/
@Parameter(property = Constants.PROPERTY_RETRY_TOTAL_RETRIES, defaultValue = "3")
private int totalRetries;
/**
* Backoff time for reaching out the DB Allocator Service.
*/
@Parameter(property = Constants.PROPERTY_RETRY_BACKOFF_SECONDS, defaultValue = "10")
private int backoffTimeSeconds;
/**
* URI to the DB Allocator Service.
*/
@Parameter(property = Constants.PROPERTY_DB_ALLOCATOR_URI)
private String dbAllocatorURI;
/**
* Username used for allocating DBs.
*/
@Parameter(property = Constants.PROPERTY_DB_ALLOCATOR_USER)
private String user;
/**
* Fallback username used for allocating DBs.
*/
@Parameter(property = Constants.PROPERTY_DB_ALLOCATOR_USER_FALLBACK)
private String fallbackUser;
/**
* Type of the database to be used.
*/
@Parameter(property = Constants.PROPERTY_DB_ALLOCATOR_DATABASE_TYPE)
private String type;
/**
* Expiration in minutes.
*/
@Parameter(property = Constants.PROPERTY_DB_ALLOCATOR_EXPIRATION_MIN, defaultValue = "1440")
private int expirationInMinutes;
/**
* Preferred DB location.
*/
@Parameter(property = Constants.PROPERTY_DB_ALLOCATOR_LOCATION, defaultValue = "geo_RDU")
private String location;
/**
* A property set as an output of this Mojo for JDBC Driver.
*/
@Parameter(property = Constants.PROPERTY_TO_BE_SET_DRIVER, defaultValue = "keycloak.connectionsJpa.driver")
private String propertyDriver;
/**
* A property set as an output of this Mojo for Database Schema.
*/
@Parameter(property = Constants.PROPERTY_TO_BE_SET_DATABASE, defaultValue = "keycloak.connectionsJpa.database")
private String propertyDatabase;
/**
* A property set as an output of this Mojo for DB Username.
*/
@Parameter(property = Constants.PROPERTY_TO_BE_SET_USER, defaultValue = "keycloak.connectionsJpa.user")
private String propertyUser;
/**
* A property set as an output of this Mojo for DB Password.
*/
@Parameter(property = Constants.PROPERTY_TO_BE_SET_PASSWORD, defaultValue = "keycloak.connectionsJpa.password")
private String propertyPassword;
/**
* A property set as an output of this Mojo for JDBC Connection URI.
*/
@Parameter(property = Constants.PROPERTY_TO_BE_SET_JDBC_URL, defaultValue = "keycloak.connectionsJpa.url")
private String propertyURL;
@Override
public void execute() throws MojoFailureException {
if (skip) {
logger.info("Skipping");
return;
}
logger.info("Total retries: " + totalRetries + "; backOffTime: " + backoffTimeSeconds);
try {
IncrementalBackoffRetryPolicy retryPolicy = new IncrementalBackoffRetryPolicy(totalRetries, backoffTimeSeconds, TimeUnit.SECONDS);
DBAllocatorServiceClient client = new DBAllocatorServiceClient(dbAllocatorURI, retryPolicy);
setFallbackUserIfNecessary();
AllocationResult allocate = client.allocate(user, type, expirationInMinutes, TimeUnit.MINUTES, location);
reactorProjects.forEach((project) -> setPropertiesToProject(project, allocate));
if (printSummary) {
logger.info("Allocated database:");
logger.info("-- UUID: " + allocate.getUUID());
logger.info("-- Driver: " + allocate.getDriver());
logger.info("-- Database: " + allocate.getDatabase());
logger.info("-- User: " + allocate.getUser());
logger.info("-- Password: " + allocate.getPassword());
logger.info("-- URL: " + allocate.getURL());
}
EraseResult eraseResult = client.erase(allocate);
if (printSummary) {
logger.info("Erased database:");
logger.info("-- UUID: " + eraseResult.getUUID());
}
} catch (DBAllocatorException e) {
String error = e.getMessage();
if (e.getErrorResponse() != null) {
error = String.format("[%s](%s)", e.getErrorResponse().getStatus(), e.getErrorResponse().readEntity(String.class));
}
throw new MojoFailureException("An error occurred while communicating with DBAllocator (" + error + ")", e);
}
}
private void setFallbackUserIfNecessary() {
if (StringUtils.isBlank(user)) {
if (StringUtils.isBlank(fallbackUser)) {
throw new IllegalArgumentException("Both " + Constants.PROPERTY_DB_ALLOCATOR_USER + " and " + Constants.PROPERTY_DB_ALLOCATOR_USER_FALLBACK + " are empty");
}
user = fallbackUser;
}
}
private void setPropertiesToProject(MavenProject project, AllocationResult allocate) {
project.getProperties().setProperty(propertyDriver, allocate.getDriver());
project.getProperties().setProperty(propertyDatabase, allocate.getDatabase());
project.getProperties().setProperty(propertyUser, allocate.getUser());
project.getProperties().setProperty(propertyPassword, allocate.getPassword());
project.getProperties().setProperty(propertyURL, allocate.getURL());
project.getProperties().setProperty(Constants.PROPERTY_ALLOCATED_DB, allocate.getUUID());
}
}

View file

@ -1,20 +0,0 @@
package org.keycloak.testsuite.dballocator;
public interface Constants {
String PROPERTY_ALLOCATED_DB = "dballocator.allocated.uuid";
String PROPERTY_DB_ALLOCATOR_URI = "dballocator.uri";
String PROPERTY_DB_ALLOCATOR_USER = "dballocator.user";
String PROPERTY_DB_ALLOCATOR_USER_FALLBACK = "user.name";
String PROPERTY_DB_ALLOCATOR_DATABASE_TYPE = "dballocator.type";
String PROPERTY_DB_ALLOCATOR_EXPIRATION_MIN = "dballocator.expirationMin";
String PROPERTY_DB_ALLOCATOR_LOCATION = "dballocator.location";
String PROPERTY_TO_BE_SET_DRIVER = "dballocator.properties.driver";
String PROPERTY_TO_BE_SET_DATABASE = "dballocator.properties.database";
String PROPERTY_TO_BE_SET_USER = "dballocator.properties.user";
String PROPERTY_TO_BE_SET_PASSWORD = "dballocator.properties.password";
String PROPERTY_TO_BE_SET_JDBC_URL = "dballocator.properties.url";
String PROPERTY_PRINT_SUMMARY = "dballocator.summary";
String PROPERTY_SKIP = "dballocator.skip";
String PROPERTY_RETRY_TOTAL_RETRIES = "dballocator.retry.totalRetries";
String PROPERTY_RETRY_BACKOFF_SECONDS = "dballocator.retry.backoffSeconds";
}

View file

@ -1,93 +0,0 @@
package org.keycloak.testsuite.dballocator;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.keycloak.testsuite.dballocator.client.data.AllocationResult;
import org.keycloak.testsuite.dballocator.client.DBAllocatorServiceClient;
import org.keycloak.testsuite.dballocator.client.exceptions.DBAllocatorException;
import org.keycloak.testsuite.dballocator.client.retry.IncrementalBackoffRetryPolicy;
import org.keycloak.testsuite.dballocator.client.data.ReleaseResult;
import java.net.URI;
import java.util.concurrent.TimeUnit;
/**
* Releases a DB from DB Allocator Service.
*/
@Mojo(name = "release", defaultPhase = LifecyclePhase.TEST)
public class ReleaseDBMojo extends AbstractMojo {
private final Log logger = getLog();
@Parameter(defaultValue = "${project}", required = true)
protected MavenProject project;
/**
* Enables printing out a summary after execution.
*/
@Parameter(property = Constants.PROPERTY_PRINT_SUMMARY, defaultValue = "true")
private boolean printSummary;
/**
* Skips the execution of this Mojo.
*/
@Parameter(property = Constants.PROPERTY_SKIP, defaultValue = "false")
private boolean skip;
/**
* The number of retries for reaching the DB Allocator Service
*/
@Parameter(property = Constants.PROPERTY_RETRY_TOTAL_RETRIES, defaultValue = "3")
private int totalRetries;
/**
* Backoff time for reaching out the DB Allocator Service.
*/
@Parameter(property = Constants.PROPERTY_RETRY_BACKOFF_SECONDS, defaultValue = "10")
private int backoffTimeSeconds;
/**
* URI to the DB Allocator Service.
*/
@Parameter(property = Constants.PROPERTY_DB_ALLOCATOR_URI)
private String dbAllocatorURI;
/**
* UUID for releasing the allocated DB.
*/
@Parameter(property = Constants.PROPERTY_ALLOCATED_DB)
private String allocatedUUID;
@Override
public void execute() throws MojoFailureException {
if (skip) {
logger.info("Skipping");
return;
}
logger.info("Total retries: " + totalRetries + "; backOffTime: " + backoffTimeSeconds);
try {
IncrementalBackoffRetryPolicy retryPolicy = new IncrementalBackoffRetryPolicy(totalRetries, backoffTimeSeconds, TimeUnit.SECONDS);
DBAllocatorServiceClient client = new DBAllocatorServiceClient(dbAllocatorURI, retryPolicy);
ReleaseResult release = client.release(AllocationResult.forRelease(allocatedUUID));
if (printSummary) {
logger.info("Released database:");
logger.info("-- UUID: " + release.getUUID());
}
} catch (DBAllocatorException e) {
String error = e.getMessage();
if (e.getErrorResponse() != null) {
error = String.format("[%s](%s)", e.getErrorResponse().getStatus(), e.getErrorResponse().readEntity(String.class));
}
throw new MojoFailureException("An error occurred while communicating with DBAllocator (" + error + ")", e);
}
}
}

View file

@ -1,11 +0,0 @@
package org.keycloak.testsuite.dballocator.client;
import org.keycloak.testsuite.dballocator.client.exceptions.DBAllocatorUnavailableException;
import jakarta.ws.rs.core.Response;
import java.util.concurrent.Callable;
@FunctionalInterface
public interface BackoffRetryPolicy {
Response retryTillHttpOk(Callable<Response> callableSupplier) throws DBAllocatorUnavailableException;
}

View file

@ -1,119 +0,0 @@
package org.keycloak.testsuite.dballocator.client;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient43Engine;
import org.keycloak.testsuite.dballocator.client.data.AllocationResult;
import org.keycloak.testsuite.dballocator.client.data.EraseResult;
import org.keycloak.testsuite.dballocator.client.data.ReleaseResult;
import org.keycloak.testsuite.dballocator.client.exceptions.DBAllocatorException;
import org.keycloak.testsuite.dballocator.client.retry.IncrementalBackoffRetryPolicy;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.Invocation;
import jakarta.ws.rs.core.Response;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.jboss.logging.Logger;
public class DBAllocatorServiceClient {
private static final int TIMEOUT = 10_000;
private final Client restClient;
private final URI allocatorServletURI;
private final BackoffRetryPolicy retryPolicy;
private final Logger logger = Logger.getLogger(DBAllocatorServiceClient.class);
public DBAllocatorServiceClient(String allocatorServletURI, BackoffRetryPolicy retryPolicy) {
Objects.requireNonNull(allocatorServletURI, "DB Allocator URI must not be null");
this.allocatorServletURI = URI.create(allocatorServletURI);
this.retryPolicy = retryPolicy != null ? retryPolicy : new IncrementalBackoffRetryPolicy();
this.restClient = ((ResteasyClientBuilder) ResteasyClientBuilder.newBuilder()).httpEngine(createEngine()).build();
}
private final ApacheHttpClient43Engine createEngine() {
RequestConfig reqConfig = RequestConfig.custom()
.setConnectTimeout(TIMEOUT)
.setSocketTimeout(TIMEOUT)
.setConnectionRequestTimeout(TIMEOUT)
.build();
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(reqConfig)
.setMaxConnTotal(1)
.build();
ApacheHttpClient43Engine engine = new ApacheHttpClient43Engine(httpClient);
engine.setFollowRedirects(true);
return engine;
}
public AllocationResult allocate(String user, String type, int expiration, TimeUnit expirationTimeUnit, String location) throws DBAllocatorException {
Objects.requireNonNull(user, "User can not be null");
Objects.requireNonNull(type, "DB Type must not be null");
try {
String typeWithLocation = location != null ? type + "&&" + location : type;
Invocation.Builder target = restClient
.target(allocatorServletURI)
.queryParam("operation", "allocate")
.queryParam("requestee", user)
.queryParam("expression", typeWithLocation)
.queryParam("expiry", expirationTimeUnit.toMinutes(expiration))
.request();
logger.info("Calling " + allocatorServletURI);
Response response = retryPolicy.retryTillHttpOk(() -> target.get());
Properties properties = new Properties();
String content = response.readEntity(String.class);
if (content != null) {
try(InputStream is = new ByteArrayInputStream(content.getBytes())) {
properties.load(is);
}
}
return AllocationResult.successful(properties);
} catch (IOException e) {
throw new DBAllocatorException(e);
}
}
public EraseResult erase(AllocationResult allocationResult) throws DBAllocatorException {
Objects.requireNonNull(allocationResult, "Previous allocation result must not be null");
Objects.requireNonNull(allocationResult.getUUID(), "UUID must not be null");
Invocation.Builder target = restClient
.target(allocatorServletURI)
.queryParam("operation", "erase")
.queryParam("uuid", allocationResult.getUUID())
.request();
try (Response response = retryPolicy.retryTillHttpOk(() -> target.get())) {
return EraseResult.successful(allocationResult.getUUID());
}
}
public ReleaseResult release(AllocationResult allocationResult) throws DBAllocatorException {
Objects.requireNonNull(allocationResult, "Previous allocation result must not be null");
Objects.requireNonNull(allocationResult.getUUID(), "UUID must not be null");
Invocation.Builder target = restClient
.target(allocatorServletURI)
.queryParam("operation", "dealloc")
.queryParam("uuid", allocationResult.getUUID())
.request();
try (Response response = retryPolicy.retryTillHttpOk(() -> target.get())) {
return ReleaseResult.successful(allocationResult.getUUID());
}
}
}

View file

@ -1,81 +0,0 @@
package org.keycloak.testsuite.dballocator.client.data;
import java.util.Properties;
public class AllocationResult {
private final String uuid;
private final String driver;
private final String database;
private final String user;
private final String password;
private final String url;
private AllocationResult(String uuid) {
this.uuid = uuid;
this.driver = null;
this.database = null;
this.user = null;
this.password = null;
this.url = null;
}
private AllocationResult(String uuid, String driver, String database, String user, String password, String url) {
this.uuid = uuid;
this.driver = driver;
this.database = database;
this.user = user;
this.password = password;
this.url = url;
}
public static AllocationResult forRelease(String uuid) {
return new AllocationResult(uuid);
}
public static AllocationResult successful(Properties properties) {
return new AllocationResult(
properties.getProperty("uuid"),
properties.getProperty("db.jdbc_class"),
properties.getProperty("db.name"),
properties.getProperty("db.username"),
properties.getProperty("db.password"),
properties.getProperty("db.jdbc_url"));
}
public String getDriver() {
return driver;
}
public String getDatabase() {
return database;
}
public String getUser() {
return user;
}
public String getPassword() {
return password;
}
public String getURL() {
return url;
}
public String getUUID() {
return uuid;
}
@Override
public String toString() {
return "AllocationResult{" +
"uuid='" + uuid + '\'' +
", driver='" + driver + '\'' +
", database='" + database + '\'' +
", user='" + user + '\'' +
", password='" + password + '\'' +
", url='" + url + '\'' +
'}';
}
}

View file

@ -1,45 +0,0 @@
/*
* Copyright 2017 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.testsuite.dballocator.client.data;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class EraseResult {
private final String uuid;
private EraseResult(String uuid) {
this.uuid = uuid;
}
public static EraseResult successful(String uuid) {
return new EraseResult(uuid);
}
public String getUUID() {
return uuid;
}
@Override
public String toString() {
return "EraseResult{" +
"uuid='" + uuid + '\'' +
'}';
}
}

View file

@ -1,25 +0,0 @@
package org.keycloak.testsuite.dballocator.client.data;
public class ReleaseResult {
private final String uuid;
private ReleaseResult(String uuid) {
this.uuid = uuid;
}
public static ReleaseResult successful(String uuid) {
return new ReleaseResult(uuid);
}
public String getUUID() {
return uuid;
}
@Override
public String toString() {
return "ReleaseResult{" +
"uuid='" + uuid + '\'' +
'}';
}
}

View file

@ -1,25 +0,0 @@
package org.keycloak.testsuite.dballocator.client.exceptions;
import jakarta.ws.rs.core.Response;
public class DBAllocatorException extends Exception {
private Response errorResponse;
public DBAllocatorException(Response errorResponse) {
this.errorResponse = errorResponse;
}
public DBAllocatorException(Response errorResponse, Throwable throwable) {
super(throwable);
this.errorResponse = errorResponse;
}
public DBAllocatorException(Throwable throwable) {
super(throwable);
}
public Response getErrorResponse() {
return errorResponse;
}
}

View file

@ -1,11 +0,0 @@
package org.keycloak.testsuite.dballocator.client.exceptions;
import jakarta.ws.rs.core.Response;
public class DBAllocatorUnavailableException extends DBAllocatorException {
public DBAllocatorUnavailableException(Response errorResponse) {
super(errorResponse);
}
}

View file

@ -1,65 +0,0 @@
package org.keycloak.testsuite.dballocator.client.retry;
import org.keycloak.testsuite.dballocator.client.BackoffRetryPolicy;
import org.keycloak.testsuite.dballocator.client.exceptions.DBAllocatorUnavailableException;
import jakarta.ws.rs.core.Response;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
import org.jboss.logging.Logger;
public class IncrementalBackoffRetryPolicy implements BackoffRetryPolicy {
public static final int DEFAULT_TOTAL_RETRIES = 3;
public static final int DEFAULT_BACKOFF_TIME = 10;
public static final TimeUnit DEFAULT_BACKOFF_TIME_UNIT = TimeUnit.SECONDS;
private final int totalRetries;
private final int backoffTime;
private final TimeUnit backoffTimeUnit;
private final Logger logger = Logger.getLogger(IncrementalBackoffRetryPolicy.class);
public IncrementalBackoffRetryPolicy() {
this(DEFAULT_TOTAL_RETRIES, DEFAULT_BACKOFF_TIME, DEFAULT_BACKOFF_TIME_UNIT);
}
public IncrementalBackoffRetryPolicy(int totalRetries, int backoffTime, TimeUnit backoffTimeUnit) {
this.backoffTime = backoffTime;
this.backoffTimeUnit = backoffTimeUnit;
this.totalRetries = totalRetries;
}
@Override
public Response retryTillHttpOk(Callable<Response> callableSupplier) throws DBAllocatorUnavailableException {
return retryTillHttpOk(callableSupplier, totalRetries, backoffTime, backoffTimeUnit);
}
private Response retryTillHttpOk(Callable<Response> callableSupplier, int totalRetries, int backoffTime, TimeUnit backoffTimeUnit) throws DBAllocatorUnavailableException {
int retryCount = 0;
Response response;
while(true) {
try {
response = callableSupplier.call();
} catch (Exception e) {
response = null;
}
if (response != null) {
logger.info("Response status: " + response.getStatus());
if (response.getStatus() == 200) {
return response;
}
}
logger.info("retryCount: " + (retryCount + 1) + ", totalRetries: " + totalRetries);
if (++retryCount > totalRetries) {
logger.info("retryCount exceeded: " + retryCount);
throw new DBAllocatorUnavailableException(response);
}
logger.info("backoffTime * retryCount: " + backoffTime * retryCount);
LockSupport.parkNanos(backoffTimeUnit.toNanos(backoffTime * retryCount));
}
}
}

View file

@ -1,71 +0,0 @@
package org.keycloak.testsuite.dballocator.client;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.testsuite.dballocator.client.data.AllocationResult;
import org.keycloak.testsuite.dballocator.client.data.EraseResult;
import org.keycloak.testsuite.dballocator.client.data.ReleaseResult;
import org.keycloak.testsuite.dballocator.client.exceptions.DBAllocatorException;
import org.keycloak.testsuite.dballocator.client.exceptions.DBAllocatorUnavailableException;
import org.keycloak.testsuite.dballocator.client.mock.MockResponse;
import jakarta.ws.rs.core.Response;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.concurrent.TimeUnit;
public class DBAllocatorServiceClientTest {
@Test
public void testSuccessfulAllocation() throws Exception {
//given
String mockURI = "http://localhost:8080/test";
String testProperties = null;
try(InputStream is = DBAllocatorServiceClientTest.class.getResourceAsStream("/db-allocator-response.properties")) {
testProperties = IOUtils.toString(is, Charset.defaultCharset());
}
Response successfulResponse = new MockResponse(200, testProperties);
BackoffRetryPolicy retryPolicyMock = callableSupplier -> successfulResponse;
DBAllocatorServiceClient client = new DBAllocatorServiceClient(mockURI, retryPolicyMock);
//when
AllocationResult allocationResult = client.allocate("user", "mariadb_galera_101", 1440, TimeUnit.SECONDS, "geo_RDU");
//then
Assert.assertEquals("d328bb0e-3dcc-42da-8ce1-83738a8dfede", allocationResult.getUUID());
Assert.assertEquals("org.mariadb.jdbc.Driver", allocationResult.getDriver());
Assert.assertEquals("dbname", allocationResult.getDatabase());
Assert.assertEquals("username", allocationResult.getUser());
Assert.assertEquals("password", allocationResult.getPassword());
Assert.assertEquals("jdbc:mariadb://mariadb-101-galera.keycloak.org:3306", allocationResult.getURL());
EraseResult erase = client.erase(allocationResult);
ReleaseResult result = client.release(allocationResult);
}
@Test
public void testFailureAllocation() throws Exception {
//given
String mockURI = "http://localhost:8080/test";
Response serverErrorResponse = new MockResponse(500, null);
BackoffRetryPolicy retryPolicyMock = callableSupplier -> {
throw new DBAllocatorUnavailableException(serverErrorResponse);
};
DBAllocatorServiceClient client = new DBAllocatorServiceClient(mockURI, retryPolicyMock);
//when
try {
client.allocate("user", "mariadb_galera_101", 1440, TimeUnit.SECONDS, "geo_RDU");
Assert.fail();
} catch (DBAllocatorException e) {
Assert.assertEquals(500, e.getErrorResponse().getStatus());
}
}
}

View file

@ -1,158 +0,0 @@
package org.keycloak.testsuite.dballocator.client.mock;
import jakarta.ws.rs.core.EntityTag;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.core.Link;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.MultivaluedMap;
import jakarta.ws.rs.core.NewCookie;
import jakarta.ws.rs.core.Response;
import java.lang.annotation.Annotation;
import java.net.URI;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
public class MockResponse extends Response {
private final int status;
private final String entity;
public MockResponse(int status, String entity) {
this.status = status;
this.entity = entity;
}
@Override
public int getStatus() {
return status;
}
@Override
public StatusType getStatusInfo() {
throw new UnsupportedOperationException();
}
@Override
public Object getEntity() {
return entity;
}
@Override
public <T> T readEntity(Class<T> aClass) {
if (aClass.isAssignableFrom(String.class)) {
return (T) entity;
}
throw new UnsupportedOperationException();
}
@Override
public <T> T readEntity(GenericType<T> genericType) {
throw new UnsupportedOperationException();
}
@Override
public <T> T readEntity(Class<T> aClass, Annotation[] annotations) {
throw new UnsupportedOperationException();
}
@Override
public <T> T readEntity(GenericType<T> genericType, Annotation[] annotations) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasEntity() {
throw new UnsupportedOperationException();
}
@Override
public boolean bufferEntity() {
throw new UnsupportedOperationException();
}
@Override
public void close() {
}
@Override
public MediaType getMediaType() {
throw new UnsupportedOperationException();
}
@Override
public Locale getLanguage() {
throw new UnsupportedOperationException();
}
@Override
public int getLength() {
throw new UnsupportedOperationException();
}
@Override
public Set<String> getAllowedMethods() {
throw new UnsupportedOperationException();
}
@Override
public Map<String, NewCookie> getCookies() {
throw new UnsupportedOperationException();
}
@Override
public EntityTag getEntityTag() {
throw new UnsupportedOperationException();
}
@Override
public Date getDate() {
throw new UnsupportedOperationException();
}
@Override
public Date getLastModified() {
throw new UnsupportedOperationException();
}
@Override
public URI getLocation() {
throw new UnsupportedOperationException();
}
@Override
public Set<Link> getLinks() {
throw new UnsupportedOperationException();
}
@Override
public boolean hasLink(String s) {
throw new UnsupportedOperationException();
}
@Override
public Link getLink(String s) {
throw new UnsupportedOperationException();
}
@Override
public Link.Builder getLinkBuilder(String s) {
throw new UnsupportedOperationException();
}
@Override
public MultivaluedMap<String, Object> getMetadata() {
throw new UnsupportedOperationException();
}
@Override
public MultivaluedMap<String, String> getStringHeaders() {
throw new UnsupportedOperationException();
}
@Override
public String getHeaderString(String s) {
throw new UnsupportedOperationException();
}
}

View file

@ -1,68 +0,0 @@
package org.keycloak.testsuite.dballocator.client.retry;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.testsuite.dballocator.client.exceptions.DBAllocatorUnavailableException;
import org.keycloak.testsuite.dballocator.client.retry.IncrementalBackoffRetryPolicy;
import jakarta.ws.rs.core.Response;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
public class IncrementalBackoffRetryPolicyTest {
static class BackoffCounter implements Callable<Response> {
LongAdder adder = new LongAdder();
Response responseToReport;
public BackoffCounter(Response responseToReport) {
this.responseToReport = responseToReport;
}
@Override
public Response call() throws Exception {
adder.add(1);
return responseToReport;
}
public Long getCounter() {
return adder.longValue();
}
}
@Test
public void testBackoffLoop() {
//given
long expectedNumberOfRetries = 2;
long expectedNumberOfInvocations = expectedNumberOfRetries + 1;
BackoffCounter counter = new BackoffCounter(Response.serverError().build());
IncrementalBackoffRetryPolicy backoffRetryPolicy = new IncrementalBackoffRetryPolicy((int) expectedNumberOfRetries, 0, TimeUnit.NANOSECONDS);
//when
try {
backoffRetryPolicy.retryTillHttpOk(counter);
Assert.fail();
} catch (DBAllocatorUnavailableException e) {
//then
Assert.assertEquals(expectedNumberOfInvocations, counter.getCounter().longValue());
}
}
@Test
public void testIgnoringBackoffWhenGettingSuccessfulResponse() throws Exception {
//given
BackoffCounter counter = new BackoffCounter(Response.ok().build());
IncrementalBackoffRetryPolicy backoffRetryPolicy = new IncrementalBackoffRetryPolicy(3, 0, TimeUnit.NANOSECONDS);
//when
Response response = backoffRetryPolicy.retryTillHttpOk(counter);
//then
Assert.assertEquals(1, counter.getCounter().longValue());
Assert.assertEquals(200, response.getStatus());
}
}

View file

@ -1,25 +0,0 @@
#Generated by DBAllocator
#Mon Mar 18 12:49:24 UTC 2019
db.password=password
hibernate.connection.password=password
hibernate41.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
broken=false
db.username=username
server_geo=RDU
dballoc.db_type=clustered
db.name=dbname
db.jdbc_url=jdbc\:mariadb\://mariadb-101-galera.keycloak.org\:3306
datasource.class.xa=org.mariadb.jdbc.MySQLDataSource
server_uid=RDU_mariadb_galera_101
hibernate33.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.connection.username=username
server_labels=mariadb_galera_101
db.jdbc_class=org.mariadb.jdbc.Driver
db.schema=dballo01
hibernate.connection.driver_class=org.mariadb.jdbc.Driver
uuid=d328bb0e-3dcc-42da-8ce1-83738a8dfede
db.primary_label=mariadb_galera_101
server_label_primary=mariadb_galera_101
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.connection.url=jdbc\:mariadb\://mariadb-101-galera-01.keycloak.org\:3306
hibernate.connection.schema=dballo01

View file

@ -1,5 +0,0 @@
log4j.rootLogger=info, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %t [%c] %m%n

View file

@ -77,8 +77,6 @@
<jdbc.mvn.version>${h2.version}</jdbc.mvn.version> <jdbc.mvn.version>${h2.version}</jdbc.mvn.version>
<keycloak.connectionsJpa.schema>DEFAULT</keycloak.connectionsJpa.schema> <keycloak.connectionsJpa.schema>DEFAULT</keycloak.connectionsJpa.schema>
<dballocator.skip>true</dballocator.skip>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
@ -235,18 +233,6 @@
<build> <build>
<pluginManagement> <pluginManagement>
<plugins> <plugins>
<plugin>
<groupId>org.keycloak</groupId>
<artifactId>db-allocator-plugin</artifactId>
<version>${project.version}</version>
<configuration>
<propertyDatabase>keycloak.connectionsJpa.database</propertyDatabase>
<propertyDriver>keycloak.connectionsJpa.driver</propertyDriver>
<propertyURL>keycloak.connectionsJpa.url</propertyURL>
<propertyUser>keycloak.connectionsJpa.user</propertyUser>
<propertyPassword>keycloak.connectionsJpa.password</propertyPassword>
</configuration>
</plugin>
<plugin> <plugin>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<configuration> <configuration>
@ -326,28 +312,6 @@
</modules> </modules>
<profiles> <profiles>
<profile>
<id>jpa</id>
<build>
<plugins>
<!-- Just allocate the DB now. It will be released after the tests, so the "release" is declared in the base-tests module -->
<plugin>
<groupId>org.keycloak</groupId>
<artifactId>db-allocator-plugin</artifactId>
<inherited>false</inherited>
<executions>
<execution>
<id>allocate-db</id>
<goals>
<goal>allocate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile> <profile>
<id>test-70-migration</id> <id>test-70-migration</id>
<properties> <properties>
@ -429,13 +393,11 @@
</build> </build>
</profile> </profile>
<!-- Specifies default DB properties, which are used for test with embedded H2. Those are overriden when testing with any docker container <!-- Specifies default DB properties, which are used for test with embedded H2. Those are overriden when testing with any docker container
profile like "db-mysql" or any dballocator profile. Also those can be manually overriden when running the test from CMD --> profile like "db-mysql". Also those can be manually overriden when running the test from CMD -->
<profile> <profile>
<id>db-default-properties</id> <id>db-default-properties</id>
<activation> <activation>
<property> <activeByDefault>true</activeByDefault>
<name>!dballocator.uri</name>
</property>
</activation> </activation>
<properties> <properties>
<keycloak.connectionsJpa.driver>org.h2.Driver</keycloak.connectionsJpa.driver> <keycloak.connectionsJpa.driver>org.h2.Driver</keycloak.connectionsJpa.driver>
@ -468,14 +430,6 @@
<docker.database.wait-for-log-regex>(?si)Ready for start up.*ready [^\n]{0,30}connections</docker.database.wait-for-log-regex> <docker.database.wait-for-log-regex>(?si)Ready for start up.*ready [^\n]{0,30}connections</docker.database.wait-for-log-regex>
</properties> </properties>
</profile> </profile>
<profile>
<id>db-allocator-db-mysql</id>
<properties>
<keycloak.storage.connections.vendor>mysql</keycloak.storage.connections.vendor>
<dballocator.type>mysql80</dballocator.type>
<dballocator.skip>false</dballocator.skip>
</properties>
</profile>
<profile> <profile>
<id>db-postgres</id> <id>db-postgres</id>
<properties> <properties>
@ -516,22 +470,6 @@
<jdbc.mvn.version>${aws-jdbc-wrapper.version}</jdbc.mvn.version> <jdbc.mvn.version>${aws-jdbc-wrapper.version}</jdbc.mvn.version>
</properties> </properties>
</profile> </profile>
<profile>
<id>db-allocator-db-postgres</id>
<properties>
<keycloak.storage.connections.vendor>postgres</keycloak.storage.connections.vendor>
<dballocator.type>postgresql132</dballocator.type>
<dballocator.skip>false</dballocator.skip>
</properties>
</profile>
<profile>
<id>db-allocator-db-postgresplus</id>
<properties>
<keycloak.storage.connections.vendor>postgres</keycloak.storage.connections.vendor>
<dballocator.type>postgresplus131</dballocator.type>
<dballocator.skip>false</dballocator.skip>
</properties>
</profile>
<profile> <profile>
<id>db-mariadb</id> <id>db-mariadb</id>
<properties> <properties>
@ -555,14 +493,6 @@
<docker.database.wait-for-log-regex>(?si)Ready for start up.*ready [^\n]{0,30}connections</docker.database.wait-for-log-regex> <docker.database.wait-for-log-regex>(?si)Ready for start up.*ready [^\n]{0,30}connections</docker.database.wait-for-log-regex>
</properties> </properties>
</profile> </profile>
<profile>
<id>db-allocator-db-mariadb</id>
<properties>
<keycloak.storage.connections.vendor>mariadb</keycloak.storage.connections.vendor>
<dballocator.type>mariadb_galera_103</dballocator.type>
<dballocator.skip>false</dballocator.skip>
</properties>
</profile>
<profile> <profile>
<id>db-mssql</id> <id>db-mssql</id>
<properties> <properties>
@ -586,14 +516,6 @@
<jdbc.mvn.version>${mssql-jdbc.version}</jdbc.mvn.version> <jdbc.mvn.version>${mssql-jdbc.version}</jdbc.mvn.version>
</properties> </properties>
</profile> </profile>
<profile>
<id>db-allocator-db-mssql2019</id>
<properties>
<keycloak.storage.connections.vendor>mssql</keycloak.storage.connections.vendor>
<dballocator.type>mssql2019</dballocator.type>
<dballocator.skip>false</dballocator.skip>
</properties>
</profile>
<profile> <profile>
<id>db-oracle</id> <id>db-oracle</id>
<properties> <properties>
@ -619,14 +541,6 @@
<jdbc.mvn.version>${oracle-jdbc.version}</jdbc.mvn.version> <jdbc.mvn.version>${oracle-jdbc.version}</jdbc.mvn.version>
</properties> </properties>
</profile> </profile>
<profile>
<id>db-allocator-db-oracleRAC</id>
<properties>
<keycloak.storage.connections.vendor>oracle</keycloak.storage.connections.vendor>
<dballocator.type>oracle19cRAC</dballocator.type>
<dballocator.skip>false</dballocator.skip>
</properties>
</profile>
</profiles> </profiles>
</project> </project>

View file

@ -454,27 +454,6 @@
</build> </build>
<profiles> <profiles>
<profile>
<id>jpa</id>
<build>
<plugins>
<!-- DB will be released after the test -->
<plugin>
<groupId>org.keycloak</groupId>
<artifactId>db-allocator-plugin</artifactId>
<inherited>false</inherited>
<executions>
<execution>
<id>release-db</id>
<goals>
<goal>release</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile> <profile>
<id>app-server-wildfly</id> <id>app-server-wildfly</id>

View file

@ -50,7 +50,6 @@
</plugins> </plugins>
</build> </build>
<modules> <modules>
<module>db-allocator-plugin</module>
<module>integration-arquillian</module> <module>integration-arquillian</module>
<module>model</module> <module>model</module>
<module>utils</module> <module>utils</module>