/** * Copyright (c) Codice Foundation * <p/> * 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 3 of the * License, or any later version. * <p/> * This program 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. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package templates; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.File; import java.io.StringWriter; import java.io.Writer; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ddf.action.Action; import ddf.action.ActionProvider; import ddf.catalog.CatalogFramework; import ddf.catalog.data.ContentType; import ddf.catalog.data.Metacard; import ddf.catalog.data.Result; import ddf.catalog.operation.SourceInfoRequestEnterprise; import ddf.catalog.operation.SourceInfoResponse; import ddf.catalog.operation.SourceResponse; import ddf.catalog.source.SourceDescriptor; import ddf.catalog.source.SourceUnavailableException; import freemarker.ext.beans.BeansWrapper; import freemarker.template.Configuration; import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; public class SearchPageTest { private static final String SCHEME = "http"; private static final String HOST = "ddf.test.host"; private static final int PORT = 8181; private static final String SCHEME_SPECIFIC_PART = SCHEME + "://" + HOST + ":" + PORT; private static final long HIT_COUNT = 1004; private static final long PAGE_SIZE = 5; private static final String URL = SCHEME_SPECIFIC_PART + "/services/catalog/query?format=querypage&count=" + PAGE_SIZE + "&start=1&q=mace&temporalCriteria=absoluteTime&dtend=&dtend=&dtoffset=&offsetTime=&offsetTimeUnits=minutes&radius=14000&lat=45.2&lon=31.2&latitude=45.2&longitude=31.2&radiusValue=14&radiusUnits=kilometers&bbox=&west=&south=&east=&north=&type=Resource&typeList=Resource&src=ddf&federationSources=ddf"; private static final String HTML_ACTION = "/someAction/html"; private static final String METACARD_ACTION = "/someAction/metacard"; private static final String RESOURCE_ACTION = "/someAction/resource"; private static final String HEADER = "Test Header"; private static final String FOOTER = "Test Footer"; private static final String TITLE = "Test Title"; private static final String LOCAL_ID = "localDDF"; private static final String FED_SOURCE_1_ID = "fed1"; private static final String FED_SOURCE_2_ID = "fed2"; private static final String CONTENT_TYPE_1 = "contentType 1"; private static final String CONTENT_TYPE_2 = "contentType 2"; private static final String CONTENT_TYPE_3 = "contentType 3"; private static final String METACARD_LOCATION = "POINT(1 2)"; private static final String RESOURCE_SIZE = "10240"; private static final String METACARD_TITLE = "Metacard"; private static final Logger LOGGER = LoggerFactory.getLogger(SearchPageTest.class); private static List<Metacard> metacards; private static Date runTimeDate = new Date(); private static String generatedHtml; @BeforeClass public static void setUp() throws Exception { Configuration cfg = new Configuration(); cfg.setDirectoryForTemplateLoading(new File("src/main/resources/templates")); cfg.setObjectWrapper(new DefaultObjectWrapper()); Template temp = cfg.getTemplate("searchpage.ftl"); Map<String, Object> root = new HashMap<String, Object>(); root.put("request", createRequest()); root.put("response", createResponse()); root.put("exchange", createExchange()); root.put("headers", createHeaders()); Writer out = new StringWriter(); temp.process(root, out); out.flush(); generatedHtml = out.toString(); LOGGER.info(generatedHtml); } private static Message createRequest() { Message message = mock(Message.class); SourceResponse sourceResponse = mock(SourceResponse.class); when(sourceResponse.getHits()).thenReturn(new Long(HIT_COUNT)); List<Result> results = new ArrayList<Result>(); int count = 0; for (Metacard metacard : getMetacards()) { Result result = mock(Result.class); when(result.getMetacard()).thenReturn(metacard); results.add(result); count++; if (count >= PAGE_SIZE) { break; } } when(sourceResponse.getResults()).thenReturn(results); when(message.getBody()).thenReturn(sourceResponse); return message; } private static Message createResponse() { Message message = mock(Message.class); return message; } private static Map<String, String> createHeaders() { Map<String, String> headers = new HashMap<String, String>(); headers.put("url", URL); return headers; } private static boolean hasResource(Metacard metacard) { return hasResource(metacard.getTitle()); } private static boolean hasResource(String title) { int index = Integer.parseInt(title.split(" ")[1]); return hasResource(index); } private static boolean hasResource(int i) { return 0 == (i % 2); } private static List<Metacard> getMetacards() { if (null == metacards) { metacards = new ArrayList<Metacard>(); for (int i = 0; i < HIT_COUNT; i++) { Metacard metacard = mock(Metacard.class); when(metacard.getSourceId()).thenReturn(LOCAL_ID); when(metacard.getLocation()).thenReturn(METACARD_LOCATION); when(metacard.getTitle()).thenReturn(METACARD_TITLE + " " + i); when(metacard.getEffectiveDate()).thenReturn(runTimeDate); when(metacard.getCreatedDate()).thenReturn(runTimeDate); if (hasResource(i)) { // just give even numbered metacards resources, any uri is // fine try { URI uri = generateActionUrl(RESOURCE_ACTION, metacard).toURI(); when(metacard.getResourceURI()).thenReturn(uri); when(metacard.getResourceSize()).thenReturn(RESOURCE_SIZE + i); } catch (URISyntaxException e) { } } metacards.add(metacard); } } return metacards; } private static Exchange createExchange() { Set<ContentType> contentTypes = new HashSet<ContentType>(); ContentType a = mock(ContentType.class); when(a.getName()).thenReturn(CONTENT_TYPE_1); ContentType b = mock(ContentType.class); when(b.getName()).thenReturn(CONTENT_TYPE_2); ContentType c = mock(ContentType.class); when(c.getName()).thenReturn(CONTENT_TYPE_3); ContentType d = mock(ContentType.class); when(d.getName()).thenReturn(CONTENT_TYPE_3); // duplicate should be // filtered contentTypes.add(a); contentTypes.add(b); contentTypes.add(c); contentTypes.add(d); List<ActionProvider> htmlActionProviderList = new ArrayList<ActionProvider>(); htmlActionProviderList.add(buildActionProvider(HTML_ACTION)); List<ActionProvider> metacardActionProviderList = new ArrayList<ActionProvider>(); metacardActionProviderList.add(buildActionProvider(METACARD_ACTION)); List<ActionProvider> thumbnailActionProviderList = new ArrayList<ActionProvider>(); List<ActionProvider> resourceActionProviderList = new ArrayList<ActionProvider>(); resourceActionProviderList.add(buildActionProvider(RESOURCE_ACTION, true)); SourceInfoRequestEnterprise sourceInfoRequest = mock(SourceInfoRequestEnterprise.class); CatalogFramework catalog = mock(CatalogFramework.class); SourceInfoResponse sourceInfoResponse = mock(SourceInfoResponse.class); Set<SourceDescriptor> srcSet = new HashSet<SourceDescriptor>(); when(catalog.getId()).thenReturn(LOCAL_ID); SourceDescriptor localSrc = mock(SourceDescriptor.class); when(localSrc.getSourceId()).thenReturn(LOCAL_ID); when(localSrc.isAvailable()).thenReturn(true); when(localSrc.getContentTypes()).thenReturn(contentTypes); srcSet.add(localSrc); SourceDescriptor fedSource1 = mock(SourceDescriptor.class); when(fedSource1.getSourceId()).thenReturn(FED_SOURCE_1_ID); when(fedSource1.isAvailable()).thenReturn(true); srcSet.add(fedSource1); srcSet.add(fedSource1); // add it twice, should be filtered SourceDescriptor fedSource2 = mock(SourceDescriptor.class); when(fedSource2.getSourceId()).thenReturn(FED_SOURCE_2_ID); when(fedSource2.getContentTypes()).thenReturn(new HashSet<ContentType>()); when(fedSource2.isAvailable()).thenReturn(false); srcSet.add(fedSource2); when(sourceInfoResponse.getSourceInfo()).thenReturn(srcSet); try { when(catalog.getSourceInfo(sourceInfoRequest)).thenReturn(sourceInfoResponse); } catch (SourceUnavailableException e) { } BeansWrapper beansWrapper = new BeansWrapper(); Exchange exchange = mock(Exchange.class); when(exchange.getProperty("title")).thenReturn(TITLE); when(exchange.getProperty("header")).thenReturn(HEADER); when(exchange.getProperty("footer")).thenReturn(FOOTER); when(exchange.getProperty("catalog")).thenReturn(catalog); when(exchange.getProperty("beansWrapper")).thenReturn(beansWrapper); when(exchange.getProperty("sourceInfoReqEnterprise")).thenReturn(sourceInfoRequest); when(exchange.getProperty("htmlActionProviderList")).thenReturn(htmlActionProviderList); when(exchange.getProperty("metacardActionProviderList")) .thenReturn(metacardActionProviderList); when(exchange.getProperty("thumbnailActionProviderList")) .thenReturn(thumbnailActionProviderList); when(exchange.getProperty("resourceActionProviderList")) .thenReturn(resourceActionProviderList); return exchange; } private static ActionProvider buildActionProvider(String actionStr) { return buildActionProvider(actionStr, false); } private static ActionProvider buildActionProvider(String actionStr, boolean halfNull) { ActionProvider metacardAction = mock(ActionProvider.class); boolean returnNull = false; for (Metacard metacard : getMetacards()) { Action action = mock(Action.class); URL url = generateActionUrl(actionStr, metacard); when(action.getUrl()).thenReturn((halfNull && returnNull) ? null : url); when(metacardAction.getAction(metacard)).thenReturn(action); returnNull = !returnNull; } return metacardAction; } private static java.net.URL generateActionUrl(String actionStr, Metacard metacard) { try { return new URI(SCHEME, null, HOST, PORT, actionStr, null, metacard.getTitle()).toURL(); } catch (MalformedURLException e) { LOGGER.error("Malformed URL", e); return null; } catch (URISyntaxException e) { LOGGER.error("URI Syntax error", e); return null; } } @Test public void testHeader() { assertTrue(generatedHtml.contains("<div class=\"banner\">" + HEADER + "</div>")); } @Test public void testFooter() { assertTrue(generatedHtml .contains("<div class=\"navbar-fixed-bottom banner\">" + FOOTER + "</div>")); } @Test public void testSites() { // contains each site once and only once assertTrue(containsExactlyOnce(generatedHtml, "<option title=\"" + LOCAL_ID + "\">" + LOCAL_ID + "</option>")); assertTrue(containsExactlyOnce(generatedHtml, "<option title=\"" + FED_SOURCE_1_ID + "\">" + FED_SOURCE_1_ID + "</option>")); assertTrue(containsExactlyOnce(generatedHtml, "<option disabled=\"disabled\" class=\"disabled_option\" title=\"" + FED_SOURCE_2_ID + "\">" + FED_SOURCE_2_ID + "</option>")); } @Test public void testContentTypes() { assertTrue(containsExactlyOnce(generatedHtml, "<option>" + CONTENT_TYPE_1 + "</option>")); assertTrue(containsExactlyOnce(generatedHtml, "<option>" + CONTENT_TYPE_2 + "</option>")); assertTrue(containsExactlyOnce(generatedHtml, "<option>" + CONTENT_TYPE_3 + "</option>")); } @Test public void testHitCount() { assertTrue(generatedHtml.contains( "<div class=\"resultsCount pull-left span6\" ><p class=\"lead\">Total Results: " + NumberFormat.getIntegerInstance().format(HIT_COUNT) + " </p></div>")); } @Test public void testMetacardActionProvider() { int count = 0; for (Metacard metacard : getMetacards()) { if (count < PAGE_SIZE) { assertTrue(generatedHtml.contains( "<a class=\"metacard-modal\" href=\"" + generateActionUrl(HTML_ACTION, metacard) + "\">" + metacard.getTitle() + "</a>")); } else { assertFalse(generatedHtml.contains( "<a href=\"" + generateActionUrl(HTML_ACTION, metacard) + "\">" + metacard .getTitle() + "</a>")); } count++; } } @Test public void testResourceActionProvider() { int count = 0; for (Metacard metacard : getMetacards()) { if (null == metacard.getResourceURI() || count >= PAGE_SIZE && hasResource(metacard)) { assertFalse(generatedHtml.contains( "<a href=\"" + generateActionUrl(RESOURCE_ACTION, metacard) + "\">")); assertFalse(generatedHtml.contains( "<div style=\"visibility: hidden;\" class=\"resourceSize\">" + RESOURCE_SIZE + count + "</div>")); } else { assertTrue(generatedHtml.contains( "<a href=\"" + generateActionUrl(RESOURCE_ACTION, metacard) + "\" target=\"_blank\">")); assertTrue(generatedHtml.contains( "<div style=\"visibility: hidden;\" class=\"resourceSize\">" + RESOURCE_SIZE + count + "</div>")); } count++; } } @Test public void testDates() { String timeAsString = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz").format(runTimeDate); int lastIndexCreated = -1; int lastIndexEffective = -1; int count = 0; for (Iterator<Metacard> itr = getMetacards().iterator(); itr.hasNext() && count < PAGE_SIZE; itr.next()) { count++; lastIndexCreated = generatedHtml .indexOf("Effective: " + timeAsString + "<br>", lastIndexCreated + 1); lastIndexEffective = generatedHtml .indexOf("Received: " + timeAsString + "</td>", lastIndexEffective + 1); assertTrue(lastIndexCreated != -1); assertTrue(lastIndexEffective != -1); } } @Test public void testPageCount() { boolean hasPages = (PAGE_SIZE < HIT_COUNT); if (hasPages) { assertTrue(generatedHtml.contains("<div class=\"pagination pull-right span6\">")); assertTrue(generatedHtml .contains("<li class=\"disabled\"><a href=\"" + URL + "\">Prev</a></li>")); assertTrue(generatedHtml .contains("<li class=\"active\"><a href=\"" + URL + "\">1</a></li>")); assertTrue(generatedHtml.contains(">Next</a></li>")); int pages = (int) Math.ceil(((double) HIT_COUNT) / ((double) PAGE_SIZE)); for (int i = 2; i <= pages && i <= 4; i++) { assertTrue(generatedHtml.contains(">" + i + "</a></li>")); } } else { assertFalse(generatedHtml.contains("<div class=\"pagination pull-right span6\">")); } } private boolean containsExactlyOnce(String string, String fragment) { return string.contains(fragment) && (string.indexOf(fragment) == string .lastIndexOf(fragment)); } }