updated generic.resoscript, and also addded versioning. Added first test

This commit is contained in:
Joshua Darnell 2020-03-09 18:10:59 -07:00
parent 16c34664d0
commit 467c06ea6a
7 changed files with 343 additions and 127 deletions

View File

@ -454,10 +454,10 @@ A sample of the runtime terminal output follows:
```gherkin ```gherkin
> Task :testWebApiServer_1_0_2_Platinum > Task :testWebApiServer_1_0_2_Platinum
@REQ-WA103-END3 @core @2.4.1 @core-endorsement @metadata @REQ-WA103-END3 @core @x.y.z @core-endorsement @metadata
Scenario: Request and Validate Server Metadata Scenario: Request and Validate Server Metadata
Using RESOScript: /path/to/your.resoscript Using RESOScript: /path/to/your.resocript
Given a RESOScript file was provided Given a RESOScript file was provided
RESOScript loaded successfully! RESOScript loaded successfully!
@ -467,23 +467,26 @@ A sample of the runtime terminal output follows:
Service root is: https://api.server.com Service root is: https://api.server.com
And an OData client was successfully created from the given RESOScript And an OData client was successfully created from the given RESOScript
Fetching Edm with OData Client from: https://api.server.com/$metadata Request URI: https://api.server.com/$metadata?$format=application/xml
Found Default Entity Container: 'Default' Request succeeded...185032 bytes received.
When a default entity container exists for the service root in "ClientSettings_WebAPIURI" When a GET request is made to the resolved Url in "REQ-WA103-END3"
Asserted Response Code: 200, Server Response Code: 200 Asserted Response Code: 200, Server Response Code: 200
Then the server responds with a status code of 200 Then the server responds with a status code of 200
Edm Metadata is valid! Response is valid XML!
And the Edm metadata returned by the server are valid And the response is valid XML
Fetching XMLMetadata with OData Client from: https://api.server.com/$metadata
XML Metadata retrieved from: https://api.server.com
And XML Metadata are requested from the service root in "ClientSettings_WebAPIURI"
XML Metadata is valid! XML Metadata is valid!
And the XML metadata returned by the server are valid And the XML metadata returned by the server are valid
Fetching Edm with OData Client from: https://api.server.com/$metadata
Found Default Entity Container: 'Default'
And a default entity container exists for the service root in "ClientSettings_WebAPIURI"
Edm Metadata is valid!
And the Edm metadata returned by the server are valid
Found EntityContainer for the given resource: 'Property' Found EntityContainer for the given resource: 'Property'
And the metadata contains the "Parameter_EndpointResource" resource And the metadata contains the "Parameter_EndpointResource" resource
@ -500,9 +503,8 @@ A sample of the runtime terminal output follows:
1 Scenarios (1 passed) 1 Scenarios (1 passed)
10 Steps (10 passed) 11 Steps (11 passed)
0m3.071s 0m3.342s
``` ```
This shows configuration parameters, requests, and responses in a lightweight-manner. This shows configuration parameters, requests, and responses in a lightweight-manner.

Binary file not shown.

View File

@ -11,11 +11,17 @@
Contact josh@reso.org with further questions. Contact josh@reso.org with further questions.
--> -->
<!DOCTYPE OutputScript [ <!DOCTYPE OutputScript [
<!ELEMENT OutputScript (ClientSettings|Parameters|Requests)*> <!ELEMENT OutputScript (RESOScriptVersion|ClientSettings|Parameters|Requests)*>
<!ELEMENT ClientSettings (WebAPIURI|AuthenticationType|BearerToken|ClientScope|Version|Preauthenticate)*> <!ELEMENT RESOScriptVersion (#PCDATA)>
<!ELEMENT ClientSettings
(RESOScriptVersion|WebAPIURI|AuthenticationType|
BearerToken|ClientIdentification|ClientSecret|TokenURI|ClientScope|Version|Preauthenticate)*>
<!ELEMENT WebAPIURI (#PCDATA)> <!ELEMENT WebAPIURI (#PCDATA)>
<!ELEMENT AuthenticationType (#PCDATA)> <!ELEMENT AuthenticationType (#PCDATA)>
<!ELEMENT BearerToken (#PCDATA)> <!ELEMENT BearerToken (#PCDATA)>
<!ELEMENT ClientIdentification (#PCDATA)>
<!ELEMENT ClientSecret (#PCDATA)>
<!ELEMENT TokenURI (#PCDATA)>
<!ELEMENT ClientScope (#PCDATA)> <!ELEMENT ClientScope (#PCDATA)>
<!ELEMENT Version (#PCDATA)> <!ELEMENT Version (#PCDATA)>
<!ELEMENT Preauthenticate (#PCDATA)> <!ELEMENT Preauthenticate (#PCDATA)>
@ -36,60 +42,142 @@
WebAPIReference CDATA #REQUIRED> WebAPIReference CDATA #REQUIRED>
]> ]>
<!--
############################################################
TODO: this document will be updated with language
matching the OAuth 2.0 Specification and ClientSettings
will be removed.
See:
https://tools.ietf.org/html/rfc8252
Watch for subsequent changes to this file.
ClientSettings will be converted to Parameters forthwith.
############################################################-->
<OutputScript> <OutputScript>
<!-- TODO: deprecate ClientSettings and move them to Parameters -->
<!--
############################################################
Metadata
############################################################-->
<!-- The current version of this RESOScript -->
<RESOScriptVersion>1.0.4</RESOScriptVersion>
<!--
############################################################
Client Settings
TODO: deprecate ClientSettings and move them to Parameters
############################################################-->
<ClientSettings> <ClientSettings>
<!-- URLS --> <!-- URLS -->
<WebAPIURI><!--REQUIRED: URI of your Web API Service Root goes here --></WebAPIURI> <WebAPIURI><!--REQUIRED: URI of your Web API Service Root goes here --></WebAPIURI>
<!-- Credentials --> <!-- Credentials -->
<AuthenticationType>Authorization Code</AuthenticationType>
<BearerToken><!-- REQUIRED: Your BearerToken goes here --></BearerToken> <!-- AuthenticationType
<ClientScope>all</ClientScope>
<Version>Web API/1.0</Version> This is the OAuth2 grant_type.
<Preauthenticate>FALSE</Preauthenticate> Use "authorization_code" for BearerToken and "client_credentials" for Client Credentials.
See:
* https://www.oauth.com/oauth2-servers/access-tokens/authorization-code-request/
* https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/
-->
<AuthenticationType>authorization_code</AuthenticationType>
<!-- Grant Type: authorization_code-->
<BearerToken><!-- REQUIRED: Your BearerToken goes here if using Access Tokens --></BearerToken>
<!-- Grant Type: client_credentials -->
<ClientIdentification><!-- REQUIRED: Your client_id value if using Client Credentials--></ClientIdentification>
<ClientSecret><!-- REQUIRED: Your client_secret value if using Client Credentials--></ClientSecret>
<TokenURI><!-- REQUIRED: Your token endpoint URI--></TokenURI>
<ClientScope>
<!--OPTIONAL - your client scope. See: https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/ -->
</ClientScope>
</ClientSettings> </ClientSettings>
<!--
############################################################
Parameters Section - add your testing variables here
############################################################-->
<Parameters> <Parameters>
<!--
############################################################
Service Configuration
############################################################-->
<!-- REQUIRED: The DataSystems endpoint being tested <!-- REQUIRED: Core - The DataSystems endpoint being tested
NOTE: the FULL DataSystems URL is required as it might not be relative to the Service Root. NOTE: the FULL DataSystems URL is required as it might not be relative to the Service Root.
This will likely change in future revisions. --> This will likely change in future revisions. -->
<Parameter Name="EndpointDataSystem" Value="REQUIRED: YOUR DATA SYSTEMS ENDPOINT GOES HERE" /> <Parameter Name="EndpointDataSystem" Value="REQUIRED: YOUR DATA SYSTEMS ENDPOINT GOES HERE" />
<!-- REQUIRED: The name of the resource being tested --> <!-- REQUIRED: Core - The name of the resource being tested -->
<Parameter Name="EndpointResource" Value="REQUIRED: YOUR RESOURCE GOES HERE, FOR EXAMPLE 'Property'" /> <Parameter Name="EndpointResource" Value="REQUIRED: YOUR RESOURCE GOES HERE, FOR EXAMPLE 'Property'" />
<!-- HTTP Code Testing --> <!--
############################################################
Required Fields and Values
############################################################-->
<!-- REQUIRED: 200 Response OK --> <!-- Note: some of the required values already have sample values provided. See later sections for their values.-->
<Parameter Name="200_OK" Value="*Parameter_EndpointResource*" />
<!-- REQUIRED: 400 Bad Request - Requires Full URL & Separate Login Credentials --> <!-- REQUIRED: Core - Substitute key name from your Resource here, either Key or KeyNumeric -->
<Parameter Name="400BadRequest" Value="*Parameter_EndpointResource*?$filter=BadField eq 'SoBad'" />
<!-- REQUIRED: 403 Forbidden -->
<Parameter Name="403Forbidden" Value="Teams" />
<!-- REQUIRED: 404 Not Found -->
<Parameter Name="404NotFound" Value="ResourceNotFound" />
<!-- REQUIRED: 501 Not Implemented -->
<Parameter Name="501NotImplemented" Value="*Parameter_EndpointResource*?$search=red OR blue" />
<!-- REQUIRED: Substitute key name from your Resource here, either Key or KeyNumeric -->
<Parameter Name="KeyOrKeyNumericField" Value="ListingKey" /> <Parameter Name="KeyOrKeyNumericField" Value="ListingKey" />
<!-- REQUIRED: Provide a value for the KeyOrKeyNumeric from your server --> <!-- REQUIRED: Core - Provide a value for the KeyOrKeyNumeric from your server -->
<Parameter Name="KeyOrKeyNumericValue" Value="REQUIRED: YOUR KeyOrKeyNumericValue GOES HERE" /> <Parameter Name="KeyOrKeyNumericValue" Value="REQUIRED: YOUR KeyOrKeyNumericValue GOES HERE" />
<!-- For Top, Skip, and Sort Testing --> <!-- REQUIRED: Core - Integer Field. Should be one of: Type="Edm.Int16", Type="Edm.Int32", or Type="Edm.Int64" -->
<Parameter Name="TopCount" Value="5" />
<Parameter Name="SortCount" Value="20" />
<!-- Integer Field for eq, ne, gt, ge, lt, le testing -->
<!-- Type="Edm.Int16" or Type="Edm.Int32" or Type="Edm.Int64" for non-lookup fields -->
<Parameter Name="FilterIntegerField" Value="BedroomsTotal" /> <Parameter Name="FilterIntegerField" Value="BedroomsTotal" />
<!-- REQUIRED: Core - Enumerated Field for Single-Value Testing -->
<Parameter Name="SingleValueLookupField" Value="PropertyType" />
<Parameter Name="SingleLookupValue" Value="Residential" />
<Parameter Name="SingleValueLookupNamespace" Value="PropertyEnums.PropertyType" />
<!-- REQUIRED: Core - Enumerated Field for Multi-value testing -->
<Parameter Name="MultipleValueLookupField" Value="Appliances" />
<Parameter Name="MultipleValueLookupNamespace" Value="PropertyEnums.Appliances" />
<Parameter Name="MultipleLookupValue1" Value="Refrigerator" />
<Parameter Name="MultipleLookupValue2" Value="Stacked" />
<!-- REQUIRED: Bronze - Date Field for comparisons. Should be Type="Edm.Date" -->
<Parameter Name="DateField" Value="ListingContractDate" />
<Parameter Name="TimestampField" Value="ModificationTimestamp" />
<!-- REQUIRED: Platinum - String Field for comparisons. Should be Type="Edm.String" -->
<Parameter Name="StringField" Value="StreetName" />
<!-- REQUIRED: Platinum - Expand Testing -->
<Parameter Name="ExpandField" Value="ListAgent" />
<!-- REQUIRED: Platinum - GeoSpatial Testing -->
<Parameter Name="GeoSpatialLatitudeField" Value="Latitude" />
<Parameter Name="GeoSpatialLongitudeField" Value="Longitude" />
<Parameter Name="GeoSpatialField" Value="Coordinates" />
<Parameter Name="GeoSpatialValue" Value="REQUIRED: YOUR COORDINATES GO HERE in 'Longitude Latitude' format" /> <!-- "Longitude Latitude" -->
<!-- REQUIRED: New Fields for WS103 Testing -->
<Parameter Name="ValueField" Value="AboveGradeFinishedArea" />
<Parameter Name="CastField" Value="AboveGradeFinishedArea" />
<Parameter Name="CastFieldValue" Value="YOUR CastFieldValue GOES HERE, FOR EXAMPLE 1200" />
<Parameter Name="ConcatFieldOne" Value="StreetName" />
<Parameter Name="ConcatFieldOneValue" Value="REQUIRED: Your OneValue GOES HERE>" />
<Parameter Name="ConcatFieldTwo" Value="City" />
<Parameter Name="ConcatFieldTwoValue" Value="YOUR TwoValue GOES HERE" />
<Parameter Name="ConcatFieldBothValue" Value="Your 'OneValue: TwoValue' GOES HERE" /> <!-- format 'OneValue: TwoValue' -->
<!--
############################################################
Sample Field Values
############################################################-->
<!-- FilterIntegerField Sample Values-->
<Parameter Name="FilterIntegerValueLow" Value="9" /> <Parameter Name="FilterIntegerValueLow" Value="9" />
<Parameter Name="FilterIntegerValueHigh" Value="15" /> <Parameter Name="FilterIntegerValueHigh" Value="15" />
<Parameter Name="FilterIntegerNotFound" Value="-1" /> <Parameter Name="FilterIntegerNotFound" Value="-1" />
@ -99,71 +187,71 @@
<Parameter Name="FilterNotValue" Value="-1" /> <Parameter Name="FilterNotValue" Value="-1" />
<!-- Enumerated Field for "has" testing --> <!-- Enumerated Field for "has" testing -->
<Parameter Name="FilterHasField" Value="PropertyType" /> <Parameter Name="FilterHasField" Value="*Parameter_SingleValueLookupField*" />
<Parameter Name="FilterHasValue" Value="Residential" /> <Parameter Name="FilterHasValue" Value="*Parameter_SingleValueLookupValue*" />
<Parameter Name="FilterHasLookupNamespace" Value="PropertyEnums.PropertyType" /> <Parameter Name="FilterHasLookupNamespace" Value="*Parameter_SingleValueLookupNamespace*" />
<Parameter Name="FilterHasLookupValue" Value="*Parameter_FilterHasLookupNamespace*'*Parameter_FilterHasValue*'" /> <Parameter Name="FilterHasLookupValue" Value="*Parameter_FilterHasLookupNamespace*'*Parameter_FilterHasValue*'" />
<!-- Enumerated Field for SingleValue/Multi-value testing --> <!-- Platinum - String Fields for testing -->
<Parameter Name="SingleValueLookupField" Value="PropertyType" /> <Parameter Name="ContainsField" Value="*Parameter_StringField*" />
<Parameter Name="SingleLookupValue" Value="Residential" />
<Parameter Name="SingleValueLookupNamespace" Value="PropertyEnums.PropertyType" />
<Parameter Name="MultipleValueLookupField" Value="Appliances" />
<Parameter Name="MultipleValueLookupNamespace" Value="PropertyEnums.Appliances" />
<Parameter Name="MultipleLookupValue1" Value="Refrigerator" />
<Parameter Name="MultipleLookupValue2" Value="Stacked" />
<!-- For Expand Testing -->
<Parameter Name="ExpandField" Value="ListAgent" />
<!-- For Geo-spatial Testing -->
<Parameter Name="GeoSpatialLatitudeField" Value="Latitude" />
<Parameter Name="GeoSpatialLongitudeField" Value="Longitude" />
<Parameter Name="GeoSpatialField" Value="Coordinates" />
<Parameter Name="GeoSpatialValue" Value="REQUIRED: YOUR COORDINATES GO HERE in 'Longitude Latitude' format" /> <!-- "Longitude Latitude" -->
<Parameter Name="GeoSpatialDistanceValue" Value="100" />
<!--String Fields for testing -->
<!-- Type="Edm.String" -->
<Parameter Name="ContainsField" Value="StreetName" />
<Parameter Name="ContainsValue" Value="M" /> <Parameter Name="ContainsValue" Value="M" />
<Parameter Name="EndsWithField" Value="StreetName" /> <Parameter Name="EndsWithField" Value="*Parameter_StringField*" />
<Parameter Name="EndsWithValue" Value="Rd" /> <Parameter Name="EndsWithValue" Value="Rd" />
<Parameter Name="StartsWithField" Value="StreetName" /> <Parameter Name="StartsWithField" Value="*Parameter_StringField*" />
<Parameter Name="StartsWithValue" Value="M" /> <Parameter Name="StartsWithValue" Value="M" />
<Parameter Name="ToLowerField" Value="StreetName" /> <Parameter Name="ToLowerField" Value="*Parameter_StringField*" />
<Parameter Name="ToLowerValue" Value="main" /> <Parameter Name="ToLowerValue" Value="main" />
<Parameter Name="ToUpperField" Value="StreetName" /> <Parameter Name="ToUpperField" Value="*Parameter_StringField*" />
<Parameter Name="ToUpperValue" Value="MAIN" /> <Parameter Name="ToUpperValue" Value="MAIN" />
<!-- REQUIRED: Date Fields for testing --> <!-- Gold and Platinum: Date Fields for testing -->
<Parameter Name="DateField" Value="ListingContractDate" />
<Parameter Name="DateTimeValue" Value="2018-12-31T23:55:55-09:00" /> <Parameter Name="DateTimeValue" Value="2018-12-31T23:55:55-09:00" />
<Parameter Name="DateValue" Value="2018-12-31" /> <Parameter Name="DateValue" Value="2018-12-31" />
<Parameter Name="YearValue" Value="2018" /> <Parameter Name="YearValue" Value="2018" />
<Parameter Name="MonthValue" Value="12" /> <Parameter Name="MonthValue" Value="12" />
<Parameter Name="DayValue" Value="31" /> <Parameter Name="DayValue" Value="31" />
<Parameter Name="TimestampField" Value="ModificationTimestamp" />
<Parameter Name="TimeValue" Value="23:55:55" /> <Parameter Name="TimeValue" Value="23:55:55" />
<Parameter Name="HourValue" Value="23" /> <Parameter Name="HourValue" Value="23" />
<Parameter Name="MinuteValue" Value="55" /> <Parameter Name="MinuteValue" Value="55" />
<Parameter Name="SecondValue" Value="55" /> <Parameter Name="SecondValue" Value="55" />
<Parameter Name="FractionalValue" Value="30" /> <Parameter Name="FractionalValue" Value="30" />
<!-- REQUIRED: New Fields for WS103 Testing --> <!-- Platinum - GeoSpatial query values -->
<Parameter Name="ValueField" Value="AboveGradeFinishedArea" /> <Parameter Name="GeoSpatialDistanceValue" Value="100" />
<Parameter Name="CastField" Value="AboveGradeFinishedArea" />
<Parameter Name="CastFieldType" Value="Edm.String" />
<Parameter Name="CastFieldValue" Value="YOUR CastFieldValue GOES HERE, FOR EXAMPLE 1200" />
<Parameter Name="ConcatFieldOne" Value="StreetName" />
<Parameter Name="ConcatFieldOneValue" Value="YOUR OneValue GOES HERE>" />
<Parameter Name="ConcatFieldTwo" Value="City" />
<Parameter Name="ConcatFieldTwoValue" Value="YOUR TwoValue GOES HERE" />
<Parameter Name="ConcatFieldBothValue" Value="Your 'OneValue: TwoValue' GOES HERE" /> <!-- format 'OneValue: TwoValue' -->
<!-- Computed OData $select list - do not change --> <!--
############################################################
HTTP Code Testing
############################################################-->
<!-- 200 Response OK: This should always work! No need to change it -->
<Parameter Name="200_OK" Value="*Parameter_EndpointResource*" />
<!-- REQUIRED: 400 Bad Request - Adjust to something that produces a 400 response if this doesn't work -->
<Parameter Name="400BadRequest" Value="*Parameter_EndpointResource*?$filter=BadField eq 'SoBad'" />
<!-- REQUIRED: 403 Forbidden - Set this to a restricted resource for the given credentials -->
<Parameter Name="403Forbidden" Value="Teams" />
<!-- REQUIRED: 404 Not Found - You shouldn't need to change this -->
<Parameter Name="404NotFound" Value="ResourceNotFound" />
<!-- REQUIRED: 501 Not Implemented - Set this to an OData query that hasn't been implemented on your server -->
<Parameter Name="501NotImplemented" Value="*Parameter_EndpointResource*?$search=red OR blue" />
<!--
############################################################
Constants and Computed Values - Do Not Change
############################################################-->
<!-- For Top, Skip, and Sort Testing -->
<Parameter Name="TopCount" Value="5" />
<Parameter Name="SortCount" Value="20" />
<!-- New Values for WS103 Testing -->
<Parameter Name="CastFieldType" Value="Edm.String" />
<!-- Computed OData $select list -->
<Parameter Name="SelectList" <Parameter Name="SelectList"
Value="*Parameter_KeyOrKeyNumericField*,*Parameter_FilterIntegerField*,*Parameter_ContainsField*,*Parameter_FilterHasField*,*Parameter_DateField*" /> Value="*Parameter_KeyOrKeyNumericField*,*Parameter_FilterIntegerField*,*Parameter_ContainsField*,*Parameter_FilterHasField*,*Parameter_DateField*" />
@ -172,19 +260,21 @@
<Parameter Name="MultipleValueLookupValue1" Value="*Parameter_MultipleValueLookupNamespace*'*Parameter_MultipleLookupValue1*'"/> <Parameter Name="MultipleValueLookupValue1" Value="*Parameter_MultipleValueLookupNamespace*'*Parameter_MultipleLookupValue1*'"/>
<Parameter Name="MultipleValueLookupValue2" Value="*Parameter_MultipleValueLookupNamespace*'*Parameter_MultipleLookupValue2*'" /> <Parameter Name="MultipleValueLookupValue2" Value="*Parameter_MultipleValueLookupNamespace*'*Parameter_MultipleLookupValue2*'" />
<Parameter Name="OptionalMetadataFormatParameter" Value="?$format=application/xml" />
<!--
############################################################
Optional Parameters. You should not need these
############################################################-->
<!-- OPTIONAL: System Specific Additional Required Parameters for Queries. Leave Blank if none. --> <!-- OPTIONAL: System Specific Additional Required Parameters for Queries. Leave Blank if none. -->
<Parameter Name="RequiredParameters" Value="" /> <Parameter Name="RequiredParameters" Value="" />
<Parameter Name="RequiredParametersFilter" Value="" /> <Parameter Name="RequiredParametersFilter" Value="" />
<!-- Note: you may need to use Value="?$format=application/xml" on your server -->
<Parameter Name="OptionalMetadataFormatParameter" Value="" />
</Parameters> </Parameters>
<Requests> <Requests>
<!-- NOTE: the query in this test is no longer being used for automated testing,
was originally: Url="*ClientSettings_WebAPIURI*/$metadata*Parameter_OptionalMetadataFormatParameter*"-->
<Request <Request
TestDescription="Metadata Endpoint" TestDescription="Metadata Endpoint"
RequirementId="REQ-WA103-END3" RequirementId="REQ-WA103-END3"
@ -192,7 +282,7 @@
Capability="Core" Capability="Core"
WebAPIReference="" WebAPIReference=""
OutputFile="REQ-WA103-END3.metadata.xml" OutputFile="REQ-WA103-END3.metadata.xml"
Url="" Url="*ClientSettings_WebAPIURI*/$metadata*Parameter_OptionalMetadataFormatParameter*"
/> />
<Request <Request

View File

@ -8,11 +8,12 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-END3 @core @x.y.z @core-endorsement @metadata @REQ-WA103-END3 @core @x.y.z @core-endorsement @metadata
Scenario: Request and Validate Server Metadata Scenario: Request and Validate Server Metadata
When a default entity container exists for the service root in "ClientSettings_WebAPIURI" When a GET request is made to the resolved Url in "REQ-WA103-END3"
Then the server responds with a status code of 200 Then the server responds with a status code of 200
And the Edm metadata returned by the server are valid And the response is valid XML
And XML Metadata are requested from the service root in "ClientSettings_WebAPIURI"
And the XML metadata returned by the server are valid And the XML metadata returned by the server are valid
And a default entity container exists for the service root in "ClientSettings_WebAPIURI"
And the Edm metadata returned by the server are valid
And the metadata contains the "Parameter_EndpointResource" resource And the metadata contains the "Parameter_EndpointResource" resource
And resource metadata for "Parameter_EndpointResource" contains the fields in "Parameter_SelectList" And resource metadata for "Parameter_EndpointResource" contains the fields in "Parameter_SelectList"
@ -369,3 +370,13 @@ Feature: Web API Server 1.0.2 Certification
And the response has results And the response has results
And String data in "Parameter_ToUpperField" "toupper" "Parameter_ToUpperValue" And String data in "Parameter_ToUpperField" "toupper" "Parameter_ToUpperValue"
@REQ-WA103-QO29 @platinum @2.4.4 @expandability-endorsement
Scenario: Query Support: $expand
When a GET request is made to the resolved Url in "REQ-WA103-QO29"
Then the server responds with a status code of 200
And the response is valid JSON
And the response has results
And data are present in fields contained within "Parameter_SelectList"
And data are present within "Parameter_ExpandField"
And an OData NavigationProperty exists for the given "Parameter_EndpointResource"
And the expanded data were found in the related resource

View File

@ -4,26 +4,27 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.POJONode; import com.fasterxml.jackson.databind.node.POJONode;
import io.cucumber.java8.En; import io.cucumber.java8.En;
import io.restassured.response.Response;
import io.restassured.response.ValidatableResponse;
import io.restassured.specification.RequestSpecification;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.olingo.client.api.communication.ODataClientErrorException; import org.apache.olingo.client.api.communication.ODataClientErrorException;
import org.apache.olingo.client.api.communication.request.retrieve.ODataRawRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataRawRequest;
import org.apache.olingo.client.api.communication.response.ODataRawResponse; import org.apache.olingo.client.api.communication.response.ODataRawResponse;
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
import org.apache.olingo.client.api.domain.ClientEntitySet;
import org.apache.olingo.client.api.edm.xml.XMLMetadata; import org.apache.olingo.client.api.edm.xml.XMLMetadata;
import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer; import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlProperty; import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
import org.apache.olingo.commons.api.format.ContentType;
import org.reso.commander.Commander; import org.reso.commander.Commander;
import org.reso.commander.TestUtils; import org.reso.commander.TestUtils;
import org.reso.models.ClientSettings; import org.reso.models.ClientSettings;
import org.reso.models.Request; import org.reso.models.Request;
import org.reso.models.Settings; import org.reso.models.Settings;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.net.URI; import java.net.URI;
import java.sql.Time; import java.sql.Time;
@ -44,21 +45,45 @@ import static org.reso.commander.TestUtils.Operators.*;
public class WebAPIServer_1_0_2 implements En { public class WebAPIServer_1_0_2 implements En {
private static final Logger LOG = LogManager.getLogger(WebAPIServer_1_0_2.class); private static final Logger LOG = LogManager.getLogger(WebAPIServer_1_0_2.class);
private static Settings settings; private static Settings settings;
//container to hold retrieved metadata for later comparisons //container to hold retrieved metadata for later comparisons
private static AtomicReference<XMLMetadata> xmlMetadata = new AtomicReference<>(); private static AtomicReference<XMLMetadata> xmlMetadata = new AtomicReference<>();
private static AtomicReference<Edm> edm = new AtomicReference<>(); private static AtomicReference<Edm> edm = new AtomicReference<>();
private Response response;
private ValidatableResponse json;
private RequestSpecification request;
private String serviceRoot, bearerToken, clientId, clientSecret, authorizationUri, tokenUri, redirectUri, scope; private String serviceRoot, bearerToken, clientId, clientSecret, authorizationUri, tokenUri, redirectUri, scope;
private String pathToRESOScript; private String pathToRESOScript;
/**
* Accessors used for running one-off tests that have dependent metadata tests
* @param commander the commander instance to make the request with.
* @return the XMLMetadata for the given request.
*/
private static XMLMetadata getXMLMetadata(Commander commander) {
if (xmlMetadata.get() == null) {
xmlMetadata.set(commander.getXMLMetadata());
}
return xmlMetadata.get();
}
/**
* Accessors used for running one-off tests that have dependent metadata tests
* @param commander the commander instance to make the request with.
* @return the Edm for the given request.
*/
private static Edm getEdmMetadata(Commander commander) {
if (edm.get() == null) {
edm.set(commander.getEdm());
}
return edm.get();
}
public WebAPIServer_1_0_2() { public WebAPIServer_1_0_2() {
//TODO: split into separate test files and parallelize to remove the need for Atomic "globals" //TODO: split into separate test files and parallelize to remove the need for Atomic "globals"
AtomicReference<Commander> commander = new AtomicReference<>(); AtomicReference<Commander> commander = new AtomicReference<>();
AtomicReference<ODataRawResponse> oDataRawResponse = new AtomicReference<>(); AtomicReference<ODataRawResponse> oDataRawResponse = new AtomicReference<>();
AtomicReference<Request> request = new AtomicReference<>(); AtomicReference<Request> request = new AtomicReference<>();
AtomicReference<URI> requestUri = new AtomicReference<>();
AtomicReference<Integer> responseCode = new AtomicReference<>(); AtomicReference<Integer> responseCode = new AtomicReference<>();
AtomicReference<String> responseData = new AtomicReference<>(); AtomicReference<String> responseData = new AtomicReference<>();
AtomicReference<String> initialResponseData = new AtomicReference<>(); //used if two result sets need to be compared AtomicReference<String> initialResponseData = new AtomicReference<>(); //used if two result sets need to be compared
@ -98,10 +123,10 @@ public class WebAPIServer_1_0_2 implements En {
* Executes HTTP GET request and sets the expected local variables. * Executes HTTP GET request and sets the expected local variables.
* Handles exceptions and sets response codes. * Handles exceptions and sets response codes.
*/ */
Function<URI, Void> executeGetRequest = (URI requestUri) -> { Function<URI, Void> executeGetRequest = (URI uri) -> {
LOG.info("Request URI: " + requestUri); LOG.info("Request URI: " + uri);
try { try {
rawRequest.set(commander.get().getClient().getRetrieveRequestFactory().getRawRequest(requestUri)); rawRequest.set(commander.get().getClient().getRetrieveRequestFactory().getRawRequest(uri));
oDataRawResponse.set(rawRequest.get().execute()); oDataRawResponse.set(rawRequest.get().execute());
responseData.set(TestUtils.convertInputStreamToString(oDataRawResponse.get().getRawResponse())); responseData.set(TestUtils.convertInputStreamToString(oDataRawResponse.get().getRawResponse()));
serverODataHeaderVersion.set(oDataRawResponse.get().getHeader(HEADER_ODATA_VERSION).toString()); serverODataHeaderVersion.set(oDataRawResponse.get().getHeader(HEADER_ODATA_VERSION).toString());
@ -204,9 +229,12 @@ public class WebAPIServer_1_0_2 implements En {
* XMLMetadata Validator * XMLMetadata Validator
*/ */
And("^the XML metadata returned by the server are valid$", () -> { And("^the XML metadata returned by the server are valid$", () -> {
assertNotNull("ERROR: No XML Metadata Exists!", xmlMetadata.get()); assertNotNull("ERROR: No Response Data exists to convert to XML Metadata!", responseData.get());
try { try {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(responseData.get().getBytes());
xmlMetadata.set(commander.get().getClient().getDeserializer(ContentType.APPLICATION_XML).toMetadata(byteArrayInputStream));
boolean isValid = commander.get().validateMetadata(xmlMetadata.get()); boolean isValid = commander.get().validateMetadata(xmlMetadata.get());
LOG.info("XML Metadata is " + (isValid ? "valid" : "invalid") + "!"); LOG.info("XML Metadata is " + (isValid ? "valid" : "invalid") + "!");
assertTrue(isValid); assertTrue(isValid);
@ -316,9 +344,9 @@ public class WebAPIServer_1_0_2 implements En {
initialResponseData.set(responseData.get()); initialResponseData.set(responseData.get());
//TODO: convert to OData filter factory //TODO: convert to OData filter factory
URI requestUri = Commander.prepareURI(Settings.resolveParameters(settings.getRequests().get(requirementId), settings).getUrl() + "&$skip=" + skipCount); requestUri.set(Commander.prepareURI(Settings.resolveParameters(settings.getRequests().get(requirementId), settings).getUrl() + "&$skip=" + skipCount));
executeGetRequest.apply(requestUri); executeGetRequest.apply(requestUri.get());
} catch (Exception ex) { } catch (Exception ex) {
fail(ex.getMessage()); fail(ex.getMessage());
} }
@ -353,8 +381,8 @@ public class WebAPIServer_1_0_2 implements En {
//reset local state each time a get request is run //reset local state each time a get request is run
resetRequestState.run(); resetRequestState.run();
URI requestUri = Commander.prepareURI(Settings.resolveParameters(settings.getRequests().get(requirementId), settings).getUrl()); requestUri.set(Commander.prepareURI(Settings.resolveParameters(settings.getRequests().get(requirementId), settings).getUrl()));
executeGetRequest.apply(requestUri); executeGetRequest.apply(requestUri.get());
} catch (Exception ex) { } catch (Exception ex) {
LOG.debug("Exception was thrown in " + this.getClass() + ": " + ex.toString()); LOG.debug("Exception was thrown in " + this.getClass() + ": " + ex.toString());
} }
@ -861,5 +889,61 @@ public class WebAPIServer_1_0_2 implements En {
fail(ex.getMessage()); fail(ex.getMessage());
} }
}); });
/*
* Tests whether a navigation property can be found in the given resource name.
*/
And("^an OData NavigationProperty exists for the given \"([^\"]*)\"$", (String parameterEndpointResource) -> {
String resourceName = Settings.resolveParametersString(parameterEndpointResource, settings);
List<CsdlNavigationProperty> navigationProperties
= TestUtils.findNavigationPropertiesForEntityTypeName(getEdmMetadata(commander.get()), getXMLMetadata(commander.get()), resourceName);
assertTrue("ERROR: no navigation properties found for the given '" + resourceName + "' resource!",
navigationProperties.size() > 0);
LOG.info("Found the following Navigation Properties:");
navigationProperties.forEach(csdlNavigationProperty -> {
LOG.info("\tName: " + csdlNavigationProperty.getName());
LOG.info("\tType: " + csdlNavigationProperty.getType());
});
});
/*
* Checks to see whether the expanded field has data
*/
And("^data are present within \"([^\"]*)\"$", (String parameterExpandField) -> {
String expandField = Settings.resolveParametersString(parameterExpandField, settings);
assertFalse("ERROR: no expand field found for " + parameterExpandField, expandField.isEmpty());
ClientEntitySet results = commander.get().getClient().getRetrieveRequestFactory().getEntitySetRequest(requestUri.get()).execute().getBody();
LOG.info("Results count is: " + results.getEntities().size());
AtomicInteger counter = new AtomicInteger();
results.getEntities().forEach(clientEntity -> {
LOG.info("\nItem #" + counter.getAndIncrement());
clientEntity.getProperties().forEach(clientProperty -> {
LOG.info("\tField Name: " + clientProperty.getName());
LOG.info("\tField Value: " + clientProperty.getValue().toString());
LOG.info("\tType Name: " + clientProperty.getValue().getTypeName());
LOG.info("\n");
assertNotNull("ERROR: '" + parameterExpandField + "' not found in results!", clientProperty.getName());
assertNotNull("ERROR: data type could not be found for " + clientProperty.getName(), clientProperty.getValue().getTypeName());
});
});
});
/*
* Checks to see whether expanding the EndpointResource on ExpandField produces equivalent records from the corresponding
* resource of the expanded type
*/
And("^the expanded data were found in the related resource$", () -> {
//TODO: this depends on either finding the appropriate navigation property for a given relationship, or having the Expanded resource name
});
} }
} }

View File

@ -188,7 +188,7 @@ public class Commander {
*/ */
public Edm getEdm() { public Edm getEdm() {
if (edm == null) { if (edm == null) {
getODataRetrieveEdmResponse().getBody(); edm = getODataRetrieveEdmResponse().getBody();
} }
return edm; return edm;
} }
@ -199,9 +199,12 @@ public class Commander {
* @return XMLMetadata representation of the server metadata. * @return XMLMetadata representation of the server metadata.
*/ */
public XMLMetadata getXMLMetadata() { public XMLMetadata getXMLMetadata() {
if (xmlMetadata == null) {
EdmMetadataRequest metadataRequest = client.getRetrieveRequestFactory().getMetadataRequest(serviceRoot); EdmMetadataRequest metadataRequest = client.getRetrieveRequestFactory().getMetadataRequest(serviceRoot);
LOG.info("Fetching XMLMetadata with OData Client from: " + metadataRequest.getURI().toString()); LOG.info("Fetching XMLMetadata with OData Client from: " + metadataRequest.getURI().toString());
return metadataRequest.getXMLMetadata(); xmlMetadata = metadataRequest.getXMLMetadata();
}
return xmlMetadata;
} }
/** /**
@ -434,6 +437,10 @@ public class Commander {
return getEntitySet(requestUri, limit, integerVoidFunction); return getEntitySet(requestUri, limit, integerVoidFunction);
} }
public ClientEntitySet getEntitySet(String requestUri) {
return getEntitySet(requestUri, 1);
}
/** /**
* Fairly primitive, for now, version of a fetch function. * Fairly primitive, for now, version of a fetch function.
* TODO: add a function that can write a page at a time. * TODO: add a function that can write a page at a time.
@ -458,7 +465,6 @@ public class Commander {
if (requestUri != null && requestUri.length() > 0 && preparedUri != null) { if (requestUri != null && requestUri.length() > 0 && preparedUri != null) {
uriBuilder = new URIBuilder(preparedUri); uriBuilder = new URIBuilder(preparedUri);
if (uriBuilder != null) {
if (skip != null && skip > 0) uriBuilder.addParameter("$skip", skip.toString()); if (skip != null && skip > 0) uriBuilder.addParameter("$skip", skip.toString());
URI uri = uriBuilder.build(); URI uri = uriBuilder.build();
@ -466,7 +472,6 @@ public class Commander {
return uri; return uri;
} }
}
} catch (Exception ex) { } catch (Exception ex) {
LOG.error("ERROR: " + ex.toString()); LOG.error("ERROR: " + ex.toString());
} }
@ -495,7 +500,7 @@ public class Commander {
} catch (Exception ex) { } catch (Exception ex) {
//NOTE: sometimes a bad skip link in the payload can cause exceptions...the Olingo library validates the responses. //NOTE: sometimes a bad skip link in the payload can cause exceptions...the Olingo library validates the responses.
LOG.error("ERROR: getEntitySet could not continue. " + ex.getCause()); LOG.error("ERROR: getEntitySet could not continue. " + ex.toString());
System.exit(NOT_OK); System.exit(NOT_OK);
} finally { } finally {
//trim results size to requested limit //trim results size to requested limit

View File

@ -9,6 +9,7 @@ import org.apache.olingo.client.api.edm.xml.XMLMetadata;
import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer; import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlProperty; import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlSchema; import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
import org.apache.olingo.commons.core.edm.primitivetype.EdmDate; import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
@ -80,6 +81,29 @@ public final class TestUtils {
return schemaForType.getEntityType(entityTypeName).getProperties(); return schemaForType.getEntityType(entityTypeName).getProperties();
} }
/**
* Gets a list of CsdlProperty items for the given entityTypeName.
*
* @param xmlMetadata the metadata to search.
* @param entityTypeName the name of the entityType to search for. MUST be in the default EntityContainer.
* @return a list of CsdlProperty items for the given entityTypeName
* @throws Exception is thrown if the given metadata doesn't contain the given type name.
*/
public static List<CsdlNavigationProperty> findNavigationPropertiesForEntityTypeName(Edm edm, XMLMetadata xmlMetadata, String entityTypeName) {
assertNotNull("ERROR: Edm Cannot be Null!", edm);
assertNotNull("ERROR: XMLMetadata Cannot be Null!", xmlMetadata);
assertNotNull("ERROR: entityTypeName cannot be null!", entityTypeName);
CsdlEntityContainer entityContainer = findDefaultEntityContainer(edm, xmlMetadata);
assertNotNull("ERROR: could not find a default entity container for the given server!", entityContainer);
CsdlSchema schemaForType = xmlMetadata.getSchema(entityContainer.getEntitySet(entityTypeName).getTypeFQN().getNamespace());
assertNotNull("ERROR: could not find type corresponding to given type name: " + entityTypeName, schemaForType);
return schemaForType.getEntityType(entityTypeName).getNavigationProperties();
}
/** /**
* Returns true if each item in the list is true * Returns true if each item in the list is true
* *