Skip to content

Commit d48e188

Browse files
authored
Merge pull request #1483 from telefonicaid/fix/remove_measures_with_attribute_name_id_type
FIX: Remove measures with attributes name 'id' or 'type' (hotfix 3.4.3)
2 parents 7411974 + 0f172ab commit d48e188

File tree

5 files changed

+213
-5
lines changed

5 files changed

+213
-5
lines changed

CHANGES_NEXT_RELEASE

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-

doc/api.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ parameters defined at device level in database, the parameters are inherit from
152152
## Entity attributes
153153

154154
In the config group/device model there are four list of attributes with different purpose to configure how the
155-
information coming from the device is mapped to the Context Broker attributes:
155+
information coming from the device (measures) is mapped to the Context Broker attributes:
156156

157157
- **`attributes`**: Are measures that are pushed from the device to the IoT agent. This measure changes will be sent
158158
to the Context Broker as updateContext requests over the device entity. NGSI queries to the context broker will be
@@ -179,7 +179,9 @@ information coming from the device is mapped to the Context Broker attributes:
179179
All of them have the same syntax, a list of objects with the following attributes:
180180

181181
- **object_id** (optional): name of the attribute as coming from the device.
182-
- **name** (mandatory): ID of the attribute in the target entity in the Context Broker.
182+
- **name** (mandatory): ID of the attribute in the target entity in the Context Broker. Note that `id` and `type`
183+
are not valid attribute names at Context Broker. Thus, although a measure named `id` or `type` will not break the IOT Agent, they
184+
are silently ignored and never progress toward Context Broker entities.
183185
- **type** (mandatory): name of the type of the attribute in the target entity.
184186
- **metadata** (optional): additional static metadata for the attribute in the target entity. (e.g. `unitCode`)
185187

@@ -209,6 +211,10 @@ Additionally for commands (which are attributes of type `command`) the following
209211
- **contentType**: `content-type` header used when send command by HTTP transport (ignored in other kinds of
210212
transports)
211213

214+
Note that, when information comming from devices, this means measures, are not defined neither in the group, nor in the
215+
device, the IoT agent will store that information into the destination entity using the same attribute name than the
216+
measure name, unless `explicitAttrs` is defined. Measures `id` or `type` names are invalid, and will be ignored.
217+
212218
## Multientity support
213219

214220
The IOTA is able to persists measures coming from a single device to more than one entity, declaring the target entities

lib/services/ngsi/entities-NGSI-v2.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,16 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
340340
attributes,
341341
typeInformation
342342
);
343+
// if any measure has name 'id' or 'type' it should be removed
344+
// (as they cannot be progressed as attribute names, given that 'id' or 'type' are forbidden names for attributes in CB)
345+
var attributesWithoutIdType = [];
346+
attributes.forEach(function (attribute) {
347+
if (attribute.name !== 'id' && attribute.name !== 'type') {
348+
attributesWithoutIdType.push(attribute);
349+
}
350+
});
351+
attributes = attributesWithoutIdType;
352+
343353
const payload = {
344354
entities: [
345355
{
@@ -729,7 +739,9 @@ function sendUpdateValueNgsi2(entityName, attributes, typeInformation, token, ca
729739
attr,
730740
newAttr
731741
);
732-
delete payload.entities[0][attr.object_id];
742+
if (!['id', 'type'].includes(attr.object_id)) {
743+
delete payload.entities[0][attr.object_id];
744+
}
733745
attr = undefined; // stop processing attr
734746
newAttr = undefined;
735747
} else {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "iotagent-node-lib",
33
"license": "AGPL-3.0-only",
44
"description": "IoT Agent library to interface with NGSI Context Broker",
5-
"version": "3.4.3",
5+
"version": "3.4.4",
66
"homepage": "https://github.com/telefonicaid/iotagent-node-lib",
77
"keywords": [
88
"fiware",

test/unit/ngsiv2/ngsiService/active-devices-test.js

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,52 @@ const iotAgentConfig = {
156156
}
157157
}
158158
]
159+
},
160+
StupidDevice: {
161+
type: 'StupidDevice',
162+
commands: [],
163+
lazy: [],
164+
staticAttributes: [],
165+
active: [
166+
{
167+
name: 'type',
168+
object_id: 't',
169+
type: 'text'
170+
},
171+
{
172+
name: 'id',
173+
object_id: 'i',
174+
type: 'text'
175+
},
176+
{
177+
name: 'meas',
178+
object_id: 'm',
179+
type: 'String'
180+
}
181+
]
182+
},
183+
StupidDevice2: {
184+
type: 'StupidDevice2',
185+
commands: [],
186+
lazy: [],
187+
staticAttributes: [],
188+
active: [
189+
{
190+
name: 'type',
191+
object_id: 'type',
192+
type: 'text'
193+
},
194+
{
195+
name: 'id',
196+
object_id: 'id',
197+
type: 'text'
198+
},
199+
{
200+
name: 'meas',
201+
object_id: 'meas',
202+
type: 'String'
203+
}
204+
]
159205
}
160206
},
161207
service: 'smartgondor',
@@ -856,6 +902,150 @@ describe('NGSI-v2 - Active attributes test', function () {
856902
});
857903
});
858904

905+
describe('When the IoT Agent receives autoprovisioned id and type measures', function () {
906+
const valuesIdType = [
907+
{
908+
name: 'id',
909+
type: 'text',
910+
value: 'idIoTA'
911+
},
912+
{
913+
name: 'type',
914+
type: 'text',
915+
value: 'typeIoTA'
916+
},
917+
{
918+
name: 'm',
919+
type: 'text',
920+
value: 'measIoTA'
921+
}
922+
];
923+
924+
beforeEach(function (done) {
925+
926+
nock.cleanAll();
927+
928+
contextBrokerMock = nock('http://192.168.1.1:1026')
929+
.matchHeader('fiware-service', 'smartgondor')
930+
.matchHeader('fiware-servicepath', 'gardens')
931+
.post('/v2/entities?options=upsert', {
932+
id: 'stupiddevice1',
933+
type: 'StupidDevice',
934+
meas: {
935+
value: 'measIoTA',
936+
type: 'String'
937+
}
938+
})
939+
.reply(204);
940+
941+
iotAgentLib.activate(iotAgentConfig, done);
942+
});
943+
944+
it('should not affect to the real ID and Type to store in the context broker', function (done) {
945+
iotAgentLib.update('stupiddevice1', 'StupidDevice', '', valuesIdType, function (error) {
946+
should.not.exist(error);
947+
contextBrokerMock.done();
948+
done();
949+
});
950+
});
951+
});
952+
953+
describe('When the IoT Agent receives provisioned id and type measures with different object_id names', function () {
954+
const valuesIdType2 = [
955+
{
956+
name: 'i',
957+
type: 'text',
958+
value: 'idIoTA2'
959+
},
960+
{
961+
name: 't',
962+
type: 'text',
963+
value: 'typeIoTA2'
964+
},
965+
{
966+
name: 'm',
967+
type: 'text',
968+
value: 'measIoTA2'
969+
}
970+
];
971+
972+
beforeEach(function (done) {
973+
974+
nock.cleanAll();
975+
976+
contextBrokerMock = nock('http://192.168.1.1:1026')
977+
.matchHeader('fiware-service', 'smartgondor')
978+
.matchHeader('fiware-servicepath', 'gardens')
979+
.post('/v2/entities?options=upsert', {
980+
id: 'stupiddevice2',
981+
type: 'StupidDevice',
982+
meas: {
983+
value: 'measIoTA2',
984+
type: 'String'
985+
}
986+
})
987+
.reply(204);
988+
989+
iotAgentLib.activate(iotAgentConfig, done);
990+
});
991+
992+
it('should not affect to the real ID and Type to store in the context broker', function (done) {
993+
iotAgentLib.update('stupiddevice2', 'StupidDevice', '', valuesIdType2, function (error) {
994+
should.not.exist(error);
995+
contextBrokerMock.done();
996+
done();
997+
});
998+
});
999+
});
1000+
1001+
describe('When the IoT Agent receives provisioned id and type measures with the same object_id name', function () {
1002+
const valuesIdType3 = [
1003+
{
1004+
name: 'id',
1005+
type: 'text',
1006+
value: 'idIoTA'
1007+
},
1008+
{
1009+
name: 'type',
1010+
type: 'text',
1011+
value: 'typeIoTA'
1012+
},
1013+
{
1014+
name: 'meas',
1015+
type: 'text',
1016+
value: 'measIoTA'
1017+
}
1018+
];
1019+
1020+
beforeEach(function (done) {
1021+
1022+
nock.cleanAll();
1023+
1024+
contextBrokerMock = nock('http://192.168.1.1:1026')
1025+
.matchHeader('fiware-service', 'smartgondor')
1026+
.matchHeader('fiware-servicepath', 'gardens')
1027+
.post('/v2/entities?options=upsert', {
1028+
id: 'stupiddevice3',
1029+
type: 'StupidDevice2',
1030+
meas: {
1031+
value: 'measIoTA',
1032+
type: 'String'
1033+
}
1034+
})
1035+
.reply(204);
1036+
1037+
iotAgentLib.activate(iotAgentConfig, done);
1038+
});
1039+
1040+
it('should not affect to the real ID and Type to store in the context broker', function (done) {
1041+
iotAgentLib.update('stupiddevice3', 'StupidDevice2', '', valuesIdType3, function (error) {
1042+
should.not.exist(error);
1043+
contextBrokerMock.done();
1044+
done();
1045+
});
1046+
});
1047+
});
1048+
8591049
describe('When the IoT Agent receives new information from a device and CBis defined using environment variables', function () {
8601050
beforeEach(function (done) {
8611051
process.env.IOTA_CB_HOST = 'cbhost';
@@ -873,6 +1063,7 @@ describe('NGSI-v2 - Active attributes test', function () {
8731063

8741064
iotAgentLib.activate(iotAgentConfig, done);
8751065
});
1066+
8761067
it('should change the value of the corresponding attribute in the context broker', function (done) {
8771068
iotAgentLib.update('light1', 'Light', '', values, function (error) {
8781069
should.not.exist(error);

0 commit comments

Comments
 (0)