/* * 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.esigate.test.cases; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletResponse; import junit.framework.TestCase; import junitx.framework.AssertionFailedError; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.esigate.http.HttpResponseUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Performance test * * @author Alexis Thaveau */ public class PerformanceTestCase extends TestCase { /** * Runnable that perform a GET request. This object is reusable and thread safe. */ private class HttpGetRequestRunnable implements Runnable { long count = 0; Throwable exception; String lastResult; final String url; private HttpGetRequestRunnable(String url) { this.url = url; } public void run() { if (exception == null) { count++; try { HttpUriRequest request = new HttpGet(url); HttpResponse response = httpClient.execute(request); String result = HttpResponseUtils.toString(response, null); if (lastResult == null) { lastResult = result; } assertEquals("Status should be 200", HttpServletResponse.SC_OK, response.getStatusLine() .getStatusCode()); assertEquals("Result should always be the same", lastResult, result); } catch (Throwable e) { exception = e; } } } } private final static String AGGREGATED1 = "http://localhost:8080/esigate-app-aggregated1/"; private final static String AGGREGATED2 = "http://localhost:8080/esigate-app-aggregated2/"; private final static String AGGREGATOR = "http://localhost:8080/esigate-app-aggregator/"; private final static String AGGREGATOR_NO_CACHE = "http://localhost:8080/esigate-app-aggregator/nocache/ag1/"; private static final Logger LOG = LoggerFactory.getLogger(PerformanceTestCase.class); private HttpClient httpClient; /** * Execute la tache avec plusieurs Threads * * @param request * @return * @throws Exception */ private long execute(HttpGetRequestRunnable request, int numberOfRequests, int threads) throws Exception { PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); httpClient = HttpClientBuilder .create() .setConnectionManager(connectionManager) .setMaxConnTotal(threads) .setMaxConnPerRoute(threads) .setDefaultRequestConfig( RequestConfig.custom().setConnectTimeout(10000).setSocketTimeout(10000).build()) .build(); // Warm up request.run(); BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(); ThreadPoolExecutor threadPool = new ThreadPoolExecutor(threads, threads, 5, TimeUnit.SECONDS, queue); long start = System.currentTimeMillis(); threadPool.prestartAllCoreThreads(); for (int i = 0; i < numberOfRequests; i++) { threadPool.submit(request); } threadPool.shutdown(); // wait maximum 20 s threadPool.awaitTermination(200, TimeUnit.SECONDS); connectionManager.shutdown(); if (request.exception != null) { throw new AssertionFailedError("Exception for request " + request.url + " after " + request.count + " requests", request.exception); } if (threadPool.getCompletedTaskCount() < threadPool.getTaskCount()) { // All task were not executed String msg = request.url + " : Only " + threadPool.getCompletedTaskCount() + "/" + threadPool.getTaskCount() + " have been renderered " + " => Maybe a performance issue"; threadPool.shutdownNow(); fail(msg); } long end = System.currentTimeMillis(); long execTime = end - start; LOG.debug("Executed request " + request.url + " " + numberOfRequests + " times with " + threads + " threads in " + execTime + "ms"); return execTime; } /** * Performance test * * @throws Exception */ public void testAggregator() throws Exception { HttpGetRequestRunnable runAggregated1 = new HttpGetRequestRunnable(AGGREGATED1 + "templateslow.jsp"); HttpGetRequestRunnable runAggregated2 = new HttpGetRequestRunnable(AGGREGATED2 + "template.html"); HttpGetRequestRunnable runAggregator = new HttpGetRequestRunnable(AGGREGATOR + "templateslow.jsp"); HttpGetRequestRunnable runAggregatorNoCache = new HttpGetRequestRunnable(AGGREGATOR_NO_CACHE + "templateslow.jsp"); long execTimeAggregated1 = execute(runAggregated1, 5000, 50); long execTimeAggregated2 = execute(runAggregated2, 5000, 50); long execTimeDirectAccess = execTimeAggregated1 + execTimeAggregated2; LOG.debug("Total execution time direct access: " + execTimeDirectAccess + "ms"); long execTimeAggregator = execute(runAggregator, 5000, 50); LOG.debug("Total execution time with aggregator (cache): " + execTimeAggregator + "ms"); long execTimeAggregatorNoCache = execute(runAggregatorNoCache, 5000, 50); LOG.debug("Total execution time with aggregator (no cache): " + execTimeAggregatorNoCache + "ms"); /* * Expected time : 10% of total time to retrieve resources without aggregator */ long expectedExecTime = Math.round((execTimeDirectAccess) * 1.10); LOG.debug("Maximum expected :" + expectedExecTime + "ms"); if (execTimeAggregator > expectedExecTime) { fail("Performance issue :" + execTimeAggregator + "ms to render template.html with aggregator," + execTimeDirectAccess + "ms without aggregator- Expected " + expectedExecTime + "ms"); } if (execTimeAggregatorNoCache > expectedExecTime) { fail("Performance issue :" + execTimeAggregatorNoCache + "ms to render template.html with aggregator(without cache)," + execTimeDirectAccess + "ms without aggregator- Expected " + expectedExecTime + "ms"); } } }