/* (c) 2014 - 2016 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.wcs2_0; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.io.File; import java.util.Map; import javax.xml.namespace.QName; import org.apache.commons.io.FileUtils; import org.geoserver.catalog.DimensionPresentation; import org.geoserver.catalog.ResourceInfo; import org.geoserver.data.test.CiteTestData; import org.geoserver.data.test.SystemTestData; import org.geoserver.ows.util.CaseInsensitiveMap; import org.geoserver.ows.util.KvpUtils; import org.geoserver.wcs2_0.kvp.WCS20GetCoverageRequestReader; import org.junit.Test; import org.springframework.mock.web.MockHttpServletResponse; import net.opengis.wcs20.GetCoverageType; import ucar.nc2.Dimension; import ucar.nc2.Variable; import ucar.nc2.dataset.NetcdfDataset; /** * Base support class for NetCDF wcs tests. * * @author Daniele Romagnoli, GeoSolutions * */ public class WCSNetCDFTest extends WCSNetCDFBaseTest { public static final double DELTA = 1e-6; public static QName POLYPHEMUS = new QName(CiteTestData.WCS_URI, "polyphemus", CiteTestData.WCS_PREFIX); public static QName NO2 = new QName(CiteTestData.WCS_URI, "NO2", CiteTestData.WCS_PREFIX); public static QName TEMPERATURE_SURFACE_NETCDF = new QName(CiteTestData.WCS_URI, "Temperature_surface_NetCDF", CiteTestData.WCS_PREFIX); public static QName TEMPERATURE_SURFACE_GRIB = new QName(CiteTestData.WCS_URI, "Temperature_surface", CiteTestData.WCS_PREFIX); public static QName SNOW_DEPTH_GRIB = new QName(CiteTestData.WCS_URI, "Snow_depth_water_equivalent_surface", CiteTestData.WCS_PREFIX); /** * Only setup coverages */ protected void setUpTestData(SystemTestData testData) throws Exception { super.setUpTestData(testData); } @SuppressWarnings("unchecked") protected GetCoverageType parse(String url) throws Exception { Map<String, Object> rawKvp = new CaseInsensitiveMap(KvpUtils.parseQueryString(url)); Map<String, Object> kvp = new CaseInsensitiveMap(parseKvp(rawKvp)); WCS20GetCoverageRequestReader reader = new WCS20GetCoverageRequestReader(); GetCoverageType gc = (GetCoverageType) reader.createRequest(); return (GetCoverageType) reader.read(gc, kvp, rawKvp); } @Override protected void onSetUp(SystemTestData testData) throws Exception { super.onSetUp(testData); testData.addRasterLayer(POLYPHEMUS, "pol.zip", null, null, this.getClass(), getCatalog()); setupRasterDimension(getLayerId(NO2), ResourceInfo.TIME, DimensionPresentation.LIST, null); setupRasterDimension(getLayerId(NO2), ResourceInfo.ELEVATION, DimensionPresentation.LIST, null); testData.addRasterLayer(TEMPERATURE_SURFACE_NETCDF, "rotated-pole.nc", null, null, this.getClass(), getCatalog()); testData.addRasterLayer(TEMPERATURE_SURFACE_GRIB, "rap-native.grib2", null, null, this.getClass(), getCatalog()); testData.addRasterLayer(SNOW_DEPTH_GRIB, "cosmo-eu.grib2", null, null, this.getClass(), getCatalog()); } /** * This test checks if an exception is not thrown when is requested an image with a total size lower than the maximum * geoserver output size. * */ @Test public void testOutputMemoryNotExceeded() throws Exception { // Setting of the output limit to 40 Kb setOutputLimit(40); // http response from the request inside the string MockHttpServletResponse response = getAsServletResponse("ows?request=GetCoverage&service=WCS&version=2.0.1" + "&coverageId=wcs__NO2&format=application/x-netcdf&subset=http://www.opengis.net/def/axis/OGC/0/elevation(450)"); // The status code should be correct assertEquals(200, response.getStatus()); // The output format should be netcdf assertEquals("application/x-netcdf", response.getContentType()); // Reset output limit setOutputLimit(-1); } /** * This test checks if an exception is thrown when is requested an image with a total size greater than the maximum * geoserver output memory allowed. * */ @Test public void testOutputMemoryExceeded() throws Exception { // Setting of the output limit to 40 Kb setOutputLimit(40); // http response from the request inside the string MockHttpServletResponse response = getAsServletResponse("ows?request=GetCoverage&service=WCS&version=2.0.1" + "&coverageId=wcs__NO2&format=application/x-netcdf"); // The output format should be xml because an exception must be thrown assertEquals("application/xml", response.getContentType()); // Reset output limit setOutputLimit(-1); } /** * This test checks if an exception is not thrown when is requested an image with a total size lower than the maximum * geoserver input size. * */ @Test public void testInputMemoryCorrect() throws Exception { // Setting of the input limit to 40 Kb setInputLimit(40); // http response from the request inside the string MockHttpServletResponse response = getAsServletResponse("ows?request=GetCoverage&service=WCS&version=2.0.1" + "&coverageId=wcs__NO2&format=application/x-netcdf&subset=http://www.opengis.net/def/axis/OGC/0/elevation(450)"); // The status code should be correct assertEquals(200, response.getStatus()); // The output format should be netcdf assertEquals("application/x-netcdf", response.getContentType()); // Reset input limit setInputLimit(-1); } /** * This test checks if an exception is thrown when is requested an image with a total size greater than the maximum * geoserver input memory allowed. * */ @Test public void testInputMemoryExceeded() throws Exception { // Setting of the input limit to 40 Kb setInputLimit(40); // http response from the request inside the string MockHttpServletResponse response = getAsServletResponse("ows?request=GetCoverage&service=WCS&version=2.0.1" + "&coverageId=wcs__NO2&format=application/x-netcdf"); // The output format should be xml because an exception must be thrown assertEquals("application/xml", response.getContentType()); // Reset input limit setInputLimit(-1); } /** * Test NetCDF output from a NetCDF file with a rotated pole projection. */ @Test public void testNetcdfRotatedPole() throws Exception { MockHttpServletResponse response = getAsServletResponse( "ows?request=GetCoverage&service=WCS&version=2.0.1" + "&coverageid=wcs__Temperature_surface_NetCDF&format=application/x-netcdf"); assertEquals(200, response.getStatus()); assertEquals("application/x-netcdf", response.getContentType()); byte[] responseBytes = getBinary(response); File file = File.createTempFile("netcdf-rotated-pole-", "-wcs__Temperature_surface_NetCDF.nc", new File("./target")); FileUtils.writeByteArrayToFile(file, responseBytes); try (NetcdfDataset dataset = NetcdfDataset.openDataset(file.getAbsolutePath())) { assertNotNull(dataset); // check dimensions Dimension rlonDim = dataset.findDimension("rlon"); assertNotNull(rlonDim); assertEquals(7, rlonDim.getLength()); Dimension rlatDim = dataset.findDimension("rlat"); assertNotNull(rlatDim); assertEquals(5, rlatDim.getLength()); // check coordinate variables Variable rlonVar = dataset.findVariable("rlon"); assertNotNull(rlonVar); assertEquals(1, rlonVar.getDimensions().size()); assertEquals(rlonDim, rlonVar.getDimensions().get(0)); assertEquals("grid_longitude", rlonVar.findAttribute("long_name").getStringValue()); assertEquals("grid_longitude", rlonVar.findAttribute("standard_name").getStringValue()); assertEquals("degrees", rlonVar.findAttribute("units").getStringValue()); assertArrayEquals(new float[] { -30, -20, -10, 0, 10, 20, 30 }, (float[]) rlonVar.read().copyTo1DJavaArray(), (float) DELTA); Variable rlatVar = dataset.findVariable("rlat"); assertNotNull(rlatVar); assertEquals(1, rlatVar.getDimensions().size()); assertEquals(rlatDim, rlatVar.getDimensions().get(0)); assertEquals("grid_latitude", rlatVar.findAttribute("long_name").getStringValue()); assertEquals("grid_latitude", rlatVar.findAttribute("standard_name").getStringValue()); assertEquals("degrees", rlatVar.findAttribute("units").getStringValue()); assertArrayEquals(new float[] { -20, -10, 0, 10, 20 }, (float[]) rlatVar.read().copyTo1DJavaArray(), (float) DELTA); // check projection variable Variable projVar = dataset.findVariable("rotated_latitude_longitude"); assertNotNull(projVar); assertEquals("rotated_latitude_longitude", projVar.findAttribute("grid_mapping_name").getStringValue()); assertEquals(74.0, projVar.findAttribute("grid_north_pole_longitude").getNumericValue() .doubleValue(), DELTA); assertEquals(36.0, projVar.findAttribute("grid_north_pole_latitude").getNumericValue() .doubleValue(), DELTA); // check data variable Variable tempVar = dataset.findVariable("Temperature_surface_NetCDF"); assertNotNull(tempVar); assertEquals("rotated_latitude_longitude", tempVar.findAttribute("grid_mapping").getStringValue()); assertEquals("K", tempVar.findAttribute("units").getStringValue()); assertEquals(2, tempVar.getDimensions().size()); assertEquals(rlatDim, tempVar.getDimensions().get(0)); assertEquals(rlonDim, tempVar.getDimensions().get(1)); assertArrayEquals( new float[] { 300, 299, 298, 297, 296, 295, 294, 299, 300, 299, 298, 297, 296, 295, 298, 299, 300, 299, 298, 297, 296, 297, 298, 299, 300, 299, 298, 297, 296, 297, 298, 299, 300, 299, 298 }, (float[]) tempVar.read().copyTo1DJavaArray(), (float) DELTA); } finally { FileUtils.deleteQuietly(file); } } /** * Test NetCDF output from an RAP native GRIB2 file with a GDS template 32769 rotated pole projection. */ @Test public void testRapNativeGribRotatedPole() throws Exception { MockHttpServletResponse response = getAsServletResponse( "ows?request=GetCoverage&service=WCS&version=2.0.1" + "&coverageid=wcs__Temperature_surface&format=application/x-netcdf"); assertEquals(200, response.getStatus()); assertEquals("application/x-netcdf", response.getContentType()); byte[] responseBytes = getBinary(response); File file = File.createTempFile("rap-native-grib-rotated-pole-", "-wcs__Temperature_surface.nc", new File("./target")); FileUtils.writeByteArrayToFile(file, responseBytes); try (NetcdfDataset dataset = NetcdfDataset.openDataset(file.getAbsolutePath())) { assertNotNull(dataset); // check dimensions Dimension rlonDim = dataset.findDimension("rlon"); assertNotNull(rlonDim); assertEquals(7, rlonDim.getLength()); Dimension rlatDim = dataset.findDimension("rlat"); assertNotNull(rlatDim); assertEquals(5, rlatDim.getLength()); // check coordinate variables Variable rlonVar = dataset.findVariable("rlon"); assertNotNull(rlonVar); assertEquals(1, rlonVar.getDimensions().size()); assertEquals(rlonDim, rlonVar.getDimensions().get(0)); assertEquals("grid_longitude", rlonVar.findAttribute("long_name").getStringValue()); assertEquals("grid_longitude", rlonVar.findAttribute("standard_name").getStringValue()); assertEquals("degrees", rlonVar.findAttribute("units").getStringValue()); assertArrayEquals(new float[] { -30, -20, -10, 0, 10, 20, 30 }, (float[]) rlonVar.read().copyTo1DJavaArray(), (float) DELTA); Variable rlatVar = dataset.findVariable("rlat"); assertNotNull(rlatVar); assertEquals(1, rlatVar.getDimensions().size()); assertEquals(rlatDim, rlatVar.getDimensions().get(0)); assertEquals("grid_latitude", rlatVar.findAttribute("long_name").getStringValue()); assertEquals("grid_latitude", rlatVar.findAttribute("standard_name").getStringValue()); assertEquals("degrees", rlatVar.findAttribute("units").getStringValue()); assertArrayEquals(new float[] { -20, -10, 0, 10, 20 }, (float[]) rlatVar.read().copyTo1DJavaArray(), (float) DELTA); // check projection variable Variable projVar = dataset.findVariable("rotated_latitude_longitude"); assertNotNull(projVar); assertEquals("rotated_latitude_longitude", projVar.findAttribute("grid_mapping_name").getStringValue()); assertEquals(74.0, projVar.findAttribute("grid_north_pole_longitude").getNumericValue() .doubleValue(), DELTA); assertEquals(36.0, projVar.findAttribute("grid_north_pole_latitude").getNumericValue() .doubleValue(), DELTA); // check data variable Variable dataVar = dataset.findVariable("Temperature_surface"); assertNotNull(dataVar); assertEquals("rotated_latitude_longitude", dataVar.findAttribute("grid_mapping").getStringValue()); assertEquals("K", dataVar.findAttribute("units").getStringValue()); assertEquals(2, dataVar.getDimensions().size()); assertEquals(rlatDim, dataVar.getDimensions().get(0)); assertEquals(rlonDim, dataVar.getDimensions().get(1)); assertArrayEquals( new float[] { 300, 299, 298, 297, 296, 295, 294, 299, 300, 299, 298, 297, 296, 295, 298, 299, 300, 299, 298, 297, 296, 297, 298, 299, 300, 299, 298, 297, 296, 297, 298, 299, 300, 299, 298 }, (float[]) dataVar.read().copyTo1DJavaArray(), (float) DELTA); } finally { FileUtils.deleteQuietly(file); } } /** * Test NetCDF output from a COSMO EU GRIB2 file with a GDS template 1 rotated pole projection. */ @Test public void testCosmoEuGribRotatedPole() throws Exception { MockHttpServletResponse response = getAsServletResponse( "ows?request=GetCoverage&service=WCS&version=2.0.1" + "&coverageid=wcs__Snow_depth_water_equivalent_surface&format=application/x-netcdf"); assertEquals(200, response.getStatus()); assertEquals("application/x-netcdf", response.getContentType()); byte[] responseBytes = getBinary(response); File file = File.createTempFile("cosmo-eu-grib-rotated-pole-", "-wcs__Snow_depth_water_equivalent_surface.nc", new File("./target")); FileUtils.writeByteArrayToFile(file, responseBytes); try (NetcdfDataset dataset = NetcdfDataset.openDataset(file.getAbsolutePath())) { assertNotNull(dataset); // check dimensions Dimension rlonDim = dataset.findDimension("rlon"); assertNotNull(rlonDim); assertEquals(5, rlonDim.getLength()); Dimension rlatDim = dataset.findDimension("rlat"); assertNotNull(rlatDim); assertEquals(5, rlatDim.getLength()); // check coordinate variables Variable rlonVar = dataset.findVariable("rlon"); assertNotNull(rlonVar); assertEquals(1, rlonVar.getDimensions().size()); assertEquals(rlonDim, rlonVar.getDimensions().get(0)); assertEquals("grid_longitude", rlonVar.findAttribute("long_name").getStringValue()); assertEquals("grid_longitude", rlonVar.findAttribute("standard_name").getStringValue()); assertEquals("degrees", rlonVar.findAttribute("units").getStringValue()); assertArrayEquals(new float[] { -18, -8, 2, 12, 22 }, (float[]) rlonVar.read().copyTo1DJavaArray(), (float) DELTA); Variable rlatVar = dataset.findVariable("rlat"); assertNotNull(rlatVar); assertEquals(1, rlatVar.getDimensions().size()); assertEquals(rlatDim, rlatVar.getDimensions().get(0)); assertEquals("grid_latitude", rlatVar.findAttribute("long_name").getStringValue()); assertEquals("grid_latitude", rlatVar.findAttribute("standard_name").getStringValue()); assertEquals("degrees", rlatVar.findAttribute("units").getStringValue()); assertArrayEquals(new float[] { -20, -10, 0, 10, 20 }, (float[]) rlatVar.read().copyTo1DJavaArray(), (float) DELTA); // check projection variable Variable projVar = dataset.findVariable("rotated_latitude_longitude"); assertNotNull(projVar); assertEquals("rotated_latitude_longitude", projVar.findAttribute("grid_mapping_name").getStringValue()); assertEquals(-170.0, projVar.findAttribute("grid_north_pole_longitude") .getNumericValue().doubleValue(), DELTA); assertEquals(40.0, projVar.findAttribute("grid_north_pole_latitude").getNumericValue() .doubleValue(), DELTA); // check data variable Variable dataVar = dataset.findVariable("Snow_depth_water_equivalent_surface"); assertNotNull(dataVar); assertEquals("rotated_latitude_longitude", dataVar.findAttribute("grid_mapping").getStringValue()); assertEquals(2, dataVar.getDimensions().size()); assertEquals(rlatDim, dataVar.getDimensions().get(0)); assertEquals(rlonDim, dataVar.getDimensions().get(1)); assertArrayEquals( new float[] { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124 }, (float[]) dataVar.read().copyTo1DJavaArray(), (float) DELTA); } finally { FileUtils.deleteQuietly(file); } } }