/* (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.importer.mosaic; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.URL; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Properties; import javax.xml.namespace.QName; import org.apache.commons.io.FileUtils; import org.custommonkey.xmlunit.XMLAssert; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CatalogBuilder; import org.geoserver.catalog.CoverageStoreInfo; import org.geoserver.catalog.DimensionInfo; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.ResourceInfo; import org.geoserver.data.test.MockData; import org.geoserver.data.test.TestData; import org.geoserver.data.util.IOUtils; import org.geoserver.importer.FileData; import org.geoserver.importer.ImportContext; import org.geoserver.importer.ImportTask; import org.geoserver.importer.ImporterTestSupport; import org.geoserver.importer.SpatialFile; import org.geotools.coverage.grid.io.GranuleSource; import org.geotools.coverage.grid.io.StructuredGridCoverage2DReader; import org.geotools.data.Query; import org.geotools.filter.text.ecql.ECQL; import org.geotools.referencing.factory.gridshift.DataUtilities; import org.junit.Test; import org.opengis.filter.Filter; import org.w3c.dom.Document; public class ImporterMosaicTest extends ImporterTestSupport { protected static QName WATTEMP = new QName(MockData.SF_URI, "watertemp", MockData.SF_PREFIX); @Test public void testSimpleMosaic() throws Exception { File dir = unpack("mosaic/bm.zip"); ImportContext context = importer.createContext(new Mosaic(dir)); assertEquals(1, context.getTasks().size()); ImportTask task = context.getTasks().get(0); assertTrue(task.getData() instanceof Mosaic); assertTrue(task.getData().getFormat() instanceof MosaicFormat); importer.run(context); runChecks(dir.getName()); } @Test public void testFilenameTimeHandler() throws Exception { Mosaic m = new Mosaic(unpack("mosaic/bm_time.zip")); m.setTimeMode(TimeMode.FILENAME); FilenameTimeHandler th = (FilenameTimeHandler) m.getTimeHandler(); th.setFilenameRegex("(\\d){6}"); th.setTimeFormat("yyyyMM"); m.prepare(); List<FileData> files = m.getFiles(); assertEquals(4,files.size()); for (int i = 0; i < files.size(); i++) { FileData fd = files.get(i); assertTrue(fd instanceof Granule); Granule g = (Granule) fd; //TODO: comparison fails on build server assertNotNull(g.getTimestamp()); //assertEquals(date(2004, i), g.getTimestamp()); } } @Test public void testTimeMosaic() throws Exception { Mosaic m = new Mosaic(unpack("mosaic/bm_time.zip")); m.setTimeMode(TimeMode.FILENAME); FilenameTimeHandler th = (FilenameTimeHandler) m.getTimeHandler(); th.setFilenameRegex("(\\d){6}"); th.setTimeFormat("yyyyMM"); ImportContext context = importer.createContext(m); assertEquals(1, context.getTasks().size()); importer.run(context); LayerInfo l = context.getTasks().get(0).getLayer(); ResourceInfo r = l.getResource(); assertTrue(r.getMetadata().containsKey("time")); DimensionInfo d = (DimensionInfo) r.getMetadata().get("time"); assertNotNull(d); runChecks(l.getName()); Document dom = getAsDOM(String.format("/%s/%s/wms?request=getcapabilities", r.getStore().getWorkspace().getName(), l.getName())); XMLAssert.assertXpathExists( "//wms:Layer[wms:Name = '" + m.getName() + "']/wms:Dimension[@name = 'time']", dom); } @Test public void testTimeMosaicAuto() throws Exception { Mosaic m = new Mosaic(unpack("mosaic/bm_time.zip")); m.setTimeMode(TimeMode.AUTO); ImportContext context = importer.createContext(m); assertEquals(1, context.getTasks().size()); importer.run(context); LayerInfo l = context.getTasks().get(0).getLayer(); ResourceInfo r = l.getResource(); assertTrue(r.getMetadata().containsKey("time")); DimensionInfo d = (DimensionInfo) r.getMetadata().get("time"); assertNotNull(d); runChecks(l.getName()); Document dom = getAsDOM(String.format("/%s/%s/wms?request=getcapabilities", r.getStore().getWorkspace().getName(), l.getName())); XMLAssert.assertXpathExists( "//wms:Layer[wms:Name = '" + m.getName() + "']/wms:Dimension[@name = 'time']", dom); } @Test public void testHarvest() throws Exception { Catalog catalog = getCatalog(); getTestData().addRasterLayer(WATTEMP, "watertemp.zip", null, null, TestData.class, catalog); // check how many layers we have int initialLayerCount = catalog.count(LayerInfo.class, Filter.INCLUDE); // grab the original count CoverageStoreInfo store = catalog.getCoverageStoreByName(WATTEMP.getLocalPart()); StructuredGridCoverage2DReader reader = (StructuredGridCoverage2DReader) store .getGridCoverageReader(null, null); GranuleSource gs = reader.getGranules(reader.getGridCoverageNames()[0], true); int originalCount = gs.getCount(Query.ALL); String mosaicLocation = store.getURL(); File mosaicFolder = DataUtilities.urlToFile(new URL(mosaicLocation)); try (InputStream is = MockData.class.getResourceAsStream("harvesting.zip")) { IOUtils.decompress(is, mosaicFolder); } String fileName1 = "NCOM_wattemp_000_20081102T0000000_12.tiff"; File file1 = new File(mosaicFolder, fileName1); assertTrue(file1.exists()); ImportContext context = importer.createContext(new SpatialFile(file1), store); String fileName2 = "NCOM_wattemp_100_20081102T0000000_12.tiff"; File file2 = new File(mosaicFolder, fileName2); importer.update(context, new SpatialFile(file2)); assertEquals(2, context.getTasks().size()); importer.run(context); assertEquals(originalCount + 2, gs.getCount(Query.ALL)); assertEquals(1, gs.getCount(new Query(null, ECQL.toFilter("location = '" + fileName1 + "'")))); assertEquals(1, gs.getCount(new Query(null, ECQL.toFilter("location = '" + fileName2 + "'")))); // make sure we did not create a new layer int layerCount = catalog.count(LayerInfo.class, Filter.INCLUDE); assertEquals(initialLayerCount, layerCount); } @Test public void testPopulateEmptyMosaic() throws Exception { Catalog catalog = getCatalog(); // prepare an empty mosaic File root = getTestData().getDataDirectoryRoot(); String mosaicName = "emptyMosaic"; File mosaicRoot = new File(root, mosaicName); if (mosaicRoot.exists()) { FileUtils.deleteDirectory(mosaicRoot); } mosaicRoot.mkdirs(); Properties props = new Properties(); props.put("SPI", "org.geotools.data.h2.H2DataStoreFactory"); props.put("database", "empty"); try (FileOutputStream fos = new FileOutputStream(new File(mosaicRoot, "datastore.properties"))) { props.store(fos, null); } CatalogBuilder cb = new CatalogBuilder(catalog); cb.setWorkspace(catalog.getDefaultWorkspace()); CoverageStoreInfo store = cb.buildCoverageStore(mosaicName); store.setURL("./" + mosaicName); store.setType("ImageMosaic"); catalog.save(store); // put a granule in the mosaic unpack("geotiff/EmissiveCampania.tif.bz2", mosaicRoot); File granule = new File(mosaicRoot, "EmissiveCampania.tif"); store = catalog.getCoverageStoreByName(mosaicName); ImportContext context = importer.createContext(new SpatialFile(granule), store); assertEquals(1, context.getTasks().size()); importer.run(context); // check the import produced a granule StructuredGridCoverage2DReader reader = (StructuredGridCoverage2DReader) store .getGridCoverageReader(null, null); GranuleSource granules = reader.getGranules(mosaicName, true); assertEquals(1, granules.getCount(Query.ALL)); // check we now also have a layer LayerInfo layer = catalog.getLayerByName(mosaicName); assertNotNull(layer); } Date date(int year, int month) { Calendar c = Calendar.getInstance(); c.set(Calendar.YEAR, year); c.set(Calendar.MONTH, month); c.set(Calendar.DAY_OF_MONTH, 1); c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.MINUTE, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); return c.getTime(); } }