Date comparisons through REQ-WA103-QO24, fractional seconds comparisons

This commit is contained in:
Joshua Darnell 2020-03-02 04:25:33 -08:00
parent d412f0bdd4
commit 521920a1f8
4 changed files with 981 additions and 752 deletions

Binary file not shown.

View File

@ -138,7 +138,7 @@
<Parameter Name="ToUpperValue" Value="MAIN" />
<!-- REQUIRED: Date Fields for testing -->
<Parameter Name="DateField" Value="ModificationTimestamp" />
<Parameter Name="DateField" Value="ListingContractDate" />
<Parameter Name="DateTimeValue" Value="2018-12-31T23:55:55-09:00" />
<Parameter Name="DateValue" Value="2018-12-31" />
<Parameter Name="YearValue" Value="2018" />
@ -496,57 +496,57 @@
<Request
TestDescription="Query Support: $filter: Date: year"
RequirementId="REQ-WA103-QO18"
RequirementId="REQ-WA103-QO18.1"
MetallicLevel="Gold"
Capability="Filterability ($filter)"
WebAPIReference="2.4.4"
OutputFile="REQ-WA103-QO18_DateYear.json"
OutputFile="REQ-WA103-QO18.1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_SelectList*&amp;$filter=*Parameter_DateField* ne null and year(*Parameter_DateField*) eq *Parameter_YearValue**Parameter_RequiredParameters*"
/>
<Request
TestDescription="Query Support: $filter: Time: year"
RequirementId="REQ-WA103-QO18"
RequirementId="REQ-WA103-QO18.2"
MetallicLevel="Gold"
Capability="Filterability ($filter)"
WebAPIReference="2.4.4"
OutputFile="REQ-WA103-QO18_TimeYear.json"
OutputFile="REQ-WA103-QO18.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_SelectList*&amp;$filter=*Parameter_TimestampField* ne null and year(*Parameter_TimestampField*) eq *Parameter_YearValue**Parameter_RequiredParameters*"
/>
<Request
TestDescription="Query Support: $filter: Date: month"
RequirementId="REQ-WA103-QO19"
RequirementId="REQ-WA103-QO19.1"
MetallicLevel="Gold"
Capability="Filterability ($filter)"
WebAPIReference="2.4.4"
OutputFile="REQ-WA103-QO19_DateMonth.json"
OutputFile="REQ-WA103-QO19.1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_SelectList*&amp;$filter=*Parameter_DateField* ne null and month(*Parameter_DateField*) eq *Parameter_MonthValue**Parameter_RequiredParameters*"
/>
<Request
TestDescription="Query Support: $filter: Time: month"
RequirementId="REQ-WA103-QO19"
RequirementId="REQ-WA103-QO19.2"
MetallicLevel="Gold"
Capability="Filterability ($filter)"
WebAPIReference="2.4.4"
OutputFile="REQ-WA103-QO19_TimeMonth.json"
OutputFile="REQ-WA103-QO19.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_SelectList*&amp;$filter=*Parameter_TimestampField* ne null and month(*Parameter_TimestampField*) eq *Parameter_MonthValue**Parameter_RequiredParameters*"
/>
<Request
TestDescription="Query Support: $filter: Date: day"
RequirementId="REQ-WA103-QO20"
RequirementId="REQ-WA103-QO20.1"
MetallicLevel="Gold"
Capability="Filterability ($filter)"
WebAPIReference="2.4.4"
OutputFile="REQ-WA103-QO20_DateDay.json"
OutputFile="REQ-WA103-QO20.1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_SelectList*&amp;$filter=*Parameter_DateField* ne null and day(*Parameter_DateField*) eq *Parameter_DayValue**Parameter_RequiredParameters*"
/>
<Request
TestDescription="Query Support: $filter: Time: day"
RequirementId="REQ-WA103-QO20"
RequirementId="REQ-WA103-QO20.2"
MetallicLevel="Gold"
Capability="Filterability ($filter)"
WebAPIReference="2.4.4"

View File

@ -245,3 +245,83 @@ Feature: Web API Server 1.0.2 Certification
And the response is valid JSON
And the response has results
And DateTimeOffset data in "Parameter_TimestampField" is sorted in "desc" order
@REQ-WA103-QO18.1 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: year
When a GET request is made to the resolved Url in "REQ-WA103-QO18.1"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "year" data in Date Field "Parameter_DateField" "eq" "Parameter_YearValue"
@REQ-WA103-QO18.2 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: year comparison with timestamp
When a GET request is made to the resolved Url in "REQ-WA103-QO18.2"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "year" data in Timestamp Field "Parameter_TimestampField" "eq" "Parameter_YearValue"
@REQ-WA103-QO19.1 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: month
When a GET request is made to the resolved Url in "REQ-WA103-QO19.1"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "month" data in Date Field "Parameter_DateField" "eq" "Parameter_MonthValue"
@REQ-WA103-QO19.2 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: month comparison with timestamp
When a GET request is made to the resolved Url in "REQ-WA103-QO19.2"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "month" data in Timestamp Field "Parameter_TimestampField" "eq" "Parameter_MonthValue"
@REQ-WA103-QO20.1 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: day
When a GET request is made to the resolved Url in "REQ-WA103-QO20.1"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "day" data in Date Field "Parameter_DateField" "eq" "Parameter_DayValue"
@REQ-WA103-QO20.2 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: day comparison with timestamp
When a GET request is made to the resolved Url in "REQ-WA103-QO20.2"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "day" data in Timestamp Field "Parameter_TimestampField" "eq" "Parameter_DayValue"
@REQ-WA103-QO21 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: hour comparison with timestamp
When a GET request is made to the resolved Url in "REQ-WA103-QO21"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "hour" data in Timestamp Field "Parameter_TimestampField" "eq" "Parameter_HourValue"
@REQ-WA103-QO22 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: minute comparison with timestamp
When a GET request is made to the resolved Url in "REQ-WA103-QO22"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "minute" data in Timestamp Field "Parameter_TimestampField" "gt" "Parameter_MinuteValue"
@REQ-WA103-QO23 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: second comparison with timestamp
When a GET request is made to the resolved Url in "REQ-WA103-QO23"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "second" data in Timestamp Field "Parameter_TimestampField" "lt" "Parameter_SecondValue"
@REQ-WA103-QO24 @gold @2.4.4 @filterability-endorsement
Scenario: Query Support: $filter: Date: fractional seconds comparison with timestamp
When a GET request is made to the resolved Url in "REQ-WA103-QO24"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And "fractional" data in Timestamp Field "Parameter_TimestampField" "lt" "Parameter_FractionalValue"

View File

@ -28,7 +28,7 @@ import java.io.*;
import java.net.URI;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@ -500,6 +500,11 @@ public class WebAPIServer_1_0_2 implements En {
});
});
/*
* Year comparison glue
*/
/*
* Timestamp comparison glue
*/
@ -592,6 +597,60 @@ public class WebAPIServer_1_0_2 implements En {
}
});
});
And("^\"([^\"]*)\" data in Date Field \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String stringDatePart, String parameterFieldName, String op, String parameterAssertedValue) -> {
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
AtomicReference<Integer> fieldValue = new AtomicReference<>();
AtomicInteger assertedValue = new AtomicInteger();
AtomicReference<String> datePart = new AtomicReference<>(stringDatePart.toLowerCase());
try {
assertedValue.set(Integer.parseInt(Settings.resolveParametersString(parameterAssertedValue, settings)));
LOG.info("Asserted value is: " + assertedValue.get());
from(responseData.get()).getList(JSON_VALUE_PATH, HashMap.class).forEach(item -> {
try {
fieldValue.set(Utils.getDatePart(datePart.get(), item.get(fieldName)));
assertTrue(Utils.compare(fieldValue.get(), op, assertedValue.get()));
} catch (Exception ex){
//fail();
LOG.error("ERROR: exception thrown." + ex);
}
});
} catch (Exception ex) {
fail();
LOG.error("ERROR: exception thrown." + ex);
}
});
/*
* Year comparison from Timestamp Field
* TODO: consolidate with Year comparison with Date Field
*/
And("^\"([^\"]*)\" data in Timestamp Field \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String stringDatePart, String parameterFieldName, String op, String parameterAssertedValue) -> {
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
AtomicReference<Integer> fieldValue = new AtomicReference<>();
AtomicReference<Integer> assertedValue = new AtomicReference<>();
AtomicReference<String> datePart = new AtomicReference<>(stringDatePart.toLowerCase());
try {
assertedValue.set(Integer.parseInt(Settings.resolveParametersString(parameterAssertedValue, settings)));
LOG.info("Asserted value is: " + assertedValue.get().toString());
from(responseData.get()).getList(JSON_VALUE_PATH, HashMap.class).forEach(item -> {
try {
fieldValue.set(Utils.getTimestampPart(datePart.get(), item.get(fieldName).toString()));
assertTrue(Utils.compare(fieldValue.get(), op, assertedValue.get()));
} catch (Exception ex){
fail();
LOG.error("ERROR: exception thrown." + ex);
}
});
} catch (Exception ex) {
fail();
LOG.error("ERROR: exception thrown." + ex);
}
});
}
/**
@ -609,6 +668,17 @@ public class WebAPIServer_1_0_2 implements En {
LESS_THAN_OR_EQUAL = "le";
}
private static class DateParts {
private static final String
YEAR = "year",
MONTH = "month",
DAY = "day",
HOUR = "hour",
MINUTE = "minute",
SECOND = "second",
FRACTIONAL = "fractional";
}
private static class Utils {
/**
@ -708,6 +778,34 @@ public class WebAPIServer_1_0_2 implements En {
return result;
}
/**
* Year Comparator
* @param lhs Year to compare
* @param op an OData binary operator to use for comparisons
* @param rhs Timestamp to compare
* @return true if lhs op rhs, false otherwise
*/
private static boolean compare(Year lhs, String op, Year rhs) {
String operator = op.toLowerCase();
boolean result = false;
if (operator.contentEquals(Operators.GREATER_THAN)) {
result = lhs.isAfter(rhs);
} else if (operator.contentEquals(Operators.GREATER_THAN_OR_EQUAL)) {
result = lhs.isAfter(rhs) || lhs.equals(rhs);
} else if (operator.contentEquals(Operators.EQ)) {
result = lhs.equals(rhs);
} else if (operator.contentEquals(Operators.NE)) {
result = !lhs.equals(rhs);
} else if (operator.contentEquals(Operators.LESS_THAN)) {
result = lhs.isBefore(rhs);
} else if (operator.contentEquals(Operators.LESS_THAN_OR_EQUAL)) {
result = lhs.isBefore(rhs) || lhs.equals(rhs);
}
LOG.info("Compare: " + lhs + " " + operator + " " + rhs + " ==> " + result);
return result;
}
/**
* Time Comparator
* @param lhs Time to compare
@ -860,6 +958,57 @@ public class WebAPIServer_1_0_2 implements En {
return EdmDateTimeOffset.getInstance().valueOfString(edmDateTimeOffsetString, true, null, null, null, null, Date.class);
}
/***
* Tries to parse datePart from the given Object value
* @param datePart the timestamp part, "Year", "Month", "Day", etc. to try and parse
* @param value the value to try and parse
* @return the Integer portion of the date if successful, otherwise throws an Exception
* @exception throws an exception if value cannot be parsed into a date.
*/
private static Integer getDatePart(String datePart, Object value) throws EdmPrimitiveTypeException {
LocalDate date = LocalDate.parse(parseDateFromEdmDateString(value.toString()).toString());
switch (datePart) {
case DateParts.YEAR:
return date.getYear();
case DateParts.MONTH:
return date.getMonthValue();
case DateParts.DAY:
return date.getDayOfMonth();
default:
return null;
}
}
/***
* Tries to parse datePart from the given Object value
* @param timestampPart the timestamp part, "Year", "Month", "Day", etc. to try and parse
* @param value the value to try and parse
* @return the Integer portion of the date if successful, otherwise throws an Exception
*/
private static Integer getTimestampPart(String timestampPart, Object value) throws EdmPrimitiveTypeException {
//Turns nanoseconds into two most significant 2 digits for fractional comparisons
Integer ADJUSTMENT_FACTOR = 10000000;
OffsetDateTime offsetDateTime = OffsetDateTime.parse(value.toString());
if (timestampPart.equals(DateParts.YEAR)) {
return offsetDateTime.getYear();
} else if (timestampPart.equals(DateParts.MONTH)) {
return offsetDateTime.getMonthValue();
} else if (timestampPart.equals(DateParts.DAY)) {
return offsetDateTime.getDayOfMonth();
} else if (timestampPart.equals(DateParts.HOUR)) {
return offsetDateTime.getHour();
} else if (timestampPart.equals(DateParts.MINUTE)) {
return offsetDateTime.getMinute();
} else if (timestampPart.equals(DateParts.SECOND)) {
return offsetDateTime.getSecond();
} else if (timestampPart.equals(DateParts.FRACTIONAL)) {
return offsetDateTime.getNano() / ADJUSTMENT_FACTOR;
} else {
return null;
}
}
/**
* Converts the given inputStream to a string.
* @param inputStream the input stream to convert.