Skip to content
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

Conversation

KeshavSoni2511
Copy link
Contributor

Fix for issue #752

@KeshavSoni2511
Copy link
Contributor Author

KeshavSoni2511 commented May 26, 2023

IMG_4038
Hi @fgalan , the tests are passing on my local setup but here the tests are failing. Kindly look into the issue or anything I can fix. Thanks

@mapedraza
Copy link
Collaborator

mapedraza commented Jun 6, 2023

Hi @fgalan , the tests are passing on my local setup but here the tests are failing. Kindly look into the issue or anything I can fix. Thanks

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 n Node version manager to switch between different node versions

Probably those errors are related with #1333

@KeshavSoni2511
Copy link
Contributor Author

Hi @mapedraza , I have tested the setup on Node V16. I will test the setup on Node V18 and will share my findings.

@KeshavSoni2511
Copy link
Contributor Author

Hi @fgalan , @mapedraza I have tested the setup on Node V18 and npm V9.5.1 and test cases are passing and also I have used the link n Node version manager shared by @mapedraza . Please find the logs of test cases of pull request #1375 and also I have attached the screenshot of passing test cases. Thanks.
Screenshot 2023-06-21 000549

@mapedraza
Copy link
Collaborator

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)

KeshavSoni2511 and others added 2 commits June 27, 2023 10:15
…t.js

Co-authored-by: mapedraza <40356341+mapedraza@users.noreply.github.com>
@KeshavSoni2511
Copy link
Contributor Author

KeshavSoni2511 commented Jun 27, 2023

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)

Hi @mapedraza , Thanks for the help and I have done changes as suggested by you and I am sharing the test cases screenshot.

Screenshot 2023-06-26 215608

@KeshavSoni2511
Copy link
Contributor Author

Hi @mapedraza, If you got any chance to review this PR.

@mapedraza
Copy link
Collaborator

There are still tests failling. You need to solve them before merging this PR

Copy link
Collaborator

@mapedraza mapedraza left a 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

Comment on lines +309 to +337
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
);
}

Copy link
Collaborator

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
Comment on lines 1148 to 1186
```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"
}
]
}
]
}
```

Copy link
Collaborator

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.

Copy link
Contributor Author

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
Comment on lines 1245 to 1271

```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

Copy link
Collaborator

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1178705

Comment on lines 90 to 123
/**
* 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
});
}

Copy link
Collaborator

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1178705

Comment on lines 189 to 214
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));
}
}

Copy link
Collaborator

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1178705

Comment on lines 122 to 160
/**
* 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)
});
});
}

Copy link
Collaborator

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1178705

Comment on lines 224 to 253
/**
* 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)
});
});
}

Copy link
Collaborator

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1178705

Comment on lines 373 to 378
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(
Copy link
Collaborator

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1178705

Comment on lines 126 to 138
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'];
}
}
Copy link
Collaborator

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)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1178705

@mapedraza
Copy link
Collaborator

@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

@KeshavSoni2511
Copy link
Contributor Author

Hi @mapedraza, As in this comment, #752 (comment) it is suggested to keep the backward compatibility intact.
I have created the separate functions for /iot/services and /iot/configGroups to return the result in services:[] and configGroups:[] objects respectively.
listGroups() will output the result into services: [] object here but listConfigGroups() will output the result into configGroups:[] object here.

As per @mapedraza, I need to delete the listConfigGroups() and other functions which are similar to previous one. And handle both APIs /iot/services and /iot/configGroups in the same function by using if/else or some other logic. Could you please confirm my understanding?

@mapedraza
Copy link
Collaborator

mapedraza commented Sep 22, 2023

@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.

@AlvaroVega
Copy link
Member

What is the difference between this PR and these others: #1198 and #954.
I guess two of there PRs should be closed.

@mapedraza
Copy link
Collaborator

What is the difference between this PR and these others: #1198 and #954. I guess two of there PRs should be closed.

Older PRs closed

q
Merge remote-tracking branch 'upstream/master' into Added_Feature_ConfigGroups
@KeshavSoni2511
Copy link
Contributor Author

Hi @mapedraza , I have updated the PR as per the review comments received. Please review, Thanks.

@KeshavSoni2511
Copy link
Contributor Author

Hi @mapedraza, If you got any chance to review this PR.

@KeshavSoni2511
Copy link
Contributor Author

Hi @fgalan, if you got any chance to review this PR

Copy link
Collaborator

@mapedraza mapedraza left a 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.

@mapedraza
Copy link
Collaborator

mapedraza commented Aug 6, 2024

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 @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.

@KeshavSoni2511
Copy link
Contributor Author

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.

@mapedraza mapedraza changed the base branch from master to prelanding/new-config-groups August 7, 2024 07:55
@mapedraza
Copy link
Collaborator

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

@mapedraza mapedraza merged commit e53d004 into telefonicaid:prelanding/new-config-groups Aug 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants