KEYCLOAK-5586 Add support for testing cross dc tests on jboss-based containers

This commit is contained in:
vramik 2017-09-21 15:01:01 +02:00
parent da72968085
commit f806d4a5d6
16 changed files with 779 additions and 188 deletions

View file

@ -446,19 +446,19 @@ and argument: `-p 8181`
## Cross-DC tests ## Cross-DC tests
Cross-DC tests use 2 data centers, each with one automatically started and one manually controlled backend servers Cross-DC tests use 2 data centers, each with one automatically started and one manually controlled backend servers,
(currently only Keycloak on Undertow), and 1 frontend loadbalancer server node that sits in front of all servers. and 1 frontend loadbalancer server node that sits in front of all servers.
The browser usually communicates directly with the frontent node and the test controls where the HTTP requests The browser usually communicates directly with the frontent node and the test controls where the HTTP requests
land by adjusting load balancer configuration (e.g. to direct the traffic to only a single DC). land by adjusting load balancer configuration (e.g. to direct the traffic to only a single DC).
For an example of a test, see [org.keycloak.testsuite.crossdc.ActionTokenCrossDCTest](tests/base/src/test/java/org/keycloak/testsuite/crossdc/ActionTokenCrossDCTest.java). For an example of a test, see [org.keycloak.testsuite.crossdc.ActionTokenCrossDCTest](tests/base/src/test/java/org/keycloak/testsuite/crossdc/ActionTokenCrossDCTest.java).
The cross DC requires setting a profile specifying used cache server (currently only Infinispan) by specifying The cross DC requires setting a profile specifying used cache server by specifying
`cache-server-infinispan` profile in maven. `cache-server-infinispan` or `cache-server-jdg` profile in maven.
#### Run Cross-DC Tests from Maven #### Run Cross-DC Tests from Maven
First compile the Infinispan/JDG test server via the following command: a) First compile the Infinispan/JDG test server via the following command:
`mvn -Pcache-server-infinispan -f testsuite/integration-arquillian -DskipTests clean install` `mvn -Pcache-server-infinispan -f testsuite/integration-arquillian -DskipTests clean install`
@ -466,14 +466,30 @@ or
`mvn -Pcache-server-jdg -f testsuite/integration-arquillian -DskipTests clean install` `mvn -Pcache-server-jdg -f testsuite/integration-arquillian -DskipTests clean install`
Then you can run the tests using the following command (adjust the test specification according to your needs): b) Then in case you want to use **JBoss-based** containers instead of containers on Embedded Undertow run following command:
`mvn -Pcache-server-infinispan -Dtest=*.crossdc.* -pl testsuite/integration-arquillian/tests/base test` `mvn -Pauth-servers-crossdc-jboss,auth-server-wildfly -f testsuite/integration-arquillian -DskipTests clean install`
*note: 'auth-server-wildfly' can be replaced by 'auth-server-eap'*
c1) Then you can run the tests using the following command (adjust the test specification according to your needs) for containers on **Undertow**:
`mvn -Pcache-server-infinispan,auth-servers-crossdc-undertow -Dtest=*.crossdc.* -pl testsuite/integration-arquillian/tests/base clean install`
or or
`mvn -Pcache-server-jdg -Dtest=*.crossdc.* -pl testsuite/integration-arquillian/tests/base test` `mvn -Pcache-server-jdg,auth-servers-crossdc-undertow -Dtest=*.crossdc.* -pl testsuite/integration-arquillian/tests/base clean install`
c2) For **JBoss-based** containers:
`mvn -Pcache-server-infinispan,auth-servers-crossdc-jboss,auth-server-wildfly -Dtest=*.crossdc.* -pl testsuite/integration-arquillian/tests/base clean install`
or
`mvn -Pcache-server-jdg,auth-servers-crossdc-jboss,auth-server-wildfly -Dtest=*.crossdc.* -pl testsuite/integration-arquillian/tests/base clean install`
*note: 'auth-server-wildfly can be replaced by auth-server-eap'*
It can be useful to add additional system property to enable logging: It can be useful to add additional system property to enable logging:
-Dkeycloak.infinispan.logging.level=debug -Dkeycloak.infinispan.logging.level=debug

View file

@ -45,7 +45,7 @@
<selenium.version>3.5.3</selenium.version> <selenium.version>3.5.3</selenium.version>
<arquillian-drone.version>2.4.2</arquillian-drone.version> <arquillian-drone.version>2.4.2</arquillian-drone.version>
<arquillian-graphene.version>2.3.1</arquillian-graphene.version> <arquillian-graphene.version>2.3.1</arquillian-graphene.version>
<arquillian-wildfly-container.version>2.1.0.Beta1</arquillian-wildfly-container.version> <arquillian-wildfly-container.version>2.1.0.Final</arquillian-wildfly-container.version>
<arquillian-wls-container.version>1.0.1.Final</arquillian-wls-container.version> <arquillian-wls-container.version>1.0.1.Final</arquillian-wls-container.version>
<arquillian-infinispan-container.version>1.2.0.Beta2</arquillian-infinispan-container.version> <arquillian-infinispan-container.version>1.2.0.Beta2</arquillian-infinispan-container.version>
<version.shrinkwrap.resolvers>2.2.6</version.shrinkwrap.resolvers> <version.shrinkwrap.resolvers>2.2.6</version.shrinkwrap.resolvers>
@ -56,7 +56,7 @@
<migration.70.version>1.9.8.Final</migration.70.version> <migration.70.version>1.9.8.Final</migration.70.version>
<migration.70.authz.version>2.2.1.Final</migration.70.authz.version> <migration.70.authz.version>2.2.1.Final</migration.70.authz.version>
<migration.71.version>2.5.5.Final</migration.71.version> <migration.71.version>2.5.5.Final</migration.71.version>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
</properties> </properties>

View file

@ -0,0 +1,129 @@
embed-server --server-config=standalone-ha.xml
echo **** Begin ****
echo *** Update jgoups subsystem ***
/subsystem=jgroups/stack=udp/transport=UDP:write-attribute(name=site, value=${jboss.site.name})
echo *** Update infinispan subsystem ***
/subsystem=infinispan/cache-container=keycloak:write-attribute(name=module, value=org.keycloak.keycloak-model-infinispan)
echo ** Update replicated-cache work element **
/subsystem=infinispan/cache-container=keycloak/replicated-cache=work/store=custom:add( \
class=org.keycloak.models.sessions.infinispan.remotestore.KeycloakRemoteStoreConfigurationBuilder, \
passivation=false, \
fetch-state=false, \
purge=false, \
preload=false, \
shared=true \
)
/subsystem=infinispan/cache-container=keycloak/replicated-cache=work/store=custom:write-attribute( \
name=properties, value={ \
rawValues=true, \
marshaller=org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory, \
transportFactory=org.keycloak.models.sessions.infinispan.remotestore.KeycloakTcpTransportFactory, \
remoteServers=localhost:${remote.cache.port}, \
remoteCacheName=work, \
sessionCache=false \
} \
)
/subsystem=infinispan/cache-container=keycloak/replicated-cache=work:write-attribute(name=statistics-enabled,value=true)
echo ** Update distributed-cache sessions element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions/store=custom:add( \
class=org.keycloak.models.sessions.infinispan.remotestore.KeycloakRemoteStoreConfigurationBuilder, \
passivation=false, \
fetch-state=false, \
purge=false, \
preload=false, \
shared=true \
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions/store=custom:write-attribute( \
name=properties, value={ \
remoteCacheName=sessions, \
useConfigTemplateFromCache=work, \
sessionCache=true \
} \
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:write-attribute(name=statistics-enabled,value=true)
echo ** Update distributed-cache offlineSessions element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions/store=custom:add( \
class=org.keycloak.models.sessions.infinispan.remotestore.KeycloakRemoteStoreConfigurationBuilder, \
passivation=false, \
fetch-state=false, \
purge=false, \
preload=false, \
shared=true \
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions/store=custom:write-attribute( \
name=properties, value={ \
remoteCacheName=offlineSessions, \
useConfigTemplateFromCache=work, \
sessionCache=true \
} \
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:write-attribute(name=statistics-enabled,value=true)
echo ** Update distributed-cache loginFailures element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures/store=custom:add( \
class=org.keycloak.models.sessions.infinispan.remotestore.KeycloakRemoteStoreConfigurationBuilder, \
passivation=false, \
fetch-state=false, \
purge=false, \
preload=false, \
shared=true \
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures/store=custom:write-attribute( \
name=properties, value={ \
remoteCacheName=loginFailures, \
useConfigTemplateFromCache=work, \
sessionCache=true \
} \
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:write-attribute(name=statistics-enabled,value=true)
echo ** Update distributed-cache actionTokens element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens/store=custom:add( \
class=org.keycloak.models.sessions.infinispan.remotestore.KeycloakRemoteStoreConfigurationBuilder, \
passivation=false, \
fetch-state=false, \
purge=false, \
preload=true, \
shared=true \
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens/store=custom:write-attribute( \
name=properties, value={ \
remoteCacheName=actionTokens, \
useConfigTemplateFromCache=work, \
sessionCache=false \
} \
)
/subsystem=infinispan/cache-container=keycloak/distributed-cache=actionTokens:write-attribute(name=statistics-enabled,value=true)
echo ** Update distributed-cache authenticationSessions element **
/subsystem=infinispan/cache-container=keycloak/distributed-cache=authenticationSessions:write-attribute(name=statistics-enabled,value=true)
echo *** Enable debug logging ***
/subsystem=logging/logger=org.keycloak.cluster.infinispan:add(level=DEBUG)
/subsystem=logging/logger=org.keycloak.connections.infinispan:add(level=DEBUG)
/subsystem=logging/logger=org.keycloak.models.cache.infinispan:add(level=DEBUG)
/subsystem=logging/logger=org.keycloak.models.sessions.infinispan:add(level=DEBUG)
echo *** Update undertow subsystem ***
/subsystem=undertow/server=default-server/http-listener=default:write-attribute(name=proxy-address-forwarding,value=true)
echo **** End ****

View file

@ -26,11 +26,11 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging> <packaging>pom</packaging>
<artifactId>integration-arquillian-servers-auth-server-eap</artifactId> <artifactId>integration-arquillian-servers-auth-server-eap</artifactId>
<name>Auth Server - JBoss - EAP</name> <name>Auth Server - JBoss - EAP</name>
<properties> <properties>
<auth.server.jboss>eap</auth.server.jboss> <auth.server.jboss>eap</auth.server.jboss>
<auth.server.home>${project.build.directory}/unpacked/${product.unpacked.folder.name}</auth.server.home> <auth.server.home>${project.build.directory}/unpacked/${product.unpacked.folder.name}</auth.server.home>
@ -57,6 +57,7 @@
<goal>enforce</goal> <goal>enforce</goal>
</goals> </goals>
<configuration> <configuration>
<skip>false</skip>
<rules> <rules>
<requireProperty> <requireProperty>
<property>product.version</property> <property>product.version</property>
@ -71,5 +72,5 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View file

@ -191,6 +191,7 @@
<dir>${auth.server.home}/standalone/configuration</dir> <dir>${auth.server.home}/standalone/configuration</dir>
<includes> <includes>
<include>standalone.xml</include> <include>standalone.xml</include>
<include>standalone-ha.xml</include>
</includes> </includes>
<stylesheet>${common.resources}/keycloak-server-subsystem.xsl</stylesheet> <stylesheet>${common.resources}/keycloak-server-subsystem.xsl</stylesheet>
<outputDir>${auth.server.home}/standalone/configuration</outputDir> <outputDir>${auth.server.home}/standalone/configuration</outputDir>
@ -575,6 +576,119 @@
</pluginManagement> </pluginManagement>
</build> </build>
</profile> </profile>
<profile>
<id>auth-servers-crossdc-jboss</id>
<properties>
<crossdc.jboss.jdbc.url>jdbc:h2:tcp://localhost:9092/mem:keycloak-dc-shared;DB_CLOSE_DELAY=-1</crossdc.jboss.jdbc.url>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-profile-activation</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>auth.server.jboss</property>
<message>Profile "auth-servers-crossdc-jboss" requires activation of another profile: either "auth-server-wildfly" or "auth-server-eap".</message>
<regex>(wildfly|eap)</regex>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>xml-maven-plugin</artifactId>
<executions>
<execution>
<id>jpa-h2-tcp</id>
<phase>process-resources</phase>
<goals>
<goal>transform</goal>
</goals>
<configuration>
<transformationSets>
<transformationSet>
<dir>${auth.server.home}/standalone/configuration</dir>
<includes>
<include>standalone-ha.xml</include>
</includes>
<stylesheet>${common.resources}/datasource-jdbc-url.xsl</stylesheet>
<outputDir>${auth.server.home}/standalone/configuration</outputDir>
<parameters>
<parameter>
<name>pool.name</name>
<value>KeycloakDS</value>
</parameter>
<parameter>
<name>jdbc.url</name>
<value>${crossdc.jboss.jdbc.url}</value>
</parameter>
</parameters>
</transformationSet>
</transformationSets>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>crossdc-setup</id>
<phase>process-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${auth.server.home}/bin/jboss-cli.sh</executable>
<arguments>
<argument>--file=${common.resources}/crossdc/cross-dc-setup.cli</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>remove-temp-data-crossdc-setup</id>
<phase>process-resources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<workingDirectory>${auth.server.home}/standalone/</workingDirectory>
<executable>rm</executable>
<arguments>
<argument>-rf</argument>
<argument>data</argument>
<argument>log</argument>
<argument>tmp</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
<profile> <profile>
<id>auth-server-cluster</id> <id>auth-server-cluster</id>
<properties> <properties>

View file

@ -26,9 +26,9 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging> <packaging>pom</packaging>
<artifactId>integration-arquillian-servers-auth-server-wildfly</artifactId> <artifactId>integration-arquillian-servers-auth-server-wildfly</artifactId>
<name>Auth Server - JBoss - Wildfly</name> <name>Auth Server - JBoss - Wildfly</name>
<dependencies> <dependencies>
@ -38,9 +38,20 @@
<type>zip</type> <type>zip</type>
</dependency> </dependency>
</dependencies> </dependencies>
<properties> <properties>
<auth.server.jboss>wildfly</auth.server.jboss> <auth.server.jboss>wildfly</auth.server.jboss>
</properties> </properties>
<build>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
</build>
</project> </project>

View file

@ -33,6 +33,7 @@
<module name="org.keycloak.keycloak-model-infinispan"/> <module name="org.keycloak.keycloak-model-infinispan"/>
<module name="org.keycloak.keycloak-model-jpa"/> <module name="org.keycloak.keycloak-model-jpa"/>
<module name="org.infinispan"/> <module name="org.infinispan"/>
<module name="org.infinispan.client.hotrod"/>
<module name="org.jboss.logging"/> <module name="org.jboss.logging"/>
<module name="org.jboss.resteasy.resteasy-jaxrs"/> <module name="org.jboss.resteasy.resteasy-jaxrs"/>
<module name="javax.persistence.api"/> <module name="javax.persistence.api"/>

View file

@ -94,7 +94,7 @@ public class SimpleUndertowLoadBalancer {
.build(); .build();
undertow.start(); undertow.start();
log.infof("Loadbalancer started and ready to serve requests on http://%s:%d", host, port); log.infof("#### Loadbalancer started and ready to serve requests on http://%s:%d ####", host, port);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View file

@ -135,6 +135,11 @@ public class AuthServerTestEnricher {
return managementClient; return managementClient;
} }
public void distinguishContainersInConsoleOutput(@Observes(precedence = 5) StartContainer event) {
log.info("*****************************************************************"
+ "*****************************************************************************");
}
public void initializeSuiteContext(@Observes(precedence = 2) BeforeSuite event) { public void initializeSuiteContext(@Observes(precedence = 2) BeforeSuite event) {
Set<ContainerInfo> containers = containerRegistry.get().getContainers().stream() Set<ContainerInfo> containers = containerRegistry.get().getContainers().stream()
@ -165,15 +170,16 @@ public class AuthServerTestEnricher {
} }
containers.stream() containers.stream()
.filter(c -> c.getQualifier().startsWith(AUTH_SERVER_CONTAINER + "-cross-dc-")) .filter(c -> c.getQualifier().startsWith("auth-server-" + System.getProperty("node.name") + "-"))
.sorted((a, b) -> a.getQualifier().compareTo(b.getQualifier())) .sorted((a, b) -> a.getQualifier().compareTo(b.getQualifier()))
.forEach(c -> { .forEach(c -> {
String portOffsetString = c.getArquillianContainer().getContainerConfiguration().getContainerProperties().getOrDefault("bindHttpPortOffset", "0"); String portOffsetString = c.getArquillianContainer().getContainerConfiguration().getContainerProperties().getOrDefault("bindHttpPortOffset", "0");
String dcString = c.getArquillianContainer().getContainerConfiguration().getContainerProperties().getOrDefault("dataCenter", "0"); updateWithAuthServerInfo(c, Integer.valueOf(portOffsetString));
updateWithAuthServerInfo(c, Integer.valueOf(portOffsetString));
suiteContext.addAuthServerBackendsInfo(Integer.valueOf(dcString), c);
});
String dcString = c.getArquillianContainer().getContainerConfiguration().getContainerProperties().getOrDefault("dataCenter", "0");
suiteContext.addAuthServerBackendsInfo(Integer.valueOf(dcString), c);
});
containers.stream() containers.stream()
.filter(c -> c.getQualifier().startsWith("cache-server-cross-dc-")) .filter(c -> c.getQualifier().startsWith("cache-server-cross-dc-"))
.sorted((a, b) -> a.getQualifier().compareTo(b.getQualifier())) .sorted((a, b) -> a.getQualifier().compareTo(b.getQualifier()))

View file

@ -1,23 +1,18 @@
package org.keycloak.testsuite.arquillian; package org.keycloak.testsuite.arquillian;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider; import java.io.IOException;
import org.keycloak.testsuite.Retry; import java.io.NotSerializableException;
import java.util.Map; import java.lang.management.ManagementFactory;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.MalformedURLException;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXServiceURL;
import org.jboss.arquillian.container.spi.Container;
import org.jboss.arquillian.container.spi.ContainerRegistry;
import org.jboss.arquillian.test.spi.TestEnricher;
import java.io.IOException;
import java.lang.reflect.Parameter; import java.lang.reflect.Parameter;
import java.net.MalformedURLException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.management.Attribute; import javax.management.Attribute;
import javax.management.AttributeNotFoundException; import javax.management.AttributeNotFoundException;
@ -26,21 +21,26 @@ import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo; import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException; import javax.management.MBeanException;
import javax.management.MBeanInfo; import javax.management.MBeanInfo;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException; import javax.management.ReflectionException;
import javax.management.remote.JMXServiceURL;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.jboss.arquillian.container.spi.Container;
import org.jboss.arquillian.container.spi.ContainerRegistry;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.spi.Validate;
import org.jboss.arquillian.test.spi.TestEnricher;
import org.jboss.logging.Logger;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.testsuite.Retry;
import org.keycloak.testsuite.arquillian.annotation.JmxInfinispanCacheStatistics; import org.keycloak.testsuite.arquillian.annotation.JmxInfinispanCacheStatistics;
import java.util.Set;
import org.keycloak.testsuite.arquillian.annotation.JmxInfinispanChannelStatistics; import org.keycloak.testsuite.arquillian.annotation.JmxInfinispanChannelStatistics;
import org.keycloak.testsuite.arquillian.jmx.JmxConnectorRegistry; import org.keycloak.testsuite.arquillian.jmx.JmxConnectorRegistry;
import org.keycloak.testsuite.arquillian.undertow.KeycloakOnUndertow; import org.keycloak.testsuite.arquillian.undertow.KeycloakOnUndertow;
import org.keycloak.testsuite.crossdc.DC; import org.keycloak.testsuite.crossdc.DC;
import java.io.NotSerializableException;
import java.lang.management.ManagementFactory;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.jboss.arquillian.core.spi.Validate;
import org.jboss.logging.Logger;
/** /**
* *
@ -81,8 +81,6 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
} }
private InfinispanStatistics getInfinispanCacheStatistics(JmxInfinispanCacheStatistics annotation) throws MalformedObjectNameException, IOException, MalformedURLException { private InfinispanStatistics getInfinispanCacheStatistics(JmxInfinispanCacheStatistics annotation) throws MalformedObjectNameException, IOException, MalformedURLException {
MBeanServerConnection mbsc = getJmxServerConnection(annotation);
ObjectName mbeanName = new ObjectName(String.format( ObjectName mbeanName = new ObjectName(String.format(
"%s:type=%s,name=\"%s(%s)\",manager=\"%s\",component=%s", "%s:type=%s,name=\"%s(%s)\",manager=\"%s\",component=%s",
annotation.domain().isEmpty() ? getDefaultDomain(annotation.dc().getDcIndex(), annotation.dcNodeIndex()) : InfinispanConnectionProvider.JMX_DOMAIN, annotation.domain().isEmpty() ? getDefaultDomain(annotation.dc().getDcIndex(), annotation.dcNodeIndex()) : InfinispanConnectionProvider.JMX_DOMAIN,
@ -93,7 +91,7 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
annotation.component() annotation.component()
)); ));
InfinispanStatistics value = new InfinispanCacheStatisticsImpl(mbsc, mbeanName); InfinispanStatistics value = new InfinispanCacheStatisticsImpl(getJmxServerConnection(annotation), mbeanName);
if (annotation.domain().isEmpty()) { if (annotation.domain().isEmpty()) {
try { try {
@ -101,7 +99,7 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
if (annotation.dc() != DC.UNDEFINED && annotation.dcNodeIndex() != -1 if (annotation.dc() != DC.UNDEFINED && annotation.dcNodeIndex() != -1
&& suiteContext.get().getAuthServerBackendsInfo(annotation.dc().getDcIndex()).get(annotation.dcNodeIndex()).isStarted()) { && suiteContext.get().getAuthServerBackendsInfo(annotation.dc().getDcIndex()).get(annotation.dcNodeIndex()).isStarted()) {
LOG.warn("Could not reset statistics for " + mbeanName); LOG.warn("Could not reset statistics for " + mbeanName + ". The reason is: \"" + ex.getMessage() + "\"");
} }
} }
} }
@ -110,8 +108,6 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
} }
private InfinispanStatistics getJGroupsChannelStatistics(JmxInfinispanChannelStatistics annotation) throws MalformedObjectNameException, IOException, MalformedURLException { private InfinispanStatistics getJGroupsChannelStatistics(JmxInfinispanChannelStatistics annotation) throws MalformedObjectNameException, IOException, MalformedURLException {
MBeanServerConnection mbsc = getJmxServerConnection(annotation);
ObjectName mbeanName = new ObjectName(String.format( ObjectName mbeanName = new ObjectName(String.format(
"%s:type=%s,cluster=\"%s\"", "%s:type=%s,cluster=\"%s\"",
annotation.domain().isEmpty() ? getDefaultDomain(annotation.dc().getDcIndex(), annotation.dcNodeIndex()) : InfinispanConnectionProvider.JMX_DOMAIN, annotation.domain().isEmpty() ? getDefaultDomain(annotation.dc().getDcIndex(), annotation.dcNodeIndex()) : InfinispanConnectionProvider.JMX_DOMAIN,
@ -119,7 +115,7 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
annotation.cluster() annotation.cluster()
)); ));
InfinispanStatistics value = new InfinispanChannelStatisticsImpl(mbsc, mbeanName); InfinispanStatistics value = new InfinispanChannelStatisticsImpl(getJmxServerConnection(annotation), mbeanName);
if (annotation.domain().isEmpty()) { if (annotation.domain().isEmpty()) {
try { try {
@ -127,7 +123,7 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
if (annotation.dc() != DC.UNDEFINED && annotation.dcNodeIndex() != -1 if (annotation.dc() != DC.UNDEFINED && annotation.dcNodeIndex() != -1
&& suiteContext.get().getAuthServerBackendsInfo(annotation.dc().getDcIndex()).get(annotation.dcNodeIndex()).isStarted()) { && suiteContext.get().getAuthServerBackendsInfo(annotation.dc().getDcIndex()).get(annotation.dcNodeIndex()).isStarted()) {
LOG.warn("Could not reset statistics for " + mbeanName); LOG.warn("Could not reset statistics for " + mbeanName + ". The reason is: \"" + ex.getMessage() + "\"");
} }
} }
} }
@ -162,12 +158,20 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
private String getDefaultDomain(int dcIndex, int dcNodeIndex) { private String getDefaultDomain(int dcIndex, int dcNodeIndex) {
if (dcIndex != -1 && dcNodeIndex != -1) { if (dcIndex != -1 && dcNodeIndex != -1) {
if (Boolean.parseBoolean(System.getProperty("auth.server.jboss.crossdc"))) {
//backend-jboss-server
return "org.wildfly.clustering.infinispan";
}
//backend-undertow-server
return InfinispanConnectionProvider.JMX_DOMAIN + "-" + suiteContext.get().getAuthServerBackendsInfo(dcIndex).get(dcNodeIndex).getQualifier(); return InfinispanConnectionProvider.JMX_DOMAIN + "-" + suiteContext.get().getAuthServerBackendsInfo(dcIndex).get(dcNodeIndex).getQualifier();
} }
//cache-server
return InfinispanConnectionProvider.JMX_DOMAIN; return InfinispanConnectionProvider.JMX_DOMAIN;
} }
private MBeanServerConnection getJmxServerConnection(JmxInfinispanCacheStatistics annotation) throws MalformedURLException, IOException { private Supplier<MBeanServerConnection> getJmxServerConnection(JmxInfinispanCacheStatistics annotation) throws MalformedURLException {
final String host; final String host;
final int port; final int port;
@ -175,7 +179,46 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
ContainerInfo node = suiteContext.get().getAuthServerBackendsInfo(annotation.dc().getDcIndex()).get(annotation.dcNodeIndex()); ContainerInfo node = suiteContext.get().getAuthServerBackendsInfo(annotation.dc().getDcIndex()).get(annotation.dcNodeIndex());
Container container = node.getArquillianContainer(); Container container = node.getArquillianContainer();
if (container.getDeployableContainer() instanceof KeycloakOnUndertow) { if (container.getDeployableContainer() instanceof KeycloakOnUndertow) {
return ManagementFactory.getPlatformMBeanServer(); return () -> ManagementFactory.getPlatformMBeanServer();
}
host = "localhost";
port = container.getContainerConfiguration().getContainerProperties().containsKey("managementPort")
? Integer.valueOf(container.getContainerConfiguration().getContainerProperties().get("managementPort"))
: 9990;
} else {
host = annotation.host().isEmpty()
? System.getProperty((annotation.hostProperty().isEmpty()
? "keycloak.connectionsInfinispan.remoteStoreServer"
: annotation.hostProperty()))
: annotation.host();
port = annotation.managementPort() == -1
? Integer.valueOf(System.getProperty((annotation.managementPortProperty().isEmpty()
? "cache.server.management.port"
: annotation.managementPortProperty())))
: annotation.managementPort();
}
JMXServiceURL url = new JMXServiceURL("service:jmx:remote+http://" + host + ":" + port);
return () -> {
try {
return jmxConnectorRegistry.get().getConnection(url).getMBeanServerConnection();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
};
}
private Supplier<MBeanServerConnection> getJmxServerConnection(JmxInfinispanChannelStatistics annotation) throws MalformedURLException {
final String host;
final int port;
if (annotation.dc() != DC.UNDEFINED && annotation.dcNodeIndex() != -1) {
ContainerInfo node = suiteContext.get().getAuthServerBackendsInfo(annotation.dc().getDcIndex()).get(annotation.dcNodeIndex());
Container container = node.getArquillianContainer();
if (container.getDeployableContainer() instanceof KeycloakOnUndertow) {
return () -> ManagementFactory.getPlatformMBeanServer();
} }
host = "localhost"; host = "localhost";
port = container.getContainerConfiguration().getContainerProperties().containsKey("managementPort") port = container.getContainerConfiguration().getContainerProperties().containsKey("managementPort")
@ -196,79 +239,50 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
} }
JMXServiceURL url = new JMXServiceURL("service:jmx:remote+http://" + host + ":" + port); JMXServiceURL url = new JMXServiceURL("service:jmx:remote+http://" + host + ":" + port);
JMXConnector jmxc = jmxConnectorRegistry.get().getConnection(url); return () -> {
try {
return jmxc.getMBeanServerConnection(); return jmxConnectorRegistry.get().getConnection(url).getMBeanServerConnection();
} } catch (IOException ex) {
throw new RuntimeException(ex);
private MBeanServerConnection getJmxServerConnection(JmxInfinispanChannelStatistics annotation) throws MalformedURLException, IOException {
final String host;
final int port;
if (annotation.dc() != DC.UNDEFINED && annotation.dcNodeIndex() != -1) {
ContainerInfo node = suiteContext.get().getAuthServerBackendsInfo(annotation.dc().getDcIndex()).get(annotation.dcNodeIndex());
Container container = node.getArquillianContainer();
if (container.getDeployableContainer() instanceof KeycloakOnUndertow) {
return ManagementFactory.getPlatformMBeanServer();
} }
host = "localhost"; };
port = container.getContainerConfiguration().getContainerProperties().containsKey("managementPort")
? Integer.valueOf(container.getContainerConfiguration().getContainerProperties().get("managementPort"))
: 9990;
} else {
host = annotation.host().isEmpty()
? System.getProperty((annotation.hostProperty().isEmpty()
? "keycloak.connectionsInfinispan.remoteStoreServer"
: annotation.hostProperty()))
: annotation.host();
port = annotation.managementPort() == -1
? Integer.valueOf(System.getProperty((annotation.managementPortProperty().isEmpty()
? "cache.server.management.port"
: annotation.managementPortProperty())))
: annotation.managementPort();
}
String jmxUrl = "service:jmx:remote+http://" + host + ":" + port;
LOG.infof("JMX Service URL: %s", jmxUrl);
JMXServiceURL url = new JMXServiceURL(jmxUrl);
JMXConnector jmxc = jmxConnectorRegistry.get().getConnection(url);
return jmxc.getMBeanServerConnection();
} }
private static abstract class CacheStatisticsImpl implements InfinispanStatistics { private static abstract class CacheStatisticsImpl implements InfinispanStatistics {
protected final MBeanServerConnection mbsc; private final Supplier<MBeanServerConnection> mbscCreateor;
private final ObjectName mbeanNameTemplate; private final ObjectName mbeanNameTemplate;
private ObjectName mbeanName; private ObjectName mbeanName;
public CacheStatisticsImpl(MBeanServerConnection mbsc, ObjectName mbeanNameTemplate) { public CacheStatisticsImpl(Supplier<MBeanServerConnection> mbscCreateor, ObjectName mbeanNameTemplate) {
this.mbsc = mbsc; this.mbscCreateor = mbscCreateor;
this.mbeanNameTemplate = mbeanNameTemplate; this.mbeanNameTemplate = mbeanNameTemplate;
} }
protected MBeanServerConnection getConnection() {
return mbscCreateor.get();
}
@Override @Override
public boolean exists() { public boolean exists() {
try { try {
getMbeanName(); getMbeanName();
return true; return true;
} catch (Exception ex) { } catch (IOException | RuntimeException ex) {
return false; return false;
} }
} }
@Override @Override
public Map<String, Object> getStatistics() { public Map<String, Object> getStatistics() {
try { try {
MBeanInfo mBeanInfo = mbsc.getMBeanInfo(getMbeanName()); MBeanInfo mBeanInfo = getConnection().getMBeanInfo(getMbeanName());
String[] statAttrs = Arrays.asList(mBeanInfo.getAttributes()).stream() String[] statAttrs = Arrays.asList(mBeanInfo.getAttributes()).stream()
.filter(MBeanAttributeInfo::isReadable) .filter(MBeanAttributeInfo::isReadable)
.map(MBeanAttributeInfo::getName) .map(MBeanAttributeInfo::getName)
.collect(Collectors.toList()) .collect(Collectors.toList())
.toArray(new String[] {}); .toArray(new String[] {});
return mbsc.getAttributes(getMbeanName(), statAttrs) return getConnection().getAttributes(getMbeanName(), statAttrs)
.asList() .asList()
.stream() .stream()
.collect(Collectors.toMap(Attribute::getName, Attribute::getValue)); .collect(Collectors.toMap(Attribute::getName, Attribute::getValue));
@ -279,7 +293,7 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
protected ObjectName getMbeanName() throws IOException, RuntimeException { protected ObjectName getMbeanName() throws IOException, RuntimeException {
if (this.mbeanName == null) { if (this.mbeanName == null) {
Set<ObjectName> queryNames = mbsc.queryNames(mbeanNameTemplate, null); Set<ObjectName> queryNames = getConnection().queryNames(mbeanNameTemplate, null);
if (queryNames.isEmpty()) { if (queryNames.isEmpty()) {
throw new RuntimeException("No MBean of template " + mbeanNameTemplate + " found at JMX server"); throw new RuntimeException("No MBean of template " + mbeanNameTemplate + " found at JMX server");
} }
@ -292,7 +306,7 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
@Override @Override
public Comparable getSingleStatistics(String statisticsName) { public Comparable getSingleStatistics(String statisticsName) {
try { try {
return (Comparable) mbsc.getAttribute(getMbeanName(), statisticsName); return (Comparable) getConnection().getAttribute(getMbeanName(), statisticsName);
} catch (IOException | InstanceNotFoundException | MBeanException | ReflectionException | AttributeNotFoundException ex) { } catch (IOException | InstanceNotFoundException | MBeanException | ReflectionException | AttributeNotFoundException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
@ -305,7 +319,7 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
try { try {
getMbeanName(); getMbeanName();
if (! isAvailable()) throw new RuntimeException("Not available"); if (! isAvailable()) throw new RuntimeException("Not available");
} catch (Exception ex) { } catch (IOException | RuntimeException ex) {
throw new RuntimeException("Timed out while waiting for " + mbeanNameTemplate + " to become available", ex); throw new RuntimeException("Timed out while waiting for " + mbeanNameTemplate + " to become available", ex);
} }
}, 1 + (int) timeInMillis / 100, 100); }, 1 + (int) timeInMillis / 100, 100);
@ -316,14 +330,14 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
private static class InfinispanCacheStatisticsImpl extends CacheStatisticsImpl { private static class InfinispanCacheStatisticsImpl extends CacheStatisticsImpl {
public InfinispanCacheStatisticsImpl(MBeanServerConnection mbsc, ObjectName mbeanName) { public InfinispanCacheStatisticsImpl(Supplier<MBeanServerConnection> mbscCreator, ObjectName mbeanName) {
super(mbsc, mbeanName); super(mbscCreator, mbeanName);
} }
@Override @Override
public void reset() { public void reset() {
try { try {
mbsc.invoke(getMbeanName(), "resetStatistics", new Object[] {}, new String[] {}); getConnection().invoke(getMbeanName(), "resetStatistics", new Object[] {}, new String[] {});
} catch (IOException | InstanceNotFoundException | MBeanException | ReflectionException ex) { } catch (IOException | InstanceNotFoundException | MBeanException | ReflectionException ex) {
throw new RuntimeException(ex); throw new RuntimeException(ex);
} }
@ -337,14 +351,14 @@ public class CacheStatisticsControllerEnricher implements TestEnricher {
private static class InfinispanChannelStatisticsImpl extends CacheStatisticsImpl { private static class InfinispanChannelStatisticsImpl extends CacheStatisticsImpl {
public InfinispanChannelStatisticsImpl(MBeanServerConnection mbsc, ObjectName mbeanName) { public InfinispanChannelStatisticsImpl(Supplier<MBeanServerConnection> mbscCreator, ObjectName mbeanName) {
super(mbsc, mbeanName); super(mbscCreator, mbeanName);
} }
@Override @Override
public void reset() { public void reset() {
try { try {
mbsc.invoke(getMbeanName(), "resetStats", new Object[] {}, new String[] {}); getConnection().invoke(getMbeanName(), "resetStats", new Object[] {}, new String[] {});
} catch (NotSerializableException ex) { } catch (NotSerializableException ex) {
// Ignore return value not serializable, the invocation has already done its job // Ignore return value not serializable, the invocation has already done its job
} catch (IOException | InstanceNotFoundException | MBeanException | ReflectionException ex) { } catch (IOException | InstanceNotFoundException | MBeanException | ReflectionException ex) {

View file

@ -27,6 +27,7 @@ import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
import org.jboss.arquillian.core.api.annotation.Inject; import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.annotation.Observes; import org.jboss.arquillian.core.api.annotation.Observes;
import org.jboss.arquillian.test.spi.event.suite.BeforeSuite; import org.jboss.arquillian.test.spi.event.suite.BeforeSuite;
import org.jboss.logging.Logger;
/** /**
* *
@ -34,6 +35,8 @@ import org.jboss.arquillian.test.spi.event.suite.BeforeSuite;
*/ */
public class JmxConnectorRegistryCreator { public class JmxConnectorRegistryCreator {
private final Logger log = Logger.getLogger(JmxConnectorRegistryCreator.class);
@Inject @Inject
@ApplicationScoped @ApplicationScoped
private InstanceProducer<JmxConnectorRegistry> connectorRegistry; private InstanceProducer<JmxConnectorRegistry> connectorRegistry;
@ -46,6 +49,7 @@ public class JmxConnectorRegistryCreator {
@Override @Override
public JMXConnector getConnection(JMXServiceURL url) { public JMXConnector getConnection(JMXServiceURL url) {
JMXConnector res = connectors.get(url); JMXConnector res = connectors.get(url);
if (res == null) { if (res == null) {
try { try {
@ -55,7 +59,10 @@ public class JmxConnectorRegistryCreator {
res = conn; res = conn;
} }
res.connect(); res.connect();
log.infof("Connected to JMX Service URL: %s", url);
} catch (IOException ex) { } catch (IOException ex) {
//remove conn from connectors in case something goes wrong. The connection will be established on-demand
connectors.remove(url, res);
throw new RuntimeException("Could not instantiate JMX connector for " + url, ex); throw new RuntimeException("Could not instantiate JMX connector for " + url, ex);
} }
} }

View file

@ -21,8 +21,8 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@ -58,10 +58,12 @@ import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import org.apache.http.client.CookieStore; import org.apache.http.client.CookieStore;
import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.BasicCookieStore;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import static org.hamcrest.Matchers.containsString;
/** /**
@ -126,8 +128,7 @@ public class ConcurrentLoginTest extends AbstractConcurrencyTest {
CookieStore cookieStore = new BasicCookieStore(); CookieStore cookieStore = new BasicCookieStore();
context.setCookieStore(cookieStore); context.setCookieStore(cookieStore);
HttpUriRequest request = handleLogin(getPageContent(oauth.getLoginFormUrl(), httpClient, context), userName, password); HttpUriRequest request = handleLogin(getPageContent(oauth.getLoginFormUrl(), httpClient, context), userName, password);
log.debug("Executing login request"); Assert.assertThat(parseAndCloseResponse(httpClient.execute(request, context)), containsString("<title>AUTH_RESPONSE</title>"));
Assert.assertTrue(parseAndCloseResponse(httpClient.execute(request, context)).contains("<title>AUTH_RESPONSE</title>"));
return context; return context;
} }
@ -306,12 +307,8 @@ public class ConcurrentLoginTest extends AbstractConcurrencyTest {
} }
private static Map<String, String> getQueryFromUrl(String url) throws URISyntaxException { private static Map<String, String> getQueryFromUrl(String url) throws URISyntaxException {
Map<String, String> m = new HashMap<>(); return URLEncodedUtils.parse(new URI(url), Charset.forName("UTF-8")).stream()
List<NameValuePair> pairs = URLEncodedUtils.parse(new URI(url), "UTF-8"); .collect(Collectors.toMap(p -> p.getName(), p -> p.getValue()));
for (NameValuePair p : pairs) {
m.put(p.getName(), p.getValue());
}
return m;
} }
@ -411,4 +408,4 @@ public class ConcurrentLoginTest extends AbstractConcurrencyTest {
} }
} }

View file

@ -50,6 +50,8 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
// Keep the following constants in sync with arquillian // Keep the following constants in sync with arquillian
public static final String QUALIFIER_NODE_BALANCER = "auth-server-balancer-cross-dc"; public static final String QUALIFIER_NODE_BALANCER = "auth-server-balancer-cross-dc";
public static final String QUALIFIER_JBOSS_DC_0_NODE_1 = "auth-server-jboss-cross-dc-0_1";
public static final String QUALIFIER_JBOSS_DC_1_NODE_1 = "auth-server-jboss-cross-dc-1_1";
@ArquillianResource @ArquillianResource
@LoadBalancer(value = QUALIFIER_NODE_BALANCER) @LoadBalancer(value = QUALIFIER_NODE_BALANCER)
@ -208,7 +210,7 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
/** /**
* Disables routing requests to the given data center in the load balancer. * Disables routing requests to the given data center in the load balancer.
* @param dcIndex * @param dc
*/ */
public void disableDcOnLoadBalancer(DC dc) { public void disableDcOnLoadBalancer(DC dc) {
int dcIndex = dc.ordinal(); int dcIndex = dc.ordinal();
@ -218,7 +220,7 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
/** /**
* Enables routing requests to all started nodes to the given data center in the load balancer. * Enables routing requests to all started nodes to the given data center in the load balancer.
* @param dcIndex * @param dc
*/ */
public void enableDcOnLoadBalancer(DC dc) { public void enableDcOnLoadBalancer(DC dc) {
int dcIndex = dc.ordinal(); int dcIndex = dc.ordinal();
@ -235,7 +237,7 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
/** /**
* Disables routing requests to the given node within the given data center in the load balancer. * Disables routing requests to the given node within the given data center in the load balancer.
* @param dcIndex * @param dc
* @param nodeIndex * @param nodeIndex
*/ */
public void disableLoadBalancerNode(DC dc, int nodeIndex) { public void disableLoadBalancerNode(DC dc, int nodeIndex) {
@ -246,7 +248,7 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
/** /**
* Enables routing requests to the given node within the given data center in the load balancer. * Enables routing requests to the given node within the given data center in the load balancer.
* @param dcIndex * @param dc
* @param nodeIndex * @param nodeIndex
*/ */
public void enableLoadBalancerNode(DC dc, int nodeIndex) { public void enableLoadBalancerNode(DC dc, int nodeIndex) {
@ -264,7 +266,7 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
/** /**
* Starts a manually-controlled backend auth-server node in cross-DC scenario. * Starts a manually-controlled backend auth-server node in cross-DC scenario.
* @param dcIndex * @param dc
* @param nodeIndex * @param nodeIndex
* @return Started instance descriptor. * @return Started instance descriptor.
*/ */
@ -275,6 +277,8 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
assertThat((Integer) nodeIndex, lessThan(dcNodes.size())); assertThat((Integer) nodeIndex, lessThan(dcNodes.size()));
ContainerInfo dcNode = dcNodes.get(nodeIndex); ContainerInfo dcNode = dcNodes.get(nodeIndex);
assertTrue("Node " + dcNode.getQualifier() + " has to be controlled manually", dcNode.isManual()); assertTrue("Node " + dcNode.getQualifier() + " has to be controlled manually", dcNode.isManual());
log.infof("Starting backend node: %s (dcIndex: %d, nodeIndex: %d)", dcNode.getQualifier(), dcIndex, nodeIndex);
containerController.start(dcNode.getQualifier()); containerController.start(dcNode.getQualifier());
createRESTClientsForNode(dcNode); createRESTClientsForNode(dcNode);
@ -284,7 +288,7 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
/** /**
* Stops a manually-controlled backend auth-server node in cross-DC scenario. * Stops a manually-controlled backend auth-server node in cross-DC scenario.
* @param dcIndex * @param dc
* @param nodeIndex * @param nodeIndex
* @return Stopped instance descriptor. * @return Stopped instance descriptor.
*/ */
@ -298,13 +302,15 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
removeRESTClientsForNode(dcNode); removeRESTClientsForNode(dcNode);
assertTrue("Node " + dcNode.getQualifier() + " has to be controlled manually", dcNode.isManual()); assertTrue("Node " + dcNode.getQualifier() + " has to be controlled manually", dcNode.isManual());
log.infof("Stopping backend node: %s (dcIndex: %d, nodeIndex: %d)", dcNode.getQualifier(), dcIndex, nodeIndex);
containerController.stop(dcNode.getQualifier()); containerController.stop(dcNode.getQualifier());
return dcNode; return dcNode;
} }
/** /**
* Returns stream of all nodes in the given dc that are started manually. * Returns stream of all nodes in the given dc that are started manually.
* @param dcIndex * @param dc
* @return * @return
*/ */
public Stream<ContainerInfo> getManuallyStartedBackendNodes(DC dc) { public Stream<ContainerInfo> getManuallyStartedBackendNodes(DC dc) {
@ -315,7 +321,7 @@ public abstract class AbstractCrossDCTest extends AbstractTestRealmKeycloakTest
/** /**
* Returns stream of all nodes in the given dc that are started automatically. * Returns stream of all nodes in the given dc that are started automatically.
* @param dcIndex * @param dc
* @return * @return
*/ */
public Stream<ContainerInfo> getAutomaticallyStartedBackendNodes(DC dc) { public Stream<ContainerInfo> getAutomaticallyStartedBackendNodes(DC dc) {

View file

@ -21,6 +21,9 @@ import java.io.IOException;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import javax.ws.rs.NotFoundException; import javax.ws.rs.NotFoundException;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -31,9 +34,11 @@ import org.keycloak.models.UserLoginFailureModel;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.Assert; import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.Retry; import org.keycloak.testsuite.Retry;
import org.keycloak.testsuite.client.KeycloakTestingClient; import org.keycloak.testsuite.client.KeycloakTestingClient;
import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
import org.keycloak.testsuite.util.ClientBuilder; import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.RealmBuilder; import org.keycloak.testsuite.util.RealmBuilder;
@ -45,7 +50,31 @@ import org.keycloak.testsuite.util.UserBuilder;
public class BruteForceCrossDCTest extends AbstractAdminCrossDCTest { public class BruteForceCrossDCTest extends AbstractAdminCrossDCTest {
private static final String REALM_NAME = "brute-force-test"; private static final String REALM_NAME = "brute-force-test";
@Deployment(name = "dc0")
@TargetsContainer(QUALIFIER_JBOSS_DC_0_NODE_1)
public static WebArchive deployDC0() {
return RunOnServerDeployment.create(
BruteForceCrossDCTest.class,
AbstractAdminCrossDCTest.class,
AbstractCrossDCTest.class,
AbstractTestRealmKeycloakTest.class,
KeycloakTestingClient.class
);
}
@Deployment(name = "dc1")
@TargetsContainer(QUALIFIER_JBOSS_DC_1_NODE_1)
public static WebArchive deployDC1() {
return RunOnServerDeployment.create(
BruteForceCrossDCTest.class,
AbstractAdminCrossDCTest.class,
AbstractCrossDCTest.class,
AbstractTestRealmKeycloakTest.class,
KeycloakTestingClient.class
);
}
@Before @Before
public void beforeTest() { public void beforeTest() {
try { try {
@ -220,6 +249,7 @@ public class BruteForceCrossDCTest extends AbstractAdminCrossDCTest {
// TODO Having this working on Wildfly might be a challenge. Maybe require @Deployment with @TargetsContainer descriptor generated at runtime as we don't know the container qualifier at compile time... Maybe workaround by add endpoint to TestingResourceProvider if needed.. // TODO Having this working on Wildfly might be a challenge. Maybe require @Deployment with @TargetsContainer descriptor generated at runtime as we don't know the container qualifier at compile time... Maybe workaround by add endpoint to TestingResourceProvider if needed..
// resolution on Wildfly: make deployment available on both dc0_1 and dc1_1, see @Deployment methods
private void addUserLoginFailure(KeycloakTestingClient testingClient) throws URISyntaxException, IOException { private void addUserLoginFailure(KeycloakTestingClient testingClient) throws URISyntaxException, IOException {
testingClient.server().run(session -> { testingClient.server().run(session -> {
RealmModel realm = session.realms().getRealmByName(REALM_NAME); RealmModel realm = session.realms().getRealmByName(REALM_NAME);

View file

@ -64,7 +64,7 @@
<container qualifier="auth-server-undertow" mode="suite" > <container qualifier="auth-server-undertow" mode="suite" >
<configuration> <configuration>
<property name="enabled">${auth.server.undertow} &amp;&amp; ! ${auth.server.undertow.crossdc}</property> <property name="enabled">${auth.server.undertow} &amp;&amp; ! ${auth.server.crossdc}</property>
<property name="bindAddress">0.0.0.0</property> <property name="bindAddress">0.0.0.0</property>
<property name="adapterImplClass">org.keycloak.testsuite.arquillian.undertow.KeycloakOnUndertow</property> <property name="adapterImplClass">org.keycloak.testsuite.arquillian.undertow.KeycloakOnUndertow</property>
<property name="bindHttpPort">${auth.server.http.port}</property> <property name="bindHttpPort">${auth.server.http.port}</property>
@ -74,7 +74,7 @@
<container qualifier="auth-server-${auth.server}" mode="suite" > <container qualifier="auth-server-${auth.server}" mode="suite" >
<configuration> <configuration>
<property name="enabled">${auth.server.jboss}</property> <property name="enabled">${auth.server.jboss} &amp;&amp; ! ${auth.server.crossdc}</property>
<property name="adapterImplClass">${auth.server.adapter.impl.class}</property> <property name="adapterImplClass">${auth.server.adapter.impl.class}</property>
<property name="jbossHome">${auth.server.home}</property> <property name="jbossHome">${auth.server.home}</property>
<property name="${auth.server.config.property.name}">${auth.server.config.property.value}</property> <property name="${auth.server.config.property.name}">${auth.server.config.property.value}</property>
@ -186,18 +186,18 @@
</group> </group>
<!-- Cross DC with embedded undertow. Node numbering is [centre #].[node #] --> <!-- Cross DC. Node numbering is [centre #].[node #] -->
<group qualifier="auth-server-undertow-cross-dc"> <group qualifier="auth-server-jboss-cross-dc">
<container qualifier="cache-server-cross-dc-1" mode="suite" > <container qualifier="cache-server-cross-dc-1" mode="suite" >
<configuration> <configuration>
<property name="enabled">${auth.server.undertow.crossdc} &amp;&amp; ! ${cache.server.lifecycle.skip}</property> <property name="enabled">${auth.server.crossdc} &amp;&amp; ! ${cache.server.lifecycle.skip}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property> <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${cache.server.home}</property> <property name="jbossHome">${cache.server.home}</property>
<property name="serverConfig">clustered.xml</property> <property name="serverConfig">clustered.xml</property>
<property name="jbossArguments"> <property name="jbossArguments">
-Djboss.socket.binding.port-offset=${cache.server.port.offset} -Djboss.socket.binding.port-offset=${cache.server.port.offset}
-Djboss.default.multicast.address=234.56.78.99 -Djboss.default.multicast.address=234.56.78.99
-Djboss.node.name=cache-server -Djboss.node.name=cache-server-dc-1
${adapter.test.props} ${adapter.test.props}
${auth.server.profile} ${auth.server.profile}
</property> </property>
@ -213,7 +213,7 @@
<container qualifier="cache-server-cross-dc-2" mode="suite" > <container qualifier="cache-server-cross-dc-2" mode="suite" >
<configuration> <configuration>
<property name="enabled">${auth.server.undertow.crossdc} &amp;&amp; ! ${cache.server.lifecycle.skip}</property> <property name="enabled">${auth.server.crossdc} &amp;&amp; ! ${cache.server.lifecycle.skip}</property>
<property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property> <property name="adapterImplClass">org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</property>
<property name="jbossHome">${cache.server.home}</property> <property name="jbossHome">${cache.server.home}</property>
<property name="setupCleanServerBaseDir">true</property> <property name="setupCleanServerBaseDir">true</property>
@ -238,11 +238,11 @@
<container qualifier="auth-server-balancer-cross-dc" mode="suite" > <container qualifier="auth-server-balancer-cross-dc" mode="suite" >
<configuration> <configuration>
<property name="enabled">${auth.server.undertow.crossdc}</property> <property name="enabled">${auth.server.crossdc}</property>
<property name="adapterImplClass">org.keycloak.testsuite.arquillian.undertow.lb.SimpleUndertowLoadBalancerContainer</property> <property name="adapterImplClass">org.keycloak.testsuite.arquillian.undertow.lb.SimpleUndertowLoadBalancerContainer</property>
<property name="bindAddress">localhost</property> <property name="bindAddress">localhost</property>
<property name="bindHttpPort">${auth.server.http.port}</property> <property name="bindHttpPort">${auth.server.http.port}</property>
<property name="nodes">auth-server-undertow-cross-dc-0_1=http://localhost:8101,auth-server-undertow-cross-dc-0_2-manual=http://localhost:8102,auth-server-undertow-cross-dc-1_1=http://localhost:8111,auth-server-undertow-cross-dc-1_2-manual=http://localhost:8112</property> <property name="nodes">auth-server-${node.name}-cross-dc-0_1=http://localhost:8101,auth-server-${node.name}-cross-dc-0_2-manual=http://localhost:8102,auth-server-${node.name}-cross-dc-1_1=http://localhost:8111,auth-server-${node.name}-cross-dc-1_2-manual=http://localhost:8112</property>
</configuration> </configuration>
</container> </container>
@ -253,7 +253,6 @@
<property name="bindAddress">localhost</property> <property name="bindAddress">localhost</property>
<property name="bindHttpPort">${auth.server.http.port}</property> <property name="bindHttpPort">${auth.server.http.port}</property>
<property name="bindHttpPortOffset">-79</property> <property name="bindHttpPortOffset">-79</property>
<property name="route">auth-server-undertow-cross-dc-0_1</property>
<property name="remoteMode">${undertow.remote}</property> <property name="remoteMode">${undertow.remote}</property>
<property name="dataCenter">0</property> <property name="dataCenter">0</property>
<property name="keycloakConfigPropertyOverrides">{ <property name="keycloakConfigPropertyOverrides">{
@ -277,7 +276,6 @@
<property name="bindAddress">localhost</property> <property name="bindAddress">localhost</property>
<property name="bindHttpPort">${auth.server.http.port}</property> <property name="bindHttpPort">${auth.server.http.port}</property>
<property name="bindHttpPortOffset">-78</property> <property name="bindHttpPortOffset">-78</property>
<property name="route">auth-server-undertow-cross-dc-0_2-manual</property>
<property name="remoteMode">${undertow.remote}</property> <property name="remoteMode">${undertow.remote}</property>
<property name="dataCenter">0</property> <property name="dataCenter">0</property>
<property name="keycloakConfigPropertyOverrides">{ <property name="keycloakConfigPropertyOverrides">{
@ -302,7 +300,6 @@
<property name="bindAddress">localhost</property> <property name="bindAddress">localhost</property>
<property name="bindHttpPort">${auth.server.http.port}</property> <property name="bindHttpPort">${auth.server.http.port}</property>
<property name="bindHttpPortOffset">-69</property> <property name="bindHttpPortOffset">-69</property>
<property name="route">auth-server-undertow-cross-dc-1_1</property>
<property name="remoteMode">${undertow.remote}</property> <property name="remoteMode">${undertow.remote}</property>
<property name="dataCenter">1</property> <property name="dataCenter">1</property>
<property name="keycloakConfigPropertyOverrides">{ <property name="keycloakConfigPropertyOverrides">{
@ -326,7 +323,6 @@
<property name="bindAddress">localhost</property> <property name="bindAddress">localhost</property>
<property name="bindHttpPort">${auth.server.http.port}</property> <property name="bindHttpPort">${auth.server.http.port}</property>
<property name="bindHttpPortOffset">-68</property> <property name="bindHttpPortOffset">-68</property>
<property name="route">auth-server-undertow-cross-dc-1_2-manual</property>
<property name="remoteMode">${undertow.remote}</property> <property name="remoteMode">${undertow.remote}</property>
<property name="dataCenter">1</property> <property name="dataCenter">1</property>
<property name="keycloakConfigPropertyOverrides">{ <property name="keycloakConfigPropertyOverrides">{
@ -343,8 +339,97 @@
}</property> }</property>
</configuration> </configuration>
</container> </container>
</group> <container qualifier="auth-server-jboss-cross-dc-0_1" mode="suite" >
<configuration>
<property name="enabled">${auth.server.jboss.crossdc}</property>
<property name="adapterImplClass">${auth.server.adapter.impl.class}</property>
<property name="jbossHome">${auth.server.crossdc01.home}</property>
<property name="serverConfig">standalone-ha.xml</property>
<property name="jbossArguments">
-Djboss.socket.binding.port-offset=${auth.server.crossdc01.port.offset}
-Djboss.default.multicast.address=234.56.78.1
-Dremote.cache.port=12232
-Djboss.site.name=dc0
-Djboss.node.name=auth-server-${node.name}-cross-dc-0_1
</property>
<property name="javaVmArguments">
-Djava.net.preferIPv4Stack=true
${auth.server.crossdc01.jvm.debug.args}
</property>
<property name="managementPort">${auth.server.crossdc01.management.port}</property>
<property name="bindHttpPortOffset">-79</property>
<property name="dataCenter">0</property>
</configuration>
</container>
<container qualifier="auth-server-jboss-cross-dc-0_2-manual" mode="manual" >
<configuration>
<property name="enabled">${auth.server.jboss.crossdc}</property>
<property name="adapterImplClass">${auth.server.adapter.impl.class}</property>
<property name="jbossHome">${auth.server.crossdc02.home}</property>
<property name="serverConfig">standalone-ha.xml</property>
<property name="jbossArguments">
-Djboss.socket.binding.port-offset=${auth.server.crossdc02.port.offset}
-Djboss.default.multicast.address=234.56.78.1
-Dremote.cache.port=12232
-Djboss.site.name=dc0
-Djboss.node.name=auth-server-${node.name}-cross-dc-0_2-manual
</property>
<property name="javaVmArguments">
-Djava.net.preferIPv4Stack=true
${auth.server.crossdc02.jvm.debug.args}
</property>
<property name="managementPort">${auth.server.crossdc02.management.port}</property>
<property name="bindHttpPortOffset">-78</property>
<property name="dataCenter">0</property>
</configuration>
</container>
<container qualifier="auth-server-jboss-cross-dc-1_1" mode="suite" >
<configuration>
<property name="enabled">${auth.server.jboss.crossdc}</property>
<property name="adapterImplClass">${auth.server.adapter.impl.class}</property>
<property name="jbossHome">${auth.server.crossdc11.home}</property>
<property name="serverConfig">standalone-ha.xml</property>
<property name="jbossArguments">
-Djboss.socket.binding.port-offset=${auth.server.crossdc11.port.offset}
-Djboss.default.multicast.address=234.56.78.2
-Dremote.cache.port=13232
-Djboss.site.name=dc1
-Djboss.node.name=auth-server-${node.name}-cross-dc-1_1
</property>
<property name="javaVmArguments">
-Djava.net.preferIPv4Stack=true
${auth.server.crossdc11.jvm.debug.args}
</property>
<property name="managementPort">${auth.server.crossdc11.management.port}</property>
<property name="bindHttpPortOffset">-69</property>
<property name="dataCenter">1</property>
</configuration>
</container>
<container qualifier="auth-server-jboss-cross-dc-1_2-manual" mode="manual" >
<configuration>
<property name="enabled">${auth.server.jboss.crossdc}</property>
<property name="adapterImplClass">${auth.server.adapter.impl.class}</property>
<property name="jbossHome">${auth.server.crossdc12.home}</property>
<property name="serverConfig">standalone-ha.xml</property>
<property name="jbossArguments">
-Djboss.socket.binding.port-offset=${auth.server.crossdc12.port.offset}
-Djboss.default.multicast.address=234.56.78.2
-Dremote.cache.port=13232
-Djboss.site.name=dc1
-Djboss.node.name=auth-server-${node.name}-cross-dc-1_2-manual
</property>
<property name="javaVmArguments">
-Djava.net.preferIPv4Stack=true
${auth.server.crossdc12.jvm.debug.args}
</property>
<property name="managementPort">${auth.server.crossdc12.management.port}</property>
<property name="bindHttpPortOffset">-68</property>
<property name="dataCenter">1</property>
</configuration>
</container>
</group>
<container qualifier="auth-server-balancer-wildfly" mode="suite" > <container qualifier="auth-server-balancer-wildfly" mode="suite" >
<configuration> <configuration>

View file

@ -41,10 +41,12 @@
<properties> <properties>
<auth.server>undertow</auth.server> <auth.server>undertow</auth.server>
<auth.server.undertow>true</auth.server.undertow> <auth.server.undertow>true</auth.server.undertow>
<auth.server.undertow.crossdc>false</auth.server.undertow.crossdc>
<auth.server.crossdc>false</auth.server.crossdc> <auth.server.crossdc>false</auth.server.crossdc>
<auth.server.undertow.crossdc>false</auth.server.undertow.crossdc>
<auth.server.jboss.crossdc>false</auth.server.jboss.crossdc>
<cache.server.lifecycle.skip>false</cache.server.lifecycle.skip> <cache.server.lifecycle.skip>false</cache.server.lifecycle.skip>
<auth.server.container>auth-server-${auth.server}</auth.server.container> <auth.server.container>auth-server-${auth.server}</auth.server.container>
<auth.server.home>${containers.home}/${auth.server.container}</auth.server.home> <auth.server.home>${containers.home}/${auth.server.container}</auth.server.home>
<auth.server.config.dir>${auth.server.home}</auth.server.config.dir> <auth.server.config.dir>${auth.server.home}</auth.server.config.dir>
@ -60,16 +62,16 @@
<auth.server.memory.settings>-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m</auth.server.memory.settings> <auth.server.memory.settings>-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m</auth.server.memory.settings>
<auth.server.config.property.name>serverConfig</auth.server.config.property.name> <auth.server.config.property.name>serverConfig</auth.server.config.property.name>
<auth.server.adapter.impl.class>org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</auth.server.adapter.impl.class> <auth.server.adapter.impl.class>org.jboss.as.arquillian.container.managed.ManagedDeployableContainer</auth.server.adapter.impl.class>
<auth.server.jboss.artifactId>integration-arquillian-servers-auth-server-${auth.server}</auth.server.jboss.artifactId> <auth.server.jboss.artifactId>integration-arquillian-servers-auth-server-${auth.server}</auth.server.jboss.artifactId>
<auth.server.jboss.skip.unpack>${auth.server.undertow}</auth.server.jboss.skip.unpack> <auth.server.jboss.skip.unpack>${auth.server.undertow}</auth.server.jboss.skip.unpack>
<auth.server.jboss.startup.timeout>300</auth.server.jboss.startup.timeout> <auth.server.jboss.startup.timeout>300</auth.server.jboss.startup.timeout>
<!--debug properties--> <!--debug properties-->
<auth.server.debug.port>5005</auth.server.debug.port> <auth.server.debug.port>5005</auth.server.debug.port>
<auth.server.debug.suspend>n</auth.server.debug.suspend> <auth.server.debug.suspend>n</auth.server.debug.suspend>
<auth.server.jboss.jvm.debug.args>-agentlib:jdwp=transport=dt_socket,server=y,suspend=${auth.server.debug.suspend},address=${auth.server.host}:${auth.server.debug.port}</auth.server.jboss.jvm.debug.args> <auth.server.jboss.jvm.debug.args>-agentlib:jdwp=transport=dt_socket,server=y,suspend=${auth.server.debug.suspend},address=${auth.server.host}:${auth.server.debug.port}</auth.server.jboss.jvm.debug.args>
<auth.server.remote>false</auth.server.remote> <auth.server.remote>false</auth.server.remote>
<auth.server.profile/> <auth.server.profile/>
<auth.server.feature/> <auth.server.feature/>
@ -91,7 +93,7 @@
<adapter.test.props/> <adapter.test.props/>
<migration.import.properties/> <migration.import.properties/>
<kie.maven.settings/> <kie.maven.settings/>
<examples.home>${project.build.directory}/examples</examples.home> <examples.home>${project.build.directory}/examples</examples.home>
<browser>htmlUnit</browser> <browser>htmlUnit</browser>
@ -242,10 +244,10 @@
<auth.server.config.property.value>${auth.server.config.property.value}</auth.server.config.property.value> <auth.server.config.property.value>${auth.server.config.property.value}</auth.server.config.property.value>
<auth.server.adapter.impl.class>${auth.server.adapter.impl.class}</auth.server.adapter.impl.class> <auth.server.adapter.impl.class>${auth.server.adapter.impl.class}</auth.server.adapter.impl.class>
<auth.server.jboss.jvm.debug.args>${auth.server.jboss.jvm.debug.args}</auth.server.jboss.jvm.debug.args> <auth.server.jboss.jvm.debug.args>${auth.server.jboss.jvm.debug.args}</auth.server.jboss.jvm.debug.args>
<auth.server.profile>${auth.server.profile}</auth.server.profile> <auth.server.profile>${auth.server.profile}</auth.server.profile>
<auth.server.feature>${auth.server.feature}</auth.server.feature> <auth.server.feature>${auth.server.feature}</auth.server.feature>
<frontend.console.output>${frontend.console.output}</frontend.console.output> <frontend.console.output>${frontend.console.output}</frontend.console.output>
<backends.console.output>${backend.console.output}</backends.console.output> <backends.console.output>${backend.console.output}</backends.console.output>
@ -254,7 +256,7 @@
<adapter.test.props>${adapter.test.props}</adapter.test.props> <adapter.test.props>${adapter.test.props}</adapter.test.props>
<migration.import.properties>${migration.import.properties}</migration.import.properties> <migration.import.properties>${migration.import.properties}</migration.import.properties>
<kie.maven.settings>${kie.maven.settings}</kie.maven.settings> <kie.maven.settings>${kie.maven.settings}</kie.maven.settings>
<testsuite.constants>${testsuite.constants}</testsuite.constants> <testsuite.constants>${testsuite.constants}</testsuite.constants>
<cli.log.output>${cli.log.output}</cli.log.output> <cli.log.output>${cli.log.output}</cli.log.output>
<test.intermittent>${test.intermittent}</test.intermittent> <test.intermittent>${test.intermittent}</test.intermittent>
@ -287,10 +289,11 @@
<client.key.passphrase>${client.key.passphrase}</client.key.passphrase> <client.key.passphrase>${client.key.passphrase}</client.key.passphrase>
<auth.server.ocsp.responder.enabled>${auth.server.ocsp.responder.enabled}</auth.server.ocsp.responder.enabled> <auth.server.ocsp.responder.enabled>${auth.server.ocsp.responder.enabled}</auth.server.ocsp.responder.enabled>
<!--cache server properties--> <!--cache server properties-->
<auth.server.crossdc>${auth.server.crossdc}</auth.server.crossdc> <auth.server.crossdc>${auth.server.crossdc}</auth.server.crossdc>
<auth.server.undertow.crossdc>${auth.server.undertow.crossdc}</auth.server.undertow.crossdc> <auth.server.undertow.crossdc>${auth.server.undertow.crossdc}</auth.server.undertow.crossdc>
<auth.server.jboss.crossdc>${auth.server.jboss.crossdc}</auth.server.jboss.crossdc>
<cache.server.lifecycle.skip>${cache.server.lifecycle.skip}</cache.server.lifecycle.skip> <cache.server.lifecycle.skip>${cache.server.lifecycle.skip}</cache.server.lifecycle.skip>
<cache.server>${cache.server}</cache.server> <cache.server>${cache.server}</cache.server>
@ -367,14 +370,13 @@
</dependency> </dependency>
</dependencies> </dependencies>
</profile> </profile>
<profile> <profile>
<id>auth-server-wildfly</id> <id>auth-server-wildfly</id>
<properties> <properties>
<auth.server>wildfly</auth.server> <auth.server>wildfly</auth.server>
<auth.server.jboss>true</auth.server.jboss> <auth.server.jboss>true</auth.server.jboss>
<auth.server.undertow>false</auth.server.undertow> <auth.server.undertow>false</auth.server.undertow>
<auth.server.undertow.crossdc>false</auth.server.undertow.crossdc>
<auth.server.config.property.value>standalone.xml</auth.server.config.property.value> <auth.server.config.property.value>standalone.xml</auth.server.config.property.value>
<auth.server.config.dir>${auth.server.home}/standalone/configuration</auth.server.config.dir> <auth.server.config.dir>${auth.server.home}/standalone/configuration</auth.server.config.dir>
<h2.version>1.3.173</h2.version> <h2.version>1.3.173</h2.version>
@ -393,7 +395,6 @@
<auth.server>eap</auth.server> <auth.server>eap</auth.server>
<auth.server.jboss>true</auth.server.jboss> <auth.server.jboss>true</auth.server.jboss>
<auth.server.undertow>false</auth.server.undertow> <auth.server.undertow>false</auth.server.undertow>
<auth.server.undertow.crossdc>false</auth.server.undertow.crossdc>
<auth.server.config.property.value>standalone.xml</auth.server.config.property.value> <auth.server.config.property.value>standalone.xml</auth.server.config.property.value>
<auth.server.config.dir>${auth.server.home}/standalone/configuration</auth.server.config.dir> <auth.server.config.dir>${auth.server.home}/standalone/configuration</auth.server.config.dir>
<h2.version>1.3.173</h2.version> <h2.version>1.3.173</h2.version>
@ -406,14 +407,192 @@
</dependencies> </dependencies>
</profile> </profile>
<profile>
<id>auth-servers-crossdc-undertow</id>
<properties>
<auth.servers.crossdc>true</auth.servers.crossdc>
<auth.server.undertow.crossdc>true</auth.server.undertow.crossdc>
<node.name>undertow</node.name>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-profile-activation</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>cache.server.jboss</property>
<message>Profile "auth-servers-crossdc-undertow" requires activation of another profile: either "cache-server-infinispan" or "cache-server-jdg".</message>
<regex>true</regex>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<node.name>${node.name}</node.name>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>auth-servers-crossdc-jboss</id>
<properties>
<auth.servers.crossdc>true</auth.servers.crossdc>
<auth.server.jboss.crossdc>true</auth.server.jboss.crossdc>
<node.name>jboss</node.name>
<auth.server.crossdc01.home>${containers.home}/auth-server-${auth.server}-crossdc01</auth.server.crossdc01.home>
<auth.server.crossdc02.home>${containers.home}/auth-server-${auth.server}-crossdc02</auth.server.crossdc02.home>
<auth.server.crossdc11.home>${containers.home}/auth-server-${auth.server}-crossdc11</auth.server.crossdc11.home>
<auth.server.crossdc12.home>${containers.home}/auth-server-${auth.server}-crossdc12</auth.server.crossdc12.home>
<!-- property specifies keycloak-add-user.json file destination -->
<auth.server.config.dir>${auth.server.crossdc01.home}/standalone/configuration</auth.server.config.dir>
<auth.server.crossdc01.jvm.debug.port>5001</auth.server.crossdc01.jvm.debug.port>
<auth.server.crossdc02.jvm.debug.port>5002</auth.server.crossdc02.jvm.debug.port>
<auth.server.crossdc11.jvm.debug.port>5011</auth.server.crossdc11.jvm.debug.port>
<auth.server.crossdc12.jvm.debug.port>5012</auth.server.crossdc12.jvm.debug.port>
<!-- default is "n", possible to override by e.g. -Dauth.server.crossdc01.debug.suspend=y -->
<auth.server.crossdc01.debug.suspend>${auth.server.debug.suspend}</auth.server.crossdc01.debug.suspend>
<auth.server.crossdc02.debug.suspend>${auth.server.debug.suspend}</auth.server.crossdc02.debug.suspend>
<auth.server.crossdc11.debug.suspend>${auth.server.debug.suspend}</auth.server.crossdc11.debug.suspend>
<auth.server.crossdc12.debug.suspend>${auth.server.debug.suspend}</auth.server.crossdc12.debug.suspend>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copy-auth-server-crossdc-nodes</id>
<phase>process-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<move todir="${auth.server.crossdc01.home}">
<fileset dir="${auth.server.home}"/>
</move>
<copy todir="${auth.server.crossdc02.home}">
<fileset dir="${auth.server.crossdc01.home}"/>
</copy>
<copy todir="${auth.server.crossdc11.home}">
<fileset dir="${auth.server.crossdc01.home}"/>
</copy>
<copy todir="${auth.server.crossdc12.home}">
<fileset dir="${auth.server.crossdc01.home}"/>
</copy>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce-profiles-activation</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireProperty>
<property>cache.server.jboss</property>
<message>Profile "auth-servers-crossdc-jboss" requires activation of another profile: either "cache-server-infinispan" or "cache-server-jdg".</message>
<regex>true</regex>
</requireProperty>
<requireProperty>
<property>auth.server.jboss</property>
<message>Profile "auth-servers-crossdc-jboss" requires activation of another profile: either "auth-server-wildfly" or "auth-server-eap".</message>
<regex>true</regex>
</requireProperty>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<run.h2>true</run.h2>
<node.name>${node.name}</node.name>
<auth.server.crossdc01.home>${auth.server.crossdc01.home}</auth.server.crossdc01.home>
<auth.server.crossdc02.home>${auth.server.crossdc02.home}</auth.server.crossdc02.home>
<auth.server.crossdc11.home>${auth.server.crossdc11.home}</auth.server.crossdc11.home>
<auth.server.crossdc12.home>${auth.server.crossdc12.home}</auth.server.crossdc12.home>
<!--8101-->
<auth.server.crossdc01.port.offset>21</auth.server.crossdc01.port.offset>
<!--8102-->
<auth.server.crossdc02.port.offset>22</auth.server.crossdc02.port.offset>
<!--8111-->
<auth.server.crossdc11.port.offset>31</auth.server.crossdc11.port.offset>
<!--8112-->
<auth.server.crossdc12.port.offset>32</auth.server.crossdc12.port.offset>
<auth.server.crossdc01.management.port>10011</auth.server.crossdc01.management.port>
<auth.server.crossdc02.management.port>10012</auth.server.crossdc02.management.port>
<auth.server.crossdc11.management.port>10021</auth.server.crossdc11.management.port>
<auth.server.crossdc12.management.port>10022</auth.server.crossdc12.management.port>
<auth.server.crossdc01.jvm.debug.args>
-agentlib:jdwp=transport=dt_socket,server=y,suspend=${auth.server.crossdc01.debug.suspend},address=localhost:${auth.server.crossdc01.jvm.debug.port}
</auth.server.crossdc01.jvm.debug.args>
<auth.server.crossdc02.jvm.debug.args>
-agentlib:jdwp=transport=dt_socket,server=y,suspend=${auth.server.crossdc02.debug.suspend},address=localhost:${auth.server.crossdc02.jvm.debug.port}
</auth.server.crossdc02.jvm.debug.args>
<auth.server.crossdc11.jvm.debug.args>
-agentlib:jdwp=transport=dt_socket,server=y,suspend=${auth.server.crossdc11.debug.suspend},address=localhost:${auth.server.crossdc11.jvm.debug.port}
</auth.server.crossdc11.jvm.debug.args>
<auth.server.crossdc12.jvm.debug.args>
-agentlib:jdwp=transport=dt_socket,server=y,suspend=${auth.server.crossdc12.debug.suspend},address=localhost:${auth.server.crossdc12.jvm.debug.port}
</auth.server.crossdc12.jvm.debug.args>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<configuration>
<skip>${skipTests}</skip>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile> <profile>
<id>cache-server-infinispan</id> <id>cache-server-infinispan</id>
<properties> <properties>
<cache.server>infinispan</cache.server> <cache.server>infinispan</cache.server>
<auth.server.undertow.crossdc>true</auth.server.undertow.crossdc>
<auth.server.crossdc>true</auth.server.crossdc> <auth.server.crossdc>true</auth.server.crossdc>
<cache.server.jboss>true</cache.server.jboss> <cache.server.jboss>true</cache.server.jboss>
<cache.server.config.dir>${cache.server.home}/standalone/configuration</cache.server.config.dir> <cache.server.config.dir>${cache.server.home}/standalone/configuration</cache.server.config.dir>
<keycloak.testsuite.logging.pattern>%d{HH:mm:ss,SSS} [%t] %-5p [%c{1.}] %m%n</keycloak.testsuite.logging.pattern> <keycloak.testsuite.logging.pattern>%d{HH:mm:ss,SSS} [%t] %-5p [%c{1.}] %m%n</keycloak.testsuite.logging.pattern>
</properties> </properties>
<dependencies> <dependencies>
@ -429,17 +608,15 @@
<artifactId>maven-enforcer-plugin</artifactId> <artifactId>maven-enforcer-plugin</artifactId>
<executions> <executions>
<execution> <execution>
<id>enforce-profile-activation</id>
<goals> <goals>
<goal>enforce</goal> <goal>enforce</goal>
</goals> </goals>
<configuration> <configuration>
<rules> <rules>
<!--requireActiveProfile 'auth-server-wildfly/eap' doesn't work unless the profiles are defined in all submodule poms
using requireProperty instead-->
<requireProperty> <requireProperty>
<property>cache.server</property> <property>auth.servers.crossdc</property>
<regex>(infinispan)|(jdg)</regex> <message>Profile "cache-server-infinispan" requires activation of another profile: either "auth-servers-crossdc-undertow" or "auth-servers-crossdc-jboss".</message>
<regexMessage>Profile "cache-server-infinispan" requires activation of profile "cache-server-infinispan" or "cache-server-jdg".</regexMessage>
</requireProperty> </requireProperty>
</rules> </rules>
</configuration> </configuration>
@ -480,12 +657,11 @@
</pluginManagement> </pluginManagement>
</build> </build>
</profile> </profile>
<profile> <profile>
<id>cache-server-jdg</id> <id>cache-server-jdg</id>
<properties> <properties>
<cache.server>jdg</cache.server> <cache.server>jdg</cache.server>
<auth.server.undertow.crossdc>true</auth.server.undertow.crossdc>
<auth.server.crossdc>true</auth.server.crossdc> <auth.server.crossdc>true</auth.server.crossdc>
<cache.server.jboss>true</cache.server.jboss> <cache.server.jboss>true</cache.server.jboss>
<cache.server.config.dir>${cache.server.home}/standalone/configuration</cache.server.config.dir> <cache.server.config.dir>${cache.server.home}/standalone/configuration</cache.server.config.dir>
@ -504,17 +680,15 @@
<artifactId>maven-enforcer-plugin</artifactId> <artifactId>maven-enforcer-plugin</artifactId>
<executions> <executions>
<execution> <execution>
<id>enforce-profile-activation</id>
<goals> <goals>
<goal>enforce</goal> <goal>enforce</goal>
</goals> </goals>
<configuration> <configuration>
<rules> <rules>
<!--requireActiveProfile 'auth-server-wildfly/eap' doesn't work unless the profiles are defined in all submodule poms
using requireProperty instead-->
<requireProperty> <requireProperty>
<property>cache.server</property> <property>auth.servers.crossdc</property>
<regex>(infinispan)|(jdg)</regex> <message>Profile "cache-server-jdg" requires activation of another profile: either "auth-servers-crossdc-undertow" or "auth-servers-crossdc-jboss".</message>
<regexMessage>Profile "cache-server-jdg" requires activation of profile "cache-server-infinispan" or "cache-server-jdg".</regexMessage>
</requireProperty> </requireProperty>
</rules> </rules>
</configuration> </configuration>
@ -569,8 +743,8 @@
</profile> </profile>
<!-- <!--
profile that enables/disables specified feature, for more details see profile that enables/disables specified feature, for more details see
https://keycloak.gitbooks.io/documentation/content/server_installation/topics/profiles.html https://keycloak.gitbooks.io/documentation/content/server_installation/topics/profiles.html
--> -->
<profile> <profile>
<id>auth-server-enable-disable-feature</id> <id>auth-server-enable-disable-feature</id>
@ -765,7 +939,7 @@
</pluginManagement> </pluginManagement>
</build> </build>
</profile> </profile>
<profile> <profile>
<id>jdbc-driver-dependency</id> <id>jdbc-driver-dependency</id>
<activation> <activation>
@ -807,13 +981,13 @@
</profile> </profile>
<!-- Profiles for migration tests--> <!-- Profiles for migration tests-->
<profile> <profile>
<id>auth-server-migration</id> <id>auth-server-migration</id>
<properties> <properties>
<migration.import.file>target/test-classes/migration-test/migration-realm-${migrated.auth.server.version}.json</migration.import.file> <migration.import.file>target/test-classes/migration-test/migration-realm-${migrated.auth.server.version}.json</migration.import.file>
<migration.import.props.previous> <migration.import.props.previous>
-Dkeycloak.migration.action=import -Dkeycloak.migration.action=import
-Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.file=${migration.import.file} -Dkeycloak.migration.file=${migration.import.file}
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING -Dkeycloak.migration.strategy=OVERWRITE_EXISTING
@ -883,8 +1057,8 @@
</plugins> </plugins>
</pluginManagement> </pluginManagement>
</build> </build>
</profile> </profile>
<profile> <profile>
<id>migration-import</id> <id>migration-import</id>
<activation> <activation>
@ -896,7 +1070,7 @@
<properties> <properties>
<migration.import.file>target/test-classes/migration-test/migration-realm-${migrated.auth.server.version}.json</migration.import.file> <migration.import.file>target/test-classes/migration-test/migration-realm-${migrated.auth.server.version}.json</migration.import.file>
<migration.import.properties> <migration.import.properties>
-Dkeycloak.migration.action=import -Dkeycloak.migration.action=import
-Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.file=${migration.import.file} -Dkeycloak.migration.file=${migration.import.file}
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING -Dkeycloak.migration.strategy=OVERWRITE_EXISTING
@ -934,7 +1108,7 @@
</plugins> </plugins>
</build> </build>
</profile> </profile>
<profile> <profile>
<id>migration-productized</id> <id>migration-productized</id>
<activation> <activation>
@ -946,7 +1120,7 @@
<migration.import.file>target/test-classes/migration-test/migration-realm-${migrated.version.import.file.suffix}.json</migration.import.file> <migration.import.file>target/test-classes/migration-test/migration-realm-${migrated.version.import.file.suffix}.json</migration.import.file>
</properties> </properties>
</profile> </profile>
<profile> <profile>
<id>no-account</id> <id>no-account</id>
<properties> <properties>
@ -1280,7 +1454,7 @@
<auth.server.management.port.jmx>9999</auth.server.management.port.jmx> <auth.server.management.port.jmx>9999</auth.server.management.port.jmx>
</properties> </properties>
</profile> </profile>
<profile> <profile>
<!--see KEYCLOAK-4793--> <!--see KEYCLOAK-4793-->
<id>kie.maven.settings</id> <id>kie.maven.settings</id>
@ -1299,7 +1473,7 @@
</kie.maven.settings> </kie.maven.settings>
</properties> </properties>
</profile> </profile>
</profiles> </profiles>
</project> </project>