feat: Asynchronous initialization of Parse Server (#8232)

BREAKING CHANGE: This release introduces the asynchronous initialization of Parse Server to prevent mounting Parse Server before being ready to receive request; it changes how Parse Server is imported, initialized and started; it also removes the callback `serverStartComplete`; see the [Parse Server 6 migration guide](https://github.com/parse-community/parse-server/blob/alpha/6.0.0.md) for more details (#8232)
This commit is contained in:
Daniel
2022-12-22 01:30:13 +11:00
committed by GitHub
parent db9941c5a6
commit 99fcf45e55
21 changed files with 494 additions and 310 deletions

View File

@@ -61,34 +61,19 @@ describe('server', () => {
});
});
it('fails if database is unreachable', done => {
reconfigureServer({
it('fails if database is unreachable', async () => {
const server = new ParseServer.default({
...defaultConfiguration,
databaseAdapter: new MongoStorageAdapter({
uri: 'mongodb://fake:fake@localhost:43605/drew3',
mongoOptions: {
serverSelectionTimeoutMS: 2000,
},
}),
}).catch(() => {
const config = Config.get('test');
config.schemaCache.clear();
//Need to use rest api because saving via JS SDK results in fail() not getting called
request({
method: 'POST',
url: 'http://localhost:8378/1/classes/NewClass',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
body: {},
}).then(fail, response => {
expect(response.status).toEqual(500);
const body = response.data;
expect(body.code).toEqual(1);
expect(body.message).toEqual('Internal server error.');
reconfigureServer().then(done, done);
});
});
const error = await server.start().catch(e => e);
expect(`${error}`.includes('MongoServerSelectionError')).toBeTrue();
await reconfigureServer();
});
describe('mail adapter', () => {
@@ -295,91 +280,47 @@ describe('server', () => {
});
});
it('can create a parse-server v1', done => {
it('can create a parse-server v1', async () => {
await reconfigureServer({ appId: 'aTestApp' });
const parseServer = new ParseServer.default(
Object.assign({}, defaultConfiguration, {
appId: 'aTestApp',
masterKey: 'aTestMasterKey',
serverURL: 'http://localhost:12666/parse',
serverStartComplete: () => {
expect(Parse.applicationId).toEqual('aTestApp');
const app = express();
app.use('/parse', parseServer.app);
const server = app.listen(12666);
const obj = new Parse.Object('AnObject');
let objId;
obj
.save()
.then(obj => {
objId = obj.id;
const q = new Parse.Query('AnObject');
return q.first();
})
.then(obj => {
expect(obj.id).toEqual(objId);
server.close(async () => {
await reconfigureServer();
done();
});
})
.catch(() => {
server.close(async () => {
await reconfigureServer();
done();
});
});
},
})
);
await parseServer.start();
expect(Parse.applicationId).toEqual('aTestApp');
const app = express();
app.use('/parse', parseServer.app);
const server = app.listen(12666);
const obj = new Parse.Object('AnObject');
await obj.save();
const query = await new Parse.Query('AnObject').first();
expect(obj.id).toEqual(query.id);
await new Promise(resolve => server.close(resolve));
});
it('can create a parse-server v2', done => {
let objId;
let server;
it('can create a parse-server v2', async () => {
await reconfigureServer({ appId: 'anOtherTestApp' });
const parseServer = ParseServer.ParseServer(
Object.assign({}, defaultConfiguration, {
appId: 'anOtherTestApp',
masterKey: 'anOtherTestMasterKey',
serverURL: 'http://localhost:12667/parse',
serverStartComplete: error => {
const promise = error ? Promise.reject(error) : Promise.resolve();
promise
.then(() => {
expect(Parse.applicationId).toEqual('anOtherTestApp');
const app = express();
app.use('/parse', parseServer);
server = app.listen(12667);
const obj = new Parse.Object('AnObject');
return obj.save();
})
.then(obj => {
objId = obj.id;
const q = new Parse.Query('AnObject');
return q.first();
})
.then(obj => {
expect(obj.id).toEqual(objId);
server.close(async () => {
await reconfigureServer();
done();
});
})
.catch(error => {
fail(JSON.stringify(error));
if (server) {
server.close(async () => {
await reconfigureServer();
done();
});
} else {
done();
}
});
},
})
);
expect(Parse.applicationId).toEqual('anOtherTestApp');
await parseServer.start();
const app = express();
app.use('/parse', parseServer.app);
const server = app.listen(12667);
const obj = new Parse.Object('AnObject');
await obj.save();
const q = await new Parse.Query('AnObject').first();
expect(obj.id).toEqual(q.id);
await new Promise(resolve => server.close(resolve));
});
it('has createLiveQueryServer', done => {
@@ -558,6 +499,84 @@ describe('server', () => {
.catch(done.fail);
});
it('can call start', async () => {
await reconfigureServer({ appId: 'aTestApp' });
const config = {
...defaultConfiguration,
appId: 'aTestApp',
masterKey: 'aTestMasterKey',
serverURL: 'http://localhost:12701/parse',
};
const parseServer = new ParseServer.ParseServer(config);
await parseServer.start();
expect(Parse.applicationId).toEqual('aTestApp');
expect(Parse.serverURL).toEqual('http://localhost:12701/parse');
const app = express();
app.use('/parse', parseServer.app);
const server = app.listen(12701);
const testObject = new Parse.Object('TestObject');
await expectAsync(testObject.save()).toBeResolved();
await new Promise(resolve => server.close(resolve));
});
it('start is required to mount', async () => {
await reconfigureServer({ appId: 'aTestApp' });
const config = {
...defaultConfiguration,
appId: 'aTestApp',
masterKey: 'aTestMasterKey',
serverURL: 'http://localhost:12701/parse',
};
const parseServer = new ParseServer.ParseServer(config);
expect(Parse.applicationId).toEqual('aTestApp');
expect(Parse.serverURL).toEqual('http://localhost:12701/parse');
const app = express();
app.use('/parse', parseServer.app);
const server = app.listen(12701);
const response = await request({
headers: {
'X-Parse-Application-Id': 'aTestApp',
},
method: 'POST',
url: 'http://localhost:12701/parse/classes/TestObject',
}).catch(e => new Parse.Error(e.data.code, e.data.error));
expect(response).toEqual(
new Parse.Error(Parse.Error.INTERNAL_SERVER_ERROR, 'Invalid server state: initialized')
);
const health = await request({
url: 'http://localhost:12701/parse/health',
}).catch(e => e);
expect(health.data.status).toBe('initialized');
expect(health.status).toBe(503);
await new Promise(resolve => server.close(resolve));
});
it('can get starting state', async () => {
await reconfigureServer({ appId: 'test2', silent: false });
const parseServer = new ParseServer.ParseServer({
...defaultConfiguration,
appId: 'test2',
masterKey: 'abc',
serverURL: 'http://localhost:12668/parse',
async cloud() {
await new Promise(resolve => setTimeout(resolve, 2000));
},
});
const express = require('express');
const app = express();
app.use('/parse', parseServer.app);
const server = app.listen(12668);
const startingPromise = parseServer.start();
const health = await request({
url: 'http://localhost:12668/parse/health',
}).catch(e => e);
expect(health.data.status).toBe('starting');
expect(health.status).toBe(503);
expect(health.headers['retry-after']).toBe('1');
await startingPromise;
await new Promise(resolve => server.close(resolve));
});
it('should not fail when Google signin is introduced without the optional clientId', done => {
const jwt = require('jsonwebtoken');