test: improve transaction tests to use async/await (#7759)

This commit is contained in:
Corey
2022-01-03 18:49:43 -05:00
committed by GitHub
parent d05fb9f2fa
commit a43638f300
2 changed files with 203 additions and 299 deletions

View File

@@ -15,35 +15,18 @@ describe('ParseServerRESTController', () => {
); );
}); });
it('should handle a get request', done => { it('should handle a get request', async () => {
RESTController.request('GET', '/classes/MyObject').then( const res = await RESTController.request('GET', '/classes/MyObject');
res => { expect(res.results.length).toBe(0);
expect(res.results.length).toBe(0);
done();
},
err => {
console.log(err);
jfail(err);
done();
}
);
}); });
it('should handle a get request with full serverURL mount path', done => { it('should handle a get request with full serverURL mount path', async () => {
RESTController.request('GET', '/1/classes/MyObject').then( const res = await RESTController.request('GET', '/1/classes/MyObject');
res => { expect(res.results.length).toBe(0);
expect(res.results.length).toBe(0);
done();
},
err => {
jfail(err);
done();
}
);
}); });
it('should handle a POST batch without transaction', done => { it('should handle a POST batch without transaction', async () => {
RESTController.request('POST', 'batch', { const res = await RESTController.request('POST', 'batch', {
requests: [ requests: [
{ {
method: 'GET', method: 'GET',
@@ -59,20 +42,12 @@ describe('ParseServerRESTController', () => {
path: '/classes/MyObject', path: '/classes/MyObject',
}, },
], ],
}).then( });
res => { expect(res.length).toBe(3);
expect(res.length).toBe(3);
done();
},
err => {
jfail(err);
done();
}
);
}); });
it('should handle a POST batch with transaction=false', done => { it('should handle a POST batch with transaction=false', async () => {
RESTController.request('POST', 'batch', { const res = await RESTController.request('POST', 'batch', {
requests: [ requests: [
{ {
method: 'GET', method: 'GET',
@@ -89,16 +64,8 @@ describe('ParseServerRESTController', () => {
}, },
], ],
transaction: false, transaction: false,
}).then( });
res => { expect(res.length).toBe(3);
expect(res.length).toBe(3);
done();
},
err => {
jfail(err);
done();
}
);
}); });
it('should handle response status', async () => { it('should handle response status', async () => {
@@ -186,54 +153,43 @@ describe('ParseServerRESTController', () => {
} }
}); });
it('should handle a batch request with transaction = true', async done => { it('should handle a batch request with transaction = true', async () => {
await reconfigureServer();
const myObject = new Parse.Object('MyObject'); // This is important because transaction only works on pre-existing collections const myObject = new Parse.Object('MyObject'); // This is important because transaction only works on pre-existing collections
myObject await myObject.save();
.save() await myObject.destroy();
.then(() => { spyOn(databaseAdapter, 'createObject').and.callThrough();
return myObject.destroy(); const response = await RESTController.request('POST', 'batch', {
}) requests: [
.then(() => { {
spyOn(databaseAdapter, 'createObject').and.callThrough(); method: 'POST',
path: '/1/classes/MyObject',
return RESTController.request('POST', 'batch', { body: { key: 'value1' },
requests: [ },
{ {
method: 'POST', method: 'POST',
path: '/1/classes/MyObject', path: '/1/classes/MyObject',
body: { key: 'value1' }, body: { key: 'value2' },
}, },
{ ],
method: 'POST', transaction: true,
path: '/1/classes/MyObject', });
body: { key: 'value2' }, expect(response.length).toEqual(2);
}, expect(response[0].success.objectId).toBeDefined();
], expect(response[0].success.createdAt).toBeDefined();
transaction: true, expect(response[1].success.objectId).toBeDefined();
}).then(response => { expect(response[1].success.createdAt).toBeDefined();
expect(response.length).toEqual(2); const query = new Parse.Query('MyObject');
expect(response[0].success.objectId).toBeDefined(); const results = await query.find();
expect(response[0].success.createdAt).toBeDefined(); expect(databaseAdapter.createObject.calls.count() % 2).toBe(0);
expect(response[1].success.objectId).toBeDefined(); for (let i = 0; i + 1 < databaseAdapter.createObject.calls.length; i = i + 2) {
expect(response[1].success.createdAt).toBeDefined(); expect(databaseAdapter.createObject.calls.argsFor(i)[3]).toBe(
const query = new Parse.Query('MyObject'); databaseAdapter.createObject.calls.argsFor(i + 1)[3]
return query.find().then(results => { );
expect(databaseAdapter.createObject.calls.count() % 2).toBe(0); }
for (let i = 0; i + 1 < databaseAdapter.createObject.calls.length; i = i + 2) { expect(results.map(result => result.get('key')).sort()).toEqual([
expect(databaseAdapter.createObject.calls.argsFor(i)[3]).toBe( 'value1',
databaseAdapter.createObject.calls.argsFor(i + 1)[3] 'value2',
); ]);
}
expect(results.map(result => result.get('key')).sort()).toEqual([
'value1',
'value2',
]);
done();
});
});
})
.catch(done.fail);
}); });
it('should not save anything when one operation fails in a transaction', async () => { it('should not save anything when one operation fails in a transaction', async () => {
@@ -560,21 +516,11 @@ describe('ParseServerRESTController', () => {
}); });
} }
it('should handle a POST request', done => { it('should handle a POST request', async () => {
RESTController.request('POST', '/classes/MyObject', { key: 'value' }) await RESTController.request('POST', '/classes/MyObject', { key: 'value' });
.then(() => { const res = await RESTController.request('GET', '/classes/MyObject');
return RESTController.request('GET', '/classes/MyObject'); expect(res.results.length).toBe(1);
}) expect(res.results[0].key).toEqual('value');
.then(res => {
expect(res.results.length).toBe(1);
expect(res.results[0].key).toEqual('value');
done();
})
.catch(err => {
console.log(err);
jfail(err);
done();
});
}); });
it('should handle a POST request with context', async () => { it('should handle a POST request with context', async () => {
@@ -593,125 +539,76 @@ describe('ParseServerRESTController', () => {
); );
}); });
it('ensures sessionTokens are properly handled', done => { it('ensures sessionTokens are properly handled', async () => {
let userId; const user = await Parse.User.signUp('user', 'pass');
Parse.User.signUp('user', 'pass') const sessionToken = user.getSessionToken();
.then(user => { const res = await RESTController.request('GET', '/users/me', undefined, {
userId = user.id; sessionToken,
const sessionToken = user.getSessionToken(); });
return RESTController.request('GET', '/users/me', undefined, { // Result is in JSON format
sessionToken, expect(res.objectId).toEqual(user.id);
}); });
})
.then(res => { it('ensures masterKey is properly handled', async () => {
// Result is in JSON format const user = await Parse.User.signUp('user', 'pass');
expect(res.objectId).toEqual(userId); const userId = user.id;
done(); await Parse.User.logOut();
}) const res = await RESTController.request('GET', '/classes/_User', undefined, {
.catch(err => { useMasterKey: true,
console.log(err); });
jfail(err); expect(res.results.length).toBe(1);
done(); expect(res.results[0].objectId).toEqual(userId);
});
it('ensures no user is created when passing an empty username', async () => {
try {
await RESTController.request('POST', '/classes/_User', {
username: '',
password: 'world',
}); });
fail('Success callback should not be called when passing an empty username.');
} catch (err) {
expect(err.code).toBe(Parse.Error.USERNAME_MISSING);
expect(err.message).toBe('bad or missing username');
}
}); });
it('ensures masterKey is properly handled', done => { it('ensures no user is created when passing an empty password', async () => {
let userId; try {
Parse.User.signUp('user', 'pass') await RESTController.request('POST', '/classes/_User', {
.then(user => { username: 'hello',
userId = user.id; password: '',
return Parse.User.logOut().then(() => { });
return RESTController.request('GET', '/classes/_User', undefined, { fail('Success callback should not be called when passing an empty password.');
useMasterKey: true, } catch (err) {
}); expect(err.code).toBe(Parse.Error.PASSWORD_MISSING);
}); expect(err.message).toBe('password is required');
}) }
.then(
res => {
expect(res.results.length).toBe(1);
expect(res.results[0].objectId).toEqual(userId);
done();
},
err => {
jfail(err);
done();
}
);
}); });
it('ensures no user is created when passing an empty username', done => { it('ensures no session token is created on creating users', async () => {
RESTController.request('POST', '/classes/_User', { const user = await RESTController.request('POST', '/classes/_User', {
username: '',
password: 'world',
}).then(
() => {
jfail(new Error('Success callback should not be called when passing an empty username.'));
done();
},
err => {
expect(err.code).toBe(Parse.Error.USERNAME_MISSING);
expect(err.message).toBe('bad or missing username');
done();
}
);
});
it('ensures no user is created when passing an empty password', done => {
RESTController.request('POST', '/classes/_User', {
username: 'hello',
password: '',
}).then(
() => {
jfail(new Error('Success callback should not be called when passing an empty password.'));
done();
},
err => {
expect(err.code).toBe(Parse.Error.PASSWORD_MISSING);
expect(err.message).toBe('password is required');
done();
}
);
});
it('ensures no session token is created on creating users', done => {
RESTController.request('POST', '/classes/_User', {
username: 'hello', username: 'hello',
password: 'world', password: 'world',
}) });
.then(user => { expect(user.sessionToken).toBeUndefined();
expect(user.sessionToken).toBeUndefined(); const query = new Parse.Query('_Session');
const query = new Parse.Query('_Session'); const sessions = await query.find({ useMasterKey: true });
return query.find({ useMasterKey: true }); expect(sessions.length).toBe(0);
})
.then(sessions => {
expect(sessions.length).toBe(0);
done();
}, done.fail);
}); });
it('ensures a session token is created when passing installationId != cloud', done => { it('ensures a session token is created when passing installationId != cloud', async () => {
RESTController.request( const user = await RESTController.request(
'POST', 'POST',
'/classes/_User', '/classes/_User',
{ username: 'hello', password: 'world' }, { username: 'hello', password: 'world' },
{ installationId: 'my-installation' } { installationId: 'my-installation' }
) );
.then(user => { expect(user.sessionToken).not.toBeUndefined();
expect(user.sessionToken).not.toBeUndefined(); const query = new Parse.Query('_Session');
const query = new Parse.Query('_Session'); const sessions = await query.find({ useMasterKey: true });
return query.find({ useMasterKey: true }); expect(sessions.length).toBe(1);
}) expect(sessions[0].get('installationId')).toBe('my-installation');
.then(
sessions => {
expect(sessions.length).toBe(1);
expect(sessions[0].get('installationId')).toBe('my-installation');
done();
},
err => {
jfail(err);
done();
}
);
}); });
it('ensures logIn is saved with installationId', async () => { it('ensures logIn is saved with installationId', async () => {

View File

@@ -89,10 +89,32 @@ describe('batch', () => {
expect(internalURL).toEqual('/classes/Object'); expect(internalURL).toEqual('/classes/Object');
}); });
it('should handle a batch request without transaction', async done => { it('should return the proper url with no url provided', () => {
const originalURL = '/parse/batch';
const internalURL = batch.makeBatchRoutingPathFunction(
originalURL,
undefined,
publicServerURL
)('/parse/classes/Object');
expect(internalURL).toEqual('/classes/Object');
});
it('should return the proper url with no public url provided', () => {
const originalURL = '/parse/batch';
const internalURL = batch.makeBatchRoutingPathFunction(
originalURL,
serverURLNaked,
undefined
)('/parse/classes/Object');
expect(internalURL).toEqual('/classes/Object');
});
it('should handle a batch request without transaction', async () => {
spyOn(databaseAdapter, 'createObject').and.callThrough(); spyOn(databaseAdapter, 'createObject').and.callThrough();
request({ const response = await request({
method: 'POST', method: 'POST',
headers: headers, headers: headers,
url: 'http://localhost:8378/1/batch', url: 'http://localhost:8378/1/batch',
@@ -110,28 +132,25 @@ describe('batch', () => {
}, },
], ],
}), }),
}).then(response => {
expect(response.data.length).toEqual(2);
expect(response.data[0].success.objectId).toBeDefined();
expect(response.data[0].success.createdAt).toBeDefined();
expect(response.data[1].success.objectId).toBeDefined();
expect(response.data[1].success.createdAt).toBeDefined();
const query = new Parse.Query('MyObject');
query.find().then(results => {
expect(databaseAdapter.createObject.calls.count()).toBe(2);
expect(databaseAdapter.createObject.calls.argsFor(0)[3]).toEqual(null);
expect(databaseAdapter.createObject.calls.argsFor(1)[3]).toEqual(null);
expect(results.map(result => result.get('key')).sort()).toEqual(['value1', 'value2']);
done();
});
}); });
expect(response.data.length).toEqual(2);
expect(response.data[0].success.objectId).toBeDefined();
expect(response.data[0].success.createdAt).toBeDefined();
expect(response.data[1].success.objectId).toBeDefined();
expect(response.data[1].success.createdAt).toBeDefined();
const query = new Parse.Query('MyObject');
const results = await query.find();
expect(databaseAdapter.createObject.calls.count()).toBe(2);
expect(databaseAdapter.createObject.calls.argsFor(0)[3]).toEqual(null);
expect(databaseAdapter.createObject.calls.argsFor(1)[3]).toEqual(null);
expect(results.map(result => result.get('key')).sort()).toEqual(['value1', 'value2']);
}); });
it('should handle a batch request with transaction = false', async done => { it('should handle a batch request with transaction = false', async () => {
await reconfigureServer();
spyOn(databaseAdapter, 'createObject').and.callThrough(); spyOn(databaseAdapter, 'createObject').and.callThrough();
request({ const response = await request({
method: 'POST', method: 'POST',
headers: headers, headers: headers,
url: 'http://localhost:8378/1/batch', url: 'http://localhost:8378/1/batch',
@@ -150,21 +169,18 @@ describe('batch', () => {
], ],
transaction: false, transaction: false,
}), }),
}).then(response => {
expect(response.data.length).toEqual(2);
expect(response.data[0].success.objectId).toBeDefined();
expect(response.data[0].success.createdAt).toBeDefined();
expect(response.data[1].success.objectId).toBeDefined();
expect(response.data[1].success.createdAt).toBeDefined();
const query = new Parse.Query('MyObject');
query.find().then(results => {
expect(databaseAdapter.createObject.calls.count()).toBe(2);
expect(databaseAdapter.createObject.calls.argsFor(0)[3]).toEqual(null);
expect(databaseAdapter.createObject.calls.argsFor(1)[3]).toEqual(null);
expect(results.map(result => result.get('key')).sort()).toEqual(['value1', 'value2']);
done();
});
}); });
expect(response.data.length).toEqual(2);
expect(response.data[0].success.objectId).toBeDefined();
expect(response.data[0].success.createdAt).toBeDefined();
expect(response.data[1].success.objectId).toBeDefined();
expect(response.data[1].success.createdAt).toBeDefined();
const query = new Parse.Query('MyObject');
const results = await query.find();
expect(databaseAdapter.createObject.calls.count()).toBe(2);
expect(databaseAdapter.createObject.calls.argsFor(0)[3]).toEqual(null);
expect(databaseAdapter.createObject.calls.argsFor(1)[3]).toEqual(null);
expect(results.map(result => result.get('key')).sort()).toEqual(['value1', 'value2']);
}); });
if ( if (
@@ -191,58 +207,48 @@ describe('batch', () => {
} }
}); });
it('should handle a batch request with transaction = true', async done => { it('should handle a batch request with transaction = true', async () => {
await reconfigureServer();
const myObject = new Parse.Object('MyObject'); // This is important because transaction only works on pre-existing collections const myObject = new Parse.Object('MyObject'); // This is important because transaction only works on pre-existing collections
myObject await myObject.save();
.save() await myObject.destroy();
.then(() => { spyOn(databaseAdapter, 'createObject').and.callThrough();
return myObject.destroy(); const response = await request({
}) method: 'POST',
.then(() => { headers: headers,
spyOn(databaseAdapter, 'createObject').and.callThrough(); url: 'http://localhost:8378/1/batch',
body: JSON.stringify({
request({ requests: [
method: 'POST', {
headers: headers, method: 'POST',
url: 'http://localhost:8378/1/batch', path: '/1/classes/MyObject',
body: JSON.stringify({ body: { key: 'value1' },
requests: [ },
{ {
method: 'POST', method: 'POST',
path: '/1/classes/MyObject', path: '/1/classes/MyObject',
body: { key: 'value1' }, body: { key: 'value2' },
}, },
{ ],
method: 'POST', transaction: true,
path: '/1/classes/MyObject', }),
body: { key: 'value2' }, });
}, expect(response.data.length).toEqual(2);
], expect(response.data[0].success.objectId).toBeDefined();
transaction: true, expect(response.data[0].success.createdAt).toBeDefined();
}), expect(response.data[1].success.objectId).toBeDefined();
}).then(response => { expect(response.data[1].success.createdAt).toBeDefined();
expect(response.data.length).toEqual(2); const query = new Parse.Query('MyObject');
expect(response.data[0].success.objectId).toBeDefined(); const results = await query.find();
expect(response.data[0].success.createdAt).toBeDefined(); expect(databaseAdapter.createObject.calls.count() % 2).toBe(0);
expect(response.data[1].success.objectId).toBeDefined(); for (let i = 0; i + 1 < databaseAdapter.createObject.calls.length; i = i + 2) {
expect(response.data[1].success.createdAt).toBeDefined(); expect(databaseAdapter.createObject.calls.argsFor(i)[3]).toBe(
const query = new Parse.Query('MyObject'); databaseAdapter.createObject.calls.argsFor(i + 1)[3]
query.find().then(results => { );
expect(databaseAdapter.createObject.calls.count() % 2).toBe(0); }
for (let i = 0; i + 1 < databaseAdapter.createObject.calls.length; i = i + 2) { expect(results.map(result => result.get('key')).sort()).toEqual([
expect(databaseAdapter.createObject.calls.argsFor(i)[3]).toBe( 'value1',
databaseAdapter.createObject.calls.argsFor(i + 1)[3] 'value2',
); ]);
}
expect(results.map(result => result.get('key')).sort()).toEqual([
'value1',
'value2',
]);
done();
});
});
});
}); });
it('should not save anything when one operation fails in a transaction', async () => { it('should not save anything when one operation fails in a transaction', async () => {
@@ -350,6 +356,7 @@ describe('batch', () => {
transaction: true, transaction: true,
}), }),
}); });
fail();
} catch (error) { } catch (error) {
expect(error).toBeDefined(); expect(error).toBeDefined();
const query = new Parse.Query('MyObject'); const query = new Parse.Query('MyObject');