From 553b4706fccede1b6c889c1273af3c289ffba42b Mon Sep 17 00:00:00 2001 From: Ken Zangelin Date: Tue, 20 Apr 2021 17:33:56 +0200 Subject: [PATCH] Implemented POST /temporal/entities - to add entities to TRoE without actually creating any entity (for the current state) --- CHANGES_NEXT_RELEASE | 1 + src/app/orionld/orionldRestServices.cpp | 25 +- src/lib/orionld/common/orionldState.cpp | 4 + src/lib/orionld/common/orionldState.h | 3 +- src/lib/orionld/rest/orionldServiceInit.cpp | 11 + .../orionld/serviceRoutines/CMakeLists.txt | 1 + .../serviceRoutines/orionldPostEntities.cpp | 3 +- .../orionldPostTemporalEntities.cpp | 154 +++++++++++ .../orionldPostTemporalEntities.h | 40 +++ src/lib/orionld/troe/pgEntityTreat.cpp | 2 +- src/lib/orionld/troe/troePostEntities.cpp | 90 +++--- .../ngsild_temporal_representation_501.test | 28 +- .../troe_post_temporal_entities.test | 260 ++++++++++++++++++ 13 files changed, 549 insertions(+), 73 deletions(-) create mode 100644 src/lib/orionld/serviceRoutines/orionldPostTemporalEntities.cpp create mode 100644 src/lib/orionld/serviceRoutines/orionldPostTemporalEntities.h create mode 100644 test/functionalTest/cases/0000_troe/troe_post_temporal_entities.test diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 78a653d7bc..65f1ad510f 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -8,3 +8,4 @@ * Issue #280 Implemented GET /attributes, but only without details=true * Issue #280 Slightly increased response from Batch Upsert * Issue #280 Implemented system attributes (createdAt, modifiedAt) for sub-attributes +* Issue #280 Implemented POST /temporal/entities - to add entities to TRoE without actually creating any entity (for the current state) diff --git a/src/app/orionld/orionldRestServices.cpp b/src/app/orionld/orionldRestServices.cpp index 5a6c483723..516aa939be 100644 --- a/src/app/orionld/orionldRestServices.cpp +++ b/src/app/orionld/orionldRestServices.cpp @@ -58,6 +58,7 @@ #include "orionld/serviceRoutines/orionldGetTemporalEntities.h" #include "orionld/serviceRoutines/orionldGetTemporalEntity.h" #include "orionld/serviceRoutines/orionldPostTemporalQuery.h" +#include "orionld/serviceRoutines/orionldPostTemporalEntities.h" #include "orionld/rest/OrionLdRestService.h" // OrionLdRestServiceSimplified #include "orionld/orionldRestServices.h" // Own Interface @@ -99,18 +100,18 @@ static const int getServices = (sizeof(getServiceV) / sizeof(getServiceV[0])); // static OrionLdRestServiceSimplified postServiceV[] = { - { "/ngsi-ld/v1/entities/*/attrs", orionldPostEntity }, - { "/ngsi-ld/v1/entities", orionldPostEntities }, - { "/ngsi-ld/v1/entityOperations/create", orionldPostBatchCreate }, - { "/ngsi-ld/v1/entityOperations/upsert", orionldPostBatchUpsert }, - { "/ngsi-ld/v1/entityOperations/update", orionldPostBatchUpdate }, - { "/ngsi-ld/v1/entityOperations/delete", orionldPostBatchDelete }, - { "/ngsi-ld/v1/entityOperations/query", orionldPostQuery }, - { "/ngsi-ld/v1/subscriptions", orionldPostSubscriptions }, - { "/ngsi-ld/v1/csourceRegistrations", orionldPostRegistrations }, - { "/ngsi-ld/v1/temporal/entities/*/attrs", orionldNotImplemented }, - { "/ngsi-ld/v1/temporal/entities", orionldNotImplemented }, - { "/ngsi-ld/v1/temporal/entityOperations/query", orionldPostTemporalQuery } + { "/ngsi-ld/v1/entities/*/attrs", orionldPostEntity }, + { "/ngsi-ld/v1/entities", orionldPostEntities }, + { "/ngsi-ld/v1/entityOperations/create", orionldPostBatchCreate }, + { "/ngsi-ld/v1/entityOperations/upsert", orionldPostBatchUpsert }, + { "/ngsi-ld/v1/entityOperations/update", orionldPostBatchUpdate }, + { "/ngsi-ld/v1/entityOperations/delete", orionldPostBatchDelete }, + { "/ngsi-ld/v1/entityOperations/query", orionldPostQuery }, + { "/ngsi-ld/v1/subscriptions", orionldPostSubscriptions }, + { "/ngsi-ld/v1/csourceRegistrations", orionldPostRegistrations }, + { "/ngsi-ld/v1/temporal/entities/*/attrs", orionldNotImplemented }, + { "/ngsi-ld/v1/temporal/entities", orionldPostTemporalEntities }, + { "/ngsi-ld/v1/temporal/entityOperations/query", orionldPostTemporalQuery } }; static const int postServices = (sizeof(postServiceV) / sizeof(postServiceV[0])); diff --git a/src/lib/orionld/common/orionldState.cpp b/src/lib/orionld/common/orionldState.cpp index f32db93f4e..78fb205830 100644 --- a/src/lib/orionld/common/orionldState.cpp +++ b/src/lib/orionld/common/orionldState.cpp @@ -39,6 +39,7 @@ extern "C" #include "orionld/types/OrionldGeoIndex.h" // OrionldGeoIndex #include "orionld/db/dbConfiguration.h" // DB_DRIVER_MONGOC #include "orionld/context/orionldCoreContext.h" // orionldCoreContext +#include "orionld/troe/troe.h" // TroeMode #include "orionld/common/QNode.h" // QNode #include "orionld/common/performance.h" // REQUEST_PERFORMANCE #include "orionld/common/orionldState.h" // Own interface @@ -145,6 +146,9 @@ void orionldStateInit(void) orionldState.uriParams.limit = 20; // orionldState.delayedKjFreeVecSize = sizeof(orionldState.delayedKjFreeVec) / sizeof(orionldState.delayedKjFreeVec[0]); + + // TRoE + orionldState.troeOpMode = TROE_ENTITY_CREATE; } diff --git a/src/lib/orionld/common/orionldState.h b/src/lib/orionld/common/orionldState.h index 447b86f202..3f0adb95d4 100644 --- a/src/lib/orionld/common/orionldState.h +++ b/src/lib/orionld/common/orionldState.h @@ -49,6 +49,7 @@ extern "C" #include "orionld/types/OrionldGeoIndex.h" // OrionldGeoIndex #include "orionld/types/OrionldGeoJsonType.h" // OrionldGeoJsonType #include "orionld/types/OrionldPrefixCache.h" // OrionldPrefixCache +#include "orionld/troe/troe.h" // TroeMode #include "orionld/context/OrionldContext.h" // OrionldContext @@ -203,7 +204,6 @@ typedef struct OrionldConnectionState int geoAttrs; char* geoType; KjNode* geoCoordsP; - bool entityCreated; // If an entity is created, if complex context, it must be stored char* entityId; OrionldUriParamOptions uriParamOptions; OrionldUriParams uriParams; @@ -288,6 +288,7 @@ typedef struct OrionldConnectionState KjNode* troeIgnoreV[20]; unsigned int troeIgnoreIx; KjNode* batchEntities; + TroeMode troeOpMode; // // GeoJSON - help vars for the case: diff --git a/src/lib/orionld/rest/orionldServiceInit.cpp b/src/lib/orionld/rest/orionldServiceInit.cpp index cc0233a5f1..064bebaf3a 100644 --- a/src/lib/orionld/rest/orionldServiceInit.cpp +++ b/src/lib/orionld/rest/orionldServiceInit.cpp @@ -80,6 +80,7 @@ extern "C" #include "orionld/serviceRoutines/orionldDeleteSubscription.h" // orionldDeleteSubscription #include "orionld/serviceRoutines/orionldGetEntityTypes.h" // orionldGetEntityTypes #include "orionld/serviceRoutines/orionldGetEntityAttributes.h" // orionldGetEntityAttributes +#include "orionld/serviceRoutines/orionldPostTemporalEntities.h" // orionldPostTemporalEntities #include "orionld/troe/troePostEntities.h" // troePostEntities #include "orionld/troe/troePostBatchDelete.h" // troePostBatchDelete #include "orionld/troe/troeDeleteAttribute.h" // troeDeleteAttribute @@ -403,6 +404,14 @@ static void restServicePrepare(OrionLdRestService* serviceP, OrionLdRestServiceS serviceP->options |= ORIONLD_SERVICE_OPTION_NO_V2_URI_PARAMS; } + else if (serviceP->serviceRoutine == orionldPostTemporalEntities) + { + serviceP->options = 0; // Tenant will be created if necessary + + serviceP->options |= ORIONLD_SERVICE_OPTION_PREFETCH_ID_AND_TYPE; + serviceP->options |= ORIONLD_SERVICE_OPTION_NO_V2_URI_PARAMS; + serviceP->options |= ORIONLD_SERVICE_OPTION_CREATE_CONTEXT; + } else if (serviceP->serviceRoutine == orionldGetVersion) { serviceP->options = 0; // Tenant is Ignored @@ -431,6 +440,8 @@ static void restServicePrepare(OrionLdRestService* serviceP, OrionLdRestServiceS { if (serviceP->serviceRoutine == orionldPostEntities) serviceP->troeRoutine = troePostEntities; + else if (serviceP->serviceRoutine == orionldPostTemporalEntities) + serviceP->troeRoutine = NULL; // TRoE processing is taken care of INSIDE the service routine else if (serviceP->serviceRoutine == orionldPostBatchDelete) serviceP->troeRoutine = troePostBatchDelete; else if (serviceP->serviceRoutine == orionldPostEntity) diff --git a/src/lib/orionld/serviceRoutines/CMakeLists.txt b/src/lib/orionld/serviceRoutines/CMakeLists.txt index a0e9948034..525df6194e 100644 --- a/src/lib/orionld/serviceRoutines/CMakeLists.txt +++ b/src/lib/orionld/serviceRoutines/CMakeLists.txt @@ -58,6 +58,7 @@ SET (SOURCES orionldGetTemporalEntity.cpp orionldPostTemporalQuery.cpp orionldGetEntityAttributes.cpp + orionldPostTemporalEntities.cpp ) # Include directories diff --git a/src/lib/orionld/serviceRoutines/orionldPostEntities.cpp b/src/lib/orionld/serviceRoutines/orionldPostEntities.cpp index fbddb6b565..700c082813 100644 --- a/src/lib/orionld/serviceRoutines/orionldPostEntities.cpp +++ b/src/lib/orionld/serviceRoutines/orionldPostEntities.cpp @@ -419,8 +419,7 @@ bool orionldPostEntities(ConnectionInfo* ciP) return false; } - orionldState.httpStatusCode = SccCreated; - orionldState.entityCreated = true; + orionldState.httpStatusCode = 201; httpHeaderLocationAdd(ciP, "/ngsi-ld/v1/entities/", entityId); diff --git a/src/lib/orionld/serviceRoutines/orionldPostTemporalEntities.cpp b/src/lib/orionld/serviceRoutines/orionldPostTemporalEntities.cpp new file mode 100644 index 0000000000..4d27371534 --- /dev/null +++ b/src/lib/orionld/serviceRoutines/orionldPostTemporalEntities.cpp @@ -0,0 +1,154 @@ +/* +* +* Copyright 2021 FIWARE Foundation e.V. +* +* This file is part of Orion-LD Context Broker. +* +* Orion-LD Context Broker is free software: you can redistribute it and/or +* modify it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* Orion-LD Context Broker is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +* General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with Orion-LD Context Broker. If not, see http://www.gnu.org/licenses/. +* +* For those usages not covered by this license please contact with +* orionld at fiware dot org +* +* Author: Ken Zangelin +*/ +extern "C" +{ +#include "kjson/kjRender.h" // kjFastRender +} + +#include "logMsg/logMsg.h" // LM_* +#include "logMsg/traceLevels.h" // Lmt* + +#include "rest/ConnectionInfo.h" // ConnectionInfo +#include "rest/httpHeaderAdd.h" // httpHeaderLocationAdd + +#include "orionld/common/orionldState.h" // orionldState +#include "orionld/common/orionldErrorResponse.h" // orionldErrorResponseCreate +#include "orionld/common/CHECK.h" // OBJECT_CHECK +#include "orionld/common/numberToDate.h" // numberToDate +#include "orionld/rest/OrionLdRestService.h" // OrionLdRestService +#include "orionld/payloadCheck/pcheckEntity.h" // pcheckEntity +#include "orionld/payloadCheck/pcheckUri.h" // pcheckUri +#include "orionld/troe/troePostEntities.h" // troePostEntities +#include "orionld/mongoBackend/mongoEntityExists.h" // mongoEntityExists +#include "orionld/serviceRoutines/orionldPostTemporalEntities.h" // Own Interface + + + +// ---------------------------------------------------------------------------- +// +// orionldPostTemporalEntities - +// +// The Payload Body for "POST /temporal/entities" looks like this: +// +// { +// "@context": "https://...", +// "id": "urn:ngsi-ld:entities:E1", +// "type": "T", +// "attr1": [ +// { +// "type": "Property", +// "value": 14, +// "observedAt": "2021-04-20T08:31:00", +// "sub-R1": { "type": "Relationship", "object": "urn:xxx" }, +// "sub-P1": { "type": "Property", "value": 14 }, +// ... +// }, +// { +// ... +// } +// ], +// "attr2": [ +// { +// "type": "Relationship", +// "object": "urn:xxx", +// "observedAt": "2021-04-20T08:31:00", +// "sub-R1": { "type": "Relationship", "object": "urn:xxx" }, +// "sub-P1": { "type": "Property", "value": 14 }, +// ... +// }, +// { +// ... +// } +// ] +// } +// +// This request adds entries in the TRoE database for the entity urn:ngsi-ld:entities:E1 and all of its attrs and their sub-attrs +// +bool orionldPostTemporalEntities(ConnectionInfo* ciP) +{ + OBJECT_CHECK(orionldState.requestTree, "toplevel"); + + char* detail; + KjNode* locationP = NULL; + KjNode* observationSpaceP = NULL; + KjNode* operationSpaceP = NULL; + KjNode* createdAtP = NULL; + KjNode* modifiedAtP = NULL; + + if (pcheckEntity(orionldState.requestTree->value.firstChildP, &locationP, &observationSpaceP, &operationSpaceP, &createdAtP, &modifiedAtP, false) == false) + return false; + + char* entityId = orionldState.payloadIdNode->value.s; + char* entityType = orionldState.payloadTypeNode->value.s; + + + // + // Entity ID and TYPE + // + if (pcheckUri(entityId, true, &detail) == false) + { + orionldErrorResponseCreate(OrionldBadRequestData, "Invalid Entity id", "The id specified cannot be resolved to a URL or URN"); // FIXME: Include 'detail' and name (entityId) + return false; + } + + if (pcheckUri(entityType, false, &detail) == false) + { + orionldErrorResponseCreate(OrionldBadRequestData, "Invalid Entity Type", detail); // FIXME: Include 'detail' and name (entityId) + return false; + } + + + // Does the entity already exist? + // FIXME: This check should really be made in the TRoE database but, seems valid enough to do the + // search in mongo instead + // + int httpStatusCode = 201; + + if (mongoEntityExists(entityId, orionldState.tenant) == true) + httpStatusCode = 204; + + // + // Nothing is sent to mongo, only TRoE is updated + // And, the TRoE function is invoked by orionldMhdConnectionTreat + // + numberToDate(orionldState.requestTime, orionldState.requestTimeString, sizeof(orionldState.requestTimeString)); + orionldState.troeOpMode = TROE_ENTITY_REPLACE; + bool troeOk = troePostEntities(ciP); + + if (troeOk == true) + { + if (httpStatusCode == 201) + httpHeaderLocationAdd(ciP, "/ngsi-ld/v1/temporal/entities/", entityId); + + orionldState.httpStatusCode = httpStatusCode; + return true; + } + + LM_E(("troePostEntities failed (%s: %s)", orionldState.pd.title, orionldState.pd.detail)); + orionldErrorResponseCreate(orionldState.pd.type, orionldState.pd.title, orionldState.pd.detail); + orionldState.httpStatusCode = orionldState.pd.type; + + return false; +} diff --git a/src/lib/orionld/serviceRoutines/orionldPostTemporalEntities.h b/src/lib/orionld/serviceRoutines/orionldPostTemporalEntities.h new file mode 100644 index 0000000000..d50e8a6122 --- /dev/null +++ b/src/lib/orionld/serviceRoutines/orionldPostTemporalEntities.h @@ -0,0 +1,40 @@ +#ifndef SRC_LIB_ORIONLD_SERVICEROUTINES_ORIONLDPOSTTEMPORALENTITIES_H_ +#define SRC_LIB_ORIONLD_SERVICEROUTINES_ORIONLDPOSTTEMPORALENTITIES_H_ + +/* +* +* Copyright 2021 FIWARE Foundation e.V. +* +* This file is part of Orion-LD Context Broker. +* +* Orion-LD Context Broker is free software: you can redistribute it and/or +* modify it under the terms of the GNU Affero General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* Orion-LD Context Broker is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +* General Public License for more details. +* +* You should have received a copy of the GNU Affero General Public License +* along with Orion-LD Context Broker. If not, see http://www.gnu.org/licenses/. +* +* For those usages not covered by this license please contact with +* orionld at fiware dot org +* +* Author: Ken Zangelin +*/ +#include "logMsg/logMsg.h" + +#include "rest/ConnectionInfo.h" + + + +// ---------------------------------------------------------------------------- +// +// orionldPostTemporalEntities - +// +extern bool orionldPostTemporalEntities(ConnectionInfo* ciP); + +#endif // SRC_LIB_ORIONLD_SERVICEROUTINES_ORIONLDPOSTTEMPORALENTITIES_H_ diff --git a/src/lib/orionld/troe/pgEntityTreat.cpp b/src/lib/orionld/troe/pgEntityTreat.cpp index e88c208b0b..1e3372c3dc 100644 --- a/src/lib/orionld/troe/pgEntityTreat.cpp +++ b/src/lib/orionld/troe/pgEntityTreat.cpp @@ -111,7 +111,7 @@ bool pgEntityTreat(PGconn* connectionP, KjNode* entityP, char* id, char* type, T (strcmp(attrP->name, "createdAt") == 0) || (strcmp(attrP->name, "modifiedAt") == 0)) { - // If present, all these "attributes" are ignmoredd + // If present, all these "attributes" are ignored } else LM_E(("Internal Error (The attribute '%s' is neither an Object nor an Array)", attrP->name)); diff --git a/src/lib/orionld/troe/troePostEntities.cpp b/src/lib/orionld/troe/troePostEntities.cpp index 4c95869de3..1b29e0d493 100644 --- a/src/lib/orionld/troe/troePostEntities.cpp +++ b/src/lib/orionld/troe/troePostEntities.cpp @@ -47,6 +47,34 @@ extern "C" +// ----------------------------------------------------------------------------- +// +// troeSubAttrsExpand - +// +static void troeSubAttrsExpand(KjNode* attrP) +{ + KjNode* subAttrP = attrP->value.firstChildP; + KjNode* nextSubAttr; + + while (subAttrP != NULL) + { + nextSubAttr = subAttrP->next; + + if (strcmp(subAttrP->name, "type") == 0) {} + else if (strcmp(subAttrP->name, "id") == 0) {} + else if (strcmp(subAttrP->name, "value") == 0) {} + else if (strcmp(subAttrP->name, "object") == 0) {} + else if ((strcmp(subAttrP->name, "createdAt") == 0) || (strcmp(subAttrP->name, "modifiedAt") == 0)) + kjChildRemove(attrP, subAttrP); + else + subAttrP->name = orionldSubAttributeExpand(orionldState.contextP, subAttrP->name, true, NULL); + + subAttrP = nextSubAttr; + } +} + + + // ----------------------------------------------------------------------------- // // troeEntityExpand - @@ -56,17 +84,18 @@ void troeEntityExpand(KjNode* entityP) KjNode* attrP = entityP->value.firstChildP; KjNode* nextAttr; + LM_TMP(("PTE: Expanding attribute names, and their sub-attribute names as well")); while (attrP != NULL) { nextAttr = attrP->next; - if (strcmp(attrP->name, "type") == 0) + if (strcmp(attrP->name, "type") == 0) attrP->value.s = orionldContextItemExpand(orionldState.contextP, attrP->value.s, true, NULL); // entity type - else if (strcmp(attrP->name, "id") == 0) {} - else if (strcmp(attrP->name, "location") == 0) {} - else if (strcmp(attrP->name, "observationSpace") == 0) {} - else if (strcmp(attrP->name, "operationSpace") == 0) {} - else if ((strcmp(attrP->name, "createdAt") == 0) || (strcmp(attrP->name, "modifiedAt") == 0)) + else if (strcmp(attrP->name, "id") == 0) {} + else if (strcmp(attrP->name, "location") == 0) {} + else if (strcmp(attrP->name, "observationSpace") == 0) {} + else if (strcmp(attrP->name, "operationSpace") == 0) {} + else if ((strcmp(attrP->name, "createdAt") == 0) || (strcmp(attrP->name, "modifiedAt") == 0)) { kjChildRemove(entityP, attrP); } @@ -75,26 +104,12 @@ void troeEntityExpand(KjNode* entityP) attrP->name = orionldAttributeExpand(orionldState.contextP, attrP->name, true, NULL); if (attrP->type == KjObject) + troeSubAttrsExpand(attrP); + else if (attrP->type == KjArray) { - KjNode* subAttrP = attrP->value.firstChildP; - KjNode* nextSubAttr; - - while (subAttrP != NULL) + for (KjNode* attrInstanceP = attrP->value.firstChildP; attrInstanceP != NULL; attrInstanceP = attrInstanceP->next) { - nextSubAttr = subAttrP->next; - - if (strcmp(subAttrP->name, "type") == 0) {} - else if (strcmp(subAttrP->name, "id") == 0) {} - else if (strcmp(subAttrP->name, "value") == 0) {} - else if (strcmp(subAttrP->name, "object") == 0) {} - else if ((strcmp(subAttrP->name, "createdAt") == 0) || (strcmp(subAttrP->name, "modifiedAt") == 0)) - { - kjChildRemove(attrP, subAttrP); - } - else - subAttrP->name = orionldSubAttributeExpand(orionldState.contextP, subAttrP->name, true, NULL); - - subAttrP = nextSubAttr; + troeSubAttrsExpand(attrInstanceP); } } } @@ -104,6 +119,7 @@ void troeEntityExpand(KjNode* entityP) } + // ---------------------------------------------------------------------------- // // troePostEntities - @@ -113,33 +129,43 @@ bool troePostEntities(ConnectionInfo* ciP) PGconn* connectionP; KjNode* entityP = orionldState.requestTree; - // - // FIXME: the tree should be served expanded by orionldPostEntities() - // - - // Expand entity type and attribute names - FIXME: Remove once orionldPostEntities() has been fixed to do that troeEntityExpand(entityP); connectionP = pgConnectionGet(orionldState.troeDbName); if (connectionP == NULL) + { + orionldProblemDetailsFill(&orionldState.pd, OrionldInternalError, "Database Error", "No connection to TRoE database", 500); LM_RE(false, ("no connection to postgres")); + } if (pgTransactionBegin(connectionP) != true) + { + orionldProblemDetailsFill(&orionldState.pd, OrionldInternalError, "Database Error", "Transaction begin for TRoE database", 500); LM_RE(false, ("pgTransactionBegin failed")); + } char* entityId = orionldState.payloadIdNode->value.s; char* entityType = orionldContextItemExpand(orionldState.contextP, orionldState.payloadTypeNode->value.s, true, NULL); // entity type - if (pgEntityTreat(connectionP, entityP, entityId, entityType, TROE_ENTITY_CREATE, TROE_ENTITY_CREATE) == false) + if (pgEntityTreat(connectionP, entityP, entityId, entityType, orionldState.troeOpMode, orionldState.troeOpMode) == false) { LM_E(("Database Error (post entities TRoE layer failed)")); if (pgTransactionRollback(connectionP) == false) - LM_RE(false, ("pgTransactionRollback failed")); + LM_E(("pgTransactionRollback failed")); + + orionldProblemDetailsFill(&orionldState.pd, OrionldInternalError, "Database Error", "unable to push the entity information to the TRoE database", 500); + pgConnectionRelease(connectionP); + return false; } else { if (pgTransactionCommit(connectionP) != true) - LM_RE(false, ("pgTransactionCommit failed")); + { + LM_E(("pgTransactionCommit failed")); + orionldProblemDetailsFill(&orionldState.pd, OrionldInternalError, "Database Error", "Unable to commit transaction", 500); + pgConnectionRelease(connectionP); + return false; + } } pgConnectionRelease(connectionP); diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_temporal_representation_501.test b/test/functionalTest/cases/0000_ngsild/ngsild_temporal_representation_501.test index 6d952daccb..441552c179 100644 --- a/test/functionalTest/cases/0000_ngsild/ngsild_temporal_representation_501.test +++ b/test/functionalTest/cases/0000_ngsild/ngsild_temporal_representation_501.test @@ -30,8 +30,10 @@ brokerStart CB --SHELL-- +# Requests that have been implemented: +# 01. POST /ngsi-ld/v1/temporal/entities # -# 01. Get 501 for POST /ngsi-ld/v1/temporal/entities +# Requests that still give 501: # 02. Get 501 for GET /ngsi-ld/v1/temporal/entities # 03. Get 501 for GET /ngsi-ld/v1/temporal/entities/ # 04. Get 501 for DELETE /ngsi-ld/v1/temporal/entities/ @@ -42,16 +44,6 @@ brokerStart CB # 09. Get 501 for POST /ngsi-ld/v1/temporal/entityOperations/query # -echo "01. Get 501 for POST /ngsi-ld/v1/temporal/entities" -echo "==================================================" -payload='{ - "id": "urn:ngsi-ld:City:Madrid", - "type": "T_City" -}' -orionCurl --url /ngsi-ld/v1/temporal/entities -X POST --payload "$payload" -echo -echo - echo "02. Get 501 for GET /ngsi-ld/v1/temporal/entities" echo "=================================================" orionCurl --url /ngsi-ld/v1/temporal/entities @@ -125,20 +117,6 @@ echo --REGEXPECT-- -01. Get 501 for POST /ngsi-ld/v1/temporal/entities -================================================== -HTTP/1.1 501 Not Implemented -Content-Length: 135 -Content-Type: application/json -Date: REGEX(.*) - -{ - "detail": "/ngsi-ld/v1/temporal/entities", - "title": "Not Implemented", - "type": "https://uri.etsi.org/ngsi-ld/errors/OperationNotSupported" -} - - 02. Get 501 for GET /ngsi-ld/v1/temporal/entities ================================================= HTTP/1.1 501 Not Implemented diff --git a/test/functionalTest/cases/0000_troe/troe_post_temporal_entities.test b/test/functionalTest/cases/0000_troe/troe_post_temporal_entities.test new file mode 100644 index 0000000000..d40d7354f3 --- /dev/null +++ b/test/functionalTest/cases/0000_troe/troe_post_temporal_entities.test @@ -0,0 +1,260 @@ +# Copyright 2021 FIWARE Foundation e.V. +# +# This file is part of Orion-LD Context Broker. +# +# Orion-LD Context Broker is free software: you can redistribute it and/or +# modify it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# Orion-LD Context Broker is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero +# General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with Orion-LD Context Broker. If not, see http://www.gnu.org/licenses/. +# +# For those usages not covered by this license please contact with +# orionld at fiware dot org + +# VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh + +--NAME-- +Simple test of creation of a Temporal Entity, using POST /temporal/entities, with all types of Attributes + +--SHELL-INIT-- +export BROKER=orionld +dbInit CB +pgInit $CB_DB_NAME +brokerStart CB 100 IPv4 -troe + +--SHELL-- + +# +# 01. Push an entity directly to the TRoE DB, using POST /temporal/entities - see 201 Created +# 02. See E1 in the temporal database +# 03. See the attributes in the temporal database +# 04. See the sub-attributes in the temporal database +# 05. Create an entity urn:ngsi-ld:entities:E1 in mongo +# 06. Use POST /temporal/entities to push urn:ngsi-ld:entities:E1 to TRoE - see 204 No Content +# + +echo "01. Push an entity directly to the TRoE DB, using POST /temporal/entities - see 201 Created" +echo "===========================================================================================" +payload='{ + "id": "urn:ngsi-ld:entities:E1", + "type": "T", + "SP": [ + { + "type": "Property", + "value": "SP of E1", + "observedAt": "2021-04-20T07:11:00.123Z", + "Sub-R": { + "type": "Relationship", + "object": "urn:ngsi-ld:rel:R1", + "observedAt": "2021-04-20T07:12:00.123Z" + }, + "Sub-String": { + "type": "Property", + "value": "string sub-property", + "observedAt": "2021-04-20T07:12:00.124Z" + }, + "Sub-Bool": { + "type": "Property", + "value": true, + "observedAt": "2021-04-20T07:12:00.125Z" + }, + "Sub-Array": { + "type": "Property", + "value": [ 1, 2, 3 ], + "observedAt": "2021-04-20T07:12:00.126Z" + }, + "Sub-Object": { + "type": "Property", + "value": { "pi": 3.14, "bTrue": true, "c3": "3" }, + "observedAt": "2021-04-20T07:12:00.127Z" + }, + "Sub-Int": { + "type": "Property", + "value": 33, + "observedAt": "2021-04-20T07:12:00.128Z", + "unitCode": "pi-i" + }, + "Sub-Float": { + "type": "Property", + "value": 3.1415927, + "observedAt": "2021-04-20T07:12:00.129Z", + "unitCode": "pi-f" + } + } + ], + "I": [ + { + "type": "Property", + "value": 1, + "observedAt": "2021-04-20T07:11:00.001Z", + "unitCode": "cm" + }, + { + "type": "Property", + "value": 2, + "observedAt": "2021-04-20T07:11:00.002Z", + "unitCode": "cm" + } + ], + "F": [ + { + "type": "Property", + "value": 3.14, + "observedAt": "2021-04-20T07:11:00.125Z" + } + ], + "Object": [ + { + "type": "Property", + "value": { + "A": 1, + "vec": [ 1, 2, 3 ] + }, + "observedAt": "2021-04-20T07:11:00.126Z" + } + ], + "Array": [ + { + "type": "Property", + "value": [ "S1", "S2", "S3" ], + "observedAt": "2021-04-20T07:11:00.127Z" + } + ], + "B": [ + { + "type": "Property", + "value": true, + "observedAt": "2021-04-20T07:11:00.128Z" + } + ], + "R1": [ + { + "type": "Relationship", + "object": "urn:ngsi-ld:relationships:R1", + "observedAt": "2021-04-20T07:11:00.129Z" + } + ] +}' +orionCurl --url /ngsi-ld/v1/temporal/entities --payload "$payload" +echo +echo + + +echo "02. See E1 in the temporal database" +echo "===================================" +postgresCmd -sql "SELECT opMode,id,type FROM entities" +echo +echo + + +echo "03. See the attributes in the temporal database" +echo "===============================================" +postgresCmd -sql "SELECT opMode,id,valueType,entityId,subProperties,unitcode,datasetid,text,number,boolean,compound,observedAt FROM attributes" +echo +echo + + +echo "04. See the sub-attributes in the temporal database" +echo "===================================================" +postgresCmd -sql "SELECT id,valueType,entityId,attrInstanceId,unitcode,text,number,boolean,compound,observedAt FROM subAttributes" +echo +echo + + +echo "05. Create an entity urn:ngsi-ld:entities:E1 in mongo" +echo "=====================================================" +payload='{ + "id": "urn:ngsi-ld:entities:E1", + "type": "T", + "A1": { + "type": "Property", + "value": 5 + } +}' +orionCurl --url /ngsi-ld/v1/entities --payload "$payload" +echo +echo + + +echo "06. Use POST /temporal/entities to push urn:ngsi-ld:entities:E1 to TRoE - see 204 No Content" +echo "============================================================================================" +payload='{ + "id": "urn:ngsi-ld:entities:E1", + "type": "T", + "A1": { + "type": "Property", + "value": 6 + } +}' +orionCurl --url /ngsi-ld/v1/temporal/entities --payload "$payload" +echo +echo + + +--REGEXPECT-- +01. Push an entity directly to the TRoE DB, using POST /temporal/entities - see 201 Created +=========================================================================================== +HTTP/1.1 201 Created +Content-Length: 0 +Location: /ngsi-ld/v1/temporal/entities/urn:ngsi-ld:entities:E1 +Date: REGEX(.*) + + + +02. See E1 in the temporal database +=================================== +opmode,id,type +Replace,urn:ngsi-ld:entities:E1,https://uri.etsi.org/ngsi-ld/default-context/T + + +03. See the attributes in the temporal database +=============================================== +opmode,id,valuetype,entityid,subproperties,unitcode,datasetid,text,number,boolean,compound,observedat +Replace,https://uri.etsi.org/ngsi-ld/default-context/SP,String,urn:ngsi-ld:entities:E1,t,,,SP of E1,,,,2021-04-20 07:11:00.123 +Replace,https://uri.etsi.org/ngsi-ld/default-context/I,Number,urn:ngsi-ld:entities:E1,f,cm,,,1,,,2021-04-20 07:11:00.001 +Replace,https://uri.etsi.org/ngsi-ld/default-context/I,Number,urn:ngsi-ld:entities:E1,f,cm,,,2,,,2021-04-20 07:11:00.002 +Replace,https://uri.etsi.org/ngsi-ld/default-context/F,Number,urn:ngsi-ld:entities:E1,f,,,,3.14,,,2021-04-20 07:11:00.125 +Replace,https://uri.etsi.org/ngsi-ld/default-context/Object,Compound,urn:ngsi-ld:entities:E1,f,,,,,,"{""A"": 1, ""vec"": [1, 2, 3]}",2021-04-20 07:11:00.126 +Replace,https://uri.etsi.org/ngsi-ld/default-context/Array,Compound,urn:ngsi-ld:entities:E1,f,,,,,,"[""S1"", ""S2"", ""S3""]",2021-04-20 07:11:00.127 +Replace,https://uri.etsi.org/ngsi-ld/default-context/B,Boolean,urn:ngsi-ld:entities:E1,f,,,,,t,,2021-04-20 07:11:00.128 +Replace,https://uri.etsi.org/ngsi-ld/default-context/R1,Relationship,urn:ngsi-ld:entities:E1,f,,,urn:ngsi-ld:relationships:R1,,,,2021-04-20 07:11:00.129 + + +04. See the sub-attributes in the temporal database +=================================================== +id,valuetype,entityid,attrinstanceid,unitcode,text,number,boolean,compound,observedat +https://uri.etsi.org/ngsi-ld/default-context/Sub-R,Relationship,urn:ngsi-ld:entities:E1,urn:ngsi-ld:attribute:instance:REGEX(.*),,urn:ngsi-ld:rel:R1,,,,2021-04-20 07:12:00.123 +https://uri.etsi.org/ngsi-ld/default-context/Sub-String,String,urn:ngsi-ld:entities:E1,urn:ngsi-ld:attribute:instance:REGEX(.*),,string sub-property,,,,2021-04-20 07:12:00.124 +https://uri.etsi.org/ngsi-ld/default-context/Sub-Bool,Boolean,urn:ngsi-ld:entities:E1,urn:ngsi-ld:attribute:instance:REGEX(.*),,,,t,,2021-04-20 07:12:00.125 +https://uri.etsi.org/ngsi-ld/default-context/Sub-Array,Compound,urn:ngsi-ld:entities:E1,urn:ngsi-ld:attribute:instance:REGEX(.*),,,,,"[1, 2, 3]",2021-04-20 07:12:00.126 +https://uri.etsi.org/ngsi-ld/default-context/Sub-Object,Compound,urn:ngsi-ld:entities:E1,urn:ngsi-ld:attribute:instance:REGEX(.*),,,,,"{""c3"": ""3"", ""pi"": 3.14, ""bTrue"": true}",2021-04-20 07:12:00.127 +https://uri.etsi.org/ngsi-ld/default-context/Sub-Int,Number,urn:ngsi-ld:entities:E1,urn:ngsi-ld:attribute:instance:REGEX(.*),pi-i,,33,,,2021-04-20 07:12:00.128 +https://uri.etsi.org/ngsi-ld/default-context/Sub-Float,Number,urn:ngsi-ld:entities:E1,urn:ngsi-ld:attribute:instance:REGEX(.*),pi-f,,3.141593,,,2021-04-20 07:12:00.129 + + +05. Create an entity urn:ngsi-ld:entities:E1 in mongo +===================================================== +HTTP/1.1 201 Created +Content-Length: 0 +Location: /ngsi-ld/v1/entities/urn:ngsi-ld:entities:E1 +Date: REGEX(.*) + + + +06. Use POST /temporal/entities to push urn:ngsi-ld:entities:E1 to TRoE - see 204 No Content +============================================================================================ +HTTP/1.1 204 No Content +Date: REGEX(.*) + + + +--TEARDOWN-- +brokerStop CB +dbDrop CB