/**
* Copyright Alex Objelean
*/
package ro.isdc.wro.manager.callback;
import static org.junit.Assert.assertEquals;
import java.io.StringWriter;
import java.util.concurrent.Callable;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.output.WriterOutputStream;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;
import ro.isdc.wro.WroRuntimeException;
import ro.isdc.wro.config.Context;
import ro.isdc.wro.http.support.DelegatingServletOutputStream;
import ro.isdc.wro.manager.WroManager;
import ro.isdc.wro.manager.factory.BaseWroManagerFactory;
import ro.isdc.wro.manager.factory.WroManagerFactory;
import ro.isdc.wro.model.WroModel;
import ro.isdc.wro.model.factory.WroModelFactory;
import ro.isdc.wro.model.group.Group;
import ro.isdc.wro.model.group.GroupExtractor;
import ro.isdc.wro.model.resource.Resource;
import ro.isdc.wro.model.resource.ResourceType;
import ro.isdc.wro.util.ObjectFactory;
import ro.isdc.wro.util.WroTestUtils;
import ro.isdc.wro.util.WroUtil;
/**
* @author Alex Objelean
*/
public class TestLifecycleCallbackRegistry {
private LifecycleCallbackRegistry registry;
@BeforeClass
public static void onBeforeClass() {
assertEquals(0, Context.countActive());
}
@AfterClass
public static void onAfterClass() {
assertEquals(0, Context.countActive());
}
@Before
public void setUp() {
Context.set(Context.standaloneContext());
registry = new LifecycleCallbackRegistry();
}
@After
public void tearDown() {
Context.unset();
}
@Test
public void shouldInvokeRegisteredCallbacks() {
final LifecycleCallback callback = Mockito.mock(LifecycleCallback.class);
final Resource changedResource = Resource.create("test.js");
registry.registerCallback(factoryFor(callback));
registry.onBeforeModelCreated();
Mockito.verify(callback).onBeforeModelCreated();
registry.onAfterModelCreated();
Mockito.verify(callback).onAfterModelCreated();
registry.onBeforePreProcess();
Mockito.verify(callback).onBeforePreProcess();
registry.onAfterPreProcess();
Mockito.verify(callback).onAfterPreProcess();
registry.onBeforePostProcess();
Mockito.verify(callback).onBeforePostProcess();
registry.onAfterPostProcess();
Mockito.verify(callback).onAfterPostProcess();
registry.onBeforeMerge();
Mockito.verify(callback).onBeforeMerge();
registry.onAfterMerge();
Mockito.verify(callback).onAfterMerge();
registry.onProcessingComplete();
Mockito.verify(callback).onProcessingComplete();
registry.onResourceChanged(changedResource);
Mockito.verify(callback).onResourceChanged(Mockito.eq(changedResource));
}
private ObjectFactory<LifecycleCallback> factoryFor(final LifecycleCallback callback) {
return new ObjectFactory<LifecycleCallback>() {
public LifecycleCallback create() {
return callback;
}
};
}
@Test
public void shouldCatchCallbacksExceptionsAndContinueExecution() {
final LifecycleCallback failingCallback = Mockito.mock(LifecycleCallback.class);
final LifecycleCallback simpleCallback = Mockito.spy(new LifecycleCallbackSupport());
final Resource changedResource = Resource.create("test.js");
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onBeforeModelCreated();
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onAfterModelCreated();
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onBeforePreProcess();
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onAfterPreProcess();
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onBeforePostProcess();
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onAfterPostProcess();
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onBeforeMerge();
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onAfterMerge();
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onProcessingComplete();
Mockito.doThrow(new IllegalStateException()).when(failingCallback).onResourceChanged(Mockito.any(Resource.class));
registry.registerCallback(factoryFor(failingCallback));
registry.registerCallback(factoryFor(simpleCallback));
registry.onBeforeModelCreated();
registry.onAfterModelCreated();
registry.onBeforePreProcess();
registry.onAfterPreProcess();
registry.onBeforePostProcess();
registry.onAfterPostProcess();
registry.onBeforeMerge();
registry.onAfterMerge();
registry.onProcessingComplete();
registry.onResourceChanged(changedResource);
Mockito.verify(simpleCallback).onBeforeModelCreated();
Mockito.verify(simpleCallback).onAfterModelCreated();
Mockito.verify(simpleCallback).onBeforePreProcess();
Mockito.verify(simpleCallback).onAfterPreProcess();
Mockito.verify(simpleCallback).onBeforePostProcess();
Mockito.verify(simpleCallback).onAfterPostProcess();
Mockito.verify(simpleCallback).onBeforeMerge();
Mockito.verify(simpleCallback).onAfterMerge();
Mockito.verify(simpleCallback).onProcessingComplete();
Mockito.verify(simpleCallback).onResourceChanged(Mockito.eq(changedResource));
}
/**
* TODO: Simplify the test and move common usage to utility method.
*/
@Test
public void shouldInvokeCallbackWhenCallingProcess()
throws Exception {
final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
final HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
Mockito.when(response.getOutputStream()).thenReturn(
new DelegatingServletOutputStream(new WriterOutputStream(new StringWriter())));
Mockito.when(request.getRequestURL()).thenReturn(new StringBuffer(""));
Mockito.when(request.getRequestURI()).thenReturn("");
Mockito.when(request.getServletPath()).thenReturn("");
Context.unset();
Context.set(Context.webContext(request, response, Mockito.mock(FilterConfig.class)));
final LifecycleCallback callback = Mockito.mock(LifecycleCallback.class);
final String groupName = "group";
final GroupExtractor groupExtractor = Mockito.mock(GroupExtractor.class);
Mockito.when(groupExtractor.getGroupName(Mockito.any(HttpServletRequest.class))).thenReturn(groupName);
Mockito.when(groupExtractor.getResourceType(Mockito.any(HttpServletRequest.class))).thenReturn(ResourceType.JS);
final Group group = new Group(groupName);
group.addResource(Resource.create("classpath:1.js"));
final WroModelFactory modelFactory = WroUtil.factoryFor(new WroModel().addGroup(group));
final WroManagerFactory managerFactory = new BaseWroManagerFactory().setGroupExtractor(groupExtractor).setModelFactory(
modelFactory);
final WroManager manager = managerFactory.create();
manager.registerCallback(new ObjectFactory<LifecycleCallback>() {
public LifecycleCallback create() {
return callback;
}
});
manager.process();
Mockito.verify(callback).onBeforeModelCreated();
Mockito.verify(callback).onAfterModelCreated();
Mockito.verify(callback, Mockito.atLeastOnce()).onBeforePreProcess();
Mockito.verify(callback, Mockito.atLeastOnce()).onAfterPreProcess();
Mockito.verify(callback).onBeforeMerge();
Mockito.verify(callback).onAfterMerge();
Mockito.verify(callback).onProcessingComplete();
// This will fail because the callback is invoked also on processors which are skipped
// Mockito.verifyNoMoreInteractions(callback);
}
@Test
public void shouldBeThreadSafe()
throws Exception {
registry = new LifecycleCallbackRegistry() {
@Override
protected void onException(final Exception e) {
throw WroRuntimeException.wrap(e);
}
};
registry.registerCallback(new ObjectFactory<LifecycleCallback>() {
public LifecycleCallback create() {
return new PerformanceLoggerCallback();
}
});
WroTestUtils.runConcurrently(new Callable<Void>() {
public Void call()
throws Exception {
Context.set(Context.standaloneContext());
try {
registry.onBeforeModelCreated();
Thread.sleep(10);
registry.onAfterModelCreated();
registry.onBeforeMerge();
registry.onBeforePreProcess();
registry.onAfterPreProcess();
registry.onAfterMerge();
registry.onBeforePostProcess();
registry.onAfterPostProcess();
registry.onProcessingComplete();
return null;
} finally {
Context.unset();
}
}
});
}
}