keycloak-aplcache

KEYCLOAK-2589 Copy AssertEvents to Arquillian testsuite

3/24/2016 12:08:36 PM

Changes

Details

diff --git a/core/src/main/java/org/keycloak/representations/idm/EventRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/EventRepresentation.java
index 93be310..0621b9b 100644
--- a/core/src/main/java/org/keycloak/representations/idm/EventRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/EventRepresentation.java
@@ -105,4 +105,37 @@ public class EventRepresentation {
     public void setDetails(Map<String, String> details) {
         this.details = details;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        EventRepresentation that = (EventRepresentation) o;
+
+        if (time != that.time) return false;
+        if (type != null ? !type.equals(that.type) : that.type != null) return false;
+        if (realmId != null ? !realmId.equals(that.realmId) : that.realmId != null) return false;
+        if (clientId != null ? !clientId.equals(that.clientId) : that.clientId != null) return false;
+        if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
+        if (sessionId != null ? !sessionId.equals(that.sessionId) : that.sessionId != null) return false;
+        if (ipAddress != null ? !ipAddress.equals(that.ipAddress) : that.ipAddress != null) return false;
+        if (error != null ? !error.equals(that.error) : that.error != null) return false;
+        return !(details != null ? !details.equals(that.details) : that.details != null);
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = (int) (time ^ (time >>> 32));
+        result = 31 * result + (type != null ? type.hashCode() : 0);
+        result = 31 * result + (realmId != null ? realmId.hashCode() : 0);
+        result = 31 * result + (clientId != null ? clientId.hashCode() : 0);
+        result = 31 * result + (userId != null ? userId.hashCode() : 0);
+        result = 31 * result + (sessionId != null ? sessionId.hashCode() : 0);
+        result = 31 * result + (ipAddress != null ? ipAddress.hashCode() : 0);
+        result = 31 * result + (error != null ? error.hashCode() : 0);
+        result = 31 * result + (details != null ? details.hashCode() : 0);
+        return result;
+    }
 }
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/build.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/build.xml
new file mode 100644
index 0000000..b34fc7d
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/build.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project name="inject-provider" basedir="." default="inject-provider">
+
+    <scriptdef name="inject-provider" language="javascript"  manager="bsf">
+        <attribute name="path"/>
+        <![CDATA[
+            importClass(Packages.java.io.File);
+            importClass(Packages.org.keycloak.util.JsonSerialization);
+
+            path = attributes.get("path");
+            file = new File(path);
+            root = JsonSerialization.mapper.readTree(file);
+
+            // inject provider
+            providers = root.withArray("providers");
+            providers.add("module:org.keycloak.testsuite.integration-arquillian-event-queue");
+
+            // save file
+            JsonSerialization.prettyMapper.writeValue(file, root);
+        ]]>
+    </scriptdef>
+
+    <target name="inject-provider">
+        <inject-provider path="${auth.server.home}/standalone/configuration/keycloak-server.json"/>
+    </target>
+</project>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
index 72c2f98..1468f79 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
@@ -97,13 +97,102 @@
                                     </artifactItems>
                                 </configuration>
                             </execution>
+                            <execution>
+                                <id>copy-event-queue-provider</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>copy</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.keycloak.testsuite</groupId>
+                                            <artifactId>integration-arquillian-event-queue</artifactId>
+                                            <version>${project.version}</version>
+                                            <type>jar</type>
+                                            <overWrite>false</overWrite>
+                                            <outputDirectory>${auth.server.home}/modules/org/keycloak/testsuite/integration-arquillian-event-queue/main</outputDirectory>
+                                        </artifactItem>
+                                    </artifactItems>
+                                </configuration>
+                            </execution>
+                            <execution>
+                                <id>install-event-queue-module</id>
+                                <phase>generate-resources</phase>
+                                <goals>
+                                    <goal>unpack</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.keycloak.testsuite</groupId>
+                                            <artifactId>integration-arquillian-event-queue</artifactId>
+                                            <version>${project.version}</version>
+                                            <type>jar</type>
+                                            <outputDirectory>${auth.server.home}/modules</outputDirectory>
+                                            <includes>**/module.xml</includes>
+                                        </artifactItem>
+                                    </artifactItems>
+                                </configuration>
+                            </execution>
                         </executions>
                     </plugin>
                     <plugin>
-                        <artifactId>maven-enforcer-plugin</artifactId>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-antrun-plugin</artifactId>
+                        <version>1.8</version>
+                        <executions>
+                            <execution>
+                                <id>inject-into-keycloak-server-json</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <target>
+                                        <ant antfile="../build.xml" inheritRefs="true">
+                                            <target name="inject-provider"/>
+                                        </ant>
+                                    </target>
+                                </configuration>
+                            </execution>
+                        </executions>
+                        <dependencies>
+                            <dependency>
+                                <groupId>ant-contrib</groupId>
+                                <artifactId>ant-contrib</artifactId>
+                                <version>1.0b3</version>
+                                <exclusions>
+                                    <exclusion>
+                                        <groupId>ant</groupId>
+                                        <artifactId>ant</artifactId>
+                                    </exclusion>
+                                </exclusions>
+                            </dependency>
+                            <dependency>
+                                <groupId>org.apache.ant</groupId>
+                                <artifactId>ant-apache-bsf</artifactId>
+                                <version>1.9.3</version>
+                            </dependency>
+                            <dependency>
+                                <groupId>org.apache.bsf</groupId>
+                                <artifactId>bsf-api</artifactId>
+                                <version>3.1</version>
+                            </dependency>
+                            <dependency>
+                                <groupId>rhino</groupId>
+                                <artifactId>js</artifactId>
+                                <version>1.7R2</version>
+                            </dependency>
+                            <dependency>
+                                <groupId>org.keycloak</groupId>
+                                <artifactId>keycloak-core</artifactId>
+                                <version>${project.version}</version>
+                            </dependency>
+                        </dependencies>
                     </plugin>
                     <plugin>
-                        <artifactId>maven-antrun-plugin</artifactId>
+                        <artifactId>maven-enforcer-plugin</artifactId>
                     </plugin>
                     <plugin>
                         <groupId>org.codehaus.mojo</groupId>
diff --git a/testsuite/integration-arquillian/servers/auth-server/pom.xml b/testsuite/integration-arquillian/servers/auth-server/pom.xml
index d9f8222..f37234d 100644
--- a/testsuite/integration-arquillian/servers/auth-server/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/pom.xml
@@ -30,6 +30,7 @@
     <name>Auth Server</name>
 
     <modules>
+        <module>services</module>
         <module>jboss</module>
         <module>undertow</module>
     </modules>
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/pom.xml b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/pom.xml
new file mode 100644
index 0000000..47ae3e4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-servers-auth-server-services</artifactId>
+        <version>1.9.2.Final-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>integration-arquillian-event-queue</artifactId>
+    <name>Auth Server Services - Event Queue</name>
+
+    <dependencies>
+
+        <!-- Keycloak deps for tests -->
+
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-dependencies-server-all</artifactId>
+            <type>pom</type>
+        </dependency>
+
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.undertow</groupId>
+            <artifactId>undertow-servlet</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <configuration>
+                        <skip>true</skip>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+    </build>
+</project>
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/AssertEventsServletFilter.java b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/AssertEventsServletFilter.java
new file mode 100644
index 0000000..6d0d4ed
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/AssertEventsServletFilter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.events;
+
+import org.keycloak.events.Event;
+import org.keycloak.util.JsonSerialization;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.concurrent.BlockingQueue;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class AssertEventsServletFilter implements Filter {
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        HttpServletRequest req = (HttpServletRequest) servletRequest;
+
+        if ("/event-queue".equals(req.getRequestURI().substring(req.getContextPath().length()))) {
+            BlockingQueue<Event> events = EventsListenerProvider.getInstance();
+            HttpServletResponse resp = (HttpServletResponse) servletResponse;
+            resp.setContentType("application/json");
+
+            Event event = events.poll();
+            if (event != null) {
+                JsonSerialization.writeValueToStream(servletResponse.getOutputStream(), event);
+            } else {
+                resp.setStatus(204);
+            }
+        } else {
+            filterChain.doFilter(servletRequest, servletResponse);
+        }
+    }
+
+    @Override
+    public void destroy() {
+    }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsListenerProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsListenerProvider.java
new file mode 100644
index 0000000..a4a1a40
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsListenerProvider.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.events;
+
+import org.keycloak.events.Event;
+import org.keycloak.events.EventListenerProvider;
+import org.keycloak.events.admin.AdminEvent;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class EventsListenerProvider implements EventListenerProvider {
+
+    private static final BlockingQueue<Event> events = new LinkedBlockingQueue<Event>();
+
+    @Override
+    public void onEvent(Event event) {
+        events.add(event);
+    }
+
+    @Override
+    public void onEvent(AdminEvent event, boolean includeRepresentation) {
+        // TODO: implement if needed
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    public static BlockingQueue<Event> getInstance() {
+        return events;
+    }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsListenerProviderFactory.java b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsListenerProviderFactory.java
new file mode 100644
index 0000000..aecc01a
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsListenerProviderFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.events;
+
+import org.keycloak.Config;
+import org.keycloak.events.EventListenerProvider;
+import org.keycloak.events.EventListenerProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class EventsListenerProviderFactory implements EventListenerProviderFactory {
+
+    private static final EventsListenerProvider INSTANCE = new EventsListenerProvider();
+
+    private EventsServer server = new EventsServer();
+
+    @Override
+    public EventListenerProvider create(KeycloakSession session) {
+        return INSTANCE;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+        server.start();
+    }
+
+    @Override
+    public void close() {
+        server.stop();
+    }
+
+    @Override
+    public String getId() {
+        return "event-queue";
+    }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsServer.java b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsServer.java
new file mode 100644
index 0000000..0b04ee3
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/java/org/keycloak/testsuite/events/EventsServer.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.events;
+
+import io.undertow.Undertow;
+import io.undertow.server.handlers.PathHandler;
+import io.undertow.servlet.Servlets;
+import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.api.DeploymentManager;
+import io.undertow.servlet.api.FilterInfo;
+import io.undertow.servlet.api.ServletContainer;
+import io.undertow.servlet.api.ServletContainer.Factory;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.ServletException;
+import java.util.logging.Logger;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class EventsServer {
+
+    private static final Logger log = Logger.getLogger(EventsServer.class.getName());
+
+    private String rootPath = "/";
+    private int port;
+    private Undertow server;
+
+    public EventsServer() {
+        int eventsPort = Integer.parseInt(System.getProperty("auth.server.events.http.port", "8089"));
+        int portOffset = Integer.parseInt(System.getProperty("auth.server.port.offset", "0"));
+        int jbossPortOffset = Integer.parseInt(System.getProperty("jboss.socket.binding.port-offset", "-1"));
+
+        log.fine("Configuration:");
+        log.fine("  auth.server.events.http.port: " + eventsPort);
+        log.fine("  auth.server.port.offset: " + portOffset);
+        log.fine("  jboss.socket.binding.port-offset: " + jbossPortOffset);
+        port = eventsPort + (jbossPortOffset != -1 ? jbossPortOffset : portOffset);
+    }
+
+    public void start() {
+
+        PathHandler root = new PathHandler();
+        this.server = Undertow.builder().addHttpListener(port, "localhost").setHandler(root).build();
+        this.server.start();
+
+        ServletContainer container = Factory.newInstance();
+
+        DeploymentInfo di = new DeploymentInfo();
+        di.setClassLoader(getClass().getClassLoader());
+        di.setContextPath(rootPath);
+        di.setDeploymentName("testing-event-queue");
+
+        FilterInfo filter = Servlets.filter("EventsFilter", AssertEventsServletFilter.class);
+        di.addFilter(filter);
+        di.addFilterUrlMapping("EventsFilter", "/event-queue", DispatcherType.REQUEST);
+
+        DeploymentManager manager = container.addDeployment(di);
+        manager.deploy();
+
+        try {
+            root.addPrefixPath(rootPath, manager.start());
+        } catch (ServletException e) {
+            throw new RuntimeException(e);
+        }
+        log.info("Started EventsServer on port: " + port);
+    }
+
+    public void stop() {
+        this.server.stop();
+    }
+
+    public void setRootPath(String rootPath) {
+        this.rootPath = rootPath;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory
new file mode 100644
index 0000000..e995149
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/META-INF/services/org.keycloak.events.EventListenerProviderFactory
@@ -0,0 +1,35 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.testsuite.events.EventsListenerProviderFactory
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/org/keycloak/testsuite/integration-arquillian-event-queue/main/module.xml b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/org/keycloak/testsuite/integration-arquillian-event-queue/main/module.xml
new file mode 100644
index 0000000..19f3d41
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/event-queue/src/main/resources/org/keycloak/testsuite/integration-arquillian-event-queue/main/module.xml
@@ -0,0 +1,30 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.testsuite.integration-arquillian-event-queue">
+    <resources>
+        <resource-root path="integration-arquillian-event-queue-${project.version}.jar"/>
+    </resources>
+    <dependencies>
+        <module name="javax.api"/>
+        <module name="javax.servlet.api"/>
+        <module name="io.undertow.core"/>
+        <module name="io.undertow.servlet"/>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-server-spi"/>
+    </dependencies>
+</module>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/pom.xml b/testsuite/integration-arquillian/servers/auth-server/services/pom.xml
new file mode 100644
index 0000000..4684ec0
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-servers-auth-server</artifactId>
+        <version>1.9.2.Final-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>integration-arquillian-servers-auth-server-services</artifactId>
+    <packaging>pom</packaging>
+    <name>Auth Server Services</name>
+
+    <modules>
+        <module>event-queue</module>
+    </modules>
+
+</project>
diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml
index 662a102..bcec08c 100644
--- a/testsuite/integration-arquillian/tests/base/pom.xml
+++ b/testsuite/integration-arquillian/tests/base/pom.xml
@@ -57,6 +57,11 @@
             <artifactId>commons-configuration</artifactId>
             <version>1.10</version>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak.testsuite</groupId>
+            <artifactId>integration-arquillian-event-queue</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
     
     <build>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AbstractEventTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AbstractEventTest.java
index ba50fe7..597556c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AbstractEventTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AbstractEventTest.java
@@ -38,7 +38,7 @@ public abstract class AbstractEventTest extends AbstractAuthTest {
         configRep.setAdminEventsDetailsEnabled(false);
         configRep.setAdminEventsEnabled(false);
         configRep.setEventsEnabled(false);
-        configRep.setEnabledEventTypes(Collections.EMPTY_LIST); // resets to all types
+        configRep.setEnabledEventTypes(Collections.<String>emptyList()); // resets to all types
         saveConfig();
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java
new file mode 100644
index 0000000..8e4c92a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AssertEvents.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.Assert;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
+import org.keycloak.common.util.PemUtils;
+import org.keycloak.events.Details;
+import org.keycloak.events.EventType;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.UserSessionRepresentation;
+import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.TokenUtil;
+
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class AssertEvents {
+
+    static final String DEFAULT_CLIENT_ID = "test-app";
+    static final String DEFAULT_IP_ADDRESS = "127.0.0.1";
+    static final String DEFAULT_REALM = "test";
+    static final String DEFAULT_USERNAME = "test-user@localhost";
+
+    String defaultRedirectUri = "http://localhost:8081/app/auth";
+    String defaultEventsQueueUri = "http://localhost:8092";
+
+    private RealmResource realmResource;
+    private RealmRepresentation realmRep;
+    private AbstractKeycloakTest context;
+    private PublicKey realmPublicKey;
+    private UserRepresentation defaultUser;
+
+    public AssertEvents(AbstractKeycloakTest ctx) throws Exception {
+        context = ctx;
+
+        realmResource = context.adminClient.realms().realm(DEFAULT_REALM);
+        realmRep = realmResource.toRepresentation();
+        String pubKeyString = realmRep.getPublicKey();
+        realmPublicKey = PemUtils.decodePublicKey(pubKeyString);
+
+        defaultUser = getUser(DEFAULT_USERNAME);
+        if (defaultUser == null) {
+            throw new RuntimeException("Default user does not exist: " + DEFAULT_USERNAME + ". Make sure to add it to your test realm.");
+        }
+
+        defaultEventsQueueUri = getAuthServerEventsQueueUri();
+    }
+
+    String getAuthServerEventsQueueUri() {
+        int httpPort = Integer.parseInt(System.getProperty("auth.server.event.http.port", "8089"));
+        int portOffset = Integer.parseInt(System.getProperty("auth.server.port.offset", "0"));
+        return "http://localhost:" + (httpPort + portOffset);
+    }
+
+    public EventRepresentation poll() {
+        EventRepresentation event = fetchNextEvent();
+        Assert.assertNotNull("Event expected", event);
+
+        return event;
+    }
+
+    public void clear() {
+        realmResource.clearEvents();
+    }
+
+    public ExpectedEvent expectRequiredAction(EventType event) {
+        return expectLogin().event(event).removeDetail(Details.CONSENT).session(isUUID());
+    }
+
+    public ExpectedEvent expectLogin() {
+        return expect(EventType.LOGIN)
+                .detail(Details.CODE_ID, isCodeId())
+                //.detail(Details.USERNAME, DEFAULT_USERNAME)
+                //.detail(Details.AUTH_METHOD, OIDCLoginProtocol.LOGIN_PROTOCOL)
+                //.detail(Details.AUTH_TYPE, AuthorizationEndpoint.CODE_AUTH_TYPE)
+                .detail(Details.REDIRECT_URI, defaultRedirectUri)
+                .detail(Details.CONSENT, Details.CONSENT_VALUE_NO_CONSENT_REQUIRED)
+                .session(isUUID());
+    }
+
+    public ExpectedEvent expectClientLogin() {
+        return expect(EventType.CLIENT_LOGIN)
+                .detail(Details.CODE_ID, isCodeId())
+                .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
+                .detail(Details.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS)
+                .removeDetail(Details.CODE_ID)
+                .session(isUUID());
+    }
+
+    public ExpectedEvent expectSocialLogin() {
+        return expect(EventType.LOGIN)
+                .detail(Details.CODE_ID, isCodeId())
+                .detail(Details.USERNAME, DEFAULT_USERNAME)
+                .detail(Details.AUTH_METHOD, "form")
+                .detail(Details.REDIRECT_URI, defaultRedirectUri)
+                .session(isUUID());
+    }
+
+    public ExpectedEvent expectCodeToToken(String codeId, String sessionId) {
+        return expect(EventType.CODE_TO_TOKEN)
+                .detail(Details.CODE_ID, codeId)
+                .detail(Details.TOKEN_ID, isUUID())
+                .detail(Details.REFRESH_TOKEN_ID, isUUID())
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_REFRESH)
+                .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
+                .session(sessionId);
+    }
+
+    public ExpectedEvent expectRefresh(String refreshTokenId, String sessionId) {
+        return expect(EventType.REFRESH_TOKEN)
+                .detail(Details.TOKEN_ID, isUUID())
+                .detail(Details.REFRESH_TOKEN_ID, refreshTokenId)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_REFRESH)
+                .detail(Details.UPDATED_REFRESH_TOKEN_ID, isUUID())
+                .detail(Details.CLIENT_AUTH_METHOD, ClientIdAndSecretAuthenticator.PROVIDER_ID)
+                .session(sessionId);
+    }
+
+    public ExpectedEvent expectLogout(String sessionId) {
+        return expect(EventType.LOGOUT).client((String) null)
+                .detail(Details.REDIRECT_URI, defaultRedirectUri)
+                .session(sessionId);
+    }
+
+    public ExpectedEvent expectRegister(String username, String email) {
+        UserRepresentation user = username != null ? getUser(username) : null;
+        return expect(EventType.REGISTER)
+                .user(user != null ? user.getId() : null)
+                .detail(Details.USERNAME, username)
+                .detail(Details.EMAIL, email)
+                .detail(Details.REGISTER_METHOD, "form")
+                .detail(Details.REDIRECT_URI, defaultRedirectUri);
+    }
+
+    public ExpectedEvent expectAccount(EventType event) {
+        return expect(event).client("account");
+    }
+
+    public ExpectedEvent expect(EventType event) {
+        return new ExpectedEvent()
+                .realm(realmRep.getId())
+                .client(DEFAULT_CLIENT_ID)
+                .user(defaultUser.getId())
+                .ipAddress(DEFAULT_IP_ADDRESS)
+                .session((String) null)
+                .event(event);
+    }
+
+    UserRepresentation getUser(String username) {
+        List<UserRepresentation> result = realmResource.users().search(username, null, null, null, 0, 1);
+        return result.size() > 0 ? result.get(0) : null;
+    }
+
+    public PublicKey getRealmPublicKey() {
+        return realmPublicKey;
+    }
+
+    public class ExpectedEvent {
+        private EventRepresentation expected = new EventRepresentation();
+        private Matcher<String> userId;
+        private Matcher<String> sessionId;
+        private HashMap<String, Matcher<String>> details;
+
+        public ExpectedEvent realm(RealmRepresentation realm) {
+            expected.setRealmId(realm.getId());
+            return this;
+        }
+
+        public ExpectedEvent realm(String realmId) {
+            expected.setRealmId(realmId);
+            return this;
+        }
+
+        public ExpectedEvent client(ClientRepresentation client) {
+            expected.setClientId(client.getClientId());
+            return this;
+        }
+
+        public ExpectedEvent client(String clientId) {
+            expected.setClientId(clientId);
+            return this;
+        }
+
+        public ExpectedEvent user(UserRepresentation user) {
+            return user(user.getId());
+        }
+
+        public ExpectedEvent user(String userId) {
+            return user(CoreMatchers.equalTo(userId));
+        }
+
+        public ExpectedEvent user(Matcher<String> userId) {
+            this.userId = userId;
+            return this;
+        }
+
+        public ExpectedEvent session(UserSessionRepresentation session) {
+            return session(session.getId());
+        }
+
+        public ExpectedEvent session(String sessionId) {
+            return session(CoreMatchers.equalTo(sessionId));
+        }
+
+        public ExpectedEvent session(Matcher<String> sessionId) {
+            this.sessionId = sessionId;
+            return this;
+        }
+
+        public ExpectedEvent ipAddress(String ipAddress) {
+            expected.setIpAddress(ipAddress);
+            return this;
+        }
+
+        public ExpectedEvent event(EventType e) {
+            expected.setType(e.name());
+            return this;
+        }
+
+        public ExpectedEvent detail(String key, String value) {
+            return detail(key, CoreMatchers.equalTo(value));
+        }
+
+        public ExpectedEvent detail(String key, Matcher<String> matcher) {
+            if (details == null) {
+                details = new HashMap<String, Matcher<String>>();
+            }
+            details.put(key, matcher);
+            return this;
+        }
+
+        public ExpectedEvent removeDetail(String key) {
+            if (details != null) {
+                details.remove(key);
+            }
+            return this;
+        }
+
+        public ExpectedEvent clearDetails() {
+            if (details != null) details.clear();
+            return this;
+        }
+
+        public ExpectedEvent error(String error) {
+            expected.setError(error);
+            return this;
+        }
+
+        public EventRepresentation assertEvent() {
+            return assertEvent(poll());
+        }
+
+        public EventRepresentation assertEvent(EventRepresentation actual) {
+            if (expected.getError() != null && !expected.getType().toString().endsWith("_ERROR")) {
+                expected.setType(expected.getType() + "_ERROR");
+            }
+            Assert.assertEquals(expected.getType(), actual.getType());
+            Assert.assertEquals(expected.getRealmId(), actual.getRealmId());
+            Assert.assertEquals(expected.getClientId(), actual.getClientId());
+            Assert.assertEquals(expected.getError(), actual.getError());
+            Assert.assertEquals(expected.getIpAddress(), actual.getIpAddress());
+            Assert.assertThat(actual.getUserId(), userId);
+            Assert.assertThat(actual.getSessionId(), sessionId);
+
+            if (details == null || details.isEmpty()) {
+//                Assert.assertNull(actual.getDetails());
+            } else {
+                Assert.assertNotNull(actual.getDetails());
+                for (Map.Entry<String, Matcher<String>> d : details.entrySet()) {
+                    String actualValue = actual.getDetails().get(d.getKey());
+                    if (!actual.getDetails().containsKey(d.getKey())) {
+                        Assert.fail(d.getKey() + " missing");
+                    }
+
+                    Assert.assertThat("Unexpected value for " + d.getKey(), actualValue, d.getValue());
+                }
+                /*
+                for (String k : actual.getDetails().keySet()) {
+                    if (!details.containsKey(k)) {
+                        Assert.fail(k + " was not expected");
+                    }
+                }
+                */
+            }
+
+            return actual;
+        }
+    }
+
+    public static Matcher<String> isCodeId() {
+        return isUUID();
+    }
+
+    public static Matcher<String> isUUID() {
+        return new TypeSafeMatcher<String>() {
+            @Override
+            protected boolean matchesSafely(String item) {
+                return 36 == item.length() && item.charAt(8) == '-' && item.charAt(13) == '-' && item.charAt(18) == '-' && item.charAt(23) == '-';
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Not an UUID");
+            }
+        };
+    }
+
+    private EventRepresentation fetchNextEvent() {
+        CloseableHttpClient httpclient = HttpClients.createDefault();
+        try {
+            HttpPost post = new HttpPost(defaultEventsQueueUri + "/event-queue");
+            CloseableHttpResponse response = httpclient.execute(post);
+            if (response.getStatusLine().getStatusCode() != 200) {
+                throw new RuntimeException("Failed to retrieve event from " + post.getURI() + ": " + response.getStatusLine().toString() + " / " + IOUtils.toString(response.getEntity().getContent()));
+            }
+
+            return JsonSerialization.readValue(response.getEntity().getContent(), EventRepresentation.class);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        finally {
+            try {
+                httpclient.close();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
index ae0f5f9..f5d64a5 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
@@ -11,7 +11,8 @@
         "jboss-logging" : {
             "success-level": "debug",
             "error-level": "warn"
-        }
+        },
+        "event-queue": {}
     },
 
     "realm": {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json
new file mode 100644
index 0000000..845adda
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json
@@ -0,0 +1,186 @@
+{
+  "id": "test",
+  "realm": "test",
+  "enabled": true,
+  "sslRequired": "external",
+  "registrationAllowed": true,
+  "resetPasswordAllowed": true,
+  "editUsernameAllowed" : 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",
+      "firstName": "Tom",
+      "lastName": "Brady",
+      "credentials" : [
+        { "type" : "password",
+          "value" : "password" }
+      ],
+      "realmRoles": ["user", "offline_access"],
+      "clientRoles": {
+        "test-app": [ "customer-user" ],
+        "account": [ "view-profile", "manage-account" ]
+      }
+    },
+    {
+      "username" : "john-doh@localhost",
+      "enabled": true,
+      "email" : "john-doh@localhost",
+      "firstName": "John",
+      "lastName": "Doh",
+      "credentials" : [
+        { "type" : "password",
+          "value" : "password" }
+      ],
+      "realmRoles": ["user"],
+      "clientRoles": {
+        "test-app": [ "customer-user" ],
+        "account": [ "view-profile", "manage-account" ]
+      }
+    },
+    {
+      "username" : "keycloak-user@localhost",
+      "enabled": true,
+      "email" : "keycloak-user@localhost",
+      "credentials" : [
+        { "type" : "password",
+          "value" : "password" }
+      ],
+      "realmRoles": ["user"],
+      "clientRoles": {
+        "test-app": [ "customer-user" ],
+        "account": [ "view-profile", "manage-account" ]
+      }
+    },
+    {
+      "username" : "topGroupUser",
+      "enabled": true,
+      "email" : "top@redhat.com",
+      "credentials" : [
+        { "type" : "password",
+          "value" : "password" }
+      ],
+      "groups": [
+        "/topGroup"
+      ]
+    },
+    {
+      "username" : "level2GroupUser",
+      "enabled": true,
+      "email" : "level2@redhat.com",
+      "credentials" : [
+        { "type" : "password",
+          "value" : "password" }
+      ],
+      "groups": [
+        "/topGroup/level2group"
+      ]
+    }
+  ],
+  "scopeMappings": [
+    {
+      "client": "third-party",
+      "roles": ["user"]
+    },
+    {
+      "client": "test-app",
+      "roles": ["user"]
+    }
+  ],
+  "clients": [
+    {
+      "clientId": "test-app",
+      "enabled": true,
+      "baseUrl": "http://localhost:8081/app",
+      "redirectUris": [
+        "http://localhost:8081/app/*"
+      ],
+      "adminUrl": "http://localhost:8081/app/logout",
+      "secret": "password"
+    },
+    {
+      "clientId" : "third-party",
+      "enabled": true,
+      "consentRequired": true,
+
+      "redirectUris": [
+        "http://localhost:8081/app/*"
+      ],
+      "secret": "password"
+    }
+  ],
+  "roles" : {
+    "realm" : [
+      {
+        "name": "user",
+        "description": "Have User privileges"
+      },
+      {
+        "name": "admin",
+        "description": "Have Administrator privileges"
+      }
+    ],
+    "client" : {
+      "test-app" : [
+        {
+          "name": "customer-user",
+          "description": "Have Customer User privileges"
+        },
+        {
+          "name": "customer-admin",
+          "description": "Have Customer Admin privileges"
+        }
+      ]
+    }
+
+  },
+  "groups" : [
+    {
+      "name": "topGroup",
+      "attributes": {
+        "topAttribute": ["true"]
+
+      },
+      "realmRoles": ["user"],
+
+      "subGroups": [
+        {
+          "name": "level2group",
+          "realmRoles": ["admin"],
+          "clientRoles": {
+            "test-app": ["customer-user"]
+          },
+          "attributes": {
+            "level2Attribute": ["true"]
+
+          }
+        }
+      ]
+    }
+  ],
+
+
+  "clientScopeMappings": {
+    "test-app": [
+      {
+        "client": "third-party",
+        "roles": ["customer-user"]
+      }
+    ]
+  },
+
+  "internationalizationEnabled": true,
+  "supportedLocales": ["en", "de"],
+  "defaultLocale": "en",
+  "eventsListeners": ["jboss-logging", "event-queue"]
+}
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index 7fd15a5..4830299 100644
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -48,6 +48,7 @@
         
         <auth.server.port.offset>100</auth.server.port.offset>
         <auth.server.http.port>8180</auth.server.http.port>
+        <auth.server.events.http.port>8089</auth.server.events.http.port>
         <auth.server.https.port>8543</auth.server.https.port>
         <auth.server.management.port>10090</auth.server.management.port>
         <auth.server.management.port.jmx>10099</auth.server.management.port.jmx>
@@ -140,6 +141,7 @@
 
                             <auth.server.port.offset>${auth.server.port.offset}</auth.server.port.offset>
                             <auth.server.http.port>${auth.server.http.port}</auth.server.http.port>
+                            <auth.server.events.http.port>${auth.server.events.http.port}</auth.server.events.http.port>
                             <auth.server.https.port>${auth.server.https.port}</auth.server.https.port>
                             <auth.server.management.port>${auth.server.management.port}</auth.server.management.port>
                             <auth.server.management.port.jmx>${auth.server.management.port.jmx}</auth.server.management.port.jmx>