diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index f9628185bc..f705fc336d 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -3,6 +3,7 @@ - Fix: $max and $min operators were not supported with DateTime attributes (#4585) - Fix: wrong date values should not allowed in subscription's expires field (#4541) - Fix: do not raise DB alarm in case of wrong GeoJSON in client request +- Fix: metadata modifications are not considered as change (with regards to subscription alterationTypes) if notifyOnMetadataChange is false (#4605) - Upgrade cjexl version from 0.3.0 to 0.4.0 (new transformations: now, getTime and toIsoString) - Upgrade Debian version from 12.4 to 12.6 in Dockerfile - Fix: invalid date in expires field of subscription (#2303) diff --git a/src/lib/apiTypesV2/Subscription.h b/src/lib/apiTypesV2/Subscription.h index 3f6669472e..88d6660038 100644 --- a/src/lib/apiTypesV2/Subscription.h +++ b/src/lib/apiTypesV2/Subscription.h @@ -57,7 +57,9 @@ typedef enum NotificationType */ typedef enum SubAltType { - EntityChangeBothValueAndMetadata, // this is the reference one used by parsing/rendering logic + // EntityChange has been specialized into three sub-types in order to solve #4605 + // (EntityChangeBothValueAndMetadata is thre reference one used in parsing/rendering logic) + EntityChangeBothValueAndMetadata, EntityChangeOnlyValue, EntityChangeOnlyMetadata, EntityUpdate, diff --git a/src/lib/cache/subCache.cpp b/src/lib/cache/subCache.cpp index 6653496e2c..d19bd7b201 100644 --- a/src/lib/cache/subCache.cpp +++ b/src/lib/cache/subCache.cpp @@ -490,6 +490,11 @@ static bool subMatch return false; } + // If notifyOnMetadataChange is false and only metadata has been changed, we "downgrade" to ngsiv2::EntityUpdate + if (!cSubP->notifyOnMetadataChange && (targetAltType == ngsiv2::EntityChangeOnlyMetadata)) + { + targetAltType = ngsiv2::EntityUpdate; + } // // If one of the attribute names in the scope vector @@ -509,8 +514,11 @@ static bool subMatch } else if ((isChangeAltType(targetAltType)) || (targetAltType == ngsiv2::EntityCreate)) { - if (!attributeMatch(cSubP, attrsWithModifiedValue) && - !(cSubP->notifyOnMetadataChange && attributeMatch(cSubP, attrsWithModifiedMd))) + // No match if: 1) there is no change in the *value* of attributes listed in conditions.attrs and 2) there is no change + // in the *metadata* of the attributes listed in conditions.attrs (the 2) only if notifyOnMetadataChange is true) + bool b1 = attributeMatch(cSubP, attrsWithModifiedValue); + bool b2 = attributeMatch(cSubP, attrsWithModifiedMd); + if (!b1 && !(cSubP->notifyOnMetadataChange && b2)) { LM_T(LmtSubCacheMatch, ("No match due to attributes")); return false; diff --git a/src/lib/mongoBackend/MongoCommonUpdate.cpp b/src/lib/mongoBackend/MongoCommonUpdate.cpp index 758c1cbb0a..a866f45446 100644 --- a/src/lib/mongoBackend/MongoCommonUpdate.cpp +++ b/src/lib/mongoBackend/MongoCommonUpdate.cpp @@ -1641,15 +1641,21 @@ static bool addTriggeredSubscriptions_noCache if (subs.count(subIdStr) == 0) { + // Early extraction of fiedl from DB document. The rest of fields are got later + bool notifyOnMetadataChange = sub.hasField(CSUB_NOTIFYONMETADATACHANGE)? getBoolFieldF(sub, CSUB_NOTIFYONMETADATACHANGE) : true; + + // If notifyOnMetadataChange is false and only metadata has been changed, we "downgrade" to ngsiv2::EntityUpdate + if (!notifyOnMetadataChange && (targetAltType == ngsiv2::EntityChangeOnlyMetadata)) + { + targetAltType = ngsiv2::EntityUpdate; + } + // Check alteration type if (!matchAltType(sub, targetAltType)) { continue; } - // Early extraction of fiedl from DB document. The rest of fields are got later - bool notifyOnMetadataChange = sub.hasField(CSUB_NOTIFYONMETADATACHANGE)? getBoolFieldF(sub, CSUB_NOTIFYONMETADATACHANGE) : true; - // Depending of the alteration type, we use the list of attributes in the request or the list // with effective modifications. Note that EntityDelete doesn't check the list if (targetAltType == ngsiv2::EntityUpdate) @@ -1662,9 +1668,10 @@ static bool addTriggeredSubscriptions_noCache else if ((isChangeAltType(targetAltType)) || (targetAltType == ngsiv2::EntityCreate)) { // Skip if: 1) there is no change in the *value* of attributes listed in conditions.attrs and 2) there is no change - // in the *metadata* of the attributes listed in conditions.attrs (the 2) only if notifyOnMetadtaChange is true) + // in the *metadata* of the attributes listed in conditions.attrs (the 2) only if notifyOnMetadataChange is true) bool b1 = condValueAttrMatch(sub, attrsWithModifiedValue); bool b2 = condValueAttrMatch(sub, attrsWithModifiedMd); + if (!b1 && !(notifyOnMetadataChange && b2)) { continue; @@ -2795,14 +2802,7 @@ static bool processContextAttributeVector } } - attributes.push_back(ca->name); - - /* If actual update then targetAltType changes from EntityUpdate (the value used to initialize - * the variable) to EntityChange */ - /*if (changeType != NO_CHANGE) - { - targetAltType = ngsiv2::SubAltType::EntityChange; - }*/ + attributes.push_back(ca->name); } /* Add triggered subscriptions */ diff --git a/test/functionalTest/cases/4605_alterationtype_entityupdate_with_notifyonmetadatachange/alterationtype_entityupdate_with_notifyonmetadatachange.test b/test/functionalTest/cases/4605_alterationtype_entityupdate_with_notifyonmetadatachange/alterationtype_entityupdate_with_notifyonmetadatachange.test new file mode 100644 index 0000000000..1e2fc196a5 --- /dev/null +++ b/test/functionalTest/cases/4605_alterationtype_entityupdate_with_notifyonmetadatachange/alterationtype_entityupdate_with_notifyonmetadatachange.test @@ -0,0 +1,332 @@ +# Copyright 2024 Telefonica Investigacion y Desarrollo, S.A.U +# +# This file is part of Orion Context Broker. +# +# Orion 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 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 Context Broker. If not, see http://www.gnu.org/licenses/. +# +# For those usages not covered by this license please contact with +# iot_support at tid dot es + +# VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh + +--NAME-- +alterationType entityUpdate in combination with notifyOnMetadataChange + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# 01. Create sub with alterationType entityUpdate+entityCreate and notifyOnMetadataChange false +# 02. Create entity dummy-device-01 with two attributes +# 03. Update entity dummy-device-01 metadata in two attributes +# 04. Dump accumulator and see three notifications +# + + +echo "01. Create sub with alterationType entityUpdate+entityCreate and notifyOnMetadataChange false" +echo "=============================================================================================" +payload='{ + "subject": { + "entities": [ + { + "idPattern": ".*", + "type": "DummyDevice" + } + ], + "condition": { + "attrs": [ + "temperature", + "humidity" + ], + "notifyOnMetadataChange": false, + "alterationTypes": [ + "entityUpdate", + "entityCreate" + ] + } + }, + "notification": { + "attrs": [ + "temperature", + "humidity" + ], + "onlyChangedAttrs": true, + "attrsFormat": "normalized", + "http": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify" + }, + "metadata": [ + "TimeInstant" + ] + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create entity dummy-device-01 with two attributes" +echo "=====================================================" +payload=' +{ + "id": "dummy-device-01", + "type": "DummyDevice", + "temperature": { + "type": "Number", + "value": 20, + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:00:00.000Z" + } + } + }, + "humidity": { + "type": "Number", + "value": 50, + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:00:00.000Z" + } + } + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update entity dummy-device-01 metadata in two attributes" +echo "============================================================" +payload='{ + "temperature": { + "type": "Number", + "value": 20, + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:10:00.000Z" + } + } + }, + "humidity": { + "type": "Number", + "value": 50, + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:10:00.000Z" + } + } + } +}' +orionCurl --url /v2/entities/dummy-device-01/attrs -X POST --payload "$payload" +echo +echo + + +echo "03. Update entity dummy-device-01 without actual update" +echo "=======================================================" +payload='{ + "temperature": { + "type": "Number", + "value": 20 + }, + "humidity": { + "type": "Number", + "value": 50 + } +}' +orionCurl --url /v2/entities/dummy-device-01/attrs -X POST --payload "$payload" +echo +echo + + +echo "04. Dump accumulator and see three notifications" +echo "================================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create sub with alterationType entityUpdate+entityCreate and notifyOnMetadataChange false +============================================================================================= +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/subscriptions/REGEX([0-9a-f]{24}) +Content-Length: 0 + + + +02. Create entity dummy-device-01 with two attributes +===================================================== +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/dummy-device-01?type=DummyDevice +Content-Length: 0 + + + +03. Update entity dummy-device-01 metadata in two attributes +============================================================ +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +03. Update entity dummy-device-01 without actual update +======================================================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Dump accumulator and see three notifications +================================================ +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 347 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "humidity": { + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:00:00.000Z" + } + }, + "type": "Number", + "value": 50 + }, + "id": "dummy-device-01", + "temperature": { + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:00:00.000Z" + } + }, + "type": "Number", + "value": 20 + }, + "type": "DummyDevice" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 347 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "humidity": { + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:10:00.000Z" + } + }, + "type": "Number", + "value": 50 + }, + "id": "dummy-device-01", + "temperature": { + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:10:00.000Z" + } + }, + "type": "Number", + "value": 20 + }, + "type": "DummyDevice" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 347 +User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) +Ngsiv2-Attrsformat: normalized +Host: 127.0.0.1:REGEX(\d+) +Accept: application/json +Content-Type: application/json; charset=utf-8 +Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 + +{ + "data": [ + { + "humidity": { + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:10:00.000Z" + } + }, + "type": "Number", + "value": 50 + }, + "id": "dummy-device-01", + "temperature": { + "metadata": { + "TimeInstant": { + "type": "DateTime", + "value": "2024-08-20T00:10:00.000Z" + } + }, + "type": "Number", + "value": 20 + }, + "type": "DummyDevice" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop