diff --git a/src/routes/test/tasks-test.js b/src/routes/test/tasks-test.js new file mode 100644 index 000000000..5ec30a0cb --- /dev/null +++ b/src/routes/test/tasks-test.js @@ -0,0 +1,140 @@ +'use strict'; + +/* global it:false */ +/* global describe:false */ +/* global before:false */ +/* global after:false */ + +var async = require('async'), + config = require('../../config.js'), + database = require('../../database.js'), + expect = require('expect.js'), + server = require('../../server.js'), + superagent = require('superagent'), + tasks = require('../../tasks.js'); + +var SERVER_URL = 'http://localhost:' + config.get('port'); + +var USERNAME = 'superadmin', PASSWORD = 'Foobar?1337', EMAIL ='silly@me.com'; +var token = null; +let taskId = null; + +function setup(done) { + config._reset(); + config.setFqdn('example-tasks-test.com'); + config.setAdminFqdn('my.example-tasks-test.com'); + + async.series([ + server.start.bind(null), + database._clear.bind(null), + + function createAdmin(callback) { + superagent.post(SERVER_URL + '/api/v1/cloudron/activate') + .query({ setupToken: 'somesetuptoken' }) + .send({ username: USERNAME, password: PASSWORD, email: EMAIL }) + .end(function (error, result) { + expect(result).to.be.ok(); + expect(result.statusCode).to.eql(201); + + // stash token for further use + token = result.body.token; + + callback(); + }); + } + ], done); +} + +function cleanup(done) { + database._clear(function (error) { + expect(!error).to.be.ok(); + + server.stop(done); + }); +} + +let AUDIT_SOURCE = { ip: '1.2.3.4' }; + +describe('Tasks API', function () { + before(setup); + after(cleanup); + + it('can get task', function (done) { + let taskId = null; + let task = tasks.startTask(tasks._TASK_IDENTITY, [ 'ping' ], AUDIT_SOURCE); + task.on('error', done); + task.on('start', (tid) => { taskId = tid; }); + + task.on('finish', function (error, result) { + superagent.get(SERVER_URL + '/api/v1/tasks/' + taskId) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.percent).to.be(100); + expect(res.body.active).to.be(false); // finished + expect(res.body.result).to.be('ping'); + expect(res.body.errorMessage).to.be(null); + done(); + }); + }); + }); + + it('can get logs', function (done) { + let taskId = null; + let task = tasks.startTask(tasks._TASK_CRASH, [ 'ping' ], AUDIT_SOURCE); + task.on('error', done); + task.on('start', (tid) => { taskId = tid; }); + + task.on('finish', function (error) { + superagent.get(SERVER_URL + '/api/v1/tasks/' + taskId + '/logs') + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + done(); + }); + }); + }); + + it('cannot stop inactive task', function (done) { + let taskId = null; + let task = tasks.startTask(tasks._TASK_IDENTITY, [ 'ping' ], AUDIT_SOURCE); + task.on('error', done); + task.on('start', (tid) => { taskId = tid; }); + + task.on('finish', function (error) { + superagent.post(SERVER_URL + '/api/v1/tasks/' + taskId + '/stop') + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(409); + done(); + }); + }); + }); + + + it('can stop task', function (done) { + let taskId = null; + let task = tasks.startTask(tasks._TASK_SLEEP, [ 10000 ], AUDIT_SOURCE); + task.on('error', done); + task.on('start', (tid) => { + taskId = tid; + superagent.post(SERVER_URL + '/api/v1/tasks/' + taskId + '/stop') + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(204); + }); + }); + task.on('finish', () => { + superagent.get(SERVER_URL + '/api/v1/tasks/' + taskId) + .query({ access_token: token }) + .end(function (err, res) { + expect(res.statusCode).to.equal(200); + expect(res.body.percent).to.be(100); + expect(res.body.active).to.be(false); // finished + expect(res.body.result).to.be(null); + expect(res.body.errorMessage).to.contain('signal SIGTERM'); + done(); + }); + }); + }); +}); diff --git a/src/tasks.js b/src/tasks.js index 590e030fe..f85c55f7f 100644 --- a/src/tasks.js +++ b/src/tasks.js @@ -22,6 +22,7 @@ exports = module.exports = { _TASK_IDENTITY: '_identity', _TASK_CRASH: '_crash', _TASK_ERROR: '_error', + _TASK_SLEEP: '_sleep' }; let assert = require('assert'), diff --git a/src/taskworker.js b/src/taskworker.js index 1c272e682..76430a2b1 100755 --- a/src/taskworker.js +++ b/src/taskworker.js @@ -19,7 +19,8 @@ const TASKS = { // indexed by task type _identity: (arg, progressCallback, callback) => callback(null, arg), _error: (arg, progressCallback, callback) => callback(new Error(`Failed for arg: ${arg}`)), - _crash: (arg) => { throw new Error(`Crashing for arg: ${arg}`); } + _crash: (arg) => { throw new Error(`Crashing for arg: ${arg}`); }, + _sleep: (arg) => setTimeout(process.exit, arg) }; process.on('SIGTERM', function () { diff --git a/src/test/tasks-test.js b/src/test/tasks-test.js index 4e657ff6f..d206327e3 100644 --- a/src/test/tasks-test.js +++ b/src/test/tasks-test.js @@ -60,7 +60,7 @@ describe('task', function () { }); }); - it('can run valid task - crash', function (done) { + it('can get logs of crash', function (done) { let taskId = null; let task = tasks.startTask(tasks._TASK_CRASH, [ 'ping' ], AUDIT_SOURCE); task.on('error', done); @@ -77,4 +77,21 @@ describe('task', function () { }); }); + it('can stop task', function (done) { + let taskId = null; + let task = tasks.startTask(tasks._TASK_SLEEP, [ 10000 ], AUDIT_SOURCE); + task.on('error', done); + task.on('start', (tid) => { + taskId = tid; + tasks.stopTask(taskId, AUDIT_SOURCE, () => {}); + }); + task.on('finish', function (error, result) { + expect(error).to.be.ok(); + expect(error.message).to.contain('SIGTERM'); + expect(result).to.be(null); + expect(taskId).to.be.ok(); + done(); + }); + }); + });