async function setup(options) { await reconfigureServer({ appId: Parse.applicationId, masterKey: Parse.masterKey, serverURL: Parse.serverURL, idempotencyOptions: options, }); }
it('should fail trying to create a malformed function (REST)', done => { request({ method: 'POST', url: Parse.serverURL + '/hooks/functions', headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, }, body: JSON.stringify({ functionName: 'SomeFunction' }), }).then(fail, response => { const body = response.data; expect(body.error).toBe('invalid hook declaration'); expect(body.code).toBe(143); done(); }); });
it('should re-throw any other error unchanged when writing request entry fails for any other reason', async () => { spyOn(rest, 'create').and.rejectWith(new Parse.Error(0, "some other error")); Parse.Cloud.define('myFunction', () => {}); const params = { method: 'POST', url: 'http://localhost:8378/1/functions/myFunction', headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, 'X-Parse-Request-Id': 'abc-123' } }; await request(params).then(fail, e => { expect(e.status).toEqual(400); expect(e.data.error).toEqual("some other error"); }); });
it('should not interfere with calls of different request ID', async () => { let counter = 0; Parse.Cloud.afterSave('MyClass', () => { counter++; }); const promises = [...Array(100).keys()].map(() => { const params = { method: 'POST', url: 'http://localhost:8378/1/classes/MyClass', headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, 'X-Parse-Request-Id': uuid.v4() } }; return request(params); }); await expectAsync(Promise.all(promises)).toBeResolved(); expect(counter).toBe(100); });
// Tests it('should enforce idempotency for cloud code function', async () => { let counter = 0; Parse.Cloud.define('myFunction', () => { counter++; }); const params = { method: 'POST', url: 'http://localhost:8378/1/functions/myFunction', headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, 'X-Parse-Request-Id': 'abc-123' } }; expect(Config.get(Parse.applicationId).idempotencyOptions.ttl).toBe(30); await request(params); await request(params).then(fail, e => { expect(e.status).toEqual(400); expect(e.data.error).toEqual("Duplicate request"); }); expect(counter).toBe(1); });
masterKey: Parse.masterKey, serverURL: Parse.serverURL, push: {
it('should enforce idempotency for cloud code jobs', async () => { let counter = 0; Parse.Cloud.job('myJob', () => { counter++; }); const params = { method: 'POST', url: 'http://localhost:8378/1/jobs/myJob', headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, 'X-Parse-Request-Id': 'abc-123' } }; await expectAsync(request(params)).toBeResolved(); await request(params).then(fail, e => { expect(e.status).toEqual(400); expect(e.data.error).toEqual("Duplicate request"); }); expect(counter).toBe(1); });
headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, 'Content-Type': 'application/json', },
it('should delete request entry after TTL', async () => { let counter = 0; Parse.Cloud.define('myFunction', () => { counter++; }); const params = { method: 'POST', url: 'http://localhost:8378/1/functions/myFunction', headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, 'X-Parse-Request-Id': 'abc-123' } }; await expectAsync(request(params)).toBeResolved(); if (SIMULATE_TTL) { await deleteRequestEntry('abc-123'); } else { await new Promise(resolve => setTimeout(resolve, 130000)); } await expectAsync(request(params)).toBeResolved(); expect(counter).toBe(2); });
it('should enforce idempotency for class object creation', async () => { let counter = 0; Parse.Cloud.afterSave('MyClass', () => { counter++; }); const params = { method: 'POST', url: 'http://localhost:8378/1/classes/MyClass', headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, 'X-Parse-Request-Id': 'abc-123' } }; await expectAsync(request(params)).toBeResolved(); await request(params).then(fail, e => { expect(e.status).toEqual(400); expect(e.data.error).toEqual("Duplicate request"); }); expect(counter).toBe(1); });
it('should enforce idempotency for installation object creation', async () => { let counter = 0; Parse.Cloud.afterSave('_Installation', () => { counter++; }); const params = { method: 'POST', url: 'http://localhost:8378/1/installations', body: { installationId: "1", deviceType: "ios" }, headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, 'X-Parse-Request-Id': 'abc-123' } }; await expectAsync(request(params)).toBeResolved(); await request(params).then(fail, e => { expect(e.status).toEqual(400); expect(e.data.error).toEqual("Duplicate request"); }); expect(counter).toBe(1); });
it('should enforce idempotency for user object creation', async () => { let counter = 0; Parse.Cloud.afterSave('_User', () => { counter++; }); const params = { method: 'POST', url: 'http://localhost:8378/1/users', body: { username: "user", password: "pass" }, headers: { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, 'X-Parse-Request-Id': 'abc-123' } }; await expectAsync(request(params)).toBeResolved(); await request(params).then(fail, e => { expect(e.status).toEqual(400); expect(e.data.error).toEqual("Duplicate request"); }); expect(counter).toBe(1); });