/*
* Copyright (c) 2010. All rights reserved.
*/
package ro.isdc.wro.manager.factory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Callable;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import ro.isdc.wro.WroRuntimeException;
import ro.isdc.wro.cache.CacheStrategy;
import ro.isdc.wro.cache.ConfigurableCacheStrategy;
import ro.isdc.wro.cache.impl.MemoryCacheStrategy;
import ro.isdc.wro.config.Context;
import ro.isdc.wro.config.support.ContextPropagatingCallable;
import ro.isdc.wro.manager.WroManager;
import ro.isdc.wro.model.factory.ConfigurableModelFactory;
import ro.isdc.wro.model.factory.WroModelFactory;
import ro.isdc.wro.model.factory.XmlModelFactory;
import ro.isdc.wro.model.resource.locator.ClasspathUriLocator;
import ro.isdc.wro.model.resource.locator.ServletContextUriLocator;
import ro.isdc.wro.model.resource.locator.UriLocator;
import ro.isdc.wro.model.resource.locator.UrlUriLocator;
import ro.isdc.wro.model.resource.locator.factory.ConfigurableLocatorFactory;
import ro.isdc.wro.model.resource.processor.ResourcePostProcessor;
import ro.isdc.wro.model.resource.processor.ResourcePreProcessor;
import ro.isdc.wro.model.resource.processor.decorator.ExtensionsAwareProcessorDecorator;
import ro.isdc.wro.model.resource.processor.decorator.ProcessorDecorator;
import ro.isdc.wro.model.resource.processor.factory.ConfigurableProcessorsFactory;
import ro.isdc.wro.model.resource.processor.factory.ProcessorsFactory;
import ro.isdc.wro.model.resource.processor.impl.css.CssImportPreProcessor;
import ro.isdc.wro.model.resource.processor.impl.css.CssMinProcessor;
import ro.isdc.wro.model.resource.processor.impl.css.CssVariablesProcessor;
import ro.isdc.wro.model.resource.processor.impl.js.JSMinProcessor;
import ro.isdc.wro.model.resource.support.AbstractConfigurableMultipleStrategy;
import ro.isdc.wro.model.resource.support.hash.ConfigurableHashStrategy;
import ro.isdc.wro.model.resource.support.hash.HashStrategy;
import ro.isdc.wro.model.resource.support.hash.MD5HashStrategy;
import ro.isdc.wro.model.resource.support.naming.ConfigurableNamingStrategy;
import ro.isdc.wro.model.resource.support.naming.FolderHashEncoderNamingStrategy;
import ro.isdc.wro.model.resource.support.naming.NamingStrategy;
import ro.isdc.wro.model.resource.support.naming.TimestampNamingStrategy;
import ro.isdc.wro.util.AbstractDecorator;
import ro.isdc.wro.util.WroTestUtils;
import ro.isdc.wro.util.WroUtil;
/**
* TestConfigurableWroManagerFactory.
*
* @author Alex Objelean
* @created Created on Jan 5, 2010
*/
public class TestConfigurableWroManagerFactory {
private ConfigurableWroManagerFactory victim;
@Mock
private FilterConfig mockFilterConfig;
private ConfigurableLocatorFactory uriLocatorFactory;
@Mock
private ServletContext mockServletContext;
private ProcessorsFactory processorsFactory;
@Mock
private HttpServletRequest mockRequest;
@Mock
private HttpServletResponse mockResponse;
private Properties configProperties;
@BeforeClass
public static void onBeforeClass() {
assertEquals(0, Context.countActive());
}
@AfterClass
public static void onAfterClass() {
assertEquals(0, Context.countActive());
}
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
// init context
Context.set(Context.webContext(mockRequest, mockResponse, mockFilterConfig));
Mockito.when(mockFilterConfig.getServletContext()).thenReturn(mockServletContext);
victim = new ConfigurableWroManagerFactory();
configProperties = new Properties();
victim.setConfigProperties(configProperties);
}
/**
* Creates the manager and initialize processors with locators used for assetions.
*/
private void createManager() {
// create one instance for test
final WroManager manager = victim.create();
processorsFactory = manager.getProcessorsFactory();
uriLocatorFactory = (ConfigurableLocatorFactory) AbstractDecorator.getOriginalDecoratedObject(manager.getUriLocatorFactory());
}
/**
* When no uri locators are set, the default factory is used.
*/
@Test
public void shouldHaveNoLocatorsWhenNoUriLocatorsParamSet() {
createManager();
assertTrue(uriLocatorFactory.getConfiguredStrategies().isEmpty());
}
@Test
public void shouldHaveNoLocatorsWhenNoLocatorsInitParamSet() {
createManager();
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableLocatorFactory.PARAM_URI_LOCATORS)).thenReturn("");
assertTrue(uriLocatorFactory.getConfiguredStrategies().isEmpty());
}
@Test
public void shouldLoadUriLocatorsFromConfigurationFile() {
configProperties.setProperty(ConfigurableLocatorFactory.PARAM_URI_LOCATORS, "servletContext");
createManager();
assertEquals(1, uriLocatorFactory.getConfiguredStrategies().size());
assertSame(ServletContextUriLocator.class, uriLocatorFactory.getConfiguredStrategies().iterator().next().getClass());
}
@Test
public void shouldLoadUriLocatorsFromFilterConfigRatherThanFromConfigProperties() {
configProperties.setProperty(ConfigurableLocatorFactory.PARAM_URI_LOCATORS, "servletContext");
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableLocatorFactory.PARAM_URI_LOCATORS)).thenReturn(
"classpath, servletContext");
createManager();
assertEquals(2, uriLocatorFactory.getConfiguredStrategies().size());
final Iterator<UriLocator> locatorsIterator = uriLocatorFactory.getConfiguredStrategies().iterator();
assertSame(ClasspathUriLocator.class, locatorsIterator.next().getClass());
assertSame(ServletContextUriLocator.class, locatorsIterator.next().getClass());
}
@Test(expected = WroRuntimeException.class)
public void cannotUseInvalidUriLocatorsSet() {
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableLocatorFactory.PARAM_URI_LOCATORS)).thenReturn(
"INVALID1,INVALID2");
createManager();
uriLocatorFactory.getConfiguredStrategies();
}
@Test
public void shouldHaveCorrectLocatorsSet() {
configureValidUriLocators(mockFilterConfig);
createManager();
assertEquals(3, uriLocatorFactory.getConfiguredStrategies().size());
}
/**
* @param filterConfig
*/
private void configureValidUriLocators(final FilterConfig filterConfig) {
Mockito.when(filterConfig.getInitParameter(ConfigurableLocatorFactory.PARAM_URI_LOCATORS)).thenReturn(
ConfigurableLocatorFactory.createItemsAsString(ServletContextUriLocator.ALIAS, UrlUriLocator.ALIAS,
ClasspathUriLocator.ALIAS));
}
@Test
public void testProcessorsExecutionOrder() {
createManager();
configureValidUriLocators(mockFilterConfig);
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableProcessorsFactory.PARAM_PRE_PROCESSORS)).thenReturn(
AbstractConfigurableMultipleStrategy.createItemsAsString(JSMinProcessor.ALIAS, CssImportPreProcessor.ALIAS,
CssVariablesProcessor.ALIAS));
final List<ResourcePreProcessor> list = (List<ResourcePreProcessor>) processorsFactory.getPreProcessors();
assertEquals(JSMinProcessor.class, list.get(0).getClass());
assertEquals(CssImportPreProcessor.class, list.get(1).getClass());
assertEquals(CssVariablesProcessor.class, list.get(2).getClass());
}
@Test
public void testWithEmptyPreProcessors() {
createManager();
configureValidUriLocators(mockFilterConfig);
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableProcessorsFactory.PARAM_PRE_PROCESSORS)).thenReturn("");
assertTrue(processorsFactory.getPreProcessors().isEmpty());
}
@Test(expected = WroRuntimeException.class)
public void cannotUseInvalidPreProcessorsSet() {
createManager();
configureValidUriLocators(mockFilterConfig);
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableProcessorsFactory.PARAM_PRE_PROCESSORS)).thenReturn(
"INVALID1,INVALID2");
processorsFactory.getPreProcessors();
}
@Test
public void testWhenValidPreProcessorsSet() {
createManager();
configureValidUriLocators(mockFilterConfig);
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableProcessorsFactory.PARAM_PRE_PROCESSORS)).thenReturn(
"cssUrlRewriting");
assertEquals(1, processorsFactory.getPreProcessors().size());
}
@Test
public void testWithEmptyPostProcessors() {
createManager();
configureValidUriLocators(mockFilterConfig);
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableProcessorsFactory.PARAM_POST_PROCESSORS)).thenReturn("");
assertTrue(processorsFactory.getPostProcessors().isEmpty());
}
@Test(expected = WroRuntimeException.class)
public void cannotUseInvalidPostProcessorsSet() {
createManager();
configureValidUriLocators(mockFilterConfig);
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableProcessorsFactory.PARAM_POST_PROCESSORS)).thenReturn(
"INVALID1,INVALID2");
processorsFactory.getPostProcessors();
}
@Test
public void testWhenValidPostProcessorsSet() {
createManager();
configureValidUriLocators(mockFilterConfig);
Mockito.when(mockFilterConfig.getInitParameter(ConfigurableProcessorsFactory.PARAM_POST_PROCESSORS)).thenReturn(
"cssMinJawr, jsMin, cssVariables");
assertEquals(3, processorsFactory.getPostProcessors().size());
}
@Test
public void testConfigPropertiesWithValidPreProcessor() {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableProcessorsFactory.PARAM_PRE_PROCESSORS, "cssMin");
victim.setConfigProperties(configProperties);
createManager();
final Collection<ResourcePreProcessor> list = processorsFactory.getPreProcessors();
assertEquals(1, list.size());
assertEquals(CssMinProcessor.class, list.iterator().next().getClass());
}
@Test
public void testConfigPropertiesWithValidPostProcessor() {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableProcessorsFactory.PARAM_POST_PROCESSORS, "jsMin");
victim.setConfigProperties(configProperties);
createManager();
assertEquals(1, processorsFactory.getPostProcessors().size());
assertEquals(JSMinProcessor.class,
((ProcessorDecorator) processorsFactory.getPostProcessors().iterator().next()).getDecoratedObject().getClass());
}
@Test
public void testConfigPropertiesWithMultipleValidPostProcessor() {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableProcessorsFactory.PARAM_POST_PROCESSORS, "jsMin, cssMin");
victim.setConfigProperties(configProperties);
createManager();
assertEquals(2, processorsFactory.getPostProcessors().size());
assertEquals(JSMinProcessor.class,
((ProcessorDecorator) processorsFactory.getPostProcessors().iterator().next()).getDecoratedObject().getClass());
}
@Test(expected = WroRuntimeException.class)
public void testConfigPropertiesWithInvalidPreProcessor() {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableProcessorsFactory.PARAM_PRE_PROCESSORS, "INVALID");
victim.setConfigProperties(configProperties);
createManager();
processorsFactory.getPreProcessors();
}
public void shouldUseExtensionAwareProcessorWhenProcessorNameContainsDotCharacter() {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableProcessorsFactory.PARAM_PRE_PROCESSORS, "jsMin.js");
victim.setConfigProperties(configProperties);
assertEquals(1, processorsFactory.getPreProcessors().size());
assertTrue(processorsFactory.getPreProcessors().iterator().next() instanceof ExtensionsAwareProcessorDecorator);
}
@Test(expected = WroRuntimeException.class)
public void testConfigPropertiesWithInvalidPostProcessor() {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableProcessorsFactory.PARAM_POST_PROCESSORS, "INVALID");
victim.setConfigProperties(configProperties);
createManager();
processorsFactory.getPostProcessors();
}
@Test(expected = WroRuntimeException.class)
public void cannotConfigureInvalidNamingStrategy()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableNamingStrategy.KEY, "INVALID");
victim.setConfigProperties(configProperties);
victim.create().getNamingStrategy().rename("name", WroUtil.EMPTY_STREAM);
}
@Test
public void shouldUseConfiguredNamingStrategy()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableNamingStrategy.KEY, TimestampNamingStrategy.ALIAS);
victim.setConfigProperties(configProperties);
final NamingStrategy actual = ((ConfigurableNamingStrategy) victim.create().getNamingStrategy()).getConfiguredStrategy();
assertEquals(TimestampNamingStrategy.class, actual.getClass());
}
@Test(expected = WroRuntimeException.class)
public void cannotConfigureInvalidHashStrategy()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableHashStrategy.KEY, "INVALID");
victim.setConfigProperties(configProperties);
victim.create().getHashStrategy().getHash(WroUtil.EMPTY_STREAM);
}
@Test
public void shouldUseConfiguredHashStrategy()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableHashStrategy.KEY, MD5HashStrategy.ALIAS);
victim.setConfigProperties(configProperties);
final HashStrategy actual = ((ConfigurableHashStrategy) victim.create().getHashStrategy()).getConfiguredStrategy();
assertEquals(MD5HashStrategy.class, actual.getClass());
}
@Test(expected = WroRuntimeException.class)
public void cannotConfigureInvalidCacheStrategy()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableCacheStrategy.KEY, "INVALID");
victim.setConfigProperties(configProperties);
victim.create().getCacheStrategy().clear();
}
@Test
public void shouldUseConfiguredCacheStrategy()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableCacheStrategy.KEY, MemoryCacheStrategy.ALIAS);
victim.setConfigProperties(configProperties);
final CacheStrategy<?, ?> actual = ((ConfigurableCacheStrategy) AbstractDecorator.getOriginalDecoratedObject(victim.create().getCacheStrategy())).getConfiguredStrategy();
assertEquals(MemoryCacheStrategy.class, actual.getClass());
}
@Test(expected = WroRuntimeException.class)
public void cannotConfigureInvalidRequestHandler()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableCacheStrategy.KEY, "INVALID");
victim.setConfigProperties(configProperties);
victim.create().getCacheStrategy().clear();
}
@Test
public void shouldUseConfiguredRequestHandler()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableCacheStrategy.KEY, MemoryCacheStrategy.ALIAS);
victim.setConfigProperties(configProperties);
final CacheStrategy<?, ?> actual = ((ConfigurableCacheStrategy) AbstractDecorator.getOriginalDecoratedObject(victim.create().getCacheStrategy())).getConfiguredStrategy();
assertEquals(MemoryCacheStrategy.class, actual.getClass());
}
@Test
public void shouldUseConfiguredModelFactory()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableModelFactory.KEY, XmlModelFactory.ALIAS);
victim.setConfigProperties(configProperties);
final WroModelFactory actual = ((ConfigurableModelFactory) AbstractDecorator.getOriginalDecoratedObject(victim.create().getModelFactory())).getConfiguredStrategy();
assertEquals(XmlModelFactory.class, actual.getClass());
}
@Test(expected = WroRuntimeException.class)
public void cannotUseInvalidConfiguredModelFactory()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableModelFactory.KEY, "invalid");
victim.setConfigProperties(configProperties);
((ConfigurableModelFactory) AbstractDecorator.getOriginalDecoratedObject(victim.create().getModelFactory())).getConfiguredStrategy();
}
@Test
public void shouldConsiderContributeMethodsWhenManagerFactoryIsExtended() {
final String alias = "contributed";
victim = new ConfigurableWroManagerFactory() {
@Override
protected void contributePreProcessors(final Map<String, ResourcePreProcessor> map) {
map.put(alias, new JSMinProcessor());
}
@Override
protected void contributePostProcessors(final Map<String, ResourcePostProcessor> map) {
map.put(alias, new JSMinProcessor());
}
@Override
protected void contributeLocators(final Map<String, UriLocator> map) {
map.put(alias, new UrlUriLocator());
}
};
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableProcessorsFactory.PARAM_PRE_PROCESSORS, alias);
configProperties.setProperty(ConfigurableProcessorsFactory.PARAM_POST_PROCESSORS, alias);
configProperties.setProperty(ConfigurableLocatorFactory.PARAM_URI_LOCATORS, alias);
victim.setConfigProperties(configProperties);
final WroManager manager = victim.create();
assertFalse(manager.getProcessorsFactory().getPostProcessors().isEmpty());
assertFalse(manager.getProcessorsFactory().getPreProcessors().isEmpty());
}
@Test
public void shouldApplyNamingStrategyConcurrently()
throws Exception {
final Properties configProperties = new Properties();
configProperties.setProperty(ConfigurableNamingStrategy.KEY, FolderHashEncoderNamingStrategy.ALIAS);
victim.setConfigProperties(configProperties);
WroTestUtils.runConcurrently(ContextPropagatingCallable.decorate(new Callable<Void>() {
public Void call()
throws Exception {
victim.create().getNamingStrategy().rename("", new ByteArrayInputStream("".getBytes()));
return null;
}
}));
}
@After
public void tearDown() {
Context.unset();
}
}