/* (c) 2015 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.csw;
import static junit.framework.TestCase.assertEquals;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.custommonkey.xmlunit.exceptions.XpathException;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.MetadataMap;
import org.geoserver.csw.DownloadLinkHandler.CloseableLinksIterator;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.data.test.TestData;
import org.geoserver.test.GeoServerSystemTestSupport;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.csw.CSW;
import org.geotools.csw.DC;
import org.geotools.csw.DCT;
import org.geotools.data.CloseableIterator;
import org.geotools.data.FileGroupProvider.FileGroup;
import org.geotools.data.FileResourceInfo;
import org.geotools.filter.v1_1.OGC;
import org.geotools.ows.OWS;
import org.geotools.xlink.XLINK;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
public class DirectDownloadTest extends GeoServerSystemTestSupport {
private static Map<String, String> TEST_NAMESPACES;
private XpathEngine xpathEngine;
@BeforeClass
public static void configureXMLUnit() throws Exception {
System.clearProperty("DefaultCatalogStore");
TEST_NAMESPACES = new HashMap<String, String>();
TEST_NAMESPACES.put("csw", CSW.NAMESPACE);
TEST_NAMESPACES.put("dc", DC.NAMESPACE);
TEST_NAMESPACES.put("dct", DCT.NAMESPACE);
TEST_NAMESPACES.put("csw", CSW.NAMESPACE);
TEST_NAMESPACES.put("ows", OWS.NAMESPACE);
TEST_NAMESPACES.put("ogc", OGC.NAMESPACE);
TEST_NAMESPACES.put("gml", "http://www.opengis.net/gml");
TEST_NAMESPACES.put("xlink", XLINK.NAMESPACE);
TEST_NAMESPACES.put("xsi", "http://www.w3.org/2001/XMLSchema-instance");
TEST_NAMESPACES.put("xsd", "http://www.w3.org/2001/XMLSchema");
TEST_NAMESPACES.put("xs", "http://www.w3.org/2001/XMLSchema");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(TEST_NAMESPACES));
};
public static String CSW_PREFIX = "csw";
public static String CSW_URI = "http://www.opengis.net/csw/2.0.2";
public static QName WATTEMP = new QName(CSW_URI, "watertemp", CSW_PREFIX);
private final static String GET_RECORD_REQUEST = "csw?service=csw&version=2.0.2&request=GetRecords"
+ "&elementsetname=full&typeNames=csw:Record&resultType=results"
+ "&constraint=title=%27watertemp%27";
@Override
protected void setUpTestData(SystemTestData testData) throws Exception {
testData.setUpRasterLayer(WATTEMP, "watertemp.zip", null, null, TestData.class);
}
@Override
protected void onSetUp(SystemTestData testData) throws Exception {
super.onSetUp(testData);
enableDirectDownload();
}
private void enableDirectDownload() {
final Catalog cat = getCatalog();
String name = "watertemp";
final CoverageInfo coverageInfo = cat.getCoverageByName(name);
coverageInfo.setName(name);
coverageInfo.setNativeName(name);
// This line of code has been commented on purpose
// in order to test the fix for GEOS-7290
// coverageInfo.setNativeCoverageName(name);
coverageInfo.setTitle(name);
final MetadataMap metadata = coverageInfo.getMetadata();
DirectDownloadSettings settings = new DirectDownloadSettings();
settings.setDirectDownloadEnabled(true);
// Setting 10K limit
settings.setMaxDownloadSize(10);
metadata.getMap().put(DirectDownloadSettings.DIRECTDOWNLOAD_KEY, settings);
cat.save(coverageInfo);
}
@Test
public void testGetRecordWithDirectDownloadLink() throws Exception {
Document dom = getAsDOM(GET_RECORD_REQUEST);
print(dom);
// check we have the expected results
assertXpathEvaluatesTo("1", "count(//csw:Record/dc:identifier)", dom);
assertXpathEvaluatesTo("6", "count(//csw:Record/dct:references)", dom);
assertXpathEvaluatesTo("csw:watertemp", "//csw:Record/dc:identifier", dom);
NodeList nodes = getMatchingNodes("//csw:Record/dct:references", dom);
int size = nodes.getLength();
// Get direct download links
Set<String> links = new HashSet<String>();
for (int i = 0; i < size; i++) {
Node node = nodes.item(i);
String link = node.getTextContent();
if (link.toUpperCase().contains("DIRECTDOWNLOAD") && link.contains("TIME")) {
links.add(link);
}
}
// Get links from the reader
final Catalog cat = getCatalog();
String name = "watertemp";
final CoverageInfo coverageInfo = cat.getCoverageByName(name);
GridCoverage2DReader reader = null;
CloseableLinksIterator<String> iterator = null;
Set<String> generatedLinks = new HashSet<String>();
try {
reader = (GridCoverage2DReader) coverageInfo.getGridCoverageReader(null, null);
FileResourceInfo resourceInfo = (FileResourceInfo) reader.getInfo(name);
CloseableIterator<FileGroup> files = resourceInfo.getFiles(null);
String baseLink = DownloadLinkHandler.LINK;
MockHttpServletRequest request = createRequest(baseLink);
baseLink = request.getRequestURL() + "?" + request.getQueryString();
baseLink = baseLink.replace("${nameSpace}", coverageInfo.getNamespace().getName())
.replace("${layerName}", coverageInfo.getName()).replace("${version}", "2.0.2");
iterator = new CloseableLinksIterator<String>(baseLink, files);
while (iterator.hasNext()) {
generatedLinks.add(iterator.next());
}
} finally {
if (iterator != null) {
iterator.close();
}
if (reader != null) {
try {
reader.dispose();
} catch (Throwable t) {
// Ignore on disposal
}
}
}
// Look for links matching
Iterator<String> it = links.iterator();
int matches = 0;
while (it.hasNext()) {
String cswLink = it.next();
if (generatedLinks.contains(cswLink)) {
matches++;
}
}
assertEquals(4, matches);
}
@Test
public void testDirectDownloadExceedingLimit() throws Exception {
Document dom = getAsDOM(GET_RECORD_REQUEST);
NodeList nodes = getMatchingNodes("//csw:Record/dct:references", dom);
int size = nodes.getLength();
String downloadLink = null;
// Getting the fullDataset Download link
for (int i = 0; i < size; i++) {
Node node = nodes.item(i);
String link = node.getTextContent();
if (link.toUpperCase().contains("DIRECTDOWNLOAD") && !link.contains("TIME")) {
downloadLink = link;
break;
}
}
downloadLink = downloadLink.substring(downloadLink.indexOf("ows?"));
// The output will not be a zip.
// The download will exceed the limit so it returns an exception
MockHttpServletResponse response = getAsServletResponse(downloadLink);
assertEquals("application/xml", response.getContentType());
Document domResponse = dom(new ByteArrayInputStream(response.getContentAsString()
.getBytes()));
Element root = domResponse.getDocumentElement();
assertEquals("ows:ExceptionReport", root.getNodeName());
String exceptionText = evaluate("//ows:ExceptionReport/ows:Exception/ows:ExceptionText",
domResponse);
assertTrue(exceptionText.contains(DirectDownload.LIMIT_MESSAGE));
}
@Test
public void testDirectDownloadFile() throws Exception {
Document dom = getAsDOM(GET_RECORD_REQUEST);
NodeList nodes = getMatchingNodes("//csw:Record/dct:references", dom);
int size = nodes.getLength();
// Getting a file downloadLink
String link = null;
for (int i = 0; i < size; i++) {
Node node = nodes.item(i);
link = node.getTextContent();
if (link.toUpperCase().contains("DIRECTDOWNLOAD") && link.contains("TIME")) {
break;
}
}
link = link.substring(link.indexOf("ows?"));
// The output will be a zip.
MockHttpServletResponse response = getAsServletResponse(link);
assertEquals("application/zip", response.getContentType());
}
private XpathEngine getXpathEngine() {
if (xpathEngine == null) {
xpathEngine = XMLUnit.newXpathEngine();
Map<String, String> namespaces = new HashMap<String, String>();
namespaces.putAll(TEST_NAMESPACES);
xpathEngine.setNamespaceContext(new SimpleNamespaceContext(namespaces));
}
return xpathEngine;
}
/**
* Return the flattened value corresponding to an XPath expression from a document.
*
* @param xpath
* XPath expression
* @param document
* the document under test
* @return flattened string value
*/
protected String evaluate(String xpath, Document document) {
try {
return getXpathEngine().evaluate(xpath, document);
} catch (XpathException e) {
throw new RuntimeException(e);
}
}
/**
* Return the list of nodes in a document that match an XPath expression.
*
* @param xpath
* XPath expression
* @param document
* the document under test
* @return list of matching nodes
*/
protected NodeList getMatchingNodes(String xpath, Document document) {
try {
return getXpathEngine().getMatchingNodes(xpath, document);
} catch (XpathException e) {
throw new RuntimeException(e);
}
}
@AfterClass
public static void resetStore() {
System.setProperty("DefaultCatalogStore", "org.geoserver.csw.store.simple.GeoServerSimpleCatalogStore");
}
}