org.geoserver.kml.KMLTest.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.kml.KMLTest.java

Source

/* Copyright (c) 2001 - 2013 OpenPlans - www.openplans.org. All rights reserved.
 * This code is licensed under the GPL 2.0 license, available at the root
 * application directory.
 */
package org.geoserver.kml;

import static junit.framework.Assert.assertNull;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.Collections;
import java.util.TimeZone;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.xml.namespace.QName;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.test.RemoteOWSTestSupport;
import org.geoserver.wms.WMSTestSupport;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.w3c.dom.Document;

import com.mockrunner.mock.web.MockHttpServletResponse;

public class KMLTest extends WMSTestSupport {

    private static final QName STORM_OBS = new QName(MockData.CITE_URI, "storm_obs", MockData.CITE_PREFIX);
    private static TimeZone oldTimeZone;

    @Override
    protected void setUpTestData(SystemTestData testData) throws Exception {
        super.setUpTestData(testData);
        testData.setUpDefaultRasterLayers();
    }

    @BeforeClass
    public static void setTimeZone() {
        // System.setProperty("user.timezone", "UTC");
        oldTimeZone = TimeZone.getDefault();
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    }

    @AfterClass
    public static void clearTimeZone() {
        // System.clearProperty("user.timezone");
        TimeZone.setDefault(oldTimeZone);
    }

    @Override
    protected void onSetUp(SystemTestData testData) throws Exception {
        super.onSetUp(testData);
        Catalog catalog = getCatalog();
        testData.addStyle("notthere", "notthere.sld", getClass(), catalog);
        testData.addStyle("scaleRange", "scaleRange.sld", getClass(), catalog);
        testData.addVectorLayer(STORM_OBS, Collections.EMPTY_MAP, "storm_obs.properties", getClass(), catalog);
    }

    @Test
    public void testVector() throws Exception {
        Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + MockData.BASIC_POLYGONS.getPrefix() + ":"
                + MockData.BASIC_POLYGONS.getLocalPart() + "&styles=" + MockData.BASIC_POLYGONS.getLocalPart()
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326");

        assertEquals(getFeatureSource(MockData.BASIC_POLYGONS).getFeatures().size(),
                doc.getElementsByTagName("Placemark").getLength());
    }

    @Test
    public void testVectorScaleRange() throws Exception {
        Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + MockData.BASIC_POLYGONS.getPrefix() + ":"
                + MockData.BASIC_POLYGONS.getLocalPart()
                + "&styles=scaleRange&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326");

        assertEquals(getFeatureSource(MockData.BASIC_POLYGONS).getFeatures().size(),
                doc.getElementsByTagName("Placemark").getLength());
    }

    @Test
    public void testVectorWithFeatureId() throws Exception {
        Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + MockData.BASIC_POLYGONS.getPrefix() + ":"
                + MockData.BASIC_POLYGONS.getLocalPart() + "&styles=" + MockData.BASIC_POLYGONS.getLocalPart()
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326"
                + "&featureid=BasicPolygons.1107531493643");

        assertEquals(1, doc.getElementsByTagName("Placemark").getLength());
    }

    @Test
    public void testBasicVector() throws Exception {
        Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.ROAD_SEGMENTS)
                + "&styles=&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326&featureId=RoadSegments.1107532045088");

        // print(doc);
        assertXpathEvaluatesTo("1", "count(//kml:Placemark)", doc);
        assertXpathEvaluatesTo("RoadSegments.1107532045088", "//kml:Placemark/@id", doc);
        assertXpathEvaluatesTo("RoadSegments.1107532045088", "//kml:Placemark/kml:name", doc);
        String expectedDescription = "<h4>RoadSegments</h4>\n" + "\n" + "<ul class=\"textattributes\">\n" + "  \n"
                + "  <li><strong><span class=\"atr-name\">FID</span>:</strong> <span class=\"atr-value\">102</span></li>\n"
                + "  <li><strong><span class=\"atr-name\">NAME</span>:</strong> <span class=\"atr-value\">Route 5</span></li>\n"
                + "</ul>\n";
        assertXpathEvaluatesTo(expectedDescription, "//kml:Placemark/kml:description", doc);
        // check look-at
        assertXpathEvaluatesTo("-0.0020000000000095497", "//kml:Placemark/kml:LookAt/kml:longitude", doc);
        assertXpathEvaluatesTo("5.000000003008154E-5", "//kml:Placemark/kml:LookAt/kml:latitude", doc);
        // check style
        assertXpathEvaluatesTo("00ffffff", "//kml:Placemark/kml:Style/kml:IconStyle/kml:color", doc);
        assertXpathEvaluatesTo("0.4", "//kml:Placemark/kml:Style/kml:IconStyle/kml:scale", doc);
        assertXpathEvaluatesTo("http://icons.opengeo.org/markers/icon-line.1.png",
                "//kml:Placemark/kml:Style/kml:IconStyle/kml:Icon/kml:href", doc);
        assertXpathEvaluatesTo("00ffffff", "//kml:Placemark/kml:Style/kml:LabelStyle/kml:color", doc);
        assertXpathEvaluatesTo("ff000000", "//kml:Placemark/kml:Style/kml:LineStyle/kml:color", doc);
        assertXpathEvaluatesTo("4.0", "//kml:Placemark/kml:Style/kml:LineStyle/kml:width", doc);
        // check geometry
        assertXpathEvaluatesTo("-0.002000087662804264,4.997808429893395E-5",
                "//kml:Placemark/kml:MultiGeometry/kml:Point/kml:coordinates", doc);
        assertXpathEvaluatesTo("-0.0042,-6.0E-4 -0.0032,-3.0E-4 -0.0026,-1.0E-4 -0.0014,2.0E-4 2.0E-4,7.0E-4",
                "//kml:Placemark/kml:MultiGeometry/kml:LineString/kml:coordinates", doc);
    }

    @Test
    public void testNoAttributes() throws Exception {
        Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.ROAD_SEGMENTS)
                + "&styles=&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326&featureId=RoadSegments.1107532045088&kmattr=false");

        // print(doc);
        assertXpathEvaluatesTo("1", "count(//kml:Placemark)", doc);
        assertXpathEvaluatesTo("RoadSegments.1107532045088", "//kml:Placemark/@id", doc);
        // no name or description
        assertXpathEvaluatesTo("0", "count(//kml:Placemark/kml:name)", doc);
        assertXpathEvaluatesTo("0", "count(//kml:Placemark/kml:description)", doc);
        // check look-at
        assertXpathEvaluatesTo("-0.0020000000000095497", "//kml:Placemark/kml:LookAt/kml:longitude", doc);
        assertXpathEvaluatesTo("5.000000003008154E-5", "//kml:Placemark/kml:LookAt/kml:latitude", doc);
        // style does not need icon information
        assertXpathEvaluatesTo("0", "count(//kml:Placemark/kml:Style/kml:IconStyle)", doc);
        assertXpathEvaluatesTo("0", "count(//kml:Placemark/kml:Style/kml:LabelStyle)", doc);
        assertXpathEvaluatesTo("ff000000", "//kml:Placemark/kml:Style/kml:LineStyle/kml:color", doc);
        assertXpathEvaluatesTo("4.0", "//kml:Placemark/kml:Style/kml:LineStyle/kml:width", doc);
        // check geometry
        assertXpathEvaluatesTo("0", "count(//kml:Placemark/kml:MultiGeometry)", doc);
        assertXpathEvaluatesTo("-0.0042,-6.0E-4 -0.0032,-3.0E-4 -0.0026,-1.0E-4 -0.0014,2.0E-4 2.0E-4,7.0E-4",
                "//kml:Placemark/kml:LineString/kml:coordinates", doc);
    }

    @Ignore
    @Test
    public void testTimeTemplate() throws Exception {
        FeatureTypeInfo ftInfo = getCatalog().getResourceByName(getLayerId(MockData.OTHER), FeatureTypeInfo.class);
        File resourceDir = getDataDirectory().findResourceDir(ftInfo);
        File templateFile = new File(resourceDir, "time.ftl");
        try {
            // create the time template

            FileUtils.writeStringToFile(templateFile, "${dates.value}");

            Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                    + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.OTHER)
                    + "&styles=&height=1024&width=1024&bbox= -96.0000,0.0000,-90.0000,84.0000&srs=EPSG:4326");

            // print(doc);
            assertXpathEvaluatesTo("1", "count(//kml:Placemark)", doc);
            assertXpathEvaluatesTo("2002-02-12T00:00:00Z", "//kml:Placemark/kml:TimeStamp/kml:when", doc);
        } finally {
            assertTrue(templateFile.delete());
        }
    }

    @Ignore
    @Test
    public void testTimeInvervalTemplate() throws Exception {
        FeatureTypeInfo ftInfo = getCatalog().getResourceByName(getLayerId(MockData.OTHER), FeatureTypeInfo.class);
        File resourceDir = getDataDirectory().findResourceDir(ftInfo);
        File templateFile = new File(resourceDir, "time.ftl");
        try {
            // create the time template 
            FileUtils.writeStringToFile(templateFile, "${dates.value}||${dates.value}");

            Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                    + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.OTHER)
                    + "&styles=&height=1024&width=1024&bbox= -96.0000,0.0000,-90.0000,84.0000&srs=EPSG:4326");

            // print(doc);
            assertXpathEvaluatesTo("1", "count(//kml:Placemark)", doc);
            assertXpathEvaluatesTo("2002-02-12T00:00:00Z", "//kml:Placemark/kml:TimeSpan/kml:begin", doc);
            assertXpathEvaluatesTo("2002-02-12T00:00:00Z", "//kml:Placemark/kml:TimeSpan/kml:end", doc);
        } finally {
            assertTrue(templateFile.delete());
        }
    }

    @Test
    public void testHeightTemplate() throws Exception {
        FeatureTypeInfo ftInfo = getCatalog().getResourceByName(getLayerId(MockData.OTHER), FeatureTypeInfo.class);
        File resourceDir = getDataDirectory().findResourceDir(ftInfo);
        File templateFile = new File(resourceDir, "height.ftl");
        try {
            // create the height template
            FileUtils.writeStringToFile(templateFile, "200");

            Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                    + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.OTHER)
                    + "&styles=&height=1024&width=1024&bbox= -96.0000,0.0000,-90.0000,84.0000&srs=EPSG:4326");

            // coordinates are reprojected and we get the height at 200
            assertXpathEvaluatesTo("-92.99954926766114,4.52401492058674,200.0",
                    "//kml:Placemark/kml:Point/kml:coordinates", doc);
        } finally {
            assertTrue(templateFile.delete());
        }
    }

    @Test
    public void testVectorWithRemoteLayer() throws Exception {
        if (!RemoteOWSTestSupport.isRemoteWFSStatesAvailable(LOGGER))
            return;

        Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=topp:states" + "&styles=Default"
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326" + "&remote_ows_type=wfs"
                + "&remote_ows_url=" + RemoteOWSTestSupport.WFS_SERVER_URL + "&cql_filter=PERSONS>20000000");
        // print(doc);

        assertEquals(1, doc.getElementsByTagName("Placemark").getLength());
    }

    // see GEOS-1948
    @Test
    public void testMissingGraphic() throws Exception {
        Document doc = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.BRIDGES) + "&styles=notthere"
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326");
        assertEquals(1, doc.getElementsByTagName("Placemark").getLength());
    }

    @Test
    public void testContentDisposition() throws Exception {
        MockHttpServletResponse resp = getAsServletResponse("wms?request=getmap&service=wms&version=1.1.1"
                + "&format=" + KMZMapOutputFormat.MIME_TYPE + "&layers=" + MockData.BASIC_POLYGONS.getPrefix() + ":"
                + MockData.BASIC_POLYGONS.getLocalPart() + "&styles=" + MockData.BASIC_POLYGONS.getLocalPart()
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326");
        assertEquals("attachment; filename=cite-BasicPolygons.kmz", resp.getHeader("Content-Disposition"));
    }

    @Test
    public void testEncodeTime() throws Exception {
        setupTemplate(STORM_OBS, "time.ftl", "${obs_datetime.value}");
        // AA: for the life of me I cannot make xpath work against this output, not sure why, so going
        // to test with strings instead...
        String doc = getAsString("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(STORM_OBS)
                + "&styles=&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326&featureId=storm_obs.1321870537475");
        assertTrue(doc.contains("<when>1994-07-0"));
    }

    @Test
    public void testKmltitleFormatOption() throws Exception {
        final String kmlRequest = "wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.BRIDGES) + "&styles=notthere"
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326"
                + "&format_options=kmltitle:myCustomLayerTitle";

        Document doc = getAsDOM(kmlRequest);
        print(doc);
        assertEquals("name",
                doc.getElementsByTagName("Document").item(0).getFirstChild().getNextSibling().getLocalName());
        assertEquals("myCustomLayerTitle",
                doc.getElementsByTagName("Document").item(0).getFirstChild().getNextSibling().getTextContent());
    }

    @Test
    public void testKmltitleFormatOptionWithMultipleLayers() throws Exception {
        final String kmlRequest = "wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.BRIDGES) + ","
                + getLayerId(MockData.BASIC_POLYGONS) + "&styles=notthere" + ","
                + MockData.BASIC_POLYGONS.getLocalPart()
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326"
                + "&format_options=kmltitle:myCustomLayerTitle";

        Document doc = getAsDOM(kmlRequest);
        print(doc);
        assertEquals("name",
                doc.getElementsByTagName("Document").item(0).getFirstChild().getNextSibling().getLocalName());
        assertEquals(1, doc.getElementsByTagName("Document").getLength());
        assertEquals(2, doc.getElementsByTagName("Folder").getLength());
        assertEquals("myCustomLayerTitle",
                doc.getElementsByTagName("Document").item(0).getFirstChild().getNextSibling().getTextContent());
        assertXpathEvaluatesTo("cite:Bridges", "//kml:Folder[1]/kml:name", doc);
        assertXpathEvaluatesTo("cite:BasicPolygons", "//kml:Folder[2]/kml:name", doc);
    }

    @Test
    public void testRelativeLinks() throws Exception {
        final String kmlRequest = "wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.BASIC_POLYGONS) + "&styles="
                + MockData.BASIC_POLYGONS.getLocalPart()
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326&format_options=rellinks:true";

        // first page
        Document dom = getAsDOM(kmlRequest + "&startIndex=0&maxFeatures=1");
        // print(dom);
        // only one link, the "next" one
        assertXpathEvaluatesTo("1", "count(//kml:Folder/kml:NetworkLink)", dom);
        assertXpathEvaluatesTo("next", "//kml:Folder/kml:NetworkLink/@id", dom);
        assertXpathEvaluatesTo("Next page", "//kml:Folder/kml:NetworkLink/kml:description", dom);
        assertXpathEvaluatesTo(
                "http://localhost:8080/geoserver/rest/cite/BasicPolygons.kml?startindex=1&maxfeatures=1",
                "//kml:Folder/kml:NetworkLink/kml:Link/kml:href", dom);

        // mid page
        dom = getAsDOM(kmlRequest + "&startIndex=1&maxFeatures=1");
        // print(dom);
        // only one link, the "next" one
        assertXpathEvaluatesTo("2", "count(//kml:Folder/kml:NetworkLink)", dom);
        assertXpathEvaluatesTo("prev", "//kml:Folder/kml:NetworkLink[1]/@id", dom);
        assertXpathEvaluatesTo("Previous page", "//kml:Folder/kml:NetworkLink[1]/kml:description", dom);
        assertXpathEvaluatesTo(
                "http://localhost:8080/geoserver/rest/cite/BasicPolygons.kml?startindex=0&maxfeatures=1",
                "//kml:Folder/kml:NetworkLink[1]/kml:Link/kml:href", dom);
        assertXpathEvaluatesTo("next", "//kml:Folder/kml:NetworkLink[2]/@id", dom);
        assertXpathEvaluatesTo("Next page", "//kml:Folder/kml:NetworkLink[2]/kml:description", dom);
        assertXpathEvaluatesTo(
                "http://localhost:8080/geoserver/rest/cite/BasicPolygons.kml?startindex=2&maxfeatures=1",
                "//kml:Folder/kml:NetworkLink[2]/kml:Link/kml:href", dom);

        // the last page is same as the mid one, as the code does not have enough context to know it's hitting
        // the last one squarely
    }

    @Test
    public void testForceGroundOverlay() throws Exception {
        Document dom = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.BASIC_POLYGONS) + "&styles="
                + MockData.BASIC_POLYGONS.getLocalPart()
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326&format_options=kmscore:0;autofit:true");
        // print(dom);

        assertXpathEvaluatesTo("0", "count(//kml:Placemark)", dom);
        assertXpathEvaluatesTo("1", "count(//kml:GroundOverlay)", dom);
        String pngOverlay = "http://localhost:8080/geoserver/wms?service=wms&request=GetMap&version=1.1.1&format=image%2Fpng&layers=cite%3ABasicPolygons&styles=BasicPolygons&height=512&width=1024&transparent=true&bbox=-180.0%2C-90.0%2C180.0%2C90.0&srs=EPSG%3A4326&format_options=AUTOFIT%3Atrue%3BKMSCORE%3A0%3B";
        assertXpathEvaluatesTo(pngOverlay, "//kml:GroundOverlay/kml:Icon/kml:href", dom);
    }

    @Test
    public void testRasterLayer() throws Exception {
        Document dom = getAsDOM("wms?request=getmap&service=wms&version=1.1.1" + "&format="
                + KMLMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.TASMANIA_DEM)
                + "&styles=&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326");
        // print(dom);

        assertXpathEvaluatesTo("0", "count(//kml:Placemark)", dom);
        assertXpathEvaluatesTo("1", "count(//kml:GroundOverlay)", dom);
        String pngOverlay = "http://localhost:8080/geoserver/wms?service=wms&request=GetMap&version=1.1.1&format=image%2Fpng&layers=wcs%3ADEM&styles=raster&height=1024&width=1024&transparent=true&bbox=-180.0%2C-90.0%2C180.0%2C90.0&srs=EPSG%3A4326";
        assertXpathEvaluatesTo(pngOverlay, "//kml:GroundOverlay/kml:Icon/kml:href", dom);
    }

    @Test
    public void testKMZMixed() throws Exception {
        // force vector layers to be vector dumps (kmscore 100)
        MockHttpServletResponse response = getAsServletResponse("wms?request=getmap&service=wms&version=1.1.1"
                + "&format=" + KMZMapOutputFormat.MIME_TYPE + "&layers=" + getLayerId(MockData.BASIC_POLYGONS) + ","
                + getLayerId(MockData.WORLD) + "&styles=" + MockData.BASIC_POLYGONS.getLocalPart() + ","
                + "&height=1024&width=1024&bbox=-180,-90,180,90&srs=EPSG:4326&format_options=kmscore:100");

        // check the contents of the zip file
        assertEquals(KMZMapOutputFormat.MIME_TYPE, response.getContentType());
        ByteArrayInputStream bis = getBinaryInputStream(response);
        ZipInputStream zis = new ZipInputStream(bis);

        // first entry, the kml document itself
        ZipEntry entry = zis.getNextEntry();
        assertEquals("wms.kml", entry.getName());
        // we need to clone the input stream, as dom(is) closes the stream
        byte[] data = IOUtils.toByteArray(zis);
        Document dom = dom(new ByteArrayInputStream(data));
        // print(dom);
        // we have the placemarks in the first folder (vector), and no ground overlays
        assertXpathEvaluatesTo("3", "count(//kml:Folder[1]/kml:Placemark)", dom);
        assertXpathEvaluatesTo("0", "count(//kml:Folder[1]/kml:GroundOverlay)", dom);
        // we have only the ground overlay in the second folder
        assertXpathEvaluatesTo("0", "count(//kml:Folder[2]/kml:Placemark)", dom);
        assertXpathEvaluatesTo("1", "count(//kml:Folder[2]/kml:GroundOverlay)", dom);
        assertXpathEvaluatesTo("images/layers_1.png", "//kml:Folder[2]/kml:GroundOverlay/kml:Icon/kml:href", dom);
        zis.closeEntry();

        // the images folder
        entry = zis.getNextEntry();
        assertEquals("images/", entry.getName());
        zis.closeEntry();

        // the ground overlay for the raster layer
        entry = zis.getNextEntry();
        assertEquals("images/layers_1.png", entry.getName());
        zis.closeEntry();
        assertNull(zis.getNextEntry());
    }
}