Skip to content

Commit

Permalink
#8 - set date interval/instant from temporal extent in collections de…
Browse files Browse the repository at this point in the history
…scription
  • Loading branch information
lgoltz committed Jul 2, 2018
1 parent e56782e commit 1756e3b
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@
import static org.opengis.cite.wfs30.util.JsonUtils.findLinksWithSupportedMediaTypeByRel;
import static org.opengis.cite.wfs30.util.JsonUtils.findLinksWithoutRelOrType;
import static org.opengis.cite.wfs30.util.JsonUtils.findUnsupportedTypes;
import static org.opengis.cite.wfs30.util.JsonUtils.formatDate;
import static org.opengis.cite.wfs30.util.JsonUtils.formatDateRange;
import static org.opengis.cite.wfs30.util.JsonUtils.formatDateRangeWithDuration;
import static org.opengis.cite.wfs30.util.JsonUtils.hasProperty;
import static org.opengis.cite.wfs30.util.JsonUtils.parseExtent;
import static org.opengis.cite.wfs30.util.JsonUtils.parseAsDate;
import static org.opengis.cite.wfs30.util.JsonUtils.parseSpatialExtent;
import static org.opengis.cite.wfs30.util.JsonUtils.parseTemporalExtent;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;

import java.net.URISyntaxException;
import java.text.ParseException;
import java.time.Duration;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
Expand All @@ -30,13 +36,13 @@
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;
import org.testng.SkipException;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
import com.reprezen.kaizen.oasparser.model3.MediaType;
import com.reprezen.kaizen.oasparser.model3.OpenApi3;
import com.reprezen.kaizen.oasparser.model3.Operation;
Expand All @@ -52,8 +58,6 @@
*/
public class GetFeaturesOperation extends CommonFixture {

private static final ISO8601DateFormat DATE_FORMAT = new ISO8601DateFormat();

private final Map<String, ResponseData> collectionNameAndResponse = new HashMap<>();

private List<Map<String, Object>> collections;
Expand Down Expand Up @@ -84,9 +88,8 @@ public Object[][] collectionItemUrisWithLimits( ITestContext testContext ) {
@DataProvider(name = "collectionItemUrisWithBboxes")
public Iterator<Object[]> collectionItemUrisWithBboxes( ITestContext testContext ) {
List<Object[]> collectionsWithBboxes = new ArrayList<>();
int i = 0;
for ( Map<String, Object> collection : collections ) {
BBox extent = parseExtent( collection );
BBox extent = parseSpatialExtent( collection );
if ( extent != null ) {
collectionsWithBboxes.add( new Object[] { collection, extent } );
// These should include test cases which cross the
Expand All @@ -105,19 +108,34 @@ public Iterator<Object[]> collectionItemUrisWithBboxes( ITestContext testContext
}

@DataProvider(name = "collectionItemUrisWithTimes")
public Object[][] collectionItemUrisWithTimes( ITestContext testContext ) {
// TODO: find values
Object[][] collectionsData = new Object[collections.size() * 3][];
int i = 0;
public Iterator<Object[]> collectionItemUrisWithTimes( ITestContext testContext ) {
List<Object[]> collectionsWithTimes = new ArrayList<>();
for ( Map<String, Object> collection : collections ) {
// Example 6. A date-time
collectionsData[i++] = new Object[] { collection, "2018-02-12T23%3A20%3A50Z" };
// Example 7. A period using a start and end time
collectionsData[i++] = new Object[] { collection, "2018-02-12T00%3A00%3A00Z%2F2018-03-18T12%3A31%3A12Z" };
// Example 8. A period using start time and a duration
collectionsData[i++] = new Object[] { collection, "2018-02-12T00%3A00%3A00Z%2FP1M6DT12H31M12S" };
TemporalExtent temporalExtent = parseTemporalExtent( collection );
if ( temporalExtent != null ) {
ZonedDateTime begin = temporalExtent.getBegin();
ZonedDateTime end = temporalExtent.getEnd();

Duration between = Duration.between( begin, end );
Duration quarter = between.dividedBy( 4 );
ZonedDateTime beginInterval = begin.plus( quarter );
ZonedDateTime endInterval = beginInterval.plus( quarter );

// Example 6. A date-time
collectionsWithTimes.add( new Object[] { collection, formatDate( begin ), beginInterval, null } );
// Example 7. A period using a start and end time
collectionsWithTimes.add( new Object[] { collection, formatDateRange( beginInterval, endInterval ),
beginInterval, endInterval } );
// Example 8. A period using start time and a duration
LocalDate beginIntervalDate = beginInterval.toLocalDate();
LocalDate endIntervalDate = beginIntervalDate.plusDays( 2 );
collectionsWithTimes.add( new Object[] {
collection,
formatDateRangeWithDuration( beginIntervalDate, endIntervalDate ),
beginIntervalDate, endIntervalDate } );
}
}
return collectionsData;
return collectionsWithTimes.iterator();
}

@BeforeClass
Expand Down Expand Up @@ -159,10 +177,10 @@ public void validateGetFeaturesOperation( Map<String, Object> collection ) {
throw new SkipException( "Could not find url for collection with name " + collectionName
+ " supporting GeoJson (type " + GEOJSON_MIME_TYPE + ")" );

Date timeStampBeforeResponse = new Date();
ZonedDateTime timeStampBeforeResponse = ZonedDateTime.now();
Response response = init().baseUri( getFeaturesUrl ).accept( GEOJSON_MIME_TYPE ).when().request( GET );
response.then().statusCode( 200 );
Date timeStampAfterResponse = new Date();
ZonedDateTime timeStampAfterResponse = ZonedDateTime.now();
ResponseData responseData = new ResponseData( response, timeStampBeforeResponse, timeStampAfterResponse );
collectionNameAndResponse.put( collectionName, responseData );
}
Expand Down Expand Up @@ -402,10 +420,10 @@ public void validateLimitParameter_requests( Map<String, Object> collection, int
if ( getFeaturesUrl.isEmpty() )
throw new SkipException( "Could not find url for collection with name " + collectionName
+ " supporting GeoJson (type " + GEOJSON_MIME_TYPE + ")" );
Date timeStampBeforeResponse = new Date();
ZonedDateTime timeStampBeforeResponse = ZonedDateTime.now();
Response response = init().baseUri( getFeaturesUrl ).accept( GEOJSON_MIME_TYPE ).param( "limit", limit ).when().request( GET );
response.then().statusCode( 200 );
Date timeStampAfterResponse = new Date();
ZonedDateTime timeStampAfterResponse = ZonedDateTime.now();

JsonPath jsonPath = response.jsonPath();
int numberOfFeatures = jsonPath.getList( "features" ).size();
Expand Down Expand Up @@ -507,11 +525,11 @@ public void validateBboxParameter_requests( Map<String, Object> collection, BBox
if ( getFeaturesUrl.isEmpty() )
throw new SkipException( "Could not find url for collection with name " + collectionName
+ " supporting GeoJson (type " + GEOJSON_MIME_TYPE + ")" );
Date timeStampBeforeResponse = new Date();
ZonedDateTime timeStampBeforeResponse = ZonedDateTime.now();
Response response = init().baseUri( getFeaturesUrl ).accept( GEOJSON_MIME_TYPE ).param( "bbox",
bbox.asQueryParameter() ).when().request( GET );
response.then().statusCode( 200 );
Date timeStampAfterResponse = new Date();
ZonedDateTime timeStampAfterResponse = ZonedDateTime.now();

JsonPath jsonPath = response.jsonPath();
assertTimeStamp( collectionName, jsonPath, timeStampBeforeResponse, timeStampAfterResponse, false );
Expand Down Expand Up @@ -586,25 +604,32 @@ public void validateTimeParameter( Map<String, Object> collection ) {
*
* @param collection
* the collection under test, never <code>null</code>
* @param time
* time parameter to request, never <code>null</code>
* @param queryParameter
* time parameter as string to use as query parameter, never <code>null</code>
* @param begin
* a {@link ZonedDateTime} or {@link LocalDate}, the begin of the interval (or instant), never
* <code>null</code>
* @param end
* a {@link ZonedDateTime} or {@link LocalDate}, the end of the interval, never <code>null</code> if the
* request is an instant
* @throws URISyntaxException
* if the creation of a uri fails
*
*/
@Test(description = "Implements A.4.4.12. Bounding Box Parameter (Requirement 23)", dataProvider = "collectionItemUrisWithTimes", dependsOnMethods = "validateGetFeaturesOperation")
public void validateTimeParameter_requests( Map<String, Object> collection, String time )
public void validateTimeParameter_requests( Map<String, Object> collection, String queryParameter, Object begin,
Object end )
throws URISyntaxException {
String collectionName = (String) collection.get( "name" );

String getFeaturesUrl = findGetFeatureUrlForGeoJson( collection );
if ( getFeaturesUrl.isEmpty() )
throw new SkipException( "Could not find url for collection with name " + collectionName
+ " supporting GeoJson (type " + GEOJSON_MIME_TYPE + ")" );
Date timeStampBeforeResponse = new Date();
Response response = init().baseUri( getFeaturesUrl ).accept( GEOJSON_MIME_TYPE ).param( "time", time ).when().request( GET );
ZonedDateTime timeStampBeforeResponse = ZonedDateTime.now();
Response response = init().baseUri( getFeaturesUrl ).accept( GEOJSON_MIME_TYPE ).param( "time", queryParameter ).when().request( GET );
response.then().statusCode( 200 );
Date timeStampAfterResponse = new Date();
ZonedDateTime timeStampAfterResponse = ZonedDateTime.now();

JsonPath jsonPath = response.jsonPath();
assertTimeStamp( collectionName, jsonPath, timeStampBeforeResponse, timeStampAfterResponse, false );
Expand All @@ -614,23 +639,22 @@ public void validateTimeParameter_requests( Map<String, Object> collection, Stri
// TODO: assert returned features
}

private void assertTimeStamp( String collectionName, JsonPath jsonPath, Date timeStampBeforeResponse,
Date timeStampAfterResponse, boolean skipIfNoTimeStamp ) {
private void assertTimeStamp( String collectionName, JsonPath jsonPath, ZonedDateTime timeStampBeforeResponse,
ZonedDateTime timeStampAfterResponse, boolean skipIfNoTimeStamp ) {
String timeStamp = jsonPath.getString( "timeStamp" );
if ( timeStamp == null )
if ( skipIfNoTimeStamp )
throw new SkipException( "Property timeStamp is not set in collection items '" + collectionName + "'" );
else
return;

Date date = parseAsDate( timeStamp );
assertTrue( date.before( timeStampAfterResponse ),
"timeStamp in response must be before the request was send ("
+ DATE_FORMAT.format( timeStampAfterResponse ) + ") but was '" + timeStamp
+ "'" );
assertTrue( date.after( timeStampBeforeResponse ), "timeStamp in response must be after the request was send ("
+ DATE_FORMAT.format( timeStampBeforeResponse )
+ ") but was '" + timeStamp + "'" );
ZonedDateTime date = parseAsDate( timeStamp );
assertTrue( date.isBefore( timeStampAfterResponse ),
"timeStamp in response must be before the request was send (" + formatDate( timeStampAfterResponse )
+ ") but was '" + timeStamp + "'" );
assertTrue( date.isAfter( timeStampBeforeResponse ),
"timeStamp in response must be after the request was send (" + formatDate( timeStampBeforeResponse )
+ ") but was '" + timeStamp + "'" );
}

private void assertNumberReturned( String collectionName, JsonPath jsonPath, boolean skipIfNoNumberReturned ) {
Expand Down Expand Up @@ -701,14 +725,6 @@ private List<String> createListOfMediaTypesToSupport( TestPoint testPoint, Map<S
return mediaTypesToSupport;
}

private Date parseAsDate( String timeStamp ) {
try {
return DATE_FORMAT.parse( timeStamp );
} catch ( ParseException e ) {
throw new AssertionError( "timeStamp " + timeStamp + "is not a valid date" );
}
}

private void assertIntegerGreaterZero( Object value, String propertyName ) {
if ( value instanceof Number )
assertIntegerGreaterZero( ( (Number) value ).intValue(), propertyName );
Expand All @@ -731,11 +747,12 @@ private class ResponseData {

private final Response response;

private final Date timeStampBeforeResponse;
private final ZonedDateTime timeStampBeforeResponse;

private final Date timeStampAfterResponse;
private final ZonedDateTime timeStampAfterResponse;

public ResponseData( Response response, Date timeStampBeforeResponse, Date timeStampAfterResponse ) {
public ResponseData( Response response, ZonedDateTime timeStampBeforeResponse,
ZonedDateTime timeStampAfterResponse ) {
this.response = response;
this.timeStampBeforeResponse = timeStampBeforeResponse;
this.timeStampAfterResponse = timeStampAfterResponse;
Expand Down
96 changes: 94 additions & 2 deletions src/main/java/org/opengis/cite/wfs30/util/JsonUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDate;
import java.time.Period;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand All @@ -23,7 +27,95 @@ private JsonUtils() {
}

/**
* Parses the extent from the passed collection.
* Parses the temporal extent from the passed collection.
*
* @param collection
* the collection containing the extent to parse, never <code>null</code>
* @return the parsed temporal extent, <code>null</code> if no extent exists
* @throws IllegalArgumentException
* if the number of items in the extent invalid
*
*/
public static TemporalExtent parseTemporalExtent( Map<String, Object> collection ) {
Object extent = collection.get( "extent" );
if ( extent == null || !( extent instanceof Map ) )
return null;
Object spatial = ( (Map<String, Object>) extent ).get( "temporal" );
if ( spatial == null || !( spatial instanceof List ) )
return null;
List<Object> coords = (List<Object>) spatial;
if ( coords.size() == 2 ) {
ZonedDateTime begin = parseAsDate( (String) coords.get( 0 ) );
ZonedDateTime end = parseAsDate( (String) coords.get( 1 ) );
return new TemporalExtent( begin, end );
}
throw new IllegalArgumentException( "Temporal extent with " + coords.size() + " items is invalid" );
}

/**
* Parses the passed string as ISO 8601 date.
*
* @param dateTime
* the dateTime to parse, never <code>null</code>
* @return the parsed date, never <code>null</code>
*/
public static ZonedDateTime parseAsDate( String dateTime ) {
return ZonedDateTime.parse( dateTime );
}

/**
* Formats the passed string as ISO 8601 date. Example: "2018-02-12T23:20:50Z"
*
* @param dateTime
* the dateTime to format, never <code>null</code>
* @return the formatted date, never <code>null</code>
*/
public static String formatDate( ZonedDateTime dateTime ) {
return DateTimeFormatter.ISO_INSTANT.format( dateTime );
}

/**
* Formats the passed string as ISO 8601 date. Example: "2018-02-12"
*
* @param date
* the dateTime to format, never <code>null</code>
* @return the formatted date, never <code>null</code>
*/
public static String formatDate( LocalDate date ) {
return DateTimeFormatter.ISO_DATE.format( date );
}

/**
* Formats the passed string as a period using a start and end time. Example:
* "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z"
*
* @param beginDateTime
* the begin dateTime to format, never <code>null</code>
* @param endDateTime
* the end dateTime to format, never <code>null</code>
* @return the formatted date, never <code>null</code>
*/
public static String formatDateRange( ZonedDateTime beginDateTime, ZonedDateTime endDateTime ) {
return formatDate( beginDateTime ) + "/" + formatDate( endDateTime );
}

/**
* Formats the passed string as a period using start time and a duration. Example:
* "2018-02-12T00:00:00Z/P1M6DT12H31M12S"
*
* @param beginDate
* the begin date to format, never <code>null</code>
* @param endDate
* the end date to format, never <code>null</code>
* @return the formatted date, never <code>null</code>
*/
public static String formatDateRangeWithDuration( LocalDate beginDate, LocalDate endDate ) {
Period betweenDate = Period.between( beginDate, endDate );
return formatDate( beginDate ) + "/" + betweenDate;
}

/**
* Parses the spatial extent from the passed collection.
*
* @param collection
* the collection containing the extent to parse, never <code>null</code>
Expand All @@ -32,7 +124,7 @@ private JsonUtils() {
* if the number of items in the extent invalid
*
*/
public static BBox parseExtent( Map<String, Object> collection ) {
public static BBox parseSpatialExtent( Map<String, Object> collection ) {
Object extent = collection.get( "extent" );
if ( extent == null || !( extent instanceof Map ) )
return null;
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/org/opengis/cite/wfs30/util/TemporalExtent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.opengis.cite.wfs30.util;

import java.time.ZonedDateTime;

/**
* @author <a href="mailto:[email protected]">Lyn Goltz </a>
*/
public class TemporalExtent {

private ZonedDateTime begin;

private ZonedDateTime end;

public TemporalExtent( ZonedDateTime begin, ZonedDateTime end ) {
this.begin = begin;
this.end = end;
}

public ZonedDateTime getBegin() {
return begin;
}

public ZonedDateTime getEnd() {
return end;
}

}
Loading

0 comments on commit 1756e3b

Please sign in to comment.