From 7a259d7fb97156bd3f822c0a9879ae2141e9501e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Pro=C3=9F?= Date: Wed, 18 Dec 2024 14:27:28 +0100 Subject: [PATCH 1/8] Adjust pom.xml --- pom.xml | 157 ++------------------------------------------------------ 1 file changed, 5 insertions(+), 152 deletions(-) diff --git a/pom.xml b/pom.xml index e913f22..7030c6f 100644 --- a/pom.xml +++ b/pom.xml @@ -3,10 +3,9 @@ org.opengis.cite ets-common - 6 + 14-SNAPSHOT 4.0.0 - org.opengis.cite ets-sta10 1.5-SNAPSHOT jar @@ -51,7 +50,6 @@ sta10 1.0 - 5.5.2 @@ -59,10 +57,6 @@ org.opengis.cite.teamengine teamengine-spi - - com.sun.jersey - jersey-client - junit junit @@ -74,36 +68,22 @@ org.json json - 20231013 org.apache.httpcomponents httpclient - 4.5.13 - - - joda-time - joda-time org.apache.httpcomponents httpcore - 4.4.1 org.testng testng - 6.8.21 - xml-apis - xml-apis - 1.4.01 - - - javax.ws.rs - jsr311-api - 1.1.1 + org.glassfish.jersey.connectors + jersey-apache-connector @@ -113,7 +93,6 @@ io.fabric8 docker-maven-plugin - 0.40.2 @@ -121,7 +100,7 @@ ${project.basedir}/src/docker - ${project.version}-teamengine-${docker.teamengine.version} + ${project.version}-teamengine-${teamengine.version} @@ -154,65 +133,9 @@ - - maven-dependency-plugin - 3.0.0 - - - - org.opengis.cite.teamengine - teamengine-web - ${docker.teamengine.version} - war - - - org.opengis.cite.teamengine - teamengine-web - ${docker.teamengine.version} - common-libs - zip - - - org.opengis.cite.teamengine - teamengine-console - ${docker.teamengine.version} - base - zip - - - - - - maven-javadoc-plugin - 2.10.2 - - true - package - - http://testng.org/javadocs/ - - - - - attach-javadocs - - jar - - - - - - maven-surefire-plugin - - - maven-compiler-plugin - - - maven-jar-plugin - maven-assembly-plugin @@ -223,80 +146,10 @@ - - maven-release-plugin - 2.5.3 - - true - @{project.version} - release - - - - maven-site-plugin - - - org.codehaus.mojo - buildnumber-maven-plugin - - - maven-scm-publish-plugin - 1.1 - - gh-pages - - - - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 2.9 - - - - license - issue-tracking - - - - - true - - - - - + - - release - - - - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - --pinentry-mode - loopback - - - - - - - - docker From 4b752a89a66322abdb519ad7a9efb3682ce4e14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Pro=C3=9F?= Date: Wed, 18 Dec 2024 14:27:36 +0100 Subject: [PATCH 2/8] Adjust code --- .../org/opengis/cite/sta10/CommonFixture.java | 18 +- .../cite/sta10/ReusableEntityFilter.java | 26 +-- .../opengis/cite/sta10/SuiteAttribute.java | 3 +- .../cite/sta10/SuiteFixtureListener.java | 14 +- .../cite/sta10/TestFailureListener.java | 16 +- .../opengis/cite/sta10/util/ClientUtils.java | 203 ++++++++---------- .../sta10/VerifySuiteFixtureListener.java | 43 ++-- 7 files changed, 152 insertions(+), 171 deletions(-) diff --git a/src/main/java/org/opengis/cite/sta10/CommonFixture.java b/src/main/java/org/opengis/cite/sta10/CommonFixture.java index c4e2bdc..58c5777 100644 --- a/src/main/java/org/opengis/cite/sta10/CommonFixture.java +++ b/src/main/java/org/opengis/cite/sta10/CommonFixture.java @@ -1,13 +1,9 @@ package org.opengis.cite.sta10; -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.ClientRequest; -import com.sun.jersey.api.client.ClientResponse; - import java.net.URI; import java.util.Map; -import javax.ws.rs.core.MediaType; +import org.glassfish.jersey.client.ClientRequest; import org.opengis.cite.sta10.util.ClientUtils; import org.testng.ITestContext; import org.testng.SkipException; @@ -15,6 +11,10 @@ import org.testng.annotations.BeforeMethod; import org.w3c.dom.Document; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + /** * A supporting base class that sets up a common test fixture. These * configuration methods are invoked before those defined in a subclass. @@ -36,7 +36,7 @@ public class CommonFixture { /** * An HTTP response message. */ - protected ClientResponse response; + protected Response response; /** * Initializes the common test fixture with a client component for @@ -75,7 +75,7 @@ public void clearMessages() { * @see ClientUtils#getResponseEntityAsDocument(com.sun.jersey.api.client.ClientResponse, * java.lang.String) */ - public Document getResponseEntityAsDocument(ClientResponse response, + public Document getResponseEntityAsDocument(Response response, String targetURI) { return ClientUtils.getResponseEntityAsDocument(response, targetURI); } @@ -89,11 +89,11 @@ public Document getResponseEntityAsDocument(ClientResponse response, * @param qryParams A Map containing query parameters (may be null); * @param mediaTypes A list of acceptable media types; if not specified, * generic XML ("application/xml") is preferred. - * @return A ClientRequest object. + * @return A Response object. * @see ClientUtils#buildGetRequest(java.net.URI, java.util.Map, * javax.ws.rs.core.MediaType...) */ - public ClientRequest buildGetRequest(URI endpoint, + public Response buildGetRequest(URI endpoint, Map qryParams, MediaType... mediaTypes) { return ClientUtils.buildGetRequest(endpoint, qryParams, mediaTypes); } diff --git a/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java b/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java index a16ad47..5c14743 100644 --- a/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java +++ b/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java @@ -1,9 +1,12 @@ package org.opengis.cite.sta10; -import com.sun.jersey.api.client.ClientHandlerException; -import com.sun.jersey.api.client.ClientRequest; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.filter.ClientFilter; +import java.io.IOException; + +import org.glassfish.jersey.client.ClientResponse; + +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientResponseContext; +import jakarta.ws.rs.client.ClientResponseFilter; /** * Buffers the (response) entity so it can be read multiple times. @@ -11,16 +14,15 @@ *

WARNING: The entity InputStream must be reset after each * read attempt.

*/ -public class ReusableEntityFilter extends ClientFilter { +public class ReusableEntityFilter implements ClientResponseFilter { + /** {@inheritDoc} */ @Override - public ClientResponse handle(ClientRequest req) throws ClientHandlerException { - // leave request entity--it can usually be read multiple times - ClientResponse rsp = getNext().handle(req); - if (rsp.hasEntity()) { - rsp.bufferEntity(); - } - return rsp; + public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { + if (responseContext instanceof ClientResponse) { + ((ClientResponse) responseContext).bufferEntity(); + } } } + diff --git a/src/main/java/org/opengis/cite/sta10/SuiteAttribute.java b/src/main/java/org/opengis/cite/sta10/SuiteAttribute.java index ef7cc58..4a13390 100644 --- a/src/main/java/org/opengis/cite/sta10/SuiteAttribute.java +++ b/src/main/java/org/opengis/cite/sta10/SuiteAttribute.java @@ -1,8 +1,9 @@ package org.opengis.cite.sta10; -import com.sun.jersey.api.client.Client; import org.w3c.dom.Document; +import jakarta.ws.rs.client.Client; + /** * An enumerated type defining ISuite attributes that may be set to constitute a * shared test fixture. diff --git a/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java b/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java index 29a718c..a000189 100644 --- a/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java +++ b/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java @@ -1,9 +1,13 @@ package org.opengis.cite.sta10; -import com.sun.jersey.api.client.Client; - -import java.io.*; -import java.net.*; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; @@ -16,6 +20,8 @@ import org.testng.ISuite; import org.testng.ISuiteListener; +import jakarta.ws.rs.client.Client; + /** * A listener that performs various tasks before and after a test suite is run, * usually concerned with maintaining a shared test suite fixture. Since this diff --git a/src/main/java/org/opengis/cite/sta10/TestFailureListener.java b/src/main/java/org/opengis/cite/sta10/TestFailureListener.java index 4c57101..22fd58a 100644 --- a/src/main/java/org/opengis/cite/sta10/TestFailureListener.java +++ b/src/main/java/org/opengis/cite/sta10/TestFailureListener.java @@ -1,16 +1,16 @@ package org.opengis.cite.sta10; -import com.sun.jersey.api.client.ClientRequest; -import com.sun.jersey.api.client.ClientResponse; - import java.nio.charset.StandardCharsets; -import javax.ws.rs.core.MediaType; +import org.glassfish.jersey.client.ClientRequest; import org.opengis.cite.sta10.util.ClientUtils; import org.testng.ITestResult; import org.testng.TestListenerAdapter; import org.w3c.dom.Document; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; + /** * A listener that augments a test result with diagnostic information in the * event that a test method failed. This information will appear in the XML @@ -52,7 +52,7 @@ String getRequestMessageInfo(ClientRequest req) { } StringBuilder msgInfo = new StringBuilder(); msgInfo.append("Method: ").append(req.getMethod()).append('\n'); - msgInfo.append("Target URI: ").append(req.getURI()).append('\n'); + msgInfo.append("Target URI: ").append(req.getUri()).append('\n'); msgInfo.append("Headers: ").append(req.getHeaders()).append('\n'); if (null != req.getEntity()) { Object entity = req.getEntity(); @@ -74,7 +74,7 @@ String getRequestMessageInfo(ClientRequest req) { * @return A string containing information gleaned from the response * message. */ - String getResponseMessageInfo(ClientResponse rsp) { + String getResponseMessageInfo(Response rsp) { if (null == rsp) { return "No response message."; } @@ -82,10 +82,10 @@ String getResponseMessageInfo(ClientResponse rsp) { msgInfo.append("Status: ").append(rsp.getStatus()).append('\n'); msgInfo.append("Headers: ").append(rsp.getHeaders()).append('\n'); if (rsp.hasEntity()) { - if (rsp.getType().isCompatible(MediaType.APPLICATION_XML_TYPE)) { + if (rsp.getMediaType().isCompatible(MediaType.APPLICATION_XML_TYPE)) { Document doc = ClientUtils.getResponseEntityAsDocument(rsp, null); } else { - byte[] body = rsp.getEntity(byte[].class); + byte[] body = rsp.readEntity(byte[].class); msgInfo.append(new String(body, StandardCharsets.UTF_8)); } msgInfo.append('\n'); diff --git a/src/main/java/org/opengis/cite/sta10/util/ClientUtils.java b/src/main/java/org/opengis/cite/sta10/util/ClientUtils.java index 247318e..5649049 100644 --- a/src/main/java/org/opengis/cite/sta10/util/ClientUtils.java +++ b/src/main/java/org/opengis/cite/sta10/util/ClientUtils.java @@ -1,173 +1,144 @@ package org.opengis.cite.sta10.util; -import java.io.IOException; -import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.SocketAddress; -import java.net.URL; - -import com.sun.jersey.api.client.Client; -import com.sun.jersey.api.client.ClientRequest; -import com.sun.jersey.api.client.ClientResponse; -import com.sun.jersey.api.client.config.ClientConfig; -import com.sun.jersey.api.client.config.DefaultClientConfig; -import com.sun.jersey.api.client.filter.LoggingFilter; -import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory; -import com.sun.jersey.client.urlconnection.URLConnectionClientHandler; - import java.net.URI; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import javax.ws.rs.HttpMethod; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.UriBuilder; + import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; +import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.logging.LoggingFeature; import org.opengis.cite.sta10.ReusableEntityFilter; import org.w3c.dom.Document; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Invocation; +import jakarta.ws.rs.client.Invocation.Builder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.UriBuilder; + /** * Provides various utility methods for creating and configuring HTTP client * components. */ public class ClientUtils { + private static final Logger LOGGER = Logger.getLogger(ClientUtils.class.getName()); + /** - * Builds a client component for interacting with HTTP endpoints. The client - * will automatically redirect to the URI declared in 3xx responses. The - * connection timeout is 10 s. Request and response messages may be logged - * to a JDK logger (in the namespace "com.sun.jersey.api.client"). - * + * Builds a client component for interacting with HTTP endpoints. The client will + * automatically redirect to the URI declared in 3xx responses. The connection timeout + * is 10 s. Request and response messages may be logged to a JDK logger (in the + * namespace "com.sun.jersey.api.client"). * @return A Client component. */ public static Client buildClient() { - ClientConfig config = new DefaultClientConfig(); - config.getProperties().put( - ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true); - config.getProperties().put( - ClientConfig.PROPERTY_CONNECT_TIMEOUT, 10000); - Client client = Client.create(config); - client.addFilter(new ReusableEntityFilter()); - client.addFilter(new LoggingFilter()); - return client; + ClientConfig config = new ClientConfig(); + config.property(ClientProperties.FOLLOW_REDIRECTS, true); + config.property(ClientProperties.CONNECT_TIMEOUT, 10000); + config.register(new LoggingFeature(LOGGER, Level.ALL, LoggingFeature.Verbosity.PAYLOAD_ANY, 5000)); + Client client = ClientBuilder.newClient(config); + client.register(new ReusableEntityFilter()); + return client; } /** - * Constructs a client component that uses a specified web proxy. Proxy - * authentication is not supported. Configuring the client to use an - * intercepting proxy can be useful when debugging a test. - * + * Constructs a client component that uses a specified web proxy. Proxy authentication + * is not supported. Configuring the client to use an intercepting proxy can be useful + * when debugging a test. * @param proxyHost The host name or IP address of the proxy server. * @param proxyPort The port number of the proxy listener. * @return A Client component that submits requests through a web proxy. */ - public static Client buildClientWithProxy(final String proxyHost, - final int proxyPort) { - ClientConfig config = new DefaultClientConfig(); - config.getProperties().put( - ClientConfig.PROPERTY_FOLLOW_REDIRECTS, true); - Client client = new Client(new URLConnectionClientHandler( - new HttpURLConnectionFactory() { - SocketAddress addr = new InetSocketAddress(proxyHost, proxyPort); - Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); - - @Override - public HttpURLConnection getHttpURLConnection(URL url) throws IOException { - return (HttpURLConnection) url.openConnection(proxy); - } - }), config); - client.addFilter(new LoggingFilter()); - return client; + public static Client buildClientWithProxy(final String proxyHost, final int proxyPort) { + ClientConfig config = new ClientConfig(); + config.connectorProvider(new ApacheConnectorProvider()); + config.register(new LoggingFeature(LOGGER, Level.ALL, LoggingFeature.Verbosity.PAYLOAD_ANY, 5000)); + SocketAddress addr = new InetSocketAddress(proxyHost, proxyPort); + Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); + config.property(ClientProperties.PROXY_URI, proxy); + config.property(ClientProperties.FOLLOW_REDIRECTS, true); + config.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT, LoggingFeature.Verbosity.PAYLOAD_ANY); + config.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_CLIENT, Level.ALL); + Client client = ClientBuilder.newClient(config); + client.register(new ReusableEntityFilter()); + return client; } /** * Builds an HTTP request message that uses the GET method. - * - * @param endpoint A URI indicating the target resource. - * @param qryParams A Map containing query parameters (may be null); - * @param mediaTypes A list of acceptable media types; if not specified, - * generic XML ("application/xml") is preferred. + * @param endpoint A URI indicating the target resource. + * @param qryParams A Map containing query parameters (may be null); + * @param mediaTypes A list of acceptable media types; if not specified, the Accept + * header is omitted. * @return A ClientRequest object. */ - public static ClientRequest buildGetRequest(URI endpoint, - Map qryParams, MediaType... mediaTypes) { - UriBuilder uriBuilder = UriBuilder.fromUri(endpoint); - if (null != qryParams) { - for (Map.Entry param : qryParams.entrySet()) { - uriBuilder.queryParam(param.getKey(), param.getValue()); + public static Response buildGetRequest(URI endpoint, Map qryParams, MediaType... mediaTypes) { + UriBuilder uriBuilder = UriBuilder.fromUri(endpoint); + if (null != qryParams) { + for (Map.Entry param : qryParams.entrySet()) { + uriBuilder.queryParam(param.getKey(), param.getValue()); + } + } + URI uri = uriBuilder.build(); + WebTarget target = buildClient().target(uri); + Builder reqBuilder = target.request(); + if (null != mediaTypes && mediaTypes.length > 0) { + reqBuilder = reqBuilder.accept(mediaTypes); } - } - URI uri = uriBuilder.build(); - ClientRequest.Builder reqBuilder = ClientRequest.create(); - if (null == mediaTypes || mediaTypes.length == 0) { - reqBuilder = reqBuilder.accept(MediaType.APPLICATION_XML_TYPE); - } else { - reqBuilder = reqBuilder.accept(mediaTypes); - } - ClientRequest req = reqBuilder.build(uri, HttpMethod.GET); - return req; + Invocation req = reqBuilder.buildGet(); + return req.invoke(); } /** * Creates a copy of the given MediaType object but without any parameters. - * * @param mediaType A MediaType descriptor. - * @return A new (immutable) MediaType object having the same type and - * subtype. + * @return A new (immutable) MediaType object having the same type and subtype. */ public static MediaType removeParameters(MediaType mediaType) { - return new MediaType(mediaType.getType(), mediaType.getSubtype()); + return new MediaType(mediaType.getType(), mediaType.getSubtype()); } /** - * Obtains the (XML) response entity as a JAXP Source object and resets the - * entity input stream for subsequent reads. - * - * @param response A representation of an HTTP response message. - * @param targetURI The target URI from which the entity was retrieved (may - * be null). - * @return A Source to read the entity from; its system identifier is set - * using the given targetURI value (this may be used to resolve any relative - * URIs found in the source). + * Obtains the (XML) response entity as a JAXP Source object and resets the entity + * input stream for subsequent reads. + * @param response A representation of an HTTP response message. + * @param targetURI The target URI from which the entity was retrieved (may be null). + * @return A Source to read the entity from; its system identifier is set using the + * given targetURI value (this may be used to resolve any relative URIs found in the + * source). */ - public static Source getResponseEntityAsSource(ClientResponse response, - String targetURI) { - Source source = response.getEntity(DOMSource.class); - if (null != targetURI && !targetURI.isEmpty()) { - source.setSystemId(targetURI); - } - if (response.getEntityInputStream().markSupported()) { - try { - // NOTE: entity was buffered by client filter - response.getEntityInputStream().reset(); - } catch (IOException ex) { - Logger.getLogger(ClientUtils.class.getName()).log(Level.WARNING, - "Failed to reset response entity.", ex); + public static Source getResponseEntityAsSource(Response response, String targetURI) { + Source source = response.readEntity(DOMSource.class); + if (null != targetURI && !targetURI.isEmpty()) { + source.setSystemId(targetURI); } - } - return source; + return source; } /** - * Obtains the (XML) response entity as a DOM Document and resets the entity - * input stream for subsequent reads. - * - * @param response A representation of an HTTP response message. - * @param targetURI The target URI from which the entity was retrieved (may - * be null). - * @return A Document representing the entity; its base URI is set using the - * given targetURI value (this may be used to resolve any relative URIs - * found in the document). + * Obtains the (XML) response entity as a DOM Document and resets the entity input + * stream for subsequent reads. + * @param response A representation of an HTTP response message. + * @param targetURI The target URI from which the entity was retrieved (may be null). + * @return A Document representing the entity; its base URI is set using the given + * targetURI value (this may be used to resolve any relative URIs found in the + * document). */ - public static Document getResponseEntityAsDocument(ClientResponse response, - String targetURI) { - DOMSource domSource = (DOMSource) getResponseEntityAsSource(response, - targetURI); - Document entityDoc = (Document) domSource.getNode(); - entityDoc.setDocumentURI(domSource.getSystemId()); - return entityDoc; + public static Document getResponseEntityAsDocument(Response response, String targetURI) { + DOMSource domSource = (DOMSource) getResponseEntityAsSource(response, targetURI); + Document entityDoc = (Document) domSource.getNode(); + entityDoc.setDocumentURI(domSource.getSystemId()); + return entityDoc; } } diff --git a/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java b/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java index 2ed0f1a..eebf72c 100644 --- a/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java +++ b/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java @@ -8,12 +8,13 @@ import java.net.URL; import java.util.HashMap; import java.util.Map; + import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.mockito.Matchers; +import org.mockito.ArgumentMatchers; import org.testng.ISuite; import org.testng.xml.XmlSuite; import org.w3c.dom.Document; @@ -45,25 +46,25 @@ public void setUp() { public void tearDown() { } -// @Test(expected = IllegalArgumentException.class) -// public void noSuiteParameters() { -// Map params = new HashMap(); -// when(xmlSuite.getParameters()).thenReturn(params); -// SuiteFixtureListener iut = new SuiteFixtureListener(); -// iut.onStart(suite); -// } -// -// @Test -// public void processIUTParameter() throws URISyntaxException { -// URL url = this.getClass().getResource("/atom-feed.xml"); -// Map params = new HashMap(); -// params.put(TestRunArg.IUT.toString(), url.toURI().toString()); -// when(xmlSuite.getParameters()).thenReturn(params); -// SuiteFixtureListener iut = new SuiteFixtureListener(); -// iut.onStart(suite); -// verify(suite).setAttribute( -// Matchers.eq(SuiteAttribute.TEST_SUBJECT.getName()), -// Matchers.isA(Document.class)); -// } + @Test(expected = IllegalArgumentException.class) + public void noSuiteParameters() { + Map params = new HashMap(); + when(xmlSuite.getParameters()).thenReturn(params); + SuiteFixtureListener iut = new SuiteFixtureListener(); + iut.onStart(suite); + } + + @Test + public void processIUTParameter() throws URISyntaxException { + URL url = this.getClass().getResource("/atom-feed.xml"); + Map params = new HashMap(); + params.put(TestRunArg.IUT.toString(), url.toURI().toString()); + when(xmlSuite.getParameters()).thenReturn(params); + SuiteFixtureListener iut = new SuiteFixtureListener(); + iut.onStart(suite); + verify(suite).setAttribute( + ArgumentMatchers.eq(SuiteAttribute.TEST_SUBJECT.getName()), + ArgumentMatchers.isA(Document.class)); + } } From 051455867334cdc6d19c1bc724e576f571b55ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Pro=C3=9F?= Date: Wed, 18 Dec 2024 14:46:19 +0100 Subject: [PATCH 3/8] Formatting, javadoc --- .../org/opengis/cite/sta10/CommonFixture.java | 148 +- .../cite/sta10/ReusableEntityFilter.java | 20 +- .../opengis/cite/sta10/SuiteAttribute.java | 91 +- .../cite/sta10/SuiteFixtureListener.java | 438 +- .../cite/sta10/TestFailureListener.java | 148 +- .../opengis/cite/sta10/TestNGController.java | 238 +- .../org/opengis/cite/sta10/TestRunArg.java | 30 +- .../opengis/cite/sta10/TestRunListener.java | 29 +- .../createUpdateDelete/Capability2Tests.java | 2981 +++++----- .../createUpdateDelete/package-info.java | 3 +- .../filteringExtension/Capability3Tests.java | 4877 +++++++++-------- .../filteringExtension/package-info.java | 3 +- .../org/opengis/cite/sta10/package-info.java | 9 +- .../sta10/sensingCore/Capability1Tests.java | 1338 ++--- .../cite/sta10/sensingCore/package-info.java | 3 +- .../opengis/cite/sta10/util/ClientUtils.java | 208 +- .../cite/sta10/util/ControlInformation.java | 29 +- .../util/EntityPropertiesSampleValue.java | 154 +- .../opengis/cite/sta10/util/EntityType.java | 202 +- .../opengis/cite/sta10/util/HTTPMethods.java | 446 +- .../cite/sta10/util/ServiceURLBuilder.java | 422 +- .../cite/sta10/util/TestSuiteLogger.java | 107 +- .../opengis/cite/sta10/VerifyETSAssert.java | 98 +- .../sta10/VerifySuiteFixtureListener.java | 76 +- .../cite/sta10/VerifyTestNGController.java | 78 +- 25 files changed, 6186 insertions(+), 5990 deletions(-) diff --git a/src/main/java/org/opengis/cite/sta10/CommonFixture.java b/src/main/java/org/opengis/cite/sta10/CommonFixture.java index 58c5777..b3b6894 100644 --- a/src/main/java/org/opengis/cite/sta10/CommonFixture.java +++ b/src/main/java/org/opengis/cite/sta10/CommonFixture.java @@ -16,86 +16,86 @@ import jakarta.ws.rs.core.Response; /** - * A supporting base class that sets up a common test fixture. These - * configuration methods are invoked before those defined in a subclass. + * A supporting base class that sets up a common test fixture. These configuration methods + * are invoked before those defined in a subclass. */ public class CommonFixture { - /** - * Root test suite package (absolute path). - */ - public static final String ROOT_PKG_PATH = "/org/opengis/cite/sta10/"; - /** - * HTTP client component (JAX-RS Client API). - */ - protected Client client; - /** - * An HTTP request message. - */ - protected ClientRequest request; - /** - * An HTTP response message. - */ - protected Response response; + /** + * Root test suite package (absolute path). + */ + public static final String ROOT_PKG_PATH = "/org/opengis/cite/sta10/"; - /** - * Initializes the common test fixture with a client component for - * interacting with HTTP endpoints. - * - * @param testContext The test context that contains all the information for - * a test run, including suite attributes. - */ - @BeforeClass - public void initCommonFixture(ITestContext testContext) { - Object obj = testContext.getSuite().getAttribute(SuiteAttribute.CLIENT.getName()); - if (null != obj) { - this.client = Client.class.cast(obj); - } - obj = testContext.getSuite().getAttribute(SuiteAttribute.TEST_SUBJECT.getName()); - if (null == obj) { - throw new SkipException("Test subject not found in ITestContext."); - } - } + /** + * HTTP client component (JAX-RS Client API). + */ + protected Client client; - @BeforeMethod - public void clearMessages() { - this.request = null; - this.response = null; - } + /** + * An HTTP request message. + */ + protected ClientRequest request; - /** - * Obtains the (XML) response entity as a DOM Document. This convenience - * method wraps a static method call to facilitate unit testing (Mockito - * workaround). - * - * @param response A representation of an HTTP response message. - * @param targetURI The target URI from which the entity was retrieved (may - * be null). - * @return A Document representing the entity. - * @see ClientUtils#getResponseEntityAsDocument(com.sun.jersey.api.client.ClientResponse, - * java.lang.String) - */ - public Document getResponseEntityAsDocument(Response response, - String targetURI) { - return ClientUtils.getResponseEntityAsDocument(response, targetURI); - } + /** + * An HTTP response message. + */ + protected Response response; - /** - * Builds an HTTP request message that uses the GET method. This convenience - * method wraps a static method call to facilitate unit testing (Mockito - * workaround). - * - * @param endpoint A URI indicating the target resource. - * @param qryParams A Map containing query parameters (may be null); - * @param mediaTypes A list of acceptable media types; if not specified, - * generic XML ("application/xml") is preferred. - * @return A Response object. - * @see ClientUtils#buildGetRequest(java.net.URI, java.util.Map, - * javax.ws.rs.core.MediaType...) - */ - public Response buildGetRequest(URI endpoint, - Map qryParams, MediaType... mediaTypes) { - return ClientUtils.buildGetRequest(endpoint, qryParams, mediaTypes); - } + /** + * Initializes the common test fixture with a client component for interacting with + * HTTP endpoints. + * @param testContext The test context that contains all the information for a test + * run, including suite attributes. + */ + @BeforeClass + public void initCommonFixture(ITestContext testContext) { + Object obj = testContext.getSuite().getAttribute(SuiteAttribute.CLIENT.getName()); + if (null != obj) { + this.client = Client.class.cast(obj); + } + obj = testContext.getSuite().getAttribute(SuiteAttribute.TEST_SUBJECT.getName()); + if (null == obj) { + throw new SkipException("Test subject not found in ITestContext."); + } + } + + /** + *

+ * clearMessages. + *

+ */ + @BeforeMethod + public void clearMessages() { + this.request = null; + this.response = null; + } + + /** + * Obtains the (XML) response entity as a DOM Document. This convenience method wraps + * a static method call to facilitate unit testing (Mockito workaround). + * @param response A representation of an HTTP response message. + * @param targetURI The target URI from which the entity was retrieved (may be null). + * @return A Document representing the entity. + * @see ClientUtils#getResponseEntityAsDocument(com.sun.jersey.api.client.ClientResponse, + * java.lang.String) + */ + public Document getResponseEntityAsDocument(Response response, String targetURI) { + return ClientUtils.getResponseEntityAsDocument(response, targetURI); + } + + /** + * Builds an HTTP request message that uses the GET method. This convenience method + * wraps a static method call to facilitate unit testing (Mockito workaround). + * @param endpoint A URI indicating the target resource. + * @param qryParams A Map containing query parameters (may be null); + * @param mediaTypes A list of acceptable media types; if not specified, generic XML + * ("application/xml") is preferred. + * @return A Response object. + * @see ClientUtils#buildGetRequest(java.net.URI, java.util.Map, + * javax.ws.rs.core.MediaType...) + */ + public Response buildGetRequest(URI endpoint, Map qryParams, MediaType... mediaTypes) { + return ClientUtils.buildGetRequest(endpoint, qryParams, mediaTypes); + } } diff --git a/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java b/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java index 5c14743..5dadbaf 100644 --- a/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java +++ b/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java @@ -11,18 +11,18 @@ /** * Buffers the (response) entity so it can be read multiple times. *

- *

WARNING: The entity InputStream must be reset after each - * read attempt.

+ *

+ * WARNING: The entity InputStream must be reset after each read attempt. + *

*/ public class ReusableEntityFilter implements ClientResponseFilter { - /** {@inheritDoc} */ - @Override - public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { - if (responseContext instanceof ClientResponse) { - ((ClientResponse) responseContext).bufferEntity(); - } - } + /** {@inheritDoc} */ + @Override + public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { + if (responseContext instanceof ClientResponse) { + ((ClientResponse) responseContext).bufferEntity(); + } + } } - diff --git a/src/main/java/org/opengis/cite/sta10/SuiteAttribute.java b/src/main/java/org/opengis/cite/sta10/SuiteAttribute.java index 4a13390..967553b 100644 --- a/src/main/java/org/opengis/cite/sta10/SuiteAttribute.java +++ b/src/main/java/org/opengis/cite/sta10/SuiteAttribute.java @@ -5,46 +5,61 @@ import jakarta.ws.rs.client.Client; /** - * An enumerated type defining ISuite attributes that may be set to constitute a - * shared test fixture. + * An enumerated type defining ISuite attributes that may be set to constitute a shared + * test fixture. */ @SuppressWarnings("rawtypes") public enum SuiteAttribute { - /** - * A client component for interacting with HTTP endpoints. - */ - CLIENT("httpClient", Client.class), - /** - * A DOM Document representation of the test subject or metadata about it. - */ - TEST_SUBJECT("testSubject", Document.class), - /** - * An integer denoting the conformance level to check. A given conformance - * level includes all lower levels. - */ - LEVEL("level", Integer.class); - - private final Class attrType; - private final String attrName; - - private SuiteAttribute(String attrName, Class attrType) { - this.attrName = attrName; - this.attrType = attrType; - } - - public Class getType() { - return attrType; - } - - public String getName() { - return attrName; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(attrName); - sb.append('(').append(attrType.getName()).append(')'); - return sb.toString(); - } + /** + * A client component for interacting with HTTP endpoints. + */ + CLIENT("httpClient", Client.class), + /** + * A DOM Document representation of the test subject or metadata about it. + */ + TEST_SUBJECT("testSubject", Document.class), + /** + * An integer denoting the conformance level to check. A given conformance level + * includes all lower levels. + */ + LEVEL("level", Integer.class); + + private final Class attrType; + + private final String attrName; + + private SuiteAttribute(String attrName, Class attrType) { + this.attrName = attrName; + this.attrType = attrType; + } + + /** + *

+ * getType. + *

+ * @return a {@link java.lang.Class} object + */ + public Class getType() { + return attrType; + } + + /** + *

+ * getName. + *

+ * @return a {@link java.lang.String} object + */ + public String getName() { + return attrName; + } + + /** {@inheritDoc} */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(attrName); + sb.append('(').append(attrType.getName()).append(')'); + return sb.toString(); + } + } diff --git a/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java b/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java index a000189..053c7d9 100644 --- a/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java +++ b/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java @@ -23,236 +23,242 @@ import jakarta.ws.rs.client.Client; /** - * A listener that performs various tasks before and after a test suite is run, - * usually concerned with maintaining a shared test suite fixture. Since this - * listener is loaded using the ServiceLoader mechanism, its methods will be - * called before those of other suite listeners listed in the test suite - * definition and before any annotated configuration methods. + * A listener that performs various tasks before and after a test suite is run, usually + * concerned with maintaining a shared test suite fixture. Since this listener is loaded + * using the ServiceLoader mechanism, its methods will be called before those of other + * suite listeners listed in the test suite definition and before any annotated + * configuration methods. *

- * Attributes set on an ISuite instance are not inherited by constituent test - * group contexts (ITestContext). However, suite attributes are still accessible - * from lower contexts. + * Attributes set on an ISuite instance are not inherited by constituent test group + * contexts (ITestContext). However, suite attributes are still accessible from lower + * contexts. * * @see org.testng.ISuite ISuite interface */ public class SuiteFixtureListener implements ISuiteListener { - @Override - public void onStart(ISuite suite) { - processSuiteParameters(suite); - registerClientComponent(suite); - } + /** {@inheritDoc} */ + @Override + public void onStart(ISuite suite) { + processSuiteParameters(suite); + registerClientComponent(suite); + } - @Override - public void onFinish(ISuite suite) { - } + /** {@inheritDoc} */ + @Override + public void onFinish(ISuite suite) { + } - /** - * Processes test suite arguments and sets suite attributes accordingly. The - * entity referenced by the {@link TestRunArg#IUT iut} argument is parsed - * and the resulting Document is set as the value of the "testSubject" - * attribute. - * - * @param suite An ISuite object representing a TestNG test suite. - */ - void processSuiteParameters(ISuite suite) { - Map params = suite.getXmlSuite().getParameters(); - TestSuiteLogger.log(Level.CONFIG, - "Suite parameters\n" + params.toString()); + /** + * Processes test suite arguments and sets suite attributes accordingly. The entity + * referenced by the {@link TestRunArg#IUT iut} argument is parsed and the resulting + * Document is set as the value of the "testSubject" attribute. + * @param suite An ISuite object representing a TestNG test suite. + */ + void processSuiteParameters(ISuite suite) { + Map params = suite.getXmlSuite().getParameters(); + TestSuiteLogger.log(Level.CONFIG, "Suite parameters\n" + params.toString()); - Integer level = new Integer(1); - if (null != params.get(TestRunArg.ICS.toString())) { - try { - level = Integer.valueOf(params.get(TestRunArg.ICS.toString())); - } catch (NumberFormatException nfe) { // use default value instead - } - } - suite.setAttribute(SuiteAttribute.LEVEL.getName(), level); + Integer level = new Integer(1); + if (null != params.get(TestRunArg.ICS.toString())) { + try { + level = Integer.valueOf(params.get(TestRunArg.ICS.toString())); + } + catch (NumberFormatException nfe) { // use default value instead + } + } + suite.setAttribute(SuiteAttribute.LEVEL.getName(), level); - String iutParam = params.get(TestRunArg.IUT.toString()); + String iutParam = params.get(TestRunArg.IUT.toString()); - String response = checkServiceRootUri(iutParam); - if (!response.equals("")) { - throw new IllegalArgumentException( - response); - } - suite.setAttribute(SuiteAttribute.TEST_SUBJECT.getName(), iutParam); - if (TestSuiteLogger.isLoggable(Level.FINE)) { - StringBuilder logMsg = new StringBuilder( - "Parsed resource retrieved from "); - logMsg.append(TestRunArg.IUT).append("\n"); - // logMsg.append(XMLUtils.writeNodeToString(iutDoc)); - TestSuiteLogger.log(Level.FINE, logMsg.toString()); - } - } + String response = checkServiceRootUri(iutParam); + if (!response.equals("")) { + throw new IllegalArgumentException(response); + } + suite.setAttribute(SuiteAttribute.TEST_SUBJECT.getName(), iutParam); + if (TestSuiteLogger.isLoggable(Level.FINE)) { + StringBuilder logMsg = new StringBuilder("Parsed resource retrieved from "); + logMsg.append(TestRunArg.IUT).append("\n"); + // logMsg.append(XMLUtils.writeNodeToString(iutDoc)); + TestSuiteLogger.log(Level.FINE, logMsg.toString()); + } + } - /** - * A client component is added to the suite fixture as the value of the - * {@link SuiteAttribute#CLIENT} attribute; it may be subsequently accessed - * via the {@link org.testng.ITestContext#getSuite()} method. - * - * @param suite The test suite instance. - */ - void registerClientComponent(ISuite suite) { - Client client = ClientUtils.buildClient(); - if (null != client) { - suite.setAttribute(SuiteAttribute.CLIENT.getName(), client); - } - } + /** + * A client component is added to the suite fixture as the value of the + * {@link SuiteAttribute#CLIENT} attribute; it may be subsequently accessed via the + * {@link org.testng.ITestContext#getSuite()} method. + * @param suite The test suite instance. + */ + void registerClientComponent(ISuite suite) { + Client client = ClientUtils.buildClient(); + if (null != client) { + suite.setAttribute(SuiteAttribute.CLIENT.getName(), client); + } + } - /** - * Checking the service root URL to be compliant with SensorThings API - * - * @param rootUri The root URL for the service under test - * @return If the root URL of the service is not compliant to SensorThings API, it will return the reason it is not compliant. Otherwise it returns empty String. - */ - private String checkServiceRootUri(String rootUri) { - rootUri = rootUri.trim(); - if (rootUri.lastIndexOf('/') == rootUri.length() - 1) { - rootUri = rootUri.substring(0, rootUri.length() - 1); - } - HttpURLConnection connection = null; - String response = null; - //Create connection - URL url = null; - try { - url = new URL(rootUri); + /** + * Checking the service root URL to be compliant with SensorThings API + * @param rootUri The root URL for the service under test + * @return If the root URL of the service is not compliant to SensorThings API, it + * will return the reason it is not compliant. Otherwise it returns empty String. + */ + private String checkServiceRootUri(String rootUri) { + rootUri = rootUri.trim(); + if (rootUri.lastIndexOf('/') == rootUri.length() - 1) { + rootUri = rootUri.substring(0, rootUri.length() - 1); + } + HttpURLConnection connection = null; + String response = null; + // Create connection + URL url = null; + try { + url = new URL(rootUri); - connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - connection.setRequestProperty("Content-Type", - "application/json"); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Content-Type", "application/json"); - connection.setUseCaches(false); - connection.setDoOutput(true); + connection.setUseCaches(false); + connection.setDoOutput(true); + + // Get Response + InputStream is = connection.getInputStream(); + BufferedReader rd = new BufferedReader(new InputStreamReader(is)); + StringBuilder responseBuilder = new StringBuilder(); // or StringBuffer if not + // Java 5+ + String line; + while ((line = rd.readLine()) != null) { + responseBuilder.append(line); + responseBuilder.append('\r'); + } + response = responseBuilder.toString(); + rd.close(); + } + catch (MalformedURLException e) { + e.printStackTrace(); + return "The requested URL is not well formed: " + rootUri + "."; + } + catch (ProtocolException e) { + e.printStackTrace(); + return "Unknown protocol in requested URL: " + rootUri + "."; + } + catch (IOException e) { + e.printStackTrace(); + return "Cannot connect to " + rootUri + "."; + } + JSONObject jsonResponse = null; + JSONArray entities = null; + try { + jsonResponse = new JSONObject(response); + entities = jsonResponse.getJSONArray("value"); + } + catch (JSONException e) { + e.printStackTrace(); + return "The service response for the root URI \"" + rootUri + "\" is not JSON."; + } + Map addedLinks = new HashMap<>(); + addedLinks.put("Things", false); + addedLinks.put("Locations", false); + addedLinks.put("HistoricalLocations", false); + addedLinks.put("Datastreams", false); + addedLinks.put("Sensors", false); + addedLinks.put("Observations", false); + addedLinks.put("ObservedProperties", false); + addedLinks.put("FeaturesOfInterest", false); + for (int i = 0; i < entities.length(); i++) { + JSONObject entity = null; + String name, nameUrl; + try { + entity = entities.getJSONObject(i); + if (!entity.has("name")) { + return "The name component of Service root URI response is not available.[ENTITY]: " + + entity.toString(); + } + if (!entity.has("url")) { + return "The name component of Service root URI response is not available. [ENTITY]: " + + entity.toString(); + } + name = entity.getString("name"); + nameUrl = entity.getString("url"); + } + catch (JSONException e) { + e.printStackTrace(); + return "The service response for the root URI \"" + rootUri + "\" is not JSON."; + } + switch (name) { + case "Things": + if (!nameUrl.equals(rootUri + "/Things")) { + return "The URL for Things in Service Root URI is not compliant to SensorThings API."; + } + addedLinks.remove("Things"); + addedLinks.put(name, true); + break; + case "Locations": + if (!nameUrl.equals(rootUri + "/Locations")) { + return "The URL for Locations in Service Root URI is not compliant to SensorThings API."; + } + addedLinks.remove("Locations"); + addedLinks.put(name, true); + break; + case "HistoricalLocations": + if (!nameUrl.equals(rootUri + "/HistoricalLocations")) { + return "The URL for HistoricalLocations in Service Root URI is not compliant to SensorThings API."; + } + addedLinks.remove("HistoricalLocations"); + addedLinks.put(name, true); + break; + case "Datastreams": + if (!nameUrl.equals(rootUri + "/Datastreams")) { + return "The URL for Datastreams in Service Root URI is not compliant to SensorThings API."; + } + addedLinks.remove("Datastreams"); + addedLinks.put(name, true); + break; + case "Sensors": + if (!nameUrl.equals(rootUri + "/Sensors")) { + return "The URL for Sensors in Service Root URI is not compliant to SensorThings API."; + } + addedLinks.remove("Sensors"); + addedLinks.put(name, true); + break; + case "Observations": + if (!nameUrl.equals(rootUri + "/Observations")) { + return "The URL for Observations in Service Root URI is not compliant to SensorThings API."; + } + addedLinks.remove("Observations"); + addedLinks.put(name, true); + break; + case "ObservedProperties": + if (!nameUrl.equals(rootUri + "/ObservedProperties")) { + return "The URL for ObservedProperties in Service Root URI is not compliant to SensorThings API."; + } + addedLinks.remove("ObservedProperties"); + addedLinks.put(name, true); + break; + case "FeaturesOfInterest": + if (!nameUrl.equals(rootUri + "/FeaturesOfInterest")) { + return "The URL for FeaturesOfInterest in Service Root URI is not compliant to SensorThings API."; + } + addedLinks.remove("FeaturesOfInterest"); + addedLinks.put(name, true); + break; + case "MultiDatastreams": + if (!nameUrl.equals(rootUri + "/MultiDatastreams")) { + return "The URL for MultiDatastreams in Service Root URI is not compliant to SensorThings API."; + } + break; + default: + return "There is a component in Service Root URI response that is not in SensorThings API : " + + name; + } + } + for (String key : addedLinks.keySet()) { + if (addedLinks.get(key) == false) { + return "The Service Root URI response does not contain "; + } + } + return ""; + } - //Get Response - InputStream is = connection.getInputStream(); - BufferedReader rd = new BufferedReader(new InputStreamReader(is)); - StringBuilder responseBuilder = new StringBuilder(); // or StringBuffer if not Java 5+ - String line; - while ((line = rd.readLine()) != null) { - responseBuilder.append(line); - responseBuilder.append('\r'); - } - response = responseBuilder.toString(); - rd.close(); - } catch (MalformedURLException e) { - e.printStackTrace(); - return "The requested URL is not well formed: " + rootUri + "."; - } catch (ProtocolException e) { - e.printStackTrace(); - return "Unknown protocol in requested URL: " + rootUri + "."; - } catch (IOException e) { - e.printStackTrace(); - return "Cannot connect to " + rootUri + "."; - } - JSONObject jsonResponse = null; - JSONArray entities = null; - try { - jsonResponse = new JSONObject(response); - entities = jsonResponse.getJSONArray("value"); - } catch (JSONException e) { - e.printStackTrace(); - return "The service response for the root URI \"" + rootUri + "\" is not JSON."; - } - Map addedLinks = new HashMap<>(); - addedLinks.put("Things", false); - addedLinks.put("Locations", false); - addedLinks.put("HistoricalLocations", false); - addedLinks.put("Datastreams", false); - addedLinks.put("Sensors", false); - addedLinks.put("Observations", false); - addedLinks.put("ObservedProperties", false); - addedLinks.put("FeaturesOfInterest", false); - for (int i = 0; i < entities.length(); i++) { - JSONObject entity = null; - String name, nameUrl; - try { - entity = entities.getJSONObject(i); - if (!entity.has("name")) { - return "The name component of Service root URI response is not available.[ENTITY]: " + entity.toString(); - } - if (!entity.has("url")) { - return "The name component of Service root URI response is not available. [ENTITY]: " + entity.toString(); - } - name = entity.getString("name"); - nameUrl = entity.getString("url"); - } catch (JSONException e) { - e.printStackTrace(); - return "The service response for the root URI \"" + rootUri + "\" is not JSON."; - } - switch (name) { - case "Things": - if (!nameUrl.equals(rootUri + "/Things")) { - return "The URL for Things in Service Root URI is not compliant to SensorThings API."; - } - addedLinks.remove("Things"); - addedLinks.put(name, true); - break; - case "Locations": - if (!nameUrl.equals(rootUri + "/Locations")) { - return "The URL for Locations in Service Root URI is not compliant to SensorThings API."; - } - addedLinks.remove("Locations"); - addedLinks.put(name, true); - break; - case "HistoricalLocations": - if (!nameUrl.equals(rootUri + "/HistoricalLocations")) { - return "The URL for HistoricalLocations in Service Root URI is not compliant to SensorThings API."; - } - addedLinks.remove("HistoricalLocations"); - addedLinks.put(name, true); - break; - case "Datastreams": - if (!nameUrl.equals(rootUri + "/Datastreams")) { - return "The URL for Datastreams in Service Root URI is not compliant to SensorThings API."; - } - addedLinks.remove("Datastreams"); - addedLinks.put(name, true); - break; - case "Sensors": - if (!nameUrl.equals(rootUri + "/Sensors")) { - return "The URL for Sensors in Service Root URI is not compliant to SensorThings API."; - } - addedLinks.remove("Sensors"); - addedLinks.put(name, true); - break; - case "Observations": - if (!nameUrl.equals(rootUri + "/Observations")) { - return "The URL for Observations in Service Root URI is not compliant to SensorThings API."; - } - addedLinks.remove("Observations"); - addedLinks.put(name, true); - break; - case "ObservedProperties": - if (!nameUrl.equals(rootUri + "/ObservedProperties")) { - return "The URL for ObservedProperties in Service Root URI is not compliant to SensorThings API."; - } - addedLinks.remove("ObservedProperties"); - addedLinks.put(name, true); - break; - case "FeaturesOfInterest": - if (!nameUrl.equals(rootUri + "/FeaturesOfInterest")) { - return "The URL for FeaturesOfInterest in Service Root URI is not compliant to SensorThings API."; - } - addedLinks.remove("FeaturesOfInterest"); - addedLinks.put(name, true); - break; - case "MultiDatastreams": - if (!nameUrl.equals(rootUri + "/MultiDatastreams")) { - return "The URL for MultiDatastreams in Service Root URI is not compliant to SensorThings API."; - } - break; - default: - return "There is a component in Service Root URI response that is not in SensorThings API : " + name; - } - } - for (String key : addedLinks.keySet()) { - if (addedLinks.get(key) == false) { - return "The Service Root URI response does not contain "; - } - } - return ""; - } } diff --git a/src/main/java/org/opengis/cite/sta10/TestFailureListener.java b/src/main/java/org/opengis/cite/sta10/TestFailureListener.java index 22fd58a..de63204 100644 --- a/src/main/java/org/opengis/cite/sta10/TestFailureListener.java +++ b/src/main/java/org/opengis/cite/sta10/TestFailureListener.java @@ -12,85 +12,83 @@ import jakarta.ws.rs.core.Response; /** - * A listener that augments a test result with diagnostic information in the - * event that a test method failed. This information will appear in the XML - * report when the test run is completed. + * A listener that augments a test result with diagnostic information in the event that a + * test method failed. This information will appear in the XML report when the test run is + * completed. */ public class TestFailureListener extends TestListenerAdapter { - /** - * Sets the "request" and "response" attributes of a test result. The value - * of these attributes is a string that contains information about the - * content of an outgoing or incoming message: target resource, status code, - * headers, entity (if present). The entity is represented as a String with - * UTF-8 character encoding. - * - * @param result A description of a test result (with a fail verdict). - */ - @Override - public void onTestFailure(ITestResult result) { - super.onTestFailure(result); - Object instance = result.getInstance(); - if (CommonFixture.class.isInstance(instance)) { - CommonFixture fixture = CommonFixture.class.cast(instance); - result.setAttribute("request", getRequestMessageInfo(fixture.request)); - result.setAttribute("response", getResponseMessageInfo(fixture.response)); - } - } + /** + * {@inheritDoc} + * + * Sets the "request" and "response" attributes of a test result. The value of these + * attributes is a string that contains information about the content of an outgoing + * or incoming message: target resource, status code, headers, entity (if present). + * The entity is represented as a String with UTF-8 character encoding. + */ + @Override + public void onTestFailure(ITestResult result) { + super.onTestFailure(result); + Object instance = result.getInstance(); + if (CommonFixture.class.isInstance(instance)) { + CommonFixture fixture = CommonFixture.class.cast(instance); + result.setAttribute("request", getRequestMessageInfo(fixture.request)); + result.setAttribute("response", getResponseMessageInfo(fixture.response)); + } + } - /** - * Gets diagnostic information about a request message. If the request - * contains a message body, it should be represented as a DOM Document node - * or as an object having a meaningful toString() implementation. - * - * @param req An object representing an HTTP request message. - * @return A string containing information gleaned from the request message. - */ - String getRequestMessageInfo(ClientRequest req) { - if (null == req) { - return "No request message."; - } - StringBuilder msgInfo = new StringBuilder(); - msgInfo.append("Method: ").append(req.getMethod()).append('\n'); - msgInfo.append("Target URI: ").append(req.getUri()).append('\n'); - msgInfo.append("Headers: ").append(req.getHeaders()).append('\n'); - if (null != req.getEntity()) { - Object entity = req.getEntity(); - String body = ""; - if (Document.class.isInstance(entity)) { - Document doc = Document.class.cast(entity); - } else { - body = entity.toString(); - } - msgInfo.append(body).append('\n'); - } - return msgInfo.toString(); - } + /** + * Gets diagnostic information about a request message. If the request contains a + * message body, it should be represented as a DOM Document node or as an object + * having a meaningful toString() implementation. + * @param req An object representing an HTTP request message. + * @return A string containing information gleaned from the request message. + */ + String getRequestMessageInfo(ClientRequest req) { + if (null == req) { + return "No request message."; + } + StringBuilder msgInfo = new StringBuilder(); + msgInfo.append("Method: ").append(req.getMethod()).append('\n'); + msgInfo.append("Target URI: ").append(req.getUri()).append('\n'); + msgInfo.append("Headers: ").append(req.getHeaders()).append('\n'); + if (null != req.getEntity()) { + Object entity = req.getEntity(); + String body = ""; + if (Document.class.isInstance(entity)) { + Document doc = Document.class.cast(entity); + } + else { + body = entity.toString(); + } + msgInfo.append(body).append('\n'); + } + return msgInfo.toString(); + } - /** - * Gets diagnostic information about a response message. - * - * @param rsp An object representing an HTTP response message. - * @return A string containing information gleaned from the response - * message. - */ - String getResponseMessageInfo(Response rsp) { - if (null == rsp) { - return "No response message."; - } - StringBuilder msgInfo = new StringBuilder(); - msgInfo.append("Status: ").append(rsp.getStatus()).append('\n'); - msgInfo.append("Headers: ").append(rsp.getHeaders()).append('\n'); - if (rsp.hasEntity()) { - if (rsp.getMediaType().isCompatible(MediaType.APPLICATION_XML_TYPE)) { - Document doc = ClientUtils.getResponseEntityAsDocument(rsp, null); - } else { - byte[] body = rsp.readEntity(byte[].class); - msgInfo.append(new String(body, StandardCharsets.UTF_8)); - } - msgInfo.append('\n'); - } - return msgInfo.toString(); - } + /** + * Gets diagnostic information about a response message. + * @param rsp An object representing an HTTP response message. + * @return A string containing information gleaned from the response message. + */ + String getResponseMessageInfo(Response rsp) { + if (null == rsp) { + return "No response message."; + } + StringBuilder msgInfo = new StringBuilder(); + msgInfo.append("Status: ").append(rsp.getStatus()).append('\n'); + msgInfo.append("Headers: ").append(rsp.getHeaders()).append('\n'); + if (rsp.hasEntity()) { + if (rsp.getMediaType().isCompatible(MediaType.APPLICATION_XML_TYPE)) { + Document doc = ClientUtils.getResponseEntityAsDocument(rsp, null); + } + else { + byte[] body = rsp.readEntity(byte[].class); + msgInfo.append(new String(body, StandardCharsets.UTF_8)); + } + msgInfo.append('\n'); + } + return msgInfo.toString(); + } } diff --git a/src/main/java/org/opengis/cite/sta10/TestNGController.java b/src/main/java/org/opengis/cite/sta10/TestNGController.java index c25b3fc..e82b72a 100644 --- a/src/main/java/org/opengis/cite/sta10/TestNGController.java +++ b/src/main/java/org/opengis/cite/sta10/TestNGController.java @@ -28,123 +28,123 @@ */ public class TestNGController implements TestSuiteController { - private TestRunExecutor executor; - private Properties etsProperties = new Properties(); - - /** - * A convenience method to facilitate test development. - * - * @param args Test run arguments (optional). The first argument must refer - * to an XML properties file containing the expected set of test - * run arguments. If no argument is supplied, the file located at - * ${user.home}/test-run-props.xml will be used. - * @throws Exception If the test run cannot be executed (usually due to - * unsatisfied pre-conditions). - */ - public static void main(String[] args) throws Exception { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - File xmlArgs = null; - if (args.length > 0) { - xmlArgs = (args[0].startsWith("file:")) ? new File( - URI.create(args[0])) : new File(args[0]); - } else { - String homeDir = System.getProperty("user.home"); - xmlArgs = new File(homeDir, "test-run-props.xml"); - } -// if (!xmlArgs.exists()) { -// throw new IllegalArgumentException( -// "Test run arguments not found at " + xmlArgs); -// } - Document testRunArgs = db.parse(xmlArgs); - TestNGController controller = new TestNGController(); - Source testResults = controller.doTestRun(testRunArgs); - System.out.println("Test results: " + testResults.getSystemId()); - } - - /** - * Default constructor uses the location given by the "user.home" system - * property as the root output directory. - */ - public TestNGController() { - this(new File(System.getProperty("user.home")).toURI().toString()); - } - - /** - * Construct a controller that writes results to the given output directory. - * - * @param outputDirUri A file URI that specifies the location of the directory in - * which test results will be written. It will be created if it - * does not exist. - */ - public TestNGController(String outputDirUri) { - InputStream is = getClass().getResourceAsStream("ets.properties"); - try { - this.etsProperties.load(is); - } catch (IOException ex) { - TestSuiteLogger.log(Level.WARNING, - "Unable to load ets.properties. " + ex.getMessage()); - } - URL tngSuite = TestNGController.class.getResource("testng.xml"); - File resultsDir = new File(URI.create(outputDirUri)); - TestSuiteLogger.log(Level.CONFIG, "Using TestNG config: " + tngSuite); - TestSuiteLogger.log(Level.CONFIG, - "Using outputDirPath: " + resultsDir.getAbsolutePath()); - // NOTE: setting third argument to 'true' enables the default listeners - this.executor = new TestNGExecutor(tngSuite.toString(), - resultsDir.getAbsolutePath(), false); - } - - @Override - public String getCode() { - return etsProperties.getProperty("ets-code"); - } - - @Override - public String getVersion() { - return etsProperties.getProperty("ets-version"); - } - - @Override - public String getTitle() { - return etsProperties.getProperty("ets-title"); - } - - @Override - public Source doTestRun(Document testRunArgs) throws Exception { - validateTestRunArgs(testRunArgs); - return executor.execute(testRunArgs); - } - - /** - * Validates the test run arguments. The test run is aborted if any of - * these checks fail. - * - * @param testRunArgs A DOM Document containing a set of XML properties (key-value - * pairs). - * @throws IllegalArgumentException If any arguments are missing or invalid for some reason. - */ - void validateTestRunArgs(Document testRunArgs) { -// if (null == testRunArgs -// || !testRunArgs.getDocumentElement().getNodeName() -// .equals("properties")) { -// throw new IllegalArgumentException( -// "Input is not an XML properties document."); -// } -// NodeList entries = testRunArgs.getDocumentElement() -// .getElementsByTagName("entry"); -// if (entries.getLength() == 0) { -// throw new IllegalArgumentException("No test run arguments found."); -// } -// Map args = new HashMap(); -// for (int i = 0; i < entries.getLength(); i++) { -// Element entry = (Element) entries.item(i); -// args.put(entry.getAttribute("key"), entry.getTextContent()); -// } -// if (!args.containsKey(TestRunArg.IUT.toString())) { -// throw new IllegalArgumentException(String.format( -// "Missing argument: '%s' must be present.", -// TestRunArg.IUT)); -// } - } + private TestRunExecutor executor; + + private Properties etsProperties = new Properties(); + + /** + * A convenience method to facilitate test development. + * @param args Test run arguments (optional). The first argument must refer to an XML + * properties file containing the expected set of test run arguments. If no argument + * is supplied, the file located at ${user.home}/test-run-props.xml will be used. + * @throws java.lang.Exception If the test run cannot be executed (usually due to + * unsatisfied pre-conditions). + */ + public static void main(String[] args) throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + File xmlArgs = null; + if (args.length > 0) { + xmlArgs = (args[0].startsWith("file:")) ? new File(URI.create(args[0])) : new File(args[0]); + } + else { + String homeDir = System.getProperty("user.home"); + xmlArgs = new File(homeDir, "test-run-props.xml"); + } + // if (!xmlArgs.exists()) { + // throw new IllegalArgumentException( + // "Test run arguments not found at " + xmlArgs); + // } + Document testRunArgs = db.parse(xmlArgs); + TestNGController controller = new TestNGController(); + Source testResults = controller.doTestRun(testRunArgs); + System.out.println("Test results: " + testResults.getSystemId()); + } + + /** + * Default constructor uses the location given by the "user.home" system property as + * the root output directory. + */ + public TestNGController() { + this(new File(System.getProperty("user.home")).toURI().toString()); + } + + /** + * Construct a controller that writes results to the given output directory. + * @param outputDirUri A file URI that specifies the location of the directory in + * which test results will be written. It will be created if it does not exist. + */ + public TestNGController(String outputDirUri) { + InputStream is = getClass().getResourceAsStream("ets.properties"); + try { + this.etsProperties.load(is); + } + catch (IOException ex) { + TestSuiteLogger.log(Level.WARNING, "Unable to load ets.properties. " + ex.getMessage()); + } + URL tngSuite = TestNGController.class.getResource("testng.xml"); + File resultsDir = new File(URI.create(outputDirUri)); + TestSuiteLogger.log(Level.CONFIG, "Using TestNG config: " + tngSuite); + TestSuiteLogger.log(Level.CONFIG, "Using outputDirPath: " + resultsDir.getAbsolutePath()); + // NOTE: setting third argument to 'true' enables the default listeners + this.executor = new TestNGExecutor(tngSuite.toString(), resultsDir.getAbsolutePath(), false); + } + + /** {@inheritDoc} */ + @Override + public String getCode() { + return etsProperties.getProperty("ets-code"); + } + + /** {@inheritDoc} */ + @Override + public String getVersion() { + return etsProperties.getProperty("ets-version"); + } + + /** {@inheritDoc} */ + @Override + public String getTitle() { + return etsProperties.getProperty("ets-title"); + } + + /** {@inheritDoc} */ + @Override + public Source doTestRun(Document testRunArgs) throws Exception { + validateTestRunArgs(testRunArgs); + return executor.execute(testRunArgs); + } + + /** + * Validates the test run arguments. The test run is aborted if any of these checks + * fail. + * @param testRunArgs A DOM Document containing a set of XML properties (key-value + * pairs). + * @throws IllegalArgumentException If any arguments are missing or invalid for some + * reason. + */ + void validateTestRunArgs(Document testRunArgs) { + // if (null == testRunArgs + // || !testRunArgs.getDocumentElement().getNodeName() + // .equals("properties")) { + // throw new IllegalArgumentException( + // "Input is not an XML properties document."); + // } + // NodeList entries = testRunArgs.getDocumentElement() + // .getElementsByTagName("entry"); + // if (entries.getLength() == 0) { + // throw new IllegalArgumentException("No test run arguments found."); + // } + // Map args = new HashMap(); + // for (int i = 0; i < entries.getLength(); i++) { + // Element entry = (Element) entries.item(i); + // args.put(entry.getAttribute("key"), entry.getTextContent()); + // } + // if (!args.containsKey(TestRunArg.IUT.toString())) { + // throw new IllegalArgumentException(String.format( + // "Missing argument: '%s' must be present.", + // TestRunArg.IUT)); + // } + } + } diff --git a/src/main/java/org/opengis/cite/sta10/TestRunArg.java b/src/main/java/org/opengis/cite/sta10/TestRunArg.java index c594b37..45f688f 100644 --- a/src/main/java/org/opengis/cite/sta10/TestRunArg.java +++ b/src/main/java/org/opengis/cite/sta10/TestRunArg.java @@ -5,19 +5,21 @@ */ public enum TestRunArg { - /** - * An absolute URI that refers to a representation of the test subject or - * metadata about it. - */ - IUT, - /** - * An integer value denoting the conformance level to check. A given - * conformance level includes all lower levels. - */ - ICS; + /** + * An absolute URI that refers to a representation of the test subject or metadata + * about it. + */ + IUT, + /** + * An integer value denoting the conformance level to check. A given conformance level + * includes all lower levels. + */ + ICS; + + /** {@inheritDoc} */ + @Override + public String toString() { + return name().toLowerCase(); + } - @Override - public String toString() { - return name().toLowerCase(); - } } diff --git a/src/main/java/org/opengis/cite/sta10/TestRunListener.java b/src/main/java/org/opengis/cite/sta10/TestRunListener.java index bfe9d5a..65a457c 100644 --- a/src/main/java/org/opengis/cite/sta10/TestRunListener.java +++ b/src/main/java/org/opengis/cite/sta10/TestRunListener.java @@ -3,23 +3,28 @@ import org.testng.IExecutionListener; /** - * A listener that is invoked before and after a test run. It is often used to - * configure a shared fixture that endures for the duration of the entire test - * run. A FixtureManager may be used to manage such a fixture. + * A listener that is invoked before and after a test run. It is often used to configure a + * shared fixture that endures for the duration of the entire test run. A FixtureManager + * may be used to manage such a fixture. *

- *

A shared fixture should be used with caution in order to avoid undesirable - * test interactions. In general, it should be populated with "read-only" - * objects that are not modified during the test run.

+ *

+ * A shared fixture should be used with caution in order to avoid undesirable test + * interactions. In general, it should be populated with "read-only" objects that are not + * modified during the test run. + *

* * @see com.occamlab.te.spi.executors.FixtureManager FixtureManager */ public class TestRunListener implements IExecutionListener { - @Override - public void onExecutionStart() { - } + /** {@inheritDoc} */ + @Override + public void onExecutionStart() { + } + + /** {@inheritDoc} */ + @Override + public void onExecutionFinish() { + } - @Override - public void onExecutionFinish() { - } } diff --git a/src/main/java/org/opengis/cite/sta10/createUpdateDelete/Capability2Tests.java b/src/main/java/org/opengis/cite/sta10/createUpdateDelete/Capability2Tests.java index 67f6e68..a6e8a44 100644 --- a/src/main/java/org/opengis/cite/sta10/createUpdateDelete/Capability2Tests.java +++ b/src/main/java/org/opengis/cite/sta10/createUpdateDelete/Capability2Tests.java @@ -27,1595 +27,1394 @@ */ public class Capability2Tests { - /** - * The root URL of the SensorThings service under the test - */ - public String rootUri;//="http://localhost:8080/OGCSensorThings/v1.0"; - - /** - * The list of ids for all the Things created during test procedure (will be - * used for clean-up) - */ - private List thingIds = new ArrayList<>(); - /** - * The list of ids for all the Locations created during test procedure (will - * be used for clean-up) - */ - private List locationIds = new ArrayList<>(); - /** - * The list of ids for all the HistoricalLocations created during test - * procedure (will be used for clean-up) - */ - private List historicalLocationIds = new ArrayList<>(); - /** - * The list of ids for all the Datastreams created during test procedure - * (will be used for clean-up) - */ - private List datastreamIds = new ArrayList<>(); - /** - * The list of ids for all the Observations created during test procedure - * (will be used for clean-up) - */ - private List observationIds = new ArrayList<>(); - /** - * The list of ids for all the Sensors created during test procedure (will - * be used for clean-up) - */ - private List sensorIds = new ArrayList<>(); - /** - * The list of ids for all the ObservedPropeties created during test - * procedure (will be used for clean-up) - */ - private List obsPropIds = new ArrayList<>(); - /** - * The list of ids for all the FeaturesOfInterest created during test - * procedure (will be used for clean-up) - */ - private List foiIds = new ArrayList<>(); - - /** - * This method will be run before starting the test for this conformance - * class. It cleans the database to start test. - * - * @param testContext The test context to find out whether this class is - * requested to test or not - */ - @BeforeClass - public void obtainTestSubject(ITestContext testContext) { - Object obj = testContext.getSuite().getAttribute( - SuiteAttribute.LEVEL.getName()); - if ((null != obj)) { - Integer level = Integer.class.cast(obj); - Assert.assertTrue(level.intValue() > 1, - "Conformance level 2 will not be checked since ics = " + level); - } - - rootUri = testContext.getSuite().getAttribute( - SuiteAttribute.TEST_SUBJECT.getName()).toString(); - rootUri = rootUri.trim(); - if (rootUri.lastIndexOf('/') == rootUri.length() - 1) { - rootUri = rootUri.substring(0, rootUri.length() - 1); - } - deleteEverythings(); - } - - /** - * This method is testing create or POST entities. It only tests simple - * create, no deep insert. It makes sure that the response is 201 and use - * simple GET to make sure the entity is added to the service. - */ - @Test(description = "POST Entities", groups = "level-2", priority = 2) - public void createEntities() { - try { - /* Thing */ - String urlParameters = "{" - + "\"name\":\"Test Thing\"," - + "\"description\":\"This is a Test Thing From TestNG\"" - + "}"; - JSONObject entity = postEntity(EntityType.THING, urlParameters); - long thingId = entity.getLong(ControlInformation.ID); - thingIds.add(thingId); - - /* Location */ - urlParameters = "{\n" - + " \"name\": \"bow river\",\n" - + " \"description\": \"bow river\",\n" - + " \"encodingType\": \"application/vnd.geo+json\",\n" - + " \"location\": { \"type\": \"Point\", \"coordinates\": [-114.05, 51.05] }\n" - + "}"; - entity = postEntity(EntityType.LOCATION, urlParameters); - long locationId = entity.getLong(ControlInformation.ID); - locationIds.add(locationId); - JSONObject locationEntity = entity; - - /* Sensor */ - urlParameters = "{\n" - + " \"name\": \"Fuguro Barometer\",\n" - + " \"description\": \"Fuguro Barometer\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Barometer\"\n" - + "}"; - entity = postEntity(EntityType.SENSOR, urlParameters); - long sensorId = entity.getLong(ControlInformation.ID); - sensorIds.add(sensorId); - - /* ObservedProperty */ - urlParameters = "{\n" - + " \"name\": \"DewPoint Temperature\",\n" - + " \"definition\": \"http://dbpedia.org/page/Dew_point\",\n" - + " \"description\": \"The dewpoint temperature is the temperature to which the air must be cooled, at constant pressure, for dew to form. As the grass and other objects near the ground cool to the dewpoint, some of the water vapor in the atmosphere condenses into liquid water on the objects.\"\n" - + "}"; - entity = postEntity(EntityType.OBSERVED_PROPERTY, urlParameters); - long obsPropId = entity.getLong(ControlInformation.ID); - obsPropIds.add(obsPropId); - - /* FeatureOfInterest */ - urlParameters = "{\n" - + " \"name\": \"A weather station.\",\n" - + " \"description\": \"A weather station.\",\n" - + " \"encodingType\": \"application/vnd.geo+json\",\n" - + " \"feature\": {\n" - + " \"type\": \"Point\",\n" - + " \"coordinates\": [\n" - + " 10,\n" - + " 10\n" - + " ]\n" - + " }\n" - + "}"; - entity = postEntity(EntityType.FEATURE_OF_INTEREST, urlParameters); - long foiId = entity.getLong(ControlInformation.ID); - foiIds.add(foiId); - - /* Datastream */ - urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" - + " \"ObservedProperty\":{ \"@iot.id\":" + obsPropId + "},\n" - + " \"Sensor\": { \"@iot.id\": " + sensorId + " }\n" - + "}"; - entity = postEntity(EntityType.DATASTREAM, urlParameters); - long datastreamId = entity.getLong(ControlInformation.ID); - datastreamIds.add(datastreamId); - - /* Observation */ - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-01T00:40:00.000Z\",\n" - + " \"result\": 8,\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "},\n" - + " \"FeatureOfInterest\": {\"@iot.id\": " + foiId + "} \n" - + "}"; - entity = postEntity(EntityType.OBSERVATION, urlParameters); - long obsId1 = entity.getLong(ControlInformation.ID); - observationIds.add(obsId1); - //POST Observation without FOI (Automatic creation of FOI) - //Add location to the Thing - urlParameters = "{\"Locations\":[{\"@iot.id\":" + locationId + "}]}"; - patchEntity(EntityType.THING, urlParameters, thingId); - - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-01T00:00:00.000Z\",\n" - + " \"resultTime\": \"2015-03-01T01:00:00.000Z\",\n" - + " \"result\": 100,\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" - + "}"; - entity = postEntity(EntityType.OBSERVATION, urlParameters); - checkForObservationResultTime(entity, "2015-03-01T01:00:00.000Z"); - long obsId2 = entity.getLong(ControlInformation.ID); - observationIds.add(obsId2); - long automatedFOIId = checkAutomaticInsertionOfFOI(obsId2, locationEntity, -1); - foiIds.add(automatedFOIId); - //POST another Observation to make sure it is linked to the previously created FOI - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-05-01T00:00:00.000Z\",\n" - + " \"result\": 105,\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" - + "}"; - entity = postEntity(EntityType.OBSERVATION, urlParameters); - checkForObservationResultTime(entity, null); - long obsId3 = entity.getLong(ControlInformation.ID); - observationIds.add(obsId3); - checkAutomaticInsertionOfFOI(obsId2, locationEntity, automatedFOIId); - - /* HistoricalLocation */ - urlParameters = "{\n" - + " \"time\": \"2015-03-01T00:40:00.000Z\",\n" - + " \"Thing\":{\"@iot.id\": " + thingId + "},\n" - + " \"Locations\": [{\"@iot.id\": " + locationId + "}] \n" - + "}"; - entity = postEntity(EntityType.HISTORICAL_LOCATION, urlParameters); - long histLocId = entity.getLong(ControlInformation.ID); - historicalLocationIds.add(histLocId); - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This method is testing create or POST in the form of Deep Insert. It - * makes sure the response is 201. Also using GET requests, it makes sure - * the entity and all its related entities are created and added to the - * service. - */ - @Test(description = "POST Entities using Deep Insert", groups = "level-2", priority = 2) - public void createEntitiesWithDeepInsert() { - try { - /* Thing */ - String urlParameters = "{\n" - + " \"name\": \"Office Building\",\n" - + " \"description\": \"Office Building\",\n" - + " \"properties\": {\n" - + " \"reference\": \"Third Floor\"\n" - + " },\n" - + " \"Locations\": [\n" - + " {\n" - + " \"name\": \"West Roof\",\n" - + " \"description\": \"West Roof\",\n" - + " \"location\": { \"type\": \"Point\", \"coordinates\": [-117.05, 51.05] },\n" - + " \"encodingType\": \"application/vnd.geo+json\"\n" - + " }\n" - + " ],\n" - + " \"Datastreams\": [\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Lumen\",\n" - + " \"symbol\": \"lm\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" - + " },\n" - + " \"name\": \"Light exposure.\",\n" - + " \"description\": \"Light exposure.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" - + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" - + " },\n" - + " \"Sensor\": { \n" - + " \"name\": \"Acme Fluxomatic 1000\",\n" - + " \"description\": \"Acme Fluxomatic 1000\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Light flux sensor\"\n" - + " }\n" - + " }\n" - + " ]\n" - + "}"; - JSONObject entity = postEntity(EntityType.THING, urlParameters); - long thingId = entity.getLong(ControlInformation.ID); - //Check Datastream - JSONObject deepInsertedObj = new JSONObject("{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Lumen\",\n" - + " \"symbol\": \"lm\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" - + " },\n" - + " \"name\": \"Light exposure.\",\n" - + " \"description\": \"Light exposure.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\"\n" - + " }\n"); - long datastreamId = checkRelatedEntity(EntityType.THING, thingId, EntityType.DATASTREAM, deepInsertedObj); - datastreamIds.add(datastreamId); - //Check Location - deepInsertedObj = new JSONObject("{\n" - + " \"name\": \"West Roof\",\n" - + " \"description\": \"West Roof\",\n" - + " \"location\": { \"type\": \"Point\", \"coordinates\": [-117.05, 51.05] },\n" - + " \"encodingType\": \"application/vnd.geo+json\"\n" - + " }\n"); - locationIds.add(checkRelatedEntity(EntityType.THING, thingId, EntityType.LOCATION, deepInsertedObj)); - //Check Sensor - deepInsertedObj = new JSONObject("{\n" - + " \"name\": \"Acme Fluxomatic 1000\",\n" - + " \"description\": \"Acme Fluxomatic 1000\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Light flux sensor\"\n" - + " }\n"); - sensorIds.add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.SENSOR, deepInsertedObj)); - //Check ObservedProperty - deepInsertedObj = new JSONObject("{\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" - + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" - + " },\n"); - obsPropIds.add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.OBSERVED_PROPERTY, deepInsertedObj)); - thingIds.add(thingId); - - /* Datastream */ - urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" - + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" - + " },\n" - + " \"Sensor\": { \n" - + " \"name\": \"Acme Fluxomatic 1000\",\n" - + " \"description\": \"Acme Fluxomatic 1000\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Light flux sensor\"\n" - + " },\n" - + " \"Observations\": [\n" - + " {\n" - + " \"phenomenonTime\": \"2015-03-01T00:10:00Z\",\n" - + " \"result\": 10\n" - + " }\n" - + " ]" - + "}"; - entity = postEntity(EntityType.DATASTREAM, urlParameters); - datastreamId = entity.getLong(ControlInformation.ID); - //Check Sensor - deepInsertedObj = new JSONObject("{\n" - + " \"name\": \"Acme Fluxomatic 1000\",\n" - + " \"description\": \"Acme Fluxomatic 1000\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Light flux sensor\"\n" - + " }\n"); - sensorIds.add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.SENSOR, deepInsertedObj)); - //Check ObservedProperty - deepInsertedObj = new JSONObject("{\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" - + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" - + " },\n"); - obsPropIds.add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.OBSERVED_PROPERTY, deepInsertedObj)); - //Check Observation - deepInsertedObj = new JSONObject("{\n" - + " \"phenomenonTime\": \"2015-03-01T00:10:00.000Z\",\n" - + " \"result\": 10\n" - + " }\n"); - observationIds.add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.OBSERVATION, deepInsertedObj)); - datastreamIds.add(datastreamId); - - /* Observation */ - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" - + " \"result\": 100,\n" - + " \"FeatureOfInterest\": {\n" - + " \t\"name\": \"A weather station.\",\n" - + " \t\"description\": \"A weather station.\",\n" - + " \t\"encodingType\": \"application/vnd.geo+json\",\n" - + " \"feature\": {\n" - + " \"type\": \"Point\",\n" - + " \"coordinates\": [\n" - + " -114.05,\n" - + " 51.05\n" - + " ]\n" - + " }\n" - + " },\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" - + "}"; - entity = postEntity(EntityType.OBSERVATION, urlParameters); - long obsId1 = entity.getLong(ControlInformation.ID); - //Check FeaturOfInterest - deepInsertedObj = new JSONObject("{\n" - + " \"name\": \"A weather station.\",\n" - + " \"description\": \"A weather station.\",\n" - + " \"encodingType\": \"application/vnd.geo+json\",\n" - + " \"feature\": {\n" - + " \"type\": \"Point\",\n" - + " \"coordinates\": [\n" - + " -114.05,\n" - + " 51.05\n" - + " ]\n" - + " }\n" - + " }\n"); - foiIds.add(checkRelatedEntity(EntityType.OBSERVATION, obsId1, EntityType.FEATURE_OF_INTEREST, deepInsertedObj)); - observationIds.add(obsId1); - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This method is testing create or POST with invalid Deep Insert. It makes - * sure that if there is any problem in the request body of Deep Insert, - * none of the entities in that query is created. The response should be 400 - * or 409 and the entities should not be accessible using GET. - */ - @Test(description = "POST Invalid Entities using Deep Insert", groups = "level-2", priority = 1) - public void createInvalidEntitiesWithDeepInsert() { - try { - String urlParameters = "{\n" - + " \"name\": \"Office Building\",\n" - + " \"description\": \"Office Building\",\n" - + " \"properties\": {\n" - + " \"reference\": \"Third Floor\"\n" - + " },\n" - + " \"Locations\": [\n" - + " {\n" - + " \"name\": \"West Roof\",\n" - + " \"description\": \"West Roof\",\n" - + " \"location\": { \"type\": \"Point\", \"coordinates\": [-117.05, 51.05] },\n" - + " \"encodingType\": \"application/vnd.geo+json\"\n" - + " }\n" - + " ],\n" - + " \"Datastreams\": [\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Lumen\",\n" - + " \"symbol\": \"lm\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" - + " },\n" - + " \"name\": \"Light exposure.\",\n" - + " \"description\": \"Light exposure.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" - + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" - + " }\n" - + " }\n" - + " ]\n" - + "}"; - postInvalidEntity(EntityType.THING, urlParameters); - List entityTypesToCheck = new ArrayList<>(); - entityTypesToCheck.add(EntityType.THING); - entityTypesToCheck.add(EntityType.LOCATION); - entityTypesToCheck.add(EntityType.HISTORICAL_LOCATION); - entityTypesToCheck.add(EntityType.DATASTREAM); - entityTypesToCheck.add(EntityType.OBSERVED_PROPERTY); - checkNotExisting(entityTypesToCheck); - - /* Datastream */ - urlParameters = "{" - + "\"name\": \"Office Building\"," - + "\"description\": \"Office Building\"" - + "}"; - long thingId = postEntity(EntityType.THING, urlParameters).getLong("@iot.id"); - - urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" - + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" - + " },\n" - + " \"Observations\": [\n" - + " {\n" - + " \"phenomenonTime\": \"2015-03-01T00:10:00Z\",\n" - + " \"result\": 10\n" - + " }\n" - + " ]" - + "}"; - postInvalidEntity(EntityType.DATASTREAM, urlParameters); - - urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" - + " \"Sensor\": { \n" - + " \"name\": \"Acme Fluxomatic 1000\",\n" - + " \"description\": \"Acme Fluxomatic 1000\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Light flux sensor\"\n" - + " },\n" - + " \"Observations\": [\n" - + " {\n" - + " \"phenomenonTime\": \"2015-03-01T00:10:00Z\",\n" - + " \"result\": 10\n" - + " }\n" - + " ]" - + "}"; - postInvalidEntity(EntityType.DATASTREAM, urlParameters); - - urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" - + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" - + " },\n" - + " \"Sensor\": { \n" - + " \"name\": \"Acme Fluxomatic 1000\",\n" - + " \"description\": \"Acme Fluxomatic 1000\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Light flux sensor\"\n" - + " },\n" - + " \"Observations\": [\n" - + " {\n" - + " \"phenomenonTime\": \"2015-03-01T00:10:00Z\",\n" - + " \"result\": 10\n" - + " }\n" - + " ]" - + "}"; - postInvalidEntity(EntityType.DATASTREAM, urlParameters); - -// urlParameters = "{\n" + -// " \"unitOfMeasurement\": {\n" + -// " \"name\": \"Celsius\",\n" + -// " \"symbol\": \"degC\",\n" + -// " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + -// " },\n" + -// " \"description\": \"test datastream.\",\n" + -// " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + -// " \"Thing\": { \"@iot.id\": " + thingId + " },\n" + -// " \"ObservedProperty\": {\n" + -// " \"name\": \"Luminous Flux\",\n" + -// " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + -// " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" + -// " },\n" + -// " \"Sensor\": { \n" + -// " \"description\": \"Acme Fluxomatic 1000\",\n" + -// " \"encodingType\": \"http://schema.org/description\",\n" + -// " \"metadata\": \"Light flux sensor\"\n" + -// " },\n" + -// " \"Observations\": [\n" + -// " {\n" + -// " }\n" + -// " ]" + -// "}"; -// postInvalidEntity(EntityType.DATASTREAM, urlParameters); - entityTypesToCheck.clear(); - entityTypesToCheck.add(EntityType.DATASTREAM); - entityTypesToCheck.add(EntityType.SENSOR); - entityTypesToCheck.add(EntityType.OBSERVATION); - entityTypesToCheck.add(EntityType.FEATURE_OF_INTEREST); - entityTypesToCheck.add(EntityType.OBSERVED_PROPERTY); - checkNotExisting(entityTypesToCheck); - - /* Observation */ - urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" - + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" - + " },\n" - + " \"Sensor\": { \n" - + " \"name\": \"Acme Fluxomatic 1000\",\n" - + " \"description\": \"Acme Fluxomatic 1000\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Light flux sensor\"\n" - + " }\n" - + "}"; - long datastreamId = postEntity(EntityType.DATASTREAM, urlParameters).getLong("@iot.id"); - - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" - + " \"result\": 100,\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" - + "}"; - postInvalidEntity(EntityType.OBSERVATION, urlParameters); - - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" - + " \"result\": 100,\n" - + " \"FeatureOfInterest\": {\n" - + " \t\"name\": \"A weather station.\",\n" - + " \t\"description\": \"A weather station.\",\n" - + " \"feature\": {\n" - + " \"type\": \"Point\",\n" - + " \"coordinates\": [\n" - + " -114.05,\n" - + " 51.05\n" - + " ]\n" - + " }\n" - + " },\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" - + "}"; - postInvalidEntity(EntityType.OBSERVATION, urlParameters); - - entityTypesToCheck.clear(); - entityTypesToCheck.add(EntityType.OBSERVATION); - entityTypesToCheck.add(EntityType.FEATURE_OF_INTEREST); - checkNotExisting(entityTypesToCheck); - - deleteEverythings(); - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This method is testing create or POST invalid entities. The response - * should be 400 or 409 and the entity should not be accessible using GET. - */ - @Test(description = "POST Invalid Entities", groups = "level-2", priority = 3) - public void createInvalidEntities() { - try { - /* Datastream */ - // Without Sensor - String urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"Thing\": { \"@iot.id\": " + thingIds.get(0) + " },\n" - + " \"ObservedProperty\":{ \"@iot.id\":" + obsPropIds.get(0) + "}\n" - + "}"; - postInvalidEntity(EntityType.DATASTREAM, urlParameters); - //Without ObservedProperty - urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"Thing\": { \"@iot.id\": " + thingIds.get(0) + " },\n" - + " \"Sensor\": { \"@iot.id\": " + sensorIds.get(0) + " }\n" - + "}"; - postInvalidEntity(EntityType.DATASTREAM, urlParameters); - //Without Things - urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"ObservedProperty\":{ \"@iot.id\":" + obsPropIds.get(0) + "},\n" - + " \"Sensor\": { \"@iot.id\": " + sensorIds.get(0) + " }\n" - + "}"; - postInvalidEntity(EntityType.DATASTREAM, urlParameters); - - /* Observation */ - //Create Thing and Datastream - urlParameters = "{" - + "\"name\":\"This is a Test Thing From TestNG\"," - + "\"description\":\"This is a Test Thing From TestNG\"" - + "}"; - long thingId = postEntity(EntityType.THING, urlParameters).getLong(ControlInformation.ID); - thingIds.add(thingId); - urlParameters = "{\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Celsius\",\n" - + " \"symbol\": \"degC\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" - + " },\n" - + " \"name\": \"test datastream.\",\n" - + " \"description\": \"test datastream.\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" - + " \"ObservedProperty\":{ \"@iot.id\":" + obsPropIds.get(0) + "},\n" - + " \"Sensor\": { \"@iot.id\": " + sensorIds.get(0) + " }\n" - + "}"; - long datastreamId = postEntity(EntityType.DATASTREAM, urlParameters).getLong(ControlInformation.ID); - datastreamIds.add(datastreamId); - //Without Datastream - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-01T00:40:00.000Z\",\n" - + " \"result\": 8,\n" - + " \"FeatureOfInterest\": {\"@iot.id\": " + foiIds.get(0) + "} \n" - + "}"; - postInvalidEntity(EntityType.OBSERVATION, urlParameters); - //Without FOI and without Thing's Location - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-01T00:00:00.000Z\",\n" - + " \"result\": 100,\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" - + "}"; - postInvalidEntity(EntityType.OBSERVATION, urlParameters); - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - - } - - /** - * This method is testing partial update or PATCH. The response should be - * 200 and only the properties in the PATCH body should be updated, and the - * rest must be unchanged. - */ - @Test(description = "PATCH Entities", groups = "level-2", priority = 4) - public void patchEntities() { - try { - /* Thing */ - long thingId = thingIds.get(0); - JSONObject entity = getEntity(EntityType.THING, thingId); - String urlParameters = "{\"description\":\"This is a PATCHED Test Thing From TestNG\"}"; - Map diffs = new HashMap<>(); - diffs.put("description", "This is a PATCHED Test Thing From TestNG"); - JSONObject updatedEntity = patchEntity(EntityType.THING, urlParameters, thingId); - checkPatch(EntityType.THING, entity, updatedEntity, diffs); - - /* Location */ - long locationId = locationIds.get(0); - entity = getEntity(EntityType.LOCATION, locationId); - urlParameters = "{\"location\": { \"type\": \"Point\", \"coordinates\": [114.05, -50] }}"; - diffs = new HashMap<>(); - diffs.put("location", new JSONObject("{ \"type\": \"Point\", \"coordinates\": [114.05, -50] }}")); - updatedEntity = patchEntity(EntityType.LOCATION, urlParameters, locationId); - checkPatch(EntityType.LOCATION, entity, updatedEntity, diffs); - - /* HistoricalLocation */ - long histLocId = historicalLocationIds.get(0); - entity = getEntity(EntityType.HISTORICAL_LOCATION, histLocId); - urlParameters = "{\"time\": \"2015-07-01T00:00:00.000Z\"}"; - diffs = new HashMap<>(); - diffs.put("time", "2015-07-01T00:00:00.000Z"); - updatedEntity = patchEntity(EntityType.HISTORICAL_LOCATION, urlParameters, histLocId); - checkPatch(EntityType.HISTORICAL_LOCATION, entity, updatedEntity, diffs); - - /* Sensor */ - long sensorId = sensorIds.get(0); - entity = getEntity(EntityType.SENSOR, sensorId); - urlParameters = "{\"metadata\": \"PATCHED\"}"; - diffs = new HashMap<>(); - diffs.put("metadata", "PATCHED"); - updatedEntity = patchEntity(EntityType.SENSOR, urlParameters, sensorId); - checkPatch(EntityType.SENSOR, entity, updatedEntity, diffs); - - /* ObserverdProperty */ - long obsPropId = obsPropIds.get(0); - entity = getEntity(EntityType.OBSERVED_PROPERTY, obsPropId); - urlParameters = "{\"description\":\"PATCHED\"}"; - diffs = new HashMap<>(); - diffs.put("description", "PATCHED"); - updatedEntity = patchEntity(EntityType.OBSERVED_PROPERTY, urlParameters, obsPropId); - checkPatch(EntityType.OBSERVED_PROPERTY, entity, updatedEntity, diffs); - - /* FeatureOfInterest */ - long foiId = foiIds.get(0); - entity = getEntity(EntityType.FEATURE_OF_INTEREST, foiId); - urlParameters = "{\"feature\":{ \"type\": \"Point\", \"coordinates\": [114.05, -51.05] }}"; - diffs = new HashMap<>(); - diffs.put("feature", new JSONObject("{ \"type\": \"Point\", \"coordinates\": [114.05, -51.05] }")); - updatedEntity = patchEntity(EntityType.FEATURE_OF_INTEREST, urlParameters, foiId); - checkPatch(EntityType.FEATURE_OF_INTEREST, entity, updatedEntity, diffs); - - /* Datastream */ - long datastreamId = datastreamIds.get(0); - entity = getEntity(EntityType.DATASTREAM, datastreamId); - urlParameters = "{\"description\": \"Patched Description\"}"; - diffs = new HashMap<>(); - diffs.put("description", "Patched Description"); - updatedEntity = patchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); - checkPatch(EntityType.DATASTREAM, entity, updatedEntity, diffs); - //Second PATCH for UOM - entity = updatedEntity; - urlParameters = "{ \"unitOfMeasurement\": {\n" - + " \"name\": \"Entropy2\",\n" - + " \"symbol\": \"S2\",\n" - + " \"definition\": \"http://qudt.org/vocab/unit#Entropy2\"\n" - + " } }"; - diffs = new HashMap<>(); - diffs.put("unitOfMeasurement", new JSONObject("{\"name\": \"Entropy2\",\"symbol\": \"S2\",\"definition\": \"http://qudt.org/vocab/unit#Entropy2\"}")); - updatedEntity = patchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); - checkPatch(EntityType.DATASTREAM, entity, updatedEntity, diffs); - - /* Observation */ - long obsId1 = observationIds.get(0); - entity = getEntity(EntityType.OBSERVATION, obsId1); - urlParameters = "{\"phenomenonTime\": \"2015-07-01T00:40:00.000Z\"}"; - diffs = new HashMap<>(); - diffs.put("phenomenonTime", "2015-07-01T00:40:00.000Z"); - updatedEntity = patchEntity(EntityType.OBSERVATION, urlParameters, obsId1); - checkPatch(EntityType.OBSERVATION, entity, updatedEntity, diffs); - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This method is testing DELETE and its integrity constraint. The response - * should be 200. After DELETE the GET request to that entity should return - * 404. - */ - @Test(description = "DELETE Entities", groups = "level-2", priority = 5) - public void deleteEntities() { - for (int i = 0; i < observationIds.size(); i++) { - deleteEntity(EntityType.OBSERVATION, observationIds.get(i)); - } - for (int i = 0; i < foiIds.size(); i++) { - deleteEntity(EntityType.FEATURE_OF_INTEREST, foiIds.get(i)); - } - for (int i = 0; i < datastreamIds.size(); i++) { - deleteEntity(EntityType.DATASTREAM, datastreamIds.get(i)); - } - for (int i = 0; i < obsPropIds.size(); i++) { - deleteEntity(EntityType.OBSERVED_PROPERTY, obsPropIds.get(i)); - } - for (int i = 0; i < sensorIds.size(); i++) { - deleteEntity(EntityType.SENSOR, sensorIds.get(i)); - } - for (int i = 0; i < historicalLocationIds.size(); i++) { - deleteEntity(EntityType.HISTORICAL_LOCATION, historicalLocationIds.get(i)); - } - for (int i = 0; i < locationIds.size(); i++) { - deleteEntity(EntityType.LOCATION, locationIds.get(i)); - } - for (int i = 0; i < thingIds.size(); i++) { - deleteEntity(EntityType.THING, thingIds.get(i)); - } - - checkDeleteIntegrityConstraint(); - } - - /** - * This is helper method for checking the integrity containt of DELETE. For - * each entity, it checks after deleting, it confirm the deletion of its - * related entities mentioned in the integrity constraint of the - * specification. - */ - private void checkDeleteIntegrityConstraint() { - //Thing - createEntitiesForDelete(); - deleteEntity(EntityType.THING, thingIds.get(0)); - List entityTypes = new ArrayList<>(); - entityTypes.add(EntityType.THING); - entityTypes.add(EntityType.DATASTREAM); - entityTypes.add(EntityType.HISTORICAL_LOCATION); - entityTypes.add(EntityType.OBSERVATION); - checkNotExisting(entityTypes); - entityTypes.clear(); - entityTypes.add(EntityType.LOCATION); - entityTypes.add(EntityType.SENSOR); - entityTypes.add(EntityType.OBSERVED_PROPERTY); - entityTypes.add(EntityType.FEATURE_OF_INTEREST); - checkExisting(entityTypes); - - //Datastream - createEntitiesForDelete(); - deleteEntity(EntityType.DATASTREAM, datastreamIds.get(0)); - entityTypes.clear(); - entityTypes.add(EntityType.DATASTREAM); - entityTypes.add(EntityType.OBSERVATION); - checkNotExisting(entityTypes); - entityTypes.clear(); - entityTypes.add(EntityType.THING); - entityTypes.add(EntityType.SENSOR); - entityTypes.add(EntityType.OBSERVED_PROPERTY); - entityTypes.add(EntityType.FEATURE_OF_INTEREST); - entityTypes.add(EntityType.LOCATION); - entityTypes.add(EntityType.HISTORICAL_LOCATION); - checkExisting(entityTypes); - - //Loation - createEntitiesForDelete(); - deleteEntity(EntityType.LOCATION, locationIds.get(0)); - entityTypes.clear(); - entityTypes.add(EntityType.LOCATION); - entityTypes.add(EntityType.HISTORICAL_LOCATION); - checkNotExisting(entityTypes); - entityTypes.clear(); - entityTypes.add(EntityType.THING); - entityTypes.add(EntityType.SENSOR); - entityTypes.add(EntityType.OBSERVED_PROPERTY); - entityTypes.add(EntityType.FEATURE_OF_INTEREST); - entityTypes.add(EntityType.DATASTREAM); - entityTypes.add(EntityType.OBSERVATION); - checkExisting(entityTypes); - - //HistoricalLoation - createEntitiesForDelete(); - deleteEntity(EntityType.HISTORICAL_LOCATION, historicalLocationIds.get(0)); - entityTypes.clear(); - entityTypes.add(EntityType.HISTORICAL_LOCATION); - checkNotExisting(entityTypes); - entityTypes.clear(); - entityTypes.add(EntityType.THING); - entityTypes.add(EntityType.SENSOR); - entityTypes.add(EntityType.OBSERVED_PROPERTY); - entityTypes.add(EntityType.FEATURE_OF_INTEREST); - entityTypes.add(EntityType.DATASTREAM); - entityTypes.add(EntityType.OBSERVATION); - entityTypes.add(EntityType.LOCATION); - checkExisting(entityTypes); - - //Sensor - createEntitiesForDelete(); - deleteEntity(EntityType.SENSOR, sensorIds.get(0)); - entityTypes.clear(); - entityTypes.add(EntityType.SENSOR); - entityTypes.add(EntityType.DATASTREAM); - entityTypes.add(EntityType.OBSERVATION); - checkNotExisting(entityTypes); - entityTypes.clear(); - entityTypes.add(EntityType.THING); - entityTypes.add(EntityType.OBSERVED_PROPERTY); - entityTypes.add(EntityType.FEATURE_OF_INTEREST); - entityTypes.add(EntityType.LOCATION); - entityTypes.add(EntityType.HISTORICAL_LOCATION); - checkExisting(entityTypes); - - //ObservedProperty - createEntitiesForDelete(); - deleteEntity(EntityType.OBSERVED_PROPERTY, obsPropIds.get(0)); - entityTypes.clear(); - entityTypes.add(EntityType.OBSERVED_PROPERTY); - entityTypes.add(EntityType.DATASTREAM); - entityTypes.add(EntityType.OBSERVATION); - checkNotExisting(entityTypes); - entityTypes.clear(); - entityTypes.add(EntityType.THING); - entityTypes.add(EntityType.SENSOR); - entityTypes.add(EntityType.FEATURE_OF_INTEREST); - entityTypes.add(EntityType.LOCATION); - entityTypes.add(EntityType.HISTORICAL_LOCATION); - checkExisting(entityTypes); - - //FeatureOfInterest - createEntitiesForDelete(); - deleteEntity(EntityType.FEATURE_OF_INTEREST, foiIds.get(0)); - entityTypes.clear(); - entityTypes.add(EntityType.FEATURE_OF_INTEREST); - entityTypes.add(EntityType.OBSERVATION); - checkNotExisting(entityTypes); - entityTypes.clear(); - entityTypes.add(EntityType.THING); - entityTypes.add(EntityType.SENSOR); - entityTypes.add(EntityType.OBSERVED_PROPERTY); - entityTypes.add(EntityType.LOCATION); - entityTypes.add(EntityType.HISTORICAL_LOCATION); - entityTypes.add(EntityType.DATASTREAM); - checkExisting(entityTypes); - - //Observation - createEntitiesForDelete(); - deleteEntity(EntityType.OBSERVATION, observationIds.get(0)); - entityTypes.clear(); - entityTypes.add(EntityType.OBSERVATION); - checkNotExisting(entityTypes); - entityTypes.clear(); - entityTypes.add(EntityType.THING); - entityTypes.add(EntityType.SENSOR); - entityTypes.add(EntityType.OBSERVED_PROPERTY); - entityTypes.add(EntityType.FEATURE_OF_INTEREST); - entityTypes.add(EntityType.DATASTREAM); - entityTypes.add(EntityType.HISTORICAL_LOCATION); - entityTypes.add(EntityType.LOCATION); - checkExisting(entityTypes); - } - - //TODO: Add invalid PATCH test for other entities when it is implemented in the service - - /** - * This method is testing invalid partial update or PATCH. The PATCH request - * is invalid if the body contains related entities as inline content. - */ - @Test(description = "Invalid PATCH Entities", groups = "level-2", priority = 4) - public void invalidPatchEntities() { - /** - * Thing * - */ - long thingId = thingIds.get(0); - String urlParameters = "{\"Locations\": [\n" - + " {\n" - + " \"name\": \"West Roof\",\n" - + " \"description\": \"West Roof\",\n" - + " \"location\": { \"type\": \"Point\", \"coordinates\": [-117.05, 51.05] },\n" - + " \"encodingType\": \"application/vnd.geo+json\"\n" - + " }\n" - + " ]}"; - invalidPatchEntity(EntityType.THING, urlParameters, thingId); - urlParameters = "{\"Datastreams\": [\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Lumen\",\n" - + " \"symbol\": \"lm\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" - + " }}]}"; - invalidPatchEntity(EntityType.THING, urlParameters, thingId); - -// /** Location **/ -// long locationId = locationIds.get(0); -// urlParameters = "{\"Things\":[{\"description\":\"Orange\"}]}"; -// invalidPatchEntity(EntityType.LOCATION, urlParameters, locationId); -// -// /** HistoricalLocation **/ -// long histLocId = historicalLocationIds.get(0); -// urlParameters = "{\"time\": \"2015-07-01T00:00:00.000Z\"}"; -// invalidPatchEntity(EntityType.HISTORICAL_LOCATION, urlParameters, histLocId); -// - /** - * Sensor * - */ - long sensorId = sensorIds.get(0); - urlParameters = "{\"Datastreams\": [\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Lumen\",\n" - + " \"symbol\": \"lm\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"}\n" - + " ,\"Thing\":{\"@iot.id\":" + thingId + "}" - + " }]}"; - invalidPatchEntity(EntityType.SENSOR, urlParameters, sensorId); - - /** - * ObserverdProperty * - */ - long obsPropId = obsPropIds.get(0); - urlParameters = "{\"Datastreams\": [\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Lumen\",\n" - + " \"symbol\": \"lm\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"}\n" - + " ,\"Thing\":{\"@iot.id\":" + thingId + "}" - + " }]}"; - invalidPatchEntity(EntityType.OBSERVED_PROPERTY, urlParameters, obsPropId); - -// /** FeatureOfInterest **/ -// long foiId = foiIds.get(0); -// urlParameters = "{\"feature\":{ \"type\": \"Point\", \"coordinates\": [114.05, -51.05] }}"; -// invalidPatchEntity(EntityType.FEATURE_OF_INTEREST, urlParameters, foiId); - /** - * Datastream * - */ - long datastreamId = datastreamIds.get(0); - urlParameters = "{\"ObservedProperty\": {\n" - + " \t\"name\": \"Count\",\n" - + "\t\"definition\": \"http://qudt.org/vocab/unit#Dimensionless\",\n" - + "\t\"name\": \"Count is a dimensionless property.\",\n" - + "\t\"description\": \"Count is a dimensionless property.\"\n" - + " } }"; - invalidPatchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); - urlParameters = "{\"Sensor\": {\n" - + " \t\"name\": \"Acme Traffic 2000\", \n" - + " \t\"description\": \"Acme Traffic 2000\", \n" - + " \t\"encodingType\": \"application/pdf\",\n" - + " \t\"metadata\": \"Traffic counting device\"\n" - + " }}"; - invalidPatchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); - urlParameters = "{" - + "\"Thing\": {" - + " \"name\": \"test\"," - + " \"description\": \"test\"" - + " }" - + "}"; - invalidPatchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); - urlParameters = "{\"Observations\": [\n" - + " {\n" - + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" - + " \"result\": 92122,\n" - + " \"resultQuality\": \"High\"\n" - + " }\n" - + " ]}"; - invalidPatchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); - -// /** Observation **/ -// long obsId1 = observationIds.get(0); -// urlParameters = "{\"phenomenonTime\": \"2015-07-01T00:40:00.000Z\"}"; -// invalidPatchEntity(EntityType.OBSERVATION, urlParameters, obsId1); - } - - /** - * This method is testing DELETE request for a nonexistent entity. The - * response should be 404. - */ - @Test(description = "DELETE nonexistent Entities", groups = "level-2", priority = 5) - public void deleteNoneexistentEntities() { - deleteNonExsistentEntity(EntityType.THING); - deleteNonExsistentEntity(EntityType.LOCATION); - deleteNonExsistentEntity(EntityType.HISTORICAL_LOCATION); - deleteNonExsistentEntity(EntityType.SENSOR); - deleteNonExsistentEntity(EntityType.OBSERVED_PROPERTY); - deleteNonExsistentEntity(EntityType.DATASTREAM); - deleteNonExsistentEntity(EntityType.OBSERVATION); - deleteNonExsistentEntity(EntityType.FEATURE_OF_INTEREST); - } - - /** - * This method created the URL string for the entity with specific id and - * then send a GET request to that URL. - * - * @param entityType Entity type in from EntityType enum - * @param id The id of requested entity - * @return The requested entity in the format of JSON Object. - */ - private JSONObject getEntity(EntityType entityType, long id) { - if (id == -1) { - return null; - } - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); - try { - return new JSONObject(HTTPMethods.doGet(urlString).get("response").toString()); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - return null; - } - } - - /** - * This method created the URL string for the entity and then POST the - * entity with urlParameters to that URL. - * - * @param entityType Entity type in from EntityType enum - * @param urlParameters POST body - * @return The created entity in the form of JSON Object - */ - private JSONObject postEntity(EntityType entityType, String urlParameters) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - try { - Map responseMap = HTTPMethods.doPost(urlString, urlParameters); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 201, "Error during creation of entity " + entityType.name()); - String response = responseMap.get("response").toString(); - long id = Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")"))); - - urlString = urlString + "(" + id + ")"; - responseMap = HTTPMethods.doGet(urlString); - responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "The POSTed entity is not created. [Request] " + urlString); - - JSONObject result = new JSONObject(responseMap.get("response").toString()); - return result; - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - return null; - } - } - - /** - * This helper method is sending invalid POST request and confirm that the - * response is correct based on specification. - * - * @param entityType Entity type in from EntityType enum - * @param urlParameters POST body (invalid) - */ - private void postInvalidEntity(EntityType entityType, String urlParameters) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - - Map responseMap = HTTPMethods.doPost(urlString, urlParameters); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertTrue(responseCode == 400 || responseCode == 409, "The " + entityType.name() + " should not be created due to integrity constraints. [Request] " + urlString); - - } - - /** - * This method created the URL string for the entity with specific id and - * then send DELETE request to that URl. - * - * @param entityType Entity type in from EntityType enum - * @param id The id of requested entity - */ - private void deleteEntity(EntityType entityType, long id) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); - Map responseMap = HTTPMethods.doDelete(urlString); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "DELETE does not work properly for " + entityType + " with id " + id + ". Returned with response code " + responseCode + ". [Request] " + urlString); - - responseMap = HTTPMethods.doGet(urlString); - responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 404, "Deleted entity was not actually deleted : " + entityType + "(" + id + "). [Request] " + urlString); - } - - /** - * This method create the URL string for a nonexistent entity and send the - * DELETE request to that URL and confirm that the response is correct based - * on specification. - * - * @param entityType Entity type in from EntityType enum - */ - private void deleteNonExsistentEntity(EntityType entityType) { - long id = Long.MAX_VALUE; - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); - Map responseMap = HTTPMethods.doDelete(urlString); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 404, "DELETE does not work properly for nonexistent " + entityType + " with id " + id + ". Returned with response code " + responseCode + ". [Request] " + urlString); - - } - - - /** - * This method created the URL string for the entity with specific id and - * then PATCH the entity with urlParameters to that URL. - * - * @param entityType Entity type in from EntityType enum - * @param urlParameters The PATCH body - * @param id The id of requested entity - * @return The patched entity in the format of JSON Object - */ - private JSONObject patchEntity(EntityType entityType, String urlParameters, long id) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); - try { - - Map responseMap = HTTPMethods.doPatch(urlString, urlParameters); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "Error during updating(PATCH) of entity " + entityType.name() + "with [Request] " + urlString); - responseMap = HTTPMethods.doGet(urlString); - JSONObject result = new JSONObject(responseMap.get("response").toString()); - return result; - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - return null; - } - } - - /** - * This method created the URL string for the entity with specific id and - * then PATCH invalid entity with urlParameters to that URL and confirms - * that the response is correct based on specification. - * - * @param entityType Entity type in from EntityType enum - * @param urlParameters The PATCH body (invalid) - * @param id The id of requested entity - */ - private void invalidPatchEntity(EntityType entityType, String urlParameters, long id) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); - - Map responseMap = HTTPMethods.doPatch(urlString, urlParameters); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 400, "Error: Patching related entities inline must be illegal for entity " + entityType.name() + ". [Request] " + urlString); - - } - - /** - * Check the patched entity properties are updates correctly - * - * @param entityType Entity type in from EntityType enum - * @param oldEntity The old properties of the patched entity - * @param newEntity The updated properties of the patched entity - * @param diffs The properties that supposed to be updated besed on the - * request due to the specification - */ - private void checkPatch(EntityType entityType, JSONObject oldEntity, JSONObject newEntity, Map diffs) { - try { - for (String property : entityType.getProperties()) { - if (diffs.containsKey(property)) { - assertParameterEquals(property, newEntity.get(property).toString(), diffs.get(property).toString(), "PATCH was not applied correctly for " + entityType + "'s " + property + "."); - } else { - assertParameterEquals(property, newEntity.get(property).toString(), oldEntity.get(property).toString(), "PATCH was not applied correctly for " + entityType + "'s " + property + "."); - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * Check the FeatureOfInterest is created automatically correctly if not - * inserted in Observation - * - * @param obsId The observation id - * @param locationObj The Location object that the FOI is supposed to be - * created based on that - * @param expectedFOIId The id of the FOI linked to the Observation - * @return The id of FOI - */ - private long checkAutomaticInsertionOfFOI(long obsId, JSONObject locationObj, long expectedFOIId) { - String urlString = rootUri + "/Observations(" + obsId + ")/FeatureOfInterest"; - try { - Map responseMap = HTTPMethods.doGet(urlString); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "ERROR: FeatureOfInterest was not automatically create."); - JSONObject result = new JSONObject(responseMap.get("response").toString()); - long id = result.getLong(ControlInformation.ID); - if (expectedFOIId != -1) { - Assert.assertEquals(id, expectedFOIId, "ERROR: the Observation should have linked to FeatureOfInterest with ID: " + expectedFOIId + " , but it is linked for FeatureOfInterest with Id: " + id + ". [Request] " + urlString); - } - Assert.assertEquals(result.getJSONObject("feature").toString(), locationObj.getJSONObject("location").toString(), "ERROR: Automatic created FeatureOfInterest does not match last Location of that Thing. [Request] " + urlString); - return id; - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - return -1; - } - - /** - * Check the related entity of a given entity - * - * @param parentEntityType The given entity type - * @param parentId The given entity id - * @param relationEntityType The relation entity type - * @param relationObj The expected related entity object - * @return The id of related object - */ - private long checkRelatedEntity(EntityType parentEntityType, long parentId, EntityType relationEntityType, JSONObject relationObj) { - boolean isCollection = true; - String urlString = ServiceURLBuilder.buildURLString(rootUri, parentEntityType, parentId, relationEntityType, null); - if (parentEntityType.getRelations().contains(relationEntityType.singular)) { - isCollection = false; - } - - try { - Map responseMap = HTTPMethods.doGet(urlString); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "ERROR: Deep inserted " + relationEntityType + " does not created or linked to " + parentEntityType + ". [Request] " + urlString); - JSONObject result = new JSONObject(responseMap.get("response").toString()); - if (isCollection == true) { - result = result.getJSONArray("value").getJSONObject(0); - } - Iterator iterator = relationObj.keys(); - while (iterator.hasNext()) { - String key = iterator.next().toString(); - assertParameterEquals(key, Objects.toString(result.get(key)), Objects.toString(relationObj.get(key)), "ERROR: Deep inserted " + relationEntityType + " is not created correctly. [Request] " + urlString); - } - return result.getLong(ControlInformation.ID); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - return -1; - } - - private void assertParameterEquals(String key, final String actual, final String expected, String message) { - if (key.toLowerCase().contains("time") && !"null".equals(expected) && !"null".equals(actual)) { - if (expected.contains("/")) { - String[] expextedParts = expected.split("/"); - String[] actualParts = actual.split("/"); - Assert.assertEquals(ZonedDateTime.parse(actualParts[0]), ZonedDateTime.parse(expextedParts[0]), message); - Assert.assertEquals(ZonedDateTime.parse(actualParts[1]), ZonedDateTime.parse(expextedParts[1]), message); - } else { - Assert.assertEquals(ZonedDateTime.parse(actual), ZonedDateTime.parse(expected), message); - } - } else { - Assert.assertEquals(actual, expected, message); - } - } - - /** - * Check the Observation have the resultTime even if it is null - * - * @param observation The observation JSON object - * @param resultTimeValue The expected value of resultTime - */ - private void checkForObservationResultTime(JSONObject observation, String resultTimeValue) { - try { - if (resultTimeValue == null) { - Assert.assertEquals(observation.get("resultTime").toString(), "null", "The resultTime of the Observation " + observation.getLong(ControlInformation.ID) + " should have been null but it is now \"" + observation.get("resultTime").toString() + "\"."); - } else { - Assert.assertEquals(ZonedDateTime.parse(observation.getString("resultTime")), ZonedDateTime.parse(resultTimeValue), "The resultTime of the Observation " + observation.getLong(ControlInformation.ID) + " should have been \"" + resultTimeValue + "\" but it is now \"" + observation.get("resultTime").toString() + "\"."); - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * Check the database is empty of certain entity types - * - * @param entityTypes List of entity types - */ - private void checkNotExisting(List entityTypes) { - for (EntityType entityType : entityTypes) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - try { - JSONObject result = new JSONObject(responseMap.get("response").toString()); - JSONArray array = result.getJSONArray("value"); - Assert.assertEquals(array.length(), 0, entityType + " is created although it shouldn't. [Request] " + urlString); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } - } - - /** - * Check there are some entityes for certain entity types - * - * @param entityTypes List of entity types - */ - private void checkExisting(List entityTypes) { - for (EntityType entityType : entityTypes) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - try { - JSONObject result = new JSONObject(responseMap.get("response").toString()); - JSONArray array = result.getJSONArray("value"); - Assert.assertTrue(array.length() > 0, entityType + " is created although it shouldn't. [Request] " + urlString); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } - } - - /** - * This method is run after all the tests of this class is run and clean the - * database. - */ - @AfterClass - public void deleteEverythings() { - deleteEntityType(EntityType.OBSERVATION); - deleteEntityType(EntityType.FEATURE_OF_INTEREST); - deleteEntityType(EntityType.DATASTREAM); - deleteEntityType(EntityType.SENSOR); - deleteEntityType(EntityType.OBSERVED_PROPERTY); - deleteEntityType(EntityType.HISTORICAL_LOCATION); - deleteEntityType(EntityType.LOCATION); - deleteEntityType(EntityType.THING); - } - - /** - * Delete all the entities of a certain entity type - * - * @param entityType The entity type from EntityType enum - */ - private void deleteEntityType(EntityType entityType) { - JSONArray array = null; - String urlString = ""; - do { - try { - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - JSONObject result = new JSONObject(responseMap.get("response").toString()); - array = result.getJSONArray("value"); - for (int i = 0; i < array.length(); i++) { - long id = array.getJSONObject(i).getLong(ControlInformation.ID); - deleteEntity(entityType, id); - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } while (array.length() > 0); - } - - /** - * Create entities as a pre-process for testing DELETE. - */ - private void createEntitiesForDelete() { - String urlString = ""; - try { - - deleteEverythings(); - thingIds.clear(); - locationIds.clear(); - historicalLocationIds.clear(); - datastreamIds.clear(); - sensorIds.clear(); - observationIds.clear(); - obsPropIds.clear(); - foiIds.clear(); - - //First Thing - String urlParameters = "{\n" - + " \"name\": \"thing 1\",\n" - + " \"description\": \"thing 1\",\n" - + " \"properties\": {\n" - + " \"reference\": \"first\"\n" - + " },\n" - + " \"Locations\": [\n" - + " {\n" - + " \"name\": \"location 1\",\n" - + " \"description\": \"location 1\",\n" - + " \"location\": {\n" - + " \"type\": \"Point\",\n" - + " \"coordinates\": [\n" - + " -117.05,\n" - + " 51.05\n" - + " ]\n" - + " },\n" - + " \"encodingType\": \"application/vnd.geo+json\"\n" - + " }\n" - + " ],\n" - + " \"Datastreams\": [\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Lumen\",\n" - + " \"symbol\": \"lm\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" - + " },\n" - + " \"name\": \"datastream 1\",\n" - + " \"description\": \"datastream 1\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" - + " \"description\": \"observedProperty 1\"\n" - + " },\n" - + " \"Sensor\": {\n" - + " \"name\": \"sensor 1\",\n" - + " \"description\": \"sensor 1\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Light flux sensor\"\n" - + " }\n" - + " }\n" - + " ]\n" - + "}"; - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, -1, null, null); - Map responseMap = HTTPMethods.doPost(urlString, urlParameters); - String response = responseMap.get("response").toString(); - thingIds.add(Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")")))); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingIds.get(0), EntityType.LOCATION, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - locationIds.add(array.getJSONObject(0).getLong(ControlInformation.ID)); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingIds.get(0), EntityType.DATASTREAM, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - datastreamIds.add(array.getJSONObject(0).getLong(ControlInformation.ID)); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamIds.get(0), EntityType.SENSOR, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - sensorIds.add(new JSONObject(response).getLong(ControlInformation.ID)); - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamIds.get(0), EntityType.OBSERVED_PROPERTY, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - obsPropIds.add(new JSONObject(response).getLong(ControlInformation.ID)); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingIds.get(0), EntityType.HISTORICAL_LOCATION, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - historicalLocationIds.add(array.getJSONObject(0).getLong(ControlInformation.ID)); - - //Observations - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamIds.get(0), EntityType.OBSERVATION, null); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" - + " \"result\": 1 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationIds.add(Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")))); - - //FeatureOfInterest - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, observationIds.get(0), EntityType.FEATURE_OF_INTEREST, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - foiIds.add(new JSONObject(response).getLong(ControlInformation.ID)); - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - - } + /** + * The root URL of the SensorThings service under the test + */ + public String rootUri;// ="http://localhost:8080/OGCSensorThings/v1.0"; + + /** + * The list of ids for all the Things created during test procedure (will be used for + * clean-up) + */ + private List thingIds = new ArrayList<>(); + + /** + * The list of ids for all the Locations created during test procedure (will be used + * for clean-up) + */ + private List locationIds = new ArrayList<>(); + + /** + * The list of ids for all the HistoricalLocations created during test procedure (will + * be used for clean-up) + */ + private List historicalLocationIds = new ArrayList<>(); + + /** + * The list of ids for all the Datastreams created during test procedure (will be used + * for clean-up) + */ + private List datastreamIds = new ArrayList<>(); + + /** + * The list of ids for all the Observations created during test procedure (will be + * used for clean-up) + */ + private List observationIds = new ArrayList<>(); + + /** + * The list of ids for all the Sensors created during test procedure (will be used for + * clean-up) + */ + private List sensorIds = new ArrayList<>(); + + /** + * The list of ids for all the ObservedPropeties created during test procedure (will + * be used for clean-up) + */ + private List obsPropIds = new ArrayList<>(); + + /** + * The list of ids for all the FeaturesOfInterest created during test procedure (will + * be used for clean-up) + */ + private List foiIds = new ArrayList<>(); + + /** + * This method will be run before starting the test for this conformance class. It + * cleans the database to start test. + * @param testContext The test context to find out whether this class is requested to + * test or not + */ + @BeforeClass + public void obtainTestSubject(ITestContext testContext) { + Object obj = testContext.getSuite().getAttribute(SuiteAttribute.LEVEL.getName()); + if ((null != obj)) { + Integer level = Integer.class.cast(obj); + Assert.assertTrue(level.intValue() > 1, "Conformance level 2 will not be checked since ics = " + level); + } + + rootUri = testContext.getSuite().getAttribute(SuiteAttribute.TEST_SUBJECT.getName()).toString(); + rootUri = rootUri.trim(); + if (rootUri.lastIndexOf('/') == rootUri.length() - 1) { + rootUri = rootUri.substring(0, rootUri.length() - 1); + } + deleteEverythings(); + } + + /** + * This method is testing create or POST entities. It only tests simple create, no + * deep insert. It makes sure that the response is 201 and use simple GET to make sure + * the entity is added to the service. + */ + @Test(description = "POST Entities", groups = "level-2", priority = 2) + public void createEntities() { + try { + /* Thing */ + String urlParameters = "{" + "\"name\":\"Test Thing\"," + + "\"description\":\"This is a Test Thing From TestNG\"" + "}"; + JSONObject entity = postEntity(EntityType.THING, urlParameters); + long thingId = entity.getLong(ControlInformation.ID); + thingIds.add(thingId); + + /* Location */ + urlParameters = "{\n" + " \"name\": \"bow river\",\n" + " \"description\": \"bow river\",\n" + + " \"encodingType\": \"application/vnd.geo+json\",\n" + + " \"location\": { \"type\": \"Point\", \"coordinates\": [-114.05, 51.05] }\n" + "}"; + entity = postEntity(EntityType.LOCATION, urlParameters); + long locationId = entity.getLong(ControlInformation.ID); + locationIds.add(locationId); + JSONObject locationEntity = entity; + + /* Sensor */ + urlParameters = "{\n" + " \"name\": \"Fuguro Barometer\",\n" + " \"description\": \"Fuguro Barometer\",\n" + + " \"encodingType\": \"application/pdf\",\n" + " \"metadata\": \"Barometer\"\n" + "}"; + entity = postEntity(EntityType.SENSOR, urlParameters); + long sensorId = entity.getLong(ControlInformation.ID); + sensorIds.add(sensorId); + + /* ObservedProperty */ + urlParameters = "{\n" + " \"name\": \"DewPoint Temperature\",\n" + + " \"definition\": \"http://dbpedia.org/page/Dew_point\",\n" + + " \"description\": \"The dewpoint temperature is the temperature to which the air must be cooled, at constant pressure, for dew to form. As the grass and other objects near the ground cool to the dewpoint, some of the water vapor in the atmosphere condenses into liquid water on the objects.\"\n" + + "}"; + entity = postEntity(EntityType.OBSERVED_PROPERTY, urlParameters); + long obsPropId = entity.getLong(ControlInformation.ID); + obsPropIds.add(obsPropId); + + /* FeatureOfInterest */ + urlParameters = "{\n" + " \"name\": \"A weather station.\",\n" + + " \"description\": \"A weather station.\",\n" + + " \"encodingType\": \"application/vnd.geo+json\",\n" + " \"feature\": {\n" + + " \"type\": \"Point\",\n" + " \"coordinates\": [\n" + " 10,\n" + " 10\n" + + " ]\n" + " }\n" + "}"; + entity = postEntity(EntityType.FEATURE_OF_INTEREST, urlParameters); + long foiId = entity.getLong(ControlInformation.ID); + foiIds.add(foiId); + + /* Datastream */ + urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" + " \"ObservedProperty\":{ \"@iot.id\":" + + obsPropId + "},\n" + " \"Sensor\": { \"@iot.id\": " + sensorId + " }\n" + "}"; + entity = postEntity(EntityType.DATASTREAM, urlParameters); + long datastreamId = entity.getLong(ControlInformation.ID); + datastreamIds.add(datastreamId); + + /* Observation */ + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:40:00.000Z\",\n" + " \"result\": 8,\n" + + " \"Datastream\":{\"@iot.id\": " + datastreamId + "},\n" + + " \"FeatureOfInterest\": {\"@iot.id\": " + foiId + "} \n" + "}"; + entity = postEntity(EntityType.OBSERVATION, urlParameters); + long obsId1 = entity.getLong(ControlInformation.ID); + observationIds.add(obsId1); + // POST Observation without FOI (Automatic creation of FOI) + // Add location to the Thing + urlParameters = "{\"Locations\":[{\"@iot.id\":" + locationId + "}]}"; + patchEntity(EntityType.THING, urlParameters, thingId); + + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:00:00.000Z\",\n" + + " \"resultTime\": \"2015-03-01T01:00:00.000Z\",\n" + " \"result\": 100,\n" + + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" + "}"; + entity = postEntity(EntityType.OBSERVATION, urlParameters); + checkForObservationResultTime(entity, "2015-03-01T01:00:00.000Z"); + long obsId2 = entity.getLong(ControlInformation.ID); + observationIds.add(obsId2); + long automatedFOIId = checkAutomaticInsertionOfFOI(obsId2, locationEntity, -1); + foiIds.add(automatedFOIId); + // POST another Observation to make sure it is linked to the previously + // created FOI + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-05-01T00:00:00.000Z\",\n" + " \"result\": 105,\n" + + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" + "}"; + entity = postEntity(EntityType.OBSERVATION, urlParameters); + checkForObservationResultTime(entity, null); + long obsId3 = entity.getLong(ControlInformation.ID); + observationIds.add(obsId3); + checkAutomaticInsertionOfFOI(obsId2, locationEntity, automatedFOIId); + + /* HistoricalLocation */ + urlParameters = "{\n" + " \"time\": \"2015-03-01T00:40:00.000Z\",\n" + " \"Thing\":{\"@iot.id\": " + + thingId + "},\n" + " \"Locations\": [{\"@iot.id\": " + locationId + "}] \n" + "}"; + entity = postEntity(EntityType.HISTORICAL_LOCATION, urlParameters); + long histLocId = entity.getLong(ControlInformation.ID); + historicalLocationIds.add(histLocId); + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This method is testing create or POST in the form of Deep Insert. It makes sure the + * response is 201. Also using GET requests, it makes sure the entity and all its + * related entities are created and added to the service. + */ + @Test(description = "POST Entities using Deep Insert", groups = "level-2", priority = 2) + public void createEntitiesWithDeepInsert() { + try { + /* Thing */ + String urlParameters = "{\n" + " \"name\": \"Office Building\",\n" + + " \"description\": \"Office Building\",\n" + " \"properties\": {\n" + + " \"reference\": \"Third Floor\"\n" + " },\n" + " \"Locations\": [\n" + " {\n" + + " \"name\": \"West Roof\",\n" + " \"description\": \"West Roof\",\n" + + " \"location\": { \"type\": \"Point\", \"coordinates\": [-117.05, 51.05] },\n" + + " \"encodingType\": \"application/vnd.geo+json\"\n" + " }\n" + " ],\n" + + " \"Datastreams\": [\n" + " {\n" + " \"unitOfMeasurement\": {\n" + + " \"name\": \"Lumen\",\n" + " \"symbol\": \"lm\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" + + " },\n" + " \"name\": \"Light exposure.\",\n" + + " \"description\": \"Light exposure.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"ObservedProperty\": {\n" + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" + + " },\n" + " \"Sensor\": { \n" + " \"name\": \"Acme Fluxomatic 1000\",\n" + + " \"description\": \"Acme Fluxomatic 1000\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Light flux sensor\"\n" + " }\n" + " }\n" + " ]\n" + "}"; + JSONObject entity = postEntity(EntityType.THING, urlParameters); + long thingId = entity.getLong(ControlInformation.ID); + // Check Datastream + JSONObject deepInsertedObj = new JSONObject("{\n" + " \"unitOfMeasurement\": {\n" + + " \"name\": \"Lumen\",\n" + " \"symbol\": \"lm\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" + + " },\n" + " \"name\": \"Light exposure.\",\n" + + " \"description\": \"Light exposure.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\"\n" + + " }\n"); + long datastreamId = checkRelatedEntity(EntityType.THING, thingId, EntityType.DATASTREAM, deepInsertedObj); + datastreamIds.add(datastreamId); + // Check Location + deepInsertedObj = new JSONObject( + "{\n" + " \"name\": \"West Roof\",\n" + " \"description\": \"West Roof\",\n" + + " \"location\": { \"type\": \"Point\", \"coordinates\": [-117.05, 51.05] },\n" + + " \"encodingType\": \"application/vnd.geo+json\"\n" + " }\n"); + locationIds.add(checkRelatedEntity(EntityType.THING, thingId, EntityType.LOCATION, deepInsertedObj)); + // Check Sensor + deepInsertedObj = new JSONObject("{\n" + " \"name\": \"Acme Fluxomatic 1000\",\n" + + " \"description\": \"Acme Fluxomatic 1000\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Light flux sensor\"\n" + " }\n"); + sensorIds.add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.SENSOR, deepInsertedObj)); + // Check ObservedProperty + deepInsertedObj = new JSONObject("{\n" + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" + + " },\n"); + obsPropIds.add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.OBSERVED_PROPERTY, + deepInsertedObj)); + thingIds.add(thingId); + + /* Datastream */ + urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" + " \"ObservedProperty\": {\n" + + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" + + " },\n" + " \"Sensor\": { \n" + " \"name\": \"Acme Fluxomatic 1000\",\n" + + " \"description\": \"Acme Fluxomatic 1000\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Light flux sensor\"\n" + " },\n" + " \"Observations\": [\n" + + " {\n" + " \"phenomenonTime\": \"2015-03-01T00:10:00Z\",\n" + + " \"result\": 10\n" + " }\n" + " ]" + "}"; + entity = postEntity(EntityType.DATASTREAM, urlParameters); + datastreamId = entity.getLong(ControlInformation.ID); + // Check Sensor + deepInsertedObj = new JSONObject("{\n" + " \"name\": \"Acme Fluxomatic 1000\",\n" + + " \"description\": \"Acme Fluxomatic 1000\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Light flux sensor\"\n" + " }\n"); + sensorIds.add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.SENSOR, deepInsertedObj)); + // Check ObservedProperty + deepInsertedObj = new JSONObject("{\n" + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" + + " },\n"); + obsPropIds.add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.OBSERVED_PROPERTY, + deepInsertedObj)); + // Check Observation + deepInsertedObj = new JSONObject("{\n" + " \"phenomenonTime\": \"2015-03-01T00:10:00.000Z\",\n" + + " \"result\": 10\n" + " }\n"); + observationIds + .add(checkRelatedEntity(EntityType.DATASTREAM, datastreamId, EntityType.OBSERVATION, deepInsertedObj)); + datastreamIds.add(datastreamId); + + /* Observation */ + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" + " \"result\": 100,\n" + + " \"FeatureOfInterest\": {\n" + " \t\"name\": \"A weather station.\",\n" + + " \t\"description\": \"A weather station.\",\n" + + " \t\"encodingType\": \"application/vnd.geo+json\",\n" + " \"feature\": {\n" + + " \"type\": \"Point\",\n" + " \"coordinates\": [\n" + " -114.05,\n" + + " 51.05\n" + " ]\n" + " }\n" + " },\n" + " \"Datastream\":{\"@iot.id\": " + + datastreamId + "}\n" + "}"; + entity = postEntity(EntityType.OBSERVATION, urlParameters); + long obsId1 = entity.getLong(ControlInformation.ID); + // Check FeaturOfInterest + deepInsertedObj = new JSONObject( + "{\n" + " \"name\": \"A weather station.\",\n" + " \"description\": \"A weather station.\",\n" + + " \"encodingType\": \"application/vnd.geo+json\",\n" + " \"feature\": {\n" + + " \"type\": \"Point\",\n" + " \"coordinates\": [\n" + " -114.05,\n" + + " 51.05\n" + " ]\n" + " }\n" + " }\n"); + foiIds.add(checkRelatedEntity(EntityType.OBSERVATION, obsId1, EntityType.FEATURE_OF_INTEREST, + deepInsertedObj)); + observationIds.add(obsId1); + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This method is testing create or POST with invalid Deep Insert. It makes sure that + * if there is any problem in the request body of Deep Insert, none of the entities in + * that query is created. The response should be 400 or 409 and the entities should + * not be accessible using GET. + */ + @Test(description = "POST Invalid Entities using Deep Insert", groups = "level-2", priority = 1) + public void createInvalidEntitiesWithDeepInsert() { + try { + String urlParameters = "{\n" + " \"name\": \"Office Building\",\n" + + " \"description\": \"Office Building\",\n" + " \"properties\": {\n" + + " \"reference\": \"Third Floor\"\n" + " },\n" + " \"Locations\": [\n" + " {\n" + + " \"name\": \"West Roof\",\n" + " \"description\": \"West Roof\",\n" + + " \"location\": { \"type\": \"Point\", \"coordinates\": [-117.05, 51.05] },\n" + + " \"encodingType\": \"application/vnd.geo+json\"\n" + " }\n" + " ],\n" + + " \"Datastreams\": [\n" + " {\n" + " \"unitOfMeasurement\": {\n" + + " \"name\": \"Lumen\",\n" + " \"symbol\": \"lm\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" + + " },\n" + " \"name\": \"Light exposure.\",\n" + + " \"description\": \"Light exposure.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"ObservedProperty\": {\n" + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" + + " }\n" + " }\n" + " ]\n" + "}"; + postInvalidEntity(EntityType.THING, urlParameters); + List entityTypesToCheck = new ArrayList<>(); + entityTypesToCheck.add(EntityType.THING); + entityTypesToCheck.add(EntityType.LOCATION); + entityTypesToCheck.add(EntityType.HISTORICAL_LOCATION); + entityTypesToCheck.add(EntityType.DATASTREAM); + entityTypesToCheck.add(EntityType.OBSERVED_PROPERTY); + checkNotExisting(entityTypesToCheck); + + /* Datastream */ + urlParameters = "{" + "\"name\": \"Office Building\"," + "\"description\": \"Office Building\"" + "}"; + long thingId = postEntity(EntityType.THING, urlParameters).getLong("@iot.id"); + + urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" + " \"ObservedProperty\": {\n" + + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" + + " },\n" + " \"Observations\": [\n" + " {\n" + + " \"phenomenonTime\": \"2015-03-01T00:10:00Z\",\n" + " \"result\": 10\n" + + " }\n" + " ]" + "}"; + postInvalidEntity(EntityType.DATASTREAM, urlParameters); + + urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" + " \"Sensor\": { \n" + + " \"name\": \"Acme Fluxomatic 1000\",\n" + + " \"description\": \"Acme Fluxomatic 1000\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Light flux sensor\"\n" + " },\n" + " \"Observations\": [\n" + + " {\n" + " \"phenomenonTime\": \"2015-03-01T00:10:00Z\",\n" + + " \"result\": 10\n" + " }\n" + " ]" + "}"; + postInvalidEntity(EntityType.DATASTREAM, urlParameters); + + urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"ObservedProperty\": {\n" + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" + + " },\n" + " \"Sensor\": { \n" + " \"name\": \"Acme Fluxomatic 1000\",\n" + + " \"description\": \"Acme Fluxomatic 1000\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Light flux sensor\"\n" + " },\n" + " \"Observations\": [\n" + + " {\n" + " \"phenomenonTime\": \"2015-03-01T00:10:00Z\",\n" + + " \"result\": 10\n" + " }\n" + " ]" + "}"; + postInvalidEntity(EntityType.DATASTREAM, urlParameters); + + // urlParameters = "{\n" + + // " \"unitOfMeasurement\": {\n" + + // " \"name\": \"Celsius\",\n" + + // " \"symbol\": \"degC\",\n" + + // " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + + // " },\n" + + // " \"description\": \"test datastream.\",\n" + + // " \"observationType\": + // \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + // + + // " \"Thing\": { \"@iot.id\": " + thingId + " },\n" + + // " \"ObservedProperty\": {\n" + + // " \"name\": \"Luminous Flux\",\n" + + // " \"definition\": + // \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + // + + // " \"description\": \"Luminous Flux or Luminous Power is the measure of the + // perceived power of light.\"\n" + + // " },\n" + + // " \"Sensor\": { \n" + + // " \"description\": \"Acme Fluxomatic 1000\",\n" + + // " \"encodingType\": \"http://schema.org/description\",\n" + + // " \"metadata\": \"Light flux sensor\"\n" + + // " },\n" + + // " \"Observations\": [\n" + + // " {\n" + + // " }\n" + + // " ]" + + // "}"; + // postInvalidEntity(EntityType.DATASTREAM, urlParameters); + entityTypesToCheck.clear(); + entityTypesToCheck.add(EntityType.DATASTREAM); + entityTypesToCheck.add(EntityType.SENSOR); + entityTypesToCheck.add(EntityType.OBSERVATION); + entityTypesToCheck.add(EntityType.FEATURE_OF_INTEREST); + entityTypesToCheck.add(EntityType.OBSERVED_PROPERTY); + checkNotExisting(entityTypesToCheck); + + /* Observation */ + urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" + " \"ObservedProperty\": {\n" + + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + + " \"description\": \"Luminous Flux or Luminous Power is the measure of the perceived power of light.\"\n" + + " },\n" + " \"Sensor\": { \n" + " \"name\": \"Acme Fluxomatic 1000\",\n" + + " \"description\": \"Acme Fluxomatic 1000\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Light flux sensor\"\n" + " }\n" + "}"; + long datastreamId = postEntity(EntityType.DATASTREAM, urlParameters).getLong("@iot.id"); + + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" + " \"result\": 100,\n" + + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" + "}"; + postInvalidEntity(EntityType.OBSERVATION, urlParameters); + + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" + " \"result\": 100,\n" + + " \"FeatureOfInterest\": {\n" + " \t\"name\": \"A weather station.\",\n" + + " \t\"description\": \"A weather station.\",\n" + " \"feature\": {\n" + + " \"type\": \"Point\",\n" + " \"coordinates\": [\n" + " -114.05,\n" + + " 51.05\n" + " ]\n" + " }\n" + " },\n" + " \"Datastream\":{\"@iot.id\": " + + datastreamId + "}\n" + "}"; + postInvalidEntity(EntityType.OBSERVATION, urlParameters); + + entityTypesToCheck.clear(); + entityTypesToCheck.add(EntityType.OBSERVATION); + entityTypesToCheck.add(EntityType.FEATURE_OF_INTEREST); + checkNotExisting(entityTypesToCheck); + + deleteEverythings(); + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This method is testing create or POST invalid entities. The response should be 400 + * or 409 and the entity should not be accessible using GET. + */ + @Test(description = "POST Invalid Entities", groups = "level-2", priority = 3) + public void createInvalidEntities() { + try { + /* Datastream */ + // Without Sensor + String urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"Thing\": { \"@iot.id\": " + thingIds.get(0) + " },\n" + + " \"ObservedProperty\":{ \"@iot.id\":" + obsPropIds.get(0) + "}\n" + "}"; + postInvalidEntity(EntityType.DATASTREAM, urlParameters); + // Without ObservedProperty + urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"Thing\": { \"@iot.id\": " + thingIds.get(0) + " },\n" + " \"Sensor\": { \"@iot.id\": " + + sensorIds.get(0) + " }\n" + "}"; + postInvalidEntity(EntityType.DATASTREAM, urlParameters); + // Without Things + urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"ObservedProperty\":{ \"@iot.id\":" + obsPropIds.get(0) + "},\n" + + " \"Sensor\": { \"@iot.id\": " + sensorIds.get(0) + " }\n" + "}"; + postInvalidEntity(EntityType.DATASTREAM, urlParameters); + + /* Observation */ + // Create Thing and Datastream + urlParameters = "{" + "\"name\":\"This is a Test Thing From TestNG\"," + + "\"description\":\"This is a Test Thing From TestNG\"" + "}"; + long thingId = postEntity(EntityType.THING, urlParameters).getLong(ControlInformation.ID); + thingIds.add(thingId); + urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" + " \"name\": \"Celsius\",\n" + + " \"symbol\": \"degC\",\n" + + " \"definition\": \"http://qudt.org/vocab/unit#DegreeCelsius\"\n" + " },\n" + + " \"name\": \"test datastream.\",\n" + " \"description\": \"test datastream.\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"Thing\": { \"@iot.id\": " + thingId + " },\n" + " \"ObservedProperty\":{ \"@iot.id\":" + + obsPropIds.get(0) + "},\n" + " \"Sensor\": { \"@iot.id\": " + sensorIds.get(0) + " }\n" + "}"; + long datastreamId = postEntity(EntityType.DATASTREAM, urlParameters).getLong(ControlInformation.ID); + datastreamIds.add(datastreamId); + // Without Datastream + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:40:00.000Z\",\n" + " \"result\": 8,\n" + + " \"FeatureOfInterest\": {\"@iot.id\": " + foiIds.get(0) + "} \n" + "}"; + postInvalidEntity(EntityType.OBSERVATION, urlParameters); + // Without FOI and without Thing's Location + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:00:00.000Z\",\n" + " \"result\": 100,\n" + + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" + "}"; + postInvalidEntity(EntityType.OBSERVATION, urlParameters); + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + + } + + /** + * This method is testing partial update or PATCH. The response should be 200 and only + * the properties in the PATCH body should be updated, and the rest must be unchanged. + */ + @Test(description = "PATCH Entities", groups = "level-2", priority = 4) + public void patchEntities() { + try { + /* Thing */ + long thingId = thingIds.get(0); + JSONObject entity = getEntity(EntityType.THING, thingId); + String urlParameters = "{\"description\":\"This is a PATCHED Test Thing From TestNG\"}"; + Map diffs = new HashMap<>(); + diffs.put("description", "This is a PATCHED Test Thing From TestNG"); + JSONObject updatedEntity = patchEntity(EntityType.THING, urlParameters, thingId); + checkPatch(EntityType.THING, entity, updatedEntity, diffs); + + /* Location */ + long locationId = locationIds.get(0); + entity = getEntity(EntityType.LOCATION, locationId); + urlParameters = "{\"location\": { \"type\": \"Point\", \"coordinates\": [114.05, -50] }}"; + diffs = new HashMap<>(); + diffs.put("location", new JSONObject("{ \"type\": \"Point\", \"coordinates\": [114.05, -50] }}")); + updatedEntity = patchEntity(EntityType.LOCATION, urlParameters, locationId); + checkPatch(EntityType.LOCATION, entity, updatedEntity, diffs); + + /* HistoricalLocation */ + long histLocId = historicalLocationIds.get(0); + entity = getEntity(EntityType.HISTORICAL_LOCATION, histLocId); + urlParameters = "{\"time\": \"2015-07-01T00:00:00.000Z\"}"; + diffs = new HashMap<>(); + diffs.put("time", "2015-07-01T00:00:00.000Z"); + updatedEntity = patchEntity(EntityType.HISTORICAL_LOCATION, urlParameters, histLocId); + checkPatch(EntityType.HISTORICAL_LOCATION, entity, updatedEntity, diffs); + + /* Sensor */ + long sensorId = sensorIds.get(0); + entity = getEntity(EntityType.SENSOR, sensorId); + urlParameters = "{\"metadata\": \"PATCHED\"}"; + diffs = new HashMap<>(); + diffs.put("metadata", "PATCHED"); + updatedEntity = patchEntity(EntityType.SENSOR, urlParameters, sensorId); + checkPatch(EntityType.SENSOR, entity, updatedEntity, diffs); + + /* ObserverdProperty */ + long obsPropId = obsPropIds.get(0); + entity = getEntity(EntityType.OBSERVED_PROPERTY, obsPropId); + urlParameters = "{\"description\":\"PATCHED\"}"; + diffs = new HashMap<>(); + diffs.put("description", "PATCHED"); + updatedEntity = patchEntity(EntityType.OBSERVED_PROPERTY, urlParameters, obsPropId); + checkPatch(EntityType.OBSERVED_PROPERTY, entity, updatedEntity, diffs); + + /* FeatureOfInterest */ + long foiId = foiIds.get(0); + entity = getEntity(EntityType.FEATURE_OF_INTEREST, foiId); + urlParameters = "{\"feature\":{ \"type\": \"Point\", \"coordinates\": [114.05, -51.05] }}"; + diffs = new HashMap<>(); + diffs.put("feature", new JSONObject("{ \"type\": \"Point\", \"coordinates\": [114.05, -51.05] }")); + updatedEntity = patchEntity(EntityType.FEATURE_OF_INTEREST, urlParameters, foiId); + checkPatch(EntityType.FEATURE_OF_INTEREST, entity, updatedEntity, diffs); + + /* Datastream */ + long datastreamId = datastreamIds.get(0); + entity = getEntity(EntityType.DATASTREAM, datastreamId); + urlParameters = "{\"description\": \"Patched Description\"}"; + diffs = new HashMap<>(); + diffs.put("description", "Patched Description"); + updatedEntity = patchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); + checkPatch(EntityType.DATASTREAM, entity, updatedEntity, diffs); + // Second PATCH for UOM + entity = updatedEntity; + urlParameters = "{ \"unitOfMeasurement\": {\n" + " \"name\": \"Entropy2\",\n" + + " \"symbol\": \"S2\",\n" + " \"definition\": \"http://qudt.org/vocab/unit#Entropy2\"\n" + + " } }"; + diffs = new HashMap<>(); + diffs.put("unitOfMeasurement", new JSONObject( + "{\"name\": \"Entropy2\",\"symbol\": \"S2\",\"definition\": \"http://qudt.org/vocab/unit#Entropy2\"}")); + updatedEntity = patchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); + checkPatch(EntityType.DATASTREAM, entity, updatedEntity, diffs); + + /* Observation */ + long obsId1 = observationIds.get(0); + entity = getEntity(EntityType.OBSERVATION, obsId1); + urlParameters = "{\"phenomenonTime\": \"2015-07-01T00:40:00.000Z\"}"; + diffs = new HashMap<>(); + diffs.put("phenomenonTime", "2015-07-01T00:40:00.000Z"); + updatedEntity = patchEntity(EntityType.OBSERVATION, urlParameters, obsId1); + checkPatch(EntityType.OBSERVATION, entity, updatedEntity, diffs); + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This method is testing DELETE and its integrity constraint. The response should be + * 200. After DELETE the GET request to that entity should return 404. + */ + @Test(description = "DELETE Entities", groups = "level-2", priority = 5) + public void deleteEntities() { + for (int i = 0; i < observationIds.size(); i++) { + deleteEntity(EntityType.OBSERVATION, observationIds.get(i)); + } + for (int i = 0; i < foiIds.size(); i++) { + deleteEntity(EntityType.FEATURE_OF_INTEREST, foiIds.get(i)); + } + for (int i = 0; i < datastreamIds.size(); i++) { + deleteEntity(EntityType.DATASTREAM, datastreamIds.get(i)); + } + for (int i = 0; i < obsPropIds.size(); i++) { + deleteEntity(EntityType.OBSERVED_PROPERTY, obsPropIds.get(i)); + } + for (int i = 0; i < sensorIds.size(); i++) { + deleteEntity(EntityType.SENSOR, sensorIds.get(i)); + } + for (int i = 0; i < historicalLocationIds.size(); i++) { + deleteEntity(EntityType.HISTORICAL_LOCATION, historicalLocationIds.get(i)); + } + for (int i = 0; i < locationIds.size(); i++) { + deleteEntity(EntityType.LOCATION, locationIds.get(i)); + } + for (int i = 0; i < thingIds.size(); i++) { + deleteEntity(EntityType.THING, thingIds.get(i)); + } + + checkDeleteIntegrityConstraint(); + } + + /** + * This is helper method for checking the integrity containt of DELETE. For each + * entity, it checks after deleting, it confirm the deletion of its related entities + * mentioned in the integrity constraint of the specification. + */ + private void checkDeleteIntegrityConstraint() { + // Thing + createEntitiesForDelete(); + deleteEntity(EntityType.THING, thingIds.get(0)); + List entityTypes = new ArrayList<>(); + entityTypes.add(EntityType.THING); + entityTypes.add(EntityType.DATASTREAM); + entityTypes.add(EntityType.HISTORICAL_LOCATION); + entityTypes.add(EntityType.OBSERVATION); + checkNotExisting(entityTypes); + entityTypes.clear(); + entityTypes.add(EntityType.LOCATION); + entityTypes.add(EntityType.SENSOR); + entityTypes.add(EntityType.OBSERVED_PROPERTY); + entityTypes.add(EntityType.FEATURE_OF_INTEREST); + checkExisting(entityTypes); + + // Datastream + createEntitiesForDelete(); + deleteEntity(EntityType.DATASTREAM, datastreamIds.get(0)); + entityTypes.clear(); + entityTypes.add(EntityType.DATASTREAM); + entityTypes.add(EntityType.OBSERVATION); + checkNotExisting(entityTypes); + entityTypes.clear(); + entityTypes.add(EntityType.THING); + entityTypes.add(EntityType.SENSOR); + entityTypes.add(EntityType.OBSERVED_PROPERTY); + entityTypes.add(EntityType.FEATURE_OF_INTEREST); + entityTypes.add(EntityType.LOCATION); + entityTypes.add(EntityType.HISTORICAL_LOCATION); + checkExisting(entityTypes); + + // Loation + createEntitiesForDelete(); + deleteEntity(EntityType.LOCATION, locationIds.get(0)); + entityTypes.clear(); + entityTypes.add(EntityType.LOCATION); + entityTypes.add(EntityType.HISTORICAL_LOCATION); + checkNotExisting(entityTypes); + entityTypes.clear(); + entityTypes.add(EntityType.THING); + entityTypes.add(EntityType.SENSOR); + entityTypes.add(EntityType.OBSERVED_PROPERTY); + entityTypes.add(EntityType.FEATURE_OF_INTEREST); + entityTypes.add(EntityType.DATASTREAM); + entityTypes.add(EntityType.OBSERVATION); + checkExisting(entityTypes); + + // HistoricalLoation + createEntitiesForDelete(); + deleteEntity(EntityType.HISTORICAL_LOCATION, historicalLocationIds.get(0)); + entityTypes.clear(); + entityTypes.add(EntityType.HISTORICAL_LOCATION); + checkNotExisting(entityTypes); + entityTypes.clear(); + entityTypes.add(EntityType.THING); + entityTypes.add(EntityType.SENSOR); + entityTypes.add(EntityType.OBSERVED_PROPERTY); + entityTypes.add(EntityType.FEATURE_OF_INTEREST); + entityTypes.add(EntityType.DATASTREAM); + entityTypes.add(EntityType.OBSERVATION); + entityTypes.add(EntityType.LOCATION); + checkExisting(entityTypes); + + // Sensor + createEntitiesForDelete(); + deleteEntity(EntityType.SENSOR, sensorIds.get(0)); + entityTypes.clear(); + entityTypes.add(EntityType.SENSOR); + entityTypes.add(EntityType.DATASTREAM); + entityTypes.add(EntityType.OBSERVATION); + checkNotExisting(entityTypes); + entityTypes.clear(); + entityTypes.add(EntityType.THING); + entityTypes.add(EntityType.OBSERVED_PROPERTY); + entityTypes.add(EntityType.FEATURE_OF_INTEREST); + entityTypes.add(EntityType.LOCATION); + entityTypes.add(EntityType.HISTORICAL_LOCATION); + checkExisting(entityTypes); + + // ObservedProperty + createEntitiesForDelete(); + deleteEntity(EntityType.OBSERVED_PROPERTY, obsPropIds.get(0)); + entityTypes.clear(); + entityTypes.add(EntityType.OBSERVED_PROPERTY); + entityTypes.add(EntityType.DATASTREAM); + entityTypes.add(EntityType.OBSERVATION); + checkNotExisting(entityTypes); + entityTypes.clear(); + entityTypes.add(EntityType.THING); + entityTypes.add(EntityType.SENSOR); + entityTypes.add(EntityType.FEATURE_OF_INTEREST); + entityTypes.add(EntityType.LOCATION); + entityTypes.add(EntityType.HISTORICAL_LOCATION); + checkExisting(entityTypes); + + // FeatureOfInterest + createEntitiesForDelete(); + deleteEntity(EntityType.FEATURE_OF_INTEREST, foiIds.get(0)); + entityTypes.clear(); + entityTypes.add(EntityType.FEATURE_OF_INTEREST); + entityTypes.add(EntityType.OBSERVATION); + checkNotExisting(entityTypes); + entityTypes.clear(); + entityTypes.add(EntityType.THING); + entityTypes.add(EntityType.SENSOR); + entityTypes.add(EntityType.OBSERVED_PROPERTY); + entityTypes.add(EntityType.LOCATION); + entityTypes.add(EntityType.HISTORICAL_LOCATION); + entityTypes.add(EntityType.DATASTREAM); + checkExisting(entityTypes); + + // Observation + createEntitiesForDelete(); + deleteEntity(EntityType.OBSERVATION, observationIds.get(0)); + entityTypes.clear(); + entityTypes.add(EntityType.OBSERVATION); + checkNotExisting(entityTypes); + entityTypes.clear(); + entityTypes.add(EntityType.THING); + entityTypes.add(EntityType.SENSOR); + entityTypes.add(EntityType.OBSERVED_PROPERTY); + entityTypes.add(EntityType.FEATURE_OF_INTEREST); + entityTypes.add(EntityType.DATASTREAM); + entityTypes.add(EntityType.HISTORICAL_LOCATION); + entityTypes.add(EntityType.LOCATION); + checkExisting(entityTypes); + } + + // TODO: Add invalid PATCH test for other entities when it is implemented in the + // service + + /** + * This method is testing invalid partial update or PATCH. The PATCH request is + * invalid if the body contains related entities as inline content. + */ + @Test(description = "Invalid PATCH Entities", groups = "level-2", priority = 4) + public void invalidPatchEntities() { + /** + * Thing * + */ + long thingId = thingIds.get(0); + String urlParameters = "{\"Locations\": [\n" + " {\n" + " \"name\": \"West Roof\",\n" + + " \"description\": \"West Roof\",\n" + + " \"location\": { \"type\": \"Point\", \"coordinates\": [-117.05, 51.05] },\n" + + " \"encodingType\": \"application/vnd.geo+json\"\n" + " }\n" + " ]}"; + invalidPatchEntity(EntityType.THING, urlParameters, thingId); + urlParameters = "{\"Datastreams\": [\n" + " {\n" + " \"unitOfMeasurement\": {\n" + + " \"name\": \"Lumen\",\n" + " \"symbol\": \"lm\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" + + " }}]}"; + invalidPatchEntity(EntityType.THING, urlParameters, thingId); + + // /** Location **/ + // long locationId = locationIds.get(0); + // urlParameters = "{\"Things\":[{\"description\":\"Orange\"}]}"; + // invalidPatchEntity(EntityType.LOCATION, urlParameters, locationId); + // + // /** HistoricalLocation **/ + // long histLocId = historicalLocationIds.get(0); + // urlParameters = "{\"time\": \"2015-07-01T00:00:00.000Z\"}"; + // invalidPatchEntity(EntityType.HISTORICAL_LOCATION, urlParameters, histLocId); + // + /** + * Sensor * + */ + long sensorId = sensorIds.get(0); + urlParameters = "{\"Datastreams\": [\n" + " {\n" + " \"unitOfMeasurement\": {\n" + + " \"name\": \"Lumen\",\n" + " \"symbol\": \"lm\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"}\n" + + " ,\"Thing\":{\"@iot.id\":" + thingId + "}" + " }]}"; + invalidPatchEntity(EntityType.SENSOR, urlParameters, sensorId); + + /** + * ObserverdProperty * + */ + long obsPropId = obsPropIds.get(0); + urlParameters = "{\"Datastreams\": [\n" + " {\n" + " \"unitOfMeasurement\": {\n" + + " \"name\": \"Lumen\",\n" + " \"symbol\": \"lm\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"}\n" + + " ,\"Thing\":{\"@iot.id\":" + thingId + "}" + " }]}"; + invalidPatchEntity(EntityType.OBSERVED_PROPERTY, urlParameters, obsPropId); + + // /** FeatureOfInterest **/ + // long foiId = foiIds.get(0); + // urlParameters = "{\"feature\":{ \"type\": \"Point\", \"coordinates\": [114.05, + // -51.05] }}"; + // invalidPatchEntity(EntityType.FEATURE_OF_INTEREST, urlParameters, foiId); + /** + * Datastream * + */ + long datastreamId = datastreamIds.get(0); + urlParameters = "{\"ObservedProperty\": {\n" + " \t\"name\": \"Count\",\n" + + "\t\"definition\": \"http://qudt.org/vocab/unit#Dimensionless\",\n" + + "\t\"name\": \"Count is a dimensionless property.\",\n" + + "\t\"description\": \"Count is a dimensionless property.\"\n" + " } }"; + invalidPatchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); + urlParameters = "{\"Sensor\": {\n" + " \t\"name\": \"Acme Traffic 2000\", \n" + + " \t\"description\": \"Acme Traffic 2000\", \n" + " \t\"encodingType\": \"application/pdf\",\n" + + " \t\"metadata\": \"Traffic counting device\"\n" + " }}"; + invalidPatchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); + urlParameters = "{" + "\"Thing\": {" + " \"name\": \"test\"," + " \"description\": \"test\"" + " }" + "}"; + invalidPatchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); + urlParameters = "{\"Observations\": [\n" + " {\n" + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" + + " \"result\": 92122,\n" + " \"resultQuality\": \"High\"\n" + " }\n" + " ]}"; + invalidPatchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); + + // /** Observation **/ + // long obsId1 = observationIds.get(0); + // urlParameters = "{\"phenomenonTime\": \"2015-07-01T00:40:00.000Z\"}"; + // invalidPatchEntity(EntityType.OBSERVATION, urlParameters, obsId1); + } + + /** + * This method is testing DELETE request for a nonexistent entity. The response should + * be 404. + */ + @Test(description = "DELETE nonexistent Entities", groups = "level-2", priority = 5) + public void deleteNoneexistentEntities() { + deleteNonExsistentEntity(EntityType.THING); + deleteNonExsistentEntity(EntityType.LOCATION); + deleteNonExsistentEntity(EntityType.HISTORICAL_LOCATION); + deleteNonExsistentEntity(EntityType.SENSOR); + deleteNonExsistentEntity(EntityType.OBSERVED_PROPERTY); + deleteNonExsistentEntity(EntityType.DATASTREAM); + deleteNonExsistentEntity(EntityType.OBSERVATION); + deleteNonExsistentEntity(EntityType.FEATURE_OF_INTEREST); + } + + /** + * This method created the URL string for the entity with specific id and then send a + * GET request to that URL. + * @param entityType Entity type in from EntityType enum + * @param id The id of requested entity + * @return The requested entity in the format of JSON Object. + */ + private JSONObject getEntity(EntityType entityType, long id) { + if (id == -1) { + return null; + } + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); + try { + return new JSONObject(HTTPMethods.doGet(urlString).get("response").toString()); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + return null; + } + } + + /** + * This method created the URL string for the entity and then POST the entity with + * urlParameters to that URL. + * @param entityType Entity type in from EntityType enum + * @param urlParameters POST body + * @return The created entity in the form of JSON Object + */ + private JSONObject postEntity(EntityType entityType, String urlParameters) { + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + try { + Map responseMap = HTTPMethods.doPost(urlString, urlParameters); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 201, "Error during creation of entity " + entityType.name()); + String response = responseMap.get("response").toString(); + long id = Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")"))); + + urlString = urlString + "(" + id + ")"; + responseMap = HTTPMethods.doGet(urlString); + responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, "The POSTed entity is not created. [Request] " + urlString); + + JSONObject result = new JSONObject(responseMap.get("response").toString()); + return result; + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + return null; + } + } + + /** + * This helper method is sending invalid POST request and confirm that the response is + * correct based on specification. + * @param entityType Entity type in from EntityType enum + * @param urlParameters POST body (invalid) + */ + private void postInvalidEntity(EntityType entityType, String urlParameters) { + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + + Map responseMap = HTTPMethods.doPost(urlString, urlParameters); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertTrue(responseCode == 400 || responseCode == 409, "The " + entityType.name() + + " should not be created due to integrity constraints. [Request] " + urlString); + + } + + /** + * This method created the URL string for the entity with specific id and then send + * DELETE request to that URl. + * @param entityType Entity type in from EntityType enum + * @param id The id of requested entity + */ + private void deleteEntity(EntityType entityType, long id) { + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); + Map responseMap = HTTPMethods.doDelete(urlString); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, "DELETE does not work properly for " + entityType + " with id " + id + + ". Returned with response code " + responseCode + ". [Request] " + urlString); + + responseMap = HTTPMethods.doGet(urlString); + responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 404, + "Deleted entity was not actually deleted : " + entityType + "(" + id + "). [Request] " + urlString); + } + + /** + * This method create the URL string for a nonexistent entity and send the DELETE + * request to that URL and confirm that the response is correct based on + * specification. + * @param entityType Entity type in from EntityType enum + */ + private void deleteNonExsistentEntity(EntityType entityType) { + long id = Long.MAX_VALUE; + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); + Map responseMap = HTTPMethods.doDelete(urlString); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 404, "DELETE does not work properly for nonexistent " + entityType + + " with id " + id + ". Returned with response code " + responseCode + ". [Request] " + urlString); + + } + + /** + * This method created the URL string for the entity with specific id and then PATCH + * the entity with urlParameters to that URL. + * @param entityType Entity type in from EntityType enum + * @param urlParameters The PATCH body + * @param id The id of requested entity + * @return The patched entity in the format of JSON Object + */ + private JSONObject patchEntity(EntityType entityType, String urlParameters, long id) { + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); + try { + + Map responseMap = HTTPMethods.doPatch(urlString, urlParameters); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, + "Error during updating(PATCH) of entity " + entityType.name() + "with [Request] " + urlString); + responseMap = HTTPMethods.doGet(urlString); + JSONObject result = new JSONObject(responseMap.get("response").toString()); + return result; + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + return null; + } + } + + /** + * This method created the URL string for the entity with specific id and then PATCH + * invalid entity with urlParameters to that URL and confirms that the response is + * correct based on specification. + * @param entityType Entity type in from EntityType enum + * @param urlParameters The PATCH body (invalid) + * @param id The id of requested entity + */ + private void invalidPatchEntity(EntityType entityType, String urlParameters, long id) { + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); + + Map responseMap = HTTPMethods.doPatch(urlString, urlParameters); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 400, "Error: Patching related entities inline must be illegal for entity " + + entityType.name() + ". [Request] " + urlString); + + } + + /** + * Check the patched entity properties are updates correctly + * @param entityType Entity type in from EntityType enum + * @param oldEntity The old properties of the patched entity + * @param newEntity The updated properties of the patched entity + * @param diffs The properties that supposed to be updated besed on the request due to + * the specification + */ + private void checkPatch(EntityType entityType, JSONObject oldEntity, JSONObject newEntity, Map diffs) { + try { + for (String property : entityType.getProperties()) { + if (diffs.containsKey(property)) { + assertParameterEquals(property, newEntity.get(property).toString(), diffs.get(property).toString(), + "PATCH was not applied correctly for " + entityType + "'s " + property + "."); + } + else { + assertParameterEquals(property, newEntity.get(property).toString(), + oldEntity.get(property).toString(), + "PATCH was not applied correctly for " + entityType + "'s " + property + "."); + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * Check the FeatureOfInterest is created automatically correctly if not inserted in + * Observation + * @param obsId The observation id + * @param locationObj The Location object that the FOI is supposed to be created based + * on that + * @param expectedFOIId The id of the FOI linked to the Observation + * @return The id of FOI + */ + private long checkAutomaticInsertionOfFOI(long obsId, JSONObject locationObj, long expectedFOIId) { + String urlString = rootUri + "/Observations(" + obsId + ")/FeatureOfInterest"; + try { + Map responseMap = HTTPMethods.doGet(urlString); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, "ERROR: FeatureOfInterest was not automatically create."); + JSONObject result = new JSONObject(responseMap.get("response").toString()); + long id = result.getLong(ControlInformation.ID); + if (expectedFOIId != -1) { + Assert.assertEquals(id, expectedFOIId, + "ERROR: the Observation should have linked to FeatureOfInterest with ID: " + expectedFOIId + + " , but it is linked for FeatureOfInterest with Id: " + id + ". [Request] " + + urlString); + } + Assert.assertEquals(result.getJSONObject("feature").toString(), + locationObj.getJSONObject("location").toString(), + "ERROR: Automatic created FeatureOfInterest does not match last Location of that Thing. [Request] " + + urlString); + return id; + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + return -1; + } + + /** + * Check the related entity of a given entity + * @param parentEntityType The given entity type + * @param parentId The given entity id + * @param relationEntityType The relation entity type + * @param relationObj The expected related entity object + * @return The id of related object + */ + private long checkRelatedEntity(EntityType parentEntityType, long parentId, EntityType relationEntityType, + JSONObject relationObj) { + boolean isCollection = true; + String urlString = ServiceURLBuilder.buildURLString(rootUri, parentEntityType, parentId, relationEntityType, + null); + if (parentEntityType.getRelations().contains(relationEntityType.singular)) { + isCollection = false; + } + + try { + Map responseMap = HTTPMethods.doGet(urlString); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, "ERROR: Deep inserted " + relationEntityType + + " does not created or linked to " + parentEntityType + ". [Request] " + urlString); + JSONObject result = new JSONObject(responseMap.get("response").toString()); + if (isCollection == true) { + result = result.getJSONArray("value").getJSONObject(0); + } + Iterator iterator = relationObj.keys(); + while (iterator.hasNext()) { + String key = iterator.next().toString(); + assertParameterEquals(key, Objects.toString(result.get(key)), Objects.toString(relationObj.get(key)), + "ERROR: Deep inserted " + relationEntityType + " is not created correctly. [Request] " + + urlString); + } + return result.getLong(ControlInformation.ID); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + return -1; + } + + private void assertParameterEquals(String key, final String actual, final String expected, String message) { + if (key.toLowerCase().contains("time") && !"null".equals(expected) && !"null".equals(actual)) { + if (expected.contains("/")) { + String[] expextedParts = expected.split("/"); + String[] actualParts = actual.split("/"); + Assert.assertEquals(ZonedDateTime.parse(actualParts[0]), ZonedDateTime.parse(expextedParts[0]), + message); + Assert.assertEquals(ZonedDateTime.parse(actualParts[1]), ZonedDateTime.parse(expextedParts[1]), + message); + } + else { + Assert.assertEquals(ZonedDateTime.parse(actual), ZonedDateTime.parse(expected), message); + } + } + else { + Assert.assertEquals(actual, expected, message); + } + } + + /** + * Check the Observation have the resultTime even if it is null + * @param observation The observation JSON object + * @param resultTimeValue The expected value of resultTime + */ + private void checkForObservationResultTime(JSONObject observation, String resultTimeValue) { + try { + if (resultTimeValue == null) { + Assert.assertEquals(observation.get("resultTime").toString(), "null", + "The resultTime of the Observation " + observation.getLong(ControlInformation.ID) + + " should have been null but it is now \"" + observation.get("resultTime").toString() + + "\"."); + } + else { + Assert.assertEquals(ZonedDateTime.parse(observation.getString("resultTime")), + ZonedDateTime.parse(resultTimeValue), + "The resultTime of the Observation " + observation.getLong(ControlInformation.ID) + + " should have been \"" + resultTimeValue + "\" but it is now \"" + + observation.get("resultTime").toString() + "\"."); + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * Check the database is empty of certain entity types + * @param entityTypes List of entity types + */ + private void checkNotExisting(List entityTypes) { + for (EntityType entityType : entityTypes) { + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + try { + JSONObject result = new JSONObject(responseMap.get("response").toString()); + JSONArray array = result.getJSONArray("value"); + Assert.assertEquals(array.length(), 0, + entityType + " is created although it shouldn't. [Request] " + urlString); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + } + + /** + * Check there are some entityes for certain entity types + * @param entityTypes List of entity types + */ + private void checkExisting(List entityTypes) { + for (EntityType entityType : entityTypes) { + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + try { + JSONObject result = new JSONObject(responseMap.get("response").toString()); + JSONArray array = result.getJSONArray("value"); + Assert.assertTrue(array.length() > 0, + entityType + " is created although it shouldn't. [Request] " + urlString); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + } + + /** + * This method is run after all the tests of this class is run and clean the database. + */ + @AfterClass + public void deleteEverythings() { + deleteEntityType(EntityType.OBSERVATION); + deleteEntityType(EntityType.FEATURE_OF_INTEREST); + deleteEntityType(EntityType.DATASTREAM); + deleteEntityType(EntityType.SENSOR); + deleteEntityType(EntityType.OBSERVED_PROPERTY); + deleteEntityType(EntityType.HISTORICAL_LOCATION); + deleteEntityType(EntityType.LOCATION); + deleteEntityType(EntityType.THING); + } + + /** + * Delete all the entities of a certain entity type + * @param entityType The entity type from EntityType enum + */ + private void deleteEntityType(EntityType entityType) { + JSONArray array = null; + String urlString = ""; + do { + try { + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + JSONObject result = new JSONObject(responseMap.get("response").toString()); + array = result.getJSONArray("value"); + for (int i = 0; i < array.length(); i++) { + long id = array.getJSONObject(i).getLong(ControlInformation.ID); + deleteEntity(entityType, id); + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + while (array.length() > 0); + } + + /** + * Create entities as a pre-process for testing DELETE. + */ + private void createEntitiesForDelete() { + String urlString = ""; + try { + + deleteEverythings(); + thingIds.clear(); + locationIds.clear(); + historicalLocationIds.clear(); + datastreamIds.clear(); + sensorIds.clear(); + observationIds.clear(); + obsPropIds.clear(); + foiIds.clear(); + + // First Thing + String urlParameters = "{\n" + " \"name\": \"thing 1\",\n" + " \"description\": \"thing 1\",\n" + + " \"properties\": {\n" + " \"reference\": \"first\"\n" + " },\n" + + " \"Locations\": [\n" + " {\n" + " \"name\": \"location 1\",\n" + + " \"description\": \"location 1\",\n" + " \"location\": {\n" + + " \"type\": \"Point\",\n" + " \"coordinates\": [\n" + + " -117.05,\n" + " 51.05\n" + " ]\n" + + " },\n" + " \"encodingType\": \"application/vnd.geo+json\"\n" + + " }\n" + " ],\n" + " \"Datastreams\": [\n" + " {\n" + + " \"unitOfMeasurement\": {\n" + " \"name\": \"Lumen\",\n" + + " \"symbol\": \"lm\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html#Lumen\"\n" + + " },\n" + " \"name\": \"datastream 1\",\n" + + " \"description\": \"datastream 1\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"ObservedProperty\": {\n" + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + + " \"description\": \"observedProperty 1\"\n" + " },\n" + + " \"Sensor\": {\n" + " \"name\": \"sensor 1\",\n" + + " \"description\": \"sensor 1\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Light flux sensor\"\n" + " }\n" + " }\n" + + " ]\n" + "}"; + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, -1, null, null); + Map responseMap = HTTPMethods.doPost(urlString, urlParameters); + String response = responseMap.get("response").toString(); + thingIds.add(Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")")))); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingIds.get(0), + EntityType.LOCATION, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + locationIds.add(array.getJSONObject(0).getLong(ControlInformation.ID)); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingIds.get(0), + EntityType.DATASTREAM, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + datastreamIds.add(array.getJSONObject(0).getLong(ControlInformation.ID)); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamIds.get(0), + EntityType.SENSOR, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + sensorIds.add(new JSONObject(response).getLong(ControlInformation.ID)); + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamIds.get(0), + EntityType.OBSERVED_PROPERTY, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + obsPropIds.add(new JSONObject(response).getLong(ControlInformation.ID)); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingIds.get(0), + EntityType.HISTORICAL_LOCATION, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + historicalLocationIds.add(array.getJSONObject(0).getLong(ControlInformation.ID)); + + // Observations + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamIds.get(0), + EntityType.OBSERVATION, null); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" + " \"result\": 1 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationIds + .add(Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")))); + + // FeatureOfInterest + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, observationIds.get(0), + EntityType.FEATURE_OF_INTEREST, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + foiIds.add(new JSONObject(response).getLong(ControlInformation.ID)); + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + + } + } diff --git a/src/main/java/org/opengis/cite/sta10/createUpdateDelete/package-info.java b/src/main/java/org/opengis/cite/sta10/createUpdateDelete/package-info.java index bc639e1..307e74a 100644 --- a/src/main/java/org/opengis/cite/sta10/createUpdateDelete/package-info.java +++ b/src/main/java/org/opengis/cite/sta10/createUpdateDelete/package-info.java @@ -1,8 +1,7 @@ /** * Conformance Level 2 extends Level 1. * - * @see HTML5 + * @see HTML5 * - Conformance classes */ package org.opengis.cite.sta10.createUpdateDelete; diff --git a/src/main/java/org/opengis/cite/sta10/filteringExtension/Capability3Tests.java b/src/main/java/org/opengis/cite/sta10/filteringExtension/Capability3Tests.java index ac3cd5d..be75bfa 100644 --- a/src/main/java/org/opengis/cite/sta10/filteringExtension/Capability3Tests.java +++ b/src/main/java/org/opengis/cite/sta10/filteringExtension/Capability3Tests.java @@ -28,2318 +28,2569 @@ */ public class Capability3Tests { - /** - * The root URL of the SensorThings service under the test - */ - public String rootUri;//="http://localhost:8080/OGCSensorThings/v1.0"; - - private long thingId1, thingId2, - datastreamId1, datastreamId2, datastreamId3, datastreamId4, - locationId1, locationId2, historicalLocationId1, - historicalLocationId2, historicalLocationId3, historicalLocationId4, - sensorId1, sensorId2, sensorId3, sensorId4, - observedPropertyId1, observedPropertyId2, observedPropertyId3, - observationId1, observationId2, observationId3, observationId4, observationId5, observationId6, observationId7, observationId8, observationId9, observationId10, observationId11, observationId12, - featureOfInterestId1, featureOfInterestId2; - - /** - * This method will be run before starting the test for this conformance - * class. It creates a set of entities to start testing query options. - * - * @param testContext The test context to find out whether this class is - * requested to test or not - */ - @BeforeClass - public void obtainTestSubject(ITestContext testContext) { - Object obj = testContext.getSuite().getAttribute( - SuiteAttribute.LEVEL.getName()); - if ((null != obj)) { - Integer level = Integer.class.cast(obj); - Assert.assertTrue(level.intValue() > 2, - "Conformance level 3 will not be checked since ics = " + level); - } - - rootUri = testContext.getSuite().getAttribute( - SuiteAttribute.TEST_SUBJECT.getName()).toString(); - rootUri = rootUri.trim(); - if (rootUri.lastIndexOf('/') == rootUri.length() - 1) { - rootUri = rootUri.substring(0, rootUri.length() - 1); - } - createEntities(); - } - - /** - * This method is testing $select query option. It tests $select for - * collection of entities with 1 level and 2 levels resource path. It also - * tests $select for one or more properties. - */ - @Test(description = "Check Query Evaluation Priority.", groups = "level-3") - public void readEntitiesWithSelectQO() { - checkSelectForEntityType(EntityType.THING); - checkSelectForEntityType(EntityType.LOCATION); - checkSelectForEntityType(EntityType.HISTORICAL_LOCATION); - checkSelectForEntityType(EntityType.DATASTREAM); - checkSelectForEntityType(EntityType.SENSOR); - checkSelectForEntityType(EntityType.OBSERVED_PROPERTY); - checkSelectForEntityType(EntityType.OBSERVATION); - checkSelectForEntityType(EntityType.FEATURE_OF_INTEREST); - checkSelectForEntityTypeRelations(EntityType.THING); - checkSelectForEntityTypeRelations(EntityType.LOCATION); - checkSelectForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); - checkSelectForEntityTypeRelations(EntityType.DATASTREAM); - checkSelectForEntityTypeRelations(EntityType.SENSOR); - checkSelectForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); - checkSelectForEntityTypeRelations(EntityType.OBSERVATION); - checkSelectForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); - - } - - /** - * This method is testing $expand query option. It tests $expand for - * collection of entities with 1 level and 2 levels resource path. It also - * tests $expand for one or more collections, and also tests multilevel - * $expand. - */ - @Test(description = "GET Entities with $expand", groups = "level-3") - public void readEntitiesWithExpandQO() { - checkExpandtForEntityType(EntityType.THING); - checkExpandtForEntityType(EntityType.LOCATION); - checkExpandtForEntityType(EntityType.HISTORICAL_LOCATION); - checkExpandtForEntityType(EntityType.DATASTREAM); - checkExpandtForEntityType(EntityType.SENSOR); - checkExpandtForEntityType(EntityType.OBSERVED_PROPERTY); - checkExpandtForEntityType(EntityType.OBSERVATION); - checkExpandtForEntityType(EntityType.FEATURE_OF_INTEREST); - checkExpandtForEntityTypeRelations(EntityType.THING); - checkExpandtForEntityTypeRelations(EntityType.LOCATION); - checkExpandtForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); - checkExpandtForEntityTypeRelations(EntityType.DATASTREAM); - checkExpandtForEntityTypeRelations(EntityType.SENSOR); - checkExpandtForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); - checkExpandtForEntityTypeRelations(EntityType.OBSERVATION); - checkExpandtForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); - checkExpandtForEntityTypeMultilevel(EntityType.THING); - checkExpandtForEntityTypeMultilevel(EntityType.LOCATION); - checkExpandtForEntityTypeMultilevel(EntityType.HISTORICAL_LOCATION); - checkExpandtForEntityTypeMultilevel(EntityType.DATASTREAM); - checkExpandtForEntityTypeMultilevel(EntityType.SENSOR); - checkExpandtForEntityTypeMultilevel(EntityType.OBSERVED_PROPERTY); - checkExpandtForEntityTypeMultilevel(EntityType.OBSERVATION); - checkExpandtForEntityTypeMultilevel(EntityType.FEATURE_OF_INTEREST); - checkExpandtForEntityTypeMultilevelRelations(EntityType.THING); - checkExpandtForEntityTypeMultilevelRelations(EntityType.LOCATION); - checkExpandtForEntityTypeMultilevelRelations(EntityType.HISTORICAL_LOCATION); - checkExpandtForEntityTypeMultilevelRelations(EntityType.DATASTREAM); - checkExpandtForEntityTypeMultilevelRelations(EntityType.SENSOR); - checkExpandtForEntityTypeMultilevelRelations(EntityType.OBSERVED_PROPERTY); - checkExpandtForEntityTypeMultilevelRelations(EntityType.OBSERVATION); - checkExpandtForEntityTypeMultilevelRelations(EntityType.FEATURE_OF_INTEREST); - - } - - /** - * This method is testing $top query option. It tests $top for collection of - * entities with 1 level and 2 levels resource path. It also tests - * {@literal @iot.nextLink} with regard to $top. - */ - @Test(description = "GET Entities with $top", groups = "level-3") - public void readEntitiesWithTopQO() { - checkTopForEntityType(EntityType.THING); - checkTopForEntityType(EntityType.LOCATION); - checkTopForEntityType(EntityType.HISTORICAL_LOCATION); - checkTopForEntityType(EntityType.DATASTREAM); - checkTopForEntityType(EntityType.SENSOR); - checkTopForEntityType(EntityType.OBSERVED_PROPERTY); - checkTopForEntityType(EntityType.OBSERVATION); - checkTopForEntityType(EntityType.FEATURE_OF_INTEREST); - checkTopForEntityTypeRelation(EntityType.THING); - checkTopForEntityTypeRelation(EntityType.LOCATION); - checkTopForEntityTypeRelation(EntityType.HISTORICAL_LOCATION); - checkTopForEntityTypeRelation(EntityType.DATASTREAM); - checkTopForEntityTypeRelation(EntityType.SENSOR); - checkTopForEntityTypeRelation(EntityType.OBSERVED_PROPERTY); - checkTopForEntityTypeRelation(EntityType.OBSERVATION); - checkTopForEntityTypeRelation(EntityType.FEATURE_OF_INTEREST); - - } - - /** - * This method is testing $skip query option. It tests $skip for collection - * of entities with 1 level and 2 levels resource path. It also tests - * {@literal @iot.nextLink} with regard to $skip. - */ - @Test(description = "GET Entities with $skip", groups = "level-3") - public void readEntitiesWithSkipQO() { - checkSkipForEntityType(EntityType.THING); - checkSkipForEntityType(EntityType.LOCATION); - checkSkipForEntityType(EntityType.HISTORICAL_LOCATION); - checkSkipForEntityType(EntityType.DATASTREAM); - checkSkipForEntityType(EntityType.SENSOR); - checkSkipForEntityType(EntityType.OBSERVED_PROPERTY); - checkSkipForEntityType(EntityType.OBSERVATION); - checkSkipForEntityType(EntityType.FEATURE_OF_INTEREST); - checkSkipForEntityTypeRelation(EntityType.THING); - checkSkipForEntityTypeRelation(EntityType.LOCATION); - checkSkipForEntityTypeRelation(EntityType.HISTORICAL_LOCATION); - checkSkipForEntityTypeRelation(EntityType.DATASTREAM); - checkSkipForEntityTypeRelation(EntityType.SENSOR); - checkSkipForEntityTypeRelation(EntityType.OBSERVED_PROPERTY); - checkSkipForEntityTypeRelation(EntityType.OBSERVATION); - checkSkipForEntityTypeRelation(EntityType.FEATURE_OF_INTEREST); - - } - - /** - * This method is testing $orderby query option. It tests $orderby for - * collection of entities with 1 level and 2 levels resource path. It also - * tests $orderby for one or more properties, and ascending and descending - * sorting. - */ - @Test(description = "GET Entities with $orderby", groups = "level-3") - public void readEntitiesWithOrderbyQO() { - checkOrderbyForEntityType(EntityType.THING); - checkOrderbyForEntityType(EntityType.LOCATION); - checkOrderbyForEntityType(EntityType.HISTORICAL_LOCATION); - checkOrderbyForEntityType(EntityType.DATASTREAM); - checkOrderbyForEntityType(EntityType.SENSOR); - checkOrderbyForEntityType(EntityType.OBSERVED_PROPERTY); - checkOrderbyForEntityType(EntityType.OBSERVATION); - checkOrderbyForEntityType(EntityType.FEATURE_OF_INTEREST); - checkOrderbyForEntityTypeRelations(EntityType.THING); - checkOrderbyForEntityTypeRelations(EntityType.LOCATION); - checkOrderbyForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); - checkOrderbyForEntityTypeRelations(EntityType.DATASTREAM); - checkOrderbyForEntityTypeRelations(EntityType.SENSOR); - checkOrderbyForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); - checkOrderbyForEntityTypeRelations(EntityType.OBSERVATION); - checkOrderbyForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); - } - - /** - * This method is testing $count query option. It tests $count for - * collection of entities with 1 level and 2 levels resource path. - */ - @Test(description = "GET Entities with $count", groups = "level-3") - public void readEntitiesWithCountQO() { - checkCountForEntityType(EntityType.THING); - checkCountForEntityType(EntityType.LOCATION); - checkCountForEntityType(EntityType.HISTORICAL_LOCATION); - checkCountForEntityType(EntityType.DATASTREAM); - checkCountForEntityType(EntityType.SENSOR); - checkCountForEntityType(EntityType.OBSERVED_PROPERTY); - checkCountForEntityType(EntityType.OBSERVATION); - checkCountForEntityType(EntityType.FEATURE_OF_INTEREST); - checkCountForEntityTypeRelations(EntityType.THING); - checkCountForEntityTypeRelations(EntityType.LOCATION); - checkCountForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); - checkCountForEntityTypeRelations(EntityType.DATASTREAM); - checkCountForEntityTypeRelations(EntityType.SENSOR); - checkCountForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); - checkCountForEntityTypeRelations(EntityType.OBSERVATION); - checkCountForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); - } - - /** - * This method is testing $filter query option for - * {@literal <, <=, =, >=, >} on properties. It tests $filter for collection - * of entities with 1 level and 2 levels resource path. - * - * @throws java.io.UnsupportedEncodingException Should not happen, UTF-8 - * should always be supported. - */ - @Test(description = "GET Entities with $filter", groups = "level-3") - public void readEntitiesWithFilterQO() throws UnsupportedEncodingException { - checkFilterForEntityType(EntityType.THING); - checkFilterForEntityType(EntityType.LOCATION); - checkFilterForEntityType(EntityType.HISTORICAL_LOCATION); - checkFilterForEntityType(EntityType.DATASTREAM); - checkFilterForEntityType(EntityType.SENSOR); - checkFilterForEntityType(EntityType.OBSERVED_PROPERTY); - checkFilterForEntityType(EntityType.OBSERVATION); - checkFilterForEntityType(EntityType.FEATURE_OF_INTEREST); - checkFilterForEntityTypeRelations(EntityType.THING); - checkFilterForEntityTypeRelations(EntityType.LOCATION); - checkFilterForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); - checkFilterForEntityTypeRelations(EntityType.DATASTREAM); - checkFilterForEntityTypeRelations(EntityType.SENSOR); - checkFilterForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); - checkFilterForEntityTypeRelations(EntityType.OBSERVATION); - checkFilterForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); - } - - /** - * This method is testing the correct priority of the query options. It uses - * $count, $top, $skip, $orderby, and $filter togther and check the priority - * in result. - */ - @Test(description = "Check priotity of query options", groups = "level-3") - public void checkQueriesPriorityOrdering() { - String urlString = ""; - try { - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, -1, null, "?$count=true&$top=1&$skip=2&$orderby=phenomenonTime%20asc&$filter=result%20gt%20'3'"); - Map responseMap = HTTPMethods.doGet(urlString); - Assert.assertEquals(Integer.parseInt(responseMap.get("response-code").toString()), 200, "There is problem for GET Observations using multiple Query Options! HTTP status code: " + responseMap.get("response-code") + ". [Request] " + urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - Assert.assertEquals(new JSONObject(response).getLong("@iot.count"), 6, "The query order of execution is not correct. The expected count is 6, but the service returned " + new JSONObject(response).getLong("@iot.count") + ". [Request] " + urlString); - Assert.assertEquals(array.length(), 1, "The query asked for top 1, but the service rerurned " + array.length() + " entities. [Request] " + urlString); - Assert.assertEquals(array.getJSONObject(0).getString("result"), "6", "The query order of execution is not correct. The expected Observation result is 6, but it is " + array.getJSONObject(0).getString("result") + ". [Request] " + urlString); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } - - /** - * This helper method is checking $orderby for 2 level of entities. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkOrderbyForEntityTypeRelations(EntityType entityType) { - List relations = entityType.getRelations(); - String urlString = ""; - try { - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - if (array.length() == 0) { - return; - } - long id = array.getJSONObject(0).getLong(ControlInformation.ID); - - for (String relation : relations) { - if (!EntityType.isPlural(relation)) { - continue; - } - EntityType relationEntityType = EntityType.getForRelation(relation); - List properties = relationEntityType.getProperties(); - //single orderby - for (String property : properties) { - if (property.equals("unitOfMeasurement")) { - continue; - } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$orderby=" + property); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - Assert.assertTrue(compareWithPrevious(i, array, property) <= 0, "The ordering is not correct for EntityType " + entityType + " orderby property " + property + ". [Request] " + urlString); - } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$orderby=" + property + "%20asc"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - Assert.assertTrue(compareWithPrevious(i, array, property) <= 0, "The ordering is not correct for EntityType " + entityType + " orderby asc property " + property + ". [Request] " + urlString); - } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$orderby=" + property + "%20desc"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - Assert.assertTrue(compareWithPrevious(i, array, property) >= 0, "The ordering is not correct for EntityType " + entityType + " orderby desc property " + property + ". [Request] " + urlString); - } - } - - //multiple orderby - List orderbyPropeties = new ArrayList<>(); - String orderby = "?$orderby="; - String orderbyAsc = "?$orderby="; - String orderbyDesc = "?$orderby="; - for (String property : properties) { - if (property.equals("unitOfMeasurement")) { - continue; - } - if (orderby.charAt(orderby.length() - 1) != '=') { - orderby += ","; - } - orderby += property; - orderbyPropeties.add(property); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, orderby); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - for (String orderProperty : orderbyPropeties) { - int compare = compareWithPrevious(i, array, orderProperty); - Assert.assertTrue(compare <= 0, "The ordering is not correct for EntityType " + entityType + " orderby property " + orderProperty + ". [Request] " + urlString); - if (compare != 0) { - break; - } - } - } - if (orderbyAsc.charAt(orderbyAsc.length() - 1) != '=') { - orderbyAsc += ","; - } - orderbyAsc += property + "%20asc"; - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, orderbyAsc); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - for (String orderProperty : orderbyPropeties) { - int compare = compareWithPrevious(i, array, orderProperty); - Assert.assertTrue(compare <= 0, "The ordering is not correct for EntityType " + entityType + " orderby asc property " + orderProperty + ". [Request] " + urlString); - if (compare != 0) { - break; - } - } - } - if (orderbyDesc.charAt(orderbyDesc.length() - 1) != '=') { - orderbyDesc += ","; - } - orderbyDesc += property + "%20desc"; - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, orderbyDesc); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - for (String orderProperty : orderbyPropeties) { - int compare = compareWithPrevious(i, array, orderProperty); - Assert.assertTrue(compare >= 0, "The ordering is not correct for EntityType " + entityType + " orderby desc property " + orderProperty + ". [Request] " + urlString); - if (compare != 0) { - break; - } - } - } - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - - } - - /** - * This helper method is checking $orderby for a collection. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkOrderbyForEntityType(EntityType entityType) { - List properties = entityType.getProperties(); - String urlString = ""; - try { - //single orderby - for (String property : properties) { - if (property.equals("unitOfMeasurement")) { - continue; - } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$orderby=" + property); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - Assert.assertTrue(compareWithPrevious(i, array, property) <= 0, "The default ordering is not correct for EntityType " + entityType + " orderby property " + property + ". [Request] " + urlString); - } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$orderby=" + property + "%20asc"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - Assert.assertTrue(compareWithPrevious(i, array, property) <= 0, "The ascending ordering is not correct for EntityType " + entityType + " orderby asc property " + property + ". [Request] " + urlString); - } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$orderby=" + property + "%20desc"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - Assert.assertTrue(compareWithPrevious(i, array, property) >= 0, "The descending ordering is not correct for EntityType " + entityType + " orderby desc property " + property + ". [Request] " + urlString); - } - } - - //multiple orderby - List orderbyPropeties = new ArrayList<>(); - String orderby = "?$orderby="; - String orderbyAsc = "?$orderby="; - String orderbyDesc = "?$orderby="; - for (String property : properties) { - if (property.equals("unitOfMeasurement")) { - continue; - } - if (orderby.charAt(orderby.length() - 1) != '=') { - orderby += ","; - } - orderby += property; - orderbyPropeties.add(property); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, orderby); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - for (String orderProperty : orderbyPropeties) { - int compare = compareWithPrevious(i, array, orderProperty); - Assert.assertTrue(compare <= 0, "The ordering is not correct for EntityType " + entityType + " orderby property " + orderProperty + ". [Request] " + urlString); - if (compare != 0) { - break; - } - } - } - if (orderbyAsc.charAt(orderbyAsc.length() - 1) != '=') { - orderbyAsc += ","; - } - orderbyAsc += property + "%20asc"; - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, orderbyAsc); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - for (String orderProperty : orderbyPropeties) { - int compare = compareWithPrevious(i, array, orderProperty); - Assert.assertTrue(compare <= 0, "The ordering is not correct for EntityType " + entityType + " orderby asc property " + orderProperty + ". [Request] " + urlString); - if (compare != 0) { - break; - } - } - } - if (orderbyDesc.charAt(orderbyDesc.length() - 1) != '=') { - orderbyDesc += ","; - } - orderbyDesc += property + "%20desc"; - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, orderbyDesc); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - for (int i = 1; i < array.length(); i++) { - for (String orderProperty : orderbyPropeties) { - int compare = compareWithPrevious(i, array, orderProperty); - Assert.assertTrue(compare >= 0, "The ordering is not correct for EntityType " + entityType + " orderby desc property " + orderProperty + ". [Request] " + urlString); - if (compare != 0) { - break; - } - } - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - - } - - private int compareWithPrevious(int idx, JSONArray array, String property) throws JSONException { - JSONObject jObj1 = array.getJSONObject(idx - 1); - JSONObject jObj2 = array.getJSONObject(idx); - Object o1 = jObj1.get(property); - Object o2 = jObj2.get(property); - return compareForOrder(o1, o2); - } - - private int compareForOrder(Object o1, Object o2) { - if (o1 instanceof Comparable && o2 instanceof Comparable) { - if (o1.getClass().isAssignableFrom(o2.getClass())) { - return ((Comparable) o1).compareTo(o2); - } else if (o2.getClass().isAssignableFrom(o1.getClass())) { - return -((Comparable) o2).compareTo(o1); - } - } - return o1.toString().compareTo(o2.toString()); - } - - /** - * This helper method is checking $skip for s collection. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkSkipForEntityType(EntityType entityType) { - String urlString = ""; - try { - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=1"); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (entityType) { - case THING: - case LOCATION: - case FEATURE_OF_INTEREST: - Assert.assertEquals(array.length(), 1, "Query requested entities skipping 1, result should have contained 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(array.length(), 2, "Query requested entities skipping 1, result should have contained 2 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - case HISTORICAL_LOCATION: - case SENSOR: - case DATASTREAM: - Assert.assertEquals(array.length(), 3, "Query requested entities skipping 1, result should have contained 3 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 11, "Query requested entities skipping 1, result should have contained 11 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - default: - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=2"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (entityType) { - case THING: - case LOCATION: - case FEATURE_OF_INTEREST: - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 2, result should have contained 0 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(array.length(), 1, "Query requested entities skipping 2, result should have contained 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case HISTORICAL_LOCATION: - case SENSOR: - case DATASTREAM: - Assert.assertEquals(array.length(), 2, "Query requested entities skipping 2, result should have contained 2 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 10, "Query requested entities skipping 2, result should have contained 10 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - default: - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=3"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (entityType) { - case THING: - case LOCATION: - case FEATURE_OF_INTEREST: - case OBSERVED_PROPERTY: - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 3, result should have contained 0 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case HISTORICAL_LOCATION: - case SENSOR: - case DATASTREAM: - Assert.assertEquals(array.length(), 1, "Query requested entities skipping 3, result should have contained 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 9, "Query requested entities skipping 3, result should have contained 9 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - default: - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=4"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (entityType) { - case THING: - case LOCATION: - case FEATURE_OF_INTEREST: - case OBSERVED_PROPERTY: - case HISTORICAL_LOCATION: - case SENSOR: - case DATASTREAM: - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 4, result should have contained 0 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 8, "Query requested entities skipping 4, result should have contained 8 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - default: - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=12"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 12, result should have contained 0 entity, but it contains " + array.length() + ". [Request] " + urlString); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } - - /** - * This helper method is checking $skip for 2 level of entities. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkSkipForEntityTypeRelation(EntityType entityType) { - String urlString = ""; - try { - List relations = entityType.getRelations(); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - if (array.length() == 0) { - return; - } - long id = array.getJSONObject(0).getLong(ControlInformation.ID); - - for (String relation : relations) { - if (!EntityType.isPlural(relation)) { - continue; - } - EntityType relationEntityType = EntityType.getForRelation(relation); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$skip=1"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (entityType) { - case THING: - switch (relationEntityType) { - case LOCATION: - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 1, result should have contained 0 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case HISTORICAL_LOCATION: - Assert.assertEquals(array.length(), 1, "Query requested entities skipping 1, result should have contained 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case DATASTREAM: - Assert.assertEquals(array.length(), 1, "Query requested entities skipping 1, result should have contained 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - } - break; - case LOCATION: - switch (relationEntityType) { - case HISTORICAL_LOCATION: - Assert.assertEquals(array.length(), 1, "Query requested entities skipping 1, result should have contained 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case THING: - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 1, result should have contained 0 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - } - break; - case FEATURE_OF_INTEREST: - Assert.assertEquals(array.length(), 5, "Query requested entities skipping 1, result should have contained 5 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - case OBSERVED_PROPERTY: - Assert.assertTrue(array.length() == 1 || array.length() == 0, "Query requested entities skipping 1, result should have contained 0 or 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case HISTORICAL_LOCATION: - switch (relationEntityType) { - case LOCATION: - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 1, result should have contained 0 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - } - break; - case SENSOR: - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 1, result should have contained 0 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case DATASTREAM: - switch (relationEntityType) { - case OBSERVATION: - Assert.assertEquals(array.length(), 2, "Query requested entities skipping 1, result should have contained 2 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - } - break; - default: - break; - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + "[Request] " + urlString); - } - } - - /** - * This helper method is checking $top for a collection. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkTopForEntityType(EntityType entityType) { - String urlString = ""; - try { - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=1"); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - Assert.assertEquals(array.length(), 1, "Query requested 1 entity but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink" + "[Request] " + urlString); - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=2"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - Assert.assertEquals(array.length(), 2, "Query requested 2 entities but response contains " + array.length()+ ". [Request] " + urlString); - switch (entityType) { - case THING: - case LOCATION: - case FEATURE_OF_INTEREST: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString ); - } catch (JSONException e) { - } - break; - default: - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink"); - } - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=3"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - switch (entityType) { - case THING: - Assert.assertEquals(array.length(), 2, "Query requested 3 Things, there are only 2 Things, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case LOCATION: - Assert.assertEquals(array.length(), 2, "Query requested 3 Locations, there are only 2 Locations, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case FEATURE_OF_INTEREST: - Assert.assertEquals(array.length(), 2, "Query requested 3 FeaturesOfInterest, there are only 2 FeaturesOfInterest, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(array.length(), 3, "Query requested 3 entities but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - default: - Assert.assertEquals(array.length(), 3, "Query requested 3 entities but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink" + " [Request] " + urlString); - } - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=4"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - switch (entityType) { - case THING: - Assert.assertEquals(array.length(), 2, "Query requested 4 Things, there are only 2 Things, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case LOCATION: - Assert.assertEquals(array.length(), 2, "Query requested 4 Locations, there are only 2 Locations, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case FEATURE_OF_INTEREST: - Assert.assertEquals(array.length(), 2, "Query requested 4 FeaturesOfInterest, there are only 2 FeaturesOfInterest, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(array.length(), 3, "Query requested 4 ObservedProperties, there are only 3 ObservedProperties, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case SENSOR: - case HISTORICAL_LOCATION: - case DATASTREAM: - Assert.assertEquals(array.length(), 4, "Query requested 4 entities but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - default: - Assert.assertEquals(array.length(), 4, "Query requested 4 entities but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink. [Request] " + urlString); - } - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=5"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - switch (entityType) { - case THING: - Assert.assertEquals(array.length(), 2, "Query requested 5 Things, there are only 2 Things, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case LOCATION: - Assert.assertEquals(array.length(), 2, "Query requested 5 Locations, there are only 2 Locations, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case FEATURE_OF_INTEREST: - Assert.assertEquals(array.length(), 2, "Query requested 5 FeaturesOfInterest, there are only 2 FeaturesOfInterest, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(array.length(), 3, "Query requested 5 ObservedProperties, there are only 3 ObservedProperties, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case SENSOR: - Assert.assertEquals(array.length(), 4, "Query requested 5 Sensors, there are only 4 Sensors, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case HISTORICAL_LOCATION: - Assert.assertEquals(array.length(), 4, "Query requested 5 HistoricalLocations, there are only 4 HistoricalLocations, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case DATASTREAM: - Assert.assertEquals(array.length(), 4, "Query requested 5 Datastreams, there are only 4 Datastreams, but response contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - default: - Assert.assertEquals(array.length(), 5, "Query requested 5 entities but response contains " + array.length()); - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink. [Request] " + urlString); - } - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=12"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=13"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (entityType) { - case THING: - Assert.assertEquals(array.length(), 2, "Query requested 13 Things, there are only 2 Things, but response contains " + array.length() + ". [Request] " + urlString); - break; - case LOCATION: - Assert.assertEquals(array.length(), 2, "Query requested 13 Locations, there are only 2 Locations, but response contains " + array.length() + ". [Request] " + urlString); - break; - case FEATURE_OF_INTEREST: - Assert.assertEquals(array.length(), 2, "Query requested 13 FeaturesOfInterest, there are only 2 FeaturesOfInterest, but response contains " + array.length() + ". [Request] " + urlString); - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(array.length(), 3, "Query requested 13 ObservedProperties, there are only 3 ObservedProperties, but response contains " + array.length() + ". [Request] " + urlString); - break; - case SENSOR: - Assert.assertEquals(array.length(), 4, "Query requested 13 Sensors, there are only 4 Sensors, but response contains " + array.length() + ". [Request] " + urlString); - break; - case HISTORICAL_LOCATION: - Assert.assertEquals(array.length(), 4, "Query requested 13 HistoricalLocations, there are only 4 HistoricalLocations, but response contains " + array.length() + ". [Request] " + urlString); - break; - case DATASTREAM: - Assert.assertEquals(array.length(), 4, "Query requested 13 Datastreams, there are only 4 Datastreams, but response contains " + array.length() + ". [Request] " + urlString); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 12, "Query requested 13 Observations, there are only 12 Observations, but response contains " + array.length() + ". [Request] " + urlString); - break; - } - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } - - /** - * This helper method is checking $top for 2 level of entities. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkTopForEntityTypeRelation(EntityType entityType) { - String urlString = ""; - try { - List relations = entityType.getRelations(); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - if (array.length() == 0) { - return; - } - long id = array.getJSONObject(0).getLong(ControlInformation.ID); - - for (String relation : relations) { - if (!EntityType.isPlural(relation)) { - continue; - } - EntityType relationEntityType = EntityType.getForRelation(relation); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$top=3"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - switch (entityType) { - case THING: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (relationEntityType) { - case LOCATION: - Assert.assertEquals(array.length(), 1, "Query requested entities 3 entities, result should have contained 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case HISTORICAL_LOCATION: - Assert.assertEquals(array.length(), 2, "Query requested entities 3 entities, result should have contained 2 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - case DATASTREAM: - Assert.assertEquals(array.length(), 2, "Query requested entities 3 entities, result should have contained 2 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - } - break; - case LOCATION: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (relationEntityType) { - case HISTORICAL_LOCATION: - Assert.assertEquals(array.length(), 2, "Query requested entities 3 entities, result should have contained 2 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - case THING: - Assert.assertEquals(array.length(), 1, "Query requested entities 3 entities, result should have contained 1 entity, but it contains" + array.length() + ". [Request] " + urlString); - break; - } - break; - case FEATURE_OF_INTEREST: - Assert.assertEquals(array.length(), 3, "Query requested entities 3 entities, result should have contained 3 entities, but it contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink. [Request] " + urlString); - } - break; - case OBSERVED_PROPERTY: - Assert.assertTrue(array.length() == 1 || array.length() == 2, "Query requested entities 3 entities, result should have contained 1 or 2 entities, but it contains " + array.length() + ". [Request] " + urlString); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - break; - case HISTORICAL_LOCATION: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (relationEntityType) { - case LOCATION: - Assert.assertEquals(array.length(), 1, "Query requested entities 3 entities, result should have contained 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - } - break; - case SENSOR: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - Assert.assertEquals(array.length(), 1, "Query requested entities 3 entities, result should have contained 1 entity, but it contains " + array.length() + ". [Request] " + urlString); - break; - case DATASTREAM: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink. [Request] " + urlString); - } catch (JSONException e) { - } - switch (relationEntityType) { - case OBSERVATION: - Assert.assertEquals(array.length(), 3, "Query requested entities 3 entities, result should have contained 3 entities, but it contains " + array.length() + ". [Request] " + urlString); - break; - } - break; - default: - break; - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } - - /** - * This helper method is checking $select for a collection. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkSelectForEntityType(EntityType entityType) { - List selectedProperties; - List properties = entityType.getProperties(); - for (String property : properties) { - selectedProperties = new ArrayList<>(); - selectedProperties.add(property); - String response = getEntities(entityType, -1, null, selectedProperties, null); - checkEntitiesAllAspectsForSelectResponse(entityType, response, selectedProperties); - } - selectedProperties = new ArrayList<>(); - for (String property : properties) { - selectedProperties.add(property); - String response = getEntities(entityType, -1, null, selectedProperties, null); - checkEntitiesAllAspectsForSelectResponse(entityType, response, selectedProperties); - } - } - - /** - * This helper method is checking $select for 2 level of entities. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkSelectForEntityTypeRelations(EntityType entityType) { - String urlString = ""; - try { - List parentRelations = entityType.getRelations(); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - if (array.length() == 0) { - return; - } - long id = array.getJSONObject(0).getLong(ControlInformation.ID); - - for (String parentRelation : parentRelations) { - EntityType relationEntityType = EntityType.getForRelation(parentRelation); - List selectedProperties; - List properties = relationEntityType.getProperties(); - for (String property : properties) { - selectedProperties = new ArrayList<>(); - selectedProperties.add(property); - response = getEntities(entityType, id, relationEntityType, selectedProperties, null); - checkEntitiesAllAspectsForSelectResponse(relationEntityType, response, selectedProperties); - } - selectedProperties = new ArrayList<>(); - for (String property : properties) { - selectedProperties.add(property); - response = getEntities(entityType, id, relationEntityType, selectedProperties, null); - checkEntitiesAllAspectsForSelectResponse(relationEntityType, response, selectedProperties); - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } - - /** - * Send GET request with $select and $expand and check the response. - * - * @param entityType Entity type from EntityType enum list - * @param id The id of the entity - * @param relationEntityType The relation entity type from EntityType enum - * list - * @param selectedProperties The list of selected properties - * @param expandedRelations The list of expanded properties - * @return The response of GET request in string format - */ - private String getEntities(EntityType entityType, long id, EntityType relationEntityType, List selectedProperties, List expandedRelations) { - String urlString = rootUri; - String selectString = ""; - if (selectedProperties != null && selectedProperties.size() > 0) { - selectString = "?$select="; - for (String select : selectedProperties) { - if (selectString.charAt(selectString.length() - 1) != '=') { - selectString += ','; - } - selectString += select; - } - } - String expandString = ""; - if (expandedRelations != null && expandedRelations.size() > 0) { - expandString = selectString.equals("") ? "?$expand=" : "&$expand="; - for (String expand : expandedRelations) { - if (expandString.charAt(expandString.length() - 1) != '=') { - expandString += ','; - } - expandString += expand; - } - } - if (entityType != null) { - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, selectString + expandString); - } - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "Error during getting entities: " + entityType.name() + ". [Request] " + urlString); - return response; - } - - /** - * This helper method is the start point for checking $select response - * - * @param entityType Entity type from EntityType enum list - * @param response The response to be checked - * @param selectedProperties The list of selected properties - */ - private void checkEntitiesAllAspectsForSelectResponse(EntityType entityType, String response, List selectedProperties) { - checkEntitiesProperties(entityType, response, selectedProperties); - checkEntitiesRelations(entityType, response, selectedProperties, null); - } - - /** - * This method is checking properties for the $select response of a - * collection - * - * @param entityType Entity type from EntityType enum list - * @param response The response to be checked - * @param selectedProperties The list of selected properties - */ - private void checkEntitiesProperties(EntityType entityType, String response, List selectedProperties) { - try { - JSONObject jsonResponse = new JSONObject(response.toString()); - JSONArray entities = null; - if (response.contains("value")) { - entities = jsonResponse.getJSONArray("value"); - } else { - entities = new JSONArray(); - entities.put(jsonResponse); - } - checkPropertiesForEntityArray(entityType, entities, selectedProperties); - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Response] " + response.toString()); - } - - } - - /** - * This method is checking properties for the $select array of entities - * - * @param entityType Entity type from EntityType enum list - * @param entities The JSONArray of entities to be checked - * @param selectedProperties The list of selected properties - */ - private void checkPropertiesForEntityArray(EntityType entityType, JSONArray entities, List selectedProperties) { - int count = 0; - for (int i = 0; i < entities.length() && count < 2; i++) { - count++; - JSONObject entity = null; - try { - entity = entities.getJSONObject(i); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - checkEntityProperties(entityType, entity, selectedProperties); - } - } - - /** - * This method is checking properties for the $select response of a single - * entity - * - * @param entityType Entity type from EntityType enum list - * @param response The response to be checked - * @param selectedProperties The list of selected properties - */ - private void checkEntityProperties(EntityType entityType, Object response, List selectedProperties) { - try { - JSONObject entity = new JSONObject(response.toString()); - List properties = entityType.getProperties(); - for (String property : properties) { - if (selectedProperties.contains(property)) { - try { - Assert.assertNotNull(entity.get(property), "Entity type \"" + entityType + "\" does not have selected property: \"" + property + "\". [Response]: " + response.toString()); - } catch (JSONException e) { - Assert.fail("Entity type \"" + entityType + "\" does not have selected property: \"" + property + "\". [Response]: " + response.toString()); - } - } else { - try { - Assert.assertNull(entity.get(property), "Entity type \"" + entityType + "\" contains not-selected property: \"" + property + "\". [Response]: " + response.toString()); - } catch (JSONException e) { - } - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Response]: " + response.toString()); - } - - } - - /** - * This method is checking the related entities of selected and/or expanded - * entities for a collection - * - * @param entityType Entity type from EntityType enum list - * @param response The response to be checked - * @param selectedProperties The list of selected properties - * @param expandedRelations The list of expanded properties - */ - private void checkEntitiesRelations(EntityType entityType, String response, List selectedProperties, List expandedRelations) { - try { - JSONObject jsonResponse = new JSONObject(response.toString()); - JSONArray entities = null; - if (response.contains("value")) { - entities = jsonResponse.getJSONArray("value"); - } else { - entities = new JSONArray(); - entities.put(jsonResponse); - } - int count = 0; - for (int i = 0; i < entities.length() && count < 2; i++) { - count++; - JSONObject entity = entities.getJSONObject(i); - checkEntityRelations(entityType, entity, selectedProperties, expandedRelations); - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()+ " [Response]: " + response.toString()); - } - - } - - /** - * This method is checking the related entities of selected and/or expanded - * entities for a single entity - * - * @param entityType Entity type from EntityType enum list - * @param response The response to be checked - * @param selectedProperties The list of selected properties - * @param expandedRelations The list of expanded properties - */ - private void checkEntityRelations(EntityType entityType, Object response, List selectedProperties, List expandedRelations) { - try { - JSONObject entity = new JSONObject(response.toString()); - List relations = entityType.getRelations(); - for (String relation : relations) { - EntityType relationType = EntityType.getForRelation(relation); - if (selectedProperties == null || selectedProperties.contains(relation)) { - if (expandedRelations == null || !listContainsString(expandedRelations, relation)) { - try { - Assert.assertNotNull(entity.get(relation + ControlInformation.NAVIGATION_LINK), "Entity type \"" + entityType + "\" does not have selected relation: \"" + relation + "\". [Response]: " + response.toString()); - } catch (JSONException e) { - Assert.fail("Entity type \"" + entityType + "\" does not have selected relation: \"" + relation + "\". [Response]: " + response.toString()); - } - } else { - Assert.assertNotNull(entity.get(relation), "Entity type \"" + entityType + "\" does not have expanded relation Correctly: \"" + relation + "\". [Response]: " + response.toString()); - JSONArray expandedEntityArray = null; - try { - if (!EntityType.isPlural(relation)) { - expandedEntityArray = new JSONArray(); - expandedEntityArray.put(entity.getJSONObject(relation)); - } else { - expandedEntityArray = entity.getJSONArray(relation); - } - } catch (JSONException e) { - Assert.fail("Entity type \"" + entityType + "\" does not have expanded relation Correctly: \"" + relation + "\". [Response]: " + response.toString()); - } - checkPropertiesForEntityArray(relationType, expandedEntityArray, new ArrayList<>(relationType.getProperties())); - if (listContainsString(expandedRelations, "/")) { - List secondLevelRelations = relationType.getRelations(); - JSONObject expandedEntity = expandedEntityArray.getJSONObject(0); - for (String secondLeveleRelation : secondLevelRelations) { - EntityType secondLevelRelationType = EntityType.getForRelation(secondLeveleRelation); - if (listContainsString(expandedRelations, relation + "/" + secondLeveleRelation)) { - - expandedEntityArray = null; - try { - if (!EntityType.isPlural(secondLeveleRelation)) { - expandedEntityArray = new JSONArray(); - expandedEntityArray.put(expandedEntity.getJSONObject(secondLeveleRelation)); - } else { - expandedEntityArray = expandedEntity.getJSONArray(secondLeveleRelation); - } - } catch (JSONException e) { - Assert.fail("Entity type \"" + entityType + "\" does not have expanded relation Correctly: \"" + relation + "/" + secondLeveleRelation + "\". [Response]: " + response.toString()); - } - checkPropertiesForEntityArray(secondLevelRelationType, expandedEntityArray, new ArrayList<>(secondLevelRelationType.getProperties())); - } - } - } - } - } else { - try { - Assert.assertNull(entity.get(relation + ControlInformation.NAVIGATION_LINK), "Entity type \"" + entityType + "\" contains not-selectd relation: \"" + relation + "\". [Response]: " + response.toString()); - } catch (JSONException e) { - } - try { - Assert.assertNull(entity.get(relation), "Entity type \"" + entityType + "\" contains not-selectd relation: \"" + relation + "\". [Response]: " + response.toString()); - } catch (JSONException e) { - } - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Response]: " + response.toString()); - } - } - - /** - * This helper method is checking $expand for a collection. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkExpandtForEntityType(EntityType entityType) { - List expandedRelations; - List relations = entityType.getRelations(); - for (String relation : relations) { - expandedRelations = new ArrayList<>(); - expandedRelations.add(relation); - String response = getEntities(entityType, -1, null, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); - } - expandedRelations = new ArrayList<>(); - for (String relation : relations) { - expandedRelations.add(relation); - String response = getEntities(entityType, -1, null, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); - } - } - - /** - * This helper method is checking $expand for 2 level of entities. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkExpandtForEntityTypeRelations(EntityType entityType) { - String urlString=""; - try { - List parentRelations = entityType.getRelations(); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - if (array.length() == 0) { - return; - } - long id = array.getJSONObject(0).getLong(ControlInformation.ID); - - for (String parentRelation : parentRelations) { - EntityType relationEntityType = EntityType.getForRelation(parentRelation); - List expandedRelations; - List relations = relationEntityType.getRelations(); - for (String relation : relations) { - expandedRelations = new ArrayList<>(); - expandedRelations.add(relation); - response = getEntities(entityType, id, relationEntityType, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(relationEntityType, response, expandedRelations); - } - expandedRelations = new ArrayList<>(); - for (String relation : relations) { - expandedRelations.add(relation); - response = getEntities(entityType, id, relationEntityType, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(relationEntityType, response, expandedRelations); - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request]: " + urlString); - } - } - - /** - * This helper method is checking multilevel $expand for 2 level of - * entities. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkExpandtForEntityTypeMultilevelRelations(EntityType entityType) { - String urlString =""; - try { - List parentRelations = entityType.getRelations(); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - if (array.length() == 0) { - return; - } - long id = array.getJSONObject(0).getLong(ControlInformation.ID); - - for (String parentRelation : parentRelations) { - EntityType parentRelationType = EntityType.getForRelation(parentRelation); - List expandedRelations; - List relations = parentRelationType.getRelations(); - for (String relation : relations) { - EntityType relationType = EntityType.getForRelation(relation); - List secondLevelRelations = relationType.getRelations(); - - for (String secondLevelRelation : secondLevelRelations) { - expandedRelations = new ArrayList<>(); - expandedRelations.add(relation + "/" + secondLevelRelation); - response = getEntities(entityType, id, parentRelationType, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(parentRelationType, response, expandedRelations); - } - } - expandedRelations = new ArrayList<>(); - for (String relation : relations) { - EntityType relationType = EntityType.getForRelation(relation); - List secondLevelRelations = relationType.getRelations(); - for (String secondLevelRelation : secondLevelRelations) { - expandedRelations.add(relation + "/" + secondLevelRelation); - response = getEntities(entityType, id, parentRelationType, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(parentRelationType, response, expandedRelations); - } - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } - - /** - * This helper method is checking multilevel $expand for a collection. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkExpandtForEntityTypeMultilevel(EntityType entityType) { - List expandedRelations; - List relations = entityType.getRelations(); - for (String relation : relations) { - EntityType relationType = EntityType.getForRelation(relation); - List secondLevelRelations = relationType.getRelations(); - - for (String secondLevelRelation : secondLevelRelations) { - expandedRelations = new ArrayList<>(); - expandedRelations.add(relation + "/" + secondLevelRelation); - String response = getEntities(entityType, -1, null, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); - } - } - expandedRelations = new ArrayList<>(); - for (String relation : relations) { - EntityType relationType = EntityType.getForRelation(relation); - List secondLevelRelations = relationType.getRelations(); - for (String secondLevelRelation : secondLevelRelations) { - expandedRelations.add(relation + "/" + secondLevelRelation); - String response = getEntities(entityType, -1, null, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); - } - } - } - - /** - * This helper method is checking $count for a collection. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkCountForEntityType(EntityType entityType) { - - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$count=true"); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - int count = -1; - try { - count = new JSONObject(response).getInt("@iot.count"); - } catch (JSONException e) { - Assert.fail("the query asked for count but the response does not contain count, for getting collection: " + entityType + " [Request] " + urlString); - } - switch (entityType) { - case THING: - case LOCATION: - case FEATURE_OF_INTEREST: - Assert.assertEquals(count, 2, "The count for " + entityType + "should be 2, but it is " + count + " [Request] " + urlString); - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(count, 3, "The count for " + entityType + "should be 3, but it is " + count + " [Request] " + urlString); - break; - case HISTORICAL_LOCATION: - case SENSOR: - case DATASTREAM: - Assert.assertEquals(count, 4, "The count for " + entityType + "should be 4, but it is " + count + " [Request] " + urlString); - break; - case OBSERVATION: - Assert.assertEquals(count, 12, "The count for " + entityType + "should be 12, but it is " + count + " [Request] " + urlString); - break; - default: - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$count=false"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - try { - Assert.assertNull(new JSONObject(response).getInt("@iot.count"), "the query asked for not count but the response does contain count, for getting collection: " + entityType + ". [Request] " + urlString); - Assert.fail("the query asked for not count but the response does contain count, for getting collection: " + entityType + ". [Request] " + urlString); - } catch (JSONException e) { - } - } - - /** - * This helper method is checking $count for 2 level of entities. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkCountForEntityTypeRelations(EntityType entityType) { - String urlString = ""; - try { - List relations = entityType.getRelations(); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - if (array.length() == 0) { - return; - } - long id = array.getJSONObject(0).getLong(ControlInformation.ID); - - for (String relation : relations) { - if (!EntityType.isPlural(relation)) { - return; - } - EntityType relationEntityType = EntityType.getForRelation(relation); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$count=true"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - int count = -1; - try { - count = new JSONObject(response).getInt("@iot.count"); - } catch (JSONException e) { - Assert.fail("the query asked for count but the response does not contain count, for getting collection: " + entityType + ". [Request] " + urlString); - } - switch (relationEntityType) { - case THING: - case LOCATION: - Assert.assertEquals(count, 1, "The count for " + entityType + "should be 1, but it is " + count + " [Request] " + urlString); - break; - case HISTORICAL_LOCATION: - case DATASTREAM: - switch (entityType) { - case THING: - Assert.assertEquals(count, 2, "The count for " + entityType + "should be 2, but it is " + count + " [Request] " + urlString); - break; - case SENSOR: - Assert.assertEquals(count, 1, "The count for " + entityType + "should be 1, but it is " + count + " [Request] " + urlString); - break; - case OBSERVED_PROPERTY: - Assert.assertTrue(count == 2 || count == 1, "The count for " + entityType + "should be 1 or 2, but it is " + count + " [Request] " + urlString); - break; - } - break; - case OBSERVATION: - if (entityType.equals(EntityType.DATASTREAM)) { - Assert.assertEquals(count, 3, "The count for " + entityType + "should be 3, but it is " + count + " [Request] " + urlString); - } else if (entityType.equals(EntityType.FEATURE_OF_INTEREST)) { - Assert.assertEquals(count, 6, "The count for " + entityType + "should be 6, but it is " + count + " [Request] " + urlString); - } - break; - default: - break; - } - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$count=false"); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - try { - Assert.assertNull(new JSONObject(response).getInt("@iot.count"), "the query asked for not count but the response does contain count, for getting collection: " + entityType + ". [Request] " + urlString); - Assert.fail("the query asked for not count but the response does contain count, for getting collection: " + entityType + ". [Request] " + urlString); - } catch (JSONException e) { - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - } - - /** - * This helper method is the start point for checking $expand response. - * - * @param entityType Entity type from EntityType enum list - * @param response The response to be checked - * @param expandedRelations List of expanded relations - */ - private void checkEntitiesAllAspectsForExpandResponse(EntityType entityType, String response, List expandedRelations) { - checkEntitiesRelations(entityType, response, null, expandedRelations); - } - - /** - * This helper method is checking $filter for a collection. - * - * @param entityType Entity type from EntityType enum list - * @throws java.io.UnsupportedEncodingException Should not happen, UTF-8 - * should always be supported. - */ - private void checkFilterForEntityType(EntityType entityType) throws UnsupportedEncodingException { - List properties = entityType.getProperties(); - List filteredProperties; - List samplePropertyValues; - for (int i = 0; i < properties.size(); i++) { - String property = properties.get(i); - filteredProperties = new ArrayList<>(); - samplePropertyValues = new ArrayList<>(); - filteredProperties.add(property); - if (property.equals("location") || property.equals("feature") || property.equals("unitOfMeasurement")) { - continue; - } - Comparable propertyValue = EntityPropertiesSampleValue.getPropertyValueFor(entityType, i); - samplePropertyValues.add(propertyValue); - - propertyValue = URLEncoder.encode(propertyValue.toString(), "UTF-8"); - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20lt%20" + propertyValue); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -2); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20le%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -1); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20eq%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 0); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20ne%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -3); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20ge%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 1); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20gt%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 2); - } - } - - /** - * This helper method is checking $filter for 2 level of entities. - * - * @param entityType Entity type from EntityType enum list - * @throws java.io.UnsupportedEncodingException Should not happen, UTF-8 - * should always be supported. - */ - private void checkFilterForEntityTypeRelations(EntityType entityType) throws UnsupportedEncodingException { - List relations = entityType.getRelations(); - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - JSONArray array = null; - try { - array = new JSONObject(response).getJSONArray("value"); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - if (array.length() == 0) { - return; - } - long id = 0; - try { - id = array.getJSONObject(0).getLong(ControlInformation.ID); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - - for (String relation : relations) { - if (!EntityType.isPlural(relation)) { - return; - } - EntityType relationEntityType = EntityType.getForRelation(relation); - - List properties = relationEntityType.getProperties(); - List filteredProperties; - List samplePropertyValues; - for (int i = 0; i < properties.size(); i++) { - filteredProperties = new ArrayList<>(); - samplePropertyValues = new ArrayList<>(); - String property = properties.get(i); - filteredProperties.add(property); - if (property.equals("location") || property.equals("feature") || property.equals("unitOfMeasurement")) { - continue; - } - Comparable propertyValue = EntityPropertiesSampleValue.getPropertyValueFor(relationEntityType, i); - samplePropertyValues.add(propertyValue); - - propertyValue = URLEncoder.encode(propertyValue.toString(), "UTF-8"); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20lt%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -2); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20le%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -1); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20eq%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 0); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20ne%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -3); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20ge%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 1); - - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20gt%20" + propertyValue); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 2); - } - } - } - - /** - * This method is checking the properties of the filtered collection - * - * @param response The response to be checked - * @param properties List of filtered properties - * @param values List of values for filtered properties - * @param operator The operator of the filter - */ - private void checkPropertiesForFilter(String response, List properties, List values, int operator) { - try { - JSONObject entities = new JSONObject(response); - JSONArray entityArray = entities.getJSONArray("value"); - for (int i = 0; i < entityArray.length(); i++) { - JSONObject entity = entityArray.getJSONObject(i); - for (int j = 0; j < properties.size(); j++) { - Object propertyValue = ""; - try { - propertyValue = entity.get(properties.get(j)); - } catch (JSONException e) { - Assert.fail("The entity does not have property " + properties.get(j) + " [Response] " + response.toString()); - } - if (propertyValue == null) { - Assert.fail("The entity has null value for property " + properties.get(j) + " [Response] " + response.toString()); - } - Comparable value = values.get(j); - if (value instanceof String && ((String) value).charAt(0) == '\'') { - String sValue = (String) value; - value = sValue.substring(1, sValue.length() - 1); - if (!(propertyValue instanceof String)) { - propertyValue = propertyValue.toString(); - } - } else if (value instanceof DateTime) { - propertyValue = ISODateTimeFormat.dateTimeParser().parseDateTime(propertyValue.toString()); - } - - int result = value.compareTo(propertyValue); - switch (operator) { - case -3: - Assert.assertTrue(result != 0, properties.get(j) + " should not be equal to " + value + ". But the property value is " + propertyValue + " [Response] " + response.toString()); - break; - case -2: - Assert.assertTrue(result > 0, properties.get(j) + " should be less than " + value + ". But the property value is " + propertyValue + " [Response] " + response.toString()); - break; - case -1: - Assert.assertTrue(result >= 0, properties.get(j) + " should be less than or equal to " + value + ". But the property value is " + propertyValue + " [Response] " + response.toString()); - break; - case 0: - Assert.assertTrue(result == 0, properties.get(j) + " should be equal to than " + value + ". But the property value is " + propertyValue + " [Response] " + response.toString()); - break; - case 1: - Assert.assertTrue(result <= 0, properties.get(j) + " should be greate than or equal to " + value + ". But the property value is " + propertyValue + " [Response] " + response.toString()); - break; - case 2: - Assert.assertTrue(result < 0, properties.get(j) + " should be greater than " + value + ". But the property value is " + propertyValue + " [Response] " + response.toString()); - break; - } - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Response] " + response.toString()); - } - } - - /** - * Create entities as a pre-process for testing query options. - */ - private void createEntities() { - String urlString = ""; - try { - //First Thing - String urlParameters = "{\n" - + " \"name\": \"thing 1\",\n" - + " \"description\": \"thing 1\",\n" - + " \"properties\": {\n" - + " \"reference\": \"first\"\n" - + " },\n" - + " \"Locations\": [\n" - + " {\n" - + " \"name\": \"location 1\",\n" - + " \"description\": \"location 1\",\n" - + " \"location\": {\n" - + " \"type\": \"Point\",\n" - + " \"coordinates\": [\n" - + " -117.05,\n" - + " 51.05\n" - + " ]\n" - + " },\n" - + " \"encodingType\": \"application/vnd.geo+json\"\n" - + " }\n" - + " ],\n" - + " \"Datastreams\": [\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Lumen\",\n" - + " \"symbol\": \"lm\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html/Lumen\"\n" - + " },\n" - + " \"name\": \"datastream 1\",\n" - + " \"description\": \"datastream 1\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html/LuminousFlux\",\n" - + " \"description\": \"observedProperty 1\"\n" - + " },\n" - + " \"Sensor\": {\n" - + " \"name\": \"sensor 1\",\n" - + " \"description\": \"sensor 1\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Light flux sensor\"\n" - + " }\n" - + " },\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Centigrade\",\n" - + " \"symbol\": \"C\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html/Lumen\"\n" - + " },\n" - + " \"name\": \"datastream 2\",\n" - + " \"description\": \"datastream 2\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Tempretaure\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html/Tempreture\",\n" - + " \"description\": \"observedProperty 2\"\n" - + " },\n" - + " \"Sensor\": {\n" - + " \"name\": \"sensor 2\",\n" - + " \"description\": \"sensor 2\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Tempreture sensor\"\n" - + " }\n" - + " }\n" - + " ]\n" - + "}"; - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, -1, null, null); - Map responseMap = HTTPMethods.doPost(urlString, urlParameters); - String response = responseMap.get("response").toString(); - thingId1 = Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")"))); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, EntityType.LOCATION, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - JSONArray array = new JSONObject(response).getJSONArray("value"); - locationId1 = array.getJSONObject(0).getLong(ControlInformation.ID); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, EntityType.DATASTREAM, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - datastreamId1 = array.getJSONObject(0).getLong(ControlInformation.ID); - datastreamId2 = array.getJSONObject(1).getLong(ControlInformation.ID); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, EntityType.SENSOR, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - sensorId1 = new JSONObject(response).getLong(ControlInformation.ID); - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, EntityType.OBSERVED_PROPERTY, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - observedPropertyId1 = new JSONObject(response).getLong(ControlInformation.ID); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId2, EntityType.SENSOR, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - sensorId2 = new JSONObject(response).getLong(ControlInformation.ID); - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, EntityType.OBSERVED_PROPERTY, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - observedPropertyId2 = new JSONObject(response).getLong(ControlInformation.ID); - - //Second Thing - urlParameters = "{\n" - + " \"name\": \"thing 2\",\n" - + " \"description\": \"thing 2\",\n" - + " \"properties\": {\n" - + " \"reference\": \"second\"\n" - + " },\n" - + " \"Locations\": [\n" - + " {\n" - + " \"name\": \"location 2\",\n" - + " \"description\": \"location 2\",\n" - + " \"location\": {\n" - + " \"type\": \"Point\",\n" - + " \"coordinates\": [\n" - + " -100.05,\n" - + " 50.05\n" - + " ]\n" - + " },\n" - + " \"encodingType\": \"application/vnd.geo+json\"\n" - + " }\n" - + " ],\n" - + " \"Datastreams\": [\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Lumen\",\n" - + " \"symbol\": \"lm\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html/Lumen\"\n" - + " },\n" - + " \"name\": \"datastream 3\",\n" - + " \"description\": \"datastream 3\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"ObservedProperty\": {\n" - + " \"name\": \"Second Luminous Flux\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html/LuminousFlux\",\n" - + " \"description\": \"observedProperty 3\"\n" - + " },\n" - + " \"Sensor\": {\n" - + " \"name\": \"sensor 3\",\n" - + " \"description\": \"sensor 3\",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Second Light flux sensor\"\n" - + " }\n" - + " },\n" - + " {\n" - + " \"unitOfMeasurement\": {\n" - + " \"name\": \"Centigrade\",\n" - + " \"symbol\": \"C\",\n" - + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html/Lumen\"\n" - + " },\n" - + " \"name\": \"datastream 2\",\n" - + " \"description\": \"datastream 2\",\n" - + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" - + " \"ObservedProperty\": {\n" - + " \"@iot.id\": " + observedPropertyId2 + "\n" - + " },\n" - + " \"Sensor\": {\n" - + " \"name\": \"sensor 4 \",\n" - + " \"description\": \"sensor 4 \",\n" - + " \"encodingType\": \"application/pdf\",\n" - + " \"metadata\": \"Second Tempreture sensor\"\n" - + " }\n" - + " }\n" - + " ]\n" - + "}"; - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, -1, null, null); - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - thingId2 = Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")"))); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, EntityType.LOCATION, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - locationId2 = array.getJSONObject(0).getLong(ControlInformation.ID); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, EntityType.DATASTREAM, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - datastreamId3 = array.getJSONObject(0).getLong(ControlInformation.ID); - datastreamId4 = array.getJSONObject(1).getLong(ControlInformation.ID); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId3, EntityType.SENSOR, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - sensorId3 = new JSONObject(response).getLong(ControlInformation.ID); - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId3, EntityType.OBSERVED_PROPERTY, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - observedPropertyId3 = new JSONObject(response).getLong(ControlInformation.ID); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId4, EntityType.SENSOR, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - sensorId4 = new JSONObject(response).getLong(ControlInformation.ID); - - //HistoricalLocations - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, null, null); - urlParameters = "{\"Locations\": [\n" - + " {\n" - + " \"@iot.id\": " + locationId2 + "\n" - + " }\n" - + " ]}"; - HTTPMethods.doPatch(urlString, urlParameters); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, null, null); - urlParameters = "{\"Locations\": [\n" - + " {\n" - + " \"@iot.id\": " + locationId1 + "\n" - + " }\n" - + " ]}"; - HTTPMethods.doPatch(urlString, urlParameters); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, EntityType.HISTORICAL_LOCATION, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - historicalLocationId1 = array.getJSONObject(0).getLong(ControlInformation.ID); - historicalLocationId2 = array.getJSONObject(1).getLong(ControlInformation.ID); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, EntityType.HISTORICAL_LOCATION, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - array = new JSONObject(response).getJSONArray("value"); - historicalLocationId3 = array.getJSONObject(0).getLong(ControlInformation.ID); - historicalLocationId4 = array.getJSONObject(1).getLong(ControlInformation.ID); - - //Observations - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, EntityType.OBSERVATION, null); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" - + " \"result\": 1 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId1 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-02T00:00:00Z\",\n" - + " \"result\": 2 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId2 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-03T00:00:00Z\",\n" - + " \"result\": 3 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId3 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId2, EntityType.OBSERVATION, null); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-04T00:00:00Z\",\n" - + " \"result\": 4 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId4 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-05T00:00:00Z\",\n" - + " \"result\": 5 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId5 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-06T00:00:00Z\",\n" - + " \"result\": 6 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId6 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId3, EntityType.OBSERVATION, null); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-07T00:00:00Z\",\n" - + " \"result\": 7 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId7 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-08T00:00:00Z\",\n" - + " \"result\": 8 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId8 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-09T00:00:00Z\",\n" - + " \"result\": 9 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId9 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId4, EntityType.OBSERVATION, null); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-10T00:00:00Z\",\n" - + " \"result\": 10 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId10 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-11T00:00:00Z\",\n" - + " \"result\": 11 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId11 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - urlParameters = "{\n" - + " \"phenomenonTime\": \"2015-03-12T00:00:00Z\",\n" - + " \"result\": 12 \n" - + " }"; - responseMap = HTTPMethods.doPost(urlString, urlParameters); - response = responseMap.get("response").toString(); - observationId12 = Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); - - //FeatureOfInterest - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, observationId1, EntityType.FEATURE_OF_INTEREST, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - featureOfInterestId1 = new JSONObject(response).getLong(ControlInformation.ID); - - urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, observationId7, EntityType.FEATURE_OF_INTEREST, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); - featureOfInterestId2 = new JSONObject(response).getLong(ControlInformation.ID); - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); - } - - } - - /** - * The helper method to check if a list contains a entity name string - * - * @param list The list to be searched - * @param entity The entity name to be checked - * @return True if the entity name exists is the list, false otherwise - */ - private boolean listContainsString(List list, String entity) { - for (String item : list) { - if (item.toLowerCase().contains(entity.toLowerCase())) { - if (entity.toLowerCase().equals("locations") && (item.toLowerCase().equals("historicallocations/thing") || item.toLowerCase().equals("historicallocations") || item.toLowerCase().equals("things/historicallocations") || item.toLowerCase().equals("thing/historicallocations"))) { - continue; - } - if (!entity.contains("/") && item.contains("/" + entity)) { - continue; - } - return true; - - } - } - return false; - } - - /** - * This method is run after all the tests of this class is run and clean the - * database. - */ - @AfterClass - public void deleteEverythings() { - deleteEntityType(EntityType.OBSERVATION); - deleteEntityType(EntityType.FEATURE_OF_INTEREST); - deleteEntityType(EntityType.DATASTREAM); - deleteEntityType(EntityType.SENSOR); - deleteEntityType(EntityType.OBSERVED_PROPERTY); - deleteEntityType(EntityType.HISTORICAL_LOCATION); - deleteEntityType(EntityType.LOCATION); - deleteEntityType(EntityType.THING); - } - - /** - * Delete all the entities of a certain entity type - * - * @param entityType The entity type from EntityType enum - */ - private void deleteEntityType(EntityType entityType) { - JSONArray array = null; - String urlString = ""; - do { - try { - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - Map responseMap = HTTPMethods.doGet(urlString); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - JSONObject result = new JSONObject(responseMap.get("response").toString()); - array = result.getJSONArray("value"); - for (int i = 0; i < array.length(); i++) { - long id = array.getJSONObject(i).getLong(ControlInformation.ID); - deleteEntity(entityType, id); - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + "[Request] " + urlString); - } - } while (array.length() > 0); - } - - /** - * This method created the URL string for the entity with specific id and - * then send DELETE request to that URl. - * - * @param entityType Entity type in from EntityType enum - * @param id The id of requested entity - */ - private void deleteEntity(EntityType entityType, long id) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); - Map responseMap = HTTPMethods.doDelete(urlString); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "DELETE does not work properly for " + entityType + " with id " + id + ". Returned with response code " + responseCode + ". [Request] " + urlString); - - responseMap = HTTPMethods.doGet(urlString); - responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 404, "Deleted entity was not actually deleted : " + entityType + "(" + id + "). [Request] " + urlString); - } + /** + * The root URL of the SensorThings service under the test + */ + public String rootUri;// ="http://localhost:8080/OGCSensorThings/v1.0"; + + private long thingId1, thingId2, datastreamId1, datastreamId2, datastreamId3, datastreamId4, locationId1, + locationId2, historicalLocationId1, historicalLocationId2, historicalLocationId3, historicalLocationId4, + sensorId1, sensorId2, sensorId3, sensorId4, observedPropertyId1, observedPropertyId2, observedPropertyId3, + observationId1, observationId2, observationId3, observationId4, observationId5, observationId6, + observationId7, observationId8, observationId9, observationId10, observationId11, observationId12, + featureOfInterestId1, featureOfInterestId2; + + /** + * This method will be run before starting the test for this conformance class. It + * creates a set of entities to start testing query options. + * @param testContext The test context to find out whether this class is requested to + * test or not + */ + @BeforeClass + public void obtainTestSubject(ITestContext testContext) { + Object obj = testContext.getSuite().getAttribute(SuiteAttribute.LEVEL.getName()); + if ((null != obj)) { + Integer level = Integer.class.cast(obj); + Assert.assertTrue(level.intValue() > 2, "Conformance level 3 will not be checked since ics = " + level); + } + + rootUri = testContext.getSuite().getAttribute(SuiteAttribute.TEST_SUBJECT.getName()).toString(); + rootUri = rootUri.trim(); + if (rootUri.lastIndexOf('/') == rootUri.length() - 1) { + rootUri = rootUri.substring(0, rootUri.length() - 1); + } + createEntities(); + } + + /** + * This method is testing $select query option. It tests $select for collection of + * entities with 1 level and 2 levels resource path. It also tests $select for one or + * more properties. + */ + @Test(description = "Check Query Evaluation Priority.", groups = "level-3") + public void readEntitiesWithSelectQO() { + checkSelectForEntityType(EntityType.THING); + checkSelectForEntityType(EntityType.LOCATION); + checkSelectForEntityType(EntityType.HISTORICAL_LOCATION); + checkSelectForEntityType(EntityType.DATASTREAM); + checkSelectForEntityType(EntityType.SENSOR); + checkSelectForEntityType(EntityType.OBSERVED_PROPERTY); + checkSelectForEntityType(EntityType.OBSERVATION); + checkSelectForEntityType(EntityType.FEATURE_OF_INTEREST); + checkSelectForEntityTypeRelations(EntityType.THING); + checkSelectForEntityTypeRelations(EntityType.LOCATION); + checkSelectForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); + checkSelectForEntityTypeRelations(EntityType.DATASTREAM); + checkSelectForEntityTypeRelations(EntityType.SENSOR); + checkSelectForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); + checkSelectForEntityTypeRelations(EntityType.OBSERVATION); + checkSelectForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); + + } + + /** + * This method is testing $expand query option. It tests $expand for collection of + * entities with 1 level and 2 levels resource path. It also tests $expand for one or + * more collections, and also tests multilevel $expand. + */ + @Test(description = "GET Entities with $expand", groups = "level-3") + public void readEntitiesWithExpandQO() { + checkExpandtForEntityType(EntityType.THING); + checkExpandtForEntityType(EntityType.LOCATION); + checkExpandtForEntityType(EntityType.HISTORICAL_LOCATION); + checkExpandtForEntityType(EntityType.DATASTREAM); + checkExpandtForEntityType(EntityType.SENSOR); + checkExpandtForEntityType(EntityType.OBSERVED_PROPERTY); + checkExpandtForEntityType(EntityType.OBSERVATION); + checkExpandtForEntityType(EntityType.FEATURE_OF_INTEREST); + checkExpandtForEntityTypeRelations(EntityType.THING); + checkExpandtForEntityTypeRelations(EntityType.LOCATION); + checkExpandtForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); + checkExpandtForEntityTypeRelations(EntityType.DATASTREAM); + checkExpandtForEntityTypeRelations(EntityType.SENSOR); + checkExpandtForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); + checkExpandtForEntityTypeRelations(EntityType.OBSERVATION); + checkExpandtForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); + checkExpandtForEntityTypeMultilevel(EntityType.THING); + checkExpandtForEntityTypeMultilevel(EntityType.LOCATION); + checkExpandtForEntityTypeMultilevel(EntityType.HISTORICAL_LOCATION); + checkExpandtForEntityTypeMultilevel(EntityType.DATASTREAM); + checkExpandtForEntityTypeMultilevel(EntityType.SENSOR); + checkExpandtForEntityTypeMultilevel(EntityType.OBSERVED_PROPERTY); + checkExpandtForEntityTypeMultilevel(EntityType.OBSERVATION); + checkExpandtForEntityTypeMultilevel(EntityType.FEATURE_OF_INTEREST); + checkExpandtForEntityTypeMultilevelRelations(EntityType.THING); + checkExpandtForEntityTypeMultilevelRelations(EntityType.LOCATION); + checkExpandtForEntityTypeMultilevelRelations(EntityType.HISTORICAL_LOCATION); + checkExpandtForEntityTypeMultilevelRelations(EntityType.DATASTREAM); + checkExpandtForEntityTypeMultilevelRelations(EntityType.SENSOR); + checkExpandtForEntityTypeMultilevelRelations(EntityType.OBSERVED_PROPERTY); + checkExpandtForEntityTypeMultilevelRelations(EntityType.OBSERVATION); + checkExpandtForEntityTypeMultilevelRelations(EntityType.FEATURE_OF_INTEREST); + + } + + /** + * This method is testing $top query option. It tests $top for collection of entities + * with 1 level and 2 levels resource path. It also tests {@literal @iot.nextLink} + * with regard to $top. + */ + @Test(description = "GET Entities with $top", groups = "level-3") + public void readEntitiesWithTopQO() { + checkTopForEntityType(EntityType.THING); + checkTopForEntityType(EntityType.LOCATION); + checkTopForEntityType(EntityType.HISTORICAL_LOCATION); + checkTopForEntityType(EntityType.DATASTREAM); + checkTopForEntityType(EntityType.SENSOR); + checkTopForEntityType(EntityType.OBSERVED_PROPERTY); + checkTopForEntityType(EntityType.OBSERVATION); + checkTopForEntityType(EntityType.FEATURE_OF_INTEREST); + checkTopForEntityTypeRelation(EntityType.THING); + checkTopForEntityTypeRelation(EntityType.LOCATION); + checkTopForEntityTypeRelation(EntityType.HISTORICAL_LOCATION); + checkTopForEntityTypeRelation(EntityType.DATASTREAM); + checkTopForEntityTypeRelation(EntityType.SENSOR); + checkTopForEntityTypeRelation(EntityType.OBSERVED_PROPERTY); + checkTopForEntityTypeRelation(EntityType.OBSERVATION); + checkTopForEntityTypeRelation(EntityType.FEATURE_OF_INTEREST); + + } + + /** + * This method is testing $skip query option. It tests $skip for collection of + * entities with 1 level and 2 levels resource path. It also tests + * {@literal @iot.nextLink} with regard to $skip. + */ + @Test(description = "GET Entities with $skip", groups = "level-3") + public void readEntitiesWithSkipQO() { + checkSkipForEntityType(EntityType.THING); + checkSkipForEntityType(EntityType.LOCATION); + checkSkipForEntityType(EntityType.HISTORICAL_LOCATION); + checkSkipForEntityType(EntityType.DATASTREAM); + checkSkipForEntityType(EntityType.SENSOR); + checkSkipForEntityType(EntityType.OBSERVED_PROPERTY); + checkSkipForEntityType(EntityType.OBSERVATION); + checkSkipForEntityType(EntityType.FEATURE_OF_INTEREST); + checkSkipForEntityTypeRelation(EntityType.THING); + checkSkipForEntityTypeRelation(EntityType.LOCATION); + checkSkipForEntityTypeRelation(EntityType.HISTORICAL_LOCATION); + checkSkipForEntityTypeRelation(EntityType.DATASTREAM); + checkSkipForEntityTypeRelation(EntityType.SENSOR); + checkSkipForEntityTypeRelation(EntityType.OBSERVED_PROPERTY); + checkSkipForEntityTypeRelation(EntityType.OBSERVATION); + checkSkipForEntityTypeRelation(EntityType.FEATURE_OF_INTEREST); + + } + + /** + * This method is testing $orderby query option. It tests $orderby for collection of + * entities with 1 level and 2 levels resource path. It also tests $orderby for one or + * more properties, and ascending and descending sorting. + */ + @Test(description = "GET Entities with $orderby", groups = "level-3") + public void readEntitiesWithOrderbyQO() { + checkOrderbyForEntityType(EntityType.THING); + checkOrderbyForEntityType(EntityType.LOCATION); + checkOrderbyForEntityType(EntityType.HISTORICAL_LOCATION); + checkOrderbyForEntityType(EntityType.DATASTREAM); + checkOrderbyForEntityType(EntityType.SENSOR); + checkOrderbyForEntityType(EntityType.OBSERVED_PROPERTY); + checkOrderbyForEntityType(EntityType.OBSERVATION); + checkOrderbyForEntityType(EntityType.FEATURE_OF_INTEREST); + checkOrderbyForEntityTypeRelations(EntityType.THING); + checkOrderbyForEntityTypeRelations(EntityType.LOCATION); + checkOrderbyForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); + checkOrderbyForEntityTypeRelations(EntityType.DATASTREAM); + checkOrderbyForEntityTypeRelations(EntityType.SENSOR); + checkOrderbyForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); + checkOrderbyForEntityTypeRelations(EntityType.OBSERVATION); + checkOrderbyForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); + } + + /** + * This method is testing $count query option. It tests $count for collection of + * entities with 1 level and 2 levels resource path. + */ + @Test(description = "GET Entities with $count", groups = "level-3") + public void readEntitiesWithCountQO() { + checkCountForEntityType(EntityType.THING); + checkCountForEntityType(EntityType.LOCATION); + checkCountForEntityType(EntityType.HISTORICAL_LOCATION); + checkCountForEntityType(EntityType.DATASTREAM); + checkCountForEntityType(EntityType.SENSOR); + checkCountForEntityType(EntityType.OBSERVED_PROPERTY); + checkCountForEntityType(EntityType.OBSERVATION); + checkCountForEntityType(EntityType.FEATURE_OF_INTEREST); + checkCountForEntityTypeRelations(EntityType.THING); + checkCountForEntityTypeRelations(EntityType.LOCATION); + checkCountForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); + checkCountForEntityTypeRelations(EntityType.DATASTREAM); + checkCountForEntityTypeRelations(EntityType.SENSOR); + checkCountForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); + checkCountForEntityTypeRelations(EntityType.OBSERVATION); + checkCountForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); + } + + /** + * This method is testing $filter query option for {@literal <, <=, =, >=, >} on + * properties. It tests $filter for collection of entities with 1 level and 2 levels + * resource path. + * @throws java.io.UnsupportedEncodingException Should not happen, UTF-8 should always + * be supported. + */ + @Test(description = "GET Entities with $filter", groups = "level-3") + public void readEntitiesWithFilterQO() throws UnsupportedEncodingException { + checkFilterForEntityType(EntityType.THING); + checkFilterForEntityType(EntityType.LOCATION); + checkFilterForEntityType(EntityType.HISTORICAL_LOCATION); + checkFilterForEntityType(EntityType.DATASTREAM); + checkFilterForEntityType(EntityType.SENSOR); + checkFilterForEntityType(EntityType.OBSERVED_PROPERTY); + checkFilterForEntityType(EntityType.OBSERVATION); + checkFilterForEntityType(EntityType.FEATURE_OF_INTEREST); + checkFilterForEntityTypeRelations(EntityType.THING); + checkFilterForEntityTypeRelations(EntityType.LOCATION); + checkFilterForEntityTypeRelations(EntityType.HISTORICAL_LOCATION); + checkFilterForEntityTypeRelations(EntityType.DATASTREAM); + checkFilterForEntityTypeRelations(EntityType.SENSOR); + checkFilterForEntityTypeRelations(EntityType.OBSERVED_PROPERTY); + checkFilterForEntityTypeRelations(EntityType.OBSERVATION); + checkFilterForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST); + } + + /** + * This method is testing the correct priority of the query options. It uses $count, + * $top, $skip, $orderby, and $filter togther and check the priority in result. + */ + @Test(description = "Check priotity of query options", groups = "level-3") + public void checkQueriesPriorityOrdering() { + String urlString = ""; + try { + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, -1, null, + "?$count=true&$top=1&$skip=2&$orderby=phenomenonTime%20asc&$filter=result%20gt%20'3'"); + Map responseMap = HTTPMethods.doGet(urlString); + Assert.assertEquals(Integer.parseInt(responseMap.get("response-code").toString()), 200, + "There is problem for GET Observations using multiple Query Options! HTTP status code: " + + responseMap.get("response-code") + ". [Request] " + urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + Assert.assertEquals(new JSONObject(response).getLong("@iot.count"), 6, + "The query order of execution is not correct. The expected count is 6, but the service returned " + + new JSONObject(response).getLong("@iot.count") + ". [Request] " + urlString); + Assert.assertEquals(array.length(), 1, "The query asked for top 1, but the service rerurned " + + array.length() + " entities. [Request] " + urlString); + Assert.assertEquals(array.getJSONObject(0).getString("result"), "6", + "The query order of execution is not correct. The expected Observation result is 6, but it is " + + array.getJSONObject(0).getString("result") + ". [Request] " + urlString); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + + /** + * This helper method is checking $orderby for 2 level of entities. + * @param entityType Entity type from EntityType enum list + */ + private void checkOrderbyForEntityTypeRelations(EntityType entityType) { + List relations = entityType.getRelations(); + String urlString = ""; + try { + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + if (array.length() == 0) { + return; + } + long id = array.getJSONObject(0).getLong(ControlInformation.ID); + + for (String relation : relations) { + if (!EntityType.isPlural(relation)) { + continue; + } + EntityType relationEntityType = EntityType.getForRelation(relation); + List properties = relationEntityType.getProperties(); + // single orderby + for (String property : properties) { + if (property.equals("unitOfMeasurement")) { + continue; + } + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$orderby=" + property); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + Assert.assertTrue(compareWithPrevious(i, array, property) <= 0, + "The ordering is not correct for EntityType " + entityType + " orderby property " + + property + ". [Request] " + urlString); + } + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$orderby=" + property + "%20asc"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + Assert.assertTrue(compareWithPrevious(i, array, property) <= 0, + "The ordering is not correct for EntityType " + entityType + " orderby asc property " + + property + ". [Request] " + urlString); + } + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$orderby=" + property + "%20desc"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + Assert.assertTrue(compareWithPrevious(i, array, property) >= 0, + "The ordering is not correct for EntityType " + entityType + " orderby desc property " + + property + ". [Request] " + urlString); + } + } + + // multiple orderby + List orderbyPropeties = new ArrayList<>(); + String orderby = "?$orderby="; + String orderbyAsc = "?$orderby="; + String orderbyDesc = "?$orderby="; + for (String property : properties) { + if (property.equals("unitOfMeasurement")) { + continue; + } + if (orderby.charAt(orderby.length() - 1) != '=') { + orderby += ","; + } + orderby += property; + orderbyPropeties.add(property); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, orderby); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + for (String orderProperty : orderbyPropeties) { + int compare = compareWithPrevious(i, array, orderProperty); + Assert.assertTrue(compare <= 0, "The ordering is not correct for EntityType " + entityType + + " orderby property " + orderProperty + ". [Request] " + urlString); + if (compare != 0) { + break; + } + } + } + if (orderbyAsc.charAt(orderbyAsc.length() - 1) != '=') { + orderbyAsc += ","; + } + orderbyAsc += property + "%20asc"; + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + orderbyAsc); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + for (String orderProperty : orderbyPropeties) { + int compare = compareWithPrevious(i, array, orderProperty); + Assert.assertTrue(compare <= 0, "The ordering is not correct for EntityType " + entityType + + " orderby asc property " + orderProperty + ". [Request] " + urlString); + if (compare != 0) { + break; + } + } + } + if (orderbyDesc.charAt(orderbyDesc.length() - 1) != '=') { + orderbyDesc += ","; + } + orderbyDesc += property + "%20desc"; + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + orderbyDesc); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + for (String orderProperty : orderbyPropeties) { + int compare = compareWithPrevious(i, array, orderProperty); + Assert.assertTrue(compare >= 0, "The ordering is not correct for EntityType " + entityType + + " orderby desc property " + orderProperty + ". [Request] " + urlString); + if (compare != 0) { + break; + } + } + } + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + + } + + /** + * This helper method is checking $orderby for a collection. + * @param entityType Entity type from EntityType enum list + */ + private void checkOrderbyForEntityType(EntityType entityType) { + List properties = entityType.getProperties(); + String urlString = ""; + try { + // single orderby + for (String property : properties) { + if (property.equals("unitOfMeasurement")) { + continue; + } + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$orderby=" + property); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + Assert.assertTrue(compareWithPrevious(i, array, property) <= 0, + "The default ordering is not correct for EntityType " + entityType + " orderby property " + + property + ". [Request] " + urlString); + } + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, + "?$orderby=" + property + "%20asc"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + Assert.assertTrue(compareWithPrevious(i, array, property) <= 0, + "The ascending ordering is not correct for EntityType " + entityType + + " orderby asc property " + property + ". [Request] " + urlString); + } + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, + "?$orderby=" + property + "%20desc"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + Assert.assertTrue(compareWithPrevious(i, array, property) >= 0, + "The descending ordering is not correct for EntityType " + entityType + + " orderby desc property " + property + ". [Request] " + urlString); + } + } + + // multiple orderby + List orderbyPropeties = new ArrayList<>(); + String orderby = "?$orderby="; + String orderbyAsc = "?$orderby="; + String orderbyDesc = "?$orderby="; + for (String property : properties) { + if (property.equals("unitOfMeasurement")) { + continue; + } + if (orderby.charAt(orderby.length() - 1) != '=') { + orderby += ","; + } + orderby += property; + orderbyPropeties.add(property); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, orderby); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + for (String orderProperty : orderbyPropeties) { + int compare = compareWithPrevious(i, array, orderProperty); + Assert.assertTrue(compare <= 0, "The ordering is not correct for EntityType " + entityType + + " orderby property " + orderProperty + ". [Request] " + urlString); + if (compare != 0) { + break; + } + } + } + if (orderbyAsc.charAt(orderbyAsc.length() - 1) != '=') { + orderbyAsc += ","; + } + orderbyAsc += property + "%20asc"; + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, orderbyAsc); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + for (String orderProperty : orderbyPropeties) { + int compare = compareWithPrevious(i, array, orderProperty); + Assert.assertTrue(compare <= 0, "The ordering is not correct for EntityType " + entityType + + " orderby asc property " + orderProperty + ". [Request] " + urlString); + if (compare != 0) { + break; + } + } + } + if (orderbyDesc.charAt(orderbyDesc.length() - 1) != '=') { + orderbyDesc += ","; + } + orderbyDesc += property + "%20desc"; + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, orderbyDesc); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + for (int i = 1; i < array.length(); i++) { + for (String orderProperty : orderbyPropeties) { + int compare = compareWithPrevious(i, array, orderProperty); + Assert.assertTrue(compare >= 0, "The ordering is not correct for EntityType " + entityType + + " orderby desc property " + orderProperty + ". [Request] " + urlString); + if (compare != 0) { + break; + } + } + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + + } + + private int compareWithPrevious(int idx, JSONArray array, String property) throws JSONException { + JSONObject jObj1 = array.getJSONObject(idx - 1); + JSONObject jObj2 = array.getJSONObject(idx); + Object o1 = jObj1.get(property); + Object o2 = jObj2.get(property); + return compareForOrder(o1, o2); + } + + private int compareForOrder(Object o1, Object o2) { + if (o1 instanceof Comparable && o2 instanceof Comparable) { + if (o1.getClass().isAssignableFrom(o2.getClass())) { + return ((Comparable) o1).compareTo(o2); + } + else if (o2.getClass().isAssignableFrom(o1.getClass())) { + return -((Comparable) o2).compareTo(o1); + } + } + return o1.toString().compareTo(o2.toString()); + } + + /** + * This helper method is checking $skip for s collection. + * @param entityType Entity type from EntityType enum list + */ + private void checkSkipForEntityType(EntityType entityType) { + String urlString = ""; + try { + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=1"); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response should not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (entityType) { + case THING: + case LOCATION: + case FEATURE_OF_INTEREST: + Assert.assertEquals(array.length(), 1, + "Query requested entities skipping 1, result should have contained 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case OBSERVED_PROPERTY: + Assert.assertEquals(array.length(), 2, + "Query requested entities skipping 1, result should have contained 2 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case HISTORICAL_LOCATION: + case SENSOR: + case DATASTREAM: + Assert.assertEquals(array.length(), 3, + "Query requested entities skipping 1, result should have contained 3 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case OBSERVATION: + Assert.assertEquals(array.length(), 11, + "Query requested entities skipping 1, result should have contained 11 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + default: + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=2"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response should not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (entityType) { + case THING: + case LOCATION: + case FEATURE_OF_INTEREST: + Assert.assertEquals(array.length(), 0, + "Query requested entities skipping 2, result should have contained 0 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case OBSERVED_PROPERTY: + Assert.assertEquals(array.length(), 1, + "Query requested entities skipping 2, result should have contained 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case HISTORICAL_LOCATION: + case SENSOR: + case DATASTREAM: + Assert.assertEquals(array.length(), 2, + "Query requested entities skipping 2, result should have contained 2 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case OBSERVATION: + Assert.assertEquals(array.length(), 10, + "Query requested entities skipping 2, result should have contained 10 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + default: + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=3"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response should not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (entityType) { + case THING: + case LOCATION: + case FEATURE_OF_INTEREST: + case OBSERVED_PROPERTY: + Assert.assertEquals(array.length(), 0, + "Query requested entities skipping 3, result should have contained 0 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case HISTORICAL_LOCATION: + case SENSOR: + case DATASTREAM: + Assert.assertEquals(array.length(), 1, + "Query requested entities skipping 3, result should have contained 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case OBSERVATION: + Assert.assertEquals(array.length(), 9, + "Query requested entities skipping 3, result should have contained 9 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + default: + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=4"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response should not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (entityType) { + case THING: + case LOCATION: + case FEATURE_OF_INTEREST: + case OBSERVED_PROPERTY: + case HISTORICAL_LOCATION: + case SENSOR: + case DATASTREAM: + Assert.assertEquals(array.length(), 0, + "Query requested entities skipping 4, result should have contained 0 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case OBSERVATION: + Assert.assertEquals(array.length(), 8, + "Query requested entities skipping 4, result should have contained 8 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + default: + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$skip=12"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response should not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + Assert.assertEquals(array.length(), 0, + "Query requested entities skipping 12, result should have contained 0 entity, but it contains " + + array.length() + ". [Request] " + urlString); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + + /** + * This helper method is checking $skip for 2 level of entities. + * @param entityType Entity type from EntityType enum list + */ + private void checkSkipForEntityTypeRelation(EntityType entityType) { + String urlString = ""; + try { + List relations = entityType.getRelations(); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + if (array.length() == 0) { + return; + } + long id = array.getJSONObject(0).getLong(ControlInformation.ID); + + for (String relation : relations) { + if (!EntityType.isPlural(relation)) { + continue; + } + EntityType relationEntityType = EntityType.getForRelation(relation); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$skip=1"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response should not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (entityType) { + case THING: + switch (relationEntityType) { + case LOCATION: + Assert.assertEquals(array.length(), 0, + "Query requested entities skipping 1, result should have contained 0 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case HISTORICAL_LOCATION: + Assert.assertEquals(array.length(), 1, + "Query requested entities skipping 1, result should have contained 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case DATASTREAM: + Assert.assertEquals(array.length(), 1, + "Query requested entities skipping 1, result should have contained 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + } + break; + case LOCATION: + switch (relationEntityType) { + case HISTORICAL_LOCATION: + Assert.assertEquals(array.length(), 1, + "Query requested entities skipping 1, result should have contained 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case THING: + Assert.assertEquals(array.length(), 0, + "Query requested entities skipping 1, result should have contained 0 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + } + break; + case FEATURE_OF_INTEREST: + Assert.assertEquals(array.length(), 5, + "Query requested entities skipping 1, result should have contained 5 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case OBSERVED_PROPERTY: + Assert.assertTrue(array.length() == 1 || array.length() == 0, + "Query requested entities skipping 1, result should have contained 0 or 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case HISTORICAL_LOCATION: + switch (relationEntityType) { + case LOCATION: + Assert.assertEquals(array.length(), 0, + "Query requested entities skipping 1, result should have contained 0 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + } + break; + case SENSOR: + Assert.assertEquals(array.length(), 0, + "Query requested entities skipping 1, result should have contained 0 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case DATASTREAM: + switch (relationEntityType) { + case OBSERVATION: + Assert.assertEquals(array.length(), 2, + "Query requested entities skipping 1, result should have contained 2 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + } + break; + default: + break; + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + "[Request] " + urlString); + } + } + + /** + * This helper method is checking $top for a collection. + * @param entityType Entity type from EntityType enum list + */ + private void checkTopForEntityType(EntityType entityType) { + String urlString = ""; + try { + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=1"); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + Assert.assertEquals(array.length(), 1, + "Query requested 1 entity but response contains " + array.length() + ". [Request] " + urlString); + try { + Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + Assert.fail("The response does not have nextLink" + "[Request] " + urlString); + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=2"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + Assert.assertEquals(array.length(), 2, + "Query requested 2 entities but response contains " + array.length() + ". [Request] " + urlString); + switch (entityType) { + case THING: + case LOCATION: + case FEATURE_OF_INTEREST: + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + default: + try { + Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + Assert.fail("The response does not have nextLink"); + } + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=3"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + switch (entityType) { + case THING: + Assert.assertEquals(array.length(), 2, + "Query requested 3 Things, there are only 2 Things, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case LOCATION: + Assert.assertEquals(array.length(), 2, + "Query requested 3 Locations, there are only 2 Locations, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case FEATURE_OF_INTEREST: + Assert.assertEquals(array.length(), 2, + "Query requested 3 FeaturesOfInterest, there are only 2 FeaturesOfInterest, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case OBSERVED_PROPERTY: + Assert.assertEquals(array.length(), 3, "Query requested 3 entities but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + default: + Assert.assertEquals(array.length(), 3, "Query requested 3 entities but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + Assert.fail("The response does not have nextLink" + " [Request] " + urlString); + } + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=4"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + switch (entityType) { + case THING: + Assert.assertEquals(array.length(), 2, + "Query requested 4 Things, there are only 2 Things, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case LOCATION: + Assert.assertEquals(array.length(), 2, + "Query requested 4 Locations, there are only 2 Locations, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case FEATURE_OF_INTEREST: + Assert.assertEquals(array.length(), 2, + "Query requested 4 FeaturesOfInterest, there are only 2 FeaturesOfInterest, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case OBSERVED_PROPERTY: + Assert.assertEquals(array.length(), 3, + "Query requested 4 ObservedProperties, there are only 3 ObservedProperties, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case SENSOR: + case HISTORICAL_LOCATION: + case DATASTREAM: + Assert.assertEquals(array.length(), 4, "Query requested 4 entities but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + default: + Assert.assertEquals(array.length(), 4, "Query requested 4 entities but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + Assert.fail("The response does not have nextLink. [Request] " + urlString); + } + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=5"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + switch (entityType) { + case THING: + Assert.assertEquals(array.length(), 2, + "Query requested 5 Things, there are only 2 Things, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case LOCATION: + Assert.assertEquals(array.length(), 2, + "Query requested 5 Locations, there are only 2 Locations, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case FEATURE_OF_INTEREST: + Assert.assertEquals(array.length(), 2, + "Query requested 5 FeaturesOfInterest, there are only 2 FeaturesOfInterest, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case OBSERVED_PROPERTY: + Assert.assertEquals(array.length(), 3, + "Query requested 5 ObservedProperties, there are only 3 ObservedProperties, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case SENSOR: + Assert.assertEquals(array.length(), 4, + "Query requested 5 Sensors, there are only 4 Sensors, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case HISTORICAL_LOCATION: + Assert.assertEquals(array.length(), 4, + "Query requested 5 HistoricalLocations, there are only 4 HistoricalLocations, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case DATASTREAM: + Assert.assertEquals(array.length(), 4, + "Query requested 5 Datastreams, there are only 4 Datastreams, but response contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + default: + Assert.assertEquals(array.length(), 5, + "Query requested 5 entities but response contains " + array.length()); + try { + Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + Assert.fail("The response does not have nextLink. [Request] " + urlString); + } + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=12"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$top=13"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (entityType) { + case THING: + Assert.assertEquals(array.length(), 2, + "Query requested 13 Things, there are only 2 Things, but response contains " + + array.length() + ". [Request] " + urlString); + break; + case LOCATION: + Assert.assertEquals(array.length(), 2, + "Query requested 13 Locations, there are only 2 Locations, but response contains " + + array.length() + ". [Request] " + urlString); + break; + case FEATURE_OF_INTEREST: + Assert.assertEquals(array.length(), 2, + "Query requested 13 FeaturesOfInterest, there are only 2 FeaturesOfInterest, but response contains " + + array.length() + ". [Request] " + urlString); + break; + case OBSERVED_PROPERTY: + Assert.assertEquals(array.length(), 3, + "Query requested 13 ObservedProperties, there are only 3 ObservedProperties, but response contains " + + array.length() + ". [Request] " + urlString); + break; + case SENSOR: + Assert.assertEquals(array.length(), 4, + "Query requested 13 Sensors, there are only 4 Sensors, but response contains " + + array.length() + ". [Request] " + urlString); + break; + case HISTORICAL_LOCATION: + Assert.assertEquals(array.length(), 4, + "Query requested 13 HistoricalLocations, there are only 4 HistoricalLocations, but response contains " + + array.length() + ". [Request] " + urlString); + break; + case DATASTREAM: + Assert.assertEquals(array.length(), 4, + "Query requested 13 Datastreams, there are only 4 Datastreams, but response contains " + + array.length() + ". [Request] " + urlString); + break; + case OBSERVATION: + Assert.assertEquals(array.length(), 12, + "Query requested 13 Observations, there are only 12 Observations, but response contains " + + array.length() + ". [Request] " + urlString); + break; + } + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + + /** + * This helper method is checking $top for 2 level of entities. + * @param entityType Entity type from EntityType enum list + */ + private void checkTopForEntityTypeRelation(EntityType entityType) { + String urlString = ""; + try { + List relations = entityType.getRelations(); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + if (array.length() == 0) { + return; + } + long id = array.getJSONObject(0).getLong(ControlInformation.ID); + + for (String relation : relations) { + if (!EntityType.isPlural(relation)) { + continue; + } + EntityType relationEntityType = EntityType.getForRelation(relation); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$top=3"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + switch (entityType) { + case THING: + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (relationEntityType) { + case LOCATION: + Assert.assertEquals(array.length(), 1, + "Query requested entities 3 entities, result should have contained 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case HISTORICAL_LOCATION: + Assert.assertEquals(array.length(), 2, + "Query requested entities 3 entities, result should have contained 2 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case DATASTREAM: + Assert.assertEquals(array.length(), 2, + "Query requested entities 3 entities, result should have contained 2 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + } + break; + case LOCATION: + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (relationEntityType) { + case HISTORICAL_LOCATION: + Assert.assertEquals(array.length(), 2, + "Query requested entities 3 entities, result should have contained 2 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case THING: + Assert.assertEquals(array.length(), 1, + "Query requested entities 3 entities, result should have contained 1 entity, but it contains" + + array.length() + ". [Request] " + urlString); + break; + } + break; + case FEATURE_OF_INTEREST: + Assert.assertEquals(array.length(), 3, + "Query requested entities 3 entities, result should have contained 3 entities, but it contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + Assert.fail("The response does not have nextLink. [Request] " + urlString); + } + break; + case OBSERVED_PROPERTY: + Assert.assertTrue(array.length() == 1 || array.length() == 2, + "Query requested entities 3 entities, result should have contained 1 or 2 entities, but it contains " + + array.length() + ". [Request] " + urlString); + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response should not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + break; + case HISTORICAL_LOCATION: + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response should not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (relationEntityType) { + case LOCATION: + Assert.assertEquals(array.length(), 1, + "Query requested entities 3 entities, result should have contained 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + } + break; + case SENSOR: + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response should not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + Assert.assertEquals(array.length(), 1, + "Query requested entities 3 entities, result should have contained 1 entity, but it contains " + + array.length() + ". [Request] " + urlString); + break; + case DATASTREAM: + try { + Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), + "The response does not have nextLink. [Request] " + urlString); + } + catch (JSONException e) { + } + switch (relationEntityType) { + case OBSERVATION: + Assert.assertEquals(array.length(), 3, + "Query requested entities 3 entities, result should have contained 3 entities, but it contains " + + array.length() + ". [Request] " + urlString); + break; + } + break; + default: + break; + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + + /** + * This helper method is checking $select for a collection. + * @param entityType Entity type from EntityType enum list + */ + private void checkSelectForEntityType(EntityType entityType) { + List selectedProperties; + List properties = entityType.getProperties(); + for (String property : properties) { + selectedProperties = new ArrayList<>(); + selectedProperties.add(property); + String response = getEntities(entityType, -1, null, selectedProperties, null); + checkEntitiesAllAspectsForSelectResponse(entityType, response, selectedProperties); + } + selectedProperties = new ArrayList<>(); + for (String property : properties) { + selectedProperties.add(property); + String response = getEntities(entityType, -1, null, selectedProperties, null); + checkEntitiesAllAspectsForSelectResponse(entityType, response, selectedProperties); + } + } + + /** + * This helper method is checking $select for 2 level of entities. + * @param entityType Entity type from EntityType enum list + */ + private void checkSelectForEntityTypeRelations(EntityType entityType) { + String urlString = ""; + try { + List parentRelations = entityType.getRelations(); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + if (array.length() == 0) { + return; + } + long id = array.getJSONObject(0).getLong(ControlInformation.ID); + + for (String parentRelation : parentRelations) { + EntityType relationEntityType = EntityType.getForRelation(parentRelation); + List selectedProperties; + List properties = relationEntityType.getProperties(); + for (String property : properties) { + selectedProperties = new ArrayList<>(); + selectedProperties.add(property); + response = getEntities(entityType, id, relationEntityType, selectedProperties, null); + checkEntitiesAllAspectsForSelectResponse(relationEntityType, response, selectedProperties); + } + selectedProperties = new ArrayList<>(); + for (String property : properties) { + selectedProperties.add(property); + response = getEntities(entityType, id, relationEntityType, selectedProperties, null); + checkEntitiesAllAspectsForSelectResponse(relationEntityType, response, selectedProperties); + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + + /** + * Send GET request with $select and $expand and check the response. + * @param entityType Entity type from EntityType enum list + * @param id The id of the entity + * @param relationEntityType The relation entity type from EntityType enum list + * @param selectedProperties The list of selected properties + * @param expandedRelations The list of expanded properties + * @return The response of GET request in string format + */ + private String getEntities(EntityType entityType, long id, EntityType relationEntityType, + List selectedProperties, List expandedRelations) { + String urlString = rootUri; + String selectString = ""; + if (selectedProperties != null && selectedProperties.size() > 0) { + selectString = "?$select="; + for (String select : selectedProperties) { + if (selectString.charAt(selectString.length() - 1) != '=') { + selectString += ','; + } + selectString += select; + } + } + String expandString = ""; + if (expandedRelations != null && expandedRelations.size() > 0) { + expandString = selectString.equals("") ? "?$expand=" : "&$expand="; + for (String expand : expandedRelations) { + if (expandString.charAt(expandString.length() - 1) != '=') { + expandString += ','; + } + expandString += expand; + } + } + if (entityType != null) { + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + selectString + expandString); + } + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, + "Error during getting entities: " + entityType.name() + ". [Request] " + urlString); + return response; + } + + /** + * This helper method is the start point for checking $select response + * @param entityType Entity type from EntityType enum list + * @param response The response to be checked + * @param selectedProperties The list of selected properties + */ + private void checkEntitiesAllAspectsForSelectResponse(EntityType entityType, String response, + List selectedProperties) { + checkEntitiesProperties(entityType, response, selectedProperties); + checkEntitiesRelations(entityType, response, selectedProperties, null); + } + + /** + * This method is checking properties for the $select response of a collection + * @param entityType Entity type from EntityType enum list + * @param response The response to be checked + * @param selectedProperties The list of selected properties + */ + private void checkEntitiesProperties(EntityType entityType, String response, List selectedProperties) { + try { + JSONObject jsonResponse = new JSONObject(response.toString()); + JSONArray entities = null; + if (response.contains("value")) { + entities = jsonResponse.getJSONArray("value"); + } + else { + entities = new JSONArray(); + entities.put(jsonResponse); + } + checkPropertiesForEntityArray(entityType, entities, selectedProperties); + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail( + "An Exception occurred during testing!:\n" + e.getMessage() + " [Response] " + response.toString()); + } + + } + + /** + * This method is checking properties for the $select array of entities + * @param entityType Entity type from EntityType enum list + * @param entities The JSONArray of entities to be checked + * @param selectedProperties The list of selected properties + */ + private void checkPropertiesForEntityArray(EntityType entityType, JSONArray entities, + List selectedProperties) { + int count = 0; + for (int i = 0; i < entities.length() && count < 2; i++) { + count++; + JSONObject entity = null; + try { + entity = entities.getJSONObject(i); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + checkEntityProperties(entityType, entity, selectedProperties); + } + } + + /** + * This method is checking properties for the $select response of a single entity + * @param entityType Entity type from EntityType enum list + * @param response The response to be checked + * @param selectedProperties The list of selected properties + */ + private void checkEntityProperties(EntityType entityType, Object response, List selectedProperties) { + try { + JSONObject entity = new JSONObject(response.toString()); + List properties = entityType.getProperties(); + for (String property : properties) { + if (selectedProperties.contains(property)) { + try { + Assert.assertNotNull(entity.get(property), + "Entity type \"" + entityType + "\" does not have selected property: \"" + property + + "\". [Response]: " + response.toString()); + } + catch (JSONException e) { + Assert.fail("Entity type \"" + entityType + "\" does not have selected property: \"" + property + + "\". [Response]: " + response.toString()); + } + } + else { + try { + Assert.assertNull(entity.get(property), + "Entity type \"" + entityType + "\" contains not-selected property: \"" + property + + "\". [Response]: " + response.toString()); + } + catch (JSONException e) { + } + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Response]: " + + response.toString()); + } + + } + + /** + * This method is checking the related entities of selected and/or expanded entities + * for a collection + * @param entityType Entity type from EntityType enum list + * @param response The response to be checked + * @param selectedProperties The list of selected properties + * @param expandedRelations The list of expanded properties + */ + private void checkEntitiesRelations(EntityType entityType, String response, List selectedProperties, + List expandedRelations) { + try { + JSONObject jsonResponse = new JSONObject(response.toString()); + JSONArray entities = null; + if (response.contains("value")) { + entities = jsonResponse.getJSONArray("value"); + } + else { + entities = new JSONArray(); + entities.put(jsonResponse); + } + int count = 0; + for (int i = 0; i < entities.length() && count < 2; i++) { + count++; + JSONObject entity = entities.getJSONObject(i); + checkEntityRelations(entityType, entity, selectedProperties, expandedRelations); + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Response]: " + + response.toString()); + } + + } + + /** + * This method is checking the related entities of selected and/or expanded entities + * for a single entity + * @param entityType Entity type from EntityType enum list + * @param response The response to be checked + * @param selectedProperties The list of selected properties + * @param expandedRelations The list of expanded properties + */ + private void checkEntityRelations(EntityType entityType, Object response, List selectedProperties, + List expandedRelations) { + try { + JSONObject entity = new JSONObject(response.toString()); + List relations = entityType.getRelations(); + for (String relation : relations) { + EntityType relationType = EntityType.getForRelation(relation); + if (selectedProperties == null || selectedProperties.contains(relation)) { + if (expandedRelations == null || !listContainsString(expandedRelations, relation)) { + try { + Assert.assertNotNull(entity.get(relation + ControlInformation.NAVIGATION_LINK), + "Entity type \"" + entityType + "\" does not have selected relation: \"" + relation + + "\". [Response]: " + response.toString()); + } + catch (JSONException e) { + Assert.fail("Entity type \"" + entityType + "\" does not have selected relation: \"" + + relation + "\". [Response]: " + response.toString()); + } + } + else { + Assert.assertNotNull(entity.get(relation), + "Entity type \"" + entityType + "\" does not have expanded relation Correctly: \"" + + relation + "\". [Response]: " + response.toString()); + JSONArray expandedEntityArray = null; + try { + if (!EntityType.isPlural(relation)) { + expandedEntityArray = new JSONArray(); + expandedEntityArray.put(entity.getJSONObject(relation)); + } + else { + expandedEntityArray = entity.getJSONArray(relation); + } + } + catch (JSONException e) { + Assert + .fail("Entity type \"" + entityType + "\" does not have expanded relation Correctly: \"" + + relation + "\". [Response]: " + response.toString()); + } + checkPropertiesForEntityArray(relationType, expandedEntityArray, + new ArrayList<>(relationType.getProperties())); + if (listContainsString(expandedRelations, "/")) { + List secondLevelRelations = relationType.getRelations(); + JSONObject expandedEntity = expandedEntityArray.getJSONObject(0); + for (String secondLeveleRelation : secondLevelRelations) { + EntityType secondLevelRelationType = EntityType.getForRelation(secondLeveleRelation); + if (listContainsString(expandedRelations, relation + "/" + secondLeveleRelation)) { + + expandedEntityArray = null; + try { + if (!EntityType.isPlural(secondLeveleRelation)) { + expandedEntityArray = new JSONArray(); + expandedEntityArray.put(expandedEntity.getJSONObject(secondLeveleRelation)); + } + else { + expandedEntityArray = expandedEntity.getJSONArray(secondLeveleRelation); + } + } + catch (JSONException e) { + Assert.fail("Entity type \"" + entityType + + "\" does not have expanded relation Correctly: \"" + relation + "/" + + secondLeveleRelation + "\". [Response]: " + response.toString()); + } + checkPropertiesForEntityArray(secondLevelRelationType, expandedEntityArray, + new ArrayList<>(secondLevelRelationType.getProperties())); + } + } + } + } + } + else { + try { + Assert.assertNull(entity.get(relation + ControlInformation.NAVIGATION_LINK), + "Entity type \"" + entityType + "\" contains not-selectd relation: \"" + relation + + "\". [Response]: " + response.toString()); + } + catch (JSONException e) { + } + try { + Assert.assertNull(entity.get(relation), + "Entity type \"" + entityType + "\" contains not-selectd relation: \"" + relation + + "\". [Response]: " + response.toString()); + } + catch (JSONException e) { + } + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Response]: " + + response.toString()); + } + } + + /** + * This helper method is checking $expand for a collection. + * @param entityType Entity type from EntityType enum list + */ + private void checkExpandtForEntityType(EntityType entityType) { + List expandedRelations; + List relations = entityType.getRelations(); + for (String relation : relations) { + expandedRelations = new ArrayList<>(); + expandedRelations.add(relation); + String response = getEntities(entityType, -1, null, null, expandedRelations); + checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); + } + expandedRelations = new ArrayList<>(); + for (String relation : relations) { + expandedRelations.add(relation); + String response = getEntities(entityType, -1, null, null, expandedRelations); + checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); + } + } + + /** + * This helper method is checking $expand for 2 level of entities. + * @param entityType Entity type from EntityType enum list + */ + private void checkExpandtForEntityTypeRelations(EntityType entityType) { + String urlString = ""; + try { + List parentRelations = entityType.getRelations(); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + if (array.length() == 0) { + return; + } + long id = array.getJSONObject(0).getLong(ControlInformation.ID); + + for (String parentRelation : parentRelations) { + EntityType relationEntityType = EntityType.getForRelation(parentRelation); + List expandedRelations; + List relations = relationEntityType.getRelations(); + for (String relation : relations) { + expandedRelations = new ArrayList<>(); + expandedRelations.add(relation); + response = getEntities(entityType, id, relationEntityType, null, expandedRelations); + checkEntitiesAllAspectsForExpandResponse(relationEntityType, response, expandedRelations); + } + expandedRelations = new ArrayList<>(); + for (String relation : relations) { + expandedRelations.add(relation); + response = getEntities(entityType, id, relationEntityType, null, expandedRelations); + checkEntitiesAllAspectsForExpandResponse(relationEntityType, response, expandedRelations); + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request]: " + urlString); + } + } + + /** + * This helper method is checking multilevel $expand for 2 level of entities. + * @param entityType Entity type from EntityType enum list + */ + private void checkExpandtForEntityTypeMultilevelRelations(EntityType entityType) { + String urlString = ""; + try { + List parentRelations = entityType.getRelations(); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + if (array.length() == 0) { + return; + } + long id = array.getJSONObject(0).getLong(ControlInformation.ID); + + for (String parentRelation : parentRelations) { + EntityType parentRelationType = EntityType.getForRelation(parentRelation); + List expandedRelations; + List relations = parentRelationType.getRelations(); + for (String relation : relations) { + EntityType relationType = EntityType.getForRelation(relation); + List secondLevelRelations = relationType.getRelations(); + + for (String secondLevelRelation : secondLevelRelations) { + expandedRelations = new ArrayList<>(); + expandedRelations.add(relation + "/" + secondLevelRelation); + response = getEntities(entityType, id, parentRelationType, null, expandedRelations); + checkEntitiesAllAspectsForExpandResponse(parentRelationType, response, expandedRelations); + } + } + expandedRelations = new ArrayList<>(); + for (String relation : relations) { + EntityType relationType = EntityType.getForRelation(relation); + List secondLevelRelations = relationType.getRelations(); + for (String secondLevelRelation : secondLevelRelations) { + expandedRelations.add(relation + "/" + secondLevelRelation); + response = getEntities(entityType, id, parentRelationType, null, expandedRelations); + checkEntitiesAllAspectsForExpandResponse(parentRelationType, response, expandedRelations); + } + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + + /** + * This helper method is checking multilevel $expand for a collection. + * @param entityType Entity type from EntityType enum list + */ + private void checkExpandtForEntityTypeMultilevel(EntityType entityType) { + List expandedRelations; + List relations = entityType.getRelations(); + for (String relation : relations) { + EntityType relationType = EntityType.getForRelation(relation); + List secondLevelRelations = relationType.getRelations(); + + for (String secondLevelRelation : secondLevelRelations) { + expandedRelations = new ArrayList<>(); + expandedRelations.add(relation + "/" + secondLevelRelation); + String response = getEntities(entityType, -1, null, null, expandedRelations); + checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); + } + } + expandedRelations = new ArrayList<>(); + for (String relation : relations) { + EntityType relationType = EntityType.getForRelation(relation); + List secondLevelRelations = relationType.getRelations(); + for (String secondLevelRelation : secondLevelRelations) { + expandedRelations.add(relation + "/" + secondLevelRelation); + String response = getEntities(entityType, -1, null, null, expandedRelations); + checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); + } + } + } + + /** + * This helper method is checking $count for a collection. + * @param entityType Entity type from EntityType enum list + */ + private void checkCountForEntityType(EntityType entityType) { + + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$count=true"); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + int count = -1; + try { + count = new JSONObject(response).getInt("@iot.count"); + } + catch (JSONException e) { + Assert.fail("the query asked for count but the response does not contain count, for getting collection: " + + entityType + " [Request] " + urlString); + } + switch (entityType) { + case THING: + case LOCATION: + case FEATURE_OF_INTEREST: + Assert.assertEquals(count, 2, + "The count for " + entityType + "should be 2, but it is " + count + " [Request] " + urlString); + break; + case OBSERVED_PROPERTY: + Assert.assertEquals(count, 3, + "The count for " + entityType + "should be 3, but it is " + count + " [Request] " + urlString); + break; + case HISTORICAL_LOCATION: + case SENSOR: + case DATASTREAM: + Assert.assertEquals(count, 4, + "The count for " + entityType + "should be 4, but it is " + count + " [Request] " + urlString); + break; + case OBSERVATION: + Assert.assertEquals(count, 12, + "The count for " + entityType + "should be 12, but it is " + count + " [Request] " + urlString); + break; + default: + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$count=false"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + try { + Assert.assertNull(new JSONObject(response).getInt("@iot.count"), + "the query asked for not count but the response does contain count, for getting collection: " + + entityType + ". [Request] " + urlString); + Assert.fail("the query asked for not count but the response does contain count, for getting collection: " + + entityType + ". [Request] " + urlString); + } + catch (JSONException e) { + } + } + + /** + * This helper method is checking $count for 2 level of entities. + * @param entityType Entity type from EntityType enum list + */ + private void checkCountForEntityTypeRelations(EntityType entityType) { + String urlString = ""; + try { + List relations = entityType.getRelations(); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + if (array.length() == 0) { + return; + } + long id = array.getJSONObject(0).getLong(ControlInformation.ID); + + for (String relation : relations) { + if (!EntityType.isPlural(relation)) { + return; + } + EntityType relationEntityType = EntityType.getForRelation(relation); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$count=true"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + int count = -1; + try { + count = new JSONObject(response).getInt("@iot.count"); + } + catch (JSONException e) { + Assert.fail( + "the query asked for count but the response does not contain count, for getting collection: " + + entityType + ". [Request] " + urlString); + } + switch (relationEntityType) { + case THING: + case LOCATION: + Assert.assertEquals(count, 1, "The count for " + entityType + "should be 1, but it is " + count + + " [Request] " + urlString); + break; + case HISTORICAL_LOCATION: + case DATASTREAM: + switch (entityType) { + case THING: + Assert.assertEquals(count, 2, "The count for " + entityType + "should be 2, but it is " + + count + " [Request] " + urlString); + break; + case SENSOR: + Assert.assertEquals(count, 1, "The count for " + entityType + "should be 1, but it is " + + count + " [Request] " + urlString); + break; + case OBSERVED_PROPERTY: + Assert.assertTrue(count == 2 || count == 1, "The count for " + entityType + + "should be 1 or 2, but it is " + count + " [Request] " + urlString); + break; + } + break; + case OBSERVATION: + if (entityType.equals(EntityType.DATASTREAM)) { + Assert.assertEquals(count, 3, "The count for " + entityType + "should be 3, but it is " + + count + " [Request] " + urlString); + } + else if (entityType.equals(EntityType.FEATURE_OF_INTEREST)) { + Assert.assertEquals(count, 6, "The count for " + entityType + "should be 6, but it is " + + count + " [Request] " + urlString); + } + break; + default: + break; + } + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$count=false"); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + try { + Assert.assertNull(new JSONObject(response).getInt("@iot.count"), + "the query asked for not count but the response does contain count, for getting collection: " + + entityType + ". [Request] " + urlString); + Assert.fail( + "the query asked for not count but the response does contain count, for getting collection: " + + entityType + ". [Request] " + urlString); + } + catch (JSONException e) { + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + } + + /** + * This helper method is the start point for checking $expand response. + * @param entityType Entity type from EntityType enum list + * @param response The response to be checked + * @param expandedRelations List of expanded relations + */ + private void checkEntitiesAllAspectsForExpandResponse(EntityType entityType, String response, + List expandedRelations) { + checkEntitiesRelations(entityType, response, null, expandedRelations); + } + + /** + * This helper method is checking $filter for a collection. + * @param entityType Entity type from EntityType enum list + * @throws java.io.UnsupportedEncodingException Should not happen, UTF-8 should always + * be supported. + */ + private void checkFilterForEntityType(EntityType entityType) throws UnsupportedEncodingException { + List properties = entityType.getProperties(); + List filteredProperties; + List samplePropertyValues; + for (int i = 0; i < properties.size(); i++) { + String property = properties.get(i); + filteredProperties = new ArrayList<>(); + samplePropertyValues = new ArrayList<>(); + filteredProperties.add(property); + if (property.equals("location") || property.equals("feature") || property.equals("unitOfMeasurement")) { + continue; + } + Comparable propertyValue = EntityPropertiesSampleValue.getPropertyValueFor(entityType, i); + samplePropertyValues.add(propertyValue); + + propertyValue = URLEncoder.encode(propertyValue.toString(), "UTF-8"); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, + "?$filter=" + property + "%20lt%20" + propertyValue); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -2); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, + "?$filter=" + property + "%20le%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -1); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, + "?$filter=" + property + "%20eq%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 0); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, + "?$filter=" + property + "%20ne%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -3); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, + "?$filter=" + property + "%20ge%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 1); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, + "?$filter=" + property + "%20gt%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 2); + } + } + + /** + * This helper method is checking $filter for 2 level of entities. + * @param entityType Entity type from EntityType enum list + * @throws java.io.UnsupportedEncodingException Should not happen, UTF-8 should always + * be supported. + */ + private void checkFilterForEntityTypeRelations(EntityType entityType) throws UnsupportedEncodingException { + List relations = entityType.getRelations(); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + JSONArray array = null; + try { + array = new JSONObject(response).getJSONArray("value"); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + if (array.length() == 0) { + return; + } + long id = 0; + try { + id = array.getJSONObject(0).getLong(ControlInformation.ID); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + + for (String relation : relations) { + if (!EntityType.isPlural(relation)) { + return; + } + EntityType relationEntityType = EntityType.getForRelation(relation); + + List properties = relationEntityType.getProperties(); + List filteredProperties; + List samplePropertyValues; + for (int i = 0; i < properties.size(); i++) { + filteredProperties = new ArrayList<>(); + samplePropertyValues = new ArrayList<>(); + String property = properties.get(i); + filteredProperties.add(property); + if (property.equals("location") || property.equals("feature") || property.equals("unitOfMeasurement")) { + continue; + } + Comparable propertyValue = EntityPropertiesSampleValue.getPropertyValueFor(relationEntityType, i); + samplePropertyValues.add(propertyValue); + + propertyValue = URLEncoder.encode(propertyValue.toString(), "UTF-8"); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$filter=" + property + "%20lt%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -2); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$filter=" + property + "%20le%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -1); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$filter=" + property + "%20eq%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 0); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$filter=" + property + "%20ne%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, -3); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$filter=" + property + "%20ge%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 1); + + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, + "?$filter=" + property + "%20gt%20" + propertyValue); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 2); + } + } + } + + /** + * This method is checking the properties of the filtered collection + * @param response The response to be checked + * @param properties List of filtered properties + * @param values List of values for filtered properties + * @param operator The operator of the filter + */ + private void checkPropertiesForFilter(String response, List properties, List values, + int operator) { + try { + JSONObject entities = new JSONObject(response); + JSONArray entityArray = entities.getJSONArray("value"); + for (int i = 0; i < entityArray.length(); i++) { + JSONObject entity = entityArray.getJSONObject(i); + for (int j = 0; j < properties.size(); j++) { + Object propertyValue = ""; + try { + propertyValue = entity.get(properties.get(j)); + } + catch (JSONException e) { + Assert.fail("The entity does not have property " + properties.get(j) + " [Response] " + + response.toString()); + } + if (propertyValue == null) { + Assert.fail("The entity has null value for property " + properties.get(j) + " [Response] " + + response.toString()); + } + Comparable value = values.get(j); + if (value instanceof String && ((String) value).charAt(0) == '\'') { + String sValue = (String) value; + value = sValue.substring(1, sValue.length() - 1); + if (!(propertyValue instanceof String)) { + propertyValue = propertyValue.toString(); + } + } + else if (value instanceof DateTime) { + propertyValue = ISODateTimeFormat.dateTimeParser().parseDateTime(propertyValue.toString()); + } + + int result = value.compareTo(propertyValue); + switch (operator) { + case -3: + Assert.assertTrue(result != 0, + properties.get(j) + " should not be equal to " + value + + ". But the property value is " + propertyValue + " [Response] " + + response.toString()); + break; + case -2: + Assert.assertTrue(result > 0, + properties.get(j) + " should be less than " + value + ". But the property value is " + + propertyValue + " [Response] " + response.toString()); + break; + case -1: + Assert.assertTrue(result >= 0, + properties.get(j) + " should be less than or equal to " + value + + ". But the property value is " + propertyValue + " [Response] " + + response.toString()); + break; + case 0: + Assert.assertTrue(result == 0, + properties.get(j) + " should be equal to than " + value + + ". But the property value is " + propertyValue + " [Response] " + + response.toString()); + break; + case 1: + Assert.assertTrue(result <= 0, + properties.get(j) + " should be greate than or equal to " + value + + ". But the property value is " + propertyValue + " [Response] " + + response.toString()); + break; + case 2: + Assert.assertTrue(result < 0, + properties.get(j) + " should be greater than " + value + + ". But the property value is " + propertyValue + " [Response] " + + response.toString()); + break; + } + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail( + "An Exception occurred during testing!:\n" + e.getMessage() + " [Response] " + response.toString()); + } + } + + /** + * Create entities as a pre-process for testing query options. + */ + private void createEntities() { + String urlString = ""; + try { + // First Thing + String urlParameters = "{\n" + " \"name\": \"thing 1\",\n" + " \"description\": \"thing 1\",\n" + + " \"properties\": {\n" + " \"reference\": \"first\"\n" + " },\n" + + " \"Locations\": [\n" + " {\n" + " \"name\": \"location 1\",\n" + + " \"description\": \"location 1\",\n" + " \"location\": {\n" + + " \"type\": \"Point\",\n" + " \"coordinates\": [\n" + + " -117.05,\n" + " 51.05\n" + " ]\n" + + " },\n" + " \"encodingType\": \"application/vnd.geo+json\"\n" + + " }\n" + " ],\n" + " \"Datastreams\": [\n" + " {\n" + + " \"unitOfMeasurement\": {\n" + " \"name\": \"Lumen\",\n" + + " \"symbol\": \"lm\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html/Lumen\"\n" + + " },\n" + " \"name\": \"datastream 1\",\n" + + " \"description\": \"datastream 1\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"ObservedProperty\": {\n" + " \"name\": \"Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html/LuminousFlux\",\n" + + " \"description\": \"observedProperty 1\"\n" + " },\n" + + " \"Sensor\": {\n" + " \"name\": \"sensor 1\",\n" + + " \"description\": \"sensor 1\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Light flux sensor\"\n" + " }\n" + " },\n" + + " {\n" + " \"unitOfMeasurement\": {\n" + + " \"name\": \"Centigrade\",\n" + " \"symbol\": \"C\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html/Lumen\"\n" + + " },\n" + " \"name\": \"datastream 2\",\n" + + " \"description\": \"datastream 2\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"ObservedProperty\": {\n" + " \"name\": \"Tempretaure\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html/Tempreture\",\n" + + " \"description\": \"observedProperty 2\"\n" + " },\n" + + " \"Sensor\": {\n" + " \"name\": \"sensor 2\",\n" + + " \"description\": \"sensor 2\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Tempreture sensor\"\n" + " }\n" + " }\n" + + " ]\n" + "}"; + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, -1, null, null); + Map responseMap = HTTPMethods.doPost(urlString, urlParameters); + String response = responseMap.get("response").toString(); + thingId1 = Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")"))); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, EntityType.LOCATION, + null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + JSONArray array = new JSONObject(response).getJSONArray("value"); + locationId1 = array.getJSONObject(0).getLong(ControlInformation.ID); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, EntityType.DATASTREAM, + null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + datastreamId1 = array.getJSONObject(0).getLong(ControlInformation.ID); + datastreamId2 = array.getJSONObject(1).getLong(ControlInformation.ID); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, + EntityType.SENSOR, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + sensorId1 = new JSONObject(response).getLong(ControlInformation.ID); + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, + EntityType.OBSERVED_PROPERTY, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + observedPropertyId1 = new JSONObject(response).getLong(ControlInformation.ID); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId2, + EntityType.SENSOR, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + sensorId2 = new JSONObject(response).getLong(ControlInformation.ID); + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, + EntityType.OBSERVED_PROPERTY, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + observedPropertyId2 = new JSONObject(response).getLong(ControlInformation.ID); + + // Second Thing + urlParameters = "{\n" + " \"name\": \"thing 2\",\n" + " \"description\": \"thing 2\",\n" + + " \"properties\": {\n" + " \"reference\": \"second\"\n" + " },\n" + + " \"Locations\": [\n" + " {\n" + " \"name\": \"location 2\",\n" + + " \"description\": \"location 2\",\n" + " \"location\": {\n" + + " \"type\": \"Point\",\n" + " \"coordinates\": [\n" + + " -100.05,\n" + " 50.05\n" + " ]\n" + + " },\n" + " \"encodingType\": \"application/vnd.geo+json\"\n" + + " }\n" + " ],\n" + " \"Datastreams\": [\n" + " {\n" + + " \"unitOfMeasurement\": {\n" + " \"name\": \"Lumen\",\n" + + " \"symbol\": \"lm\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html/Lumen\"\n" + + " },\n" + " \"name\": \"datastream 3\",\n" + + " \"description\": \"datastream 3\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"ObservedProperty\": {\n" + " \"name\": \"Second Luminous Flux\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html/LuminousFlux\",\n" + + " \"description\": \"observedProperty 3\"\n" + " },\n" + + " \"Sensor\": {\n" + " \"name\": \"sensor 3\",\n" + + " \"description\": \"sensor 3\",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Second Light flux sensor\"\n" + " }\n" + + " },\n" + " {\n" + " \"unitOfMeasurement\": {\n" + + " \"name\": \"Centigrade\",\n" + " \"symbol\": \"C\",\n" + + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/unit/Instances.html/Lumen\"\n" + + " },\n" + " \"name\": \"datastream 2\",\n" + + " \"description\": \"datastream 2\",\n" + + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + + " \"ObservedProperty\": {\n" + " \"@iot.id\": " + observedPropertyId2 + + "\n" + " },\n" + " \"Sensor\": {\n" + + " \"name\": \"sensor 4 \",\n" + " \"description\": \"sensor 4 \",\n" + + " \"encodingType\": \"application/pdf\",\n" + + " \"metadata\": \"Second Tempreture sensor\"\n" + " }\n" + " }\n" + + " ]\n" + "}"; + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, -1, null, null); + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + thingId2 = Long.parseLong(response.substring(response.indexOf("(") + 1, response.indexOf(")"))); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, EntityType.LOCATION, + null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + locationId2 = array.getJSONObject(0).getLong(ControlInformation.ID); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, EntityType.DATASTREAM, + null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + datastreamId3 = array.getJSONObject(0).getLong(ControlInformation.ID); + datastreamId4 = array.getJSONObject(1).getLong(ControlInformation.ID); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId3, + EntityType.SENSOR, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + sensorId3 = new JSONObject(response).getLong(ControlInformation.ID); + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId3, + EntityType.OBSERVED_PROPERTY, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + observedPropertyId3 = new JSONObject(response).getLong(ControlInformation.ID); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId4, + EntityType.SENSOR, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + sensorId4 = new JSONObject(response).getLong(ControlInformation.ID); + + // HistoricalLocations + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, null, null); + urlParameters = "{\"Locations\": [\n" + " {\n" + " \"@iot.id\": " + locationId2 + "\n" + " }\n" + + " ]}"; + HTTPMethods.doPatch(urlString, urlParameters); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, null, null); + urlParameters = "{\"Locations\": [\n" + " {\n" + " \"@iot.id\": " + locationId1 + "\n" + " }\n" + + " ]}"; + HTTPMethods.doPatch(urlString, urlParameters); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, + EntityType.HISTORICAL_LOCATION, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + historicalLocationId1 = array.getJSONObject(0).getLong(ControlInformation.ID); + historicalLocationId2 = array.getJSONObject(1).getLong(ControlInformation.ID); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, + EntityType.HISTORICAL_LOCATION, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + array = new JSONObject(response).getJSONArray("value"); + historicalLocationId3 = array.getJSONObject(0).getLong(ControlInformation.ID); + historicalLocationId4 = array.getJSONObject(1).getLong(ControlInformation.ID); + + // Observations + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, + EntityType.OBSERVATION, null); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" + " \"result\": 1 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId1 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-02T00:00:00Z\",\n" + " \"result\": 2 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId2 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-03T00:00:00Z\",\n" + " \"result\": 3 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId3 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId2, + EntityType.OBSERVATION, null); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-04T00:00:00Z\",\n" + " \"result\": 4 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId4 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-05T00:00:00Z\",\n" + " \"result\": 5 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId5 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-06T00:00:00Z\",\n" + " \"result\": 6 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId6 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId3, + EntityType.OBSERVATION, null); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-07T00:00:00Z\",\n" + " \"result\": 7 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId7 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-08T00:00:00Z\",\n" + " \"result\": 8 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId8 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-09T00:00:00Z\",\n" + " \"result\": 9 \n" + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId9 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId4, + EntityType.OBSERVATION, null); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-10T00:00:00Z\",\n" + " \"result\": 10 \n" + + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId10 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-11T00:00:00Z\",\n" + " \"result\": 11 \n" + + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId11 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-12T00:00:00Z\",\n" + " \"result\": 12 \n" + + " }"; + responseMap = HTTPMethods.doPost(urlString, urlParameters); + response = responseMap.get("response").toString(); + observationId12 = Long + .parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")"))); + + // FeatureOfInterest + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, observationId1, + EntityType.FEATURE_OF_INTEREST, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + featureOfInterestId1 = new JSONObject(response).getLong(ControlInformation.ID); + + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, observationId7, + EntityType.FEATURE_OF_INTEREST, null); + responseMap = HTTPMethods.doGet(urlString); + response = responseMap.get("response").toString(); + featureOfInterestId2 = new JSONObject(response).getLong(ControlInformation.ID); + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Request] " + urlString); + } + + } + + /** + * The helper method to check if a list contains a entity name string + * @param list The list to be searched + * @param entity The entity name to be checked + * @return True if the entity name exists is the list, false otherwise + */ + private boolean listContainsString(List list, String entity) { + for (String item : list) { + if (item.toLowerCase().contains(entity.toLowerCase())) { + if (entity.toLowerCase().equals("locations") && (item.toLowerCase().equals("historicallocations/thing") + || item.toLowerCase().equals("historicallocations") + || item.toLowerCase().equals("things/historicallocations") + || item.toLowerCase().equals("thing/historicallocations"))) { + continue; + } + if (!entity.contains("/") && item.contains("/" + entity)) { + continue; + } + return true; + + } + } + return false; + } + + /** + * This method is run after all the tests of this class is run and clean the database. + */ + @AfterClass + public void deleteEverythings() { + deleteEntityType(EntityType.OBSERVATION); + deleteEntityType(EntityType.FEATURE_OF_INTEREST); + deleteEntityType(EntityType.DATASTREAM); + deleteEntityType(EntityType.SENSOR); + deleteEntityType(EntityType.OBSERVED_PROPERTY); + deleteEntityType(EntityType.HISTORICAL_LOCATION); + deleteEntityType(EntityType.LOCATION); + deleteEntityType(EntityType.THING); + } + + /** + * Delete all the entities of a certain entity type + * @param entityType The entity type from EntityType enum + */ + private void deleteEntityType(EntityType entityType) { + JSONArray array = null; + String urlString = ""; + do { + try { + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + Map responseMap = HTTPMethods.doGet(urlString); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + JSONObject result = new JSONObject(responseMap.get("response").toString()); + array = result.getJSONArray("value"); + for (int i = 0; i < array.length(); i++) { + long id = array.getJSONObject(i).getLong(ControlInformation.ID); + deleteEntity(entityType, id); + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + "[Request] " + urlString); + } + } + while (array.length() > 0); + } + + /** + * This method created the URL string for the entity with specific id and then send + * DELETE request to that URl. + * @param entityType Entity type in from EntityType enum + * @param id The id of requested entity + */ + private void deleteEntity(EntityType entityType, long id) { + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); + Map responseMap = HTTPMethods.doDelete(urlString); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, "DELETE does not work properly for " + entityType + " with id " + id + + ". Returned with response code " + responseCode + ". [Request] " + urlString); + + responseMap = HTTPMethods.doGet(urlString); + responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 404, + "Deleted entity was not actually deleted : " + entityType + "(" + id + "). [Request] " + urlString); + } } diff --git a/src/main/java/org/opengis/cite/sta10/filteringExtension/package-info.java b/src/main/java/org/opengis/cite/sta10/filteringExtension/package-info.java index 60d399a..84fb6a7 100644 --- a/src/main/java/org/opengis/cite/sta10/filteringExtension/package-info.java +++ b/src/main/java/org/opengis/cite/sta10/filteringExtension/package-info.java @@ -1,8 +1,7 @@ /** * Conformance Level 3 includes extension. * - * @see HTML5 + * @see HTML5 * - Conformance classes */ package org.opengis.cite.sta10.filteringExtension; diff --git a/src/main/java/org/opengis/cite/sta10/package-info.java b/src/main/java/org/opengis/cite/sta10/package-info.java index d276082..e0811dc 100644 --- a/src/main/java/org/opengis/cite/sta10/package-info.java +++ b/src/main/java/org/opengis/cite/sta10/package-info.java @@ -1,8 +1,9 @@ /** - * The root package includes supporting classes of general utility such as the - * main controller, listeners, and reporters. + * The root package includes supporting classes of general utility such as the main + * controller, listeners, and reporters. *

- *

Subsidiary packages correspond to distinct test groups such as conformance - * classes.

+ *

+ * Subsidiary packages correspond to distinct test groups such as conformance classes. + *

*/ package org.opengis.cite.sta10; \ No newline at end of file diff --git a/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java b/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java index 9b0aaaa..5b65165 100644 --- a/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java +++ b/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java @@ -23,651 +23,697 @@ */ public class Capability1Tests { - /** - * The root URL of the SensorThings service under the test - */ - public String rootUri;//="http://localhost:8080/OGCSensorThings/v1.0"; - /** - * The variable that defines to which recursive level the resource path - * should be tested - */ - private final int resourcePathLevel = 4; - - /** - * This method will be run before starting the test for this conformance - * class. - * - * @param testContext The test context to find out whether this class is - * requested to test or not - */ - @BeforeClass - public void obtainTestSubject(ITestContext testContext) { - Object obj = testContext.getSuite().getAttribute( - SuiteAttribute.LEVEL.getName()); - if ((null != obj)) { - Integer level = Integer.class.cast(obj); - Assert.assertTrue(level.intValue() > 0, - "Conformance level 1 will not be checked since ics = " + level); - } - - rootUri = testContext.getSuite().getAttribute( - SuiteAttribute.TEST_SUBJECT.getName()).toString(); - rootUri = rootUri.trim(); - if (rootUri.lastIndexOf('/') == rootUri.length() - 1) { - rootUri = rootUri.substring(0, rootUri.length() - 1); - } - - } - - /** - * This method is testing GET entities. It should return 200. Then the - * response entities are tested for control information, mandatory - * properties, and mandatory related entities. - */ - @Test(description = "GET Entities", groups = "level-1") - public void readEntitiesAndCheckResponse() { - String response = getEntities(EntityType.THING); - checkEntitiesAllAspectsForResponse(EntityType.THING, response); - response = getEntities(EntityType.LOCATION); - checkEntitiesAllAspectsForResponse(EntityType.LOCATION, response); - response = getEntities(EntityType.HISTORICAL_LOCATION); - checkEntitiesAllAspectsForResponse(EntityType.HISTORICAL_LOCATION, response); - response = getEntities(EntityType.DATASTREAM); - checkEntitiesAllAspectsForResponse(EntityType.DATASTREAM, response); - response = getEntities(EntityType.SENSOR); - checkEntitiesAllAspectsForResponse(EntityType.SENSOR, response); - response = getEntities(EntityType.OBSERVATION); - checkEntitiesAllAspectsForResponse(EntityType.OBSERVATION, response); - response = getEntities(EntityType.OBSERVED_PROPERTY); - checkEntitiesAllAspectsForResponse(EntityType.OBSERVED_PROPERTY, response); - response = getEntities(EntityType.FEATURE_OF_INTEREST); - checkEntitiesAllAspectsForResponse(EntityType.FEATURE_OF_INTEREST, response); - } - - /** - * This method is testing GET when requesting a nonexistent entity. The - * response should be 404. - */ - @Test(description = "GET nonexistent Entity", groups = "level-1") - public void readNonexistentEntity() { - readNonexistentEntityWithEntityType(EntityType.THING); - readNonexistentEntityWithEntityType(EntityType.LOCATION); - readNonexistentEntityWithEntityType(EntityType.HISTORICAL_LOCATION); - readNonexistentEntityWithEntityType(EntityType.DATASTREAM); - readNonexistentEntityWithEntityType(EntityType.SENSOR); - readNonexistentEntityWithEntityType(EntityType.OBSERVATION); - readNonexistentEntityWithEntityType(EntityType.OBSERVED_PROPERTY); - readNonexistentEntityWithEntityType(EntityType.FEATURE_OF_INTEREST); - } - - /** - * This method is testing GET for a specific entity with its id. It checks - * the control information, mandatory properties and mandatory related - * entities for the response entity. - */ - @Test(description = "GET Specific Entity", groups = "level-1") - public void readEntityAndCheckResponse() { - String response = readEntityWithEntityType(EntityType.THING); - checkEntityAllAspectsForResponse(EntityType.THING, response); - response = readEntityWithEntityType(EntityType.LOCATION); - checkEntityAllAspectsForResponse(EntityType.LOCATION, response); - response = readEntityWithEntityType(EntityType.HISTORICAL_LOCATION); - checkEntityAllAspectsForResponse(EntityType.HISTORICAL_LOCATION, response); - response = readEntityWithEntityType(EntityType.DATASTREAM); - checkEntityAllAspectsForResponse(EntityType.DATASTREAM, response); - response = readEntityWithEntityType(EntityType.SENSOR); - checkEntityAllAspectsForResponse(EntityType.SENSOR, response); - response = readEntityWithEntityType(EntityType.OBSERVATION); - checkEntityAllAspectsForResponse(EntityType.OBSERVATION, response); - response = readEntityWithEntityType(EntityType.OBSERVED_PROPERTY); - checkEntityAllAspectsForResponse(EntityType.OBSERVED_PROPERTY, response); - response = readEntityWithEntityType(EntityType.FEATURE_OF_INTEREST); - checkEntityAllAspectsForResponse(EntityType.FEATURE_OF_INTEREST, response); - } - - /** - * This method is testing GET for a property of an entity. - */ - @Test(description = "GET Property of an Entity", groups = "level-1") - public void readPropertyOfEntityAndCheckResponse() { - readPropertyOfEntityWithEntityType(EntityType.THING); - readPropertyOfEntityWithEntityType(EntityType.LOCATION); - readPropertyOfEntityWithEntityType(EntityType.HISTORICAL_LOCATION); - readPropertyOfEntityWithEntityType(EntityType.DATASTREAM); - readPropertyOfEntityWithEntityType(EntityType.OBSERVED_PROPERTY); - readPropertyOfEntityWithEntityType(EntityType.SENSOR); - readPropertyOfEntityWithEntityType(EntityType.OBSERVATION); - readPropertyOfEntityWithEntityType(EntityType.FEATURE_OF_INTEREST); - } - - /** - * This helper method is testing property and property/$value for single - * entity of a given entity type - * - * @param entityType Entity type from EntityType enum list - */ - private void readPropertyOfEntityWithEntityType(EntityType entityType) { - try { - String response = getEntities(entityType); - Long id = new JSONObject(response).getJSONArray("value").getJSONObject(0).getLong(ControlInformation.ID); - for (String property : entityType.getProperties()) { - checkGetPropertyOfEntity(entityType, id, property); - checkGetPropertyValueOfEntity(entityType, id, property); - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This helper method sending GET request for requesting a property and - * check the response is 200. - * - * @param entityType Entity type from EntityType enum list - * @param id The id of the entity - * @param property The property to get requested - */ - private void checkGetPropertyOfEntity(EntityType entityType, long id, String property) { - try { - Map responseMap = getEntity(entityType, id, property); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "Reading property \"" + property + "\" of the existing " + entityType.name() + " with id " + id + " failed."); - String response = responseMap.get("response").toString(); - JSONObject entity = null; - entity = new JSONObject(response.toString()); - try { - Assert.assertNotNull(entity.get(property), "Reading property \"" + property + "\"of \"" + entityType + "\" fails."); - } catch (JSONException e) { - Assert.fail("Reading property \"" + property + "\"of \"" + entityType + "\" fails."); - } - Assert.assertEquals(entity.length(), 1, "The response for getting property " + property + " of a " + entityType + " returns more properties!"); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This helper method sending GET request for requesting a property $value - * and check the response is 200. - * - * @param entityType Entity type from EntityType enum list - * @param id The id of the entity - * @param property The property to get requested - */ - private void checkGetPropertyValueOfEntity(EntityType entityType, long id, String property) { - Map responseMap = getEntity(entityType, id, property + "/$value"); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "Reading property value of \"" + property + "\" of the exitixting " + entityType.name() + " with id " + id + " failed."); - String response = responseMap.get("response").toString(); - if (!property.equals("location") && !property.equals("feature") && !property.equals("unitOfMeasurement")) { - Assert.assertEquals(response.indexOf("{"), -1, "Reading property value of \"" + property + "\"of \"" + entityType + "\" fails."); - } else { - Assert.assertEquals(response.indexOf("{"), 0, "Reading property value of \"" + property + "\"of \"" + entityType + "\" fails."); - } - } - - /** - * This method is testing the resource paths based on specification to the - * specified level. - */ - @Test(description = "Check Resource Path", groups = "level-1") - public void checkResourcePaths() { - readRelatedEntityOfEntityWithEntityType(EntityType.THING); - readRelatedEntityOfEntityWithEntityType(EntityType.LOCATION); - readRelatedEntityOfEntityWithEntityType(EntityType.HISTORICAL_LOCATION); - readRelatedEntityOfEntityWithEntityType(EntityType.DATASTREAM); - readRelatedEntityOfEntityWithEntityType(EntityType.OBSERVED_PROPERTY); - readRelatedEntityOfEntityWithEntityType(EntityType.SENSOR); - readRelatedEntityOfEntityWithEntityType(EntityType.OBSERVATION); - readRelatedEntityOfEntityWithEntityType(EntityType.FEATURE_OF_INTEREST); - } - - /** - * This helper method is the start point for testing resource path. It adds - * the entity type to be tested to resource path chain and call the other - * method to test the chain. - * - * @param entityType Entity type from EntityType enum list - */ - private void readRelatedEntityOfEntityWithEntityType(EntityType entityType) { - List entityTypes = new ArrayList<>(); - List ids = new ArrayList<>(); - entityTypes.add(entityType.plural); - readRelatedEntity(entityTypes, ids); - } - - /** - * This helper method is testing the chain to the specified level. It - * confirms that the response is 200. - * - * @param entityTypes List of entity type from EntityType enum list for the - * chain - * @param ids List of ids for teh chain - */ - private void readRelatedEntity(List entityTypes, List ids) { - if (entityTypes.size() > resourcePathLevel) { - return; - } - try { - String headName = entityTypes.get(entityTypes.size() - 1); - EntityType headEntity = EntityType.getForRelation(headName); - boolean isPlural = EntityType.isPlural(headName); - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityTypes, ids, null); - Map responseMap = HTTPMethods.doGet(urlString); - Assert.assertEquals(responseMap.get("response-code"), 200, "Reading relation of the entity from request: " + urlString + " failed with type: " + entityTypes.toString()); - String response = responseMap.get("response").toString(); - Long id; - if (isPlural) { - JSONArray jsonValueArray = new JSONObject(response).getJSONArray("value"); - if(jsonValueArray == null || jsonValueArray.length() == 0){ - Assert.fail("Expecting a non-empty list for request: " + urlString); - } - id = jsonValueArray.getJSONObject(0).getLong(ControlInformation.ID); - } else { - id = new JSONObject(response).getLong(ControlInformation.ID); - } - - //check $ref - urlString = ServiceURLBuilder.buildURLString(rootUri, entityTypes, ids, "$ref"); - responseMap = HTTPMethods.doGet(urlString); - Assert.assertEquals(responseMap.get("response-code"), 200, "Reading relation of the entity from request: " + urlString + " failed with type: " + entityTypes.toString()); - response = responseMap.get("response").toString(); - checkAssociationLinks(response, entityTypes, ids); - - if (entityTypes.size() == resourcePathLevel) { - return; - } - if (EntityType.isPlural(headName)) { - ids.add(id); - } else { - ids.add(null); - } - for (String relation : headEntity.getRelations()) { - entityTypes.add(relation); - readRelatedEntity(entityTypes, ids); - entityTypes.remove(entityTypes.size() - 1); - } - ids.remove(ids.size() - 1); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - - } - - /** - * This method is checking the response for the request of Association Link. - * It confirms that it contains a list of selfLinks. - * - * @param response The response for GET association link request - * @param entityTypes List of entity type from EntityType enum list for the - * chain - * @param ids List of ids for teh chain - */ - private void checkAssociationLinks(String response, List entityTypes, List ids) { - - try { - if (EntityType.isPlural(entityTypes.get(entityTypes.size() - 1))) { - Assert.assertTrue(response.contains("value"), "The GET entities Association Link response does not match SensorThings API : missing \"value\" in response.: " + entityTypes.toString() + ids.toString()); - JSONArray value = new JSONObject(response).getJSONArray("value"); - int count = 0; - for (int i = 0; i < value.length() && count < 2; i++) { - count++; - JSONObject obj = value.getJSONObject(i); - try { - Assert.assertNotNull(obj.get(ControlInformation.SELF_LINK), "The Association Link does not contain self-links.: " + entityTypes.toString() + ids.toString()); - } catch (JSONException e) { - Assert.fail("The Association Link does not contain self-links.: " + entityTypes.toString() + ids.toString()); - } - Assert.assertEquals(obj.length(), 1, "The Association Link contains properties other than self-link.: " + entityTypes.toString() + ids.toString()); - } - } else { - JSONObject obj = new JSONObject(response); - try { - Assert.assertNotNull(obj.get(ControlInformation.SELF_LINK), "The Association Link does not contain self-links.: " + entityTypes.toString() + ids.toString()); - } catch (JSONException e) { - Assert.fail("The Association Link does not contain self-links.: " + entityTypes.toString() + ids.toString()); - } - Assert.assertEquals(obj.length(), 1, "The Association Link contains properties other than self-link.: " + entityTypes.toString() + ids.toString()); - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This method is reading a specific entity and return it as a string. - * - * @param entityType Entity type from EntityType enum list - * @return The entity response as a string - */ - private String readEntityWithEntityType(EntityType entityType) { - try { - String response = getEntities(entityType); - Long id = new JSONObject(response.toString()).getJSONArray("value").getJSONObject(0).getLong(ControlInformation.ID); - Map responseMap = getEntity(entityType, id, null); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "Reading existing " + entityType.name() + " with id " + id + " failed."); - response = responseMap.get("response").toString(); - return response; - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - return null; - } - } - - /** - * This method is check the response of sending a GET request to - * m=nonexistent entity is 404. - * - * @param entityType Entity type from EntityType enum list - */ - private void readNonexistentEntityWithEntityType(EntityType entityType) { - long id = Long.MAX_VALUE; - int responseCode = Integer.parseInt(getEntity(entityType, id, null).get("response-code").toString()); - Assert.assertEquals(responseCode, 404, "Reading non-existing " + entityType.name() + " with id " + id + " failed."); - } - - /** - * This method is testing the root URL of the service under test. It - * basically checks the first page. - */ - @Test(description = "Check Service Root UI", groups = "level-1") - public void checkServiceRootUri() { - try { - String response = getEntities(null); - JSONObject jsonResponse = new JSONObject(response.toString()); - JSONArray entities = jsonResponse.getJSONArray("value"); - Map addedLinks = new HashMap<>(); - addedLinks.put("Things", false); - addedLinks.put("Locations", false); - addedLinks.put("HistoricalLocations", false); - addedLinks.put("Datastreams", false); - addedLinks.put("Sensors", false); - addedLinks.put("Observations", false); - addedLinks.put("ObservedProperties", false); - addedLinks.put("FeaturesOfInterest", false); - for (int i = 0; i < entities.length(); i++) { - JSONObject entity = entities.getJSONObject(i); - try { - Assert.assertNotNull(entity.get("name")); - Assert.assertNotNull(entity.get("url")); - } catch (JSONException e) { - Assert.fail("Service root URI does not have proper JSON keys: name and value."); - } - String name = entity.getString("name"); - String nameUrl = entity.getString("url"); - switch (name) { - case "Things": - Assert.assertEquals(nameUrl, rootUri + "/Things", "The URL for Things in Service Root URI is not compliant to SensorThings API."); - addedLinks.remove("Things"); - addedLinks.put(name, true); - break; - case "Locations": - Assert.assertEquals(nameUrl, rootUri + "/Locations", "The URL for Locations in Service Root URI is not compliant to SensorThings API."); - addedLinks.remove("Locations"); - addedLinks.put(name, true); - break; - case "HistoricalLocations": - Assert.assertEquals(nameUrl, rootUri + "/HistoricalLocations", "The URL for HistoricalLocations in Service Root URI is not compliant to SensorThings API."); - addedLinks.remove("HistoricalLocations"); - addedLinks.put(name, true); - break; - case "Datastreams": - Assert.assertEquals(nameUrl, rootUri + "/Datastreams", "The URL for Datastreams in Service Root URI is not compliant to SensorThings API."); - addedLinks.remove("Datastreams"); - addedLinks.put(name, true); - break; - case "Sensors": - Assert.assertEquals(nameUrl, rootUri + "/Sensors", "The URL for Sensors in Service Root URI is not compliant to SensorThings API."); - addedLinks.remove("Sensors"); - addedLinks.put(name, true); - break; - case "Observations": - Assert.assertEquals(nameUrl, rootUri + "/Observations", "The URL for Observations in Service Root URI is not compliant to SensorThings API."); - addedLinks.remove("Observations"); - addedLinks.put(name, true); - break; - case "ObservedProperties": - Assert.assertEquals(nameUrl, rootUri + "/ObservedProperties", "The URL for ObservedProperties in Service Root URI is not compliant to SensorThings API."); - addedLinks.remove("ObservedProperties"); - addedLinks.put(name, true); - break; - case "FeaturesOfInterest": - Assert.assertEquals(nameUrl, rootUri + "/FeaturesOfInterest", "The URL for FeaturesOfInterest in Service Root URI is not compliant to SensorThings API."); - addedLinks.remove("FeaturesOfInterest"); - addedLinks.put(name, true); - break; - case "MultiDatastreams": - Assert.assertEquals(nameUrl, rootUri + "/MultiDatastreams", "The URL for MultiDatastreams in Service Root URI is not compliant to SensorThings API."); - break; - default: - Assert.fail("There is a component in Service Root URI response that is not in SensorThings API : " + name); - break; - } - } - for (String key : addedLinks.keySet()) { - Assert.assertTrue(addedLinks.get(key), "The Service Root URI response does not contain " + key); - } - - } catch (Exception e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This helper method is sending GET request to a collection of entities. - * - * @param entityType Entity type from EntityType enum list - * @return The response of GET request in string format. - */ - private String getEntities(EntityType entityType) { - String urlString = rootUri; - if (entityType != null) { - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); - } - Map responseMap = HTTPMethods.doGet(urlString); - String response = responseMap.get("response").toString(); - int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); - Assert.assertEquals(responseCode, 200, "Error during getting entities: " + ((entityType != null) ? entityType.name() : "root URI")); - if (entityType != null) { - Assert.assertTrue(response.indexOf("value") != -1, "The GET entities response for entity type \"" + entityType + "\" does not match SensorThings API : missing \"value\" in response."); - } else { // GET Service Base URI - Assert.assertTrue(response.indexOf("value") != -1, "The GET entities response for service root URI does not match SensorThings API : missing \"value\" in response."); - } - return response.toString(); - } - - /** - * This helper method is sending Get request to a specific entity - * - * @param entityType Entity type from EntityType enum list - * @param id The if of the specific entity - * @param property The requested property of the entity - * @return The response-code and response (body) of the request in Map - * format. - */ - private Map getEntity(EntityType entityType, long id, String property) { - if (id == -1) { - return null; - } - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, property); - return HTTPMethods.doGet(urlString); - } - - /** - * This helper method is the start point for checking the response for a - * collection in all aspects. - * - * @param entityType Entity type from EntityType enum list - * @param response The response of the GET request to be checked - */ - private void checkEntitiesAllAspectsForResponse(EntityType entityType, String response) { - checkEntitiesControlInformation(response); - checkEntitiesProperties(entityType, response); - checkEntitiesRelations(entityType, response); - } - - /** - * This helper method is the start point for checking the response for a - * specific entity in all aspects. - * - * @param entityType Entity type from EntityType enum list - * @param response The response of the GET request to be checked - */ - private void checkEntityAllAspectsForResponse(EntityType entityType, String response) { - checkEntityControlInformation(response); - checkEntityProperties(entityType, response); - checkEntityRelations(entityType, response); - } - - /** - * This helper method is checking the control information of the response - * for a collection - * - * @param response The response of the GET request to be checked - */ - private void checkEntitiesControlInformation(String response) { - try { - JSONObject jsonResponse = new JSONObject(response.toString()); - JSONArray entities = jsonResponse.getJSONArray("value"); - int count = 0; - for (int i = 0; i < entities.length() && count < 2; i++) { - count++; - JSONObject entity = entities.getJSONObject(i); - checkEntityControlInformation(entity); - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This helper method is checking the control information of the response - * for a specific entity - * - * @param response The response of the GET request to be checked - */ - private void checkEntityControlInformation(Object response) { - try { - JSONObject entity = new JSONObject(response.toString()); - try { - Assert.assertNotNull(entity.get(ControlInformation.ID), "The entity does not have mandatory control information : " + ControlInformation.ID); - } catch (JSONException e) { - Assert.fail("The entity does not have mandatory control information : " + ControlInformation.ID); - } - try { - Assert.assertNotNull(entity.get(ControlInformation.SELF_LINK), "The entity does not have mandatory control information : " + ControlInformation.SELF_LINK); - } catch (JSONException e) { - Assert.fail("The entity does not have mandatory control information : " + ControlInformation.SELF_LINK); - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - - /** - * This helper method is checking the mandatory properties of the response - * for a collection - * - * @param entityType Entity type from EntityType enum list - * @param response The response of the GET request to be checked - */ - private void checkEntitiesProperties(EntityType entityType, String response) { - try { - JSONObject jsonResponse = new JSONObject(response.toString()); - JSONArray entities = jsonResponse.getJSONArray("value"); - int count = 0; - for (int i = 0; i < entities.length() && count < 2; i++) { - count++; - JSONObject entity = entities.getJSONObject(i); - checkEntityProperties(entityType, entity); - } - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - - } - - /** - * This helper method is checking the mandatory properties of the response - * for a specific entity - * - * @param entityType Entity type from EntityType enum list - * @param response The response of the GET request to be checked - */ - private void checkEntityProperties(EntityType entityType, Object response) { - try { - JSONObject entity = new JSONObject(response.toString()); - for (String property : entityType.getProperties()) { - try { - Assert.assertNotNull(entity.get(property), "Entity type \"" + entityType + "\" does not have mandatory property: \"" + property + "\"."); - } catch (JSONException e) { - Assert.fail("Entity type \"" + entityType + "\" does not have mandatory property: \"" + property + "\"."); - } - } - - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - - } - - /** - * This helper method is checking the mandatory relations of the response - * for a collection - * - * @param entityType Entity type from EntityType enum list - * @param response The response of the GET request to be checked - */ - private void checkEntitiesRelations(EntityType entityType, String response) { - try { - JSONObject jsonResponse = new JSONObject(response); - JSONArray entities = jsonResponse.getJSONArray("value"); - int count = 0; - for (int i = 0; i < entities.length() && count < 2; i++) { - count++; - JSONObject entity = entities.getJSONObject(i); - checkEntityRelations(entityType, entity); - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Response] " + response.toString()); - } - - } - - /** - * This helper method is checking the mandatory relations of the response - * for a specific entity - * - * @param entityType Entity type from EntityType enum list - * @param response The response of the GET request to be checked - */ - private void checkEntityRelations(EntityType entityType, Object response) { - try { - JSONObject entity = new JSONObject(response.toString()); - for (String relation : entityType.getRelations()) { - try { - Assert.assertNotNull(entity.get(relation + ControlInformation.NAVIGATION_LINK), "Entity type \"" + entityType + "\" does not have mandatory relation: \"" + relation + "\". [Response] " + response.toString()); - } catch (JSONException e) { - Assert.fail("Entity type \"" + entityType + "\" does not have mandatory relation: \"" + relation + "\". [Response] " + response.toString()); - } - } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage() + " [Response] " + response.toString()); - } - } + /** + * The root URL of the SensorThings service under the test + */ + public String rootUri;// ="http://localhost:8080/OGCSensorThings/v1.0"; + + /** + * The variable that defines to which recursive level the resource path should be + * tested + */ + private final int resourcePathLevel = 4; + + /** + * This method will be run before starting the test for this conformance class. + * @param testContext The test context to find out whether this class is requested to + * test or not + */ + @BeforeClass + public void obtainTestSubject(ITestContext testContext) { + Object obj = testContext.getSuite().getAttribute(SuiteAttribute.LEVEL.getName()); + if ((null != obj)) { + Integer level = Integer.class.cast(obj); + Assert.assertTrue(level.intValue() > 0, "Conformance level 1 will not be checked since ics = " + level); + } + + rootUri = testContext.getSuite().getAttribute(SuiteAttribute.TEST_SUBJECT.getName()).toString(); + rootUri = rootUri.trim(); + if (rootUri.lastIndexOf('/') == rootUri.length() - 1) { + rootUri = rootUri.substring(0, rootUri.length() - 1); + } + + } + + /** + * This method is testing GET entities. It should return 200. Then the response + * entities are tested for control information, mandatory properties, and mandatory + * related entities. + */ + @Test(description = "GET Entities", groups = "level-1") + public void readEntitiesAndCheckResponse() { + String response = getEntities(EntityType.THING); + checkEntitiesAllAspectsForResponse(EntityType.THING, response); + response = getEntities(EntityType.LOCATION); + checkEntitiesAllAspectsForResponse(EntityType.LOCATION, response); + response = getEntities(EntityType.HISTORICAL_LOCATION); + checkEntitiesAllAspectsForResponse(EntityType.HISTORICAL_LOCATION, response); + response = getEntities(EntityType.DATASTREAM); + checkEntitiesAllAspectsForResponse(EntityType.DATASTREAM, response); + response = getEntities(EntityType.SENSOR); + checkEntitiesAllAspectsForResponse(EntityType.SENSOR, response); + response = getEntities(EntityType.OBSERVATION); + checkEntitiesAllAspectsForResponse(EntityType.OBSERVATION, response); + response = getEntities(EntityType.OBSERVED_PROPERTY); + checkEntitiesAllAspectsForResponse(EntityType.OBSERVED_PROPERTY, response); + response = getEntities(EntityType.FEATURE_OF_INTEREST); + checkEntitiesAllAspectsForResponse(EntityType.FEATURE_OF_INTEREST, response); + } + + /** + * This method is testing GET when requesting a nonexistent entity. The response + * should be 404. + */ + @Test(description = "GET nonexistent Entity", groups = "level-1") + public void readNonexistentEntity() { + readNonexistentEntityWithEntityType(EntityType.THING); + readNonexistentEntityWithEntityType(EntityType.LOCATION); + readNonexistentEntityWithEntityType(EntityType.HISTORICAL_LOCATION); + readNonexistentEntityWithEntityType(EntityType.DATASTREAM); + readNonexistentEntityWithEntityType(EntityType.SENSOR); + readNonexistentEntityWithEntityType(EntityType.OBSERVATION); + readNonexistentEntityWithEntityType(EntityType.OBSERVED_PROPERTY); + readNonexistentEntityWithEntityType(EntityType.FEATURE_OF_INTEREST); + } + + /** + * This method is testing GET for a specific entity with its id. It checks the control + * information, mandatory properties and mandatory related entities for the response + * entity. + */ + @Test(description = "GET Specific Entity", groups = "level-1") + public void readEntityAndCheckResponse() { + String response = readEntityWithEntityType(EntityType.THING); + checkEntityAllAspectsForResponse(EntityType.THING, response); + response = readEntityWithEntityType(EntityType.LOCATION); + checkEntityAllAspectsForResponse(EntityType.LOCATION, response); + response = readEntityWithEntityType(EntityType.HISTORICAL_LOCATION); + checkEntityAllAspectsForResponse(EntityType.HISTORICAL_LOCATION, response); + response = readEntityWithEntityType(EntityType.DATASTREAM); + checkEntityAllAspectsForResponse(EntityType.DATASTREAM, response); + response = readEntityWithEntityType(EntityType.SENSOR); + checkEntityAllAspectsForResponse(EntityType.SENSOR, response); + response = readEntityWithEntityType(EntityType.OBSERVATION); + checkEntityAllAspectsForResponse(EntityType.OBSERVATION, response); + response = readEntityWithEntityType(EntityType.OBSERVED_PROPERTY); + checkEntityAllAspectsForResponse(EntityType.OBSERVED_PROPERTY, response); + response = readEntityWithEntityType(EntityType.FEATURE_OF_INTEREST); + checkEntityAllAspectsForResponse(EntityType.FEATURE_OF_INTEREST, response); + } + + /** + * This method is testing GET for a property of an entity. + */ + @Test(description = "GET Property of an Entity", groups = "level-1") + public void readPropertyOfEntityAndCheckResponse() { + readPropertyOfEntityWithEntityType(EntityType.THING); + readPropertyOfEntityWithEntityType(EntityType.LOCATION); + readPropertyOfEntityWithEntityType(EntityType.HISTORICAL_LOCATION); + readPropertyOfEntityWithEntityType(EntityType.DATASTREAM); + readPropertyOfEntityWithEntityType(EntityType.OBSERVED_PROPERTY); + readPropertyOfEntityWithEntityType(EntityType.SENSOR); + readPropertyOfEntityWithEntityType(EntityType.OBSERVATION); + readPropertyOfEntityWithEntityType(EntityType.FEATURE_OF_INTEREST); + } + + /** + * This helper method is testing property and property/$value for single entity of a + * given entity type + * @param entityType Entity type from EntityType enum list + */ + private void readPropertyOfEntityWithEntityType(EntityType entityType) { + try { + String response = getEntities(entityType); + Long id = new JSONObject(response).getJSONArray("value").getJSONObject(0).getLong(ControlInformation.ID); + for (String property : entityType.getProperties()) { + checkGetPropertyOfEntity(entityType, id, property); + checkGetPropertyValueOfEntity(entityType, id, property); + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This helper method sending GET request for requesting a property and check the + * response is 200. + * @param entityType Entity type from EntityType enum list + * @param id The id of the entity + * @param property The property to get requested + */ + private void checkGetPropertyOfEntity(EntityType entityType, long id, String property) { + try { + Map responseMap = getEntity(entityType, id, property); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, "Reading property \"" + property + "\" of the existing " + + entityType.name() + " with id " + id + " failed."); + String response = responseMap.get("response").toString(); + JSONObject entity = null; + entity = new JSONObject(response.toString()); + try { + Assert.assertNotNull(entity.get(property), + "Reading property \"" + property + "\"of \"" + entityType + "\" fails."); + } + catch (JSONException e) { + Assert.fail("Reading property \"" + property + "\"of \"" + entityType + "\" fails."); + } + Assert.assertEquals(entity.length(), 1, "The response for getting property " + property + " of a " + + entityType + " returns more properties!"); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This helper method sending GET request for requesting a property $value and check + * the response is 200. + * @param entityType Entity type from EntityType enum list + * @param id The id of the entity + * @param property The property to get requested + */ + private void checkGetPropertyValueOfEntity(EntityType entityType, long id, String property) { + Map responseMap = getEntity(entityType, id, property + "/$value"); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, "Reading property value of \"" + property + "\" of the exitixting " + + entityType.name() + " with id " + id + " failed."); + String response = responseMap.get("response").toString(); + if (!property.equals("location") && !property.equals("feature") && !property.equals("unitOfMeasurement")) { + Assert.assertEquals(response.indexOf("{"), -1, + "Reading property value of \"" + property + "\"of \"" + entityType + "\" fails."); + } + else { + Assert.assertEquals(response.indexOf("{"), 0, + "Reading property value of \"" + property + "\"of \"" + entityType + "\" fails."); + } + } + + /** + * This method is testing the resource paths based on specification to the specified + * level. + */ + @Test(description = "Check Resource Path", groups = "level-1") + public void checkResourcePaths() { + readRelatedEntityOfEntityWithEntityType(EntityType.THING); + readRelatedEntityOfEntityWithEntityType(EntityType.LOCATION); + readRelatedEntityOfEntityWithEntityType(EntityType.HISTORICAL_LOCATION); + readRelatedEntityOfEntityWithEntityType(EntityType.DATASTREAM); + readRelatedEntityOfEntityWithEntityType(EntityType.OBSERVED_PROPERTY); + readRelatedEntityOfEntityWithEntityType(EntityType.SENSOR); + readRelatedEntityOfEntityWithEntityType(EntityType.OBSERVATION); + readRelatedEntityOfEntityWithEntityType(EntityType.FEATURE_OF_INTEREST); + } + + /** + * This helper method is the start point for testing resource path. It adds the entity + * type to be tested to resource path chain and call the other method to test the + * chain. + * @param entityType Entity type from EntityType enum list + */ + private void readRelatedEntityOfEntityWithEntityType(EntityType entityType) { + List entityTypes = new ArrayList<>(); + List ids = new ArrayList<>(); + entityTypes.add(entityType.plural); + readRelatedEntity(entityTypes, ids); + } + + /** + * This helper method is testing the chain to the specified level. It confirms that + * the response is 200. + * @param entityTypes List of entity type from EntityType enum list for the chain + * @param ids List of ids for teh chain + */ + private void readRelatedEntity(List entityTypes, List ids) { + if (entityTypes.size() > resourcePathLevel) { + return; + } + try { + String headName = entityTypes.get(entityTypes.size() - 1); + EntityType headEntity = EntityType.getForRelation(headName); + boolean isPlural = EntityType.isPlural(headName); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityTypes, ids, null); + Map responseMap = HTTPMethods.doGet(urlString); + Assert.assertEquals(responseMap.get("response-code"), 200, "Reading relation of the entity from request: " + + urlString + " failed with type: " + entityTypes.toString()); + String response = responseMap.get("response").toString(); + Long id; + if (isPlural) { + JSONArray jsonValueArray = new JSONObject(response).getJSONArray("value"); + if (jsonValueArray == null || jsonValueArray.length() == 0) { + Assert.fail("Expecting a non-empty list for request: " + urlString); + } + id = jsonValueArray.getJSONObject(0).getLong(ControlInformation.ID); + } + else { + id = new JSONObject(response).getLong(ControlInformation.ID); + } + + // check $ref + urlString = ServiceURLBuilder.buildURLString(rootUri, entityTypes, ids, "$ref"); + responseMap = HTTPMethods.doGet(urlString); + Assert.assertEquals(responseMap.get("response-code"), 200, "Reading relation of the entity from request: " + + urlString + " failed with type: " + entityTypes.toString()); + response = responseMap.get("response").toString(); + checkAssociationLinks(response, entityTypes, ids); + + if (entityTypes.size() == resourcePathLevel) { + return; + } + if (EntityType.isPlural(headName)) { + ids.add(id); + } + else { + ids.add(null); + } + for (String relation : headEntity.getRelations()) { + entityTypes.add(relation); + readRelatedEntity(entityTypes, ids); + entityTypes.remove(entityTypes.size() - 1); + } + ids.remove(ids.size() - 1); + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + + } + + /** + * This method is checking the response for the request of Association Link. It + * confirms that it contains a list of selfLinks. + * @param response The response for GET association link request + * @param entityTypes List of entity type from EntityType enum list for the chain + * @param ids List of ids for teh chain + */ + private void checkAssociationLinks(String response, List entityTypes, List ids) { + + try { + if (EntityType.isPlural(entityTypes.get(entityTypes.size() - 1))) { + Assert.assertTrue(response.contains("value"), + "The GET entities Association Link response does not match SensorThings API : missing \"value\" in response.: " + + entityTypes.toString() + ids.toString()); + JSONArray value = new JSONObject(response).getJSONArray("value"); + int count = 0; + for (int i = 0; i < value.length() && count < 2; i++) { + count++; + JSONObject obj = value.getJSONObject(i); + try { + Assert.assertNotNull(obj.get(ControlInformation.SELF_LINK), + "The Association Link does not contain self-links.: " + entityTypes.toString() + + ids.toString()); + } + catch (JSONException e) { + Assert.fail("The Association Link does not contain self-links.: " + entityTypes.toString() + + ids.toString()); + } + Assert.assertEquals(obj.length(), 1, + "The Association Link contains properties other than self-link.: " + entityTypes.toString() + + ids.toString()); + } + } + else { + JSONObject obj = new JSONObject(response); + try { + Assert.assertNotNull(obj.get(ControlInformation.SELF_LINK), + "The Association Link does not contain self-links.: " + entityTypes.toString() + + ids.toString()); + } + catch (JSONException e) { + Assert.fail("The Association Link does not contain self-links.: " + entityTypes.toString() + + ids.toString()); + } + Assert.assertEquals(obj.length(), 1, "The Association Link contains properties other than self-link.: " + + entityTypes.toString() + ids.toString()); + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This method is reading a specific entity and return it as a string. + * @param entityType Entity type from EntityType enum list + * @return The entity response as a string + */ + private String readEntityWithEntityType(EntityType entityType) { + try { + String response = getEntities(entityType); + Long id = new JSONObject(response.toString()).getJSONArray("value") + .getJSONObject(0) + .getLong(ControlInformation.ID); + Map responseMap = getEntity(entityType, id, null); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, + "Reading existing " + entityType.name() + " with id " + id + " failed."); + response = responseMap.get("response").toString(); + return response; + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + return null; + } + } + + /** + * This method is check the response of sending a GET request to m=nonexistent entity + * is 404. + * @param entityType Entity type from EntityType enum list + */ + private void readNonexistentEntityWithEntityType(EntityType entityType) { + long id = Long.MAX_VALUE; + int responseCode = Integer.parseInt(getEntity(entityType, id, null).get("response-code").toString()); + Assert.assertEquals(responseCode, 404, + "Reading non-existing " + entityType.name() + " with id " + id + " failed."); + } + + /** + * This method is testing the root URL of the service under test. It basically checks + * the first page. + */ + @Test(description = "Check Service Root UI", groups = "level-1") + public void checkServiceRootUri() { + try { + String response = getEntities(null); + JSONObject jsonResponse = new JSONObject(response.toString()); + JSONArray entities = jsonResponse.getJSONArray("value"); + Map addedLinks = new HashMap<>(); + addedLinks.put("Things", false); + addedLinks.put("Locations", false); + addedLinks.put("HistoricalLocations", false); + addedLinks.put("Datastreams", false); + addedLinks.put("Sensors", false); + addedLinks.put("Observations", false); + addedLinks.put("ObservedProperties", false); + addedLinks.put("FeaturesOfInterest", false); + for (int i = 0; i < entities.length(); i++) { + JSONObject entity = entities.getJSONObject(i); + try { + Assert.assertNotNull(entity.get("name")); + Assert.assertNotNull(entity.get("url")); + } + catch (JSONException e) { + Assert.fail("Service root URI does not have proper JSON keys: name and value."); + } + String name = entity.getString("name"); + String nameUrl = entity.getString("url"); + switch (name) { + case "Things": + Assert.assertEquals(nameUrl, rootUri + "/Things", + "The URL for Things in Service Root URI is not compliant to SensorThings API."); + addedLinks.remove("Things"); + addedLinks.put(name, true); + break; + case "Locations": + Assert.assertEquals(nameUrl, rootUri + "/Locations", + "The URL for Locations in Service Root URI is not compliant to SensorThings API."); + addedLinks.remove("Locations"); + addedLinks.put(name, true); + break; + case "HistoricalLocations": + Assert.assertEquals(nameUrl, rootUri + "/HistoricalLocations", + "The URL for HistoricalLocations in Service Root URI is not compliant to SensorThings API."); + addedLinks.remove("HistoricalLocations"); + addedLinks.put(name, true); + break; + case "Datastreams": + Assert.assertEquals(nameUrl, rootUri + "/Datastreams", + "The URL for Datastreams in Service Root URI is not compliant to SensorThings API."); + addedLinks.remove("Datastreams"); + addedLinks.put(name, true); + break; + case "Sensors": + Assert.assertEquals(nameUrl, rootUri + "/Sensors", + "The URL for Sensors in Service Root URI is not compliant to SensorThings API."); + addedLinks.remove("Sensors"); + addedLinks.put(name, true); + break; + case "Observations": + Assert.assertEquals(nameUrl, rootUri + "/Observations", + "The URL for Observations in Service Root URI is not compliant to SensorThings API."); + addedLinks.remove("Observations"); + addedLinks.put(name, true); + break; + case "ObservedProperties": + Assert.assertEquals(nameUrl, rootUri + "/ObservedProperties", + "The URL for ObservedProperties in Service Root URI is not compliant to SensorThings API."); + addedLinks.remove("ObservedProperties"); + addedLinks.put(name, true); + break; + case "FeaturesOfInterest": + Assert.assertEquals(nameUrl, rootUri + "/FeaturesOfInterest", + "The URL for FeaturesOfInterest in Service Root URI is not compliant to SensorThings API."); + addedLinks.remove("FeaturesOfInterest"); + addedLinks.put(name, true); + break; + case "MultiDatastreams": + Assert.assertEquals(nameUrl, rootUri + "/MultiDatastreams", + "The URL for MultiDatastreams in Service Root URI is not compliant to SensorThings API."); + break; + default: + Assert + .fail("There is a component in Service Root URI response that is not in SensorThings API : " + + name); + break; + } + } + for (String key : addedLinks.keySet()) { + Assert.assertTrue(addedLinks.get(key), "The Service Root URI response does not contain " + key); + } + + } + catch (Exception e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This helper method is sending GET request to a collection of entities. + * @param entityType Entity type from EntityType enum list + * @return The response of GET request in string format. + */ + private String getEntities(EntityType entityType) { + String urlString = rootUri; + if (entityType != null) { + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + } + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + Assert.assertEquals(responseCode, 200, + "Error during getting entities: " + ((entityType != null) ? entityType.name() : "root URI")); + if (entityType != null) { + Assert.assertTrue(response.indexOf("value") != -1, "The GET entities response for entity type \"" + + entityType + "\" does not match SensorThings API : missing \"value\" in response."); + } + else { // GET Service Base URI + Assert.assertTrue(response.indexOf("value") != -1, + "The GET entities response for service root URI does not match SensorThings API : missing \"value\" in response."); + } + return response.toString(); + } + + /** + * This helper method is sending Get request to a specific entity + * @param entityType Entity type from EntityType enum list + * @param id The if of the specific entity + * @param property The requested property of the entity + * @return The response-code and response (body) of the request in Map format. + */ + private Map getEntity(EntityType entityType, long id, String property) { + if (id == -1) { + return null; + } + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, property); + return HTTPMethods.doGet(urlString); + } + + /** + * This helper method is the start point for checking the response for a collection in + * all aspects. + * @param entityType Entity type from EntityType enum list + * @param response The response of the GET request to be checked + */ + private void checkEntitiesAllAspectsForResponse(EntityType entityType, String response) { + checkEntitiesControlInformation(response); + checkEntitiesProperties(entityType, response); + checkEntitiesRelations(entityType, response); + } + + /** + * This helper method is the start point for checking the response for a specific + * entity in all aspects. + * @param entityType Entity type from EntityType enum list + * @param response The response of the GET request to be checked + */ + private void checkEntityAllAspectsForResponse(EntityType entityType, String response) { + checkEntityControlInformation(response); + checkEntityProperties(entityType, response); + checkEntityRelations(entityType, response); + } + + /** + * This helper method is checking the control information of the response for a + * collection + * @param response The response of the GET request to be checked + */ + private void checkEntitiesControlInformation(String response) { + try { + JSONObject jsonResponse = new JSONObject(response.toString()); + JSONArray entities = jsonResponse.getJSONArray("value"); + int count = 0; + for (int i = 0; i < entities.length() && count < 2; i++) { + count++; + JSONObject entity = entities.getJSONObject(i); + checkEntityControlInformation(entity); + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This helper method is checking the control information of the response for a + * specific entity + * @param response The response of the GET request to be checked + */ + private void checkEntityControlInformation(Object response) { + try { + JSONObject entity = new JSONObject(response.toString()); + try { + Assert.assertNotNull(entity.get(ControlInformation.ID), + "The entity does not have mandatory control information : " + ControlInformation.ID); + } + catch (JSONException e) { + Assert.fail("The entity does not have mandatory control information : " + ControlInformation.ID); + } + try { + Assert.assertNotNull(entity.get(ControlInformation.SELF_LINK), + "The entity does not have mandatory control information : " + ControlInformation.SELF_LINK); + } + catch (JSONException e) { + Assert.fail("The entity does not have mandatory control information : " + ControlInformation.SELF_LINK); + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + } + + /** + * This helper method is checking the mandatory properties of the response for a + * collection + * @param entityType Entity type from EntityType enum list + * @param response The response of the GET request to be checked + */ + private void checkEntitiesProperties(EntityType entityType, String response) { + try { + JSONObject jsonResponse = new JSONObject(response.toString()); + JSONArray entities = jsonResponse.getJSONArray("value"); + int count = 0; + for (int i = 0; i < entities.length() && count < 2; i++) { + count++; + JSONObject entity = entities.getJSONObject(i); + checkEntityProperties(entityType, entity); + } + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + + } + + /** + * This helper method is checking the mandatory properties of the response for a + * specific entity + * @param entityType Entity type from EntityType enum list + * @param response The response of the GET request to be checked + */ + private void checkEntityProperties(EntityType entityType, Object response) { + try { + JSONObject entity = new JSONObject(response.toString()); + for (String property : entityType.getProperties()) { + try { + Assert.assertNotNull(entity.get(property), "Entity type \"" + entityType + + "\" does not have mandatory property: \"" + property + "\"."); + } + catch (JSONException e) { + Assert.fail("Entity type \"" + entityType + "\" does not have mandatory property: \"" + property + + "\"."); + } + } + + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + } + + } + + /** + * This helper method is checking the mandatory relations of the response for a + * collection + * @param entityType Entity type from EntityType enum list + * @param response The response of the GET request to be checked + */ + private void checkEntitiesRelations(EntityType entityType, String response) { + try { + JSONObject jsonResponse = new JSONObject(response); + JSONArray entities = jsonResponse.getJSONArray("value"); + int count = 0; + for (int i = 0; i < entities.length() && count < 2; i++) { + count++; + JSONObject entity = entities.getJSONObject(i); + checkEntityRelations(entityType, entity); + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail( + "An Exception occurred during testing!:\n" + e.getMessage() + " [Response] " + response.toString()); + } + + } + + /** + * This helper method is checking the mandatory relations of the response for a + * specific entity + * @param entityType Entity type from EntityType enum list + * @param response The response of the GET request to be checked + */ + private void checkEntityRelations(EntityType entityType, Object response) { + try { + JSONObject entity = new JSONObject(response.toString()); + for (String relation : entityType.getRelations()) { + try { + Assert.assertNotNull(entity.get(relation + ControlInformation.NAVIGATION_LINK), + "Entity type \"" + entityType + "\" does not have mandatory relation: \"" + relation + + "\". [Response] " + response.toString()); + } + catch (JSONException e) { + Assert.fail("Entity type \"" + entityType + "\" does not have mandatory relation: \"" + relation + + "\". [Response] " + response.toString()); + } + } + } + catch (JSONException e) { + e.printStackTrace(); + Assert.fail( + "An Exception occurred during testing!:\n" + e.getMessage() + " [Response] " + response.toString()); + } + } } diff --git a/src/main/java/org/opengis/cite/sta10/sensingCore/package-info.java b/src/main/java/org/opengis/cite/sta10/sensingCore/package-info.java index 223a672..77576ce 100644 --- a/src/main/java/org/opengis/cite/sta10/sensingCore/package-info.java +++ b/src/main/java/org/opengis/cite/sta10/sensingCore/package-info.java @@ -1,8 +1,7 @@ /** * Conformance Level 1 includes basic facilities. * - * @see HTML5 + * @see HTML5 * - Conformance classes */ package org.opengis.cite.sta10.sensingCore; diff --git a/src/main/java/org/opengis/cite/sta10/util/ClientUtils.java b/src/main/java/org/opengis/cite/sta10/util/ClientUtils.java index 5649049..0a1a525 100644 --- a/src/main/java/org/opengis/cite/sta10/util/ClientUtils.java +++ b/src/main/java/org/opengis/cite/sta10/util/ClientUtils.java @@ -28,117 +28,117 @@ import jakarta.ws.rs.core.UriBuilder; /** - * Provides various utility methods for creating and configuring HTTP client - * components. + * Provides various utility methods for creating and configuring HTTP client components. */ public class ClientUtils { - private static final Logger LOGGER = Logger.getLogger(ClientUtils.class.getName()); + private static final Logger LOGGER = Logger.getLogger(ClientUtils.class.getName()); - /** - * Builds a client component for interacting with HTTP endpoints. The client will - * automatically redirect to the URI declared in 3xx responses. The connection timeout - * is 10 s. Request and response messages may be logged to a JDK logger (in the - * namespace "com.sun.jersey.api.client"). - * @return A Client component. - */ - public static Client buildClient() { - ClientConfig config = new ClientConfig(); - config.property(ClientProperties.FOLLOW_REDIRECTS, true); - config.property(ClientProperties.CONNECT_TIMEOUT, 10000); - config.register(new LoggingFeature(LOGGER, Level.ALL, LoggingFeature.Verbosity.PAYLOAD_ANY, 5000)); - Client client = ClientBuilder.newClient(config); - client.register(new ReusableEntityFilter()); - return client; - } + /** + * Builds a client component for interacting with HTTP endpoints. The client will + * automatically redirect to the URI declared in 3xx responses. The connection timeout + * is 10 s. Request and response messages may be logged to a JDK logger (in the + * namespace "com.sun.jersey.api.client"). + * @return A Client component. + */ + public static Client buildClient() { + ClientConfig config = new ClientConfig(); + config.property(ClientProperties.FOLLOW_REDIRECTS, true); + config.property(ClientProperties.CONNECT_TIMEOUT, 10000); + config.register(new LoggingFeature(LOGGER, Level.ALL, LoggingFeature.Verbosity.PAYLOAD_ANY, 5000)); + Client client = ClientBuilder.newClient(config); + client.register(new ReusableEntityFilter()); + return client; + } - /** - * Constructs a client component that uses a specified web proxy. Proxy authentication - * is not supported. Configuring the client to use an intercepting proxy can be useful - * when debugging a test. - * @param proxyHost The host name or IP address of the proxy server. - * @param proxyPort The port number of the proxy listener. - * @return A Client component that submits requests through a web proxy. - */ - public static Client buildClientWithProxy(final String proxyHost, final int proxyPort) { - ClientConfig config = new ClientConfig(); - config.connectorProvider(new ApacheConnectorProvider()); - config.register(new LoggingFeature(LOGGER, Level.ALL, LoggingFeature.Verbosity.PAYLOAD_ANY, 5000)); - SocketAddress addr = new InetSocketAddress(proxyHost, proxyPort); - Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); - config.property(ClientProperties.PROXY_URI, proxy); - config.property(ClientProperties.FOLLOW_REDIRECTS, true); - config.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT, LoggingFeature.Verbosity.PAYLOAD_ANY); - config.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_CLIENT, Level.ALL); - Client client = ClientBuilder.newClient(config); - client.register(new ReusableEntityFilter()); - return client; - } + /** + * Constructs a client component that uses a specified web proxy. Proxy authentication + * is not supported. Configuring the client to use an intercepting proxy can be useful + * when debugging a test. + * @param proxyHost The host name or IP address of the proxy server. + * @param proxyPort The port number of the proxy listener. + * @return A Client component that submits requests through a web proxy. + */ + public static Client buildClientWithProxy(final String proxyHost, final int proxyPort) { + ClientConfig config = new ClientConfig(); + config.connectorProvider(new ApacheConnectorProvider()); + config.register(new LoggingFeature(LOGGER, Level.ALL, LoggingFeature.Verbosity.PAYLOAD_ANY, 5000)); + SocketAddress addr = new InetSocketAddress(proxyHost, proxyPort); + Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); + config.property(ClientProperties.PROXY_URI, proxy); + config.property(ClientProperties.FOLLOW_REDIRECTS, true); + config.property(LoggingFeature.LOGGING_FEATURE_VERBOSITY_CLIENT, LoggingFeature.Verbosity.PAYLOAD_ANY); + config.property(LoggingFeature.LOGGING_FEATURE_LOGGER_LEVEL_CLIENT, Level.ALL); + Client client = ClientBuilder.newClient(config); + client.register(new ReusableEntityFilter()); + return client; + } - /** - * Builds an HTTP request message that uses the GET method. - * @param endpoint A URI indicating the target resource. - * @param qryParams A Map containing query parameters (may be null); - * @param mediaTypes A list of acceptable media types; if not specified, the Accept - * header is omitted. - * @return A ClientRequest object. - */ - public static Response buildGetRequest(URI endpoint, Map qryParams, MediaType... mediaTypes) { - UriBuilder uriBuilder = UriBuilder.fromUri(endpoint); - if (null != qryParams) { - for (Map.Entry param : qryParams.entrySet()) { - uriBuilder.queryParam(param.getKey(), param.getValue()); - } - } - URI uri = uriBuilder.build(); - WebTarget target = buildClient().target(uri); - Builder reqBuilder = target.request(); - if (null != mediaTypes && mediaTypes.length > 0) { - reqBuilder = reqBuilder.accept(mediaTypes); - } - Invocation req = reqBuilder.buildGet(); - return req.invoke(); - } + /** + * Builds an HTTP request message that uses the GET method. + * @param endpoint A URI indicating the target resource. + * @param qryParams A Map containing query parameters (may be null); + * @param mediaTypes A list of acceptable media types; if not specified, the Accept + * header is omitted. + * @return A ClientRequest object. + */ + public static Response buildGetRequest(URI endpoint, Map qryParams, MediaType... mediaTypes) { + UriBuilder uriBuilder = UriBuilder.fromUri(endpoint); + if (null != qryParams) { + for (Map.Entry param : qryParams.entrySet()) { + uriBuilder.queryParam(param.getKey(), param.getValue()); + } + } + URI uri = uriBuilder.build(); + WebTarget target = buildClient().target(uri); + Builder reqBuilder = target.request(); + if (null != mediaTypes && mediaTypes.length > 0) { + reqBuilder = reqBuilder.accept(mediaTypes); + } + Invocation req = reqBuilder.buildGet(); + return req.invoke(); + } - /** - * Creates a copy of the given MediaType object but without any parameters. - * @param mediaType A MediaType descriptor. - * @return A new (immutable) MediaType object having the same type and subtype. - */ - public static MediaType removeParameters(MediaType mediaType) { - return new MediaType(mediaType.getType(), mediaType.getSubtype()); - } + /** + * Creates a copy of the given MediaType object but without any parameters. + * @param mediaType A MediaType descriptor. + * @return A new (immutable) MediaType object having the same type and subtype. + */ + public static MediaType removeParameters(MediaType mediaType) { + return new MediaType(mediaType.getType(), mediaType.getSubtype()); + } - /** - * Obtains the (XML) response entity as a JAXP Source object and resets the entity - * input stream for subsequent reads. - * @param response A representation of an HTTP response message. - * @param targetURI The target URI from which the entity was retrieved (may be null). - * @return A Source to read the entity from; its system identifier is set using the - * given targetURI value (this may be used to resolve any relative URIs found in the - * source). - */ - public static Source getResponseEntityAsSource(Response response, String targetURI) { - Source source = response.readEntity(DOMSource.class); - if (null != targetURI && !targetURI.isEmpty()) { - source.setSystemId(targetURI); - } - return source; - } + /** + * Obtains the (XML) response entity as a JAXP Source object and resets the entity + * input stream for subsequent reads. + * @param response A representation of an HTTP response message. + * @param targetURI The target URI from which the entity was retrieved (may be null). + * @return A Source to read the entity from; its system identifier is set using the + * given targetURI value (this may be used to resolve any relative URIs found in the + * source). + */ + public static Source getResponseEntityAsSource(Response response, String targetURI) { + Source source = response.readEntity(DOMSource.class); + if (null != targetURI && !targetURI.isEmpty()) { + source.setSystemId(targetURI); + } + return source; + } + + /** + * Obtains the (XML) response entity as a DOM Document and resets the entity input + * stream for subsequent reads. + * @param response A representation of an HTTP response message. + * @param targetURI The target URI from which the entity was retrieved (may be null). + * @return A Document representing the entity; its base URI is set using the given + * targetURI value (this may be used to resolve any relative URIs found in the + * document). + */ + public static Document getResponseEntityAsDocument(Response response, String targetURI) { + DOMSource domSource = (DOMSource) getResponseEntityAsSource(response, targetURI); + Document entityDoc = (Document) domSource.getNode(); + entityDoc.setDocumentURI(domSource.getSystemId()); + return entityDoc; + } - /** - * Obtains the (XML) response entity as a DOM Document and resets the entity input - * stream for subsequent reads. - * @param response A representation of an HTTP response message. - * @param targetURI The target URI from which the entity was retrieved (may be null). - * @return A Document representing the entity; its base URI is set using the given - * targetURI value (this may be used to resolve any relative URIs found in the - * document). - */ - public static Document getResponseEntityAsDocument(Response response, String targetURI) { - DOMSource domSource = (DOMSource) getResponseEntityAsSource(response, targetURI); - Document entityDoc = (Document) domSource.getNode(); - entityDoc.setDocumentURI(domSource.getSystemId()); - return entityDoc; - } } diff --git a/src/main/java/org/opengis/cite/sta10/util/ControlInformation.java b/src/main/java/org/opengis/cite/sta10/util/ControlInformation.java index 9c496b6..3279c93 100644 --- a/src/main/java/org/opengis/cite/sta10/util/ControlInformation.java +++ b/src/main/java/org/opengis/cite/sta10/util/ControlInformation.java @@ -5,17 +5,20 @@ */ public class ControlInformation { - /** - * The system-generated identifier of an entity. - * It is unique among the entities of the same entity type in a SensorThings service. - */ - public static final String ID = "@iot.id"; - /** - * The absolute URL of an entity that is unique among all other entities. - */ - public static final String SELF_LINK = "@iot.selfLink"; - /** - * The relative URL that retrieves content of related entities. - */ - public static final String NAVIGATION_LINK = "@iot.navigationLink"; + /** + * The system-generated identifier of an entity. It is unique among the entities of + * the same entity type in a SensorThings service. + */ + public static final String ID = "@iot.id"; + + /** + * The absolute URL of an entity that is unique among all other entities. + */ + public static final String SELF_LINK = "@iot.selfLink"; + + /** + * The relative URL that retrieves content of related entities. + */ + public static final String NAVIGATION_LINK = "@iot.navigationLink"; + } diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java b/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java index 638783a..1656f05 100644 --- a/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java +++ b/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java @@ -3,79 +3,91 @@ import org.joda.time.format.ISODateTimeFormat; /** - * Provides list of sample values for each property of each entity for testing - * $filter. These values are the same as the properties of one of the entities - * that is created in pre-test. + * Provides list of sample values for each property of each entity for testing $filter. + * These values are the same as the properties of one of the entities that is created in + * pre-test. */ public class EntityPropertiesSampleValue { - /** - * Sample properties for Thing entity. - */ - public static final String[] THING_PROPERTIES_Values = {"'thing 1'", "'thing 1'"}; - /** - * Sample properties for Location entity. - */ - public static final String[] LOCATION_PROPERTIES_Values = {"'location 2'", "'location 2'", "'application/vnd.geo+json'", "location"}; - /** - * Sample properties for HistoricalLocation entity. - */ - public static final Comparable[] HISTORICAL_LOCATION_PROPERTIES_Values = {ISODateTimeFormat.dateTime().parseDateTime("2015-10-14T21:30:00.104Z")}; - /** - * Sample properties for Datastream entity. - */ - public static final String[] DATASTREAM_PROPERTIES_Values = {"'datastream 1'", "'datastream 1'", "unitOfMeasurement", "'http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement'"}; - /** - * Sample properties for Sensor entity. - */ - public static final String[] SENSOR_PROPERTIES_Values = {"'sensor 1'", "'sensor 1'", "'application/pdf'", "'Light flux sensor'"}; - /** - * Sample properties for ObservedProperty entity. - */ - public static final String[] OBSERVED_PROPETY_PROPERTIES_Values = {"'Luminous Flux'", "'http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html/LuminousFlux'", "'observedProperty 1'"}; - /** - * Sample properties for Observation entity. - */ - public static final Comparable[] OBSERVATION_PROPERTIES_Values = { - ISODateTimeFormat.dateTime().parseDateTime("2015-03-02T00:00:00.000Z"), - "'2'", - ISODateTimeFormat.dateTime().parseDateTime("2015-03-02T00:00:00.000Z")}; - /** - * Sample properties for FeatureOfInterest entity. - */ - public static final String[] FEATURE_OF_INTEREST_PROPERTIES_Values = {"'Generated using location details: location 1'", "'Generated using location details: location 1'", "'application/vnd.geo+json'", "feature"}; + /** + * Sample properties for Thing entity. + */ + public static final String[] THING_PROPERTIES_Values = { "'thing 1'", "'thing 1'" }; + + /** + * Sample properties for Location entity. + */ + public static final String[] LOCATION_PROPERTIES_Values = { "'location 2'", "'location 2'", + "'application/vnd.geo+json'", "location" }; + + /** + * Sample properties for HistoricalLocation entity. + */ + public static final Comparable[] HISTORICAL_LOCATION_PROPERTIES_Values = { + ISODateTimeFormat.dateTime().parseDateTime("2015-10-14T21:30:00.104Z") }; + + /** + * Sample properties for Datastream entity. + */ + public static final String[] DATASTREAM_PROPERTIES_Values = { "'datastream 1'", "'datastream 1'", + "unitOfMeasurement", "'http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement'" }; + + /** + * Sample properties for Sensor entity. + */ + public static final String[] SENSOR_PROPERTIES_Values = { "'sensor 1'", "'sensor 1'", "'application/pdf'", + "'Light flux sensor'" }; + + /** + * Sample properties for ObservedProperty entity. + */ + public static final String[] OBSERVED_PROPETY_PROPERTIES_Values = { "'Luminous Flux'", + "'http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html/LuminousFlux'", "'observedProperty 1'" }; + + /** + * Sample properties for Observation entity. + */ + public static final Comparable[] OBSERVATION_PROPERTIES_Values = { + ISODateTimeFormat.dateTime().parseDateTime("2015-03-02T00:00:00.000Z"), "'2'", + ISODateTimeFormat.dateTime().parseDateTime("2015-03-02T00:00:00.000Z") }; + + /** + * Sample properties for FeatureOfInterest entity. + */ + public static final String[] FEATURE_OF_INTEREST_PROPERTIES_Values = { + "'Generated using location details: location 1'", "'Generated using location details: location 1'", + "'application/vnd.geo+json'", "feature" }; + + /** + * Returning the sample property value for the properties[index] of the entityType + * @param entityType The type of the entity in the format of EntityType enum + * @param index The index of the requested properties in the properties list of the + * entityType + * @return The sample value from the properties list of the given "entityType" + * positioned in location "index" in the list + */ + public static Comparable getPropertyValueFor(EntityType entityType, int index) { + switch (entityType) { + case THING: + return THING_PROPERTIES_Values[index]; + case LOCATION: + return LOCATION_PROPERTIES_Values[index]; + case FEATURE_OF_INTEREST: + return FEATURE_OF_INTEREST_PROPERTIES_Values[index]; + case OBSERVED_PROPERTY: + return OBSERVED_PROPETY_PROPERTIES_Values[index]; + case HISTORICAL_LOCATION: + return HISTORICAL_LOCATION_PROPERTIES_Values[index]; + case SENSOR: + return SENSOR_PROPERTIES_Values[index]; + case DATASTREAM: + return DATASTREAM_PROPERTIES_Values[index]; + case OBSERVATION: + return OBSERVATION_PROPERTIES_Values[index]; + default: + break; + } + return null; + } - /** - * Returning the sample property value for the properties[index] of the - * entityType - * - * @param entityType The type of the entity in the format of EntityType enum - * @param index The index of the requested properties in the properties list - * of the entityType - * @return The sample value from the properties list of the given - * "entityType" positioned in location "index" in the list - */ - public static Comparable getPropertyValueFor(EntityType entityType, int index) { - switch (entityType) { - case THING: - return THING_PROPERTIES_Values[index]; - case LOCATION: - return LOCATION_PROPERTIES_Values[index]; - case FEATURE_OF_INTEREST: - return FEATURE_OF_INTEREST_PROPERTIES_Values[index]; - case OBSERVED_PROPERTY: - return OBSERVED_PROPETY_PROPERTIES_Values[index]; - case HISTORICAL_LOCATION: - return HISTORICAL_LOCATION_PROPERTIES_Values[index]; - case SENSOR: - return SENSOR_PROPERTIES_Values[index]; - case DATASTREAM: - return DATASTREAM_PROPERTIES_Values[index]; - case OBSERVATION: - return OBSERVATION_PROPERTIES_Values[index]; - default: - break; - } - return null; - } } diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityType.java b/src/main/java/org/opengis/cite/sta10/util/EntityType.java index f3c8576..6001e89 100644 --- a/src/main/java/org/opengis/cite/sta10/util/EntityType.java +++ b/src/main/java/org/opengis/cite/sta10/util/EntityType.java @@ -13,89 +13,123 @@ * List of entity types in SensorThings API. */ public enum EntityType { - THING("Thing", "Things"), - LOCATION("Location", "Locations"), - SENSOR("Sensor", "Sensors"), - OBSERVED_PROPERTY("ObservedProperty", "ObservedProperties"), - OBSERVATION("Observation", "Observations"), - DATASTREAM("Datastream", "Datastreams"), - FEATURE_OF_INTEREST("FeatureOfInterest", "FeaturesOfInterest"), - HISTORICAL_LOCATION("HistoricalLocation", "HistoricalLocations"); - public final String singular; - public final String plural; - private final List properties = new ArrayList<>(); - private final List relations = new ArrayList<>(); - - private static final Map NAMES_MAP = new HashMap<>(); - private static final Set NAMES_PLURAL = new HashSet<>(); - - static { - THING.addProperties("name", "description"); - THING.addRelations(DATASTREAM.plural, HISTORICAL_LOCATION.plural, LOCATION.plural); - - LOCATION.addProperties("name", "description", "encodingType", "location"); - LOCATION.addRelations(HISTORICAL_LOCATION.plural, THING.plural); - - SENSOR.addProperties("name", "description", "encodingType", "metadata"); - SENSOR.addRelations(DATASTREAM.plural); - - OBSERVED_PROPERTY.addProperties("name", "definition", "description"); - OBSERVED_PROPERTY.addRelations(DATASTREAM.plural); - - OBSERVATION.addProperties("phenomenonTime", "result", "resultTime"); - OBSERVATION.addRelations(DATASTREAM.singular, FEATURE_OF_INTEREST.singular); - - DATASTREAM.addProperties("name", "description", "unitOfMeasurement", "observationType"); - DATASTREAM.addRelations(THING.singular, SENSOR.singular, OBSERVED_PROPERTY.singular, OBSERVATION.plural); - - FEATURE_OF_INTEREST.addProperties("name", "description", "encodingType", "feature"); - FEATURE_OF_INTEREST.addRelations(OBSERVATION.plural); - - HISTORICAL_LOCATION.addProperties("time"); - HISTORICAL_LOCATION.addRelations(THING.singular, LOCATION.plural); - - for (EntityType entityType : EntityType.values()) { - NAMES_MAP.put(entityType.singular, entityType); - NAMES_MAP.put(entityType.plural, entityType); - NAMES_PLURAL.add(entityType.plural); - } - } - - public static EntityType getForRelation(String relation) { - EntityType entityType = NAMES_MAP.get(relation); - if (entityType == null) { - throw new IllegalArgumentException("Unknown relation: " + relation); - } - return entityType; - } - - public static boolean isPlural(String relation) { - return NAMES_PLURAL.contains(relation); - } - - private EntityType(String singular, String plural) { - this.singular = singular; - this.plural = plural; - } - - public String getRootEntitySet() { - return plural; - } - - public List getRelations() { - return Collections.unmodifiableList(relations); - } - - public List getProperties() { - return Collections.unmodifiableList(properties); - } - - private void addProperties(String... properties) { - this.properties.addAll(Arrays.asList(properties)); - } - - private void addRelations(String... relations) { - this.relations.addAll(Arrays.asList(relations)); - } + + THING("Thing", "Things"), LOCATION("Location", "Locations"), SENSOR("Sensor", "Sensors"), + OBSERVED_PROPERTY("ObservedProperty", "ObservedProperties"), OBSERVATION("Observation", "Observations"), + DATASTREAM("Datastream", "Datastreams"), FEATURE_OF_INTEREST("FeatureOfInterest", "FeaturesOfInterest"), + HISTORICAL_LOCATION("HistoricalLocation", "HistoricalLocations"); + + public final String singular; + + public final String plural; + + private final List properties = new ArrayList<>(); + + private final List relations = new ArrayList<>(); + + private static final Map NAMES_MAP = new HashMap<>(); + + private static final Set NAMES_PLURAL = new HashSet<>(); + + static { + THING.addProperties("name", "description"); + THING.addRelations(DATASTREAM.plural, HISTORICAL_LOCATION.plural, LOCATION.plural); + + LOCATION.addProperties("name", "description", "encodingType", "location"); + LOCATION.addRelations(HISTORICAL_LOCATION.plural, THING.plural); + + SENSOR.addProperties("name", "description", "encodingType", "metadata"); + SENSOR.addRelations(DATASTREAM.plural); + + OBSERVED_PROPERTY.addProperties("name", "definition", "description"); + OBSERVED_PROPERTY.addRelations(DATASTREAM.plural); + + OBSERVATION.addProperties("phenomenonTime", "result", "resultTime"); + OBSERVATION.addRelations(DATASTREAM.singular, FEATURE_OF_INTEREST.singular); + + DATASTREAM.addProperties("name", "description", "unitOfMeasurement", "observationType"); + DATASTREAM.addRelations(THING.singular, SENSOR.singular, OBSERVED_PROPERTY.singular, OBSERVATION.plural); + + FEATURE_OF_INTEREST.addProperties("name", "description", "encodingType", "feature"); + FEATURE_OF_INTEREST.addRelations(OBSERVATION.plural); + + HISTORICAL_LOCATION.addProperties("time"); + HISTORICAL_LOCATION.addRelations(THING.singular, LOCATION.plural); + + for (EntityType entityType : EntityType.values()) { + NAMES_MAP.put(entityType.singular, entityType); + NAMES_MAP.put(entityType.plural, entityType); + NAMES_PLURAL.add(entityType.plural); + } + } + + /** + *

+ * getForRelation. + *

+ * @param relation a {@link java.lang.String} object + * @return a {@link org.opengis.cite.sta10.util.EntityType} object + */ + public static EntityType getForRelation(String relation) { + EntityType entityType = NAMES_MAP.get(relation); + if (entityType == null) { + throw new IllegalArgumentException("Unknown relation: " + relation); + } + return entityType; + } + + /** + *

+ * isPlural. + *

+ * @param relation a {@link java.lang.String} object + * @return a boolean + */ + public static boolean isPlural(String relation) { + return NAMES_PLURAL.contains(relation); + } + + private EntityType(String singular, String plural) { + this.singular = singular; + this.plural = plural; + } + + /** + *

+ * getRootEntitySet. + *

+ * @return a {@link java.lang.String} object + */ + public String getRootEntitySet() { + return plural; + } + + /** + *

+ * Getter for the field relations. + *

+ * @return a {@link java.util.List} object + */ + public List getRelations() { + return Collections.unmodifiableList(relations); + } + + /** + *

+ * Getter for the field properties. + *

+ * @return a {@link java.util.List} object + */ + public List getProperties() { + return Collections.unmodifiableList(properties); + } + + private void addProperties(String... properties) { + this.properties.addAll(Arrays.asList(properties)); + } + + private void addRelations(String... relations) { + this.relations.addAll(Arrays.asList(relations)); + } } diff --git a/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java b/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java index b7a416e..c2a43f5 100644 --- a/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java +++ b/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java @@ -25,220 +25,234 @@ */ public class HTTPMethods { - /** - * Send HTTP GET request to the urlString and return response code and response body - * - * @param urlString The URL that the GET request should be sent to - * @return response-code and response(response body) of the HTTP GET in the MAP format. - * If the response is not 200, the response(response body) will be empty. - */ - public static Map doGet(String urlString) { - HttpURLConnection connection = null; - try { - //Create connection - URL url = new URL(urlString); - connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("GET"); - connection.setRequestProperty("Content-Type", - "application/json"); - - connection.setUseCaches(false); - connection.setDoOutput(true); - - Map result = new HashMap(); - result.put("response-code", connection.getResponseCode()); - if (connection.getResponseCode() == 200) { - //Get Response - InputStream is = connection.getInputStream(); - BufferedReader rd = new BufferedReader(new InputStreamReader(is)); - StringBuilder response = new StringBuilder(); // or StringBuffer if not Java 5+ - String line; - while ((line = rd.readLine()) != null) { - response.append(line); - response.append('\r'); - } - rd.close(); - result.put("response", response.toString()); - } else { - result.put("response", ""); - } - return result; - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - if (connection != null) { - connection.disconnect(); - } - - } - } - - /** - * Send HTTP POST request to the urlString with postBody and return response code and response body - * - * @param urlString The URL that the POST request should be sent to - * @param postBody The body of the POST request - * @return response-code and response of the HTTP POST in the MAP format. - * If the response is 201, the response will contain the self-link to the created entity. Otherwise, it will be empty String. - */ - public static Map doPost(String urlString, String postBody) { - HttpURLConnection connection = null; - try { - //Create connection - URL url = new URL(urlString); - byte[] postData = postBody.getBytes(StandardCharsets.UTF_8); - int postDataLength = postData.length; - connection = (HttpURLConnection) url.openConnection(); - connection.setDoOutput(true); - connection.setInstanceFollowRedirects(false); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("charset", "utf-8"); - connection.setRequestProperty("Content-Length", Integer.toString(postDataLength)); - connection.setUseCaches(false); - try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) { - wr.write(postData); - } - - Map result = new HashMap(); - result.put("response-code", connection.getResponseCode()); - if (connection.getResponseCode() == 201) { - result.put("response", connection.getHeaderField("location")); - } else { - result.put("response", ""); - } - return result; - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - if (connection != null) { - connection.disconnect(); - } - } - } - - /** - * Send HTTP PUT request to the urlString with putBody and return response code and response body - * - * @param urlString The URL that the PUT request should be sent to - * @param putBody The body of the PUT request - * @return response-code and response(response body) of the HTTP PUT in the MAP format. - * If the response is not 200, the response(response body) will be empty. - */ - public static Map doPut(String urlString, String putBody) { - HttpURLConnection connection = null; - try { - //Create connection - URL url = new URL(urlString); - byte[] postData = putBody.getBytes(StandardCharsets.UTF_8); - int postDataLength = postData.length; - connection = (HttpURLConnection) url.openConnection(); - connection.setDoOutput(true); - connection.setInstanceFollowRedirects(false); - connection.setRequestMethod("PUT"); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("charset", "utf-8"); - connection.setRequestProperty("Content-Length", Integer.toString(postDataLength)); - connection.setUseCaches(false); - try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) { - wr.write(postData); - } - - Map result = new HashMap(); - result.put("response-code", connection.getResponseCode()); - if (connection.getResponseCode() == 200) { - //Get Response - InputStream is = connection.getInputStream(); - BufferedReader rd = new BufferedReader(new InputStreamReader(is)); - StringBuilder response = new StringBuilder(); // or StringBuffer if not Java 5+ - String line; - while ((line = rd.readLine()) != null) { - response.append(line); - response.append('\r'); - } - rd.close(); - result.put("response", response.toString()); - } else { - result.put("response", ""); - } - return result; - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - if (connection != null) { - connection.disconnect(); - } - } - } - - /** - * Send HTTP DELETE request to the urlString and return response code - * - * @param urlString The URL that the DELETE request should be sent to - * @return response-code of the HTTP DELETE in the MAP format. - * The MAP contains an empty response, in order to be consistent with what other HTTP requests return. - */ - public static Map doDelete(String urlString) { - HttpURLConnection connection = null; - try { - //Create connection - URL url = new URL(urlString); - connection = (HttpURLConnection) url.openConnection(); - connection.setDoOutput(true); - connection.setRequestProperty( - "Content-Type", "application/x-www-form-urlencoded"); - connection.setRequestMethod("DELETE"); - connection.connect(); - - Map result = new HashMap(); - result.put("response-code", connection.getResponseCode()); - result.put("response", ""); - - return result; - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - if (connection != null) { - connection.disconnect(); - } - } - } - - /** - * Send HTTP PATCH request to the urlString with patchBody and return response code and response body - * - * @param urlString The URL that the PATCH request should be sent to - * @param patchBody The body of the PATCH request - * @return response-code and response(response body) of the HTTP PATCH in the MAP format. - * If the response is not 200, the response(response body) will be empty. - */ - public static Map doPatch(String urlString, String patchBody) { - URI uri = null; - try { - uri = new URI(urlString); - - CloseableHttpClient httpClient = HttpClients.createDefault(); - HttpPatch request = new HttpPatch(uri); - StringEntity params = new StringEntity(patchBody, ContentType.APPLICATION_JSON); - request.setEntity(params); - CloseableHttpResponse response = httpClient.execute(request); - Map result = new HashMap(); - result.put("response-code", response.getStatusLine().getStatusCode()); - result.put("response", EntityUtils.toString(response.getEntity())); - response.close(); - httpClient.close(); - return result; - } catch (URISyntaxException e) { - e.printStackTrace(); - } catch (ClientProtocolException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } + /** + * Send HTTP GET request to the urlString and return response code and response body + * @param urlString The URL that the GET request should be sent to + * @return response-code and response(response body) of the HTTP GET in the MAP + * format. If the response is not 200, the response(response body) will be empty. + */ + public static Map doGet(String urlString) { + HttpURLConnection connection = null; + try { + // Create connection + URL url = new URL(urlString); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setRequestProperty("Content-Type", "application/json"); + + connection.setUseCaches(false); + connection.setDoOutput(true); + + Map result = new HashMap(); + result.put("response-code", connection.getResponseCode()); + if (connection.getResponseCode() == 200) { + // Get Response + InputStream is = connection.getInputStream(); + BufferedReader rd = new BufferedReader(new InputStreamReader(is)); + StringBuilder response = new StringBuilder(); // or StringBuffer if not + // Java 5+ + String line; + while ((line = rd.readLine()) != null) { + response.append(line); + response.append('\r'); + } + rd.close(); + result.put("response", response.toString()); + } + else { + result.put("response", ""); + } + return result; + } + catch (Exception e) { + e.printStackTrace(); + return null; + } + finally { + if (connection != null) { + connection.disconnect(); + } + + } + } + + /** + * Send HTTP POST request to the urlString with postBody and return response code and + * response body + * @param urlString The URL that the POST request should be sent to + * @param postBody The body of the POST request + * @return response-code and response of the HTTP POST in the MAP format. If the + * response is 201, the response will contain the self-link to the created entity. + * Otherwise, it will be empty String. + */ + public static Map doPost(String urlString, String postBody) { + HttpURLConnection connection = null; + try { + // Create connection + URL url = new URL(urlString); + byte[] postData = postBody.getBytes(StandardCharsets.UTF_8); + int postDataLength = postData.length; + connection = (HttpURLConnection) url.openConnection(); + connection.setDoOutput(true); + connection.setInstanceFollowRedirects(false); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("charset", "utf-8"); + connection.setRequestProperty("Content-Length", Integer.toString(postDataLength)); + connection.setUseCaches(false); + try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) { + wr.write(postData); + } + + Map result = new HashMap(); + result.put("response-code", connection.getResponseCode()); + if (connection.getResponseCode() == 201) { + result.put("response", connection.getHeaderField("location")); + } + else { + result.put("response", ""); + } + return result; + } + catch (Exception e) { + e.printStackTrace(); + return null; + } + finally { + if (connection != null) { + connection.disconnect(); + } + } + } + + /** + * Send HTTP PUT request to the urlString with putBody and return response code and + * response body + * @param urlString The URL that the PUT request should be sent to + * @param putBody The body of the PUT request + * @return response-code and response(response body) of the HTTP PUT in the MAP + * format. If the response is not 200, the response(response body) will be empty. + */ + public static Map doPut(String urlString, String putBody) { + HttpURLConnection connection = null; + try { + // Create connection + URL url = new URL(urlString); + byte[] postData = putBody.getBytes(StandardCharsets.UTF_8); + int postDataLength = postData.length; + connection = (HttpURLConnection) url.openConnection(); + connection.setDoOutput(true); + connection.setInstanceFollowRedirects(false); + connection.setRequestMethod("PUT"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("charset", "utf-8"); + connection.setRequestProperty("Content-Length", Integer.toString(postDataLength)); + connection.setUseCaches(false); + try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) { + wr.write(postData); + } + + Map result = new HashMap(); + result.put("response-code", connection.getResponseCode()); + if (connection.getResponseCode() == 200) { + // Get Response + InputStream is = connection.getInputStream(); + BufferedReader rd = new BufferedReader(new InputStreamReader(is)); + StringBuilder response = new StringBuilder(); // or StringBuffer if not + // Java 5+ + String line; + while ((line = rd.readLine()) != null) { + response.append(line); + response.append('\r'); + } + rd.close(); + result.put("response", response.toString()); + } + else { + result.put("response", ""); + } + return result; + } + catch (Exception e) { + e.printStackTrace(); + return null; + } + finally { + if (connection != null) { + connection.disconnect(); + } + } + } + + /** + * Send HTTP DELETE request to the urlString and return response code + * @param urlString The URL that the DELETE request should be sent to + * @return response-code of the HTTP DELETE in the MAP format. The MAP contains an + * empty response, in order to be consistent with what other HTTP requests return. + */ + public static Map doDelete(String urlString) { + HttpURLConnection connection = null; + try { + // Create connection + URL url = new URL(urlString); + connection = (HttpURLConnection) url.openConnection(); + connection.setDoOutput(true); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + connection.setRequestMethod("DELETE"); + connection.connect(); + + Map result = new HashMap(); + result.put("response-code", connection.getResponseCode()); + result.put("response", ""); + + return result; + } + catch (Exception e) { + e.printStackTrace(); + return null; + } + finally { + if (connection != null) { + connection.disconnect(); + } + } + } + + /** + * Send HTTP PATCH request to the urlString with patchBody and return response code + * and response body + * @param urlString The URL that the PATCH request should be sent to + * @param patchBody The body of the PATCH request + * @return response-code and response(response body) of the HTTP PATCH in the MAP + * format. If the response is not 200, the response(response body) will be empty. + */ + public static Map doPatch(String urlString, String patchBody) { + URI uri = null; + try { + uri = new URI(urlString); + + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpPatch request = new HttpPatch(uri); + StringEntity params = new StringEntity(patchBody, ContentType.APPLICATION_JSON); + request.setEntity(params); + CloseableHttpResponse response = httpClient.execute(request); + Map result = new HashMap(); + result.put("response-code", response.getStatusLine().getStatusCode()); + result.put("response", EntityUtils.toString(response.getEntity())); + response.close(); + httpClient.close(); + return result; + } + catch (URISyntaxException e) { + e.printStackTrace(); + } + catch (ClientProtocolException e) { + e.printStackTrace(); + } + catch (IOException e) { + e.printStackTrace(); + } + return null; + } + } diff --git a/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java b/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java index 6595b99..d3fde82 100644 --- a/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java +++ b/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java @@ -8,209 +8,223 @@ */ public class ServiceURLBuilder { - /** - * Build the URL String based on the entityType, parent EntityType and id, and the targeted property or query - * - * @param rootURI The base URL of the SensorThings Service - * @param parentEntityType The entity type of the parent entity - * @param parentId The parent entity id - * @param relationEntityType The entity type of the targeted entity - * @param property The targeted property or the query string - * @return The URL String created based on the input parameters - */ - public static String buildURLString(String rootURI, EntityType parentEntityType, long parentId, EntityType relationEntityType, String property) { - String urlString = rootURI; - if (relationEntityType == null) { - switch (parentEntityType) { - case THING: - urlString += "/Things"; - break; - case LOCATION: - urlString += "/Locations"; - break; - case HISTORICAL_LOCATION: - urlString += "/HistoricalLocations"; - break; - case DATASTREAM: - urlString += "/Datastreams"; - break; - case SENSOR: - urlString += "/Sensors"; - break; - case OBSERVATION: - urlString += "/Observations"; - break; - case OBSERVED_PROPERTY: - urlString += "/ObservedProperties"; - break; - case FEATURE_OF_INTEREST: - urlString += "/FeaturesOfInterest"; - break; - default: - Assert.fail("Entity type is not recognized in SensorThings API : " + parentEntityType); - return null; - } - if (parentId != -1) { - urlString += "(" + parentId + ")"; - } - } else { - switch (parentEntityType) { - case THING: - urlString += "/Things(" + parentId + ")"; - switch (relationEntityType) { - case LOCATION: - urlString += "/Locations"; - break; - case HISTORICAL_LOCATION: - urlString += "/HistoricalLocations"; - break; - case DATASTREAM: - urlString += "/Datastreams"; - break; - default: - Assert.fail("Entity type relation is not recognized in SensorThings API : " + parentEntityType + " and " + relationEntityType); - } - break; - case LOCATION: - urlString += "/Locations(" + parentId + ")"; - switch (relationEntityType) { - case THING: - urlString += "/Things"; - break; - case HISTORICAL_LOCATION: - urlString += "/HistoricalLocations"; - break; - default: - Assert.fail("Entity type relation is not recognized in SensorThings API : " + parentEntityType + " and " + relationEntityType); - } - break; - case HISTORICAL_LOCATION: - urlString += "/HistoricalLocations(" + parentId + ")"; - switch (relationEntityType) { - case THING: - urlString += "/Thing"; - break; - case LOCATION: - urlString += "/Locations"; - break; - default: - Assert.fail("Entity type relation is not recognized in SensorThings API : " + parentEntityType + " and " + relationEntityType); - } - break; - case DATASTREAM: - urlString += "/Datastreams(" + parentId + ")"; - switch (relationEntityType) { - case THING: - urlString += "/Thing"; - break; - case SENSOR: - urlString += "/Sensor"; - break; - case OBSERVATION: - urlString += "/Observations"; - break; - case OBSERVED_PROPERTY: - urlString += "/ObservedProperty"; - break; - default: - Assert.fail("Entity type relation is not recognized in SensorThings API : " + parentEntityType + " and " + relationEntityType); - } - break; - case SENSOR: - urlString += "/Sensors(" + parentId + ")"; - switch (relationEntityType) { - case DATASTREAM: - urlString += "/Datastreams"; - break; - default: - Assert.fail("Entity type relation is not recognized in SensorThings API : " + parentEntityType + " and " + relationEntityType); - } - break; - case OBSERVATION: - urlString += "/Observations(" + parentId + ")"; - switch (relationEntityType) { - case THING: - case DATASTREAM: - urlString += "/Datastream"; - break; - case FEATURE_OF_INTEREST: - urlString += "/FeatureOfInterest"; - break; - default: - Assert.fail("Entity type relation is not recognized in SensorThings API : " + parentEntityType + " and " + relationEntityType); - } - break; - case OBSERVED_PROPERTY: - urlString += "/ObservedProperties(" + parentId + ")"; - switch (relationEntityType) { - case DATASTREAM: - urlString += "/Datastreams"; - break; - default: - Assert.fail("Entity type relation is not recognized in SensorThings API : " + parentEntityType + " and " + relationEntityType); - } - break; - case FEATURE_OF_INTEREST: - urlString += "/FeaturesOfInterest(" + parentId + ")"; - switch (relationEntityType) { - case OBSERVATION: - urlString += "/Observations"; - break; - default: - Assert.fail("Entity type relation is not recognized in SensorThings API : " + parentEntityType + " and " + relationEntityType); - } - break; - default: - Assert.fail("Entity type is not recognized in SensorThings API : " + parentEntityType); - } - } - if (property != null) { - if (property.indexOf('?') >= 0) { - urlString += property; - } else { - urlString += "/" + property; - } - } - return urlString; - } + /** + * Build the URL String based on the entityType, parent EntityType and id, and the + * targeted property or query + * @param rootURI The base URL of the SensorThings Service + * @param parentEntityType The entity type of the parent entity + * @param parentId The parent entity id + * @param relationEntityType The entity type of the targeted entity + * @param property The targeted property or the query string + * @return The URL String created based on the input parameters + */ + public static String buildURLString(String rootURI, EntityType parentEntityType, long parentId, + EntityType relationEntityType, String property) { + String urlString = rootURI; + if (relationEntityType == null) { + switch (parentEntityType) { + case THING: + urlString += "/Things"; + break; + case LOCATION: + urlString += "/Locations"; + break; + case HISTORICAL_LOCATION: + urlString += "/HistoricalLocations"; + break; + case DATASTREAM: + urlString += "/Datastreams"; + break; + case SENSOR: + urlString += "/Sensors"; + break; + case OBSERVATION: + urlString += "/Observations"; + break; + case OBSERVED_PROPERTY: + urlString += "/ObservedProperties"; + break; + case FEATURE_OF_INTEREST: + urlString += "/FeaturesOfInterest"; + break; + default: + Assert.fail("Entity type is not recognized in SensorThings API : " + parentEntityType); + return null; + } + if (parentId != -1) { + urlString += "(" + parentId + ")"; + } + } + else { + switch (parentEntityType) { + case THING: + urlString += "/Things(" + parentId + ")"; + switch (relationEntityType) { + case LOCATION: + urlString += "/Locations"; + break; + case HISTORICAL_LOCATION: + urlString += "/HistoricalLocations"; + break; + case DATASTREAM: + urlString += "/Datastreams"; + break; + default: + Assert.fail("Entity type relation is not recognized in SensorThings API : " + + parentEntityType + " and " + relationEntityType); + } + break; + case LOCATION: + urlString += "/Locations(" + parentId + ")"; + switch (relationEntityType) { + case THING: + urlString += "/Things"; + break; + case HISTORICAL_LOCATION: + urlString += "/HistoricalLocations"; + break; + default: + Assert.fail("Entity type relation is not recognized in SensorThings API : " + + parentEntityType + " and " + relationEntityType); + } + break; + case HISTORICAL_LOCATION: + urlString += "/HistoricalLocations(" + parentId + ")"; + switch (relationEntityType) { + case THING: + urlString += "/Thing"; + break; + case LOCATION: + urlString += "/Locations"; + break; + default: + Assert.fail("Entity type relation is not recognized in SensorThings API : " + + parentEntityType + " and " + relationEntityType); + } + break; + case DATASTREAM: + urlString += "/Datastreams(" + parentId + ")"; + switch (relationEntityType) { + case THING: + urlString += "/Thing"; + break; + case SENSOR: + urlString += "/Sensor"; + break; + case OBSERVATION: + urlString += "/Observations"; + break; + case OBSERVED_PROPERTY: + urlString += "/ObservedProperty"; + break; + default: + Assert.fail("Entity type relation is not recognized in SensorThings API : " + + parentEntityType + " and " + relationEntityType); + } + break; + case SENSOR: + urlString += "/Sensors(" + parentId + ")"; + switch (relationEntityType) { + case DATASTREAM: + urlString += "/Datastreams"; + break; + default: + Assert.fail("Entity type relation is not recognized in SensorThings API : " + + parentEntityType + " and " + relationEntityType); + } + break; + case OBSERVATION: + urlString += "/Observations(" + parentId + ")"; + switch (relationEntityType) { + case THING: + case DATASTREAM: + urlString += "/Datastream"; + break; + case FEATURE_OF_INTEREST: + urlString += "/FeatureOfInterest"; + break; + default: + Assert.fail("Entity type relation is not recognized in SensorThings API : " + + parentEntityType + " and " + relationEntityType); + } + break; + case OBSERVED_PROPERTY: + urlString += "/ObservedProperties(" + parentId + ")"; + switch (relationEntityType) { + case DATASTREAM: + urlString += "/Datastreams"; + break; + default: + Assert.fail("Entity type relation is not recognized in SensorThings API : " + + parentEntityType + " and " + relationEntityType); + } + break; + case FEATURE_OF_INTEREST: + urlString += "/FeaturesOfInterest(" + parentId + ")"; + switch (relationEntityType) { + case OBSERVATION: + urlString += "/Observations"; + break; + default: + Assert.fail("Entity type relation is not recognized in SensorThings API : " + + parentEntityType + " and " + relationEntityType); + } + break; + default: + Assert.fail("Entity type is not recognized in SensorThings API : " + parentEntityType); + } + } + if (property != null) { + if (property.indexOf('?') >= 0) { + urlString += property; + } + else { + urlString += "/" + property; + } + } + return urlString; + } + + /** + * Build the URL String based on a chain of entity type hierarchy and ids, and the + * targeted property or query + * @param rootURI The base URL of the SensorThings Service + * @param entityTypes The list of entity type chain + * @param ids The ids for the entity type chain + * @param property The targeted property or the query string + * @return The URL String created based on the input parameters + */ + public static String buildURLString(String rootURI, List entityTypes, List ids, String property) { + String urlString = rootURI; + if (entityTypes.size() != ids.size() && entityTypes.size() != ids.size() + 1) { + Assert.fail("There is problem with the path of entities!!!"); + } + if (urlString.charAt(urlString.length() - 1) != '/') { + urlString += '/'; + } + for (int i = 0; i < entityTypes.size(); i++) { + urlString += entityTypes.get(i); + if (i < ids.size()) { + if (ids.get(i) == null) { + urlString += "/"; + } + else { + urlString += "(" + ids.get(i) + ")/"; + } + } + } + if (urlString.charAt(urlString.length() - 1) == '/') { + urlString = urlString.substring(0, urlString.length() - 1); + } + if (property != null) { + if (property.indexOf('?') >= 0) { + urlString += property; + } + else { + urlString += "/" + property; + } + } + return urlString; + } - /** - * Build the URL String based on a chain of entity type hierarchy and ids, and the targeted property or query - * - * @param rootURI The base URL of the SensorThings Service - * @param entityTypes The list of entity type chain - * @param ids The ids for the entity type chain - * @param property The targeted property or the query string - * @return The URL String created based on the input parameters - */ - public static String buildURLString(String rootURI, List entityTypes, List ids, String property) { - String urlString = rootURI; - if (entityTypes.size() != ids.size() && entityTypes.size() != ids.size() + 1) { - Assert.fail("There is problem with the path of entities!!!"); - } - if (urlString.charAt(urlString.length() - 1) != '/') { - urlString += '/'; - } - for (int i = 0; i < entityTypes.size(); i++) { - urlString += entityTypes.get(i); - if (i < ids.size()) { - if (ids.get(i) == null) { - urlString += "/"; - } else { - urlString += "(" + ids.get(i) + ")/"; - } - } - } - if (urlString.charAt(urlString.length() - 1) == '/') { - urlString = urlString.substring(0, urlString.length() - 1); - } - if (property != null) { - if (property.indexOf('?') >= 0) { - urlString += property; - } else { - urlString += "/" + property; - } - } - return urlString; - } } diff --git a/src/main/java/org/opengis/cite/sta10/util/TestSuiteLogger.java b/src/main/java/org/opengis/cite/sta10/util/TestSuiteLogger.java index ebf837a..fe9c203 100644 --- a/src/main/java/org/opengis/cite/sta10/util/TestSuiteLogger.java +++ b/src/main/java/org/opengis/cite/sta10/util/TestSuiteLogger.java @@ -4,70 +4,65 @@ import java.util.logging.Logger; /** - * Logging utility class that provides simple access to the JDK Logging API. Set - * the "java.util.logging.config.file" system property to specify the location - * of the desired logging configuration file. A sample configuration file is - * available at {@code src/main/config/logging.properties}. + * Logging utility class that provides simple access to the JDK Logging API. Set the + * "java.util.logging.config.file" system property to specify the location of the desired + * logging configuration file. A sample configuration file is available at + * {@code src/main/config/logging.properties}. * * @see java.util.logging.LogManager LogManager */ public class TestSuiteLogger { - private static final Logger LOGR = - Logger.getLogger(TestSuiteLogger.class.getPackage().getName()); + private static final Logger LOGR = Logger.getLogger(TestSuiteLogger.class.getPackage().getName()); - /** - * Logs a message at the specified logging level with the given message - * parameters. - * - * @param level The logging {@link Level level}. - * @param message A String representing the content of the log message. - * @param params An array of message parameters. - */ - public static void log(Level level, String message, Object[] params) { - if (LOGR.isLoggable(level)) { - LOGR.log(level, message, params); - } - } + /** + * Logs a message at the specified logging level with the given message parameters. + * @param level The logging {@link Level level}. + * @param message A String representing the content of the log message. + * @param params An array of message parameters. + */ + public static void log(Level level, String message, Object[] params) { + if (LOGR.isLoggable(level)) { + LOGR.log(level, message, params); + } + } - /** - * Logs a message at the specified logging level with the given Exception - * object that represents a noteworthy error condition. - * - * @param level The logging {@link Level level}. - * @param message A String representing the content of the log message. - * @param except An object that indicates an exceptional situation. - */ - public static void log(Level level, String message, Exception except) { - if (LOGR.isLoggable(level)) { - LOGR.log(level, message, except); - } - } + /** + * Logs a message at the specified logging level with the given Exception object that + * represents a noteworthy error condition. + * @param level The logging {@link Level level}. + * @param message A String representing the content of the log message. + * @param except An object that indicates an exceptional situation. + */ + public static void log(Level level, String message, Exception except) { + if (LOGR.isLoggable(level)) { + LOGR.log(level, message, except); + } + } - /** - * Logs a simple message at the specified logging level. - * - * @param level The logging {@link Level level}. - * @param message A String representing the content of the log message. - */ - public static void log(Level level, String message) { - if (LOGR.isLoggable(level)) { - LOGR.log(level, message); - } - } + /** + * Logs a simple message at the specified logging level. + * @param level The logging {@link Level level}. + * @param message A String representing the content of the log message. + */ + public static void log(Level level, String message) { + if (LOGR.isLoggable(level)) { + LOGR.log(level, message); + } + } - /** - * Indicates if the logger is enabled at a given logging level. Message - * levels lower than this value will be discarded. - * - * @param level The logging {@link Level level}. - * @return true if the logger is currently enabled for this logging level; - * false otherwise. - */ - public static boolean isLoggable(Level level) { - return LOGR.isLoggable(level); - } + /** + * Indicates if the logger is enabled at a given logging level. Message levels lower + * than this value will be discarded. + * @param level The logging {@link Level level}. + * @return true if the logger is currently enabled for this logging level; false + * otherwise. + */ + public static boolean isLoggable(Level level) { + return LOGR.isLoggable(level); + } + + private TestSuiteLogger() { + } - private TestSuiteLogger() { - } } diff --git a/src/test/java/org/opengis/cite/sta10/VerifyETSAssert.java b/src/test/java/org/opengis/cite/sta10/VerifyETSAssert.java index 77a42c0..c5ec1ae 100644 --- a/src/test/java/org/opengis/cite/sta10/VerifyETSAssert.java +++ b/src/test/java/org/opengis/cite/sta10/VerifyETSAssert.java @@ -21,53 +21,59 @@ public class VerifyETSAssert { - private static final String WADL_NS = "http://wadl.dev.java.net/2009/02"; - private static DocumentBuilder docBuilder; - private static SchemaFactory factory; - @Rule - public ExpectedException thrown = ExpectedException.none(); + private static final String WADL_NS = "http://wadl.dev.java.net/2009/02"; - public VerifyETSAssert() { - } + private static DocumentBuilder docBuilder; - @BeforeClass - public static void setUpClass() throws ParserConfigurationException { - factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - docBuilder = dbf.newDocumentBuilder(); - } + private static SchemaFactory factory; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + public VerifyETSAssert() { + } + + @BeforeClass + public static void setUpClass() throws ParserConfigurationException { + factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + docBuilder = dbf.newDocumentBuilder(); + } + + // @Test + // public void validateUsingSchemaHints_expect2Errors() throws SAXException { + // thrown.expect(AssertionError.class); + // thrown.expectMessage("2 schema validation error(s) detected"); + // URL url = this.getClass().getResource("/Gamma.xml"); + // Schema schema = factory.newSchema(); + // Validator validator = schema.newValidator(); + // ETSAssert + // .assertSchemaValid(validator, new StreamSource(url.toString())); + // } + // + // @Test + // public void assertXPathWithNamespaceBindings() throws SAXException, + // IOException { + // Document doc = docBuilder.parse(this.getClass().getResourceAsStream( + // "/capabilities-simple.xml")); + // Map nsBindings = new HashMap(); + // nsBindings.put(WADL_NS, "ns1"); + // String xpath = "//ns1:resources"; + // ETSAssert.assertXPath(xpath, doc, nsBindings); + // } + // + // @Test + // public void assertXPath_expectFalse() throws SAXException, IOException { + // thrown.expect(AssertionError.class); + // thrown.expectMessage("Unexpected result evaluating XPath expression"); + // Document doc = docBuilder.parse(this.getClass().getResourceAsStream( + // "/capabilities-simple.xml")); + // // using built-in namespace binding + // String xpath = + // "//ows:OperationsMetadata/ows:Constraint[@name='XMLEncoding']/ows:DefaultValue = + // 'TRUE'"; + // ETSAssert.assertXPath(xpath, doc, null); + // } -// @Test -// public void validateUsingSchemaHints_expect2Errors() throws SAXException { -// thrown.expect(AssertionError.class); -// thrown.expectMessage("2 schema validation error(s) detected"); -// URL url = this.getClass().getResource("/Gamma.xml"); -// Schema schema = factory.newSchema(); -// Validator validator = schema.newValidator(); -// ETSAssert -// .assertSchemaValid(validator, new StreamSource(url.toString())); -// } -// -// @Test -// public void assertXPathWithNamespaceBindings() throws SAXException, -// IOException { -// Document doc = docBuilder.parse(this.getClass().getResourceAsStream( -// "/capabilities-simple.xml")); -// Map nsBindings = new HashMap(); -// nsBindings.put(WADL_NS, "ns1"); -// String xpath = "//ns1:resources"; -// ETSAssert.assertXPath(xpath, doc, nsBindings); -// } -// -// @Test -// public void assertXPath_expectFalse() throws SAXException, IOException { -// thrown.expect(AssertionError.class); -// thrown.expectMessage("Unexpected result evaluating XPath expression"); -// Document doc = docBuilder.parse(this.getClass().getResourceAsStream( -// "/capabilities-simple.xml")); -// // using built-in namespace binding -// String xpath = "//ows:OperationsMetadata/ows:Constraint[@name='XMLEncoding']/ows:DefaultValue = 'TRUE'"; -// ETSAssert.assertXPath(xpath, doc, null); -// } } diff --git a/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java b/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java index eebf72c..63dfc1b 100644 --- a/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java +++ b/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java @@ -21,50 +21,50 @@ public class VerifySuiteFixtureListener { - private static XmlSuite xmlSuite; - private static ISuite suite; + private static XmlSuite xmlSuite; - public VerifySuiteFixtureListener() { - } + private static ISuite suite; - @BeforeClass - public static void setUpClass() { - xmlSuite = mock(XmlSuite.class); - suite = mock(ISuite.class); - when(suite.getXmlSuite()).thenReturn(xmlSuite); - } + public VerifySuiteFixtureListener() { + } - @AfterClass - public static void tearDownClass() { - } + @BeforeClass + public static void setUpClass() { + xmlSuite = mock(XmlSuite.class); + suite = mock(ISuite.class); + when(suite.getXmlSuite()).thenReturn(xmlSuite); + } - @Before - public void setUp() { - } + @AfterClass + public static void tearDownClass() { + } - @After - public void tearDown() { - } + @Before + public void setUp() { + } - @Test(expected = IllegalArgumentException.class) - public void noSuiteParameters() { - Map params = new HashMap(); - when(xmlSuite.getParameters()).thenReturn(params); - SuiteFixtureListener iut = new SuiteFixtureListener(); - iut.onStart(suite); - } + @After + public void tearDown() { + } - @Test - public void processIUTParameter() throws URISyntaxException { - URL url = this.getClass().getResource("/atom-feed.xml"); - Map params = new HashMap(); - params.put(TestRunArg.IUT.toString(), url.toURI().toString()); - when(xmlSuite.getParameters()).thenReturn(params); - SuiteFixtureListener iut = new SuiteFixtureListener(); - iut.onStart(suite); - verify(suite).setAttribute( - ArgumentMatchers.eq(SuiteAttribute.TEST_SUBJECT.getName()), - ArgumentMatchers.isA(Document.class)); - } + @Test(expected = IllegalArgumentException.class) + public void noSuiteParameters() { + Map params = new HashMap(); + when(xmlSuite.getParameters()).thenReturn(params); + SuiteFixtureListener iut = new SuiteFixtureListener(); + iut.onStart(suite); + } + + @Test + public void processIUTParameter() throws URISyntaxException { + URL url = this.getClass().getResource("/atom-feed.xml"); + Map params = new HashMap(); + params.put(TestRunArg.IUT.toString(), url.toURI().toString()); + when(xmlSuite.getParameters()).thenReturn(params); + SuiteFixtureListener iut = new SuiteFixtureListener(); + iut.onStart(suite); + verify(suite).setAttribute(ArgumentMatchers.eq(SuiteAttribute.TEST_SUBJECT.getName()), + ArgumentMatchers.isA(Document.class)); + } } diff --git a/src/test/java/org/opengis/cite/sta10/VerifyTestNGController.java b/src/test/java/org/opengis/cite/sta10/VerifyTestNGController.java index 6153736..b84c85a 100644 --- a/src/test/java/org/opengis/cite/sta10/VerifyTestNGController.java +++ b/src/test/java/org/opengis/cite/sta10/VerifyTestNGController.java @@ -14,47 +14,45 @@ /** * Verifies the results of executing a test run using the main controller * (TestNGController). - * + * */ public class VerifyTestNGController { - private static DocumentBuilder docBuilder; - private Properties testRunProps; - - @BeforeClass - public static void initParser() throws ParserConfigurationException { - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - dbf.setNamespaceAware(true); - dbf.setValidating(false); - dbf.setFeature( - "http://apache.org/xml/features/nonvalidating/load-external-dtd", - false); - docBuilder = dbf.newDocumentBuilder(); - } - - @Before - public void loadDefaultTestRunProperties() - throws InvalidPropertiesFormatException, IOException { - this.testRunProps = new Properties(); - this.testRunProps.loadFromXML(getClass().getResourceAsStream( - "/test-run-props.xml")); - } - -// @Test -// public void doTestRun() throws Exception { -// URL testSubject = getClass().getResource("/atom-feed-2.xml"); -// this.testRunProps.setProperty(TestRunArg.IUT.toString(), testSubject -// .toURI().toString()); -// ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024); -// this.testRunProps.storeToXML(outStream, "Integration test"); -// Document testRunArgs = docBuilder.parse(new ByteArrayInputStream( -// outStream.toByteArray())); -// TestNGController controller = new TestNGController(); -// Source results = controller.doTestRun(testRunArgs); -// String xpath = "/testng-results/@failed"; -// XdmValue failed = XMLUtils.evaluateXPath2(results, xpath, null); -// int numFailed = Integer.parseInt(failed.getUnderlyingValue() -// .getStringValue()); -// assertEquals("Unexpected number of fail verdicts.", 0, numFailed); -// } + private static DocumentBuilder docBuilder; + + private Properties testRunProps; + + @BeforeClass + public static void initParser() throws ParserConfigurationException { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setNamespaceAware(true); + dbf.setValidating(false); + dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + docBuilder = dbf.newDocumentBuilder(); + } + + @Before + public void loadDefaultTestRunProperties() throws InvalidPropertiesFormatException, IOException { + this.testRunProps = new Properties(); + this.testRunProps.loadFromXML(getClass().getResourceAsStream("/test-run-props.xml")); + } + + // @Test + // public void doTestRun() throws Exception { + // URL testSubject = getClass().getResource("/atom-feed-2.xml"); + // this.testRunProps.setProperty(TestRunArg.IUT.toString(), testSubject + // .toURI().toString()); + // ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024); + // this.testRunProps.storeToXML(outStream, "Integration test"); + // Document testRunArgs = docBuilder.parse(new ByteArrayInputStream( + // outStream.toByteArray())); + // TestNGController controller = new TestNGController(); + // Source results = controller.doTestRun(testRunArgs); + // String xpath = "/testng-results/@failed"; + // XdmValue failed = XMLUtils.evaluateXPath2(results, xpath, null); + // int numFailed = Integer.parseInt(failed.getUnderlyingValue() + // .getStringValue()); + // assertEquals("Unexpected number of fail verdicts.", 0, numFailed); + // } + } From b266cbb0d9c6c1454fd6f9f98ca00768b794eb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Pro=C3=9F?= Date: Wed, 18 Dec 2024 15:32:44 +0100 Subject: [PATCH 4/8] Adjust assembly file --- src/assembly/deps.xml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/assembly/deps.xml b/src/assembly/deps.xml index 069f159..19c923f 100644 --- a/src/assembly/deps.xml +++ b/src/assembly/deps.xml @@ -10,21 +10,13 @@ false - - - com.sun.jersey:jersey-client - - / - false - runtime - false - org.opengis.cite.teamengine:teamengine-spi - com.sun.jersey:jersey-client - org.testng:testng - javax.ws.rs:jsr311-api + *:jersey-client + *:jersey-server + *:jersey-common + jakarta.ws.rs:jakarta.ws.rs-api / false @@ -34,3 +26,4 @@ + From d126ab8a23938891a9d2250e5cacffdc2ed24131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Pro=C3=9F?= Date: Wed, 18 Dec 2024 15:32:56 +0100 Subject: [PATCH 5/8] Adjust Dockerfile --- src/docker/Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/docker/Dockerfile b/src/docker/Dockerfile index a1d9b04..9b26eba 100644 --- a/src/docker/Dockerfile +++ b/src/docker/Dockerfile @@ -1,4 +1,6 @@ -FROM tomcat:7.0-jre8 +FROM tomcat:10.1-jre17 + +RUN apt update && apt install -y unzip # add TEAM Engine webapp ADD maven/dependency/teamengine-web-*.war /root/ @@ -21,5 +23,7 @@ RUN cd /root/ && unzip -q ets-sta10-*-ctl.zip -d /root/te_base/scripts ADD maven/ets-sta10-*-deps.zip /root/ RUN cd /root/ && unzip -q -o ets-sta10-*-deps.zip -d /usr/local/tomcat/webapps/teamengine/WEB-INF/lib +RUN rm -R /root/te_base/scripts/note + # run tomcat CMD ["catalina.sh", "run"] From b815d078d48a83d3020e1f04ba1a26be3292cf5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Pro=C3=9F?= Date: Wed, 18 Dec 2024 15:33:13 +0100 Subject: [PATCH 6/8] Re-enable test --- .../cite/sta10/SuiteFixtureListener.java | 3 +++ .../sta10/VerifySuiteFixtureListener.java | 23 ++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java b/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java index 053c7d9..95e9a34 100644 --- a/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java +++ b/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java @@ -70,6 +70,9 @@ void processSuiteParameters(ISuite suite) { suite.setAttribute(SuiteAttribute.LEVEL.getName(), level); String iutParam = params.get(TestRunArg.IUT.toString()); + if (iutParam == null) { + throw new IllegalArgumentException("No IUT specified."); + } String response = checkServiceRootUri(iutParam); if (!response.equals("")) { diff --git a/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java b/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java index 63dfc1b..1442d9c 100644 --- a/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java +++ b/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java @@ -55,16 +55,17 @@ public void noSuiteParameters() { iut.onStart(suite); } - @Test - public void processIUTParameter() throws URISyntaxException { - URL url = this.getClass().getResource("/atom-feed.xml"); - Map params = new HashMap(); - params.put(TestRunArg.IUT.toString(), url.toURI().toString()); - when(xmlSuite.getParameters()).thenReturn(params); - SuiteFixtureListener iut = new SuiteFixtureListener(); - iut.onStart(suite); - verify(suite).setAttribute(ArgumentMatchers.eq(SuiteAttribute.TEST_SUBJECT.getName()), - ArgumentMatchers.isA(Document.class)); - } + // STA uses only URLs, not files + // @Test + // public void processIUTParameter() throws URISyntaxException { + // URL url = this.getClass().getResource("/atom-feed.xml"); + // Map params = new HashMap(); + // params.put(TestRunArg.IUT.toString(), url.toURI().toString()); + // when(xmlSuite.getParameters()).thenReturn(params); + // SuiteFixtureListener iut = new SuiteFixtureListener(); + // iut.onStart(suite); + // verify(suite).setAttribute(ArgumentMatchers.eq(SuiteAttribute.TEST_SUBJECT.getName()), + // ArgumentMatchers.isA(Document.class)); + // } } From 3d2629be33c44174b166d4a960b26319bf7b270b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Pro=C3=9F?= Date: Wed, 18 Dec 2024 15:33:26 +0100 Subject: [PATCH 7/8] Adjust site descriptor --- src/site/site.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/site/site.xml b/src/site/site.xml index 01b3641..eb1a6ff 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -1,13 +1,13 @@ + xsi:schemaLocation="http://maven.apache.org/DECORATION/1.7.0 http://maven.apache.org/xsd/decoration-1.7.0.xsd"> org.apache.maven.skins maven-fluido-skin - 1.3.1 + 1.5 From 77c7a890b439c691458b6e6dbe6c88e0a649df71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Pro=C3=9F?= Date: Wed, 18 Dec 2024 16:09:52 +0100 Subject: [PATCH 8/8] Organize imports --- .../opengis/cite/sta10/TestNGController.java | 4 ---- .../opengis/cite/sta10/util/HTTPMethods.java | 23 +++++++++++-------- .../cite/sta10/util/ServiceURLBuilder.java | 1 + .../opengis/cite/sta10/VerifyETSAssert.java | 11 +-------- .../sta10/VerifySuiteFixtureListener.java | 5 ---- 5 files changed, 15 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/opengis/cite/sta10/TestNGController.java b/src/main/java/org/opengis/cite/sta10/TestNGController.java index e82b72a..57584db 100644 --- a/src/main/java/org/opengis/cite/sta10/TestNGController.java +++ b/src/main/java/org/opengis/cite/sta10/TestNGController.java @@ -5,8 +5,6 @@ import java.io.InputStream; import java.net.URI; import java.net.URL; -import java.util.HashMap; -import java.util.Map; import java.util.Properties; import java.util.logging.Level; @@ -16,8 +14,6 @@ import org.opengis.cite.sta10.util.TestSuiteLogger; import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; import com.occamlab.te.spi.executors.TestRunExecutor; import com.occamlab.te.spi.executors.testng.TestNGExecutor; diff --git a/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java b/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java index c2a43f5..4ccf00c 100644 --- a/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java +++ b/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java @@ -1,6 +1,19 @@ package org.opengis.cite.sta10.util; +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPatch; @@ -9,16 +22,6 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; -import org.testng.Assert; - -import java.io.*; -import java.net.HttpURLConnection; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; /** * Sending HTTP Methods: GET, POST, PUT, PATCH, and DELETE diff --git a/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java b/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java index d3fde82..f972a6b 100644 --- a/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java +++ b/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java @@ -1,6 +1,7 @@ package org.opengis.cite.sta10.util; import java.util.List; + import org.testng.Assert; /** diff --git a/src/test/java/org/opengis/cite/sta10/VerifyETSAssert.java b/src/test/java/org/opengis/cite/sta10/VerifyETSAssert.java index c5ec1ae..272dcaa 100644 --- a/src/test/java/org/opengis/cite/sta10/VerifyETSAssert.java +++ b/src/test/java/org/opengis/cite/sta10/VerifyETSAssert.java @@ -1,23 +1,14 @@ package org.opengis.cite.sta10; -import java.io.IOException; -import java.net.URL; -import java.util.HashMap; -import java.util.Map; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; + import org.junit.BeforeClass; import org.junit.Rule; -import org.junit.Test; import org.junit.rules.ExpectedException; -import org.w3c.dom.Document; -import org.xml.sax.SAXException; public class VerifyETSAssert { diff --git a/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java b/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java index 1442d9c..fa27bd3 100644 --- a/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java +++ b/src/test/java/org/opengis/cite/sta10/VerifySuiteFixtureListener.java @@ -1,11 +1,8 @@ package org.opengis.cite.sta10; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.net.URISyntaxException; -import java.net.URL; import java.util.HashMap; import java.util.Map; @@ -14,10 +11,8 @@ import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.mockito.ArgumentMatchers; import org.testng.ISuite; import org.testng.xml.XmlSuite; -import org.w3c.dom.Document; public class VerifySuiteFixtureListener {