From 8280c929a6bca3be3b1d12a9de18a71fdd6095e0 Mon Sep 17 00:00:00 2001 From: Sean Arms <67096+lesserwhirls@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:01:51 -0700 Subject: [PATCH 1/2] Add default palette GetMap test Add test to check if the default palette is correctly applied to GetMap requests when the styles parameter is empty nor not included in the request. --- .../thredds/server/wms/TestWmsServer.java | 66 ++++++++++--------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/tds/src/integrationTests/java/thredds/server/wms/TestWmsServer.java b/tds/src/integrationTests/java/thredds/server/wms/TestWmsServer.java index ac4da86813..78a55a993f 100644 --- a/tds/src/integrationTests/java/thredds/server/wms/TestWmsServer.java +++ b/tds/src/integrationTests/java/thredds/server/wms/TestWmsServer.java @@ -8,7 +8,6 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.concurrent.*; -import java.util.stream.Collectors; import jakarta.servlet.http.HttpServletResponse; import org.jdom2.Document; import org.jdom2.Element; @@ -20,13 +19,9 @@ import org.jdom2.xpath.XPathFactory; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.Reader; import java.io.StringReader; -import java.lang.invoke.MethodHandles; -import java.nio.charset.Charset; import java.util.Arrays; import java.util.List; import thredds.test.util.TestOnLocalServer; @@ -40,7 +35,6 @@ import static com.google.common.truth.Truth.assertWithMessage; public class TestWmsServer { - private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static final double TOLERANCE = 1.0e-8; private final Namespace NS_WMS = Namespace.getNamespace("wms", "http://www.opengis.net/wms"); @@ -72,8 +66,8 @@ public void testCapabilities() throws IOException, JDOMException { public void testGetPng() { String endpoint = TestOnLocalServer.withHttpPath("/wms/scanCdmUnitTests/conventions/cf/ipcc/tas_A1.nc?service=WMS&version=1.3.0" - + "&request=GetMap&CRS=CRS:84&WIDTH=512&HEIGHT=512&LAYERS=tas&BBOX=0,-90,360,90&format=" - + ContentType.png.toString() + "&time=1850-01-16T12:00:00Z"); + + "&request=GetMap&CRS=CRS:84&WIDTH=512&HEIGHT=512&LAYERS=tas&BBOX=0,-90,360,90&format=" + ContentType.png + + "&time=1850-01-16T12:00:00Z"); testGetPng(endpoint); } @@ -83,17 +77,26 @@ public void testGetPngInAnotherProjection() { String endpoint = TestOnLocalServer.withHttpPath("/wms/scanCdmUnitTests/conventions/cf/ipcc/tas_A1.nc?service=WMS&version=1.3.0" + "&request=GetMap&CRS=EPSG:3857&WIDTH=512&HEIGHT=512&LAYERS=tas&BBOX=0,-90,360,90&format=" - + ContentType.png.toString() + "&time=1850-01-16T12:00:00Z"); + + ContentType.png + "&time=1850-01-16T12:00:00Z"); testGetPng(endpoint); } - private static void testGetPng(String endpoint) { - byte[] result = TestOnLocalServer.getContent(endpoint, HttpServletResponse.SC_OK, ContentType.png.toString()); - // make sure we get a png back - // first byte (unsigned) should equal 137 (decimal) - assertThat(result[0] & 0xFF).isEqualTo(137); - // bytes 1, 2, and 3, when interperted as ASCII, should be P N G - assertThat(new String(((byte[]) Arrays.copyOfRange(result, 1, 4)), Charset.forName("US-ASCII"))).isEqualTo("PNG"); + @Test + @Category(NeedsCdmUnitTest.class) + public void testGetMapPaletteDefault() { + String basePath = "/wms/scanLocal/2004050300_eta_211.nc?TRANSPARENT=TRUE&LAYERS=Z_sfc&" + + "TIME=2003-09-25T00%3A00%3A00.000Z&COLORSCALERANGE=0%2C2920&NUMCOLORBANDS=20&ABOVEMAXCOLOR=0x000000&" + + "BELOWMINCOLOR=0xFF0000FF&BGCOLOR=transparent&LOGSCALE=false&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&" + + "SRS=EPSG%3A4326&BBOX=-171.36,32.88,-48.48,155.76&WIDTH=256&HEIGHT=256&format=" + ContentType.png; + + String endpointNoStyles = TestOnLocalServer.withHttpPath(basePath); + String endpointEmptyStyles = TestOnLocalServer.withHttpPath(basePath + "&STYLES="); + String endpointExpectedStyles = TestOnLocalServer.withHttpPath(basePath + "&STYLES=default-scalar%2Fx-Occam"); + String endpointDiffStyles = TestOnLocalServer.withHttpPath(basePath + "&STYLES=default-scalar%2Fx-Rainbow"); + + assertThat(testGetPng(endpointNoStyles)).isEqualTo(testGetPng(endpointExpectedStyles)); + assertThat(testGetPng(endpointEmptyStyles)).isEqualTo(testGetPng(endpointExpectedStyles)); + assertThat(testGetPng(endpointDiffStyles)).isNotEqualTo(testGetPng(endpointExpectedStyles)); } @Test @@ -102,13 +105,9 @@ public void testGetLegendGraphic() { String endpoint = TestOnLocalServer.withHttpPath("/wms/scanCdmUnitTests/conventions/cf/ipcc/tas_A1.nc?service=WMS&version=1.3.0" + "&request=GetLegendGraphic&Layers=tas&colorscalerange=225.0,310.0&style=default-scalar/x-Rainbow&format=" - + ContentType.png.toString()); - byte[] result = TestOnLocalServer.getContent(endpoint, HttpServletResponse.SC_OK, ContentType.png.toString()); - // make sure we get a png back - // first byte (unsigned) should equal 137 (decimal) - assertThat(result[0] & 0xFF).isEqualTo(137); - // bytes 1, 2, and 3, when interperted as ASCII, should be P N G - assertThat(new String(((byte[]) Arrays.copyOfRange(result, 1, 4)), Charset.forName("US-ASCII"))).isEqualTo("PNG"); + + ContentType.png); + + testGetPng(endpoint); } @Test @@ -118,14 +117,9 @@ public void testGetLegendGraphicWithSLD() { try { String endpoint = TestOnLocalServer.withHttpPath( "/wms/scanCdmUnitTests/conventions/cf/ipcc/tas_A1.nc?service=WMS&version=1.3.0&request=GetLegendGraphic&Layers=tas&format=" - + ContentType.png.toString() + + ContentType.png + "&SLD_BODY=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22ISO-8859-1%22%3F%3E%20%3CStyledLayerDescriptor%20version%3D%221.1.0%22%20xsi%3AschemaLocation%3D%22http%3A%2F%2Fwww.opengis.net%2Fsld%20StyledLayerDescriptor.xsd%22%20xmlns%3D%22http%3A%2F%2Fwww.opengis.net%2Fsld%22%20xmlns%3Aogc%3D%22http%3A%2F%2Fwww.opengis.net%2Fogc%22%20xmlns%3Ase%3D%22http%3A%2F%2Fwww.opengis.net%2Fse%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%3E%20%3CNamedLayer%3E%20%3Cse%3AName%3Etas%3C%2Fse%3AName%3E%20%3CUserStyle%3E%20%3Cse%3AName%3EThesholded%20colour%20scheme%3C%2Fse%3AName%3E%20%3Cse%3ACoverageStyle%3E%20%3Cse%3ARule%3E%20%3Cse%3ARasterSymbolizer%3E%20%3Cse%3AOpacity%3E1.0%3C%2Fse%3AOpacity%3E%20%3Cse%3AColorMap%3E%20%3Cse%3ACategorize%20fallbackValue%3D%22%2300000000%22%3E%20%3Cse%3ALookupValue%3ERasterdata%3C%2Fse%3ALookupValue%3E%20%3Cse%3AValue%3E%23FF0000FF%3C%2Fse%3AValue%3E%20%3Cse%3AThreshold%3E275.0%3C%2Fse%3AThreshold%3E%20%3Cse%3AValue%3E%23FF00FFFF%3C%2Fse%3AValue%3E%20%3Cse%3AThreshold%3E280.0%3C%2Fse%3AThreshold%3E%20%3Cse%3AValue%3E%23FF00FF00%3C%2Fse%3AValue%3E%20%3Cse%3AThreshold%3E285.0%3C%2Fse%3AThreshold%3E%20%3Cse%3AValue%3E%23FFFFFF00%3C%2Fse%3AValue%3E%20%3Cse%3AThreshold%3E290.0%3C%2Fse%3AThreshold%3E%20%3Cse%3AValue%3E%23FFFFC800%3C%2Fse%3AValue%3E%20%3Cse%3AThreshold%3E295.0%3C%2Fse%3AThreshold%3E%20%3Cse%3AValue%3E%23FFFFAFAF%3C%2Fse%3AValue%3E%20%3Cse%3AThreshold%3E300.0%3C%2Fse%3AThreshold%3E%20%3Cse%3AValue%3E%23FFFF0000%3C%2Fse%3AValue%3E%20%3C%2Fse%3ACategorize%3E%20%3C%2Fse%3AColorMap%3E%20%3C%2Fse%3ARasterSymbolizer%3E%20%3C%2Fse%3ARule%3E%20%3C%2Fse%3ACoverageStyle%3E%20%3C%2FUserStyle%3E%20%3C%2FNamedLayer%3E%20%3C%2FStyledLayerDescriptor%3E"); - byte[] result = TestOnLocalServer.getContent(endpoint, HttpServletResponse.SC_OK, ContentType.png.toString()); - // make sure we get a png back - // first byte (unsigned) should equal 137 (decimal) - assertThat(result[0] & 0xFF).isEqualTo(137); - // bytes 1, 2, and 3, when interperted as ASCII, should be P N G - assertThat(new String(((byte[]) Arrays.copyOfRange(result, 1, 4)), Charset.forName("US-ASCII"))).isEqualTo("PNG"); + byte[] result = testGetPng(endpoint); } finally { System.setProperty("httpservices.urlencode", "true"); } @@ -192,7 +186,7 @@ public void shouldGetMapInParallel() throws InterruptedException { } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } - }).collect(Collectors.toList()); + }).toList(); assertWithMessage("result codes = " + Arrays.toString(resultCodes.toArray())) .that(resultCodes.stream().allMatch(code -> code.equals(HttpServletResponse.SC_OK))).isTrue(); @@ -227,4 +221,14 @@ private void checkValue(String endpoint, double expectedValue) throws IOExceptio assertThat(element.getContentSize()).isEqualTo(1); assertThat(Double.valueOf(element.getText())).isWithin(TOLERANCE).of(expectedValue); } + + private static byte[] testGetPng(String endpoint) { + byte[] result = TestOnLocalServer.getContent(endpoint, HttpServletResponse.SC_OK, ContentType.png.toString()); + // make sure we get a png back + // first byte (unsigned) should equal 137 (decimal) + assertThat(result[0] & 0xFF).isEqualTo(137); + // bytes 1, 2, and 3, when interpreted as ASCII, should be P N G + assertThat(new String(Arrays.copyOfRange(result, 1, 4), StandardCharsets.US_ASCII)).isEqualTo("PNG"); + return result; + } } From 37f73e3cb57499be087db37440b437fbf2a8b237 Mon Sep 17 00:00:00 2001 From: Sean Arms <67096+lesserwhirls@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:03:37 -0700 Subject: [PATCH 2/2] Set default styles parameter in GetMap requests Use "default" for the STYLES parameter of GetMap requests when the parameter is missing or empty. If not set, default-/default (e.g. default-scalar/default) is used by edal-java, which does not take into account defaults set in wmsConfig.xml. Fixes Unidata/tds#552 --- .../main/java/thredds/server/wms/ThreddsWmsServlet.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tds/src/main/java/thredds/server/wms/ThreddsWmsServlet.java b/tds/src/main/java/thredds/server/wms/ThreddsWmsServlet.java index f8091e14f7..30b2694af6 100644 --- a/tds/src/main/java/thredds/server/wms/ThreddsWmsServlet.java +++ b/tds/src/main/java/thredds/server/wms/ThreddsWmsServlet.java @@ -33,6 +33,7 @@ import com.google.common.cache.RemovalListener; import com.google.common.util.concurrent.UncheckedExecutionException; import java.io.IOException; +import java.util.Collections; import java.util.Formatter; import java.util.concurrent.ExecutionException; import org.slf4j.Logger; @@ -70,6 +71,8 @@ public class ThreddsWmsServlet extends WmsServlet { private static final Logger logger = LoggerFactory.getLogger(ThreddsWmsServlet.class); + private static final Map defaultStyles = Collections.singletonMap("styles", "default"); + private static class CachedWmsCatalogue { public final ThreddsWmsCatalogue wmsCatalogue; public final long lastModified; @@ -112,6 +115,11 @@ protected void dispatchWmsRequest(String request, RequestParams params, HttpServ TdsRequestedDataset tdsDataset = new TdsRequestedDataset(httpServletRequest, removePrefix); ThreddsWmsCatalogue catalogue = acquireCatalogue(httpServletRequest, httpServletResponse, tdsDataset.getPath()); + // set default style if needed + if (request.equals("GetMap") && params.getString("styles", "").isEmpty()) { + params = params.mergeParameters(defaultStyles); + } + /* * Now that we've got a WmsCatalogue, we can pass this request to the * super implementation which will handle things from here.