Node.js CronJob execution when using mocha for testing - node.js

So, I've got some js code which is a slackbot which supposed to simply listen and parse the date provided, then start a CronJob to run a certain function according to the cron or date format provided. Something like this.
var CronJob = require ('cron').CronJob;
...
robot.respond(date, function (msg)) {
if(!isValidDate(date)) msg.reply("not a valid date);
var interval = isCronDate(date) ? date : new Date(date);
msg.reply("Job about to be scheduled.")
var schedule = new CronJob(interval, processDataOnDate(), function() { msg.reply("hello") }, true);
}
I've got a coffee file testing this code, and I expect certain responses back, but I do NOT expect the cron job to be executed based on the date I've provided in my test code. However, it is. Is this normal? Does mocha force the code to finish execution due to the fact that this is a unit test, or am I doing something wrong? I am running this to execute my unit test.
mocha --compilers coffee:coffee-script/register
For further information I am running this as a slackbot, so this is all done in the form of 'say' and 'reply.' One of my tests looks like this.
beforeEach ->
yield #room.user.say 'bob', '#bot schedule at 2017-05-25 18:00:00'
expect(#room.messages).to.eql [
['bob', 'bot schedule at 2017-05-25 18:00:00']
['bot', 'Job about to be scheduled']
]
The test fails and informs me that the actual result included the message 'hello' from the bot, despite the fact that the date I've provided in my test is in the future.

The last parameter when you're initializing your CronJob indicates that it should execute the job immediately:
new CronJob(interval, processDataOnDate(), function() { msg.reply("hello") }, true);
That will cause the job to execute immediately, even though your execution date is in the future.
See: https://www.npmjs.com/package/cron#api

Related

Stopping and starting execution of cron-job-manager (node-cron) upon condition

So, I found an old question about this (here: How to stop a node cron job) but it doesn't work for me (and I can't realize the reason why).
I'm using cron-job-manager (since I plan to use more than one scheduled job at the same time) but as far as I know it should be built on node-cron (but I'm a newbie, so...)
So, I'm asking again: how do I deal with starting and stopping a cron job under certain conditions?
I'm actually doing this for a discord bot: basically, the user input a command for starting and one for stopping.
First try was something like:
job = cron('keyTask','* * * * * *', ()=>{
//Do the actual job
},
{
start: false,
timeZone:"Europe/London",
});
switch args[1]
case go:
job.start();
break;
case stop:
job.stop();
break;
This start the job successfully when the user gives the 'go' command, but when it gives the 'stop' command, the scheduled job just won't stop.
Second try is:
var x = args [1];
new cron('keyTask' , '* * * * * *', job(doTheThing(x)) ,
{
start: false,
timeZone:"Europe/London",
});
Where job() is a function defined beforehand that contains the actual job and DoTheThing() is something that gives true or false depending on what the user is saying in input.
This executes the scheduled job once and then stops.
Somehow I suspect that the issue here is related to the fact that I'm defining function externally, while in most examples I saw the function is always written within the cron().
So, I'm out of ideas: thanks in advance for any help!

Schedule Agenda job to run every day at midnight

I am new to Agenda jobs (https://github.com/rschmukler/agenda) and fail to understand how I can schedule a job to run every day at a given time. I have tried the following:
agenda.every('everyday at 00:01', ...) - runs only one time.
agenda.schedule('at 00:01', ...) and then job.repeatEvery('1 day') but without much effect.
Agenda internally uses Human Interval which is inspired by date. i checked demo of date here and found that everyday at 00:00 is accepted but could not use that very well with Agenda.
Any help will be appreciated. Thank you.
//You can use something like this...
agenda.define('first', (job, done) => {
Somefunction()
job.repeatEvery('24 hours', {
skipImmediate: true
});
job.save()
done()
})
agenda.start()
agenda.on('ready', function () {
agenda.schedule('everyday at 00:00','first')
})
// This worked for me..
I think you can use repeatAt() for this purpose. Like repeatAt('12am')
or you can also use 24 hour format:- repeatAt('00:00')
The solution proposed by others, I think is a bit funky as calling job.repeatEvery() within the job handler feels kind of out of its place.
agenda.every accepts cron format, therefore you can apply it to any defined job and run the handler according to the cron sequence
You have a defined job:
agenda.define('do-something', async (job, done) => {
// Doing some heavy async stuff here
async heavyStuff();
done();
})
After server initialisation you can call it anywhere in your code to setup a repeated job. Just make sure await agenda.start() was already called and agenda has an established mongo connection
await agenda.every("0 1 * * *", "do-something");
This will run the do-something job and call the handler every day at 00:01am

Analyse code coverage of a nodejs app during a crash recover story

I am actually trying to reach the highest score of code coverage for my nodeJS app, I am using Mocha + Chai + Istanbul to ensure this code coverage.
Part of my code's app is dedicated to recover a potential service interruption, to do so most of app objects are serialized real time in Redis.
So when the app start for the first time, I am exclusively loading data from mongoDB. After a crash recovery, I am also loading data from Redis. Obviously my app is not using the same part of the code to perform this two kind of initialization.
For this reason Istanbul dead-code report is not accurate and differ if I am running my test in the 1st or the 2nd case.
I am looking for a way to simulate a process interruption without killing Istanbul process to be able to get a complete Istanbul report.
I tried to solved it by using child_process :
var masterLogger = require("./storage/file-logger").master;
const exec = require("child_process").exec;
var redis_flush = exec("redis-cli -n 6 flushall");
var srv1;
var srv2;
redis_flush.on("close", function() {
masterLogger.fatal("Redis clear");
redis_flush = null;
masterLogger.fatal("Starting SRV1");
srv1 = exec("npm test");
srv1.on("close", function() {
masterLogger.fatal("SRV1 killed");
srv1 = null;
masterLogger.fatal("Starting SRV2");
srv2 = exec("npm test");
srv2.on("close", function() {
masterLogger.fatal("SRV2 killed");
srv2 = null;
});
});
});
process.on("SIGINT", function() {
if (redis_flush)
redis_flush.kill();
else if (srv1)
srv1.kill();
else if (srv2)
srv2.kill();
else
process.exit(0);
});
But Istanbul is providing a code-coverage report only for this part of code (Where I reached 100% ^^)...
NB: npm test -> Start my app with a test env
Best regards
After more research on this issue, I realized it was probably easier to "concatenate" the result of two distinct execution.
And apparently the Istanbul team thought about it ->
Look at the last answer of this github ticket
This solution gives me a way to generate multiple coverage files and then generate a single report.

Queue up javascript code in a single process

Lets say I have a bunch of tasks in an object, each with a date object. I was wondering if it's even possible to have tasks within the object be run within a single process and trigger when the date is called.
Here's an example:
var tasks = [
"when": "1501121620",
"what": function(){
console.log("hello world");
},
"when": "1501121625",
"what": function(){
console.log("hello world x2");
},
]
I'm fine with having these stored within a database and the what script being evaled from a string. I need a point in the right direction. I've never seen anything like this in the node world.
I'm thinking about using hotload and using the file system so I don't need to deal with databases.
Should I just look into setInterval or is there something out there that is more sophisticated? I know things like cron exist, the thing is I need all of these tasks to occur within an already existing running process. I need to be able to add a new task to the queue without ending the process.
To add a little context I need some way of queuing up socket.io .emit() functions.
Do not reinvent the wheel. Use cron package from npm. He is written pure on js (using second variant from bellow). So all of these tasks will occur within an already existing running process. For example your can create CronJob like this:
var CronJob = require('cron').CronJob;
var job = new CronJob(1421110908157);
job.addCallback(function() { /* some stuff to do */ });
In pure javascript you can do it only through setTimeout and setInterval methods. There are two variants:
1) Set interval callback, which will check your task queue and execute callbacks in appropriate time:
setInterval(function() {
for (var i = 0; ii = tasks.length; ++i) {
var task = tasks[i];
if (task.when*1000 < Date.now()) {
task.what();
tasks.splice(i,1);
--i;
}
};
}, 1000);
As you see accuracy of callback calling time will be dependent on interval time. Less interval time => more accuracy, but also more CPU usage.
2) Create wrapper around your tasks. So when you want to add new task you're calling some method addTask, that will be calling setTimeout with your task callback. Beware that maximum time for setTimeout is 2147483647ms (around 25 days). So if your time exceeds max time, you must set timeout on the maximum time with callback which will be set new timeout with remaining time. For example:
var MAX_TIME = 2147483647;
function addTask(task) {
if (task.when*1000 < MAX_TIME) {
setTimeout(task.what, task.when);
}
else {
task.when -= MAX_TIME/1000;
setTimeout(addTask.bind(null, task), MAX_TIME);
}
}

How to run cleanup with vows.js?

I'm using Vows.js to test some node.js which is creating records in a database. As a result of this it creates some test records in the database. I'd like to remove these records once the tests have run. Is there a way to run a cleanup function when a batch of tests is run in Vows?
You can define the teardown function in your context that is executed once all the tests in your context are run.
vows.describe('Foo').addBatch({
'A Context' : {
topic : { foo: 'bar' },
'it works' : function (topic) { assert.equal(topic.foo, "bar"); },
teardown : function (topic) { topic.foo = "baz" }
}
});
You can see this in Vows own tests.
If it were me, I would use a separate test database when running automated tests, and empty that database before each test run.
There's an open pull request for vows implementing afterSuite:
https://github.com/phstc/vows/commit/d5b40e85e924e06cca560b4d8d6a264528bbab2b

Resources