diff --git a/package.json b/package.json index b96c6366..8b163d92 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,8 @@ "build": "babel src/ -d lib/ --copy-files", "watch": "babel --watch src/ -d lib/ --copy-files", "pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} mongodb-runner start", - "test": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} TESTING=1 jasmine", + "testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} TESTING=1 jasmine", + "test": "npm run testonly", "posttest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} mongodb-runner stop", "coverage": "npm run pretest && cross-env MONGODB_VERSION=${MONGODB_VERSION:=4.0.4} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} MONGODB_STORAGE_ENGINE=${MONGODB_STORAGE_ENGINE:=mmapv1} TESTING=1 nyc jasmine && npm run posttest", "start": "node ./bin/parse-server", diff --git a/spec/ParseServerRESTController.spec.js b/spec/ParseServerRESTController.spec.js index 11c23bdd..b3b8ea36 100644 --- a/spec/ParseServerRESTController.spec.js +++ b/spec/ParseServerRESTController.spec.js @@ -190,10 +190,90 @@ describe('ParseServerRESTController', () => { path: '/1/classes/MyObject', body: { key: 10 }, }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, ], transaction: true, }).catch(error => { - expect(error.message).toBeDefined(); + expect(error).toBeDefined(); const query = new Parse.Query('MyObject'); query.find().then(results => { expect(results.length).toBe(0); @@ -231,6 +311,86 @@ describe('ParseServerRESTController', () => { path: '/1/classes/MyObject2', body: { key: 10 }, }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, ], transaction: true, }); @@ -296,13 +456,13 @@ describe('ParseServerRESTController', () => { 'value2', ]); - expect(databaseAdapter.createObject.calls.count()).toBe(5); + expect(databaseAdapter.createObject.calls.count()).toBe(13); let transactionalSession; let transactionalSession2; let myObjectDBCalls = 0; let myObject2DBCalls = 0; let myObject3DBCalls = 0; - for (let i = 0; i < 5; i++) { + for (let i = 0; i < 13; i++) { const args = databaseAdapter.createObject.calls.argsFor(i); switch (args[0]) { case 'MyObject': @@ -318,7 +478,11 @@ describe('ParseServerRESTController', () => { break; case 'MyObject2': myObject2DBCalls++; - transactionalSession2 = args[3]; + if (!transactionalSession2) { + transactionalSession2 = args[3]; + } else { + expect(transactionalSession2).toBe(args[3]); + } if (transactionalSession) { expect(transactionalSession).not.toBe(args[3]); } @@ -330,7 +494,7 @@ describe('ParseServerRESTController', () => { } } expect(myObjectDBCalls).toEqual(2); - expect(myObject2DBCalls).toEqual(1); + expect(myObject2DBCalls).toEqual(9); expect(myObject3DBCalls).toEqual(2); }); }); diff --git a/spec/batch.spec.js b/spec/batch.spec.js index 68ee0c01..c225be32 100644 --- a/spec/batch.spec.js +++ b/spec/batch.spec.js @@ -251,6 +251,86 @@ describe('batch', () => { path: '/1/classes/MyObject', body: { key: 10 }, }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject', + body: { key: 10 }, + }, ], transaction: true, }), @@ -297,6 +377,86 @@ describe('batch', () => { path: '/1/classes/MyObject2', body: { key: 10 }, }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 'value1' }, + }, + { + method: 'POST', + path: '/1/classes/MyObject2', + body: { key: 10 }, + }, ], transaction: true, }), @@ -373,13 +533,13 @@ describe('batch', () => { 'value2', ]); - expect(databaseAdapter.createObject.calls.count()).toBe(5); + expect(databaseAdapter.createObject.calls.count()).toBe(13); let transactionalSession; let transactionalSession2; let myObjectDBCalls = 0; let myObject2DBCalls = 0; let myObject3DBCalls = 0; - for (let i = 0; i < 5; i++) { + for (let i = 0; i < 13; i++) { const args = databaseAdapter.createObject.calls.argsFor(i); switch (args[0]) { case 'MyObject': @@ -395,7 +555,11 @@ describe('batch', () => { break; case 'MyObject2': myObject2DBCalls++; - transactionalSession2 = args[3]; + if (!transactionalSession2) { + transactionalSession2 = args[3]; + } else { + expect(transactionalSession2).toBe(args[3]); + } if (transactionalSession) { expect(transactionalSession).not.toBe(args[3]); } @@ -407,7 +571,7 @@ describe('batch', () => { } } expect(myObjectDBCalls).toEqual(2); - expect(myObject2DBCalls).toEqual(1); + expect(myObject2DBCalls).toEqual(9); expect(myObject3DBCalls).toEqual(2); }); }); diff --git a/src/ParseServerRESTController.js b/src/ParseServerRESTController.js index 4bcd7bf0..1f705030 100644 --- a/src/ParseServerRESTController.js +++ b/src/ParseServerRESTController.js @@ -64,37 +64,32 @@ function ParseServerRESTController(applicationId, router) { config ).then( response => { - return Promise.resolve({ success: response }); + return { success: response }; }, error => { - if (data.transaction === true) { - return Promise.reject(error); - } - return Promise.resolve({ + return { error: { code: error.code, error: error.message }, - }); + }; } ); }); - return Promise.all(promises) - .catch(error => { - if (data.transaction === true) { + return Promise.all(promises).then(result => { + if (data.transaction === true) { + if ( + result.find(resultItem => typeof resultItem.error === 'object') + ) { return config.database.abortTransactionalSession().then(() => { - throw error; + return Promise.reject(result); }); } else { - throw error; - } - }) - .then(result => { - if (data.transaction === true) { return config.database.commitTransactionalSession().then(() => { return result; }); - } else { - return result; } - }); + } else { + return result; + } + }); }); } diff --git a/src/batch.js b/src/batch.js index 10ae294a..1a920520 100644 --- a/src/batch.js +++ b/src/batch.js @@ -107,33 +107,26 @@ function handleBatch(router, req) { return { success: response.response }; }, error => { - if (req.body.transaction === true) { - return Promise.reject(error); - } return { error: { code: error.code, error: error.message } }; } ); }); - return Promise.all(promises) - .catch(error => { - if (req.body.transaction === true) { + return Promise.all(promises).then(results => { + if (req.body.transaction === true) { + if (results.find(result => typeof result.error === 'object')) { return req.config.database.abortTransactionalSession().then(() => { - throw error; + return Promise.reject({ response: results }); }); } else { - throw error; - } - }) - .then(results => { - if (req.body.transaction === true) { return req.config.database.commitTransactionalSession().then(() => { return { response: results }; }); - } else { - return { response: results }; } - }); + } else { + return { response: results }; + } + }); }); }