diff --git a/pom.xml b/pom.xml index 4912b61..fedacfb 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 4.0.0 ets-sta10 - 0.8-SNAPSHOT + 1.1-SNAPSHOT jar SensorThings API (STA) @@ -76,7 +76,7 @@ org.json json - 20090211 + 20171018 org.apache.httpcomponents diff --git a/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java b/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java index a16ad47..bf7bf05 100644 --- a/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java +++ b/src/main/java/org/opengis/cite/sta10/ReusableEntityFilter.java @@ -8,7 +8,7 @@ /** * Buffers the (response) entity so it can be read multiple times. *

- *

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

*/ public class ReusableEntityFilter extends ClientFilter { diff --git a/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java b/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java index e556629..ec5b794 100644 --- a/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java +++ b/src/main/java/org/opengis/cite/sta10/SuiteFixtureListener.java @@ -1,13 +1,11 @@ package org.opengis.cite.sta10; import com.sun.jersey.api.client.Client; - import java.io.*; import java.net.*; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -46,9 +44,8 @@ public void onFinish(ISuite suite) { * 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. + * + * @param suite An ISuite object representing a TestNG test suite. */ void processSuiteParameters(ISuite suite) { Map params = suite.getXmlSuite().getParameters(); @@ -67,7 +64,7 @@ void processSuiteParameters(ISuite suite) { String iutParam = params.get(TestRunArg.IUT.toString()); String response = checkServiceRootUri(iutParam); - if(!response.equals("")){ + if (!response.equals("")) { throw new IllegalArgumentException( response); } @@ -76,7 +73,7 @@ void processSuiteParameters(ISuite suite) { StringBuilder logMsg = new StringBuilder( "Parsed resource retrieved from "); logMsg.append(TestRunArg.IUT).append("\n"); - // logMsg.append(XMLUtils.writeNodeToString(iutDoc)); + // logMsg.append(XMLUtils.writeNodeToString(iutDoc)); TestSuiteLogger.log(Level.FINE, logMsg.toString()); } } @@ -97,13 +94,16 @@ void registerClientComponent(ISuite suite) { /** * 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. + * @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); + if (rootUri.lastIndexOf('/') == rootUri.length() - 1) { + rootUri = rootUri.substring(0, rootUri.length() - 1); } HttpURLConnection connection = null; String response = null; @@ -112,7 +112,7 @@ private String checkServiceRootUri(String rootUri) { try { url = new URL(rootUri); - connection = (HttpURLConnection) url.openConnection(); + connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setRequestProperty("Content-Type", "application/json"); @@ -133,13 +133,13 @@ private String checkServiceRootUri(String rootUri) { rd.close(); } catch (MalformedURLException e) { e.printStackTrace(); - return "Cannot connect to "+rootUri+"."; + return "Cannot connect to " + rootUri + "."; } catch (ProtocolException e) { e.printStackTrace(); - return "Cannot connect to "+rootUri+"."; + return "Cannot connect to " + rootUri + "."; } catch (IOException e) { e.printStackTrace(); - return "Cannot connect to "+rootUri+"."; + return "Cannot connect to " + rootUri + "."; } JSONObject jsonResponse = null; JSONArray entities = null; @@ -148,13 +148,14 @@ private String checkServiceRootUri(String rootUri) { entities = jsonResponse.getJSONArray("value"); } catch (JSONException e) { e.printStackTrace(); - return "The service response for the root URI \""+rootUri+"\" is not JSON."; + 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("MultiDatastreams", true); addedLinks.put("Sensors", false); addedLinks.put("Observations", false); addedLinks.put("ObservedProperties", false); @@ -164,82 +165,30 @@ private String checkServiceRootUri(String rootUri) { String name, nameUrl; try { entity = entities.getJSONObject(i); - if(entity.get("name") == null){ + if (entity.get("name") == null) { return "The name component of Service root URI response is not available."; } - if(entity.get("url") == null){ + if (entity.get("url") == null) { return "The name component of Service root URI response is not available."; } 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."; + 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; - default: - return "There is a component in Service Root URI response that is not in SensorThings API : " + name; + if (addedLinks.containsKey(name)) { + if (!nameUrl.equals(rootUri + "/" + name)) { + return "The URL for " + name + " in Service Root URI is not compliant to SensorThings API."; + } + addedLinks.put(name, true); + } else { + 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 "; + 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/TestRunListener.java b/src/main/java/org/opengis/cite/sta10/TestRunListener.java index bfe9d5a..03e52b9 100644 --- a/src/main/java/org/opengis/cite/sta10/TestRunListener.java +++ b/src/main/java/org/opengis/cite/sta10/TestRunListener.java @@ -6,8 +6,9 @@ * 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 + * 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.

* 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 88e7c76..fcb60de 100644 --- a/src/main/java/org/opengis/cite/sta10/createUpdateDelete/Capability2Tests.java +++ b/src/main/java/org/opengis/cite/sta10/createUpdateDelete/Capability2Tests.java @@ -5,16 +5,17 @@ import java.util.Iterator; import java.util.List; import java.util.Map; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.opengis.cite.sta10.SuiteAttribute; import org.opengis.cite.sta10.util.ControlInformation; -import org.opengis.cite.sta10.util.EntityProperties; import org.opengis.cite.sta10.util.EntityType; import org.opengis.cite.sta10.util.HTTPMethods; import org.opengis.cite.sta10.util.ServiceURLBuilder; +import org.opengis.cite.sta10.util.Utils; +import static org.opengis.cite.sta10.util.Utils.quoteIdForJson; +import static org.opengis.cite.sta10.util.Utils.quoteIdForUrl; import org.testng.Assert; import org.testng.ITestContext; import org.testng.annotations.AfterClass; @@ -35,42 +36,42 @@ public class Capability2Tests { * The list of ids for all the Things created during test procedure (will be * used for clean-up) */ - private List thingIds = new ArrayList<>(); + 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<>(); + 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<>(); + 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<>(); + 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<>(); + 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<>(); + 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<>(); + 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<>(); + private List foiIds = new ArrayList<>(); /** * This method will be run before starting the test for this conformance @@ -112,7 +113,7 @@ public void createEntities() { + "\"description\":\"This is a Test Thing From TestNG\"" + "}"; JSONObject entity = postEntity(EntityType.THING, urlParameters); - long thingId = entity.getLong(ControlInformation.ID); + Object thingId = entity.get(ControlInformation.ID); thingIds.add(thingId); /* Location */ @@ -123,7 +124,7 @@ public void createEntities() { + " \"location\": { \"type\": \"Point\", \"coordinates\": [-114.05, 51.05] }\n" + "}"; entity = postEntity(EntityType.LOCATION, urlParameters); - long locationId = entity.getLong(ControlInformation.ID); + Object locationId = entity.get(ControlInformation.ID); locationIds.add(locationId); JSONObject locationEntity = entity; @@ -135,7 +136,7 @@ public void createEntities() { + " \"metadata\": \"Barometer\"\n" + "}"; entity = postEntity(EntityType.SENSOR, urlParameters); - long sensorId = entity.getLong(ControlInformation.ID); + Object sensorId = entity.get(ControlInformation.ID); sensorIds.add(sensorId); /* ObservedProperty */ @@ -145,7 +146,7 @@ public void createEntities() { + " \"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); + Object obsPropId = entity.get(ControlInformation.ID); obsPropIds.add(obsPropId); /* FeatureOfInterest */ @@ -162,7 +163,7 @@ public void createEntities() { + " }\n" + "}"; entity = postEntity(EntityType.FEATURE_OF_INTEREST, urlParameters); - long foiId = entity.getLong(ControlInformation.ID); + Object foiId = entity.get(ControlInformation.ID); foiIds.add(foiId); /* Datastream */ @@ -175,61 +176,63 @@ public void createEntities() { + " \"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" + + " \"Thing\": { \"@iot.id\": " + quoteIdForJson(thingId) + " },\n" + + " \"ObservedProperty\":{ \"@iot.id\":" + quoteIdForJson(obsPropId) + "},\n" + + " \"Sensor\": { \"@iot.id\": " + quoteIdForJson(sensorId) + " }\n" + "}"; entity = postEntity(EntityType.DATASTREAM, urlParameters); - long datastreamId = entity.getLong(ControlInformation.ID); + Object datastreamId = entity.get(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" + + " \"Datastream\":{\"@iot.id\": " + quoteIdForJson(datastreamId) + "},\n" + + " \"FeatureOfInterest\": {\"@iot.id\": " + quoteIdForJson(foiId) + "} \n" + "}"; entity = postEntity(EntityType.OBSERVATION, urlParameters); - long obsId1 = entity.getLong(ControlInformation.ID); + Object obsId1 = entity.get(ControlInformation.ID); observationIds.add(obsId1); + //POST Observation without FOI (Automatic creation of FOI) //Add location to the Thing - urlParameters = "{\"Locations\":[{\"@iot.id\":" + locationId + "}]}"; + urlParameters = "{\"Locations\":[{\"@iot.id\":" + quoteIdForJson(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" + + " \"Datastream\":{\"@iot.id\": " + quoteIdForJson(datastreamId) + "}\n" + "}"; entity = postEntity(EntityType.OBSERVATION, urlParameters); checkForObservationResultTime(entity, "2015-03-01T01:00:00.000Z"); - long obsId2 = entity.getLong(ControlInformation.ID); + Object obsId2 = entity.get(ControlInformation.ID); observationIds.add(obsId2); - long automatedFOIId = checkAutomaticInsertionOfFOI(obsId2, locationEntity, -1); + Object automatedFOIId = checkAutomaticInsertionOfFOI(obsId2, locationEntity, null); 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" + + " \"Datastream\":{\"@iot.id\": " + quoteIdForJson(datastreamId) + "}\n" + "}"; entity = postEntity(EntityType.OBSERVATION, urlParameters); checkForObservationResultTime(entity, null); - long obsId3 = entity.getLong(ControlInformation.ID); + Object obsId3 = entity.get(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" + + " \"Thing\":{\"@iot.id\": " + quoteIdForJson(thingId) + "},\n" + + " \"Locations\": [{\"@iot.id\": " + quoteIdForJson(locationId) + "}] \n" + "}"; entity = postEntity(EntityType.HISTORICAL_LOCATION, urlParameters); - long histLocId = entity.getLong(ControlInformation.ID); + Object histLocId = entity.get(ControlInformation.ID); historicalLocationIds.add(histLocId); } catch (JSONException e) { @@ -287,7 +290,7 @@ public void createEntitiesWithDeepInsert() { + " ]\n" + "}"; JSONObject entity = postEntity(EntityType.THING, urlParameters); - long thingId = entity.getLong(ControlInformation.ID); + Object thingId = entity.get(ControlInformation.ID); //Check Datastream JSONObject deepInsertedObj = new JSONObject("{\n" + " \"unitOfMeasurement\": {\n" @@ -299,7 +302,7 @@ public void createEntitiesWithDeepInsert() { + " \"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); + Object datastreamId = checkRelatedEntity(EntityType.THING, thingId, EntityType.DATASTREAM, deepInsertedObj); datastreamIds.add(datastreamId); //Check Location deepInsertedObj = new JSONObject("{\n" @@ -336,7 +339,7 @@ public void createEntitiesWithDeepInsert() { + " \"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" + + " \"Thing\": { \"@iot.id\": " + quoteIdForJson(thingId) + " },\n" + " \"ObservedProperty\": {\n" + " \"name\": \"Luminous Flux\",\n" + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" @@ -356,7 +359,7 @@ public void createEntitiesWithDeepInsert() { + " ]" + "}"; entity = postEntity(EntityType.DATASTREAM, urlParameters); - datastreamId = entity.getLong(ControlInformation.ID); + datastreamId = entity.get(ControlInformation.ID); //Check Sensor deepInsertedObj = new JSONObject("{\n" + " \"name\": \"Acme Fluxomatic 1000\",\n" @@ -396,10 +399,10 @@ public void createEntitiesWithDeepInsert() { + " ]\n" + " }\n" + " },\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" + + " \"Datastream\":{\"@iot.id\": " + quoteIdForJson(datastreamId) + "}\n" + "}"; entity = postEntity(EntityType.OBSERVATION, urlParameters); - long obsId1 = entity.getLong(ControlInformation.ID); + Object obsId1 = entity.get(ControlInformation.ID); //Check FeaturOfInterest deepInsertedObj = new JSONObject("{\n" + " \"name\": \"A weather station.\",\n" @@ -477,7 +480,7 @@ public void createInvalidEntitiesWithDeepInsert() { + "\"name\": \"Office Building\"," + "\"description\": \"Office Building\"" + "}"; - long thingId = postEntity(EntityType.THING, urlParameters).getLong("@iot.id"); + Object thingId = postEntity(EntityType.THING, urlParameters).get("@iot.id"); urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" @@ -488,7 +491,7 @@ public void createInvalidEntitiesWithDeepInsert() { + " \"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" + + " \"Thing\": { \"@iot.id\": " + quoteIdForJson(thingId) + " },\n" + " \"ObservedProperty\": {\n" + " \"name\": \"Luminous Flux\",\n" + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" @@ -512,7 +515,7 @@ public void createInvalidEntitiesWithDeepInsert() { + " \"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" + + " \"Thing\": { \"@iot.id\": " + quoteIdForJson(thingId) + " },\n" + " \"Sensor\": { \n" + " \"name\": \"Acme Fluxomatic 1000\",\n" + " \"description\": \"Acme Fluxomatic 1000\",\n" @@ -565,7 +568,7 @@ public void createInvalidEntitiesWithDeepInsert() { // " },\n" + // " \"description\": \"test datastream.\",\n" + // " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + -// " \"Thing\": { \"@iot.id\": " + thingId + " },\n" + +// " \"Thing\": { \"@iot.id\": " + quoteIdForJson(thingId) + " },\n" + // " \"ObservedProperty\": {\n" + // " \"name\": \"Luminous Flux\",\n" + // " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" + @@ -600,7 +603,7 @@ public void createInvalidEntitiesWithDeepInsert() { + " \"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" + + " \"Thing\": { \"@iot.id\": " + quoteIdForJson(thingId) + " },\n" + " \"ObservedProperty\": {\n" + " \"name\": \"Luminous Flux\",\n" + " \"definition\": \"http://www.qudt.org/qudt/owl/1.0.0/quantity/Instances.html#LuminousFlux\",\n" @@ -613,12 +616,12 @@ public void createInvalidEntitiesWithDeepInsert() { + " \"metadata\": \"Light flux sensor\"\n" + " }\n" + "}"; - long datastreamId = postEntity(EntityType.DATASTREAM, urlParameters).getLong("@iot.id"); + Object datastreamId = postEntity(EntityType.DATASTREAM, urlParameters).get("@iot.id"); urlParameters = "{\n" + " \"phenomenonTime\": \"2015-03-01T00:00:00Z\",\n" + " \"result\": 100,\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" + + " \"Datastream\":{\"@iot.id\": " + quoteIdForJson(datastreamId) + "}\n" + "}"; postInvalidEntity(EntityType.OBSERVATION, urlParameters); @@ -636,7 +639,7 @@ public void createInvalidEntitiesWithDeepInsert() { + " ]\n" + " }\n" + " },\n" - + " \"Datastream\":{\"@iot.id\": " + datastreamId + "}\n" + + " \"Datastream\":{\"@iot.id\": " + quoteIdForJson(datastreamId) + "}\n" + "}"; postInvalidEntity(EntityType.OBSERVATION, urlParameters); @@ -671,8 +674,8 @@ public void createInvalidEntities() { + " \"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" + + " \"Thing\": { \"@iot.id\": " + quoteIdForJson(thingIds.get(0)) + " },\n" + + " \"ObservedProperty\":{ \"@iot.id\":" + quoteIdForJson(obsPropIds.get(0)) + "}\n" + "}"; postInvalidEntity(EntityType.DATASTREAM, urlParameters); //Without ObservedProperty @@ -685,8 +688,8 @@ public void createInvalidEntities() { + " \"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" + + " \"Thing\": { \"@iot.id\": " + quoteIdForJson(thingIds.get(0)) + " },\n" + + " \"Sensor\": { \"@iot.id\": " + quoteIdForJson(sensorIds.get(0)) + " }\n" + "}"; postInvalidEntity(EntityType.DATASTREAM, urlParameters); //Without Things @@ -699,8 +702,8 @@ public void createInvalidEntities() { + " \"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" + + " \"ObservedProperty\":{ \"@iot.id\":" + quoteIdForJson(obsPropIds.get(0)) + "},\n" + + " \"Sensor\": { \"@iot.id\": " + quoteIdForJson(sensorIds.get(0)) + " }\n" + "}"; postInvalidEntity(EntityType.DATASTREAM, urlParameters); @@ -710,7 +713,7 @@ public void createInvalidEntities() { + "\"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); + Object thingId = postEntity(EntityType.THING, urlParameters).get(ControlInformation.ID); thingIds.add(thingId); urlParameters = "{\n" + " \"unitOfMeasurement\": {\n" @@ -721,24 +724,24 @@ public void createInvalidEntities() { + " \"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" + + " \"Thing\": { \"@iot.id\": " + quoteIdForJson(thingId) + " },\n" + + " \"ObservedProperty\":{ \"@iot.id\":" + quoteIdForJson(obsPropIds.get(0)) + "},\n" + + " \"Sensor\": { \"@iot.id\": " + quoteIdForJson(sensorIds.get(0)) + " }\n" + "}"; - long datastreamId = postEntity(EntityType.DATASTREAM, urlParameters).getLong(ControlInformation.ID); + Object datastreamId = postEntity(EntityType.DATASTREAM, urlParameters).get(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" + + " \"FeatureOfInterest\": {\"@iot.id\": " + quoteIdForJson(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" + + " \"Datastream\":{\"@iot.id\": " + quoteIdForJson(datastreamId) + "}\n" + "}"; postInvalidEntity(EntityType.OBSERVATION, urlParameters); @@ -758,7 +761,7 @@ public void createInvalidEntities() { public void patchEntities() { try { /* Thing */ - long thingId = thingIds.get(0); + Object 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<>(); @@ -767,7 +770,7 @@ public void patchEntities() { checkPatch(EntityType.THING, entity, updatedEntity, diffs); /* Location */ - long locationId = locationIds.get(0); + Object locationId = locationIds.get(0); entity = getEntity(EntityType.LOCATION, locationId); urlParameters = "{\"location\": { \"type\": \"Point\", \"coordinates\": [114.05, -50] }}"; diffs = new HashMap<>(); @@ -776,7 +779,7 @@ public void patchEntities() { checkPatch(EntityType.LOCATION, entity, updatedEntity, diffs); /* HistoricalLocation */ - long histLocId = historicalLocationIds.get(0); + Object histLocId = historicalLocationIds.get(0); entity = getEntity(EntityType.HISTORICAL_LOCATION, histLocId); urlParameters = "{\"time\": \"2015-07-01T00:00:00.000Z\"}"; diffs = new HashMap<>(); @@ -785,7 +788,7 @@ public void patchEntities() { checkPatch(EntityType.HISTORICAL_LOCATION, entity, updatedEntity, diffs); /* Sensor */ - long sensorId = sensorIds.get(0); + Object sensorId = sensorIds.get(0); entity = getEntity(EntityType.SENSOR, sensorId); urlParameters = "{\"metadata\": \"PATCHED\"}"; diffs = new HashMap<>(); @@ -794,7 +797,7 @@ public void patchEntities() { checkPatch(EntityType.SENSOR, entity, updatedEntity, diffs); /* ObserverdProperty */ - long obsPropId = obsPropIds.get(0); + Object obsPropId = obsPropIds.get(0); entity = getEntity(EntityType.OBSERVED_PROPERTY, obsPropId); urlParameters = "{\"description\":\"PATCHED\"}"; diffs = new HashMap<>(); @@ -803,7 +806,7 @@ public void patchEntities() { checkPatch(EntityType.OBSERVED_PROPERTY, entity, updatedEntity, diffs); /* FeatureOfInterest */ - long foiId = foiIds.get(0); + Object foiId = foiIds.get(0); entity = getEntity(EntityType.FEATURE_OF_INTEREST, foiId); urlParameters = "{\"feature\":{ \"type\": \"Point\", \"coordinates\": [114.05, -51.05] }}"; diffs = new HashMap<>(); @@ -812,7 +815,7 @@ public void patchEntities() { checkPatch(EntityType.FEATURE_OF_INTEREST, entity, updatedEntity, diffs); /* Datastream */ - long datastreamId = datastreamIds.get(0); + Object datastreamId = datastreamIds.get(0); entity = getEntity(EntityType.DATASTREAM, datastreamId); urlParameters = "{\"description\": \"Patched Description\"}"; diffs = new HashMap<>(); @@ -832,7 +835,7 @@ public void patchEntities() { checkPatch(EntityType.DATASTREAM, entity, updatedEntity, diffs); /* Observation */ - long obsId1 = observationIds.get(0); + Object obsId1 = observationIds.get(0); entity = getEntity(EntityType.OBSERVATION, obsId1); urlParameters = "{\"phenomenonTime\": \"2015-07-01T00:40:00.000Z\"}"; diffs = new HashMap<>(); @@ -855,7 +858,7 @@ public void patchEntities() { public void putEntities() { try { /* Thing */ - long thingId = thingIds.get(0); + Object thingId = thingIds.get(0); JSONObject entity = getEntity(EntityType.THING, thingId); String urlParameters = "{" + "\"name\":\"This is a Updated Test Thing From TestNG\"," @@ -868,7 +871,7 @@ public void putEntities() { checkPut(EntityType.THING, entity, updatedEntity, diffs); /* Location */ - long locationId = locationIds.get(0); + Object locationId = locationIds.get(0); entity = getEntity(EntityType.LOCATION, locationId); urlParameters = "{" + "\"encodingType\":\"application/vnd.geo+json\"," @@ -883,7 +886,7 @@ public void putEntities() { checkPut(EntityType.LOCATION, entity, updatedEntity, diffs); /* HistoricalLocation */ - long histLocId = historicalLocationIds.get(0); + Object histLocId = historicalLocationIds.get(0); entity = getEntity(EntityType.HISTORICAL_LOCATION, histLocId); urlParameters = "{\"time\": \"2015-08-01T00:00:00.000Z\"}"; diffs = new HashMap<>(); @@ -892,7 +895,7 @@ public void putEntities() { checkPut(EntityType.HISTORICAL_LOCATION, entity, updatedEntity, diffs); /* Sensor */ - long sensorId = sensorIds.get(0); + Object sensorId = sensorIds.get(0); entity = getEntity(EntityType.SENSOR, sensorId); urlParameters = "{" + "\"name\": \"UPDATED\", " @@ -907,7 +910,7 @@ public void putEntities() { checkPut(EntityType.SENSOR, entity, updatedEntity, diffs); /* ObserverdProperty */ - long obsPropId = obsPropIds.get(0); + Object obsPropId = obsPropIds.get(0); urlParameters = "{" + "\"name\":\"QWERTY\", " + "\"definition\": \"ZXCVB\", " @@ -923,7 +926,7 @@ public void putEntities() { checkPut(EntityType.OBSERVED_PROPERTY, entity, updatedEntity, diffs); /* FeatureOfInterest */ - long foiId = foiIds.get(0); + Object foiId = foiIds.get(0); entity = getEntity(EntityType.FEATURE_OF_INTEREST, foiId); urlParameters = "{" + "\"encodingType\":\"application/vnd.geo+json\"," @@ -939,7 +942,7 @@ public void putEntities() { checkPut(EntityType.FEATURE_OF_INTEREST, entity, updatedEntity, diffs); /* Datastream */ - long datastreamId = datastreamIds.get(0); + Object datastreamId = datastreamIds.get(0); entity = getEntity(EntityType.DATASTREAM, datastreamId); urlParameters = "{\n" + " \"name\": \"Data coming from sensor on ISS.\",\n" @@ -960,7 +963,7 @@ public void putEntities() { checkPut(EntityType.DATASTREAM, entity, updatedEntity, diffs); /* Observation */ - long obsId1 = observationIds.get(0); + Object obsId1 = observationIds.get(0); entity = getEntity(EntityType.OBSERVATION, obsId1); urlParameters = "{\"result\": \"99\", \"phenomenonTime\": \"2015-08-01T00:40:00.000Z\"}"; diffs = new HashMap<>(); @@ -1147,7 +1150,6 @@ private void checkDeleteIntegrityConstraint() { } //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. @@ -1157,7 +1159,7 @@ public void invalidPatchEntities() { /** * Thing * */ - long thingId = thingIds.get(0); + Object thingId = thingIds.get(0); String urlParameters = "{\"Locations\": [\n" + " {\n" + " \"name\": \"West Roof\",\n" @@ -1177,51 +1179,51 @@ public void invalidPatchEntities() { invalidPatchEntity(EntityType.THING, urlParameters, thingId); // /** Location **/ -// long locationId = locationIds.get(0); +// Object locationId = locationIds.get(0); // urlParameters = "{\"Things\":[{\"description\":\"Orange\"}]}"; // invalidPatchEntity(EntityType.LOCATION, urlParameters, locationId); // // /** HistoricalLocation **/ -// long histLocId = historicalLocationIds.get(0); +// Object histLocId = historicalLocationIds.get(0); // urlParameters = "{\"time\": \"2015-07-01T00:00:00.000Z\"}"; // invalidPatchEntity(EntityType.HISTORICAL_LOCATION, urlParameters, histLocId); // /** * Sensor * */ - long sensorId = sensorIds.get(0); + Object 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 + "}" + + " ,\"Thing\":{\"@iot.id\":" + quoteIdForJson(thingId) + "}" + " }]}"; invalidPatchEntity(EntityType.SENSOR, urlParameters, sensorId); /** * ObserverdProperty * */ - long obsPropId = obsPropIds.get(0); + Object 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 + "}" + + " ,\"Thing\":{\"@iot.id\":" + quoteIdForJson(thingId) + "}" + " }]}"; invalidPatchEntity(EntityType.OBSERVED_PROPERTY, urlParameters, obsPropId); // /** FeatureOfInterest **/ -// long foiId = foiIds.get(0); +// Object 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); + Object datastreamId = datastreamIds.get(0); urlParameters = "{\"ObservedProperty\": {\n" + " \t\"name\": \"Count\",\n" + "\t\"definition\": \"http://qudt.org/vocab/unit#Dimensionless\",\n" @@ -1253,7 +1255,7 @@ public void invalidPatchEntities() { invalidPatchEntity(EntityType.DATASTREAM, urlParameters, datastreamId); // /** Observation **/ -// long obsId1 = observationIds.get(0); +// Object obsId1 = observationIds.get(0); // urlParameters = "{\"phenomenonTime\": \"2015-07-01T00:40:00.000Z\"}"; // invalidPatchEntity(EntityType.OBSERVATION, urlParameters, obsId1); } @@ -1282,8 +1284,8 @@ public void deleteNoneexistentEntities() { * @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) { + private JSONObject getEntity(EntityType entityType, Object id) { + if (id == null) { return null; } String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); @@ -1305,13 +1307,13 @@ private JSONObject getEntity(EntityType entityType, long id) { * @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); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, 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(")"))); + Object id = response.substring(response.indexOf("(") + 1, response.indexOf(")")); urlString = urlString + "(" + id + ")"; responseMap = HTTPMethods.doGet(urlString); @@ -1335,7 +1337,7 @@ private JSONObject postEntity(EntityType entityType, String urlParameters) { * @param urlParameters POST body (invalid) */ private void postInvalidEntity(EntityType entityType, String urlParameters) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, null); Map responseMap = HTTPMethods.doPost(urlString, urlParameters); int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); @@ -1350,7 +1352,7 @@ private void postInvalidEntity(EntityType entityType, String urlParameters) { * @param entityType Entity type in from EntityType enum * @param id The id of requested entity */ - private void deleteEntity(EntityType entityType, long id) { + private void deleteEntity(EntityType entityType, Object id) { String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); Map responseMap = HTTPMethods.doDelete(urlString); int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); @@ -1369,7 +1371,7 @@ private void deleteEntity(EntityType entityType, long id) { * @param entityType Entity type in from EntityType enum */ private void deleteNonExsistentEntity(EntityType entityType) { - long id = Long.MAX_VALUE; + Object 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()); @@ -1386,7 +1388,7 @@ private void deleteNonExsistentEntity(EntityType entityType) { * @param id The id of requested entity * @return The updated entity in the format of JSON Object */ - private JSONObject updateEntity(EntityType entityType, String urlParameters, long id) { + private JSONObject updateEntity(EntityType entityType, String urlParameters, Object id) { String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); try { Map responseMap = HTTPMethods.doPut(urlString, urlParameters); @@ -1413,7 +1415,7 @@ private JSONObject updateEntity(EntityType entityType, String urlParameters, lon * @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) { + private JSONObject patchEntity(EntityType entityType, String urlParameters, Object id) { String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); try { @@ -1440,7 +1442,7 @@ private JSONObject patchEntity(EntityType entityType, String urlParameters, long * @param urlParameters The PATCH body (invalid) * @param id The id of requested entity */ - private void invalidPatchEntity(EntityType entityType, String urlParameters, long id) { + private void invalidPatchEntity(EntityType entityType, String urlParameters, Object id) { String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); Map responseMap = HTTPMethods.doPatch(urlString, urlParameters); @@ -1460,11 +1462,13 @@ private void invalidPatchEntity(EntityType entityType, String urlParameters, lon */ private void checkPatch(EntityType entityType, JSONObject oldEntity, JSONObject newEntity, Map diffs) { try { - for (String property : EntityProperties.getPropertiesListFor(entityType)) { - if (diffs.containsKey(property)) { - Assert.assertEquals(newEntity.get(property).toString(), diffs.get(property).toString(), "PATCH was not applied correctly for " + entityType + "'s " + property + "."); + for (EntityType.EntityProperty property : entityType.getProperties()) { + if (diffs.containsKey(property.name)) { + Assert.assertEquals(newEntity.get(property.name).toString(), diffs.get(property.name).toString(), "PATCH was not applied correctly for " + entityType + "'s " + property.name + "."); + } else if (newEntity.has(property.name) && oldEntity.has(property.name)) { + Assert.assertEquals(newEntity.get(property.name).toString(), oldEntity.get(property.name).toString(), "PATCH was not applied correctly for " + entityType + "'s " + property.name + "."); } else { - Assert.assertEquals(newEntity.get(property).toString(), oldEntity.get(property).toString(), "PATCH was not applied correctly for " + entityType + "'s " + property + "."); + Assert.assertEquals(newEntity.has(property.name), oldEntity.has(property.name), "PATCH was not applied correctly for " + entityType + "'s " + property.name + "."); } } } catch (JSONException e) { @@ -1484,9 +1488,9 @@ private void checkPatch(EntityType entityType, JSONObject oldEntity, JSONObject */ private void checkPut(EntityType entityType, JSONObject oldEntity, JSONObject newEntity, Map diffs) { try { - for (String property : EntityProperties.getPropertiesListFor(entityType)) { - if (diffs.containsKey(property)) { - Assert.assertEquals(newEntity.get(property).toString(), diffs.get(property).toString(), "PUT was not applied correctly for " + entityType + "."); + for (EntityType.EntityProperty property : entityType.getProperties()) { + if (diffs.containsKey(property.name)) { + Assert.assertEquals(newEntity.get(property.name).toString(), diffs.get(property.name).toString(), "PUT was not applied correctly for " + entityType + "."); } else { // Assert.assertEquals(newEntity.get(property), oldEntity.get(property), "PUT was not applied correctly for "+entityType+"."); } @@ -1508,15 +1512,15 @@ private void checkPut(EntityType entityType, JSONObject oldEntity, JSONObject ne * @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"; + private Object checkAutomaticInsertionOfFOI(Object obsId, JSONObject locationObj, Object expectedFOIId) { + String urlString = rootUri + "/Observations(" + quoteIdForUrl(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."); + Assert.assertEquals(responseCode, 200, "ERROR: FeatureOfInterest was not automatically created."); JSONObject result = new JSONObject(responseMap.get("response").toString()); - long id = result.getLong(ControlInformation.ID); - if (expectedFOIId != -1) { + Object id = result.get(ControlInformation.ID); + if (expectedFOIId != null) { Assert.assertEquals(id, expectedFOIId, "ERROR: the Observation should have linked to FeatureOfInterest with ID: " + expectedFOIId + " , but it is linked for FeatureOfInterest with Id: " + id + "."); } Assert.assertEquals(result.getJSONObject("feature").toString(), locationObj.getJSONObject("location").toString(), "ERROR: Automatic created FeatureOfInterest does not match last Location of that Thing."); @@ -1537,17 +1541,17 @@ private long checkAutomaticInsertionOfFOI(long obsId, JSONObject locationObj, lo * @param relationObj The expected related entity object * @return The id of related object */ - private long checkRelatedEntity(EntityType parentEntityType, long parentId, EntityType relationEntityType, JSONObject relationObj) { + private Object checkRelatedEntity(EntityType parentEntityType, Object parentId, EntityType relationEntityType, JSONObject relationObj) { boolean isCollection = true; String urlString = ServiceURLBuilder.buildURLString(rootUri, parentEntityType, parentId, relationEntityType, null); - if (urlString.trim().charAt(urlString.trim().length() - 1) != 's') { + 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); + Assert.assertEquals(responseCode, 200, "ERROR: Deep inserted " + relationEntityType + " was not created or linked to " + parentEntityType); JSONObject result = new JSONObject(responseMap.get("response").toString()); if (isCollection == true) { result = result.getJSONArray("value").getJSONObject(0); @@ -1557,7 +1561,7 @@ private long checkRelatedEntity(EntityType parentEntityType, long parentId, Enti String key = iterator.next().toString(); Assert.assertEquals(result.get(key).toString(), relationObj.get(key).toString(), "ERROR: Deep inserted " + relationEntityType + " is not created correctly."); } - return result.getLong(ControlInformation.ID); + return result.get(ControlInformation.ID); } catch (JSONException e) { e.printStackTrace(); Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); @@ -1574,9 +1578,9 @@ private long checkRelatedEntity(EntityType parentEntityType, long parentId, Enti 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() + "\"."); + Assert.assertEquals(observation.get("resultTime").toString(), "null", "The resultTime of the Observation " + observation.get(ControlInformation.ID) + " should have been null but it is now \"" + observation.get("resultTime").toString() + "\"."); } else { - Assert.assertEquals(observation.get("resultTime").toString(), resultTimeValue, "The resultTime of the Observation " + observation.getLong(ControlInformation.ID) + " should have been \"" + resultTimeValue + "\" but it is now \"" + observation.get("resultTime").toString() + "\"."); + Assert.assertEquals(observation.get("resultTime").toString(), resultTimeValue, "The resultTime of the Observation " + observation.get(ControlInformation.ID) + " should have been \"" + resultTimeValue + "\" but it is now \"" + observation.get("resultTime").toString() + "\"."); } } catch (JSONException e) { e.printStackTrace(); @@ -1591,7 +1595,7 @@ private void checkForObservationResultTime(JSONObject observation, String result */ private void checkNotExisting(List entityTypes) { for (EntityType entityType : entityTypes) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, null); Map responseMap = HTTPMethods.doGet(urlString); try { JSONObject result = new JSONObject(responseMap.get("response").toString()); @@ -1611,7 +1615,7 @@ private void checkNotExisting(List entityTypes) { */ private void checkExisting(List entityTypes) { for (EntityType entityType : entityTypes) { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, null); Map responseMap = HTTPMethods.doGet(urlString); try { JSONObject result = new JSONObject(responseMap.get("response").toString()); @@ -1649,13 +1653,13 @@ private void deleteEntityType(EntityType entityType) { JSONArray array = null; do { try { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, 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); + Object id = array.getJSONObject(i).get(ControlInformation.ID); deleteEntity(entityType, id); } } catch (JSONException e) { @@ -1726,37 +1730,37 @@ private void createEntitiesForDelete() { + " }\n" + " ]\n" + "}"; - String urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, -1, null, null); + String urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, null, 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(")")))); + thingIds.add(Utils.idObjectFromPostResult(response)); 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)); + locationIds.add(array.getJSONObject(0).get(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)); + datastreamIds.add(array.getJSONObject(0).get(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)); + sensorIds.add(new JSONObject(response).get(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)); + obsPropIds.add(new JSONObject(response).get(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)); + historicalLocationIds.add(array.getJSONObject(0).get(ControlInformation.ID)); //Observations urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamIds.get(0), EntityType.OBSERVATION, null); @@ -1766,13 +1770,13 @@ private void createEntitiesForDelete() { + " }"; responseMap = HTTPMethods.doPost(urlString, urlParameters); response = responseMap.get("response").toString(); - observationIds.add(Long.parseLong(response.substring(response.lastIndexOf("(") + 1, response.lastIndexOf(")")))); + observationIds.add(Utils.idObjectFromPostResult(response)); //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)); + foiIds.add(new JSONObject(response).get(ControlInformation.ID)); } catch (JSONException e) { e.printStackTrace(); 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 0d9781e..4f0ebad 100644 --- a/src/main/java/org/opengis/cite/sta10/filteringExtension/Capability3Tests.java +++ b/src/main/java/org/opengis/cite/sta10/filteringExtension/Capability3Tests.java @@ -3,10 +3,8 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; - import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; import org.json.JSONArray; @@ -14,12 +12,18 @@ import org.json.JSONObject; import org.opengis.cite.sta10.SuiteAttribute; import org.opengis.cite.sta10.util.ControlInformation; -import org.opengis.cite.sta10.util.EntityProperties; +import org.opengis.cite.sta10.util.EntityCounts; import org.opengis.cite.sta10.util.EntityPropertiesSampleValue; -import org.opengis.cite.sta10.util.EntityRelations; import org.opengis.cite.sta10.util.EntityType; +import org.opengis.cite.sta10.util.EntityUtils; +import org.opengis.cite.sta10.util.Expand; import org.opengis.cite.sta10.util.HTTPMethods; +import org.opengis.cite.sta10.util.PathElement; +import org.opengis.cite.sta10.util.Query; +import org.opengis.cite.sta10.util.Request; import org.opengis.cite.sta10.util.ServiceURLBuilder; +import org.opengis.cite.sta10.util.Utils; +import static org.opengis.cite.sta10.util.Utils.quoteIdForJson; import org.testng.Assert; import org.testng.ITestContext; import org.testng.annotations.AfterClass; @@ -36,7 +40,7 @@ public class Capability3Tests { */ public String rootUri;//="http://localhost:8080/OGCSensorThings/v1.0"; - private long thingId1, thingId2, + private Object thingId1, thingId2, datastreamId1, datastreamId2, datastreamId3, datastreamId4, locationId1, locationId2, historicalLocationId1, historicalLocationId2, historicalLocationId3, historicalLocationId4, @@ -45,6 +49,8 @@ public class Capability3Tests { observationId1, observationId2, observationId3, observationId4, observationId5, observationId6, observationId7, observationId8, observationId9, observationId10, observationId11, observationId12, featureOfInterestId1, featureOfInterestId2; + private EntityCounts entityCounts = new EntityCounts(); + /** * This method will be run before starting the test for this conformance * class. It creates a set of entities to start testing query options. @@ -86,14 +92,14 @@ public void readEntitiesWithSelectQO() { 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); + checkSelectForEntityTypeRelations(EntityType.THING, thingId1); + checkSelectForEntityTypeRelations(EntityType.LOCATION, locationId1); + checkSelectForEntityTypeRelations(EntityType.HISTORICAL_LOCATION, historicalLocationId1); + checkSelectForEntityTypeRelations(EntityType.DATASTREAM, datastreamId1); + checkSelectForEntityTypeRelations(EntityType.SENSOR, sensorId1); + checkSelectForEntityTypeRelations(EntityType.OBSERVED_PROPERTY, observedPropertyId1); + checkSelectForEntityTypeRelations(EntityType.OBSERVATION, observationId1); + checkSelectForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST, featureOfInterestId1); } @@ -105,39 +111,47 @@ public void readEntitiesWithSelectQO() { */ @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); - + checkExpandForEntityType(EntityType.THING); + checkExpandForEntityType(EntityType.LOCATION); + checkExpandForEntityType(EntityType.HISTORICAL_LOCATION); + checkExpandForEntityType(EntityType.DATASTREAM); + checkExpandForEntityType(EntityType.SENSOR); + checkExpandForEntityType(EntityType.OBSERVED_PROPERTY); + checkExpandForEntityType(EntityType.OBSERVATION); + checkExpandForEntityType(EntityType.FEATURE_OF_INTEREST); + checkExpandForEntityTypeRelations(EntityType.THING, thingId1); + checkExpandForEntityTypeRelations(EntityType.LOCATION, locationId1); + checkExpandForEntityTypeRelations(EntityType.HISTORICAL_LOCATION, historicalLocationId1); + checkExpandForEntityTypeRelations(EntityType.DATASTREAM, datastreamId1); + checkExpandForEntityTypeRelations(EntityType.SENSOR, sensorId1); + checkExpandForEntityTypeRelations(EntityType.OBSERVED_PROPERTY, observedPropertyId1); + checkExpandForEntityTypeRelations(EntityType.OBSERVATION, observationId1); + checkExpandForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST, featureOfInterestId1); + checkExpandForEntityTypeMultilevel(EntityType.THING); + checkExpandForEntityTypeMultilevel(EntityType.LOCATION); + checkExpandForEntityTypeMultilevel(EntityType.HISTORICAL_LOCATION); + checkExpandForEntityTypeMultilevel(EntityType.DATASTREAM); + checkExpandForEntityTypeMultilevel(EntityType.SENSOR); + checkExpandForEntityTypeMultilevel(EntityType.OBSERVED_PROPERTY); + checkExpandForEntityTypeMultilevel(EntityType.OBSERVATION); + checkExpandForEntityTypeMultilevel(EntityType.FEATURE_OF_INTEREST); + checkExpandForEntityTypeMultilevelRelations(EntityType.THING, thingId1); + checkExpandForEntityTypeMultilevelRelations(EntityType.LOCATION, locationId1); + checkExpandForEntityTypeMultilevelRelations(EntityType.HISTORICAL_LOCATION, historicalLocationId1); + checkExpandForEntityTypeMultilevelRelations(EntityType.DATASTREAM, datastreamId1); + checkExpandForEntityTypeMultilevelRelations(EntityType.SENSOR, sensorId1); + checkExpandForEntityTypeMultilevelRelations(EntityType.OBSERVED_PROPERTY, observedPropertyId1); + checkExpandForEntityTypeMultilevelRelations(EntityType.OBSERVATION, observationId1); + checkExpandForEntityTypeMultilevelRelations(EntityType.FEATURE_OF_INTEREST, featureOfInterestId1); + + checkNestedExpandForEntity(EntityType.THING, thingId1); + checkNestedExpandForEntity(EntityType.LOCATION, locationId1); + checkNestedExpandForEntity(EntityType.HISTORICAL_LOCATION, historicalLocationId1); + checkNestedExpandForEntity(EntityType.DATASTREAM, datastreamId1); + checkNestedExpandForEntity(EntityType.SENSOR, sensorId1); + checkNestedExpandForEntity(EntityType.OBSERVED_PROPERTY, observedPropertyId1); + checkNestedExpandForEntity(EntityType.OBSERVATION, observationId1); + checkNestedExpandForEntity(EntityType.FEATURE_OF_INTEREST, featureOfInterestId1); } /** @@ -155,15 +169,14 @@ public void readEntitiesWithTopQO() { 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); - + checkTopForEntityTypeRelation(EntityType.THING, thingId1); + checkTopForEntityTypeRelation(EntityType.LOCATION, locationId1); + checkTopForEntityTypeRelation(EntityType.HISTORICAL_LOCATION, historicalLocationId1); + checkTopForEntityTypeRelation(EntityType.DATASTREAM, datastreamId1); + checkTopForEntityTypeRelation(EntityType.SENSOR, sensorId1); + checkTopForEntityTypeRelation(EntityType.OBSERVED_PROPERTY, observedPropertyId1); + checkTopForEntityTypeRelation(EntityType.OBSERVATION, observationId1); + checkTopForEntityTypeRelation(EntityType.FEATURE_OF_INTEREST, featureOfInterestId1); } /** @@ -181,14 +194,14 @@ public void readEntitiesWithSkipQO() { 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); + checkSkipForEntityTypeRelation(EntityType.THING, thingId1); + checkSkipForEntityTypeRelation(EntityType.LOCATION, locationId1); + checkSkipForEntityTypeRelation(EntityType.HISTORICAL_LOCATION, historicalLocationId1); + checkSkipForEntityTypeRelation(EntityType.DATASTREAM, datastreamId1); + checkSkipForEntityTypeRelation(EntityType.SENSOR, sensorId1); + checkSkipForEntityTypeRelation(EntityType.OBSERVED_PROPERTY, observedPropertyId1); + checkSkipForEntityTypeRelation(EntityType.OBSERVATION, observationId1); + checkSkipForEntityTypeRelation(EntityType.FEATURE_OF_INTEREST, featureOfInterestId1); } @@ -232,14 +245,14 @@ public void readEntitiesWithCountQO() { 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); + checkCountForEntityTypeRelations(EntityType.THING, thingId1); + checkCountForEntityTypeRelations(EntityType.LOCATION, locationId1); + checkCountForEntityTypeRelations(EntityType.HISTORICAL_LOCATION, historicalLocationId1); + checkCountForEntityTypeRelations(EntityType.DATASTREAM, datastreamId1); + checkCountForEntityTypeRelations(EntityType.SENSOR, sensorId1); + checkCountForEntityTypeRelations(EntityType.OBSERVED_PROPERTY, observedPropertyId1); + checkCountForEntityTypeRelations(EntityType.OBSERVATION, observationId1); + checkCountForEntityTypeRelations(EntityType.FEATURE_OF_INTEREST, featureOfInterestId1); } /** @@ -247,8 +260,7 @@ public void readEntitiesWithCountQO() { * {@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. + * @throws java.io.UnsupportedEncodingException Should not happen for UTF-8. */ @Test(description = "GET Entities with $filter", groups = "level-3") public void readEntitiesWithFilterQO() throws UnsupportedEncodingException { @@ -275,17 +287,17 @@ public void readEntitiesWithFilterQO() throws UnsupportedEncodingException { * $count, $top, $skip, $orderby, and $filter togther and check the priority * in result. */ - @Test(description = "Check priotity of query options", groups = "level-3") + @Test(description = "Check priority of query options", groups = "level-3") public void checkQueriesPriorityOrdering() { try { - String urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, -1, null, "?$count=true&$top=1&$skip=2&$orderby=phenomenonTime%20asc&$filter=result%20gt%20'3'"); + String urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.OBSERVATION, null, 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")); 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")); Assert.assertEquals(array.length(), 1, "The query asked for top 1, but the service rerurned " + array.length() + " entities."); - 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")); + Assert.assertEquals(array.getJSONObject(0).get("result").toString(), "6", "The query order of execution is not correct. The expected Observation result is 6, but it is " + array.getJSONObject(0).get("result").toString()); } catch (JSONException e) { e.printStackTrace(); Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); @@ -298,48 +310,48 @@ public void checkQueriesPriorityOrdering() { * @param entityType Entity type from EntityType enum list */ private void checkOrderbyForEntityTypeRelations(EntityType entityType) { - String[] relations = EntityRelations.getRelationsListFor(entityType); + List relations = entityType.getRelations(); try { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, 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); + Object id = array.getJSONObject(0).get(ControlInformation.ID); for (String relation : relations) { - if (relation.charAt(relation.length() - 1) != 's' && !relation.equals("FeaturesOfInteret")) { + if (!EntityType.isPlural(relation)) { continue; } - String[] properties = EntityProperties.getPropertiesListFor(relation); - EntityType relationEntityType = getEntityTypeFor(relation); + EntityType relationEntityType = EntityType.getForRelation(relation); + List properties = relationEntityType.getProperties(); //single orderby - for (String property : properties) { - if (property.equals("unitOfMeasurement")) { + for (EntityType.EntityProperty property : properties) { + if (!property.canSort) { continue; } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$orderby=" + property); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$orderby=" + property.name); 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); + Assert.assertTrue(compareWithPrevious(i, array, property.name) <= 0, "The ordering is not correct for EntityType " + entityType + " orderby property " + property); } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$orderby=" + property + "%20asc"); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$orderby=" + property.name + "%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); + Assert.assertTrue(compareWithPrevious(i, array, property.name) <= 0, "The ordering is not correct for EntityType " + entityType + " orderby asc property " + property); } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$orderby=" + property + "%20desc"); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$orderby=" + property.name + "%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); + Assert.assertTrue(compareWithPrevious(i, array, property.name) >= 0, "The ordering is not correct for EntityType " + entityType + " orderby desc property " + property); } } @@ -348,15 +360,15 @@ private void checkOrderbyForEntityTypeRelations(EntityType entityType) { String orderby = "?$orderby="; String orderbyAsc = "?$orderby="; String orderbyDesc = "?$orderby="; - for (String property : properties) { - if (property.equals("unitOfMeasurement")) { + for (EntityType.EntityProperty property : properties) { + if (!property.canSort) { continue; } if (orderby.charAt(orderby.length() - 1) != '=') { orderby += ","; } - orderby += property; - orderbyPropeties.add(property); + orderby += property.name; + orderbyPropeties.add(property.name); urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, orderby); responseMap = HTTPMethods.doGet(urlString); response = responseMap.get("response").toString(); @@ -419,33 +431,33 @@ private void checkOrderbyForEntityTypeRelations(EntityType entityType) { * @param entityType Entity type from EntityType enum list */ private void checkOrderbyForEntityType(EntityType entityType) { - String[] properties = EntityProperties.getPropertiesListFor(entityType); + List properties = entityType.getProperties(); try { //single orderby - for (String property : properties) { - if (property.equals("unitOfMeasurement")) { + for (EntityType.EntityProperty property : properties) { + if (!property.canSort) { continue; } - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$orderby=" + property); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$orderby=" + property.name); 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); + Assert.assertTrue(compareWithPrevious(i, array, property.name) <= 0, "The default ordering is not correct for EntityType " + entityType + " orderby property " + property.name); } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$orderby=" + property + "%20asc"); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$orderby=" + property.name + "%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); + Assert.assertTrue(compareWithPrevious(i, array, property.name) <= 0, "The ascending ordering is not correct for EntityType " + entityType + " orderby asc property " + property.name); } - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$orderby=" + property + "%20desc"); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$orderby=" + property.name + "%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); + Assert.assertTrue(compareWithPrevious(i, array, property.name) >= 0, "The descending ordering is not correct for EntityType " + entityType + " orderby desc property " + property.name); } } @@ -454,16 +466,16 @@ private void checkOrderbyForEntityType(EntityType entityType) { String orderby = "?$orderby="; String orderbyAsc = "?$orderby="; String orderbyDesc = "?$orderby="; - for (String property : properties) { - if (property.equals("unitOfMeasurement")) { + for (EntityType.EntityProperty property : properties) { + if (!property.canSort) { continue; } if (orderby.charAt(orderby.length() - 1) != '=') { orderby += ","; } - orderby += property; - orderbyPropeties.add(property); - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, orderby); + orderby += property.name; + orderbyPropeties.add(property.name); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, orderby); Map responseMap = HTTPMethods.doGet(urlString); String response = responseMap.get("response").toString(); JSONArray array = new JSONObject(response).getJSONArray("value"); @@ -480,7 +492,7 @@ private void checkOrderbyForEntityType(EntityType entityType) { orderbyAsc += ","; } orderbyAsc += property + "%20asc"; - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, orderbyAsc); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, orderbyAsc); responseMap = HTTPMethods.doGet(urlString); response = responseMap.get("response").toString(); array = new JSONObject(response).getJSONArray("value"); @@ -497,7 +509,7 @@ private void checkOrderbyForEntityType(EntityType entityType) { orderbyDesc += ","; } orderbyDesc += property + "%20desc"; - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, orderbyDesc); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, orderbyDesc); responseMap = HTTPMethods.doGet(urlString); response = responseMap.get("response").toString(); array = new JSONObject(response).getJSONArray("value"); @@ -521,6 +533,14 @@ private void checkOrderbyForEntityType(EntityType entityType) { private int compareWithPrevious(int idx, JSONArray array, String property) throws JSONException { JSONObject jObj1 = array.getJSONObject(idx - 1); JSONObject jObj2 = array.getJSONObject(idx); + if (!jObj1.has(property) && !jObj2.has(property)) { + // Neither has the property, they are the same. + return 0; + } + if (!jObj1.has(property) || !jObj2.has(property)) { + // One of the two does not have the property, oder undefined? + return 0; + } Object o1 = jObj1.get(property); Object o2 = jObj2.get(property); return compareForOrder(o1, o2); @@ -543,131 +563,25 @@ private int compareForOrder(Object o1, Object o2) { * @param entityType Entity type from EntityType enum list */ private void checkSkipForEntityType(EntityType entityType) { - try { + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural)); + // in case an implementation returns fewer than 12 entities by default we request 12. + request.getQuery() + .setTop(12L) + .setSkip(1L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - String 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."); - } 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()); - 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()); - 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()); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 11, "Query requested entities skipping 1, result should have contained 11 entities, but it contains " + array.length()); - break; - default: - break; - } + request.getQuery().setSkip(2L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - 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."); - } 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()); - 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()); - 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()); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 10, "Query requested entities skipping 2, result should have contained 10 entities, but it contains " + array.length()); - break; - default: - break; - } + request.getQuery().setSkip(3L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - 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."); - } 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()); - 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()); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 9, "Query requested entities skipping 3, result should have contained 9 entities, but it contains " + array.length()); - 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."); - } 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()); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 8, "Query requested entities skipping 4, result should have contained 8 entities, but it contains " + array.length()); - break; - default: - break; - } + request.getQuery().setSkip(4L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - 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."); - } catch (JSONException e) { - } - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 12, result should have contained 0 entity, but it contains " + array.length()); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } + request.getQuery().setSkip(12L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); } /** @@ -675,85 +589,21 @@ private void checkSkipForEntityType(EntityType entityType) { * * @param entityType Entity type from EntityType enum list */ - private void checkSkipForEntityTypeRelation(EntityType entityType) { - try { - String[] relations = EntityRelations.getRelationsListFor(entityType); - String 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 (relation.charAt(relation.length() - 1) != 's' && !relation.equals("FeaturesOfInterest")) { - continue; - } - EntityType relationEntityType = getEntityTypeFor(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."); - } 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()); - 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()); - break; - case DATASTREAM: - Assert.assertEquals(array.length(), 1, "Query requested entities skipping 1, result should have contained 1 entity, but it contains " + array.length()); - 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()); - break; - case THING: - Assert.assertEquals(array.length(), 0, "Query requested entities skipping 1, result should have contained 0 entity, but it contains " + array.length()); - 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()); - 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()); - 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()); - 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()); - 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()); - break; - } - break; - default: - break; - } + private void checkSkipForEntityTypeRelation(EntityType entityType, Object entityId) { + List relations = entityType.getRelations(); + for (String relation : relations) { + if (!EntityType.isPlural(relation)) { + continue; } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural, entityId)) + .addElement(new PathElement(relation)); + // in case an implementation returns fewer than 12 entities by default we request 12. + request.getQuery() + .setTop(12L) + .setSkip(1L); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } } @@ -763,247 +613,28 @@ private void checkSkipForEntityTypeRelation(EntityType entityType) { * @param entityType Entity type from EntityType enum list */ private void checkTopForEntityType(EntityType entityType) { - try { - String 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()); - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink"); - } - - 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()); - 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"); - } catch (JSONException e) { - } - break; - default: - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink"); - } - break; - } + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural)); + request.getQuery().setTop(1L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } catch (JSONException e) { - } - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(array.length(), 3, "Query requested 3 entities but response contains " + array.length()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } catch (JSONException e) { - } - break; - default: - Assert.assertEquals(array.length(), 3, "Query requested 3 entities but response contains " + array.length()); - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink"); - } - break; - } + request.getQuery().setTop(2L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } catch (JSONException e) { - } - break; - default: - Assert.assertEquals(array.length(), 4, "Query requested 4 entities but response contains " + array.length()); - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink"); - } - break; - } + request.getQuery().setTop(3L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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"); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink"); - } - break; - } + request.getQuery().setTop(4L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - 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"); - } catch (JSONException e) { - } + request.getQuery().setTop(5L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - 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"); - } 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()); - break; - case LOCATION: - Assert.assertEquals(array.length(), 2, "Query requested 13 Locations, there are only 2 Locations, but response contains " + array.length()); - break; - case FEATURE_OF_INTEREST: - Assert.assertEquals(array.length(), 2, "Query requested 13 FeaturesOfInterest, there are only 2 FeaturesOfInterest, but response contains " + array.length()); - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(array.length(), 3, "Query requested 13 ObservedProperties, there are only 3 ObservedProperties, but response contains " + array.length()); - break; - case SENSOR: - Assert.assertEquals(array.length(), 4, "Query requested 13 Sensors, there are only 4 Sensors, but response contains " + array.length()); - break; - case HISTORICAL_LOCATION: - Assert.assertEquals(array.length(), 4, "Query requested 13 HistoricalLocations, there are only 4 HistoricalLocations, but response contains " + array.length()); - break; - case DATASTREAM: - Assert.assertEquals(array.length(), 4, "Query requested 13 Datastreams, there are only 4 Datastreams, but response contains " + array.length()); - break; - case OBSERVATION: - Assert.assertEquals(array.length(), 12, "Query requested 13 Observations, there are only 12 Observations, but response contains " + array.length()); - break; - } + request.getQuery().setTop(12L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } + request.getQuery().setTop(13L); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); } /** @@ -1011,110 +642,19 @@ private void checkTopForEntityType(EntityType entityType) { * * @param entityType Entity type from EntityType enum list */ - private void checkTopForEntityTypeRelation(EntityType entityType) { - try { - String[] relations = EntityRelations.getRelationsListFor(entityType); - String 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 (relation.charAt(relation.length() - 1) != 's' && !relation.equals("FeaturesOfInterest")) { - continue; - } - EntityType relationEntityType = getEntityTypeFor(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"); - } 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()); - 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()); - break; - case DATASTREAM: - Assert.assertEquals(array.length(), 2, "Query requested entities 3 entities, result should have contained 2 entities, but it contains " + array.length()); - break; - } - break; - case LOCATION: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - break; - case THING: - Assert.assertEquals(array.length(), 1, "Query requested entities 3 entities, result should have contained 1 entity, but it contains" + array.length()); - 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()); - try { - Assert.assertNotNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } catch (JSONException e) { - Assert.fail("The response does not have nextLink"); - } - 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()); - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink"); - } catch (JSONException e) { - } - break; - case HISTORICAL_LOCATION: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink"); - } 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()); - break; - } - break; - case SENSOR: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response should not have nextLink"); - } catch (JSONException e) { - } - Assert.assertEquals(array.length(), 1, "Query requested entities 3 entities, result should have contained 1 entity, but it contains " + array.length()); - break; - case DATASTREAM: - try { - Assert.assertNull(new JSONObject(response).get("@iot.nextLink"), "The response does not have nextLink"); - } 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()); - break; - } - break; - default: - break; - } + private void checkTopForEntityTypeRelation(EntityType entityType, Object entityId) { + List relations = entityType.getRelations(); + for (String relation : relations) { + if (!EntityType.isPlural(relation)) { + continue; } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural, entityId)) + .addElement(new PathElement(relation)); + Query query = request.getQuery(); + query.setTop(3L); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } } @@ -1124,19 +664,21 @@ private void checkTopForEntityTypeRelation(EntityType entityType) { * @param entityType Entity type from EntityType enum list */ private void checkSelectForEntityType(EntityType entityType) { - List selectedProperties; - String[] properties = EntityProperties.getPropertiesListFor(entityType); - for (String property : properties) { - selectedProperties = new ArrayList<>(); - selectedProperties.add(property); - String response = getEntities(entityType, -1, null, selectedProperties, null); - checkEntitiesAllAspectsForSelectResponse(entityType, response, selectedProperties); + List properties = entityType.getProperties(); + for (EntityType.EntityProperty property : properties) { + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural)); + request.getQuery().addSelect(property.name); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } - selectedProperties = new ArrayList<>(); - for (String property : properties) { - selectedProperties.add(property); - String response = getEntities(entityType, -1, null, selectedProperties, null); - checkEntitiesAllAspectsForSelectResponse(entityType, response, selectedProperties); + + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural)); + for (EntityType.EntityProperty property : properties) { + request.getQuery().addSelect(property.name); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } } @@ -1145,420 +687,289 @@ private void checkSelectForEntityType(EntityType entityType) { * * @param entityType Entity type from EntityType enum list */ - private void checkSelectForEntityTypeRelations(EntityType entityType) { - try { - String[] parentRelations = EntityRelations.getRelationsListFor(entityType); - String 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 = getEntityTypeFor(parentRelation); - List selectedProperties; - String[] properties = EntityProperties.getPropertiesListFor(relationEntityType); - 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); - } + private void checkSelectForEntityTypeRelations(EntityType entityType, Object entityId) { + List parentRelations = entityType.getRelations(); + for (String parentRelation : parentRelations) { + EntityType relationEntityType = EntityType.getForRelation(parentRelation); + List properties = relationEntityType.getProperties(); + for (EntityType.EntityProperty property : properties) { + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural, entityId)); + request.addElement(new PathElement(parentRelation)); + + request.getQuery().addSelect(property.name); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - } - /** - * 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; + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural, entityId)); + request.addElement(new PathElement(parentRelation)); + for (EntityType.EntityProperty property : properties) { + request.getQuery().addSelect(property.name); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } } - 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()); - 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 + * This helper method is checking $expand for a collection. for instance: + * /Things?$expand=Datastreams,HistoricalLocations * - * @param entityType Entity type from EntityType enum list - * @param response The response to be checked - * @param selectedProperties The list of selected properties + * @param entityType Entity type from EntityType enum list */ - 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()); + private void checkExpandForEntityType(EntityType entityType) { + List relations = entityType.getRelations(); + for (String relation : relations) { + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural)); + request.getQuery().addExpand(new Expand().addElement(new PathElement(relation))); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural)); + for (String relation : relations) { + request.getQuery().addExpand(new Expand().addElement(new PathElement(relation))); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); + } } /** - * This method is checking properties for the $select array of entities + * This helper method is checking $expand for entities with relations. For + * instance: /Things(709)/Datastreams?$expand=Thing,Sensor * - * @param entityType Entity type from EntityType enum list - * @param entities The JSONArray of entities to be checked - * @param selectedProperties The list of selected properties + * @param entityType Entity type from EntityType enum list */ - 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()); + private void checkExpandForEntityTypeRelations(EntityType entityType, Object entityId) { + PathElement entityPathElement = new PathElement(entityType.plural, entityId); + List parentRelations = entityType.getRelations(); + for (String parentRelation : parentRelations) { + EntityType parentRelationEntityType = EntityType.getForRelation(parentRelation); + PathElement parentRelationPathElement = new PathElement(parentRelation); + List relations = parentRelationEntityType.getRelations(); + for (String relation : relations) { + Request request = new Request(rootUri); + request.addElement(entityPathElement); + request.addElement(parentRelationPathElement); + request.getQuery().addExpand(new Expand().addElement(new PathElement(relation))); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } - 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()); - String[] properties = EntityProperties.getPropertiesListFor(entityType); - for (String property : properties) { - if (selectedProperties.contains(property)) { - try { - Assert.assertNotNull(entity.get(property), "Entity type \"" + entityType + "\" does not have selected property: \"" + property + "\"."); - } catch (JSONException e) { - Assert.fail("Entity type \"" + entityType + "\" does not have selected property: \"" + property + "\"."); - } - } else { - try { - Assert.assertNull(entity.get(property), "Entity type \"" + entityType + "\" contains not-selected property: \"" + property + "\"."); - } catch (JSONException e) { - } - } + Request request = new Request(rootUri); + request.addElement(entityPathElement); + request.addElement(parentRelationPathElement); + for (String relation : relations) { + request.getQuery().addExpand(new Expand().addElement(new PathElement(relation))); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); } - } /** - * This method is checking the related entities of selected and/or expanded - * entities for a collection + * This helper method is checking multilevel $expand for 2 level of + * entities. For instance: + * /Things(709)/Datastreams?$expand=Thing/Datastreams,Thing/HistoricalLocations * - * @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 + * @param entityType Entity type from EntityType enum list */ - 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); + private void checkExpandForEntityTypeMultilevelRelations(EntityType entityType, Object entityId) { + PathElement entityPathElement = new PathElement(entityType.plural, entityId); + List parentRelations = entityType.getRelations(); + for (String parentRelation : parentRelations) { + EntityType parentRelationEntityType = EntityType.getForRelation(parentRelation); + PathElement parentRelationPathElement = new PathElement(parentRelation); + + List relations = parentRelationEntityType.getRelations(); + for (String relation : relations) { + EntityType relationType = EntityType.getForRelation(relation); + List secondLevelRelations = relationType.getRelations(); + for (String secondLevelRelation : secondLevelRelations) { + Request request = new Request(rootUri); + request.addElement(entityPathElement); + request.addElement(parentRelationPathElement); + Expand expand = new Expand() + .addElement(new PathElement(relation)) + .addElement(new PathElement(secondLevelRelation)); + request.getQuery().addExpand(expand); + JSONObject response = request.executeGet(); + request.reNest(); + EntityUtils.checkResponse(response, request, entityCounts); + } } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); - } - - } + Request request = new Request(rootUri); + request.addElement(entityPathElement); + request.addElement(parentRelationPathElement); - /** - * 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()); - String[] relations = EntityRelations.getRelationsListFor(entityType); for (String relation : relations) { - 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 + "\"."); - } catch (JSONException e) { - Assert.fail("Entity type \"" + entityType + "\" does not have selected relation: \"" + relation + "\"."); - } - } else { - Assert.assertNotNull(entity.get(relation), "Entity type \"" + entityType + "\" does not have expanded relation Correctly: \"" + relation + "\"."); - JSONArray expandedEntityArray = null; - try { - if (relation.charAt(relation.length() - 1) != 's' && !relation.equals("FeaturesOfInterest")) { - 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 + "\"."); - } - checkPropertiesForEntityArray(getEntityTypeFor(relation), expandedEntityArray, new ArrayList(Arrays.asList(EntityProperties.getPropertiesListFor(relation)))); - if (listContainsString(expandedRelations, "/")) { - String[] secondLevelRelations = EntityRelations.getRelationsListFor(relation); - JSONObject expandedEntity = expandedEntityArray.getJSONObject(0); - for (String secondLeveleRelation : secondLevelRelations) { - if (listContainsString(expandedRelations, relation + "/" + secondLeveleRelation)) { - - expandedEntityArray = null; - try { - if (secondLeveleRelation.charAt(secondLeveleRelation.length() - 1) != 's' && !secondLeveleRelation.equals("FeaturesOfInterest")) { - 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 + "\"."); - } - checkPropertiesForEntityArray(getEntityTypeFor(secondLeveleRelation), expandedEntityArray, new ArrayList(Arrays.asList(EntityProperties.getPropertiesListFor(secondLeveleRelation)))); - } - } - } - } - } else { - try { - Assert.assertNull(entity.get(relation + ControlInformation.NAVIGATION_LINK), "Entity type \"" + entityType + "\" contains not-selectd relation: \"" + relation + "\"."); - } catch (JSONException e) { - } - try { - Assert.assertNull(entity.get(relation), "Entity type \"" + entityType + "\" contains not-selectd relation: \"" + relation + "\"."); - } catch (JSONException e) { - } + EntityType relationType = EntityType.getForRelation(relation); + List secondLevelRelations = relationType.getRelations(); + for (String secondLevelRelation : secondLevelRelations) { + Expand expand = new Expand() + .addElement(new PathElement(relation)) + .addElement(new PathElement(secondLevelRelation)); + request.getQuery().addExpand(expand); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request.clone().reNest(), entityCounts); } } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); } } /** - * This helper method is checking $expand for a collection. + * This helper method is checking multilevel $expand for a collection. For + * instance: /Things?$expand=Datastreams/Thing,Datastreams/Sensor * * @param entityType Entity type from EntityType enum list */ - private void checkExpandtForEntityType(EntityType entityType) { - List expandedRelations; - String[] relations = EntityRelations.getRelationsListFor(entityType); - 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<>(); + private void checkExpandForEntityTypeMultilevel(EntityType entityType) { + List relations = entityType.getRelations(); for (String relation : relations) { - expandedRelations.add(relation); - String response = getEntities(entityType, -1, null, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); - } - } + EntityType relationType = EntityType.getForRelation(relation); + List secondLevelRelations = relationType.getRelations(); - /** - * This helper method is checking $expand for 2 level of entities. - * - * @param entityType Entity type from EntityType enum list - */ - private void checkExpandtForEntityTypeRelations(EntityType entityType) { - try { - String[] parentRelations = EntityRelations.getRelationsListFor(entityType); - String 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 = getEntityTypeFor(parentRelation); - List expandedRelations; - String[] relations = EntityRelations.getRelationsListFor(relationEntityType); - 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); - } + for (String secondLevelRelation : secondLevelRelations) { + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural)); + Expand expand = new Expand() + .addElement(new PathElement(relation)) + .addElement(new PathElement(secondLevelRelation)); + request.getQuery().addExpand(expand); + JSONObject response = request.executeGet(); + request.reNest(); + EntityUtils.checkResponse(response, request, entityCounts); } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); } - } - /** - * 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) { - try { - String[] parentRelations = EntityRelations.getRelationsListFor(entityType); - String 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 = getEntityTypeFor(parentRelation); - List expandedRelations; - String[] relations = EntityRelations.getRelationsListFor(relationEntityType); - for (String relation : relations) { - String[] secondLevelRelations = EntityRelations.getRelationsListFor(relation); - - for (String secondLevelRelation : secondLevelRelations) { - expandedRelations = new ArrayList<>(); - expandedRelations.add(relation + "/" + secondLevelRelation); - response = getEntities(entityType, id, relationEntityType, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(relationEntityType, response, expandedRelations); - } - } - expandedRelations = new ArrayList<>(); - for (String relation : relations) { - String[] secondLevelRelations = EntityRelations.getRelationsListFor(relation); - for (String secondLevelRelation : secondLevelRelations) { - expandedRelations.add(relation + "/" + secondLevelRelation); - response = getEntities(entityType, id, relationEntityType, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(relationEntityType, response, expandedRelations); - } - } + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural)); + for (String relation : relations) { + EntityType relationType = EntityType.getForRelation(relation); + List secondLevelRelations = relationType.getRelations(); + for (String secondLevelRelation : secondLevelRelations) { + Expand expand = new Expand() + .addElement(new PathElement(relation)) + .addElement(new PathElement(secondLevelRelation)); + request.getQuery().addExpand(expand); + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request.clone().reNest(), entityCounts); } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); } } /** - * This helper method is checking multilevel $expand for a collection. + * This helper method is checking nested expands two levels deep including + * select, top, skip and count options. For instance: + *
+     * ObservedProperties(722)?
+     *   $select=name,description&
+     *   $expand=Datastreams(
+     *     $select=name,unitOfMeasurement,Thing,ObservedProperty;
+     *     $expand=Thing(
+     *       $select=name,Datastreams,Locations
+     *     ),
+     *     Sensor(
+     *       $select=description,metadata
+     *     ),
+     *     ObservedProperty(
+     *       $select=name,description
+     *     ),
+     *     Observations(
+     *       $select=result,Datastream;
+     *       $count=false
+     *     );
+     *     $count=true
+     *   )
+     * 
* * @param entityType Entity type from EntityType enum list */ - private void checkExpandtForEntityTypeMultilevel(EntityType entityType) { - - List expandedRelations; - String[] relations = EntityRelations.getRelationsListFor(entityType); - for (String relation : relations) { - String[] secondLevelRelations = EntityRelations.getRelationsListFor(relation); - - for (String secondLevelRelation : secondLevelRelations) { - expandedRelations = new ArrayList<>(); - expandedRelations.add(relation + "/" + secondLevelRelation); - String response = getEntities(entityType, -1, null, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); + private void checkNestedExpandForEntity(EntityType entityType, Object entityId) { + PathElement collectionPathElement = new PathElement(entityType.plural); + PathElement entityPathElement = new PathElement(entityType.plural, entityId); + Request request2 = new Request(rootUri); + request2.addElement(collectionPathElement); + boolean even = true; + long skip = 0; + + List parentRelations = entityType.getRelations(); + for (String parentRelation : parentRelations) { + EntityType parentRelationEntityType = EntityType.getForRelation(parentRelation); + List childRelations = parentRelationEntityType.getRelations(); + for (String childRelation : childRelations) { + EntityType childRelationEntityType = EntityType.getForRelation(childRelation); + Request request = new Request(rootUri); + request.addElement(entityPathElement); + Query query = request.getQuery(); + entityType.getHalfPropertiesRelations(query.getSelect(), even); + query.setCount(even); + query.setTop(2L); + query.setSkip(skip); + Expand expand = new Expand() + .addElement(new PathElement(parentRelation)); + query.addExpand(expand); + even = !even; + skip = 1 - skip; + + query = expand.getQuery(); + query.setCount(even); + query.setTop(2L); + query.setSkip(skip); + parentRelationEntityType.getHalfPropertiesRelations(query.getSelect(), even); + expand = new Expand() + .addElement(new PathElement(childRelation)); + query.addExpand(expand); + even = !even; + skip = 1 - skip; + + query = expand.getQuery(); + childRelationEntityType.getHalfPropertiesRelations(query.getSelect(), even); + query.setCount(even); + query.setTop(2L); + query.setSkip(skip); + even = !even; + skip = 1 - skip; + + JSONObject response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); + + request.getPath().clear(); + request.addElement(collectionPathElement); + response = request.executeGet(); + EntityUtils.checkResponse(response, request, entityCounts); } - } - expandedRelations = new ArrayList<>(); - for (String relation : relations) { - String[] secondLevelRelations = EntityRelations.getRelationsListFor(relation); - for (String secondLevelRelation : secondLevelRelations) { - expandedRelations.add(relation + "/" + secondLevelRelation); - String response = getEntities(entityType, -1, null, null, expandedRelations); - checkEntitiesAllAspectsForExpandResponse(entityType, response, expandedRelations); + + Query query1 = request2.getQuery(); + Expand expand = new Expand() + .addElement(new PathElement(parentRelation)); + query1.addExpand(expand); + entityType.getHalfPropertiesRelations(query1.getSelect(), even); + query1.setCount(even); + even = !even; + + Query query2 = expand.getQuery(); + for (String childRelation : childRelations) { + parentRelationEntityType.getHalfPropertiesRelations(query2.getSelect(), even); + query2.setCount(even); + EntityType childRelationEntityType = EntityType.getForRelation(childRelation); + expand = new Expand() + .addElement(new PathElement(childRelation)); + query2.addExpand(expand); + even = !even; + + Query query3 = expand.getQuery(); + childRelationEntityType.getHalfPropertiesRelations(query3.getSelect(), even); + query3.setCount(even); + even = !even; + + JSONObject response = request2.executeGet(); + EntityUtils.checkResponse(response, request2, entityCounts); + even = !even; } } } @@ -1569,45 +980,13 @@ private void checkExpandtForEntityTypeMultilevel(EntityType entityType) { * @param entityType Entity type from EntityType enum list */ private void checkCountForEntityType(EntityType entityType) { + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural)); + request.getQuery().setCount(true); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); - 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); - } - 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); - break; - case OBSERVED_PROPERTY: - Assert.assertEquals(count, 3, "The count for " + entityType + "should be 3, but it is " + count); - break; - case HISTORICAL_LOCATION: - case SENSOR: - case DATASTREAM: - Assert.assertEquals(count, 4, "The count for " + entityType + "should be 4, but it is " + count); - break; - case OBSERVATION: - Assert.assertEquals(count, 12, "The count for " + entityType + "should be 12, but it is " + count); - 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); - Assert.fail("the query asked for not count but the response does contain count, for getting collection: " + entityType); - } catch (JSONException e) { - } + request.getQuery().setCount(false); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); } /** @@ -1615,88 +994,24 @@ private void checkCountForEntityType(EntityType entityType) { * * @param entityType Entity type from EntityType enum list */ - private void checkCountForEntityTypeRelations(EntityType entityType) { - try { - String[] relations = EntityRelations.getRelationsListFor(entityType); - String 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 (relation.charAt(relation.length() - 1) != 's' && !relation.equals("FeatureOfInterest")) { - return; - } - EntityType relationEntityType = getEntityTypeFor(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); - } - switch (relationEntityType) { - case THING: - case LOCATION: - Assert.assertEquals(count, 1, "The count for " + entityType + "should be 1, but it is " + count); - 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); - break; - case SENSOR: - Assert.assertEquals(count, 1, "The count for " + entityType + "should be 1, but it is " + count); - break; - case OBSERVED_PROPERTY: - Assert.assertTrue(count == 2 || count == 1, "The count for " + entityType + "should be 1 or 2, but it is " + count); - break; - } - break; - case OBSERVATION: - if (entityType.equals(EntityType.DATASTREAM)) { - Assert.assertEquals(count, 3, "The count for " + entityType + "should be 3, but it is " + count); - } else if (entityType.equals(EntityType.FEATURE_OF_INTEREST)) { - Assert.assertEquals(count, 6, "The count for " + entityType + "should be 6, but it is " + count); - } - 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); - Assert.fail("the query asked for not count but the response does contain count, for getting collection: " + entityType); - } catch (JSONException e) { - } + private void checkCountForEntityTypeRelations(EntityType entityType, Object entityId) { + List relations = entityType.getRelations(); + for (String relation : relations) { + if (!EntityType.isPlural(relation)) { + continue; } - } catch (JSONException e) { - e.printStackTrace(); - Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); + Request request = new Request(rootUri); + request.addElement(new PathElement(entityType.plural, entityId)) + .addElement(new PathElement(relation)); + Query query = request.getQuery(); + query.setCount(true); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); + + query.setCount(false); + EntityUtils.checkResponse(request.executeGet(), request, entityCounts); } } - /** - * 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. * @@ -1705,47 +1020,52 @@ private void checkEntitiesAllAspectsForExpandResponse(EntityType entityType, Str * should always be supported. */ private void checkFilterForEntityType(EntityType entityType) throws UnsupportedEncodingException { - String[] properties = EntityProperties.getPropertiesListFor(entityType); + List properties = entityType.getProperties(); List filteredProperties; List samplePropertyValues; - for (int i = 0; i < properties.length; i++) { + for (int i = 0; i < properties.size(); i++) { + EntityType.EntityProperty property = properties.get(i); filteredProperties = new ArrayList<>(); samplePropertyValues = new ArrayList<>(); - String property = properties[i]; - filteredProperties.add(property); - if (property.equals("location") || property.equals("feature") || property.equals("unitOfMeasurement")) { + // TODO: Do we need a canFilter here, or are those sets the same? + if (!property.canSort) { continue; } + filteredProperties.add(property.name); Comparable propertyValue = EntityPropertiesSampleValue.getPropertyValueFor(entityType, i); + if (propertyValue == null) { + // No sample value available. + continue; + } samplePropertyValues.add(propertyValue); propertyValue = URLEncoder.encode(propertyValue.toString(), "UTF-8"); - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, "?$filter=" + property + "%20lt%20" + propertyValue); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, "?$filter=" + property.name + "%20gt%20" + propertyValue); responseMap = HTTPMethods.doGet(urlString); response = responseMap.get("response").toString(); checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 2); @@ -1760,8 +1080,8 @@ private void checkFilterForEntityType(EntityType entityType) throws UnsupportedE * should always be supported. */ private void checkFilterForEntityTypeRelations(EntityType entityType) throws UnsupportedEncodingException { - String[] relations = EntityRelations.getRelationsListFor(entityType); - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + List relations = entityType.getRelations(); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, null, null); Map responseMap = HTTPMethods.doGet(urlString); String response = responseMap.get("response").toString(); JSONArray array = null; @@ -1774,61 +1094,64 @@ private void checkFilterForEntityTypeRelations(EntityType entityType) throws Uns if (array.length() == 0) { return; } - long id = 0; + Object id = null; try { - id = array.getJSONObject(0).getLong(ControlInformation.ID); + id = array.getJSONObject(0).get(ControlInformation.ID); } catch (JSONException e) { e.printStackTrace(); Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); } for (String relation : relations) { - if (relation.charAt(relation.length() - 1) != 's' && !relation.equals("FeatureOfInterest")) { + if (!EntityType.isPlural(relation)) { return; } - EntityType relationEntityType = getEntityTypeFor(relation); + EntityType relationEntityType = EntityType.getForRelation(relation); - String[] properties = EntityProperties.getPropertiesListFor(relationEntityType); + List properties = relationEntityType.getProperties(); List filteredProperties; List samplePropertyValues; - for (int i = 0; i < properties.length; i++) { + for (int i = 0; i < properties.size(); i++) { filteredProperties = new ArrayList<>(); samplePropertyValues = new ArrayList<>(); - String property = properties[i]; - filteredProperties.add(property); - if (property.equals("location") || property.equals("feature") || property.equals("unitOfMeasurement")) { + EntityType.EntityProperty property = properties.get(i); + if (!property.canSort) { continue; } + filteredProperties.add(property.name); Comparable propertyValue = EntityPropertiesSampleValue.getPropertyValueFor(relationEntityType, i); + if (propertyValue == null) { + continue; + } samplePropertyValues.add(propertyValue); propertyValue = URLEncoder.encode(propertyValue.toString(), "UTF-8"); - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property + "%20lt%20" + propertyValue); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%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); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, relationEntityType, "?$filter=" + property.name + "%20gt%20" + propertyValue); responseMap = HTTPMethods.doGet(urlString); response = responseMap.get("response").toString(); checkPropertiesForFilter(response, filteredProperties, samplePropertyValues, 2); @@ -1900,40 +1223,10 @@ private void checkPropertiesForFilter(String response, List properties, } } - /** - * Find EntityType from its name string - * - * @param name entity type name string - * @return The entity type from EntityType enum list - */ - private EntityType getEntityTypeFor(String name) { - switch (name.toLowerCase()) { - case "thing": - case "things": - return EntityType.THING; - case "location": - case "locations": - return EntityType.LOCATION; - case "historicallocation": - case "historicallocations": - return EntityType.HISTORICAL_LOCATION; - case "datastream": - case "datastreams": - return EntityType.DATASTREAM; - case "sensor": - case "sensors": - return EntityType.SENSOR; - case "observedproperty": - case "observedproperties": - return EntityType.OBSERVED_PROPERTY; - case "observation": - case "observations": - return EntityType.OBSERVATION; - case "featureofinterest": - case "featuresofinterest": - return EntityType.FEATURE_OF_INTEREST; - } - return null; + private Object postAndGetId(String urlString, String postContent) { + Map responseMap = HTTPMethods.doPost(urlString, postContent); + String response = responseMap.get("response").toString(); + return Utils.idObjectFromPostResult(response); } /** @@ -2007,41 +1300,39 @@ private void createEntities() { + " }\n" + " ]\n" + "}"; - String 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(")"))); + String urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, null, null, null); + thingId1 = postAndGetId(urlString, urlParameters); urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, EntityType.LOCATION, null); - responseMap = HTTPMethods.doGet(urlString); - response = responseMap.get("response").toString(); + Map responseMap = HTTPMethods.doGet(urlString); + String response = responseMap.get("response").toString(); JSONArray array = new JSONObject(response).getJSONArray("value"); - locationId1 = array.getJSONObject(0).getLong(ControlInformation.ID); + locationId1 = array.getJSONObject(0).get(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); + datastreamId1 = array.getJSONObject(0).get(ControlInformation.ID); + datastreamId2 = array.getJSONObject(1).get(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); + sensorId1 = new JSONObject(response).get(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); + observedPropertyId1 = new JSONObject(response).get(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); + sensorId2 = new JSONObject(response).get(ControlInformation.ID); + urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId2, EntityType.OBSERVED_PROPERTY, null); responseMap = HTTPMethods.doGet(urlString); response = responseMap.get("response").toString(); - observedPropertyId2 = new JSONObject(response).getLong(ControlInformation.ID); + observedPropertyId2 = new JSONObject(response).get(ControlInformation.ID); //Second Thing urlParameters = "{\n" @@ -2096,7 +1387,7 @@ private void createEntities() { + " \"description\": \"datastream 2\",\n" + " \"observationType\": \"http://www.opengis.net/def/observationType/OGC-OM/2.0/OM_Measurement\",\n" + " \"ObservedProperty\": {\n" - + " \"@iot.id\": " + observedPropertyId2 + "\n" + + " \"@iot.id\": " + quoteIdForJson(observedPropertyId2) + "\n" + " },\n" + " \"Sensor\": {\n" + " \"name\": \"sensor 4 \",\n" @@ -2107,43 +1398,41 @@ private void createEntities() { + " }\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, null, null, null); + thingId2 = postAndGetId(urlString, urlParameters); 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); + locationId2 = array.getJSONObject(0).get(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); + datastreamId3 = array.getJSONObject(0).get(ControlInformation.ID); + datastreamId4 = array.getJSONObject(1).get(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); + sensorId3 = new JSONObject(response).get(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); + observedPropertyId3 = new JSONObject(response).get(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); + sensorId4 = new JSONObject(response).get(ControlInformation.ID); //HistoricalLocations urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId1, null, null); urlParameters = "{\"Locations\": [\n" + " {\n" - + " \"@iot.id\": " + locationId2 + "\n" + + " \"@iot.id\": " + quoteIdForJson(locationId2) + "\n" + " }\n" + " ]}"; HTTPMethods.doPatch(urlString, urlParameters); @@ -2151,7 +1440,7 @@ private void createEntities() { urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.THING, thingId2, null, null); urlParameters = "{\"Locations\": [\n" + " {\n" - + " \"@iot.id\": " + locationId1 + "\n" + + " \"@iot.id\": " + quoteIdForJson(locationId1) + "\n" + " }\n" + " ]}"; HTTPMethods.doPatch(urlString, urlParameters); @@ -2160,15 +1449,15 @@ private void createEntities() { 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); + historicalLocationId1 = array.getJSONObject(0).get(ControlInformation.ID); + historicalLocationId2 = array.getJSONObject(1).get(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); + historicalLocationId3 = array.getJSONObject(0).get(ControlInformation.ID); + historicalLocationId4 = array.getJSONObject(1).get(ControlInformation.ID); //Observations urlString = ServiceURLBuilder.buildURLString(rootUri, EntityType.DATASTREAM, datastreamId1, EntityType.OBSERVATION, null); @@ -2176,103 +1465,116 @@ private void createEntities() { + " \"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(")"))); + observationId1 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId2 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId3 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId4 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId5 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId6 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId7 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId8 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId9 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId10 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId11 = postAndGetId(urlString, urlParameters); 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(")"))); + observationId12 = postAndGetId(urlString, urlParameters); //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); + featureOfInterestId1 = new JSONObject(response).get(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); + featureOfInterestId2 = new JSONObject(response).get(ControlInformation.ID); + + entityCounts.setGlobalCount(EntityType.DATASTREAM, 4); + entityCounts.setGlobalCount(EntityType.FEATURE_OF_INTEREST, 2); + entityCounts.setGlobalCount(EntityType.HISTORICAL_LOCATION, 4); + entityCounts.setGlobalCount(EntityType.LOCATION, 2); + entityCounts.setGlobalCount(EntityType.OBSERVATION, 12); + entityCounts.setGlobalCount(EntityType.OBSERVED_PROPERTY, 3); + entityCounts.setGlobalCount(EntityType.SENSOR, 4); + entityCounts.setGlobalCount(EntityType.THING, 2); + + entityCounts.setCount(EntityType.THING, thingId1, EntityType.LOCATION, 1); + entityCounts.setCount(EntityType.THING, thingId2, EntityType.LOCATION, 1); + entityCounts.setCount(EntityType.THING, thingId1, EntityType.HISTORICAL_LOCATION, 2); + entityCounts.setCount(EntityType.THING, thingId2, EntityType.HISTORICAL_LOCATION, 2); + entityCounts.setCount(EntityType.THING, thingId1, EntityType.DATASTREAM, 2); + entityCounts.setCount(EntityType.THING, thingId2, EntityType.DATASTREAM, 2); + entityCounts.setCount(EntityType.LOCATION, locationId1, EntityType.THING, 1); + entityCounts.setCount(EntityType.LOCATION, locationId2, EntityType.THING, 1); + entityCounts.setCount(EntityType.LOCATION, locationId1, EntityType.HISTORICAL_LOCATION, 2); + entityCounts.setCount(EntityType.LOCATION, locationId2, EntityType.HISTORICAL_LOCATION, 2); + entityCounts.setCount(EntityType.HISTORICAL_LOCATION, historicalLocationId1, EntityType.LOCATION, 1); + entityCounts.setCount(EntityType.HISTORICAL_LOCATION, historicalLocationId2, EntityType.LOCATION, 1); + entityCounts.setCount(EntityType.HISTORICAL_LOCATION, historicalLocationId3, EntityType.LOCATION, 1); + entityCounts.setCount(EntityType.HISTORICAL_LOCATION, historicalLocationId4, EntityType.LOCATION, 1); + entityCounts.setCount(EntityType.DATASTREAM, datastreamId1, EntityType.OBSERVATION, 3); + entityCounts.setCount(EntityType.DATASTREAM, datastreamId2, EntityType.OBSERVATION, 3); + entityCounts.setCount(EntityType.DATASTREAM, datastreamId3, EntityType.OBSERVATION, 3); + entityCounts.setCount(EntityType.DATASTREAM, datastreamId4, EntityType.OBSERVATION, 3); + entityCounts.setCount(EntityType.SENSOR, sensorId1, EntityType.DATASTREAM, 1); + entityCounts.setCount(EntityType.SENSOR, sensorId2, EntityType.DATASTREAM, 1); + entityCounts.setCount(EntityType.SENSOR, sensorId3, EntityType.DATASTREAM, 1); + entityCounts.setCount(EntityType.SENSOR, sensorId4, EntityType.DATASTREAM, 1); + entityCounts.setCount(EntityType.OBSERVED_PROPERTY, observedPropertyId1, EntityType.DATASTREAM, 1); + entityCounts.setCount(EntityType.OBSERVED_PROPERTY, observedPropertyId2, EntityType.DATASTREAM, 2); + entityCounts.setCount(EntityType.OBSERVED_PROPERTY, observedPropertyId3, EntityType.DATASTREAM, 1); + entityCounts.setCount(EntityType.FEATURE_OF_INTEREST, featureOfInterestId1, EntityType.OBSERVATION, 6); + entityCounts.setCount(EntityType.FEATURE_OF_INTEREST, featureOfInterestId2, EntityType.OBSERVATION, 6); } catch (JSONException e) { e.printStackTrace(); @@ -2281,29 +1583,6 @@ private void createEntities() { } - /** - * 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. @@ -2329,13 +1608,13 @@ private void deleteEntityType(EntityType entityType) { JSONArray array = null; do { try { - String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, 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); + Object id = array.getJSONObject(i).get(ControlInformation.ID); deleteEntity(entityType, id); } } catch (JSONException e) { @@ -2352,7 +1631,7 @@ private void deleteEntityType(EntityType entityType) { * @param entityType Entity type in from EntityType enum * @param id The id of requested entity */ - private void deleteEntity(EntityType entityType, long id) { + private void deleteEntity(EntityType entityType, Object id) { String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, null); Map responseMap = HTTPMethods.doDelete(urlString); int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); 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 7a0d99e..2448f50 100644 --- a/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java +++ b/src/main/java/org/opengis/cite/sta10/sensingCore/Capability1Tests.java @@ -4,14 +4,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.opengis.cite.sta10.SuiteAttribute; import org.opengis.cite.sta10.util.ControlInformation; -import org.opengis.cite.sta10.util.EntityProperties; -import org.opengis.cite.sta10.util.EntityRelations; import org.opengis.cite.sta10.util.EntityType; import org.opengis.cite.sta10.util.HTTPMethods; import org.opengis.cite.sta10.util.ServiceURLBuilder; @@ -151,8 +148,8 @@ public void readPropertyOfEntityAndCheckResponse() { 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 : EntityProperties.getPropertiesListFor(entityType)) { + Object id = new JSONObject(response).getJSONArray("value").getJSONObject(0).get(ControlInformation.ID); + for (EntityType.EntityProperty property : entityType.getProperties()) { checkGetPropertyOfEntity(entityType, id, property); checkGetPropertyValueOfEntity(entityType, id, property); } @@ -170,20 +167,20 @@ private void readPropertyOfEntityWithEntityType(EntityType entityType) { * @param id The id of the entity * @param property The property to get requested */ - private void checkGetPropertyOfEntity(EntityType entityType, long id, String property) { + private void checkGetPropertyOfEntity(EntityType entityType, Object id, EntityType.EntityProperty property) { try { - Map responseMap = getEntity(entityType, id, property); + Map responseMap = getEntity(entityType, id, property.name); 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."); + Assert.assertEquals(responseCode, 200, "Reading property \"" + property.name + "\" of the existing " + entityType.name() + " with id " + id + " failed."); String response = responseMap.get("response").toString(); JSONObject entity = null; - entity = new JSONObject(response.toString()); + entity = new JSONObject(response); try { - Assert.assertNotNull(entity.get(property), "Reading property \"" + property + "\"of \"" + entityType + "\" fails."); + Assert.assertNotNull(entity.get(property.name), "Reading property \"" + property.name + "\"of \"" + entityType + "\" fails."); } catch (JSONException e) { - Assert.fail("Reading property \"" + property + "\"of \"" + entityType + "\" fails."); + Assert.fail("Reading property \"" + property.name + "\"of \"" + entityType + "\" fails."); } - Assert.assertEquals(entity.length(), 1, "The response for getting property " + property + " of a " + entityType + " returns more properties!"); + Assert.assertEquals(entity.length(), 1, "The response for getting property " + property.name + " of a " + entityType + " returns more properties!"); } catch (JSONException e) { e.printStackTrace(); Assert.fail("An Exception occurred during testing!:\n" + e.getMessage()); @@ -198,15 +195,19 @@ private void checkGetPropertyOfEntity(EntityType entityType, long id, String pro * @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"); + private void checkGetPropertyValueOfEntity(EntityType entityType, Object id, EntityType.EntityProperty property) { + Map responseMap = getEntity(entityType, id, property.name + "/$value"); int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + if (responseCode != 200 && property.optional) { + // The property is optional, and probably not present. + return; + } 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."); + if ("object".equalsIgnoreCase(property.jsonType)) { + Assert.assertEquals(response.indexOf("{"), 0, "Reading property value of \"" + property + "\" of \"" + entityType + "\" fails."); } else { - Assert.assertEquals(response.indexOf("{"), 0, "Reading property value of \"" + property + "\"of \"" + entityType + "\" fails."); + Assert.assertEquals(response.indexOf("{"), -1, "Reading property value of \"" + property + "\" of \"" + entityType + "\" fails."); } } @@ -235,35 +236,8 @@ public void checkResourcePaths() { */ private void readRelatedEntityOfEntityWithEntityType(EntityType entityType) { List entityTypes = new ArrayList<>(); - List ids = new ArrayList<>(); - switch (entityType) { - case THING: - entityTypes.add("Things"); - break; - case LOCATION: - entityTypes.add("Locations"); - break; - case HISTORICAL_LOCATION: - entityTypes.add("HistoricalLocations"); - break; - case DATASTREAM: - entityTypes.add("Datastreams"); - break; - case SENSOR: - entityTypes.add("Sensors"); - break; - case OBSERVATION: - entityTypes.add("Observations"); - break; - case OBSERVED_PROPERTY: - entityTypes.add("ObservedProperties"); - break; - case FEATURE_OF_INTEREST: - entityTypes.add("FeaturesOfInterest"); - break; - default: - Assert.fail("Entity type is not recognized in SensorThings API : " + entityType); - } + List ids = new ArrayList<>(); + entityTypes.add(entityType.plural); readRelatedEntity(entityTypes, ids); } @@ -273,21 +247,26 @@ private void readRelatedEntityOfEntityWithEntityType(EntityType entityType) { * * @param entityTypes List of entity type from EntityType enum list for the * chain - * @param ids List of ids for teh chain + * @param ids List of ids for the chain */ - private void readRelatedEntity(List entityTypes, List ids) { + 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 failed: " + entityTypes.toString()); String response = responseMap.get("response").toString(); - if (!entityTypes.get(entityTypes.size() - 1).toLowerCase().equals("featuresofinterest") && !entityTypes.get(entityTypes.size() - 1).endsWith("s")) { - return; + Object id; + if (isPlural) { + id = new JSONObject(response).getJSONArray("value").getJSONObject(0).get(ControlInformation.ID); + } else { + id = new JSONObject(response).get(ControlInformation.ID); } - Long id = new JSONObject(response.toString()).getJSONArray("value").getJSONObject(0).getLong(ControlInformation.ID); //check $ref urlString = ServiceURLBuilder.buildURLString(rootUri, entityTypes, ids, "$ref"); @@ -299,8 +278,12 @@ private void readRelatedEntity(List entityTypes, List ids) { if (entityTypes.size() == resourcePathLevel) { return; } - ids.add(id); - for (String relation : EntityRelations.getRelationsListFor(entityTypes.get(entityTypes.size() - 1))) { + 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); @@ -320,17 +303,27 @@ private void readRelatedEntity(List entityTypes, List ids) { * @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 + * @param ids List of ids for the chain */ - private void checkAssociationLinks(String response, List entityTypes, List ids) { + private void checkAssociationLinks(String response, List entityTypes, List ids) { try { - Assert.assertTrue(response.indexOf("value") != -1, "The GET entities Association Link response does not match SensorThings API : missing \"value\" in response.: " + entityTypes.toString() + ids.toString()); - JSONArray value = new JSONObject(response.toString()).getJSONArray("value"); - int count = 0; - for (int i = 0; i < value.length() && count < 2; i++) { - count++; - JSONObject obj = value.getJSONObject(i); + 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) { @@ -353,7 +346,7 @@ private void checkAssociationLinks(String response, List entityTypes, Li private String readEntityWithEntityType(EntityType entityType) { try { String response = getEntities(entityType); - Long id = new JSONObject(response.toString()).getJSONArray("value").getJSONObject(0).getLong(ControlInformation.ID); + Object id = new JSONObject(response.toString()).getJSONArray("value").getJSONObject(0).get(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."); @@ -393,6 +386,7 @@ public void checkServiceRootUri() { addedLinks.put("Locations", false); addedLinks.put("HistoricalLocations", false); addedLinks.put("Datastreams", false); + addedLinks.put("MultiDatastreams", false); addedLinks.put("Sensors", false); addedLinks.put("Observations", false); addedLinks.put("ObservedProperties", false); @@ -407,50 +401,11 @@ public void checkServiceRootUri() { } 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; - default: - Assert.fail("There is a component in Service Root URI response that is not in SensorThings API : " + name); - break; + if (addedLinks.containsKey(name)) { + Assert.assertEquals(nameUrl, rootUri + "/" + name, "The URL for " + name + " in Service Root URI is not compliant to SensorThings API."); + addedLinks.put(name, true); + } else { + Assert.fail("There is a component in Service Root URI response that is not in SensorThings API : " + name); } } for (String key : addedLinks.keySet()) { @@ -472,18 +427,18 @@ public void checkServiceRootUri() { private String getEntities(EntityType entityType) { String urlString = rootUri; if (entityType != null) { - urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, -1, null, null); + urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, null, 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."); + Assert.assertTrue(response.contains("value"), "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."); + Assert.assertTrue(response.contains("value"), "The GET entities response for service root URI does not match SensorThings API : missing \"value\" in response."); } - return response.toString(); + return response; } /** @@ -493,10 +448,10 @@ private String getEntities(EntityType entityType) { * @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. + * format. */ - private Map getEntity(EntityType entityType, long id, String property) { - if (id == -1) { + private Map getEntity(EntityType entityType, Object id, String property) { + if (id == null) { return null; } String urlString = ServiceURLBuilder.buildURLString(rootUri, entityType, id, null, property); @@ -611,9 +566,12 @@ private void checkEntitiesProperties(EntityType entityType, String response) { private void checkEntityProperties(EntityType entityType, Object response) { try { JSONObject entity = new JSONObject(response.toString()); - for (String property : EntityProperties.getPropertiesListFor(entityType)) { + for (EntityType.EntityProperty property : entityType.getProperties()) { + if (property.optional) { + continue; + } try { - Assert.assertNotNull(entity.get(property), "Entity type \"" + entityType + "\" does not have mandatory property: \"" + property + "\"."); + Assert.assertNotNull(entity.get(property.name), "Entity type \"" + entityType + "\" does not have mandatory property: \"" + property + "\"."); } catch (JSONException e) { Assert.fail("Entity type \"" + entityType + "\" does not have mandatory property: \"" + property + "\"."); } @@ -660,7 +618,7 @@ private void checkEntitiesRelations(EntityType entityType, String response) { private void checkEntityRelations(EntityType entityType, Object response) { try { JSONObject entity = new JSONObject(response.toString()); - for (String relation : EntityRelations.getRelationsListFor(entityType)) { + for (String relation : entityType.getRelations()) { try { Assert.assertNotNull(entity.get(relation + ControlInformation.NAVIGATION_LINK), "Entity type \"" + entityType + "\" does not have mandatory relation: \"" + relation + "\"."); } catch (JSONException e) { diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityCounts.java b/src/main/java/org/opengis/cite/sta10/util/EntityCounts.java new file mode 100644 index 0000000..4a749f1 --- /dev/null +++ b/src/main/java/org/opengis/cite/sta10/util/EntityCounts.java @@ -0,0 +1,80 @@ +/* + * Copyright 2016 Open Geospatial Consortium. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opengis.cite.sta10.util; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Map; + +/** + * A helper class for keeping track of entity counts. Both global counts, and + * linked counts per individual entity. + * + * @author Hylke van der Schaaf + */ +public class EntityCounts { + + private final Map globalCounts = new EnumMap<>(EntityType.class); + private final Map>> linkedCounts = new EnumMap<>(EntityType.class); + + public long getCount(EntityType type) { + Long count = globalCounts.get(type); + return count == null ? -1 : count; + } + + public long getCount(EntityType parentType, Object parentId, EntityType linkedType) { + Map> parents = linkedCounts.get(parentType); + if (parents == null) { + return -1; + } + Map parent = parents.get(parentId); + if (parent == null) { + return -1; + } + Long count = parent.get(linkedType); + return count == null ? -1 : count; + } + + private Map> getParents(EntityType type) { + Map> parents = linkedCounts.get(type); + if (parents == null) { + parents = new HashMap<>(); + linkedCounts.put(type, parents); + } + return parents; + } + + private Map getCounts(EntityType parentType, Object parentId) { + Map> parents = getParents(parentType); + Map parent = parents.get(parentId); + if (parent == null) { + parent = new EnumMap<>(EntityType.class); + parents.put(parentId, parent); + } + return parent; + } + + public EntityCounts setGlobalCount(EntityType type, long count) { + globalCounts.put(type, count); + return this; + } + + public EntityCounts setCount(EntityType parentType, Object parentId, EntityType linkedType, long count) { + getCounts(parentType, parentId).put(linkedType, count); + return this; + } + +} diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityProperties.java b/src/main/java/org/opengis/cite/sta10/util/EntityProperties.java deleted file mode 100644 index 9ced9a5..0000000 --- a/src/main/java/org/opengis/cite/sta10/util/EntityProperties.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.opengis.cite.sta10.util; - -/** - * Mandatory properties of each entity. - */ -public class EntityProperties { - - /** - * List of Mandatory properties for Thing entity. - */ - public static final String[] THING_PROPERTIES = {"name", "description"}; - /** - * List of Mandatory properties for Location entity. - */ - public static final String[] LOCATION_PROPERTIES = {"name", "description", "encodingType", "location"}; - /** - * List of Mandatory properties for HistoricalLocation entity. - */ - public static final String[] HISTORICAL_LOCATION_PROPERTIES = {"time"}; - /** - * List of Mandatory properties for Datastream entity. - */ - public static final String[] DATASTREAM_PROPERTIES = {"name", "description", "unitOfMeasurement", "observationType"}; - /** - * List of Mandatory properties for Sensor entity. - */ - public static final String[] SENSOR_PROPERTIES = {"name", "description", "encodingType", "metadata"}; - /** - * List of Mandatory properties for ObservedProperty entity. - */ - public static final String[] OBSERVED_PROPETY_PROPERTIES = {"name", "definition", "description"}; - /** - * List of Mandatory properties for Observation entity. - */ - public static final String[] OBSERVATION_PROPERTIES = {"phenomenonTime", "result", "resultTime"}; - /** - * List of Mandatory properties for FeatureOfInterest entity. - */ - public static final String[] FEATURE_OF_INTEREST_PROPERTIES = {"name", "description", "encodingType", "feature"}; - - /** - * Returning the list of mandatory properties for the given entity name. - * - * @param name The type of entity in String format - * @return List of all mandatory properties for the given entity - */ - public static String[] getPropertiesListFor(String name) { - switch (name.toLowerCase()) { - case "thing": - case "things": - return THING_PROPERTIES; - case "location": - case "locations": - return LOCATION_PROPERTIES; - case "historicallocation": - case "historicallocations": - return HISTORICAL_LOCATION_PROPERTIES; - case "datastream": - case "datastreams": - return DATASTREAM_PROPERTIES; - case "sensor": - case "sensors": - return SENSOR_PROPERTIES; - case "observedproperty": - case "observedproperties": - return OBSERVED_PROPETY_PROPERTIES; - case "observation": - case "observations": - return OBSERVATION_PROPERTIES; - case "featureofinterest": - case "featuresofinterest": - return FEATURE_OF_INTEREST_PROPERTIES; - } - return null; - } - - /** - * Returning the list of mandatory properties for the given entityType. - * - * @param entityType The type of entity from EntityType enum - * @return List of all mandatory properties for the given entityType - */ - public static String[] getPropertiesListFor(EntityType entityType) { - switch (entityType) { - case THING: - return THING_PROPERTIES; - case LOCATION: - return LOCATION_PROPERTIES; - case FEATURE_OF_INTEREST: - return FEATURE_OF_INTEREST_PROPERTIES; - case OBSERVED_PROPERTY: - return OBSERVED_PROPETY_PROPERTIES; - case HISTORICAL_LOCATION: - return HISTORICAL_LOCATION_PROPERTIES; - case SENSOR: - return SENSOR_PROPERTIES; - case DATASTREAM: - return DATASTREAM_PROPERTIES; - case OBSERVATION: - return OBSERVATION_PROPERTIES; - default: - break; - } - return null; - } -} 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..9df4828 100644 --- a/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java +++ b/src/main/java/org/opengis/cite/sta10/util/EntityPropertiesSampleValue.java @@ -56,25 +56,29 @@ public class EntityPropertiesSampleValue { * "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; + try { + 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; + } + } catch (IndexOutOfBoundsException e) { + // No sample value for this property... } return null; } diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityRelations.java b/src/main/java/org/opengis/cite/sta10/util/EntityRelations.java deleted file mode 100644 index c56c794..0000000 --- a/src/main/java/org/opengis/cite/sta10/util/EntityRelations.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.opengis.cite.sta10.util; - -/** - * List of the entity relations for each entity type. - */ -public class EntityRelations { - /** - * List of entity relations for Thing entity. - */ - public static final String[] THING_RELATIONS = {"Datastreams", "Locations", "HistoricalLocations"}; - /** - * List of entity relations for Location entity. - */ - public static final String[] LOCATION_RELATIONS = {"Things", "HistoricalLocations"}; - /** - * List of entity relations for HistoricalLocation entity. - */ - public static final String[] HISTORICAL_LOCATION_RELATIONS = {"Thing", "Locations"}; - /** - * List of entity relations for Datastream entity. - */ - public static final String[] DATASTREAM_RELATIONS = {"Thing", "Sensor", "ObservedProperty", "Observations"}; - /** - * List of entity relations for Sensor entity. - */ - public static final String[] SENSOR_RELATIONS = {"Datastreams"}; - /** - * List of entity relations for Observation entity. - */ - public static final String[] OBSERVATION_RELATIONS = {"Datastream", "FeatureOfInterest"}; - /** - * List of entity relations for ObservedProperty entity. - */ - public static final String[] OBSERVED_PROPERTY_RELATIONS = {"Datastreams"}; - /** - * List of entity relations for FeatureOfInterest entity. - */ - public static final String[] FEATURE_OF_INTEREST_RELATIONS = {"Observations"}; - - - /** - * Returning the list of entity relations for the given entityType. - * - * @param entityType The type of entity from EntityType enum - * @return List of all entity relations for the given entityType - */ - public static String[] getRelationsListFor(EntityType entityType) { - switch (entityType) { - case THING: - return THING_RELATIONS; - case LOCATION: - return LOCATION_RELATIONS; - case FEATURE_OF_INTEREST: - return FEATURE_OF_INTEREST_RELATIONS; - case OBSERVED_PROPERTY: - return OBSERVED_PROPERTY_RELATIONS; - case HISTORICAL_LOCATION: - return HISTORICAL_LOCATION_RELATIONS; - case SENSOR: - return SENSOR_RELATIONS; - case DATASTREAM: - return DATASTREAM_RELATIONS; - case OBSERVATION: - return OBSERVATION_RELATIONS; - default: - break; - } - return null; - } - - /** - * Returning the list of entity relations for the given entity name. - * - * @param name The type of entity in String format - * @return List of all entity relations for the given entity - */ - public static String[] getRelationsListFor(String name) { - switch (name.toLowerCase()) { - case "thing": - case "things": - return THING_RELATIONS; - case "location": - case "locations": - return LOCATION_RELATIONS; - case "historicallocation": - case "historicallocations": - return HISTORICAL_LOCATION_RELATIONS; - case "datastream": - case "datastreams": - return DATASTREAM_RELATIONS; - case "sensor": - case "sensors": - return SENSOR_RELATIONS; - case "observedproperty": - case "observedproperties": - return OBSERVED_PROPERTY_RELATIONS; - case "observation": - case "observations": - return OBSERVATION_RELATIONS; - case "featureofinterest": - case "featuresofinterest": - return FEATURE_OF_INTEREST_RELATIONS; - } - 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 a010028..3a6998e 100644 --- a/src/main/java/org/opengis/cite/sta10/util/EntityType.java +++ b/src/main/java/org/opengis/cite/sta10/util/EntityType.java @@ -1,15 +1,197 @@ package org.opengis.cite.sta10.util; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** * List of entity types in SensorThings API. */ public enum EntityType { - THING, - LOCATION, - SENSOR, - OBSERVED_PROPERTY, - OBSERVATION, - DATASTREAM, - FEATURE_OF_INTEREST, - HISTORICAL_LOCATION + 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"); + + /** + * The class representing an EntityProperty. + */ + public static class EntityProperty { + + public final String name; + public final boolean optional; + public final boolean canSort; + public final String jsonType; + + public EntityProperty(String name, boolean optional, boolean canSort, String jsonType) { + this.name = name; + this.optional = optional; + this.canSort = canSort; + this.jsonType = jsonType; + } + + @Override + public String toString() { + return name; + } + } + /** + * The singular name of the entity type. + */ + public final String singular; + /** + * The plural (collection) name of the entity type. + */ + public final String plural; + private final List properties = new ArrayList<>(); + private final Map propertiesByName = new HashMap<>(); + private final List relations = new ArrayList<>(); + + private static final Map NAMES_MAP = new HashMap<>(); + private static final Set NAMES_PLURAL = new HashSet<>(); + + static { + // TODO: Add properties, fix test that break + THING.addProperty("name", false, true); + THING.addProperty("description", false, true); + THING.addProperty("properties", true, false, "object"); + THING.addRelations(DATASTREAM.plural, HISTORICAL_LOCATION.plural, LOCATION.plural); + + LOCATION.addProperty("name", false, true); + LOCATION.addProperty("description", false, true); + LOCATION.addProperty("encodingType", false, true); + LOCATION.addProperty("location", false, false, "object"); + LOCATION.addRelations(HISTORICAL_LOCATION.plural, THING.plural); + + SENSOR.addProperty("name", false, true); + SENSOR.addProperty("description", false, true); + SENSOR.addProperty("encodingType", false, true); + SENSOR.addProperty("metadata", false, true); + SENSOR.addRelations(DATASTREAM.plural); + + OBSERVED_PROPERTY.addProperty("name", false, true); + OBSERVED_PROPERTY.addProperty("definition", false, true); + OBSERVED_PROPERTY.addProperty("description", false, true); + OBSERVED_PROPERTY.addRelations(DATASTREAM.plural); + + OBSERVATION.addProperty("phenomenonTime", false, true); + OBSERVATION.addProperty("result", false, true, "any"); + OBSERVATION.addProperty("resultTime", false, true); + OBSERVATION.addProperty("resultQuality", true, true); + OBSERVATION.addProperty("validTime", true, true); + OBSERVATION.addProperty("parameters", true, true, "object"); + OBSERVATION.addRelations(DATASTREAM.singular, FEATURE_OF_INTEREST.singular); + + DATASTREAM.addProperty("name", false, true); + DATASTREAM.addProperty("description", false, true); + DATASTREAM.addProperty("unitOfMeasurement", false, false, "object"); + DATASTREAM.addProperty("observationType", false, true); + DATASTREAM.addProperty("observedArea", true, false, "object"); + DATASTREAM.addProperty("phenomenonTime", true, true); + DATASTREAM.addProperty("resultTime", true, true); + DATASTREAM.addRelations(THING.singular, SENSOR.singular, OBSERVED_PROPERTY.singular, OBSERVATION.plural); + + FEATURE_OF_INTEREST.addProperty("name", false, true); + FEATURE_OF_INTEREST.addProperty("description", false, true); + FEATURE_OF_INTEREST.addProperty("encodingType", false, true); + FEATURE_OF_INTEREST.addProperty("feature", false, false, "object"); + FEATURE_OF_INTEREST.addRelations(OBSERVATION.plural); + + HISTORICAL_LOCATION.addProperty("time", false, true); + 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); + } + + public Set getPropertyNames() { + return propertiesByName.keySet(); + } + + public EntityProperty getPropertyForName(String property) { + return propertiesByName.get(property); + } + + /** + * Clears and then fills the target list with either the odd or even + * properties and relations. Always returns "id". + * + * @param target the list to fill. + * @param even if true, the even properties are taken, otherwise the odd. + */ + public void getHalfPropertiesRelations(List target, final boolean even) { + target.clear(); + target.add("id"); + boolean isEven = true; + for (EntityProperty property : properties) { + if (even == isEven) { + target.add(property.name); + } + isEven = !isEven; + } + for (String relation : relations) { + if (even == isEven) { + target.add(relation); + } + isEven = !isEven; + } + } + + private void addProperty(String name, boolean optional, boolean canSort) { + EntityProperty property = new EntityProperty(name, optional, canSort, "string"); + properties.add(property); + propertiesByName.put(name, property); + } + + private void addProperty(String name, boolean optional, boolean canSort, String jsonType) { + EntityProperty property = new EntityProperty(name, optional, canSort, jsonType); + properties.add(property); + propertiesByName.put(name, property); + } + + private void addRelations(String... relations) { + this.relations.addAll(Arrays.asList(relations)); + } + } diff --git a/src/main/java/org/opengis/cite/sta10/util/EntityUtils.java b/src/main/java/org/opengis/cite/sta10/util/EntityUtils.java new file mode 100644 index 0000000..2468dfb --- /dev/null +++ b/src/main/java/org/opengis/cite/sta10/util/EntityUtils.java @@ -0,0 +1,245 @@ +package org.opengis.cite.sta10.util; + +import java.util.ArrayList; +import java.util.List; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.testng.Assert; + +/** + * Utility methods for comparing results and cleaning the service. + * + * @author Hylke van der Schaaf + */ +public class EntityUtils { + + /** + * Find the expected count value for the given request. Can not determine + * the count for paths like /Datastreams(xxx)/Thing/Locations since the id + * of the Thing can not be determined from the path. + * + * @param request The request to determine the count for. + * @param entityCounts The object holding the entity counts. + * @return The expected count for the given request. + */ + public static long findCountForRequest(Request request, EntityCounts entityCounts) { + Object parentId = -1; + long count = -1; + EntityType parentType = null; + for (PathElement element : request.getPath()) { + EntityType elementType = element.getEntityType(); + if (element.getId() != null) { + parentId = element.getId(); + parentType = elementType; + count = -1; + } else if (parentType == null) { + if (!element.isCollection()) { + throw new IllegalArgumentException("Non-collection requested without parent."); + } + count = entityCounts.getCount(elementType); + } else if (element.isCollection()) { + count = entityCounts.getCount(parentType, parentId, elementType); + parentType = null; + parentId = -1; + } else { + count = -1; + // Can not determine the id of this single-entity. + } + } + + return count; + } + + /** + * Checks the given response against the given request. + * + * @param response The response object to check. + * @param request The request to check the response against. + * @param entityCounts The object with the expected entity counts. + */ + public static void checkResponse(JSONObject response, Request request, EntityCounts entityCounts) { + try { + if (request.isCollection()) { + checkCollection(response.getJSONArray("value"), request, entityCounts); + + // check count for request + Query expandQuery = request.getQuery(); + Boolean count = expandQuery.getCount(); + String countProperty = "@iot.count"; + if (count != null) { + if (count) { + Assert.assertTrue(response.has(countProperty), "Response should have property " + countProperty + " for request: '" + request.toString() + "'"); + } else { + Assert.assertFalse(response.has(countProperty), "Response should not have property " + countProperty + " for request: '" + request.toString() + "'"); + } + } + + long expectedCount = findCountForRequest(request, entityCounts); + if (response.has(countProperty) && expectedCount != -1) { + long foundCount = response.getLong(countProperty); + Assert.assertEquals(foundCount, expectedCount, "Incorrect count for collection of " + request.getEntityType() + " for request: '" + request.toString() + "'"); + } + Long top = expandQuery.getTop(); + if (top != null && expectedCount != -1) { + int foundNumber = response.getJSONArray("value").length(); + long skip = expandQuery.getSkip() == null ? 0 : expandQuery.getSkip(); + + long expectedNumber = Math.max(0, Math.min(expectedCount - skip, top)); + if (foundNumber != expectedNumber) { + Assert.fail("Requested " + top + " of " + expectedCount + ", expected " + expectedNumber + " with skip of " + skip + " but received " + foundNumber + " for request: '" + request.toString() + "'"); + } + + String nextLinkProperty = "@iot.nextLink"; + if (foundNumber + skip < expectedCount) { + // should have nextLink + Assert.assertTrue(response.has(nextLinkProperty), "Entity should have " + nextLinkProperty + " for request: '" + request.toString() + "'"); + } else { + // should not have nextLink + Assert.assertFalse(response.has(nextLinkProperty), "Entity should not have " + nextLinkProperty + " for request: '" + request.toString() + "'"); + } + + } + + } else { + checkEntity(response, request, entityCounts); + } + } catch (JSONException ex) { + Assert.fail("Failure when checking response of query '" + request.getLastUrl() + "'", ex); + } + } + + /** + * Check a collection from a response, against the given expand as present + * in the request. + * + * @param collection The collection of items to check. + * @param expand The expand that led to the collection. + * @param entityCounts The object with the expected entity counts. + * @throws JSONException if there is a problem with the json. + */ + public static void checkCollection(JSONArray collection, Expand expand, EntityCounts entityCounts) throws JSONException { + // Check entities + for (int i = 0; i < collection.length(); i++) { + checkEntity(collection.getJSONObject(i), expand, entityCounts); + } + // todo: check orderby + // todo: check filter + } + + /** + * Check the given entity from a response against the given expand. + * + * @param entity The entity to check. + * @param expand The expand that led to the entity. + * @param entityCounts The object with the expected entity counts. + * @throws JSONException if there is a problem with the json. + */ + public static void checkEntity(JSONObject entity, Expand expand, EntityCounts entityCounts) throws JSONException { + EntityType entityType = expand.getEntityType(); + Query query = expand.getQuery(); + + // Check properties & select + List select = new ArrayList<>(query.getSelect()); + if (select.isEmpty()) { + select.add("id"); + select.addAll(entityType.getPropertyNames()); + if (expand.isToplevel()) { + select.addAll(entityType.getRelations()); + } + } + if (select.contains("id")) { + Assert.assertTrue(entity.has("@iot.id"), "Entity should have property @iot.id for request: '" + expand.toString() + "'"); + } else { + Assert.assertFalse(entity.has("@iot.id"), "Entity should not have property @iot.id for request: '" + expand.toString() + "'"); + } + for (EntityType.EntityProperty property : entityType.getProperties()) { + if (select.contains(property.name)) { + Assert.assertTrue( + entity.has(property.name) || property.optional, + "Entity should have property " + property.name + " for request: '" + expand.toString() + "'"); + } else { + Assert.assertFalse(entity.has(property.name), "Entity should not have property " + property.name + " for request: '" + expand.toString() + "'"); + } + } + for (String relationName : entityType.getRelations()) { + String propertyName = relationName + "@iot.navigationLink"; + if (select.contains(relationName)) { + Assert.assertTrue(entity.has(propertyName), "Entity should have property " + propertyName + " for request: '" + expand.toString() + "'"); + } else { + Assert.assertFalse(entity.has(propertyName), "Entity should not have property " + propertyName + " for request: '" + expand.toString() + "'"); + } + } + + // Entity id in case we need to check counts. + Object entityId = entity.opt("@iot.id"); + + // Check expand + List relations = new ArrayList<>(entityType.getRelations()); + for (Expand subExpand : query.getExpand()) { + PathElement path = subExpand.getPath().get(0); + String propertyName = path.getPropertyName(); + if (!entity.has(propertyName)) { + Assert.fail("Entity should have expanded " + propertyName + " for request: '" + expand.toString() + "'"); + } + + // Check the expanded items + if (subExpand.isCollection()) { + checkCollection(entity.getJSONArray(propertyName), subExpand, entityCounts); + } else { + checkEntity(entity.getJSONObject(propertyName), subExpand, entityCounts); + } + relations.remove(propertyName); + + // For expanded collections, check count, top, skip + if (subExpand.isCollection()) { + // Check count + Query expandQuery = subExpand.getQuery(); + Boolean count = expandQuery.getCount(); + String countProperty = propertyName + "@iot.count"; + boolean hasCountProperty = entity.has(countProperty); + if (count != null) { + if (count) { + Assert.assertTrue(hasCountProperty, "Entity should have property " + countProperty + " for request: '" + expand.toString() + "'"); + } else { + Assert.assertFalse(hasCountProperty, "Entity should not have property " + countProperty + " for request: '" + expand.toString() + "'"); + } + } + + long expectedCount = entityCounts.getCount(entityType, entityId, EntityType.getForRelation(propertyName)); + if (hasCountProperty && expectedCount != -1) { + long foundCount = entity.getLong(countProperty); + Assert.assertEquals(foundCount, expectedCount, "Found incorrect count for " + countProperty); + } + + Long top = expandQuery.getTop(); + if (top != null && expectedCount != -1) { + int foundNumber = entity.getJSONArray(propertyName).length(); + long skip = expandQuery.getSkip() == null ? 0 : expandQuery.getSkip(); + + long expectedNumber = Math.min(expectedCount - skip, top); + if (foundNumber != expectedNumber) { + Assert.fail("Requested " + top + " of " + expectedCount + ", expected " + expectedNumber + " with skip of " + skip + " but received " + foundNumber); + } + + String nextLinkProperty = propertyName + "@iot.nextLink"; + if (foundNumber + skip < expectedCount) { + // should have nextLink + Assert.assertTrue(entity.has(nextLinkProperty), "Entity should have " + nextLinkProperty + " for expand " + subExpand.toString()); + } else { + // should not have nextLink + Assert.assertFalse(entity.has(nextLinkProperty), "Entity should have " + nextLinkProperty + " for expand " + subExpand.toString()); + } + + } + + } + } + for (String propertyName : relations) { + if (entity.has(propertyName)) { + Assert.fail("Entity should not have expanded " + propertyName + " for request: '" + expand.toString() + "'"); + } + } + } + +} diff --git a/src/main/java/org/opengis/cite/sta10/util/Expand.java b/src/main/java/org/opengis/cite/sta10/util/Expand.java new file mode 100644 index 0000000..c8fb4a5 --- /dev/null +++ b/src/main/java/org/opengis/cite/sta10/util/Expand.java @@ -0,0 +1,125 @@ +/* + * Copyright 2016 Open Geospatial Consortium. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opengis.cite.sta10.util; + +import java.util.ArrayList; +import java.util.List; + +/** + * {@link java.lang.Object#clone()} returns a deep copy. + * + * @author Hylke van der Schaaf + */ +public class Expand implements Cloneable { + + private final List path = new ArrayList<>(); + private final Query query; + + public Expand() { + query = new Query(); + query.setParent(this); + } + + public Expand(Query query) { + this.query = query; + query.setParent(this); + } + + public List getPath() { + return path; + } + + public Expand addElement(PathElement element) { + path.add(element); + return this; + } + + public boolean isCollection() { + return path.get(path.size() - 1).isCollection(); + } + + public EntityType getEntityType() { + return path.get(path.size() - 1).getEntityType(); + } + + public Query getQuery() { + return query; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + boolean firstDone = false; + for (PathElement element : path) { + if (firstDone) { + sb.append("/"); + } else { + firstDone = true; + } + sb.append(element.toString()); + } + if (!query.isEmpty()) { + sb.append('('); + sb.append(query.toString(true)); + sb.append(')'); + } + return sb.toString(); + } + + public boolean isToplevel() { + return false; + } + + /** + * Turns a multi-level expand (Datastreams/Sensor) into nested expands. + * + * @return a proper nested expand. + */ + public Expand reNest() { + if (path.size() == 1) { + return this; + } + query.reNestExpands(); + Query currentQuery = query; + Expand currentExpand = null; + for (int i = path.size() - 1; i >= 0; i--) { + currentExpand = new Expand(currentQuery); + currentExpand.addElement(path.get(i)); + currentQuery = new Query(); + currentQuery.addExpand(currentExpand); + } + return currentExpand; + } + + @Override + public Expand clone() { + Expand clone; + try { + // Can't use super.clone() since that would make the path of the + // clone a reference to our path. + clone = getClass().newInstance(); + } catch (InstantiationException | IllegalAccessException ex) { + // should not happen + throw new IllegalStateException(ex); + } + for (PathElement item : path) { + clone.path.add(item.clone()); + } + clone.query.duplicate(query); + return clone; + } + +} 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..1ad05d4 100644 --- a/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java +++ b/src/main/java/org/opengis/cite/sta10/util/HTTPMethods.java @@ -1,4 +1,3 @@ - package org.opengis.cite.sta10.util; import org.apache.http.client.ClientProtocolException; @@ -101,7 +100,7 @@ public static Map doPost(String urlString, String postBody) { wr.write(postData); } - Map result = new HashMap(); + Map result = new HashMap<>(); result.put("response-code", connection.getResponseCode()); if (connection.getResponseCode() == 201) { result.put("response", connection.getHeaderField("location")); diff --git a/src/main/java/org/opengis/cite/sta10/util/PathElement.java b/src/main/java/org/opengis/cite/sta10/util/PathElement.java new file mode 100644 index 0000000..75c4083 --- /dev/null +++ b/src/main/java/org/opengis/cite/sta10/util/PathElement.java @@ -0,0 +1,82 @@ +/* + * Copyright 2016 Open Geospatial Consortium. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opengis.cite.sta10.util; + +/** + * + * @author Hylke van der Schaaf + */ +public class PathElement implements Cloneable { + + private final EntityType entityType; + private final boolean plural; + private final Object id; + + public PathElement(EntityType entityType, boolean plural, Object id) { + this.entityType = entityType; + this.plural = plural; + this.id = id; + } + + public PathElement(String pathPart) { + this(pathPart, null); + } + + public PathElement(String pathPart, Object id) { + entityType = EntityType.getForRelation(pathPart); + plural = EntityType.isPlural(pathPart); + this.id = id; + } + + public EntityType getEntityType() { + return entityType; + } + + public String getPropertyName() { + return plural ? entityType.plural : entityType.singular; + } + + @Override + public String toString() { + StringBuilder value = new StringBuilder(); + value.append(plural ? entityType.plural : entityType.singular); + if (id != null) { + value.append('(').append(Utils.quoteIdForUrl(id)).append(')'); + } + return value.toString(); + } + + public boolean isCollection() { + return plural && id == null; + } + + public Object getId() { + return id; + } + + @Override + protected PathElement clone() { + PathElement clone; + try { + clone = (PathElement) super.clone(); + } catch (CloneNotSupportedException ex) { + // should not happen + throw new IllegalStateException(ex); + } + return clone; + } + +} diff --git a/src/main/java/org/opengis/cite/sta10/util/Query.java b/src/main/java/org/opengis/cite/sta10/util/Query.java new file mode 100644 index 0000000..dbbdc32 --- /dev/null +++ b/src/main/java/org/opengis/cite/sta10/util/Query.java @@ -0,0 +1,309 @@ +/* + * Copyright 2016 Open Geospatial Consortium. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opengis.cite.sta10.util; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; + +/** + * + * @author Hylke van der Schaaf + */ +public class Query { + + /** + * The value of the count option, or null if not set. + */ + private Boolean count; + /** + * The value of the top option, or null if not set. + */ + private Long top; + /** + * The value of the skip option, or null if not set. + */ + private Long skip; + /** + * The value of the expand option, empty if not set. + */ + private final List expand = new ArrayList<>(); + /** + * The value of the select option, empty if not set. + */ + private final List select = new ArrayList<>(); + /** + * The value of the orderBy option, or null if not set. + */ + private String orderBy; + /** + * The value of the filter option, or null if not set. + */ + private String filter; + /** + * The expand this query is part of. + */ + private Expand parent; + + public void setParent(Expand parent) { + this.parent = parent; + } + + /** + * creates the url version of the query. + * + * @param inExpand flag to indicate the query is part of an Expand option. + * @return the Query as a string to be used in a URL. + */ + public String toString(boolean inExpand) { + char separator = inExpand ? ';' : '&'; + boolean isCollection = parent.isCollection(); + + StringBuilder sb = new StringBuilder(); + if (top != null && isCollection) { + sb.append(separator).append("$top=").append(top); + } + if (skip != null && isCollection) { + sb.append(separator).append("$skip=").append(skip); + } + if (!select.isEmpty()) { + sb.append(separator).append("$select="); + boolean firstDone = false; + for (String property : select) { + if (firstDone) { + sb.append(","); + } else { + firstDone = true; + } + sb.append(property); + } + } + if (filter != null && isCollection) { + sb.append(separator).append("$filter="); + String filterString = filter; + if (!inExpand) { + filterString = Utils.urlEncode(filterString); + } + sb.append(filterString); + } + if (!expand.isEmpty()) { + sb.append(separator).append("$expand="); + boolean firstDone = false; + for (Expand e : expand) { + if (firstDone) { + sb.append(","); + } else { + firstDone = true; + } + String expandUrl = e.toString(); + sb.append(expandUrl); + } + } + if (orderBy != null && isCollection) { + sb.append(separator).append("$orderby=").append(orderBy); + } + if (count != null && isCollection) { + sb.append(separator).append("$count=").append(count); + } + if (sb.length() > 0) { + return sb.substring(1); + } + return ""; + } + + /** + * Properly nests the expands. Removes duplicates. + */ + public void reNestExpands() { + List newExpands = new ArrayList<>(); + Map expandMap = new EnumMap<>(EntityType.class); + for (Expand oldExpand : expand) { + Expand reNest = oldExpand.reNest(); + EntityType entityType = reNest.getEntityType(); + if (expandMap.containsKey(entityType)) { + Expand existing = expandMap.get(entityType); + existing.getQuery().addExpand(reNest.getQuery().getExpand()); + existing.getQuery().reNestExpands(); + } else { + newExpands.add(reNest); + expandMap.put(entityType, reNest); + } + } + expand.clear(); + expand.addAll(newExpands); + } + + public boolean isEmpty() { + return count == null + && top == null + && skip == null + && expand.isEmpty() + && select.isEmpty() + && orderBy == null + && filter == null; + } + + /** + * The value of the count option, or null if not set. + * + * @return the count + */ + public Boolean getCount() { + return count; + } + + /** + * The value of the count option, or null if not set. + * + * @param count the count to set + * @return this Query; + */ + public Query setCount(Boolean count) { + this.count = count; + return this; + } + + /** + * The value of the top option, or null if not set. + * + * @return the top + */ + public Long getTop() { + return top; + } + + /** + * Set the value of the top option. + * + * @param top the top to set + * @return this Query; + */ + public Query setTop(Long top) { + this.top = top; + return this; + } + + /** + * The value of the skip option, or null if not set. + * + * @return the skip + */ + public Long getSkip() { + return skip; + } + + /** + * Set the value of the skip option. + * + * @param skip the skip to set + * @return this Query; + */ + public Query setSkip(Long skip) { + this.skip = skip; + return this; + } + + /** + * The value of the expand option, empty if not set. + * + * @return the expand + */ + public List getExpand() { + return expand; + } + + /** + * Add an expand option. + * + * @param expand the expand to add. + * @return this Query; + */ + public Query addExpand(Expand expand) { + this.expand.add(expand); + return this; + } + + /** + * Add a list of expand options. + * + * @param expand the expands to add + * @return this Query; + */ + public Query addExpand(List expand) { + this.expand.addAll(expand); + return this; + } + + /** + * The value of the select option, empty if not set. + * + * @return the select + */ + public List getSelect() { + return select; + } + + /** + * The value of the select option, empty if not set. + * + * @param select the select to add + * @return this Query; + */ + public Query addSelect(String select) { + this.select.add(select); + return this; + } + + /** + * The value of the filter option, or null if not set. + * + * @return the filter + */ + public String getFilter() { + return filter; + } + + /** + * The value of the filter option, or null if not set. + * + * @param filter the filter to set + * @return this Query; + */ + public Query setFilter(String filter) { + this.filter = filter; + return this; + } + + /** + * Duplicate the source into this query by making a deep copy. + * + * @param source the source to duplicate. + */ + public void duplicate(Query source) { + count = source.count; + filter = source.filter; + orderBy = source.orderBy; + skip = source.skip; + top = source.top; + for (Expand item : source.expand) { + expand.add(item.clone()); + } + for (String item : source.select) { + select.add(item); + } + } +} diff --git a/src/main/java/org/opengis/cite/sta10/util/Request.java b/src/main/java/org/opengis/cite/sta10/util/Request.java new file mode 100644 index 0000000..feffaed --- /dev/null +++ b/src/main/java/org/opengis/cite/sta10/util/Request.java @@ -0,0 +1,105 @@ +/* + * Copyright 2016 Open Geospatial Consortium. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opengis.cite.sta10.util; + +import java.util.Map; +import org.json.JSONException; +import org.json.JSONObject; +import org.testng.Assert; + +/** + * + * @author Hylke van der Schaaf + */ +public class Request extends Expand { + + private String baseUrl; + private String lastUrl; + + public Request() { + } + + public Request(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + @Override + public Request reNest() { + getQuery().reNestExpands(); + return this; + } + + @Override + public boolean isToplevel() { + return true; + } + + @Override + public String toString() { + if (lastUrl == null) { + buildUrl(); + } + return lastUrl; + } + + public String getLastUrl() { + return lastUrl; + } + + public String buildUrl() { + StringBuilder urlString = new StringBuilder(baseUrl); + for (PathElement element : getPath()) { + urlString.append('/').append(element.toString()); + } + urlString.append('?').append(getQuery().toString(false)); + lastUrl = urlString.toString(); + return lastUrl; + } + + public JSONObject executeGet() { + String fetchUrl = buildUrl(); + Map responseMap = HTTPMethods.doGet(fetchUrl); + String response = responseMap.get("response").toString(); + int responseCode = Integer.parseInt(responseMap.get("response-code").toString()); + if (responseCode != 200) { + Assert.assertEquals(responseCode, 200, "Error during request: " + fetchUrl); + } + JSONObject jsonResponse = null; + try { + jsonResponse = new JSONObject(response); + } catch (JSONException ex) { + ex.printStackTrace(); + Assert.fail("Failed to parse response for request: " + fetchUrl, ex); + } + return jsonResponse; + } + + @Override + public Request clone() { + Request clone = (Request) super.clone(); + clone.baseUrl = baseUrl; + return clone; + } + +} 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 6423383..d819412 100644 --- a/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java +++ b/src/main/java/org/opengis/cite/sta10/util/ServiceURLBuilder.java @@ -1,8 +1,7 @@ package org.opengis.cite.sta10.util; -import org.testng.Assert; - import java.util.List; +import org.testng.Assert; /** * Utility class that helps preparing the URL string for the targeted entity. @@ -19,7 +18,7 @@ public class ServiceURLBuilder { * @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) { + public static String buildURLString(String rootURI, EntityType parentEntityType, Object parentId, EntityType relationEntityType, String property) { String urlString = rootURI; if (relationEntityType == null) { switch (parentEntityType) { @@ -51,13 +50,13 @@ public static String buildURLString(String rootURI, EntityType parentEntityType, Assert.fail("Entity type is not recognized in SensorThings API : " + parentEntityType); return null; } - if (parentId != -1) { - urlString += "(" + parentId + ")"; + if (parentId != null) { + urlString += "(" + Utils.quoteIdForUrl(parentId) + ")"; } } else { switch (parentEntityType) { case THING: - urlString += "/Things(" + parentId + ")"; + urlString += "/Things(" + Utils.quoteIdForUrl(parentId) + ")"; switch (relationEntityType) { case LOCATION: urlString += "/Locations"; @@ -73,7 +72,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType, } break; case LOCATION: - urlString += "/Locations(" + parentId + ")"; + urlString += "/Locations(" + Utils.quoteIdForUrl(parentId) + ")"; switch (relationEntityType) { case THING: urlString += "/Things"; @@ -86,7 +85,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType, } break; case HISTORICAL_LOCATION: - urlString += "/HistoricalLocations(" + parentId + ")"; + urlString += "/HistoricalLocations(" + Utils.quoteIdForUrl(parentId) + ")"; switch (relationEntityType) { case THING: urlString += "/Thing"; @@ -99,7 +98,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType, } break; case DATASTREAM: - urlString += "/Datastreams(" + parentId + ")"; + urlString += "/Datastreams(" + Utils.quoteIdForUrl(parentId) + ")"; switch (relationEntityType) { case THING: urlString += "/Thing"; @@ -118,7 +117,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType, } break; case SENSOR: - urlString += "/Sensors(" + parentId + ")"; + urlString += "/Sensors(" + Utils.quoteIdForUrl(parentId) + ")"; switch (relationEntityType) { case DATASTREAM: urlString += "/Datastreams"; @@ -128,7 +127,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType, } break; case OBSERVATION: - urlString += "/Observations(" + parentId + ")"; + urlString += "/Observations(" + Utils.quoteIdForUrl(parentId) + ")"; switch (relationEntityType) { case THING: case DATASTREAM: @@ -142,7 +141,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType, } break; case OBSERVED_PROPERTY: - urlString += "/ObservedProperties(" + parentId + ")"; + urlString += "/ObservedProperties(" + Utils.quoteIdForUrl(parentId) + ")"; switch (relationEntityType) { case DATASTREAM: urlString += "/Datastreams"; @@ -152,7 +151,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType, } break; case FEATURE_OF_INTEREST: - urlString += "/FeaturesOfInterest(" + parentId + ")"; + urlString += "/FeaturesOfInterest(" + Utils.quoteIdForUrl(parentId) + ")"; switch (relationEntityType) { case OBSERVATION: urlString += "/Observations"; @@ -184,7 +183,7 @@ public static String buildURLString(String rootURI, EntityType parentEntityType, * @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) { + 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!!!"); @@ -195,7 +194,12 @@ public static String buildURLString(String rootURI, List entityTypes, Li for (int i = 0; i < entityTypes.size(); i++) { urlString += entityTypes.get(i); if (i < ids.size()) { - urlString += "(" + ids.get(i) + ")/"; + Object id = ids.get(i); + if (id == null) { + urlString += "/"; + } else { + urlString += "(" + Utils.quoteIdForUrl(id) + ")/"; + } } } if (urlString.charAt(urlString.length() - 1) == '/') { diff --git a/src/main/java/org/opengis/cite/sta10/util/Utils.java b/src/main/java/org/opengis/cite/sta10/util/Utils.java new file mode 100644 index 0000000..f9808dc --- /dev/null +++ b/src/main/java/org/opengis/cite/sta10/util/Utils.java @@ -0,0 +1,79 @@ +/* + * Copyright 2016 Open Geospatial Consortium. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.opengis.cite.sta10.util; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * + * @author jab + */ +public class Utils { + + private Utils() { + } + + public static String urlEncode(String link) { + try { + return URLEncoder.encode(link, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException ex) { + } + return link; + } + + /** + * Quote the ID for use in json, if needed. + * + * @param id The id to quote. + * @return The quoted id. + */ + public static String quoteIdForJson(Object id) { + if (id instanceof Number) { + return id.toString(); + } + return "\"" + id + "\""; + } + + /** + * Quote the ID for use in URLs, if needed. + * + * @param id The id to quote. + * @return The quoted id. + */ + public static String quoteIdForUrl(Object id) { + if (id instanceof Number) { + return id.toString(); + } + return "'" + id + "'"; + } + + public static Object idObjectFromPostResult(String postResultLine) { + int pos1 = postResultLine.lastIndexOf("(") + 1; + int pos2 = postResultLine.lastIndexOf(")"); + String part = postResultLine.substring(pos1, pos2); + try { + return Long.parseLong(part); + } catch (NumberFormatException exc) { + // Id was not a long, thus a String. + if (!part.startsWith("'") || !part.endsWith("'")) { + throw new IllegalArgumentException("Strings in urls must be quoted with single quotes."); + } + return part.substring(1, part.length() - 1); + } + } +}