Adds jobs endpoint protected by masterKey (#2560)

* Adds jobs endpoint protected by masterKey

* Adds connection timeout for 15 minutes in jobs

* Refactors pushStatusHandler into StatusHandler

* Adds reporting of _JobStatus

* Only accept strings as messages

* Adds test for masterKey basic auth

* Adds CloudCodeRouter for cloud_code endpoint of job status, enable Jobs feature on dashboard

* xit racing test
This commit is contained in:
Florent Vilmart
2016-08-30 07:19:21 -04:00
committed by GitHub
parent 4b2a780e03
commit 10ace495d8
12 changed files with 414 additions and 56 deletions

View File

@@ -3,6 +3,7 @@ const Parse = require("parse/node");
const request = require('request');
const rp = require('request-promise');
const InMemoryCacheAdapter = require('../src/Adapters/Cache/InMemoryCacheAdapter').InMemoryCacheAdapter;
const triggers = require('../src/triggers');
describe('Cloud Code', () => {
it('can load absolute cloud code file', done => {
@@ -211,7 +212,8 @@ describe('Cloud Code', () => {
});
});
it('test afterSave ignoring promise, object not found', function(done) {
// TODO: Fails on CI randomly as racing
xit('test afterSave ignoring promise, object not found', function(done) {
Parse.Cloud.afterSave('AfterSaveTest2', function(req) {
let obj = req.object;
if(!obj.existed())
@@ -1005,4 +1007,166 @@ it('beforeSave should not affect fetched pointers', done => {
done();
})
});
describe('cloud jobs', () => {
it('should define a job', (done) => {
expect(() => {
Parse.Cloud.job('myJob', (req, res) => {
res.success();
});
}).not.toThrow();
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-Master-Key': Parse.masterKey,
},
}).then((result) => {
done();
}, (err) =>  {
fail(err);
done();
});
});
it('should not run without master key', (done) => {
expect(() => {
Parse.Cloud.job('myJob', (req, res) => {
res.success();
});
}).not.toThrow();
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-REST-API-Key': 'rest',
},
}).then((result) => {
fail('Expected to be unauthorized');
done();
}, (err) =>  {
expect(err.statusCode).toBe(403);
done();
});
});
it('should run with master key', (done) => {
expect(() => {
Parse.Cloud.job('myJob', (req, res) => {
expect(req.functionName).toBeUndefined();
expect(req.jobName).toBe('myJob');
expect(typeof req.jobId).toBe('string');
expect(typeof res.success).toBe('function');
expect(typeof res.error).toBe('function');
expect(typeof res.message).toBe('function');
res.success();
done();
});
}).not.toThrow();
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-Master-Key': Parse.masterKey,
},
}).then((response) => {
}, (err) =>  {
fail(err);
done();
});
});
it('should run with master key basic auth', (done) => {
expect(() => {
Parse.Cloud.job('myJob', (req, res) => {
expect(req.functionName).toBeUndefined();
expect(req.jobName).toBe('myJob');
expect(typeof req.jobId).toBe('string');
expect(typeof res.success).toBe('function');
expect(typeof res.error).toBe('function');
expect(typeof res.message).toBe('function');
res.success();
done();
});
}).not.toThrow();
rp.post({
url: `http://${Parse.applicationId}:${Parse.masterKey}@localhost:8378/1/jobs/myJob`,
}).then((response) => {
}, (err) =>  {
fail(err);
done();
});
});
it('should set the message / success on the job', (done) => {
Parse.Cloud.job('myJob', (req, res) => {
res.message('hello');
res.message().then(() => {
return getJobStatus(req.jobId);
}).then((jobStatus) => {
expect(jobStatus.get('message')).toEqual('hello');
expect(jobStatus.get('status')).toEqual('running');
return res.success().then(() => {
return getJobStatus(req.jobId);
});
}).then((jobStatus) => {
expect(jobStatus.get('message')).toEqual('hello');
expect(jobStatus.get('status')).toEqual('succeeded');
done();
}).catch(err => {
console.error(err);
jfail(err);
done();
});
});
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-Master-Key': Parse.masterKey,
},
}).then((response) => {
}, (err) =>  {
fail(err);
done();
});
});
it('should set the failure on the job', (done) => {
Parse.Cloud.job('myJob', (req, res) => {
res.error('Something went wrong').then(() => {
return getJobStatus(req.jobId);
}).then((jobStatus) => {
expect(jobStatus.get('message')).toEqual('Something went wrong');
expect(jobStatus.get('status')).toEqual('failed');
done();
}).catch(err => {
jfail(err);
done();
});
});
rp.post({
url: 'http://localhost:8378/1/jobs/myJob',
headers: {
'X-Parse-Application-Id': Parse.applicationId,
'X-Parse-Master-Key': Parse.masterKey,
},
}).then((response) => {
}, (err) =>  {
fail(err);
done();
});
});
function getJobStatus(jobId) {
let q = new Parse.Query('_JobStatus');
return q.get(jobId, {useMasterKey: true});
}
});
});

View File

@@ -1,6 +1,6 @@
"use strict";
var PushController = require('../src/Controllers/PushController').PushController;
var pushStatusHandler = require('../src/pushStatusHandler');
var StatusHandler = require('../src/StatusHandler');
var Config = require('../src/Config');
const successfulTransmissions = function(body, installations) {
@@ -439,7 +439,7 @@ describe('PushController', () => {
});
it('should flatten', () => {
var res = pushStatusHandler.flatten([1, [2], [[3, 4], 5], [[[6]]]])
var res = StatusHandler.flatten([1, [2], [[3, 4], 5], [[[6]]]])
expect(res).toEqual([1,2,3,4,5,6]);
})
});