/*******************************************************************************
* Copyright (c) 2011, 2014 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EclipseSource - initial API and implementation
******************************************************************************/
package org.eclipse.rap.rwt.internal.lifecycle;
import static java.util.Arrays.asList;
import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
import static org.eclipse.rap.rwt.testfixture.internal.ConcurrencyTestUtil.joinThreads;
import static org.eclipse.rap.rwt.testfixture.internal.ConcurrencyTestUtil.startThreads;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.eclipse.rap.rwt.internal.service.ContextProvider;
import org.eclipse.rap.rwt.testfixture.internal.Fixture;
import org.eclipse.rap.rwt.testfixture.internal.LoggingPhaseListener;
import org.eclipse.rap.rwt.testfixture.internal.TestLogger;
import org.eclipse.rap.rwt.testfixture.internal.TestServletContext;
import org.eclipse.rap.rwt.testfixture.internal.LoggingPhaseListener.PhaseEventInfo;
import org.eclipse.swt.widgets.Display;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class PhaseListenerManager_Test {
private List<Throwable> exceptionsInServletLog;
private PhaseListenerManager phaseListenerManager;
private LifeCycle lifeCycle;
@Before
public void setUp() {
Fixture.setUp();
lifeCycle = mock( LifeCycle.class );
phaseListenerManager = new PhaseListenerManager();
exceptionsInServletLog = new LinkedList<Throwable>();
setupServletContextLog();
}
@After
public void tearDown() {
Fixture.tearDown();
}
@Test
public void testAddPhaseListener() {
LoggingPhaseListener phaseListener = new LoggingPhaseListener( null );
phaseListenerManager.addPhaseListener( phaseListener );
assertEquals( asList( phaseListener ), getPhaseListeners() );
}
@Test( expected = NullPointerException.class )
public void testAddPhaseListener_failsWithNull() {
phaseListenerManager.addPhaseListener( null );
}
@Test
public void testAddPhaseListener_twice() {
PhaseListener phaseListener = new EmptyPhaseListener();
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.addPhaseListener( phaseListener );
assertEquals( asList( phaseListener ), getPhaseListeners() );
}
@Test( expected = NullPointerException.class )
public void testRemovePhaseListener_failsWithNull() {
phaseListenerManager.removePhaseListener( null );
}
@Test
public void testRemovePhaseListener() {
LoggingPhaseListener phaseListener = new LoggingPhaseListener( null );
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.removePhaseListener( phaseListener );
assertEquals( asList(), getPhaseListeners() );
}
@Test
public void testRemovePhaseListener_twice() {
LoggingPhaseListener phaseListener = new LoggingPhaseListener( null );
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.removePhaseListener( phaseListener );
phaseListenerManager.removePhaseListener( phaseListener );
assertEquals( asList(), getPhaseListeners() );
}
@Test
public void testRemovePhaseListener_withUnknownPhaseListener() {
phaseListenerManager.addPhaseListener( new LoggingPhaseListener( null ) );
phaseListenerManager.removePhaseListener( new LoggingPhaseListener( null ) );
assertEquals( 1, getPhaseListeners().size() );
}
@Test
public void testClear() {
phaseListenerManager.addPhaseListener( new LoggingPhaseListener( null ) );
phaseListenerManager.clear();
assertTrue( getPhaseListeners().isEmpty() );
}
@Test
public void testGetPhaseListeners_returnsSafeCopy() {
phaseListenerManager.addPhaseListener( new LoggingPhaseListener( null ) );
PhaseListener[] phaseListeners1 = phaseListenerManager.getPhaseListeners();
phaseListeners1[ 0 ] = null;
PhaseListener[] phaseListeners2 = phaseListenerManager.getPhaseListeners();
assertNotNull( phaseListeners2[ 0 ] );
}
@Test
public void testAddRemovePhaseListenerConcurrently() throws InterruptedException {
final int threadCount = 120;
final List<Thread> succeededThreads = Collections.synchronizedList( new LinkedList<Thread>() );
Runnable runnable = new Runnable() {
public void run() {
EmptyPhaseListener phaseListener = new EmptyPhaseListener();
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.getPhaseListeners();
Thread.yield();
phaseListenerManager.removePhaseListener( phaseListener );
succeededThreads.add( Thread.currentThread() );
}
};
joinThreads( startThreads( threadCount, runnable ) );
assertEquals( threadCount, succeededThreads.size() );
assertTrue( getPhaseListeners().isEmpty() );
}
@Test
public void testNotifyBeforePhase_withSpecificListener() {
LoggingPhaseListener phaseListener = new LoggingPhaseListener( PhaseId.READ_DATA );
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.notifyBeforePhase( PhaseId.READ_DATA, lifeCycle );
assertEquals( 1, phaseListener.getLoggedEvents().length );
PhaseEventInfo phaseEvent = phaseListener.getLoggedEvents()[ 0 ];
assertSame( lifeCycle, phaseEvent.source );
assertEquals( PhaseId.READ_DATA, phaseEvent.phaseId );
}
@Test
public void testNotifyBeforePhase_withNonMatchingListener() {
LoggingPhaseListener phaseListener = new LoggingPhaseListener( PhaseId.RENDER );
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.notifyBeforePhase( PhaseId.READ_DATA, lifeCycle );
assertEquals( 0, phaseListener.getLoggedEvents().length );
}
@Test
public void testNotifyBeforePhase_withANYListener() {
LoggingPhaseListener phaseListener = new LoggingPhaseListener( PhaseId.ANY );
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.notifyBeforePhase( PhaseId.READ_DATA, lifeCycle );
assertEquals( 1, phaseListener.getLoggedEvents().length );
PhaseEventInfo phaseEvent = phaseListener.getLoggedEvents()[ 0 ];
assertSame( lifeCycle, phaseEvent.source );
assertEquals( PhaseId.READ_DATA, phaseEvent.phaseId );
}
@Test
public void testExceptionsInBeforePhaseEvent() {
phaseListenerManager.addPhaseListener( new ExceptionPhaseListener() );
phaseListenerManager.addPhaseListener( new ExceptionPhaseListener() );
phaseListenerManager.notifyBeforePhase( PhaseId.READ_DATA, lifeCycle );
assertEquals( 2, exceptionsInServletLog.size() );
}
@Test
public void testErrorInBeforePhaseEvent() {
phaseListenerManager.addPhaseListener( new ErrorPhaseListener() );
try {
phaseListenerManager.notifyBeforePhase( PhaseId.READ_DATA, lifeCycle );
fail();
} catch( TestError expected ) {
}
}
@Test
public void testNotifyAfterPhase_withSpecificListener() {
LoggingPhaseListener phaseListener = new LoggingPhaseListener( PhaseId.READ_DATA );
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.notifyAfterPhase( PhaseId.READ_DATA, lifeCycle );
assertEquals( 1, phaseListener.getLoggedEvents().length );
assertSame( lifeCycle, phaseListener.getLoggedEvents()[ 0 ].source );
assertEquals( PhaseId.READ_DATA, phaseListener.getLoggedEvents()[ 0 ].phaseId );
}
@Test
public void testNotifyAfterPhase_withNonMatchingListener() {
LoggingPhaseListener phaseListener = new LoggingPhaseListener( PhaseId.RENDER );
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.notifyAfterPhase( PhaseId.READ_DATA, lifeCycle );
assertEquals( 0, phaseListener.getLoggedEvents().length );
}
@Test
public void testNotifyAfterPhase_withANYListener() {
PhaseId phase = PhaseId.READ_DATA;
LoggingPhaseListener phaseListener = new LoggingPhaseListener( PhaseId.ANY );
phaseListenerManager.addPhaseListener( phaseListener );
phaseListenerManager.notifyAfterPhase( phase, lifeCycle );
assertEquals( 1, phaseListener.getLoggedEvents().length );
PhaseEventInfo phaseEvent = phaseListener.getLoggedEvents()[ 0 ];
assertSame( lifeCycle, phaseEvent.source );
assertEquals( phase, phaseEvent.phaseId );
}
@Test
public void testExceptionsInAfterPhaseEvent() {
phaseListenerManager.addPhaseListener( new ExceptionPhaseListener() );
phaseListenerManager.addPhaseListener( new ExceptionPhaseListener() );
phaseListenerManager.notifyAfterPhase( PhaseId.READ_DATA, lifeCycle );
assertEquals( 2, exceptionsInServletLog.size() );
}
@Test
public void testErrorInAfterPhaseEvent() {
phaseListenerManager.addPhaseListener( new ErrorPhaseListener() );
try {
phaseListenerManager.notifyAfterPhase( PhaseId.READ_DATA, lifeCycle );
fail();
} catch( TestError expected ) {
}
}
// see bug 372960
@Test
public void testCurrentPhaseMatchPhaseEventPhase() {
new Display();
Fixture.fakeNewRequest();
final List<PhaseId> log = new ArrayList<PhaseId>();
LifeCycle lifeCycle = getApplicationContext().getLifeCycleFactory().getLifeCycle();
lifeCycle.addPhaseListener( new PhaseListener() {
public PhaseId getPhaseId() {
return PhaseId.PROCESS_ACTION;
}
public void beforePhase( PhaseEvent event ) {
log.add( CurrentPhase.get() );
log.add( event.getPhaseId() );
}
public void afterPhase( PhaseEvent event ) {
}
} );
Fixture.executeLifeCycleFromServerThread();
assertEquals( log.get( 0 ), log.get( 1 ) );
}
private List<PhaseListener> getPhaseListeners() {
return asList( phaseListenerManager.getPhaseListeners() );
}
private void setupServletContextLog() {
HttpSession session = ContextProvider.getUISession().getHttpSession();
TestServletContext servletContext = ( TestServletContext )session.getServletContext();
servletContext.setLogger( new TestLogger() {
public void log( String message, Throwable throwable ) {
exceptionsInServletLog.add( throwable );
}
} );
}
private static class TestError extends Error {
private static final long serialVersionUID = 1L;
}
private static class EmptyPhaseListener implements PhaseListener {
private static final long serialVersionUID = 1L;
public void beforePhase( PhaseEvent event ) {
}
public void afterPhase( PhaseEvent event ) {
}
public PhaseId getPhaseId() {
return null;
}
}
private static class ExceptionPhaseListener implements PhaseListener {
private static final long serialVersionUID = 1L;
public void beforePhase( PhaseEvent event ) {
throw new RuntimeException();
}
public void afterPhase( PhaseEvent event ) {
throw new RuntimeException();
}
public PhaseId getPhaseId() {
return PhaseId.ANY;
}
}
private static class ErrorPhaseListener implements PhaseListener {
private static final long serialVersionUID = 1L;
public void beforePhase( PhaseEvent event ) {
throw new TestError();
}
public void afterPhase( PhaseEvent event ) {
throw new TestError();
}
public PhaseId getPhaseId() {
return PhaseId.ANY;
}
}
}