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 c953a9c94d..e228270ba8 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 failed = new AtomicReference(); - final List threads = new LinkedList<>(); - final Lock lock = SYNCHRONIZED ? new ReentrantLock() : null; + protected void run(final KeycloakRunnable... runnables) { + run(DEFAULT_THREADS, DEFAULT_NUMBER_OF_EXECUTIONS, runnables); + } - 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(); - } + protected void run(final int numThreads, final int totalNumberOfExecutions, final KeycloakRunnable... runnables) { + final ExecutorService service = SYNCHRONIZED + ? Executors.newSingleThreadExecutor() + : Executors.newFixedThreadPool(numThreads); - 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(); - } - } + ThreadLocal keycloaks = new ThreadLocal() { + @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> tasks = new LinkedList<>(); + Collection failures = new ConcurrentLinkedQueue<>(); + final List> 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 f3c66b51e3..2d2053bd12 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("*********************************************"); - - 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); - - ClientResource client = realm.clients().get(clientId); - client.roles().create(r); - - assertNotNull(client.roles().get(name).toRepresentation()); - } - }); - long end = System.currentTimeMillis() - start; - System.out.println("createClientRole took " + end); - 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)); + } + + 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)); + } + } + + 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) { + + } + + 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 1208dc954a..11e3bc05e6 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("AUTH_RESPONSE")); - - run(new KeycloakRunnable() { + AtomicInteger clientIndex = new AtomicInteger(); + ThreadLocal oauthClient = new ThreadLocal() { @Override - public void run(Keycloak keycloak, RealmResource realm, int threadNum, int iterationNum) { - OAuthClient oauth = new OAuthClient(); - oauth.init(adminClient, driver); + protected OAuthClient initialValue() { + OAuthClient oauth1 = new OAuthClient(); + oauth1.init(adminClient, driver); + return oauth1; + } + }; - 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(); + 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()); - String pageContent = getPageContent(oauth.getLoginFormUrl(), httpClient, context); - String currentUrl = context.getRedirectLocations().get(0).toString(); + final HttpClientContext context = HttpClientContext.create(); + String pageContent = getPageContent(oauth1.getLoginFormUrl(), httpClient, context); + String currentUrl = context.getRedirectLocations().get(0).toString(); + Assert.assertThat(pageContent, Matchers.containsString("AUTH_RESPONSE")); + String code = getQueryFromUrl(currentUrl).get(OAuth2Constants.CODE); - Assert.assertTrue(pageContent.contains("AUTH_RESPONSE")); + OAuthClient.AccessTokenResponse accessRes = oauth1.doAccessTokenRequest(code, "password"); + Assert.assertEquals("AccessTokenResponse: error: '" + accessRes.getError() + "' desc: '" + accessRes.getErrorDescription() + "'", + 200, accessRes.getStatusCode()); - 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 = oauth1.doRefreshTokenRequest(accessRes.getRefreshToken(), "password"); + Assert.assertEquals("AccessTokenResponse: error: '" + refreshRes.getError() + "' desc: '" + refreshRes.getErrorDescription() + "'", + 200, refreshRes.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); - } - } + 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); + log.debugf("Response Code: %d, Body: %s", responseCode, resp); } - 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()); - } - return result.toString(); + return resp; } catch (IOException | UnsupportedOperationException ex) { throw new RuntimeException(ex); } finally {