Skip to content

Commit dc0391c

Browse files
committed
Adding Unit tests
1 parent 26b6721 commit dc0391c

7 files changed

Lines changed: 245 additions & 4 deletions

File tree

src/community/png-wind/pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,22 @@
3030
<classifier>tests</classifier>
3131
<scope>test</scope>
3232
</dependency>
33+
<dependency>
34+
<groupId>org.geoserver</groupId>
35+
<artifactId>gs-wms1_1</artifactId>
36+
<scope>provided</scope>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.geoserver</groupId>
40+
<artifactId>gs-wms1_1</artifactId>
41+
<classifier>tests</classifier>
42+
<scope>test</scope>
43+
</dependency>
3344
<dependency>
3445
<groupId>org.geoserver</groupId>
3546
<artifactId>gs-wms-core</artifactId>
47+
<classifier>tests</classifier>
48+
<scope>test</scope>
3649
</dependency>
3750
</dependencies>
3851
</project>

src/community/png-wind/src/main/java/org/geoserver/pngwind/PngWindMapResponse.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import java.util.Map;
1111
import java.util.logging.Level;
1212
import java.util.logging.Logger;
13-
1413
import org.eclipse.imagen.media.viewer.RenderedImageBrowser;
1514
import org.geoserver.platform.ServiceException;
1615
import org.geoserver.pngwind.config.PngWindConfig;

src/community/png-wind/src/main/java/org/geoserver/pngwind/PngWindQuantizer.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.awt.image.RenderedImage;
1414
import java.awt.image.SampleModel;
1515
import java.util.LinkedHashMap;
16+
import java.util.Locale;
1617
import java.util.Map;
1718
import java.util.logging.Level;
1819
import java.util.logging.Logger;
@@ -180,7 +181,12 @@ public PngWindQuantizedImage quantize(
180181
md.put(
181182
"bbox",
182183
String.format(
183-
"%f,%f,%f,%f", envelope.getMinX(), envelope.getMinY(), envelope.getMaxX(), envelope.getMaxY()));
184+
Locale.ROOT,
185+
"%f,%f,%f,%f",
186+
envelope.getMinX(),
187+
envelope.getMinY(),
188+
envelope.getMaxX(),
189+
envelope.getMaxY()));
184190
/*if (timeOrNull != null) md.put("time", timeOrNull);
185191
if (elevationOrNull != null) md.put("elevation", elevationOrNull);
186192
*/

src/community/png-wind/src/main/java/org/geoserver/pngwind/config/PngWindConfigLoader.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,6 @@ private static Properties loadProperties(GeoServerResourceLoader loader) {
101101
throw new IllegalStateException(
102102
"Failed to load PNG-WIND config from GeoServer data dir resource: " + RESOURCE, e);
103103
}
104-
105-
106104
}
107105

108106
private static BandTypeMatcher parseMatcher(Properties props, String prefix) {
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
package org.geoserver.pngwind;
2+
3+
import static org.junit.Assert.assertArrayEquals;
4+
import static org.junit.Assert.assertEquals;
5+
import static org.junit.Assert.assertNotNull;
6+
import static org.junit.Assert.assertTrue;
7+
8+
import java.awt.image.BufferedImage;
9+
import java.awt.image.Raster;
10+
import java.io.ByteArrayInputStream;
11+
import java.io.DataInputStream;
12+
import java.io.IOException;
13+
import java.nio.charset.StandardCharsets;
14+
import java.util.HashMap;
15+
import java.util.LinkedHashMap;
16+
import java.util.List;
17+
import java.util.Map;
18+
import javax.imageio.ImageIO;
19+
import javax.imageio.ImageReader;
20+
import javax.imageio.stream.ImageInputStream;
21+
import javax.xml.namespace.QName;
22+
import org.geoserver.catalog.Catalog;
23+
import org.geoserver.catalog.CoverageDimensionInfo;
24+
import org.geoserver.catalog.CoverageInfo;
25+
import org.geoserver.data.test.MockData;
26+
import org.geoserver.data.test.SystemTestData;
27+
import org.geoserver.pngwind.config.PngWindConfigurator;
28+
import org.geoserver.wms.WMSTestSupport;
29+
import org.geotools.util.NumberRange;
30+
import org.junit.Test;
31+
import org.springframework.mock.web.MockHttpServletResponse;
32+
33+
public class PngWindWmsIntegrationTest extends WMSTestSupport {
34+
35+
private static final String UV_LAYER = "winduv";
36+
private static final String SD_LAYER = "windspeeddir";
37+
private static final QName WIND_UV = new QName(MockData.SF_URI, UV_LAYER, MockData.SF_PREFIX);
38+
private static final QName WIND_SPEEDDIR = new QName(MockData.SF_URI, SD_LAYER, MockData.SF_PREFIX);
39+
40+
private static final String OUTPUT_FORMAT = "image/vnd.png-wind";
41+
private static final double DELTA = 1E-6;
42+
43+
@Override
44+
protected void onSetUp(SystemTestData testData) throws Exception {
45+
super.onSetUp(testData);
46+
testData.addRasterLayer(WIND_UV, "test-data/wind-uv.tif", "tif", new HashMap<>(), getClass(), getCatalog());
47+
testData.addRasterLayer(
48+
WIND_SPEEDDIR, "test-data/wind-speeddir.tif", "tif", new HashMap<>(), getClass(), getCatalog());
49+
configureCoverageDimensions(
50+
UV_LAYER,
51+
new String[] {"u", "v"},
52+
new String[] {"m/s", "m/s"},
53+
new Double[] {-20d, -20d},
54+
new Double[] {20d, 20d},
55+
new Double[] {-999d, -999d});
56+
57+
configureCoverageDimensions(
58+
SD_LAYER,
59+
new String[] {"speed", "direction"},
60+
new String[] {"m/s", "deg"},
61+
new Double[] {-20d, 0d},
62+
new Double[] {20d, 350d},
63+
new Double[] {Double.NaN, Double.NaN});
64+
PngWindConfigurator configurator = applicationContext.getBean(PngWindConfigurator.class);
65+
configurator.onReload();
66+
}
67+
68+
private void configureCoverageDimensions(
69+
String layerName,
70+
String[] dimensionNames,
71+
String[] dimensionUnits,
72+
Double[] mins,
73+
Double[] maxs,
74+
Double[] nodataValues)
75+
throws IOException {
76+
Catalog catalog = getCatalog();
77+
78+
CoverageInfo coverage = catalog.getCoverageByName(MockData.SF_PREFIX, layerName);
79+
assertNotNull("Coverage not found in catalog: " + MockData.SF_PREFIX + ":" + layerName, coverage);
80+
81+
List<CoverageDimensionInfo> dimensions = coverage.getDimensions();
82+
assertEquals("Unexpected number of dimensions", dimensionNames.length, dimensions.size());
83+
84+
for (int i = 0; i < dimensions.size(); i++) {
85+
CoverageDimensionInfo dim = dimensions.get(i);
86+
dim.setName(dimensionNames[i]);
87+
dim.setDescription(dimensionNames[i]);
88+
89+
if (dimensionUnits != null && i < dimensionUnits.length) {
90+
dim.setUnit(dimensionUnits[i]);
91+
}
92+
if (mins != null && i < mins.length && mins[i] != null) {
93+
dim.setRange(new NumberRange<>(Double.class, mins[i], maxs[i]));
94+
} else if (maxs != null && i < maxs.length && maxs[i] != null) {
95+
dim.setRange(new NumberRange<>(Double.class, mins[i], maxs[i]));
96+
}
97+
if (nodataValues != null && i < nodataValues.length && nodataValues[i] != null) {
98+
dim.getNullValues().clear();
99+
dim.getNullValues().add(nodataValues[i]);
100+
}
101+
}
102+
103+
catalog.save(coverage);
104+
}
105+
106+
@Test
107+
public void testGetMapPngWindFromUvCoverage() throws Exception {
108+
MockHttpServletResponse response = getAsServletResponse("wms?service=WMS&version=1.1.1"
109+
+ "&request=GetMap"
110+
+ "&layers=" + MockData.SF_PREFIX + ":" + UV_LAYER
111+
+ "&styles="
112+
+ "&srs=EPSG:4326"
113+
+ "&bbox=0,0,20,20"
114+
+ "&width=10"
115+
+ "&height=10"
116+
+ "&format=" + PngWindConstants.MIME_TYPE);
117+
118+
assertEquals(200, response.getStatus());
119+
assertEquals(OUTPUT_FORMAT, response.getContentType());
120+
121+
byte[] png = response.getContentAsByteArray();
122+
assertTrue(png.length > 0);
123+
124+
Map<String, String> textChunks = readPngTextChunks(png);
125+
assertEquals(PngWindConstants.FORMAT, textChunks.get("format"));
126+
assertEquals("u", textChunks.get("wind_b1_name"));
127+
assertEquals("v", textChunks.get("wind_b2_name"));
128+
assertEquals(-20d, Double.parseDouble(textChunks.get("wind_b1_offset")), DELTA);
129+
assertEquals(0.156862d, Double.parseDouble(textChunks.get("wind_b1_scale")), DELTA);
130+
assertEquals(-20d, Double.parseDouble(textChunks.get("wind_b2_offset")), DELTA);
131+
assertEquals(0.156862d, Double.parseDouble(textChunks.get("wind_b2_scale")), DELTA);
132+
assertEquals("m/s", textChunks.get("wind_b1_uom"));
133+
assertEquals("m/s", textChunks.get("wind_b2_uom"));
134+
assertEquals("EPSG:4326", textChunks.get("CRS"));
135+
assertEquals("0.000000,0.000000,20.000000,20.000000", textChunks.get("bbox"));
136+
}
137+
138+
@Test
139+
public void testGetMapPngWindFromSpeedDirectionCoverage() throws Exception {
140+
MockHttpServletResponse response = getAsServletResponse("wms?service=WMS&version=1.1.1"
141+
+ "&request=GetMap"
142+
+ "&layers=" + MockData.SF_PREFIX + ":" + SD_LAYER
143+
+ "&styles="
144+
+ "&srs=EPSG:4326"
145+
+ "&bbox=0,0,20,20"
146+
+ "&width=20"
147+
+ "&height=20"
148+
+ "&format=" + OUTPUT_FORMAT);
149+
150+
assertEquals(200, response.getStatus());
151+
assertEquals(OUTPUT_FORMAT, response.getContentType());
152+
153+
byte[] png = response.getContentAsByteArray();
154+
assertTrue(png.length > 0);
155+
try (ImageInputStream in = ImageIO.createImageInputStream(new ByteArrayInputStream(png))) {
156+
ImageReader reader = ImageIO.getImageReadersByFormatName("png").next();
157+
reader.setInput(in);
158+
assertEquals(20, reader.getWidth(0));
159+
assertEquals(20, reader.getHeight(0));
160+
BufferedImage image = reader.read(0);
161+
Raster data = image.getData();
162+
for (int y = 0; y < data.getHeight(); y++) {
163+
// The pixel values on the edges should be nodata, therefore 0 as the 3rd band
164+
assertEquals(0, data.getSample(0, y, 2));
165+
assertEquals(0, data.getSample(19, y, 2));
166+
}
167+
}
168+
169+
Map<String, String> textChunks = readPngTextChunks(png);
170+
assertEquals(PngWindConstants.FORMAT, textChunks.get("format"));
171+
assertEquals("U", textChunks.get("wind_b1_name"));
172+
assertEquals("V", textChunks.get("wind_b2_name"));
173+
assertEquals(-20d, Double.parseDouble(textChunks.get("wind_b1_offset")), DELTA);
174+
assertEquals(0.156862d, Double.parseDouble(textChunks.get("wind_b1_scale")), DELTA);
175+
assertEquals(-20d, Double.parseDouble(textChunks.get("wind_b2_offset")), DELTA);
176+
assertEquals(0.156862d, Double.parseDouble(textChunks.get("wind_b2_scale")), DELTA);
177+
assertEquals("m/s", textChunks.get("wind_b1_uom"));
178+
assertEquals("m/s", textChunks.get("wind_b2_uom"));
179+
assertEquals("EPSG:4326", textChunks.get("CRS"));
180+
assertEquals("0.000000,0.000000,20.000000,20.000000", textChunks.get("bbox"));
181+
}
182+
183+
/** Reads PNG tEXt chunks without depending on PNG metadata DOM parsing. */
184+
private static Map<String, String> readPngTextChunks(byte[] png) throws IOException {
185+
Map<String, String> result = new LinkedHashMap<>();
186+
187+
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(png))) {
188+
byte[] signature = new byte[8];
189+
in.readFully(signature);
190+
assertArrayEquals(new byte[] {(byte) 137, 80, 78, 71, 13, 10, 26, 10}, signature);
191+
192+
while (true) {
193+
int length = in.readInt();
194+
byte[] typeBytes = new byte[4];
195+
in.readFully(typeBytes);
196+
String type = new String(typeBytes, StandardCharsets.ISO_8859_1);
197+
198+
byte[] data = new byte[length];
199+
in.readFully(data);
200+
in.readInt(); // CRC
201+
202+
if ("tEXt".equals(type)) {
203+
int sep = -1;
204+
for (int i = 0; i < data.length; i++) {
205+
if (data[i] == 0) {
206+
sep = i;
207+
break;
208+
}
209+
}
210+
if (sep > 0) {
211+
String key = new String(data, 0, sep, StandardCharsets.ISO_8859_1);
212+
String value = new String(data, sep + 1, data.length - sep - 1, StandardCharsets.ISO_8859_1);
213+
result.put(key, value);
214+
}
215+
}
216+
217+
if ("IEND".equals(type)) {
218+
break;
219+
}
220+
}
221+
}
222+
223+
return result;
224+
}
225+
}
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)