From c9dfac277f5a0975f910d10a2a58a9b54ec5b756 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Thu, 18 Feb 2016 18:44:04 -0800 Subject: [PATCH 1/2] Add ability to test multiple server configurations --- spec/helper.js | 27 +++++++++-- spec/index.spec.js | 38 +++++++++++++++ src/DatabaseAdapter.js | 9 +++- src/cache.js | 10 +++- src/index.js | 103 +++++++++++++++++++++++------------------ 5 files changed, 136 insertions(+), 51 deletions(-) create mode 100644 spec/index.spec.js diff --git a/spec/helper.js b/spec/helper.js index 8b587f7d5d..4a4d27c7e9 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -7,12 +7,13 @@ 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'; -// Set up an API server for testing -var api = new ParseServer({ +// Default server configuration for tests. +var defaultConfiguration = { databaseURI: databaseURI, cloud: cloudMain, appId: 'test', @@ -29,13 +30,30 @@ 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 +69,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 +241,4 @@ global.expectError = expectError; global.arrayContains = arrayContains; global.jequal = jequal; global.range = range; +global.setServerConfiguration = setServerConfiguration; diff --git a/spec/index.spec.js b/spec/index.spec.js new file mode 100644 index 0000000000..a92eab01c0 --- /dev/null +++ b/spec/index.spec.js @@ -0,0 +1,38 @@ +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', + 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(); + }); + }); +}); diff --git a/src/DatabaseAdapter.js b/src/DatabaseAdapter.js index 4967d5665d..b044c46531 100644 --- a/src/DatabaseAdapter.js +++ b/src/DatabaseAdapter.js @@ -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, }; diff --git a/src/cache.js b/src/cache.js index aba6ce16ff..eeb2803178 100644 --- a/src/cache.js +++ b/src/cache.js @@ -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, }; diff --git a/src/index.js b/src/index.js index 47b639f423..36eda1b968 100644 --- a/src/index.js +++ b/src/index.js @@ -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,49 +91,45 @@ 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); - if(args.serverURL) { - Parse.serverURL = args.serverURL; + Parse.initialize(appId, javascriptKey, masterKey); + if (serverURL) { + Parse.serverURL = serverURL; } // This app serves the Parse API directly. @@ -129,7 +141,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); } From 5378de7398dbe85f97219085468b5149fddc7246 Mon Sep 17 00:00:00 2001 From: Drew Gross Date: Fri, 19 Feb 2016 19:00:43 -0800 Subject: [PATCH 2/2] Add server URL to tests --- spec/helper.js | 3 ++- spec/index.spec.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/helper.js b/spec/helper.js index 4a4d27c7e9..c89e2dbe9e 100644 --- a/spec/helper.js +++ b/spec/helper.js @@ -11,11 +11,13 @@ var DatabaseAdapter = require('../src/DatabaseAdapter'); var databaseURI = process.env.DATABASE_URI; var cloudMain = process.env.CLOUD_CODE_MAIN || './cloud/main.js'; +var port = 8378; // Default server configuration for tests. var defaultConfiguration = { databaseURI: databaseURI, cloud: cloudMain, + serverURL: 'http://localhost:' + port + '/1', appId: 'test', javascriptKey: 'test', dotNetKey: 'windows', @@ -36,7 +38,6 @@ var defaultConfiguration = { 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 diff --git a/spec/index.spec.js b/spec/index.spec.js index a92eab01c0..0e3eba5db8 100644 --- a/spec/index.spec.js +++ b/spec/index.spec.js @@ -10,6 +10,7 @@ describe('server', () => { 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',