From 2c1d672904f246ec5b247b0823c2fc190eabf5b4 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 16 Feb 2021 00:29:17 -0800 Subject: [PATCH 1/5] Fix error when a not yet inserted job is updated --- spec/CloudCode.spec.js | 4 +++- src/StatusHandler.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index 3153920d36..e2c4b8c843 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -1549,7 +1549,9 @@ describe('Cloud Code', () => { describe('cloud jobs', () => { it('should define a job', done => { expect(() => { - Parse.Cloud.job('myJob', () => {}); + Parse.Cloud.job('myJob', ({ message }) => { + message('Hello, world!!!'); + }); }).not.toThrow(); request({ diff --git a/src/StatusHandler.js b/src/StatusHandler.js index 45010f3847..102643b64a 100644 --- a/src/StatusHandler.js +++ b/src/StatusHandler.js @@ -41,7 +41,7 @@ function statusHandler(className, database) { function update(where, object) { lastPromise = lastPromise.then(() => { - return database.update(className, where, object); + return database.update(className, where, object, { upsert: true }); }); return lastPromise; } From 595e4c787f8eb2fd1e59c147a51c0cd488249634 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Tue, 16 Feb 2021 00:36:25 -0800 Subject: [PATCH 2/5] Add entry to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b06ddcff8b..8768a2051e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ ___ - IMPROVE: Parse Server is from now on continuously tested against all recent Node.js versions that have not reached their end-of-life support date. [7161](https://github.com/parse-community/parse-server/pull/7177). Thanks to [Manuel Trezza](https://github.com/mtrezza). - IMPROVE: Optimize queries on classes with pointer permissions. [#7061](https://github.com/parse-community/parse-server/pull/7061). Thanks to [Pedro Diaz](https://github.com/pdiaz) - IMPROVE: Parse Server will from now on be continuously tested against all relevant Postgres versions (minor versions). Added Postgres compatibility table to Parse Server docs. [#7176](https://github.com/parse-community/parse-server/pull/7176). Thanks to [Corey Baker](https://github.com/cbaker6). +- FIX: Fix error when a not yet inserted job is updated [#7196](https://github.com/parse-community/parse-server/pull/7196). Thanks to [Antonio Davi Macedo Coelho de Castro](https://github.com/davimacedo). - FIX: request.context for afterFind triggers. [#7078](https://github.com/parse-community/parse-server/pull/7078). Thanks to [dblythy](https://github.com/dblythy) - FIX: Winston Logger interpolating stdout to console [#7114](https://github.com/parse-community/parse-server/pull/7114). Thanks to [dplewis](https://github.com/dplewis) From cf83992065d5b6639d8a898ffd650a25c0538385 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Thu, 18 Feb 2021 00:16:47 -0800 Subject: [PATCH 3/5] revert the upsert change and fix the test --- spec/CloudCode.spec.js | 54 ++++++++++++++++++++++++------------------ src/StatusHandler.js | 2 +- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index e2c4b8c843..21ad022608 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -1547,30 +1547,38 @@ describe('Cloud Code', () => { }); describe('cloud jobs', () => { - it('should define a job', done => { - expect(() => { - Parse.Cloud.job('myJob', ({ message }) => { - message('Hello, world!!!'); - }); - }).not.toThrow(); + for (let x = 0; x < 1000; x++) { + fit('should define a job', done => { + expect(() => { + Parse.Cloud.job('myJob', ({ message }) => { + message('Hello, world!!!'); + }); + }).not.toThrow(); - request({ - method: 'POST', - url: 'http://localhost:8378/1/jobs/myJob', - headers: { - 'X-Parse-Application-Id': Parse.applicationId, - 'X-Parse-Master-Key': Parse.masterKey, - }, - }).then( - () => { - done(); - }, - err => { - fail(err); - done(); - } - ); - }); + request({ + method: 'POST', + url: 'http://localhost:8378/1/jobs/myJob', + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Master-Key': Parse.masterKey, + }, + }) + .then(async response => { + const jobStatusId = response.headers['x-parse-job-status-id']; + const checkJobStatus = async () => { + const jobStatus = await new Parse.Query('_JobStatus').get(jobStatusId, { + useMasterKey: true, + }); + return jobStatus.get('finishedAt') && jobStatus.get('message') === 'Hello, world!!!'; + }; + while (!(await checkJobStatus())) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + }) + .then(done) + .catch(done.fail); + }); + } it('should not run without master key', done => { expect(() => { diff --git a/src/StatusHandler.js b/src/StatusHandler.js index 102643b64a..45010f3847 100644 --- a/src/StatusHandler.js +++ b/src/StatusHandler.js @@ -41,7 +41,7 @@ function statusHandler(className, database) { function update(where, object) { lastPromise = lastPromise.then(() => { - return database.update(className, where, object, { upsert: true }); + return database.update(className, where, object); }); return lastPromise; } From 703c396bbf3ed94a01b82ddccdc00480ad0332cc Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Thu, 18 Feb 2021 00:17:58 -0800 Subject: [PATCH 4/5] Revert the change so job execute a single time --- spec/CloudCode.spec.js | 58 ++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index 21ad022608..ec368c9a9b 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -1547,38 +1547,36 @@ describe('Cloud Code', () => { }); describe('cloud jobs', () => { - for (let x = 0; x < 1000; x++) { - fit('should define a job', done => { - expect(() => { - Parse.Cloud.job('myJob', ({ message }) => { - message('Hello, world!!!'); - }); - }).not.toThrow(); + it('should define a job', done => { + expect(() => { + Parse.Cloud.job('myJob', ({ message }) => { + message('Hello, world!!!'); + }); + }).not.toThrow(); - request({ - method: 'POST', - url: 'http://localhost:8378/1/jobs/myJob', - headers: { - 'X-Parse-Application-Id': Parse.applicationId, - 'X-Parse-Master-Key': Parse.masterKey, - }, + request({ + method: 'POST', + url: 'http://localhost:8378/1/jobs/myJob', + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Master-Key': Parse.masterKey, + }, + }) + .then(async response => { + const jobStatusId = response.headers['x-parse-job-status-id']; + const checkJobStatus = async () => { + const jobStatus = await new Parse.Query('_JobStatus').get(jobStatusId, { + useMasterKey: true, + }); + return jobStatus.get('finishedAt') && jobStatus.get('message') === 'Hello, world!!!'; + }; + while (!(await checkJobStatus())) { + await new Promise(resolve => setTimeout(resolve, 100)); + } }) - .then(async response => { - const jobStatusId = response.headers['x-parse-job-status-id']; - const checkJobStatus = async () => { - const jobStatus = await new Parse.Query('_JobStatus').get(jobStatusId, { - useMasterKey: true, - }); - return jobStatus.get('finishedAt') && jobStatus.get('message') === 'Hello, world!!!'; - }; - while (!(await checkJobStatus())) { - await new Promise(resolve => setTimeout(resolve, 100)); - } - }) - .then(done) - .catch(done.fail); - }); - } + .then(done) + .catch(done.fail); + }); it('should not run without master key', done => { expect(() => { From bc771fa191d0e3876037f888f1becd9497dd5d97 Mon Sep 17 00:00:00 2001 From: Antonio Davi Macedo Coelho de Castro Date: Thu, 18 Feb 2021 00:43:41 -0800 Subject: [PATCH 5/5] Fix other tests with potential similar problem --- spec/CloudCode.spec.js | 129 ++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 65 deletions(-) diff --git a/spec/CloudCode.spec.js b/spec/CloudCode.spec.js index ec368c9a9b..c726bfd89e 100644 --- a/spec/CloudCode.spec.js +++ b/spec/CloudCode.spec.js @@ -1565,9 +1565,7 @@ describe('Cloud Code', () => { .then(async response => { const jobStatusId = response.headers['x-parse-job-status-id']; const checkJobStatus = async () => { - const jobStatus = await new Parse.Query('_JobStatus').get(jobStatusId, { - useMasterKey: true, - }); + const jobStatus = await getJobStatus(jobStatusId); return jobStatus.get('finishedAt') && jobStatus.get('message') === 'Hello, world!!!'; }; while (!(await checkJobStatus())) { @@ -1610,7 +1608,6 @@ describe('Cloud Code', () => { expect(typeof req.jobId).toBe('string'); expect(typeof req.message).toBe('function'); expect(typeof res).toBe('undefined'); - done(); }); }).not.toThrow(); @@ -1621,13 +1618,19 @@ describe('Cloud Code', () => { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, }, - }).then( - () => {}, - err => { - fail(err); - done(); - } - ); + }) + .then(async response => { + const jobStatusId = response.headers['x-parse-job-status-id']; + const checkJobStatus = async () => { + const jobStatus = await getJobStatus(jobStatusId); + return jobStatus.get('finishedAt'); + }; + while (!(await checkJobStatus())) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + }) + .then(done) + .catch(done.fail); }); it('should run with master key basic auth', done => { @@ -1638,25 +1641,30 @@ describe('Cloud Code', () => { expect(typeof req.jobId).toBe('string'); expect(typeof req.message).toBe('function'); expect(typeof res).toBe('undefined'); - done(); }); }).not.toThrow(); request({ method: 'POST', url: `http://${Parse.applicationId}:${Parse.masterKey}@localhost:8378/1/jobs/myJob`, - }).then( - () => {}, - err => { - fail(err); - done(); - } - ); + }) + .then(async response => { + const jobStatusId = response.headers['x-parse-job-status-id']; + const checkJobStatus = async () => { + const jobStatus = await getJobStatus(jobStatusId); + return jobStatus.get('finishedAt'); + }; + while (!(await checkJobStatus())) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + }) + .then(done) + .catch(done.fail); }); it('should set the message / success on the job', done => { Parse.Cloud.job('myJob', req => { - const promise = req + return req .message('hello') .then(() => { return getJobStatus(req.jobId); @@ -1665,21 +1673,6 @@ describe('Cloud Code', () => { expect(jobStatus.get('message')).toEqual('hello'); expect(jobStatus.get('status')).toEqual('running'); }); - promise - .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(); - }); - return promise; }); request({ @@ -1689,32 +1682,28 @@ describe('Cloud Code', () => { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, }, - }).then( - () => {}, - err => { - fail(err); - done(); - } - ); + }) + .then(async response => { + const jobStatusId = response.headers['x-parse-job-status-id']; + const checkJobStatus = async () => { + const jobStatus = await getJobStatus(jobStatusId); + return ( + jobStatus.get('finishedAt') && + jobStatus.get('message') === 'hello' && + jobStatus.get('status') === 'succeeded' + ); + }; + while (!(await checkJobStatus())) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + }) + .then(done) + .catch(done.fail); }); it('should set the failure on the job', done => { - Parse.Cloud.job('myJob', req => { - const promise = Promise.reject('Something went wrong'); - new Promise(resolve => setTimeout(resolve, 200)) - .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(); - }); - return promise; + Parse.Cloud.job('myJob', () => { + return Promise.reject('Something went wrong'); }); request({ @@ -1724,13 +1713,23 @@ describe('Cloud Code', () => { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, }, - }).then( - () => {}, - err => { - fail(err); - done(); - } - ); + }) + .then(async response => { + const jobStatusId = response.headers['x-parse-job-status-id']; + const checkJobStatus = async () => { + const jobStatus = await getJobStatus(jobStatusId); + return ( + jobStatus.get('finishedAt') && + jobStatus.get('message') === 'Something went wrong' && + jobStatus.get('status') === 'failed' + ); + }; + while (!(await checkJobStatus())) { + await new Promise(resolve => setTimeout(resolve, 100)); + } + }) + .then(done) + .catch(done.fail); }); it('should set the failure message on the job error', async () => {