-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added feature config groups #1375
Added feature config groups #1375
Conversation
|
Hi @Keshav-NEC , thank for your willingness to contribute! The tests only fails on Node V18, which version are you using in your local enviroment?. Would be great if you can review it using the same version (V18). I suggest to use Probably those errors are related with #1333 |
Hi @mapedraza , I have tested the setup on |
Hi @fgalan , @mapedraza I have tested the setup on |
test/unit/ngsiv2/provisioning/device-provisioning-configGroup-api_test.js
Show resolved
Hide resolved
test/unit/ngsiv2/provisioning/singleGroupConfigurationMode-test.js
Outdated
Show resolved
Hide resolved
As mentioned in my previous comment, you did not addressed the changes made in #1333 in your new tests. Take as an example the ones I noted above and check the rest of the codebase (I suggested 3, the tests indicates 5, so 2 are remaining) |
…t.js Co-authored-by: mapedraza <40356341+mapedraza@users.noreply.github.com>
Hi @mapedraza , Thanks for the help and I have done changes as suggested by you and I am sharing the test cases screenshot. |
Hi @mapedraza, If you got any chance to review this PR. |
There are still tests failling. You need to solve them before merging this PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As general comment, all the logic is duplicated for /iot/services
and /iot/configGroups
. It is quite more easy. The logic should be the same, it is enough routing /iot/configGroups
to same methods than /iot/services
function loadConfigContextRoutes(router) { | ||
router.post( | ||
'/iot/configGroups', | ||
restUtils.checkRequestAttributes('headers', mandatoryHeaders), | ||
restUtils.checkBody(templateConfigGroup), | ||
handleCreateDeviceGroup | ||
); | ||
|
||
router.get( | ||
'/iot/configGroups', | ||
restUtils.checkRequestAttributes('headers', mandatoryHeaders), | ||
handleListDeviceGroups | ||
); | ||
|
||
router.put( | ||
'/iot/configGroups', | ||
restUtils.checkRequestAttributes('headers', mandatoryHeaders), | ||
restUtils.checkRequestAttributes('query', mandatoryParameters), | ||
handleModifyDeviceGroups | ||
); | ||
|
||
router.delete( | ||
'/iot/configGroups', | ||
restUtils.checkRequestAttributes('headers', mandatoryHeaders), | ||
restUtils.checkRequestAttributes('query', mandatoryParameters), | ||
handleDeleteDeviceGroups | ||
); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The route is uppercase aware? Did you try requesting to /iot/configgroups
?
doc/api.md
Outdated
```json | ||
{ | ||
"configGroups": [ | ||
{ | ||
"resource": "/deviceTest", | ||
"apikey": "801230BJKL23Y9090DSFL123HJK09H324HV8732", | ||
"type": "Light", | ||
"trust": "8970A9078A803H3BL98PINEQRW8342HBAMS", | ||
"cbHost": "http://orion:1026", | ||
"commands": [{ "name": "wheel1", "type": "Wheel" }], | ||
"attributes": [ | ||
{ | ||
"name": "luminescence", | ||
"type": "Integer", | ||
"metadata": { | ||
"unitCode": { "type": "Text", "value": "CAL" } | ||
} | ||
} | ||
], | ||
"lazy": [{ "name": "status", "type": "Boolean" }] | ||
}, | ||
{ | ||
"resource": "/deviceTest2", | ||
"apikey": "A21323ASDG12312ASDN21LWQEJPO2J123", | ||
"type": "Switch", | ||
"trust": "8970A9078A803H3BL98PINEQRW8342HBAMS", | ||
"cbHost": "http://orion:1026", | ||
"commands": [{ "name": "on", "type": "order" }], | ||
"attributes": [ | ||
{ | ||
"name": "swithc_status", | ||
"type": "boolean" | ||
} | ||
] | ||
} | ||
] | ||
} | ||
``` | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should replace the existing example, not adding a new one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 1178705
doc/api.md
Outdated
|
||
```json | ||
{ | ||
"configGroups": [ | ||
{ | ||
"resource": "/deviceTest", | ||
"apikey": "801230BJKL23Y9090DSFL123HJK09H324HV8732", | ||
"type": "Light", | ||
"trust": "8970A9078A803H3BL98PINEQRW8342HBAMS", | ||
"cbHost": "http://orion:1026", | ||
"commands": [{ "name": "wheel1", "type": "Wheel" }], | ||
"attributes": [ | ||
{ | ||
"name": "luminescence", | ||
"type": "Integer", | ||
"metadata": { | ||
"unitCode": { "type": "Text", "value": "CAL" } | ||
} | ||
} | ||
], | ||
"lazy": [{ "name": "status", "type": "Boolean" }] | ||
} | ||
] | ||
} | ||
``` | ||
OR | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should replace the existing example, not adding a new one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 1178705
/** | ||
* List all the configGroups created in the IoT Agent. The result, passed as a parameter in the callback | ||
* will be an object with two attributes: the services array with the list of groups; and a count | ||
* attribute with the total number of groups in the collection. | ||
* | ||
* @param {Number} service Service for wich all the configurations want to be retrieved. | ||
* @param {Number} limit Maximum number of entries to return. | ||
* @param {Number} offset Number of entries to skip for pagination. | ||
*/ | ||
function listConfigGroups(service, limit, offset, callback) { | ||
const result = []; | ||
let skipped = 0; | ||
const filteredGroups = getConfigurationsByService(service); | ||
|
||
for (const i in filteredGroups) { | ||
if (registeredGroups.hasOwnProperty(filteredGroups[i])) { | ||
if (offset && skipped < parseInt(offset, 10)) { | ||
skipped++; | ||
} else { | ||
result.push(registeredGroups[filteredGroups[i]]); | ||
} | ||
|
||
if (limit && result.length === parseInt(limit, 10)) { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
callback(null, { | ||
count: filteredGroups.length, | ||
configGroups: result | ||
}); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is duplicated, same as function listGroups(service, limit, offset, callback)
. No needed to duplicate code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 1178705
function findConfigGroups(service, subservice, callback) { | ||
if (config.getConfig().singleConfigurationMode === true) { | ||
return findSingleConfigurationMode(service, subservice, callback); | ||
} | ||
const result = []; | ||
|
||
for (const i in registeredGroups) { | ||
if ( | ||
registeredGroups.hasOwnProperty(i) && | ||
registeredGroups[i].service === service && | ||
registeredGroups[i].subservice === subservice | ||
) { | ||
result.push(registeredGroups[i]); | ||
} | ||
} | ||
|
||
if (result.length > 0) { | ||
return callback(null, { | ||
count: result.length, | ||
configGroups: result | ||
}); | ||
} else { | ||
return callback(new errors.DeviceGroupNotFound(service, subservice)); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is duplicated, same as function find(service, subservice, callback)
. No needed to duplicate code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 1178705
/** | ||
* List all the configGroups created in the IoT Agent. | ||
* | ||
* @param {Number} service Service for wich all the configurations want to be retrieved. | ||
* @param {Number} limit Maximum number of entries to return. | ||
* @param {Number} offset Number of entries to skip for pagination. | ||
*/ | ||
function listConfigGroups(service, limit, offset, callback) { | ||
const condition = {}; | ||
|
||
function toObjectFn(obj) { | ||
return obj.toObject(); | ||
} | ||
|
||
if (service) { | ||
condition.service = service; | ||
} | ||
|
||
const query = Group.model.find(condition).sort(); | ||
|
||
if (limit) { | ||
query.limit(parseInt(limit, 10)); | ||
} | ||
|
||
if (offset) { | ||
query.skip(parseInt(offset, 10)); | ||
} | ||
|
||
async.series([query.exec.bind(query), Group.model.countDocuments.bind(Group.model, condition)], function ( | ||
error, | ||
results | ||
) { | ||
callback(error, { | ||
count: results[1], | ||
configGroups: results[0].map(toObjectFn) | ||
}); | ||
}); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicated code, same as function listGroups(service, limit, offset, callback)
. It is not required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 1178705
/** | ||
* List all the configGroups created in the IoT Agent for a service and a subservice. | ||
* | ||
* @param {String} service Service used to filter the groups. | ||
* @param {String} subservice Subservice used to filter the groups. | ||
* @param {Function} callback The callback function. | ||
*/ | ||
function findConfigGroups(service, subservice, callback) { | ||
const condition = {}; | ||
|
||
function toObjectFn(obj) { | ||
return obj.toObject(); | ||
} | ||
|
||
condition.service = service; | ||
condition.subservice = subservice; | ||
|
||
const query = Group.model.find(condition).sort(); | ||
|
||
async.series([query.exec.bind(query), Group.model.countDocuments.bind(Group.model, condition)], function ( | ||
error, | ||
results | ||
) { | ||
callback(error, { | ||
count: results[1], | ||
configGroups: results[0].map(toObjectFn) | ||
}); | ||
}); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicated code, same as function find(service, subservice, callback)
. No required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 1178705
exports.list = alarmsInt(constants.MONGO_ALARM + '_02', intoTrans(context, listGroups)); | ||
exports.listConfigGroups = alarmsInt(constants.MONGO_ALARM + '_12', intoTrans(context, listConfigGroups)); | ||
exports.init = alarmsInt(constants.MONGO_ALARM + '_03', intoTrans(context, init)); | ||
exports.find = alarmsInt(constants.MONGO_ALARM + '_04', intoTrans(context, find)); | ||
exports.findConfigGroups = alarmsInt(constants.MONGO_ALARM + '_13', intoTrans(context, findConfigGroups)); | ||
exports.findType = alarmsInt( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exporting duplicated functions, not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 1178705
if (req.body.configGroups) { | ||
for (let i = 0; i < req.body.configGroups.length; i++) { | ||
req.body.configGroups[i] = applyMap(apiToInternal, req.body.configGroups[i]); | ||
req.body.configGroups[i].service = req.headers['fiware-service']; | ||
req.body.configGroups[i].subservice = req.headers['fiware-servicepath']; | ||
} | ||
} else { | ||
for (let i = 0; i < req.body.services.length; i++) { | ||
req.body.services[i] = applyMap(apiToInternal, req.body.services[i]); | ||
req.body.services[i].service = req.headers['fiware-service']; | ||
req.body.services[i].subservice = req.headers['fiware-servicepath']; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic of different routes ( /iot/services
and /iot/configGroups
should be the same)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 1178705
@Keshav-NEC thank you so mucho for your contribution. I think it is quite easy to change the PR according to my feedback. Please, address all the comments and the general idea before reviewing again |
Hi @mapedraza, As in this comment, #752 (comment) it is suggested to keep the backward compatibility intact. As per @mapedraza, I need to delete the |
@Keshav-NEC as you stated, the idea is to not break previous methods and paths. My comment comes because of the duplicated logic you added: function listGroups(service, limit, offset, callback) {
const result = [];
let skipped = 0;
const filteredGroups = getConfigurationsByService(service);
for (const i in filteredGroups) {
if (registeredGroups.hasOwnProperty(filteredGroups[i])) {
if (offset && skipped < parseInt(offset, 10)) {
skipped++;
} else {
result.push(registeredGroups[filteredGroups[i]]);
}
if (limit && result.length === parseInt(limit, 10)) {
break;
}
}
}
callback(null, {
count: filteredGroups.length,
services: result
});
} function listConfigGroups(service, limit, offset, callback) {
const result = [];
let skipped = 0;
const filteredGroups = getConfigurationsByService(service);
for (const i in filteredGroups) {
if (registeredGroups.hasOwnProperty(filteredGroups[i])) {
if (offset && skipped < parseInt(offset, 10)) {
skipped++;
} else {
result.push(registeredGroups[filteredGroups[i]]);
}
if (limit && result.length === parseInt(limit, 10)) {
break;
}
}
}
callback(null, {
count: filteredGroups.length,
configGroups: result
});
} Both codeblocks mentioned above differs just in one line, the name of the variable passed to the callback. Probably there are better ways to implement it without duplicating code, that supposes worst maintainability (duplicating logics and paths). There are different alternatives to achieve this, like controlling it at higher level, or a wrapping the function. Take the one you feel confident with it, but try not to duplicate the code. |
Hi @mapedraza , I have updated the PR as per the review comments received. Please review, Thanks. |
Line 62 removed and rebased
Hi @mapedraza, If you got any chance to review this PR. |
Hi @fgalan, if you got any chance to review this PR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @KeshavSoni2511, than you so much for your amazing job. Now it is more aligned. Just some minor improvements points:
- 1): I can't see tests implementing cross functionality. I mean, creating groups using services and then retrieving it through configGroup endpoint. It should be aded in both ways, I mean, creating as services and configGroup and retrieving them with the opposite.
- 2) In order to configure the keyword used by the new endpoint, it would be great if instead of having a magic word, it is moved to the constans file (lib/constants.js), replacing each time in the code appears 'configgroups'. It should be configured for the API route and for the term used in the json response.
Hi @KeshavSoni2511, could you address what I noted in my previous comment?. It would be great if you complete everything so we can merge it Thanks in advance!
|
Hi @mapedraza, Hope you are doing well. FYI, due to sudden layoff, I am not working with NEC anymore. I think anyone else from NEC can do requested changes. |
Really sad to hear that. I will merge your PR into a prelanding branch, so the work you accomplished is not going to be be thrown. Thank for your help |
Fix for issue #752