keycloak-aplcache

Details

diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/AbstractConcurrencyTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/AbstractConcurrencyTest.java
index c953a9c..e228270 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/AbstractConcurrencyTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/AbstractConcurrencyTest.java
@@ -19,16 +19,17 @@ package org.keycloak.testsuite.admin.concurrency;
 
 import org.keycloak.admin.client.Keycloak;
 import org.keycloak.admin.client.resource.RealmResource;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
-import org.keycloak.testsuite.admin.AbstractAdminTest;
+import java.util.LinkedList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 
 
 /**
@@ -36,77 +37,71 @@ import org.keycloak.testsuite.admin.AbstractAdminTest;
  */
 public abstract class AbstractConcurrencyTest extends AbstractTestRealmKeycloakTest {
 
-    private static final int DEFAULT_THREADS = 5;
-    private static final int DEFAULT_ITERATIONS = 20;
+    private static final int DEFAULT_THREADS = 4;
+    private static final int DEFAULT_NUMBER_OF_EXECUTIONS = 20 * DEFAULT_THREADS;
 
     public static final String REALM_NAME = "test";
 
     // If enabled only one request is allowed at the time. Useful for checking that test is working.
     private static final boolean SYNCHRONIZED = false;
 
-    protected void run(final KeycloakRunnable runnable) throws Throwable {
-        run(runnable, DEFAULT_THREADS, DEFAULT_ITERATIONS);
-    }
-
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
     }
 
-    protected void run(final KeycloakRunnable runnable, final int numThreads, final int numIterationsPerThread) throws Throwable {
-        final CountDownLatch latch = new CountDownLatch(numThreads);
-        final AtomicReference<Throwable> failed = new AtomicReference();
-        final List<Thread> threads = new LinkedList<>();
-        final Lock lock = SYNCHRONIZED ? new ReentrantLock() : null;
-
-        for (int t = 0; t < numThreads; t++) {
-            final int threadNum = t;
-            Thread thread = new Thread() {
-                @Override
-                public void run() {
-                    Keycloak keycloak = null;
-                    try {
-                        if (lock != null) {
-                            lock.lock();
-                        }
-
-                        keycloak = Keycloak.getInstance(getAuthServerRoot().toString(), "master", "admin", "admin", org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID);
-                        RealmResource realm = keycloak.realm(REALM_NAME);
-                        for (int i = 0; i < numIterationsPerThread && latch.getCount() > 0; i++) {
-                            log.infov("thread {0}, iteration {1}", threadNum, i);
-                            runnable.run(keycloak, realm, threadNum, i);
-                        }
-                        latch.countDown();
-                    } catch (Throwable t) {
-                        failed.compareAndSet(null, t);
-                        while (latch.getCount() > 0) {
-                            latch.countDown();
-                        }
-                    } finally {
-                        keycloak.close();
-                        if (lock != null) {
-                            lock.unlock();
-                        }
-                    }
+    protected void run(final KeycloakRunnable... runnables) {
+        run(DEFAULT_THREADS, DEFAULT_NUMBER_OF_EXECUTIONS, runnables);
+    }
+
+    protected void run(final int numThreads, final int totalNumberOfExecutions, final KeycloakRunnable... runnables) {
+        final ExecutorService service = SYNCHRONIZED
+          ? Executors.newSingleThreadExecutor()
+          : Executors.newFixedThreadPool(numThreads);
+
+        ThreadLocal<Keycloak> keycloaks = new ThreadLocal<Keycloak>() {
+            @Override
+            protected Keycloak initialValue() {
+                return Keycloak.getInstance(getAuthServerRoot().toString(), "master", "admin", "admin", org.keycloak.models.Constants.ADMIN_CLI_CLIENT_ID);
+            }
+        };
+
+        AtomicInteger currentThreadIndex = new AtomicInteger();
+        Collection<Callable<Void>> tasks = new LinkedList<>();
+        Collection<Throwable> failures = new ConcurrentLinkedQueue<>();
+        final List<Callable<Void>> runnablesToTasks = new LinkedList<>();
+        for (KeycloakRunnable runnable : runnables) {
+            runnablesToTasks.add(() -> {
+                int arrayIndex = currentThreadIndex.getAndIncrement() % numThreads;
+                try {
+                    runnable.run(arrayIndex % numThreads, keycloaks.get(), keycloaks.get().realm(REALM_NAME));
+                } catch (Throwable ex) {
+                    failures.add(ex);
                 }
-            };
-            thread.start();
-            threads.add(thread);
+                return null;
+            });
+        }
+        for (int i = 0; i < totalNumberOfExecutions; i ++) {
+            runnablesToTasks.forEach(tasks::add);
         }
 
-        latch.await();
-
-        for (Thread t : threads) {
-            t.join();
+        try {
+            service.invokeAll(tasks);
+            service.shutdown();
+            service.awaitTermination(3, TimeUnit.MINUTES);
+        } catch (InterruptedException ex) {
+            throw new RuntimeException(ex);
         }
 
-        if (failed.get() != null) {
-            throw failed.get();
+        if (! failures.isEmpty()) {
+            RuntimeException ex = new RuntimeException("There were failures in threads");
+            failures.forEach(ex::addSuppressed);
+            throw ex;
         }
     }
 
     protected interface KeycloakRunnable {
 
-        void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum);
+        void run(int threadIndex, Keycloak keycloak, RealmResource realm) throws Throwable;
 
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/ConcurrencyTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/ConcurrencyTest.java
index f3c66b5..2d2053b 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/ConcurrencyTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/ConcurrencyTest.java
@@ -17,12 +17,12 @@
 
 package org.keycloak.testsuite.admin.concurrency;
 
-import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.keycloak.admin.client.Keycloak;
 import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ClientsResource;
 import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.admin.client.resource.RolesResource;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.GroupRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
@@ -31,7 +31,11 @@ import javax.ws.rs.NotFoundException;
 import javax.ws.rs.core.Response;
 import org.keycloak.testsuite.admin.ApiUtil;
 
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 /**
@@ -39,203 +43,198 @@ import static org.junit.Assert.fail;
  */
 public class ConcurrencyTest extends AbstractConcurrencyTest {
 
-    boolean passedCreateClient = false;
-    boolean passedCreateRole = false;
+    public void concurrentTest(KeycloakRunnable... tasks) throws Throwable {
+        System.out.println("***************************");
+        long start = System.currentTimeMillis();
+        run(tasks);
+        long end = System.currentTimeMillis() - start;
+        System.out.println("took " + end + " ms");
+    }
 
-    //@Test
+    @Test
     public void testAllConcurrently() throws Throwable {
-        Thread client = new Thread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    createClient();
-                    passedCreateClient = true;
-                } catch (Throwable throwable) {
-                    throw new RuntimeException(throwable);
-                }
-            }
-        });
-        Thread role = new Thread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    createRole();
-                    passedCreateRole = true;
-                } catch (Throwable throwable) {
-                    throw new RuntimeException(throwable);
-                }
-            }
-        });
-
-        client.start();
-        role.start();
-        client.join();
-        role.join();
-        Assert.assertTrue(passedCreateClient);
-        Assert.assertTrue(passedCreateRole);
+        AtomicInteger uniqueCounter = new AtomicInteger(100000);
+        concurrentTest(
+          new CreateClient(uniqueCounter),
+          new CreateRemoveClient(uniqueCounter),
+          new CreateGroup(uniqueCounter),
+          new CreateRole(uniqueCounter)
+        );
     }
 
     @Test
     public void createClient() throws Throwable {
-        System.out.println("***************************");
-        long start = System.currentTimeMillis();
-        run(new KeycloakRunnable() {
-            @Override
-            public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) {
-                String name = "c-" + threadNum + "-" + iterationNum;
-                ClientRepresentation c = new ClientRepresentation();
-                c.setClientId(name);
-                Response response = realm.clients().create(c);
-                String id = ApiUtil.getCreatedId(response);
-                response.close();
-
-                c = realm.clients().get(id).toRepresentation();
-                assertNotNull(c);
-                boolean found = false;
-                for (ClientRepresentation r : realm.clients().findAll()) {
-                    if (r.getClientId().equals(name)) {
-                        found = true;
-                        break;
-                    }
-                }
-                if (!found) {
-                    fail("Client " + name + " not found in client list");
-                }
-            }
-        });
-        long end = System.currentTimeMillis() - start;
-        System.out.println("createClient took " + end);
-
+        AtomicInteger uniqueCounter = new AtomicInteger();
+        concurrentTest(new CreateClient(uniqueCounter));
     }
 
     @Test
     public void createGroup() throws Throwable {
-        System.out.println("***************************");
-        long start = System.currentTimeMillis();
-        run(new KeycloakRunnable() {
-            @Override
-            public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) {
-                String name = "c-" + threadNum + "-" + iterationNum;
-                GroupRepresentation c = new GroupRepresentation();
-                c.setName(name);
-                Response response = realm.groups().add(c);
-                String id = ApiUtil.getCreatedId(response);
-                response.close();
-
-                c = realm.groups().group(id).toRepresentation();
-                assertNotNull(c);
-                boolean found = false;
-                for (GroupRepresentation r : realm.groups().groups()) {
-                    if (r.getName().equals(name)) {
-                        found = true;
-                        break;
-                    }
-                }
-                if (!found) {
-                    fail("Group " + name + " not found in group list");
-                }
-            }
-        });
-        long end = System.currentTimeMillis() - start;
-        System.out.println("createGroup took " + end);
-
+        AtomicInteger uniqueCounter = new AtomicInteger();
+        concurrentTest(new CreateGroup(uniqueCounter));
     }
 
     @Test
-    @Ignore
     public void createRemoveClient() throws Throwable {
         // FYI< this will fail as HSQL seems to be trying to perform table locks.
-        System.out.println("***************************");
-        long start = System.currentTimeMillis();
-        run(new KeycloakRunnable() {
-            @Override
-            public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) {
-                String name = "c-" + threadNum + "-" + iterationNum;
-                ClientRepresentation c = new ClientRepresentation();
-                c.setClientId(name);
-                Response response = realm.clients().create(c);
-                String id = ApiUtil.getCreatedId(response);
-                response.close();
-
-                c = realm.clients().get(id).toRepresentation();
-                assertNotNull(c);
-                boolean found = false;
-                for (ClientRepresentation r : realm.clients().findAll()) {
-                    if (r.getClientId().equals(name)) {
-                        found = true;
-                        break;
-                    }
-                }
-                if (!found) {
-                    fail("Client " + name + " not found in client list");
-                }
-                realm.clients().get(id).remove();
-                try {
-                    c = realm.clients().get(id).toRepresentation();
-                    fail("Client " + name + " should not be found.  Should throw a 404");
-                } catch (NotFoundException e) {
-
-                }
-                found = false;
-                for (ClientRepresentation r : realm.clients().findAll()) {
-                    if (r.getClientId().equals(name)) {
-                        found = true;
-                        break;
-                    }
-                }
-                Assert.assertFalse("Client " + name + " should not be in client list", found);
-
-            }
-        });
-        long end = System.currentTimeMillis() - start;
-        System.out.println("createClient took " + end);
-
-    }
-
-
-    @Test
-    public void createRole() throws Throwable {
-        long start = System.currentTimeMillis();
-        run(new KeycloakRunnable() {
-            @Override
-            public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) {
-                String name = "r-" + threadNum + "-" + iterationNum;
-                RoleRepresentation r = new RoleRepresentation(name, null, false);
-                realm.roles().create(r);
-                assertNotNull(realm.roles().get(name).toRepresentation());
-            }
-        });
-        long end = System.currentTimeMillis() - start;
-        System.out.println("createRole took " + end);
-
+        AtomicInteger uniqueCounter = new AtomicInteger();
+        concurrentTest(new CreateRemoveClient(uniqueCounter));
     }
 
     @Test
     public void createClientRole() throws Throwable {
-        long start = System.currentTimeMillis();
         ClientRepresentation c = new ClientRepresentation();
         c.setClientId("client");
         Response response = adminClient.realm(REALM_NAME).clients().create(c);
         final String clientId = ApiUtil.getCreatedId(response);
         response.close();
 
-        System.out.println("*********************************************");
+        AtomicInteger uniqueCounter = new AtomicInteger();
+        concurrentTest(new CreateClientRole(uniqueCounter, clientId));
+    }
+
+    @Test
+    public void createRole() throws Throwable {
+        AtomicInteger uniqueCounter = new AtomicInteger();
+        run(new CreateRole(uniqueCounter));
+    }
 
-        run(new KeycloakRunnable() {
-            @Override
-            public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) {
-                String name = "r-" + threadNum + "-" + iterationNum;
-                RoleRepresentation r = new RoleRepresentation(name, null, false);
+    private class CreateClient implements KeycloakRunnable {
+
+        private final AtomicInteger clientIndex;
+
+        public CreateClient(AtomicInteger clientIndex) {
+            this.clientIndex = clientIndex;
+        }
+
+        @Override
+        public void run(int threadIndex, Keycloak keycloak, RealmResource realm) throws Throwable {
+            String name = "c-" + clientIndex.getAndIncrement();
+            ClientRepresentation c = new ClientRepresentation();
+            c.setClientId(name);
+            Response response = realm.clients().create(c);
+            String id = ApiUtil.getCreatedId(response);
+            response.close();
+
+            c = realm.clients().get(id).toRepresentation();
+            assertNotNull(c);
+            assertTrue("Client " + name + " not found in client list",
+              realm.clients().findAll().stream()
+                .map(ClientRepresentation::getClientId)
+                .filter(Objects::nonNull)
+                .anyMatch(name::equals));
+        }
+    }
 
-                ClientResource client = realm.clients().get(clientId);
-                client.roles().create(r);
+    private class CreateRemoveClient implements KeycloakRunnable {
+
+        private final AtomicInteger clientIndex;
+
+        public CreateRemoveClient(AtomicInteger clientIndex) {
+            this.clientIndex = clientIndex;
+        }
+
+        @Override
+        public void run(int threadIndex, Keycloak keycloak, RealmResource realm) throws Throwable {
+            String name = "c-" + clientIndex.getAndIncrement();
+            ClientRepresentation c = new ClientRepresentation();
+            c.setClientId(name);
+            final ClientsResource clients = realm.clients();
+
+            Response response = clients.create(c);
+            String id = ApiUtil.getCreatedId(response);
+            response.close();
+            final ClientResource client = clients.get(id);
+
+            c = client.toRepresentation();
+            assertNotNull(c);
+            assertTrue("Client " + name + " not found in client list",
+              clients.findAll().stream()
+                .map(ClientRepresentation::getClientId)
+                .filter(Objects::nonNull)
+                .anyMatch(name::equals));
+
+            client.remove();
+            try {
+                client.toRepresentation();
+                fail("Client " + name + " should not be found.  Should throw a 404");
+            } catch (NotFoundException e) {
 
-                assertNotNull(client.roles().get(name).toRepresentation());
             }
-        });
-        long end = System.currentTimeMillis() - start;
-        System.out.println("createClientRole took " + end);
-        System.out.println("*********************************************");
 
+            assertFalse("Client " + name + " should now not present in client list",
+              clients.findAll().stream()
+                .map(ClientRepresentation::getClientId)
+                .filter(Objects::nonNull)
+                .anyMatch(name::equals));
+        }
     }
+
+    private class CreateGroup implements KeycloakRunnable {
+
+        private final AtomicInteger uniqueIndex;
+
+        public CreateGroup(AtomicInteger uniqueIndex) {
+            this.uniqueIndex = uniqueIndex;
+        }
+
+        @Override
+        public void run(int threadIndex, Keycloak keycloak, RealmResource realm) throws Throwable {
+            String name = "g-" + uniqueIndex.getAndIncrement();
+            GroupRepresentation c = new GroupRepresentation();
+            c.setName(name);
+            Response response = realm.groups().add(c);
+            String id = ApiUtil.getCreatedId(response);
+            response.close();
+
+            c = realm.groups().group(id).toRepresentation();
+            assertNotNull(c);
+            assertTrue("Group " + name + " not found in group list",
+              realm.groups().groups().stream()
+                .map(GroupRepresentation::getName)
+                .filter(Objects::nonNull)
+                .anyMatch(name::equals));
+        }
+    }
+
+    private class CreateClientRole implements KeycloakRunnable {
+
+        private final AtomicInteger uniqueCounter;
+        private final String clientId;
+
+        public CreateClientRole(AtomicInteger uniqueCounter, String clientId) {
+            this.uniqueCounter = uniqueCounter;
+            this.clientId = clientId;
+        }
+
+        @Override
+        public void run(int threadIndex, Keycloak keycloak, RealmResource realm) throws Throwable {
+            String name = "cr-" + uniqueCounter.getAndIncrement();
+            RoleRepresentation r = new RoleRepresentation(name, null, false);
+
+            final RolesResource roles = realm.clients().get(clientId).roles();
+            roles.create(r);
+            assertNotNull(roles.get(name).toRepresentation());
+        }
+    }
+
+    private class CreateRole implements KeycloakRunnable {
+
+        private final AtomicInteger uniqueCounter;
+
+        public CreateRole(AtomicInteger uniqueCounter) {
+            this.uniqueCounter = uniqueCounter;
+        }
+
+        @Override
+        public void run(int threadIndex, Keycloak keycloak, RealmResource realm) throws Throwable {
+            String name = "r-" + uniqueCounter.getAndIncrement();
+            RoleRepresentation r = new RoleRepresentation(name, null, false);
+
+            final RolesResource roles = realm.roles();
+            roles.create(r);
+            assertNotNull(roles.get(name).toRepresentation());
+        }
+    }
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/ConcurrentLoginTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/ConcurrentLoginTest.java
index 1208dc9..11e3bc0 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/ConcurrentLoginTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/concurrency/ConcurrentLoginTest.java
@@ -17,9 +17,7 @@
 
 package org.keycloak.testsuite.admin.concurrency;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -28,8 +26,6 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
 import javax.ws.rs.core.Response;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
@@ -50,11 +46,13 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
-import org.keycloak.admin.client.Keycloak;
-import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.testsuite.util.OAuthClient;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import org.hamcrest.Matchers;
+
 
 
 /**
@@ -63,7 +61,6 @@ import org.keycloak.testsuite.util.OAuthClient;
 public class ConcurrentLoginTest extends AbstractConcurrencyTest {
     
     private static final int DEFAULT_THREADS = 10;
-    private static final int DEFAULT_ITERATIONS = 20;
     private static final int CLIENTS_PER_THREAD = 10;
     private static final int DEFAULT_CLIENTS_COUNT = CLIENTS_PER_THREAD * DEFAULT_THREADS;
     
@@ -89,11 +86,6 @@ public class ConcurrentLoginTest extends AbstractConcurrencyTest {
         log.debug("clients created");
     }
 
-    @Override
-    protected void run(final KeycloakRunnable runnable) throws Throwable {
-        run(runnable, DEFAULT_THREADS, DEFAULT_ITERATIONS);
-    }
-
     @Test
     public void concurrentLogin() throws Throwable {
         System.out.println("*********************************************");
@@ -108,42 +100,39 @@ public class ConcurrentLoginTest extends AbstractConcurrencyTest {
             log.debug("Executing login request");
             
             Assert.assertTrue(parseAndCloseResponse(httpClient.execute(request)).contains("<title>AUTH_RESPONSE</title>"));
-
-            run(new KeycloakRunnable() {
+            AtomicInteger clientIndex = new AtomicInteger();
+            ThreadLocal<OAuthClient> oauthClient = new ThreadLocal<OAuthClient>() {
                 @Override
-                public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) {
-                    OAuthClient oauth = new OAuthClient();
-                    oauth.init(adminClient, driver);
-
-                    int startIndex = CLIENTS_PER_THREAD * threadNum;
-                    for (int i = startIndex; i < startIndex + CLIENTS_PER_THREAD; i++) {
-                        oauth.clientId("client" + i);
-                        log.trace("Accessing login page for " + oauth.getClientId() + " thread " + threadNum + " iteration " + iterationNum);
-                        try {
-                            final HttpClientContext context = HttpClientContext.create();
-
-                            String pageContent = getPageContent(oauth.getLoginFormUrl(), httpClient, context);
-                            String currentUrl = context.getRedirectLocations().get(0).toString();
-
-                            Assert.assertTrue(pageContent.contains("<title>AUTH_RESPONSE</title>"));
-
-                            String code = getQueryFromUrl(currentUrl).get(OAuth2Constants.CODE);
-                            OAuthClient.AccessTokenResponse accessRes = oauth.doAccessTokenRequest(code, "password");
-                            Assert.assertEquals("AccessTokenResponse: error: '" + accessRes.getError() + "' desc: '" + accessRes.getErrorDescription() + "'",
-                                    200, accessRes.getStatusCode());
-
-                            OAuthClient.AccessTokenResponse refreshRes = oauth.doRefreshTokenRequest(accessRes.getRefreshToken(), "password");
-                            Assert.assertEquals("AccessTokenResponse: error: '" + refreshRes.getError() + "' desc: '" + refreshRes.getErrorDescription() + "'",
-                                    200, refreshRes.getStatusCode());
-
-                            if (userSessionId.get() == null) {
-                                AccessToken token = oauth.verifyToken(accessRes.getAccessToken());
-                                userSessionId.set(token.getSessionState());
-                            }
-                        } catch (Exception ex) {
-                            throw new RuntimeException(ex);
-                        }
-                    }
+                protected OAuthClient initialValue() {
+                    OAuthClient oauth1 = new OAuthClient();
+                    oauth1.init(adminClient, driver);
+                    return oauth1;
+                }
+            };
+
+            run(DEFAULT_THREADS, DEFAULT_CLIENTS_COUNT, (threadIndex, keycloak, realm) -> {
+                int i = clientIndex.getAndIncrement();
+                OAuthClient oauth1 = oauthClient.get();
+                oauth1.clientId("client" + i);
+                log.infof("%d [%s]: Accessing login page for %s", threadIndex, Thread.currentThread().getName(), oauth1.getClientId());
+
+                final HttpClientContext context = HttpClientContext.create();
+                String pageContent = getPageContent(oauth1.getLoginFormUrl(), httpClient, context);
+                String currentUrl = context.getRedirectLocations().get(0).toString();
+                Assert.assertThat(pageContent, Matchers.containsString("<title>AUTH_RESPONSE</title>"));
+                String code = getQueryFromUrl(currentUrl).get(OAuth2Constants.CODE);
+
+                OAuthClient.AccessTokenResponse accessRes = oauth1.doAccessTokenRequest(code, "password");
+                Assert.assertEquals("AccessTokenResponse: error: '" + accessRes.getError() + "' desc: '" + accessRes.getErrorDescription() + "'",
+                  200, accessRes.getStatusCode());
+
+                OAuthClient.AccessTokenResponse refreshRes = oauth1.doRefreshTokenRequest(accessRes.getRefreshToken(), "password");
+                Assert.assertEquals("AccessTokenResponse: error: '" + refreshRes.getError() + "' desc: '" + refreshRes.getErrorDescription() + "'",
+                  200, refreshRes.getStatusCode());
+
+                if (userSessionId.get() == null) {
+                    AccessToken token = oauth.verifyToken(accessRes.getAccessToken());
+                    userSessionId.set(token.getSessionState());
                 }
             });
 
@@ -154,15 +143,13 @@ public class ConcurrentLoginTest extends AbstractConcurrencyTest {
         }
     }
 
-
     protected void logStats(long start) {
         long end = System.currentTimeMillis() - start;
         log.info("concurrentLogin took " + (end/1000) + "s");
         log.info("*********************************************");
     }
-
     
-    private String getPageContent(String url, CloseableHttpClient httpClient, HttpClientContext context) throws Exception {
+    private String getPageContent(String url, CloseableHttpClient httpClient, HttpClientContext context) throws IOException {
 
         HttpGet request = new HttpGet(url);
 
@@ -179,23 +166,15 @@ public class ConcurrentLoginTest extends AbstractConcurrencyTest {
 
     }
 
-    private String parseAndCloseResponse(CloseableHttpResponse response) throws UnsupportedOperationException, IOException {
+    private String parseAndCloseResponse(CloseableHttpResponse response) {
         try {
             int responseCode = response.getStatusLine().getStatusCode();
+            String resp = EntityUtils.toString(response.getEntity());
+
             if (responseCode != 200) {
-                log.debug("Response Code : " + responseCode);
-            }
-            BufferedReader rd = new BufferedReader(
-                    new InputStreamReader(response.getEntity().getContent()));
-            StringBuilder result = new StringBuilder();
-            String line;
-            while ((line = rd.readLine()) != null) {
-                result.append(line);
-            }
-            if (responseCode != 200) {
-                log.debug(result.toString());
+                log.debugf("Response Code: %d, Body: %s", responseCode, resp);
             }
-            return result.toString();
+            return resp;
         } catch (IOException | UnsupportedOperationException ex) {
             throw new RuntimeException(ex);
         } finally {