Added performance tests to testsuite to compare Picketlink+JPA+MySQL with Mongo.
This commit is contained in:
parent
68ed19f15d
commit
58d862819a
20 changed files with 1092 additions and 5 deletions
|
@ -118,7 +118,10 @@
|
|||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.3.161</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
|
|
@ -819,6 +819,7 @@ public class RealmAdapter implements RealmModel {
|
|||
RelationshipQuery<SocialLinkRelationship> query = getRelationshipManager().createRelationshipQuery(SocialLinkRelationship.class);
|
||||
query.setParameter(SocialLinkRelationship.SOCIAL_PROVIDER, socialLink.getSocialProvider());
|
||||
query.setParameter(SocialLinkRelationship.SOCIAL_USERNAME, socialLink.getSocialUsername());
|
||||
query.setParameter(SocialLinkRelationship.REALM, realm.getName());
|
||||
List<SocialLinkRelationship> results = query.getResultList();
|
||||
if (results.isEmpty()) {
|
||||
return null;
|
||||
|
@ -850,6 +851,7 @@ public class RealmAdapter implements RealmModel {
|
|||
relationship.setUser(((UserAdapter)user).getUser());
|
||||
relationship.setSocialProvider(socialLink.getSocialProvider());
|
||||
relationship.setSocialUsername(socialLink.getSocialUsername());
|
||||
relationship.setRealm(realm.getName());
|
||||
|
||||
getRelationshipManager().add(relationship);
|
||||
}
|
||||
|
@ -860,6 +862,7 @@ public class RealmAdapter implements RealmModel {
|
|||
relationship.setUser(((UserAdapter)user).getUser());
|
||||
relationship.setSocialProvider(socialLink.getSocialProvider());
|
||||
relationship.setSocialUsername(socialLink.getSocialUsername());
|
||||
relationship.setRealm(realm.getName());
|
||||
|
||||
getRelationshipManager().remove(relationship);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.models.picketlink.relationships;
|
|||
import org.picketlink.idm.model.AbstractAttributedType;
|
||||
import org.picketlink.idm.model.Attribute;
|
||||
import org.picketlink.idm.model.Relationship;
|
||||
import org.picketlink.idm.model.annotation.AttributeProperty;
|
||||
import org.picketlink.idm.model.sample.User;
|
||||
import org.picketlink.idm.query.AttributeParameter;
|
||||
import org.picketlink.idm.query.RelationshipQueryParameter;
|
||||
|
@ -21,6 +22,10 @@ public class SocialLinkRelationship extends AbstractAttributedType implements Re
|
|||
public static final AttributeParameter SOCIAL_PROVIDER = new AttributeParameter("socialProvider");
|
||||
public static final AttributeParameter SOCIAL_USERNAME = new AttributeParameter("socialUsername");
|
||||
|
||||
// realm is needed to allow searching as combination socialUsername+socialProvider may not be unique
|
||||
// (Same user could have mapped same facebook account to username "foo" in "realm1" and to username "bar" in "realm2")
|
||||
public static final AttributeParameter REALM = new AttributeParameter("realm");
|
||||
|
||||
public static final RelationshipQueryParameter USER = new RelationshipQueryParameter() {
|
||||
|
||||
@Override
|
||||
|
@ -39,6 +44,7 @@ public class SocialLinkRelationship extends AbstractAttributedType implements Re
|
|||
this.user = user;
|
||||
}
|
||||
|
||||
@AttributeProperty
|
||||
public String getSocialProvider() {
|
||||
return (String)getAttribute("socialProvider").getValue();
|
||||
}
|
||||
|
@ -47,6 +53,7 @@ public class SocialLinkRelationship extends AbstractAttributedType implements Re
|
|||
setAttribute(new Attribute<String>("socialProvider", socialProvider));
|
||||
}
|
||||
|
||||
@AttributeProperty
|
||||
public String getSocialUsername() {
|
||||
return (String)getAttribute("socialUsername").getValue();
|
||||
}
|
||||
|
@ -54,4 +61,13 @@ public class SocialLinkRelationship extends AbstractAttributedType implements Re
|
|||
public void setSocialUsername(String socialProviderUserId) {
|
||||
setAttribute(new Attribute<String>("socialUsername", socialProviderUserId));
|
||||
}
|
||||
|
||||
@AttributeProperty
|
||||
public String getRealm() {
|
||||
return (String)getAttribute("realm").getValue();
|
||||
}
|
||||
|
||||
public void setRealm(String realm) {
|
||||
setAttribute(new Attribute<String>("realm", realm));
|
||||
}
|
||||
}
|
||||
|
|
72
pom.xml
72
pom.xml
|
@ -12,6 +12,13 @@
|
|||
<resteasy.version>3.0.4.Final</resteasy.version>
|
||||
<undertow.version>1.0.0.Beta12</undertow.version>
|
||||
<picketlink.version>2.5.0.Beta6</picketlink.version>
|
||||
<mongo.driver.version>2.11.2</mongo.driver.version>
|
||||
<jboss.logging.version>3.1.1.GA</jboss.logging.version>
|
||||
<hibernate.javax.persistence.version>1.0.1.Final</hibernate.javax.persistence.version>
|
||||
<hibernate.entitymanager.version>3.6.6.Final</hibernate.entitymanager.version>
|
||||
<h2.version>1.3.161</h2.version>
|
||||
<dom4j.version>1.6.1</dom4j.version>
|
||||
<slf4j.version>1.6.1</slf4j.version>
|
||||
</properties>
|
||||
|
||||
<url>http://keycloak.org</url>
|
||||
|
@ -177,7 +184,7 @@
|
|||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<version>3.1.1.GA</version>
|
||||
<version>${jboss.logging.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
@ -187,7 +194,17 @@
|
|||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
<version>1.0.1.Final</version>
|
||||
<version>${hibernate.javax.persistence.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>${h2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
<version>${hibernate.entitymanager.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.api-client</groupId>
|
||||
|
@ -259,6 +276,42 @@
|
|||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
<version>1.27</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_java</artifactId>
|
||||
<version>2.9</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>${dom4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<!-- Needed for picketlink perf test -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>5.1.25</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jboss.arquillian</groupId>
|
||||
<artifactId>arquillian-bom</artifactId>
|
||||
<version>1.1.1.Final</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.arquillian.extension</groupId>
|
||||
<artifactId>arquillian-drone-bom</artifactId>
|
||||
<version>1.2.0.Beta1</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
@ -340,6 +393,21 @@
|
|||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.lazerycode.jmeter</groupId>
|
||||
<artifactId>jmeter-maven-plugin</artifactId>
|
||||
<version>1.8.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.lazerycode.jmeter</groupId>
|
||||
<artifactId>jmeter-analysis-maven-plugin</artifactId>
|
||||
<version>1.0.4</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
|
|
|
@ -147,10 +147,12 @@
|
|||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-common</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
|
@ -170,13 +172,11 @@
|
|||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.3.161</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
<version>3.6.6.Final</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -43,6 +43,10 @@ public class NoSQLSession implements KeycloakSession {
|
|||
|
||||
@Override
|
||||
public RealmModel createRealm(String id, String name) {
|
||||
if (getRealm(id) != null) {
|
||||
throw new IllegalStateException("Realm with id '" + id + "' already exists");
|
||||
}
|
||||
|
||||
RealmData newRealm = new RealmData();
|
||||
newRealm.setId(id);
|
||||
newRealm.setName(name);
|
||||
|
|
|
@ -273,6 +273,15 @@ public class RealmAdapter implements RealmModel {
|
|||
return new UserAdapter(userData, noSQL);
|
||||
}
|
||||
|
||||
// This method doesn't exists on interface actually
|
||||
public void removeUser(String name) {
|
||||
NoSQLQuery query = noSQL.createQueryBuilder()
|
||||
.andCondition("loginName", name)
|
||||
.andCondition("realmId", getOid())
|
||||
.build();
|
||||
noSQL.removeObjects(UserData.class, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleAdapter getRole(String name) {
|
||||
NoSQLQuery query = noSQL.createQueryBuilder()
|
||||
|
@ -659,6 +668,7 @@ public class RealmAdapter implements RealmModel {
|
|||
NoSQLQuery query = noSQL.createQueryBuilder()
|
||||
.andCondition("socialProvider", socialLink.getSocialProvider())
|
||||
.andCondition("socialUsername", socialLink.getSocialUsername())
|
||||
.andCondition("realmId", getOid())
|
||||
.build();
|
||||
SocialLinkData socialLinkData = noSQL.loadSingleObject(SocialLinkData.class, query);
|
||||
|
||||
|
@ -696,6 +706,7 @@ public class RealmAdapter implements RealmModel {
|
|||
socialLinkData.setSocialProvider(socialLink.getSocialProvider());
|
||||
socialLinkData.setSocialUsername(socialLink.getSocialUsername());
|
||||
socialLinkData.setUserId(userData.getId());
|
||||
socialLinkData.setRealmId(getOid());
|
||||
|
||||
noSQL.saveObject(socialLinkData);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,9 @@ public class SocialLinkData extends AbstractNoSQLObject {
|
|||
private String socialUsername;
|
||||
private String socialProvider;
|
||||
private String userId;
|
||||
// realmId is needed to allow searching as combination socialUsername+socialProvider may not be unique
|
||||
// (Same user could have mapped same facebook account to username "foo" in "realm1" and to username "bar" in "realm2")
|
||||
private String realmId;
|
||||
|
||||
@NoSQLField
|
||||
public String getSocialUsername() {
|
||||
|
@ -42,4 +45,13 @@ public class SocialLinkData extends AbstractNoSQLObject {
|
|||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
@NoSQLField
|
||||
public String getRealmId() {
|
||||
return realmId;
|
||||
}
|
||||
|
||||
public void setRealmId(String realmId) {
|
||||
this.realmId = realmId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -182,6 +182,10 @@
|
|||
<groupId>org.seleniumhq.selenium</groupId>
|
||||
<artifactId>selenium-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jmeter</groupId>
|
||||
<artifactId>ApacheJMeter_java</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
@ -193,6 +197,17 @@
|
|||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
@ -219,5 +234,156 @@
|
|||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>performance-tests</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.lazerycode.jmeter</groupId>
|
||||
<artifactId>jmeter-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jmeter-tests</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>jmeter</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-testsuite</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>jaxrs-api</artifactId>
|
||||
<version>${resteasy.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.resteasy</groupId>
|
||||
<artifactId>resteasy-jaxrs</artifactId>
|
||||
<version>${resteasy.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.logging</groupId>
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<version>${jboss.logging.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-idm-impl</artifactId>
|
||||
<version>${picketlink.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-idm-simple-schema</artifactId>
|
||||
<version>${picketlink.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.picketlink</groupId>
|
||||
<artifactId>picketlink-config</artifactId>
|
||||
<version>${picketlink.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
<version>${mongo.driver.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Needed for picketlink -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate.javax.persistence</groupId>
|
||||
<artifactId>hibernate-jpa-2.0-api</artifactId>
|
||||
<version>${hibernate.javax.persistence.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>${h2.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-entitymanager</artifactId>
|
||||
<version>${hibernate.entitymanager.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>${dom4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Needed just for picketlink perf test -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.lazerycode.jmeter</groupId>
|
||||
<artifactId>jmeter-analysis-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jmeter-tests-analyze</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>analyze</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>${project.build.directory}/jmeter/results/*.jtl</source>
|
||||
<targetDirectory>${project.build.directory}/jmeter/results</targetDirectory>
|
||||
<preserveDirectories>false</preserveDirectories>
|
||||
<writers>
|
||||
<com.lazerycode.jmeter.analyzer.writer.SummaryTextToStdOutWriter/>
|
||||
<!--<com.lazerycode.jmeter.analyzer.writer.SummaryTextToFileWriter/>-->
|
||||
<com.lazerycode.jmeter.analyzer.writer.HtmlWriter/>
|
||||
<!--<com.lazerycode.jmeter.analyzer.writer.DetailsToCsvWriter/>-->
|
||||
<com.lazerycode.jmeter.analyzer.writer.DetailsToHtmlWriter/>
|
||||
<com.lazerycode.jmeter.analyzer.writer.ChartWriter/>
|
||||
</writers>
|
||||
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
package org.keycloak.testsuite.performance;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
|
||||
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
|
||||
import org.apache.jmeter.samplers.SampleResult;
|
||||
import org.keycloak.services.models.KeycloakSession;
|
||||
import org.keycloak.services.models.KeycloakSessionFactory;
|
||||
import org.keycloak.services.models.KeycloakTransaction;
|
||||
import org.keycloak.services.models.picketlink.PicketlinkKeycloakSession;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class BaseJMeterPerformanceTest extends AbstractJavaSamplerClient {
|
||||
|
||||
|
||||
private static FutureTask<KeycloakSessionFactory> factoryProvider = new FutureTask<KeycloakSessionFactory>(new Callable() {
|
||||
|
||||
@Override
|
||||
public KeycloakSessionFactory call() throws Exception {
|
||||
return KeycloakApplication.buildSessionFactory();
|
||||
}
|
||||
|
||||
});
|
||||
private static AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
private KeycloakSessionFactory factory;
|
||||
// private KeycloakSession identitySession;
|
||||
private Worker worker;
|
||||
private boolean setupSuccess = false;
|
||||
|
||||
|
||||
// Executed once per JMeter thread
|
||||
@Override
|
||||
public void setupTest(JavaSamplerContext context) {
|
||||
super.setupTest(context);
|
||||
|
||||
worker = getWorker();
|
||||
|
||||
factory = getFactory();
|
||||
KeycloakSession identitySession = factory.createSession();
|
||||
KeycloakTransaction transaction = identitySession.getTransaction();
|
||||
transaction.begin();
|
||||
|
||||
int workerId = counter.getAndIncrement();
|
||||
try {
|
||||
worker.setup(workerId, identitySession);
|
||||
setupSuccess = true;
|
||||
} finally {
|
||||
if (setupSuccess) {
|
||||
transaction.commit();
|
||||
} else {
|
||||
transaction.rollback();
|
||||
}
|
||||
identitySession.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static KeycloakSessionFactory getFactory() {
|
||||
factoryProvider.run();
|
||||
try {
|
||||
return factoryProvider.get();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Worker getWorker() {
|
||||
String workerClass = System.getProperty("keycloak.perf.workerClass");
|
||||
if (workerClass == null) {
|
||||
throw new IllegalArgumentException("System property keycloak.perf.workerClass needs to be provided");
|
||||
}
|
||||
|
||||
try {
|
||||
Class workerClazz = Class.forName(workerClass);
|
||||
return (Worker)workerClazz.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SampleResult runTest(JavaSamplerContext context) {
|
||||
SampleResult result = new SampleResult();
|
||||
result.sampleStart();
|
||||
|
||||
if (!setupSuccess) {
|
||||
getLogger().error("setupTest didn't executed successfully. Skipping");
|
||||
result.setResponseCode("500");
|
||||
result.sampleEnd();
|
||||
result.setSuccessful(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
KeycloakSession identitySession = factory.createSession();
|
||||
KeycloakTransaction transaction = identitySession.getTransaction();
|
||||
try {
|
||||
transaction.begin();
|
||||
|
||||
worker.run(result, identitySession);
|
||||
|
||||
result.setResponseCodeOK();
|
||||
transaction.commit();
|
||||
} catch (Exception e) {
|
||||
getLogger().error("Error during worker processing", e);
|
||||
result.setResponseCode("500");
|
||||
transaction.rollback();
|
||||
} finally {
|
||||
result.sampleEnd();
|
||||
result.setSuccessful(true);
|
||||
identitySession.close();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Executed once per JMeter thread
|
||||
@Override
|
||||
public void teardownTest(JavaSamplerContext context) {
|
||||
super.teardownTest(context);
|
||||
|
||||
if (worker != null) {
|
||||
worker.tearDown();
|
||||
}
|
||||
|
||||
// TODO: Assumption is that tearDownTest is executed for each setupTest. Verify if it's always true...
|
||||
if (counter.decrementAndGet() == 0) {
|
||||
if (factory != null) {
|
||||
factory.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package org.keycloak.testsuite.performance;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.jmeter.samplers.SampleResult;
|
||||
import org.apache.jorphan.logging.LoggingManager;
|
||||
import org.apache.log.Logger;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.models.ApplicationModel;
|
||||
import org.keycloak.services.models.KeycloakSession;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class CreateRealmsWorker implements Worker {
|
||||
|
||||
private static final Logger log = LoggingManager.getLoggerForClass();
|
||||
|
||||
private static final int NUMBER_OF_REALMS_IN_EACH_REPORT = 100;
|
||||
|
||||
private static AtomicInteger realmCounter = new AtomicInteger(0);
|
||||
|
||||
private int offset;
|
||||
private int appsPerRealm;
|
||||
private int rolesPerRealm;
|
||||
private int defaultRolesPerRealm;
|
||||
private int rolesPerApp;
|
||||
private boolean createRequiredCredentials;
|
||||
|
||||
@Override
|
||||
public void setup(int workerId, KeycloakSession identitySession) {
|
||||
offset = PerfTestUtils.readSystemProperty("keycloak.perf.createRealms.realms.offset", Integer.class);
|
||||
appsPerRealm = PerfTestUtils.readSystemProperty("keycloak.perf.createRealms.appsPerRealm", Integer.class);
|
||||
rolesPerRealm = PerfTestUtils.readSystemProperty("keycloak.perf.createRealms.rolesPerRealm", Integer.class);
|
||||
defaultRolesPerRealm = PerfTestUtils.readSystemProperty("keycloak.perf.createRealms.defaultRolesPerRealm", Integer.class);
|
||||
rolesPerApp = PerfTestUtils.readSystemProperty("keycloak.perf.createRealms.rolesPerApp", Integer.class);
|
||||
createRequiredCredentials = PerfTestUtils.readSystemProperty("keycloak.perf.createRealms.createRequiredCredentials", Boolean.class);
|
||||
|
||||
realmCounter.compareAndSet(0, offset);
|
||||
|
||||
StringBuilder logBuilder = new StringBuilder("Read setup: ")
|
||||
.append("offset=" + offset)
|
||||
.append(", appsPerRealm=" + appsPerRealm)
|
||||
.append(", rolesPerRealm=" + rolesPerRealm)
|
||||
.append(", defaultRolesPerRealm=" + defaultRolesPerRealm)
|
||||
.append(", rolesPerApp=" + rolesPerApp)
|
||||
.append(", createRequiredCredentials=" + createRequiredCredentials);
|
||||
log.info(logBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(SampleResult result, KeycloakSession identitySession) {
|
||||
int realmNumber = realmCounter.getAndIncrement();
|
||||
String realmName = PerfTestUtils.getRealmName(realmNumber);
|
||||
RealmManager realmManager = new RealmManager(identitySession);
|
||||
RealmModel realm = realmManager.createRealm(realmName, realmName);
|
||||
|
||||
// Add roles
|
||||
for (int i=1 ; i<=rolesPerRealm ; i++) {
|
||||
realm.addRole(PerfTestUtils.getRoleName(realmNumber, i));
|
||||
}
|
||||
|
||||
// Add default roles
|
||||
for (int i=1 ; i<=defaultRolesPerRealm ; i++) {
|
||||
realm.addDefaultRole(PerfTestUtils.getDefaultRoleName(realmNumber, i));
|
||||
}
|
||||
|
||||
// Add applications
|
||||
for (int i=1 ; i<=appsPerRealm ; i++) {
|
||||
ApplicationModel application = realm.addApplication(PerfTestUtils.getApplicationName(realmNumber, i));
|
||||
for (int j=1 ; j<=rolesPerApp ; j++) {
|
||||
application.addRole(PerfTestUtils.getApplicationRoleName(realmNumber, i, j));
|
||||
}
|
||||
}
|
||||
|
||||
// Add required credentials
|
||||
if (createRequiredCredentials) {
|
||||
realmManager.addRequiredCredential(realm, CredentialRepresentation.PASSWORD);
|
||||
realmManager.addResourceRequiredCredential(realm, CredentialRepresentation.PASSWORD);
|
||||
realmManager.addOAuthClientRequiredCredential(realm, CredentialRepresentation.PASSWORD);
|
||||
realmManager.addRequiredCredential(realm, CredentialRepresentation.TOTP);
|
||||
realmManager.addResourceRequiredCredential(realm, CredentialRepresentation.TOTP);
|
||||
realmManager.addOAuthClientRequiredCredential(realm, CredentialRepresentation.TOTP);
|
||||
realmManager.addRequiredCredential(realm, CredentialRepresentation.CLIENT_CERT);
|
||||
realmManager.addResourceRequiredCredential(realm, CredentialRepresentation.CLIENT_CERT);
|
||||
realmManager.addOAuthClientRequiredCredential(realm, CredentialRepresentation.CLIENT_CERT);
|
||||
}
|
||||
|
||||
log.info("Finished creation of realm " + realmName);
|
||||
|
||||
int labelC = ((realmNumber - 1) / NUMBER_OF_REALMS_IN_EACH_REPORT) * NUMBER_OF_REALMS_IN_EACH_REPORT;
|
||||
result.setSampleLabel("CreateRealms " + (labelC + 1) + "-" + (labelC + NUMBER_OF_REALMS_IN_EACH_REPORT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package org.keycloak.testsuite.performance;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.jmeter.samplers.SampleResult;
|
||||
import org.apache.jorphan.logging.LoggingManager;
|
||||
import org.apache.log.Logger;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.services.models.KeycloakSession;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.RoleModel;
|
||||
import org.keycloak.services.models.SocialLinkModel;
|
||||
import org.keycloak.services.models.UserCredentialModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class CreateUsersWorker implements Worker {
|
||||
|
||||
private static final Logger log = LoggingManager.getLoggerForClass();
|
||||
|
||||
private static final int NUMBER_OF_USERS_IN_EACH_REPORT = 5000;
|
||||
|
||||
// Total number of users created during whole test
|
||||
private static AtomicInteger totalUserCounter = new AtomicInteger();
|
||||
|
||||
// Adding users will always start from 1. Each worker thread needs to add users to single realm, which is dedicated just for this worker
|
||||
private int userCounterInRealm = 0;
|
||||
private String realmId;
|
||||
|
||||
private int realmsOffset;
|
||||
private boolean addBasicUserAttributes;
|
||||
private boolean addDefaultRoles;
|
||||
private boolean addPassword;
|
||||
private int socialLinksPerUserCount;
|
||||
|
||||
@Override
|
||||
public void setup(int workerId, KeycloakSession identitySession) {
|
||||
realmsOffset = PerfTestUtils.readSystemProperty("keycloak.perf.createUsers.realms.offset", Integer.class);
|
||||
addBasicUserAttributes = PerfTestUtils.readSystemProperty("keycloak.perf.createUsers.addBasicUserAttributes", Boolean.class);
|
||||
addDefaultRoles = PerfTestUtils.readSystemProperty("keycloak.perf.createUsers.addDefaultRoles", Boolean.class);
|
||||
addPassword = PerfTestUtils.readSystemProperty("keycloak.perf.createUsers.addPassword", Boolean.class);
|
||||
socialLinksPerUserCount = PerfTestUtils.readSystemProperty("keycloak.perf.createUsers.socialLinksPerUserCount", Integer.class);
|
||||
|
||||
int realmNumber = realmsOffset + workerId;
|
||||
realmId = PerfTestUtils.getRealmName(realmNumber);
|
||||
|
||||
StringBuilder logBuilder = new StringBuilder("Read setup: ")
|
||||
.append("realmsOffset=" + realmsOffset)
|
||||
.append(", addBasicUserAttributes=" + addBasicUserAttributes)
|
||||
.append(", addDefaultRoles=" + addDefaultRoles)
|
||||
.append(", addPassword=" + addPassword)
|
||||
.append(", socialLinksPerUserCount=" + socialLinksPerUserCount)
|
||||
.append(", realmId=" + realmId);
|
||||
log.info(logBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(SampleResult result, KeycloakSession identitySession) {
|
||||
// We need to obtain realm first
|
||||
RealmModel realm = identitySession.getRealm(realmId);
|
||||
if (realm == null) {
|
||||
throw new IllegalStateException("Realm '" + realmId + "' not found");
|
||||
}
|
||||
|
||||
int userNumber = ++userCounterInRealm;
|
||||
int totalUserNumber = totalUserCounter.incrementAndGet();
|
||||
|
||||
String username = PerfTestUtils.getUsername(userNumber);
|
||||
|
||||
UserModel user = realm.addUser(username);
|
||||
|
||||
// Add basic user attributes (NOTE: Actually backend is automatically upgraded during each setter call)
|
||||
if (addBasicUserAttributes) {
|
||||
user.setFirstName(username + "FN");
|
||||
user.setLastName(username + "LN");
|
||||
user.setEmail(username + "@email.com");
|
||||
}
|
||||
|
||||
// Adding default roles of realm to user
|
||||
if (addDefaultRoles) {
|
||||
for (RoleModel role : realm.getDefaultRoles()) {
|
||||
realm.grantRole(user, role);
|
||||
}
|
||||
}
|
||||
|
||||
// Creating password (will be same as username)
|
||||
if (addPassword) {
|
||||
UserCredentialModel password = new UserCredentialModel();
|
||||
password.setType(CredentialRepresentation.PASSWORD);
|
||||
password.setValue(username);
|
||||
realm.updateCredential(user, password);
|
||||
}
|
||||
|
||||
// Creating some socialLinks
|
||||
for (int i=0 ; i<socialLinksPerUserCount ; i++) {
|
||||
String socialProvider;
|
||||
switch (i) {
|
||||
case 0: socialProvider = "facebook"; break;
|
||||
case 1: socialProvider = "twitter"; break;
|
||||
case 2: socialProvider = "google"; break;
|
||||
default: throw new IllegalArgumentException("Total number of socialLinksPerUserCount is " + socialLinksPerUserCount
|
||||
+ " which is too big.");
|
||||
}
|
||||
|
||||
SocialLinkModel socialLink = new SocialLinkModel(socialProvider, username);
|
||||
realm.addSocialLink(user, socialLink);
|
||||
}
|
||||
|
||||
log.info("Finished creation of user " + username + " in realm: " + realm.getId());
|
||||
|
||||
int labelC = ((totalUserNumber - 1) / NUMBER_OF_USERS_IN_EACH_REPORT) * NUMBER_OF_USERS_IN_EACH_REPORT;
|
||||
result.setSampleLabel("CreateUsers " + (labelC + 1) + "-" + (labelC + NUMBER_OF_USERS_IN_EACH_REPORT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package org.keycloak.testsuite.performance;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class PerfTestUtils {
|
||||
|
||||
public static <T> T readSystemProperty(String propertyName, Class<T> expectedClass) {
|
||||
String propAsString = System.getProperty(propertyName);
|
||||
if (propAsString == null || propAsString.length() == 0) {
|
||||
throw new IllegalArgumentException("Property '" + propertyName + "' not specified");
|
||||
}
|
||||
|
||||
if (Integer.class.equals(expectedClass)) {
|
||||
return expectedClass.cast(Integer.parseInt(propAsString));
|
||||
} else if (Boolean.class.equals(expectedClass)) {
|
||||
return expectedClass.cast(Boolean.valueOf(propAsString));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Not supported type " + expectedClass);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getRealmName(int realmNumber) {
|
||||
return "realm" + realmNumber;
|
||||
}
|
||||
|
||||
public static String getApplicationName(int realmNumber, int applicationNumber) {
|
||||
return getRealmName(realmNumber) + "application" + applicationNumber;
|
||||
}
|
||||
|
||||
public static String getRoleName(int realmNumber, int roleNumber) {
|
||||
return getRealmName(realmNumber) + "role" + roleNumber;
|
||||
}
|
||||
|
||||
public static String getDefaultRoleName(int realmNumber, int defaultRoleNumber) {
|
||||
return getRealmName(realmNumber) + "defrole" + defaultRoleNumber;
|
||||
}
|
||||
|
||||
public static String getApplicationRoleName(int realmNumber, int applicationNumber, int roleNumber) {
|
||||
return getApplicationName(realmNumber, applicationNumber) + "role" + roleNumber;
|
||||
}
|
||||
|
||||
public static String getUsername(int userNumber) {
|
||||
return "user" + userNumber;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package org.keycloak.testsuite.performance;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.jmeter.samplers.SampleResult;
|
||||
import org.apache.jorphan.logging.LoggingManager;
|
||||
import org.apache.log.Logger;
|
||||
import org.keycloak.services.models.KeycloakSession;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.SocialLinkModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class ReadUsersWorker implements Worker {
|
||||
|
||||
private static final Logger log = LoggingManager.getLoggerForClass();
|
||||
|
||||
private static final int NUMBER_OF_ITERATIONS_IN_EACH_REPORT = 5000;
|
||||
|
||||
// Total number of iterations read during whole test
|
||||
private static AtomicInteger totalIterationCounter = new AtomicInteger();
|
||||
|
||||
// Reading users will always start from 1. Each worker thread needs to read users to single realm, which is dedicated just for this worker
|
||||
private int userCounterInRealm = 0;
|
||||
|
||||
private int realmsOffset;
|
||||
private int readUsersPerIteration;
|
||||
private int countOfUsersPerRealm;
|
||||
private boolean readRoles;
|
||||
private boolean readScopes;
|
||||
private boolean readPassword;
|
||||
private boolean readSocialLinks;
|
||||
private boolean searchBySocialLinks;
|
||||
|
||||
private String realmId;
|
||||
private int iterationNumber;
|
||||
|
||||
@Override
|
||||
public void setup(int workerId, KeycloakSession identitySession) {
|
||||
realmsOffset = PerfTestUtils.readSystemProperty("keycloak.perf.readUsers.realms.offset", Integer.class);
|
||||
readUsersPerIteration = PerfTestUtils.readSystemProperty("keycloak.perf.readUsers.readUsersPerIteration", Integer.class);
|
||||
countOfUsersPerRealm = PerfTestUtils.readSystemProperty("keycloak.perf.readUsers.countOfUsersPerRealm", Integer.class);
|
||||
readRoles = PerfTestUtils.readSystemProperty("keycloak.perf.readUsers.readRoles", Boolean.class);
|
||||
readScopes = PerfTestUtils.readSystemProperty("keycloak.perf.readUsers.readScopes", Boolean.class);
|
||||
readPassword = PerfTestUtils.readSystemProperty("keycloak.perf.readUsers.readPassword", Boolean.class);
|
||||
readSocialLinks = PerfTestUtils.readSystemProperty("keycloak.perf.readUsers.readSocialLinks", Boolean.class);
|
||||
searchBySocialLinks = PerfTestUtils.readSystemProperty("keycloak.perf.readUsers.searchBySocialLinks", Boolean.class);
|
||||
|
||||
int realmNumber = realmsOffset + workerId;
|
||||
realmId = PerfTestUtils.getRealmName(realmNumber);
|
||||
|
||||
StringBuilder logBuilder = new StringBuilder("Read setup: ")
|
||||
.append("realmsOffset=" + realmsOffset)
|
||||
.append(", readUsersPerIteration=" + readUsersPerIteration)
|
||||
.append(", countOfUsersPerRealm=" + countOfUsersPerRealm)
|
||||
.append(", readRoles=" + readRoles)
|
||||
.append(", readScopes=" + readScopes)
|
||||
.append(", readPassword=" + readPassword)
|
||||
.append(", readSocialLinks=" + readSocialLinks)
|
||||
.append(", searchBySocialLinks=" + searchBySocialLinks)
|
||||
.append(", realmId=" + realmId);
|
||||
log.info(logBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(SampleResult result, KeycloakSession identitySession) {
|
||||
// We need to obtain realm first
|
||||
RealmModel realm = identitySession.getRealm(realmId);
|
||||
if (realm == null) {
|
||||
throw new IllegalStateException("Realm '" + realmId + "' not found");
|
||||
}
|
||||
|
||||
int totalIterationNumber = totalIterationCounter.incrementAndGet();
|
||||
String lastUsername = null;
|
||||
|
||||
for (int i=0 ; i<readUsersPerIteration ; i++) {
|
||||
++userCounterInRealm;
|
||||
|
||||
// Start reading users from 1
|
||||
if (userCounterInRealm > countOfUsersPerRealm) {
|
||||
userCounterInRealm = 1;
|
||||
}
|
||||
|
||||
String username = PerfTestUtils.getUsername(userCounterInRealm);
|
||||
lastUsername = username;
|
||||
|
||||
UserModel user = realm.getUser(username);
|
||||
|
||||
// Read roles of user in realm
|
||||
if (readRoles) {
|
||||
realm.getRoleMappings(user);
|
||||
}
|
||||
|
||||
// Read scopes of user in realm
|
||||
if (readScopes) {
|
||||
realm.getScope(user);
|
||||
}
|
||||
|
||||
// Validate password (shoould be same as username)
|
||||
if (readPassword) {
|
||||
realm.validatePassword(user, username);
|
||||
}
|
||||
|
||||
// Read socialLinks of user
|
||||
if (readSocialLinks) {
|
||||
realm.getSocialLinks(user);
|
||||
}
|
||||
|
||||
// Try to search by social links
|
||||
if (searchBySocialLinks) {
|
||||
SocialLinkModel socialLink = new SocialLinkModel("facebook", username);
|
||||
realm.getUserBySocialLink(socialLink);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Finished iteration " + ++iterationNumber + " in ReadUsers test for " + realmId + " worker. Last read user " + lastUsername + " in realm: " + realmId);
|
||||
|
||||
int labelC = ((totalIterationNumber - 1) / NUMBER_OF_ITERATIONS_IN_EACH_REPORT) * NUMBER_OF_ITERATIONS_IN_EACH_REPORT;
|
||||
result.setSampleLabel("ReadUsers " + (labelC + 1) + "-" + (labelC + NUMBER_OF_ITERATIONS_IN_EACH_REPORT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package org.keycloak.testsuite.performance;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.apache.jmeter.samplers.SampleResult;
|
||||
import org.apache.jorphan.logging.LoggingManager;
|
||||
import org.apache.log.Logger;
|
||||
import org.keycloak.services.models.KeycloakSession;
|
||||
import org.keycloak.services.models.RealmModel;
|
||||
import org.keycloak.services.models.SocialLinkModel;
|
||||
import org.keycloak.services.models.UserModel;
|
||||
import org.keycloak.services.models.nosql.keycloak.adapters.RealmAdapter;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class RemoveUsersWorker implements Worker {
|
||||
|
||||
private static final Logger log = LoggingManager.getLoggerForClass();
|
||||
|
||||
private static final int NUMBER_OF_USERS_IN_EACH_REPORT = 5000;
|
||||
|
||||
// Total number of users removed during whole test
|
||||
private static AtomicInteger totalUserCounter = new AtomicInteger();
|
||||
|
||||
// Removing users will always start from 1. Each worker thread needs to add users to single realm, which is dedicated just for this worker
|
||||
private int userCounterInRealm = 0;
|
||||
private RealmModel realm;
|
||||
|
||||
private int realmsOffset;
|
||||
|
||||
@Override
|
||||
public void setup(int workerId, KeycloakSession identitySession) {
|
||||
realmsOffset = PerfTestUtils.readSystemProperty("keycloak.perf.removeUsers.realms.offset", Integer.class);
|
||||
|
||||
int realmNumber = realmsOffset + workerId;
|
||||
String realmId = PerfTestUtils.getRealmName(realmNumber);
|
||||
realm = identitySession.getRealm(realmId);
|
||||
if (realm == null) {
|
||||
throw new IllegalStateException("Realm '" + realmId + "' not found");
|
||||
}
|
||||
|
||||
log.info("Read setup: realmsOffset=" + realmsOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(SampleResult result, KeycloakSession identitySession) {
|
||||
int userNumber = ++userCounterInRealm;
|
||||
int totalUserNumber = totalUserCounter.incrementAndGet();
|
||||
|
||||
String username = PerfTestUtils.getUsername(userNumber);
|
||||
|
||||
// TODO: Not supported in model actually. We support operation just in MongoDB
|
||||
// UserModel user = realm.removeUser(username);
|
||||
if (KeycloakApplication.SESSION_FACTORY_MONGO.equals(System.getProperty(KeycloakApplication.SESSION_FACTORY))) {
|
||||
RealmAdapter mongoRealm = (RealmAdapter)realm;
|
||||
mongoRealm.removeUser(username);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Actually removing of users is supported just for MongoDB");
|
||||
}
|
||||
|
||||
log.info("Finished removing of user " + username + " in realm: " + realm.getId());
|
||||
|
||||
int labelC = ((totalUserNumber - 1) / NUMBER_OF_USERS_IN_EACH_REPORT) * NUMBER_OF_USERS_IN_EACH_REPORT;
|
||||
result.setSampleLabel("ReadUsers " + (labelC + 1) + "-" + (labelC + NUMBER_OF_USERS_IN_EACH_REPORT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tearDown() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package org.keycloak.testsuite.performance;
|
||||
|
||||
import org.apache.jmeter.samplers.SampleResult;
|
||||
import org.apache.log.Logger;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public interface Worker {
|
||||
|
||||
void setup(int workerId, KeycloakSession identitySession);
|
||||
|
||||
void run(SampleResult result, KeycloakSession identitySession);
|
||||
|
||||
void tearDown();
|
||||
|
||||
}
|
20
testsuite/src/test/jmeter/jmeter.properties
Normal file
20
testsuite/src/test/jmeter/jmeter.properties
Normal file
|
@ -0,0 +1,20 @@
|
|||
#Thu Mar 07 18:46:04 BRT 2013
|
||||
not_in_menu=HTML Parameter Mask,HTTP User Parameter Modifier
|
||||
xml.parser=org.apache.xerces.parsers.SAXParser
|
||||
cookies=cookies
|
||||
wmlParser.className=org.apache.jmeter.protocol.http.parser.RegexpHTMLParser
|
||||
HTTPResponse.parsers=htmlParser wmlParser
|
||||
remote_hosts=127.0.0.1
|
||||
system.properties=system.properties
|
||||
beanshell.server.file=../extras/startup.bsh
|
||||
log_level.jmeter.junit=DEBUG
|
||||
sampleresult.timestamp.start=true
|
||||
jmeter.laf.mac=System
|
||||
log_level.jorphan=INFO
|
||||
classfinder.functions.contain=.functions.
|
||||
user.properties=user.properties
|
||||
wmlParser.types=text/vnd.wap.wml
|
||||
log_level.jmeter=DEBUG
|
||||
classfinder.functions.notContain=.gui.
|
||||
htmlParser.types=text/html application/xhtml+xml application/xml text/xml
|
||||
upgrade_properties=/bin/upgrade.properties
|
39
testsuite/src/test/jmeter/mongo_test.jmx
Normal file
39
testsuite/src/test/jmeter/mongo_test.jmx
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<jmeterTestPlan version="1.2" properties="2.4" jmeter="2.9 r1437961">
|
||||
<hashTree>
|
||||
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
|
||||
<stringProp name="TestPlan.comments"></stringProp>
|
||||
<boolProp name="TestPlan.functional_mode">false</boolProp>
|
||||
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
|
||||
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
|
||||
<collectionProp name="Arguments.arguments"/>
|
||||
</elementProp>
|
||||
<stringProp name="TestPlan.user_define_classpath"></stringProp>
|
||||
</TestPlan>
|
||||
<hashTree>
|
||||
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
|
||||
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
|
||||
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
|
||||
<boolProp name="LoopController.continue_forever">false</boolProp>
|
||||
<stringProp name="LoopController.loops">10</stringProp>
|
||||
</elementProp>
|
||||
<stringProp name="ThreadGroup.num_threads">1</stringProp>
|
||||
<stringProp name="ThreadGroup.ramp_time">0</stringProp>
|
||||
<longProp name="ThreadGroup.start_time">1362689985000</longProp>
|
||||
<longProp name="ThreadGroup.end_time">1362689985000</longProp>
|
||||
<boolProp name="ThreadGroup.scheduler">false</boolProp>
|
||||
<stringProp name="ThreadGroup.duration"></stringProp>
|
||||
<stringProp name="ThreadGroup.delay"></stringProp>
|
||||
</ThreadGroup>
|
||||
<hashTree>
|
||||
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Java Request" enabled="true">
|
||||
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true">
|
||||
<collectionProp name="Arguments.arguments">
|
||||
</collectionProp>
|
||||
</elementProp>
|
||||
<stringProp name="classname">org.keycloak.testsuite.performance.BaseJMeterPerformanceTest</stringProp>
|
||||
</JavaSampler>
|
||||
</hashTree>
|
||||
</hashTree>
|
||||
</hashTree>
|
||||
</jmeterTestPlan>
|
79
testsuite/src/test/jmeter/system.properties
Normal file
79
testsuite/src/test/jmeter/system.properties
Normal file
|
@ -0,0 +1,79 @@
|
|||
## Choose implementation of KeycloakSessionFactory
|
||||
# keycloak.sessionFactory=picketlink
|
||||
keycloak.sessionFactory=mongo
|
||||
|
||||
## Configure JPA (just hbm2ddl schema configurable here. Rest of the stuff in META-INF/persistence.xml)
|
||||
keycloak.jpa.hbm2ddl.auto=create
|
||||
# keycloak.jpa.hbm2ddl.auto=update
|
||||
|
||||
|
||||
## Configure MongoDB (Useful just when keycloak.sessionFactory=mongo)
|
||||
keycloak.mongodb.host=localhost
|
||||
keycloak.mongodb.port=27017
|
||||
keycloak.mongodb.databaseName=keycloakPerfTest
|
||||
# Should be DB dropped at startup of the test?
|
||||
keycloak.mongodb.dropDatabaseOnStartup=true
|
||||
|
||||
|
||||
## Specify Keycloak worker class
|
||||
keycloak.perf.workerClass=org.keycloak.testsuite.performance.CreateRealmsWorker
|
||||
# keycloak.perf.workerClass=org.keycloak.testsuite.performance.CreateUsersWorker
|
||||
# keycloak.perf.workerClass=org.keycloak.testsuite.performance.ReadUsersWorker
|
||||
# keycloak.perf.workerClass=org.keycloak.testsuite.performance.RemoveUsersWorker
|
||||
|
||||
|
||||
## Properties for CreateRealms test. This test is used to create some realms.
|
||||
# Each iteration of single worker thread will add one realm and it will add some roles, defaultRoles, credentials and applications to it
|
||||
# Offset where to start creating realms. Count (total number of realms to create) is configurable as number of JMeter threads*loopCount
|
||||
# For example: if offset==1 and in JMeter properties we have LoopController.loops=10 and num_threads=2 then we will create 20 realms in total and we will create realms "realm1" - "realm10"
|
||||
# NOTE: Count (total number of realms to create) is configurable as number of JMeter threads*loopCount
|
||||
keycloak.perf.createRealms.realms.offset=1
|
||||
# Count of apps per each realm (For example if count=5, we will create apps like "realm1app1" - "realm1app5" for realm "realm1"
|
||||
# and similarly for all other created realms)
|
||||
keycloak.perf.createRealms.appsPerRealm=5
|
||||
# Count of roles per each realm (For example if count=5, we will create roles like "realm1role1" - "realm1role5" for realm "realm1"
|
||||
# and similarly for all other created realms)
|
||||
keycloak.perf.createRealms.rolesPerRealm=5
|
||||
# Count of default roles per each realm (For example if count=2, we will create roles like "realm1defrole1" and "realm1defrole2"
|
||||
# for realm "realm1" and similarly for all other created realms)
|
||||
keycloak.perf.createRealms.defaultRolesPerRealm=2
|
||||
# Count of roles per each application (For example if count=3 we will have roles "realm1app1role1" - "realm1app1role3" for realm=1 and application=1
|
||||
# (if realmsCount=10, appsPerRealm=5 it will be 150 application roles totally)
|
||||
keycloak.perf.createRealms.rolesPerApp=3
|
||||
# Whether to create required credentials in each realm (If true, we will create "password", "totp" and client-certificate)
|
||||
keycloak.perf.createRealms.createRequiredCredentials=true
|
||||
|
||||
|
||||
## Properties for CreateUsers test. This test is used to create some users
|
||||
# Each iteration of single worker thread will add one user and it will add some default roles, passwords and bind him with some social accounts
|
||||
# Each worker will use separate realm dedicated just for him, so each worker will create user1, user2, ... , userN . N (number of users to create per realm)
|
||||
# is configurable in JMeter configuration as loopCount. Total number of created users for whole test will be threads*loopCount
|
||||
# NOTE: For each thread, the corresponding realm must already exists
|
||||
# Realm where to start creating users
|
||||
keycloak.perf.createUsers.realms.offset=1
|
||||
# Whether to add basic attributes like firstName/lastName/email to each user
|
||||
keycloak.perf.createUsers.addBasicUserAttributes=true
|
||||
# Whether to add all default roles of realm to this user
|
||||
keycloak.perf.createUsers.addDefaultRoles=true
|
||||
# Whether to add password to this user
|
||||
keycloak.perf.createUsers.addPassword=true
|
||||
# Number of social links to create for each user. Possible values are 0, 1, 2, 3 (For 3 it will create Facebook, Twitter and Google)
|
||||
keycloak.perf.createUsers.socialLinksPerUserCount=0
|
||||
|
||||
|
||||
## Properties for ReadUsers test. This test is used to read some users from DB and alternatively read some of his properties (passwords, roles, scopes, socialLinks)
|
||||
keycloak.perf.readUsers.realms.offset=1
|
||||
# Number of read users in each iteration
|
||||
keycloak.perf.readUsers.readUsersPerIteration=5
|
||||
# Number of users to read in each realm. After reading all 2000 users, reading will start again from user1
|
||||
keycloak.perf.readUsers.countOfUsersPerRealm=2000
|
||||
keycloak.perf.readUsers.readRoles=true
|
||||
keycloak.perf.readUsers.readScopes=true
|
||||
keycloak.perf.readUsers.readPassword=true
|
||||
keycloak.perf.readUsers.readSocialLinks=false
|
||||
keycloak.perf.readUsers.searchBySocialLinks=false
|
||||
|
||||
|
||||
## Properties for RemoveUsers worker. This test is used to remove some users from DB (and all their stuff actually)
|
||||
# Similarly like in CreateUsers test, each worker works just with one realm. Number of removed users depends on JMeter property loopCount
|
||||
keycloak.perf.removeUsers.realms.offset=1
|
|
@ -0,0 +1,40 @@
|
|||
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
|
||||
version="1.0">
|
||||
<persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
|
||||
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
||||
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
|
||||
<class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
|
||||
<class>org.keycloak.services.models.picketlink.mappings.RealmEntity</class>
|
||||
<class>org.keycloak.services.models.picketlink.mappings.ApplicationEntity</class>
|
||||
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
|
||||
<properties>
|
||||
<property name="hibernate.connection.url" value="jdbc:mysql://localhost/keycloakPerfTest"/>
|
||||
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
|
||||
<property name="hibernate.connection.username" value="portal"/>
|
||||
<property name="hibernate.connection.password" value="portal"/>
|
||||
<!--<property name="hibernate.hbm2ddl.auto" value="create" />-->
|
||||
<!--<property name="hibernate.hbm2ddl.auto" value="update" />-->
|
||||
<property name="hibernate.hbm2ddl.auto" value="${keycloak.jpa.hbm2ddl.auto}" />
|
||||
<property name="hibernate.show_sql" value="false" />
|
||||
<property name="hibernate.format_sql" value="true" />
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
|
||||
|
||||
</persistence>
|
Loading…
Reference in a new issue