Refactors configuration management (#4271)

* Adds flow types / Configuration interfaces

* Lets call it options

* Use a single interface to generate the configurations

* Translates options to definitions only if comments are set

* improves logic

* Moves objects around

* Fixes issue affecting logging of circular objects

* fixes undefined env

* Moves all defaults to defaults

* Adds back CLI defaults

* Restored defaults in commander.js

* Merge provided defaults and platform defaults

* Addresses visual nits

* Improves Config.js code

* Adds ability to pass the default value in trailing comments

* Load platform defaults from the definitions file

* proper default values on various options

* Adds ParseServer.start and server.start(options) as quick startup methods

* Moves creating liveQueryServer http into ParseServer.js

* removes dead code

* Adds tests to guarantee we can start a LQ Server from main module

* Fixes incorrect code regading liveQuery init port

* Start a http server for LQ if port is specified

* ensure we dont fail if config.port is not set

* Specify port

* ignore other path skipped in tests

* Adds test for custom middleware setting

* Refactors new Config into Config.get

- Hides AppCache from ParseServer.js, use Config.put which validates

* Extracts controller creation into Controllers/index.js

- This makes the ParseServer init way simpler

* Move serverURL inference into ParseServer

* review nits
This commit is contained in:
Florent Vilmart
2017-10-23 08:43:05 -04:00
committed by GitHub
parent d29a4483d0
commit 9de4b8b2a7
55 changed files with 1462 additions and 874 deletions

View File

@@ -71,7 +71,7 @@ describe("Account Lockout Policy: ", () => {
publicServerURL: "https://my.public.server.com/1"
})
.then(() => {
new Config('test');
Config.get('test');
fail('set duration to an invalid number test failed');
done();
})
@@ -95,7 +95,7 @@ describe("Account Lockout Policy: ", () => {
publicServerURL: "https://my.public.server.com/1"
})
.then(() => {
new Config('test');
Config.get('test');
fail('set threshold to an invalid number test failed');
done();
})
@@ -119,7 +119,7 @@ describe("Account Lockout Policy: ", () => {
publicServerURL: "https://my.public.server.com/1"
})
.then(() => {
new Config('test');
Config.get('test');
fail('threshold value < 1 is invalid test failed');
done();
})
@@ -143,7 +143,7 @@ describe("Account Lockout Policy: ", () => {
publicServerURL: "https://my.public.server.com/1"
})
.then(() => {
new Config('test');
Config.get('test');
fail('threshold value > 999 is invalid test failed');
done();
})
@@ -167,7 +167,7 @@ describe("Account Lockout Policy: ", () => {
publicServerURL: "https://my.public.server.com/1"
})
.then(() => {
new Config('test');
Config.get('test');
fail('duration value < 1 is invalid test failed');
done();
})
@@ -191,7 +191,7 @@ describe("Account Lockout Policy: ", () => {
publicServerURL: "https://my.public.server.com/1"
})
.then(() => {
new Config('test');
Config.get('test');
fail('duration value > 99999 is invalid test failed');
done();
})

View File

@@ -135,7 +135,7 @@ describe("AdapterLoader", ()=>{
reconfigureServer({
push: pushAdapterOptions,
}).then(() => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const pushAdapter = config.pushWorker.adapter;
expect(pushAdapter.getValidPushTypes()).toEqual(['ios']);
expect(pushAdapter.options).toEqual(pushAdapterOptions);

View File

@@ -5,7 +5,7 @@ var AudiencesRouter = require('../src/Routers/AudiencesRouter').AudiencesRouter;
describe('AudiencesRouter', () => {
it('uses find condition from request.body', (done) => {
var config = new Config('test');
var config = Config.get('test');
var androidAudienceRequest = {
'name': 'Android Users',
'query': '{ "test": "android" }'
@@ -46,7 +46,7 @@ describe('AudiencesRouter', () => {
});
it('uses find condition from request.query', (done) => {
var config = new Config('test');
var config = Config.get('test');
var androidAudienceRequest = {
'name': 'Android Users',
'query': '{ "test": "android" }'
@@ -87,7 +87,7 @@ describe('AudiencesRouter', () => {
});
it('query installations with limit = 0', (done) => {
var config = new Config('test');
var config = Config.get('test');
var androidAudienceRequest = {
'name': 'Android Users',
'query': '{ "test": "android" }'
@@ -106,7 +106,7 @@ describe('AudiencesRouter', () => {
info: {}
};
new Config('test');
Config.get('test');
var router = new AudiencesRouter();
rest.create(config, auth.nobody(config), '_Audience', androidAudienceRequest)
.then(() => {
@@ -127,7 +127,7 @@ describe('AudiencesRouter', () => {
});
it('query installations with count = 1', done => {
var config = new Config('test');
var config = Config.get('test');
var androidAudienceRequest = {
'name': 'Android Users',
'query': '{ "test": "android" }'
@@ -163,7 +163,7 @@ describe('AudiencesRouter', () => {
});
it('query installations with limit = 0 and count = 1', (done) => {
var config = new Config('test');
var config = Config.get('test');
var androidAudienceRequest = {
'name': 'Android Users',
'query': '{ "test": "android" }'
@@ -286,7 +286,7 @@ describe('AudiencesRouter', () => {
});
it_exclude_dbs(['postgres'])('should support legacy parse.com audience fields', (done) => {
const database = (new Config(Parse.applicationId)).database.adapter.database;
const database = (Config.get(Parse.applicationId)).database.adapter.database;
const now = new Date();
Parse._request('POST', 'push_audiences', { name: 'My Audience', query: JSON.stringify({ deviceType: 'ios' })}, { useMasterKey: true })
.then((audience) => {

View File

@@ -186,7 +186,7 @@ describe('AuthenticationProviders', function() {
ok(!provider.synchronizedExpiration,
"Expiration should be cleared");
// make sure the auth data is properly deleted
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
config.database.adapter.find('_User', {
fields: Object.assign({}, defaultColumns._Default, defaultColumns._Installation),
}, { objectId: model.id }, {})

View File

@@ -242,7 +242,7 @@ describe("Email Verification Token Expiration: ", () => {
return user.signUp();
})
.then(() => {
const config = new Config('test');
const config = Config.get('test');
return config.database.find('_User', {username: 'sets_email_verify_token_expires_at'});
})
.then(results => {
@@ -289,7 +289,7 @@ describe("Email Verification Token Expiration: ", () => {
followRedirect: false,
}, (error, response) => {
expect(response.statusCode).toEqual(302);
const config = new Config('test');
const config = Config.get('test');
return config.database.find('_User', {username: 'unsets_email_verify_token_expires_at'}).then((results) => {
expect(results.length).toBe(1);
return results[0];
@@ -448,7 +448,7 @@ describe("Email Verification Token Expiration: ", () => {
return user.signUp();
})
.then(() => {
const config = new Config('test');
const config = Config.get('test');
return config.database.find('_User', {username: 'newEmailVerifyTokenOnEmailReset'}).then((results) => {
return results[0];
});
@@ -465,7 +465,7 @@ describe("Email Verification Token Expiration: ", () => {
});
})
.then(() => {
const config = new Config('test');
const config = Config.get('test');
return config.database.find('_User', {username: 'newEmailVerifyTokenOnEmailReset'}).then((results) => {
return results[0];
});

View File

@@ -45,5 +45,5 @@ describe('Enable single schema cache', () => {
});
const fakeRequestForConfig = function() {
return new Config('test');
return Config.get('test');
};

View File

@@ -17,7 +17,7 @@ const mockAdapter = {
describe("FilesController",() =>{
it("should properly expand objects", (done) => {
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var gridStoreAdapter = new GridStoreAdapter('mongodb://localhost:27017/parse');
var filesController = new FilesController(gridStoreAdapter)
var result = filesController.expandFilesInObject(config, function(){});

View File

@@ -11,7 +11,7 @@ describe_only_db('mongo')("GridStoreAdapter",() =>{
it("should properly instanciate the GridStore when deleting a file", (done) => {
var databaseURI = 'mongodb://localhost:27017/parse';
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var gridStoreAdapter = new GridStoreAdapter(databaseURI);
var filesController = new FilesController(gridStoreAdapter);

View File

@@ -5,7 +5,7 @@ var InstallationsRouter = require('../src/Routers/InstallationsRouter').Installa
describe('InstallationsRouter', () => {
it('uses find condition from request.body', (done) => {
var config = new Config('test');
var config = Config.get('test');
var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android'
@@ -43,7 +43,7 @@ describe('InstallationsRouter', () => {
});
it('uses find condition from request.query', (done) => {
var config = new Config('test');
var config = Config.get('test');
var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android'
@@ -81,7 +81,7 @@ describe('InstallationsRouter', () => {
});
it('query installations with limit = 0', (done) => {
var config = new Config('test');
var config = Config.get('test');
var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android'
@@ -100,7 +100,7 @@ describe('InstallationsRouter', () => {
info: {}
};
new Config('test');
Config.get('test');
var router = new InstallationsRouter();
rest.create(config, auth.nobody(config), '_Installation', androidDeviceRequest)
.then(() => {
@@ -118,7 +118,7 @@ describe('InstallationsRouter', () => {
});
it('query installations with count = 1', done => {
var config = new Config('test');
var config = Config.get('test');
var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android'
@@ -154,7 +154,7 @@ describe('InstallationsRouter', () => {
});
it('query installations with limit = 0 and count = 1', (done) => {
var config = new Config('test');
var config = Config.get('test');
var androidDeviceRequest = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android'

View File

@@ -1234,7 +1234,7 @@ describe('Parse.ACL', () => {
});
it('regression test #701', done => {
const config = new Config('test');
const config = Config.get('test');
var anonUser = {
authData: {
anonymous: {

View File

@@ -23,7 +23,7 @@ describe_only_db('mongo')('miscellaneous', () => {
obj.set('foo', 'bar');
return obj.save();
}).then(() => {
const config = new Config(appId);
const config = Config.get(appId);
return config.database.adapter.find('TestObject', { fields: {} }, {}, {});
}).then((results) => {
expect(results.length).toEqual(1);
@@ -151,7 +151,7 @@ describe('miscellaneous', function() {
});
it('ensure that if people already have duplicate users, they can still sign up new users', done => {
const config = new Config('test');
const config = Config.get('test');
// Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently()
.then(() => config.database.adapter.createClass('_User', userSchema))
@@ -183,7 +183,7 @@ describe('miscellaneous', function() {
});
it('ensure that if people already have duplicate emails, they can still sign up new users', done => {
const config = new Config('test');
const config = Config.get('test');
// Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently()
.then(() => config.database.adapter.createClass('_User', userSchema))
@@ -211,7 +211,7 @@ describe('miscellaneous', function() {
});
it('ensure that if you try to sign up a user with a unique username and email, but duplicates in some other field that has a uniqueness constraint, you get a regular duplicate value error', done => {
const config = new Config('test');
const config = Config.get('test');
config.database.adapter.addFieldIfNotExists('_User', 'randomField', { type: 'String' })
.then(() => config.database.adapter.ensureUniqueness('_User', userSchema, ['randomField']))
.then(() => {
@@ -1546,7 +1546,7 @@ describe_only_db('mongo')('legacy _acl', () => {
},
json: true
}).then(() => {
const config = new Config('test');
const config = Config.get('test');
const adapter = config.database.adapter;
return adapter._adaptiveCollection("Report")
.then(collection => collection.find({}))

View File

@@ -5,7 +5,7 @@ const Config = require('../src/Config');
describe('a GlobalConfig', () => {
beforeEach(done => {
const config = new Config('test');
const config = Config.get('test');
const query = on_db('mongo', () => {
// Legacy is with an int...
return { objectId: 1 };
@@ -147,7 +147,7 @@ describe('a GlobalConfig', () => {
});
it('failed getting config when it is missing', (done) => {
const config = new Config('test');
const config = Config.get('test');
config.database.adapter.deleteObjectsByQuery(
'_GlobalConfig',
{ fields: { params: { __type: 'String' } } },

View File

@@ -21,7 +21,7 @@ const installationSchema = { fields: Object.assign({}, defaultColumns._Default,
describe('Installations', () => {
beforeEach(() => {
config = new Config('test');
config = Config.get('test');
database = config.database;
});

View File

@@ -1,5 +1,6 @@
var Parse = require('parse/node');
var ParseLiveQueryServer = require('../src/LiveQuery/ParseLiveQueryServer').ParseLiveQueryServer;
var ParseServer = require('../src/ParseServer').default;
// Global mock info
var queryHashValue = 'hash';
@@ -86,6 +87,66 @@ describe('ParseLiveQueryServer', function() {
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
});
it('can be initialized from ParseServer', function() {
var httpServer = {};
var parseLiveQueryServer = ParseServer.createLiveQueryServer(httpServer, {});
expect(parseLiveQueryServer.clientId).toBeUndefined();
expect(parseLiveQueryServer.clients.size).toBe(0);
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
});
it('can be initialized from ParseServer without httpServer', function(done) {
var parseLiveQueryServer = ParseServer.createLiveQueryServer(undefined, {
port: 22345
});
expect(parseLiveQueryServer.clientId).toBeUndefined();
expect(parseLiveQueryServer.clients.size).toBe(0);
expect(parseLiveQueryServer.subscriptions.size).toBe(0);
parseLiveQueryServer.server.close(done);
});
it('can be initialized through ParseServer without liveQueryServerOptions', function(done) {
var parseServer = ParseServer.start({
appId: 'hello',
masterKey: 'world',
port: 22345,
mountPath: '/1',
serverURL: 'http://localhost:12345/1',
liveQuery: {
classNames: ['Yolo']
},
startLiveQueryServer: true
});
expect(parseServer.liveQueryServer).not.toBeUndefined();
expect(parseServer.liveQueryServer.server).toBe(parseServer.server);
parseServer.server.close(done);
});
it('can be initialized through ParseServer with liveQueryServerOptions', function(done) {
var parseServer = ParseServer.start({
appId: 'hello',
masterKey: 'world',
port: 22346,
mountPath: '/1',
serverURL: 'http://localhost:12345/1',
liveQuery: {
classNames: ['Yolo']
},
liveQueryServerOptions: {
port: 22347,
}
});
expect(parseServer.liveQueryServer).not.toBeUndefined();
expect(parseServer.liveQueryServer.server).not.toBe(parseServer.server);
parseServer.liveQueryServer.server.close();
parseServer.server.close(done);
});
it('can handle connect command', function() {
var parseLiveQueryServer = new ParseLiveQueryServer(10, 10, {});
var parseWebSocket = {

View File

@@ -116,7 +116,7 @@ describe('Parse Role testing', () => {
return Parse.Object.saveAll(roles, { useMasterKey: true });
}).then(() => {
auth = new Auth({config: new Config("test"), isMaster: true, user: user});
auth = new Auth({config: Config.get("test"), isMaster: true, user: user});
getAllRolesSpy = spyOn(auth, "_getAllRolesNamesForRoleIds").and.callThrough();
return auth._loadRoles();
@@ -159,7 +159,7 @@ describe('Parse Role testing', () => {
return createRole(rolesNames[2], anotherRole, null);
}).then((lastRole) => {
roleIds[lastRole.get("name")] = lastRole.id;
var auth = new Auth({ config: new Config("test"), isMaster: true, user: user });
var auth = new Auth({ config: Config.get("test"), isMaster: true, user: user });
return auth._loadRoles();
})
}).then((roles) => {
@@ -222,7 +222,7 @@ describe('Parse Role testing', () => {
superContentManager.getRoles().add(superModerator);
return Parse.Object.saveAll([admin, moderator, contentManager, superModerator, superContentManager], {useMasterKey: true});
}).then(() => {
var auth = new Auth({ config: new Config("test"), isMaster: true });
var auth = new Auth({ config: Config.get("test"), isMaster: true });
// For each role, fetch their sibling, what they inherit
// return with result and roleId for later comparison
const promises = [admin, moderator, contentManager, superModerator].map((role) => {

View File

@@ -2523,7 +2523,7 @@ describe('Parse.User testing', () => {
});
it_exclude_dbs(['postgres'])('should cleanup null authData keys (regression test for #935)', (done) => {
const database = new Config(Parse.applicationId).database;
const database = Config.get(Parse.applicationId).database;
database.create('_User', {
username: 'user',
_hashed_password: '$2a$10$8/wZJyEuiEaobBBqzTG.jeY.XSFJd0rzaN//ososvEI4yLqI.4aie',
@@ -2557,7 +2557,7 @@ describe('Parse.User testing', () => {
});
it_exclude_dbs(['postgres'])('should not serve null authData keys', (done) => {
const database = new Config(Parse.applicationId).database;
const database = Config.get(Parse.applicationId).database;
database.create('_User', {
username: 'user',
_hashed_password: '$2a$10$8/wZJyEuiEaobBBqzTG.jeY.XSFJd0rzaN//ososvEI4yLqI.4aie',
@@ -2842,7 +2842,7 @@ describe('Parse.User testing', () => {
});
it('should not create extraneous session tokens', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
config.database.loadSchema().then((s) => {
// Lock down the _User class for creation
return s.addClassIfNotExists('_User', {}, {create: {}})

View File

@@ -4,11 +4,11 @@ var Config = require('../src/Config');
describe('Pointer Permissions', () => {
beforeEach(() => {
new Config(Parse.applicationId).database.schemaCache.clear();
Config.get(Parse.applicationId).database.schemaCache.clear();
});
it('should work with find', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -47,7 +47,7 @@ describe('Pointer Permissions', () => {
it('should work with write', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -112,7 +112,7 @@ describe('Pointer Permissions', () => {
});
it('should let a proper user find', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -172,7 +172,7 @@ describe('Pointer Permissions', () => {
});
it('should query on pointer permission enabled column', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -213,7 +213,7 @@ describe('Pointer Permissions', () => {
});
it('should not allow creating objects', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
user.set({
username: 'user1',
@@ -239,7 +239,7 @@ describe('Pointer Permissions', () => {
});
it('should handle multiple writeUserFields', done => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -278,7 +278,7 @@ describe('Pointer Permissions', () => {
});
it('should prevent creating pointer permission on missing field', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
config.database.loadSchema().then((schema) => {
return schema.addClassIfNotExists('AnObject', {}, {create: {}, writeUserFields: ['owner'], readUserFields: ['owner']});
}).then(() => {
@@ -291,7 +291,7 @@ describe('Pointer Permissions', () => {
});
it('should prevent creating pointer permission on bad field', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
config.database.loadSchema().then((schema) => {
return schema.addClassIfNotExists('AnObject', {owner: {type: 'String'}}, {create: {}, writeUserFields: ['owner'], readUserFields: ['owner']});
}).then(() => {
@@ -304,7 +304,7 @@ describe('Pointer Permissions', () => {
});
it('should prevent creating pointer permission on bad field', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('owner', 'value');
object.save().then(() => {
@@ -329,7 +329,7 @@ describe('Pointer Permissions', () => {
The owner is another user than the ACL
*/
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -374,7 +374,7 @@ describe('Pointer Permissions', () => {
PointerPerm: "owner"
ACL: logged in user has access
*/
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -419,7 +419,7 @@ describe('Pointer Permissions', () => {
PointerPerm: "owner"
ACL: logged in user has access
*/
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -466,7 +466,7 @@ describe('Pointer Permissions', () => {
The owner is another user than the ACL
*/
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -511,7 +511,7 @@ describe('Pointer Permissions', () => {
PointerPerm: "owner" : read
ACL: logged in user has access
*/
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -558,7 +558,7 @@ describe('Pointer Permissions', () => {
PointerPerm: "owner" : read // proper owner
ACL: logged in user has not access
*/
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
const user2 = new Parse.User();
user.set({
@@ -597,7 +597,7 @@ describe('Pointer Permissions', () => {
});
it('should let master key find objects', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('hello', 'world');
return object.save().then(() => {
@@ -626,7 +626,7 @@ describe('Pointer Permissions', () => {
});
it('should let master key get objects', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('hello', 'world');
return object.save().then(() => {
@@ -657,7 +657,7 @@ describe('Pointer Permissions', () => {
it('should let master key update objects', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('hello', 'world');
return object.save().then(() => {
@@ -684,7 +684,7 @@ describe('Pointer Permissions', () => {
});
it('should let master key delete objects', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const object = new Parse.Object('AnObject');
object.set('hello', 'world');
return object.save().then(() => {
@@ -710,7 +710,7 @@ describe('Pointer Permissions', () => {
});
it('should fail with invalid pointer perms', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
config.database.loadSchema().then((schema) => {
// Lock the update, and let only owner write
return schema.addClassIfNotExists('AnObject', {owner: {type: 'Pointer', targetClass: '_User'}}, {delete: {}, writeUserFields: 'owner'});
@@ -721,7 +721,7 @@ describe('Pointer Permissions', () => {
});
it('should fail with invalid pointer perms', (done) => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
config.database.loadSchema().then((schema) => {
// Lock the update, and let only owner write
return schema.addClassIfNotExists('AnObject', {owner: {type: 'Pointer', targetClass: '_User'}}, {delete: {}, writeUserFields: ['owner', 'invalid']});

View File

@@ -205,7 +205,7 @@ describe('PushController', () => {
installation.set("deviceType", "android");
installations.push(installation);
}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -276,7 +276,7 @@ describe('PushController', () => {
installations.push(installation);
}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -350,7 +350,7 @@ describe('PushController', () => {
}
}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -425,7 +425,7 @@ describe('PushController', () => {
}
}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -529,7 +529,7 @@ describe('PushController', () => {
}
}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -579,7 +579,7 @@ describe('PushController', () => {
alert: "Hello World!",
badge: 1,
}}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -616,7 +616,7 @@ describe('PushController', () => {
return ["ios"];
}
}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -677,7 +677,7 @@ describe('PushController', () => {
}
}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -762,7 +762,7 @@ describe('PushController', () => {
});
it('should not schedule push when not configured', (done) => {
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -862,7 +862,7 @@ describe('PushController', () => {
push: { adapter: pushAdapter },
scheduledPush: true
}).then(() => {
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
return Parse.Object.saveAll(installations).then(() => {
return pushController.sendPush(payload, {}, config, auth);
}).then(() => new Promise(resolve => setTimeout(resolve, 300)));
@@ -931,7 +931,7 @@ describe('PushController', () => {
reconfigureServer({
push: { adapter: pushAdapter }
}).then(() => {
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
return Parse.Object.saveAll(installations).then(() => {
return pushController.sendPush(payload, {}, config, auth);
}).then(() => new Promise(resolve => setTimeout(resolve, 100)));
@@ -996,7 +996,7 @@ describe('PushController', () => {
reconfigureServer({
push: { adapter: pushAdapter }
}).then(() => {
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
return Parse.Object.saveAll(installations).then(() => {
return pushController.sendPush(payload, {}, config, auth)
.then(() => { done.fail('should not success') })
@@ -1034,7 +1034,7 @@ describe('PushController', () => {
}
}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -1094,7 +1094,7 @@ describe('PushController', () => {
}
}
var config = new Config(Parse.applicationId);
var config = Config.get(Parse.applicationId);
var auth = {
isMaster: true
}
@@ -1230,7 +1230,7 @@ describe('PushController', () => {
scheduledPush: true
})
.then(() => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
return new Promise((resolve, reject) => {
const pushController = new PushController();
pushController.sendPush({

View File

@@ -21,7 +21,7 @@ describe('PushQueue', () => {
}
})
.then(() => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
expect(config.pushWorker.channel).toEqual('my-specific-channel', 'pushWorker.channel');
expect(config.pushControllerQueue.channel).toEqual('my-specific-channel', 'pushWorker.channel');
})
@@ -47,7 +47,7 @@ describe('PushQueue', () => {
}
})
.then(() => {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
expect(PushQueue.defaultPushChannel()).toEqual('test-parse-server-push');
expect(config.pushWorker.channel).toEqual('test-parse-server-push');
expect(config.pushControllerQueue.channel).toEqual('test-parse-server-push');

View File

@@ -16,7 +16,7 @@ describe('PushWorker', () => {
}
}
}).then(() => {
expect(new Config('test').pushWorker).toBeUndefined();
expect(Config.get('test').pushWorker).toBeUndefined();
new PushWorker({
send: (body, installations) => {
expect(installations.length <= batchSize).toBe(true);
@@ -161,7 +161,7 @@ describe('PushWorker', () => {
describe('pushStatus', () => {
it('should remove invalid installations', (done) => {
const config = new Config('test');
const config = Config.get('test');
const handler = pushStatusHandler(config);
const spy = spyOn(config.database, "update").and.callFake(() => {
return Promise.resolve();
@@ -244,7 +244,7 @@ describe('PushWorker', () => {
});
it('tracks push status per UTC offsets', (done) => {
const config = new Config('test');
const config = Config.get('test');
const handler = pushStatusHandler(config);
const spy = spyOn(rest, "update").and.callThrough();
const UTCOffset = 1;
@@ -320,7 +320,7 @@ describe('PushWorker', () => {
});
it('tracks push status per UTC offsets with negative offsets', (done) => {
const config = new Config('test');
const config = Config.get('test');
const handler = pushStatusHandler(config);
const spy = spyOn(rest, "update").and.callThrough();
const UTCOffset = -6;

View File

@@ -7,7 +7,7 @@ const Config = require("../src/Config");
describe_only_db('mongo')('Read preference option', () => {
it('should find in primary by default', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -39,7 +39,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference in the beforeFind trigger', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -75,7 +75,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference in the beforeFind trigger even changing query', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -112,7 +112,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference in the beforeFind trigger even returning query', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -152,7 +152,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference in the beforeFind trigger even returning promise', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -192,7 +192,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference to PRIMARY_PREFERRED', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -228,7 +228,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference to SECONDARY_PREFERRED', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -264,7 +264,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference to NEAREST', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -300,7 +300,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference for GET', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -334,7 +334,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference for GET using API', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -374,7 +374,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change read preference for count', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
@@ -407,7 +407,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should find includes in primary by default', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
@@ -462,7 +462,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change includes read preference', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
@@ -519,7 +519,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should find subqueries in primary by default', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
@@ -575,7 +575,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change subqueries read preference when using matchesQuery', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
@@ -632,7 +632,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change subqueries read preference when using doesNotMatchQuery', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
@@ -689,7 +689,7 @@ describe_only_db('mongo')('Read preference option', () => {
});
it('should change subqueries read preference when using matchesKeyInQuery and doesNotMatchKeyInQuery', (done) => {
const databaseAdapter = (new Config(Parse.applicationId)).database.adapter;
const databaseAdapter = (Config.get(Parse.applicationId)).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);

View File

@@ -14,7 +14,7 @@ var nobody = auth.nobody(config);
describe('rest query', () => {
beforeEach(() => {
config = new Config('test');
config = Config.get('test');
database = config.database;
});

View File

@@ -4,7 +4,7 @@ const rp = require('request-promise');
const Parse = require('parse/node');
function createUser() {
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
const user = {
objectId: '1234567890',
username: 'hello',
@@ -29,7 +29,7 @@ describe_only_db('mongo')('revocable sessions', () => {
});
user._upgradeToRevocableSession().then((res) => {
expect(res.getSessionToken().indexOf('r:')).toBe(0);
const config = new Config(Parse.applicationId);
const config = Config.get(Parse.applicationId);
// use direct access to the DB to make sure we're not
// getting the session token stripped
return config.database.loadSchema().then(schemaController => {

View File

@@ -21,7 +21,7 @@ var hasAllPODobject = () => {
describe('SchemaController', () => {
beforeEach(() => {
config = new Config('test');
config = Config.get('test');
});
it('can validate one object', (done) => {
@@ -1029,7 +1029,7 @@ describe('SchemaController', () => {
describe('Class Level Permissions for requiredAuth', () => {
beforeEach(() => {
config = new Config('test');
config = Config.get('test');
});
function createUser() {

View File

@@ -9,7 +9,7 @@ describe('Uniqueness', function() {
obj.set('unique', 'value');
obj.save().then(() => {
expect(obj.id).not.toBeUndefined();
const config = new Config('test');
const config = Config.get('test');
return config.database.adapter.ensureUniqueness('UniqueField', { fields: { unique: { __type: 'String' } } }, ['unique'])
})
.then(() => {
@@ -30,7 +30,7 @@ describe('Uniqueness', function() {
obj.save({ string: 'who cares' })
.then(() => obj.save({ ptr: obj }))
.then(() => {
const config = new Config('test');
const config = Config.get('test');
return config.database.adapter.ensureUniqueness('UniquePointer', { fields: {
string: { __type: 'String' },
ptr: { __type: 'Pointer', targetClass: 'UniquePointer' }
@@ -58,7 +58,7 @@ describe('Uniqueness', function() {
o2.set('key', 'val');
Parse.Object.saveAll([o1, o2])
.then(() => {
const config = new Config('test');
const config = Config.get('test');
return config.database.adapter.ensureUniqueness('UniqueFail', { fields: { key: { __type: 'String' } } }, ['key']);
})
.catch(error => {
@@ -68,7 +68,7 @@ describe('Uniqueness', function() {
});
it_exclude_dbs(['postgres'])('can do compound uniqueness', done => {
const config = new Config('test');
const config = Config.get('test');
config.database.adapter.ensureUniqueness('CompoundUnique', { fields: { k1: { __type: 'String' }, k2: { __type: 'String' } } }, ['k1', 'k2'])
.then(() => {
const o1 = new Parse.Object('CompoundUnique');

View File

@@ -18,7 +18,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
publicServerURL: "https://my.public.server.com/1"
})
.then(() => {
var config = new Config("test");
var config = Config.get("test");
expect(config.invalidLinkURL).toEqual("myInvalidLink");
expect(config.verifyEmailSuccessURL).toEqual("myVerifyEmailSuccess");
expect(config.choosePasswordURL).toEqual("myChoosePassword");
@@ -849,7 +849,7 @@ describe("Custom Pages, Email Verification, Password Reset", () => {
expect(response.body).toEqual('Found. Redirecting to http://localhost:8378/1/apps/password_reset_success.html?username=zxcv');
Parse.User.logIn("zxcv", "hello").then(function(){
const config = new Config('test');
const config = Config.get('test');
config.database.adapter.find('_User', { fields: {} }, { 'username': 'zxcv' }, { limit: 1 })
.then(results => {
// _perishable_token should be unset after reset password

View File

@@ -24,7 +24,6 @@ if (global._babelPolyfill) {
}
var cache = require('../src/cache').default;
var express = require('express');
var ParseServer = require('../src/index').ParseServer;
var path = require('path');
var TestUtils = require('../src/TestUtils');
@@ -116,8 +115,6 @@ if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') {
const openConnections = {};
// Set up a default API server for testing with default configuration.
var app;
var api;
var server;
// Allows testing specific configurations of Parse Server
@@ -131,17 +128,18 @@ const reconfigureServer = changedConfiguration => {
}
try {
const newConfiguration = Object.assign({}, defaultConfiguration, changedConfiguration, {
__indexBuildCompletionCallbackForTests: indexBuildPromise => indexBuildPromise.then(resolve, reject)
__indexBuildCompletionCallbackForTests: indexBuildPromise => indexBuildPromise.then(resolve, reject),
mountPath: '/1',
port,
});
cache.clear();
app = express();
api = new ParseServer(newConfiguration);
api.use(require('./testing-routes').router);
app.use('/1', api);
app.use('/1', () => {
const parseServer = ParseServer.start(newConfiguration);
parseServer.app.use(require('./testing-routes').router);
parseServer.expressApp.use('/1', (err) => {
console.error(err);
fail('should not call next');
});
server = app.listen(port);
server = parseServer.server;
server.on('connection', connection => {
const key = `${connection.remoteAddress}:${connection.remotePort}`;
openConnections[key] = connection;

View File

@@ -166,7 +166,7 @@ describe('server', () => {
it('can properly sets the push support', done => {
// default config passes push options
const config = new Config('test');
const config = Config.get('test');
expect(config.hasPushSupport).toEqual(true);
expect(config.hasPushScheduledSupport).toEqual(false);
request.get({
@@ -187,7 +187,7 @@ describe('server', () => {
reconfigureServer({
push: undefined // force no config
}).then(() => {
const config = new Config('test');
const config = Config.get('test');
expect(config.hasPushSupport).toEqual(false);
expect(config.hasPushScheduledSupport).toEqual(false);
request.get({
@@ -214,7 +214,7 @@ describe('server', () => {
}
}
}).then(() => {
const config = new Config('test');
const config = Config.get('test');
expect(config.hasPushSupport).toEqual(true);
expect(config.hasPushScheduledSupport).toEqual(false);
request.get({
@@ -242,7 +242,7 @@ describe('server', () => {
},
scheduledPush: true,
}).then(() => {
const config = new Config('test');
const config = Config.get('test');
expect(config.hasPushSupport).toEqual(true);
expect(config.hasPushScheduledSupport).toEqual(true);
request.get({
@@ -360,7 +360,7 @@ describe('server', () => {
it('properly gives publicServerURL when set', done => {
reconfigureServer({ publicServerURL: 'https://myserver.com/1' })
.then(() => {
var config = new Config('test', 'http://localhost:8378/1');
var config = Config.get('test', 'http://localhost:8378/1');
expect(config.mount).toEqual('https://myserver.com/1');
done();
});
@@ -369,7 +369,7 @@ describe('server', () => {
it('properly removes trailing slash in mount', done => {
reconfigureServer({})
.then(() => {
var config = new Config('test', 'http://localhost:8378/1/');
var config = Config.get('test', 'http://localhost:8378/1/');
expect(config.mount).toEqual('http://localhost:8378/1');
done();
});
@@ -385,6 +385,7 @@ describe('server', () => {
it('fails if the session length is not a number', done => {
reconfigureServer({ sessionLength: 'test' })
.then(done.fail)
.catch(error => {
expect(error).toEqual('Session length must be a valid number.');
done();
@@ -393,6 +394,7 @@ describe('server', () => {
it('fails if the session length is less than or equal to 0', done => {
reconfigureServer({ sessionLength: '-33' })
.then(done.fail)
.catch(error => {
expect(error).toEqual('Session length must be a value greater than 0.');
return reconfigureServer({ sessionLength: '0' })
@@ -441,4 +443,33 @@ describe('server', () => {
.then(done)
});
it('should load a middleware', (done) => {
const obj = {
middleware: function(req, res, next) {
next();
}
}
const spy = spyOn(obj, 'middleware').and.callThrough();
reconfigureServer({
middleware: obj.middleware
}).then(() => {
const query = new Parse.Query('AnObject');
return query.find();
}).then(() => {
expect(spy).toHaveBeenCalled();
done();
}).catch(done.fail);
});
it('should load a middleware from string', (done) => {
reconfigureServer({
middleware: 'spec/support/CustomMiddleware'
}).then(() => {
return request.get('http://localhost:8378/1', (err, res) => {
// Just check that the middleware set the header
expect(res.headers['x-yolo']).toBe('1');
done();
});
}).catch(done.fail);
});
});

View File

@@ -6,7 +6,7 @@ import {
arrayParser,
moduleOrObjectParser,
nullParser,
} from '../src/cli/utils/parsers';
} from '../src/Options/parsers';
describe('parsers', () => {
it('parses correctly with numberParser', () => {

View File

@@ -13,7 +13,7 @@ let database;
describe('rest create', () => {
beforeEach(() => {
config = new Config('test');
config = Config.get('test');
database = config.database;
});

View File

@@ -132,7 +132,7 @@ var masterKeyHeaders = {
describe('schemas', () => {
beforeEach(() => {
config = new Config('test');
config = Config.get('test');
});
afterEach(() => {

View File

@@ -0,0 +1,4 @@
module.exports = function(req, res, next) {
res.set('X-Yolo', '1');
next();
}