From 9639bc441a6b13fdf314c83c8f852b5ae3d69e66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Wed, 8 Nov 2023 08:36:43 +0100 Subject: [PATCH 1/8] ADD CompoundValueNode equal() method --- src/lib/parse/CompoundValueNode.cpp | 68 ++++ src/lib/parse/CompoundValueNode.h | 3 + ...notify_upon_actual_change_in_geo_json.test | 226 +++++++++++ ...tify_upon_actual_change_in_json_value.test | 370 ++++++++++++++++++ 4 files changed, 667 insertions(+) create mode 100644 test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test create mode 100644 test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test diff --git a/src/lib/parse/CompoundValueNode.cpp b/src/lib/parse/CompoundValueNode.cpp index f26209f7a9..2d19d474bd 100644 --- a/src/lib/parse/CompoundValueNode.cpp +++ b/src/lib/parse/CompoundValueNode.cpp @@ -33,6 +33,7 @@ #include "common/JsonHelper.h" #include "common/macroSubstitute.h" #include "alarmMgr/alarmMgr.h" +#include "mongoDriver/safeMongo.h" #include "parse/forbiddenChars.h" #include "orionTypes/OrionValueType.h" @@ -522,6 +523,73 @@ std::string CompoundValueNode::check(const std::string& path) +/* **************************************************************************** +* +* CompoundValueNode::equal +* +*/ +bool CompoundValueNode::equal(const orion::BSONElement& be) +{ + // Note object cannot be declared inside switch block + std::vector ba; + + switch (valueType) + { + case orion::ValueTypeString: + return (be.type() == orion::String) && (stringValue == be.String()); + + case orion::ValueTypeNumber: + // FIXME PR: unurure if this is going to work with all the Number types (int32/int64/double) + return (be.type() == orion::NumberDouble && numberValue == be.Number()); + + case orion::ValueTypeBoolean: + return (be.type() == orion::Bool) && (boolValue == be.Bool()); + + case orion::ValueTypeNull: + return (be.type() == orion::jstNULL); + + case orion::ValueTypeVector: + // nodeP must be a vector + if (be.type() != orion::Array) + { + return false; + } + ba = be.Array(); + // nodeP must have the same number of elements + if (childV.size() != ba.size()) + { + return false; + } + for (unsigned int ix = 0; ix < childV.size(); ix++) + { + if (!(childV[ix]->equal(ba[ix]))) + { + return false; + } + } + return true; + + case orion::ValueTypeObject: + // nodeP must be a object + if (be.type() != orion::Object) + { + return false; + } + // TBD + return true; + + case orion::ValueTypeNotGiven: + LM_E(("Runtime Error (value type not given (%s))", name.c_str())); + return false; + + default: + LM_E(("Runtime Error (value type unknown (%s))", name.c_str())); + return false; + } +} + + + /* **************************************************************************** * * CompoundValueNode:toJson diff --git a/src/lib/parse/CompoundValueNode.h b/src/lib/parse/CompoundValueNode.h index 98f65b38a4..b46aa2c461 100644 --- a/src/lib/parse/CompoundValueNode.h +++ b/src/lib/parse/CompoundValueNode.h @@ -33,6 +33,8 @@ #include "orionTypes/OrionValueType.h" +#include "mongoDriver/BSONElement.h" + namespace orion { @@ -112,6 +114,7 @@ class CompoundValueNode CompoundValueNode* add(const orion::ValueType _type, const std::string& _name, double _value); CompoundValueNode* add(const orion::ValueType _type, const std::string& _name, bool _value); std::string check(const std::string& path); + bool equal(const orion::BSONElement& be); std::string finish(void); std::string toJson(std::map* replacementsP = NULL); diff --git a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test b/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test new file mode 100644 index 0000000000..9822816391 --- /dev/null +++ b/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test @@ -0,0 +1,226 @@ +# Copyright 2023 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-- +Notify upon actual change in geo:json value + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# 01. Create subscription covering E-A +# 02. Create E-A entity with geo:json (notification) +# 03. Update E-A entity with same geo:json object (no notification) +# 04. Update E-A entity with different geo:json (notification) +# 05. Dump accumulator, see 2 notifications +# + +echo "01. Create subscription covering E-A" +echo "====================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E", + "type": "T" + } + ] + }, + "notification": { + "http": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify" + } + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create E-A entity with geo:json (notification)" +echo "==================================================" +payload='{ + "id": "E", + "type": "T", + "A": { + "type": "geo:json", + "value": { + "type": "Point", + "coordinates": [10.2, 10.0] + } + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update E-A entity with same geo:json (no notification)" +echo "==========================================================" +payload='{ + "A": { + "type": "geo:json", + "value": { + "type": "Point", + "coordinates": [10.2, 10.0] + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "04. Update E-A entity with different geo:json (notification)" +echo "============================================================" +payload='{ + "A": { + "type": "geo:json", + "value": { + "type": "Point", + "coordinates": [11.2, -10.0] + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "05. Dump accumulator, see 3 notifications" +echo "=========================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create subscription covering E-A +==================================== +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 E-A entity with geo:json (notification) +================================================== +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E?type=T +Content-Length: 0 + + + +03. Update E-A entity with same geo:json (no notification) +========================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Update E-A entity with different geo:json (notification) +============================================================ +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Dump accumulator, see 2 notifications +========================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 163 +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": [ + { + "A": { + "metadata": {}, + "type": "geo:json", + "value": { + "coordinates": [ + 10.2, + 10 + ], + "type": "Point" + } + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 164 +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": [ + { + "A": { + "metadata": {}, + "type": "geo:json", + "value": { + "coordinates": [ + 11.2, + -10 + ], + "type": "Point" + } + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop diff --git a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test b/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test new file mode 100644 index 0000000000..9d74d7bf56 --- /dev/null +++ b/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test @@ -0,0 +1,370 @@ +# Copyright 2023 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-- +Notify upon actual change in JSON value + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# 01. Create subscription covering E-A +# 02. Create E-A entity with JSON object (notification) +# 03. Update E-A entity with same JSON object (no notification) +# 04. Update E-A entity with JSON array (notification) +# 05. Update E-A entity with same JSON array (no notification) +# 06. Update E-A entity with same string (notification) +# 07. Dump accumulator, see 3 notifications +# + +echo "01. Create subscription covering E-A" +echo "====================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E", + "type": "T" + } + ] + }, + "notification": { + "http": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify" + } + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create E-A entity with JSON object (notification)" +echo "=====================================================" +payload='{ + "id": "E", + "type": "T", + "A": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update E-A entity with same JSON object (no notification)" +echo "=============================================================" +payload='{ + "A": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "04. Update E-A entity with JSON array (notification)" +echo "====================================================" +payload='{ + "A": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "05. Update E-A entity with same JSON array (no notification)" +echo "============================================================" +payload='{ + "A": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "06. Update E-A entity with same string (notification)" +echo "=====================================================" +payload='{ + "A": { + "value": "foo", + "type": "Text" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "07. Dump accumulator, see 3 notifications" +echo "=========================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create subscription covering E-A +==================================== +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 E-A entity with JSON object (notification) +===================================================== +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E?type=T +Content-Length: 0 + + + +03. Update E-A entity with same JSON object (no notification) +============================================================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Update E-A entity with JSON array (notification) +==================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Update E-A entity with same JSON array (no notification) +============================================================ +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +06. Update E-A entity with same string (notification) +===================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +07. Dump accumulator, see 3 notifications +========================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 271 +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": [ + { + "A": { + "metadata": {}, + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y2" + ] + }, + "text": "foo" + } + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 162 +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": [ + { + "A": { + "metadata": {}, + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 124 +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": [ + { + "A": { + "metadata": {}, + "type": "Text", + "value": "foo" + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop From 1520c7e2541f9e7e6c8db27f55b37111680955d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Wed, 8 Nov 2023 09:54:31 +0100 Subject: [PATCH 2/8] FIX correctly identify changes in JSON attribute values in subscription triggering logic --- src/lib/mongoBackend/MongoCommonUpdate.cpp | 71 +++---- src/lib/parse/CompoundValueNode.cpp | 18 +- ...notify_upon_actual_change_in_geo_json.test | 2 +- ...tify_upon_actual_change_in_json_value.test | 187 ++++++++++++++++-- 4 files changed, 229 insertions(+), 49 deletions(-) diff --git a/src/lib/mongoBackend/MongoCommonUpdate.cpp b/src/lib/mongoBackend/MongoCommonUpdate.cpp index e00218931b..544c94d3c1 100644 --- a/src/lib/mongoBackend/MongoCommonUpdate.cpp +++ b/src/lib/mongoBackend/MongoCommonUpdate.cpp @@ -529,48 +529,49 @@ static ChangeType mergeAttrInfo /* Was it an actual update? */ ChangeType changeType = NO_CHANGE; + /* We consider there is a change in the value if one or more of the following are true: + * + * 1) the value of the attribute changed (see attrValueChanges or CompoundValueNode::equal() for details) + * 2) the type of the attribute changed (in this case, !attr.hasField(ENT_ATTRS_TYPE) is needed, as attribute + * type is optional according to NGSI and the attribute may not have that field in the BSON) + * + * In addition, we consider there is change in the metadata if: + * + * 3) the metadata changed (this is done checking if the size of the original and final metadata vectors is + * different and, if they are of the same size, checking if the vectors are not equal) + */ + bool valueChanged; + bool typeChanged; + bool mdChanged; if (caP->compoundValueP == NULL) { - /* In the case of simple value, we consider there is a change in the value if one or more of the following are true: - * - * 1) the value of the attribute changed (see attrValueChanges for details) - * 2) the type of the attribute changed (in this case, !attr.hasField(ENT_ATTRS_TYPE) is needed, as attribute - * type is optional according to NGSI and the attribute may not have that field in the BSON) - * - * In addition, we consider there is change in the metadata if: - * - * 3) the metadata changed (this is done checking if the size of the original and final metadata vectors is - * different and, if they are of the same size, checking if the vectors are not equal) - */ - bool valueChanged = attrValueChanges(attr, caP, forcedUpdate, apiVersion) || - ((!caP->type.empty()) && (!attr.hasField(ENT_ATTRS_TYPE) || getStringFieldF(attr, ENT_ATTRS_TYPE) != caP->type) ); - bool mdChanged = (mdNew.nFields() != mdSize || !equalMetadata(md, mdNew)); - - if (valueChanged && !mdChanged) - { - changeType = CHANGE_ONLY_VALUE; - } - else if (!valueChanged && mdChanged) - { - changeType = CHANGE_ONLY_MD; - } - else if (valueChanged && mdChanged) - { - changeType = CHANGE_VALUE_AND_MD; - } - else // !valueChanged && !mdChanged - { - changeType = NO_CHANGE; - } + valueChanged = attrValueChanges(attr, caP, forcedUpdate, apiVersion); } else { - // FIXME #643 P6: in the case of compound value, it's more difficult to know if an attribute - // has really changed its value (many levels have to be traversed). Until we can develop the - // matching logic, we consider CHANGE_VALUE_AND_MD always. - // + valueChanged = !caP->compoundValueP->equal(getFieldF(attr, ENT_ATTRS_VALUE)); + } + typeChanged = ((!caP->type.empty()) && (!attr.hasField(ENT_ATTRS_TYPE) || getStringFieldF(attr, ENT_ATTRS_TYPE) != caP->type)); + mdChanged = (mdNew.nFields() != mdSize || !equalMetadata(md, mdNew)); + + valueChanged = valueChanged || typeChanged; + + if (valueChanged && !mdChanged) + { + changeType = CHANGE_ONLY_VALUE; + } + else if (!valueChanged && mdChanged) + { + changeType = CHANGE_ONLY_MD; + } + else if (valueChanged && mdChanged) + { changeType = CHANGE_VALUE_AND_MD; } + else // !valueChanged && !mdChanged + { + changeType = NO_CHANGE; + } /* 5. Add modification date (actual change only if actual update) */ if (changeType) diff --git a/src/lib/parse/CompoundValueNode.cpp b/src/lib/parse/CompoundValueNode.cpp index 2d19d474bd..b66f011951 100644 --- a/src/lib/parse/CompoundValueNode.cpp +++ b/src/lib/parse/CompoundValueNode.cpp @@ -532,6 +532,7 @@ bool CompoundValueNode::equal(const orion::BSONElement& be) { // Note object cannot be declared inside switch block std::vector ba; + orion::BSONObj bo; switch (valueType) { @@ -575,7 +576,22 @@ bool CompoundValueNode::equal(const orion::BSONElement& be) { return false; } - // TBD + bo = be.embeddedObject(); + if ((int) childV.size() != bo.nFields()) + { + return false; + } + for (unsigned int ix = 0; ix < childV.size(); ix++) + { + if (!bo.hasField(childV[ix]->name)) + { + return false; + } + if (!(childV[ix]->equal(getFieldF(bo, childV[ix]->name)))) + { + return false; + } + } return true; case orion::ValueTypeNotGiven: diff --git a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test b/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test index 9822816391..cd9a0c0506 100644 --- a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test +++ b/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test @@ -110,7 +110,7 @@ echo echo -echo "05. Dump accumulator, see 3 notifications" +echo "05. Dump accumulator, see 2 notifications" echo "=========================================" accumulatorDump echo diff --git a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test b/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test index 9d74d7bf56..b50fa070b2 100644 --- a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test +++ b/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test @@ -34,10 +34,12 @@ accumulatorStart --pretty-print # 01. Create subscription covering E-A # 02. Create E-A entity with JSON object (notification) # 03. Update E-A entity with same JSON object (no notification) -# 04. Update E-A entity with JSON array (notification) -# 05. Update E-A entity with same JSON array (no notification) -# 06. Update E-A entity with same string (notification) -# 07. Dump accumulator, see 3 notifications +# 04. Update E-A entity with different JSON object (notification) +# 05. Update E-A entity with JSON array (notification) +# 06. Update E-A entity with same JSON array (no notification) +# 07. Update E-A entity with different JSON array (notification) +# 08. Update E-A entity with same string (notification) +# 09. Dump accumulator, see 5 notifications # echo "01. Create subscription covering E-A" @@ -130,7 +132,40 @@ echo echo -echo "04. Update E-A entity with JSON array (notification)" +echo "04. Update E-A entity with different JSON object (notification)" +echo "===============================================================" +payload='{ + "A": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y_new" ] + } + }, + "type": "Json" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "05. Update E-A entity with JSON array (notification)" echo "====================================================" payload='{ "A": { @@ -150,7 +185,7 @@ echo echo -echo "05. Update E-A entity with same JSON array (no notification)" +echo "06. Update E-A entity with same JSON array (no notification)" echo "============================================================" payload='{ "A": { @@ -170,7 +205,27 @@ echo echo -echo "06. Update E-A entity with same string (notification)" +echo "07. Update E-A entity with different JSON array (notification)" +echo "==============================================================" +payload='{ + "A": { + "value": [ + "", + { + "x": [ "x1", "x_new" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "08. Update E-A entity with same string (notification)" echo "=====================================================" payload='{ "A": { @@ -183,7 +238,7 @@ echo echo -echo "07. Dump accumulator, see 3 notifications" +echo "09. Dump accumulator, see 5 notifications" echo "=========================================" accumulatorDump echo @@ -219,7 +274,15 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}) -04. Update E-A entity with JSON array (notification) +04. Update E-A entity with different JSON object (notification) +=============================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Update E-A entity with JSON array (notification) ==================================================== HTTP/1.1 204 No Content Date: REGEX(.*) @@ -227,7 +290,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}) -05. Update E-A entity with same JSON array (no notification) +06. Update E-A entity with same JSON array (no notification) ============================================================ HTTP/1.1 204 No Content Date: REGEX(.*) @@ -235,7 +298,15 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}) -06. Update E-A entity with same string (notification) +07. Update E-A entity with different JSON array (notification) +============================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +08. Update E-A entity with same string (notification) ===================================================== HTTP/1.1 204 No Content Date: REGEX(.*) @@ -243,7 +314,7 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}) -07. Dump accumulator, see 3 notifications +09. Dump accumulator, see 5 notifications ========================================= POST http://127.0.0.1:REGEX(\d+)/notify Fiware-Servicepath: / @@ -301,6 +372,60 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 ======================================= POST http://127.0.0.1:REGEX(\d+)/notify Fiware-Servicepath: / +Content-Length: 274 +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": [ + { + "A": { + "metadata": {}, + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y_new" + ] + }, + "text": "foo" + } + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / Content-Length: 162 User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) Ngsiv2-Attrsformat: normalized @@ -339,6 +464,44 @@ Fiware-Correlator: REGEX([0-9a-f\-]{36}); cbnotif=1 ======================================= POST http://127.0.0.1:REGEX(\d+)/notify Fiware-Servicepath: / +Content-Length: 165 +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": [ + { + "A": { + "metadata": {}, + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x_new" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / Content-Length: 124 User-Agent: orion/REGEX(\d+\.\d+\.\d+.*) Ngsiv2-Attrsformat: normalized From 484babfac3e8da8afddea813e8948ed7e9aeb544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Wed, 8 Nov 2023 12:29:36 +0100 Subject: [PATCH 3/8] FIX correctly identify changes in JSON metadata values in subscription triggering logic --- src/lib/mongoBackend/MongoCommonUpdate.cpp | 69 +- src/lib/mongoDriver/BSONArray.cpp | 11 + src/lib/mongoDriver/BSONArray.h | 1 + src/lib/mongoDriver/BSONObj.cpp | 11 + src/lib/mongoDriver/BSONObj.h | 1 + .../change_evaluation_geojson.test} | 2 +- ..._evaluation_metadata_object_and_array.test | 600 ++++++++++++++++++ ...ge_evaluation_value_object_and_array.test} | 2 +- 8 files changed, 641 insertions(+), 56 deletions(-) rename test/functionalTest/cases/{4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test => 4211_right_json_change_evaluation_in_subs/change_evaluation_geojson.test} (99%) create mode 100644 test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array.test rename test/functionalTest/cases/{4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test => 4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array.test} (99%) diff --git a/src/lib/mongoBackend/MongoCommonUpdate.cpp b/src/lib/mongoBackend/MongoCommonUpdate.cpp index 544c94d3c1..bc5e0d036e 100644 --- a/src/lib/mongoBackend/MongoCommonUpdate.cpp +++ b/src/lib/mongoBackend/MongoCommonUpdate.cpp @@ -136,7 +136,7 @@ static bool hasMetadata(std::string name, std::string type, ContextAttribute* ca * * equalMetadataValues - */ -static bool equalMetadataValues(const orion::BSONObj& md1, const orion::BSONObj& md2) +static bool equalMetadataItems(const orion::BSONObj& md1, const orion::BSONObj& md2) { bool md1TypeExist = md1.hasField(ENT_ATTRS_MD_TYPE); bool md2TypeExist = md2.hasField(ENT_ATTRS_MD_TYPE); @@ -147,58 +147,23 @@ static bool equalMetadataValues(const orion::BSONObj& md1, const orion::BSONObj& return false; } - // If type exists in both metadata elments, check if they are the same + // If type exists in both metadata elements, check if they are the same if (md1TypeExist && md2TypeExist) { - if (getFieldF(md1, ENT_ATTRS_MD_TYPE).type() != getFieldF(md2, ENT_ATTRS_MD_TYPE).type()) + if ((getFieldF(md1, ENT_ATTRS_MD_TYPE).type() != orion::String)) { + LM_E(("Runtime Error (unallowed JSON type for metadata NGSI type: %d)", getFieldF(md1, ENT_ATTRS_MD_TYPE).type())); return false; } - switch (getFieldF(md1, ENT_ATTRS_MD_TYPE).type()) + if ((getFieldF(md2, ENT_ATTRS_MD_TYPE).type() != orion::String)) { - /* FIXME #643 P6: metadata array/object are now supported, but we haven't - implemented yet the logic to compare compounds between them - case Object: - ... - break; - - case Array: - ... - break; - */ - - case orion::NumberDouble: - if (getNumberFieldF(md1, ENT_ATTRS_MD_TYPE) != getNumberFieldF(md2, ENT_ATTRS_MD_TYPE)) - { - return false; - } - break; - - case orion::Bool: - if (getBoolFieldF(md1, ENT_ATTRS_MD_TYPE) != getBoolFieldF(md2, ENT_ATTRS_MD_TYPE)) - { - return false; - } - break; - - case orion::String: - if (getStringFieldF(md1, ENT_ATTRS_MD_TYPE) != getStringFieldF(md2, ENT_ATTRS_MD_TYPE)) - { - return false; - } - break; - - case orion::jstNULL: - if (!getFieldF(md2, ENT_ATTRS_MD_TYPE).isNull()) - { - return false; - } - break; + LM_E(("Runtime Error (unallowed JSON type for metadata NGSI type: %d)", getFieldF(md2, ENT_ATTRS_MD_TYPE).type())); + return false; + } - default: - LM_E(("Runtime Error (unknown JSON type for metadata NGSI type: %d)", getFieldF(md1, ENT_ATTRS_MD_TYPE).type())); + if (getStringFieldF(md1, ENT_ATTRS_MD_TYPE) != getStringFieldF(md2, ENT_ATTRS_MD_TYPE)) + { return false; - break; } } @@ -210,15 +175,11 @@ static bool equalMetadataValues(const orion::BSONObj& md1, const orion::BSONObj& switch (getFieldF(md1, ENT_ATTRS_MD_VALUE).type()) { - /* FIXME not yet case orion::Object: - ... - break; + return getObjectFieldF(md1, ENT_ATTRS_MD_VALUE).equal(getObjectFieldF(md2, ENT_ATTRS_MD_VALUE)); case orion::Array: - ... - break; - */ + return getArrayFieldF(md1, ENT_ATTRS_MD_VALUE).equal(getArrayFieldF(md2, ENT_ATTRS_MD_VALUE)); case orion::NumberDouble: return getNumberFieldF(md1, ENT_ATTRS_MD_VALUE) == getNumberFieldF(md2, ENT_ATTRS_MD_VALUE); @@ -266,7 +227,7 @@ static bool equalMetadata(const orion::BSONObj& md1, const orion::BSONObj& md2) orion::BSONObj md1Item = getObjectFieldF(md1, currentMd); orion::BSONObj md2Item = getObjectFieldF(md2, currentMd); - if (!equalMetadataValues(md1Item, md2Item)) + if (!equalMetadataItems(md1Item, md2Item)) { return false; } @@ -281,7 +242,7 @@ static bool equalMetadata(const orion::BSONObj& md1, const orion::BSONObj& md2) * * changedAttr - */ -static bool attrValueChanges(const orion::BSONObj& attr, ContextAttribute* caP, const bool& forcedUpdate, ApiVersion apiVersion) +static bool attrValueChanges(const orion::BSONObj& attr, ContextAttribute* caP, const bool& forcedUpdate) { /* Not finding the attribute field at MongoDB is considered as an implicit "" */ if (!attr.hasField(ENT_ATTRS_VALUE)) @@ -545,7 +506,7 @@ static ChangeType mergeAttrInfo bool mdChanged; if (caP->compoundValueP == NULL) { - valueChanged = attrValueChanges(attr, caP, forcedUpdate, apiVersion); + valueChanged = attrValueChanges(attr, caP, forcedUpdate); } else { diff --git a/src/lib/mongoDriver/BSONArray.cpp b/src/lib/mongoDriver/BSONArray.cpp index 7e69099455..afef83670e 100644 --- a/src/lib/mongoDriver/BSONArray.cpp +++ b/src/lib/mongoDriver/BSONArray.cpp @@ -87,6 +87,17 @@ std::string BSONArray::toString(void) const +/* **************************************************************************** +* +* BSONArray::equal - +*/ +bool BSONArray::equal(const BSONArray& ba) +{ + return (bson_compare(this->b, ba.b) == 0); +} + + + /* **************************************************************************** * * BSONArray::operator= - diff --git a/src/lib/mongoDriver/BSONArray.h b/src/lib/mongoDriver/BSONArray.h index d0e8b52c3f..098ac3520c 100644 --- a/src/lib/mongoDriver/BSONArray.h +++ b/src/lib/mongoDriver/BSONArray.h @@ -46,6 +46,7 @@ class BSONArray BSONArray(const BSONArray& _ba); int nFields(void) const; std::string toString(void) const; + bool equal(const BSONArray& ba); BSONArray& operator= (const BSONArray& rhs); // methods to be used only by mongoDriver/ code (with references to low-level driver code) diff --git a/src/lib/mongoDriver/BSONObj.cpp b/src/lib/mongoDriver/BSONObj.cpp index ad1ad1efb7..d7fcad2a49 100644 --- a/src/lib/mongoDriver/BSONObj.cpp +++ b/src/lib/mongoDriver/BSONObj.cpp @@ -192,6 +192,17 @@ void BSONObj::toElementsVector(std::vector* v) +/* **************************************************************************** +* +* BSONObj::equal - +*/ +bool BSONObj::equal(const BSONObj& bo) +{ + return (bson_compare(this->b, bo.b) == 0); +} + + + /* **************************************************************************** * * BSONObj::operator= - diff --git a/src/lib/mongoDriver/BSONObj.h b/src/lib/mongoDriver/BSONObj.h index d8b35f2c0b..473e974c01 100644 --- a/src/lib/mongoDriver/BSONObj.h +++ b/src/lib/mongoDriver/BSONObj.h @@ -59,6 +59,7 @@ class BSONObj bool isEmpty(void) const; void toStringMap(std::map* m); void toElementsVector(std::vector* v); + bool equal(const BSONObj& bo); BSONObj& operator= (const BSONObj& rhs); // methods to be used only by mongoDriver/ code (with references to low-level driver code) diff --git a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_geojson.test similarity index 99% rename from test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test rename to test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_geojson.test index cd9a0c0506..a540d7c043 100644 --- a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_geo_json.test +++ b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_geojson.test @@ -21,7 +21,7 @@ # VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh --NAME-- -Notify upon actual change in geo:json value +Right JSON change evaluation in subs (GeoJson case) --SHELL-INIT-- dbInit CB diff --git a/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array.test b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array.test new file mode 100644 index 0000000000..6fd56fd903 --- /dev/null +++ b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array.test @@ -0,0 +1,600 @@ +# Copyright 2023 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-- +Right JSON change evaluation in subs (objects and arrays in metadata case) + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# 01. Create subscription covering E-A +# 02. Create E-A entity with JSON object in metadata (notification) +# 03. Update E-A entity with same JSON object in metadata (no notification) +# 04. Update E-A entity with different JSON object in metadata (notification) +# 05. Update E-A entity with JSON array in metadata (notification) +# 06. Update E-A entity with same JSON array in metadata (no notification) +# 07. Update E-A entity with different JSON array in metadata (notification) +# 08. Update E-A entity with same string in metadata (notification) +# 09. Dump accumulator, see 5 notifications +# + +echo "01. Create subscription covering E-A" +echo "====================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E", + "type": "T" + } + ] + }, + "notification": { + "http": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify" + } + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create E-A entity with JSON object in metadata (notification)" +echo "=================================================================" +payload='{ + "id": "E", + "type": "T", + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } + } + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update E-A entity with same JSON object in metadata (no notification)" +echo "=========================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "04. Update E-A entity with different JSON object in metadata (notification)" +echo "===========================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y_new" ] + } + }, + "type": "Json" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "05. Update E-A entity with JSON array in metadata (notification)" +echo "================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "06. Update E-A entity with same JSON array in metadata (no notification)" +echo "========================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "07. Update E-A entity with different JSON array in metadata (notification)" +echo "==========================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": [ + "", + { + "x": [ "x1", "x_new" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "08. Update E-A entity with same string in metadata (notification)" +echo "=================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": "foo", + "type": "Text" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "09. Dump accumulator, see 5 notifications" +echo "=========================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create subscription covering E-A +==================================== +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 E-A entity with JSON object in metadata (notification) +================================================================= +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E?type=T +Content-Length: 0 + + + +03. Update E-A entity with same JSON object in metadata (no notification) +========================================================================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Update E-A entity with different JSON object in metadata (notification) +=========================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Update E-A entity with JSON array in metadata (notification) +================================================================ +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +06. Update E-A entity with same JSON array in metadata (no notification) +======================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +07. Update E-A entity with different JSON array in metadata (notification) +========================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +08. Update E-A entity with same string in metadata (notification) +================================================================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +09. Dump accumulator, see 5 notifications +========================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 302 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y2" + ] + }, + "text": "foo" + } + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 305 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y_new" + ] + }, + "text": "foo" + } + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 193 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 196 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x_new" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 155 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Text", + "value": "foo" + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop diff --git a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array.test similarity index 99% rename from test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test rename to test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array.test index b50fa070b2..cc664dd6cd 100644 --- a/test/functionalTest/cases/4211_notify_upon_actual_change_in_json_value/notify_upon_actual_change_in_json_value.test +++ b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array.test @@ -21,7 +21,7 @@ # VALGRIND_READY - to mark the test ready for valgrindTestSuite.sh --NAME-- -Notify upon actual change in JSON value +Right JSON change evaluation in subs (objects and arrays in attribute value case) --SHELL-INIT-- dbInit CB From 51b921f7e626cc7f697757a9a064ac9c7ea5aacd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Wed, 8 Nov 2023 13:00:40 +0100 Subject: [PATCH 4/8] FIX forcedUpdate with JSON changes --- src/lib/mongoBackend/MongoCommonUpdate.cpp | 2 +- ...ta_object_and_array_with_forcedUpdate.test | 705 ++++++++++++++++++ ...ue_object_and_array_with_forcedUpdate.test | 628 ++++++++++++++++ 3 files changed, 1334 insertions(+), 1 deletion(-) create mode 100644 test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_forcedUpdate.test create mode 100644 test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array_with_forcedUpdate.test diff --git a/src/lib/mongoBackend/MongoCommonUpdate.cpp b/src/lib/mongoBackend/MongoCommonUpdate.cpp index bc5e0d036e..faf2315238 100644 --- a/src/lib/mongoBackend/MongoCommonUpdate.cpp +++ b/src/lib/mongoBackend/MongoCommonUpdate.cpp @@ -510,7 +510,7 @@ static ChangeType mergeAttrInfo } else { - valueChanged = !caP->compoundValueP->equal(getFieldF(attr, ENT_ATTRS_VALUE)); + valueChanged = forcedUpdate || !caP->compoundValueP->equal(getFieldF(attr, ENT_ATTRS_VALUE)); } typeChanged = ((!caP->type.empty()) && (!attr.hasField(ENT_ATTRS_TYPE) || getStringFieldF(attr, ENT_ATTRS_TYPE) != caP->type)); mdChanged = (mdNew.nFields() != mdSize || !equalMetadata(md, mdNew)); diff --git a/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_forcedUpdate.test b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_forcedUpdate.test new file mode 100644 index 0000000000..a868b6576c --- /dev/null +++ b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_forcedUpdate.test @@ -0,0 +1,705 @@ +# Copyright 2023 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-- +Right JSON change evaluation in subs (objects and arrays in metadata case with forcedUpdate) + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# Same as change_evaluation_metadata_object_and_array.test but using forcedUpdate un update operations +# +# +# 01. Create subscription covering E-A +# 02. Create E-A entity with JSON object in metadata (notification) +# 03. Update E-A entity with same JSON object in metadata (notification) +# 04. Update E-A entity with different JSON object in metadata (notification) +# 05. Update E-A entity with JSON array in metadata (notification) +# 06. Update E-A entity with same JSON array in metadata (notification) +# 07. Update E-A entity with different JSON array in metadata (notification) +# 08. Update E-A entity with same string in metadata (notification) +# 09. Dump accumulator, see 5 notifications +# + +echo "01. Create subscription covering E-A" +echo "====================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E", + "type": "T" + } + ] + }, + "notification": { + "http": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify" + } + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create E-A entity with JSON object in metadata (notification)" +echo "=================================================================" +payload='{ + "id": "E", + "type": "T", + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } + } + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update E-A entity with same JSON object in metadata (notification)" +echo "======================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "04. Update E-A entity with different JSON object in metadata (notification)" +echo "===========================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y_new" ] + } + }, + "type": "Json" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "05. Update E-A entity with JSON array in metadata (notification)" +echo "================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "06. Update E-A entity with same JSON array in metadata (notification)" +echo "=====================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "07. Update E-A entity with different JSON array in metadata (notification)" +echo "==========================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": [ + "", + { + "x": [ "x1", "x_new" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "08. Update E-A entity with same string in metadata (notification)" +echo "=================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": "foo", + "type": "Text" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "09. Dump accumulator, see 7 notifications" +echo "=========================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create subscription covering E-A +==================================== +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 E-A entity with JSON object in metadata (notification) +================================================================= +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E?type=T +Content-Length: 0 + + + +03. Update E-A entity with same JSON object in metadata (notification) +====================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Update E-A entity with different JSON object in metadata (notification) +=========================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Update E-A entity with JSON array in metadata (notification) +================================================================ +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +06. Update E-A entity with same JSON array in metadata (notification) +===================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +07. Update E-A entity with different JSON array in metadata (notification) +========================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +08. Update E-A entity with same string in metadata (notification) +================================================================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +09. Dump accumulator, see 7 notifications +========================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 302 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y2" + ] + }, + "text": "foo" + } + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 302 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y2" + ] + }, + "text": "foo" + } + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 305 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y_new" + ] + }, + "text": "foo" + } + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 193 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 193 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 196 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x_new" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 155 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Text", + "value": "foo" + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop diff --git a/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array_with_forcedUpdate.test b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array_with_forcedUpdate.test new file mode 100644 index 0000000000..150035d985 --- /dev/null +++ b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array_with_forcedUpdate.test @@ -0,0 +1,628 @@ +# Copyright 2023 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-- +Right JSON change evaluation in subs (objects and arrays in attribute value case with forcedUpdate) + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# Same as change_evaluation_value_object_and_array.test but using forcedUpdate un update operations +# +# +# 01. Create subscription covering E-A +# 02. Create E-A entity with JSON object (notification) +# 03. Update E-A entity with same JSON object (notification) +# 04. Update E-A entity with different JSON object (notification) +# 05. Update E-A entity with JSON array (notification) +# 06. Update E-A entity with same JSON array (notification) +# 07. Update E-A entity with different JSON array (notification) +# 08. Update E-A entity with same string (notification) +# 09. Dump accumulator, see 7 notifications +# + +echo "01. Create subscription covering E-A" +echo "====================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E", + "type": "T" + } + ] + }, + "notification": { + "http": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify" + } + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create E-A entity with JSON object (notification)" +echo "=====================================================" +payload='{ + "id": "E", + "type": "T", + "A": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update E-A entity with same JSON object (notification)" +echo "==========================================================" +payload='{ + "A": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "04. Update E-A entity with different JSON object (notification)" +echo "===============================================================" +payload='{ + "A": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y_new" ] + } + }, + "type": "Json" + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "05. Update E-A entity with JSON array (notification)" +echo "====================================================" +payload='{ + "A": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "06. Update E-A entity with same JSON array (notification)" +echo "=========================================================" +payload='{ + "A": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "07. Update E-A entity with different JSON array (notification)" +echo "==============================================================" +payload='{ + "A": { + "value": [ + "", + { + "x": [ "x1", "x_new" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "08. Update E-A entity with same string (notification)" +echo "=====================================================" +payload='{ + "A": { + "value": "foo", + "type": "Text" + } +}' +orionCurl --url /v2/entities/E/attrs?options=forcedUpdate --payload "$payload" +echo +echo + + +echo "09. Dump accumulator, see 7 notifications" +echo "=========================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create subscription covering E-A +==================================== +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 E-A entity with JSON object (notification) +===================================================== +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E?type=T +Content-Length: 0 + + + +03. Update E-A entity with same JSON object (notification) +========================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Update E-A entity with different JSON object (notification) +=============================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Update E-A entity with JSON array (notification) +==================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +06. Update E-A entity with same JSON array (notification) +========================================================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +07. Update E-A entity with different JSON array (notification) +============================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +08. Update E-A entity with same string (notification) +===================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +09. Dump accumulator, see 7 notifications +========================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 271 +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": [ + { + "A": { + "metadata": {}, + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y2" + ] + }, + "text": "foo" + } + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 271 +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": [ + { + "A": { + "metadata": {}, + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y2" + ] + }, + "text": "foo" + } + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 274 +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": [ + { + "A": { + "metadata": {}, + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y_new" + ] + }, + "text": "foo" + } + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 162 +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": [ + { + "A": { + "metadata": {}, + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 162 +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": [ + { + "A": { + "metadata": {}, + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 165 +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": [ + { + "A": { + "metadata": {}, + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x_new" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 124 +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": [ + { + "A": { + "metadata": {}, + "type": "Text", + "value": "foo" + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop From b4eb6b32bf7bf8480f5ec1a7cf90bf207054bdce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Wed, 8 Nov 2023 13:26:23 +0100 Subject: [PATCH 5/8] FIX simplify forcedUpdate processing --- src/lib/mongoBackend/MongoCommonUpdate.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/lib/mongoBackend/MongoCommonUpdate.cpp b/src/lib/mongoBackend/MongoCommonUpdate.cpp index faf2315238..afdec2510f 100644 --- a/src/lib/mongoBackend/MongoCommonUpdate.cpp +++ b/src/lib/mongoBackend/MongoCommonUpdate.cpp @@ -242,7 +242,7 @@ static bool equalMetadata(const orion::BSONObj& md1, const orion::BSONObj& md2) * * changedAttr - */ -static bool attrValueChanges(const orion::BSONObj& attr, ContextAttribute* caP, const bool& forcedUpdate) +static bool attrValueChanges(const orion::BSONObj& attr, ContextAttribute* caP) { /* Not finding the attribute field at MongoDB is considered as an implicit "" */ if (!attr.hasField(ENT_ATTRS_VALUE)) @@ -265,13 +265,13 @@ static bool attrValueChanges(const orion::BSONObj& attr, ContextAttribute* caP, return true; case orion::NumberDouble: - return caP->valueType != orion::ValueTypeNumber || caP->numberValue != getNumberFieldF(attr, ENT_ATTRS_VALUE) || forcedUpdate; + return caP->valueType != orion::ValueTypeNumber || caP->numberValue != getNumberFieldF(attr, ENT_ATTRS_VALUE); case orion::Bool: - return caP->valueType != orion::ValueTypeBoolean || caP->boolValue != getBoolFieldF(attr, ENT_ATTRS_VALUE) || forcedUpdate; + return caP->valueType != orion::ValueTypeBoolean || caP->boolValue != getBoolFieldF(attr, ENT_ATTRS_VALUE); case orion::String: - return caP->valueType != orion::ValueTypeString || caP->stringValue != getStringFieldF(attr, ENT_ATTRS_VALUE) || forcedUpdate; + return caP->valueType != orion::ValueTypeString || caP->stringValue != getStringFieldF(attr, ENT_ATTRS_VALUE); case orion::jstNULL: return caP->valueType != orion::ValueTypeNull; @@ -492,8 +492,9 @@ static ChangeType mergeAttrInfo /* We consider there is a change in the value if one or more of the following are true: * - * 1) the value of the attribute changed (see attrValueChanges or CompoundValueNode::equal() for details) - * 2) the type of the attribute changed (in this case, !attr.hasField(ENT_ATTRS_TYPE) is needed, as attribute + * 1) forcedUpdate is enabled + * 2) the value of the attribute changed (see attrValueChanges or CompoundValueNode::equal() for details) + * 3) the type of the attribute changed (in this case, !attr.hasField(ENT_ATTRS_TYPE) is needed, as attribute * type is optional according to NGSI and the attribute may not have that field in the BSON) * * In addition, we consider there is change in the metadata if: @@ -506,7 +507,7 @@ static ChangeType mergeAttrInfo bool mdChanged; if (caP->compoundValueP == NULL) { - valueChanged = attrValueChanges(attr, caP, forcedUpdate); + valueChanged = forcedUpdate || attrValueChanges(attr, caP); } else { From b54284eabf8f1ca78841953e4aa1516bdaebf088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Wed, 8 Nov 2023 14:03:18 +0100 Subject: [PATCH 6/8] ADD entityUpdate test cases --- ...ta_object_and_array_with_entityUpdate.test | 649 ++++++++++++++++++ ...ue_object_and_array_with_entityUpdate.test | 577 ++++++++++++++++ 2 files changed, 1226 insertions(+) create mode 100644 test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_entityUpdate.test create mode 100644 test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array_with_entityUpdate.test diff --git a/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_entityUpdate.test b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_entityUpdate.test new file mode 100644 index 0000000000..54ee0e648b --- /dev/null +++ b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_entityUpdate.test @@ -0,0 +1,649 @@ +# Copyright 2023 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-- +Right JSON change evaluation in subs (objects and arrays in metadata case with entityUpdate) + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# Same as change_evaluation_metadata_object_and_array.test but using entityUpdate in the subscription +# +# +# 01. Create subscription covering E-A +# 02. Create E-A entity with JSON object in metadata (no notification) +# 03. Update E-A entity with same JSON object in metadata (notification) +# 04. Update E-A entity with different JSON object in metadata (notification) +# 05. Update E-A entity with JSON array in metadata (notification) +# 06. Update E-A entity with same JSON array in metadata (notification) +# 07. Update E-A entity with different JSON array in metadata (notification) +# 08. Update E-A entity with same string in metadata (notification) +# 09. Dump accumulator, see 6 notifications +# + +echo "01. Create subscription covering E-A" +echo "====================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E", + "type": "T" + } + ], + "condition": { + "alterationTypes": [ "entityUpdate" ] + } + }, + "notification": { + "http": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify" + } + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create E-A entity with JSON object in metadata (no notification)" +echo "====================================================================" +payload='{ + "id": "E", + "type": "T", + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } + } + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update E-A entity with same JSON object in metadata (notification)" +echo "======================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "04. Update E-A entity with different JSON object in metadata (notification)" +echo "===========================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y_new" ] + } + }, + "type": "Json" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "05. Update E-A entity with JSON array in metadata (notification)" +echo "================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "06. Update E-A entity with same JSON array in metadata (notification)" +echo "=====================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "07. Update E-A entity with different JSON array in metadata (notification)" +echo "==========================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": [ + "", + { + "x": [ "x1", "x_new" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "08. Update E-A entity with same string in metadata (notification)" +echo "=================================================================" +payload='{ + "A": { + "value": 1, + "type": "Number", + "metadata": { + "M": { + "value": "foo", + "type": "Text" + } + } + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "09. Dump accumulator, see 6 notifications" +echo "=========================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create subscription covering E-A +==================================== +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 E-A entity with JSON object in metadata (no notification) +==================================================================== +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E?type=T +Content-Length: 0 + + + +03. Update E-A entity with same JSON object in metadata (notification) +====================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Update E-A entity with different JSON object in metadata (notification) +=========================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Update E-A entity with JSON array in metadata (notification) +================================================================ +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +06. Update E-A entity with same JSON array in metadata (notification) +===================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +07. Update E-A entity with different JSON array in metadata (notification) +========================================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +08. Update E-A entity with same string in metadata (notification) +================================================================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +09. Dump accumulator, see 6 notifications +========================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 302 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y2" + ] + }, + "text": "foo" + } + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 305 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y_new" + ] + }, + "text": "foo" + } + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 193 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 193 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 196 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x_new" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 155 +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": [ + { + "A": { + "metadata": { + "M": { + "type": "Text", + "value": "foo" + } + }, + "type": "Number", + "value": 1 + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop diff --git a/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array_with_entityUpdate.test b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array_with_entityUpdate.test new file mode 100644 index 0000000000..a0befc27d9 --- /dev/null +++ b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_value_object_and_array_with_entityUpdate.test @@ -0,0 +1,577 @@ +# Copyright 2023 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-- +Right JSON change evaluation in subs (objects and arrays in attribute value case with entityUpdate) + +--SHELL-INIT-- +dbInit CB +brokerStart CB +accumulatorStart --pretty-print + +--SHELL-- + +# +# Same as change_evaluation_value_object_and_array.test but using entityUpdate in the subscription +# +# +# 01. Create subscription covering E-A +# 02. Create E-A entity with JSON object (no notification) +# 03. Update E-A entity with same JSON object (notification) +# 04. Update E-A entity with different JSON object (notification) +# 05. Update E-A entity with JSON array (notification) +# 06. Update E-A entity with same JSON array (notification) +# 07. Update E-A entity with different JSON array (notification) +# 08. Update E-A entity with same string (notification) +# 09. Dump accumulator, see 6 notifications +# + +echo "01. Create subscription covering E-A" +echo "====================================" +payload='{ + "subject": { + "entities": [ + { + "id" : "E", + "type": "T" + } + ], + "condition": { + "alterationTypes": [ "entityUpdate" ] + } + }, + "notification": { + "http": { + "url": "http://127.0.0.1:'${LISTENER_PORT}'/notify" + } + } +}' +orionCurl --url /v2/subscriptions --payload "$payload" +echo +echo + + +echo "02. Create E-A entity with JSON object (no notification)" +echo "========================================================" +payload='{ + "id": "E", + "type": "T", + "A": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } +}' +orionCurl --url /v2/entities --payload "$payload" +echo +echo + + +echo "03. Update E-A entity with same JSON object (notification)" +echo "==========================================================" +payload='{ + "A": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y2" ] + } + }, + "type": "Json" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "04. Update E-A entity with different JSON object (notification)" +echo "===============================================================" +payload='{ + "A": { + "value": { + "text": "foo", + "number": 10, + "bool": true, + "null": null, + "array": [ + "22", + { + "x" : [ "x1", "x2" ], + "y" : 3 + }, + [ "z1", "z2" ] + ], + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ "y1", "y_new" ] + } + }, + "type": "Json" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "05. Update E-A entity with JSON array (notification)" +echo "====================================================" +payload='{ + "A": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "06. Update E-A entity with same JSON array (notification)" +echo "=========================================================" +payload='{ + "A": { + "value": [ + "", + { + "x": [ "x1", "x2" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "07. Update E-A entity with different JSON array (notification)" +echo "==============================================================" +payload='{ + "A": { + "value": [ + "", + { + "x": [ "x1", "x_new" ], + "y": "3" + }, + [ "z1", "z2" ] + ], + "type": "Array" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "08. Update E-A entity with same string (notification)" +echo "=====================================================" +payload='{ + "A": { + "value": "foo", + "type": "Text" + } +}' +orionCurl --url /v2/entities/E/attrs --payload "$payload" +echo +echo + + +echo "09. Dump accumulator, see 6 notifications" +echo "=========================================" +accumulatorDump +echo +echo + + +--REGEXPECT-- +01. Create subscription covering E-A +==================================== +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 E-A entity with JSON object (no notification) +======================================================== +HTTP/1.1 201 Created +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) +Location: /v2/entities/E?type=T +Content-Length: 0 + + + +03. Update E-A entity with same JSON object (notification) +========================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +04. Update E-A entity with different JSON object (notification) +=============================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +05. Update E-A entity with JSON array (notification) +==================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +06. Update E-A entity with same JSON array (notification) +========================================================= +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +07. Update E-A entity with different JSON array (notification) +============================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +08. Update E-A entity with same string (notification) +===================================================== +HTTP/1.1 204 No Content +Date: REGEX(.*) +Fiware-Correlator: REGEX([0-9a-f\-]{36}) + + + +09. Dump accumulator, see 6 notifications +========================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 271 +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": [ + { + "A": { + "metadata": {}, + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y2" + ] + }, + "text": "foo" + } + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 274 +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": [ + { + "A": { + "metadata": {}, + "type": "Json", + "value": { + "array": [ + "22", + { + "x": [ + "x1", + "x2" + ], + "y": 3 + }, + [ + "z1", + "z2" + ] + ], + "bool": true, + "null": null, + "number": 10, + "object": { + "x": { + "x1": "a", + "x2": "b" + }, + "y": [ + "y1", + "y_new" + ] + }, + "text": "foo" + } + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 162 +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": [ + { + "A": { + "metadata": {}, + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 162 +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": [ + { + "A": { + "metadata": {}, + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x2" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 165 +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": [ + { + "A": { + "metadata": {}, + "type": "Array", + "value": [ + "", + { + "x": [ + "x1", + "x_new" + ], + "y": "3" + }, + [ + "z1", + "z2" + ] + ] + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= +POST http://127.0.0.1:REGEX(\d+)/notify +Fiware-Servicepath: / +Content-Length: 124 +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": [ + { + "A": { + "metadata": {}, + "type": "Text", + "value": "foo" + }, + "id": "E", + "type": "T" + } + ], + "subscriptionId": "REGEX([0-9a-f]{24})" +} +======================================= + + +--TEARDOWN-- +brokerStop CB +dbDrop CB +accumulatorStop From f2818abb1ce3768db367fa9a5bdfb7de16e9116c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Wed, 8 Nov 2023 14:03:35 +0100 Subject: [PATCH 7/8] FIX typos --- src/lib/parse/CompoundValueNode.cpp | 5 +++-- ...aluation_metadata_object_and_array_with_forcedUpdate.test | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/parse/CompoundValueNode.cpp b/src/lib/parse/CompoundValueNode.cpp index b66f011951..454c239383 100644 --- a/src/lib/parse/CompoundValueNode.cpp +++ b/src/lib/parse/CompoundValueNode.cpp @@ -530,7 +530,7 @@ std::string CompoundValueNode::check(const std::string& path) */ bool CompoundValueNode::equal(const orion::BSONElement& be) { - // Note object cannot be declared inside switch block + // Note objects cannot be declared inside switch block std::vector ba; orion::BSONObj bo; @@ -540,7 +540,8 @@ bool CompoundValueNode::equal(const orion::BSONElement& be) return (be.type() == orion::String) && (stringValue == be.String()); case orion::ValueTypeNumber: - // FIXME PR: unurure if this is going to work with all the Number types (int32/int64/double) + // FIXME P2: according to regression tests, this seems to work with all number types (int32/int64/double) + // However, let's keep an eye on this in the case some day it fails... return (be.type() == orion::NumberDouble && numberValue == be.Number()); case orion::ValueTypeBoolean: diff --git a/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_forcedUpdate.test b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_forcedUpdate.test index a868b6576c..6a54735e5e 100644 --- a/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_forcedUpdate.test +++ b/test/functionalTest/cases/4211_right_json_change_evaluation_in_subs/change_evaluation_metadata_object_and_array_with_forcedUpdate.test @@ -42,7 +42,7 @@ accumulatorStart --pretty-print # 06. Update E-A entity with same JSON array in metadata (notification) # 07. Update E-A entity with different JSON array in metadata (notification) # 08. Update E-A entity with same string in metadata (notification) -# 09. Dump accumulator, see 5 notifications +# 09. Dump accumulator, see 7 notifications # echo "01. Create subscription covering E-A" From b5b623e6ac2102e4a5e6184f2fee1ab9efdccbfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferm=C3=ADn=20Gal=C3=A1n=20M=C3=A1rquez?= Date: Wed, 8 Nov 2023 14:03:44 +0100 Subject: [PATCH 8/8] ADD CNR entry --- CHANGES_NEXT_RELEASE | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 7c55d0ee44..e241145fe2 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,5 +1,6 @@ - Add: servicePath field to builtin attributes (#2877) - Add: notification.mqtt.retain and notification.mqttCustom.retain flag for MQTT retain in notifications (#4388) +- Fix: correctly detect JSON attribute and metadata value changes in subscription triggering logic (#4211, #4434, #643) - Fix: DateTime and geo:json types were not supported in custom notifications using ngsi patching (#4435) - Fix: logDeprecate not working correctly (`geo:json` wrongly considered as deprecated) - Fix: improve error traces (#4387)