Added convenience methods for Gold and Platinum Web API Certs, Updated Docker Instructions and README
Tightened up metadata checking, including checking for given resource and select list. Added better debugging info. Updated README.
This commit is contained in:
parent
82456bcf14
commit
a3687b9f6a
187
README.md
187
README.md
|
@ -335,51 +335,99 @@ ability to run individual or multiple tests using tags.
|
|||
|
||||
### Web API Usage
|
||||
|
||||
The Commander may be run in automated testing mode for a Web API 1.0.2 Server Certification using a terminal. You do not need to use the Commander JAR file mentioned elsewhere in this step. Instead, you will run the tests using Gradle for automation against a clean copy of the latest Commander code.
|
||||
The Commander may be run in automated testing mode for a Web API 1.0.2 Server Certification using a terminal.
|
||||
You do not need to use the Commander JAR file mentioned elsewhere in this step.
|
||||
Instead, you will run the tests using Gradle for automation against a clean copy of the latest Commander code.
|
||||
|
||||
You will need to download the source code so you can run Gradle in the root of the directory. This assumes that you also have Java 8 (1.8.0) or above installed, as mentioned elsewhere in this [`README`](#getting-started).
|
||||
You will need to download the source code so you can run Gradle in the root of the directory.
|
||||
This assumes that you also have Java 8 (1.8.0) or above installed, as mentioned elsewhere in this [`README`](#getting-started).
|
||||
|
||||
First, change into the directory you want to work in and clone the Commander repository. You will need to have Git installed. Chances are you already do, to check, open a command line and type `git` and if it's present, it will print some info about the app. If not, [there are instructions here](https://git-scm.com/downloads).
|
||||
First, change into the directory you want to work in and clone the Commander repository.
|
||||
You will need to have Git installed.
|
||||
Chances are you already do, to check, open a command line and type `git` and if it's present,
|
||||
it will print some info about the app. If not, [there are instructions here](https://git-scm.com/downloads).
|
||||
|
||||
**MacOS or Linux**
|
||||
##### MacOS or Linux
|
||||
```
|
||||
$ git clone https://github.com/RESOStandards/web-api-commander.git
|
||||
```
|
||||
|
||||
**Windows**
|
||||
##### Windows
|
||||
```
|
||||
C:\> git clone https://github.com/RESOStandards/web-api-commander.git
|
||||
```
|
||||
|
||||
This will clone the repository into a directory called web-api-commander, which means you will have a fresh copy of the latest code to execute. To refresh the code after you have downloaded it, issue the command `$ git pull` in the root of the directory that was just created.
|
||||
This will clone the repository into a directory called web-api-commander relative to whatever directory you're currently in,
|
||||
which also means you'll have a fresh copy of the latest code to execute.
|
||||
|
||||
The Gradle wrapper provides a convenient way to automatically install Gradle when running tests. After you have cloned the repository, issuing the following command:
|
||||
To refresh the code after you have downloaded it, issue the command `$ git pull` in the root of the directory that was just created.
|
||||
|
||||
**MacOS or Linux**
|
||||
#### Running with the Gradle Wrapper
|
||||
The Gradle wrapper provides a convenient way to automatically install Gradle when running tests.
|
||||
|
||||
After you have cloned the repository, the task you run will depend on the level of Web API 1.0.2 Server Certification
|
||||
you're interested in.
|
||||
|
||||
Before you do that, however, you'll want to make sure that you are running the 6.2.2 version of Gradle.
|
||||
|
||||
In the project directory, perform one of the following steps:
|
||||
|
||||
##### MacOS or Linux
|
||||
```$ ./gradlew wrapper --gradle-version 6.2.2 --distribution-type all```
|
||||
|
||||
##### Windows
|
||||
```C:\path\to\web-api-commander> gradlew wrapper --gradle-version 6.2.2 --distribution-type all```
|
||||
|
||||
You should see a success message. For more information, [see here](https://docs.gradle.org/current/userguide/gradle_wrapper.html).
|
||||
|
||||
### Convenience Methods for Web API 1.0.2 Gold and Platinum Certification (Recommended)
|
||||
While you may use tags to filter tests as you choose, explained in the next section, it's convenient
|
||||
to be able to run a predefined set of tests for Gold or Platinum certification.
|
||||
|
||||
These tasks will also produce reports in the local `build` directory, named according to which test you ran.
|
||||
|
||||
#### Gold Certification
|
||||
|
||||
This will run the Gold tests against the Web API 1.0.2 Server provided as `WebAPIURI` in `your.resoscript` file.
|
||||
|
||||
##### MacOS or Linux
|
||||
```
|
||||
$ ./gradlew testWebAPIServer_1_0_2 -DpathToRESOScript=/path/to/your.resoscript
|
||||
$ ./gradlew testWebAPIServer_1_0_2_Gold -DpathToRESOScript=/path/to/your.resoscript -DshowResponses=true
|
||||
```
|
||||
|
||||
**Windows**
|
||||
##### Windows
|
||||
```
|
||||
C:\path\to\web-api-commander> gradlew.bat testWebAPIServer_1_0_2 -DpathToRESOScript=C:\path\to\your.resoscript
|
||||
C:\path\to\web-api-commander> gradlew testWebAPIServer_1_0_2_Gold -DpathToRESOScript=C:\path\to\your.resoscript -DshowResponses=true
|
||||
```
|
||||
|
||||
This will run the entirety of the tests against the Web API server provided as `WebAPIURI` in `your.resoscript` file. You can pass tags to filter on in order to run one or more tests matching the given tag.
|
||||
*Note: the first time you run these tasks, they will take some time as the environment is being configured behind the
|
||||
scenes and the code is being compiled from the contents of the source directory you downloaded in the previous step.
|
||||
|
||||
Note that the first time you run this command, it will take some time to complete as Gradle will download all dependencies and compile the application before running the test suite. *Note: this step will be Dockerized so it can be run with a single command in a Docker container in upcoming versions of the Commander.*
|
||||
#### Platinum Certification
|
||||
This will run the Platinum tests against the Web API 1.0.2 Server provided as `WebAPIURI` in `your.resoscript` file.
|
||||
|
||||
|
||||
To filter by tags, a command similar to the following would be used:
|
||||
|
||||
**MacOS or Linux**
|
||||
##### MacOS or Linux
|
||||
```
|
||||
$ gradle testWebAPIServer_1_0_2 -DpathToRESOScript=/path/to/your.resoscript -Dcucumber.filter.tags="@core"
|
||||
$ ./gradlew testWebAPIServer_1_0_2_Platinum -DpathToRESOScript=/path/to/your.resoscript -DshowResponses=true
|
||||
```
|
||||
|
||||
**Windows**
|
||||
##### Windows
|
||||
```
|
||||
C:\path\to\web-api-commander> gradlew.bat testWebAPIServer_1_0_2 -DpathToRESOScript=C:\path\to\your.resoscript -Dcucumber.filter.tags="@core"
|
||||
C:\path\to\web-api-commander> gradlew testWebAPIServer_1_0_2_Platinum -DpathToRESOScript=C:\path\to\your.resoscript -DshowResponses=true
|
||||
```
|
||||
|
||||
#### Advanced feature: Tag Filtering
|
||||
You may also filter by tags. These are the items in the Cucumber .feature files prefixed by an `@` symbol. Expressions
|
||||
may also be used with tags. See the [Cucumber Documentation](https://cucumber.io/docs/cucumber/api/#tags) for more information.
|
||||
|
||||
##### MacOS or Linux
|
||||
```
|
||||
$ gradle testWebAPIServer_1_0_2_Platinum -DpathToRESOScript=/path/to/your.resoscript -Dcucumber.filter.tags="@core"
|
||||
```
|
||||
|
||||
##### Windows
|
||||
```
|
||||
C:\path\to\web-api-commander> gradlew.bat testWebAPIServer_1_0_2_Platinum -DpathToRESOScript=C:\path\to\your.resoscript -Dcucumber.filter.tags="@core"
|
||||
```
|
||||
|
||||
This would run only the tests marked as `@core` in the
|
||||
|
@ -403,9 +451,11 @@ Please feel free to suggest additional tags that might be useful.
|
|||
|
||||
A sample of the runtime terminal output follows:
|
||||
|
||||
```
|
||||
@REQ-WA103-END3 @core @x.y.z @core-support-endorsement
|
||||
Scenario: REQ-WA103-END3 - CORE - Request and Validate Server Metadata
|
||||
```gherkin
|
||||
> Task :testWebApiServer_1_0_2_Platinum
|
||||
|
||||
@REQ-WA103-END3 @core @x.y.z @core-endorsement @metadata
|
||||
Scenario: Request and Validate Server Metadata
|
||||
|
||||
Using RESOScript: /path/to/your.resoscript
|
||||
Given a RESOScript file was provided
|
||||
|
@ -414,21 +464,35 @@ A sample of the runtime terminal output follows:
|
|||
And Client Settings and Parameters were read from the file
|
||||
|
||||
Bearer token loaded... first 4 characters: abcd
|
||||
Service root is: https://api.server.com/serviceRoot
|
||||
Service root is: https://api.server.com/
|
||||
And an OData client was successfully created from the given RESOScript
|
||||
|
||||
Request URI: https://api.server.com/serviceRoot/$metadata?$format=application/xml
|
||||
Request succeeded...185032 bytes received.
|
||||
When a GET request is made to the resolved Url in "REQ-WA103-END3"
|
||||
|
||||
Response code is: 200
|
||||
Then the server responds with a status code of 200
|
||||
|
||||
Response is valid XML!
|
||||
And the response is valid XML
|
||||
Fetching XMLMetadata with OData Client from: https://api.server.com/$metadata
|
||||
When a successful metadata request is made to the service root in "ClientSettings_WebAPIURI"
|
||||
|
||||
Metadata is valid!
|
||||
And the metadata returned is valid
|
||||
|
||||
Fetching Edm with OData Client from: https://api.server.com/$metadata
|
||||
Found EntityContainer for the given resource: 'Property'
|
||||
And the metadata contains the "Parameter_EndpointResource" resource
|
||||
|
||||
Searching metadata for fields in given select list: ListingKey,BedroomsTotal,StreetName,PropertyType,ListingContractDate,ModificationTimestamp,Latitude,Longitude
|
||||
Found: 'ListingKey'
|
||||
Found: 'BedroomsTotal'
|
||||
Found: 'StreetName'
|
||||
Found: 'PropertyType'
|
||||
Found: 'ListingContractDate'
|
||||
Found: 'ModificationTimestamp'
|
||||
Found: 'Latitude'
|
||||
Found: 'Longitude'
|
||||
And resource metadata for "Parameter_EndpointResource" contains the fields in "Parameter_SelectList"
|
||||
|
||||
|
||||
1 Scenarios (1 passed)
|
||||
7 Steps (7 passed)
|
||||
0m3.244s
|
||||
|
||||
```
|
||||
|
||||
This shows configuration parameters, requests, and responses in a lightweight-manner.
|
||||
|
@ -456,24 +520,73 @@ These commands should not be necessary for the normal use of the Commander. Ther
|
|||
A [Dockerfile](./Dockerfile) has been provided to dockerize the application.
|
||||
This can be used for CI/CD environments such as Jenkins or TravisCI. The following command will build an image for you:
|
||||
|
||||
|
||||
### Commander Features Other Than Automated Web API Testing
|
||||
```
|
||||
$ docker build -t darnjo/web-api-command .
|
||||
$ docker build -t web-api-commander .
|
||||
```
|
||||
|
||||
The usage for the docker container is the same for `web-api-commander.jar` presented above.
|
||||
|
||||
```
|
||||
$ docker run -it darnjo/web-api-commander --help
|
||||
$ docker run -it web-api-commander --help
|
||||
```
|
||||
|
||||
If you have input files you may need to mount your filesystem into the docker container
|
||||
|
||||
```
|
||||
$ docker run -it -v $PWD:/app darnjo/web-api-commander --validateMetadata --inputFile <pathInContainer>
|
||||
$ docker run -it -v $PWD:/app web-api-commander --validateMetadata --inputFile <pathInContainer>
|
||||
```
|
||||
|
||||
### Automated Web API Testing
|
||||
|
||||
You may also run the tests in a Docker container locally by issuing one of the following commands.
|
||||
Docker must be running on your local machine.
|
||||
|
||||
#### MacOS or Linux All-In-One Commands
|
||||
|
||||
|
||||
##### Gold
|
||||
```
|
||||
cd ~; \
|
||||
rm -rf commander-tmp/; \
|
||||
mkdir commander-tmp; \
|
||||
cd commander-tmp; \
|
||||
git clone https://github.com/RESOStandards/web-api-commander.git; \
|
||||
cd web-api-commander; \
|
||||
docker run --rm -u gradle -v "$PWD":/home/gradle/project -v /path/to/your/resoscripts:/home/gradle/project/resoscripts -w /home/gradle/project gradle gradle testWebAPIServer_1_0_2_Gold -DpathToRESOScript=/home/gradle/project/resoscripts/your.resoscript -DshowResponses=true
|
||||
```
|
||||
|
||||
##### Platinum
|
||||
|
||||
```
|
||||
cd ~; \
|
||||
rm -rf commander-tmp/; \
|
||||
mkdir commander-tmp; \
|
||||
cd commander-tmp; \
|
||||
git clone https://github.com/RESOStandards/web-api-commander.git; \
|
||||
cd web-api-commander; \
|
||||
docker run --rm -u gradle -v "$PWD":/home/gradle/project -v /path/to/your/resoscripts:/home/gradle/project/resoscripts -w /home/gradle/project gradle gradle testWebAPIServer_1_0_2_Platinum -DpathToRESOScript=/home/gradle/project/resoscripts/your.resoscript -DshowResponses=true
|
||||
```
|
||||
|
||||
Note that this will create a directory in your home directory for the project, and build artifacts and the log will be placed in that directory,
|
||||
which is also where you will end up after runtime.
|
||||
|
||||
|
||||
#### Windows All-In-One WIP
|
||||
|
||||
##### Gold
|
||||
|
||||
```
|
||||
cd C:\;mkdir commander-tmp;cd commander-tmp;git clone https://github.com/RESOStandards/web-api-commander.git;cd web-api-commander; docker run --rm -u gradle -v C:\current\path\web-api-commander:/home/gradle/project -v C:\path\to\your\resoscripts:/home/gradle/project/resoscripts -w /home/gradle/project gradle gradle testWebAPIServer_1_0_2_Gold -DpathToRESOScript=/home/gradle/project/resoscripts/your.resoscript -DshowResponses=true
|
||||
```
|
||||
|
||||
##### Platinum
|
||||
```
|
||||
cd C:\;mkdir commander-tmp;cd commander-tmp;git clone https://github.com/RESOStandards/web-api-commander.git;cd web-api-commander;docker run --rm -u gradle -v C:\current\path\web-api-commander:/home/gradle/project -v C:\path\to\your\resoscripts:/home/gradle/project/resoscripts -w /home/gradle/project gradle gradle testWebAPIServer_1_0_2_Platinum -DpathToRESOScript=/home/gradle/project/resoscripts/your.resoscript -DshowResponses=true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Logging
|
||||
|
||||
In the current version of the Commander, two logs are produced. One is outputted in the terminal at `INFO` level during runtime through `stdout`. A detailed log called `commander.log` will be outputted at runtime and will contain details down to the wire requests.
|
||||
|
|
38
build.gradle
38
build.gradle
|
@ -67,26 +67,54 @@ tasks.withType(JavaCompile) {
|
|||
options.deprecation = true
|
||||
}
|
||||
|
||||
// task for Web API Server Testing - this is what should be run in the command line
|
||||
task testWebApiServer_1_0_2() {
|
||||
|
||||
// task for Web API Server 1.0.2 Gold Testing
|
||||
task testWebApiServer_1_0_2_Gold() {
|
||||
dependsOn jar
|
||||
doLast {
|
||||
javaexec {
|
||||
main = "io.cucumber.core.cli.Main"
|
||||
classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
|
||||
systemProperties = System.getProperties()
|
||||
args = [
|
||||
'--strict',
|
||||
'--plugin',
|
||||
'pretty',
|
||||
'--plugin',
|
||||
'json:build/web-api-server-1.0.2.json',
|
||||
'json:build/web-api-server-1.0.2.gold.json',
|
||||
'--plugin',
|
||||
'html:build/web-api-server-1.0.2.html',
|
||||
'html:build/web-api-server-1.0.2.gold.html',
|
||||
'--glue',
|
||||
'org.reso.certification.stepdefs#WebAPIServer_1_0_2',
|
||||
'src/main/java/org/reso/certification/features',
|
||||
'--tags',
|
||||
'not @platinum'
|
||||
+ (systemProperties.get('cucumber.filter.tags') != null ? ' and ' + systemProperties.get('cucumber.filter.tags') : '')
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// task for Web API Server 1.0.2 Platinum Testing - currently equivalent to all, but generates a platinum-named report.
|
||||
task testWebApiServer_1_0_2_Platinum() {
|
||||
dependsOn jar
|
||||
doLast {
|
||||
javaexec {
|
||||
main = "io.cucumber.core.cli.Main"
|
||||
classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
|
||||
systemProperties = System.getProperties()
|
||||
args = [
|
||||
'--strict',
|
||||
'--plugin',
|
||||
'pretty',
|
||||
'--plugin',
|
||||
'json:build/web-api-server-1.0.2.platinum.json',
|
||||
'--plugin',
|
||||
'html:build/web-api-server-1.0.2.platinum.html',
|
||||
'--glue',
|
||||
'org.reso.certification.stepdefs#WebAPIServer_1_0_2',
|
||||
'src/main/java/org/reso/certification/features'
|
||||
]
|
||||
systemProperties = System.getProperties()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -7,5 +7,4 @@
|
|||
* in the user manual at https://docs.gradle.org/5.2.1/userguide/multi_project_builds.html
|
||||
*/
|
||||
|
||||
rootProject.name = 'web-api-commander'
|
||||
|
||||
rootProject.setName('web-api-commander')
|
||||
|
|
|
@ -6,12 +6,12 @@ Feature: Web API Server 1.0.2 Certification
|
|||
And Client Settings and Parameters were read from the file
|
||||
And an OData client was successfully created from the given RESOScript
|
||||
|
||||
@REQ-WA103-END3 @core @x.y.z @core-endorsement
|
||||
@REQ-WA103-END3 @core @x.y.z @core-endorsement @metadata
|
||||
Scenario: Request and Validate Server Metadata
|
||||
When a GET request is made to the resolved Url in "REQ-WA103-END3"
|
||||
Then the server responds with a status code of 200
|
||||
And the response is valid XML
|
||||
When a successful metadata request is made to the service root in "ClientSettings_WebAPIURI"
|
||||
And the metadata returned is valid
|
||||
And the metadata contains the "Parameter_EndpointResource" resource
|
||||
And resource metadata for "Parameter_EndpointResource" contains the fields in "Parameter_SelectList"
|
||||
|
||||
@REQ-WA103-END2 @core @x.y.z @core-endorsement
|
||||
Scenario: Data System Endpoint test
|
||||
|
|
|
@ -14,8 +14,11 @@ import org.apache.olingo.client.api.communication.ODataClientErrorException;
|
|||
import org.apache.olingo.client.api.communication.request.retrieve.ODataRawRequest;
|
||||
import org.apache.olingo.client.api.communication.response.ODataRawResponse;
|
||||
import org.apache.olingo.client.api.edm.xml.XMLMetadata;
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
|
||||
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmTimeOfDay;
|
||||
|
@ -28,7 +31,10 @@ import java.io.*;
|
|||
import java.net.URI;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.*;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.Year;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
@ -116,6 +122,10 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
serverODataHeaderVersion.set(Utils.getHeaderData(HEADER_ODATA_VERSION, cex.getHeaderInfo()));
|
||||
responseCode.set(cex.getStatusLine().getStatusCode());
|
||||
oDataClientErrorExceptionHandled.set(true);
|
||||
throw cex;
|
||||
} catch (Exception ex) {
|
||||
fail(ex.toString());
|
||||
throw ex;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
@ -127,12 +137,15 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
if (pathToRESOScript == null) {
|
||||
pathToRESOScript = System.getProperty("pathToRESOScript");
|
||||
}
|
||||
|
||||
assertNotNull("ERROR: pathToRESOScript must be present in command arguments, see README", pathToRESOScript);
|
||||
LOG.info("Using RESOScript: " + pathToRESOScript);
|
||||
});
|
||||
And("^Client Settings and Parameters were read from the file$", () -> {
|
||||
if (settings == null) {
|
||||
settings = Settings.loadFromRESOScript(new File(System.getProperty("pathToRESOScript")));
|
||||
}
|
||||
assertNotNull("ERROR: Settings could not be loaded.", settings);
|
||||
LOG.info("RESOScript loaded successfully!");
|
||||
});
|
||||
Given("^an OData client was successfully created from the given RESOScript$", () -> {
|
||||
|
@ -165,6 +178,10 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
.bearerToken(bearerToken)
|
||||
.useEdmEnabledClient(true)
|
||||
.build());
|
||||
|
||||
assertNotNull(commander.get());
|
||||
assertTrue("ERROR: Commander must either have a valid bearer token or Client Credentials configuration.",
|
||||
commander.get().isTokenClient() || (commander.get().isOAuthClient() && commander.get().getTokenUri() != null));
|
||||
});
|
||||
|
||||
|
||||
|
@ -180,13 +197,17 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* REQ-WA103-END3
|
||||
*/
|
||||
And("^the metadata returned is valid$", () -> {
|
||||
//store the metadata for later comparisons
|
||||
xmlMetadata.set(commander.get().getClient().getDeserializer(ContentType.APPLICATION_XML)
|
||||
.toMetadata(new ByteArrayInputStream(responseData.get().getBytes())));
|
||||
if (xmlMetadata.get() == null) {
|
||||
fail("ERROR: No XML Metadata Exists!");
|
||||
}
|
||||
|
||||
try {
|
||||
boolean isValid = commander.get().validateMetadata(xmlMetadata.get());
|
||||
LOG.info("Metadata is " + (isValid ? "valid" : "invalid") + "!");
|
||||
assertTrue(isValid);
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -194,6 +215,7 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* REQ-WA103-QR1
|
||||
*/
|
||||
And("^the provided \"([^\"]*)\" is returned in \"([^\"]*)\"$", (String parameterUniqueIdValue, String parameterUniqueId) -> {
|
||||
try {
|
||||
String expectedValueAsString = Settings.resolveParametersString(parameterUniqueIdValue, settings), resolvedValueAsString = null;
|
||||
Object resolvedValue = from(responseData.get()).get(Settings.resolveParametersString(parameterUniqueId, settings));
|
||||
|
||||
|
@ -213,6 +235,9 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
} else {
|
||||
assertEquals(expectedValueAsString, resolvedValue.toString());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -220,11 +245,13 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* REQ-WA103-QR3 - $select
|
||||
*/
|
||||
And("^data are present in fields contained within \"([^\"]*)\"$", (String parameterSelectList) -> {
|
||||
try {
|
||||
AtomicInteger numFieldsWithData = new AtomicInteger();
|
||||
List<String> fieldList = new ArrayList<>(Arrays.asList(Settings.resolveParametersString(parameterSelectList, settings).split(",")));
|
||||
|
||||
AtomicInteger numResults = new AtomicInteger();
|
||||
|
||||
|
||||
//iterate over the items and count the number of fields with data to determine whether there are data present
|
||||
from(responseData.get()).getList(JSON_VALUE_PATH, HashMap.class).forEach(item -> {
|
||||
if (item != null) {
|
||||
|
@ -246,6 +273,9 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
LOG.info("Percent Fill: 0% - no fields with data found!");
|
||||
}
|
||||
assertTrue(numFieldsWithData.get() > 0);
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -254,6 +284,7 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* $top=*Parameter_TopCount*
|
||||
*/
|
||||
And("^the results contain at most \"([^\"]*)\" records$", (String parameterTopCount) -> {
|
||||
try {
|
||||
List<String> items = from(responseData.get()).getList(JSON_VALUE_PATH);
|
||||
AtomicInteger numResults = new AtomicInteger(items.size());
|
||||
|
||||
|
@ -261,6 +292,9 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
LOG.info("Number of values returned: " + numResults.get() + ", top count is: " + topCount);
|
||||
|
||||
assertTrue(numResults.get() > 0 && numResults.get() <= topCount);
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -269,6 +303,7 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* $skip=*Parameter_TopCount*
|
||||
*/
|
||||
And("^a GET request is made to the resolved Url in \"([^\"]*)\" with \\$skip=\"([^\"]*)\"$", (String requirementId, String parameterTopCount) -> {
|
||||
try {
|
||||
int skipCount = Integer.parseInt(Settings.resolveParametersString(parameterTopCount, settings));
|
||||
LOG.info("Skip count is: " + skipCount);
|
||||
|
||||
|
@ -279,8 +314,12 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
URI requestUri = Commander.prepareURI(Settings.resolveParameters(settings.getRequests().get(requirementId), settings).getUrl() + "&$skip=" + skipCount);
|
||||
|
||||
executeGetRequest.apply(requestUri);
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
And("^data in the \"([^\"]*)\" fields are different in the second request than in the first$", (String parameterUniqueId) -> {
|
||||
try {
|
||||
List<POJONode> l1 = from(initialResponseData.get()).getJsonObject(JSON_VALUE_PATH);
|
||||
List<POJONode> l2 = from(responseData.get()).getJsonObject(JSON_VALUE_PATH);
|
||||
|
||||
|
@ -292,6 +331,9 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
LOG.info("Response Page 2: " + new POJONode(l2));
|
||||
|
||||
assertEquals(combinedCount, combined.size());
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
//==================================================================================================================
|
||||
|
@ -302,34 +344,47 @@ 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 \"([^\"]*)\"$", (String requirementId) -> {
|
||||
try {
|
||||
//reset local state each time a get request is run
|
||||
resetRequestState.run();
|
||||
|
||||
URI requestUri = Commander.prepareURI(Settings.resolveParameters(settings.getRequests().get(requirementId), settings).getUrl());
|
||||
executeGetRequest.apply(requestUri);
|
||||
} catch (Exception ex) {
|
||||
LOG.debug("Exception was thrown in " + this.getClass() + ": " + ex.toString());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Assert response code
|
||||
*/
|
||||
Then("^the server responds with a status code of (\\d+)$", (Integer assertedResponseCode) -> {
|
||||
try {
|
||||
LOG.info("Asserted Response Code: " + assertedResponseCode + ", Server Response Code: " + responseCode);
|
||||
assertTrue(responseCode.get() > 0 && assertedResponseCode > 0);
|
||||
assertEquals(assertedResponseCode.intValue(), responseCode.get().intValue());
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* validate XML wrapper
|
||||
*/
|
||||
And("^the response is valid XML$", () -> {
|
||||
try {
|
||||
assertTrue(Commander.validateXML(responseData.get()));
|
||||
LOG.info("Response is valid XML!");
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* validate JSON wrapper
|
||||
*/
|
||||
And("^the response is valid JSON$", () -> {
|
||||
try {
|
||||
assertTrue(Utils.isValidJson(responseData.get()));
|
||||
LOG.info("Response is valid JSON!");
|
||||
|
||||
|
@ -337,14 +392,9 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
if (Boolean.parseBoolean(showResponses)) {
|
||||
LOG.info("Response: " + new ObjectMapper().readTree(responseData.get()).toPrettyString());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Assert OData version
|
||||
*/
|
||||
And("^the server reports OData version \"([^\"]*)\"$", (String assertODataVersion) -> {
|
||||
LOG.info("Asserted version: " + assertODataVersion + ", Reported OData Version: " + serverODataHeaderVersion.get()); ;
|
||||
assertEquals(serverODataHeaderVersion.get(), assertODataVersion);
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -353,6 +403,7 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* TODO: make a general Header assertion function
|
||||
*/
|
||||
Then("^the server responds with a status code of (\\d+) if the server headers report OData version \"([^\"]*)\"$", (Integer assertedHttpResponseCode, String assertedODataVersion) -> {
|
||||
try {
|
||||
boolean versionsMatch = serverODataHeaderVersion.get().equals(assertedODataVersion),
|
||||
responseCodesMatch = responseCode.get().intValue() == assertedHttpResponseCode.intValue();
|
||||
|
||||
|
@ -362,6 +413,10 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
LOG.info("Asserted Response Code: " + assertedHttpResponseCode + ", Response code: " + responseCode.get());
|
||||
assertTrue(responseCodesMatch);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
//DEBUG only in this case as we are expecting an error and don't want to throw or print it
|
||||
LOG.debug(ex.toString());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -369,6 +424,7 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* and is used to select among the supported comparisons.
|
||||
*/
|
||||
And("^Integer data in \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String parameterFieldName, String op, String parameterAssertedValue) -> {
|
||||
try {
|
||||
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
int assertedValue = Integer.parseInt(Settings.resolveParametersString(parameterAssertedValue, settings));
|
||||
|
||||
|
@ -386,42 +442,58 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
});
|
||||
|
||||
assertTrue(result.get());
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* True if response has results, meaning value.length > 0
|
||||
*/
|
||||
And("^the response has results$", () -> {
|
||||
try {
|
||||
int count = from(responseData.get()).getList(JSON_VALUE_PATH, HashMap.class).size();
|
||||
LOG.info("Results count is: " + count);
|
||||
assertTrue(count > 0);
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* True if data are present in the response
|
||||
*/
|
||||
And("^the response has singleton results in \"([^\"]*)\"", (String parameterFieldName) -> {
|
||||
try {
|
||||
String value = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
boolean isPresent = from(responseData.get()).get() != null;
|
||||
LOG.info("Response value is: " + value);
|
||||
LOG.info("IsPresent: " + isPresent);
|
||||
assertTrue(isPresent);
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* True if results count less than or equal to limit
|
||||
*/
|
||||
And("^the number of results is less than or equal to \"([^\"]*)\"$", (String limitField) -> {
|
||||
try {
|
||||
int count = from(responseData.get()).getList(JSON_VALUE_PATH, HashMap.class).size(),
|
||||
limit = Integer.parseInt(Settings.resolveParametersString(limitField, settings));
|
||||
LOG.info("Results count is: " + count + ", Limit is: " + limit);
|
||||
assertTrue(count <= limit);
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* True if data in the lhs expression and rhs expressions pass the AND or OR condition given in andOrOp
|
||||
*/
|
||||
And("^Integer data in \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String parameterFieldName, String opLhs, String parameterAssertedLhsValue, String andOrOp, String opRhs, String parameterAssertedRhsValue) -> {
|
||||
try {
|
||||
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
Integer assertedLhsValue = Integer.parseInt(Settings.resolveParametersString(parameterAssertedLhsValue, settings)),
|
||||
assertedRhsValue = Integer.parseInt(Settings.resolveParametersString(parameterAssertedRhsValue, settings));
|
||||
|
@ -456,12 +528,16 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
assertTrue(itemResult.get());
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Date Comparison glue
|
||||
*/
|
||||
And("^Date data in \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String parameterFieldName, String op, String parameterAssertedValue) -> {
|
||||
try {
|
||||
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
AtomicReference<Date> fieldValue = new AtomicReference<>();
|
||||
AtomicReference<Date> assertedValue = new AtomicReference<>();
|
||||
|
@ -473,16 +549,21 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
try {
|
||||
fieldValue.set(Utils.parseDateFromEdmDateTimeOffsetString(item.get(fieldName).toString()));
|
||||
assertTrue(Utils.compare(fieldValue.get(), op, assertedValue.get()));
|
||||
} catch (Exception ex){
|
||||
LOG.error(ex.toString());
|
||||
} catch (Exception ex) {
|
||||
fail(ex.toString());
|
||||
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Time comparison glue
|
||||
*/
|
||||
And("^TimeOfDay data in \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String parameterFieldName, String op, String parameterAssertedValue) -> {
|
||||
try {
|
||||
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
AtomicReference<Time> fieldValue = new AtomicReference<>();
|
||||
AtomicReference<Time> assertedValue = new AtomicReference<>();
|
||||
|
@ -494,35 +575,42 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
try {
|
||||
fieldValue.set(Utils.parseTimeOfDayFromEdmDateTimeOffsetString(item.get(fieldName).toString()));
|
||||
assertTrue(Utils.compare(fieldValue.get(), op, assertedValue.get()));
|
||||
} catch (Exception ex){
|
||||
LOG.error(ex.toString());
|
||||
} catch (Exception ex) {
|
||||
LOG.error(ex.getMessage());
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Year comparison glue
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Timestamp comparison glue
|
||||
*/
|
||||
And("^DateTimeOffset data in \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String parameterFieldName, String op, String parameterAssertedValue) -> {
|
||||
try {
|
||||
Utils.assertDateTimeOffset(parameterFieldName, op, parameterAssertedValue, responseData.get());
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Timestamp comparison to now()
|
||||
*/
|
||||
And("^DateTimeOffset data in \"([^\"]*)\" \"([^\"]*)\" now\\(\\)$", (String parameterFieldName, String op) -> {
|
||||
try {
|
||||
Utils.assertDateTimeOffset(parameterFieldName, op, Timestamp.from(Instant.now()), responseData.get());
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Single-Valued enumerations
|
||||
*/
|
||||
And("^Single Valued Enumeration Data in \"([^\"]*)\" has \"([^\"]*)\"$", (String parameterFieldName, String parameterAssertedValue) -> {
|
||||
try {
|
||||
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
AtomicReference<String> fieldValue = new AtomicReference<>();
|
||||
AtomicReference<String> assertedValue = new AtomicReference<>();
|
||||
|
@ -538,6 +626,9 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
LOG.info("Assert True: " + fieldValue.get() + " equals " + assertedValue.get() + " ==> " + result.get());
|
||||
assertTrue(result.get());
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
|
@ -545,6 +636,7 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* TODO: turn array into JSON array and parse values from there
|
||||
*/
|
||||
And("^Multiple Valued Enumeration Data in \"([^\"]*)\" has \"([^\"]*)\"$", (String parameterFieldName, String parameterAssertedValue) -> {
|
||||
try {
|
||||
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
AtomicReference<String> fieldValue = new AtomicReference<>();
|
||||
AtomicReference<String> assertedValue = new AtomicReference<>();
|
||||
|
@ -560,12 +652,16 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
LOG.info("Assert True: " + fieldValue.get() + " has " + assertedValue.get() + " ==> " + result.get());
|
||||
assertTrue(result.get());
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Date comparison ordering (asc, desc).
|
||||
*/
|
||||
And("^DateTimeOffset data in \"([^\"]*)\" is sorted in \"([^\"]*)\" order$", (String parameterFieldName, String parameterOrderByDirection) -> {
|
||||
try {
|
||||
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
final String ASC = "asc", DESC = "desc";
|
||||
AtomicReference<String> orderBy = new AtomicReference<>(parameterOrderByDirection.toLowerCase());
|
||||
|
@ -592,10 +688,12 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
}
|
||||
count.getAndIncrement();
|
||||
} catch (EdmPrimitiveTypeException ptex) {
|
||||
LOG.error("ERROR: exception thrown parsing Timestamp from given string." + ptex);
|
||||
fail();
|
||||
fail(ptex.getMessage());
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
And("^\"([^\"]*)\" data in Date Field \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String stringDatePart, String parameterFieldName, String op, String parameterAssertedValue) -> {
|
||||
|
@ -614,13 +712,11 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
fieldValue.set(Utils.getDatePart(datePart.get(), item.get(fieldName)));
|
||||
assertTrue(Utils.compare(fieldValue.get(), operator.get(), assertedValue.get()));
|
||||
} catch (Exception ex){
|
||||
//fail();
|
||||
LOG.error("ERROR: exception thrown." + ex);
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
fail();
|
||||
LOG.error("ERROR: exception thrown." + ex);
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -629,6 +725,7 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* TODO: consolidate with Year comparison with Date Field
|
||||
*/
|
||||
And("^\"([^\"]*)\" data in Timestamp Field \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String stringDatePart, String parameterFieldName, String op, String parameterAssertedValue) -> {
|
||||
try {
|
||||
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
AtomicReference<Integer> fieldValue = new AtomicReference<>();
|
||||
AtomicReference<Integer> assertedValue = new AtomicReference<>();
|
||||
|
@ -644,13 +741,14 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
fieldValue.set(Utils.getTimestampPart(datePart.get(), item.get(fieldName).toString()));
|
||||
assertTrue(Utils.compare(fieldValue.get(), operator.get(), assertedValue.get()));
|
||||
} catch (Exception ex){
|
||||
fail();
|
||||
LOG.error("ERROR: exception thrown." + ex);
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
fail();
|
||||
LOG.error("ERROR: exception thrown." + ex);
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -658,6 +756,7 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
* String functions
|
||||
*/
|
||||
And("^String data in \"([^\"]*)\" \"([^\"]*)\" \"([^\"]*)\"$", (String parameterFieldName, String op, String parameterAssertedValue) -> {
|
||||
try {
|
||||
String fieldName = Settings.resolveParametersString(parameterFieldName, settings);
|
||||
AtomicReference<String> assertedValue = new AtomicReference<>(Settings.resolveParametersString(parameterAssertedValue, settings));
|
||||
AtomicReference<String> operator = new AtomicReference<>(op.toLowerCase());
|
||||
|
@ -665,8 +764,120 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
from(responseData.get()).getList(JSON_VALUE_PATH, HashMap.class).forEach(item -> {
|
||||
assertTrue(Utils.compare(item.get(fieldName).toString(), operator.get(), assertedValue.get()));
|
||||
});
|
||||
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Metadata validation methods
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Checks that metadata are accessible and contain the resource name specified in generic.resoscript
|
||||
*/
|
||||
And("^the metadata contains the \"([^\"]*)\" resource$", (String parameterResourceName) -> {
|
||||
final String resourceName = Settings.resolveParametersString(parameterResourceName, settings);
|
||||
AtomicReference<CsdlEntityContainer> entityContainer = new AtomicReference<>();
|
||||
|
||||
try {
|
||||
entityContainer.set(ODataHelper.findDefaultEntityContainer(commander.get(), xmlMetadata.get()));
|
||||
|
||||
assertNotNull("ERROR: server metadata does not contain the given resource name: " + resourceName,
|
||||
entityContainer.get().getEntitySet(resourceName));
|
||||
|
||||
LOG.info("Found EntityContainer for the given resource: '" + resourceName + "'");
|
||||
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
And("^resource metadata for \"([^\"]*)\" contains the fields in \"([^\"]*)\"$", (String parameterResourceName, String parameterSelectList) -> {
|
||||
final String FIELD_SEPARATOR = ",";
|
||||
final String selectList = Settings.resolveParametersString(parameterSelectList, settings);
|
||||
|
||||
try {
|
||||
final String resourceName = Settings.resolveParametersString(parameterResourceName, settings);
|
||||
List<String> fieldNames = Arrays.asList(selectList.split(FIELD_SEPARATOR));
|
||||
|
||||
//create field lookup
|
||||
Map<String, CsdlProperty> fieldMap = new HashMap<>();
|
||||
ODataHelper.findEntityTypesForEntityTypeName(commander.get(), xmlMetadata.get(), resourceName)
|
||||
.forEach(csdlProperty -> fieldMap.put(csdlProperty.getName(), csdlProperty));
|
||||
|
||||
LOG.info("Searching metadata for fields in given select list: " + selectList);
|
||||
fieldNames.forEach(fieldName -> {
|
||||
//trim string just in case spaces were used after the commas
|
||||
assertNotNull("ERROR: Field name '" + fieldName + "' is not present in server metadata!", fieldMap.get(fieldName.trim()));
|
||||
LOG.info("Found: '" + fieldName.trim() + "'");
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
When("^a successful metadata request is made to the service root in \"([^\"]*)\"$", (String clientSettingsServiceRoot) -> {
|
||||
final String serviceRoot = Settings.resolveParametersString(clientSettingsServiceRoot, settings);
|
||||
|
||||
assertEquals("ERROR: given service root doesn't match the one configured in the Commander", serviceRoot, commander.get().getServiceRoot());
|
||||
try {
|
||||
xmlMetadata.set(commander.get().getXMLMetadata());
|
||||
} catch (ODataClientErrorException cex) {
|
||||
responseCode.set(cex.getStatusLine().getStatusCode());
|
||||
fail(cex.getMessage());
|
||||
} catch (Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private static final class ODataHelper {
|
||||
/**
|
||||
* Finds the default entity container for the given configuration.
|
||||
* @param commander a commander instance with a valid service root.
|
||||
* @param xmlMetadata XML Metadata to search through
|
||||
* @return the default CSDL Container for the given XMLMetadata
|
||||
* @throws Exception if required metadata cannot be parsed, an exception will be thrown with an appropriate message.
|
||||
*/
|
||||
private static CsdlEntityContainer findDefaultEntityContainer(Commander commander, XMLMetadata xmlMetadata) throws Exception {
|
||||
Edm edm = commander.getEdm();
|
||||
if (edm == null)
|
||||
throw new Exception("ERROR: Could not retrieve Edm from server using the given service root!");
|
||||
|
||||
if (xmlMetadata == null)
|
||||
throw new Exception("ERROR: the provided XML metadata was null!");
|
||||
|
||||
if (edm.getEntityContainer() == null)
|
||||
throw new Exception("ERROR: Could not find default EntityContainer for service root: " + commander.getServiceRoot());
|
||||
|
||||
String entityContainerNamespace = edm.getEntityContainer().getNamespace();
|
||||
if (entityContainerNamespace == null)
|
||||
throw new Exception("ERROR: no default EntityContainer namespace could be found");
|
||||
|
||||
return xmlMetadata.getSchema(entityContainerNamespace).getEntityContainer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of CsdlProperty items for the given entityTypeName.
|
||||
* @param commander a Commander instance with a valid service root.
|
||||
* @param xmlMetadata the metadata to search.
|
||||
* @param entityTypeName the name of the entityType to search for. MUST be in the default EntityContainer.
|
||||
* @return a list of CsdlProperty items for the given entityTypeName
|
||||
* @throws Exception is thrown if the given metadata doesn't contain the given type name.
|
||||
*/
|
||||
private static List<CsdlProperty> findEntityTypesForEntityTypeName(Commander commander, XMLMetadata xmlMetadata, String entityTypeName) throws Exception {
|
||||
CsdlEntityContainer entityContainer = findDefaultEntityContainer(commander, xmlMetadata);
|
||||
CsdlSchema schemaForType = xmlMetadata.getSchema(entityContainer.getEntitySet(entityTypeName).getTypeFQN().getNamespace());
|
||||
|
||||
if (schemaForType == null)
|
||||
throw new Exception("ERROR: could not find type corresponding to given type name: " + entityTypeName);
|
||||
|
||||
return schemaForType.getEntityType(entityTypeName).getProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -766,7 +977,6 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
} else if (operator.contentEquals(Operators.LESS_THAN_OR_EQUAL)) {
|
||||
result = lhs <= rhs;
|
||||
}
|
||||
|
||||
LOG.info("Compare: " + lhs + " " + operator + " " + rhs + " ==> " + result);
|
||||
return result;
|
||||
}
|
||||
|
@ -793,8 +1003,7 @@ public class WebAPIServer_1_0_2 implements En {
|
|||
} else if (operator.contentEquals(Operators.TO_UPPER)) {
|
||||
result = lhs.toUpperCase().equals(rhs);
|
||||
}
|
||||
|
||||
LOG.info("Compare: " + operator + "(" + lhs + ") == " + rhs + " ==> " + result);
|
||||
LOG.info("Compare: \"" + lhs + "\" " + operator + " \"" + rhs + "\" ==> " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ public class App {
|
|||
if (request.getOutputFile().toLowerCase().contains(EDMX_EXTENSION.toLowerCase())) {
|
||||
//Main.main(new String[]{"-g", "org.reso.certification.stepdefs#WebAPIServer_1_0_2", "/home/jdarnell/work/reso/github/web-api-commander/src/main/java/org/reso/certification/features/web-api-server-1.0.2.feature"});
|
||||
if (validateMetadata(commander, outputFilePath)) {
|
||||
metadata = commander.getMetadata(outputFilePath);
|
||||
metadata = commander.getEdm(outputFilePath);
|
||||
} else {
|
||||
LOG.error("Error: Invalid metadata retrieved. Cannot continue!!");
|
||||
System.exit(NOT_OK);
|
||||
|
@ -248,7 +248,7 @@ public class App {
|
|||
if (cmd.hasOption(APP_OPTIONS.ACTIONS.GET_METADATA)) {
|
||||
APP_OPTIONS.validateAction(cmd, APP_OPTIONS.ACTIONS.GET_METADATA);
|
||||
|
||||
metadata = commander.getMetadata();
|
||||
metadata = commander.getEdm();
|
||||
getMetadataReport(metadata);
|
||||
|
||||
} else if (cmd.hasOption(APP_OPTIONS.ACTIONS.VALIDATE_METADATA)) {
|
||||
|
|
|
@ -1,25 +1,20 @@
|
|||
package org.reso.commander;
|
||||
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.input.ReaderInputStream;
|
||||
import org.apache.commons.io.output.WriterOutputStream;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.olingo.client.api.ODataClient;
|
||||
import org.apache.olingo.client.api.communication.ODataClientErrorException;
|
||||
import org.apache.olingo.client.api.communication.request.retrieve.EdmMetadataRequest;
|
||||
import org.apache.olingo.client.api.communication.response.ODataRawResponse;
|
||||
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
|
||||
import org.apache.olingo.client.api.domain.ClientEntity;
|
||||
import org.apache.olingo.client.api.domain.ClientEntitySet;
|
||||
import org.apache.olingo.client.api.edm.xml.Edmx;
|
||||
import org.apache.olingo.client.api.edm.xml.XMLMetadata;
|
||||
import org.apache.olingo.client.core.ODataClientFactory;
|
||||
import org.apache.olingo.client.core.domain.ClientEntitySetImpl;
|
||||
import org.apache.olingo.client.core.edm.ClientCsdlXMLMetadata;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.reso.auth.OAuth2HttpClientFactory;
|
||||
|
@ -52,7 +47,14 @@ public class Commander {
|
|||
private ODataClient client;
|
||||
private boolean useEdmEnabledClient;
|
||||
|
||||
String serviceRoot, bearerToken, clientId, clientSecret, authorizationUri, tokenUri, redirectUri, scope;
|
||||
private String serviceRoot;
|
||||
String bearerToken;
|
||||
String clientId;
|
||||
String clientSecret;
|
||||
String authorizationUri;
|
||||
String tokenUri;
|
||||
String redirectUri;
|
||||
String scope;
|
||||
boolean isTokenClient, isOAuthClient;
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(Commander.class);
|
||||
|
@ -69,6 +71,14 @@ public class Commander {
|
|||
this.client = client;
|
||||
}
|
||||
|
||||
public String getTokenUri() {
|
||||
return tokenUri;
|
||||
}
|
||||
|
||||
public String getServiceRoot() {
|
||||
return serviceRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder pattern for creating Commander instances.
|
||||
*/
|
||||
|
@ -167,24 +177,50 @@ public class Commander {
|
|||
//private constructor for internal use, use Builder to construct instances
|
||||
private Commander() { }
|
||||
|
||||
private Edm edm;
|
||||
private XMLMetadata xmlMetadata;
|
||||
|
||||
/**
|
||||
* Gets server metadata in Edm format.
|
||||
* <p>
|
||||
* @return XMLMetadata representation of the server metadata.
|
||||
* @implNote the data in this item are cached in the commander once fetched
|
||||
* @return Edm representation of the server metadata.
|
||||
*/
|
||||
public Edm getMetadata() {
|
||||
Edm metadata = null;
|
||||
public Edm getEdm() {
|
||||
if (edm == null) {
|
||||
try {
|
||||
LOG.info("Fetching Metadata from " + serviceRoot + "...");
|
||||
metadata = client.getRetrieveRequestFactory().getMetadataRequest(serviceRoot).execute().getBody();
|
||||
LOG.info("Transfer complete! KBytes received: " + (metadata.toString().getBytes().length / 1024));
|
||||
EdmMetadataRequest metadataRequest = client.getRetrieveRequestFactory().getMetadataRequest(serviceRoot);
|
||||
LOG.info("Fetching Edm with OData Client from: " + metadataRequest.getURI().toString());
|
||||
edm = metadataRequest.execute().getBody();
|
||||
} catch (ODataClientErrorException cex) {
|
||||
LOG.error(cex.getStackTrace());
|
||||
LOG.error("ERROR: could not retrieve Metadata for the given service root!");
|
||||
LOG.error(cex.getStatusLine().toString());
|
||||
throw cex;
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
return edm;
|
||||
}
|
||||
|
||||
public Edm getMetadata(String pathToXmlMetadata) {
|
||||
/**
|
||||
* Gets server metadata in XMLMetadata format.
|
||||
* @implNote the data in this item are cached in the commander once fetched
|
||||
* @return XMLMetadata representation of the server metadata.
|
||||
*/
|
||||
public XMLMetadata getXMLMetadata() {
|
||||
if (xmlMetadata == null) {
|
||||
try {
|
||||
EdmMetadataRequest metadataRequest = client.getRetrieveRequestFactory().getMetadataRequest(serviceRoot);
|
||||
LOG.info("Fetching XMLMetadata with OData Client from: " + metadataRequest.getURI().toString());
|
||||
xmlMetadata = metadataRequest.getXMLMetadata();
|
||||
} catch (ODataClientErrorException cex) {
|
||||
LOG.error("ERROR: could not retrieve Metadata for the given service root!");
|
||||
LOG.error(cex.getStatusLine().toString());
|
||||
throw cex;
|
||||
}
|
||||
}
|
||||
return xmlMetadata;
|
||||
}
|
||||
|
||||
public Edm getEdm(String pathToXmlMetadata) {
|
||||
try {
|
||||
return client.getReader().readMetadata(new FileInputStream(pathToXmlMetadata));
|
||||
} catch (FileNotFoundException fex) {
|
||||
|
@ -202,31 +238,6 @@ public class Commander {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts Edm to XMLMetadata
|
||||
* @param edm
|
||||
* @return the XMLMetadata representation of the given Edm
|
||||
*/
|
||||
private XMLMetadata convertEdmToXMLMetadata(Edm edm) {
|
||||
XMLMetadata xmlMetadata = null;
|
||||
try {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(edm.toString().getBytes());
|
||||
xmlMetadata = client.getDeserializer(ContentType.APPLICATION_XML).toMetadata(inputStream);
|
||||
} catch (Exception ex) {
|
||||
LOG.error(ex.getStackTrace());
|
||||
}
|
||||
return xmlMetadata;
|
||||
}
|
||||
|
||||
public boolean validateMetadata(Edm metadata) {
|
||||
try {
|
||||
return validateMetadata(convertEdmToXMLMetadata(metadata));
|
||||
} catch (Exception ex) {
|
||||
LOG.error(ex.getStackTrace());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates given XMLMetadata
|
||||
*
|
||||
|
@ -256,10 +267,8 @@ public class Commander {
|
|||
public boolean validateMetadata(InputStream inputStream) {
|
||||
try {
|
||||
// deserialize metadata from given file
|
||||
XMLMetadata metadata =
|
||||
client.getDeserializer(ContentType.APPLICATION_XML).toMetadata(inputStream);
|
||||
XMLMetadata metadata = client.getDeserializer(ContentType.APPLICATION_XML).toMetadata(inputStream);
|
||||
return validateMetadata(metadata);
|
||||
|
||||
} catch (Exception ex) {
|
||||
LOG.error("ERROR in validateMetadata! " + ex.toString() );
|
||||
}
|
||||
|
@ -283,6 +292,14 @@ public class Commander {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenClient() {
|
||||
return isTokenClient;
|
||||
}
|
||||
|
||||
public boolean isOAuthClient() {
|
||||
return isOAuthClient;
|
||||
}
|
||||
|
||||
public static boolean validateXML(String xmlString) {
|
||||
return validateXML(new ByteArrayInputStream(xmlString.getBytes(UTF_8)));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue