Merge pull request #498 from drew-gross/test-configurations

Add ability to test multiple server configurations
This commit is contained in:
Drew
2016-02-19 19:28:30 -08:00
5 changed files with 138 additions and 51 deletions

View File

@@ -7,14 +7,17 @@ var DatabaseAdapter = require('../src/DatabaseAdapter');
var express = require('express');
var facebook = require('../src/oauth/facebook');
var ParseServer = require('../src/index').ParseServer;
var DatabaseAdapter = require('../src/DatabaseAdapter');
var databaseURI = process.env.DATABASE_URI;
var cloudMain = process.env.CLOUD_CODE_MAIN || './cloud/main.js';
var port = 8378;
// Set up an API server for testing
var api = new ParseServer({
// Default server configuration for tests.
var defaultConfiguration = {
databaseURI: databaseURI,
cloud: cloudMain,
serverURL: 'http://localhost:' + port + '/1',
appId: 'test',
javascriptKey: 'test',
dotNetKey: 'windows',
@@ -29,13 +32,29 @@ var api = new ParseServer({
module: "../spec/myoauth" // relative path as it's run from src
}
}
});
};
// Set up a default API server for testing with default configuration.
var api = new ParseServer(defaultConfiguration);
var app = express();
app.use('/1', api);
var port = 8378;
var server = app.listen(port);
// Prevent reinitializing the server from clobbering Cloud Code
delete defaultConfiguration.cloud;
// Allows testing specific configurations of Parse Server
var setServerConfiguration = configuration => {
api = new ParseServer(configuration);
app = express();
app.use('/1', api);
cache.clearCache();
server.close();
server = app.listen(port);
}
var restoreServerConfiguration = () => setServerConfiguration(defaultConfiguration);
// Set up a Parse client to talk to our test API server
var Parse = require('parse/node');
Parse.serverURL = 'http://localhost:' + port + '/1';
@@ -51,9 +70,11 @@ beforeEach(function(done) {
});
afterEach(function(done) {
restoreServerConfiguration();
Parse.User.logOut().then(() => {
return clearData();
}).then(() => {
DatabaseAdapter.clearDatabaseURIs();
done();
}, (error) => {
console.log('error in clearData', error);
@@ -221,3 +242,4 @@ global.expectError = expectError;
global.arrayContains = arrayContains;
global.jequal = jequal;
global.range = range;
global.setServerConfiguration = setServerConfiguration;

39
spec/index.spec.js Normal file
View File

@@ -0,0 +1,39 @@
var request = require('request');
describe('server', () => {
it('requires a master key and app id', done => {
expect(setServerConfiguration.bind(undefined, { masterKey: 'mykey' })).toThrow('You must provide an appId and masterKey!');
expect(setServerConfiguration.bind(undefined, { appId: 'myId' })).toThrow('You must provide an appId and masterKey!');
done();
});
it('fails if database is unreachable', done => {
setServerConfiguration({
databaseURI: 'mongodb://fake:fake@ds043605.mongolab.com:43605/drew3',
serverURL: 'http://localhost:8378/1',
appId: 'test',
javascriptKey: 'test',
dotNetKey: 'windows',
clientKey: 'client',
restAPIKey: 'rest',
masterKey: 'test',
collectionPrefix: 'test_',
fileKey: 'test',
});
//Need to use rest api because saving via JS SDK results in fail() not getting called
request.post({
url: 'http://localhost:8378/1/classes/NewClass',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
body: {},
json: true,
}, (error, response, body) => {
expect(response.statusCode).toEqual(500);
expect(body.code).toEqual(1);
expect(body.message).toEqual('Internal server error.');
done();
});
});
});

View File

@@ -34,6 +34,12 @@ function setAppDatabaseURI(appId, uri) {
appDatabaseURIs[appId] = uri;
}
//Used by tests
function clearDatabaseURIs() {
appDatabaseURIs = {};
dbConnections = {};
}
function getDatabaseConnection(appId) {
if (dbConnections[appId]) {
return dbConnections[appId];
@@ -52,5 +58,6 @@ module.exports = {
getDatabaseConnection: getDatabaseConnection,
setAdapter: setAdapter,
setDatabaseURI: setDatabaseURI,
setAppDatabaseURI: setAppDatabaseURI
setAppDatabaseURI: setAppDatabaseURI,
clearDatabaseURIs: clearDatabaseURIs,
};

View File

@@ -25,6 +25,13 @@ function clearUser(sessionToken) {
delete users[sessionToken];
}
//So far used only in tests
function clearCache() {
apps = {};
stats = {};
users = {};
}
module.exports = {
apps: apps,
stats: stats,
@@ -33,5 +40,6 @@ module.exports = {
updateStat: updateStat,
clearUser: clearUser,
getUser: getUser,
setUser: setUser
setUser: setUser,
clearCache: clearCache,
};

View File

@@ -11,21 +11,21 @@ var batch = require('./batch'),
PromiseRouter = require('./PromiseRouter'),
httpRequest = require('./httpRequest');
import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter';
import { S3Adapter } from './Adapters/Files/S3Adapter';
import { FilesController } from './Controllers/FilesController';
import { GridStoreAdapter } from './Adapters/Files/GridStoreAdapter';
import { S3Adapter } from './Adapters/Files/S3Adapter';
import { FilesController } from './Controllers/FilesController';
import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
import { PushController } from './Controllers/PushController';
import ParsePushAdapter from './Adapters/Push/ParsePushAdapter';
import { PushController } from './Controllers/PushController';
import { ClassesRouter } from './Routers/ClassesRouter';
import { ClassesRouter } from './Routers/ClassesRouter';
import { InstallationsRouter } from './Routers/InstallationsRouter';
import { UsersRouter } from './Routers/UsersRouter';
import { SessionsRouter } from './Routers/SessionsRouter';
import { RolesRouter } from './Routers/RolesRouter';
import { UsersRouter } from './Routers/UsersRouter';
import { SessionsRouter } from './Routers/SessionsRouter';
import { RolesRouter } from './Routers/RolesRouter';
import { FileLoggerAdapter } from './Adapters/Logger/FileLoggerAdapter';
import { LoggerController } from './Controllers/LoggerController';
import { FileLoggerAdapter } from './Adapters/Logger/FileLoggerAdapter';
import { LoggerController } from './Controllers/LoggerController';
// Mutate the Parse object to add the Cloud Code handlers
addParseCloud();
@@ -54,20 +54,36 @@ addParseCloud();
// "javascriptKey": optional key from Parse dashboard
// "push": optional key from configure push
function ParseServer(args) {
if (!args.appId || !args.masterKey) {
function ParseServer({
appId,
masterKey,
databaseAdapter,
filesAdapter = new GridStoreAdapter(),
push,
loggerAdapter = new FileLoggerAdapter(),
databaseURI,
cloud,
collectionPrefix = '',
clientKey = '',
javascriptKey = '',
dotNetKey = '',
restAPIKey = '',
fileKey = 'invalid-file-key',
facebookAppIds = [],
enableAnonymousUsers = true,
oauth = {},
serverURL = '',
}) {
if (!appId || !masterKey) {
throw 'You must provide an appId and masterKey!';
}
if (args.databaseAdapter) {
DatabaseAdapter.setAdapter(args.databaseAdapter);
if (databaseAdapter) {
DatabaseAdapter.setAdapter(databaseAdapter);
}
// Make files adapter
let filesAdapter = args.filesAdapter || new GridStoreAdapter();
// Make push adapter
let pushConfig = args.push;
let pushConfig = push;
let pushAdapter;
if (pushConfig && pushConfig.adapter) {
pushAdapter = pushConfig.adapter;
@@ -75,48 +91,44 @@ function ParseServer(args) {
pushAdapter = new ParsePushAdapter(pushConfig)
}
// Make logger adapter
let loggerAdapter = args.loggerAdapter || new FileLoggerAdapter();
if (args.databaseURI) {
DatabaseAdapter.setAppDatabaseURI(args.appId, args.databaseURI);
if (databaseURI) {
DatabaseAdapter.setAppDatabaseURI(appId, databaseURI);
}
if (args.cloud) {
if (cloud) {
addParseCloud();
if (typeof args.cloud === 'function') {
args.cloud(Parse)
} else if (typeof args.cloud === 'string') {
require(args.cloud);
if (typeof cloud === 'function') {
cloud(Parse)
} else if (typeof cloud === 'string') {
require(cloud);
} else {
throw "argument 'cloud' must either be a string or a function";
}
}
let filesController = new FilesController(filesAdapter);
cache.apps[args.appId] = {
masterKey: args.masterKey,
collectionPrefix: args.collectionPrefix || '',
clientKey: args.clientKey || '',
javascriptKey: args.javascriptKey || '',
dotNetKey: args.dotNetKey || '',
restAPIKey: args.restAPIKey || '',
fileKey: args.fileKey || 'invalid-file-key',
facebookAppIds: args.facebookAppIds || [],
cache.apps[appId] = {
masterKey: masterKey,
collectionPrefix: collectionPrefix,
clientKey: clientKey,
javascriptKey: javascriptKey,
dotNetKey: dotNetKey,
restAPIKey: restAPIKey,
fileKey: fileKey,
facebookAppIds: facebookAppIds,
filesController: filesController,
enableAnonymousUsers: args.enableAnonymousUsers || true,
oauth: args.oauth || {},
enableAnonymousUsers: enableAnonymousUsers,
oauth: oauth,
};
// To maintain compatibility. TODO: Remove in v2.1
if (process.env.FACEBOOK_APP_ID) {
cache.apps[args.appId]['facebookAppIds'].push(process.env.FACEBOOK_APP_ID);
cache.apps[appId]['facebookAppIds'].push(process.env.FACEBOOK_APP_ID);
}
// Initialize the node client SDK automatically
Parse.initialize(args.appId, args.javascriptKey || '', args.masterKey);
Parse.serverURL = args.serverURL || '';
Parse.initialize(appId, javascriptKey, masterKey);
Parse.serverURL = serverURL;
// This app serves the Parse API directly.
// It's the equivalent of https://api.parse.com/1 in the hosted Parse API.
@@ -127,7 +139,6 @@ function ParseServer(args) {
// TODO: separate this from the regular ParseServer object
if (process.env.TESTING == 1) {
console.log('enabling integration testing-routes');
api.use('/', require('./testing-routes').router);
}