Merge pull request #20 from RESOStandards/issue-19-fail-all-if-metadata-fails

Issue #19 fail all if metadata fails
This commit is contained in:
dgmyrek 2020-04-16 13:48:02 -05:00 committed by GitHub
commit 59c409d37d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1749 additions and 358 deletions

View File

@ -20,7 +20,13 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Cache Gradle packages
uses: actions/cache@v1
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
- name: Build and Run acceptance tests
run: ./gradlew build

View File

@ -42,6 +42,8 @@ dependencies {
compile 'com.networknt:json-schema-validator:1.0.35'
implementation 'org.mockito:mockito-core:3.3.3'
}
configurations {
@ -91,7 +93,8 @@ task testWebApiServer_1_0_2_Gold() {
'org.reso.certification.stepdefs#WebAPIServer_1_0_2',
'src/main/java/org/reso/certification/features/web-api',
'--tags',
(systemProperties.get('cucumber.filter.tags', '').toString().trim().length() > 0 ? 'not @platinum and ' + systemProperties.get('cucumber.filter.tags') : 'not @platinum')
(systemProperties.get('cucumber.filter.tags', '').toString().trim().length() > 0
? 'not @platinum and ' + systemProperties.get('cucumber.filter.tags') : 'not @platinum')
]
}
}
@ -141,7 +144,8 @@ task testDataDictionary_1_5() {
'org.reso.certification.stepdefs#DataDictionary',
'src/main/java/org/reso/certification/features/data-dictionary',
'--tags',
(systemProperties.get('cucumber.filter.tags', '').toString().trim().length() > 0 ? '@DD1.5 and ' + systemProperties.get('cucumber.filter.tags') : '@DD1.5')
(systemProperties.get('cucumber.filter.tags', '').toString().trim().length() > 0
? '@DD1.5 and ' + systemProperties.get('cucumber.filter.tags') : '@DD1.5')
]
}
}
@ -167,7 +171,27 @@ task testDataDictionary_1_6() {
'org.reso.certification.stepdefs#DataDictionary',
'src/main/java/org/reso/certification/features/data-dictionary',
'--tags',
(systemProperties.get('cucumber.filter.tags', '').toString().trim().length() > 0 ? '@DD1.6 and ' + systemProperties.get('cucumber.filter.tags') : '@DD1.6')
(systemProperties.get('cucumber.filter.tags', '').toString().trim().length() > 0
? '@DD1.6 and ' + systemProperties.get('cucumber.filter.tags') : '@DD1.6')
]
}
}
}
//used for internal Commander testing
test {
dependsOn assemble, compileTestJava
doLast {
javaexec {
main = "io.cucumber.core.cli.Main"
systemProperties = System.getProperties()
classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
args = ['--strict',
'--plugin',
'pretty',
'--glue',
'org.reso.commander.test.stepdefs',
'src/test/java/org/reso/commander/test/features'
]
}
}

Binary file not shown.

View File

@ -20,10 +20,8 @@ Feature: Web API Server 1.0.2 Certification
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
And the XML Metadata response is valid XML
And the XML metadata returned by the server are valid
And Edm metadata are requested from the service root in "ClientSettings_WebAPIURI"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
And the XML Metadata returned by the server are valid
And the XML Metadata returned by the server contains Edm metadata
And the Edm metadata returned by the server are valid
And the metadata contains a valid service document
And the given "Parameter_EndpointResource" resource exists within "Parameter_DD17_WellKnownResourceList"
@ -32,6 +30,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-END2 @core @2.4.1 @core-endorsement @datasystem
Scenario: REQ-WA103-END2 - Data System Endpoint test
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-END2"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -41,6 +40,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QR1 @core @2.4.1 @query-functions-endorsement
Scenario: REQ-WA103-QR1 - Search Parameters: Select KeyOrKeyNumeric Field
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QR1"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -50,6 +50,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QR3 @core @2.4.2 @query-functions-endorsement
Scenario: REQ-WA103-QR3 - Query Support: $select
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QR3"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -60,6 +61,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QR4 @core @2.4.2 @client-paging-endorsement
Scenario: REQ-WA103-QR4 - Query Support: $top
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QR4"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -71,6 +73,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QR5 @core @2.4.2 @query-support-endorsement
Scenario: REQ-WA103-QR5 - Query Support: $skip
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QR5"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -89,6 +92,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO1.1 @core @2.4.4 @core-endorsement @OData-4.0
Scenario: REQ-WA103-QO1.1 - Query Support: $select case-sensitivity for OData 4.0
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO1.1"
And the server has an OData-Version header value of "4.0" or "4.01"
Then the server responds with a status code of 400 if the server reports OData-Version "4.0"
@ -96,6 +100,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO1.2 @core @2.4.4 @core-endorsement @OData-4.0
Scenario: REQ-WA103-QO1.2 - Query Support: $filter case-sensitivity for OData 4.0
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO1.2"
And the server has an OData-Version header value of "4.0" or "4.01"
Then the server responds with a status code of 400 if the server reports OData-Version "4.0"
@ -103,6 +108,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO1.3 @core @2.4.4 @core-endorsement @OData-4.0
Scenario: REQ-WA103-QO1.3 - Query Support: $orderby asc case-sensitivity for OData 4.0
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO1.3"
And the server has an OData-Version header value of "4.0" or "4.01"
Then the server responds with a status code of 400 if the server reports OData-Version "4.0"
@ -110,6 +116,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO1.4 @core @2.4.4 @core-endorsement @OData-4.0
Scenario: REQ-WA103-QO1.4 - Query Support: $orderby desc case-sensitivity for OData 4.0
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO1.4"
And the server has an OData-Version header value of "4.0" or "4.01"
Then the server responds with a status code of 400 if the server reports OData-Version "4.0"
@ -117,6 +124,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO2 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO2 - Query Support: $filter - Integer Comparison: eq
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO2"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -128,6 +136,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO3 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO3 - Query Support: $filter - Integer Comparison: ne
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO3"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -139,6 +148,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO4 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO4 - Query Support: $filter - Integer Comparison: gt
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO4"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -150,6 +160,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO5 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO5 - Query Support: $filter - Integer Comparison: ge
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO5"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -161,6 +172,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO6 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO6 - Query Support: $filter - Integer Comparison: lt
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO6"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -172,6 +184,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO7 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO7 - Query Support: $filter - Integer Comparison: le
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO7"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -183,6 +196,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO9 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO9 - Query Support: $filter - Integer Comparison: and
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO9"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -194,6 +208,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO10 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO10 - Query Support: $filter - Integer Comparison: or
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO10"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -205,6 +220,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO11 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO11 - Query Support: $filter - Integer Comparison: not() (operator)
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO11"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -216,6 +232,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO25 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO25 - Query Support: $filter: Date portion of EdmDateTimeOffset field is greater than EdmDate value
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO25"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -227,6 +244,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO26 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO26 - Query Support: $filter: Time portion of EdmDateTimeOffset field is less than EdmTime value
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO26"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -238,6 +256,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO26.2 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO26.2 - Query Support: $filter: Date: EdmDateTimeOffset field is less than EdmDateTimeOffset value
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO26.2"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -249,6 +268,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO27 @core @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO27 - Query Support: $filter: DateTimeOffset le now()
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO27"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -265,27 +285,33 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-END1 @core @2.4.1 @core-endorsement
Scenario: REQ-WA103-END1 - Service Endpoint
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-END1"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@REQ-WA103-RC3 @core @2.5.2 @core-endorsement
Scenario: REQ-WA103-RC3 - 200 OK Request
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-RC3"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@REQ-WA103-RC5 @core @2.4.2 @core-endorsement
Scenario: REQ-WA103-RC5 - 400 Bad Request
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-RC5"
Then the server responds with a status code of 400
And the server has an OData-Version header value of "4.0" or "4.01"
# Disable this check for now until Olingo-1380 is fixed - see: https://issues.apache.org/jira/browse/OLINGO-1380
# And the server has an OData-Version header value of "4.0" or "4.01"
@REQ-WA103-RC07 @core @2.5.2 @core-endorsement
Scenario: REQ-WA103-RC07 - 404 Not Found Request
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-RC07"
Then the server responds with a status code of 404
And the server has an OData-Version header value of "4.0" or "4.01"
# Disable this check for now until Olingo-1380 is fixed - see: https://issues.apache.org/jira/browse/OLINGO-1380
# And the server has an OData-Version header value of "4.0" or "4.01"
#######################################
# Bronze Tests
@ -293,6 +319,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QM7 @bronze @2.4.9 @filterability-endorsement
Scenario: REQ-WA103-QM7 - Support Single Value Lookups
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QM7"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -304,6 +331,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QM8 @bronze @2.4.10 @filterability-endorsement
Scenario: REQ-WA103-QM8 - Support Multi Value Lookups
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QM8"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -315,6 +343,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QM8.2 @bronze @2.4.10 @filterability-endorsement
Scenario: REQ-WA103-QM8.2 - Support Multi Value Lookups multiple values
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QM8.2"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -327,6 +356,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO8 @bronze @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO8 - Query Support: $filter - Comparison: has
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO8"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -338,6 +368,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO28.1 @bronze @2.4.4 @sortability-endorsement
Scenario: REQ-WA103-QO28.1 - Query Support: $orderby asc filtered
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO28.1"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -349,6 +380,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO28.2 @bronze @2.4.4 @sortability-endorsement
Scenario: REQ-WA103-QO28.2 - Query Support: $orderby asc no filter
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO28.2"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -360,6 +392,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO28.3 @bronze @2.4.4 @sortability-endorsement
Scenario: REQ-WA103-QO28.3 - Query Support: $orderby desc filtered
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO28.3"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -371,6 +404,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO28.4 @bronze @2.4.4 @sortability-endorsement
Scenario: REQ-WA103-QO28.4 - Query Support: $orderby desc no filter
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO28.4"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -387,6 +421,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO18.1 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO18.1 - Query Support: $filter: Date: year
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -398,6 +433,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO18.2 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO18.2 - Query Support: $filter: Date: year comparison with timestamp
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -409,6 +445,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO19.1 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO19.1 - Query Support: $filter: Date: month
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -420,6 +457,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO19.2 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO19.2 - Query Support: $filter: Date: month comparison with timestamp
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -431,6 +469,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO20.1 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO20.1 - Query Support: $filter: Date: day
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -442,6 +481,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO20.2 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO20.2 - Query Support: $filter: Date: day comparison with timestamp
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -453,6 +493,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO21 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO21 - Query Support: $filter: Date: hour comparison with timestamp
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -464,6 +505,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO22 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO22 - Query Support: $filter: Date: minute comparison with timestamp
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -475,6 +517,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO23 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO23 - Query Support: $filter: Date: second comparison with timestamp
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -486,6 +529,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO24 @gold @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO24 - Query Support: $filter: Date: fractional seconds comparison with timestamp
Given valid metadata have been retrieved
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 server has an OData-Version header value of "4.0" or "4.01"
@ -501,6 +545,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO13 @platinum @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO13 - Query Support: $filter - String: contains
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO13"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -512,6 +557,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO14 @platinum @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO14 - Query Support: $filter - String: ends with
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO14"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -523,6 +569,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO15 @platinum @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO15 - Query Support: $filter - String: starts with
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO15"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -534,6 +581,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO16 @platinum @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO16 - Query Support: $filter - String: tolower() support
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO16"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -545,6 +593,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO17 @platinum @2.4.4 @filterability-endorsement
Scenario: REQ-WA103-QO17 - Query Support: $filter - String: toupper() support
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO17"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -556,6 +605,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO29.1 @platinum @2.4.4 @expandability-endorsement
Scenario: REQ-WA103-QO29.1 - Query Support: $expand
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO29.1"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -569,6 +619,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO29.2 @platinum @2.4.4 @expandability-endorsement @todo
Scenario: REQ-WA103-QO29.2 - Query Support: $expand media photo count (TODO)
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO29.2"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -579,6 +630,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO29.3 @platinum @2.4.4 @expandability-endorsement @todo
Scenario: REQ-WA103-QO29.3 - Query Support: $expand required field (TODO)
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO29.3"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -589,6 +641,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QM3 @platinum @2.4.6 @queryability-endorsement @todo
Scenario: REQ-WA103-QM3 - Support Literals: any() Lambda Expression (TODO)
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QM3"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -599,6 +652,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QM4 @platinum @2.4.6 @queryability-endorsement @todo
Scenario: REQ-WA103-QM4 - Query Support Literals: all() Lambda Operator (TODO)
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QM4"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -609,6 +663,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QM5.1 @platinum @2.4.7 @queryability-endorsement @geospatial @todo
Scenario: REQ-WA103-QM5.1 - Query Support: GeoSpatial Search Implementation (TODO)
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QM5.1"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -619,6 +674,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QM5.2 @platinum @2.4.7 @queryability-endorsement @geospatial @todo
Scenario: REQ-WA103-QM5.2 - Query Support: GeoSpatial Search Implementation (TODO)
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QM5.2"
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"
@ -629,6 +685,7 @@ Feature: Web API Server 1.0.2 Certification
@REQ-WA103-QO12 @platinum @2.4.4 @filterability-endorsement @filterability-endorsement
Scenario: REQ-WA103-QO12 - Query Support: $filter - Grouping: filter (ge, le) and (gt, lt) and expect (gt, lt)
Given valid metadata have been retrieved
When a GET request is made to the resolved Url in "REQ-WA103-QO12" using the OData Client
Then the server responds with a status code of 200
And the server has an OData-Version header value of "4.0" or "4.01"

View File

@ -1,4 +1,5 @@
package org.reso.certification.stepdefs;
import io.cucumber.java8.En;
public class DataDictionary implements En {

View File

@ -1,14 +1,8 @@
package org.reso.certification.stepdefs;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.POJONode;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.ValidationMessage;
import io.cucumber.java8.En;
import org.apache.http.HttpStatus;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
@ -21,13 +15,12 @@ import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
import org.apache.olingo.commons.api.format.ContentType;
import org.reso.commander.Commander;
import org.reso.commander.TestUtils;
import org.reso.commander.certfication.containers.WebApiTestContainer;
import org.reso.commander.certfication.containers.WebAPITestContainer;
import org.reso.commander.common.TestUtils;
import org.reso.models.Request;
import org.reso.models.Settings;
import java.io.File;
import java.io.InputStream;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DecimalFormat;
@ -40,11 +33,11 @@ import java.util.concurrent.atomic.AtomicReference;
import static io.restassured.path.json.JsonPath.from;
import static org.junit.Assert.*;
import static org.reso.commander.Commander.*;
import static org.reso.commander.TestUtils.*;
import static org.reso.commander.TestUtils.Operators.*;
import static org.reso.commander.certfication.containers.WebApiTestContainer.*;
import static org.reso.common.ErrorMsg.getAssertResponseCodeErrorMessage;
import static org.reso.common.ErrorMsg.getDefaultErrorMessage;
import static org.reso.commander.certfication.containers.WebAPITestContainer.*;
import static org.reso.commander.common.ErrorMsg.getAssertResponseCodeErrorMessage;
import static org.reso.commander.common.ErrorMsg.getDefaultErrorMessage;
import static org.reso.commander.common.TestUtils.*;
import static org.reso.commander.common.TestUtils.Operators.*;
/**
* Contains the glue code for the Web API Server 1.0.2 Platinum Certification
@ -58,109 +51,53 @@ public class WebAPIServer_1_0_2 implements En {
private static final boolean showResponses = Boolean.parseBoolean(System.getProperty(SHOW_RESPONSES));
/*
* Used to store a static instance of the WebApiTestContainer class
* Used to store a static instance of the WebAPITestContainer class
*/
private static final AtomicReference<WebApiTestContainer> container = new AtomicReference<>(new WebApiTestContainer());
private static final AtomicReference<WebAPITestContainer> container = new AtomicReference<>(new WebAPITestContainer());
/**
* Entry point to the Web API Server tests
*/
public WebAPIServer_1_0_2() {
getTestContainer().setShowResponses(showResponses);
/*
* Background
*/
Given("^a RESOScript file was provided$", () -> {
if (getTestContainer().getPathToRESOScript() == null) {
getTestContainer().setPathToRESOScript(System.getProperty("pathToRESOScript"));
}
assertNotNull("ERROR: pathToRESOScript must be present in command arguments, see README", getTestContainer().getPathToRESOScript());
LOG.info("Using RESOScript: " + getTestContainer().getPathToRESOScript());
});
And("^Client Settings and Parameters were read from the file$", () -> {
if (getTestContainer().getSettings() == null) {
getTestContainer().setSettings(Settings.loadFromRESOScript(new File(System.getProperty("pathToRESOScript"))));
}
assertNotNull("ERROR: Settings could not be loaded.", getTestContainer().getSettings());
LOG.info("RESOScript loaded successfully!");
});
Given("^a test container was successfully created from the given RESOScript$", () -> {
getTestContainer().initialize();
});
/*
* Ensures that the client either uses Authorization Codes or Client Credentials
*/
And("^the test container uses an authorization_code or client_credentials for authentication$", () -> {
assertNotNull(getTestContainer().getCommander());
assertTrue("ERROR: Commander must either have a valid Authorization Code or Client Credentials configuration.",
getTestContainer().getCommander().isTokenClient() || (getTestContainer().getCommander().isOAuthClient() && getTestContainer().getCommander().hasValidAuthConfig()));
if (getTestContainer().getCommander().isTokenClient()) {
LOG.info("Authentication Type: authorization_code");
} else if (getTestContainer().getCommander().isOAuthClient()) {
LOG.info("Authentication Type: client_credentials");
}
});
runBackground();
/*
* REQ-WA103-END2 - validate DataSystem endpoint, if present.
*/
And("^the results match the expected DataSystem JSON schema$", () -> {
if (getTestContainer().getResponseCode() == HttpStatus.SC_OK && getTestContainer().getResponseData() != null) {
try {
JsonSchemaFactory factory = JsonSchemaFactory.getInstance();
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("datasystem.schema.4.json");
JsonSchema schema = factory.getSchema(is);
getTestContainer().validateDataSystem();
assertEquals("ERROR: JSON Schema validation produced errors!", 0, getTestContainer().getSchemaValidationErrors().size());
});
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(getTestContainer().getResponseData());
if (node.findPath(JSON_VALUE_PATH).size() > 0) {
Set<ValidationMessage> errors = schema.validate(node);
if (errors.size() > 0) LOG.error("ERROR: JSON Schema validation errors were found!");
errors.forEach(LOG::error);
assertEquals("ERROR: JSON Schema validation produced errors!", 0, errors.size());
LOG.info("DataSystem response matches reference schema!");
}
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
}
And("^the XML Metadata returned by the server contains Edm metadata$", () -> {
getTestContainer().setEdm(
Commander.deserializeEdm(getTestContainer().getXMLResponseData(), getTestContainer().getCommander().getClient())
);
assertNotNull(getDefaultErrorMessage("Edm deserialized to an empty object!"), getTestContainer().getEdm());
});
/*
* Edm Metadata Validator
*/
And("^the Edm metadata returned by the server are valid$", () -> {
assertNotNull("ERROR: No Entity Data Model (Edm) Exists!", getTestContainer().getEdm());
try {
boolean isValid = getTestContainer().getCommander().validateMetadata(getTestContainer().getEdm());
LOG.info("Edm Metadata is " + (isValid ? "valid" : "invalid") + "!");
assertTrue("Edm Metadata at the given service root is not valid! " + getTestContainer().getServiceRoot(), isValid);
} catch (Exception ex) {
fail("ERROR: could not validate Edm Metadata!\n" + ex.toString());
}
assertTrue("Edm Metadata at the given service root is not valid! " + getTestContainer().getServiceRoot(),
getTestContainer().getIsValidEdm());
});
/*
* XML Metadata Validator
*/
And("^the XML metadata returned by the server are valid$", () -> {
assertNotNull("ERROR: XML Metadata (EDMX) Exists!", getTestContainer().getXMLMetadata());
try {
boolean isValid = getTestContainer().getCommander().validateMetadata(getTestContainer().getXMLMetadata());
LOG.info("XML Metadata is " + (isValid ? "valid" : "invalid") + "!");
assertTrue("XML Metadata at the given service root is not valid! " + getTestContainer().getServiceRoot(), isValid);
} catch (Exception ex) {
fail("ERROR: could not validate XML Metadata!\n" + ex.toString());
And("^the XML Metadata returned by the server are valid$", () -> {
if (!getTestContainer().getHaveMetadataBeenRequested()) {
//will lazy-load metadata from the server if not yet requested
getTestContainer().getXMLMetadata();
}
getTestContainer().validateMetadata();
assertTrue("XML Metadata at the given service root is not valid! " + getTestContainer().getServiceRoot(),
getTestContainer().getIsValidXMLMetadata());
});
/*
@ -169,7 +106,8 @@ public class WebAPIServer_1_0_2 implements En {
And("^the provided \"([^\"]*)\" is returned in \"([^\"]*)\"$", (String parameterUniqueIdValue, String parameterUniqueId) -> {
try {
String expectedValueAsString = Settings.resolveParametersString(parameterUniqueIdValue, getTestContainer().getSettings());
Object resolvedValue = from(getTestContainer().getResponseData()).get(Settings.resolveParametersString(parameterUniqueId, getTestContainer().getSettings()));
Object resolvedValue = from(getTestContainer().getResponseData())
.get(Settings.resolveParametersString(parameterUniqueId, getTestContainer().getSettings()));
//both of the inputs should be present
assertNotNull(expectedValueAsString);
@ -206,7 +144,7 @@ public class WebAPIServer_1_0_2 implements En {
assertNotNull("ERROR: no fields found within the given $select list. Check request Id: " + getTestContainer().getRequest().getRequestId() + " in your .resoscript file!",
getTestContainer().getSelectList());
LOG.info(QueryOption.SELECT + " list is: " + getTestContainer().getSelectList() );
LOG.info(QueryOption.SELECT + " list is: " + getTestContainer().getSelectList());
AtomicInteger numResults = new AtomicInteger();
//iterate over the items and count the number of fields with data to determine whether there are data present
@ -274,7 +212,7 @@ public class WebAPIServer_1_0_2 implements En {
getTestContainer().setRequestUri(Commander.prepareURI(
Settings.resolveParameters(getTestContainer().getSettings().getRequest(requestId), getTestContainer().getSettings()).getUrl()
+ AMPERSAND + ODATA_QUERY_PARAMS.SKIP + EQUALS + skipCount));
getTestContainer().executePreparedGetRequest();
getTestContainer().executePreparedRawGetRequest();
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
@ -308,7 +246,7 @@ public class WebAPIServer_1_0_2 implements En {
/*
* GET request by requirementId (see generic.resoscript)
*/
When("^a GET request is made to the resolved Url in \"([^\"]*)\"$", this::prepareAndExecuteGetRequest);
When("^a GET request is made to the resolved Url in \"([^\"]*)\"$", this::prepareAndExecuteRawGetRequest);
/*
* Assert response code
@ -339,28 +277,15 @@ public class WebAPIServer_1_0_2 implements En {
* validate XML wrapper
*/
And("^the XML Metadata response is valid XML$", () -> {
try {
assertTrue("ERROR: invalid XML response!", Commander.validateXML(getTestContainer().getXMLResponseData()));
LOG.info("Response is valid XML!");
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
assertNotNull(getDefaultErrorMessage("no XML Response data were found!"), getTestContainer().getXMLResponseData());
getTestContainer().validateXMLMetadataXML();
assertTrue("ERROR: invalid XML response!", getTestContainer().getIsValidXMLMetadataXML());
});
/*
* validate JSON wrapper
*/
And("^the response is valid JSON$", () -> {
try {
assertTrue("ERROR: invalid JSON response!", TestUtils.isValidJson(getTestContainer().getResponseData()));
LOG.info("Response is valid JSON!");
if (showResponses)
LOG.info("Response: " + new ObjectMapper().readTree(getTestContainer().getResponseData()).toPrettyString());
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
});
And("^the response is valid JSON$", getTestContainer()::validateJSON);
/*
* Assert HTTP Response Code given asserted OData version
@ -776,8 +701,12 @@ public class WebAPIServer_1_0_2 implements En {
getTestContainer().getSelectList().forEach(fieldName -> {
//need to skip the expand field when looking through the metadata
if (getTestContainer().getExpandField() == null || !fieldName.contentEquals(getTestContainer().getExpandField())) {
try {
assertNotNull("ERROR: Field name '" + fieldName + "' is not present in server metadata!", getTestContainer().getCsdlForFieldName(fieldName));
LOG.info("Found: '" + fieldName.trim() + "'");
} catch (Exception ex) {
LOG.error(getDefaultErrorMessage(ex));
}
}
});
} catch (Exception ex) {
@ -807,35 +736,17 @@ public class WebAPIServer_1_0_2 implements En {
*/
And("^XML Metadata are requested from the service root in \"([^\"]*)\"$", (String clientSettingsServiceRoot) -> {
final String serviceRoot = Settings.resolveParametersString(clientSettingsServiceRoot, getTestContainer().getSettings());
assertEquals("ERROR: given service root doesn't match the one configured in the Commander", serviceRoot, getTestContainer().getCommander().getServiceRoot());
assertEquals(getDefaultErrorMessage("given service root doesn't match the one configured in the Commander"),
serviceRoot,
getTestContainer().getCommander().getServiceRoot());
LOG.info("Requesting XML Metadata from: " + serviceRoot);
try {
assertNotNull("ERROR: could not find valid XML Metadata for given service root: " + serviceRoot, getTestContainer().getXMLMetadata());
assertNotNull(getDefaultErrorMessage("could not find valid XML Metadata for given service root:", serviceRoot),
getTestContainer().getXMLMetadata());
} catch (ODataClientErrorException cex) {
getTestContainer().setResponseCode(cex.getStatusLine().getStatusCode());
fail(cex.toString());
} catch (IllegalArgumentException aex) {
fail(getDefaultErrorMessage(aex.toString()));
} catch (Exception ex) {
fail("ERROR: "+ ex.toString());
}
});
/*
* Edm Metadata getter
*/
And("^Edm metadata are requested from the service root in \"([^\"]*)\"$", (String clientSettingsServiceRoot) -> {
final String serviceRoot = Settings.resolveParametersString(clientSettingsServiceRoot, getTestContainer().getSettings());
assertEquals("ERROR: given service root doesn't match the one configured in the Commander", serviceRoot, getTestContainer().getCommander().getServiceRoot());
LOG.info("Requesting Edm Metadata from: " + serviceRoot);
try {
assertNotNull("ERROR: could not find valid Edm Metadata for given service root: " + serviceRoot, getTestContainer().getEdm());
if (showResponses) LOG.info(Commander.getMetadataReport(getTestContainer().getEdm()));
} catch (ODataClientErrorException cex) {
getTestContainer().setResponseCode(cex.getStatusLine().getStatusCode());
fail(cex.toString());
fail(getDefaultErrorMessage(cex));
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
@ -932,8 +843,12 @@ public class WebAPIServer_1_0_2 implements En {
AtomicBoolean found = new AtomicBoolean(false);
requiredResources.forEach(requiredResource -> {
try {
if (!found.get())
found.set(found.get() || getTestContainer().getEdm().getEntityContainer().getEntitySet(requiredResource) != null);
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
});
assertTrue("ERROR: could not find one of the following Standard Resource Names in the default entity container: " + requiredResourceString.replace(FIELD_SEPARATOR, PRETTY_FIELD_SEPARATOR),
@ -1021,22 +936,39 @@ public class WebAPIServer_1_0_2 implements En {
assertNotNull("ERROR: must enter a second value", val2);
assertNotNull("ERROR: must specify an 'OData-Version' in the response header!"
+ "\nSee: http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part1-protocol/odata-v4.0-errata03-os-part1-protocol-complete.html#_Toc453752225" ,
+ "\nSee: http://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/part1-protocol/odata-v4.0-errata03-os-part1-protocol-complete.html#_Toc453752225",
getTestContainer().getServerODataHeaderVersion());
LOG.info("Reported OData-Version header value: '" + getTestContainer().getServerODataHeaderVersion() + "'");
assertTrue("ERROR: the 'OData-Version' response header must either be '" + val1 + "' or '" + val2 + "' (without quotes).",
getTestContainer().getServerODataHeaderVersion().contentEquals(val1)
|| getTestContainer().getServerODataHeaderVersion().contentEquals(val2) );
|| getTestContainer().getServerODataHeaderVersion().contentEquals(val2));
});
/*
* Ensures valid metadata have been retrieved from the server
*/
Given("^valid metadata have been retrieved$", () -> {
//NOTE: this is here so that tests may be run individually
if (!getTestContainer().getHaveMetadataBeenRequested()) {
getTestContainer().getXMLMetadata();
getTestContainer().validateMetadata();
}
assertTrue(getDefaultErrorMessage("Valid metadata could not be retrieved from the server! Please check the log for more information."),
getTestContainer().hasValidMetadata());
});
}
static WebAPITestContainer getTestContainer() {
return container.get();
}
/*
* Execute Get Request Wrapper
*/
void prepareAndExecuteGetRequest(String requestId) {
void prepareAndExecuteRawGetRequest(String requestId) {
try {
//reset local state each time a get request is run
getTestContainer().resetState();
@ -1051,13 +983,52 @@ public class WebAPIServer_1_0_2 implements En {
LOG.info("Request URI: " + getTestContainer().getRequestUri().toString());
//execute request
getTestContainer().executePreparedGetRequest();
getTestContainer().executePreparedRawGetRequest();
} catch (Exception ex) {
LOG.debug("Exception was thrown in " + this.getClass() + ": " + ex.toString());
LOG.info("Exception was thrown in " + this.getClass() + ": " + ex.toString());
}
}
static WebApiTestContainer getTestContainer() {
return container.get();
/**
* Contains background logic - make sure to update if the background changes
*/
final void runBackground() {
/*
* Background
*/
Given("^a RESOScript file was provided$", () -> {
if (getTestContainer().getPathToRESOScript() == null) {
getTestContainer().setPathToRESOScript(System.getProperty("pathToRESOScript"));
}
assertNotNull("ERROR: pathToRESOScript must be present in command arguments, see README", getTestContainer().getPathToRESOScript());
LOG.info("Using RESOScript: " + getTestContainer().getPathToRESOScript());
});
And("^Client Settings and Parameters were read from the file$", () -> {
if (getTestContainer().getSettings() == null) {
getTestContainer().setSettings(Settings.loadFromRESOScript(new File(System.getProperty("pathToRESOScript"))));
}
assertNotNull("ERROR: Settings could not be loaded.", getTestContainer().getSettings());
LOG.info("RESOScript loaded successfully!");
});
Given("^a test container was successfully created from the given RESOScript$", () -> {
getTestContainer().initialize();
});
/*
* Ensures that the client either uses Authorization Codes or Client Credentials
*/
And("^the test container uses an authorization_code or client_credentials for authentication$", () -> {
assertNotNull(getTestContainer().getCommander());
assertTrue("ERROR: Commander must either have a valid Authorization Code or Client Credentials configuration.",
getTestContainer().getCommander().isAuthTokenClient() || (getTestContainer().getCommander().isOAuth2Client() && getTestContainer().getCommander().hasValidAuthConfig()));
if (getTestContainer().getCommander().isAuthTokenClient()) {
LOG.info("Authentication Type: authorization_code");
} else if (getTestContainer().getCommander().isOAuth2Client()) {
LOG.info("Authentication Type: client_credentials");
}
});
}
}

View File

@ -22,6 +22,7 @@ import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.format.ContentType;
import org.reso.auth.OAuth2HttpClientFactory;
import org.reso.auth.TokenHttpClientFactory;
import org.reso.commander.common.TestUtils;
import org.xml.sax.*;
import javax.xml.XMLConstants;
@ -45,20 +46,19 @@ import java.util.function.Function;
* the ones the Client programmer is expected to use.
*/
public class Commander {
private static final Logger LOG = LogManager.getLogger(Commander.class);
public static final int OK = 0;
public static final int NOT_OK = 1;
public static final String AMPERSAND = "&"; //TODO: find the corresponding query params constant for this
public static final String EQUALS = "="; //TODO: find the corresponding query params constant for this
//TODO: find the corresponding query params constant for this
public static final String AMPERSAND = "&";
//TODO: find the corresponding query params constant for this
public static final String EQUALS = "=";
public static final Integer DEFAULT_PAGE_SIZE = 10;
public static final Integer DEFAULT_PAGE_LIMIT = 1;
public static final String REPORT_DIVIDER = "==============================================================";
public static final String REPORT_DIVIDER_SMALL = "===========================";
public static final String RESOSCRIPT_EXTENSION = ".resoscript";
public static final String EDMX_EXTENSION = ".xml";
private static final Logger LOG = LogManager.getLogger(Commander.class);
private static final String EDM_4_0_3_XSD = "edm.4.0.errata03.xsd", EDMX_4_0_3_XSD = "edmx.4.0.errata03.xsd";
private static String bearerToken;
@ -79,17 +79,6 @@ public class Commander {
//private constructor, should not be used. Use Builder instead.
}
/**
* Validates XML for the given xmlMetadata item
*
* @param xmlMetadata the XML metadata to validate
* @return true if valid, false otherwise
* @throws ODataSerializerException if the given XML metadata could not be serialized
*/
public static boolean validateXML(XMLMetadata xmlMetadata) throws ODataSerializerException {
return validateXML(serializeXMLMetadataToXMLString(xmlMetadata));
}
/**
* Uses an XML validator to validate that the given string contains valid XML.
*
@ -99,7 +88,9 @@ public class Commander {
public static boolean validateXML(final String xmlString) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setValidating(false); //turn off expectation of having DTD in DOCTYPE tag
//turn off expectation of having DTD in DOCTYPE tag
factory.setValidating(false);
factory.setNamespaceAware(true);
factory.setSchema(SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(new StreamSource[]{
@ -212,19 +203,6 @@ public class Commander {
return null;
}
/**
* Serializes XML Metadata to an XML string
*
* @param xmlMetadata the metadata to serialize
* @return a String containing the metadata
* @throws ODataSerializerException
*/
private static String serializeXMLMetadataToXMLString(XMLMetadata xmlMetadata) throws ODataSerializerException {
StringWriter writer = new StringWriter();
client.getSerializer(ContentType.APPLICATION_XML).write(writer, xmlMetadata);
return writer.getBuffer().toString();
}
/**
* Metadata Pretty Printer
*
@ -275,8 +253,36 @@ public class Commander {
return reportBuilder.toString();
}
/**
* Deserializes XML Metadata from a string
*
* @param xmlMetadataString a string containing XML Metadata
* @param client an instance of an OData Client
* @return the XML Metadata contained within the string
*/
public static XMLMetadata deserializeXMLMetadata(String xmlMetadataString, ODataClient client) {
//deserialize response into XML Metadata - will throw an exception if metadata are invalid
return client.getDeserializer(ContentType.APPLICATION_XML)
.toMetadata(new ByteArrayInputStream(xmlMetadataString.getBytes(StandardCharsets.UTF_8)));
}
/**
* Deserializes Edm from XML Metadata
*
* @param xmlMetadataString a string containing XML metadata
* @param client an instance of an OData Client
* @return the Edm contained within the xmlMetadataString
* <p>
* TODO: rewrite the separate Edm request in the Web API server test code to only make one request and convert
* to Edm from the XML Metadata that was received.
*/
public static Edm deserializeEdm(String xmlMetadataString, ODataClient client) {
return client.getReader().readMetadata(new ByteArrayInputStream(xmlMetadataString.getBytes(StandardCharsets.UTF_8)));
}
/**
* OData client getter
*
* @return the OData client for the current Commander instance
*/
public ODataClient getClient() {
@ -285,6 +291,7 @@ public class Commander {
/**
* OData client setter
*
* @param client sets the current Commander instance to use the given client
*/
public void setClient(ODataClient client) {
@ -293,6 +300,7 @@ public class Commander {
/**
* Token URI getter
*
* @return the tokenUri used by the current Commander instance, or null
*/
public String getTokenUri() {
@ -301,6 +309,7 @@ public class Commander {
/**
* Service Root getter
*
* @return the serviceRoot used by the current Commander instance, or null
*/
public String getServiceRoot() {
@ -313,11 +322,11 @@ public class Commander {
* @return true if the auth config is valid, false otherwise.
*/
public boolean hasValidAuthConfig() {
if (isTokenClient()) {
if (isAuthTokenClient()) {
return bearerToken != null && bearerToken.length() > 0;
}
if (isOAuthClient()) {
if (isOAuth2Client()) {
return getTokenUri() != null && getTokenUri().length() > 0
&& clientId != null && clientId.length() > 0
&& clientSecret != null && clientSecret.length() > 0;
@ -327,6 +336,7 @@ public class Commander {
/**
* Prepares an Edm Metadata request
*
* @return a prepared Edm metadata request
*/
public EdmMetadataRequest prepareEdmMetadataRequest() {
@ -338,6 +348,7 @@ public class Commander {
/**
* Prepares an XML Metadata request
*
* @return a prepared XML Metadata request
*/
public XMLMetadataRequest prepareXMLMetadataRequest() {
@ -374,12 +385,13 @@ public class Commander {
}
/**
* Validates given XMLMetadata
* Static version of the metadata validator that can work with a given client
*
* @param metadata the XMLMetadata to be validated
* @return true if the metadata is valid, meaning that it's also a valid OData 4 Service Document
* @param metadata the XML Metadata to validate
* @param client the OData client to use for validation
* @return true if the given XML metadata is valid, false otherwise
*/
public boolean validateMetadata(XMLMetadata metadata) {
public static boolean validateMetadata(XMLMetadata metadata, ODataClient client) {
try {
// call the probably-useless metadata validator. can't hurt though
// SEE: https://github.com/apache/olingo-odata4/blob/master/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataMetadataValidationImpl.java#L77-L116
@ -400,16 +412,17 @@ public class Commander {
}
/**
* Validates given XMLMetadata
* Static version of the metadata validator that can work with a given client
*
* @param metadata the XMLMetadata to be validated
* @return true if the metadata is valid, meaning that it's also a valid OData 4 Service Document
* @param edm the Edm to validate
* @param client the OData client to use for validation
* @return true if the given XML metadata is valid, false otherwise
*/
public boolean validateMetadata(Edm metadata) {
public static boolean validateMetadata(Edm edm, ODataClient client) {
try {
// call the probably-useless metadata validator. can't hurt though
// SEE: https://github.com/apache/olingo-odata4/blob/master/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataMetadataValidationImpl.java#L77-L116
client.metadataValidation().validateMetadata(metadata);
client.metadataValidation().validateMetadata(edm);
//if Edm metadata are invalid, the previous line will throw an exception and this line won't be reached.
return true;
} catch (NullPointerException nex) {
@ -423,6 +436,26 @@ public class Commander {
return false;
}
/**
* Validates given XMLMetadata
*
* @param metadata the XMLMetadata to be validated
* @return true if the metadata is valid, meaning that it's also a valid OData 4 Service Document
*/
public boolean validateMetadata(XMLMetadata metadata) {
return validateMetadata(metadata, client);
}
/**
* Validates given XMLMetadata
*
* @param metadata the XMLMetadata to be validated
* @return true if the metadata is valid, meaning that it's also a valid OData 4 Service Document
*/
public boolean validateMetadata(Edm metadata) {
return validateMetadata(metadata, client);
}
/**
* Ensures that the input stream contains valid XMLMetadata.
*
@ -473,7 +506,7 @@ public class Commander {
*
* @return true if the commander instance is a token client, false otherwise.
*/
public boolean isTokenClient() {
public boolean isAuthTokenClient() {
return isTokenClient;
}
@ -482,7 +515,7 @@ public class Commander {
*
* @return true if the commander instance is an OAuth2 client credentials client, false otherwise.
*/
public boolean isOAuthClient() {
public boolean isOAuth2Client() {
return isOAuthClient;
}
@ -531,6 +564,7 @@ public class Commander {
/**
* Executes a raw OData request in the current commander instance without trying to intepret the results
*
* @param requestUri the URI to make the request to
* @return a string containing the serialized response, or null
*/
@ -701,6 +735,7 @@ public class Commander {
/**
* Service root setter
*
* @param serviceRoot the Web API service root
* @return a Builder containing the given Web API service root
*/
@ -711,6 +746,7 @@ public class Commander {
/**
* Bearer token setter
*
* @param bearerToken the token to use to connect to the server
* @return a Builder set with the given bearerToken
*/
@ -721,6 +757,7 @@ public class Commander {
/**
* Client Identification setter
*
* @param clientId the OAuth2 client_id to use to authenticate against the server
* @return a Builder set with the given clientId
*/
@ -731,6 +768,7 @@ public class Commander {
/**
* Client Secret setter
*
* @param clientSecret the OAuth2 client_secret to use to authenticate against the server
* @return a Builder set with the given clientSecret
*/
@ -741,6 +779,7 @@ public class Commander {
/**
* Token URI setter
*
* @param tokenUri the OAuth2 token_uri to use to authenticate against the server
* @return a Builder set with the given tokenUri
*/
@ -751,6 +790,7 @@ public class Commander {
/**
* Scope setter
*
* @param scope the OAuth2 scope to use to authenticate against the server
* @return a Builder set with the given scope
*/
@ -773,6 +813,7 @@ public class Commander {
/**
* Commander builder is used to create instances of the RESO Commander, which should not be instantiated directly.
*
* @return a Commander instantiated with the given properties set
*/
public Commander build() {

View File

@ -1,5 +1,10 @@
package org.reso.commander.certfication.containers;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.ValidationMessage;
import org.apache.http.HttpStatus;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -16,37 +21,80 @@ import org.apache.olingo.commons.api.edm.Edm;
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.TestUtils;
import org.reso.commander.common.TestUtils;
import org.reso.models.ClientSettings;
import org.reso.models.Parameters;
import org.reso.models.Request;
import org.reso.models.Settings;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.*;
import static org.reso.commander.Commander.AMPERSAND;
import static org.reso.commander.Commander.EQUALS;
import static org.reso.commander.TestUtils.HEADER_ODATA_VERSION;
import static org.reso.common.ErrorMsg.getDefaultErrorMessage;
import static org.reso.commander.common.ErrorMsg.getDefaultErrorMessage;
import static org.reso.commander.common.TestUtils.HEADER_ODATA_VERSION;
import static org.reso.commander.common.TestUtils.JSON_VALUE_PATH;
/**
* Encapsulates Commander Requests and Responses during runtime
*/
public final class WebApiTestContainer implements TestContainer {
private static final Logger LOG = LogManager.getLogger(WebApiTestContainer.class);
public final class WebAPITestContainer implements TestContainer {
public static final String FIELD_SEPARATOR = ",";
public static final String EMPTY_STRING = "";
public static final String SINGLE_SPACE = " ";
public static final String DOLLAR_SIGN = "$";
public static final String PRETTY_FIELD_SEPARATOR = FIELD_SEPARATOR + SINGLE_SPACE;
private static final Logger LOG = LogManager.getLogger(WebAPITestContainer.class);
public Map<String, CsdlProperty> getFieldMap() {
private final AtomicReference<Commander> commander = new AtomicReference<>();
private final AtomicReference<XMLMetadata> xmlMetadata = new AtomicReference<>();
private final AtomicReference<Edm> edm = new AtomicReference<>();
private final AtomicReference<Settings> settings = new AtomicReference<>();
private final AtomicReference<String> serviceRoot = new AtomicReference<>();
private final AtomicReference<String> bearerToken = new AtomicReference<>();
private final AtomicReference<String> clientId = new AtomicReference<>();
private final AtomicReference<String> clientSecret = new AtomicReference<>();
private final AtomicReference<String> authorizationUri = new AtomicReference<>();
private final AtomicReference<String> tokenUri = new AtomicReference<>();
private final AtomicReference<String> redirectUri = new AtomicReference<>();
private final AtomicReference<String> scope = new AtomicReference<>();
private final AtomicReference<String> pathToRESOScript = new AtomicReference<>();
private final AtomicReference<Map<String, CsdlProperty>> fieldMap = new AtomicReference<>();
private final AtomicReference<String> xmlResponseData = new AtomicReference<>();
private final AtomicBoolean showResponses = new AtomicBoolean(false);
// Metadata and DataSystem state variables
private final AtomicBoolean isValidXMLMetadata = new AtomicBoolean(false);
private final AtomicBoolean isValidEdm = new AtomicBoolean(false);
private final AtomicBoolean isValidXMLMetadataXML = new AtomicBoolean(false);
private final AtomicBoolean haveMetadataBeenRequested = new AtomicBoolean(false);
private final AtomicBoolean haveEdmMetadataBeenRetrieved = new AtomicBoolean(false);
private final AtomicBoolean isDataSystemValid = new AtomicBoolean(false);
private final AtomicReference<Set<ValidationMessage>> schemaValidationErrors = new AtomicReference<>();
// request instance variables - these get reset with every request
private final AtomicReference<String> selectList = new AtomicReference<>();
private final AtomicReference<ODataRawResponse> oDataRawResponse = new AtomicReference<>();
private final AtomicReference<Request> request = new AtomicReference<>();
private final AtomicReference<URI> requestUri = new AtomicReference<>();
private final AtomicReference<Integer> responseCode = new AtomicReference<>();
private final AtomicReference<String> responseData = new AtomicReference<>();
private final AtomicReference<String> initialResponseData = new AtomicReference<>(); //used if two result sets need to be compared
private final AtomicReference<ODataRawRequest> rawRequest = new AtomicReference<>();
private final AtomicReference<ODataClientErrorException> oDataClientErrorException = new AtomicReference<>();
private final AtomicReference<ODataServerErrorException> oDataServerErrorException = new AtomicReference<>();
private final AtomicReference<String> serverODataHeaderVersion = new AtomicReference<>();
private final AtomicReference<Boolean> testAppliesToServerODataHeaderVersion = new AtomicReference<>();
private final AtomicReference<ODataEntitySetRequest<ClientEntitySet>> clientEntitySetRequest = new AtomicReference<>();
private final AtomicReference<ODataRetrieveResponse<ClientEntitySet>> clientEntitySetResponse = new AtomicReference<>();
private final AtomicReference<ClientEntitySet> clientEntitySet = new AtomicReference<>();
public Map<String, CsdlProperty> getFieldMap() throws Exception {
if (fieldMap.get() == null) {
fieldMap.set(new HashMap<>());
@ -65,55 +113,10 @@ public final class WebApiTestContainer implements TestContainer {
return xmlResponseData.get();
}
public static final class ODATA_QUERY_PARAMS {
private static String format = DOLLAR_SIGN + "%s";
//TODO: add additional items as needed, and see if there's a lib for this in Olingo
public static final String
COUNT = String.format(format, QueryOption.COUNT),
EXPAND = String.format(format, QueryOption.EXPAND),
FILTER = String.format(format, QueryOption.FILTER),
ORDERBY = String.format(format, QueryOption.ORDERBY),
SELECT = String.format(format, QueryOption.SELECT),
SEARCH = String.format(format, QueryOption.SEARCH),
SKIP = String.format(format, QueryOption.SKIP),
TOP = String.format(format, QueryOption.TOP);
public void setXMLResponseData(String xmlResponseData) {
this.xmlResponseData.set(xmlResponseData);
}
private AtomicReference<Commander> commander = new AtomicReference<>();
private AtomicReference<XMLMetadata> xmlMetadata = new AtomicReference<>();
private AtomicReference<Edm> edm = new AtomicReference<>();
private AtomicReference<Settings> settings = new AtomicReference<>();
private AtomicReference<String> serviceRoot = new AtomicReference<>();
private AtomicReference<String> bearerToken = new AtomicReference<>();
private AtomicReference<String> clientId = new AtomicReference<>();
private AtomicReference<String> clientSecret = new AtomicReference<>();
private AtomicReference<String> authorizationUri = new AtomicReference<>();
private AtomicReference<String> tokenUri = new AtomicReference<>();
private AtomicReference<String> redirectUri = new AtomicReference<>();
private AtomicReference<String> scope = new AtomicReference<>();
private AtomicReference<String> pathToRESOScript = new AtomicReference<>();
private AtomicReference<Map<String, CsdlProperty>> fieldMap = new AtomicReference<>();
private AtomicReference<String> xmlResponseData = new AtomicReference<>();
// request instance variables - these get reset with every request
private AtomicReference<String> selectList = new AtomicReference<>();
private AtomicReference<ODataRawResponse> oDataRawResponse = new AtomicReference<>();
private AtomicReference<Request> request = new AtomicReference<>();
private AtomicReference<URI> requestUri = new AtomicReference<>();
private AtomicReference<Integer> responseCode = new AtomicReference<>();
private AtomicReference<String> responseData = new AtomicReference<>();
private AtomicReference<String> initialResponseData = new AtomicReference<>(); //used if two result sets need to be compared
private AtomicReference<ODataRawRequest> rawRequest = new AtomicReference<>();
private AtomicReference<ODataClientErrorException> oDataClientErrorException = new AtomicReference<>();
private AtomicReference<ODataServerErrorException> oDataServerErrorException = new AtomicReference<>();
private AtomicReference<String> serverODataHeaderVersion = new AtomicReference<>();
private AtomicReference<Boolean> testAppliesToServerODataHeaderVersion = new AtomicReference<>();
private AtomicReference<ODataEntitySetRequest<ClientEntitySet>> clientEntitySetRequest = new AtomicReference<>();
private AtomicReference<ODataRetrieveResponse<ClientEntitySet>> clientEntitySetResponse = new AtomicReference<>();
private AtomicReference<ClientEntitySet> clientEntitySet = new AtomicReference<>();
/**
* Resets the state of the test container
*/
@ -140,8 +143,8 @@ public final class WebApiTestContainer implements TestContainer {
//TODO: add base64 un-encode when applicable
setBearerToken(getSettings().getClientSettings().get(ClientSettings.BEARER_TOKEN));
if (getBearerToken() != null && getBearerToken().length() > 0) {
LOG.info("Bearer token loaded... first 4 characters: " + getBearerToken().substring(0, 4));
if (getAuthToken() != null && getAuthToken().length() > 0) {
LOG.info("Bearer token loaded... first 4 characters: " + getAuthToken().substring(0, 4));
}
setClientId(getSettings().getClientSettings().get(ClientSettings.CLIENT_IDENTIFICATION));
@ -161,7 +164,7 @@ public final class WebApiTestContainer implements TestContainer {
.tokenUri(getTokenUri())
.scope(getScope())
.serviceRoot(getServiceRoot())
.bearerToken(getBearerToken())
.bearerToken(getAuthToken())
.useEdmEnabledClient(shouldUseEdmClient())
.build());
}
@ -185,10 +188,10 @@ public final class WebApiTestContainer implements TestContainer {
}
/**
* Executes HTTP GET request and sets the expected local variables in the WebApiTestContainer
* Executes HTTP GET request and sets the expected local variables in the WebAPITestContainer
* Handles exceptions and sets response codes as well.
*/
public void executePreparedGetRequest() {
public void executePreparedRawGetRequest() throws Exception {
try {
setRawRequest(getCommander().getClient().getRetrieveRequestFactory().getRawRequest(getRequestUri()));
getRawRequest().setFormat(ContentType.JSON.toContentTypeString());
@ -197,21 +200,8 @@ public final class WebApiTestContainer implements TestContainer {
setServerODataHeaderVersion(TestUtils.getHeaderData(HEADER_ODATA_VERSION, getODataRawResponse()));
setResponseCode(getODataRawResponse().getStatusCode());
LOG.info("Request succeeded..." + getResponseData().getBytes().length + " bytes received.");
} catch (ODataClientErrorException cex) {
LOG.debug("ODataClientErrorException caught. Check tests for asserted conditions...");
LOG.debug(cex);
setODataClientErrorException(cex);
setServerODataHeaderVersion(TestUtils.getHeaderData(HEADER_ODATA_VERSION, Arrays.asList(cex.getHeaderInfo())));
setResponseCode(cex.getStatusLine().getStatusCode());
} catch (ODataServerErrorException ode) {
LOG.debug("ODataServerErrorException thrown in executeGetRequest. Check tests for asserted conditions...");
//TODO: look for better ways to do this in Olingo or open PR
if (ode.getMessage().contains(Integer.toString(HttpStatus.SC_NOT_IMPLEMENTED))) {
setResponseCode(HttpStatus.SC_NOT_IMPLEMENTED);
}
setODataServerErrorException(ode);
} catch (Exception ex) {
fail("ERROR: unhandled Exception in executeGetRequest()!\n" + ex.toString());
processODataRequestException(ex);
}
}
@ -221,7 +211,7 @@ public final class WebApiTestContainer implements TestContainer {
* @param fieldName the name of the field to retrieve metadata about
* @return the metadata for the given field
*/
public CsdlProperty getCsdlForFieldName(String fieldName) {
public CsdlProperty getCsdlForFieldName(String fieldName) throws Exception {
return getFieldMap().get(fieldName);
}
@ -230,22 +220,27 @@ public final class WebApiTestContainer implements TestContainer {
*
* @return gets the local collection of Csdl Properties
*/
public Collection<CsdlProperty> getCsdlProperties() {
public Collection<CsdlProperty> getCsdlProperties() throws Exception {
return getFieldMap().values();
}
/**
* Parses an OData $select list
*
* @return the de-duplicated set of select list items
*/
public Collection<String> getSelectList() {
Arrays.stream(getRequestUri().getQuery().split(AMPERSAND)).forEach(fragment -> {
if (fragment.contains(QueryOption.SELECT.toString())) {
selectList.set(fragment.replace(ODATA_QUERY_PARAMS.SELECT, EMPTY_STRING).replace(EQUALS, EMPTY_STRING));
}
});
return new ArrayList<>(Arrays.asList(selectList.get().split(FIELD_SEPARATOR)));
return new LinkedHashSet<>((Arrays.asList(selectList.get().split(FIELD_SEPARATOR))));
}
/**
* Settings getter
*
* @return local settings instance
*/
public Settings getSettings() {
@ -254,6 +249,7 @@ public final class WebApiTestContainer implements TestContainer {
/**
* Settings setter
*
* @param settings sets local settings instance to the given settings
*/
public void setSettings(Settings settings) {
@ -262,6 +258,7 @@ public final class WebApiTestContainer implements TestContainer {
/**
* Gets the Expand field from the RESOScript
*
* @return the configured Expand field
*/
public String getExpandField() {
@ -274,19 +271,21 @@ public final class WebApiTestContainer implements TestContainer {
* @return
* @implNote the data in this item are cached in the test container once fetched
*/
public Edm getEdm() {
public Edm getEdm() throws Exception {
if (edm.get() == null) {
ODataRetrieveResponse<Edm> response = getCommander().prepareEdmMetadataRequest().execute();
responseCode.set(response.getStatusCode());
setServerODataHeaderVersion(TestUtils.getHeaderData(HEADER_ODATA_VERSION, response));
edm.set(response.getBody());
assertNotNull(getDefaultErrorMessage("no XML response data found, cannot return Edm!"), xmlResponseData.get());
edm.set(Commander.deserializeEdm(xmlResponseData.get(), getCommander().getClient()));
}
return edm.get();
}
public void setEdm(Edm edm) {
this.edm.set(edm);
}
/**
* Gets server metadata in XMLMetadata format.
*
* <p>
* Note: this method takes a slightly different approach than getting XML Metadata did previously in that
* rather than fetching the metadata directly from the server using the Olingo getXmlMetadata method,
* we make a raw request instead so that we can capture the response string for XML validation, and
@ -295,7 +294,7 @@ public final class WebApiTestContainer implements TestContainer {
* @return XMLMetadata representation of the server metadata.
* @implNote the data in this item are cached in the test container once fetched
*/
public XMLMetadata getXMLMetadata() {
public XMLMetadata getXMLMetadata() throws Exception {
if (xmlMetadata.get() == null) {
try {
String requestUri = Settings.resolveParameters(getSettings().getRequest(Request.WELL_KNOWN.METADATA_ENDPOINT), getSettings()).getUrl();
@ -304,25 +303,26 @@ public final class WebApiTestContainer implements TestContainer {
ODataRawRequest request = getCommander().getClient().getRetrieveRequestFactory().getRawRequest(URI.create(requestUri));
request.setFormat(ContentType.JSON.toContentTypeString());
LOG.info("Requesting XML Metadata from service root at: " + getServiceRoot());
ODataRawResponse response = request.execute();
xmlResponseData.set(TestUtils.convertInputStreamToString(response.getRawResponse()));
//deserialize response into XML Metadata - will throw an exception if metadata are in valid
XMLMetadata metadata = getCommander().getClient().getDeserializer(ContentType.APPLICATION_XML)
.toMetadata(new ByteArrayInputStream(xmlResponseData.get().getBytes(StandardCharsets.UTF_8)));
responseCode.set(response.getStatusCode());
setServerODataHeaderVersion(TestUtils.getHeaderData(HEADER_ODATA_VERSION, response));
xmlMetadata.set(metadata);
xmlResponseData.set(TestUtils.convertInputStreamToString(response.getRawResponse()));
xmlMetadata.set(Commander.deserializeXMLMetadata(xmlResponseData.get(), getCommander().getClient()));
} catch (Exception ex) {
getDefaultErrorMessage(ex);
processODataRequestException(ex);
} finally {
haveMetadataBeenRequested.set(true);
}
}
return xmlMetadata.get();
}
public void setXMLMetadata(XMLMetadata xmlMetadata) {
this.xmlMetadata.set(xmlMetadata);
}
public Commander getCommander() {
return commander.get();
}
@ -455,7 +455,7 @@ public final class WebApiTestContainer implements TestContainer {
this.serviceRoot.set(serviceRoot);
}
public String getBearerToken() {
public String getAuthToken() {
return bearerToken.get();
}
@ -518,4 +518,201 @@ public final class WebApiTestContainer implements TestContainer {
public void setPathToRESOScript(String pathToRESOScript) {
this.pathToRESOScript.set(pathToRESOScript);
}
private void processODataRequestException(Exception exception, boolean bubble) throws Exception {
if (exception instanceof ODataClientErrorException)
processODataRequestException((ODataClientErrorException) exception);
else if (exception instanceof ODataServerErrorException)
processODataRequestException(((ODataServerErrorException) exception));
else LOG.error(getDefaultErrorMessage(exception));
if (bubble) throw exception;
}
private void processODataRequestException(Exception exception) throws Exception {
processODataRequestException(exception, true);
}
private void processODataRequestException(ODataClientErrorException exception) {
LOG.debug("ODataClientErrorException caught. Check tests for asserted conditions...");
LOG.debug(exception);
setODataClientErrorException(exception);
setServerODataHeaderVersion(TestUtils.getHeaderData(HEADER_ODATA_VERSION, Arrays.asList(exception.getHeaderInfo())));
setResponseCode(exception.getStatusLine().getStatusCode());
}
private void processODataRequestException(ODataServerErrorException exception) {
LOG.debug("ODataServerErrorException thrown in executeGetRequest. Check tests for asserted conditions...");
//TODO: look for better ways to do this in Olingo or open PR
if (exception.getMessage().contains(Integer.toString(HttpStatus.SC_NOT_IMPLEMENTED))) {
setResponseCode(HttpStatus.SC_NOT_IMPLEMENTED);
}
setODataServerErrorException(exception);
}
public boolean getIsValidXMLMetadata() {
return isValidXMLMetadata.get();
}
private void setIsValidXMLMetadata(boolean isValid) {
isValidXMLMetadata.set(isValid);
}
public boolean getIsValidEdm() {
return isValidEdm.get();
}
private void setIsValidEdm(boolean isValid) {
isValidEdm.set(isValid);
}
public boolean getIsValidXMLMetadataXML() {
return isValidXMLMetadataXML.get();
}
private void setIsValidXMLMetadataXML(boolean isValid) {
isValidXMLMetadataXML.set(isValid);
}
public boolean getHaveMetadataBeenRequested() {
return haveMetadataBeenRequested.get();
}
public boolean getShowResponses() {
return showResponses.get();
}
public void setShowResponses(Boolean value) {
showResponses.set(value);
}
public boolean getIsValidDataSystem() {
return isDataSystemValid.get();
}
public final boolean hasValidMetadata() {
return xmlMetadata.get() != null && getIsValidXMLMetadata()
&& xmlResponseData.get() != null && getIsValidXMLMetadataXML()
&& edm.get() != null && getIsValidEdm();
}
public final WebAPITestContainer validateMetadata() {
assertNotNull(getDefaultErrorMessage("no XML response data found!"), getXMLResponseData());
validateXMLMetadataXML();
setXMLMetadata(Commander.deserializeXMLMetadata(getXMLResponseData(), getCommander().getClient()));
validateXMLMetadata();
setEdm(Commander.deserializeEdm(getXMLResponseData(), getCommander().getClient()));
validateEdm();
return this;
}
public WebAPITestContainer validateDataSystem() {
if (getResponseData() != null) {
try {
JsonSchemaFactory factory = JsonSchemaFactory.getInstance();
InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("datasystem.schema.4.json");
JsonSchema schema = factory.getSchema(is);
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(getResponseData());
if (node.findPath(JSON_VALUE_PATH).size() > 0) {
schemaValidationErrors.set(schema.validate(node));
if (getSchemaValidationErrors().size() > 0) {
LOG.error("ERROR: JSON Schema validation errors were found!");
getSchemaValidationErrors().forEach(LOG::error);
} else {
LOG.info("DataSystem response matches reference schema!");
isDataSystemValid.set(true);
}
}
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
}
return this;
}
public WebAPITestContainer validateEdm() {
try {
assertNotNull("ERROR: No Entity Data Model (Edm) Exists!", getEdm());
boolean isValid = getCommander().validateMetadata(getEdm());
setIsValidEdm(isValid);
LOG.info("Edm Metadata is " + (isValid ? "valid" : "invalid") + "!");
} catch (Exception ex) {
fail("ERROR: could not validate Edm Metadata!\n" + ex.toString());
}
return this;
}
public WebAPITestContainer validateXMLMetadata() {
try {
//note that this will lazy-load XML metadata when it's not present
assertNotNull(getDefaultErrorMessage("XML metadata was not found!"), getXMLMetadata());
boolean isValid = getCommander().validateMetadata(getXMLMetadata());
setIsValidXMLMetadata(isValid);
LOG.info("XML Metadata is " + (isValid ? "valid" : "invalid") + "!");
} catch (Exception ex) {
fail("ERROR: could not validate XML Metadata!\n" + ex.toString());
}
return this;
}
public WebAPITestContainer validateXMLMetadataXML() {
LOG.info("Validating XML Metadata response to ensure it's valid XML and matches OASIS OData XSDs...");
LOG.info("See: https://docs.oasis-open.org/odata/odata/v4.0/errata03/os/complete/schemas/");
assertNotNull("XML response data were not found in the test container! Please ensure the XML Metadata request succeeded.",
getXMLResponseData());
try {
boolean isValid = Commander.validateXML(getXMLResponseData());
setIsValidXMLMetadataXML(isValid);
LOG.info("XMLMetadata string is " + (isValid ? "valid" : "invalid") + " XML!");
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
return this;
}
public WebAPITestContainer validateJSON() {
assertNotNull(getDefaultErrorMessage("JSON response data were not found in the test container! Please ensure your request succeeded.",
getResponseData()));
try {
assertTrue("ERROR: invalid JSON response!", TestUtils.isValidJson(getResponseData()));
LOG.info("Response is valid JSON!");
if (getShowResponses())
LOG.info("Response: " + new ObjectMapper().readTree(getResponseData()).toPrettyString());
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
return this;
}
public Set<ValidationMessage> getSchemaValidationErrors() {
return schemaValidationErrors.get();
}
public static final class ODATA_QUERY_PARAMS {
private static String format = DOLLAR_SIGN + "%s";
//TODO: add additional items as needed, and see if there's a lib for this in Olingo
public static final String
COUNT = String.format(format, QueryOption.COUNT),
EXPAND = String.format(format, QueryOption.EXPAND),
FILTER = String.format(format, QueryOption.FILTER),
ORDERBY = String.format(format, QueryOption.ORDERBY),
SELECT = String.format(format, QueryOption.SELECT),
SEARCH = String.format(format, QueryOption.SEARCH),
SKIP = String.format(format, QueryOption.SKIP),
TOP = String.format(format, QueryOption.TOP);
}
}

View File

@ -1,6 +1,6 @@
package org.reso.common;
package org.reso.commander.common;
import static org.reso.commander.certfication.containers.WebApiTestContainer.EMPTY_STRING;
import static org.reso.commander.certfication.containers.WebAPITestContainer.SINGLE_SPACE;
public final class ErrorMsg {
private static final String ERROR_MESSAGE_TEMPLATE = "ERROR: %s";
@ -8,24 +8,27 @@ public final class ErrorMsg {
/**
* Formats the given items with the default error message
*
* @param msgs the list of messages to display
* @return a string containing the default error message for display
*/
public static String getDefaultErrorMessage(final String... msgs) {
return String.format(ERROR_MESSAGE_TEMPLATE, String.join(EMPTY_STRING, msgs));
return String.format(ERROR_MESSAGE_TEMPLATE, String.join(SINGLE_SPACE, msgs));
}
/**
* Formats error message using the default template
*
* @param ex the exception whose toString() method should be called
* @return formatted error message using the default format
*/
public static String getDefaultErrorMessage(final Exception ex) {
return String.format(ex.toString());
return getDefaultErrorMessage(ex.toString());
}
/**
* Specialized Assert code formatter
*
* @param assertedResponseCode the response code that was asserted
* @param serverResponseCode the server response code that was returned
* @return the formatted error message for this case

View File

@ -1,4 +1,4 @@
package org.reso.commander;
package org.reso.commander.common;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.Header;
@ -320,6 +320,7 @@ public final class TestUtils {
/**
* Helper method to find headers with a given key in an an array of headers
*
* @param key the header to get
* @param headers an array containing Header objects
* @return the value of the header with key, or null
@ -337,6 +338,7 @@ public final class TestUtils {
/**
* Helper method to unpack headers from a raw OData response
*
* @param key the header to get
* @param oDataResponse the OData raw response from the request
* @return the value of the header with key, or null

View File

@ -70,7 +70,9 @@ Overview:
prose specification document take precedence.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:edm="http://docs.oasis-open.org/odata/ns/edm" elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://docs.oasis-open.org/odata/ns/edm">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:edm="http://docs.oasis-open.org/odata/ns/edm"
elementFormDefault="qualified" attributeFormDefault="unqualified"
targetNamespace="http://docs.oasis-open.org/odata/ns/edm">
<xs:annotation>
<xs:documentation xml:lang="en">
Entity Data Model part of the Common Schema Definition Language
@ -570,7 +572,8 @@ Overview:
<xs:restriction base="xs:NCName">
<xs:maxLength value="511"/>
<!-- one or more SimpleIdentifiers separated by dots -->
<xs:pattern value="[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}(\.[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){0,}"/>
<xs:pattern
value="[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}(\.[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){0,}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="TQualifiedName">
@ -578,7 +581,8 @@ Overview:
<!--
a NamespaceName followed by a dot and a SimpleIdentifier
-->
<xs:pattern value="[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}(\.[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){1,}"/>
<xs:pattern
value="[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}(\.[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){1,}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="TEnumMemberList">
@ -591,7 +595,8 @@ Overview:
<!--
The below pattern represents the allowed identifiers in the ECMAScript specification plus the '.' for namespace qualification and the Collection() wrapper
-->
<xs:pattern value="Collection\([\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}(\.[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){1,}\)"/>
<xs:pattern
value="Collection\([\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}(\.[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){1,}\)"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
@ -601,7 +606,8 @@ Overview:
<!--
The below pattern represents the allowed identifiers in the ECMAScript specification plus the '.' for namespace qualification and the '/' for path segment separation
-->
<xs:pattern value="[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}([\./][\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){0,}"/>
<xs:pattern
value="[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}([\./][\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){0,}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="TPathWithTermSegments">
@ -613,7 +619,8 @@ Overview:
The below pattern represents the allowed identifiers in the ECMAScript specification plus the '/' for path segment separation and
the '.' for namespace qualification inside the segments.
-->
<xs:pattern value="@?[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}(([\./#@]|/@)[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){0,}(/$count)?"/>
<xs:pattern
value="@?[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}(([\./#@]|/@)[\p{L}\p{Nl}_][\p{L}\p{Nl}\p{Nd}\p{Mn}\p{Mc}\p{Pc}\p{Cf}]{0,}){0,}(/$count)?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="TClientFunction">
@ -796,7 +803,8 @@ Overview:
<!-- binary data in base64url encoding -->
<xs:simpleType name="binary">
<xs:restriction base="xs:string">
<xs:pattern value="([A-Za-z0-9_\-]{4})*([A-Za-z0-9_\-]{3}[A-Za-z0-9_\-]|[A-Za-z0-9_\-]{2}[AEIMQUYcgkosw048]=?|[A-Za-z0-9_\-][AQgw](==)?)?"/>
<xs:pattern
value="([A-Za-z0-9_\-]{4})*([A-Za-z0-9_\-]{3}[A-Za-z0-9_\-]|[A-Za-z0-9_\-]{2}[AEIMQUYcgkosw048]=?|[A-Za-z0-9_\-][AQgw](==)?)?"/>
</xs:restriction>
</xs:simpleType>
<!-- boolean without 0 and 1 -->

View File

@ -71,7 +71,9 @@ Overview:
prose specification document take precedence.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" xmlns:edm="http://docs.oasis-open.org/odata/ns/edm" elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://docs.oasis-open.org/odata/ns/edmx">
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx"
xmlns:edm="http://docs.oasis-open.org/odata/ns/edm" elementFormDefault="qualified"
attributeFormDefault="unqualified" targetNamespace="http://docs.oasis-open.org/odata/ns/edmx">
<xs:annotation>
<xs:documentation xml:lang="en">
Entity Data Model Wrapper part of the Common Schema Definition Language

View File

@ -7,7 +7,7 @@
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="\r${SIMPLE_PATTERN}" />
<PatternLayout pattern="\r${SIMPLE_PATTERN}"/>
</Console>
<File name="Log" fileName="${LOGFILE_NAME}" immediateFlush="false" append="false">
<PatternLayout pattern="${PATTERN}"/>
@ -18,8 +18,8 @@
<AppenderRef ref="Log"/>
</Logger>
<Root level="all">
<AppenderRef ref="Console" level="info" />
<AppenderRef ref="Log" />
<AppenderRef ref="Console" level="info"/>
<AppenderRef ref="Log"/>
</Root>
</Loggers>
</Configuration>

View File

@ -1,12 +0,0 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package org.reso.commander;
import org.junit.Test;
public class AppTest {
@Test public void testParameterDeserialization() {
//TODO
}
}

View File

@ -0,0 +1,29 @@
Feature: Commander Platinum Web API Test Container Tests
Background:
Given a Web API test container was created using the RESOScript "mock-platinum.resoscript"
And a Commander instance exists within the test container
Scenario: Test Container is Initialized using Token-Based Authentication
When sample metadata from "good-edmx-and-edm.xml" are loaded into the test container
And Settings are present in the test container
And an auth token is provided in "ClientSettings_BearerToken"
Then the Commander is created using auth token client mode
And the auth token has a value of "testTokenValue"
But the Commander is not created using client credentials mode
Scenario: Metadata validation returns true for known-good metadata
When sample metadata from "good-edmx-and-edm.xml" are loaded into the test container
Then metadata are valid
Scenario: Metadata validation returns false for known-bad metadata
When sample metadata from "bad-edmx-no-keyfield.xml" are loaded into the test container
Then metadata are invalid
Scenario: DataSystem validation returns true for known-good sample data
When sample JSON data from "good-datasystem.json" are loaded into the test container
Then schema validation passes for the sample DataSystem data
Scenario: DataSystem validation returns false for known-bad sample data
When sample JSON data from "bad-datasystem.json" are loaded into the test container
Then schema validation fails for the sample DataSystem data

View File

@ -0,0 +1,46 @@
Feature: Commander XML and Metadata Validation
Background:
Given an OData test client has been created
#######################################
# XML Validation Tests
#######################################
Scenario: XML Validation using OASIS reference XSDs
Given metadata were loaded from the sample resource "good-edmx-and-edm.xml"
When XML validation is performed on the resource data
Then XML validation succeeds
Scenario: XML Validation fails when XML are malformed
Given metadata were loaded from the sample resource "bad-edmx-unparsable-xml.xml"
When XML validation is performed on the resource data
Then XML validation fails
#######################################
# XML Metadata Validation Tests
#######################################
Scenario: XML Metadata validation succeeds when XML Metadata are valid
Given metadata were loaded from the sample resource "good-edmx-and-edm.xml"
When XML Metadata validation is performed on the resource data
Then XML Metadata validation succeeds
Scenario: XML Validation fails when XML Metadata are missing Key element in EntityType definition
Given metadata were loaded from the sample resource "bad-edmx-no-keyfield.xml"
When XML Metadata validation is performed on the resource data
Then XML Metadata validation fails
#######################################
# Edm Validation Tests
#######################################
Scenario: Edm validation succeeds when XML Metadata contain a valid Edm
Given metadata were loaded from the sample resource "good-edmx-and-edm.xml"
When Edm validation is performed on the resource data
Then Edm Metadata validation succeeds
Scenario: Edm validation fails when XML Metadata don't contain a valid service document
Given metadata were loaded from the sample resource "bad-edmx-wrong-edm-binding-target.xml"
When Edm validation is performed on the resource data
Then Edm Metadata validation fails

View File

@ -0,0 +1,127 @@
package org.reso.commander.test.stepdefs;
import io.cucumber.java8.En;
import org.apache.http.HttpStatus;
import org.reso.commander.certfication.containers.WebAPITestContainer;
import org.reso.commander.common.TestUtils;
import org.reso.models.Settings;
import java.io.File;
import java.net.URL;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.*;
import static org.reso.commander.common.ErrorMsg.getDefaultErrorMessage;
public class TestWebAPITestContainer implements En {
AtomicReference<WebAPITestContainer> testContainer = new AtomicReference<>();
public TestWebAPITestContainer() {
//background
Given("^a Web API test container was created using the RESOScript \"([^\"]*)\"$", (String fileName) -> {
try {
//get settings from mock RESOScript file
URL resource = getClass().getClassLoader().getResource(fileName);
assertNotNull(getDefaultErrorMessage("was unable to find the given RESOScript:", fileName), resource);
setTestContainer(new WebAPITestContainer());
getTestContainer().setSettings(Settings.loadFromRESOScript(new File(resource.getFile())));
assertNotNull(getDefaultErrorMessage("could not load mock RESOScript: " + resource.getFile()), getTestContainer().getSettings());
getTestContainer().initialize();
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
});
And("^sample metadata from \"([^\"]*)\" are loaded into the test container$", (String resourceName) -> {
assertNotNull(getDefaultErrorMessage("resourceName cannot be null!"), resourceName);
try {
String xmlMetadataString = loadResourceAsString(resourceName);
assertNotNull(getDefaultErrorMessage("could not load resourceName:", resourceName), xmlMetadataString);
getTestContainer().setResponseCode(HttpStatus.SC_OK);
getTestContainer().setXMLResponseData(xmlMetadataString);
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
});
/*
* auth settings validation
*/
When("^an auth token is provided in \"([^\"]*)\"$", (String clientSettingsAuthToken) -> {
String token = Settings.resolveParametersString(clientSettingsAuthToken, getTestContainer().getSettings());
assertNotNull(getDefaultErrorMessage("BearerToken is null in the ClientSettings section!"), token);
});
Then("^the Commander is created using auth token client mode$", () -> {
assertTrue(getDefaultErrorMessage("expected auth token Commander client!"),
getTestContainer().getCommander().isAuthTokenClient());
});
And("^the auth token has a value of \"([^\"]*)\"$", (String assertedTokenValue) -> {
assertEquals(getDefaultErrorMessage("asserted token value is not equal to the one provided in the container!"),
assertedTokenValue, getTestContainer().getAuthToken());
});
And("^a Commander instance exists within the test container$", () -> {
assertNotNull(getDefaultErrorMessage("Commander instance is null in the container!"),
getTestContainer().getCommander());
});
But("^the Commander is not created using client credentials mode$", () -> {
assertFalse(getDefaultErrorMessage("expected that the Commander was not using client credentials"),
getTestContainer().getCommander().isOAuth2Client());
});
And("^Settings are present in the test container$", () -> {
assertNotNull(getDefaultErrorMessage("settings were not found in the Web API test container!"),
getTestContainer().getSettings());
});
Then("^metadata are valid$", () -> {
getTestContainer().validateMetadata();
assertTrue(getDefaultErrorMessage("getIsMetadataValid() returned false when true was expected!"),
getTestContainer().hasValidMetadata());
});
Then("^metadata are invalid$", () -> {
getTestContainer().validateMetadata();
assertFalse(getDefaultErrorMessage("getIsMetadataValid() returned true when false was expected!"),
getTestContainer().hasValidMetadata());
});
When("^sample JSON data from \"([^\"]*)\" are loaded into the test container$", (String resourceName) -> {
getTestContainer().setResponseCode(HttpStatus.SC_OK);
getTestContainer().setResponseData(loadResourceAsString(resourceName));
});
Then("^schema validation passes for the sample DataSystem data$", () -> {
assertTrue(getDefaultErrorMessage("expected DataSystem to pass validation, but it failed!"),
getTestContainer().validateDataSystem().getIsValidDataSystem());
});
Then("^schema validation fails for the sample DataSystem data$", () -> {
assertFalse(getDefaultErrorMessage("expected DataSystem to fail validation, but it passed!"),
getTestContainer().validateDataSystem().getIsValidDataSystem());
});
}
/**
* Returns a string containing the contents of the given resource name
* @param resourceName the resource name to load
* @return string data from the resource
*/
public String loadResourceAsString(String resourceName) {
return TestUtils.convertInputStreamToString(getClass().getClassLoader().getResourceAsStream(resourceName));
}
private WebAPITestContainer getTestContainer() {
return testContainer.get();
}
private void setTestContainer(WebAPITestContainer testContainer) {
this.testContainer.set(testContainer);
}
}

View File

@ -0,0 +1,116 @@
package org.reso.commander.test.stepdefs;
import io.cucumber.java8.En;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.olingo.client.api.edm.xml.XMLMetadata;
import org.apache.olingo.commons.api.edm.Edm;
import org.reso.commander.Commander;
import org.reso.commander.common.TestUtils;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.*;
import static org.reso.commander.common.ErrorMsg.getDefaultErrorMessage;
/**
* Tests metadata validation methods
*/
public class TestXMLAndMetadataValidation implements En {
private static final Logger LOG = LogManager.getLogger(TestXMLAndMetadataValidation.class);
AtomicReference<String> xmlMetadataString = new AtomicReference<>();
AtomicReference<XMLMetadata> xmlMetadata = new AtomicReference<>();
AtomicReference<Edm> edm = new AtomicReference<>();
AtomicReference<Commander> commander = new AtomicReference<>();
//state variables
AtomicBoolean isXMLValid = new AtomicBoolean(false);
AtomicBoolean isXMLMetadataValid = new AtomicBoolean(false);
AtomicBoolean isEdmValid = new AtomicBoolean(false);
public TestXMLAndMetadataValidation() {
/*
* Background
*/
Given("^an OData test client has been created$", () -> {
commander.set(Commander.Builder.class.newInstance().build());
});
/*
* loads a test resource to a local string object by name
*/
Given("^metadata were loaded from the sample resource \"([^\"]*)\"$", (String resourceName) -> {
assertNotNull(getDefaultErrorMessage("ERROR: resource name cannot be null!", resourceName));
try {
xmlMetadataString.set(TestUtils.convertInputStreamToString(getClass().getClassLoader().getResourceAsStream(resourceName)));
assertNotNull("ERROR: no string data was loaded from the given resource!", xmlMetadataString.get());
} catch (Exception ex) {
LOG.error("An exception was thrown trying to load the given resource name: " + resourceName);
LOG.error(ex);
}
});
/*
* XML validation
*/
When("^XML validation is performed on the resource data$", () -> {
assertNotNull(getDefaultErrorMessage("resource data is null!", xmlMetadataString.get()));
isXMLValid.set(Commander.validateXML(xmlMetadataString.get()));
});
Then("^XML validation succeeds$", () -> {
assertTrue(getDefaultErrorMessage("expected XML validation to succeed but it failed!"), isXMLValid.get());
});
Then("^XML validation fails$", () -> {
assertFalse(getDefaultErrorMessage("expected XML validation to succeed but it failed!"), isXMLValid.get());
});
/*
* XML Metadata validation
*/
When("^XML Metadata validation is performed on the resource data$", () -> {
assertNotNull(getDefaultErrorMessage("resource data is null!", xmlMetadataString.get()));
try {
xmlMetadata.set(Commander.deserializeXMLMetadata(xmlMetadataString.get(), commander.get().getClient()));
assertNotNull(getDefaultErrorMessage("XML Metadata cannot be null!"), xmlMetadata.get());
isXMLMetadataValid.set(Commander.validateMetadata(xmlMetadata.get(), commander.get().getClient()));
} catch (Exception ex) {
fail(getDefaultErrorMessage("could not deserialize XML Metadata!"));
}
});
Then("^XML Metadata validation succeeds$", () -> {
assertTrue(getDefaultErrorMessage("expected XML validation to succeed but it failed!"), isXMLMetadataValid.get());
});
Then("^XML Metadata validation fails$", () -> {
assertFalse(getDefaultErrorMessage("expected XML validation to fail but it succeeded!"), isXMLMetadataValid.get());
});
/*
* Edm validation
*/
When("^Edm validation is performed on the resource data$", () -> {
try {
assertNotNull(getDefaultErrorMessage("resource data is null!", xmlMetadataString.get()));
edm.set(Commander.deserializeEdm(xmlMetadataString.get(), commander.get().getClient()));
isEdmValid.set(Commander.validateMetadata(edm.get(), commander.get().getClient()));
} catch (Exception ex) {
fail(getDefaultErrorMessage(ex));
}
});
Then("^Edm Metadata validation succeeds$", () -> {
assertTrue(getDefaultErrorMessage("expected Entity Data Model (Edm) to succeed but it failed!"), isEdmValid.get());
});
Then("^Edm Metadata validation fails$", () -> {
assertFalse(getDefaultErrorMessage("expected Entity Data Model (Edm) to fail but it succeeded!"), isEdmValid.get());
});
}
}

View File

@ -0,0 +1,14 @@
{
"odata.metadata": "http://localhost:2099/DataSystem/$metadata",
"value": [
{
"Name": "RESO_MLS",
"ServiceURI": "http://odata.reso.org/DataSystem",
"DateTimeStamp": "2014-04-11T12:02:48.509401-04:00",
"TransportVersion": "0.9",
"DataDictionaryVersion": "1.3",
"Description": "MISSING RESOURCES!",
"ID": "RESO_MLS"
}
]
}

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="org.reso.metadata.Resources">
<EntityType Name="Property">
<!-- NOTE: intentionally removed keyfield to cause invalid Edmx -->
<!-- <Key>-->
<!-- <PropertyRef Name="ListingKey"/>-->
<!-- </Key>-->
<Property Name="ListingKey" Type="Edm.String" MaxLength="255" Nullable="false"/>
<Property Name="ListingId" Type="Edm.String" MaxLength="255"/>
</EntityType>
<EnumType Name="FileAccess" UnderlyingType="Edm.Int32" IsFlags="true">
<Member Name="Read" Value="1"/>
<Member Name="Write" Value="2"/>
<Member Name="Create" Value="4"/>
<Member Name="Delete" Value="8"/>
</EnumType>
</Schema>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Default">
<EntityContainer Name="Container">
<EntitySet Name="Property" EntityType="org.reso.metadata.Resources.Property"/>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="org.reso.metadata.Resources">
<EntityType Name="Property">
<Key>
<PropertyRef Name="ListingKey"/>
</Key>
<Property Name="ListingKey" Type="Edm.String" MaxLength="255" Nullable="false"/>
<Property Name="ListingId" Type="Edm.String" MaxLength="255"/>
</EntityType>
</Schema>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Default">
<EntityContainer Name="Container">
<EntitySet Name="Property" EntityType="org.reso.metadata.Resources.Property"/>
</EntityContainer>
</Schema>
</edmx:DataServices>
<!-- NOTE: intentionally stray character-->'
</edmx:Edmx>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:DataServices>
<Schema Namespace="org.reso.metadata" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="Property">
<Key>
<PropertyRef Name="ListingKey"/>
</Key>
<Property Name="ListingKey" Nullable="false" Type="Edm.String"/>
<NavigationProperty Name="ListingPhotos" Type="Collection(org.reso.metadata.resources.Media)"/>
</EntityType>
<EntityContainer Name="EntityContainer">
<EntitySet EntityType="org.reso.metadata.resources.Property" Name="Property">
<NavigationPropertyBinding Path="ListingPhotos" Target="Media"/>
</EntitySet>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@ -0,0 +1,52 @@
{
"odata.metadata": "http://localhost:2099/DataSystem/$metadata",
"value": [
{
"Name": "RESO_MLS",
"ServiceURI": "http://odata.reso.org/DataSystem",
"DateTimeStamp": "2014-04-11T12:02:48.509401-04:00",
"TransportVersion": "0.9",
"DataDictionaryVersion": "1.3",
"Resources": [
{
"Name": "Property",
"ResourcePath": "Property",
"Description": "RESO Standard Property Resource",
"DateTimeStamp": "2014-04-11T12:02:48.509401-04:00",
"TimeZoneOffset": -5,
"Localizations": [
{
"Name": "Single Family",
"ResourcePath": "SingleFamily",
"Description": "Localized Single Family Residential Resource",
"DateTimeStamp": "2014-04-11T12:02:48.509401-04:00"
},
{
"Name": "Multi Family",
"ResourcePath": "MultiFamily",
"Description": "Localized Multi Family Residential Resource",
"DateTimeStamp": "2014-04-11T12:02:48.509401-04:00"
}
]
},
{
"Name": "Office",
"ResourcePath": "Office",
"Description": "RESO Standard Office Resource",
"DateTimeStamp": "2014-04-11T12:02:48.509401-04:00",
"TimeZoneOffset": -5,
"Localizations": []
},
{
"Name": "Member",
"ResourcePath": "Member",
"Description": "RESO Standard Member Resource",
"DateTimeStamp": "2014-04-11T12:02:48.509401-04:00",
"TimeZoneOffset": -5,
"Localizations": []
}
],
"ID": "RESO_MLS"
}
]
}

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
<edmx:DataServices>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="org.reso.metadata.Resources">
<EntityType Name="Property">
<Key>
<PropertyRef Name="ListingKey"/>
</Key>
<Property Name="ListingKey" Type="Edm.String" MaxLength="255" Nullable="false"/>
<Property Name="ModificationTimestamp" Type="Edm.DateTimeOffset"/>
</EntityType>
</Schema>
<Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Default">
<EntityContainer Name="Container">
<EntitySet Name="Property" EntityType="org.reso.metadata.Resources.Property"/>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>

View File

@ -0,0 +1,623 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
>>> To be used as a template for Web API Server 1.0.2 Platinum Certification <<<
NOTES:
* Anything marked REQUIRED should be filled in.
* Anything not market REQUIRED shouldn't have to be changed.
* Some items are marked OPTIONAL.
* Any item that has a blank Url will be skipped (which will be printed in the results).
Contact josh@reso.org with further questions.
-->
<!DOCTYPE OutputScript [
<!ELEMENT OutputScript (RESOScriptVersion|ClientSettings|Parameters|Requests)*>
<!ELEMENT RESOScriptVersion (#PCDATA)>
<!ELEMENT ClientSettings (WebAPIURI|AuthenticationType|BearerToken|ClientIdentification|ClientSecret|TokenURI|ClientScope)*>
<!ELEMENT WebAPIURI (#PCDATA)>
<!ELEMENT AuthenticationType (#PCDATA)>
<!ELEMENT BearerToken (#PCDATA)>
<!ELEMENT ClientIdentification (#PCDATA)>
<!ELEMENT ClientSecret (#PCDATA)>
<!ELEMENT TokenURI (#PCDATA)>
<!ELEMENT ClientScope (#PCDATA)>
<!ELEMENT Parameters (Parameter)*>
<!ELEMENT Parameter (#PCDATA)>
<!ATTLIST Parameter
Name CDATA #REQUIRED
Value CDATA #REQUIRED>
<!ELEMENT Requests (Request)*>
<!ELEMENT Request (#PCDATA)>
<!ATTLIST Request
OutputFile CDATA #REQUIRED
RequestId CDATA #REQUIRED
Url CDATA #REQUIRED>
]>
<OutputScript>
<!--
############################################################
Metadata
############################################################-->
<!-- The current version of this RESOScript -->
<RESOScriptVersion>2.0.2</RESOScriptVersion>
<!--
############################################################
Client Settings
TODO: deprecate ClientSettings and move them to Parameters
############################################################-->
<ClientSettings>
<!-- URLS -->
<WebAPIURI>https://api.reso.org/OData</WebAPIURI>
<!-- Credentials -->
<!-- AuthenticationType
This is the OAuth2 grant_type.
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/
-->
<!-- Grant Type: authorization_code -->
<AuthenticationType>authorization_code</AuthenticationType>
<BearerToken>testTokenValue</BearerToken>
<!-- Grant Type: client_credentials -->
<AuthenticationType>client_credentials</AuthenticationType>
<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>
<!--
############################################################
Parameters Section - add your testing variables here
############################################################-->
<Parameters>
<!--
############################################################
Service Configuration
############################################################-->
<!-- REQUIRED: Core - The name of the resource being tested. Should not be a path. -->
<Parameter Name="EndpointResource" Value="Property"/>
<!-- REQUIRED: Core - The DataSystems endpoint being tested
NOTE: the FULL DataSystems URL is required as it might not be relative to the Service Root.-->
<Parameter Name="EndpointDataSystem" Value="https://api.reso.org/OData/DataSystem"/>
<!--
############################################################
Required Fields and Values
############################################################-->
<!-- Note: some of the required values already have sample values provided. See later sections for their values.-->
<!-- REQUIRED: Core - Substitute key name from your Resource here, either Key or KeyNumeric -->
<Parameter Name="KeyOrKeyNumericField" Value="ListingKey"/>
<!-- REQUIRED: Core - Provide a value for the KeyOrKeyNumeric from your server
NOTE: if you are using Key instead of KeyNumeric values, wrap your Key in quotes: 'myUniqueKey123'
-->
<Parameter Name="KeyOrKeyNumericValue" Value="12345"/>
<!-- REQUIRED: Core - Integer Field. Should be one of: Type="Edm.Int16", Type="Edm.Int32", or Type="Edm.Int64" -->
<Parameter Name="IntegerField" 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="120.34342 35.13123123"/> <!-- "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
############################################################-->
<!-- IntegerField Sample Values-->
<Parameter Name="IntegerValueLow" Value="9"/>
<Parameter Name="IntegerValueHigh" Value="15"/>
<Parameter Name="IntegerNotFound" Value="-1"/>
<!-- Integer Field for "not" testing -->
<Parameter Name="FilterNotField" Value="*Parameter_IntegerField*"/>
<Parameter Name="FilterNotValue" Value="-1"/>
<!-- Platinum - String Fields for testing -->
<Parameter Name="ContainsValue" Value="M"/>
<Parameter Name="EndsWithValue" Value="Rd"/>
<Parameter Name="StartsWithValue" Value="M"/>
<Parameter Name="ToLowerValue" Value="main"/>
<Parameter Name="ToUpperValue" Value="MAIN"/>
<!-- Gold and Platinum: Date Fields for testing -->
<Parameter Name="DateTimeValue" Value="2018-12-31T23:55:55-09:00"/>
<Parameter Name="DateValue" Value="2018-12-31"/>
<Parameter Name="YearValue" Value="2018"/>
<Parameter Name="MonthValue" Value="12"/>
<Parameter Name="DayValue" Value="31"/>
<Parameter Name="TimeValue" Value="23:55:55"/>
<Parameter Name="HourValue" Value="23"/>
<Parameter Name="MinuteValue" Value="55"/>
<Parameter Name="SecondValue" Value="55"/>
<Parameter Name="FractionalValue" Value="30"/>
<!-- Platinum - GeoSpatial query values -->
<Parameter Name="GeoSpatialDistanceValue" Value="1000"/>
<Parameter Name="SRID" Value="4326"/>
<!--
############################################################
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: 404 Not Found - You shouldn't need to change this -->
<Parameter Name="404NotFound" Value="ResourceNotFound"/>
<!--
############################################################
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"/>
<!-- Required resource lists for Standard Resource Names requirement -->
<Parameter Name="WebAPI102_RequiredResourceList" Value="Property,Member,Office,Media"/>
<!-- Allowed Resources - Update to 1.8 once it's approved -->
<Parameter Name="DD17_WellKnownResourceList"
Value="Property,Member,Office,Contacts,ContactListings,HistoryTransactional,InternetTracking,Media,OpenHouse,OUID,Prospecting,Queue,Rules,SavedSearch,Showing,Teams"/>
<!-- Computed Has Value - uses SingleValueLookup field -->
<Parameter Name="FilterHasField" Value="*Parameter_SingleValueLookupField*"/>
<Parameter Name="FilterHasValue" Value="*Parameter_SingleValueLookupValue*"/>
<Parameter Name="FilterHasLookupNamespace" Value="*Parameter_SingleValueLookupNamespace*"/>
<Parameter Name="FilterHasLookupValue" Value="*Parameter_SingleLookupValue*"/>
<!-- Computed Enumeration Values - do not change -->
<Parameter Name="SingleValueLookupValue"
Value="*Parameter_SingleValueLookupNamespace*'*Parameter_SingleLookupValue*'"/>
<Parameter Name="FilterHasValueLookupValue"
Value="*Parameter_FilterHasLookupNamespace*'*Parameter_FilterHasLookupValue*'"/>
<Parameter Name="MultipleValueLookupValue1"
Value="*Parameter_MultipleValueLookupNamespace*'*Parameter_MultipleLookupValue1*'"/>
<Parameter Name="MultipleValueLookupValue2"
Value="*Parameter_MultipleValueLookupNamespace*'*Parameter_MultipleLookupValue2*'"/>
<!-- OPTIONAL: Useful for testing the OData Format Parameter - Value="?$format=application/xml" -->
<Parameter Name="OptionalMetadataFormatParameter" Value=""/>
<!--
############################################################
Optional Parameters. You should not need these
############################################################-->
<!-- OPTIONAL: System Specific Additional Required Parameters for Queries. Leave Blank if none. -->
<Parameter Name="RequiredParameters" Value=""/>
<Parameter Name="RequiredParametersFilter" Value=""/>
</Parameters>
<!--
############################################################
Requests Section - Queries used during testing,
DO NOT CHANGE
############################################################-->
<Requests>
<Request
RequestId="REQ-WA103-END3"
OutputFile="REQ-WA103-END3.metadata.xml"
Url="*ClientSettings_WebAPIURI*/$metadata*Parameter_OptionalMetadataFormatParameter*"
/>
<Request
RequestId="REQ-WA103-END2"
OutputFile="REQ-WA103-END2.datasystem.json"
Url="*Parameter_EndpointDataSystem*"
/>
<Request
RequestId="REQ-WA103-QR1"
OutputFile="REQ-WA103-QR1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*(*Parameter_KeyOrKeyNumericValue*)?$select=*Parameter_KeyOrKeyNumericField*,*Parameter_KeyOrKeyNumericField*"
/>
<Request
RequestId="REQ-WA103-QR3"
OutputFile="REQ-WA103-QR3.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QR4"
OutputFile="REQ-WA103-QR4.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QR5"
OutputFile="REQ-WA103-QR5.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO1.1"
OutputFile="REQ-WA103-QO1.1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$SeLeCt=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* eq *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO1.2"
OutputFile="REQ-WA103-QO1.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$FiLtEr=*Parameter_IntegerField* eq *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO1.3"
OutputFile="REQ-WA103-QO1.3.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_SortCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueLow**Parameter_RequiredParameters*&amp;$OrDeRbY=*Parameter_IntegerField* asc"
/>
<Request
RequestId="REQ-WA103-QO1.4"
OutputFile="REQ-WA103-QO1.4.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_SortCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueLow**Parameter_RequiredParameters*&amp;$oRdErBy=*Parameter_IntegerField* desc"
/>
<Request
RequestId="REQ-WA103-QO2"
OutputFile="REQ-WA103-QO2"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* eq *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO3"
OutputFile="REQ-WA103-QO3"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* ne *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO4"
OutputFile="REQ-WA103-QO4"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO5"
OutputFile="REQ-WA103-QO5.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* ge *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO6"
OutputFile="REQ-WA103-QO6.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* lt *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO7"
OutputFile="REQ-WA103-QO7.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* le *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO9"
OutputFile="REQ-WA103-QO9.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueLow* and *Parameter_IntegerField* lt *Parameter_IntegerValueHigh**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO10"
OutputFile="REQ-WA103-QO10.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueHigh* or *Parameter_IntegerField* lt *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO11"
OutputFile="REQ-WA103-QO11.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=not(*Parameter_FilterNotField* le *Parameter_FilterNotValue*)*Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO25"
OutputFile="REQ-WA103-QO25.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=date(*Parameter_TimestampField*) gt *Parameter_DateValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO26"
OutputFile="REQ-WA103-QO26.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=time(*Parameter_TimestampField*) lt *Parameter_TimeValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO26.2"
OutputFile="REQ-WA103-QO26.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=*Parameter_TimestampField* lt *Parameter_DateTimeValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO27"
OutputFile="REQ-WA103-QO27.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=*Parameter_TimestampField* le now()*Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QM7"
OutputFile="REQ-WA103-QM7.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_KeyOrKeyNumericField*,*Parameter_SingleValueLookupField*&amp;$filter=*Parameter_SingleValueLookupField* has *Parameter_SingleValueLookupValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QM8"
OutputFile="REQ-WA103-QM8.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_KeyOrKeyNumericField*,*Parameter_MultipleValueLookupField*&amp;$filter=*Parameter_MultipleValueLookupField* has *Parameter_MultipleValueLookupValue1**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QM8.2"
OutputFile="REQ-WA103-QM8.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_KeyOrKeyNumericField*,*Parameter_MultipleValueLookupField*&amp;$filter=*Parameter_MultipleValueLookupField* has *Parameter_MultipleValueLookupValue1* and *Parameter_MultipleValueLookupField* has *Parameter_MultipleValueLookupValue2**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO8"
OutputFile="REQ-WA103-QO8.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_FilterHasField*&amp;$filter=*Parameter_FilterHasField* has *Parameter_FilterHasValueLookupValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO28.1"
OutputFile="REQ-WA103-QO28.1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_SortCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*,*Parameter_TimestampField*&amp;$orderby=*Parameter_TimestampField* asc&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO28.2"
OutputFile="REQ-WA103-QO28.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_SortCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*,*Parameter_TimestampField*&amp;$orderby=*Parameter_TimestampField* asc"
/>
<Request
RequestId="REQ-WA103-QO28.3"
OutputFile="REQ-WA103-QO28.3.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_SortCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*,*Parameter_TimestampField*&amp;$orderby=*Parameter_TimestampField* desc&amp;$filter=*Parameter_IntegerField* gt *Parameter_IntegerValueLow**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO28.4"
OutputFile="REQ-WA103-QO28.4.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_SortCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*,*Parameter_TimestampField*&amp;$orderby=*Parameter_TimestampField* desc"
/>
<Request
RequestId="REQ-WA103-QO18.1"
OutputFile="REQ-WA103-QO18.1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_DateField*&amp;$filter=year(*Parameter_DateField*) eq *Parameter_YearValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO18.2"
OutputFile="REQ-WA103-QO18.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=year(*Parameter_TimestampField*) eq *Parameter_YearValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO19.1"
OutputFile="REQ-WA103-QO19.1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_DateField*&amp;$filter=month(*Parameter_DateField*) eq *Parameter_MonthValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO19.2"
OutputFile="REQ-WA103-QO19.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=month(*Parameter_TimestampField*) eq *Parameter_MonthValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO20.1"
OutputFile="REQ-WA103-QO20.1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_DateField*&amp;$filter=day(*Parameter_DateField*) eq *Parameter_DayValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO20.2"
OutputFile="REQ-WA103-QO20.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=day(*Parameter_TimestampField*) eq *Parameter_DayValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO21"
OutputFile="REQ-WA103-QO21.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=hour(*Parameter_TimestampField*) eq *Parameter_HourValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO22"
OutputFile="REQ-WA103-QO22.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=minute(*Parameter_TimestampField*) gt *Parameter_MinuteValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO23"
OutputFile="REQ-WA103-QO23.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=second(*Parameter_TimestampField*) lt *Parameter_SecondValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO24"
OutputFile="REQ-WA103-QO24.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_TimestampField*&amp;$filter=fractionalseconds(*Parameter_TimestampField*) lt *Parameter_FractionalValue**Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO29.1"
OutputFile="REQ-WA103-QO29.1.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_KeyOrKeyNumericField*,*Parameter_ExpandField*&amp;$expand=*Parameter_ExpandField*"
/>
<Request
RequestId="REQ-WA103-QO29.2"
OutputFile="REQ-WA103-QO29.2.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_KeyOrKeyNumericField*,*Parameter_ExpandField*&amp;$expand=*Parameter_ExpandField*&amp;$filter=PhotosCount gt 0"
/>
<Request
RequestId="REQ-WA103-QO29.3"
OutputFile="REQ-WA103-QO29.3.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_KeyOrKeyNumericField*,*Parameter_ExpandField*&amp;$expand=*Parameter_ExpandField**Parameter_RequiredParametersFilter*"
/>
<Request
RequestId="REQ-WA103-QM3"
OutputFile="REQ-WA103-QM3.json"
Url="*ClientSettings_WebAPIURI*/$any?$top=1"
/>
<Request
RequestId="REQ-WA103-QM4"
OutputFile="REQ-WA103-QM4_All.json"
Url="*ClientSettings_WebAPIURI*/$all?$top=1"
/>
<Request
RequestId="REQ-WA103-QM5.1"
OutputFile="REQ-WA103-QM5_GeoSpatialLongLat_PointGeo.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_GeoSpatialField*&amp;$filter=geo.distance(*Parameter_GeoSpatialField*, geography'SRID=*Parameter_SRID*;POINT(*Parameter_GeoSpatialValue*)' le *Parameter_GeoSpatialDistanceValue*"
/>
<Request
RequestId="REQ-WA103-QM5.2"
OutputFile="REQ-WA103-QM5_GeoSpatialLongLat_LatGT1_PointGeo.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_GeoSpatialField*&amp;$filter=geo.distance(*Parameter_GeoSpatialField*, geography'SRID=*Parameter_SRID*;POINT(*Parameter_GeoSpatialValue*)' le *Parameter_GeoSpatialDistanceValue* and *Parameter_GeoSpatialLatitudeField* gt 1"
/>
<Request
RequestId="REQ-WA103-QO12"
OutputFile="REQ-WA103-QO12_Grouping.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_IntegerField*&amp;$filter=(*Parameter_IntegerField* ge *Parameter_IntegerValueLow* and *Parameter_IntegerField* le *Parameter_IntegerValueHigh*) and (*Parameter_IntegerField* lt *Parameter_IntegerValueHigh* and *Parameter_IntegerField* gt *Parameter_IntegerValueLow*)*Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO13"
OutputFile="REQ-WA103-QO13.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_StringField*&amp;$filter=contains(*Parameter_StringField*,'*Parameter_ContainsValue*')*Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO14"
OutputFile="REQ-WA103-QO14_EndsWith.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_StringField*&amp;$filter=endswith(*Parameter_StringField*,'*Parameter_EndsWithValue*')*Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO15"
OutputFile="REQ-WA103-QO15_StartsWith.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_StringField*&amp;$filter=startswith(*Parameter_StringField*,'*Parameter_StartsWithValue*')*Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO16"
OutputFile="REQ-WA103-QO16_ToLowerEQ.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_StringField*&amp;$filter=tolower(*Parameter_StringField*) eq '*Parameter_ToLowerValue*'*Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-QO17"
OutputFile="REQ-WA103-QO17_ToUpperEQ.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_EndpointResource*?$top=*Parameter_TopCount*&amp;$select=*Parameter_KeyOrKeyNumericField*,*Parameter_StringField*&amp;$filter=toupper(*Parameter_StringField*) eq '*Parameter_ToUpperValue*'*Parameter_RequiredParameters*"
/>
<Request
RequestId="REQ-WA103-END1"
OutputFile="REQ-WA103-END1_Service.json"
Url="*ClientSettings_WebAPIURI*/"
/>
<!-- RESPONSE CODE SUPPORT -->
<Request
RequestId="REQ-WA103-RC3"
OutputFile="REQ-WA103-RC05_200OKRequest.json"
Url="ClientSettings_WebAPIURI*/*Parameter_200_OK*"
/>
<Request
RequestId="REQ-WA103-RC5"
OutputFile="REQ-WA103-RC05_400BadRequest.json"
Url="ClientSettings_WebAPIURI*/*Parameter_400BadRequest*"
/>
<Request
RequestId="REQ-WA103-RC07"
OutputFile="REQ-WA103-RC07_404NotFound.json"
Url="*ClientSettings_WebAPIURI*/*Parameter_404NotFound*"
/>
</Requests>
</OutputScript>