bundle/src/test/java/com/adobe/acs/commons/rewriter/impl/VersionedClientlibsTransformerFactoryTest.java
/*
* ACS AEM Commons
*
* Copyright (C) 2013 - 2023 Adobe
*
* 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 com.adobe.acs.commons.rewriter.impl;
import com.adobe.granite.ui.clientlibs.ClientLibrary;
import com.adobe.granite.ui.clientlibs.HtmlLibrary;
import com.adobe.granite.ui.clientlibs.HtmlLibraryManager;
import com.adobe.granite.ui.clientlibs.LibraryType;
import com.day.cq.wcm.contentsync.PathRewriterOptions;
import junitx.util.PrivateAccessor;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.sling.api.SlingConstants;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.testing.sling.MockResource;
import org.apache.sling.rewriter.ProcessingContext;
import org.apache.sling.rewriter.Transformer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.osgi.framework.BundleContext;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.event.Event;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.helpers.AttributesImpl;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.only;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class VersionedClientlibsTransformerFactoryTest {
@Mock
private HtmlLibraryManager htmlLibraryManager;
@Mock
private HtmlLibrary htmlLibrary;
@Mock
private HtmlLibrary proxiedHtmlLibrary;
@Mock
private HtmlLibrary resourceResolverHtmlLibrary;
@Mock
private ContentHandler handler;
@Mock
private SlingHttpServletRequest slingRequest;
@Mock
private SlingHttpServletResponse slingResponse;
@Mock
private FilterChain filterChain;
private VersionedClientlibsTransformerFactory factory;
private Filter filter;
private Transformer transformer;
@Mock
private ComponentContext componentContext;
@Mock
private BundleContext bundleContext;
@Mock
private ProcessingContext processingContext;
@Mock
private ResourceResolver resourceResolver;
private static final String PATH = "/etc/clientlibs/test";
private static final String MAP_PATH = "/mylib/test";
private static final String FAKE_STREAM_CHECKSUM="fcadcfb01c1367e9e5b7f2e6d455ba8f"; // md5 of "I love strings"
private static final String PROXIED_FAKE_STREAM_CHECKSUM="669a712c318596cd7e7520e3e2000cfb"; // md5 of "I love strings when they are proxied"
private static final byte[] BYTES;
private static final java.io.InputStream INPUTSTREAM;
private static final String INPUTSTREAM_MD5;
private static final String PROXIED_PATH = "/apps/myco/test";
private static final String PROXY_PATH = "/etc.clientlibs/myco/test";
static {
try {
BYTES = "test".getBytes("UTF-8");
INPUTSTREAM = new ByteArrayInputStream(BYTES);
INPUTSTREAM_MD5 = DigestUtils.md5Hex(BYTES);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
@Before
public void setUp() throws Exception {
when(componentContext.getBundleContext()).thenReturn(bundleContext);
when(componentContext.getProperties()).thenReturn(new Hashtable<String, Object>());
factory = new VersionedClientlibsTransformerFactory();
filter = factory.new BadMd5VersionedClientLibsFilter();
PrivateAccessor.setField(factory, "htmlLibraryManager", htmlLibraryManager);
factory.activate(componentContext);
when(htmlLibrary.getLibraryPath()).thenReturn(PATH);
when(htmlLibrary.getInputStream(false)).thenReturn(new java.io.ByteArrayInputStream("I love strings".getBytes()));
when(proxiedHtmlLibrary.getLibraryPath()).thenReturn(PROXIED_PATH);
when(proxiedHtmlLibrary.getInputStream(false)).thenReturn(new java.io.ByteArrayInputStream("I love strings when they are proxied".getBytes()));
when(resourceResolverHtmlLibrary.getLibraryPath()).thenReturn(MAP_PATH);
when(resourceResolverHtmlLibrary.getInputStream(false)).thenReturn(new java.io.ByteArrayInputStream("I love strings when they are resolved".getBytes()));
when(processingContext.getRequest()).thenReturn(slingRequest);
when(slingRequest.getResourceResolver()).thenReturn(resourceResolver);
when(resourceResolver.getSearchPath()).thenReturn(new String[] { "/libs/", "/apps/" });
transformer = factory.createTransformer();
transformer.init(processingContext, null);
transformer.setContentHandler(handler);
verifyNoMoreInteractions(bundleContext);
}
@After
public void tearDown() throws Exception {
reset(htmlLibraryManager, htmlLibrary, resourceResolverHtmlLibrary, handler);
transformer = null;
}
@Test
public void testRegisterFilter() throws Exception {
Hashtable<String, Object> props = new Hashtable<String, Object>();
props.put("enforce.md5", Boolean.TRUE);
when(componentContext.getProperties()).thenReturn(props);
factory.activate(componentContext);
verify(bundleContext).registerService(eq(Filter.class), any(Filter.class), any());
}
@Test
public void testNoop() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", PATH + ".css");
transformer.startElement(null, "a", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("a"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + ".css", attributesCaptor.getValue().getValue(0));
}
@Test
public void testCssClientLibrary() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", PATH + ".css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + "."+ FAKE_STREAM_CHECKSUM +".css", attributesCaptor.getValue().getValue(0));
}
@Test
public void testCssClientLibraryWithMd5Enforce() throws Exception {
PrivateAccessor.setField(factory, "enforceMd5", true);
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", PATH + ".css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + ".ACSHASH"+ FAKE_STREAM_CHECKSUM +".css", attributesCaptor.getValue().getValue(0));
}
@Test
public void testCssClientLibraryWithDot() throws Exception {
final String path = PATH + ".foo";
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(path))).thenReturn(htmlLibrary);
when(htmlLibrary.getLibraryPath()).thenReturn(path);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", path + ".css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals(path + "."+ FAKE_STREAM_CHECKSUM +".css", attributesCaptor.getValue().getValue(0));
}
@Test
public void testMinifiedCssClientLibrary() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", PATH + ".min.css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + ".min."+ FAKE_STREAM_CHECKSUM +".css", attributesCaptor.getValue().getValue(0));
}
@Test
public void testMinifiedCssClientLibraryWithEnforceMd5() throws Exception {
PrivateAccessor.setField(factory, "enforceMd5", true);
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", PATH + ".min.css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + ".min.ACSHASH"+ FAKE_STREAM_CHECKSUM +".css", attributesCaptor.getValue().getValue(0));
}
@Test
public void testJavaScriptClientLibrary() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", PATH + ".js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + "."+ FAKE_STREAM_CHECKSUM +".js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testJavaScriptClientLibraryWithDot() throws Exception {
final String path = PATH + ".foo";
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(path))).thenReturn(htmlLibrary);
when(htmlLibrary.getLibraryPath()).thenReturn(path);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", path + ".js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
assertEquals(path + "."+ FAKE_STREAM_CHECKSUM +".js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testBadProxiedJavaScriptClientLibrary() throws Exception {
final String badProxyPath = PROXY_PATH + "/bad";
ClientLibrary clientLibrary = mock(ClientLibrary.class);
when(htmlLibraryManager.getLibraries()).thenReturn(Collections.singletonMap(PROXIED_PATH, clientLibrary));
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PROXIED_PATH))).thenReturn(proxiedHtmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", badProxyPath + ".js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
// because the path isn't correct, we refresh the cache, so there should be exactly two retrievals of the list
verify(htmlLibraryManager, times(2)).getLibraries();
// and since neither are found, the original path is returned unchanged
assertEquals(badProxyPath + ".js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testProxiedJavaScriptClientLibrary() throws Exception {
ClientLibrary clientLibrary = mock(ClientLibrary.class);
when(clientLibrary.getTypes()).thenReturn(Collections.singleton(LibraryType.JS));
when(clientLibrary.allowProxy()).thenReturn(true);
when(htmlLibraryManager.getLibraries()).thenReturn(Collections.singletonMap(PROXIED_PATH, clientLibrary));
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PROXIED_PATH))).thenReturn(proxiedHtmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", PROXY_PATH + ".js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
verify(htmlLibraryManager, times(1)).getLibraries();
assertEquals(PROXY_PATH + "."+ PROXIED_FAKE_STREAM_CHECKSUM +".js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testProxiedStaticJavaScriptResource() throws Exception {
when(htmlLibraryManager.getLibraries()).thenReturn(Collections.emptyMap());
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", PROXY_PATH + "/resources/some-resource.js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
verifyNoMoreInteractions(htmlLibraryManager);
assertEquals(PROXY_PATH + "/resources/some-resource.js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testProxiedStaticCssResource() throws Exception {
when(htmlLibraryManager.getLibraries()).thenReturn(Collections.emptyMap());
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", PROXY_PATH + "/resources/some-resource.css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
verifyNoMoreInteractions(htmlLibraryManager);
assertEquals(PROXY_PATH + "/resources/some-resource.css", attributesCaptor.getValue().getValue(0));
}
@Test
public void testEventHandling() throws Exception {
ClientLibrary clientLibrary = mock(ClientLibrary.class);
when(clientLibrary.getTypes()).thenReturn(Collections.singleton(LibraryType.JS));
when(clientLibrary.allowProxy()).thenReturn(true);
when(htmlLibraryManager.getLibraries()).thenReturn(Collections.singletonMap(PROXIED_PATH, clientLibrary));
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PROXIED_PATH))).thenReturn(proxiedHtmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", PROXY_PATH + ".js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
factory.handleEvent(new Event("com/adobe/granite/ui/librarymanager/INVALIDATED", Collections.singletonMap(SlingConstants.PROPERTY_PATH, PROXIED_PATH)));
transformer.startElement(null, "script", null, in);
verify(htmlLibraryManager, times(2)).getLibraries();
}
@Test
public void testMinifiedJavaScriptClientLibrary() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", PATH + ".min.js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + ".min."+ FAKE_STREAM_CHECKSUM +".js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testClientLibFoundWithResourceResolverMapping() throws Exception {
MockResource clientlib = new MockResource(resourceResolver, PATH,"");
when(resourceResolver.resolve(slingRequest, MAP_PATH)).thenReturn(clientlib);
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", MAP_PATH + ".min.js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
assertEquals(MAP_PATH + ".min."+ FAKE_STREAM_CHECKSUM +".js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testCssClientLibraryWithInvalidExtension() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", PATH + ".styles");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + ".styles", attributesCaptor.getValue().getValue(0));
}
@Test
public void testCssClientLibraryWithRelAttributeValueDiffersFromStylesheet() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", PATH + ".css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "preload");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + "."+ FAKE_STREAM_CHECKSUM +".css", attributesCaptor.getValue().getValue(0));
}
@Test
public void testJavaScriptClientLibraryWithInvalidExtension() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", PATH + ".vbs");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
assertEquals(PATH + ".vbs", attributesCaptor.getValue().getValue(0));
}
@Test
public void testJavaScriptClientLibraryWithRelativePath() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", "relative/script.js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
assertEquals("relative/script.js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testJavaScriptClientLibraryWithSameSchemePath() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", "//example.com/same/scheme/script.js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
assertEquals("//example.com/same/scheme/script.js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testCssClientLibraryWithSameSchemePath() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", "//example.com/same/scheme/styles.css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals("//example.com/same/scheme/styles.css", attributesCaptor.getValue().getValue(0));
}
@Test
public void testJavaScriptClientLibraryWithDomainedPath() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.JS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "src", "", "CDATA", "http://www.example.com/same/scheme/script.js");
in.addAttribute("", "type", "", "CDATA", "text/javascript");
transformer.startElement(null, "script", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("script"), isNull(),
attributesCaptor.capture());
assertEquals("http://www.example.com/same/scheme/script.js", attributesCaptor.getValue().getValue(0));
}
@Test
public void testCssClientLibraryWithSameDomainedPath() throws Exception {
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", "https://example.com/same/scheme/styles.css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals("https://example.com/same/scheme/styles.css", attributesCaptor.getValue().getValue(0));
}
@Test
public void doFilter_nonJsCss() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/some_other/uri.html");
filter.doFilter(slingRequest, slingResponse, filterChain);
verifyNothingHappened();
}
@Test
public void doFilter_proxiedClientLibs_jsResource() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc.clientlibs/some-app/clientlibs/some-clientlib/resources/some-resource.js");
filter.doFilter(slingRequest, slingResponse, filterChain);
verifyNothingHappened();
}
@Test
public void doFilter_proxiedClientLibs_cssResource() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc.clientlibs/some-app/clientlibs/some-clientlib/resources/some-resource.css");
filter.doFilter(slingRequest, slingResponse, filterChain);
verifyNothingHappened();
}
@Test
public void doFilter_notFoundInCache_md5Match() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.min." + INPUTSTREAM_MD5 + ".js");
HtmlLibrary library = mock(HtmlLibrary.class);
when(library.getInputStream(false)).thenReturn(INPUTSTREAM);
when(library.getLibraryPath()).thenReturn("/etc/clientlibs/some.js");
when(htmlLibraryManager.getLibrary(LibraryType.JS, "/etc/clientlibs/some")).thenReturn(library);
filter.doFilter(slingRequest, slingResponse, filterChain);
verifyNo404();
}
@Test
public void doFilter_notFoundInCache_md5MisMatch() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.min.foobar.js");
HtmlLibrary library = mock(HtmlLibrary.class);
when(library.getInputStream(false)).thenReturn(INPUTSTREAM );
when(library.getLibraryPath()).thenReturn("/etc/clientlibs/some.js");
when(htmlLibraryManager.getLibrary(LibraryType.JS, "/etc/clientlibs/some")).thenReturn(library);
filter.doFilter(slingRequest, slingResponse, filterChain);
verify404();
}
@Test
public void doFilter_notFoundInCacheWithDot_md5MisMatch() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.path.min.foobar.js");
HtmlLibrary library = mock(HtmlLibrary.class);
when(library.getInputStream(false)).thenReturn(INPUTSTREAM );
when(library.getLibraryPath()).thenReturn("/etc/clientlibs/some.path.js");
when(htmlLibraryManager.getLibrary(LibraryType.JS, "/etc/clientlibs/some.path")).thenReturn(library);
filter.doFilter(slingRequest, slingResponse, filterChain);
verify404();
}
@Test
public void doFilter_notFoundInCache_NoClientLib() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.min.foobar.js");
filter.doFilter(slingRequest, slingResponse, filterChain);
verifyNo404();
}
@Test
public void doFilter_foundInCache_md5Match() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.min." + INPUTSTREAM_MD5 + ".js");
factory.getCache().put(new VersionedClientLibraryMd5CacheKey("/etc/clientlibs/some", LibraryType.JS), INPUTSTREAM_MD5);
HtmlLibrary htmlLibrary = mock(HtmlLibrary.class);
when(htmlLibrary.getLibraryPath()).thenReturn("/etc/clientlibs/some");
when(htmlLibraryManager.getLibrary(LibraryType.JS, "/etc/clientlibs/some")).thenReturn(htmlLibrary);
filter.doFilter(slingRequest, slingResponse, filterChain);
verifyNo404();
verify(htmlLibraryManager).getLibrary(LibraryType.JS, "/etc/clientlibs/some");
verify(htmlLibrary, never()).getInputStream(false);
}
@Test
public void doFilter_foundInCache_md5Match_enforceMd5() throws Exception {
PrivateAccessor.setField(factory, "enforceMd5", true);
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.min.ACSHASH" + INPUTSTREAM_MD5 + ".js");
factory.getCache().put(new VersionedClientLibraryMd5CacheKey("/etc/clientlibs/some", LibraryType.JS), INPUTSTREAM_MD5);
HtmlLibrary htmlLibrary = mock(HtmlLibrary.class);
when(htmlLibrary.getLibraryPath()).thenReturn("/etc/clientlibs/some");
when(htmlLibraryManager.getLibrary(LibraryType.JS, "/etc/clientlibs/some")).thenReturn(htmlLibrary);
filter.doFilter(slingRequest, slingResponse, filterChain);
verifyNo404();
verify(htmlLibraryManager).getLibrary(LibraryType.JS, "/etc/clientlibs/some");
verify(htmlLibrary, never()).getInputStream(false);
}
@Test
public void doFilter_foundInCacheWithDot_md5Match() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.path.min." + INPUTSTREAM_MD5 + ".js");
factory.getCache().put(new VersionedClientLibraryMd5CacheKey("/etc/clientlibs/some.path", LibraryType.JS), INPUTSTREAM_MD5);
HtmlLibrary htmlLibrary = mock(HtmlLibrary.class);
when(htmlLibrary.getLibraryPath()).thenReturn("/etc/clientlibs/some.path");
when(htmlLibraryManager.getLibrary(LibraryType.JS, "/etc/clientlibs/some.path")).thenReturn(htmlLibrary);
filter.doFilter(slingRequest, slingResponse, filterChain);
verifyNo404();
}
@Test
public void doFilter_foundInCache_md5MisMatch() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.min.foobar.js");
factory.getCache().put(new VersionedClientLibraryMd5CacheKey("/etc/clientlibs/some", LibraryType.JS), INPUTSTREAM_MD5);
HtmlLibrary htmlLibrary = mock(HtmlLibrary.class);
when(htmlLibrary.getLibraryPath()).thenReturn("/etc/clientlibs/some");
when(htmlLibraryManager.getLibrary(LibraryType.JS, "/etc/clientlibs/some")).thenReturn(htmlLibrary);
filter.doFilter(slingRequest, slingResponse, filterChain);
verify404();
}
@Test
public void doFilter_foundInCacheWithDot_md5MisMatch() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.path.min.foobar.js");
factory.getCache().put(new VersionedClientLibraryMd5CacheKey("/etc/clientlibs/some.path", LibraryType.JS), INPUTSTREAM_MD5);
HtmlLibrary htmlLibrary = mock(HtmlLibrary.class);
when(htmlLibrary.getLibraryPath()).thenReturn("/etc/clientlibs/some.path");
when(htmlLibraryManager.getLibrary(LibraryType.JS, "/etc/clientlibs/some.path")).thenReturn(htmlLibrary);
filter.doFilter(slingRequest, slingResponse, filterChain);
verify404();
}
@Test
public void doFilter_noMd5() throws Exception {
when(slingRequest.getRequestURI()).thenReturn("/etc/clientlibs/some.min.js");
filter.doFilter(slingRequest, slingResponse, filterChain);
verifyNo404();
}
@Test
public void disableTransformation_exportWithCqWcmContentSync() throws Exception {
// add PATH_REWRITING_OPTIONS attributes and init transformer
when(slingRequest.getAttribute(PathRewriterOptions.ATTRIBUTE_PATH_REWRITING_OPTIONS)).thenReturn(new HashMap<String, Object>());
transformer = factory.createTransformer();
transformer.init(processingContext, null);
transformer.setContentHandler(handler);
// transformation should not be enabled
when(htmlLibraryManager.getLibrary(eq(LibraryType.CSS), eq(PATH))).thenReturn(htmlLibrary);
final AttributesImpl in = new AttributesImpl();
in.addAttribute("", "href", "", "CDATA", PATH + ".css");
in.addAttribute("", "type", "", "CDATA", "text/css");
in.addAttribute("", "rel", "", "CDATA", "stylesheet");
transformer.startElement(null, "link", null, in);
ArgumentCaptor<Attributes> attributesCaptor = ArgumentCaptor.forClass(Attributes.class);
verify(handler, only()).startElement(isNull(), eq("link"), isNull(),
attributesCaptor.capture());
assertEquals(PATH +".css", attributesCaptor.getValue().getValue(0));
}
private void verifyNothingHappened() throws IOException, ServletException {
verifyNoInteractions(htmlLibraryManager);
verifyNo404();
}
private void verifyNo404() throws IOException, ServletException {
verify(filterChain).doFilter(slingRequest, slingResponse);
verify(slingResponse, never()).sendError(anyInt());
}
private void verify404() throws IOException, ServletException {
verify(filterChain, never()).doFilter(slingRequest, slingResponse);
verify(slingResponse).sendError(HttpServletResponse.SC_NOT_FOUND);
}
}