diff --git a/src/main/java/org/opengis/cite/wfs30/CommonDataFixture.java b/src/main/java/org/opengis/cite/wfs30/CommonDataFixture.java new file mode 100644 index 00000000..98bdc712 --- /dev/null +++ b/src/main/java/org/opengis/cite/wfs30/CommonDataFixture.java @@ -0,0 +1,55 @@ +package org.opengis.cite.wfs30; + +import static org.opengis.cite.wfs30.SuiteAttribute.REQUIREMENTCLASSES; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.opengis.cite.wfs30.conformance.RequirementClass; +import org.testng.ITestContext; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; + +/** + * @author Lyn Goltz + */ +public class CommonDataFixture extends CommonFixture { + + private List requirementClasses; + + @BeforeClass + public void requirementClasses( ITestContext testContext ) { + this.requirementClasses = (List) testContext.getSuite().getAttribute( REQUIREMENTCLASSES.getName() ); + } + + protected List createListOfMediaTypesToSupportForOtherResources( Map linkToSelf ) { + if ( this.requirementClasses == null ) + throw new SkipException( "No requirement classes described in resource /conformance available" ); + List mediaTypesToSupport = new ArrayList<>(); + for ( RequirementClass requirementClass : this.requirementClasses ) + if ( requirementClass.hasMediaTypeForOtherResources() ) + mediaTypesToSupport.add( requirementClass.getMediaTypeOtherResources() ); + if ( linkToSelf != null ) + mediaTypesToSupport.remove( linkToSelf.get( "type" ) ); + return mediaTypesToSupport; + } + + protected List createListOfMediaTypesToSupportForFeatureCollectionsAndFeatures() { + if ( this.requirementClasses == null ) + throw new SkipException( "No requirement classes described in resource /conformance available" ); + List mediaTypesToSupport = new ArrayList<>(); + for ( RequirementClass requirementClass : this.requirementClasses ) + if ( requirementClass.hasMediaTypeForFeaturesAndCollections() ) + mediaTypesToSupport.add( requirementClass.getMediaTypeFeaturesAndCollections() ); + return mediaTypesToSupport; + } + + protected List createListOfMediaTypesToSupportForFeatureCollectionsAndFeatures( Map linkToSelf ) { + List mediaTypesToSupport = createListOfMediaTypesToSupportForFeatureCollectionsAndFeatures(); + if ( linkToSelf != null ) + mediaTypesToSupport.remove( linkToSelf.get( "type" ) ); + return mediaTypesToSupport; + } + +} diff --git a/src/main/java/org/opengis/cite/wfs30/SuiteAttribute.java b/src/main/java/org/opengis/cite/wfs30/SuiteAttribute.java index 56bcfaa8..86d33120 100644 --- a/src/main/java/org/opengis/cite/wfs30/SuiteAttribute.java +++ b/src/main/java/org/opengis/cite/wfs30/SuiteAttribute.java @@ -34,6 +34,11 @@ public enum SuiteAttribute { */ API_MODEL( "apiModel", OpenApi3.class ), + /** + * Requirement classes parsed from /conformance; Added during execution. + */ + REQUIREMENTCLASSES( "requirementclasses", List.class ), + /** * Parsed collections from resource /collections; Added during execution. */ diff --git a/src/main/java/org/opengis/cite/wfs30/collections/FeatureCollectionsMetadataOperation.java b/src/main/java/org/opengis/cite/wfs30/collections/FeatureCollectionsMetadataOperation.java index 3e35dbd5..dc145544 100644 --- a/src/main/java/org/opengis/cite/wfs30/collections/FeatureCollectionsMetadataOperation.java +++ b/src/main/java/org/opengis/cite/wfs30/collections/FeatureCollectionsMetadataOperation.java @@ -5,6 +5,7 @@ import static org.opengis.cite.wfs30.SuiteAttribute.API_MODEL; import static org.opengis.cite.wfs30.WFS3.PATH.COLLECTIONS; import static org.opengis.cite.wfs30.openapi3.OpenApiUtils.retrieveTestPoints; +import static org.opengis.cite.wfs30.openapi3.OpenApiUtils.retrieveTestPointsForCollectionMetadata; import static org.opengis.cite.wfs30.util.JsonUtils.findLinkByRel; import static org.opengis.cite.wfs30.util.JsonUtils.findLinksWithSupportedMediaTypeByRel; import static org.opengis.cite.wfs30.util.JsonUtils.findLinksWithoutRelOrType; @@ -19,10 +20,10 @@ import java.util.List; import java.util.Map; -import org.opengis.cite.wfs30.CommonFixture; +import org.opengis.cite.wfs30.CommonDataFixture; import org.opengis.cite.wfs30.SuiteAttribute; -import org.opengis.cite.wfs30.openapi3.OpenApiUtils; import org.opengis.cite.wfs30.openapi3.TestPoint; +import org.opengis.cite.wfs30.openapi3.UriBuilder; import org.testng.ITestContext; import org.testng.SkipException; import org.testng.annotations.AfterClass; @@ -30,7 +31,6 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import com.reprezen.kaizen.oasparser.model3.MediaType; import com.reprezen.kaizen.oasparser.model3.OpenApi3; import io.restassured.path.json.JsonPath; @@ -39,14 +39,12 @@ /** * @author Lyn Goltz */ -public class FeatureCollectionsMetadataOperation extends CommonFixture { +public class FeatureCollectionsMetadataOperation extends CommonDataFixture { private final Map testPointAndResponses = new HashMap<>(); private final Map>> testPointAndCollections = new HashMap<>(); - private final List collectionNamesFromLandingPage = new ArrayList<>(); - private OpenApi3 apiModel; private Object[][] testPointsData; @@ -75,19 +73,6 @@ public Object[][] collections( ITestContext testContext ) { return objects; } - @BeforeClass - public void parseRequiredMetadata( ITestContext testContext ) { - Response request = init().baseUri( rootUri.toString() ).accept( JSON ).when().request( GET, "/" ); - JsonPath jsonPath = request.jsonPath(); - - List collections = jsonPath.getList( "collections" ); - for ( Object collectionObject : collections ) { - Map collection = (Map) collectionObject; - String collectionName = (String) collection.get( "name" ); - this.collectionNamesFromLandingPage.add( collectionName ); - } - } - @BeforeClass public void openApiDocument( ITestContext testContext ) { this.apiModel = (OpenApi3) testContext.getSuite().getAttribute( API_MODEL.getName() ); @@ -122,7 +107,7 @@ public void storeCollectionsInTestContext( ITestContext testContext ) { */ @Test(description = "Implements A.4.4.4. Validate the Feature Collections Metadata Operation (Requirement 9, 10)", groups = "collections", dataProvider = "collectionsUris", dependsOnGroups = "apidefinition") public void validateFeatureCollectionsMetadataOperation( TestPoint testPoint ) { - String testPointUri = testPoint.createUri(); + String testPointUri = new UriBuilder( testPoint ).buildUrl(); Response response = init().baseUri( testPointUri ).accept( JSON ).when().request( GET ); response.then().statusCode( 200 ); this.testPointAndResponses.put( testPoint, response ); @@ -163,7 +148,7 @@ public void validateFeatureCollectionsMetadataOperationResponse_Links( TestPoint // Validate that the retrieved document includes links for: Itself, Alternate encodings of this document in // every other media type as identified by the compliance classes for this server. - List mediaTypesToSupport = createListOfMediaTypesToSupport( testPoint, linkToSelf ); + List mediaTypesToSupport = createListOfMediaTypesToSupportForOtherResources( linkToSelf ); List> alternateLinks = findLinksWithSupportedMediaTypeByRel( links, mediaTypesToSupport, "alternate" ); List typesWithoutLink = findUnsupportedTypes( alternateLinks, mediaTypesToSupport ); @@ -201,10 +186,8 @@ public void validateFeatureCollectionsMetadataOperationResponse_Collections( Tes JsonPath jsonPath = response.jsonPath(); List collections = jsonPath.getList( "collections" ); - List missingCollectionNames = findMissingCollectionNames( collections ); - assertTrue( missingCollectionNames.isEmpty(), - "Feature Collection Metadata document must include a collections property for each collection in the dataset. Missing collection properties " - + missingCollectionNames ); + // Test method cannot be verified as the provided collections are not known. + this.testPointAndCollections.put( testPoint, createCollectionsMap( collections ) ); } @@ -234,25 +217,21 @@ public void validateFeatureCollectionsMetadataOperationResponse_Collections( Tes @Test(description = "Implements A.4.4.6. Validate a Collections Metadata document (Requirement 13)", groups = "collections", dataProvider = "collections", dependsOnMethods = "validateFeatureCollectionsMetadataOperationResponse_Collections") public void validateCollectionsMetadataDocument_Links( TestPoint testPoint, Map collection ) { String collectionName = (String) collection.get( "name" ); - List testPointsForNamedCollection = OpenApiUtils.retrieveTestPoints( apiModel, COLLECTIONS, - collectionName ); - if ( testPointsForNamedCollection.isEmpty() ) - throw new SkipException( "Could not find collection with name " + collectionName - + " in the OpenAPI document" ); - List mediaTypesToSupport = createListOfMediaTypesToSupport( testPointsForNamedCollection.get( 0 ), null ); + List mediaTypesToSupport = createListOfMediaTypesToSupportForFeatureCollectionsAndFeatures(); List> links = (List>) collection.get( "links" ); - List> alternateLinks = findLinksWithSupportedMediaTypeByRel( links, mediaTypesToSupport, - "item" ); - List typesWithoutLink = findUnsupportedTypes( alternateLinks, mediaTypesToSupport ); + List> items = findLinksWithSupportedMediaTypeByRel( links, mediaTypesToSupport, "item" ); + List typesWithoutLink = findUnsupportedTypes( items, mediaTypesToSupport ); assertTrue( typesWithoutLink.isEmpty(), - "Collections Metadata document must include links with relation 'item' for each supported encodings. Missing links for types " - + typesWithoutLink ); - List linksWithoutRelOrType = findLinksWithoutRelOrType( alternateLinks ); + "Collections Metadata document for collection with name " + + collectionName + + " must include links with relation 'item' for each supported encodings. Missing links for types " + + String.join( ", ", typesWithoutLink ) ); + List linksWithoutRelOrType = findLinksWithoutRelOrType( items ); assertTrue( linksWithoutRelOrType.isEmpty(), "Links with relation 'item' for encodings must include a rel and type parameter. Missing for links " - + linksWithoutRelOrType ); + + String.join( ", ", linksWithoutRelOrType ) ); } /** @@ -291,13 +270,15 @@ public void validateCollectionsMetadataDocument_Extent( TestPoint testPoint, Map public void validateTheFeatureCollectionMetadataOperationAndResponse( TestPoint testPoint, Map collection ) { String collectionName = (String) collection.get( "name" ); - List testPointsForNamedCollection = OpenApiUtils.retrieveTestPoints( apiModel, COLLECTIONS, - collectionName ); + List testPointsForNamedCollection = retrieveTestPointsForCollectionMetadata( apiModel, + collectionName ); if ( testPointsForNamedCollection.isEmpty() ) throw new SkipException( "Could not find collection with name " + collectionName + " in the OpenAPI document" ); - Response response = validateTheFeatureCollectionMetadataOperationAndResponse( testPointsForNamedCollection.get( 0 ) ); + TestPoint testPointCollectionMetadata = testPointsForNamedCollection.get( 0 ); + Response response = validateTheFeatureCollectionMetadataOperationAndResponse( testPointCollectionMetadata, + collectionName ); validateFeatureCollectionMetadataOperationResponse( response, collection ); } @@ -321,12 +302,14 @@ public void validateTheFeatureCollectionMetadataOperationAndResponse( TestPoint * Go to test A.4.4.8 * * d) References: Requirement 15 - * + * * @param testPoint * to test, never null + * @param collectionName */ - private Response validateTheFeatureCollectionMetadataOperationAndResponse( TestPoint testPoint ) { - String testPointUri = testPoint.createUri(); + private Response validateTheFeatureCollectionMetadataOperationAndResponse( TestPoint testPoint, + String collectionName ) { + String testPointUri = new UriBuilder( testPoint ).collectionName( collectionName ).buildUrl(); Response response = init().baseUri( testPointUri ).accept( JSON ).when().request( GET ); response.then().statusCode( 200 ); return response; @@ -356,26 +339,6 @@ private void validateFeatureCollectionMetadataOperationResponse( Response respon assertEquals( collection, jsonPath.get() ); } - private List findMissingCollectionNames( List collections ) { - List missingCollectionNames = new ArrayList<>(); - for ( String collectionNameFromLandingPage : this.collectionNamesFromLandingPage ) { - Map collection = findCollectionByName( collectionNameFromLandingPage, collections ); - if ( collection == null ) - missingCollectionNames.add( collectionNameFromLandingPage ); - } - return missingCollectionNames; - } - - private Map findCollectionByName( String collectionNameFromLandingPage, List collections ) { - for ( Object collectionObject : collections ) { - Map collection = (Map) collectionObject; - Object collectionName = collection.get( "name" ); - if ( collectionNameFromLandingPage.equals( collectionName ) ) - return collection; - } - return null; - } - private List> createCollectionsMap( List collections ) { List> collectionsMap = new ArrayList<>(); for ( Object collection : collections ) @@ -383,13 +346,4 @@ private List> createCollectionsMap( List collections return collectionsMap; } - private List createListOfMediaTypesToSupport( TestPoint testPoint, Map linkToSelf ) { - Map contentMediaTypes = testPoint.getContentMediaTypes(); - List mediaTypesToSupport = new ArrayList<>(); - mediaTypesToSupport.addAll( contentMediaTypes.keySet() ); - if ( linkToSelf != null ) - mediaTypesToSupport.remove( linkToSelf.get( "type" ) ); - return mediaTypesToSupport; - } - } \ No newline at end of file diff --git a/src/main/java/org/opengis/cite/wfs30/collections/GetFeatureOperation.java b/src/main/java/org/opengis/cite/wfs30/collections/GetFeatureOperation.java index 36b6478a..f8746094 100644 --- a/src/main/java/org/opengis/cite/wfs30/collections/GetFeatureOperation.java +++ b/src/main/java/org/opengis/cite/wfs30/collections/GetFeatureOperation.java @@ -3,8 +3,6 @@ import static io.restassured.http.Method.GET; import static org.opengis.cite.wfs30.SuiteAttribute.API_MODEL; import static org.opengis.cite.wfs30.WFS3.GEOJSON_MIME_TYPE; -import static org.opengis.cite.wfs30.WFS3.PATH.COLLECTIONS; -import static org.opengis.cite.wfs30.openapi3.OpenApiUtils.retrieveTestPoints; import static org.opengis.cite.wfs30.util.JsonUtils.findLinkByRel; import static org.opengis.cite.wfs30.util.JsonUtils.findLinksWithSupportedMediaTypeByRel; import static org.opengis.cite.wfs30.util.JsonUtils.findLinksWithoutRelOrType; @@ -19,16 +17,14 @@ import java.util.List; import java.util.Map; -import org.opengis.cite.wfs30.CommonFixture; +import org.opengis.cite.wfs30.CommonDataFixture; import org.opengis.cite.wfs30.SuiteAttribute; -import org.opengis.cite.wfs30.openapi3.TestPoint; import org.testng.ITestContext; import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import com.reprezen.kaizen.oasparser.model3.MediaType; import com.reprezen.kaizen.oasparser.model3.OpenApi3; import io.restassured.path.json.JsonPath; @@ -37,7 +33,7 @@ /** * @author Lyn Goltz */ -public class GetFeatureOperation extends CommonFixture { +public class GetFeatureOperation extends CommonDataFixture { private OpenApi3 apiModel; @@ -45,15 +41,6 @@ public class GetFeatureOperation extends CommonFixture { private final Map collectionNameAndResponse = new HashMap<>(); - @DataProvider(name = "collectionItemUris") - public Iterator collectionItemUris( ITestContext testContext ) { - List collectionsData = new ArrayList<>(); - for ( Map collection : collections ) { - collectionsData.add( new Object[] { collection } ); - } - return collectionsData.iterator(); - } - @DataProvider(name = "collectionFeatureId") public Iterator collectionFeatureId( ITestContext testContext ) { Map collectionNameToFeatureId = (Map) testContext.getSuite().getAttribute( SuiteAttribute.FEATUREIDS.getName() ); @@ -154,20 +141,13 @@ public void getFeatureOperation( Map collection, String featureI * @param collection * the collection under test, never null */ - @Test(description = "Implements A.4.4.15. Validate the Get Feature Operation Response (Requirement 32)", dataProvider = "collectionItemUris", dependsOnMethods = "getFeatureOperation") - public void validateTheGetFeatureOperationResponse( Map collection ) { + @Test(description = "Implements A.4.4.15. Validate the Get Feature Operation Response (Requirement 32)", dataProvider = "collectionFeatureId", dependsOnMethods = "getFeatureOperation") + public void validateTheGetFeatureOperationResponse( Map collection, String featureId ) { String collectionName = (String) collection.get( "name" ); Response response = collectionNameAndResponse.get( collectionName ); if ( response == null ) throw new SkipException( "Could not find a response for collection with name " + collectionName ); - List testPointsForNamedCollection = retrieveTestPoints( apiModel, COLLECTIONS, - collectionName + "\\/items\\/\\{.*\\}" ); - if ( testPointsForNamedCollection.isEmpty() ) - throw new SkipException( "Could not find collection with name " + collectionName - + " in the OpenAPI document" ); - TestPoint testPoint = testPointsForNamedCollection.get( 0 ); - JsonPath jsonPath = response.jsonPath(); List> links = jsonPath.getList( "links" ); @@ -188,7 +168,7 @@ public void validateTheGetFeatureOperationResponse( Map collecti // Validate that the retrieved document includes links for: // Alternate encodings of this document in every other media type as identified by the compliance classes for // this server - List mediaTypesToSupport = createListOfMediaTypesToSupport( testPoint, linkToSelf ); + List mediaTypesToSupport = createListOfMediaTypesToSupportForFeatureCollectionsAndFeatures( linkToSelf ); List> alternateLinks = findLinksWithSupportedMediaTypeByRel( links, mediaTypesToSupport, "alternate" ); List typesWithoutLink = findUnsupportedTypes( alternateLinks, mediaTypesToSupport ); @@ -203,15 +183,6 @@ public void validateTheGetFeatureOperationResponse( Map collecti + linksWithoutRelOrType ); } - private List createListOfMediaTypesToSupport( TestPoint testPoint, Map linkToSelf ) { - Map contentMediaTypes = testPoint.getContentMediaTypes(); - List mediaTypesToSupport = new ArrayList<>(); - mediaTypesToSupport.addAll( contentMediaTypes.keySet() ); - if ( linkToSelf != null ) - mediaTypesToSupport.remove( linkToSelf.get( "type" ) ); - return mediaTypesToSupport; - } - private String findGetFeatureUrlForGeoJson( Map collection ) { List links = (List) collection.get( "links" ); for ( Object linkObject : links ) { diff --git a/src/main/java/org/opengis/cite/wfs30/collections/GetFeaturesOperation.java b/src/main/java/org/opengis/cite/wfs30/collections/GetFeaturesOperation.java index 1eea7307..2d029b22 100644 --- a/src/main/java/org/opengis/cite/wfs30/collections/GetFeaturesOperation.java +++ b/src/main/java/org/opengis/cite/wfs30/collections/GetFeaturesOperation.java @@ -33,10 +33,8 @@ import java.util.Map; import java.util.Random; -import org.opengis.cite.wfs30.CommonFixture; +import org.opengis.cite.wfs30.CommonDataFixture; import org.opengis.cite.wfs30.SuiteAttribute; -import org.opengis.cite.wfs30.openapi3.OpenApiUtils; -import org.opengis.cite.wfs30.openapi3.TestPoint; import org.opengis.cite.wfs30.util.BBox; import org.opengis.cite.wfs30.util.TemporalExtent; import org.testng.ITestContext; @@ -45,7 +43,6 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import com.reprezen.kaizen.oasparser.model3.MediaType; import com.reprezen.kaizen.oasparser.model3.OpenApi3; import com.reprezen.kaizen.oasparser.model3.Operation; import com.reprezen.kaizen.oasparser.model3.Parameter; @@ -58,7 +55,7 @@ /** * @author Lyn Goltz */ -public class GetFeaturesOperation extends CommonFixture { +public class GetFeaturesOperation extends CommonDataFixture { private final Map collectionNameAndResponse = new HashMap<>(); @@ -217,13 +214,6 @@ public void validateTheGetFeaturesOperationResponse_Links( Map c if ( response == null ) throw new SkipException( "Could not find a response for collection with name " + collectionName ); - List testPointsForNamedCollection = OpenApiUtils.retrieveTestPoints( apiModel, COLLECTIONS, - collectionName + "/items" ); - if ( testPointsForNamedCollection.isEmpty() ) - throw new SkipException( "Could not find collection with name " + collectionName - + " in the OpenAPI document" ); - TestPoint testPoint = testPointsForNamedCollection.get( 0 ); - JsonPath jsonPath = response.jsonPath(); List> links = jsonPath.getList( "links" ); @@ -234,7 +224,7 @@ public void validateTheGetFeaturesOperationResponse_Links( Map c // Validate that the retrieved document includes links for: Alternate encodings of this document in // every other media type as identified by the compliance classes for this server. - List mediaTypesToSupport = createListOfMediaTypesToSupport( testPoint, linkToSelf ); + List mediaTypesToSupport = createListOfMediaTypesToSupportForFeatureCollectionsAndFeatures( linkToSelf ); List> alternateLinks = findLinksWithSupportedMediaTypeByRel( links, mediaTypesToSupport, "alternate" ); List typesWithoutLink = findUnsupportedTypes( alternateLinks, mediaTypesToSupport ); @@ -736,15 +726,6 @@ private String findGetFeaturesUrlForGeoJson( Map collection ) { return null; } - private List createListOfMediaTypesToSupport( TestPoint testPoint, Map linkToSelf ) { - Map contentMediaTypes = testPoint.getContentMediaTypes(); - List mediaTypesToSupport = new ArrayList<>(); - mediaTypesToSupport.addAll( contentMediaTypes.keySet() ); - if ( linkToSelf != null ) - mediaTypesToSupport.remove( linkToSelf.get( "type" ) ); - return mediaTypesToSupport; - } - private void assertIntegerGreaterZero( Object value, String propertyName ) { if ( value instanceof Number ) assertIntegerGreaterZero( ( (Number) value ).intValue(), propertyName ); diff --git a/src/main/java/org/opengis/cite/wfs30/conformance/ConformanceOperation.java b/src/main/java/org/opengis/cite/wfs30/conformance/ConformanceOperation.java index 847cc5b7..925af121 100644 --- a/src/main/java/org/opengis/cite/wfs30/conformance/ConformanceOperation.java +++ b/src/main/java/org/opengis/cite/wfs30/conformance/ConformanceOperation.java @@ -3,6 +3,7 @@ import static io.restassured.http.ContentType.JSON; import static io.restassured.http.Method.GET; import static org.opengis.cite.wfs30.SuiteAttribute.API_MODEL; +import static org.opengis.cite.wfs30.SuiteAttribute.REQUIREMENTCLASSES; import static org.opengis.cite.wfs30.WFS3.PATH.CONFORMANCE; import static org.opengis.cite.wfs30.openapi3.OpenApiUtils.retrieveTestPoints; import static org.testng.Assert.assertNotNull; @@ -12,7 +13,9 @@ import org.opengis.cite.wfs30.CommonFixture; import org.opengis.cite.wfs30.openapi3.TestPoint; +import org.opengis.cite.wfs30.openapi3.UriBuilder; import org.testng.ITestContext; +import org.testng.annotations.AfterClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -26,6 +29,8 @@ */ public class ConformanceOperation extends CommonFixture { + private List requirementClasses; + @DataProvider(name = "conformanceUris") public Object[][] conformanceUris( ITestContext testContext ) { OpenApi3 apiModel = (OpenApi3) testContext.getSuite().getAttribute( API_MODEL.getName() ); @@ -33,6 +38,11 @@ public Object[][] conformanceUris( ITestContext testContext ) { return new Object[][] { testPoints.toArray() }; } + @AfterClass + public void storeRequirementClassesInTestContext( ITestContext testContext ) { + testContext.getSuite().setAttribute( REQUIREMENTCLASSES.getName(), this.requirementClasses ); + } + /** * Implements A.4.4.2. Validate Conformance Operation and A.4.4.3. Validate Conformance Operation Response. * @@ -42,7 +52,7 @@ public Object[][] conformanceUris( ITestContext testContext ) { @Test(description = "Implements A.4.4.2. Validate Conformance Operation (Requirement 5) and A.4.4.3. Validate Conformance Operation Response (Requirement 6)", dataProvider = "conformanceUris", dependsOnGroups = "apidefinition") public void validateConformanceOperationAndResponse( TestPoint testPoint ) { Response response = validateConformanceOperation( testPoint ); - validateConformanceOperationResponse( testPoint, response ); + validateConformanceOperationResponse( response ); } /** @@ -63,7 +73,7 @@ public void validateConformanceOperationAndResponse( TestPoint testPoint ) { * d) References: Requirement 5 */ private Response validateConformanceOperation( TestPoint testPoint ) { - String testPointUri = testPoint.createUri(); + String testPointUri = new UriBuilder( testPoint ).buildUrl(); return init().baseUri( testPointUri ).accept( JSON ).when().request( GET ); } @@ -87,12 +97,11 @@ private Response validateConformanceOperation( TestPoint testPoint ) { * * d) References: Requirement 6 */ - private void validateConformanceOperationResponse( TestPoint testPoint, Response response ) { + private void validateConformanceOperationResponse( Response response ) { response.then().statusCode( 200 ); JsonPath jsonPath = response.jsonPath(); - List requirementClasses = parseAndValidateRequirementClasses( jsonPath ); - testPoint.addRequirementClasses( requirementClasses ); + this.requirementClasses = parseAndValidateRequirementClasses( jsonPath ); } /** @@ -102,15 +111,18 @@ private void validateConformanceOperationResponse( TestPoint testPoint, Response * @throws AssertionError * if the json does not follow the expected structure */ - List parseAndValidateRequirementClasses( JsonPath jsonPath ) { - List requirementClasses = new ArrayList<>(); + List parseAndValidateRequirementClasses( JsonPath jsonPath ) { + List requirementClasses = new ArrayList<>(); List conformsTo = jsonPath.getList( "conformsTo" ); assertNotNull( conformsTo, "Missing member 'conformsTo'." ); for ( Object conformTo : conformsTo ) { - if ( conformTo instanceof String ) - requirementClasses.add( (String) conformTo ); - else + if ( conformTo instanceof String ) { + String conformanceClass = (String) conformTo; + RequirementClass requirementClass = RequirementClass.byConformanceClass( conformanceClass ); + if ( requirementClass != null ) + requirementClasses.add( requirementClass ); + } else throw new AssertionError( "At least one element array 'conformsTo' is not a string value (" + conformTo + ")" ); } diff --git a/src/main/java/org/opengis/cite/wfs30/conformance/RequirementClass.java b/src/main/java/org/opengis/cite/wfs30/conformance/RequirementClass.java new file mode 100644 index 00000000..ab97fca5 --- /dev/null +++ b/src/main/java/org/opengis/cite/wfs30/conformance/RequirementClass.java @@ -0,0 +1,86 @@ +package org.opengis.cite.wfs30.conformance; + +/** + * + * Encapsulates all known requirement classes. + * + * @author Lyn Goltz + */ +public enum RequirementClass { + + CORE( "http://www.opengis.net/spec/wfs-1/3.0/req/core" ), + + HTML( "http://www.opengis.net/spec/wfs-1/3.0/req/html", "text/html", "text/html" ), + + GEOJSON( "http://www.opengis.net/spec/wfs-1/3.0/req/geojson", "application/geo+json", "application/json" ), + + GMLSF0( "http://www.opengis.net/spec/wfs-1/3.0/req/gmlsf0", + "application/gml+xml;version=3.2;profile=http://www.opengis.net/def/profile/ogc/2.0/gml-sf0", + "application/xml" ), + + GMLSF2( "http://www.opengis.net/spec/wfs-1/3.0/req/gmlsf2", + "application/gml+xml;version=3.2;profile=http://www.opengis.net/def/profile/ogc/2.0/gml-sf2", + "application/xml" ), + + OPENAPI30( "http://www.opengis.net/spec/wfs-1/3.0/req/oas30" ); + + private final String conformanceClass; + + private final String mediaTypeFeaturesAndCollections; + + private final String mediaTypeOtherResources; + + RequirementClass( String conformanceClass ) { + this( conformanceClass, null, null ); + } + + RequirementClass( String conformanceClass, String mediaTypeFeaturesAndCollections, String mediaTypeOtherResources ) { + this.conformanceClass = conformanceClass; + this.mediaTypeFeaturesAndCollections = mediaTypeFeaturesAndCollections; + this.mediaTypeOtherResources = mediaTypeOtherResources; + } + + /** + * @return true if the RequirementClass has a media type for features and collections, + * true otherwise + */ + public boolean hasMediaTypeForFeaturesAndCollections() { + return mediaTypeFeaturesAndCollections != null; + } + + /** + * @return media type for features and collections, null if not available + */ + public String getMediaTypeFeaturesAndCollections() { + return mediaTypeFeaturesAndCollections; + } + + /** + * @return true if the RequirementClass has a media type for other resources, + * true otherwise + */ + public boolean hasMediaTypeForOtherResources() { + return mediaTypeOtherResources != null; + } + + /** + * @return media type of other resources, null if not available + */ + public String getMediaTypeOtherResources() { + return mediaTypeOtherResources; + } + + /** + * @param conformanceClass + * the conformance class of the RequirementClass to return. + * @return the RequirementClass with the passed conformance class, null if RequirementClass exists + */ + public static RequirementClass byConformanceClass( String conformanceClass ) { + for ( RequirementClass requirementClass : values() ) { + if ( requirementClass.conformanceClass.equals( conformanceClass ) ) + return requirementClass; + } + return null; + } + +} \ No newline at end of file diff --git a/src/main/java/org/opengis/cite/wfs30/openapi3/OpenApiUtils.java b/src/main/java/org/opengis/cite/wfs30/openapi3/OpenApiUtils.java index 6ed753ec..90426255 100644 --- a/src/main/java/org/opengis/cite/wfs30/openapi3/OpenApiUtils.java +++ b/src/main/java/org/opengis/cite/wfs30/openapi3/OpenApiUtils.java @@ -1,11 +1,14 @@ package org.opengis.cite.wfs30.openapi3; +import static org.opengis.cite.wfs30.WFS3.PATH.COLLECTIONS; + import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; import org.opengis.cite.wfs30.WFS3.PATH; @@ -18,6 +21,7 @@ import com.reprezen.kaizen.oasparser.model3.Schema; import com.reprezen.kaizen.oasparser.model3.Server; import com.sun.jersey.api.uri.UriTemplate; +import com.sun.jersey.api.uri.UriTemplateParser; /** * @author Lyn Goltz @@ -27,6 +31,8 @@ public class OpenApiUtils { // as described in https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#fixed-fields private static final String DEFAULT_SERVER_URL = "/"; + public static final String TEMPLATE = "\\{.*\\}"; + private OpenApiUtils() { } @@ -54,7 +60,8 @@ public static List retrieveTestPoints( OpenApi3 apiModel ) { * @return the parsed test points, may be empty but never null */ public static List retrieveTestPoints( OpenApi3 apiModel, PATH path ) { - return retrieveTestPoints( apiModel, path, null ); + String requestedPath = "/" + path.getPathItem(); + return retrieveTestPoints( apiModel, requestedPath ); } /** @@ -63,21 +70,66 @@ public static List retrieveTestPoints( OpenApi3 apiModel, PATH path ) * * @param apiModel * never null - * @param path - * the path the test points should be assigned to, never null - * @param extendedPath + * @param collectionName * the extended path, may be null * @return the parsed test points, may be empty but never null */ - public static List retrieveTestPoints( OpenApi3 apiModel, PATH path, String extendedPath ) { + public static List retrieveTestPointsForCollectionMetadata( OpenApi3 apiModel, String collectionName ) { StringBuilder requestedPath = new StringBuilder(); - requestedPath.append( path.getPathItem() ); - if ( extendedPath != null ) { - if ( !extendedPath.startsWith( "/" ) ) - requestedPath.append( "/" ); - requestedPath.append( extendedPath ); - } - List pathItemObjects = identifyTestPoints( apiModel, requestedPath.toString() ); + requestedPath.append( "/" ); + requestedPath.append( COLLECTIONS.getPathItem() ); + requestedPath.append( "/" ); + requestedPath.append( collectionName ); + + return retrieveTestPoints( apiModel, requestedPath.toString() ); + } + + /** + * Parse the test points with the passed path including the extended path from the passed OpenApi3 document as + * described in A.4.3. Identify the Test Points. + * + * @param apiModel + * never null + * @param collectionName + * the extended path, may be null + * @return the parsed test points, may be empty but never null + */ + public static List retrieveTestPointsForCollection( OpenApi3 apiModel, String collectionName ) { + StringBuilder requestedPath = new StringBuilder(); + requestedPath.append( "/" ); + requestedPath.append( COLLECTIONS.getPathItem() ); + requestedPath.append( "/" ); + requestedPath.append( collectionName ); + requestedPath.append( "/items" ); + + return retrieveTestPoints( apiModel, requestedPath.toString() ); + } + + /** + * Parse the test points with the passed path including the extended path from the passed OpenApi3 document as + * described in A.4.3. Identify the Test Points. + * + * @param apiModel + * never null + * @param collectionName + * the extended path, may be null + * @return the parsed test points, may be empty but never null + */ + public static List retrieveTestPointsForFeature( OpenApi3 apiModel, String collectionName, + String featureId ) { + StringBuilder requestedPath = new StringBuilder(); + requestedPath.append( "/" ); + requestedPath.append( COLLECTIONS.getPathItem() ); + requestedPath.append( "/" ); + requestedPath.append( collectionName ); + requestedPath.append( "/items/" ); + requestedPath.append( featureId ); + + return retrieveTestPoints( apiModel, requestedPath.toString() ); + } + + private static List retrieveTestPoints( OpenApi3 apiModel, String requestedPath ) { + List pathItemObjects = identifyTestPoints( apiModel, requestedPath ); List pathItemAndServers = identifyServerUrls( apiModel, pathItemObjects ); return processServerObjects( pathItemAndServers ); } @@ -107,17 +159,13 @@ public static List retrieveTestPoints( OpenApi3 apiModel, PATH path, * never null */ private static List identifyTestPoints( OpenApi3 apiModel ) { - List paths = new ArrayList<>(); + List allTestPoints = new ArrayList<>(); for ( PATH path : PATH.values() ) - paths.add( path.getPathItem() ); - return identifyTestPoints( apiModel, paths ); + allTestPoints.addAll( identifyTestPoints( apiModel, "/" + path.getPathItem() ) ); + return allTestPoints; } private static List identifyTestPoints( OpenApi3 apiModel, String path ) { - return identifyTestPoints( apiModel, Collections.singletonList( path ) ); - } - - private static List identifyTestPoints( OpenApi3 apiModel, List path ) { List pathItems = new ArrayList<>(); Map pathItemObjects = apiModel.getPaths(); for ( Path pathItemObject : pathItemObjects.values() ) { @@ -129,12 +177,10 @@ private static List identifyTestPoints( OpenApi3 apiModel, List pa return pathItems; } - private static boolean isRequestedPath( String pathString, List path ) { - for ( String pathRequested : path ) { - if ( pathString.matches( "\\/" + pathRequested + "(\\/?)" ) ) - return true; - } - return false; + private static boolean isRequestedPath( String pathUnderTest, String pathToMatch ) { + UriTemplateParser parser = new UriTemplateParser( pathUnderTest ); + Matcher matcher = parser.getPattern().matcher( pathToMatch ); + return matcher.matches(); } /** @@ -249,23 +295,24 @@ private static List processServerObjects( List pat private static void processServerObject( List uris, PathItemAndServer pathItemAndServer ) { String pathString = pathItemAndServer.pathItemObject.getPathString(); - UriTemplate uriTemplate = new UriTemplate( pathItemAndServer.serverUrl + pathString ); Response response = pathItemAndServer.operationObject.getResponse( "200" ); Map contentMediaTypes = response.getContentMediaTypes(); + UriTemplate uriTemplate = new UriTemplate( pathItemAndServer.serverUrl + pathString ); if ( uriTemplate.getNumberOfTemplateVariables() == 0 ) { - TestPoint testPoint = new TestPoint( uriTemplate, contentMediaTypes ); + TestPoint testPoint = new TestPoint( pathItemAndServer.serverUrl, pathString, contentMediaTypes ); uris.add( testPoint ); } else { List> templateReplacements = collectTemplateReplacements( pathItemAndServer, uriTemplate ); if ( templateReplacements.isEmpty() ) { - TestPoint testPoint = new TestPoint( uriTemplate, contentMediaTypes ); + TestPoint testPoint = new TestPoint( pathItemAndServer.serverUrl, pathString, contentMediaTypes ); uris.add( testPoint ); } else { for ( Map templateReplacement : templateReplacements ) { - TestPoint testPoint = new TestPoint( uriTemplate, templateReplacement, contentMediaTypes ); + TestPoint testPoint = new TestPoint( pathItemAndServer.serverUrl, pathString, templateReplacement, + contentMediaTypes ); uris.add( testPoint ); } } diff --git a/src/main/java/org/opengis/cite/wfs30/openapi3/TestPoint.java b/src/main/java/org/opengis/cite/wfs30/openapi3/TestPoint.java index 29b343af..e413e351 100644 --- a/src/main/java/org/opengis/cite/wfs30/openapi3/TestPoint.java +++ b/src/main/java/org/opengis/cite/wfs30/openapi3/TestPoint.java @@ -1,12 +1,10 @@ package org.opengis.cite.wfs30.openapi3; -import java.util.HashMap; -import java.util.List; +import java.util.Collections; import java.util.Map; import java.util.Objects; import com.reprezen.kaizen.oasparser.model3.MediaType; -import com.sun.jersey.api.uri.UriTemplate; /** * Encapsulates a Test Point with the UriTemplate and predefined replacements. @@ -15,87 +13,68 @@ */ public class TestPoint { - private UriTemplate uriTemplate; + private final String serverUrl; - private Map templateReplacement; + private final String path; - private List requirementClasses; + private Map predefinedTemplateReplacement; private Map contentMediaTypes; /** - * Instantiates a TestPoint with UriTemplate but without defined replacements. + * Instantiates a TestPoint with UriTemplate but without predefined replacements. * - * @param uriTemplate - * never null + * @param serverUrl + * the serverUrl, never null + * @param path + * the path never, null * @param contentMediaTypes * the content media types for the GET operation with response "200", may be null */ - public TestPoint( UriTemplate uriTemplate, Map contentMediaTypes ) { - this( uriTemplate, null, contentMediaTypes ); + public TestPoint( String serverUrl, String path, Map contentMediaTypes ) { + this( serverUrl, path, Collections.emptyMap(), contentMediaTypes ); } /** * Instantiates a TestPoint with UriTemplate and predefined replacements. * - * @param uriTemplate - * never null - * @param templateReplacement - * may be null + * @param serverUrl + * the serverUrl, never null + * @param path + * the path, never null + * @param predefinedTemplateReplacement + * a list of predefined replacements never null * @param contentMediaTypes * the content media types for the GET operation with response "200", may be null */ - public TestPoint( UriTemplate uriTemplate, Map templateReplacement, + public TestPoint( String serverUrl, String path, Map predefinedTemplateReplacement, Map contentMediaTypes ) { - this.uriTemplate = uriTemplate; - this.templateReplacement = templateReplacement; + this.serverUrl = serverUrl; + this.path = path; + this.predefinedTemplateReplacement = Collections.unmodifiableMap( predefinedTemplateReplacement ); this.contentMediaTypes = contentMediaTypes; } /** - * @return the UriTemplate, never null - */ - public UriTemplate getUriTemplate() { - return uriTemplate; - } - - /** - * @return predefined replacements, may be null - */ - public Map getTemplateReplacement() { - return templateReplacement; - } - - /** - * Adds a new template replacement - * - * @param key - * the key of the template, never null - * @param value - * the value of the template, never null + * + * @return the serverUrl never null */ - public void addTemplateReplacement( String key, String value ) { - if ( this.templateReplacement == null ) - this.templateReplacement = new HashMap<>(); - this.templateReplacement.put( key, value ); + public String getServerUrl() { + return serverUrl; } /** - * @return a list of requirement classes the server conforms to, null if the conformance classes are - * not requested + * @return the path never, null */ - public List getRequirementClasses() { - return requirementClasses; + public String getPath() { + return path; } /** - * Adds the requirement classes the server conforms to - * - * @param requirementClasses - * never null + * @return an unmodifiable mao with predefined replacements, may be empty but never null */ - public void addRequirementClasses( List requirementClasses ) { - this.requirementClasses = requirementClasses; + public Map getPredefinedTemplateReplacement() { + return predefinedTemplateReplacement; } /** @@ -105,20 +84,9 @@ public Map getContentMediaTypes() { return contentMediaTypes; } - /** - * Creates an URI from the template with the replacement. - * - * @return the URI created from the template, never null - */ - public String createUri() { - if ( templateReplacement != null ) - return uriTemplate.createURI( templateReplacement ); - return uriTemplate.createURI(); - } - @Override public String toString() { - return "Pattern: " + uriTemplate.getPattern() + ", Replacements: " + templateReplacement; + return "Server URL: " + serverUrl + " , Path: " + path + ", Replacements: " + predefinedTemplateReplacement; } @Override @@ -128,15 +96,15 @@ public boolean equals( Object o ) { if ( o == null || getClass() != o.getClass() ) return false; TestPoint testPoint = (TestPoint) o; - return Objects.equals( uriTemplate, testPoint.uriTemplate ) - && Objects.equals( templateReplacement, testPoint.templateReplacement ) - && Objects.equals( requirementClasses, testPoint.requirementClasses ) + return Objects.equals( serverUrl, testPoint.serverUrl ) + && Objects.equals( path, testPoint.predefinedTemplateReplacement ) + && Objects.equals( predefinedTemplateReplacement, testPoint.path ) && Objects.equals( contentMediaTypes, testPoint.contentMediaTypes ); } @Override public int hashCode() { - return Objects.hash( uriTemplate, templateReplacement, requirementClasses, contentMediaTypes ); + return Objects.hash( serverUrl, path, predefinedTemplateReplacement, contentMediaTypes ); } } diff --git a/src/main/java/org/opengis/cite/wfs30/openapi3/UriBuilder.java b/src/main/java/org/opengis/cite/wfs30/openapi3/UriBuilder.java new file mode 100644 index 00000000..94614c6d --- /dev/null +++ b/src/main/java/org/opengis/cite/wfs30/openapi3/UriBuilder.java @@ -0,0 +1,88 @@ +package org.opengis.cite.wfs30.openapi3; + +import java.util.HashMap; +import java.util.Map; + +import com.sun.jersey.api.uri.UriTemplate; +import com.sun.jersey.api.uri.UriTemplateParser; + +/** + * Builds a URL out of a TestPoint. + * + * @author Lyn Goltz + */ +public class UriBuilder { + + private final TestPoint testPoint; + + private final Map templateReplacements = new HashMap<>(); + + /** + * @param testPoint + * never null + */ + public UriBuilder( TestPoint testPoint ) { + this.testPoint = testPoint; + this.templateReplacements.putAll( testPoint.getPredefinedTemplateReplacement() ); + } + + /** + * Adds the collectionName to the URI + * + * @param collectionName + * never null + * @return this UrlBuilder + */ + public UriBuilder collectionName( String collectionName ) { + String templateName = retrieveCollectionNameTemplateName(); + addTemplateReplacement( collectionName, templateName ); + return this; + } + + /** + * Adds the featureId to the URI + * + * @param featureId + * never null + * @return this UrlBuilder + */ + public UriBuilder featureId( String featureId ) { + String templateName = retrieveFeatureIdTemplateName(); + addTemplateReplacement( featureId, templateName ); + return this; + } + + /** + * @return this URI, never null + */ + public String buildUrl() { + UriTemplate uriTemplate = new UriTemplate( testPoint.getServerUrl() + testPoint.getPath() ); + return uriTemplate.createURI( templateReplacements ); + } + + private void addTemplateReplacement( String collectionName, String templateName ) { + if ( templateName != null ) + templateReplacements.put( templateName, collectionName ); + } + + private String retrieveCollectionNameTemplateName() { + String path = testPoint.getPath(); + UriTemplateParser uriTemplateParser = new UriTemplateParser( path ); + for ( String templateName : uriTemplateParser.getNames() ) { + if ( path.startsWith( "/collections/{" + templateName + "}" ) ) + return templateName; + } + return null; + } + + private String retrieveFeatureIdTemplateName() { + String path = testPoint.getPath(); + UriTemplateParser uriTemplateParser = new UriTemplateParser( path ); + for ( String templateName : uriTemplateParser.getNames() ) { + if ( path.endsWith( "items/{" + templateName + "}" ) ) + return templateName; + } + return null; + } + +} \ No newline at end of file diff --git a/src/test/java/org/opengis/cite/wfs30/collections/FeatureCollectionsMetadataOperationIT.java b/src/test/java/org/opengis/cite/wfs30/collections/FeatureCollectionsMetadataOperationIT.java index 5cc57821..c8808555 100644 --- a/src/test/java/org/opengis/cite/wfs30/collections/FeatureCollectionsMetadataOperationIT.java +++ b/src/test/java/org/opengis/cite/wfs30/collections/FeatureCollectionsMetadataOperationIT.java @@ -19,7 +19,6 @@ import com.reprezen.kaizen.oasparser.OpenApi3Parser; import com.reprezen.kaizen.oasparser.model3.MediaType; import com.reprezen.kaizen.oasparser.model3.OpenApi3; -import com.sun.jersey.api.uri.UriTemplate; /** * @author Lyn Goltz @@ -50,10 +49,8 @@ public static void initTestFixture() public void testValidateFeatureCollectionsMetadataOperationResponse() { FeatureCollectionsMetadataOperation featureCollectionsMetadataOperation = new FeatureCollectionsMetadataOperation(); featureCollectionsMetadataOperation.initCommonFixture( testContext ); - featureCollectionsMetadataOperation.parseRequiredMetadata( testContext ); featureCollectionsMetadataOperation.openApiDocument( testContext ); - UriTemplate conformanceUri = new UriTemplate( "https://www.ldproxy.nrw.de/kataster/collections" ); - TestPoint testPoint = new TestPoint( conformanceUri, mediaTypes() ); + TestPoint testPoint = new TestPoint( "https://www.ldproxy.nrw.de/kataster", "/collections", mediaTypes() ); featureCollectionsMetadataOperation.validateFeatureCollectionsMetadataOperation( testPoint ); featureCollectionsMetadataOperation.validateFeatureCollectionsMetadataOperationResponse_Links( testPoint ); featureCollectionsMetadataOperation.validateFeatureCollectionsMetadataOperationResponse_Collections( testPoint ); @@ -64,7 +61,8 @@ public void testValidateFeatureCollectionsMetadataOperationResponse() { Map collection = (Map) object[1]; featureCollectionsMetadataOperation.validateCollectionsMetadataDocument_Links( tp, collection ); featureCollectionsMetadataOperation.validateCollectionsMetadataDocument_Extent( tp, collection ); - featureCollectionsMetadataOperation.validateTheFeatureCollectionMetadataOperationAndResponse( tp, collection ); + featureCollectionsMetadataOperation.validateTheFeatureCollectionMetadataOperationAndResponse( tp, + collection ); } } diff --git a/src/test/java/org/opengis/cite/wfs30/collections/GetFeatureOperationIT.java b/src/test/java/org/opengis/cite/wfs30/collections/GetFeatureOperationIT.java index a72b1156..75577e1f 100644 --- a/src/test/java/org/opengis/cite/wfs30/collections/GetFeatureOperationIT.java +++ b/src/test/java/org/opengis/cite/wfs30/collections/GetFeatureOperationIT.java @@ -77,15 +77,7 @@ public void testGetFeatureOperations() { assertThat( featureId, notNullValue() ); getFeatureOperation.getFeatureOperation( collection, featureId ); - - Iterator iterator = getFeatureOperation.collectionItemUris( testContext ); - Object[] collectionByName = findCollectionByName( COLLECTION_NAME, iterator ); - assertThat( collectionByName, notNullValue() ); - - Map collection2 = (Map) collectionByName[0]; - assertThat( collection2, notNullValue() ); - - getFeatureOperation.validateTheGetFeatureOperationResponse( collection2 ); + getFeatureOperation.validateTheGetFeatureOperationResponse( collection, featureId ); } private Object[] findCollectionByName( String collectionName, Iterator collections ) { diff --git a/src/test/java/org/opengis/cite/wfs30/conformance/ConformanceOperationIT.java b/src/test/java/org/opengis/cite/wfs30/conformance/ConformanceOperationIT.java index 2e38170b..5cb34dc3 100644 --- a/src/test/java/org/opengis/cite/wfs30/conformance/ConformanceOperationIT.java +++ b/src/test/java/org/opengis/cite/wfs30/conformance/ConformanceOperationIT.java @@ -16,7 +16,6 @@ import org.testng.ITestContext; import com.reprezen.kaizen.oasparser.model3.MediaType; -import com.sun.jersey.api.uri.UriTemplate; /** * @author Lyn Goltz @@ -42,8 +41,7 @@ public static void initTestFixture() public void testApiDefinition() { ConformanceOperation conformanceOperation = new ConformanceOperation(); conformanceOperation.initCommonFixture( testContext ); - UriTemplate conformanceUri = new UriTemplate( "https://www.ldproxy.nrw.de/kataster/conformance" ); - TestPoint testPoint = new TestPoint( conformanceUri, mediaTypes() ); + TestPoint testPoint = new TestPoint( "https://www.ldproxy.nrw.de/kataster", "/conformance", mediaTypes() ); conformanceOperation.validateConformanceOperationAndResponse( testPoint ); } diff --git a/src/test/java/org/opengis/cite/wfs30/conformance/ConformanceOperationTest.java b/src/test/java/org/opengis/cite/wfs30/conformance/ConformanceOperationTest.java index 3d5f363d..0464e459 100644 --- a/src/test/java/org/opengis/cite/wfs30/conformance/ConformanceOperationTest.java +++ b/src/test/java/org/opengis/cite/wfs30/conformance/ConformanceOperationTest.java @@ -1,8 +1,13 @@ package org.opengis.cite.wfs30.conformance; -import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import static org.opengis.cite.wfs30.conformance.RequirementClass.CORE; +import static org.opengis.cite.wfs30.conformance.RequirementClass.GEOJSON; +import static org.opengis.cite.wfs30.conformance.RequirementClass.GMLSF2; +import static org.opengis.cite.wfs30.conformance.RequirementClass.HTML; +import static org.opengis.cite.wfs30.conformance.RequirementClass.OPENAPI30; import java.io.InputStream; import java.util.List; @@ -21,14 +26,10 @@ public void testParseAndValidateRequirementClasses() { ConformanceOperation conformanceOperationTest = new ConformanceOperation(); InputStream json = ConformanceOperationTest.class.getResourceAsStream( "req-classes.json" ); JsonPath jsonPath = new JsonPath( json ); - List requirementClasses = conformanceOperationTest.parseAndValidateRequirementClasses( jsonPath ); + List requirementClasses = conformanceOperationTest.parseAndValidateRequirementClasses( jsonPath ); assertThat( requirementClasses.size(), is( 5 ) ); - assertThat( requirementClasses, hasItem( "http://www.opengis.net/spec/wfs-1/3.0/req/core" ) ); - assertThat( requirementClasses, hasItem( "http://www.opengis.net/spec/wfs-1/3.0/req/oas30" ) ); - assertThat( requirementClasses, hasItem( "http://www.opengis.net/spec/wfs-1/3.0/req/html" ) ); - assertThat( requirementClasses, hasItem( "http://www.opengis.net/spec/wfs-1/3.0/req/geojson" ) ); - assertThat( requirementClasses, hasItem( "http://www.opengis.net/spec/wfs-1/3.0/req/gmlsf2" ) ); + assertThat( requirementClasses, hasItems( CORE, OPENAPI30, HTML, GEOJSON, GMLSF2 ) ); } @Test(expectedExceptions = AssertionError.class) diff --git a/src/test/java/org/opengis/cite/wfs30/openapi3/OpenApiUtilsTest.java b/src/test/java/org/opengis/cite/wfs30/openapi3/OpenApiUtilsTest.java index 7e460e77..5f4bf2eb 100644 --- a/src/test/java/org/opengis/cite/wfs30/openapi3/OpenApiUtilsTest.java +++ b/src/test/java/org/opengis/cite/wfs30/openapi3/OpenApiUtilsTest.java @@ -5,6 +5,9 @@ import static org.opengis.cite.wfs30.WFS3.PATH.API; import static org.opengis.cite.wfs30.WFS3.PATH.COLLECTIONS; import static org.opengis.cite.wfs30.openapi3.OpenApiUtils.retrieveTestPoints; +import static org.opengis.cite.wfs30.openapi3.OpenApiUtils.retrieveTestPointsForCollection; +import static org.opengis.cite.wfs30.openapi3.OpenApiUtils.retrieveTestPointsForCollectionMetadata; +import static org.opengis.cite.wfs30.openapi3.OpenApiUtils.retrieveTestPointsForFeature; import java.net.URL; import java.util.List; @@ -46,23 +49,23 @@ public void testRetrieveTestPoints_moreComplex() { assertThat( testPoints.size(), is( 4 ) ); TestPoint testPointWIthIndex = testPoints.get( 0 ); - assertThat( testPointWIthIndex.getTemplateReplacement().size(), is( 1 ) ); - assertThat( testPointWIthIndex.getTemplateReplacement().get( "index" ), is( "10" ) ); + assertThat( testPointWIthIndex.getPredefinedTemplateReplacement().size(), is( 1 ) ); + assertThat( testPointWIthIndex.getPredefinedTemplateReplacement().get( "index" ), is( "10" ) ); TestPoint testPointWIthIndexAndEnum1 = testPoints.get( 1 ); - assertThat( testPointWIthIndexAndEnum1.getTemplateReplacement().size(), is( 2 ) ); - assertThat( testPointWIthIndexAndEnum1.getTemplateReplacement().get( "index" ), is( "10" ) ); - assertThat( testPointWIthIndexAndEnum1.getTemplateReplacement().get( "enum" ), is( "eins" ) ); + assertThat( testPointWIthIndexAndEnum1.getPredefinedTemplateReplacement().size(), is( 2 ) ); + assertThat( testPointWIthIndexAndEnum1.getPredefinedTemplateReplacement().get( "index" ), is( "10" ) ); + assertThat( testPointWIthIndexAndEnum1.getPredefinedTemplateReplacement().get( "enum" ), is( "eins" ) ); TestPoint testPointWIthIndexAndEnum2 = testPoints.get( 2 ); - assertThat( testPointWIthIndexAndEnum2.getTemplateReplacement().size(), is( 2 ) ); - assertThat( testPointWIthIndexAndEnum2.getTemplateReplacement().get( "index" ), is( "10" ) ); - assertThat( testPointWIthIndexAndEnum2.getTemplateReplacement().get( "enum" ), is( "zwei" ) ); + assertThat( testPointWIthIndexAndEnum2.getPredefinedTemplateReplacement().size(), is( 2 ) ); + assertThat( testPointWIthIndexAndEnum2.getPredefinedTemplateReplacement().get( "index" ), is( "10" ) ); + assertThat( testPointWIthIndexAndEnum2.getPredefinedTemplateReplacement().get( "enum" ), is( "zwei" ) ); TestPoint testPointWIthIndexAndEnum3 = testPoints.get( 3 ); - assertThat( testPointWIthIndexAndEnum3.getTemplateReplacement().size(), is( 2 ) ); - assertThat( testPointWIthIndexAndEnum3.getTemplateReplacement().get( "index" ), is( "10" ) ); - assertThat( testPointWIthIndexAndEnum3.getTemplateReplacement().get( "enum" ), is( "drei" ) ); + assertThat( testPointWIthIndexAndEnum3.getPredefinedTemplateReplacement().size(), is( 2 ) ); + assertThat( testPointWIthIndexAndEnum3.getPredefinedTemplateReplacement().get( "index" ), is( "10" ) ); + assertThat( testPointWIthIndexAndEnum3.getPredefinedTemplateReplacement().get( "enum" ), is( "drei" ) ); } @Test @@ -90,38 +93,125 @@ public void testRetrieveTestPoints_COLLECTIONS() { } @Test - public void testRetrieveTestPoints_COLLECTIONS_WithExtendedPath() { + public void testRetrieveTestPointsForCollectionMetadata() { OpenApi3Parser parser = new OpenApi3Parser(); URL openAppiDocument = OpenApiUtilsTest.class.getResource( "openapi.json" ); OpenApi3 apiModel = parser.parse( openAppiDocument, true ); - List testPoints = retrieveTestPoints( apiModel, COLLECTIONS, "flurstueck" ); + List testPoints = retrieveTestPointsForCollectionMetadata( apiModel, "flurstueck" ); assertThat( testPoints.size(), is( 1 ) ); TestPoint testPoint = testPoints.get( 0 ); - assertThat( testPoint.createUri(), - is( "http://www.ldproxy.nrw.de/rest/services/kataster/collections/flurstueck" ) ); + // assertThat( testPoint.createUri(), + // is( "http://www.ldproxy.nrw.de/rest/services/kataster/collections/flurstueck" ) ); + assertThat( testPoint.getServerUrl(), is( "http://www.ldproxy.nrw.de/rest/services/kataster" ) ); + assertThat( testPoint.getPath(), is( "/collections/flurstueck" ) ); + + Map contentMediaTypes = testPoint.getContentMediaTypes(); + assertThat( contentMediaTypes.size(), is( 2 ) ); + } + + @Test + public void testRetrieveTestPointsForCollection() { + OpenApi3Parser parser = new OpenApi3Parser(); + + URL openAppiDocument = OpenApiUtilsTest.class.getResource( "openapi.json" ); + OpenApi3 apiModel = parser.parse( openAppiDocument, true ); + List testPoints = retrieveTestPointsForCollection( apiModel, "flurstueck" ); + + assertThat( testPoints.size(), is( 1 ) ); + + TestPoint testPoint = testPoints.get( 0 ); + // assertThat( testPoint.createUri(), + // is( "http://www.ldproxy.nrw.de/rest/services/kataster/collections/flurstueck/items" ) ); + assertThat( testPoint.getServerUrl(), is( "http://www.ldproxy.nrw.de/rest/services/kataster" ) ); + assertThat( testPoint.getPath(), is( "/collections/flurstueck/items" ) ); + Map contentMediaTypes = testPoint.getContentMediaTypes(); assertThat( contentMediaTypes.size(), is( 2 ) ); } @Test - public void testRetrieveTestPoints_COLLECTIONS_WithRegEx() { + public void testRetrieveTestPointsForFeature() { OpenApi3Parser parser = new OpenApi3Parser(); URL openAppiDocument = OpenApiUtilsTest.class.getResource( "openapi.json" ); OpenApi3 apiModel = parser.parse( openAppiDocument, true ); - List testPoints = retrieveTestPoints( apiModel, COLLECTIONS, "flurstueck\\/items\\/\\{.*\\}" ); + List testPoints = retrieveTestPointsForFeature( apiModel, "flurstueck", "abc" ); assertThat( testPoints.size(), is( 1 ) ); TestPoint testPoint = testPoints.get( 0 ); - testPoint.addTemplateReplacement( "featureId", "abc" ); - assertThat( testPoint.createUri(), - is( "http://www.ldproxy.nrw.de/rest/services/kataster/collections/flurstueck/items/abc" ) ); + assertThat( testPoint.getServerUrl(), is( "http://www.ldproxy.nrw.de/rest/services/kataster" ) ); + assertThat( testPoint.getPath(), is( "/collections/flurstueck/items/{featureId}" ) ); Map contentMediaTypes = testPoint.getContentMediaTypes(); assertThat( contentMediaTypes.size(), is( 2 ) ); } + @Test + public void testRetrieveTestPoints_COLLECTIONS_compactAPI() { + OpenApi3Parser parser = new OpenApi3Parser(); + + URL openAppiDocument = OpenApiUtilsTest.class.getResource( "openapi_compact-api.json" ); + OpenApi3 apiModel = parser.parse( openAppiDocument, true ); + List testPoints = retrieveTestPoints( apiModel, COLLECTIONS ); + + assertThat( testPoints.size(), is( 1 ) ); + + TestPoint testPoint = testPoints.get( 0 ); + // assertThat( testPoint.createUri(), is( "http://cloudsdi.geo-solutions.it:80/geoserver/wfs3/collections" ) ); + + assertThat( testPoint.getServerUrl(), is( "http://cloudsdi.geo-solutions.it:80/geoserver/wfs3" ) ); + assertThat( testPoint.getPath(), is( "/collections" ) ); + + assertThat( testPoint.getContentMediaTypes().size(), is( 4 ) ); + } + + @Test + public void testRetrieveTestPointsForCollectionMetadata_compactAPI() { + OpenApi3Parser parser = new OpenApi3Parser(); + + URL openAppiDocument = OpenApiUtilsTest.class.getResource( "openapi_compact-api.json" ); + OpenApi3 apiModel = parser.parse( openAppiDocument, true ); + List testPoints = retrieveTestPointsForCollectionMetadata( apiModel, "test__countries" ); + + assertThat( testPoints.size(), is( 1 ) ); + + TestPoint testPoint = testPoints.get( 0 ); + + assertThat( testPoint.getServerUrl(), is( "http://cloudsdi.geo-solutions.it:80/geoserver/wfs3" ) ); + assertThat( testPoint.getPath(), is( "/collections/{collectionId}" ) ); + } + + @Test + public void testRetrieveTestPointsForCollection_compactAPI() { + OpenApi3Parser parser = new OpenApi3Parser(); + + URL openAppiDocument = OpenApiUtilsTest.class.getResource( "openapi_compact-api.json" ); + OpenApi3 apiModel = parser.parse( openAppiDocument, true ); + List testPoints = retrieveTestPointsForCollection( apiModel, "test__countries" ); + + assertThat( testPoints.size(), is( 1 ) ); + + TestPoint testPoint = testPoints.get( 0 ); + assertThat( testPoint.getServerUrl(), is( "http://cloudsdi.geo-solutions.it:80/geoserver/wfs3" ) ); + assertThat( testPoint.getPath(), is( "/collections/{collectionId}/items" ) ); + } + + @Test + public void testRetrieveTestPointsForFeature_compactAPI() { + OpenApi3Parser parser = new OpenApi3Parser(); + + URL openAppiDocument = OpenApiUtilsTest.class.getResource( "openapi_compact-api.json" ); + OpenApi3 apiModel = parser.parse( openAppiDocument, true ); + List testPoints = retrieveTestPointsForFeature( apiModel, "test__countries", "abc" ); + + assertThat( testPoints.size(), is( 1 ) ); + + TestPoint testPoint = testPoints.get( 0 ); + assertThat( testPoint.getServerUrl(), is( "http://cloudsdi.geo-solutions.it:80/geoserver/wfs3" ) ); + assertThat( testPoint.getPath(), is( "/collections/{collectionId}/items/{featureId}" ) ); + } + } diff --git a/src/test/java/org/opengis/cite/wfs30/openapi3/UrlBuilderTest.java b/src/test/java/org/opengis/cite/wfs30/openapi3/UrlBuilderTest.java new file mode 100644 index 00000000..c5010180 --- /dev/null +++ b/src/test/java/org/opengis/cite/wfs30/openapi3/UrlBuilderTest.java @@ -0,0 +1,75 @@ +package org.opengis.cite.wfs30.openapi3; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Collections; + +import org.junit.Test; + +/** + * @author Lyn Goltz + */ +public class UrlBuilderTest { + + @Test + public void testBuildUrl_collectionMetadata_withTemplate() { + TestPoint tp = new TestPoint( "http://localhost:8080/service", "/collections/{name}", Collections.emptyMap() ); + String url = new UriBuilder( tp ).collectionName( "water" ).buildUrl(); + + assertThat( url, is( "http://localhost:8080/service/collections/water" ) ); + } + + @Test + public void testBuildUrl_collectionMetadata_withoutTemplate() { + TestPoint tp = new TestPoint( "http://localhost:8080/service", "/collections/forest", Collections.emptyMap() ); + String url = new UriBuilder( tp ).collectionName( "forest" ).buildUrl(); + + assertThat( url, is( "http://localhost:8080/service/collections/forest" ) ); + } + + @Test + public void testBuildUrl_collection_withTemplate() { + TestPoint tp = new TestPoint( "http://localhost:8080/service", "/collections/{name}/items", + Collections.emptyMap() ); + String url = new UriBuilder( tp ).collectionName( "water" ).buildUrl(); + + assertThat( url, is( "http://localhost:8080/service/collections/water/items" ) ); + } + + @Test + public void testBuildUrl_collection_withoutTemplate() { + TestPoint tp = new TestPoint( "http://localhost:8080/service", "/collections/forest/items", + Collections.emptyMap() ); + String url = new UriBuilder( tp ).collectionName( "forest" ).buildUrl(); + + assertThat( url, is( "http://localhost:8080/service/collections/forest/items" ) ); + } + + @Test + public void testBuildUrl_feature_withFeatureIdTemplate() { + TestPoint tp = new TestPoint( "http://localhost:8080/service", "/collections/forest/items/{featureId}", + Collections.emptyMap() ); + String url = new UriBuilder( tp ).collectionName( "forest" ).featureId( "1" ).buildUrl(); + + assertThat( url, is( "http://localhost:8080/service/collections/forest/items/1" ) ); + } + + @Test + public void testBuildUrl_feature_withCollectionNameAndFeatureIdTemplate() { + TestPoint tp = new TestPoint( "http://localhost:8080/service", "/collections/{name}/items/{featureId}", + Collections.emptyMap() ); + String url = new UriBuilder( tp ).collectionName( "water" ).featureId( "2" ).buildUrl(); + + assertThat( url, is( "http://localhost:8080/service/collections/water/items/2" ) ); + } + + @Test + public void testBuildUrl_feature_withoutTemplates() { + TestPoint tp = new TestPoint( "http://localhost:8080/service", "/collections/forest/items/3", + Collections.emptyMap() ); + String url = new UriBuilder( tp ).collectionName( "forest" ).featureId( "3" ).buildUrl(); + + assertThat( url, is( "http://localhost:8080/service/collections/forest/items/3" ) ); + } +} diff --git a/src/test/resources/org/opengis/cite/wfs30/openapi3/openapi_compact-api.json b/src/test/resources/org/opengis/cite/wfs30/openapi3/openapi_compact-api.json new file mode 100644 index 00000000..9b2eb04d --- /dev/null +++ b/src/test/resources/org/opengis/cite/wfs30/openapi3/openapi_compact-api.json @@ -0,0 +1,930 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "WFS 3.0 server", + "contact": { + "name": "Andrea Aime - GeoSolutions", + "email": "andrea.aime@geo-solutions.it" + }, + "version": "2.14-SNAPSHOT" + }, + "externalDocs": { + "description": "WFS specification", + "url": "https://github.com/opengeospatial/WFS_FES" + }, + "servers": [ + { + "url": "http://cloudsdi.geo-solutions.it:80/geoserver/wfs3", + "description": "This server" + } + ], + "tags": [ + { + "name": "Capabilities", + "description": "Essential characteristics of this API including information about the data." + }, + { + "name": "Features", + "description": "Access to data (features)." + } + ], + "paths": { + "/": { + "get": { + "tags": [ + "Capabilities" + ], + "summary": "landing page of this API", + "description": "The landing page provides links to the API definition, the Conformance statements and the metadata about the feature data in this dataset.", + "operationId": "getLandingPage", + "responses": { + "200": { + "description": "links to the API capabilities", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/root" + } + }, + "text/html": { + "schema": { + "type": "string" + } + }, + "application/openapi+json;version=3.0": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "text/xml": { + "schema": { + "type": "string" + } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/root" + } + } + } + } + } + } + }, + "/conformance": { + "get": { + "tags": [ + "Capabilities" + ], + "summary": "information about standards that this API conforms to", + "description": "list all requirements classes specified in a standard (e.g., WFS 3.0 Part 1: Core) that the server conforms to", + "operationId": "getRequirementsClasses", + "responses": { + "200": { + "description": "the URIs of all requirements classes supported by the server", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/req-classes" + } + }, + "text/xml": { + "schema": { + "type": "string" + } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/req-classes" + } + } + } + }, + "default": { + "description": "An error occured.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/exception" + } + } + } + } + } + } + }, + "/collections": { + "get": { + "tags": [ + "Capabilities" + ], + "summary": "describe the feature collections in the dataset", + "operationId": "describeCollections", + "responses": { + "200": { + "description": "Metdata about the feature collections shared by this API.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/content" + } + }, + "text/html": { + "schema": { + "type": "string" + } + }, + "text/xml": { + "schema": { + "type": "string" + } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/content" + } + } + } + }, + "default": { + "description": "An error occured.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/exception" + } + }, + "text/html": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/collections/{collectionId}": { + "get": { + "tags": [ + "Capabilities" + ], + "summary": "describe the {collectionId} feature collection", + "operationId": "describeCollection", + "parameters": [ + { + "$ref": "#/components/parameters/collectionId" + } + ], + "responses": { + "200": { + "description": "Metadata about the {collectionId} collection shared by this API.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/collectionInfo" + } + }, + "text/html": { + "schema": { + "type": "string" + } + }, + "text/xml": { + "schema": { + "type": "string" + } + }, + "application/x-yaml": { + "schema": { + "$ref": "#/components/schemas/collectionInfo" + } + } + } + }, + "default": { + "description": "An error occured.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/exception" + } + }, + "text/html": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/collections/{collectionId}/items": { + "get": { + "tags": [ + "Features" + ], + "summary": "retrieve features of feature collection {collectionId}", + "description": "Every feature in a dataset belongs to a collection. A dataset may consist of multiple feature collections. A feature collection is often a collection of features of a similar type, based on a common schema.\\\nUse content negotiation to request HTML or GeoJSON.", + "operationId": "getFeatures", + "parameters": [ + { + "$ref": "#/components/parameters/collectionId" + }, + { + "$ref": "#/components/parameters/limit" + }, + { + "$ref": "#/components/parameters/bbox" + }, + { + "$ref": "#/components/parameters/time" + } + ], + "responses": { + "200": { + "description": "Information about the feature collection plus the first features matching the selection parameters.", + "content": { + "application/geo+json": { + "schema": { + "$ref": "#/components/schemas/featureCollectionGeoJSON" + } + }, + "text/html": { + "schema": { + "type": "string" + } + }, + "application/gml+xml; version=3.2": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "text/xml; subtype=gml/2.1.2": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "text/xml; subtype=gml/3.2": { + "schema": { + "type": "string" + } + }, + "application/vnd.google-earth.kml+xml": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "application/vnd.google-earth.kml xml": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "text/xml; subtype=gml/3.1.1": { + "schema": { + "type": "string" + } + } + } + }, + "default": { + "description": "An error occured.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/exception" + } + }, + "text/html": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/collections/{collectionId}/items/{featureId}": { + "get": { + "tags": [ + "Features" + ], + "summary": "retrieve a feature; use content negotiation to request HTML or GeoJSON", + "operationId": "getFeature", + "parameters": [ + { + "$ref": "#/components/parameters/collectionId" + }, + { + "$ref": "#/components/parameters/featureId" + } + ], + "responses": { + "200": { + "description": "A feature.", + "content": { + "application/geo+json": { + "schema": { + "$ref": "#/components/schemas/featureGeoJSON" + } + }, + "text/html": { + "schema": { + "type": "string" + } + }, + "application/gml+xml; version=3.2": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "text/xml; subtype=gml/2.1.2": { + "schema": { + "type": "string" + } + }, + "application/json": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "text/xml; subtype=gml/3.2": { + "schema": { + "type": "string" + } + }, + "application/vnd.google-earth.kml+xml": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "application/vnd.google-earth.kml xml": { + "schema": { + "type": "string", + "format": "binary" + } + }, + "text/xml; subtype=gml/3.1.1": { + "schema": { + "type": "string" + } + } + } + }, + "default": { + "description": "An error occured.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/exception" + } + }, + "text/html": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "exception": { + "required": [ + "code" + ], + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "root": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "links": { + "type": "array", + "example": [ + { + "href": "http://data.example.org/", + "rel": "self", + "type": "application/json", + "title": "this document" + }, + { + "href": "http://data.example.org/api", + "rel": "service", + "type": "application/openapi+json;version=3.0", + "title": "the API definition" + }, + { + "href": "http://data.example.org/conformance", + "rel": "conformance", + "type": "application/json", + "title": "WFS 3.0 conformance classes implemented by this server" + }, + { + "href": "http://data.example.org/collections", + "rel": "data", + "type": "application/json", + "title": "Metadata about the feature collections" + } + ], + "items": { + "$ref": "#/components/schemas/link" + } + } + } + }, + "req-classes": { + "required": [ + "conformsTo" + ], + "type": "object", + "properties": { + "conformsTo": { + "type": "array", + "example": [ + "http://www.opengis.net/spec/wfs-1/3.0/req/core", + "http://www.opengis.net/spec/wfs-1/3.0/req/oas30", + "http://www.opengis.net/spec/wfs-1/3.0/req/html", + "http://www.opengis.net/spec/wfs-1/3.0/req/geojson" + ], + "items": { + "type": "string" + } + } + } + }, + "link": { + "required": [ + "href" + ], + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "rel": { + "type": "string", + "example": "prev" + }, + "type": { + "type": "string", + "example": "application/geo+json" + }, + "hreflang": { + "type": "string", + "example": "en" + } + } + }, + "content": { + "required": [ + "collections", + "links" + ], + "type": "object", + "properties": { + "links": { + "type": "array", + "example": [ + { + "href": "http://data.example.org/collections.json", + "rel": "self", + "type": "application/json", + "title": "this document" + }, + { + "href": "http://data.example.org/collections.html", + "rel": "alternate", + "type": "text/html", + "title": "this document as HTML" + }, + { + "href": "http://schemas.example.org/1.0/foobar.xsd", + "rel": "describedBy", + "type": "application/xml", + "title": "XML schema for Acme Corporation data" + } + ], + "items": { + "$ref": "#/components/schemas/link" + } + }, + "collections": { + "type": "array", + "items": { + "$ref": "#/components/schemas/collectionInfo" + } + } + } + }, + "collectionInfo": { + "required": [ + "links", + "name" + ], + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "identifier of the collection used, for example, in URIs", + "example": "buildings" + }, + "title": { + "type": "string", + "description": "human readable title of the collection", + "example": "Buildings" + }, + "description": { + "type": "string", + "description": "a description of the features in the collection", + "example": "Buildings in the city of Bonn." + }, + "links": { + "type": "array", + "example": [ + { + "href": "http://data.example.org/collections/buildings/items", + "rel": "item", + "type": "application/geo+json", + "title": "Buildings" + }, + { + "href": "http://example.org/concepts/building.html", + "rel": "describedBy", + "type": "text/html", + "title": "Feature catalogue for buildings" + } + ], + "items": { + "$ref": "#/components/schemas/link" + } + }, + "extent": { + "$ref": "#/components/schemas/extent" + }, + "crs": { + "type": "array", + "description": "The coordinate reference systems in which geometries may be retrieved. Coordinate reference systems are identified by a URI. The first coordinate reference system is the coordinate reference system that is used by default. This is always \"http://www.opengis.net/def/crs/OGC/1.3/CRS84\", i.e. WGS84 longitude/latitude.", + "items": { + "type": "string" + }, + "default": [ + "http://www.opengis.net/def/crs/OGC/1.3/CRS84" + ] + } + } + }, + "extent": { + "type": "object", + "properties": { + "crs": { + "type": "string", + "description": "Coordinate reference system of the coordinates in the spatial extent (property `spatial`). In the Core, only WGS84 longitude/latitude is supported. Extensions may support additional coordinate reference systems.", + "enum": [ + "http://www.opengis.net/def/crs/OGC/1.3/CRS84" + ], + "default": "http://www.opengis.net/def/crs/OGC/1.3/CRS84" + }, + "spatial": { + "maxItems": 6, + "minItems": 4, + "type": "array", + "description": "West, north, east, south edges of the spatial extent. The minimum and maximum values apply to the coordinate reference system WGS84 longitude/latitude that is supported in the Core. If, for example, a projected coordinate reference system is used, the minimum and maximum values need to be adjusted.", + "example": [ + -180, + -90, + 180, + 90 + ], + "items": { + "type": "number" + } + }, + "trs": { + "type": "string", + "description": "Temporal reference system of the coordinates in the temporal extent (property `temporal`). In the Core, only the Gregorian calendar is supported. Extensions may support additional temporal reference systems.", + "enum": [ + "http://www.opengis.net/def/uom/ISO-8601/0/Gregorian" + ], + "default": "http://www.opengis.net/def/uom/ISO-8601/0/Gregorian" + }, + "temporal": { + "maxItems": 2, + "minItems": 2, + "type": "array", + "description": "Begin and end times of the temporal extent.", + "example": [ + "2011-11-11T12:22:11Z", + "2012-11-24T12:32:43Z" + ], + "items": { + "type": "string", + "format": "dateTime" + } + } + } + }, + "featureCollectionGeoJSON": { + "required": [ + "features", + "type" + ], + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "FeatureCollection" + ] + }, + "features": { + "type": "array", + "items": { + "$ref": "#/components/schemas/featureGeoJSON" + } + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/link" + } + }, + "timeStamp": { + "type": "string", + "format": "dateTime" + }, + "numberMatched": { + "minimum": 0, + "type": "integer" + }, + "numberReturned": { + "minimum": 0, + "type": "integer" + } + } + }, + "featureGeoJSON": { + "required": [ + "geometry", + "properties", + "type" + ], + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "Feature" + ] + }, + "geometry": { + "$ref": "#/components/schemas/geometryGeoJSON" + }, + "properties": { + "type": "object", + "nullable": true + }, + "id": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + } + } + }, + "geometryGeoJSON": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "Point", + "MultiPoint", + "LineString", + "MultiLineString", + "Polygon", + "MultiPolygon", + "GeometryCollection" + ] + } + } + } + }, + "parameters": { + "limit": { + "name": "limit", + "in": "query", + "description": "The optional limit parameter limits the number of items that are\npresented in the response document.\n\nOnly items are counted that are on the first level of the collection in\nthe response document. Nested objects contained within the explicitly\nrequested items shall not be counted.\n", + "required": false, + "style": "form", + "explode": false, + "schema": { + "maximum": 1000000, + "minimum": 1, + "type": "integer", + "default": 1000000 + } + }, + "bbox": { + "name": "bbox", + "in": "query", + "description": "Only features that have a geometry that intersects the bounding box are selected. The bounding box is provided as four or six numbers, depending on whether the coordinate reference system includes a vertical axis (elevation or depth):\n* Lower left corner, coordinate axis 1 * Lower left corner, coordinate axis 2 * Lower left corner, coordinate axis 3 (optional) * Upper right corner, coordinate axis 1 * Upper right corner, coordinate axis 2 * Upper right corner, coordinate axis 3 (optional)\nThe coordinate reference system of the values is WGS84 longitude/latitude (http://www.opengis.net/def/crs/OGC/1.3/CRS84) unless a different coordinate reference system is specified in the parameter `bbox-crs`.\nFor WGS84 longitude/latitude the values are in most cases the sequence of minimum longitude, minimum latitude, maximum longitude and maximum latitude. However, in cases where the box spans the antimeridian the first value (west-most box edge) is larger than the third value (east-most box edge).\nIf a feature has multiple spatial geometry properties, it is the decision of the server whether only a single spatial geometry property is used to determine the extent or all relevant geometries.\n", + "required": false, + "style": "form", + "explode": false, + "schema": { + "maxItems": 6, + "minItems": 4, + "type": "array", + "items": { + "type": "number" + } + } + }, + "time": { + "name": "time", + "in": "query", + "description": "Either a date-time or a period string that adheres to RFC 3339. Examples:\n* A date-time: \"2018-02-12T23:20:50Z\" * A period: \"2018-02-12T00:00:00Z/2018-03-18T12:31:12Z\" or \"2018-02-12T00:00:00Z/P1M6DT12H31M12S\"\nOnly features that have a temporal property that intersects the value of `time` are selected.\nIf a feature has multiple temporal properties, it is the decision of the server whether only a single temporal property is used to determine the extent or all relevant temporal properties.", + "required": false, + "style": "form", + "explode": false, + "schema": { + "type": "string" + } + }, + "collectionId": { + "name": "collectionId", + "in": "path", + "description": "Identifier (name) of a specific collection", + "required": true, + "schema": { + "type": "string", + "enum": [ + "eumetsat__ne_10m_coastline", + "eumetsat__ne_boundary_lines_land", + "eumetsat__wind_ascat", + "eumetsat__wind_ascat_reduced", + "eumetsat__wind_ascat_thinned", + "landsat8__B3_index", + "geosolutions__LANDSAT8__B1", + "geosolutions__SENTINEL1_V2", + "geosolutions__SENTINEL1__MOSAIC_B1", + "geosolutions__SENTINEL1__vv", + "geosolutions__SENTINEL2_V2", + "geosolutions__SENTINEL2__B04", + "geosolutions__SENTINEL2__MOSAIC_B01", + "geosolutions__product", + "geosolutions__smb_simple_points", + "geosolutions__testing", + "zaatari__AgricultureSrf", + "zaatari__CultureSrf", + "zaatari__FacilitySrf", + "zaatari__HydrographySrf", + "zaatari__InformationPnt", + "zaatari__RecreationSrf", + "zaatari__SettlementSrf", + "zaatari__StructurePnt", + "zaatari__StructureSrf", + "zaatari__TransportationGroundCrv", + "zaatari__TransportationGroundSrf", + "zaatari__UtilityInfrastructureSrf", + "zaatari__o2s_A", + "zaatari__o2s_L", + "zaatari__osm_points", + "zaatari__zaatari_worldview_timeseries_index", + "geoedge__administrative_subdivision_s", + "geoedge__anchorage_p", + "geoedge__building_p", + "geoedge__built_up_area_p", + "geoedge__cemetery_s", + "geoedge__code_list_t", + "geoedge__conservation_area_s", + "geoedge__dam_c", + "geoedge__dam_s", + "geoedge__dataset_s", + "geoedge__dataset_t", + "geoedge__entity_collection_metadata_s", + "geoedge__entity_collection_metadata_t", + "geoedge__foreshore_s", + "geoedge__forest_s", + "geoedge__gauging_station_p", + "geoedge__heliport_p", + "geoedge__inland_waterbody_s", + "geoedge__land_aerodrome_p", + "geoedge__land_water_boundary_c", + "geoedge__maritime_limit_c", + "geoedge__military_installation_s", + "geoedge__navigable_canal_s", + "geoedge__park_s", + "geoedge__pipeline_c", + "geoedge__port_p", + "geoedge__reef_c", + "geoedge__restriction_info_t", + "geoedge__river_c", + "geoedge__river_s", + "geoedge__road_c", + "geoedge__rock_formation_p", + "geoedge__runway_s", + "geoedge__soil_surface_region_s", + "geoedge__trail_c", + "geoedge__tunnel_c", + "geoedge__water_aerodrome_p", + "geoedge__water_well_p", + "test__countries", + "test__eo_collection", + "test__eo_product", + "test__granule", + "sf__AggregateGeoFeature", + "sf__EntitéGénérique", + "sf__PrimitiveGeoFeature", + "daraa__AgriculturePnt", + "daraa__AgricultureSrf", + "daraa__Cultivated_2011", + "daraa__Cultivated_2012", + "daraa__Cultivated_2013", + "daraa__CulturePnt", + "daraa__CultureSrf", + "daraa__FacilityPnt", + "daraa__FacilitySrf", + "daraa__FieldBoundary_2011", + "daraa__Health_2011", + "daraa__Health_2012", + "daraa__Health_2013", + "daraa__HydrographyCrv", + "daraa__HydrographySrf", + "daraa__InformationPnt", + "daraa__Inventory_2011", + "daraa__Inventory_2012", + "daraa__Inventory_2013", + "daraa__MilitarySrf", + "daraa__RecreationPnt", + "daraa__RecreationSrf", + "daraa__SettlementPnt", + "daraa__SettlementSrf", + "daraa__StructureCrv", + "daraa__StructurePnt", + "daraa__StructureSrf", + "daraa__TransportationGroundCrv", + "daraa__TransportationGroundPnt", + "daraa__TransportationGroundSrf", + "daraa__UtilityInfrastructureCrv", + "daraa__UtilityInfrastructurePnt", + "daraa__VegetationSrf", + "daraa__daraa_landsat8_timeseries_index", + "daraa__daraa_worldview_timeseries_index", + "daraa__o2s_A", + "daraa__o2s_L", + "daraa__o2s_P", + "osm__public_gns_iceland_version_log", + "osm__public_osm_administrative_version_log", + "osm__public_osm_protected_area_version_log" + ] + } + }, + "featureId": { + "name": "featureId", + "in": "path", + "description": "Local identifier of a specific feature", + "required": true, + "schema": { + "type": "string" + } + } + } + } +} \ No newline at end of file