/* * JBoss, Home of Professional Open Source * Copyright 2013, Red Hat, Inc. and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.richfaces.resource; import java.io.ByteArrayInputStream; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.Map; import java.util.TimeZone; import javax.faces.context.FacesContext; import org.easymock.EasyMock; import org.jboss.test.faces.AbstractFacesTest; import org.richfaces.application.Module; import org.richfaces.application.ServicesFactory; import org.richfaces.application.ServicesFactoryImpl; import org.richfaces.application.Uptime; import org.richfaces.application.ServiceTracker; /** * @author Nick Belaevski * @since 4.0 */ public class AbstractBaseResourceTest extends AbstractFacesTest { @Override public void setUp() throws Exception { super.setUp(); setupFacesRequest(); } @Override public void tearDown() throws Exception { super.tearDown(); } public void testGetHeaders() throws Exception { MockResourceImpl mockResource = new MockResourceImpl(); mockResource.setCacheable(true); mockResource.setEntityTag("\"etag0\""); mockResource.setContentLength(80); mockResource.setContentType("image/png"); Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); calendar.clear(); calendar.set(2009, Calendar.JULY, 13, 12, 45, 9); mockResource.setLastModified(calendar.getTime()); calendar.add(Calendar.DATE, 1); mockResource.setCurrentTime(calendar.getTimeInMillis()); calendar.add(Calendar.DATE, 7); mockResource.setExpired(calendar.getTime()); Map<String, String> headers = mockResource.getResponseHeaders(); assertEquals("Tue, 21 Jul 2009 12:45:09 GMT", headers.get("Expires")); assertEquals("Mon, 13 Jul 2009 12:45:09 GMT", headers.get("Last-Modified")); assertEquals("Tue, 14 Jul 2009 12:45:09 GMT", headers.get("Date")); assertEquals("\"etag0\"", headers.get("ETag")); assertEquals("max-age=604800", headers.get("Cache-Control")); assertEquals("80", headers.get("Content-Length")); assertEquals("image/png", headers.get("Content-Type")); assertEquals(7, headers.size()); mockResource.setTimeToLive(14 * 24 * 60 * 60 /* 14 days */); headers = mockResource.getResponseHeaders(); assertEquals("Tue, 28 Jul 2009 12:45:09 GMT", headers.get("Expires")); assertEquals("Mon, 13 Jul 2009 12:45:09 GMT", headers.get("Last-Modified")); assertEquals("Tue, 14 Jul 2009 12:45:09 GMT", headers.get("Date")); assertEquals("max-age=1209600", headers.get("Cache-Control")); } public void testGetHeadersNonCacheable() throws Exception { MockResourceImpl mockResource = new MockResourceImpl(); mockResource.setCacheable(false); mockResource.setContentLength(120); mockResource.setContentType("image/jpg"); mockResource.setEntityTag("\"etag1\""); Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); calendar.clear(); calendar.set(2009, Calendar.JULY, 13, 12, 45, 9); mockResource.setLastModified(calendar.getTime()); calendar.add(Calendar.DATE, 1); mockResource.setCurrentTime(calendar.getTimeInMillis()); calendar.add(Calendar.DATE, 7); mockResource.setExpired(calendar.getTime()); Map<String, String> headers = mockResource.getResponseHeaders(); assertEquals("0", headers.get("Expires")); assertEquals("max-age=0, no-store, no-cache", headers.get("Cache-Control")); assertEquals("no-cache", headers.get("Pragma")); assertEquals("120", headers.get("Content-Length")); assertEquals("image/jpg", headers.get("Content-Type")); assertEquals("Mon, 13 Jul 2009 12:45:09 GMT", headers.get("Last-Modified")); assertEquals("Tue, 14 Jul 2009 12:45:09 GMT", headers.get("Date")); assertEquals(7, headers.size()); } public void testGetRequestPath() throws Exception { String resourceState = "data"; final ResourceCodec resourceCodec = EasyMock.createMock(ResourceCodec.class); EasyMock.expect( resourceCodec.encodeResourceRequestPath(EasyMock.same(facesContext), EasyMock.eq("custom.library"), EasyMock.eq("org.richfaces.resource.MockStateAwareResource"), EasyMock.aryEq(resourceState.getBytes()), EasyMock.eq("4_0_alpha"))).andReturn("/rfRes/Resource0/4_0_alpha/data?l=custom.library"); EasyMock.expect( resourceCodec.encodeJSFMapping(EasyMock.same(facesContext), EasyMock.eq("/rfRes/Resource0/4_0_alpha/data?l=custom.library"))).andReturn( "/rfRes/Resource0/4_0_alpha/data.jsf?l=custom.library"); EasyMock.expect( resourceCodec.encodeResourceRequestPath(EasyMock.same(facesContext), EasyMock.eq("custom.library"), EasyMock.eq("org.richfaces.resource.MockStateAwareResource"), EasyMock.eq(null), EasyMock.eq("4_0_alpha"))) .andReturn("/rfRes/Resource1/4_0_alpha?l=custom.library"); EasyMock.expect( resourceCodec.encodeJSFMapping(EasyMock.same(facesContext), EasyMock.eq("/rfRes/Resource1/4_0_alpha?l=custom.library"))).andReturn( "/rfRes/Resource1/4_0_alpha.jsf?l=custom.library"); EasyMock.expect( resourceCodec.encodeResourceRequestPath(EasyMock.same(facesContext), EasyMock.<String>isNull(), EasyMock.eq("org.richfaces.resource.MockResource"), EasyMock.eq(null), EasyMock.eq("4_0_alpha"))).andReturn( "/rfRes/Resource2/4_0_alpha"); EasyMock.expect(resourceCodec.encodeJSFMapping(EasyMock.same(facesContext), EasyMock.eq("/rfRes/Resource2/4_0_alpha"))) .andReturn("/rfRes/Resource2/4_0_alpha.jsf"); EasyMock.replay(resourceCodec); ServicesFactoryImpl injector = new ServicesFactoryImpl(); injector.init(Collections.<Module>singletonList(new Module() { public void configure(ServicesFactory injector) { injector.setInstance(ResourceCodec.class, resourceCodec); injector.setInstance(Uptime.class, new Uptime()); } })); ServiceTracker.setFactory(injector); MockStateAwareResourceImpl stateAwareResourceImpl = new MockStateAwareResourceImpl(); stateAwareResourceImpl.setLibraryName("custom.library"); stateAwareResourceImpl.setVersion("4_0_alpha"); stateAwareResourceImpl.setState(resourceState); assertEquals("org.richfaces.resource.MockStateAwareResource", stateAwareResourceImpl.getResourceName()); assertEquals("/rfRes/Resource0/4_0_alpha/data.jsf?l=custom.library", stateAwareResourceImpl.getRequestPath()); stateAwareResourceImpl.setTransient(true); assertEquals("/rfRes/Resource1/4_0_alpha.jsf?l=custom.library", stateAwareResourceImpl.getRequestPath()); MockResourceImpl resourceImpl = new MockResourceImpl(); resourceImpl.setVersion("4_0_alpha"); assertEquals("org.richfaces.resource.MockResource", resourceImpl.getResourceName()); assertEquals("/rfRes/Resource2/4_0_alpha.jsf", resourceImpl.getRequestPath()); EasyMock.verify(resourceCodec); } public void testGetURL() throws Exception { InputStream stream = new ByteArrayInputStream(new byte[0]); MockResourceImpl mockResource = new MockResourceImpl(); mockResource.setContentLength(130); mockResource.setContentType("image/gif"); mockResource.setInputStream(stream); Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT")); calendar.clear(); calendar.set(2009, Calendar.JUNE, 12, 21, 38, 59); Date lastModified = calendar.getTime(); mockResource.setLastModified(lastModified); calendar.add(Calendar.MONTH, 1); Date expired = calendar.getTime(); mockResource.setExpired(expired); URL url = mockResource.getURL(); assertNotNull(url); assertEquals("jsfresource:org.richfaces.resource.MockResource", url.toExternalForm()); URLConnection urlConnection = url.openConnection(); assertNotNull(urlConnection); urlConnection.connect(); assertEquals(130, urlConnection.getContentLength()); assertEquals("image/gif", urlConnection.getContentType()); assertEquals(lastModified.getTime(), urlConnection.getLastModified()); assertSame(stream, urlConnection.getInputStream()); assertSame(url, urlConnection.getURL()); MockResourceImpl mockResource2 = new MockResourceImpl(); URLConnection urlConnection2 = mockResource2.getURL().openConnection(); urlConnection2.connect(); assertEquals(-1, urlConnection2.getContentLength()); assertNull(urlConnection2.getContentType()); assertEquals(0, urlConnection2.getLastModified()); } public void testDefaults() throws Exception { ResourceImpl defaultResource = new ResourceImpl(); assertTrue(defaultResource.isCacheable(facesContext)); assertEquals("org.richfaces.resource.ResourceImpl", defaultResource.getResourceName()); assertEquals(-1, defaultResource.getContentLength(facesContext)); assertNull(defaultResource.getEntityTag(facesContext)); assertNull(defaultResource.getExpires(facesContext)); Date lastModified = defaultResource.getLastModified(facesContext); assertNotNull(lastModified); assertTrue(System.currentTimeMillis() >= lastModified.getTime()); ResourceImpl defaultETagResource = new ResourceImpl() { protected Date getLastModified(FacesContext context) { return new Date(12471234567890L); } ; protected int getContentLength(FacesContext context) { return 1297; } ; }; assertEquals("W/\"1297-12471234567890\"", defaultETagResource.getEntityTag(facesContext)); } public void testUserAgentNeedsUpdate() throws Exception { long currentTime = System.currentTimeMillis(); MockResourceImpl actualResource = new MockResourceImpl(); actualResource.setLastModified(new Date(currentTime - 30000)); MockResourceImpl expiredResource = new MockResourceImpl(); expiredResource.setLastModified(new Date(currentTime - 10000)); this.connection.addRequestHeaders(Collections.singletonMap("If-Modified-Since", ResourceUtils.formatHttpDate(new Date(currentTime - 20000)))); assertTrue(expiredResource.userAgentNeedsUpdate(facesContext)); assertFalse(actualResource.userAgentNeedsUpdate(facesContext)); } private class MockResourceImpl extends AbstractCacheableResource implements VersionedResource { private int contentLength = -1; private long currentTime; private String entityTag; private Date expired; private InputStream inputStream; private Date lastModified; private int ttl; private String version; public MockResourceImpl() { super(); setResourceName("org.richfaces.resource.MockResource"); } @Override protected int getContentLength(FacesContext context) { return contentLength; } @Override public InputStream getInputStream() throws IOException { return inputStream; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public void setContentLength(int contentLength) { this.contentLength = contentLength; } public void setInputStream(InputStream inputStream) { this.inputStream = inputStream; } @Override protected Date getLastModified(FacesContext context) { return lastModified; } public void setLastModified(Date lastModified) { this.lastModified = lastModified; } @Override public Date getExpires(FacesContext context) { return expired; } public void setExpired(Date expired) { this.expired = expired; } @Override public String getEntityTag(FacesContext context) { return entityTag; } /** * @param entityTag the entityTag to set */ public void setEntityTag(String entityTag) { this.entityTag = entityTag; } @Override boolean isResourceRequest() { return true; } @Override protected long getCurrentTime() { return currentTime; } void setCurrentTime(long currentTime) { this.currentTime = currentTime; } @Override public int getTimeToLive(FacesContext context) { return ttl; } public void setTimeToLive(int ttl) { this.ttl = ttl; } } private class MockStateAwareResourceImpl extends MockResourceImpl implements StateHolderResource { private boolean _transient; private String resourceState; public MockStateAwareResourceImpl() { super(); setResourceName("org.richfaces.resource.MockStateAwareResource"); } public void setState(String resourceState) { this.resourceState = resourceState; } public void setTransient(boolean transient1) { _transient = transient1; } public boolean isTransient() { return _transient; } public void readState(FacesContext context, DataInput dataInput) throws IOException { resourceState = dataInput.readLine(); } public void writeState(FacesContext context, DataOutput objectOutput) throws IOException { objectOutput.writeBytes(resourceState); } } private class ResourceImpl extends AbstractCacheableResource { public ResourceImpl() { super(); setResourceName("org.richfaces.resource.ResourceImpl"); } @Override public InputStream getInputStream() throws IOException { throw new UnsupportedOperationException(); } } }