/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wfs.xslt.config;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
import org.easymock.EasyMock;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.impl.FeatureTypeInfoImpl;
import org.geoserver.config.GeoServerDataDirectory;
import org.geoserver.wfs.xslt.XSLTTestSupport;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
public class TransformRepositoryTest {
File testRoot;
private TransformRepository repo;
private FeatureTypeInfoImpl ft1;
private FeatureTypeInfoImpl ft2;
@Before
public void setup() throws IOException {
// make sure the test root exists and it's empty
File dataDir = new File("./target/repository-test");
if (dataDir.exists()) {
XSLTTestSupport.deleteDirectory(dataDir);
}
assertTrue(dataDir.mkdirs());
// setup a mock catalog
Catalog catalog = EasyMock.createNiceMock(Catalog.class);
ft1 = new FeatureTypeInfoImpl(catalog);
ft1.setId("ft1-id");
ft2 = new FeatureTypeInfoImpl(catalog);
ft2.setId("ft2-id");
expect(catalog.getFeatureType("ft1-id")).andReturn(ft1).anyTimes();
expect(catalog.getFeatureType("ft2-id")).andReturn(ft2).anyTimes();
replay(catalog);
repo = new TransformRepository(new GeoServerDataDirectory(dataDir), catalog);
testRoot = new File(new File(dataDir, "wfs"), "transform");
}
@Test
public void testSaveNoName() throws IOException {
TransformInfo original = new TransformInfo();
try {
repo.putTransformInfo(original);
fail("Shoudl have thrown an exception, the tx name is not set");
} catch (IllegalArgumentException e) {
// fine
}
}
@Test
public void testSaveReloadInfo() throws IOException {
TransformInfo original = new TransformInfo();
original.setName("test");
original.setSourceFormat("application/xml");
original.setOutputFormat("text/plain");
original.setFileExtension("txt");
original.setXslt("test-tx.xslt");
repo.putTransformInfo(original);
assertTrue(new File(testRoot, "test.xml").exists());
// force the cache to be cleared and reload
repo.infoCache.clear();
TransformInfo reloaded = repo.getTransformInfo("test");
assertEquals(original, reloaded);
}
@Test
public void testLoadInfo() throws IOException {
String xml = "<transform>\n" //
+ " <sourceFormat>application/xml</sourceFormat>\n" //
+ " <outputFormat>text/plain</outputFormat>\n" //
+ " <fileExtension>txt</fileExtension>\n" //
+ " <xslt>test-tx.xslt</xslt>\n"//
+ "</transform>";
testRoot.mkdirs();
File file = new File(testRoot, "test.xml");
FileUtils.writeStringToFile(file, xml);
TransformInfo info = repo.getTransformInfo("test");
assertNotNull(info);
assertEquals("test", info.getName());
assertEquals("application/xml", info.getSourceFormat());
assertEquals("text/plain", info.getOutputFormat());
assertEquals("txt", info.getFileExtension());
assertEquals("test-tx.xslt", info.getXslt());
}
@Test
public void testRefreshFromFile() throws IOException, InterruptedException {
// write out the config and make the repo cache it
String xml1 = "<transform>\n" //
+ " <sourceFormat>application/xml</sourceFormat>\n" //
+ " <outputFormat>text/plain</outputFormat>\n" //
+ " <fileExtension>txt</fileExtension>\n" //
+ " <xslt>test-tx.xslt</xslt>\n"//
+ "</transform>";
testRoot.mkdirs();
File file = new File(testRoot, "test.xml");
FileUtils.writeStringToFile(file, xml1);
TransformInfo info1 = repo.getTransformInfo("test");
assertNotNull(info1);
// wait enough for the file to be considered stale
Thread.sleep((long) (CacheItem.MIN_INTERVALS_CHECK * 1.1));
// write another version
String xml2 = "<transform>\n" //
+ " <sourceFormat>text/xml; subtype=gml/2.1.2</sourceFormat>\n" //
+ " <outputFormat>application/json</outputFormat>\n" //
+ " <fileExtension>json</fileExtension>\n" //
+ " <xslt>json-tx.xslt</xslt>\n"//
+ "</transform>";
FileUtils.writeStringToFile(file, xml2);
// reload and check
TransformInfo info2 = repo.getTransformInfo("test");
assertNotNull(info2);
assertEquals("test", info2.getName());
assertEquals("text/xml; subtype=gml/2.1.2", info2.getSourceFormat());
assertEquals("application/json", info2.getOutputFormat());
assertEquals("json", info2.getFileExtension());
assertEquals("json-tx.xslt", info2.getXslt());
}
@Test
public void testDeleteOnFilesystem() throws IOException, InterruptedException {
// write out the config and make the repo cache it
String xml1 = "<transform>\n" //
+ " <sourceFormat>application/xml</sourceFormat>\n" //
+ " <outputFormat>text/plain</outputFormat>\n" //
+ " <fileExtension>txt</fileExtension>\n" //
+ " <xslt>test-tx.xslt</xslt>\n"//
+ "</transform>";
testRoot.mkdirs();
File file = new File(testRoot, "test.xml");
FileUtils.writeStringToFile(file, xml1);
TransformInfo info1 = repo.getTransformInfo("test");
assertNotNull(info1);
// wait enough for the file to be considered stale
Thread.sleep((long) (CacheItem.MIN_INTERVALS_CHECK * 1.1));
// delete the resource from disk
file.delete();
// reload and check we are not getting a stale object
TransformInfo info2 = repo.getTransformInfo("test");
assertNull(info2);
}
@Test
public void testFeatureTypeReference() throws Exception {
TransformInfo original = new TransformInfo();
original.setName("test");
original.setSourceFormat("application/xml");
original.setOutputFormat("text/plain");
original.setFileExtension("txt");
original.setXslt("test-tx.xslt");
original.setFeatureType(ft1);
repo.putTransformInfo(original);
File configFile = new File(testRoot, "test.xml");
assertTrue(configFile.exists());
// force the cache to be cleared and reload
repo.infoCache.clear();
TransformInfo reloaded = repo.getTransformInfo("test");
assertEquals(original, reloaded);
// check the file on disk
Document doc = XMLUnit.buildTestDocument(FileUtils.readFileToString(configFile));
XMLAssert.assertXpathEvaluatesTo("ft1-id", "/transform/featureType/id", doc);
}
@Test
public void testListMethods() throws Exception {
// prepare a set of configurations
writeConfiguration("c1", null);
writeConfiguration("c2", ft1);
writeConfiguration("c3", ft2);
// check all transforms
List<TransformInfo> configs = repo.getAllTransforms();
assertEquals(3, configs.size());
Set<String> names = getConfigurationNames(configs);
assertTrue(names.contains("c1"));
assertTrue(names.contains("c2"));
assertTrue(names.contains("c3"));
// check global
configs = repo.getAllTransforms();
assertEquals(3, configs.size());
names = getConfigurationNames(configs);
assertTrue(names.contains("c1"));
// check associated to ft1
configs = repo.getTypeTransforms(ft1);
assertEquals(1, configs.size());
names = getConfigurationNames(configs);
assertTrue(names.contains("c2"));
// check associated to ft2
configs = repo.getTypeTransforms(ft2);
assertEquals(1, configs.size());
names = getConfigurationNames(configs);
assertTrue(names.contains("c3"));
}
@Test
public void testWriteXSLT() throws Exception {
TransformInfo original = new TransformInfo();
original.setName("test");
original.setSourceFormat("application/xml");
original.setOutputFormat("text/plain");
original.setFileExtension("txt");
original.setXslt("test-tx.xslt");
repo.putTransformInfo(original);
File info = new File(testRoot, "test.xml");
assertTrue(info.exists());
repo.putTransformSheet(original, getClass().getResourceAsStream("test.xslt"));
File xslt = new File(testRoot, "test-tx.xslt");
assertTrue(xslt.exists());
String expected = IOUtils.toString(getClass().getResourceAsStream("test.xslt"));
String actual = FileUtils.readFileToString(xslt);
assertEquals(expected, actual);
repo.removeTransformInfo(original);
assertFalse(info.exists());
assertFalse(xslt.exists());
}
@Test
public void testWriteXSLTShared() throws Exception {
TransformInfo info1 = new TransformInfo();
info1.setName("test1");
info1.setSourceFormat("application/xml");
info1.setOutputFormat("text/plain");
info1.setFileExtension("txt");
info1.setXslt("test-tx.xslt");
repo.putTransformInfo(info1);
File infoFile1 = new File(testRoot, "test1.xml");
assertTrue(infoFile1.exists());
TransformInfo info2 = new TransformInfo();
info2.setName("test2");
info2.setSourceFormat("application/xml");
info2.setOutputFormat("text/plain");
info2.setFileExtension("txt");
info2.setXslt("test-tx.xslt");
repo.putTransformInfo(info2);
File infoFile2 = new File(testRoot, "test2.xml");
assertTrue(infoFile2.exists());
repo.putTransformSheet(info1, getClass().getResourceAsStream("test.xslt"));
File xslt = new File(testRoot, "test-tx.xslt");
assertTrue(xslt.exists());
repo.removeTransformInfo(info1);
assertFalse(infoFile1.exists());
// shared, not deleted
assertTrue(xslt.exists());
assertTrue(infoFile2.exists());
// remote the other too
repo.removeTransformInfo(info2);
assertFalse(xslt.exists());
assertFalse(infoFile2.exists());
}
@Test
public void testTransform() throws Exception {
TransformInfo info = new TransformInfo();
info.setName("test");
info.setSourceFormat("application/xml");
info.setOutputFormat("text/plain");
info.setFileExtension("txt");
info.setXslt("test-tx.xslt");
repo.putTransformInfo(info);
repo.putTransformSheet(info, getClass().getResourceAsStream("test.xslt"));
Transformer transformer = repo.getTransformer(info);
InputStream is = getClass().getResourceAsStream("sample.xml");
StreamSource source = new StreamSource(is);
DOMResult result = new DOMResult();
transformer.transform(source, result);
Document dom = (Document) result.getNode();
XMLAssert.assertXpathEvaluatesTo("12", "count(/html/body/table/tr/td)", dom);
XMLAssert.assertXpathEvaluatesTo("1", "count(/html/body/table/tr[td='museum'])", dom);
XMLAssert.assertXpathEvaluatesTo("1", "count(/html/body/table/tr[td='-74.0104611,40.70758763'])", dom);
}
private Set<String> getConfigurationNames(List<TransformInfo> configs) {
Set<String> result = new HashSet<String>();
for (TransformInfo ti : configs) {
result.add(ti.getName());
}
return result;
}
private void writeConfiguration(String name, FeatureTypeInfo ft) throws IOException {
TransformInfo ti = new TransformInfo();
ti.setName(name);
ti.setSourceFormat("application/xml");
ti.setOutputFormat("text/plain");
ti.setFileExtension("txt");
ti.setXslt("test-tx.xslt");
ti.setFeatureType(ft);
String xml = repo.xs.toXML(ti);
FileUtils.writeStringToFile(new File(testRoot, name + ".xml"), xml);
}
}