From a3d6ab66d01f3a058512a5ceeb50ff8cb9a51e41 Mon Sep 17 00:00:00 2001 From: David Campo Date: Thu, 23 Nov 2023 17:14:06 +0000 Subject: [PATCH] Fixed issue #1478 --- CHANGES_NEXT_RELEASE | 2 +- src/lib/orionld/common/orionldState.h | 17 +++- src/lib/orionld/forwarding/distOpRequests.cpp | 3 + .../orionld/forwarding/distOpResponses.cpp | 3 + .../serviceRoutines/orionldPatchAttribute.cpp | 18 +++- ...gsild_issue_1478-without-registration.test | 89 +++++++++++++++++++ 6 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 test/functionalTest/cases/0000_ngsild/ngsild_issue_1478-without-registration.test diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index b4801e29c9..fc6dcd1e6f 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -15,4 +15,4 @@ Fixed issues: * #1458 - Supporting system timestamps (createdAt/modifiedAt) in q * #1451 - Bug fix - removed a trailing ampersand from the URI for the connection to mongodb * #1418 - Performance - Faster startup when there are GeoProperties in DB - + * #1478 - Fixed issue diff --git a/src/lib/orionld/common/orionldState.h b/src/lib/orionld/common/orionldState.h index 4ae458cf5b..38be351f1c 100644 --- a/src/lib/orionld/common/orionldState.h +++ b/src/lib/orionld/common/orionldState.h @@ -265,6 +265,18 @@ typedef struct OrionldStateIn +// ----------------------------------------------------------------------------- +// +// OrionldStateDistOp - distributed request information +// +typedef struct OrionldStateDistOp +{ + uint32_t requests; + uint32_t e404; +} OrionldStateDistOp; + + + // ----------------------------------------------------------------------------- // // OrionldMongoC - @@ -441,8 +453,9 @@ typedef struct OrionldConnectionState KjNode* geoPropertyNodes; // object with "entityId": { }, one per entity (for Query Entities bool geoPropertyFromProjection; // It was added to the projection but needs to be removed - OrionldStateOut out; - OrionldStateIn in; + OrionldStateOut out; + OrionldStateIn in; + OrionldStateDistOp distOp; // NGSI-LD Scope (or NGSIv2 ServicePath) char* scopeV[10]; diff --git a/src/lib/orionld/forwarding/distOpRequests.cpp b/src/lib/orionld/forwarding/distOpRequests.cpp index 81ce1e76ad..7592cc3080 100644 --- a/src/lib/orionld/forwarding/distOpRequests.cpp +++ b/src/lib/orionld/forwarding/distOpRequests.cpp @@ -139,7 +139,10 @@ DistOp* distOpRequests(char* entityId, char* entityType, DistOpType operation, K if ((distOpP->regP != NULL) && (distOpP->error == false)) { if (distOpSend(distOpP, dateHeader, xff) == 0) + { distOpP->error = false; + orionldState.distOp.requests += 1; + } else distOpP->error = true; diff --git a/src/lib/orionld/forwarding/distOpResponses.cpp b/src/lib/orionld/forwarding/distOpResponses.cpp index 3c5fd6581f..0a79e4caea 100644 --- a/src/lib/orionld/forwarding/distOpResponses.cpp +++ b/src/lib/orionld/forwarding/distOpResponses.cpp @@ -273,6 +273,9 @@ void entityResponseAccumulate(DistOp* distOpP, KjNode* responseBody, KjNode* suc const char* title = (titleP != NULL)? titleP->value.s : "unspecified error from remote provider"; const char* detail = (detailP != NULL)? detailP->value.s : NULL; + if (httpResponseCode == 404) + orionldState.distOp.e404 += 1; + distOpFailure(responseBody, distOpP, title, detail, httpResponseCode, NULL); } else if (httpResponseCode == 0) diff --git a/src/lib/orionld/serviceRoutines/orionldPatchAttribute.cpp b/src/lib/orionld/serviceRoutines/orionldPatchAttribute.cpp index e50421ea79..69b186e7cc 100644 --- a/src/lib/orionld/serviceRoutines/orionldPatchAttribute.cpp +++ b/src/lib/orionld/serviceRoutines/orionldPatchAttribute.cpp @@ -353,19 +353,25 @@ bool orionldPatchAttribute(void) } KjNode* incomingP = NULL; - if ((orionldState.requestTree != NULL) && (orionldState.requestTree->value.firstChildP != NULL)) // Attribute left for local request + // + // If the entity is not found locally and all distributed requests give 404 + // then it's a 404 + // + bool notFound = ((dbEntityP == NULL) && (orionldState.distOp.requests == orionldState.distOp.e404)); + + if ((notFound == false) && (orionldState.requestTree != NULL) && (orionldState.requestTree->value.firstChildP != NULL)) // Attribute left for local request { // // First of all, make sure the attribute exists // - KjNode* dbAttrsP = kjLookup(dbEntityP, "attrs"); + KjNode* dbAttrsP = (dbEntityP != NULL)? kjLookup(dbEntityP, "attrs") : NULL; if ((dbAttrsP == NULL) && (orionldState.distributed == false)) // Entity without attributes { orionldError(OrionldResourceNotFound, "Entity/Attribute Not Found", entityId, 404); return false; } - KjNode* dbAttrP = kjLookup(dbAttrsP, longAttrNameEq); + KjNode* dbAttrP = (dbAttrsP != NULL)? kjLookup(dbAttrsP, longAttrNameEq) : NULL; if ((dbAttrP == NULL) && (orionldState.distributed == false)) { orionldError(OrionldResourceNotFound, "Entity/Attribute Not Found", entityId, 404); @@ -453,6 +459,12 @@ bool orionldPatchAttribute(void) } } + if (notFound == true) + { + orionldError(OrionldResourceNotFound, "Entity/Attribute Not Found", entityId, 404); + return false; + } + responseFix(responseBody, DoUpdateAttrs, 204, entityId); if ((troe == true) && (incomingP != NULL)) diff --git a/test/functionalTest/cases/0000_ngsild/ngsild_issue_1478-without-registration.test b/test/functionalTest/cases/0000_ngsild/ngsild_issue_1478-without-registration.test new file mode 100644 index 0000000000..23f3fb857b --- /dev/null +++ b/test/functionalTest/cases/0000_ngsild/ngsild_issue_1478-without-registration.test @@ -0,0 +1,89 @@ +# Copyright 2023 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-- +test issue 1478 + +--SHELL-INIT-- +dbInit CB openiot +orionldStart CB -experimental -multiservice -forwarding + +--SHELL-- + +# +# 01. Create an entity according to issue 1478 +# 02. Attempt to PATCH an attribute of an entity that does not exist +# + +echo "01. Create an entity according to issue 1478" +echo "============================================" +payload='{ + "id": "urn:ngsi-ld:Building:farm001", + "type": "Building", + "name": { + "type": "Property", + "value": "Victory Farm" + } +}' +orionCurl --url /ngsi-ld/v1/entities/ --payload "$payload" -H "NGSILD-Tenant: openiot" +echo +echo + +echo "02. Attempt to PATCH an attribute of an entity that does not exist" +echo "==================================================================" +payload='{ + "type": "Property", + "value": " " +}' +orionCurl --url /ngsi-ld/v1/entities/urn:ngsi-ld:Filling:001/attrs/remove -X PATCH --payload "$payload" -H "NGSILD-Tenant: openiot" +echo +echo + + +--REGEXPECT-- +01. Create an entity according to issue 1478 +============================================ +HTTP/1.1 201 Created +Content-Length: 0 +Date: REGEX(.*) +Location: /ngsi-ld/v1/entities/urn:ngsi-ld:Building:farm001 +NGSILD-Tenant: openiot + + + +02. Attempt to PATCH an attribute of an entity that does not exist +================================================================== +HTTP/1.1 404 Not Found +Content-Length: 135 +Content-Type: application/json +Date: REGEX(.*) + +{ + "detail": "urn:ngsi-ld:Filling:001", + "title": "Entity/Attribute Not Found", + "type": "https://uri.etsi.org/ngsi-ld/errors/ResourceNotFound" +} + + +--TEARDOWN-- +brokerStop CB +dbDrop CB openiot