keycloak-memoizeit
Changes
pom.xml 2(+1 -1)
testsuite/performance-web/pom.xml 106(+106 -0)
testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/KeycloakPerfServer.java 87(+87 -0)
testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/KeycloakToolsApplication.java 42(+42 -0)
testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/PerfAppServlet.java 39(+39 -0)
testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/ProviderSessionFactoryHolder.java 21(+21 -0)
testsuite/pom.xml 1(+1 -0)
Details
pom.xml 2(+1 -1)
diff --git a/pom.xml b/pom.xml
index 9d6f311..1383a9e 100755
--- a/pom.xml
+++ b/pom.xml
@@ -174,7 +174,7 @@
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-undertow</artifactId>
- <version>${resteasy.version}</version>
+ <version>${resteasy.version.latest}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
diff --git a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
index e867087..6f2aaf9 100755
--- a/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
+++ b/testsuite/integration/src/main/java/org/keycloak/testutils/KeycloakServer.java
@@ -95,6 +95,10 @@ public class KeycloakServer {
}
public static void main(String[] args) throws Throwable {
+ bootstrapKeycloakServer(args);
+ }
+
+ public static KeycloakServer bootstrapKeycloakServer(String[] args) throws Throwable {
KeycloakServerConfig config = new KeycloakServerConfig();
for (int i = 0; i < args.length; i++) {
@@ -158,6 +162,8 @@ public class KeycloakServer {
keycloak.stop();
}
});
+
+ return keycloak;
}
private KeycloakServerConfig config;
testsuite/performance-web/pom.xml 106(+106 -0)
diff --git a/testsuite/performance-web/pom.xml b/testsuite/performance-web/pom.xml
new file mode 100644
index 0000000..7ca6bac
--- /dev/null
+++ b/testsuite/performance-web/pom.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-testsuite-pom</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.0-beta-4-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-testsuite-performance-web</artifactId>
+ <name>Keycloak TestSuite for Web Performance</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-testsuite-integration</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-testsuite-tools</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <!-- Resteasy deps specified here as we want latest version of them -->
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>jaxrs-api</artifactId>
+ <version>${resteasy.version.latest}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <version>${resteasy.version.latest}</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>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-client</artifactId>
+ <version>${resteasy.version.latest}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-crypto</artifactId>
+ <version>${resteasy.version.latest}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-multipart-provider</artifactId>
+ <version>${resteasy.version.latest}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jackson-provider</artifactId>
+ <version>${resteasy.version.latest}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-undertow</artifactId>
+ <version>${resteasy.version.latest}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <configuration>
+ <workingDirectory>${project.basedir}</workingDirectory>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/KeycloakPerfServer.java b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/KeycloakPerfServer.java
new file mode 100644
index 0000000..55cc44f
--- /dev/null
+++ b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/KeycloakPerfServer.java
@@ -0,0 +1,87 @@
+package org.keycloak.testsuite.performance.web;
+
+import java.io.InputStream;
+
+import javax.servlet.DispatcherType;
+
+import io.undertow.servlet.Servlets;
+import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.api.FilterInfo;
+import io.undertow.servlet.api.ServletInfo;
+import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
+import org.jboss.resteasy.spi.ResteasyDeployment;
+import org.keycloak.services.filters.ClientConnectionFilter;
+import org.keycloak.services.filters.KeycloakSessionServletFilter;
+import org.keycloak.test.tools.KeycloakTestApplication;
+import org.keycloak.testutils.KeycloakServer;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KeycloakPerfServer {
+
+ private KeycloakServer keycloakServer;
+
+ public static void main(String[] args) throws Throwable {
+ KeycloakServer keycloakServer = KeycloakServer.bootstrapKeycloakServer(args);
+ System.out.println("Keycloak server bootstrapped");
+
+ ProviderSessionFactoryHolder.setProviderSessionFactory(keycloakServer.getProviderSessionFactory());
+ new KeycloakPerfServer(keycloakServer).start();
+ }
+
+ public KeycloakPerfServer(KeycloakServer keycloakServer) {
+ this.keycloakServer = keycloakServer;
+ }
+
+ public void start() {
+ importPerfRealm();
+ deployPerfTools();
+ deployPerfApp();
+ }
+
+ protected void importPerfRealm() {
+ InputStream perfRealmStream = KeycloakPerfServer.class.getClassLoader().getResourceAsStream("perfrealm.json");
+ keycloakServer.importRealm(perfRealmStream);
+ }
+
+ protected void deployPerfTools() {
+ ResteasyDeployment deployment = new ResteasyDeployment();
+ deployment.setApplicationClass(KeycloakToolsApplication.class.getName());
+
+ UndertowJaxrsServer server = keycloakServer.getServer();
+
+ DeploymentInfo di = server.undertowDeployment(deployment, "");
+ di.setClassLoader(KeycloakTestApplication.class.getClassLoader());
+ di.setContextPath("/keycloak-tools");
+ di.setDeploymentName("KeycloakTools");
+
+ FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
+ di.addFilter(filter);
+ di.addFilterUrlMapping("SessionFilter", "/perf/*", DispatcherType.REQUEST);
+
+ FilterInfo connectionFilter = Servlets.filter("ClientConnectionFilter", ClientConnectionFilter.class);
+ di.addFilter(connectionFilter);
+ di.addFilterUrlMapping("ClientConnectionFilter", "/perf/*", DispatcherType.REQUEST);
+
+ server.deploy(di);
+
+ System.out.println("Keycloak tools deployed");
+ }
+
+ protected void deployPerfApp() {
+ DeploymentInfo deploymentInfo = new DeploymentInfo();
+ deploymentInfo.setClassLoader(getClass().getClassLoader());
+ deploymentInfo.setDeploymentName("PerfApp");
+ deploymentInfo.setContextPath("/perf-app");
+
+ ServletInfo servlet = new ServletInfo("PerfAppServlet", PerfAppServlet.class);
+ servlet.addMapping("/*");
+
+ deploymentInfo.addServlet(servlet);
+
+ keycloakServer.getServer().deploy(deploymentInfo);
+
+ System.out.println("PerfApp deployed");
+ }
+}
diff --git a/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/KeycloakToolsApplication.java b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/KeycloakToolsApplication.java
new file mode 100644
index 0000000..94798d9
--- /dev/null
+++ b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/KeycloakToolsApplication.java
@@ -0,0 +1,42 @@
+package org.keycloak.testsuite.performance.web;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
+
+import org.jboss.resteasy.core.Dispatcher;
+import org.keycloak.provider.ProviderSessionFactory;
+import org.keycloak.test.tools.PerfTools;
+
+/**
+ * Modified version of {@link org.keycloak.test.tools.KeycloakTestApplication}, which shares ProviderSessionFactory with KeycloakApplication
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KeycloakToolsApplication extends Application {
+
+ protected ProviderSessionFactory providerSessionFactory;
+ protected Set<Class<?>> classes = new HashSet<Class<?>>();
+ protected Set<Object> singletons = new HashSet<Object>();
+
+ public KeycloakToolsApplication(@Context ServletContext context, @Context Dispatcher dispatcher) {
+ this.providerSessionFactory = ProviderSessionFactoryHolder.getProviderSessionFactory();
+ context.setAttribute(ProviderSessionFactory.class.getName(), this.providerSessionFactory);
+ singletons.add(new PerfTools(providerSessionFactory));
+ }
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ return classes;
+ }
+
+ @Override
+ public Set<Object> getSingletons() {
+ return singletons;
+ }
+
+
+}
diff --git a/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/PerfAppServlet.java b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/PerfAppServlet.java
new file mode 100644
index 0000000..cc38ae6
--- /dev/null
+++ b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/PerfAppServlet.java
@@ -0,0 +1,39 @@
+package org.keycloak.testsuite.performance.web;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class PerfAppServlet extends HttpServlet {
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String resourcePath = "perf-app-resources" + req.getPathInfo();
+ System.out.println("Resource path: " + resourcePath);
+
+ InputStream inputStream = getClass().getClassLoader().getResourceAsStream(resourcePath);
+ if (inputStream == null) {
+ resp.getWriter().println("Not found: " + resourcePath);
+ } else {
+ OutputStream servletOutputStream = resp.getOutputStream();
+
+ byte[] buf = new byte[1024];
+ int bytesRead = 0;
+ while (bytesRead != -1) {
+ bytesRead = inputStream.read(buf);
+ if (bytesRead != -1) {
+ servletOutputStream.write(buf, 0, bytesRead);
+ }
+ }
+ servletOutputStream.flush();
+ }
+ }
+}
diff --git a/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/ProviderSessionFactoryHolder.java b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/ProviderSessionFactoryHolder.java
new file mode 100644
index 0000000..ea1420b
--- /dev/null
+++ b/testsuite/performance-web/src/main/java/org/keycloak/testsuite/performance/web/ProviderSessionFactoryHolder.java
@@ -0,0 +1,21 @@
+package org.keycloak.testsuite.performance.web;
+
+import org.keycloak.provider.ProviderSessionFactory;
+
+/**
+ * Static holder to allow sharing ProviderSessionFactory among different JAX-RS applications
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ProviderSessionFactoryHolder {
+
+ private static ProviderSessionFactory providerSessionFactory;
+
+ public static ProviderSessionFactory getProviderSessionFactory() {
+ return providerSessionFactory;
+ }
+
+ public static void setProviderSessionFactory(ProviderSessionFactory providerSessionFactory) {
+ ProviderSessionFactoryHolder.providerSessionFactory = providerSessionFactory;
+ }
+}
diff --git a/testsuite/performance-web/src/main/resources/perf-app-resources/index.html b/testsuite/performance-web/src/main/resources/perf-app-resources/index.html
new file mode 100644
index 0000000..c5b7c53
--- /dev/null
+++ b/testsuite/performance-web/src/main/resources/perf-app-resources/index.html
@@ -0,0 +1,110 @@
+<html>
+<head>
+ <script src="/auth/js/keycloak.js"></script>
+</head>
+<body>
+
+<div>
+ <button onclick="keycloak.login()">Login</button>
+ <button onclick="keycloak.logout()">Logout</button>
+ <button onclick="refreshToken(9999)">Refresh Token</button>
+ <button onclick="refreshToken(30)">Refresh Token (if <30s validity)</button>
+ <button onclick="loadProfile()">Get Profile</button>
+ <button onclick="output(keycloak.tokenParsed)">Show Token</button>
+ <button onclick="output(keycloak.refreshTokenParsed)">Show Refresh Token</button>
+ <button onclick="showExpires()">Show Expires</button>
+ <button onclick="output(keycloak.idToken)">Show ID Token</button>
+ <button onclick="output(keycloak)">Show Details</button>
+ <button onclick="output(keycloak.createLoginUrl())">Show Login URL</button>
+ <button onclick="output(keycloak.createLogoutUrl())">Show Logout URL</button>
+</div>
+
+<h2>Result</h2>
+<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="output"></pre>
+
+<h2>Events</h2>
+<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="events"></pre>
+
+
+<script>
+ function loadProfile() {
+ keycloak.loadUserProfile().success(function(profile) {
+ output(profile);
+ }).error(function() {
+ output('Failed to load profile');
+ });
+ }
+
+ function refreshToken(minValidity) {
+ keycloak.updateToken(minValidity).success(function(refreshed) {
+ if (refreshed) {
+ output(keycloak.tokenParsed);
+ } else {
+ output('Token not refreshed, valid for ' + Math.round(keycloak.tokenParsed.exp - new Date().getTime() / 1000) + ' seconds');
+ }
+ }).error(function() {
+ output('Failed to refresh token');
+ });
+ }
+
+ function showExpires() {
+ if (!keycloak.tokenParsed) {
+ output("Not authenticated");
+ return;
+ }
+
+ var o = 'Token Expires:\t\t' + new Date(keycloak.tokenParsed.exp * 1000).toLocaleString() + '\n';
+ o += 'Token Expires in:\t' + Math.round(keycloak.tokenParsed.exp - new Date().getTime() / 1000) + ' seconds\n';
+
+ o += 'Refresh Token Expires:\t' + new Date(keycloak.refreshTokenParsed.exp * 1000).toLocaleString() + '\n';
+ o += 'Refresh Expires in:\t' + Math.round(keycloak.refreshTokenParsed.exp - new Date().getTime() / 1000) + ' seconds';
+ output(o);
+ }
+
+ function output(data) {
+ if (typeof data === 'object') {
+ data = JSON.stringify(data, null, ' ');
+ }
+ document.getElementById('output').innerHTML = data;
+ }
+
+ function event(event) {
+ var e = document.getElementById('events').innerHTML;
+ document.getElementById('events').innerHTML = new Date().toLocaleString() + "\t" + event + "\n" + e;
+ }
+
+ var keycloak = Keycloak({
+ url: "/auth",
+ realm: "perf-realm",
+ clientId: "perf-app"
+ });
+
+ keycloak.onAuthSuccess = function () {
+ event('Auth Success');
+ };
+
+ keycloak.onAuthError = function () {
+ event('Auth Error');
+ };
+
+ keycloak.onAuthRefreshSuccess = function () {
+ event('Auth Refresh Success');
+ };
+
+ keycloak.onAuthRefreshError = function () {
+ event('Auth Refresh Error');
+ };
+
+ keycloak.onAuthLogout = function () {
+ event('Auth Logout');
+ };
+
+ keycloak.init().success(function(authenticated) {
+ output('Init Success (' + (authenticated ? 'Authenticated' : 'Not Authenticated') + ')');
+ }).error(function() {
+ output('Init Error');
+ });
+
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/testsuite/performance-web/src/main/resources/perfrealm.json b/testsuite/performance-web/src/main/resources/perfrealm.json
new file mode 100644
index 0000000..aaa7fc4
--- /dev/null
+++ b/testsuite/performance-web/src/main/resources/perfrealm.json
@@ -0,0 +1,108 @@
+{
+ "id": "perf-realm",
+ "realm": "perf-realm",
+ "enabled": true,
+ "sslNotRequired": true,
+ "registrationAllowed": true,
+ "resetPasswordAllowed": true,
+ "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+ "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+ "requiredCredentials": [ "password" ],
+ "defaultRoles": [ "user" ],
+ "smtpServer": {
+ "from": "auto@keycloak.org",
+ "host": "localhost",
+ "port":"3025"
+ },
+ "users" : [
+ {
+ "username" : "test-user@localhost",
+ "enabled": true,
+ "email" : "test-user@localhost",
+ "credentials" : [
+ { "type" : "password",
+ "value" : "password" }
+ ]
+ }
+ ],
+ "oauthClients" : [
+ {
+ "name" : "third-party",
+ "enabled": true,
+ "redirectUris": [
+ "http://localhost:8081/app/*"
+ ],
+ "secret": "password"
+ }
+ ],
+ "roleMappings": [
+ {
+ "username": "test-user@localhost",
+ "roles": ["user"]
+ }
+ ],
+ "scopeMappings": [
+ {
+ "client": "third-party",
+ "roles": ["user"]
+ },
+ {
+ "client": "perf-app",
+ "roles": ["user"]
+ }
+ ],
+ "applications": [
+ {
+ "name": "perf-app",
+ "enabled": true,
+ "baseUrl": "http://localhost:8081/perf-app",
+ "redirectUris": [
+ "http://localhost:8081/perf-app/*"
+ ],
+ "adminUrl": "http://localhost:8081/perf-app/logout",
+ "secret": "password"
+ }
+ ],
+ "roles" : {
+ "realm" : [
+ {
+ "name": "user",
+ "description": "Have User privileges"
+ },
+ {
+ "name": "admin",
+ "description": "Have Administrator privileges"
+ }
+ ],
+ "application" : {
+ "perf-app" : [
+ {
+ "name": "customer-user",
+ "description": "Have Customer User privileges"
+ },
+ {
+ "name": "customer-admin",
+ "description": "Have Customer Admin privileges"
+ }
+ ]
+ }
+
+ },
+
+ "applicationRoleMappings": {
+ "perf-app": [
+ {
+ "username": "test-user@localhost",
+ "roles": ["customer-user"]
+ }
+ ]
+ },
+ "applicationScopeMappings": {
+ "perf-app": [
+ {
+ "client": "third-party",
+ "roles": ["customer-user"]
+ }
+ ]
+ }
+}
\ No newline at end of file
testsuite/pom.xml 1(+1 -0)
diff --git a/testsuite/pom.xml b/testsuite/pom.xml
index 36085e7..7961ca5 100755
--- a/testsuite/pom.xml
+++ b/testsuite/pom.xml
@@ -28,6 +28,7 @@
<module>integration</module>
<module>performance</module>
<module>tools</module>
+ <module>performance-web</module>
</modules>
</project>