• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

telefonicaid / perseo-fe / 17369349134

01 Sep 2025 06:19AM UTC coverage: 77.379% (-0.2%) from 77.554%
17369349134

Pull #817

github

web-flow
Merge 201d0fa4e into eed715581
Pull Request #817: [WIP] upgrade dep driver mongodb to 4

756 of 1117 branches covered (67.68%)

Branch coverage included in aggregate %.

107 of 124 new or added lines in 6 files covered. (86.29%)

4 existing lines in 3 files now uncovered.

2196 of 2698 relevant lines covered (81.39%)

68.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.38
/lib/models/noSignal.js
1
/*
2
 * Copyright 2015 Telefonica Investigación y Desarrollo, S.A.U
3
 *
4
 * This file is part of perseo-fe
5
 *
6
 * perseo-fe is free software: you can redistribute it and/or
7
 * modify it under the terms of the GNU Affero General Public License as
8
 * published by the Free Software Foundation, either version 3 of the License,
9
 * or (at your option) any later version.
10
 *
11
 * perseo-fe is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 * See the GNU Affero General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Affero General Public
17
 * License along with perseo-fe.
18
 * If not, see http://www.gnu.org/licenses/.
19
 *
20
 * For those usages not covered by the GNU Affero General Public License
21
 * please contact with::[contacto@tid.es]
22
 */
23
'use strict';
24

25
var util = require('util'),
1✔
26
    domain = require('domain'),
1✔
27
    logger = require('logops'),
1✔
28
    myutils = require('../myutils'),
1✔
29
    constants = require('../constants'),
1✔
30
    entitiesStore = require('./entitiesStore'),
1✔
31
    actions = require('./actions'),
1✔
32
    config = require('../../config'),
1✔
33
    nsRulesByInterval = {},
1✔
34
    checkers = {},
1✔
35
    intervalUnit = 1000 * 60,
1✔
36
    SERVICE = 0,
1✔
37
    SUBSERVICE = 1,
1✔
38
    NAME = 2,
1✔
39
    ATTRIBUTE = 3,
1✔
40
    ID = 4,
1✔
41
    ID_REGEXP = 5,
1✔
42
    TYPE = 6,
1✔
43
    REPORT_INTERVAL = 7,
1✔
44
    CHECK_INTERVAL = 8,
1✔
45
    MAX_TIME_DETECTION = 9,
1✔
46
    MAX_TIME_DETECTION_ATTR = 10,
1✔
47
    REPORT_INTERVAL_ATTR = 11,
1✔
48
    context = { op: 'checkNonSignal', comp: constants.COMPONENT_NAME, corr: 'n/a', trans: 'n/a' },
1✔
49
    lastTime,
50
    MIN_INTERVAL_MS = 30e3,
1✔
51
    MAX_INTERVAL_MS = 2147483647; // 2^31-1 which is 2,147,483,647ms (maximum value of a signed 32 bit integer in ms)
1✔
52
const { v4: uuidv4 } = require('uuid');
1✔
53

54
function alertFunc(nsLineRule, entity) {
55
    var d = domain.create();
2✔
56
    d.context = {};
2✔
57
    d.context.trans = uuidv4();
2✔
58
    d.context.corr = d.context.trans;
2✔
59
    d.context.srv = 'n/a';
2✔
60
    d.context.subsrv = 'n/a';
2✔
61
    d.context.op = 'alertNS';
2✔
62
    d.context.comp = constants.COMPONENT_NAME;
2✔
63

64
    d.on('error', function(err) {
2✔
65
        myutils.logErrorIf(err, 'alertFunc on ', d.context);
×
66
        d.exit();
×
67
    });
68
    d.run(function() {
2✔
69
        logger.debug(context, 'alertfunc nsLineRule %j  entity %j ', nsLineRule, entity);
2✔
70
        // We duplicate info in event and event.ev for VR and non-VR action parameters
71
        var event = {
2✔
72
            service: nsLineRule[SERVICE],
73
            subservice: nsLineRule[SUBSERVICE],
74
            ruleName: nsLineRule[NAME],
75
            reportInterval: nsLineRule[REPORT_INTERVAL],
76
            maxTimeDetection: nsLineRule[MAX_TIME_DETECTION],
77
            maxTimeDetectionAttr: nsLineRule[MAX_TIME_DETECTION_ATTR],
78
            reportIntervalAttr: nsLineRule[REPORT_INTERVAL_ATTR],
79
            internalCurrentTime: new Date().toISOString()
80
        };
81
        if (!config.nonSignalByAPI) {
2!
82
            // entity is really a entity doc obtained from mongo
83
            event.id = entity._id.id;
2✔
84
            event.type = entity._id.type;
2✔
85
            logger.debug(context, 'alertfunc event %j ', event);
2✔
86
            // Search for modDate of the entity's attribute
87
            // and copy every attribute (if not in event yet)
88
            // for use in action template
89
            Object.keys(entity.attrs).forEach(function(attrName) {
2✔
90
                if (attrName === nsLineRule[ATTRIBUTE]) {
2!
91
                    try {
2✔
92
                        lastTime = new Date(entity.attrs[attrName].modDate * 1000).toISOString();
2✔
93
                    } catch (ex) {
94
                        myutils.logErrorIf(ex, 'run ', d.context);
×
95
                    }
96
                }
97
                if (event[attrName] === undefined) {
2!
98
                    if (entity.attrs[attrName].type === 'DateTime') {
2!
99
                        event[attrName] = new Date(entity.attrs[attrName].value * 1000).toISOString();
×
100
                    } else {
101
                        event[attrName] = entity.attrs[attrName].value;
2✔
102
                    }
103
                }
104
            });
105
        } else {
106
            // entity is and NGSI object
107
            event.id = entity.id;
×
108
            event.type = entity.type;
×
109
            logger.debug(context, 'alertfunc event %j ', event);
×
110
            // Search for modDate of the entity's attribute
111
            // and copy every attribute (if not in event yet)
112
            // for use in action template
113
            const attrName = nsLineRule[ATTRIBUTE];
×
114
            if (entity[attrName]) {
×
115
                try {
×
116
                    lastTime = entity[attrName].metadata.TimeInstant.value;
×
117
                } catch (ex) {
118
                    myutils.logErrorIf(ex, 'run ', d.context);
×
119
                }
120
                if (event[attrName] === undefined) {
×
121
                    if (entity[attrName].type === 'DateTime') {
×
122
                        event[attrName] = entity[attrName].metadata.TimeInstant.value;
×
123
                    } else {
124
                        event[attrName] = entity[attrName].value;
×
125
                    }
126
                }
127
            }
128
        }
129

130
        logger.debug(context, 'lastTime could be %d', lastTime);
2✔
131
        if (lastTime !== undefined && lastTime !== null) {
2!
132
            event.lastTime = lastTime;
2✔
133
        }
134
        logger.debug(context, 'event available is %j', event);
2✔
135
        var delay;
136
        if (config.isMaster) {
2!
137
            delay = 0;
2✔
138
        } else {
139
            delay = config.slaveDelay;
×
140
        }
141
        setTimeout(function() {
2✔
142
            actions.Do(event, function(err) {
2✔
143
                myutils.logErrorIf(err, 'DoEvent', d.context);
2✔
144
            });
145
        }, delay);
146
    });
147
}
148

149
function checkNoSignal(period) {
150
    var list = nsRulesByInterval[period] || [];
1!
151
    var currentContext = context;
1✔
152
    currentContext.srv = 'n/a';
1✔
153
    currentContext.subsrv = 'n/a';
1✔
154
    logger.debug(currentContext, 'Executing no-signal handler for period of %d (%d rules)', period, list.length);
1✔
155

156
    list.forEach(function(nsrule) {
1✔
157
        currentContext.srv = nsrule[SERVICE];
1✔
158
        currentContext.subsrv = nsrule[SUBSERVICE];
1✔
159
        entitiesStore.FindSilentEntities(
1✔
160
            nsrule[SERVICE],
161
            nsrule[SUBSERVICE],
162
            {
163
                attribute: nsrule[ATTRIBUTE],
164
                id: nsrule[ID],
165
                idRegexp: nsrule[ID_REGEXP],
166
                type: nsrule[TYPE],
167
                reportInterval: nsrule[REPORT_INTERVAL],
168
                maxTimeDetection: nsrule[MAX_TIME_DETECTION],
169
                maxTimeDetectionAttr: nsrule[MAX_TIME_DETECTION_ATTR],
170
                reportIntervalAttr: nsrule[REPORT_INTERVAL_ATTR]
171
            },
172
            alertFunc.bind({}, nsrule),
173
            function(err, data) {
174
                myutils.logErrorIf(err, 'checkNoSignal nsrule %s' % nsrule.name ? nsrule.name : '', currentContext);
1!
175
                logger.debug(currentContext, 'silent entities: %j', data);
1✔
176
            }
177
        );
178
    });
179
}
180

181
function nsr2arr(service, subservice, name, nsr) {
182
    var arrayRule = [];
13✔
183
    arrayRule[SUBSERVICE] = subservice;
13✔
184
    arrayRule[SERVICE] = service;
13✔
185
    arrayRule[NAME] = name;
13✔
186
    arrayRule[ATTRIBUTE] = nsr.attribute;
13✔
187
    arrayRule[ID] = nsr.id;
13✔
188
    arrayRule[ID_REGEXP] = nsr.idRegexp;
13✔
189
    arrayRule[TYPE] = nsr.type;
13✔
190
    arrayRule[REPORT_INTERVAL] = nsr.reportInterval;
13✔
191
    arrayRule[CHECK_INTERVAL] = nsr.checkInterval;
13✔
192
    arrayRule[MAX_TIME_DETECTION] = nsr.maxTimeDetection;
13✔
193
    arrayRule[MAX_TIME_DETECTION_ATTR] = nsr.maxTimeDetectionAttr;
13✔
194
    arrayRule[REPORT_INTERVAL_ATTR] = nsr.reportIntervalAttr;
13✔
195
    return arrayRule;
13✔
196
}
197

198
function addNSRule(service, subservice, name, nsr) {
199
    var arrayRule,
200
        alreadyExists = false,
11✔
201
        intervalAsNum;
202
    context.srv = service;
11✔
203
    context.subsrv = subservice;
11✔
204
    // Verify the interval is valid. It should be as it is checked at rule creation time
205
    // but an invalid modification of DB could cause a "big" problem
206
    intervalAsNum = parseInt(nsr.checkInterval, 10);
11✔
207
    if (isNaN(intervalAsNum)) {
11✔
208
        logger.error(
1✔
209
            context,
210
            util.format('Invalid check interval %s for rule (%s, %s, %s)', nsr.checkInterval, service, subservice, name)
211
        );
212
        return 0;
1✔
213
    }
214
    intervalAsNum *= intervalUnit;
10✔
215
    if (intervalAsNum > MAX_INTERVAL_MS) {
10!
216
        logger.warn(
×
217
            context,
218
            util.format('Check interval %s too big for rule (%s, %s, %s)', nsr.checkInterval, service, subservice, name)
219
        );
220
        intervalAsNum = MAX_INTERVAL_MS;
×
221
    }
222
    if (intervalAsNum < MIN_INTERVAL_MS) {
10✔
223
        logger.warn(
1✔
224
            context,
225
            util.format(
226
                'Check interval %s too small for rule (%s, %s, %s)',
227
                nsr.checkInterval,
228
                service,
229
                subservice,
230
                name
231
            )
232
        );
233
        intervalAsNum = MIN_INTERVAL_MS;
1✔
234
    }
235

236
    arrayRule = nsr2arr(service, subservice, name, nsr);
10✔
237
    nsRulesByInterval[nsr.checkInterval] = nsRulesByInterval[nsr.checkInterval] || [];
10✔
238
    nsRulesByInterval[nsr.checkInterval].forEach(function(element, index, array) {
10✔
239
        if (element[NAME] === name && element[SERVICE] === service && element[SUBSERVICE] === subservice) {
3!
240
            array[index] = arrayRule; //Update rule
×
241
            alreadyExists = true;
×
242
            logger.debug(context, util.format('Updating no-signal rule (%s, %s, %s)', service, subservice, name));
×
243
        }
244
    });
245
    if (!alreadyExists) {
10!
246
        nsRulesByInterval[nsr.checkInterval].push(arrayRule);
10✔
247
        logger.debug(context, util.format('Adding no-signal rule (%s, %s, %s)', service, subservice, name));
10✔
248
    }
249
    if (!checkers.hasOwnProperty(nsr.checkInterval)) {
10✔
250
        logger.info(context, util.format('no-signal rule (%s, %s, %s)', service, subservice, name));
7✔
251
        checkers[nsr.checkInterval] = setInterval(checkNoSignal, intervalAsNum, nsr.checkInterval);
7✔
252
        checkers[nsr.checkInterval].unref();
7✔
253
    }
254
    return intervalAsNum;
10✔
255
}
256

257
function deleteNSRuleIf(predicate) {
258
    Object.keys(nsRulesByInterval).forEach(function(chkInt) {
112✔
259
        var line = nsRulesByInterval[chkInt] || [];
16!
260
        line.forEach(function(element, index) {
16✔
261
            if (predicate(element[SERVICE], element[SUBSERVICE], element[NAME])) {
17✔
262
                line.splice(index, 1);
9✔
263
                if (line.length === 0) {
9✔
264
                    // There are no rules left for this interval
265
                    if (checkers.hasOwnProperty(chkInt)) {
6!
266
                        clearInterval(checkers[chkInt]);
6✔
267
                        delete checkers[chkInt];
6✔
268
                    }
269
                    if (nsRulesByInterval.hasOwnProperty(chkInt)) {
6!
270
                        delete nsRulesByInterval[chkInt];
6✔
271
                    }
272
                }
273
                context.srv = element[SERVICE];
9✔
274
                context.subsrv = element[SUBSERVICE];
9✔
275
                logger.debug(
9✔
276
                    context,
277
                    util.format(
278
                        'Deleting no-signal rule (%s, %s, %s)',
279
                        element[SERVICE],
280
                        element[SUBSERVICE],
281
                        element[NAME]
282
                    )
283
                );
284
            }
285
        });
286
    });
287
}
288

289
function deleteNSRule(service, subservice, name) {
290
    deleteNSRuleIf(function(serviceElement, subserviceElement, nameElement) {
5✔
UNCOV
291
        return serviceElement === service && subserviceElement === subservice && nameElement === name;
×
292
    });
293
}
294

295
function getNSRule(service, subservice, name) {
296
    var intervals = Object.keys(nsRulesByInterval),
8✔
297
        chkInt,
298
        line;
299
    for (var i = 0; i < intervals.length; i++) {
8✔
300
        chkInt = intervals[i];
10✔
301
        line = nsRulesByInterval[chkInt] || [];
10!
302
        for (var j = 0; j < line.length; j++) {
10✔
303
            if (line[j][SERVICE] === service && line[j][SUBSERVICE] === subservice && line[j][NAME] === name) {
12✔
304
                return line[j];
4✔
305
            }
306
        }
307
    }
308
    return null;
4✔
309
}
310

311
function RuleSet() {
312
    this.set = {};
103✔
313
}
314
RuleSet.prototype.add = function(service, subservice, name) {
1✔
315
    var srvObj;
316
    if (this.set[service] === undefined) {
4!
317
        this.set[service] = {};
4✔
318
    }
319
    srvObj = this.set[service];
4✔
320
    if (srvObj[subservice] === undefined) {
4!
321
        srvObj[subservice] = {};
4✔
322
    }
323
    srvObj[subservice][name] = true;
4✔
324
};
325

326
RuleSet.prototype.includes = function(service, subservice, name) {
1✔
327
    return this.set[service] && this.set[service][subservice] && this.set[service][subservice][name] === true;
11✔
328
};
329

330
function refreshAllRules(rules) {
331
    var count = 0,
103✔
332
        ruleSet = new RuleSet(),
103✔
333
        oldRuleArr = [];
103✔
334
    context.srv = 'n/a';
103✔
335
    context.subsrv = 'n/a';
103✔
336
    logger.debug(context, 'Refreshing all no-signal rules');
103✔
337
    rules.forEach(function(rule) {
103✔
338
        if (rule.nosignal) {
15✔
339
            //check if any checkInterval has been modified, and delete if so.
340
            oldRuleArr = getNSRule(rule.service, rule.subservice, rule.name);
4✔
341
            deleteNSRuleIf(function() {
4✔
342
                return oldRuleArr && oldRuleArr[CHECK_INTERVAL] !== rule.nosignal.checkInterval;
6✔
343
            });
344
            if (addNSRule(rule.service, rule.subservice, rule.name, rule.nosignal) > 0) {
4!
345
                count++;
4✔
346
                ruleSet.add(rule.service, rule.subservice, rule.name);
4✔
347
            }
348
        }
349
    });
350
    // remove old rules not in the new set
351
    deleteNSRuleIf(function(srv, subsrv, nm) {
103✔
352
        return !ruleSet.includes(srv, subsrv, nm);
11✔
353
    });
354
    logger.debug(
103✔
355
        context,
356
        util.format('no-signal rules %d/%d, checkers: %d', count, rules.length, Object.keys(checkers).length)
357
    );
358
}
359

360
module.exports.AddNSRule = addNSRule;
1✔
361
module.exports.DeleteNSRule = deleteNSRule;
1✔
362
module.exports.RefreshAllRules = refreshAllRules;
1✔
363
module.exports.GetNSArrRule = getNSRule;
1✔
364
module.exports.CheckNoSignal = checkNoSignal;
1✔
365
module.exports.Nsr2Arr = nsr2arr;
1✔
366
module.exports.getMinIntervalMs = function() {
1✔
367
    return MIN_INTERVAL_MS;
2✔
368
};
369
module.exports.getIntervalUnit = function() {
1✔
370
    return intervalUnit;
2✔
371
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc