/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.core.portal.livetrace; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; import org.junit.Test; import static org.junit.Assert.*; public class CompletedPortalRequestsTest { private final static Random RANDOM_WHEEL = new SecureRandom(); private AtomicLong atomicRequestNumber = new AtomicLong( 0 ); @Test public void size_returns_1_after_one_trace_is_added() { CompletedPortalRequests requests = new CompletedPortalRequests( 1000 ); PortalRequestTrace trace = createTrace( 1, "http://locahost:8080/site/0/home" ); requests.add( trace ); assertEquals( 1, requests.getSize() ); } @Test public void getList_returns_1_item_after_trace_is_added() { CompletedPortalRequests requests = new CompletedPortalRequests( 1000 ); PortalRequestTrace trace = createTrace( 1, "http://locahost:8080/site/0/home" ); requests.add( trace ); List<PortalRequestTrace> actualList = requests.getList(); assertSame( 1, actualList.size() ); assertSame( trace, actualList.get( 0 ) ); } @Test public void getList_returns_items_in_opposite_order_as_they_where_inserted() { CompletedPortalRequests requests = new CompletedPortalRequests( 1000 ); PortalRequestTrace trace1 = createTrace( 1, "http://locahost:8080/site/0/home" ); requests.add( trace1 ); PortalRequestTrace trace2 = createTrace( 2, "http://locahost:8080/site/0/home" ); requests.add( trace2 ); List<PortalRequestTrace> actualList = requests.getList(); assertEquals( 2, actualList.size() ); assertSame( trace2, actualList.get( 0 ) ); assertSame( trace1, actualList.get( 1 ) ); } @Test public void getListSince_returns_items_in_opposite_order_as_they_where_inserted() { CompletedPortalRequests requests = new CompletedPortalRequests( 1000 ); PortalRequestTrace trace1 = new PortalRequestTrace( 1, "http://locahost:8080/site/0/home" ); requests.add( trace1 ); PortalRequestTrace trace2 = new PortalRequestTrace( 2, "http://locahost:8080/site/0/home" ); requests.add( trace2 ); List<PortalRequestTrace> actualList = requests.getCompletedAfter( 0 ); assertEquals( 2, actualList.size() ); assertSame( trace2, actualList.get( 0 ) ); assertSame( trace1, actualList.get( 1 ) ); } @Test public void concurrent_100_threads_adding_random_requests() { long startTime = System.currentTimeMillis(); final int numberOfThreadsToStart = 100; final CompletedPortalRequests requests = new CompletedPortalRequests( 1000 ); List<RequestSimulator> requestSimulators = new ArrayList<RequestSimulator>(); for ( int i = 0; i < numberOfThreadsToStart; i++ ) { requestSimulators.add( new RequestSimulator( requests, random( 10, 100 ) ) ); } final List<TraceInfoReaderSimulator> traceInfoReaderSimulators = new ArrayList<TraceInfoReaderSimulator>(); for ( int i = 0; i < 100; i++ ) { traceInfoReaderSimulators.add( new TraceInfoReaderSimulator( requests, 100 ) ); } List<Thread> threads = createThreadsForRequestSimulators( requestSimulators ); threads.addAll( createThreadsForTraceInfoReaderSimulators( traceInfoReaderSimulators ) ); startThreads( threads ); waitForThreadsToFinish( threads ); System.out.println( "concurrent_100_threads_adding_random_requests, time: " + ( System.currentTimeMillis() - startTime ) ); assertNoExceptionsThrownForRequestSimulators( requestSimulators ); assertEquals( 1000, requests.getSize() ); assertUniqueRequestNumbers( requests.getList() ); } @Test public void concurrent_100_threads_adding_100_requests() { long startTime = System.currentTimeMillis(); final int numberOfThreadsToStart = 100; final CompletedPortalRequests requests = new CompletedPortalRequests( 1000 ); List<RequestSimulator> requestSimulators = new ArrayList<RequestSimulator>(); for ( int i = 0; i < numberOfThreadsToStart; i++ ) { requestSimulators.add( new RequestSimulator( requests, 100 ) ); } final List<TraceInfoReaderSimulator> traceInfoReaderSimulators = new ArrayList<TraceInfoReaderSimulator>(); for ( int i = 0; i < 100; i++ ) { traceInfoReaderSimulators.add( new TraceInfoReaderSimulator( requests, 100 ) ); } final List<Thread> threads = createThreadsForRequestSimulators( requestSimulators ); threads.addAll( createThreadsForTraceInfoReaderSimulators( traceInfoReaderSimulators ) ); startThreads( threads ); waitForThreadsToFinish( threads ); System.out.println( "concurrent_100_threads_adding_100_requests, time: " + ( System.currentTimeMillis() - startTime ) ); assertNoExceptionsThrownForRequestSimulators( requestSimulators ); assertEquals( 1000, requests.getSize() ); assertUniqueRequestNumbers( requests.getList() ); } private void assertNoExceptionsThrownForRequestSimulators( List<RequestSimulator> simulators ) { for ( Simulator simulator : simulators ) { assertTrue( "Simulator have thrown exception!", !simulator.exceptionThrown ); } } private void assertUniqueRequestNumbers( List<PortalRequestTrace> traces ) { final Set<Long> usedNumbers = new HashSet<Long>(); for ( PortalRequestTrace trace : traces ) { long currentCompletedNumber = trace.getCompletedNumber(); assertTrue( currentCompletedNumber + " duplicate requestNumber found!", !usedNumbers.contains( currentCompletedNumber ) ); usedNumbers.add( currentCompletedNumber ); } } private PortalRequestTrace createTrace( long requestNumber, String url ) { PortalRequestTrace trace = new PortalRequestTrace( requestNumber, url ); trace.setCompletedNumber( requestNumber ); return trace; } private PortalRequestTrace createTrace() { long requestNumber = atomicRequestNumber.incrementAndGet(); PortalRequestTrace trace = new PortalRequestTrace( requestNumber, "http://locahost:8080/site/0/home" ); trace.setCompletedNumber( requestNumber ); return trace; } private static int random( int low, int high ) { return RANDOM_WHEEL.nextInt( high - low + 1 ) + low; } private List<Thread> createThreadsForRequestSimulators( List<RequestSimulator> simulators ) { List<Thread> threads = new ArrayList<Thread>(); for ( RequestSimulator requestSimulator : simulators ) { threads.add( new Thread( requestSimulator ) ); } return threads; } private List<Thread> createThreadsForTraceInfoReaderSimulators( List<TraceInfoReaderSimulator> simulators ) { List<Thread> threads = new ArrayList<Thread>(); for ( TraceInfoReaderSimulator requestSimulator : simulators ) { threads.add( new Thread( requestSimulator ) ); } return threads; } private void startThreads( Collection<Thread> threads ) { for ( Thread thread : threads ) { thread.start(); } } private void waitForThreadsToFinish( Collection<Thread> threads ) { for ( Thread thread : threads ) { try { thread.join(); } catch ( InterruptedException e ) { e.printStackTrace(); fail(); } } } private class RequestSimulator extends Simulator implements Runnable { private CompletedPortalRequests requests; final int numberOfExecutions; RequestSimulator( CompletedPortalRequests requests, int numberOfExecutions ) { this.requests = requests; this.numberOfExecutions = numberOfExecutions; } @Override public void run() { try { for ( int i = 0; i < numberOfExecutions; i++ ) { PortalRequestTrace trace = createTrace(); requests.add( trace ); } } catch ( Exception e ) { e.printStackTrace(); exceptionThrown = true; } } } private class TraceInfoReaderSimulator extends Simulator implements Runnable { private CompletedPortalRequests requests; final int numberOfExecutions; private int[] sleepsBeforeReading; long lastCompletedRequestNumber = -1; TraceInfoReaderSimulator( CompletedPortalRequests requests, int numberOfExecutions ) { this.requests = requests; this.numberOfExecutions = numberOfExecutions; sleepsBeforeReading = new int[numberOfExecutions]; for ( int i = 0; i < numberOfExecutions; i++ ) { sleepsBeforeReading[i] = random( 3, 9 ); } } @Override public void run() { try { for ( int i = 0; i < numberOfExecutions; i++ ) { requests.getSize(); List<PortalRequestTrace> listSince = requests.getCompletedAfter( lastCompletedRequestNumber ); if ( listSince.size() > 0 ) { lastCompletedRequestNumber = listSince.get( 0 ).getCompletedNumber(); } //noinspection UnusedDeclaration for ( PortalRequestTrace trace : listSince ) { // just simulating iteration } Thread.sleep( sleepsBeforeReading[i] ); } } catch ( Exception e ) { e.printStackTrace(); exceptionThrown = true; } } } private class Simulator { boolean exceptionThrown = false; } }