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.

File diff suppressed because it is too large Load Diff

View File

@ -244,4 +244,84 @@ Feature: Web API Server 1.0.2 Certification
Then the server responds with a status code of 200 Then the server responds with a status code of 200
And the response is valid JSON And the response is valid JSON
And the response has results And the response has results
And DateTimeOffset data in "Parameter_TimestampField" is sorted in "desc" order 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.net.URI;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.Instant; import java.time.*;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -500,6 +500,11 @@ public class WebAPIServer_1_0_2 implements En {
}); });
}); });
/*
* Year comparison glue
*/
/* /*
* Timestamp 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"; 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 { private static class Utils {
/** /**
@ -708,6 +778,34 @@ public class WebAPIServer_1_0_2 implements En {
return result; 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 * Time Comparator
* @param lhs Time to compare * @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); 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. * Converts the given inputStream to a string.
* @param inputStream the input stream to convert. * @param inputStream the input stream to convert.